diff --git a/package-lock.json b/package-lock.json index 3e5bd51b5..7528202bd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,8 +1,3399 @@ { "name": "bitcoinjs-lib", "version": "6.0.1", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "version": "6.0.1", + "license": "MIT", + "dependencies": { + "bech32": "^2.0.0", + "bip174": "^2.0.1", + "bs58check": "^2.1.2", + "create-hash": "^1.1.0", + "tiny-secp256k1": "^2.2.0", + "typeforce": "^1.11.3", + "varuint-bitcoin": "^1.1.2", + "wif": "^2.0.1" + }, + "devDependencies": { + "@types/bs58": "^4.0.0", + "@types/bs58check": "^2.1.0", + "@types/create-hash": "^1.2.2", + "@types/mocha": "^5.2.7", + "@types/node": "^16.11.7", + "@types/proxyquire": "^1.3.28", + "@types/randombytes": "^2.0.0", + "@types/wif": "^2.0.2", + "bip32": "^3.0.1", + "bip39": "^3.0.2", + "bip65": "^1.0.1", + "bip68": "^1.0.3", + "bs58": "^4.0.0", + "dhttp": "^3.0.0", + "ecpair": "^2.0.1", + "hoodwink": "^2.0.0", + "minimaldata": "^1.0.2", + "mocha": "^7.1.1", + "npm-audit-whitelister": "^1.0.2", + "nyc": "^15.1.0", + "prettier": "1.16.4", + "proxyquire": "^2.0.1", + "randombytes": "^2.1.0", + "regtest-client": "0.2.0", + "rimraf": "^2.6.3", + "ts-node": "^8.3.0", + "tslint": "^6.1.3", + "typescript": "^4.4.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz", + "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.13.tgz", + "integrity": "sha512-BQKE9kXkPlXHPeqissfxo0lySWJcYdEP0hdtJOH/iJfDdhOCcgtNCjftCJg3qqauB4h+lz2N6ixM++b9DN1Tcw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@babel/generator": "^7.12.13", + "@babel/helper-module-transforms": "^7.12.13", + "@babel/helpers": "^7.12.13", + "@babel/parser": "^7.12.13", + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.12.13", + "@babel/types": "^7.12.13", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.19", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/@babel/code-frame": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", + "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.12.13" + } + }, + "node_modules/@babel/core/node_modules/@babel/highlight": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.12.13.tgz", + "integrity": "sha512-kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.12.11", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "node_modules/@babel/core/node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/core/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@babel/generator": { + "version": "7.12.15", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.15.tgz", + "integrity": "sha512-6F2xHxBiFXWNSGb7vyCUTBF8RCLY66rS0zEPcP8t/nQyXjha5EuK4z7H5o7fWG8B4M7y6mqVWq1J+1PuwRhecQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.13", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", + "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", + "dev": true, + "dependencies": { + "@babel/helper-get-function-arity": "^7.12.13", + "@babel/template": "^7.12.13", + "@babel/types": "^7.12.13" + } + }, + "node_modules/@babel/helper-get-function-arity": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", + "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.13" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.13.tgz", + "integrity": "sha512-B+7nN0gIL8FZ8SvMcF+EPyB21KnCcZHQZFczCxbiNGV/O0rsrSBlWGLzmtBJ3GMjSVMIm4lpFhR+VdVBuIsUcQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.13" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.13.tgz", + "integrity": "sha512-NGmfvRp9Rqxy0uHSSVP+SRIW1q31a7Ji10cLBcqSDUngGentY4FRiHOFZFE1CLU5eiL0oE8reH7Tg1y99TDM/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.13" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.13.tgz", + "integrity": "sha512-acKF7EjqOR67ASIlDTupwkKM1eUisNAjaSduo5Cz+793ikfnpe7p4Q7B7EWU2PCoSTPWsQkR7hRUWEIZPiVLGA==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.12.13", + "@babel/helper-replace-supers": "^7.12.13", + "@babel/helper-simple-access": "^7.12.13", + "@babel/helper-split-export-declaration": "^7.12.13", + "@babel/helper-validator-identifier": "^7.12.11", + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.12.13", + "@babel/types": "^7.12.13", + "lodash": "^4.17.19" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz", + "integrity": "sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.13" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.13.tgz", + "integrity": "sha512-pctAOIAMVStI2TMLhozPKbf5yTEXc0OJa0eENheb4w09SrgOWEs+P4nTOZYJQCqs8JlErGLDPDJTiGIp3ygbLg==", + "dev": true, + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.12.13", + "@babel/helper-optimise-call-expression": "^7.12.13", + "@babel/traverse": "^7.12.13", + "@babel/types": "^7.12.13" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.13.tgz", + "integrity": "sha512-0ski5dyYIHEfwpWGx5GPWhH35j342JaflmCeQmsPWcrOQDtCN6C1zKAVRFVbK53lPW2c9TsuLLSUDf0tIGJ5hA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.13" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", + "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.13" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", + "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", + "dev": true + }, + "node_modules/@babel/helpers": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.12.13.tgz", + "integrity": "sha512-oohVzLRZ3GQEk4Cjhfs9YkJA4TdIDTObdBEZGrd6F/T0GPSnuV6l22eMcxlvcvzVIPH3VTtxbseudM1zIE+rPQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.12.13", + "@babel/types": "^7.12.13" + } + }, + "node_modules/@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/@babel/helper-validator-identifier": { + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.12.15", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.15.tgz", + "integrity": "sha512-AQBOU2Z9kWwSZMd6lNjCX0GUgFonL1wAM1db8L8PMk9UDaGsRCArBkU4Sc+UCM3AE4hjbXx+h58Lb3QT4oRmrA==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", + "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@babel/parser": "^7.12.13", + "@babel/types": "^7.12.13" + } + }, + "node_modules/@babel/template/node_modules/@babel/code-frame": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", + "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.12.13" + } + }, + "node_modules/@babel/template/node_modules/@babel/highlight": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.12.13.tgz", + "integrity": "sha512-kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.12.11", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.13.tgz", + "integrity": "sha512-3Zb4w7eE/OslI0fTp8c7b286/cQps3+vdLW3UcwC8VSJC6GbKn55aeVVu2QJNuCDoeKyptLOFrPq8WqZZBodyA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@babel/generator": "^7.12.13", + "@babel/helper-function-name": "^7.12.13", + "@babel/helper-split-export-declaration": "^7.12.13", + "@babel/parser": "^7.12.13", + "@babel/types": "^7.12.13", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.19" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/code-frame": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", + "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.12.13" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/highlight": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.12.13.tgz", + "integrity": "sha512-kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.12.11", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "node_modules/@babel/traverse/node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/traverse/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@babel/types": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.13.tgz", + "integrity": "sha512-oKrdZTld2im1z8bDwTOQvUbxKwE+854zc16qWZQlcTqMN00pWxHQ4ZeOq0yDMnisOpRykH2/5Qqcrk/OlbAjiQ==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.12.11", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", + "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@types/base-x": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/base-x/-/base-x-3.0.0.tgz", + "integrity": "sha512-vnqSlpsv9uFX5/z8GyKWAfWHhLGJDBkrgRRsnxlsX23DHOlNyqP/eHQiv4TwnYcZULzQIxaWA/xRWU9Dyy4qzw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/bs58": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/bs58/-/bs58-4.0.0.tgz", + "integrity": "sha512-gYX+MHD4G/R+YGYwdhG5gbJj4LsEQGr3Vg6gVDAbe7xC5Bn8dNNG2Lpo6uDX/rT5dE7VBj0rGEFuV8L0AEx4Rg==", + "dev": true, + "dependencies": { + "@types/base-x": "*" + } + }, + "node_modules/@types/bs58check": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/bs58check/-/bs58check-2.1.0.tgz", + "integrity": "sha512-OxsysnJQh82vy9DRbOcw9m2j/WiyqZLn0YBhKxdQ+aCwoHj+tWzyCgpwAkr79IfDXZKxc6h7k89T9pwS78CqTQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/create-hash": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/create-hash/-/create-hash-1.2.2.tgz", + "integrity": "sha512-Fg8/kfMJObbETFU/Tn+Y0jieYewryLrbKwLCEIwPyklZZVY2qB+64KFjhplGSw+cseZosfFXctXO+PyIYD8iZQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/mocha": { + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", + "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "16.11.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.7.tgz", + "integrity": "sha512-QB5D2sqfSjCmTuWcBWyJ+/44bcjO7VbjSbOE0ucoVbAsSNQc4Lt6QkgkVXkTDwkL4z/beecZNDvVX15D4P8Jbw==", + "dev": true + }, + "node_modules/@types/proxyquire": { + "version": "1.3.28", + "resolved": "https://registry.npmjs.org/@types/proxyquire/-/proxyquire-1.3.28.tgz", + "integrity": "sha512-SQaNzWQ2YZSr7FqAyPPiA3FYpux2Lqh3HWMZQk47x3xbMCqgC/w0dY3dw9rGqlweDDkrySQBcaScXWeR+Yb11Q==", + "dev": true + }, + "node_modules/@types/randombytes": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/randombytes/-/randombytes-2.0.0.tgz", + "integrity": "sha512-bz8PhAVlwN72vqefzxa14DKNT8jK/mV66CSjwdVQM/k3Th3EPKfUtdMniwZgMedQTFuywAsfjnZsg+pEnltaMA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/wif": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@types/wif/-/wif-2.0.2.tgz", + "integrity": "sha512-IiIuBeJzlh4LWJ7kVTrX0nwB60OG0vvGTaWC/SgSbVFw7uYUTF6gEuvDZ1goWkeirekJDD58Y8g7NljQh2fNkA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/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==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/append-transform": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", + "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", + "dev": true, + "dependencies": { + "default-require-extensions": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, + "node_modules/arg": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.1.tgz", + "integrity": "sha512-SlmP3fEA88MBv0PypnXZ8ZfJhwmDeIE3SP71j37AiXQBXYosPV0x6uISAaHYSlSVhmHOVkomen0tbGk6Anlebw==", + "dev": true + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "node_modules/base-x": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.5.tgz", + "integrity": "sha512-C3picSgzPSLE+jW3tcBzJoGwitOtazb5B+5YmAxZm2ybmTi9LNgAtDO/jjVEBZwHoXmDBZ9m/IELj3elJVRBcA==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, + "node_modules/binary-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bip174": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bip174/-/bip174-2.0.1.tgz", + "integrity": "sha512-i3X26uKJOkDTAalYAp0Er+qGMDhrbbh2o93/xiPyAN2s25KrClSpe3VXo/7mNJoqA5qfko8rLS2l3RWZgYmjKQ==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/bip32": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/bip32/-/bip32-3.0.1.tgz", + "integrity": "sha512-Uhpp9aEx3iyiO7CpbNGFxv9WcMIVdGoHG04doQ5Ln0u60uwDah7jUSc3QMV/fSZGm/Oo01/OeAmYevXV+Gz5jQ==", + "dev": true, + "dependencies": { + "@types/node": "10.12.18", + "bs58check": "^2.1.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "typeforce": "^1.11.5", + "wif": "^2.0.6" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/bip32/node_modules/@types/node": { + "version": "10.12.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz", + "integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==", + "dev": true + }, + "node_modules/bip39": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.2.tgz", + "integrity": "sha512-J4E1r2N0tUylTKt07ibXvhpT2c5pyAFgvuA5q1H9uDy6dEGpjV8jmymh3MTYJDLCNbIVClSB9FbND49I6N24MQ==", + "dev": true, + "dependencies": { + "@types/node": "11.11.6", + "create-hash": "^1.1.0", + "pbkdf2": "^3.0.9", + "randombytes": "^2.0.1" + } + }, + "node_modules/bip39/node_modules/@types/node": { + "version": "11.11.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz", + "integrity": "sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ==", + "dev": true + }, + "node_modules/bip65": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bip65/-/bip65-1.0.3.tgz", + "integrity": "sha512-RQ1nc7xtnLa5XltnCqkoR2zmhuz498RjMJwrLKQzOE049D1HUqnYfon7cVSbwS5UGm0/EQlC2CH+NY3MyITA4Q==", + "dev": true, + "engines": { + "node": ">=4.5.0" + } + }, + "node_modules/bip68": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/bip68/-/bip68-1.0.4.tgz", + "integrity": "sha512-O1htyufFTYy3EO0JkHg2CLykdXEtV2ssqw47Gq9A0WByp662xpJnMEB9m43LZjsSDjIAOozWRExlFQk2hlV1XQ==", + "dev": true, + "engines": { + "node": ">=4.5.0" + } + }, + "node_modules/bitcoin-ops": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/bitcoin-ops/-/bitcoin-ops-1.4.1.tgz", + "integrity": "sha512-pef6gxZFztEhaE9RY9HmWVmiIHqCb2OyS4HPKkpc6CIiiOa3Qmuoylxc5P2EkU3w+5eTSifI9SEZC88idAIGow==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/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==", + "dev": true + }, + "node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/bs58check": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "dependencies": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "node_modules/builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/caching-transform": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", + "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", + "dev": true, + "dependencies": { + "hasha": "^5.0.0", + "make-dir": "^3.0.0", + "package-hash": "^4.0.0", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chokidar": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.1.1" + } + }, + "node_modules/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==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/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==", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/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==", + "dev": true, + "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" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-require-extensions": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", + "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", + "dev": true, + "dependencies": { + "strip-bom": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "dependencies": { + "object-keys": "^1.0.12" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/dhttp": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dhttp/-/dhttp-3.0.3.tgz", + "integrity": "sha512-map1b8iyvxSv0uEw3DUDDK5XvH3aYA7QU9DcXy8e3FBIXSwHPHTZWVrOot7Iu9mieWq5XcrZemEJlob6IdCBmg==", + "deprecated": "Not maintained, don't use this", + "dev": true, + "dependencies": { + "statuses": "^1.5.0" + } + }, + "node_modules/diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/ecpair": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ecpair/-/ecpair-2.0.1.tgz", + "integrity": "sha512-iT3wztQMeE/nDTlfnAg8dAFUfBS7Tq2BXzq3ae6L+pWgFU0fQ3l0woTzdTBrJV3OxBjxbzjq8EQhAbEmJNWFSw==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0", + "typeforce": "^1.18.0", + "wif": "^2.0.6" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "node_modules/es-abstract": { + "version": "1.17.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", + "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", + "dev": true, + "dependencies": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, + "node_modules/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=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/fill-keys": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz", + "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=", + "dev": true, + "dependencies": { + "is-object": "~1.0.1", + "merge-descriptors": "~1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-cache-dir": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", + "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/flat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", + "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", + "deprecated": "Fixed a prototype pollution security issue in 4.1.0, please upgrade to ^4.1.1 or ^5.0.1.", + "dev": true, + "dependencies": { + "is-buffer": "~2.0.3" + }, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/fromentries": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", + "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", + "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", + "deprecated": "\"Please update to latest v2.3 or v2.2\"", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "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" + }, + "engines": { + "node": "*" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "node_modules/growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true, + "engines": { + "node": ">=4.x" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hasha": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", + "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", + "dev": true, + "dependencies": { + "is-stream": "^2.0.0", + "type-fest": "^0.8.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/hoodwink": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hoodwink/-/hoodwink-2.0.0.tgz", + "integrity": "sha512-j1jog3tDfhpWlqbVbh29qc7FG7w+NT4ed+QQFGqvww83+50AzzretB7wykZGOe28mBdvCYH3GdHaVWJQ2lJ/4w==", + "dev": true + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", + "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", + "dev": true + }, + "node_modules/is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-hook": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", + "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", + "dev": true, + "dependencies": { + "append-transform": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-processinfo": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz", + "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==", + "dev": true, + "dependencies": { + "archy": "^1.0.0", + "cross-spawn": "^7.0.0", + "istanbul-lib-coverage": "^3.0.0-alpha.1", + "make-dir": "^3.0.0", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "uuid": "^3.3.3" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", + "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", + "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "dev": true + }, + "node_modules/log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/make-error": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", + "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", + "dev": true + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "dev": true + }, + "node_modules/minimaldata": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minimaldata/-/minimaldata-1.0.2.tgz", + "integrity": "sha1-AfOywB2LJzmEP9hT1AY2xaLrdms=", + "dev": true, + "dependencies": { + "bitcoin-ops": "^1.3.0", + "pushdata-bitcoin": "^1.0.1" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "node_modules/mkdirp": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.3.tgz", + "integrity": "sha512-P+2gwrFqx8lhew375MQHHeTlY8AuOJSrGf0R5ddkEndUkmwpgUob/vQuBD1V22/Cw1/lJr4x+EjllSezBThzBg==", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mocha": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.1.tgz", + "integrity": "sha512-3qQsu3ijNS3GkWcccT5Zw0hf/rWvu1fTN9sPvEd81hlwsr30GX2GcDSSoBxo24IR8FelmrAydGC6/1J5QQP4WA==", + "dev": true, + "dependencies": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "chokidar": "3.3.0", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "3.0.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.3", + "ms": "2.1.1", + "node-environment-flags": "1.0.6", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 8.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/module-not-found-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/module-not-found-error/-/module-not-found-error-1.0.1.tgz", + "integrity": "sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA=", + "dev": true + }, + "node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "node_modules/node-environment-flags": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", + "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", + "dev": true, + "dependencies": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + } + }, + "node_modules/node-preload": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", + "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", + "dev": true, + "dependencies": { + "process-on-spawn": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-audit-whitelister": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/npm-audit-whitelister/-/npm-audit-whitelister-1.0.2.tgz", + "integrity": "sha512-MNaYMUPI4P1cGcnLNvMv0XW4F5NkVEJv2aAfLqXXKY4cgo5lXCHl1h9eUIQnWLKM3WHVOqKzUipMzfunzQZXUg==", + "dev": true, + "bin": { + "npm-audit-whitelister": "bin/npm-audit-whitelister.js" + } + }, + "node_modules/nyc": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", + "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", + "dev": true, + "dependencies": { + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^2.0.0", + "get-package-type": "^0.1.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "make-dir": "^3.0.0", + "node-preload": "^0.2.1", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "yargs": "^15.0.2" + }, + "bin": { + "nyc": "bin/nyc.js" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/nyc/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/nyc/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/nyc/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/nyc/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/nyc/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/nyc/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "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" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/nyc/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/nyc/node_modules/string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "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": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.getownpropertydescriptors": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", + "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-limit": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", + "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/package-hash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", + "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.15", + "hasha": "^5.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/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=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/pbkdf2": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", + "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", + "dev": true, + "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" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/picomatch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.1.tgz", + "integrity": "sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/prettier": { + "version": "1.16.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.16.4.tgz", + "integrity": "sha512-ZzWuos7TI5CKUeQAtFd6Zhm2s6EpAD/ZLApIhsF9pRvRtM1RFo61dM/4MSRUA0SuLugA/zgrZD8m0BaY46Og7g==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/process-on-spawn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", + "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", + "dev": true, + "dependencies": { + "fromentries": "^1.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/proxyquire": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxyquire/-/proxyquire-2.1.0.tgz", + "integrity": "sha512-kptdFArCfGRtQFv3Qwjr10lwbEV0TBJYvfqzhwucyfEXqVgmnAkyEw/S3FYzR5HI9i5QOq4rcqQjZ6AlknlCDQ==", + "dev": true, + "dependencies": { + "fill-keys": "^1.0.2", + "module-not-found-error": "^1.0.0", + "resolve": "~1.8.1" + } + }, + "node_modules/pushdata-bitcoin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pushdata-bitcoin/-/pushdata-bitcoin-1.0.1.tgz", + "integrity": "sha1-FZMdPNlnreUiBvUjqnMxrvfUOvc=", + "dev": true, + "dependencies": { + "bitcoin-ops": "^1.3.0" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "dependencies": { + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/regtest-client": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regtest-client/-/regtest-client-0.2.0.tgz", + "integrity": "sha512-eIcC8Kle/wjS47pRlw7nJpstrJDWp0bkvVPl2KJpJcK3JDNW0fMxJgE/CGpMEUSjhhFXW1rtJMN6kyKw5NIzqg==", + "dev": true, + "dependencies": { + "bs58check": "^2.1.2", + "dhttp": "^3.0.3", + "randombytes": "^2.1.0" + } + }, + "node_modules/release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", + "dev": true, + "dependencies": { + "es6-error": "^4.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", + "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.5" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "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" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/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==" + }, + "node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spawn-wrap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", + "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", + "dev": true, + "dependencies": { + "foreground-child": "^2.0.0", + "is-windows": "^1.0.2", + "make-dir": "^3.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "which": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/spawn-wrap/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/spawn-wrap/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/string.prototype.trimleft": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", + "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimright": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", + "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supports-color": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "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" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/tiny-secp256k1": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-2.2.0.tgz", + "integrity": "sha512-2hPuUGCroLrxh6xxwoe+1RgPpOOK1w2uTnhgiHBpvoutBR+krNuT4hOXQyOaaYnZgoXBB6hBYkuAJHxyeBOPzQ==", + "dependencies": { + "uint8array-tools": "0.0.6" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-node": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.3.0.tgz", + "integrity": "sha512-dyNS/RqyVTDcmNM4NIBAeDMpsAdaQ+ojdf0GOLqE6nwJOgzEkdRNzJywhDfwnuvB10oa6NLVG1rUJQCpRN7qoQ==", + "dev": true, + "dependencies": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.6", + "yn": "^3.0.0" + }, + "bin": { + "ts-node": "dist/bin.js" + }, + "engines": { + "node": ">=4.2.0" + }, + "peerDependencies": { + "typescript": ">=2.0" + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", + "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tslint": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", + "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", + "deprecated": "TSLint has been deprecated in favor of ESLint. Please see https://github.com/palantir/tslint/issues/4534 for more information.", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.3", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.13.0", + "tsutils": "^2.29.0" + }, + "bin": { + "tslint": "bin/tslint" + }, + "engines": { + "node": ">=4.8.0" + }, + "peerDependencies": { + "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev || >= 4.0.0-dev" + } + }, + "node_modules/tslint/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "peerDependencies": { + "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev" + } + }, + "node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typeforce": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz", + "integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g==" + }, + "node_modules/typescript": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", + "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/uint8array-tools": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.6.tgz", + "integrity": "sha512-aIvEHNRX1AlOYAr6qSUjQBn4mCduxx6MtC967aRDTb2UUBPj0Ix2ZFQDcmXUUO/UxRPHcw1f5a5nVbCSKDSOqA==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/varuint-bitcoin": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/varuint-bitcoin/-/varuint-bitcoin-1.1.2.tgz", + "integrity": "sha512-4EVb+w4rx+YfVM32HQX42AbbT7/1f5zwAYhIujKXKk8NQK+JfRVl3pqT3hjNn/L+RstigmGGKVwHA/P0wgITZw==", + "dependencies": { + "safe-buffer": "^5.1.1" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "node_modules/wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "dependencies": { + "string-width": "^1.0.2 || 2" + } + }, + "node_modules/wif": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz", + "integrity": "sha1-CNP1IFbGZnkplyb63g1DKudLRwQ=", + "dependencies": { + "bs58check": "<3.0.0" + } + }, + "node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "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.2" + } + }, + "node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, + "dependencies": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + } + }, "dependencies": { "@babel/code-frame": { "version": "7.15.8", @@ -606,12 +3997,6 @@ "integrity": "sha512-pef6gxZFztEhaE9RY9HmWVmiIHqCb2OyS4HPKkpc6CIiiOa3Qmuoylxc5P2EkU3w+5eTSifI9SEZC88idAIGow==", "dev": true }, - "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", - "dev": true - }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -2374,10 +5759,9 @@ } }, "tiny-secp256k1": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-2.1.2.tgz", - "integrity": "sha512-8qPw7zDK6Hco2tVGYGQeOmOPp/hZnREwy2iIkcq0ygAuqc9WHo29vKN94lNymh1QbB3nthtAMF6KTIrdbsIotA==", - "dev": true, + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-2.2.0.tgz", + "integrity": "sha512-2hPuUGCroLrxh6xxwoe+1RgPpOOK1w2uTnhgiHBpvoutBR+krNuT4hOXQyOaaYnZgoXBB6hBYkuAJHxyeBOPzQ==", "requires": { "uint8array-tools": "0.0.6" } @@ -2491,8 +5875,7 @@ "uint8array-tools": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.6.tgz", - "integrity": "sha512-aIvEHNRX1AlOYAr6qSUjQBn4mCduxx6MtC967aRDTb2UUBPj0Ix2ZFQDcmXUUO/UxRPHcw1f5a5nVbCSKDSOqA==", - "dev": true + "integrity": "sha512-aIvEHNRX1AlOYAr6qSUjQBn4mCduxx6MtC967aRDTb2UUBPj0Ix2ZFQDcmXUUO/UxRPHcw1f5a5nVbCSKDSOqA==" }, "uuid": { "version": "3.4.0", diff --git a/package.json b/package.json index c5553d57c..57c1b4d6e 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "bip174": "^2.0.1", "bs58check": "^2.1.2", "create-hash": "^1.1.0", + "tiny-secp256k1": "^2.2.0", "typeforce": "^1.11.3", "varuint-bitcoin": "^1.1.2", "wif": "^2.0.1" @@ -70,7 +71,6 @@ "bip39": "^3.0.2", "bip65": "^1.0.1", "bip68": "^1.0.3", - "bn.js": "^4.11.8", "bs58": "^4.0.0", "dhttp": "^3.0.0", "ecpair": "^2.0.1", @@ -84,7 +84,6 @@ "randombytes": "^2.1.0", "regtest-client": "0.2.0", "rimraf": "^2.6.3", - "tiny-secp256k1": "^2.1.2", "ts-node": "^8.3.0", "tslint": "^6.1.3", "typescript": "^4.4.4" diff --git a/play.mjs b/play.mjs new file mode 100644 index 000000000..75840951f --- /dev/null +++ b/play.mjs @@ -0,0 +1,105 @@ +import * as ecc from 'tiny-secp256k1'; +import { ECPairFactory } from 'ecpair' + +import { Psbt } from './src/psbt.js' +import { p2pkh, p2wpkh, p2tr } from './src/payments/index.js' +import { testnet as network } from './src/networks.js' + +console.log(''.padEnd(100, '#')) +const ECPair = ECPairFactory(ecc); +const hex = (s) => Buffer.from(s, 'hex') + +const inP2pkhKey = ECPair.fromPrivateKey(hex('82fd530c9eb33570c7e05ca5e80b740bcf1118e8f4c73d44a801fa9dd60f6449')) +const inP2wpkhKey = ECPair.fromPrivateKey(hex('35dfb4dc373860005d6f74d37064e328bc772343c354c95e31b654d0c5e22f58')) +const inP2trKey = ECPair.fromPrivateKey(hex('accaf12e04e11b08fc28f5fe75b47ea663843b698981e31f1cafa2224d6e28c0')) + +const outP2trKey = ECPair.fromPrivateKey(hex('900afde76badc8914c9940379c74857d70b4d7da590097285572df6b88ad2975')) +const outP2wpkhKey = ECPair.fromPrivateKey(hex('65ba77c6052f41325d13df8c740b5e33a26d6612e1923bf3afd67ad8081227ee')) + + + +const inP2wpkh = p2wpkh({ pubkey: inP2wpkhKey.publicKey, network }) +const inP2tr = p2tr({ internalPubkey: inP2trKey.publicKey.slice(1), network }, { eccLib: ecc }) +const outP2tr = p2tr({ internalPubkey: outP2trKey.publicKey.slice(1), network }, { eccLib: ecc }) +const outP2wpkh = p2wpkh({ pubkey: outP2wpkhKey.publicKey, network }) + +const inTweakedP2trKey = Psbt.tweakSigner(inP2trKey, { network }) + +console.log('### inP2trKey.privateKey ', inP2trKey.privateKey.toString('hex')) +console.log('### inP2trKey.publicKey ', inP2trKey.publicKey.toString('hex')) +console.log('### inP2trKey.toWIF() ', inP2trKey.toWIF()) +console.log('### inTweakedP2trKey.privateKey ', inTweakedP2trKey.privateKey.toString('hex')) +console.log('### inTweakedP2trKey.publicKey ', inTweakedP2trKey.publicKey.toString('hex')) +console.log(''.padEnd(100, '#')) + + +console.log('### inP2tr.script ', inP2tr.output.toString('hex')) +console.log('### inP2tr.address ', inP2tr.address) +console.log('### inP2tr.pubkey ', inP2tr.pubkey.toString('hex')) +console.log(''.padEnd(100, '#')) + +console.log('### p2pkh.address ', p2pkh({ pubkey: inP2pkhKey.publicKey, network }).address) +console.log('### p2wpkh.address ', inP2wpkh.address) +console.log('### inP2tr.address ', inP2tr.address) +console.log('### outP2tr.address ', outP2tr.address) +console.log(''.padEnd(100, '#')) + + +const psbt = new Psbt({ network }) +// spend p2pkh +psbt.addInput({ + hash: hex('32833f8502f64f85674d2b637ec3ff0032d5585cd305b8d68db4b83ed977f303').reverse(), + index: 0, +}).updateInput(0, { nonWitnessUtxo: hex('0200000000010147d8d83d6dd1dc8c7841f7f42d7239d2318a0a6a9bb5c936a1d54f72dcf859220000000000feffffff02122c1b00000000001976a9149e7ef1767764ff34a0595dbc4c2b70db017ed06688ac9874aeb10000000017a914b0c19f9f547df19b5fbbbfa25c850c6d1e1b550987024730440220301ddecd390bad5f957545a8eb68bf43681d11abf0a15c3a91fa47ff35178e8402206dfa3f611f2bd3da1604c9ff1f758b0cf4881b9f26ed3d5fa44531c36ba463d001210269997f09a81ec9829043a7f407d14e1fbceb799445e96613c852a8be0c1b5132749c2000') }) + +// spend p2tr +psbt.addInput({ + hash: hex('8b9fd7f222dfa16191a15485e241d2e94baa1bef3e6a989cf2d584bda800d066').reverse(), + index: 0, +}).updateInput(1, { witnessUtxo: { script: inP2tr.output, value: 67000 } }) + +// spend pwpkh +psbt.addInput({ + hash: hex('2258ccf6dcb061db928b8f74c6bb74596b43935eb04f03c5d431020ba5e4877e').reverse(), + index: 0, +}).updateInput(2, { witnessUtxo: { script: inP2wpkh.output, value: 10000 } }) + +psbt.addOutput({ + address: outP2tr.address, + value: 1780000 +}) +psbt.addOutput({ + address: outP2wpkh.address, + value: 67000 +}) + +console.log('### psbt 1', psbt.toBase64()) +// psbt.signInput(0, inP2pkhKey) +psbt.signInput(1, inTweakedP2trKey) +// psbt.signInput(2, inP2wpkhKey) +console.log('### psbt 2', psbt.toBase64()) + +const validator = ( + pubkey, + msghash, + signature, +) => { + console.log('### verifySchnorr', pubkey.toString('hex')) + // msghash[0]=0 + return ECPair.fromPublicKey(pubkey).verifySchnorr(msghash, signature) +}; + +const isValid = psbt.validateSignaturesOfInput(1, validator) +console.log('### isValid', isValid) + +// Serialize tx +psbt.finalizeAllInputs() +const tx = psbt.extractTransaction() +const rawTx = tx.toBuffer() + +console.log('### rawTx', rawTx.toString('hex')) +/// 1b9e7e80288a059adb9da6fd7c30e7383a5a924f78d3a0b6b047e07345990f48 +/// b2138ee2639c569fe7f2666635399caaa7a435b3763c079f069e194116840892 +/// e7a79cc65d17bebfc4cf03d26d6d879b754afe9cdc56ce98d2f1fac29cc7f1e2 +/// 8b9fd7f222dfa16191a15485e241d2e94baa1bef3e6a989cf2d584bda800d066 +/// 735321667cf43ded23dc935f355c4b1b1e77d9a47d11c77d384af5094e1ad171 -> 3 inputs, 2 outputs \ No newline at end of file diff --git a/play2.mjs b/play2.mjs new file mode 100644 index 000000000..10a432d59 --- /dev/null +++ b/play2.mjs @@ -0,0 +1,110 @@ +import { BIP32Factory } from 'bip32'; +import { ECPairFactory } from 'ecpair' +import * as ecc from 'tiny-secp256k1'; + +import * as bitcoin from './src/index.js'; +import { testnet as network } from './src/networks.js' + +const ECPair = ECPairFactory(ecc); +const bip32 = BIP32Factory(ecc); +const hex = (s) => Buffer.from(s, 'hex') + +// Order of the curve (N) - 1 +const N_LESS_1 = Buffer.from( + 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140', + 'hex', +); +// 1 represented as 32 bytes BE +const ONE = Buffer.from( + '0000000000000000000000000000000000000000000000000000000000000001', + 'hex', +); + + +const myKey = ECPair.fromPrivateKey(hex('accaf12e04e11b08fc28f5fe75b47ea663843b698981e31f1cafa2224d6e28c0')) +const output = createKeySpendOutput(myKey.publicKey); +const address = bitcoin.address.fromOutputScript(output, network); +const amount = 100000; +const sendAmount = 75000 +console.log('### output', output.toString('hex')) +console.log('### address', address) + +const unspent = { txId: '8162b0310f37182049429e147b0ba7ac17eb4dd5c6d3016927e4c993b63edc2b', vout: 0} + +const tx = createSigned( + myKey, + unspent.txId, + unspent.vout, + sendAmount, + [output], // public key + [amount], +); + +const txHex = tx.toHex(); +console.log('### txHex', txHex) +// txId: a618fdb361a6cfbc345d2b030ab7533dc88b3c097af58df6979b4d9aa4472379 + + +function createKeySpendOutput(publicKey) { + // x-only pubkey (remove 1 byte y parity) + const myXOnlyPubkey = publicKey.slice(1, 33); + const commitHash = bitcoin.crypto.taggedHash('TapTweak', myXOnlyPubkey); + console.log('### commitHash ', commitHash.toString('hex')) + const tweakResult = ecc.xOnlyPointAddTweak(myXOnlyPubkey, commitHash); + console.log('### tweakResult xOnlyPubkey', Buffer.from(tweakResult.xOnlyPubkey).toString('hex')) + if (tweakResult === null) throw new Error('Invalid Tweak'); + const { xOnlyPubkey: tweaked } = tweakResult; + // scriptPubkey + return Buffer.concat([ + // witness v1, PUSH_DATA 32 bytes + Buffer.from([0x51, 0x20]), + // x-only tweaked pubkey + tweaked, + ]); +} + +function signTweaked(messageHash, key) { + const privateKey = + key.publicKey[0] === 2 + ? key.privateKey + : ecc.privateAdd(ecc.privateSub(N_LESS_1, key.privateKey), ONE); + const tweakHash = bitcoin.crypto.taggedHash( + 'TapTweak', + key.publicKey.slice(1, 33), + ); + const newPrivateKey = ecc.privateAdd(privateKey, tweakHash); + if (newPrivateKey === null) throw new Error('Invalid Tweak'); + return ecc.signSchnorr(messageHash, newPrivateKey, Buffer.alloc(32)); +} + +// Function for creating signed tx +function createSigned( + key, + txid, + vout, + amountToSend, + scriptPubkeys, + values, + ) { + console.log('### scriptPubkeys', scriptPubkeys.map(s => s.toString('hex'))) + console.log('### values', values) + const tx = new bitcoin.Transaction(); + tx.version = 2; + // Add input + tx.addInput(Buffer.from(txid, 'hex').reverse(), vout); + // Add output + tx.addOutput(scriptPubkeys[0], amountToSend); + const sighash = tx.hashForWitnessV1( + 0, // which input + scriptPubkeys, // All previous outputs of all inputs + values, // All previous values of all inputs + bitcoin.Transaction.SIGHASH_DEFAULT, // sighash flag, DEFAULT is schnorr-only (DEFAULT == ALL) + ); + console.log('### sighash', sighash.toString('hex')) + console.log('### unsignedTx', tx.toHex()) + const signature = Buffer.from(signTweaked(sighash, key)); + // witness stack for keypath spend is just the signature. + // If sighash is not SIGHASH_DEFAULT (ALL) then you must add 1 byte with sighash value + tx.ins[0].witness = [signature]; + return tx; + } \ No newline at end of file diff --git a/play3.mjs b/play3.mjs new file mode 100644 index 000000000..fdff92091 --- /dev/null +++ b/play3.mjs @@ -0,0 +1,11 @@ +import * as ecc from 'tiny-secp256k1'; +import { ECPairFactory } from 'ecpair' + +import { p2tr } from './src/payments/index.js' +import { testnet as network } from './src/networks.js' + +console.log(''.padEnd(100, '#')) + +const inP2tr = p2tr({ output: Buffer.from('51209421e734b0f9d2c467ea7dd197c61acb4467cdcbc9f4cb0c571f8b63a5c40cae', 'hex'), network }, { eccLib: ecc }) + +console.log('### inP2tr',inP2tr.address) \ No newline at end of file diff --git a/play4.mjs b/play4.mjs new file mode 100644 index 000000000..1b61431c6 --- /dev/null +++ b/play4.mjs @@ -0,0 +1,11 @@ +import * as ecc from 'tiny-secp256k1'; +import { ECPairFactory } from 'ecpair' +import NETWORKS from './src/networks.js' + +const ECPair = ECPairFactory(ecc); +const hex = (s) => Buffer.from(s, 'hex') + +const key = ECPair.fromPrivateKey(hex('82fd530c9eb33570c7e05ca5e80b740bcf1118e8f4c73d44a801fa9dd60f6449'), { network: NETWORKS.testnet }) +console.log('### key.toWIF()', key.toWIF()) + +ECPair.fromWIF('cRyKzLXVgTReWe7wgfEiXktTa9tf4e5DK1STha274d7BBbnucTaR', NETWORKS.testnet); \ No newline at end of file diff --git a/play5.mjs b/play5.mjs new file mode 100644 index 000000000..bae7a7d3e --- /dev/null +++ b/play5.mjs @@ -0,0 +1,112 @@ +import * as ecc from 'tiny-secp256k1'; +import { ECPairFactory } from 'ecpair' + +import { Psbt } from './src/psbt.js' +import { p2pkh, p2wpkh, p2tr } from './src/payments/index.js' +import { testnet as network } from './src/networks.js' +console.log(''.padEnd(100, '#')) +const ECPair = ECPairFactory(ecc); +const hex = (s) => Buffer.from(s, 'hex') + +const inP2pkhKey = ECPair.fromPrivateKey(hex('82fd530c9eb33570c7e05ca5e80b740bcf1118e8f4c73d44a801fa9dd60f6449'), { network }) +const inP2wpkhKey = ECPair.fromPrivateKey(hex('35dfb4dc373860005d6f74d37064e328bc772343c354c95e31b654d0c5e22f58'), { network }) +const inP2trKey = ECPair.fromPrivateKey(hex('accaf12e04e11b08fc28f5fe75b47ea663843b698981e31f1cafa2224d6e28c0'), { network }) + +const outP2trKey = ECPair.fromPrivateKey(hex('900afde76badc8914c9940379c74857d70b4d7da590097285572df6b88ad2975'), { network }) +const outP2wpkhKey = ECPair.fromPrivateKey(hex('65ba77c6052f41325d13df8c740b5e33a26d6612e1923bf3afd67ad8081227ee'), { network }) + +console.log('### inP2pkhKey.toWIF()', inP2pkhKey.toWIF()) +console.log('### inP2trKey.toWIF()', inP2trKey.toWIF()) +console.log('### inP2wpkhKey.toWIF()', inP2wpkhKey.toWIF()) +console.log('### outP2trKey.toWIF()', outP2trKey.toWIF()) +// 02982a2876765bb37b53a12418b9e72b8afa8d54e344a1bd585299a211fbe625f3 + + + +const inP2wpkh = p2wpkh({ pubkey: inP2wpkhKey.publicKey, network }) +const inP2tr = p2tr({ internalPubkey: inP2trKey.publicKey.slice(1), network }, { eccLib: ecc }) +const outP2tr = p2tr({ internalPubkey: outP2trKey.publicKey.slice(1), network }, { eccLib: ecc }) +const outP2wpkh = p2wpkh({ pubkey: outP2wpkhKey.publicKey, network }) + + +// const inTweakedP2trKey = inP2trKeyPsbt.prepareTaprootSigner(outP2trKey, { network }) +// console.log('### inTweakedP2trKey.toWIF()', inTweakedP2trKey.toWIF()) + + +console.log('### inP2trKey.privateKey ', inP2trKey.privateKey.toString('hex')) +console.log('### inP2trKey.publicKey ', inP2trKey.publicKey.toString('hex')) +console.log('### outP2trKey.publicKey ', outP2trKey.publicKey.toString('hex')) +console.log('### inP2pkhKey.publicKey ', inP2pkhKey.publicKey.toString('hex')) +console.log('### inP2wpkhKey.publicKey ', inP2wpkhKey.publicKey.toString('hex')) +// console.log('### inTweakedP2trKey.privateKey ', inTweakedP2trKey.privateKey.toString('hex')) +// console.log('### inTweakedP2trKey.publicKey ', inTweakedP2trKey.publicKey.toString('hex')) +console.log(''.padEnd(100, '#')) + + +console.log('### inP2tr.script ', inP2tr.output.toString('hex')) +console.log('### inP2tr.address ', inP2tr.address) +console.log('### inP2tr.pubkey ', inP2tr.pubkey.toString('hex')) +console.log(''.padEnd(100, '#')) + +console.log('### p2pkh.address ', p2pkh({ pubkey: inP2pkhKey.publicKey, network }).address) +console.log('### p2wpkh.address ', inP2wpkh.address) +console.log('### inP2tr.address ', inP2tr.address) +console.log('### outP2tr.address ', outP2tr.address) + +console.log(''.padEnd(100, '#')) + + +const psbt = new Psbt({ network }) +// spend p2pkh +psbt.addInput({ + hash: hex('32833f8502f64f85674d2b637ec3ff0032d5585cd305b8d68db4b83ed977f303').reverse(), + index: 0, +}).updateInput(0, { nonWitnessUtxo: hex('0200000000010147d8d83d6dd1dc8c7841f7f42d7239d2318a0a6a9bb5c936a1d54f72dcf859220000000000feffffff02122c1b00000000001976a9149e7ef1767764ff34a0595dbc4c2b70db017ed06688ac9874aeb10000000017a914b0c19f9f547df19b5fbbbfa25c850c6d1e1b550987024730440220301ddecd390bad5f957545a8eb68bf43681d11abf0a15c3a91fa47ff35178e8402206dfa3f611f2bd3da1604c9ff1f758b0cf4881b9f26ed3d5fa44531c36ba463d001210269997f09a81ec9829043a7f407d14e1fbceb799445e96613c852a8be0c1b5132749c2000') }) + +// spend p2tr +psbt.addInput({ + hash: hex('8b9fd7f222dfa16191a15485e241d2e94baa1bef3e6a989cf2d584bda800d066').reverse(), + index: 0, +}).updateInput(1, { witnessUtxo: { script: outP2tr.output, value: 67000 } }) + +// spend pwpkh +psbt.addInput({ + hash: hex('2258ccf6dcb061db928b8f74c6bb74596b43935eb04f03c5d431020ba5e4877e').reverse(), + index: 0, +}).updateInput(2, { witnessUtxo: { script: inP2wpkh.output, value: 10000 } }) + +psbt.addOutput({ + address: inP2tr.address, + value: 1780000 +}) +psbt.addOutput({ + address: outP2wpkh.address, + value: 67000 +}) + +console.log('### psbt 1', psbt.toBase64()) + +psbt.signInput(0, inP2pkhKey) +psbt.signInput(1, outP2trKey) +psbt.signInput(2, inP2wpkhKey) + +console.log('### psbt 2', psbt.toBase64()) + +// const validator = ( +// pubkey, +// msghash, +// signature, +// ) => ECPair.fromPublicKey(pubkey).verify(msghash, signature); +// psbt.validateSignaturesOfAllInputs(validator) + +// Serialize tx +psbt.finalizeAllInputs() +const tx = psbt.extractTransaction() +const rawTx = tx.toBuffer() + +console.log('### rawTx', rawTx.toString('hex')) +/// 1b9e7e80288a059adb9da6fd7c30e7383a5a924f78d3a0b6b047e07345990f48 +/// b2138ee2639c569fe7f2666635399caaa7a435b3763c079f069e194116840892 +/// e7a79cc65d17bebfc4cf03d26d6d879b754afe9cdc56ce98d2f1fac29cc7f1e2 +/// 8b9fd7f222dfa16191a15485e241d2e94baa1bef3e6a989cf2d584bda800d066 +/// 735321667cf43ded23dc935f355c4b1b1e77d9a47d11c77d384af5094e1ad171 -> 3 inputs, 2 outputs \ No newline at end of file diff --git a/published tx b/published tx new file mode 100644 index 000000000..958922a53 --- /dev/null +++ b/published tx @@ -0,0 +1,4 @@ +published tx +### hash 990576cefd2f30f46709a14cf0eff8fe94c9d004229b9e0ff7fca7a526e9cfea +### rawTx 0200000000010303f377d93eb8b48dd6b805d35c58d53200ffc37e632b4d67854ff602853f8332000000006a473044022069582941c9bb47bde5e4840813884f1049cccc26cf0c1ae1f82ce48d440eacfc02205a56c1df124eb4922cb338f5a99ff0840e632bdc274f3799cc3955b3f8afab670121022e68bc11f5c4ba06c4faad161e3cc141299ccf92b7549b3f34703bb90134a390ffffffff66d000a8bd84d5f29c986a3eef1baa4be9d241e28554a19161a1df22f2d79f8b0000000000ffffffff7e87e4a50b0231d4c5034fb05e93436b5974bbc6748f8b92db61b0dcf6cc58220000000000ffffffff0220291b000000000022512046f6497cb2f19d50c3e9e982a950dcc86214b01fcce437a42061c7bdb1230d33b805010000000000160014c98a3134bf8f33e599a67c40000d774205c1b41400014003694b9b7e9145af36d4faf2fca82cd913f14efbdba7cf295fa488106781d3cb6a8f52d2ef6f21f9f46029773d1289464697c2ba0abbedf5821f23fe45c5b38b02483045022100a02224b6084be798ae3009a4cf0609cdbfa1faa98d7b0657c40c7fd3a39bc484022042c2b01cffc1ddb03e59c96f6ece96ec4c9133e70b21c0d82f92c47897fc5bcf012103a54ea4405b3c933fc58b2a3b67aeb6d605a6079cf6f731820c93ca89252baeb400000000 + diff --git a/r1.txt b/r1.txt new file mode 100644 index 000000000..36beb16c4 --- /dev/null +++ b/r1.txt @@ -0,0 +1,5 @@ +### rawTx 0200000000010303f377d93eb8b48dd6b805d35c58d53200ffc37e632b4d67854ff602853f8332000000006a473044022069582941c9bb47bde5e4840813884f1049cccc26cf0c1ae1f82ce48d440eacfc02205a56c1df124eb4922cb338f5a99ff0840e632bdc274f3799cc3955b3f8afab670121022e68bc11f5c4ba06c4faad161e3cc141299ccf92b7549b3f34703bb90134a390ffffffff66d000a8bd84d5f29c986a3eef1baa4be9d241e28554a19161a1df22f2d79f8b0000000000ffffffff7e87e4a50b0231d4c5034fb05e93436b5974bbc6748f8b92db61b0dcf6cc58220000000000ffffffff0220291b000000000022512046f6497cb2f19d50c3e9e982a950dcc86214b01fcce437a42061c7bdb1230d33b805010000000000160014c98a3134bf8f33e599a67c40000d774205c1b41400014003694b9b7e9145af36d4faf2fca82cd913f14efbdba7cf295fa488106781d3cb6a8f52d2ef6f21f9f46029773d1289464697c2ba0abbedf5821f23fe45c5b38b02483045022100a02224b6084be798ae3009a4cf0609cdbfa1faa98d7b0657c40c7fd3a39bc484022042c2b01cffc1ddb03e59c96f6ece96ec4c9133e70b21c0d82f92c47897fc5bcf012103a54ea4405b3c933fc58b2a3b67aeb6d605a6079cf6f731820c93ca89252baeb400000000 + +### rawTx 0200000000010303f377d93eb8b48dd6b805d35c58d53200ffc37e632b4d67854ff602853f8332000000006a473044022069582941c9bb47bde5e4840813884f1049cccc26cf0c1ae1f82ce48d440eacfc02205a56c1df124eb4922cb338f5a99ff0840e632bdc274f3799cc3955b3f8afab670121022e68bc11f5c4ba06c4faad161e3cc141299ccf92b7549b3f34703bb90134a390ffffffff66d000a8bd84d5f29c986a3eef1baa4be9d241e28554a19161a1df22f2d79f8b0000000000ffffffff7e87e4a50b0231d4c5034fb05e93436b5974bbc6748f8b92db61b0dcf6cc58220000000000ffffffff0220291b000000000022512046f6497cb2f19d50c3e9e982a950dcc86214b01fcce437a42061c7bdb1230d33b805010000000000160014c98a3134bf8f33e599a67c40000d774205c1b41400014003694b9b7e9145af36d4faf2fca82cd913f14efbdba7cf295fa488106781d3cb6a8f52d2ef6f21f9f46029773d1289464697c2ba0abbedf5821f23fe45c5b38b02483045022100a02224b6084be798ae3009a4cf0609cdbfa1faa98d7b0657c40c7fd3a39bc484022042c2b01cffc1ddb03e59c96f6ece96ec4c9133e70b21c0d82f92c47897fc5bcf012103a54ea4405b3c933fc58b2a3b67aeb6d605a6079cf6f731820c93ca89252baeb400000000 + +mempool: 0200000000010303f377d93eb8b48dd6b805d35c58d53200ffc37e632b4d67854ff602853f8332000000006a473044022069582941c9bb47bde5e4840813884f1049cccc26cf0c1ae1f82ce48d440eacfc02205a56c1df124eb4922cb338f5a99ff0840e632bdc274f3799cc3955b3f8afab670121022e68bc11f5c4ba06c4faad161e3cc141299ccf92b7549b3f34703bb90134a390ffffffff66d000a8bd84d5f29c986a3eef1baa4be9d241e28554a19161a1df22f2d79f8b0000000000ffffffff7e87e4a50b0231d4c5034fb05e93436b5974bbc6748f8b92db61b0dcf6cc58220000000000ffffffff0220291b000000000022512046f6497cb2f19d50c3e9e982a950dcc86214b01fcce437a42061c7bdb1230d33b805010000000000160014c98a3134bf8f33e599a67c40000d774205c1b41400014003694b9b7e9145af36d4faf2fca82cd913f14efbdba7cf295fa488106781d3cb6a8f52d2ef6f21f9f46029773d1289464697c2ba0abbedf5821f23fe45c5b38b02483045022100a02224b6084be798ae3009a4cf0609cdbfa1faa98d7b0657c40c7fd3a39bc484022042c2b01cffc1ddb03e59c96f6ece96ec4c9133e70b21c0d82f92c47897fc5bcf012103a54ea4405b3c933fc58b2a3b67aeb6d605a6079cf6f731820c93ca89252baeb400000000 \ No newline at end of file diff --git a/src/payments/index.d.ts b/src/payments/index.d.ts index 1edf07167..6b186c4d1 100644 --- a/src/payments/index.d.ts +++ b/src/payments/index.d.ts @@ -1,5 +1,6 @@ /// import { Network } from '../networks'; +import { TaprootLeaf, TinySecp256k1Interface } from '../types'; import { p2data as embed } from './embed'; import { p2ms } from './p2ms'; import { p2pk } from './p2pk'; @@ -7,6 +8,7 @@ import { p2pkh } from './p2pkh'; import { p2sh } from './p2sh'; import { p2wpkh } from './p2wpkh'; import { p2wsh } from './p2wsh'; +import { p2tr } from './p2tr'; export interface Payment { name?: string; network?: Network; @@ -17,11 +19,14 @@ export interface Payment { pubkeys?: Buffer[]; input?: Buffer; signatures?: Buffer[]; + internalPubkey?: Buffer; pubkey?: Buffer; signature?: Buffer; address?: string; hash?: Buffer; redeem?: Payment; + scriptsTree?: any; + scriptLeaf?: TaprootLeaf; witness?: Buffer[]; } export declare type PaymentCreator = (a: Payment, opts?: PaymentOpts) => Payment; @@ -29,8 +34,9 @@ export declare type PaymentFunction = () => Payment; export interface PaymentOpts { validate?: boolean; allowIncomplete?: boolean; + eccLib?: TinySecp256k1Interface; } export declare type StackElement = Buffer | number; export declare type Stack = StackElement[]; export declare type StackFunction = () => Stack; -export { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh }; +export { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh, p2tr }; diff --git a/src/payments/index.js b/src/payments/index.js index c23c529c6..9ce55f859 100644 --- a/src/payments/index.js +++ b/src/payments/index.js @@ -1,6 +1,6 @@ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); -exports.p2wsh = exports.p2wpkh = exports.p2sh = exports.p2pkh = exports.p2pk = exports.p2ms = exports.embed = void 0; +exports.p2tr = exports.p2wsh = exports.p2wpkh = exports.p2sh = exports.p2pkh = exports.p2pk = exports.p2ms = exports.embed = void 0; const embed_1 = require('./embed'); Object.defineProperty(exports, 'embed', { enumerable: true, @@ -50,5 +50,12 @@ Object.defineProperty(exports, 'p2wsh', { return p2wsh_1.p2wsh; }, }); +const p2tr_1 = require('./p2tr'); +Object.defineProperty(exports, 'p2tr', { + enumerable: true, + get: function() { + return p2tr_1.p2tr; + }, +}); // TODO // witness commitment diff --git a/src/payments/p2tr.d.ts b/src/payments/p2tr.d.ts new file mode 100644 index 000000000..350ed0ffc --- /dev/null +++ b/src/payments/p2tr.d.ts @@ -0,0 +1,2 @@ +import { Payment, PaymentOpts } from './index'; +export declare function p2tr(a: Payment, opts?: PaymentOpts): Payment; diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js new file mode 100644 index 000000000..d03d7980d --- /dev/null +++ b/src/payments/p2tr.js @@ -0,0 +1,253 @@ +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +exports.p2tr = void 0; +const buffer_1 = require('buffer'); +const networks_1 = require('../networks'); +const bscript = require('../script'); +const types_1 = require('../types'); +const taprootutils_1 = require('./taprootutils'); +const lazy = require('./lazy'); +const bech32_1 = require('bech32'); +const testecc_1 = require('./testecc'); +const OPS = bscript.OPS; +const TAPROOT_VERSION = 0x01; +const ANNEX_PREFIX = 0x50; +function p2tr(a, opts) { + if ( + !a.address && + !a.output && + !a.pubkey && + !a.output && + !a.internalPubkey && + !(a.witness && a.witness.length > 1) + ) + throw new TypeError('Not enough data'); + opts = Object.assign({ validate: true }, opts || {}); + const _ecc = lazy.value(() => { + if (!opts.eccLib) throw new Error('ECC Library is missing for p2tr.'); + (0, testecc_1.testEcc)(opts.eccLib); + return opts.eccLib; + }); + (0, types_1.typeforce)( + { + address: types_1.typeforce.maybe(types_1.typeforce.String), + input: types_1.typeforce.maybe(types_1.typeforce.BufferN(0)), + network: types_1.typeforce.maybe(types_1.typeforce.Object), + output: types_1.typeforce.maybe(types_1.typeforce.BufferN(34)), + internalPubkey: types_1.typeforce.maybe(types_1.typeforce.BufferN(32)), + hash: types_1.typeforce.maybe(types_1.typeforce.BufferN(32)), + pubkey: types_1.typeforce.maybe(types_1.typeforce.BufferN(32)), + signature: types_1.typeforce.maybe(types_1.typeforce.BufferN(64)), + witness: types_1.typeforce.maybe( + types_1.typeforce.arrayOf(types_1.typeforce.Buffer), + ), + // scriptsTree: typef.maybe(typef.TaprootNode), // use merkel.isMast ? + scriptLeaf: types_1.typeforce.maybe({ + version: types_1.typeforce.maybe(types_1.typeforce.Number), + output: types_1.typeforce.maybe(types_1.typeforce.Buffer), + }), + }, + a, + ); + const _address = lazy.value(() => { + const result = bech32_1.bech32m.decode(a.address); + const version = result.words.shift(); + const data = bech32_1.bech32m.fromWords(result.words); + return { + version, + prefix: result.prefix, + data: buffer_1.Buffer.from(data), + }; + }); + const _witness = lazy.value(() => { + if (!a.witness || !a.witness.length) return; + if ( + a.witness.length >= 2 && + a.witness[a.witness.length - 1][0] === ANNEX_PREFIX + ) { + // remove annex, ignored by taproot + return a.witness.slice(0, -1); + } + return a.witness.slice(); + }); + const network = a.network || networks_1.bitcoin; + const o = { name: 'p2tr', network }; + lazy.prop(o, 'address', () => { + if (!o.pubkey) return; + const words = bech32_1.bech32m.toWords(o.pubkey); + words.unshift(TAPROOT_VERSION); + return bech32_1.bech32m.encode(network.bech32, words); + }); + lazy.prop(o, 'hash', () => { + if (a.hash) return a.hash; + if (a.scriptsTree) + return (0, taprootutils_1.toHashTree)(a.scriptsTree).hash; + const w = _witness(); + if (w && w.length > 1) { + const controlBlock = w[w.length - 1]; + const leafVersion = controlBlock[0] & 0b11111110; + const script = w[w.length - 2]; + const leafHash = (0, taprootutils_1.tapLeafHash)(script, leafVersion); + return (0, taprootutils_1.rootHashFromPath)(controlBlock, leafHash); + } + return null; + }); + lazy.prop(o, 'output', () => { + if (!o.pubkey) return; + return bscript.compile([OPS.OP_1, o.pubkey]); + }); + lazy.prop(o, 'scriptLeaf', () => { + if (a.scriptLeaf) return a.scriptLeaf; + }); + lazy.prop(o, 'pubkey', () => { + if (a.pubkey) return a.pubkey; + if (a.output) return a.output.slice(2); + if (a.address) return _address().data; + if (o.internalPubkey) { + const tweakedKey = tweakKey(o.internalPubkey, o.hash, _ecc()); + if (tweakedKey) return tweakedKey.x; + } + }); + lazy.prop(o, 'internalPubkey', () => { + if (a.internalPubkey) return a.internalPubkey; + const witness = _witness(); + if (witness && witness.length > 1) + return witness[witness.length - 1].slice(1, 33); + }); + lazy.prop(o, 'signature', () => { + if (!a.witness || a.witness.length !== 1) return; + return a.witness[0]; + }); + lazy.prop(o, 'input', () => { + // todo + }); + lazy.prop(o, 'witness', () => { + if (a.witness) return a.witness; + if (a.scriptsTree && a.scriptLeaf && a.internalPubkey) { + // todo: optimize/cache + const hashTree = (0, taprootutils_1.toHashTree)(a.scriptsTree); + const leafHash = (0, taprootutils_1.tapLeafHash)( + a.scriptLeaf.output, + a.scriptLeaf.version, + ); + const path = (0, taprootutils_1.findScriptPath)(hashTree, leafHash); + const outputKey = tweakKey(a.internalPubkey, hashTree.hash, _ecc()); + if (!outputKey) return; + const version = a.scriptLeaf.version || 0xc0; + const controlBock = buffer_1.Buffer.concat( + [ + buffer_1.Buffer.from([version | outputKey.parity]), + a.internalPubkey, + ].concat(path.reverse()), + ); + return [a.scriptLeaf.output, controlBock]; + } + if (a.signature) return [a.signature]; + }); + // extended validation + if (opts.validate) { + let pubkey = buffer_1.Buffer.from([]); + if (a.address) { + if (network && network.bech32 !== _address().prefix) + throw new TypeError('Invalid prefix or Network mismatch'); + if (_address().version !== TAPROOT_VERSION) + throw new TypeError('Invalid address version'); + if (_address().data.length !== 32) + throw new TypeError('Invalid address data'); + pubkey = _address().data; + } + if (a.pubkey) { + if (pubkey.length > 0 && !pubkey.equals(a.pubkey)) + throw new TypeError('Pubkey mismatch'); + else pubkey = a.pubkey; + } + if (a.output) { + if ( + a.output.length !== 34 || + a.output[0] !== OPS.OP_1 || + a.output[1] !== 0x20 + ) + throw new TypeError('Output is invalid'); + if (pubkey.length > 0 && !pubkey.equals(a.output.slice(2))) + throw new TypeError('Pubkey mismatch'); + else pubkey = a.output.slice(2); + } + if (a.internalPubkey) { + const tweakedKey = tweakKey(a.internalPubkey, o.hash, _ecc()); + if (pubkey.length > 0 && !pubkey.equals(tweakedKey.x)) + throw new TypeError('Pubkey mismatch'); + else pubkey = tweakedKey.x; + } + if (pubkey && pubkey.length) { + if (!_ecc().isXOnlyPoint(pubkey)) + throw new TypeError('Invalid pubkey for p2tr'); + } + if (a.hash && a.scriptsTree) { + const hash = (0, taprootutils_1.toHashTree)(a.scriptsTree).hash; + if (!a.hash.equals(hash)) throw new TypeError('Hash mismatch'); + } + const witness = _witness(); + if (witness && witness.length) { + if (witness.length === 1) { + // key spending + if (a.signature && !a.signature.equals(witness[0])) + throw new TypeError('Signature mismatch'); + // todo: recheck + // if (!bscript.isSchnorSignature(a.pubkey, a.witness[0])) + // throw new TypeError('Witness has invalid signature'); + } else { + // script path spending + const controlBlock = witness[witness.length - 1]; + if (controlBlock.length < 33) + throw new TypeError( + `The control-block length is too small. Got ${ + controlBlock.length + }, expected min 33.`, + ); + if ((controlBlock.length - 33) % 32 !== 0) + throw new TypeError( + `The control-block length of ${controlBlock.length} is incorrect!`, + ); + const m = (controlBlock.length - 33) / 32; + if (m > 128) + throw new TypeError( + `The script path is too long. Got ${m}, expected max 128.`, + ); + const internalPubkey = controlBlock.slice(1, 33); + if (a.internalPubkey && !a.internalPubkey.equals(internalPubkey)) + throw new TypeError('Internal pubkey mismatch'); + if (!_ecc().isXOnlyPoint(internalPubkey)) + throw new TypeError('Invalid internalPubkey for p2tr witness'); + const leafVersion = controlBlock[0] & 0b11111110; + const script = witness[witness.length - 2]; + const leafHash = (0, taprootutils_1.tapLeafHash)(script, leafVersion); + const hash = (0, taprootutils_1.rootHashFromPath)( + controlBlock, + leafHash, + ); + const outputKey = tweakKey(internalPubkey, hash, _ecc()); + if (!outputKey) + // todo: needs test data + throw new TypeError('Invalid outputKey for p2tr witness'); + if (pubkey.length && !pubkey.equals(outputKey.x)) + throw new TypeError('Pubkey mismatch for p2tr witness'); + if (outputKey.parity !== (controlBlock[0] & 1)) + throw new Error('Incorrect parity'); + } + } + } + return Object.assign(o, a); +} +exports.p2tr = p2tr; +function tweakKey(pubKey, h, eccLib) { + if (!buffer_1.Buffer.isBuffer(pubKey)) return null; + if (pubKey.length !== 32) return null; + if (h && h.length !== 32) return null; + const tweakHash = (0, taprootutils_1.tapTweakHash)(pubKey, h); + const res = eccLib.xOnlyPointAddTweak(pubKey, tweakHash); + if (!res || res.xOnlyPubkey === null) return null; + return { + parity: res.parity, + x: buffer_1.Buffer.from(res.xOnlyPubkey), + }; +} diff --git a/src/payments/taprootutils.d.ts b/src/payments/taprootutils.d.ts new file mode 100644 index 000000000..f68a37495 --- /dev/null +++ b/src/payments/taprootutils.d.ts @@ -0,0 +1,26 @@ +/// +import { TaprootLeaf } from '../types'; +export declare function rootHashFromPath(controlBlock: Buffer, tapLeafMsg: Buffer): Buffer; +export interface HashTree { + hash: Buffer; + left?: HashTree; + right?: HashTree; +} +/** + * Build the hash tree from the scripts binary tree. + * The binary tree can be balanced or not. + * @param scriptsTree - is a list representing a binary tree where an element can be: + * - a taproot leaf [(output, version)], or + * - a pair of two taproot leafs [(output, version), (output, version)], or + * - one taproot leaf and a list of elements + */ +export declare function toHashTree(scriptsTree: TaprootLeaf[]): HashTree; +/** + * Given a MAST tree, it finds the path of a particular hash. + * @param node - the root of the tree + * @param hash - the hash to search for + * @returns - and array of hashes representing the path, or an empty array if no pat is found + */ +export declare function findScriptPath(node: HashTree, hash: Buffer): Buffer[]; +export declare function tapLeafHash(script: Buffer, version?: number): Buffer; +export declare function tapTweakHash(pubKey: Buffer, h: Buffer | undefined): Buffer; diff --git a/src/payments/taprootutils.js b/src/payments/taprootutils.js new file mode 100644 index 000000000..2da6a4b7d --- /dev/null +++ b/src/payments/taprootutils.js @@ -0,0 +1,108 @@ +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +exports.tapTweakHash = exports.tapLeafHash = exports.findScriptPath = exports.toHashTree = exports.rootHashFromPath = void 0; +const buffer_1 = require('buffer'); +const bcrypto = require('../crypto'); +const bufferutils_1 = require('../bufferutils'); +const LEAF_VERSION_TAPSCRIPT = 0xc0; +const TAP_LEAF_TAG = 'TapLeaf'; +const TAP_BRANCH_TAG = 'TapBranch'; +const TAP_TWEAK_TAG = 'TapTweak'; +function rootHashFromPath(controlBlock, tapLeafMsg) { + const k = [tapLeafMsg]; + const e = []; + const m = (controlBlock.length - 33) / 32; + for (let j = 0; j < m; j++) { + e[j] = controlBlock.slice(33 + 32 * j, 65 + 32 * j); + if (k[j].compare(e[j]) < 0) { + k[j + 1] = tapBranchHash(k[j], e[j]); + } else { + k[j + 1] = tapBranchHash(e[j], k[j]); + } + } + return k[m]; +} +exports.rootHashFromPath = rootHashFromPath; +/** + * Build the hash tree from the scripts binary tree. + * The binary tree can be balanced or not. + * @param scriptsTree - is a list representing a binary tree where an element can be: + * - a taproot leaf [(output, version)], or + * - a pair of two taproot leafs [(output, version), (output, version)], or + * - one taproot leaf and a list of elements + */ +function toHashTree(scriptsTree) { + if (scriptsTree.length === 1) { + const script = scriptsTree[0]; + if (Array.isArray(script)) { + return toHashTree(script); + } + script.version = script.version || LEAF_VERSION_TAPSCRIPT; + if ((script.version & 1) !== 0) + throw new TypeError('Invalid script version'); + return { + hash: tapLeafHash(script.output, script.version), + }; + } + const left = toHashTree([scriptsTree[0]]); + const right = toHashTree([scriptsTree[1]]); + let leftHash = left.hash; + let rightHash = right.hash; + if (leftHash.compare(rightHash) === 1) + [leftHash, rightHash] = [rightHash, leftHash]; + return { + hash: tapBranchHash(leftHash, rightHash), + left, + right, + }; +} +exports.toHashTree = toHashTree; +/** + * Given a MAST tree, it finds the path of a particular hash. + * @param node - the root of the tree + * @param hash - the hash to search for + * @returns - and array of hashes representing the path, or an empty array if no pat is found + */ +function findScriptPath(node, hash) { + if (node.left) { + if (node.left.hash.equals(hash)) return node.right ? [node.right.hash] : []; + const leftPath = findScriptPath(node.left, hash); + if (leftPath.length) + return node.right ? [node.right.hash].concat(leftPath) : leftPath; + } + if (node.right) { + if (node.right.hash.equals(hash)) return node.left ? [node.left.hash] : []; + const rightPath = findScriptPath(node.right, hash); + if (rightPath.length) + return node.left ? [node.left.hash].concat(rightPath) : rightPath; + } + return []; +} +exports.findScriptPath = findScriptPath; +function tapLeafHash(script, version) { + version = version || LEAF_VERSION_TAPSCRIPT; + return bcrypto.taggedHash( + TAP_LEAF_TAG, + buffer_1.Buffer.concat([ + buffer_1.Buffer.from([version]), + serializeScript(script), + ]), + ); +} +exports.tapLeafHash = tapLeafHash; +function tapTweakHash(pubKey, h) { + return bcrypto.taggedHash( + TAP_TWEAK_TAG, + buffer_1.Buffer.concat(h ? [pubKey, h] : [pubKey]), + ); +} +exports.tapTweakHash = tapTweakHash; +function tapBranchHash(a, b) { + return bcrypto.taggedHash(TAP_BRANCH_TAG, buffer_1.Buffer.concat([a, b])); +} +function serializeScript(s) { + const varintLen = bufferutils_1.varuint.encodingLength(s.length); + const buffer = buffer_1.Buffer.allocUnsafe(varintLen); // better + bufferutils_1.varuint.encode(s.length, buffer); + return buffer_1.Buffer.concat([buffer, s]); +} diff --git a/src/payments/testecc.d.ts b/src/payments/testecc.d.ts new file mode 100644 index 000000000..59d0de2b2 --- /dev/null +++ b/src/payments/testecc.d.ts @@ -0,0 +1,2 @@ +import { TinySecp256k1Interface } from '../types'; +export declare function testEcc(ecc: TinySecp256k1Interface): void; diff --git a/src/payments/testecc.js b/src/payments/testecc.js new file mode 100644 index 000000000..44e19c887 --- /dev/null +++ b/src/payments/testecc.js @@ -0,0 +1,72 @@ +'use strict'; +Object.defineProperty(exports, '__esModule', { value: true }); +exports.testEcc = void 0; +const h = hex => Buffer.from(hex, 'hex'); +function testEcc(ecc) { + assert(typeof ecc.isXOnlyPoint === 'function'); + assert( + ecc.isXOnlyPoint( + h('79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798'), + ), + ); + assert( + ecc.isXOnlyPoint( + h('fffffffffffffffffffffffffffffffffffffffffffffffffffffffeeffffc2e'), + ), + ); + assert( + ecc.isXOnlyPoint( + h('f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9'), + ), + ); + assert( + ecc.isXOnlyPoint( + h('0000000000000000000000000000000000000000000000000000000000000001'), + ), + ); + assert( + !ecc.isXOnlyPoint( + h('0000000000000000000000000000000000000000000000000000000000000000'), + ), + ); + assert( + !ecc.isXOnlyPoint( + h('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f'), + ), + ); + assert(typeof ecc.xOnlyPointAddTweak === 'function'); + tweakAddVectors.forEach(t => { + const r = ecc.xOnlyPointAddTweak(h(t.pubkey), h(t.tweak)); + if (t.result === null) { + assert(r === null); + } else { + assert(r !== null); + assert(r.parity === t.parity); + assert(Buffer.from(r.xOnlyPubkey).equals(h(t.result))); + } + }); +} +exports.testEcc = testEcc; +function assert(bool) { + if (!bool) throw new Error('ecc library invalid'); +} +const tweakAddVectors = [ + { + pubkey: '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', + tweak: 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140', + parity: -1, + result: null, + }, + { + pubkey: '1617d38ed8d8657da4d4761e8057bc396ea9e4b9d29776d4be096016dbd2509b', + tweak: 'a8397a935f0dfceba6ba9618f6451ef4d80637abf4e6af2669fbc9de6a8fd2ac', + parity: 1, + result: 'e478f99dab91052ab39a33ea35fd5e6e4933f4d28023cd597c9a1f6760346adf', + }, + { + pubkey: '2c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991', + tweak: '823c3cd2142744b075a87eade7e1b8678ba308d566226a0056ca2b7a76f86b47', + parity: 0, + result: '9534f8dc8c6deda2dc007655981c78b49c5d96c778fbf363462a11ec9dfd948c', + }, +]; diff --git a/src/psbt.d.ts b/src/psbt.d.ts index 8603a6955..43ce706f9 100644 --- a/src/psbt.d.ts +++ b/src/psbt.d.ts @@ -56,6 +56,17 @@ export declare class Psbt { static fromBase64(data: string, opts?: PsbtOptsOptional): Psbt; static fromHex(data: string, opts?: PsbtOptsOptional): Psbt; static fromBuffer(buffer: Buffer, opts?: PsbtOptsOptional): Psbt; + /** + * This is a helper method for converting a normal Signer into a Taproot Signer. + * Note that this helper method required for the Private Key of the Signer to be present. + * Steps: + * - if the Y coordinate of the Signer Public Key is odd then negate the Private Key + * - tweak the private key with the provided hash (should be empty for key-path spending) + * @param signer a taproot signer object, the Private Key must be present + * @param opts + * @returns a Signer having the Private and Public keys tweaked + */ + static tweakSigner(signer: Signer, opts?: TaprootSignerOpts): Signer; private __CACHE; private opts; constructor(opts?: PsbtOptsOptional, data?: PsbtBase); @@ -143,6 +154,7 @@ export interface HDSigner extends HDSignerBase { * Return a 64 byte signature (32 byte r and 32 byte s in that order) */ sign(hash: Buffer): Buffer; + signSchnorr?(hash: Buffer): Buffer; } /** * Same as above but with async sign method @@ -150,17 +162,31 @@ export interface HDSigner extends HDSignerBase { export interface HDSignerAsync extends HDSignerBase { derivePath(path: string): HDSignerAsync; sign(hash: Buffer): Promise; + signSchnorr?(hash: Buffer): Promise; } export interface Signer { publicKey: Buffer; + /** + * Private Key is optional, it is required only if the signer must be tweaked. + * See the `tweakSigner()` method. + */ + privateKey?: Buffer; network?: any; sign(hash: Buffer, lowR?: boolean): Buffer; + signSchnorr?(hash: Buffer): Buffer; getPublicKey?(): Buffer; } +export interface TaprootSignerOpts { + network?: Network; + eccLib?: any; + /** The hash used to tweak the Signer */ + tweakHash?: Buffer; +} export interface SignerAsync { publicKey: Buffer; network?: any; sign(hash: Buffer, lowR?: boolean): Promise; + signSchnorr?(hash: Buffer): Promise; getPublicKey?(): Buffer; } /** @@ -178,5 +204,5 @@ isP2WSH: boolean) => { finalScriptSig: Buffer | undefined; finalScriptWitness: Buffer | undefined; }; -declare type AllScriptType = 'witnesspubkeyhash' | 'pubkeyhash' | 'multisig' | 'pubkey' | 'nonstandard' | 'p2sh-witnesspubkeyhash' | 'p2sh-pubkeyhash' | 'p2sh-multisig' | 'p2sh-pubkey' | 'p2sh-nonstandard' | 'p2wsh-pubkeyhash' | 'p2wsh-multisig' | 'p2wsh-pubkey' | 'p2wsh-nonstandard' | 'p2sh-p2wsh-pubkeyhash' | 'p2sh-p2wsh-multisig' | 'p2sh-p2wsh-pubkey' | 'p2sh-p2wsh-nonstandard'; +declare type AllScriptType = 'witnesspubkeyhash' | 'pubkeyhash' | 'multisig' | 'pubkey' | 'taproot' | 'nonstandard' | 'p2sh-witnesspubkeyhash' | 'p2sh-pubkeyhash' | 'p2sh-multisig' | 'p2sh-pubkey' | 'p2sh-nonstandard' | 'p2wsh-pubkeyhash' | 'p2wsh-multisig' | 'p2wsh-pubkey' | 'p2wsh-nonstandard' | 'p2sh-p2wsh-pubkeyhash' | 'p2sh-p2wsh-multisig' | 'p2sh-p2wsh-pubkey' | 'p2sh-p2wsh-nonstandard'; export {}; diff --git a/src/psbt.js b/src/psbt.js index 616219580..4dce4643a 100644 --- a/src/psbt.js +++ b/src/psbt.js @@ -1,6 +1,8 @@ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); exports.Psbt = void 0; +const ecc = require('tiny-secp256k1'); // TODO: extract +const ecpair_1 = require('ecpair'); const bip174_1 = require('bip174'); const varuint = require('bip174/src/lib/converter/varint'); const utils_1 = require('bip174/src/lib/utils'); @@ -11,6 +13,7 @@ const networks_1 = require('./networks'); const payments = require('./payments'); const bscript = require('./script'); const transaction_1 = require('./transaction'); +const taprootutils_1 = require('./payments/taprootutils'); /** * These are the default arguments for a Psbt instance. */ @@ -103,6 +106,39 @@ class Psbt { checkTxForDupeIns(psbt.__CACHE.__TX, psbt.__CACHE); return psbt; } + /** + * This is a helper method for converting a normal Signer into a Taproot Signer. + * Note that this helper method required for the Private Key of the Signer to be present. + * Steps: + * - if the Y coordinate of the Signer Public Key is odd then negate the Private Key + * - tweak the private key with the provided hash (should be empty for key-path spending) + * @param signer a taproot signer object, the Private Key must be present + * @param opts + * @returns a Signer having the Private and Public keys tweaked + */ + static tweakSigner(signer, opts = {}) { + let privateKey = signer.privateKey; + if (!privateKey) { + throw new Error('Private key is required for tweaking signer!'); + } + if (signer.publicKey[0] === 3) { + privateKey = ecc.privateNegate(privateKey); + } + const tweakedPrivateKey = ecc.privateAdd( + privateKey, + (0, taprootutils_1.tapTweakHash)( + signer.publicKey.slice(1, 33), + opts.tweakHash, + ), + ); + if (!tweakedPrivateKey) { + throw new Error('Invalid tweaked private key!'); + } + const ECPair = (0, ecpair_1.ECPairFactory)(ecc); + return ECPair.fromPrivateKey(Buffer.from(tweakedPrivateKey), { + network: opts.network, + }); + } get inputCount() { return this.data.inputs.length; } @@ -298,7 +334,11 @@ class Psbt { } getInputType(inputIndex) { const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex); - const script = getScriptFromUtxo(inputIndex, input, this.__CACHE); + const { script } = getScriptAndAmountFromUtxo( + inputIndex, + input, + this.__CACHE, + ); const result = getMeaningfulScript( script, inputIndex, @@ -355,13 +395,21 @@ class Psbt { let hashCache; let scriptCache; let sighashCache; + const scriptType = this.getInputType(inputIndex); for (const pSig of mySigs) { - const sig = bscript.signature.decode(pSig.signature); + const sig = + scriptType === 'taproot' + ? { + signature: pSig.signature, + hashType: transaction_1.Transaction.SIGHASH_DEFAULT, + } + : bscript.signature.decode(pSig.signature); const { hash, script } = sighashCache !== sig.hashType ? getHashForSig( inputIndex, Object.assign({}, input, { sighashType: sig.hashType }), + this.data.inputs, this.__CACHE, true, ) @@ -526,13 +574,30 @@ class Psbt { this.__CACHE, sighashTypes, ); - const partialSig = [ - { - pubkey: keyPair.publicKey, - signature: bscript.signature.encode(keyPair.sign(hash), sighashType), - }, - ]; - this.data.updateInput(inputIndex, { partialSig }); + const scriptType = this.getInputType(inputIndex); + if (scriptType === 'taproot') { + if (!keyPair.signSchnorr) { + throw new Error( + `Need Schnorr Signer to sign taproot input #${inputIndex}.`, + ); + } + const partialSig = [ + { + pubkey: keyPair.publicKey, + signature: keyPair.signSchnorr(hash), + }, + ]; + // must be changed to use the `updateInput()` public API + this.data.inputs[inputIndex].partialSig = partialSig; + } else { + const partialSig = [ + { + pubkey: keyPair.publicKey, + signature: bscript.signature.encode(keyPair.sign(hash), sighashType), + }, + ]; + this.data.updateInput(inputIndex, { partialSig }); + } return this; } signInputAsync( @@ -671,6 +736,7 @@ function canFinalize(input, script, scriptType) { case 'pubkey': case 'pubkeyhash': case 'witnesspubkeyhash': + case 'taproot': return hasSigs(1, input.partialSig); case 'multisig': const p2ms = payments.p2ms({ output: script }); @@ -704,9 +770,9 @@ function isFinalized(input) { return !!input.finalScriptSig || !!input.finalScriptWitness; } function isPaymentFactory(payment) { - return script => { + return (script, eccLib) => { try { - payment({ output: script }); + payment({ output: script }, { eccLib }); return true; } catch (err) { return false; @@ -719,6 +785,7 @@ const isP2PKH = isPaymentFactory(payments.p2pkh); const isP2WPKH = isPaymentFactory(payments.p2wpkh); const isP2WSHScript = isPaymentFactory(payments.p2wsh); const isP2SHScript = isPaymentFactory(payments.p2sh); +const isP2TR = isPaymentFactory(payments.p2tr); function bip32DerivationIsMine(root) { return d => { if (!d.masterFingerprint.equals(root.fingerprint)) return false; @@ -920,6 +987,7 @@ function getHashAndSighashType( const { hash, sighashType, script } = getHashForSig( inputIndex, input, + inputs, cache, false, sighashTypes, @@ -930,7 +998,14 @@ function getHashAndSighashType( sighashType, }; } -function getHashForSig(inputIndex, input, cache, forValidate, sighashTypes) { +function getHashForSig( + inputIndex, + input, + inputs, + cache, + forValidate, + sighashTypes, +) { const unsignedTx = cache.__TX; const sighashType = input.sighashType || transaction_1.Transaction.SIGHASH_ALL; @@ -988,6 +1063,18 @@ function getHashForSig(inputIndex, input, cache, forValidate, sighashTypes) { prevout.value, sighashType, ); + } else if (isP2TR(meaningfulScript, ecc)) { + const prevOuts = inputs.map((i, index) => + getScriptAndAmountFromUtxo(index, i, cache), + ); + const signingScripts = prevOuts.map(o => o.script); + const values = prevOuts.map(o => o.value); + hash = unsignedTx.hashForWitnessV1( + inputIndex, + signingScripts, + values, + transaction_1.Transaction.SIGHASH_DEFAULT, + ); } else { // non-segwit if ( @@ -1050,6 +1137,15 @@ function getPayment(script, scriptType, partialSig) { signature: partialSig[0].signature, }); break; + case 'taproot': + payment = payments.p2tr( + { + output: script, + signature: partialSig[0].signature, + }, + { eccLib: ecc }, + ); + break; } return payment; } @@ -1094,7 +1190,7 @@ function getScriptFromInput(inputIndex, input, cache) { res.script = input.witnessUtxo.script; } } - if (input.witnessScript || isP2WPKH(res.script)) { + if (input.witnessScript || isP2WPKH(res.script) || isP2TR(res.script, ecc)) { res.isSegwit = true; } return res; @@ -1267,22 +1363,26 @@ function nonWitnessUtxoTxFromCache(cache, input, inputIndex) { } return c[inputIndex]; } -function getScriptFromUtxo(inputIndex, input, cache) { +function getScriptAndAmountFromUtxo(inputIndex, input, cache) { if (input.witnessUtxo !== undefined) { - return input.witnessUtxo.script; + return { + script: input.witnessUtxo.script, + value: input.witnessUtxo.value, + }; } else if (input.nonWitnessUtxo !== undefined) { const nonWitnessUtxoTx = nonWitnessUtxoTxFromCache( cache, input, inputIndex, ); - return nonWitnessUtxoTx.outs[cache.__TX.ins[inputIndex].index].script; + const o = nonWitnessUtxoTx.outs[cache.__TX.ins[inputIndex].index]; + return { script: o.script, value: o.value }; } else { throw new Error("Can't find pubkey in input without Utxo data"); } } function pubkeyInInput(pubkey, input, inputIndex, cache) { - const script = getScriptFromUtxo(inputIndex, input, cache); + const { script } = getScriptAndAmountFromUtxo(inputIndex, input, cache); const { meaningfulScript } = getMeaningfulScript( script, inputIndex, @@ -1392,11 +1492,16 @@ function checkInvalidP2WSH(script) { } function pubkeyInScript(pubkey, script) { const pubkeyHash = (0, crypto_1.hash160)(pubkey); + const pubkeyXOnly = pubkey.slice(1, 33); const decompiled = bscript.decompile(script); if (decompiled === null) throw new Error('Unknown script error'); return decompiled.some(element => { if (typeof element === 'number') return false; - return element.equals(pubkey) || element.equals(pubkeyHash); + return ( + element.equals(pubkey) || + element.equals(pubkeyHash) || + element.equals(pubkeyXOnly) + ); }); } function classifyScript(script) { @@ -1404,6 +1509,7 @@ function classifyScript(script) { if (isP2PKH(script)) return 'pubkeyhash'; if (isP2MS(script)) return 'multisig'; if (isP2PK(script)) return 'pubkey'; + if (isP2TR(script, ecc)) return 'taproot'; return 'nonstandard'; } function range(n) { diff --git a/src/types.d.ts b/src/types.d.ts index 5a8505d34..aefc6bed7 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -10,6 +10,18 @@ export declare function Signer(obj: any): boolean; export declare function Satoshi(value: number): boolean; export declare const ECPoint: any; export declare const Network: any; +export interface XOnlyPointAddTweakResult { + parity: 1 | 0; + xOnlyPubkey: Uint8Array; +} +export interface TaprootLeaf { + output: Buffer; + version?: number; +} +export interface TinySecp256k1Interface { + isXOnlyPoint(p: Uint8Array): boolean; + xOnlyPointAddTweak(p: Uint8Array, tweak: Uint8Array): XOnlyPointAddTweakResult | null; +} export declare const Buffer256bit: any; export declare const Hash160bit: any; export declare const Hash256bit: any; diff --git a/test/fixtures/p2tr.json b/test/fixtures/p2tr.json new file mode 100644 index 000000000..4c7174fc0 --- /dev/null +++ b/test/fixtures/p2tr.json @@ -0,0 +1,1026 @@ +{ + "valid": [ + { + "description": "output and pubkey from address", + "arguments": { + "address": "bc1p4dss6gkgq8003g0qyd5drwfqrztsadf2w2v3juz73gdz7cx82r6sj7lcqx" + }, + "options": {}, + "expected": { + "name": "p2tr", + "output": "OP_1 ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5", + "pubkey": "ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5", + "signature": null, + "input": null, + "witness": null + } + }, + { + "description": "address and pubkey from output", + "arguments": { + "output": "OP_1 ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5" + }, + "expected": { + "name": "p2tr", + "address": "bc1p4dss6gkgq8003g0qyd5drwfqrztsadf2w2v3juz73gdz7cx82r6sj7lcqx", + "pubkey": "ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5", + "signature": null, + "input": null, + "witness": null + } + }, + { + "description": "address and output from pubkey", + "arguments": { + "pubkey": "ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5" + }, + "expected": { + "name": "p2tr", + "address": "bc1p4dss6gkgq8003g0qyd5drwfqrztsadf2w2v3juz73gdz7cx82r6sj7lcqx", + "output": "OP_1 ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5", + "signature": null, + "input": null, + "witness": null + } + }, + { + "description": "address, output and witness from pubkey and signature", + "arguments": { + "pubkey": "ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5", + "signature": "a251221c339a7129dd0b769698aca40d8d9da9570ab796a1820b91ab7dbf5acbea21c88ba8f1e9308a21729baf080734beaf97023882d972f75e380d480fd704" + }, + "expected": { + "name": "p2tr", + "address": "bc1p4dss6gkgq8003g0qyd5drwfqrztsadf2w2v3juz73gdz7cx82r6sj7lcqx", + "output": "OP_1 ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5", + "input": null, + "witness": [ + "a251221c339a7129dd0b769698aca40d8d9da9570ab796a1820b91ab7dbf5acbea21c88ba8f1e9308a21729baf080734beaf97023882d972f75e380d480fd704" + ] + } + }, + { + "description": "address, output and signature from pubkey and witness", + "arguments": { + "pubkey": "ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5", + "witness": [ + "300602010002010001" + ] + }, + "expected": { + "name": "p2tr", + "address": "bc1p4dss6gkgq8003g0qyd5drwfqrztsadf2w2v3juz73gdz7cx82r6sj7lcqx", + "output": "OP_1 ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5", + "input": null, + "signature": "300602010002010001", + "witness": [ + "300602010002010001" + ] + } + }, + { + "description": "address, pubkey and output from internalPubkey", + "arguments": { + "internalPubkey": "9fa5ffb68821cf559001caa0577eeea4978b29416def328a707b15e91701a2f7" + }, + "expected": { + "name": "p2tr", + "address": "bc1prs7pxymu7jhsptzjlwlqnk8jyg5qmq4sdlc3rwcy7pd3ydz92xjq5ap2sg", + "pubkey": "1c3c13137cf4af00ac52fbbe09d8f222280d82b06ff111bb04f05b12344551a4", + "output": "OP_1 1c3c13137cf4af00ac52fbbe09d8f222280d82b06ff111bb04f05b12344551a4", + "signature": null, + "input": null, + "witness": null + } + }, + { + "description": "address, pubkey, internalPubkey and output from witness", + "arguments": { + "witness": [ + "9675a9982c6398ea9d441cb7a943bcd6ff033cc3a2e01a0178a7d3be4575be863871c6bf3eef5ecd34721c784259385ca9101c3a313e010ac942c99de05aaaa602", + "5799cf4b193b730fb99580b186f7477c2cca4d28957326f6f1a5d14116438530e7ec0ce1cd465ad96968ae8a6a09d4d37a060a115919f56fcfebe7b2277cc2df5cc08fb6cda9105ee2512b2e22635aba", + "7520c7b5db9562078049719228db2ac80cb9643ec96c8055aa3b29c2c03d4d99edb0ac", + "c1a7957acbaaf7b444c53d9e0c9436e8a8a3247fd515095d66ddf6201918b40a3668f9a4ccdffcf778da624dca2dda0b08e763ec52fd4ad403ec7563a3504d0cc168b9a77a410029e01dac89567c9b2e6cd726e840351df3f2f58fefe976200a19244150d04153909f660184d656ee95fa7bf8e1d4ec83da1fca34f64bc279b76d257ec623e08baba2cfa4ea9e99646e88f1eb1668c00c0f15b7443c8ab83481611cc3ae85eb89a7bfc40067eb1d2e6354a32426d0ce710e88bc4cc0718b99c325509c9d02a6a980d675a8969be10ee9bef82cafee2fc913475667ccda37b1bc7f13f64e56c449c532658ba8481631c02ead979754c809584a875951619cec8fb040c33f06468ae0266cd8693d6a64cea5912be32d8de95a6da6300b0c50fdcd6001ea41126e7b7e5280d455054a816560028f5ca53c9a50ee52f10e15c5337315bad1f5277acb109a1418649dc6ead2fe14699742fee7182f2f15e54279c7d932ed2799d01d73c97e68bbc94d6f7f56ee0a80efd7c76e3169e10d1a1ba3b5f1eb02369dc43af687461c7a2a3344d13eb5485dca29a67f16b4cb988923060fd3b65d0f0352bb634bcc44f2fe668836dcd0f604150049835135dc4b4fbf90fb334b3938a1f137eb32f047c65b85e6c1173b890b6d0162b48b186d1f1af8521945924ac8ac8efec321bf34f1d4b3d4a304a10313052c652d53f6ecb8a55586614e8950cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c" + ] + }, + "expected": { + "name": "p2tr", + "internalPubkey": "a7957acbaaf7b444c53d9e0c9436e8a8a3247fd515095d66ddf6201918b40a36", + "pubkey": "1ebe8b90363bd097aa9f352c8b21914e1886bc09fe9e70c09f33ef2d2abdf4bc", + "hash": "c5c62d7fc595ba5fbe61602eb1a29e2e4763408fe1e2b161beb7cb3c71ebcad9", + "address": "bc1pr6lghypk80gf025lx5kgkgv3fcvgd0qfl608psylx0hj624a7j7qay80rv", + "output": "OP_1 1ebe8b90363bd097aa9f352c8b21914e1886bc09fe9e70c09f33ef2d2abdf4bc", + "signature": null, + "input": null, + "witness": [ + "9675a9982c6398ea9d441cb7a943bcd6ff033cc3a2e01a0178a7d3be4575be863871c6bf3eef5ecd34721c784259385ca9101c3a313e010ac942c99de05aaaa602", + "5799cf4b193b730fb99580b186f7477c2cca4d28957326f6f1a5d14116438530e7ec0ce1cd465ad96968ae8a6a09d4d37a060a115919f56fcfebe7b2277cc2df5cc08fb6cda9105ee2512b2e22635aba", + "7520c7b5db9562078049719228db2ac80cb9643ec96c8055aa3b29c2c03d4d99edb0ac", + "c1a7957acbaaf7b444c53d9e0c9436e8a8a3247fd515095d66ddf6201918b40a3668f9a4ccdffcf778da624dca2dda0b08e763ec52fd4ad403ec7563a3504d0cc168b9a77a410029e01dac89567c9b2e6cd726e840351df3f2f58fefe976200a19244150d04153909f660184d656ee95fa7bf8e1d4ec83da1fca34f64bc279b76d257ec623e08baba2cfa4ea9e99646e88f1eb1668c00c0f15b7443c8ab83481611cc3ae85eb89a7bfc40067eb1d2e6354a32426d0ce710e88bc4cc0718b99c325509c9d02a6a980d675a8969be10ee9bef82cafee2fc913475667ccda37b1bc7f13f64e56c449c532658ba8481631c02ead979754c809584a875951619cec8fb040c33f06468ae0266cd8693d6a64cea5912be32d8de95a6da6300b0c50fdcd6001ea41126e7b7e5280d455054a816560028f5ca53c9a50ee52f10e15c5337315bad1f5277acb109a1418649dc6ead2fe14699742fee7182f2f15e54279c7d932ed2799d01d73c97e68bbc94d6f7f56ee0a80efd7c76e3169e10d1a1ba3b5f1eb02369dc43af687461c7a2a3344d13eb5485dca29a67f16b4cb988923060fd3b65d0f0352bb634bcc44f2fe668836dcd0f604150049835135dc4b4fbf90fb334b3938a1f137eb32f047c65b85e6c1173b890b6d0162b48b186d1f1af8521945924ac8ac8efec321bf34f1d4b3d4a304a10313052c652d53f6ecb8a55586614e8950cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c" + ] + } + }, + { + "description": "address, pubkey, internalPubkey and output from witness with annex", + "arguments": { + "witness": [ + "9675a9982c6398ea9d441cb7a943bcd6ff033cc3a2e01a0178a7d3be4575be863871c6bf3eef5ecd34721c784259385ca9101c3a313e010ac942c99de05aaaa602", + "5799cf4b193b730fb99580b186f7477c2cca4d28957326f6f1a5d14116438530e7ec0ce1cd465ad96968ae8a6a09d4d37a060a115919f56fcfebe7b2277cc2df5cc08fb6cda9105ee2512b2e22635aba", + "7520c7b5db9562078049719228db2ac80cb9643ec96c8055aa3b29c2c03d4d99edb0ac", + "c1a7957acbaaf7b444c53d9e0c9436e8a8a3247fd515095d66ddf6201918b40a3668f9a4ccdffcf778da624dca2dda0b08e763ec52fd4ad403ec7563a3504d0cc168b9a77a410029e01dac89567c9b2e6cd726e840351df3f2f58fefe976200a19244150d04153909f660184d656ee95fa7bf8e1d4ec83da1fca34f64bc279b76d257ec623e08baba2cfa4ea9e99646e88f1eb1668c00c0f15b7443c8ab83481611cc3ae85eb89a7bfc40067eb1d2e6354a32426d0ce710e88bc4cc0718b99c325509c9d02a6a980d675a8969be10ee9bef82cafee2fc913475667ccda37b1bc7f13f64e56c449c532658ba8481631c02ead979754c809584a875951619cec8fb040c33f06468ae0266cd8693d6a64cea5912be32d8de95a6da6300b0c50fdcd6001ea41126e7b7e5280d455054a816560028f5ca53c9a50ee52f10e15c5337315bad1f5277acb109a1418649dc6ead2fe14699742fee7182f2f15e54279c7d932ed2799d01d73c97e68bbc94d6f7f56ee0a80efd7c76e3169e10d1a1ba3b5f1eb02369dc43af687461c7a2a3344d13eb5485dca29a67f16b4cb988923060fd3b65d0f0352bb634bcc44f2fe668836dcd0f604150049835135dc4b4fbf90fb334b3938a1f137eb32f047c65b85e6c1173b890b6d0162b48b186d1f1af8521945924ac8ac8efec321bf34f1d4b3d4a304a10313052c652d53f6ecb8a55586614e8950cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c", + "5000000000000000001111111111111111" + ] + }, + "expected": { + "name": "p2tr", + "internalPubkey": "a7957acbaaf7b444c53d9e0c9436e8a8a3247fd515095d66ddf6201918b40a36", + "pubkey": "1ebe8b90363bd097aa9f352c8b21914e1886bc09fe9e70c09f33ef2d2abdf4bc", + "hash": "c5c62d7fc595ba5fbe61602eb1a29e2e4763408fe1e2b161beb7cb3c71ebcad9", + "address": "bc1pr6lghypk80gf025lx5kgkgv3fcvgd0qfl608psylx0hj624a7j7qay80rv", + "output": "OP_1 1ebe8b90363bd097aa9f352c8b21914e1886bc09fe9e70c09f33ef2d2abdf4bc", + "signature": null, + "input": null, + "witness": [ + "9675a9982c6398ea9d441cb7a943bcd6ff033cc3a2e01a0178a7d3be4575be863871c6bf3eef5ecd34721c784259385ca9101c3a313e010ac942c99de05aaaa602", + "5799cf4b193b730fb99580b186f7477c2cca4d28957326f6f1a5d14116438530e7ec0ce1cd465ad96968ae8a6a09d4d37a060a115919f56fcfebe7b2277cc2df5cc08fb6cda9105ee2512b2e22635aba", + "7520c7b5db9562078049719228db2ac80cb9643ec96c8055aa3b29c2c03d4d99edb0ac", + "c1a7957acbaaf7b444c53d9e0c9436e8a8a3247fd515095d66ddf6201918b40a3668f9a4ccdffcf778da624dca2dda0b08e763ec52fd4ad403ec7563a3504d0cc168b9a77a410029e01dac89567c9b2e6cd726e840351df3f2f58fefe976200a19244150d04153909f660184d656ee95fa7bf8e1d4ec83da1fca34f64bc279b76d257ec623e08baba2cfa4ea9e99646e88f1eb1668c00c0f15b7443c8ab83481611cc3ae85eb89a7bfc40067eb1d2e6354a32426d0ce710e88bc4cc0718b99c325509c9d02a6a980d675a8969be10ee9bef82cafee2fc913475667ccda37b1bc7f13f64e56c449c532658ba8481631c02ead979754c809584a875951619cec8fb040c33f06468ae0266cd8693d6a64cea5912be32d8de95a6da6300b0c50fdcd6001ea41126e7b7e5280d455054a816560028f5ca53c9a50ee52f10e15c5337315bad1f5277acb109a1418649dc6ead2fe14699742fee7182f2f15e54279c7d932ed2799d01d73c97e68bbc94d6f7f56ee0a80efd7c76e3169e10d1a1ba3b5f1eb02369dc43af687461c7a2a3344d13eb5485dca29a67f16b4cb988923060fd3b65d0f0352bb634bcc44f2fe668836dcd0f604150049835135dc4b4fbf90fb334b3938a1f137eb32f047c65b85e6c1173b890b6d0162b48b186d1f1af8521945924ac8ac8efec321bf34f1d4b3d4a304a10313052c652d53f6ecb8a55586614e8950cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c", + "5000000000000000001111111111111111" + ] + } + }, + { + "description": "address, pubkey, output and hash from internalPubkey and a script tree with one leaf", + "arguments": { + "internalPubkey": "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0", + "scriptsTree": [ + { + "output": "83d8ee77a0f3a32a5cea96fd1624d623b836c1e5d1ac2dcde46814b619320c18 OP_CHECKSIG" + } + ] + }, + "expected": { + "name": "p2tr", + "address": "bc1pjegs09vkeder9m4sw3ycjf2rnpa8nljdqmuleunk9eshu8cq3xysvhgp2u", + "pubkey": "9651079596cb7232eeb07449892543987a79fe4d06f9fcf2762e617e1f008989", + "output": "OP_1 9651079596cb7232eeb07449892543987a79fe4d06f9fcf2762e617e1f008989", + "hash": "16e3f3b8b9c1e453c56b547785cdd25259d65823a2064f30783acc58ef012633", + "signature": null, + "input": null, + "witness": null + } + }, + { + "description": "address, pubkey, output and hash from internalPubkey and a script tree with two leafs", + "arguments": { + "internalPubkey": "2258b1c3160be0864a541854eec9164a572f094f7562628281a8073bb89173a7", + "scriptsTree": [ + { + "output": "d826a0a53abb6ffc60df25b9c152870578faef4b2eb5a09bdd672bbe32cdd79b OP_CHECKSIG" + }, + { + "output": "d826a0a53abb6ffc60df25b9c152870578faef4b2eb5a09bdd672bbe32cdd79b OP_CHECKSIG" + } + ] + }, + "expected": { + "name": "p2tr", + "address": "bc1ptj0v8rwcj6s36p4r26ws6htx0fct43n0mxdvdeh9043whlxlq3kq9965ke", + "pubkey": "5c9ec38dd896a11d06a3569d0d5d667a70bac66fd99ac6e6e57d62ebfcdf046c", + "output": "OP_1 5c9ec38dd896a11d06a3569d0d5d667a70bac66fd99ac6e6e57d62ebfcdf046c", + "hash": "ce00198cd4667abae1f94aa5862d089e2967af5aec20715c692db74e3d66bb73", + "signature": null, + "input": null, + "witness": null + } + }, + { + "description": "address, pubkey, output and hash from internalPubkey and a script tree with three leafs", + "arguments": { + "internalPubkey": "7631cacec3343052d87ef4d0065f61dde82d7d2db0c1cc02ef61ef3c982ea763", + "scriptsTree": [ + { + "output": "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0 OP_CHECKSIG" + }, + [ + { + "output": "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0 OP_CHECKSIG" + }, + { + "output": "9b4d495b74887815a1ff623c055c6eac6b6b2e07d2a016d6526ebac71dd99744 OP_CHECKSIG" + } + ] + ] + }, + "expected": { + "name": "p2tr", + "address": "bc1pkq0t8nkmqswn3qjg9uy6ux2hsyyz4as25v8unfjc9s8q2e4c00sqku9lxh", + "pubkey": "b01eb3cedb041d3882482f09ae195781082af60aa30fc9a6582c0e0566b87be0", + "output": "OP_1 b01eb3cedb041d3882482f09ae195781082af60aa30fc9a6582c0e0566b87be0", + "hash": "7ae0cc2057b1a7bf0e09c787e1d7b6b2355ac112a7b80380a5c1e942155b0c0f", + "signature": null, + "input": null, + "witness": null + } + }, + { + "description": "address, pubkey, output and hash from internalPubkey and a script tree with four leafs", + "arguments": { + "internalPubkey": "d0c19def28bb1b39451c1a814737615983967780d223b79969ba692182c6006b", + "scriptsTree": [ + [ + { + "output": "9b4d495b74887815a1ff623c055c6eac6b6b2e07d2a016d6526ebac71dd99744 OP_CHECKSIG" + }, + { + "output": "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0 OP_CHECKSIG" + } + ], + [ + { + "output": "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0 OP_CHECKSIG" + }, + { + "output": "9b4d495b74887815a1ff623c055c6eac6b6b2e07d2a016d6526ebac71dd99744 OP_CHECKSIG" + } + ] + ] + }, + "expected": { + "name": "p2tr", + "address": "bc1pstdzevc40j059s0473rghhv9e05l9f5xv7l6dtlavvq22rzfna3syjvjut", + "pubkey": "82da2cb3157c9f42c1f5f4468bdd85cbe9f2a68667bfa6affd6300a50c499f63", + "output": "OP_1 82da2cb3157c9f42c1f5f4468bdd85cbe9f2a68667bfa6affd6300a50c499f63", + "hash": "d673e784eac9b70289130a0bd359023a0fbdde51dc069b9efb4157c2cdce3ea5", + "signature": null, + "input": null, + "witness": null + } + }, + { + "description": "address, pubkey, output and hash from internalPubkey and a script tree with seven leafs", + "arguments": { + "internalPubkey": "f95886b02a84928c5c15bdca32784993105f73de27fa6ad8c1a60389b999267c", + "scriptsTree": [ + [ + { + "output": "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0 OP_CHECKSIG" + }, + [ + { + "output": "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0 OP_CHECKSIG" + }, + { + "output": "2258b1c3160be0864a541854eec9164a572f094f7562628281a8073bb89173a7 OP_CHECKSIG" + } + ] + ], + [ + { + "output": "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0 OP_CHECKSIG" + }, + [ + { + "output": "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0 OP_CHECKSIG" + }, + [ + { + "output": "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0 OP_CHECKSIG" + }, + { + "output": "03a669ea926f381582ec4a000b9472ba8a17347f5fb159eddd4a07036a6718eb OP_CHECKSIG" + } + ] + ] + ] + ] + }, + "expected": { + "name": "p2tr", + "address": "bc1pfas4r5s5208puwzj20hvwg2dw2kanc06yxczzdd66729z63pk43q7zwlu6", + "pubkey": "4f6151d21453ce1e385253eec7214d72add9e1fa21b02135bad794516a21b562", + "output": "OP_1 4f6151d21453ce1e385253eec7214d72add9e1fa21b02135bad794516a21b562", + "hash": "16fb2e99bdf86f67ee6980d0418658f15df7e19476053b58f45a89df2e219b1b", + "signature": null, + "input": null, + "witness": null + } + }, + { + "description": "address, pubkey, output and hash from internalPubkey and a script tree with seven leafs (2)", + "arguments": { + "internalPubkey": "aba457d16a8d59151c387f24d1eb887efbe24644c1ee64b261282e7baebdb247", + "scriptsTree": [ + { + "output": "00a9da96087a72258f83b338ef7f0ea8cbbe05da5f18f091eb397d1ecbf7c3d3 OP_CHECKSIG" + }, + [ + [ + { + "output": "00a9da96087a72258f83b338ef7f0ea8cbbe05da5f18f091eb397d1ecbf7c3d3 OP_CHECKSIG" + }, + [ + { + "output": "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0 OP_CHECKSIG" + }, + { + "output": "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0 OP_CHECKSIG" + } + ] + ], + [ + [ + { + "output": "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0 OP_CHECKSIG" + }, + { + "output": "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0 OP_CHECKSIG" + } + ], + { + "output": "00a9da96087a72258f83b338ef7f0ea8cbbe05da5f18f091eb397d1ecbf7c3d3 OP_CHECKSIG" + } + ] + ] + ] + }, + "expected": { + "name": "p2tr", + "address": "bc1pmu8qwr9zljs9anger0d6q3uyr43yzjetmjmzf8p93ltycrwj28lsee3e0n", + "pubkey": "df0e070ca2fca05ecd191bdba047841d62414b2bdcb6249c258fd64c0dd251ff", + "output": "OP_1 df0e070ca2fca05ecd191bdba047841d62414b2bdcb6249c258fd64c0dd251ff", + "hash": "027391d0aac8d94725e4fcec4b07214d7c8a14bcdca2b1c08e4bc786308bdae5", + "signature": null, + "input": null, + "witness": null + } + }, + { + "description": "BIP341 Test case 1", + "arguments": { + "internalPubkey": "d6889cb081036e0faefa3a35157ad71086b123b2b144b649798b494c300a961d" + }, + "options": {}, + "expected": { + "name": "p2tr", + "output": "OP_1 53a1f6e454df1aa2776a2814a721372d6258050de330b3c6d10ee8f4e0dda343", + "pubkey": "53a1f6e454df1aa2776a2814a721372d6258050de330b3c6d10ee8f4e0dda343", + "address": "bc1p2wsldez5mud2yam29q22wgfh9439spgduvct83k3pm50fcxa5dps59h4z5", + "signature": null, + "input": null, + "witness": null + } + }, + { + "description": "BIP341 Test case 2", + "arguments": { + "internalPubkey": "187791b6f712a8ea41c8ecdd0ee77fab3e85263b37e1ec18a3651926b3a6cf27", + "scriptLeaf": { + "output": "d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8 OP_CHECKSIG", + "version": 192 + }, + "scriptsTree": [ + { + "output": "d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8 OP_CHECKSIG", + "version": 192 + } + ] + }, + "options": {}, + "expected": { + "name": "p2tr", + "output": "OP_1 147c9c57132f6e7ecddba9800bb0c4449251c92a1e60371ee77557b6620f3ea3", + "pubkey": "147c9c57132f6e7ecddba9800bb0c4449251c92a1e60371ee77557b6620f3ea3", + "address": "bc1pz37fc4cn9ah8anwm4xqqhvxygjf9rjf2resrw8h8w4tmvcs0863sa2e586", + "hash": "5b75adecf53548f3ec6ad7d78383bf84cc57b55a3127c72b9a2481752dd88b21", + "witness": [ + "20d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8ac", + "c1187791b6f712a8ea41c8ecdd0ee77fab3e85263b37e1ec18a3651926b3a6cf27" + ], + "signature": null, + "input": null + } + }, + { + "description": "BIP341 Test case 3", + "arguments": { + "internalPubkey": "93478e9488f956df2396be2ce6c5cced75f900dfa18e7dabd2428aae78451820", + "scriptLeaf": { + "output": "b617298552a72ade070667e86ca63b8f5789a9fe8731ef91202a91c9f3459007 OP_CHECKSIG", + "version": 192 + }, + "scriptsTree": [ + { + "output": "b617298552a72ade070667e86ca63b8f5789a9fe8731ef91202a91c9f3459007 OP_CHECKSIG", + "version": 192 + } + ] + }, + "options": {}, + "expected": { + "name": "p2tr", + "output": "OP_1 e4d810fd50586274face62b8a807eb9719cef49c04177cc6b76a9a4251d5450e", + "pubkey": "e4d810fd50586274face62b8a807eb9719cef49c04177cc6b76a9a4251d5450e", + "address": "bc1punvppl2stp38f7kwv2u2spltjuvuaayuqsthe34hd2dyy5w4g58qqfuag5", + "hash": "c525714a7f49c28aedbbba78c005931a81c234b2f6c99a73e4d06082adc8bf2b", + "witness": [ + "20b617298552a72ade070667e86ca63b8f5789a9fe8731ef91202a91c9f3459007ac", + "c093478e9488f956df2396be2ce6c5cced75f900dfa18e7dabd2428aae78451820" + ], + "signature": null, + "input": null + } + }, + { + "description": "BIP341 Test case 4 - spend leaf 0", + "arguments": { + "internalPubkey": "ee4fe085983462a184015d1f782d6a5f8b9c2b60130aff050ce221ecf3786592", + "scriptLeaf": { + "output": "387671353e273264c495656e27e39ba899ea8fee3bb69fb2a680e22093447d48 OP_CHECKSIG", + "version": 192 + }, + "scriptsTree": [ + { + "output": "387671353e273264c495656e27e39ba899ea8fee3bb69fb2a680e22093447d48 OP_CHECKSIG", + "version": 192 + }, + { + "output": "424950333431", + "version": 152 + } + ] + }, + "options": {}, + "expected": { + "name": "p2tr", + "output": "OP_1 0f63ca2c7639b9bb4be0465cc0aa3ee78a0761ba5f5f7d6ff8eab340f09da561", + "pubkey": "0f63ca2c7639b9bb4be0465cc0aa3ee78a0761ba5f5f7d6ff8eab340f09da561", + "address": "bc1ppa3u5trk8xumkjlqgewvp237u79qwcd6ta0h6mlca2e5puya54ssw9zq0y", + "hash": "f3004d6c183e038105d436db1424f321613366cbb7b05939bf05d763a9ebb962", + "witness": [ + "20387671353e273264c495656e27e39ba899ea8fee3bb69fb2a680e22093447d48ac", + "c0ee4fe085983462a184015d1f782d6a5f8b9c2b60130aff050ce221ecf37865927b2c2af8aa3e8b7bfe2f62a155f91427489c5c3b32be47e0b3fac755fc780e0e" + ], + "signature": null, + "input": null + } + }, + { + "description": "BIP341 Test case 4 - spend leaf 1", + "arguments": { + "internalPubkey": "ee4fe085983462a184015d1f782d6a5f8b9c2b60130aff050ce221ecf3786592", + "scriptLeaf": { + "output": "424950333431", + "version": 152 + }, + "scriptsTree": [ + { + "output": "387671353e273264c495656e27e39ba899ea8fee3bb69fb2a680e22093447d48 OP_CHECKSIG", + "version": 192 + }, + { + "output": "424950333431", + "version": 152 + } + ] + }, + "options": {}, + "expected": { + "name": "p2tr", + "output": "OP_1 0f63ca2c7639b9bb4be0465cc0aa3ee78a0761ba5f5f7d6ff8eab340f09da561", + "pubkey": "0f63ca2c7639b9bb4be0465cc0aa3ee78a0761ba5f5f7d6ff8eab340f09da561", + "address": "bc1ppa3u5trk8xumkjlqgewvp237u79qwcd6ta0h6mlca2e5puya54ssw9zq0y", + "hash": "f3004d6c183e038105d436db1424f321613366cbb7b05939bf05d763a9ebb962", + "witness": [ + "06424950333431", + "98ee4fe085983462a184015d1f782d6a5f8b9c2b60130aff050ce221ecf37865928ad69ec7cf41c2a4001fd1f738bf1e505ce2277acdcaa63fe4765192497f47a7" + ], + "signature": null, + "input": null + } + }, + { + "description": "BIP341 Test case 5 - spend leaf 0", + "arguments": { + "internalPubkey": "f9f400803e683727b14f463836e1e78e1c64417638aa066919291a225f0e8dd8", + "scriptLeaf": { + "output": "44b178d64c32c4a05cc4f4d1407268f764c940d20ce97abfd44db5c3592b72fd OP_CHECKSIG", + "version": 192 + }, + "scriptsTree": [ + { + "output": "44b178d64c32c4a05cc4f4d1407268f764c940d20ce97abfd44db5c3592b72fd OP_CHECKSIG", + "version": 192 + }, + { + "output": "546170726f6f74", + "version": 82 + } + ] + }, + "options": {}, + "expected": { + "name": "p2tr", + "output": "OP_1 053690babeabbb7850c32eead0acf8df990ced79f7a31e358fabf2658b4bc587", + "pubkey": "053690babeabbb7850c32eead0acf8df990ced79f7a31e358fabf2658b4bc587", + "address": "bc1pq5mfpw474wahs5xr9m4dpt8cm7vsemte7733udv040extz6tckrs29g04c", + "hash": "d9c2c32808b41c0301d876d49c0af72e1d98e84b99ca9b4bb67fea1a7424b755", + "witness": [ + "2044b178d64c32c4a05cc4f4d1407268f764c940d20ce97abfd44db5c3592b72fdac", + "c1f9f400803e683727b14f463836e1e78e1c64417638aa066919291a225f0e8dd8e44d5f8fa5892c8b6d4d09a08d36edd0b08636e30311302e2448ad8172fb3433" + ], + "signature": null, + "input": null + } + }, + { + "description": "BIP341 Test case 5 - spend leaf 1", + "arguments": { + "internalPubkey": "f9f400803e683727b14f463836e1e78e1c64417638aa066919291a225f0e8dd8", + "scriptLeaf": { + "output": "546170726f6f74", + "version": 82 + }, + "scriptsTree": [ + { + "output": "44b178d64c32c4a05cc4f4d1407268f764c940d20ce97abfd44db5c3592b72fd OP_CHECKSIG", + "version": 192 + }, + { + "output": "546170726f6f74", + "version": 82 + } + ] + }, + "options": {}, + "expected": { + "name": "p2tr", + "output": "OP_1 053690babeabbb7850c32eead0acf8df990ced79f7a31e358fabf2658b4bc587", + "pubkey": "053690babeabbb7850c32eead0acf8df990ced79f7a31e358fabf2658b4bc587", + "address": "bc1pq5mfpw474wahs5xr9m4dpt8cm7vsemte7733udv040extz6tckrs29g04c", + "hash": "d9c2c32808b41c0301d876d49c0af72e1d98e84b99ca9b4bb67fea1a7424b755", + "witness": [ + "07546170726f6f74", + "53f9f400803e683727b14f463836e1e78e1c64417638aa066919291a225f0e8dd864512fecdb5afa04f98839b50e6f0cb7b1e539bf6f205f67934083cdcc3c8d89" + ], + "signature": null, + "input": null + } + }, + { + "description": "BIP341 Test case 6 - spend leaf 0", + "arguments": { + "internalPubkey": "e0dfe2300b0dd746a3f8674dfd4525623639042569d829c7f0eed9602d263e6f", + "scriptLeaf": { + "output": "72ea6adcf1d371dea8fba1035a09f3d24ed5a059799bae114084130ee5898e69 OP_CHECKSIG", + "version": 192 + }, + "scriptsTree": [ + { + "output": "72ea6adcf1d371dea8fba1035a09f3d24ed5a059799bae114084130ee5898e69 OP_CHECKSIG", + "version": 192 + }, + [ + { + "output": "2352d137f2f3ab38d1eaa976758873377fa5ebb817372c71e2c542313d4abda8 OP_CHECKSIG", + "version": 192 + }, + { + "output": "7337c0dd4253cb86f2c43a2351aadd82cccb12a172cd120452b9bb8324f2186a OP_CHECKSIG", + "version": 192 + } + ] + ] + }, + "options": {}, + "expected": { + "name": "p2tr", + "output": "OP_1 91b64d5324723a985170e4dc5a0f84c041804f2cd12660fa5dec09fc21783605", + "pubkey": "91b64d5324723a985170e4dc5a0f84c041804f2cd12660fa5dec09fc21783605", + "address": "bc1pjxmy65eywgafs5tsunw95ruycpqcqnev6ynxp7jaasylcgtcxczs6n332e", + "hash": "ccbd66c6f7e8fdab47b3a486f59d28262be857f30d4773f2d5ea47f7761ce0e2", + "witness": [ + "2072ea6adcf1d371dea8fba1035a09f3d24ed5a059799bae114084130ee5898e69ac", + "c0e0dfe2300b0dd746a3f8674dfd4525623639042569d829c7f0eed9602d263e6fffe578e9ea769027e4f5a3de40732f75a88a6353a09d767ddeb66accef85e553" + ], + "signature": null, + "input": null + } + }, + { + "description": "BIP341 Test case 6 - spend leaf 1", + "arguments": { + "internalPubkey": "e0dfe2300b0dd746a3f8674dfd4525623639042569d829c7f0eed9602d263e6f", + "scriptLeaf": { + "output": "2352d137f2f3ab38d1eaa976758873377fa5ebb817372c71e2c542313d4abda8 OP_CHECKSIG", + "version": 192 + }, + "scriptsTree": [ + { + "output": "72ea6adcf1d371dea8fba1035a09f3d24ed5a059799bae114084130ee5898e69 OP_CHECKSIG", + "version": 192 + }, + [ + { + "output": "2352d137f2f3ab38d1eaa976758873377fa5ebb817372c71e2c542313d4abda8 OP_CHECKSIG", + "version": 192 + }, + { + "output": "7337c0dd4253cb86f2c43a2351aadd82cccb12a172cd120452b9bb8324f2186a OP_CHECKSIG", + "version": 192 + } + ] + ] + }, + "options": {}, + "expected": { + "name": "p2tr", + "output": "OP_1 91b64d5324723a985170e4dc5a0f84c041804f2cd12660fa5dec09fc21783605", + "pubkey": "91b64d5324723a985170e4dc5a0f84c041804f2cd12660fa5dec09fc21783605", + "address": "bc1pjxmy65eywgafs5tsunw95ruycpqcqnev6ynxp7jaasylcgtcxczs6n332e", + "hash": "ccbd66c6f7e8fdab47b3a486f59d28262be857f30d4773f2d5ea47f7761ce0e2", + "witness": [ + "202352d137f2f3ab38d1eaa976758873377fa5ebb817372c71e2c542313d4abda8ac", + "c0e0dfe2300b0dd746a3f8674dfd4525623639042569d829c7f0eed9602d263e6f9e31407bffa15fefbf5090b149d53959ecdf3f62b1246780238c24501d5ceaf62645a02e0aac1fe69d69755733a9b7621b694bb5b5cde2bbfc94066ed62b9817" + ], + "signature": null, + "input": null + } + }, + { + "description": "BIP341 Test case 6 - spend leaf 2", + "arguments": { + "internalPubkey": "e0dfe2300b0dd746a3f8674dfd4525623639042569d829c7f0eed9602d263e6f", + "scriptLeaf": { + "output": "7337c0dd4253cb86f2c43a2351aadd82cccb12a172cd120452b9bb8324f2186a OP_CHECKSIG", + "version": 192 + }, + "scriptsTree": [ + { + "output": "72ea6adcf1d371dea8fba1035a09f3d24ed5a059799bae114084130ee5898e69 OP_CHECKSIG", + "version": 192 + }, + [ + { + "output": "2352d137f2f3ab38d1eaa976758873377fa5ebb817372c71e2c542313d4abda8 OP_CHECKSIG", + "version": 192 + }, + { + "output": "7337c0dd4253cb86f2c43a2351aadd82cccb12a172cd120452b9bb8324f2186a OP_CHECKSIG", + "version": 192 + } + ] + ] + }, + "options": {}, + "expected": { + "name": "p2tr", + "output": "OP_1 91b64d5324723a985170e4dc5a0f84c041804f2cd12660fa5dec09fc21783605", + "pubkey": "91b64d5324723a985170e4dc5a0f84c041804f2cd12660fa5dec09fc21783605", + "address": "bc1pjxmy65eywgafs5tsunw95ruycpqcqnev6ynxp7jaasylcgtcxczs6n332e", + "hash": "ccbd66c6f7e8fdab47b3a486f59d28262be857f30d4773f2d5ea47f7761ce0e2", + "witness": [ + "207337c0dd4253cb86f2c43a2351aadd82cccb12a172cd120452b9bb8324f2186aac", + "c0e0dfe2300b0dd746a3f8674dfd4525623639042569d829c7f0eed9602d263e6fba982a91d4fc552163cb1c0da03676102d5b7a014304c01f0c77b2b8e888de1c2645a02e0aac1fe69d69755733a9b7621b694bb5b5cde2bbfc94066ed62b9817" + ], + "signature": null, + "input": null + } + }, + { + "description": "BIP341 Test case 7 - spend leaf 0", + "arguments": { + "internalPubkey": "55adf4e8967fbd2e29f20ac896e60c3b0f1d5b0efa9d34941b5958c7b0a0312d", + "scriptLeaf": { + "output": "71981521ad9fc9036687364118fb6ccd2035b96a423c59c5430e98310a11abe2 OP_CHECKSIG", + "version": 192 + }, + "scriptsTree": [ + { + "output": "71981521ad9fc9036687364118fb6ccd2035b96a423c59c5430e98310a11abe2 OP_CHECKSIG", + "version": 192 + }, + [ + { + "output": "d5094d2dbe9b76e2c245a2b89b6006888952e2faa6a149ae318d69e520617748 OP_CHECKSIG", + "version": 192 + }, + { + "output": "c440b462ad48c7a77f94cd4532d8f2119dcebbd7c9764557e62726419b08ad4c OP_CHECKSIG", + "version": 192 + } + ] + ] + }, + "options": {}, + "expected": { + "name": "p2tr", + "output": "OP_1 75169f4001aa68f15bbed28b218df1d0a62cbbcf1188c6665110c293c907b831", + "pubkey": "75169f4001aa68f15bbed28b218df1d0a62cbbcf1188c6665110c293c907b831", + "address": "bc1pw5tf7sqp4f50zka7629jrr036znzew70zxyvvej3zrpf8jg8hqcssyuewe", + "hash": "2f6b2c5397b6d68ca18e09a3f05161668ffe93a988582d55c6f07bd5b3329def", + "witness": [ + "2071981521ad9fc9036687364118fb6ccd2035b96a423c59c5430e98310a11abe2ac", + "c155adf4e8967fbd2e29f20ac896e60c3b0f1d5b0efa9d34941b5958c7b0a0312d3cd369a528b326bc9d2133cbd2ac21451acb31681a410434672c8e34fe757e91" + ], + "signature": null, + "input": null + } + }, + { + "description": "BIP341 Test case 7 - spend leaf 1", + "arguments": { + "internalPubkey": "55adf4e8967fbd2e29f20ac896e60c3b0f1d5b0efa9d34941b5958c7b0a0312d", + "scriptLeaf": { + "output": "d5094d2dbe9b76e2c245a2b89b6006888952e2faa6a149ae318d69e520617748 OP_CHECKSIG", + "version": 192 + }, + "scriptsTree": [ + { + "output": "71981521ad9fc9036687364118fb6ccd2035b96a423c59c5430e98310a11abe2 OP_CHECKSIG", + "version": 192 + }, + [ + { + "output": "d5094d2dbe9b76e2c245a2b89b6006888952e2faa6a149ae318d69e520617748 OP_CHECKSIG", + "version": 192 + }, + { + "output": "c440b462ad48c7a77f94cd4532d8f2119dcebbd7c9764557e62726419b08ad4c OP_CHECKSIG", + "version": 192 + } + ] + ] + }, + "options": {}, + "expected": { + "name": "p2tr", + "output": "OP_1 75169f4001aa68f15bbed28b218df1d0a62cbbcf1188c6665110c293c907b831", + "pubkey": "75169f4001aa68f15bbed28b218df1d0a62cbbcf1188c6665110c293c907b831", + "address": "bc1pw5tf7sqp4f50zka7629jrr036znzew70zxyvvej3zrpf8jg8hqcssyuewe", + "hash": "2f6b2c5397b6d68ca18e09a3f05161668ffe93a988582d55c6f07bd5b3329def", + "witness": [ + "20d5094d2dbe9b76e2c245a2b89b6006888952e2faa6a149ae318d69e520617748ac", + "c155adf4e8967fbd2e29f20ac896e60c3b0f1d5b0efa9d34941b5958c7b0a0312dd7485025fceb78b9ed667db36ed8b8dc7b1f0b307ac167fa516fe4352b9f4ef7f154e8e8e17c31d3462d7132589ed29353c6fafdb884c5a6e04ea938834f0d9d" + ], + "signature": null, + "input": null + } + }, + { + "description": "BIP341 Test case 7 - spend leaf 2", + "arguments": { + "internalPubkey": "55adf4e8967fbd2e29f20ac896e60c3b0f1d5b0efa9d34941b5958c7b0a0312d", + "scriptLeaf": { + "output": "c440b462ad48c7a77f94cd4532d8f2119dcebbd7c9764557e62726419b08ad4c OP_CHECKSIG", + "version": 192 + }, + "scriptsTree": [ + { + "output": "71981521ad9fc9036687364118fb6ccd2035b96a423c59c5430e98310a11abe2 OP_CHECKSIG", + "version": 192 + }, + [ + { + "output": "d5094d2dbe9b76e2c245a2b89b6006888952e2faa6a149ae318d69e520617748 OP_CHECKSIG", + "version": 192 + }, + { + "output": "c440b462ad48c7a77f94cd4532d8f2119dcebbd7c9764557e62726419b08ad4c OP_CHECKSIG", + "version": 192 + } + ] + ] + }, + "options": {}, + "expected": { + "name": "p2tr", + "output": "OP_1 75169f4001aa68f15bbed28b218df1d0a62cbbcf1188c6665110c293c907b831", + "pubkey": "75169f4001aa68f15bbed28b218df1d0a62cbbcf1188c6665110c293c907b831", + "address": "bc1pw5tf7sqp4f50zka7629jrr036znzew70zxyvvej3zrpf8jg8hqcssyuewe", + "hash": "2f6b2c5397b6d68ca18e09a3f05161668ffe93a988582d55c6f07bd5b3329def", + "witness": [ + "20c440b462ad48c7a77f94cd4532d8f2119dcebbd7c9764557e62726419b08ad4cac", + "c155adf4e8967fbd2e29f20ac896e60c3b0f1d5b0efa9d34941b5958c7b0a0312d737ed1fe30bc42b8022d717b44f0d93516617af64a64753b7a06bf16b26cd711f154e8e8e17c31d3462d7132589ed29353c6fafdb884c5a6e04ea938834f0d9d" + ], + "signature": null, + "input": null + } + } + ], + "invalid": [ + { + "exception": "Not enough data", + "arguments": {} + }, + { + "exception": "Not enough data", + "arguments": { + "signature": "300602010002010001" + } + }, + { + "description": "Incorrect Witness Version", + "exception": "Output is invalid", + "arguments": { + "output": "OP_0 ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5" + } + }, + { + "description": "Invalid x coordinate for pubkey in pubkey", + "exception": "Invalid pubkey for p2tr", + "arguments": { + "pubkey": "f136e956540197c21ff3c075d32a6e3c82f1ee1e646cc0f08f51b0b5edafa762" + } + }, + { + "description": "Invalid x coordinate for pubkey in output", + "exception": "Invalid pubkey for p2tr", + "arguments": { + "output": "OP_1 f136e956540197c21ff3c075d32a6e3c82f1ee1e646cc0f08f51b0b5edafa762" + } + }, + { + "description": "Invalid x coordinate for pubkey in address", + "exception": "Invalid pubkey for p2tr", + "arguments": { + "address": "bc1p7ymwj4j5qxtuy8lncp6ax2nw8jp0rms7v3kvpuy02xcttmd05a3qmwlnez" + } + }, + { + "description": "Pubkey mismatch between pubkey and output", + "exception": "Pubkey mismatch", + "options": {}, + "arguments": { + "pubkey": "ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5", + "output": "OP_1 12d7dac98d69a086a50b30959a3537950f356ffc6f50a263ab75c8a3ec9d44c1" + } + }, + { + "description": "Pubkey mismatch between pubkey and address", + "exception": "Pubkey mismatch", + "options": {}, + "arguments": { + "pubkey": "ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5", + "address": "bc1pztta4jvddxsgdfgtxz2e5dfhj58n2mludag2ycatwhy28myagnqsnl7mv7" + } + }, + { + "description": "Pubkey mismatch between output and address", + "exception": "Pubkey mismatch", + "options": {}, + "arguments": { + "output": "OP_1 ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5", + "address": "bc1pztta4jvddxsgdfgtxz2e5dfhj58n2mludag2ycatwhy28myagnqsnl7mv7" + } + }, + { + "description": "Pubkey mismatch between internalPubkey and pubkey", + "exception": "Pubkey mismatch", + "options": {}, + "arguments": { + "internalPubkey": "9fa5ffb68821cf559001caa0577eeea4978b29416def328a707b15e91701a2f7", + "pubkey": "ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5" + } + }, + { + "description": "Hash mismatch between scriptsTree and hash", + "exception": "Hash mismatch", + "options": {}, + "arguments": { + "internalPubkey": "9fa5ffb68821cf559001caa0577eeea4978b29416def328a707b15e91701a2f7", + "scriptsTree": [ + { + "output": "83d8ee77a0f3a32a5cea96fd1624d623b836c1e5d1ac2dcde46814b619320c18 OP_CHECKSIG" + } + ], + "hash": "b76077013c8e303085e300000000000000000000000000000000000000000000" + } + }, + { + "exception": "Expected Point", + "options": {}, + "arguments": { + "internalPubkey": "9fa5ffb68821cf559001caa0577eeea4978b29416def328a707b15e91701a2f8" + } + }, + { + "exception": "Signature mismatch", + "arguments": { + "pubkey": "ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5", + "signature": "a251221c339a7129dd0b769698aca40d8d9da9570ab796a1820b91ab7dbf5acbea21c88ba8f1e9308a21729baf080734beaf97023882d972f75e380d480fd704", + "witness": [ + "607b8b5b5c8614757736e3d5811790636d2a8e2ea14418f8cff66b2e898b3b7536a49b7c4bc8b3227953194bf5d0548e13e3526fdb36beeefadda1ec834a0db2" + ] + } + }, + { + "exception": "Invalid prefix or Network mismatch", + "arguments": { + "address": "bcrt1prhepe49mpmhclwcqmkzpaz43revunykc7fc0f9az6pq08sn4qe7sxtrd8y" + } + }, + { + "exception": "Invalid address version", + "arguments": { + "address": "bc1z4dss6gkgq8003g0qyd5drwfqrztsadf2w2v3juz73gdz7cx82r6s6rxhwd" + } + }, + { + "exception": "Invalid address data", + "arguments": { + "address": "bc1p4dss6gkgq8003g0qyd5drwfqrztsadf2w2v3juz73gdz7cx82qh3d2w3" + } + }, + { + "description": "Control block length too small", + "exception": "The control-block length is too small. Got 16, expected min 33.", + "arguments": { + "witness": [ + "9675a9982c6398ea9d441cb7a943bcd6ff033cc3a2e01a0178a7d3be4575be863871c6bf3eef5ecd34721c784259385ca9101c3a313e010ac942c99de05aaaa602", + "5799cf4b193b730fb99580b186f7477c2cca4d28957326f6f1a5d14116438530e7ec0ce1cd465ad96968ae8a6a09d4d37a060a115919f56fcfebe7b2277cc2df5cc08fb6cda9105ee2512b2e22635aba", + "7520c7b5db9562078049719228db2ac80cb9643ec96c8055aa3b29c2c03d4d99edb0ac", + "c1a7957acbaaf7b444c53d9e0c9436e8" + ] + } + }, + { + "description": "Control block must have a length of 33 + 32m (0 <= m <= 128)", + "exception": "The control-block length of 40 is incorrect!", + "arguments": { + "witness": [ + "9675a9982c6398ea9d441cb7a943bcd6ff033cc3a2e01a0178a7d3be4575be863871c6bf3eef5ecd34721c784259385ca9101c3a313e010ac942c99de05aaaa602", + "5799cf4b193b730fb99580b186f7477c2cca4d28957326f6f1a5d14116438530e7ec0ce1cd465ad96968ae8a6a09d4d37a060a115919f56fcfebe7b2277cc2df5cc08fb6cda9105ee2512b2e22635aba", + "7520c7b5db9562078049719228db2ac80cb9643ec96c8055aa3b29c2c03d4d99edb0ac", + "c1a7957acbaaf7b444c53d9e0c9436e8a8a3247fd515095d66ddf6201918b40a3668f9a4ccdffcf77" + ] + } + }, + { + "description": "Control block length too large", + "exception": "The script path is too long. Got 129, expected max 128.", + "arguments": { + "witness": [ + "9675a9982c6398ea9d441cb7a943bcd6ff033cc3a2e01a0178a7d3be4575be863871c6bf3eef5ecd34721c784259385ca9101c3a313e010ac942c99de05aaaa602", + "5799cf4b193b730fb99580b186f7477c2cca4d28957326f6f1a5d14116438530e7ec0ce1cd465ad96968ae8a6a09d4d37a060a115919f56fcfebe7b2277cc2df5cc08fb6cda9105ee2512b2e22635aba", + "7520c7b5db9562078049719228db2ac80cb9643ec96c8055aa3b29c2c03d4d99edb0ac", + "c1a7957acbaaf7b444c53d9e0c9436e8a8a3247fd515095d66ddf6201918b40a3668f9a4ccdffcf778da624dca2dda0b08e763ec52fd4ad403ec7563a3504d0cc168b9a77a410029e01dac89567c9b2e6cd726e840351df3f2f58fefe976200a19244150d04153909f660184d656ee95fa7bf8e1d4ec83da1fca34f64bc279b76d257ec623e08baba2cfa4ea9e99646e88f1eb1668c00c0f15b7443c8ab83481611cc3ae85eb89a7bfc40067eb1d2e6354a32426d0ce710e88bc4cc0718b99c325509c9d02a6a980d675a8969be10ee9bef82cafee2fc913475667ccda37b1bc7f13f64e56c449c532658ba8481631c02ead979754c809584a875951619cec8fb040c33f06468ae0266cd8693d6a64cea5912be32d8de95a6da6300b0c50fdcd6001ea41126e7b7e5280d455054a816560028f5ca53c9a50ee52f10e15c5337315bad1f5277acb109a1418649dc6ead2fe14699742fee7182f2f15e54279c7d932ed2799d01d73c97e68bbc94d6f7f56ee0a80efd7c76e3169e10d1a1ba3b5f1eb02369dc43af687461c7a2a3344d13eb5485dca29a67f16b4cb988923060fd3b65d0f0352bb634bcc44f2fe668836dcd0f604150049835135dc4b4fbf90fb334b3938a1f137eb32f047c65b85e6c1173b890b6d0162b48b186d1f1af8521945924ac8ac8efec321bf34f1d4b3d4a304a10313052c652d53f6ecb8a55586614e8950cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c50cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c" + ] + } + }, + { + "description": "Invalid internalPubkey in control block", + "exception": "Invalid internalPubkey for p2tr witness", + "arguments": { + "witness": [ + "9675a9982c6398ea9d441cb7a943bcd6ff033cc3a2e01a0178a7d3be4575be863871c6bf3eef5ecd34721c784259385ca9101c3a313e010ac942c99de05aaaa602", + "5799cf4b193b730fb99580b186f7477c2cca4d28957326f6f1a5d14116438530e7ec0ce1cd465ad96968ae8a6a09d4d37a060a115919f56fcfebe7b2277cc2df5cc08fb6cda9105ee2512b2e22635aba", + "7520c7b5db9562078049719228db2ac80cb9643ec96c8055aa3b29c2c03d4d99edb0ac", + "c14444444444444444453d9e0c9436e8a8a3247fd515095d66ddf6201918b40a3668f9a4ccdffcf778da624dca2dda0b08e763ec52fd4ad403ec7563a3504d0cc168b9a77a410029e01dac89567c9b2e6cd726e840351df3f2f58fefe976200a19244150d04153909f660184d656ee95fa7bf8e1d4ec83da1fca34f64bc279b76d257ec623e08baba2cfa4ea9e99646e88f1eb1668c00c0f15b7443c8ab83481611cc3ae85eb89a7bfc40067eb1d2e6354a32426d0ce710e88bc4cc0718b99c325509c9d02a6a980d675a8969be10ee9bef82cafee2fc913475667ccda37b1bc7f13f64e56c449c532658ba8481631c02ead979754c809584a875951619cec8fb040c33f06468ae0266cd8693d6a64cea5912be32d8de95a6da6300b0c50fdcd6001ea41126e7b7e5280d455054a816560028f5ca53c9a50ee52f10e15c5337315bad1f5277acb109a1418649dc6ead2fe14699742fee7182f2f15e54279c7d932ed2799d01d73c97e68bbc94d6f7f56ee0a80efd7c76e3169e10d1a1ba3b5f1eb02369dc43af687461c7a2a3344d13eb5485dca29a67f16b4cb988923060fd3b65d0f0352bb634bcc44f2fe668836dcd0f604150049835135dc4b4fbf90fb334b3938a1f137eb32f047c65b85e6c1173b890b6d0162b48b186d1f1af8521945924ac8ac8efec321bf34f1d4b3d4a304a10313052c652d53f6ecb8a55586614e8950cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c" + ] + } + }, + { + "description": "internalPubkey mismatch between control block and internalKey", + "exception": "Internal pubkey mismatch", + "arguments": { + "internalPubkey": "9fa5ffb68821cf559001caa0577eeea4978b29416def328a707b15e91701a2f7", + "witness": [ + "9675a9982c6398ea9d441cb7a943bcd6ff033cc3a2e01a0178a7d3be4575be863871c6bf3eef5ecd34721c784259385ca9101c3a313e010ac942c99de05aaaa602", + "5799cf4b193b730fb99580b186f7477c2cca4d28957326f6f1a5d14116438530e7ec0ce1cd465ad96968ae8a6a09d4d37a060a115919f56fcfebe7b2277cc2df5cc08fb6cda9105ee2512b2e22635aba", + "7520c7b5db9562078049719228db2ac80cb9643ec96c8055aa3b29c2c03d4d99edb0ac", + "c1a7957acbaaf7b444c53d9e0c9436e8a8a3247fd515095d66ddf6201918b40a3668f9a4ccdffcf778da624dca2dda0b08e763ec52fd4ad403ec7563a3504d0cc168b9a77a410029e01dac89567c9b2e6cd726e840351df3f2f58fefe976200a19244150d04153909f660184d656ee95fa7bf8e1d4ec83da1fca34f64bc279b76d257ec623e08baba2cfa4ea9e99646e88f1eb1668c00c0f15b7443c8ab83481611cc3ae85eb89a7bfc40067eb1d2e6354a32426d0ce710e88bc4cc0718b99c325509c9d02a6a980d675a8969be10ee9bef82cafee2fc913475667ccda37b1bc7f13f64e56c449c532658ba8481631c02ead979754c809584a875951619cec8fb040c33f06468ae0266cd8693d6a64cea5912be32d8de95a6da6300b0c50fdcd6001ea41126e7b7e5280d455054a816560028f5ca53c9a50ee52f10e15c5337315bad1f5277acb109a1418649dc6ead2fe14699742fee7182f2f15e54279c7d932ed2799d01d73c97e68bbc94d6f7f56ee0a80efd7c76e3169e10d1a1ba3b5f1eb02369dc43af687461c7a2a3344d13eb5485dca29a67f16b4cb988923060fd3b65d0f0352bb634bcc44f2fe668836dcd0f604150049835135dc4b4fbf90fb334b3938a1f137eb32f047c65b85e6c1173b890b6d0162b48b186d1f1af8521945924ac8ac8efec321bf34f1d4b3d4a304a10313052c652d53f6ecb8a55586614e8950cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c" + ] + } + }, + { + "description": "pubkey mismatch between outputKey and pubkey", + "exception": "Pubkey mismatch for p2tr witness", + "arguments": { + "pubkey": "df0e070ca2fca05ecd191bdba047841d62414b2bdcb6249c258fd64c0dd251ff", + "witness": [ + "9675a9982c6398ea9d441cb7a943bcd6ff033cc3a2e01a0178a7d3be4575be863871c6bf3eef5ecd34721c784259385ca9101c3a313e010ac942c99de05aaaa602", + "5799cf4b193b730fb99580b186f7477c2cca4d28957326f6f1a5d14116438530e7ec0ce1cd465ad96968ae8a6a09d4d37a060a115919f56fcfebe7b2277cc2df5cc08fb6cda9105ee2512b2e22635aba", + "7520c7b5db9562078049719228db2ac80cb9643ec96c8055aa3b29c2c03d4d99edb0ac", + "c1a7957acbaaf7b444c53d9e0c9436e8a8a3247fd515095d66ddf6201918b40a3668f9a4ccdffcf778da624dca2dda0b08e763ec52fd4ad403ec7563a3504d0cc168b9a77a410029e01dac89567c9b2e6cd726e840351df3f2f58fefe976200a19244150d04153909f660184d656ee95fa7bf8e1d4ec83da1fca34f64bc279b76d257ec623e08baba2cfa4ea9e99646e88f1eb1668c00c0f15b7443c8ab83481611cc3ae85eb89a7bfc40067eb1d2e6354a32426d0ce710e88bc4cc0718b99c325509c9d02a6a980d675a8969be10ee9bef82cafee2fc913475667ccda37b1bc7f13f64e56c449c532658ba8481631c02ead979754c809584a875951619cec8fb040c33f06468ae0266cd8693d6a64cea5912be32d8de95a6da6300b0c50fdcd6001ea41126e7b7e5280d455054a816560028f5ca53c9a50ee52f10e15c5337315bad1f5277acb109a1418649dc6ead2fe14699742fee7182f2f15e54279c7d932ed2799d01d73c97e68bbc94d6f7f56ee0a80efd7c76e3169e10d1a1ba3b5f1eb02369dc43af687461c7a2a3344d13eb5485dca29a67f16b4cb988923060fd3b65d0f0352bb634bcc44f2fe668836dcd0f604150049835135dc4b4fbf90fb334b3938a1f137eb32f047c65b85e6c1173b890b6d0162b48b186d1f1af8521945924ac8ac8efec321bf34f1d4b3d4a304a10313052c652d53f6ecb8a55586614e8950cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c" + ] + } + }, + { + "description": "parity", + "exception": "Incorrect parity", + "arguments": { + "witness": [ + "9675a9982c6398ea9d441cb7a943bcd6ff033cc3a2e01a0178a7d3be4575be863871c6bf3eef5ecd34721c784259385ca9101c3a313e010ac942c99de05aaaa602", + "5799cf4b193b730fb99580b186f7477c2cca4d28957326f6f1a5d14116438530e7ec0ce1cd465ad96968ae8a6a09d4d37a060a115919f56fcfebe7b2277cc2df5cc08fb6cda9105ee2512b2e22635aba", + "7520c7b5db9562078049719228db2ac80cb9643ec96c8055aa3b29c2c03d4d99edb0ac", + "c0a7957acbaaf7b444c53d9e0c9436e8a8a3247fd515095d66ddf6201918b40a3668f9a4ccdffcf778da624dca2dda0b08e763ec52fd4ad403ec7563a3504d0cc168b9a77a410029e01dac89567c9b2e6cd726e840351df3f2f58fefe976200a19244150d04153909f660184d656ee95fa7bf8e1d4ec83da1fca34f64bc279b76d257ec623e08baba2cfa4ea9e99646e88f1eb1668c00c0f15b7443c8ab83481611cc3ae85eb89a7bfc40067eb1d2e6354a32426d0ce710e88bc4cc0718b99c325509c9d02a6a980d675a8969be10ee9bef82cafee2fc913475667ccda37b1bc7f13f64e56c449c532658ba8481631c02ead979754c809584a875951619cec8fb040c33f06468ae0266cd8693d6a64cea5912be32d8de95a6da6300b0c50fdcd6001ea41126e7b7e5280d455054a816560028f5ca53c9a50ee52f10e15c5337315bad1f5277acb109a1418649dc6ead2fe14699742fee7182f2f15e54279c7d932ed2799d01d73c97e68bbc94d6f7f56ee0a80efd7c76e3169e10d1a1ba3b5f1eb02369dc43af687461c7a2a3344d13eb5485dca29a67f16b4cb988923060fd3b65d0f0352bb634bcc44f2fe668836dcd0f604150049835135dc4b4fbf90fb334b3938a1f137eb32f047c65b85e6c1173b890b6d0162b48b186d1f1af8521945924ac8ac8efec321bf34f1d4b3d4a304a10313052c652d53f6ecb8a55586614e8950cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c" + ] + } + } + ], + "dynamic": { + "depends": {}, + "details": [] + } +} \ No newline at end of file diff --git a/test/fixtures/psbt.json b/test/fixtures/psbt.json index 0e51d57cf..b113d75b6 100644 --- a/test/fixtures/psbt.json +++ b/test/fixtures/psbt.json @@ -116,6 +116,10 @@ { "description": "PSBT with unknown types in the inputs.", "psbt": "cHNidP8BAD8CAAAAAf//////////////////////////////////////////AAAAAAD/////AQAAAAAAAAAAA2oBAAAAAAAACg8BAgMEBQYHCAkPAQIDBAUGBwgJCgsMDQ4PAAA=" + }, + { + "description": "PSBT with one P2TR input and one P2TR output.", + "psbt": "cHNidP8BAF4CAAAAAWbQAKi9hNXynJhqPu8bqkvp0kHihVShkWGh3yLy15+LAAAAAAD/////Aej9AAAAAAAAIlEgRvZJfLLxnVDD6emCqVDcyGIUsB/M5DekIGHHvbEjDTMAAAAAAAEBK7gFAQAAAAAAIlEglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4AAA==" } ], "failSignChecks": [ @@ -273,6 +277,25 @@ } ], "result": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA=" + }, + { + "description": "Sign PSBT with 3 inputs [P2PKH, P2TR, P2WPKH] and two outputs [P2TR, P2WPKH]", + "psbt": "cHNidP8BAM8CAAAAAwPzd9k+uLSN1rgF01xY1TIA/8N+YytNZ4VP9gKFP4MyAAAAAAD/////ZtAAqL2E1fKcmGo+7xuqS+nSQeKFVKGRYaHfIvLXn4sAAAAAAP////9+h+SlCwIx1MUDT7Bek0NrWXS7xnSPi5LbYbDc9sxYIgAAAAAA/////wIgKRsAAAAAACJRIEb2SXyy8Z1Qw+npgqlQ3MhiFLAfzOQ3pCBhx72xIw0zuAUBAAAAAAAWABTJijE0v48z5ZmmfEAADXdCBcG0FAAAAAAAAQDiAgAAAAABAUfY2D1t0dyMeEH39C1yOdIxigpqm7XJNqHVT3Lc+FkiAAAAAAD+////AhIsGwAAAAAAGXapFJ5+8XZ3ZP80oFldvEwrcNsBftBmiKyYdK6xAAAAABepFLDBn59UffGbX7u/olyFDG0eG1UJhwJHMEQCIDAd3s05C61flXVFqOtov0NoHRGr8KFcOpH6R/81F46EAiBt+j9hHyvT2hYEyf8fdYsM9IgbnybtPV+kRTHDa6Rj0AEhAmmZfwmoHsmCkEOn9AfRTh+863mURelmE8hSqL4MG1EydJwgAAABASu4BQEAAAAAACJRIJQh5zSw+dLEZ+p90ZfGGstEZ83LyfTLDFcfi2OlxAyuAAEBHxAnAAAAAAAAFgAUT6KsoSi2+d7lMJxPcAUeScZf1zIAAAA=", + "keys": [ + { + "inputToSign": 0, + "WIF": "cRyKzLXVgTReWe7wgfEiXktTa9tf4e5DK1STha274d7BBbnucTaR" + }, + { + "inputToSign": 1, + "WIF": "cNPzVNoVCAfNEadTExqN2HzfC4dX42RtduE39D2i7cxuVEKY3DM3" + }, + { + "inputToSign": 2, + "WIF": "cPPRdCmAMZMjPdHfRmTCmzYVruZHJ8GbM1FqN2W6DnmEPWDg29aL" + } + ], + "result": "cHNidP8BAM8CAAAAAwPzd9k+uLSN1rgF01xY1TIA/8N+YytNZ4VP9gKFP4MyAAAAAAD/////ZtAAqL2E1fKcmGo+7xuqS+nSQeKFVKGRYaHfIvLXn4sAAAAAAP////9+h+SlCwIx1MUDT7Bek0NrWXS7xnSPi5LbYbDc9sxYIgAAAAAA/////wIgKRsAAAAAACJRIEb2SXyy8Z1Qw+npgqlQ3MhiFLAfzOQ3pCBhx72xIw0zuAUBAAAAAAAWABTJijE0v48z5ZmmfEAADXdCBcG0FAAAAAAAAQDiAgAAAAABAUfY2D1t0dyMeEH39C1yOdIxigpqm7XJNqHVT3Lc+FkiAAAAAAD+////AhIsGwAAAAAAGXapFJ5+8XZ3ZP80oFldvEwrcNsBftBmiKyYdK6xAAAAABepFLDBn59UffGbX7u/olyFDG0eG1UJhwJHMEQCIDAd3s05C61flXVFqOtov0NoHRGr8KFcOpH6R/81F46EAiBt+j9hHyvT2hYEyf8fdYsM9IgbnybtPV+kRTHDa6Rj0AEhAmmZfwmoHsmCkEOn9AfRTh+863mURelmE8hSqL4MG1EydJwgACICAi5ovBH1xLoGxPqtFh48wUEpnM+St1SbPzRwO7kBNKOQRzBEAiBpWClBybtHveXkhAgTiE8QSczMJs8MGuH4LOSNRA6s/AIgWlbB3xJOtJIsszj1qZ/whA5jK9wnTzeZzDlVs/ivq2cBAAEBK7gFAQAAAAAAIlEglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4iAgKUIec0sPnSxGfqfdGXxhrLRGfNy8n0ywxXH4tjpcQMrkADaUubfpFFrzbU+vL8qCzZE/FO+9unzylfpIgQZ4HTy2qPUtLvbyH59GApdz0SiUZGl8K6Crvt9YIfI/5FxbOLAAEBHxAnAAAAAAAAFgAUT6KsoSi2+d7lMJxPcAUeScZf1zIiAgOlTqRAWzyTP8WLKjtnrrbWBaYHnPb3MYIMk8qJJSuutEgwRQIhAKAiJLYIS+eYrjAJpM8GCc2/ofqpjXsGV8QMf9Ojm8SEAiBCwrAc/8HdsD5ZyW9uzpbsTJEz5wshwNgvksR4l/xbzwEAAAA=" } ], "combiner": [ @@ -551,6 +574,13 @@ "incorrectPubkey": "Buffer.from('029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e02a', 'hex')", "nonExistantIndex": 42 }, + "validateSignaturesOfTaprootInput": { + "psbt": "cHNidP8BAM8CAAAAAwPzd9k+uLSN1rgF01xY1TIA/8N+YytNZ4VP9gKFP4MyAAAAAAD/////ZtAAqL2E1fKcmGo+7xuqS+nSQeKFVKGRYaHfIvLXn4sAAAAAAP////9+h+SlCwIx1MUDT7Bek0NrWXS7xnSPi5LbYbDc9sxYIgAAAAAA/////wIgKRsAAAAAACJRIEb2SXyy8Z1Qw+npgqlQ3MhiFLAfzOQ3pCBhx72xIw0zuAUBAAAAAAAWABTJijE0v48z5ZmmfEAADXdCBcG0FAAAAAAAAQDiAgAAAAABAUfY2D1t0dyMeEH39C1yOdIxigpqm7XJNqHVT3Lc+FkiAAAAAAD+////AhIsGwAAAAAAGXapFJ5+8XZ3ZP80oFldvEwrcNsBftBmiKyYdK6xAAAAABepFLDBn59UffGbX7u/olyFDG0eG1UJhwJHMEQCIDAd3s05C61flXVFqOtov0NoHRGr8KFcOpH6R/81F46EAiBt+j9hHyvT2hYEyf8fdYsM9IgbnybtPV+kRTHDa6Rj0AEhAmmZfwmoHsmCkEOn9AfRTh+863mURelmE8hSqL4MG1EydJwgAAABASu4BQEAAAAAACJRIJQh5zSw+dLEZ+p90ZfGGstEZ83LyfTLDFcfi2OlxAyuIgIClCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK5AA2lLm36RRa821Pry/Kgs2RPxTvvbp88pX6SIEGeB08tqj1LS728h+fRgKXc9EolGRpfCugq77fWCHyP+RcWziwABAR8QJwAAAAAAABYAFE+irKEotvne5TCcT3AFHknGX9cyAAAA", + "index": 1, + "pubkey": "Buffer.from('029421e734b0f9d2c467ea7dd197c61acb4467cdcbc9f4cb0c571f8b63a5c40cae', 'hex')", + "incorrectPubkey": "Buffer.from('029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e02a', 'hex')", + "nonExistantIndex": 42 + }, "getFeeRate": { "psbt": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgf0cwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMASICAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAQEDBAEAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHIgIDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtxHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwEiAgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc0cwRAIgZfRbpZmLWaJ//hp77QFq8fH5DVSzqo90UKpfVqJRA70CIH9yRwOtHtuWaAsoS1bU/8uI9/t1nqu+CKow8puFE4PSAQEDBAEAAAABBCIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQVHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4iBgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8OcxDZDGpPAAAAgAAAAIADAACAIgYDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwQ2QxqTwAAAIAAAACAAgAAgAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA", "fee": 21 diff --git a/test/payments.spec.ts b/test/payments.spec.ts index bc123cba3..e89834d3b 100644 --- a/test/payments.spec.ts +++ b/test/payments.spec.ts @@ -1,113 +1,125 @@ import * as assert from 'assert'; +import * as ecc from 'tiny-secp256k1'; import { describe, it } from 'mocha'; import { PaymentCreator } from '../src/payments'; import * as u from './payments.utils'; -['embed', 'p2ms', 'p2pk', 'p2pkh', 'p2sh', 'p2wpkh', 'p2wsh'].forEach(p => { - describe(p, () => { - let fn: PaymentCreator; - const payment = require('../src/payments/' + p); - if (p === 'embed') { - fn = payment.p2data; - } else { - fn = payment[p]; - } - const fixtures = require('./fixtures/' + p); +import { TinySecp256k1Interface } from '../src/types'; - fixtures.valid.forEach((f: any) => { - it(f.description + ' as expected', () => { - const args = u.preform(f.arguments); - const actual = fn(args, f.options); - - u.equate(actual, f.expected, f.arguments); - }); - - it(f.description + ' as expected (no validation)', () => { - const args = u.preform(f.arguments); - const actual = fn( - args, - Object.assign({}, f.options, { - validate: false, - }), - ); +['embed', 'p2ms', 'p2pk', 'p2pkh', 'p2sh', 'p2wpkh', 'p2wsh', 'p2tr'].forEach( + p => { + describe(p, () => { + let fn: PaymentCreator; + const eccLib: TinySecp256k1Interface | undefined = + p === 'p2tr' ? ecc : undefined; + const payment = require('../src/payments/' + p); + if (p === 'embed') { + fn = payment.p2data; + } else { + fn = payment[p]; + } - u.equate(actual, f.expected, f.arguments); - }); - }); + const fixtures = require('./fixtures/' + p); - fixtures.invalid.forEach((f: any) => { - it( - 'throws ' + f.exception + (f.description ? 'for ' + f.description : ''), - () => { + fixtures.valid.forEach((f: any) => { + const options = Object.assign({ eccLib }, f.options || {}); + it(f.description + ' as expected', () => { const args = u.preform(f.arguments); + const actual = fn(args, options); - assert.throws(() => { - fn(args, f.options); - }, new RegExp(f.exception)); - }, - ); - }); - - if (p === 'p2sh') { - const p2wsh = require('../src/payments/p2wsh').p2wsh; - const p2pk = require('../src/payments/p2pk').p2pk; - it('properly assembles nested p2wsh with names', () => { - const actual = fn({ - redeem: p2wsh({ - redeem: p2pk({ - pubkey: Buffer.from( - '03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058', - 'hex', - ), - }), - }), + u.equate(actual, f.expected, f.arguments); }); - assert.strictEqual( - actual.address, - '3MGbrbye4ttNUXM8WAvBFRKry4fkS9fjuw', - ); - assert.strictEqual(actual.name, 'p2sh-p2wsh-p2pk'); - assert.strictEqual(actual.redeem!.name, 'p2wsh-p2pk'); - assert.strictEqual(actual.redeem!.redeem!.name, 'p2pk'); - }); - } - // cross-verify dynamically too - if (!fixtures.dynamic) return; - const { depends, details } = fixtures.dynamic; + it(f.description + ' as expected (no validation)', () => { + const args = u.preform(f.arguments); + const actual = fn( + args, + Object.assign({}, options, { + validate: false, + }), + ); - details.forEach((f: any) => { - const detail = u.preform(f); - const disabled: any = {}; - if (f.disabled) - f.disabled.forEach((k: string) => { - disabled[k] = true; + u.equate(actual, f.expected, f.arguments); }); + }); - for (const key in depends) { - if (key in disabled) continue; - const dependencies = depends[key]; + fixtures.invalid.forEach((f: any) => { + const options = Object.assign({ eccLib }, f.options || {}); + it( + 'throws ' + + f.exception + + (f.description ? 'for ' + f.description : ''), + () => { + const args = u.preform(f.arguments); - dependencies.forEach((dependency: any) => { - if (!Array.isArray(dependency)) dependency = [dependency]; + assert.throws(() => { + fn(args, options); + }, new RegExp(f.exception)); + }, + ); + }); - const args = {}; - dependency.forEach((d: any) => { - u.from(d, detail, args); + if (p === 'p2sh') { + const p2wsh = require('../src/payments/p2wsh').p2wsh; + const p2pk = require('../src/payments/p2pk').p2pk; + it('properly assembles nested p2wsh with names', () => { + const actual = fn({ + redeem: p2wsh({ + redeem: p2pk({ + pubkey: Buffer.from( + '03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058', + 'hex', + ), + }), + }), }); - const expected = u.from(key, detail); - - it( - f.description + - ', ' + - key + - ' derives from ' + - JSON.stringify(dependency), - () => { - u.equate(fn(args), expected); - }, + assert.strictEqual( + actual.address, + '3MGbrbye4ttNUXM8WAvBFRKry4fkS9fjuw', ); + assert.strictEqual(actual.name, 'p2sh-p2wsh-p2pk'); + assert.strictEqual(actual.redeem!.name, 'p2wsh-p2pk'); + assert.strictEqual(actual.redeem!.redeem!.name, 'p2pk'); }); } + + // cross-verify dynamically too + if (!fixtures.dynamic) return; + const { depends, details } = fixtures.dynamic; + + details.forEach((f: any) => { + const detail = u.preform(f); + const disabled: any = {}; + if (f.disabled) + f.disabled.forEach((k: string) => { + disabled[k] = true; + }); + + for (const key in depends) { + if (key in disabled) continue; + const dependencies = depends[key]; + + dependencies.forEach((dependency: any) => { + if (!Array.isArray(dependency)) dependency = [dependency]; + + const args = {}; + dependency.forEach((d: any) => { + u.from(d, detail, args); + }); + const expected = u.from(key, detail); + + it( + f.description + + ', ' + + key + + ' derives from ' + + JSON.stringify(dependency), + () => { + u.equate(fn(args), expected); + }, + ); + }); + } + }); }); - }); -}); + }, +); diff --git a/test/payments.utils.ts b/test/payments.utils.ts index c0635f3cf..d4aee8374 100644 --- a/test/payments.utils.ts +++ b/test/payments.utils.ts @@ -86,6 +86,12 @@ export function equate(a: any, b: any, args?: any): void { t.strictEqual(tryHex(a.hash), tryHex(b.hash), 'Inequal *.hash'); if ('pubkey' in b) t.strictEqual(tryHex(a.pubkey), tryHex(b.pubkey), 'Inequal *.pubkey'); + if ('internalPubkey' in b) + t.strictEqual( + tryHex(a.internalPubkey), + tryHex(b.internalPubkey), + 'Inequal *.internalPubkey', + ); if ('signature' in b) t.strictEqual( tryHex(a.signature), @@ -129,6 +135,7 @@ export function preform(x: any): any { if (x.data) x.data = x.data.map(fromHex); if (x.hash) x.hash = Buffer.from(x.hash, 'hex'); if (x.pubkey) x.pubkey = Buffer.from(x.pubkey, 'hex'); + if (x.internalPubkey) x.internalPubkey = Buffer.from(x.internalPubkey, 'hex'); if (x.signature) x.signature = Buffer.from(x.signature, 'hex'); if (x.pubkeys) x.pubkeys = x.pubkeys.map(fromHex); if (x.signatures) @@ -146,7 +153,12 @@ export function preform(x: any): any { if (x.redeem.network) x.redeem.network = (BNETWORKS as any)[x.redeem.network]; } - + if (x.scriptLeaf) { + x.scriptLeaf = Object.assign({}, x.scriptLeaf); + if (typeof x.scriptLeaf.output === 'string') + x.scriptLeaf.output = asmToBuffer(x.scriptLeaf.output); + } + if (x.scriptsTree) x.scriptsTree = convertScriptsTree(x.scriptsTree); return x; } @@ -169,3 +181,13 @@ export function from(path: string, object: any, result?: any): any { return result; } + +// todo: solve any type +function convertScriptsTree(scriptsTree: any): any { + if (Array.isArray(scriptsTree)) return scriptsTree.map(convertScriptsTree); + + const script = Object.assign({}, scriptsTree); + if (typeof script.output === 'string') + script.output = asmToBuffer(scriptsTree.output); + return script; +} diff --git a/test/psbt.spec.ts b/test/psbt.spec.ts index f583e8068..3f4cf93b8 100644 --- a/test/psbt.spec.ts +++ b/test/psbt.spec.ts @@ -18,6 +18,12 @@ const validator = ( signature: Buffer, ): boolean => ECPair.fromPublicKey(pubkey).verify(msghash, signature); +const schnorrValidator = ( + pubkey: Buffer, + msghash: Buffer, + signature: Buffer, +): boolean => ECPair.fromPublicKey(pubkey).verifySchnorr(msghash, signature); + const initBuffers = (object: any): typeof preFixtures => JSON.parse(JSON.stringify(object), (_, value) => { const regex = new RegExp(/^Buffer.from\(['"](.*)['"], ['"](.*)['"]\)$/); @@ -952,6 +958,36 @@ describe(`Psbt`, () => { }); }); + describe('validateSignaturesOfTaprootInput', () => { + const f = fixtures.validateSignaturesOfTaprootInput; + it('Correctly validates a signature', () => { + const psbt = Psbt.fromBase64(f.psbt); + assert.strictEqual( + psbt.validateSignaturesOfInput(f.index, schnorrValidator), + true, + ); + }); + + it('Correctly validates a signature against a pubkey', () => { + const psbt = Psbt.fromBase64(f.psbt); + assert.strictEqual( + psbt.validateSignaturesOfInput( + f.index, + schnorrValidator, + f.pubkey as any, + ), + true, + ); + assert.throws(() => { + psbt.validateSignaturesOfInput( + f.index, + schnorrValidator, + f.incorrectPubkey as any, + ); + }, new RegExp('No signatures for this pubkey')); + }); + }); + describe('getFeeRate', () => { it('Throws error if called before inputs are finalized', () => { const f = fixtures.getFeeRate; @@ -969,6 +1005,35 @@ describe(`Psbt`, () => { }); }); + describe('tweakSigner', () => { + it('Throws error if signer is missing private key', () => { + const keyPair = Object.assign({}, ECPair.makeRandom(), { + privateKey: null, + }); + assert.throws(() => { + Psbt.tweakSigner(keyPair); + }, new RegExp('Private key is required for tweaking signer!')); + }); + + it('Correctly creates tweaked signer', () => { + const keyPair = ECPair.fromPrivateKey( + Buffer.from( + 'accaf12e04e11b08fc28f5fe75b47ea663843b698981e31f1cafa2224d6e28c0', + 'hex', + ), + ); + const tweakedSigner: Signer = Psbt.tweakSigner(keyPair); + assert.strictEqual( + '029421e734b0f9d2c467ea7dd197c61acb4467cdcbc9f4cb0c571f8b63a5c40cae', + tweakedSigner.publicKey.toString('hex'), + ); + assert.strictEqual( + '1853f5034982ec659e015873a0a958a73eac785850f425fd3444b12430d58692', + tweakedSigner.privateKey!.toString('hex'), + ); + }); + }); + describe('create 1-to-1 transaction', () => { const alice = ECPair.fromWIF( 'L2uPYXe17xSTqbCjZvL2DsyXPCbXspvcu5mHLDYUgzdUbZGSKrSr', diff --git a/ts_src/payments/index.ts b/ts_src/payments/index.ts index 4b7f1117e..7bb77b6ac 100644 --- a/ts_src/payments/index.ts +++ b/ts_src/payments/index.ts @@ -1,4 +1,5 @@ import { Network } from '../networks'; +import { TaprootLeaf, TinySecp256k1Interface } from '../types'; import { p2data as embed } from './embed'; import { p2ms } from './p2ms'; import { p2pk } from './p2pk'; @@ -6,6 +7,7 @@ import { p2pkh } from './p2pkh'; import { p2sh } from './p2sh'; import { p2wpkh } from './p2wpkh'; import { p2wsh } from './p2wsh'; +import { p2tr } from './p2tr'; export interface Payment { name?: string; @@ -17,11 +19,14 @@ export interface Payment { pubkeys?: Buffer[]; input?: Buffer; signatures?: Buffer[]; + internalPubkey?: Buffer; pubkey?: Buffer; signature?: Buffer; address?: string; hash?: Buffer; redeem?: Payment; + scriptsTree?: any; // todo: solve + scriptLeaf?: TaprootLeaf; witness?: Buffer[]; } @@ -32,13 +37,14 @@ export type PaymentFunction = () => Payment; export interface PaymentOpts { validate?: boolean; allowIncomplete?: boolean; + eccLib?: TinySecp256k1Interface; } export type StackElement = Buffer | number; export type Stack = StackElement[]; export type StackFunction = () => Stack; -export { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh }; +export { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh, p2tr }; // TODO // witness commitment diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts new file mode 100644 index 000000000..fa6598dc3 --- /dev/null +++ b/ts_src/payments/p2tr.ts @@ -0,0 +1,289 @@ +import { Buffer as NBuffer } from 'buffer'; +import { bitcoin as BITCOIN_NETWORK } from '../networks'; +import * as bscript from '../script'; +import { typeforce as typef, TinySecp256k1Interface } from '../types'; +import { + toHashTree, + rootHashFromPath, + findScriptPath, + tapLeafHash, + tapTweakHash, +} from './taprootutils'; +import { Payment, PaymentOpts } from './index'; +import * as lazy from './lazy'; +import { bech32m } from 'bech32'; +import { testEcc } from './testecc'; + +const OPS = bscript.OPS; +const TAPROOT_VERSION = 0x01; +const ANNEX_PREFIX = 0x50; + +export function p2tr(a: Payment, opts?: PaymentOpts): Payment { + if ( + !a.address && + !a.output && + !a.pubkey && + !a.output && + !a.internalPubkey && + !(a.witness && a.witness.length > 1) + ) + throw new TypeError('Not enough data'); + + opts = Object.assign({ validate: true }, opts || {}); + + const _ecc = lazy.value(() => { + if (!opts!.eccLib) throw new Error('ECC Library is missing for p2tr.'); + + testEcc(opts!.eccLib); + return opts!.eccLib; + }); + + typef( + { + address: typef.maybe(typef.String), + input: typef.maybe(typef.BufferN(0)), + network: typef.maybe(typef.Object), + output: typef.maybe(typef.BufferN(34)), + internalPubkey: typef.maybe(typef.BufferN(32)), + hash: typef.maybe(typef.BufferN(32)), + pubkey: typef.maybe(typef.BufferN(32)), + signature: typef.maybe(typef.BufferN(64)), + witness: typef.maybe(typef.arrayOf(typef.Buffer)), + // scriptsTree: typef.maybe(typef.TaprootNode), // use merkel.isMast ? + scriptLeaf: typef.maybe({ + version: typef.maybe(typef.Number), + output: typef.maybe(typef.Buffer), + }), + }, + a, + ); + + const _address = lazy.value(() => { + const result = bech32m.decode(a.address!); + const version = result.words.shift(); + const data = bech32m.fromWords(result.words); + return { + version, + prefix: result.prefix, + data: NBuffer.from(data), + }; + }); + + const _witness = lazy.value(() => { + if (!a.witness || !a.witness.length) return; + if ( + a.witness.length >= 2 && + a.witness[a.witness.length - 1][0] === ANNEX_PREFIX + ) { + // remove annex, ignored by taproot + return a.witness.slice(0, -1); + } + return a.witness.slice(); + }); + + const network = a.network || BITCOIN_NETWORK; + const o: Payment = { name: 'p2tr', network }; + + lazy.prop(o, 'address', () => { + if (!o.pubkey) return; + + const words = bech32m.toWords(o.pubkey); + words.unshift(TAPROOT_VERSION); + return bech32m.encode(network.bech32, words); + }); + + lazy.prop(o, 'hash', () => { + if (a.hash) return a.hash; + if (a.scriptsTree) return toHashTree(a.scriptsTree).hash; + const w = _witness(); + if (w && w.length > 1) { + const controlBlock = w[w.length - 1]; + const leafVersion = controlBlock[0] & 0b11111110; + const script = w[w.length - 2]; + const leafHash = tapLeafHash(script, leafVersion); + return rootHashFromPath(controlBlock, leafHash); + } + return null; + }); + lazy.prop(o, 'output', () => { + if (!o.pubkey) return; + return bscript.compile([OPS.OP_1, o.pubkey]); + }); + lazy.prop(o, 'scriptLeaf', () => { + if (a.scriptLeaf) return a.scriptLeaf; + }); + lazy.prop(o, 'pubkey', () => { + if (a.pubkey) return a.pubkey; + if (a.output) return a.output.slice(2); + if (a.address) return _address().data; + if (o.internalPubkey) { + const tweakedKey = tweakKey(o.internalPubkey, o.hash, _ecc()); + if (tweakedKey) return tweakedKey.x; + } + }); + lazy.prop(o, 'internalPubkey', () => { + if (a.internalPubkey) return a.internalPubkey; + const witness = _witness(); + if (witness && witness.length > 1) + return witness[witness.length - 1].slice(1, 33); + }); + lazy.prop(o, 'signature', () => { + if (!a.witness || a.witness.length !== 1) return; + return a.witness[0]; + }); + lazy.prop(o, 'input', () => { + // todo + }); + lazy.prop(o, 'witness', () => { + if (a.witness) return a.witness; + if (a.scriptsTree && a.scriptLeaf && a.internalPubkey) { + // todo: optimize/cache + const hashTree = toHashTree(a.scriptsTree); + const leafHash = tapLeafHash(a.scriptLeaf.output, a.scriptLeaf.version); + const path = findScriptPath(hashTree, leafHash); + const outputKey = tweakKey(a.internalPubkey, hashTree.hash, _ecc()); + if (!outputKey) return; + const version = a.scriptLeaf.version || 0xc0; + const controlBock = NBuffer.concat( + [NBuffer.from([version | outputKey.parity]), a.internalPubkey].concat( + path.reverse(), + ), + ); + return [a.scriptLeaf.output, controlBock]; + } + if (a.signature) return [a.signature]; + }); + + // extended validation + if (opts.validate) { + let pubkey: Buffer = NBuffer.from([]); + if (a.address) { + if (network && network.bech32 !== _address().prefix) + throw new TypeError('Invalid prefix or Network mismatch'); + if (_address().version !== TAPROOT_VERSION) + throw new TypeError('Invalid address version'); + if (_address().data.length !== 32) + throw new TypeError('Invalid address data'); + pubkey = _address().data; + } + + if (a.pubkey) { + if (pubkey.length > 0 && !pubkey.equals(a.pubkey)) + throw new TypeError('Pubkey mismatch'); + else pubkey = a.pubkey; + } + + if (a.output) { + if ( + a.output.length !== 34 || + a.output[0] !== OPS.OP_1 || + a.output[1] !== 0x20 + ) + throw new TypeError('Output is invalid'); + if (pubkey.length > 0 && !pubkey.equals(a.output.slice(2))) + throw new TypeError('Pubkey mismatch'); + else pubkey = a.output.slice(2); + } + + if (a.internalPubkey) { + const tweakedKey = tweakKey(a.internalPubkey, o.hash, _ecc()); + if (pubkey.length > 0 && !pubkey.equals(tweakedKey!.x)) + throw new TypeError('Pubkey mismatch'); + else pubkey = tweakedKey!.x; + } + + if (pubkey && pubkey.length) { + if (!_ecc().isXOnlyPoint(pubkey)) + throw new TypeError('Invalid pubkey for p2tr'); + } + + if (a.hash && a.scriptsTree) { + const hash = toHashTree(a.scriptsTree).hash; + if (!a.hash.equals(hash)) throw new TypeError('Hash mismatch'); + } + + const witness = _witness(); + + if (witness && witness.length) { + if (witness.length === 1) { + // key spending + if (a.signature && !a.signature.equals(witness[0])) + throw new TypeError('Signature mismatch'); + // todo: recheck + // if (!bscript.isSchnorSignature(a.pubkey, a.witness[0])) + // throw new TypeError('Witness has invalid signature'); + } else { + // script path spending + const controlBlock = witness[witness.length - 1]; + if (controlBlock.length < 33) + throw new TypeError( + `The control-block length is too small. Got ${ + controlBlock.length + }, expected min 33.`, + ); + + if ((controlBlock.length - 33) % 32 !== 0) + throw new TypeError( + `The control-block length of ${controlBlock.length} is incorrect!`, + ); + + const m = (controlBlock.length - 33) / 32; + if (m > 128) + throw new TypeError( + `The script path is too long. Got ${m}, expected max 128.`, + ); + + const internalPubkey = controlBlock.slice(1, 33); + if (a.internalPubkey && !a.internalPubkey.equals(internalPubkey)) + throw new TypeError('Internal pubkey mismatch'); + + if (!_ecc().isXOnlyPoint(internalPubkey)) + throw new TypeError('Invalid internalPubkey for p2tr witness'); + + const leafVersion = controlBlock[0] & 0b11111110; + const script = witness[witness.length - 2]; + + const leafHash = tapLeafHash(script, leafVersion); + const hash = rootHashFromPath(controlBlock, leafHash); + + const outputKey = tweakKey(internalPubkey, hash, _ecc()); + if (!outputKey) + // todo: needs test data + throw new TypeError('Invalid outputKey for p2tr witness'); + + if (pubkey.length && !pubkey.equals(outputKey.x)) + throw new TypeError('Pubkey mismatch for p2tr witness'); + + if (outputKey.parity !== (controlBlock[0] & 1)) + throw new Error('Incorrect parity'); + } + } + } + + return Object.assign(o, a); +} + +interface TweakedPublicKey { + parity: number; + x: Buffer; +} + +function tweakKey( + pubKey: Buffer, + h: Buffer | undefined, + eccLib: TinySecp256k1Interface, +): TweakedPublicKey | null { + if (!NBuffer.isBuffer(pubKey)) return null; + if (pubKey.length !== 32) return null; + if (h && h.length !== 32) return null; + + const tweakHash = tapTweakHash(pubKey, h); + + const res = eccLib.xOnlyPointAddTweak(pubKey, tweakHash); + if (!res || res.xOnlyPubkey === null) return null; + + return { + parity: res.parity, + x: NBuffer.from(res.xOnlyPubkey), + }; +} diff --git a/ts_src/payments/taprootutils.ts b/ts_src/payments/taprootutils.ts new file mode 100644 index 000000000..83ed9b14c --- /dev/null +++ b/ts_src/payments/taprootutils.ts @@ -0,0 +1,125 @@ +import { Buffer as NBuffer } from 'buffer'; +import * as bcrypto from '../crypto'; + +import { varuint } from '../bufferutils'; +import { TaprootLeaf } from '../types'; + +const LEAF_VERSION_TAPSCRIPT = 0xc0; +const TAP_LEAF_TAG = 'TapLeaf'; +const TAP_BRANCH_TAG = 'TapBranch'; +const TAP_TWEAK_TAG = 'TapTweak'; + +export function rootHashFromPath( + controlBlock: Buffer, + tapLeafMsg: Buffer, +): Buffer { + const k = [tapLeafMsg]; + const e = []; + + const m = (controlBlock.length - 33) / 32; + + for (let j = 0; j < m; j++) { + e[j] = controlBlock.slice(33 + 32 * j, 65 + 32 * j); + if (k[j].compare(e[j]) < 0) { + k[j + 1] = tapBranchHash(k[j], e[j]); + } else { + k[j + 1] = tapBranchHash(e[j], k[j]); + } + } + + return k[m]; +} + +export interface HashTree { + hash: Buffer; + left?: HashTree; + right?: HashTree; +} + +/** + * Build the hash tree from the scripts binary tree. + * The binary tree can be balanced or not. + * @param scriptsTree - is a list representing a binary tree where an element can be: + * - a taproot leaf [(output, version)], or + * - a pair of two taproot leafs [(output, version), (output, version)], or + * - one taproot leaf and a list of elements + */ +export function toHashTree(scriptsTree: TaprootLeaf[]): HashTree { + if (scriptsTree.length === 1) { + const script = scriptsTree[0]; + if (Array.isArray(script)) { + return toHashTree(script); + } + script.version = script.version || LEAF_VERSION_TAPSCRIPT; + if ((script.version & 1) !== 0) + throw new TypeError('Invalid script version'); + + return { + hash: tapLeafHash(script.output, script.version), + }; + } + + const left = toHashTree([scriptsTree[0]]); + const right = toHashTree([scriptsTree[1]]); + + let leftHash = left.hash; + let rightHash = right.hash; + + if (leftHash.compare(rightHash) === 1) + [leftHash, rightHash] = [rightHash, leftHash]; + return { + hash: tapBranchHash(leftHash, rightHash), + left, + right, + }; +} + +/** + * Given a MAST tree, it finds the path of a particular hash. + * @param node - the root of the tree + * @param hash - the hash to search for + * @returns - and array of hashes representing the path, or an empty array if no pat is found + */ +export function findScriptPath(node: HashTree, hash: Buffer): Buffer[] { + if (node.left) { + if (node.left.hash.equals(hash)) return node.right ? [node.right.hash] : []; + const leftPath = findScriptPath(node.left, hash); + if (leftPath.length) + return node.right ? [node.right.hash].concat(leftPath) : leftPath; + } + + if (node.right) { + if (node.right.hash.equals(hash)) return node.left ? [node.left.hash] : []; + const rightPath = findScriptPath(node.right, hash); + if (rightPath.length) + return node.left ? [node.left.hash].concat(rightPath) : rightPath; + } + + return []; +} + +export function tapLeafHash(script: Buffer, version?: number): Buffer { + version = version || LEAF_VERSION_TAPSCRIPT; + return bcrypto.taggedHash( + TAP_LEAF_TAG, + NBuffer.concat([NBuffer.from([version]), serializeScript(script)]), + ); +} + +export function tapTweakHash(pubKey: Buffer, h: Buffer | undefined): Buffer { + return bcrypto.taggedHash( + TAP_TWEAK_TAG, + NBuffer.concat(h ? [pubKey, h] : [pubKey]), + ); +} + +function tapBranchHash(a: Buffer, b: Buffer): Buffer { + return bcrypto.taggedHash(TAP_BRANCH_TAG, NBuffer.concat([a, b])); +} + +function serializeScript(s: Buffer): Buffer { + const varintLen = varuint.encodingLength(s.length); + const buffer = NBuffer.allocUnsafe(varintLen); // better + varuint.encode(s.length, buffer); + return NBuffer.concat([buffer, s]); +} diff --git a/ts_src/payments/testecc.ts b/ts_src/payments/testecc.ts new file mode 100644 index 000000000..382d6149a --- /dev/null +++ b/ts_src/payments/testecc.ts @@ -0,0 +1,74 @@ +import { TinySecp256k1Interface } from '../types'; + +const h = (hex: string): Buffer => Buffer.from(hex, 'hex'); + +export function testEcc(ecc: TinySecp256k1Interface): void { + assert(typeof ecc.isXOnlyPoint === 'function'); + assert( + ecc.isXOnlyPoint( + h('79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798'), + ), + ); + assert( + ecc.isXOnlyPoint( + h('fffffffffffffffffffffffffffffffffffffffffffffffffffffffeeffffc2e'), + ), + ); + assert( + ecc.isXOnlyPoint( + h('f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9'), + ), + ); + assert( + ecc.isXOnlyPoint( + h('0000000000000000000000000000000000000000000000000000000000000001'), + ), + ); + assert( + !ecc.isXOnlyPoint( + h('0000000000000000000000000000000000000000000000000000000000000000'), + ), + ); + assert( + !ecc.isXOnlyPoint( + h('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f'), + ), + ); + + assert(typeof ecc.xOnlyPointAddTweak === 'function'); + tweakAddVectors.forEach(t => { + const r = ecc.xOnlyPointAddTweak(h(t.pubkey), h(t.tweak)); + if (t.result === null) { + assert(r === null); + } else { + assert(r !== null); + assert(r!.parity === t.parity); + assert(Buffer.from(r!.xOnlyPubkey).equals(h(t.result))); + } + }); +} + +function assert(bool: boolean): void { + if (!bool) throw new Error('ecc library invalid'); +} + +const tweakAddVectors = [ + { + pubkey: '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', + tweak: 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140', + parity: -1, + result: null, + }, + { + pubkey: '1617d38ed8d8657da4d4761e8057bc396ea9e4b9d29776d4be096016dbd2509b', + tweak: 'a8397a935f0dfceba6ba9618f6451ef4d80637abf4e6af2669fbc9de6a8fd2ac', + parity: 1, + result: 'e478f99dab91052ab39a33ea35fd5e6e4933f4d28023cd597c9a1f6760346adf', + }, + { + pubkey: '2c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991', + tweak: '823c3cd2142744b075a87eade7e1b8678ba308d566226a0056ca2b7a76f86b47', + parity: 0, + result: '9534f8dc8c6deda2dc007655981c78b49c5d96c778fbf363462a11ec9dfd948c', + }, +]; diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts index b9af10fcf..467d8fc58 100644 --- a/ts_src/psbt.ts +++ b/ts_src/psbt.ts @@ -1,3 +1,6 @@ +import * as ecc from 'tiny-secp256k1'; // TODO: extract +import { ECPairFactory } from 'ecpair'; + import { Psbt as PsbtBase } from 'bip174'; import * as varuint from 'bip174/src/lib/converter/varint'; import { @@ -20,6 +23,7 @@ import { bitcoin as btcNetwork, Network } from './networks'; import * as payments from './payments'; import * as bscript from './script'; import { Output, Transaction } from './transaction'; +import { tapTweakHash } from './payments/taprootutils'; export interface TransactionInput { hash: string | Buffer; @@ -114,6 +118,39 @@ export class Psbt { return psbt; } + /** + * This is a helper method for converting a normal Signer into a Taproot Signer. + * Note that this helper method required for the Private Key of the Signer to be present. + * Steps: + * - if the Y coordinate of the Signer Public Key is odd then negate the Private Key + * - tweak the private key with the provided hash (should be empty for key-path spending) + * @param signer a taproot signer object, the Private Key must be present + * @param opts + * @returns a Signer having the Private and Public keys tweaked + */ + static tweakSigner(signer: Signer, opts: TaprootSignerOpts = {}): Signer { + let privateKey: Uint8Array | undefined = signer.privateKey; + if (!privateKey) { + throw new Error('Private key is required for tweaking signer!'); + } + if (signer.publicKey[0] === 3) { + privateKey = ecc.privateNegate(privateKey!); + } + + const tweakedPrivateKey = ecc.privateAdd( + privateKey, + tapTweakHash(signer.publicKey.slice(1, 33), opts.tweakHash), + ); + if (!tweakedPrivateKey) { + throw new Error('Invalid tweaked private key!'); + } + + const ECPair = ECPairFactory(ecc); + return ECPair.fromPrivateKey(Buffer.from(tweakedPrivateKey), { + network: opts.network, + }); + } + private __CACHE: PsbtCache; private opts: PsbtOpts; @@ -378,7 +415,11 @@ export class Psbt { getInputType(inputIndex: number): AllScriptType { const input = checkForInput(this.data.inputs, inputIndex); - const script = getScriptFromUtxo(inputIndex, input, this.__CACHE); + const { script } = getScriptAndAmountFromUtxo( + inputIndex, + input, + this.__CACHE, + ); const result = getMeaningfulScript( script, inputIndex, @@ -445,13 +486,23 @@ export class Psbt { let hashCache: Buffer; let scriptCache: Buffer; let sighashCache: number; + const scriptType = this.getInputType(inputIndex); + for (const pSig of mySigs) { - const sig = bscript.signature.decode(pSig.signature); + const sig = + scriptType === 'taproot' + ? { + signature: pSig.signature, + hashType: Transaction.SIGHASH_DEFAULT, + } + : bscript.signature.decode(pSig.signature); + const { hash, script } = sighashCache! !== sig.hashType ? getHashForSig( inputIndex, Object.assign({}, input, { sighashType: sig.hashType }), + this.data.inputs, this.__CACHE, true, ) @@ -572,7 +623,6 @@ export class Psbt { ): this { if (!keyPair || !keyPair.publicKey) throw new Error('Need Signer to sign input'); - // TODO: Add a pubkey/pubkeyhash cache to each input // as input information is added, then eventually // optimize this method. @@ -634,6 +684,7 @@ export class Psbt { ): this { if (!keyPair || !keyPair.publicKey) throw new Error('Need Signer to sign input'); + const { hash, sighashType } = getHashAndSighashType( this.data.inputs, inputIndex, @@ -642,14 +693,32 @@ export class Psbt { sighashTypes, ); - const partialSig = [ - { - pubkey: keyPair.publicKey, - signature: bscript.signature.encode(keyPair.sign(hash), sighashType), - }, - ]; + const scriptType = this.getInputType(inputIndex); + + if (scriptType === 'taproot') { + if (!keyPair.signSchnorr) { + throw new Error( + `Need Schnorr Signer to sign taproot input #${inputIndex}.`, + ); + } + const partialSig = [ + { + pubkey: keyPair.publicKey, + signature: keyPair.signSchnorr!(hash), + }, + ]; + // must be changed to use the `updateInput()` public API + this.data.inputs[inputIndex].partialSig = partialSig; + } else { + const partialSig = [ + { + pubkey: keyPair.publicKey, + signature: bscript.signature.encode(keyPair.sign(hash), sighashType), + }, + ]; + this.data.updateInput(inputIndex, { partialSig }); + } - this.data.updateInput(inputIndex, { partialSig }); return this; } @@ -798,6 +867,7 @@ export interface HDSigner extends HDSignerBase { * Return a 64 byte signature (32 byte r and 32 byte s in that order) */ sign(hash: Buffer): Buffer; + signSchnorr?(hash: Buffer): Buffer; } /** @@ -806,19 +876,35 @@ export interface HDSigner extends HDSignerBase { export interface HDSignerAsync extends HDSignerBase { derivePath(path: string): HDSignerAsync; sign(hash: Buffer): Promise; + signSchnorr?(hash: Buffer): Promise; } export interface Signer { publicKey: Buffer; + /** + * Private Key is optional, it is required only if the signer must be tweaked. + * See the `tweakSigner()` method. + */ + privateKey?: Buffer; network?: any; sign(hash: Buffer, lowR?: boolean): Buffer; + signSchnorr?(hash: Buffer): Buffer; getPublicKey?(): Buffer; } +export interface TaprootSignerOpts { + network?: Network; + // TODO: revisit. + eccLib?: any; + /** The hash used to tweak the Signer */ + tweakHash?: Buffer; +} + export interface SignerAsync { publicKey: Buffer; network?: any; sign(hash: Buffer, lowR?: boolean): Promise; + signSchnorr?(hash: Buffer): Promise; getPublicKey?(): Buffer; } @@ -899,6 +985,7 @@ function canFinalize( case 'pubkey': case 'pubkeyhash': case 'witnesspubkeyhash': + case 'taproot': return hasSigs(1, input.partialSig); case 'multisig': const p2ms = payments.p2ms({ output: script }); @@ -939,10 +1026,12 @@ function isFinalized(input: PsbtInput): boolean { return !!input.finalScriptSig || !!input.finalScriptWitness; } -function isPaymentFactory(payment: any): (script: Buffer) => boolean { - return (script: Buffer): boolean => { +function isPaymentFactory( + payment: any, +): (script: Buffer, eccLib?: any) => boolean { + return (script: Buffer, eccLib?: any): boolean => { try { - payment({ output: script }); + payment({ output: script }, { eccLib }); return true; } catch (err) { return false; @@ -955,6 +1044,7 @@ const isP2PKH = isPaymentFactory(payments.p2pkh); const isP2WPKH = isPaymentFactory(payments.p2wpkh); const isP2WSHScript = isPaymentFactory(payments.p2wsh); const isP2SHScript = isPaymentFactory(payments.p2sh); +const isP2TR = isPaymentFactory(payments.p2tr); function bip32DerivationIsMine( root: HDSigner, @@ -1227,6 +1317,7 @@ function getHashAndSighashType( const { hash, sighashType, script } = getHashForSig( inputIndex, input, + inputs, cache, false, sighashTypes, @@ -1241,6 +1332,7 @@ function getHashAndSighashType( function getHashForSig( inputIndex: number, input: PsbtInput, + inputs: PsbtInput[], cache: PsbtCache, forValidate: boolean, sighashTypes?: number[], @@ -1311,6 +1403,19 @@ function getHashForSig( prevout.value, sighashType, ); + } else if (isP2TR(meaningfulScript, ecc)) { + const prevOuts: Output[] = inputs.map((i, index) => + getScriptAndAmountFromUtxo(index, i, cache), + ); + const signingScripts: any = prevOuts.map(o => o.script); + const values: any = prevOuts.map(o => o.value); + + hash = unsignedTx.hashForWitnessV1( + inputIndex, + signingScripts, + values, + Transaction.SIGHASH_DEFAULT, + ); } else { // non-segwit if ( @@ -1379,6 +1484,15 @@ function getPayment( signature: partialSig[0].signature, }); break; + case 'taproot': + payment = payments.p2tr( + { + output: script, + signature: partialSig[0].signature, + }, + { eccLib: ecc }, + ); + break; } return payment!; } @@ -1435,7 +1549,12 @@ function getScriptFromInput( res.script = input.witnessUtxo.script; } } - if (input.witnessScript || isP2WPKH(res.script!)) { + + if ( + input.witnessScript || + isP2WPKH(res.script!) || + isP2TR(res.script!, ecc) + ) { res.isSegwit = true; } return res; @@ -1651,20 +1770,24 @@ function nonWitnessUtxoTxFromCache( return c[inputIndex]; } -function getScriptFromUtxo( +function getScriptAndAmountFromUtxo( inputIndex: number, input: PsbtInput, cache: PsbtCache, -): Buffer { +): { script: Buffer; value: number } { if (input.witnessUtxo !== undefined) { - return input.witnessUtxo.script; + return { + script: input.witnessUtxo.script, + value: input.witnessUtxo.value, + }; } else if (input.nonWitnessUtxo !== undefined) { const nonWitnessUtxoTx = nonWitnessUtxoTxFromCache( cache, input, inputIndex, ); - return nonWitnessUtxoTx.outs[cache.__TX.ins[inputIndex].index].script; + const o = nonWitnessUtxoTx.outs[cache.__TX.ins[inputIndex].index]; + return { script: o.script, value: o.value }; } else { throw new Error("Can't find pubkey in input without Utxo data"); } @@ -1676,7 +1799,7 @@ function pubkeyInInput( inputIndex: number, cache: PsbtCache, ): boolean { - const script = getScriptFromUtxo(inputIndex, input, cache); + const { script } = getScriptAndAmountFromUtxo(inputIndex, input, cache); const { meaningfulScript } = getMeaningfulScript( script, inputIndex, @@ -1810,13 +1933,18 @@ function checkInvalidP2WSH(script: Buffer): void { function pubkeyInScript(pubkey: Buffer, script: Buffer): boolean { const pubkeyHash = hash160(pubkey); + const pubkeyXOnly = pubkey.slice(1, 33); const decompiled = bscript.decompile(script); if (decompiled === null) throw new Error('Unknown script error'); return decompiled.some(element => { if (typeof element === 'number') return false; - return element.equals(pubkey) || element.equals(pubkeyHash); + return ( + element.equals(pubkey) || + element.equals(pubkeyHash) || + element.equals(pubkeyXOnly) + ); }); } @@ -1825,6 +1953,7 @@ type AllScriptType = | 'pubkeyhash' | 'multisig' | 'pubkey' + | 'taproot' | 'nonstandard' | 'p2sh-witnesspubkeyhash' | 'p2sh-pubkeyhash' @@ -1844,12 +1973,14 @@ type ScriptType = | 'pubkeyhash' | 'multisig' | 'pubkey' + | 'taproot' | 'nonstandard'; function classifyScript(script: Buffer): ScriptType { if (isP2WPKH(script)) return 'witnesspubkeyhash'; if (isP2PKH(script)) return 'pubkeyhash'; if (isP2MS(script)) return 'multisig'; if (isP2PK(script)) return 'pubkey'; + if (isP2TR(script, ecc)) return 'taproot'; return 'nonstandard'; } diff --git a/ts_src/types.ts b/ts_src/types.ts index c035b4008..840ab9be2 100644 --- a/ts_src/types.ts +++ b/ts_src/types.ts @@ -1,4 +1,5 @@ import { Buffer as NBuffer } from 'buffer'; + export const typeforce = require('typeforce'); const ZERO32 = NBuffer.alloc(32, 0); @@ -6,6 +7,7 @@ const EC_P = NBuffer.from( 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', 'hex', ); + export function isPoint(p: Buffer | number | undefined | null): boolean { if (!NBuffer.isBuffer(p)) return false; if (p.length < 33) return false; @@ -65,6 +67,23 @@ export const Network = typeforce.compile({ wif: typeforce.UInt8, }); +export interface XOnlyPointAddTweakResult { + parity: 1 | 0; + xOnlyPubkey: Uint8Array; +} + +export interface TaprootLeaf { + output: Buffer; + version?: number; +} +export interface TinySecp256k1Interface { + isXOnlyPoint(p: Uint8Array): boolean; + xOnlyPointAddTweak( + p: Uint8Array, + tweak: Uint8Array, + ): XOnlyPointAddTweakResult | null; +} + export const Buffer256bit = typeforce.BufferN(32); export const Hash160bit = typeforce.BufferN(20); export const Hash256bit = typeforce.BufferN(32);