From bcbf31b5968d127ecd95a23c68896b1f33a23457 Mon Sep 17 00:00:00 2001 From: Soralit Date: Tue, 5 Oct 2021 16:22:39 +0800 Subject: [PATCH] add keystone support --- package-lock.json | 666 +++++++++++++++++++++++++++++++++++++------ package.json | 3 + src/index.js | 33 ++- src/interaction.js | 2 +- src/keystone.js | 520 +++++++++++++++++++++++++++++++++ src/keystone.test.js | 236 +++++++++++++++ 6 files changed, 1371 insertions(+), 89 deletions(-) create mode 100644 src/keystone.js create mode 100644 src/keystone.test.js diff --git a/package-lock.json b/package-lock.json index 3c1ae1d..b42b883 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,11 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@apocentre/alias-sampling": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@apocentre/alias-sampling/-/alias-sampling-0.5.3.tgz", + "integrity": "sha512-7UDWIIF9hIeJqfKXkNIzkVandlwLf1FWTSdrb9iXvOP8oF544JRXQjCbiTmCv2c9n44n/FIWtehhBfNuAx2CZA==" + }, "@babel/cli": { "version": "7.8.4", "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.8.4.tgz", @@ -981,6 +986,21 @@ "minimist": "^1.2.0" } }, + "@cvbb/bc-bech32": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@cvbb/bc-bech32/-/bc-bech32-1.1.15.tgz", + "integrity": "sha512-e80x5VsfUCpXYiheLm/c/lOEegr7ZSd5nq3HlJEcfgljXW5LosH/Kgf21he9Yyr2cBke3NrZM7DuOxvbMpPJHg==" + }, + "@cvbb/bc-ur": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/@cvbb/bc-ur/-/bc-ur-0.2.15.tgz", + "integrity": "sha512-jukQNKCzv1zxUsESeCbVV2Mkxmgz03yVmtgjPpqJ0D1HhNUz8pBt7tmLVOvAO1eeK4Q0083maebxv3r7p2uadA==", + "requires": { + "@cvbb/bc-bech32": "^1.1.15", + "@types/sha.js": "^2.4.0", + "sha.js": "^2.4.11" + } + }, "@jest/console": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", @@ -1196,6 +1216,23 @@ "@types/yargs": "^13.0.0" } }, + "@keystonehq/bc-ur-registry": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@keystonehq/bc-ur-registry/-/bc-ur-registry-0.4.4.tgz", + "integrity": "sha512-SBdKdAZfp3y14GTGrKjfJJHf4iXObjcm4/qKUZ92lj8HVR8mxHHGmHksjE328bJPTAsJPloLix4rTnWg+qgS2w==", + "requires": { + "@ngraveio/bc-ur": "^1.1.5", + "base58check": "^2.0.0", + "tslib": "^2.3.0" + }, + "dependencies": { + "tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + } + } + }, "@ledgerhq/devices": { "version": "5.34.0", "resolved": "https://registry.npmjs.org/@ledgerhq/devices/-/devices-5.34.0.tgz", @@ -1435,6 +1472,27 @@ "resolved": "https://registry.npmjs.org/@ledgerhq/logs/-/logs-5.30.0.tgz", "integrity": "sha512-wUhg2VTfUrWihjdGqKkH/s7TBzdIM1yyd2LiscYsfTX2I0xYDMnpE+NkMReeGU8PN3QhCPgnlg9/P9V6UWoJBA==" }, + "@ngraveio/bc-ur": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@ngraveio/bc-ur/-/bc-ur-1.1.6.tgz", + "integrity": "sha512-G+2XgjXde2IOcEQeCwR250aS43/Swi7gw0FuETgJy2c3HqF8f88SXDMsIGgJlZ8jXd0GeHR4aX0MfjXf523UZg==", + "requires": { + "@apocentre/alias-sampling": "^0.5.3", + "assert": "^2.0.0", + "bignumber.js": "^9.0.1", + "cbor-sync": "^1.0.4", + "crc": "^3.8.0", + "jsbi": "^3.1.5", + "sha.js": "^2.4.11" + }, + "dependencies": { + "bignumber.js": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", + "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==" + } + } + }, "@types/babel__core": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.3.tgz", @@ -1512,6 +1570,14 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz", "integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==" }, + "@types/sha.js": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@types/sha.js/-/sha.js-2.4.0.tgz", + "integrity": "sha512-amxKgPy6WJTKuw8mpUwjX2BSxuBtBmZfRwIUDIuPJKNwGN8CWDli8JTg5ONTWOtcTkHIstvT7oAhhYXqEjStHQ==", + "requires": { + "@types/node": "*" + } + }, "@types/stack-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", @@ -1769,6 +1835,17 @@ "safer-buffer": "~2.1.0" } }, + "assert": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.0.0.tgz", + "integrity": "sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A==", + "requires": { + "es6-object-assign": "^1.1.0", + "is-nan": "^1.2.1", + "object-is": "^1.0.1", + "util": "^0.12.0" + } + }, "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", @@ -1812,6 +1889,11 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" + }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -1999,6 +2081,29 @@ "safe-buffer": "^5.0.1" } }, + "base58check": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base58check/-/base58check-2.0.0.tgz", + "integrity": "sha1-gEZlLRS8h/BjvRa+lKORNNO2EXM=", + "requires": { + "bs58": "^3.0.0" + }, + "dependencies": { + "base-x": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-1.1.0.tgz", + "integrity": "sha1-QtPXF0dPnqAiB/bRqh9CaRPut6w=" + }, + "bs58": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-3.1.0.tgz", + "integrity": "sha1-1MJjiL9IBMrHFBQbGUWqR+XrJI4=", + "requires": { + "base-x": "^1.1.0" + } + } + } + }, "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -2314,6 +2419,15 @@ "unset-value": "^1.0.0" } }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -2350,6 +2464,11 @@ "lodash": "^4.17.14" } }, + "cbor-sync": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cbor-sync/-/cbor-sync-1.0.4.tgz", + "integrity": "sha512-GWlXN4wiz0vdWWXBU71Dvc1q3aBo0HytqwAZnXF1wOwjqNnDWA1vZ1gDMFLlqohak31VQzmhiYfiCX5QSSfagA==" + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -2628,6 +2747,14 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, + "crc": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", + "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", + "requires": { + "buffer": "^5.1.0" + } + }, "create-hash": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", @@ -2766,7 +2893,6 @@ "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, "requires": { "object-keys": "^1.0.12" } @@ -2947,13 +3073,17 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, "requires": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", "is-symbol": "^1.0.2" } }, + "es6-object-assign": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", + "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=" + }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -3545,6 +3675,11 @@ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", "dev": true }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" + }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -3602,28 +3737,28 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "resolved": false, "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "resolved": false, "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true, "optional": true }, "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "resolved": false, "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true, "optional": true }, "are-we-there-yet": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "resolved": false, "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", "dev": true, "optional": true, @@ -3634,14 +3769,14 @@ }, "balanced-match": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "resolved": false, "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true, "optional": true }, "brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "resolved": false, "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "optional": true, @@ -3652,42 +3787,42 @@ }, "chownr": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", + "resolved": false, "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==", "dev": true, "optional": true }, "code-point-at": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "resolved": false, "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true, "optional": true }, "concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "resolved": false, "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true, "optional": true }, "console-control-strings": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "resolved": false, "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "dev": true, "optional": true }, "core-util-is": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "resolved": false, "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true, "optional": true }, "debug": { "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "resolved": false, "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, "optional": true, @@ -3697,28 +3832,28 @@ }, "deep-extend": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "resolved": false, "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true, "optional": true }, "delegates": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "resolved": false, "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true, "optional": true }, "detect-libc": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "resolved": false, "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "dev": true, "optional": true }, "fs-minipass": { "version": "1.2.7", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "resolved": false, "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", "dev": true, "optional": true, @@ -3728,14 +3863,14 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "resolved": false, "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true, "optional": true }, "gauge": { "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "resolved": false, "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, "optional": true, @@ -3752,7 +3887,7 @@ }, "glob": { "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "resolved": false, "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "optional": true, @@ -3767,14 +3902,14 @@ }, "has-unicode": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "resolved": false, "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true, "optional": true }, "iconv-lite": { "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "resolved": false, "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "optional": true, @@ -3784,7 +3919,7 @@ }, "ignore-walk": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", + "resolved": false, "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", "dev": true, "optional": true, @@ -3794,7 +3929,7 @@ }, "inflight": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "resolved": false, "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "optional": true, @@ -3805,21 +3940,21 @@ }, "inherits": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "resolved": false, "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true, "optional": true }, "ini": { "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "resolved": false, "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "resolved": false, "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "optional": true, @@ -3829,14 +3964,14 @@ }, "isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "resolved": false, "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true, "optional": true }, "minimatch": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "resolved": false, "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "optional": true, @@ -3851,7 +3986,7 @@ }, "minipass": { "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "resolved": false, "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", "dev": true, "optional": true, @@ -3862,7 +3997,7 @@ }, "minizlib": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "resolved": false, "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", "dev": true, "optional": true, @@ -3891,14 +4026,14 @@ }, "ms": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "resolved": false, "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true, "optional": true }, "needle": { "version": "2.4.0", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.4.0.tgz", + "resolved": false, "integrity": "sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==", "dev": true, "optional": true, @@ -3910,7 +4045,7 @@ }, "node-pre-gyp": { "version": "0.14.0", - "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz", + "resolved": false, "integrity": "sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA==", "dev": true, "optional": true, @@ -3929,7 +4064,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "resolved": false, "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "dev": true, "optional": true, @@ -3940,7 +4075,7 @@ }, "npm-bundled": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", + "resolved": false, "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", "dev": true, "optional": true, @@ -3950,14 +4085,14 @@ }, "npm-normalize-package-bin": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "resolved": false, "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", "dev": true, "optional": true }, "npm-packlist": { "version": "1.4.7", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.7.tgz", + "resolved": false, "integrity": "sha512-vAj7dIkp5NhieaGZxBJB8fF4R0078rqsmhJcAfXZ6O7JJhjhPK96n5Ry1oZcfLXgfun0GWTZPOxaEyqv8GBykQ==", "dev": true, "optional": true, @@ -3968,7 +4103,7 @@ }, "npmlog": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "resolved": false, "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, "optional": true, @@ -3981,21 +4116,21 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "resolved": false, "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true, "optional": true }, "object-assign": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "resolved": false, "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true, "optional": true }, "once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "resolved": false, "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "optional": true, @@ -4005,21 +4140,21 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "resolved": false, "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "resolved": false, "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true, "optional": true }, "osenv": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "resolved": false, "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "dev": true, "optional": true, @@ -4030,21 +4165,21 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": false, "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true, "optional": true }, "process-nextick-args": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "resolved": false, "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true, "optional": true }, "rc": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "resolved": false, "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, "optional": true, @@ -4066,7 +4201,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": false, "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "optional": true, @@ -4082,7 +4217,7 @@ }, "rimraf": { "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "resolved": false, "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "dev": true, "optional": true, @@ -4092,49 +4227,49 @@ }, "safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "resolved": false, "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, "optional": true }, "safer-buffer": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "resolved": false, "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, "optional": true }, "sax": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "resolved": false, "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true, "optional": true }, "semver": { "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "resolved": false, "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true, "optional": true }, "set-blocking": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "resolved": false, "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true, "optional": true }, "signal-exit": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "resolved": false, "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true, "optional": true }, "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "resolved": false, "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "optional": true, @@ -4146,7 +4281,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": false, "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "optional": true, @@ -4156,7 +4291,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": false, "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "optional": true, @@ -4166,14 +4301,14 @@ }, "strip-json-comments": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "resolved": false, "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true, "optional": true }, "tar": { "version": "4.4.13", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", + "resolved": false, "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", "dev": true, "optional": true, @@ -4189,14 +4324,14 @@ }, "util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "resolved": false, "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true, "optional": true }, "wide-align": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "resolved": false, "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "dev": true, "optional": true, @@ -4206,14 +4341,14 @@ }, "wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "resolved": false, "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true, "optional": true }, "yallist": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "resolved": false, "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true, "optional": true @@ -4223,8 +4358,7 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "functional-red-black-tree": { "version": "1.0.1", @@ -4259,6 +4393,16 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, "get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", @@ -4268,6 +4412,15 @@ "pump": "^3.0.0" } }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -4369,11 +4522,15 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "requires": { "function-bind": "^1.1.1" } }, + "has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==" + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -4383,8 +4540,22 @@ "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 + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "requires": { + "has-symbols": "^1.0.2" + }, + "dependencies": { + "has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" + } + } }, "has-unicode": { "version": "2.0.1", @@ -4688,6 +4859,16 @@ } } }, + "internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "requires": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, "invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", @@ -4716,12 +4897,29 @@ } } }, + "is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "requires": { + "has-bigints": "^1.0.1" + } + }, "is-binary-path": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", @@ -4732,6 +4930,15 @@ "binary-extensions": "^1.0.0" } }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", @@ -4741,8 +4948,7 @@ "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 + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==" }, "is-ci": { "version": "2.0.0", @@ -4776,8 +4982,7 @@ "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 + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" }, "is-descriptor": { "version": "0.1.6", @@ -4824,6 +5029,14 @@ "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "dev": true }, + "is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, "is-glob": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", @@ -4833,6 +5046,20 @@ "is-extglob": "^2.1.1" } }, + "is-nan": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", + "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + } + }, + "is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==" + }, "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", @@ -4853,6 +5080,14 @@ } } }, + "is-number-object": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", + "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -4877,6 +5112,11 @@ "has": "^1.0.3" } }, + "is-shared-array-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", + "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==" + }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", @@ -4886,24 +5126,114 @@ "is-string": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", - "dev": true + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==" }, "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, "requires": { "has-symbols": "^1.0.1" } }, + "is-typed-array": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.8.tgz", + "integrity": "sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA==", + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-abstract": "^1.18.5", + "foreach": "^2.0.5", + "has-tostringtag": "^1.0.0" + }, + "dependencies": { + "es-abstract": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", + "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.1", + "object-inspect": "^1.11.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "object-inspect": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", + "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==" + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + } + } + }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, + "is-weakref": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz", + "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==", + "requires": { + "call-bind": "^1.0.0" + } + }, "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", @@ -5531,6 +5861,11 @@ "xmlcreate": "^2.0.3" } }, + "jsbi": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/jsbi/-/jsbi-3.2.5.tgz", + "integrity": "sha512-aBE4n43IPvjaddScbvWRA2YlTzKEynHzu7MqOyTipdHucf/VxS63ViCjxYRg86M8Rxwbt/GfzHl1kKERkt45fQ==" + }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", @@ -6373,11 +6708,19 @@ "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", "dev": true }, + "object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, "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 + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" }, "object-visit": { "version": "1.0.1", @@ -7208,6 +7551,23 @@ "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", "dev": true }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "dependencies": { + "object-inspect": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", + "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==" + } + } + }, "signal-exit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", @@ -7543,6 +7903,15 @@ "strip-ansi": "^3.0.0" } }, + "string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, "string.prototype.trimleft": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", @@ -7563,6 +7932,15 @@ "function-bind": "^1.1.1" } }, + "string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -8007,6 +8385,24 @@ "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", "dev": true }, + "unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + }, + "dependencies": { + "has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" + } + } + }, "unchained-bitcoin": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/unchained-bitcoin/-/unchained-bitcoin-0.1.3.tgz", @@ -8213,6 +8609,19 @@ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "dev": true }, + "util": { + "version": "0.12.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz", + "integrity": "sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==", + "requires": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "safe-buffer": "^5.1.2", + "which-typed-array": "^1.1.2" + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -8335,6 +8744,18 @@ "isexe": "^2.0.0" } }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, "which-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", @@ -8346,6 +8767,91 @@ "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz", "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=" }, + "which-typed-array": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.7.tgz", + "integrity": "sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw==", + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-abstract": "^1.18.5", + "foreach": "^2.0.5", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.7" + }, + "dependencies": { + "es-abstract": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", + "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.1", + "object-inspect": "^1.11.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "object-inspect": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", + "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==" + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + } + } + }, "wide-align": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", diff --git a/package.json b/package.json index 7927e0e..33655fb 100644 --- a/package.json +++ b/package.json @@ -41,10 +41,13 @@ "bin": {}, "dependencies": { "@babel/polyfill": "^7.7.0", + "@cvbb/bc-ur": "^0.2.9", + "@keystonehq/bc-ur-registry": "^0.4.4", "@ledgerhq/hw-app-btc": "^5.34.1", "@ledgerhq/hw-transport-node-hid": "^5.34.0", "@ledgerhq/hw-transport-u2f": "^5.34.0", "@ledgerhq/hw-transport-webusb": "5.53.0", + "@ngraveio/bc-ur": "^1.1.6", "bignumber.js": "^8.1.1", "bitcoinjs-lib": "^4.0.5", "bowser": "^2.6.1", diff --git a/src/index.js b/src/index.js index dc7d9b0..9f58662 100644 --- a/src/index.js +++ b/src/index.js @@ -33,6 +33,11 @@ import { TrezorSignMultisigTransaction, TrezorConfirmMultisigAddress, } from "./trezor"; +import { + KeystoneExportExtendedPublicKey, + KeystoneSignMultisigTransaction, + KEYSTONE, +} from "./keystone"; /** * Current unchained-wallets version. @@ -66,6 +71,7 @@ export const INDIRECT_KEYSTORES = { HERMIT, COLDCARD, CUSTOM, + KEYSTONE, }; /** @@ -212,11 +218,16 @@ export function ExportExtendedPublicKey({ network, includeXFP, }); + case KEYSTONE: + return new KeystoneExportExtendedPublicKey({ + bip32Path, + network, + includeXFP, + }); default: return new UnsupportedInteraction({ code: "unsupported", - text: - "This keystore is not supported when exporting extended public keys.", + text: "This keystore is not supported when exporting extended public keys.", }); } } @@ -324,11 +335,18 @@ export function SignMultisigTransaction({ outputs, bip32Paths, }); + case KEYSTONE: + return new KeystoneSignMultisigTransaction({ + network, + inputs, + outputs, + bip32Paths, + psbt, + }); default: return new UnsupportedInteraction({ code: "unsupported", - text: - "This keystore is not supported when signing multisig transactions.", + text: "This keystore is not supported when signing multisig transactions.", }); } } @@ -406,8 +424,7 @@ export function ConfirmMultisigAddress({ default: return new UnsupportedInteraction({ code: "unsupported", - text: - "This keystore is not supported when confirming multisig addresses.", + text: "This keystore is not supported when confirming multisig addresses.", }); } } @@ -430,8 +447,7 @@ export function ConfigAdapter({ KEYSTORE, jsonConfig }) { default: return new UnsupportedInteraction({ code: "unsupported", - text: - "This keystore is not supported when translating external spend configuration files.", + text: "This keystore is not supported when translating external spend configuration files.", }); } } @@ -442,3 +458,4 @@ export * from "./custom"; export * from "./hermit"; export * from "./ledger"; export * from "./trezor"; +export * from "./keystone"; diff --git a/src/interaction.js b/src/interaction.js index f90f0bb..d037c9e 100644 --- a/src/interaction.js +++ b/src/interaction.js @@ -143,7 +143,7 @@ export const LEVELS = [INFO, WARNING, ERROR]; * messages.push({state: ACTIVE, level: INFO, text: `Interaction active: ${this.param}` code: "active"}); * return messages; * } - * + * * } * * // usage diff --git a/src/keystone.js b/src/keystone.js new file mode 100644 index 0000000..89cacba --- /dev/null +++ b/src/keystone.js @@ -0,0 +1,520 @@ +/** + * This module provides classes for interacting with Keystone. + * Including reading wallet info QR from Keystone, generating multisig QR + * to Keystone and reading signature QR from Keystone + * + * @module keystone + */ + +import { + deriveChildExtendedPublicKey, + getRelativeBIP32Path, + MAINNET, P2SH, P2SH_P2WSH, P2WSH, + parseSignaturesFromPSBT, TESTNET, + unsignedMultisigPSBT, + validateBIP32Path, +} from "unchained-bitcoin"; +import {Bytes, CryptoAccount, CryptoPSBT} from "@keystonehq/bc-ur-registry"; +import {URDecoder} from "@ngraveio/bc-ur"; + +export const KEYSTONE = "keystone"; + +const KEYSTONE_BIP32_PATHS_BASES = { + [MAINNET]: { + "m/45'": P2SH, + "m/48'/0'/0'/1'": P2SH_P2WSH, + "m/48'/0'/0'/2'": P2WSH, + }, + [TESTNET]: { + "m/45'": P2SH, + "m/48'/1'/0'/1'": P2SH_P2WSH, + "m/48'/1'/0'/2'": P2WSH + } +} + +import { + IndirectKeystoreInteraction, + PENDING, + ACTIVE, + INFO, ERROR, +} from "./interaction"; + +let urDecoder = null; + +/** + * @param {string} qr - UR piece + * @returns {Object} parsed result + * { + * success: boolean, + * result: UR | undefined, + * progress: number, + * } + */ +function smartParseQR(qr) { + if (!qr) { + return { + success: false, + progress: 0, + }; + } + if (!qr.toUpperCase().startsWith("UR")) { + throw new Error("Unknown QR code"); + } + if (urDecoder === null) { + urDecoder = new URDecoder(); + } + urDecoder.receivePart(qr); + if (urDecoder.isSuccess()) { + const result = { + success: true, + result: urDecoder.resultUR(), + progress: urDecoder.getProgress(), + }; + urDecoder = new URDecoder(); + return result; + } + if (urDecoder.isError()) { + urDecoder = new URDecoder(); + throw new Error("Invalid Keystone Wallet QR code, invalid checksum"); + } + return { + success: false, + progress: urDecoder.getProgress(), + }; +} + +function commandMessage(data) { + return { + ...{ + state: PENDING, + level: INFO, + code: "keystone.command", + mode: "wallet", + }, + ...{text: `${data.instructions}`}, + ...data, + }; +} + +/** + * Base class for interactions with Keystone. + * + * @extends {module:interaction.IndirectKeystoreInteraction} + */ +export class KeystoneInteraction extends IndirectKeystoreInteraction { +} + +/** + * Base class for interactions which read a QR code displayed by a + * Keystone command. + * + * @extends {module:keystone.KeystoneInteraction} + */ + +export class KeystoneReader extends KeystoneInteraction { + constructor() { + super(); + this.reader = true; + } + + messages() { + const messages = super.messages(); + messages.push({ + state: ACTIVE, + level: INFO, + code: "keystone.scanning", + text: "Scan Keystone QR code now.", + }); + return messages; + } + + /** + * Parse QR code in UR format + * + * @param {string} qr - the raw response + * @returns { + * {success: boolean, progress: number}| + * {result: Object, success: boolean, progress: number}| + * {success: boolean, progress: number}} the parsed response + * + */ + parse(qr) { + return smartParseQR(qr); + } +} + +export class KeystoneWalletReader extends KeystoneReader { + parse(qr) { + const { + success, + result, + progress, + } = super.parse(qr); + if (!success) { + return { + success: false, + progress + }; + } + if (result.type === "bytes") { + const bytes = Bytes.fromCBOR(result.cbor).getData(); + const jsonStr = bytes.toString('utf-8'); + return { + success: true, + result: jsonStr, + progress + } + } else { + throw new Error("Unknown QR code"); + } + } + +} + +/** + * Base class for interactions which display data as a QR code for + * Keystone to read and then read the QR code Keystone displays in + * response. + * + * @extends {module:keystone.KeystoneInteraction} + */ +export class KeystoneDisplayer extends KeystoneInteraction { + constructor() { + super(); + this.displayer = true; + } +} + +export class KeystonePSBTPlayer extends KeystoneDisplayer { + encode(psbtHex) { + return new CryptoPSBT(Buffer.from(psbtHex, 'hex')).toUREncoder(400); + } +} + +export class KeystoneWalletPlayer extends KeystoneDisplayer { + encode(hex) { + return new Bytes(Buffer.from(hex, 'hex')).toUREncoder(400); + } +} + +/** + * Reads an extended public key from data in a Keystone QR code. + * + * @extends {module:keystone.KeystoneReader} + * @example + * const interaction = new KeystoneExportExtendedPublicKey(); + * const encodedString = readKeystoneQRCode(); // application dependent + * const {xpub, bip32Path} = interaction.parse(encoodedString); + * console.log(xpub); + * // "xpub..." + * console.log(bip32Path); + * // "m/45'/0'/0'" + */ + +export class KeystoneExportExtendedPublicKey extends KeystoneReader { + constructor({ + network, + bip32Path, + includeXFP + }) { + super({ + network, + bip32Path, + includeXFP, + }); + if ([MAINNET, TESTNET].find((net) => net === network)) { + this.network = network; + } else { + throw new Error("Unknown network."); + } + this.bip32Path = bip32Path; + this.includeXFP = includeXFP; + this.bip32ValidationErrorMessage = {}; + this.bip32ValidationError = this.validateBip32Path(); + } + + isSupported() { + return !this.bip32ValidationError.length; + } + + validateBip32Path() { + const bip32PathError = validateBIP32Path(this.bip32Path); + if (bip32PathError.length) { + this.bip32ValidationErrorMessage = { + text: bip32PathError, + code: "keystone.bip32_path.path_error", + }; + return bip32PathError; + } + const pathBase = this.getPathBase(); + if (pathBase) { + if (pathBase === this.bip32Path) { + // asking for known base path, no deeper derivation + return ""; + } + const relativePath = getRelativeBIP32Path(pathBase, this.bip32Path); + const relativePathError = validateBIP32Path(relativePath, { + mode: "unhardened", + }); + if (relativePathError) { + this.bip32ValidationErrorMessage = { + text: relativePathError, + code: "keystone.bip32_path.no_hardened_relative_path_error", + }; + return relativePathError; + } + return ""; + } + const unknownParentBip32PathError = `The bip32Path must begin with one of the known Keystone paths: ${Object.keys(KEYSTONE_BIP32_PATHS_BASES[this.network])}`; + this.bip32ValidationErrorMessage = { + text: unknownParentBip32PathError, + code: "keystone.bip32_path.unknown_path_base_error", + }; + return unknownParentBip32PathError; + } + + getPathBase() { + const pathBases = Object.keys(KEYSTONE_BIP32_PATHS_BASES[this.network]); + let result; + pathBases.forEach(path => { + if (this.bip32Path.startsWith(path)) { + result = path; + } + }) + return result; + } + + + messages() { + const messages = super.messages(); + messages.push( + commandMessage({ + instructions: + "①Please open Keystone, go to Menu > Multisig Wallet > More > Show/Export XPUB.", + }) + ); + messages.push( + commandMessage({ + instructions: + "②Click the camera icon above and scan the QR Code of XPUB displays on Keystone", + }) + ); + if (Object.entries(this.bip32ValidationErrorMessage).length) { + messages.push({ + state: PENDING, + level: ERROR, + code: this.bip32ValidationErrorMessage.code, + text: this.bip32ValidationErrorMessage.text, + }); + } + + return messages; + } + + deriveDeeperXpubIfNecessary(xpub) { + const pathBase = this.getPathBase(); + let relativePath = getRelativeBIP32Path( + pathBase, + this.bip32Path + ); + return relativePath.length + ? deriveChildExtendedPublicKey(xpub, relativePath, this.network) + : xpub; + } + + + parseResult(result) { + const { + xpub, + path: bip32Path, + xfp + } = result; + if (!xpub) { + throw new Error("No Extended PublicKey."); + } + if (!bip32Path) { + throw new Error("No BIP32 path."); + } + if (!this.bip32Path.startsWith(bip32Path)) { + throw new Error(`Got wrong bip32 key, expected key: ${this.getPathBase()}, received key: ${bip32Path}, please check the exported key in you Keystone.`); + } + result.xpub = this.deriveDeeperXpubIfNecessary(xpub); + result.bip32Path = this.bip32Path; + result.rootFingerprint = xfp; + Reflect.deleteProperty(result, "xfp"); + Reflect.deleteProperty(result, "path"); + return { + success: true, + result, + }; + } + + parse(qr) { + const { + success, + result + } = super.parse(qr); + if (!success) { + return { + success: false, + }; + } + if (result.type === "crypto-account") { + const cryptoAccount = CryptoAccount.fromCBOR(result.cbor); + const xfpBuffer = cryptoAccount.getMasterFingerprint(); + if (!xfpBuffer) { + throw new Error( + "Invalid Keystone Wallet QR code, no master fingerprint found" + ); + } + const xfp = xfpBuffer.toString("hex"); + const cryptoOutput = cryptoAccount.getOutputDescriptors()[0]; + if (!cryptoOutput) { + throw new Error( + "Invalid Keystone Wallet QR code, no expected crypto output found" + ); + } + const cryptoHDKey = cryptoOutput.getHDKey(); + if (!cryptoHDKey) { + throw new Error( + "Invalid Keystone Wallet QR code, no expected crypto hd key found" + ); + } + const xpub = cryptoHDKey.getBip32Key(); + const path = `m/${cryptoHDKey.getOrigin().getPath()}`; + return this.parseResult({ + xfp, + path, + xpub + }); + } else { + throw new Error("Unknown QR code"); + } + } + + parseFile(jsonString) { + try { + const result = JSON.parse(jsonString); + return this.parseResult(result); + } catch (e) { + throw new Error(`Unable to parse file, ${e.message}`); + } + } +} + +/** + * Returns signature request data to display in a QR code for Keystone + * and reads the signature data passed back by Keystone in another QR + * code. + * + * NOTE: Transactions with inputs & outputs to non-P2SH addresses are not supported by Keystone. + * + * @extends {module:keystone.KeystoneDisplayer} + * @example + * const interaction = new KeystoneSignMultisigTransaction({inputs, outputs, bip32Paths}); + * console.log(interaction.request()); + * // "IJQXGZI..." + * + * // Display a QR code containing the above data to Keystone running + * // `sign-bitcoin` and it will return another QR code which needs + * // parsed. + * const encodedString = readKeystoneQRCode(); // application dependent + * const signatures = interaction.parse(encoodedString); + * console.log(signatures); + * // ["ababa...01", ... ] + * + */ +export class KeystoneSignMultisigTransaction extends KeystoneReader { + + /** + * + * @param {object} options - options argument + * @param {array} options.inputs - inputs for the transaction + * @param {array} options.outputs - outputs for the transaction + * @param {array} options.bip32Paths - BIP32 paths + */ + constructor({ + network, + inputs, + outputs, + bip32Paths, + psbt + }) { + super(); + this.network = network; + this.inputs = inputs; + this.outputs = outputs; + this.bip32Paths = bip32Paths; + + if (psbt) { + this.psbt = psbt; + } else { + try { + this.psbt = unsignedMultisigPSBT(network, inputs, outputs); + } catch (e) { + throw new Error( + "Unable to build the PSBT from the provided parameters." + ); + } + } + } + + isSupported() { + return true; + } + + messages() { + const messages = super.messages(); + messages.push( + commandMessage({ + instructions: + "Scan this QR code into Keystone and sign the transaction.", + }) + ); + return messages; + } + + request() { + if (typeof this.psbt === "string") { + if (this.psbt.startsWith("70736274")) { + return this.psbt; + } else { + return Buffer.from(this.psbt, "base64").toString("hex"); + } + } + return this.psbt.toHex(); + } + + parse(qr) { + const { + success, + result, + progress, + } = super.parse(qr); + if (!success) { + return { + success, + progress, + }; + } + if (result.type === "crypto-psbt") { + const cryptoPSBT = CryptoPSBT.fromCBOR(result.cbor); + const psbt = cryptoPSBT.getPSBT().toString('hex'); + return { + success, + progress: 100, + result: parseSignaturesFromPSBT(psbt), + } + } else { + throw new Error("Unknown QR code"); + } + } + + parseFile(psbtB64) { + return { + success: true, + result: parseSignaturesFromPSBT(psbtB64), + type: "psbt", + }; + } +} diff --git a/src/keystone.test.js b/src/keystone.test.js new file mode 100644 index 0000000..8f95382 --- /dev/null +++ b/src/keystone.test.js @@ -0,0 +1,236 @@ +import {KeystoneReader, KeystoneExportExtendedPublicKey, KeystoneSignMultisigTransaction} from "./keystone"; +import { + MAINNET, + TEST_FIXTURES, +} from "unchained-bitcoin"; +import {ACTIVE, INFO, PENDING, ERROR} from "./interaction"; +import {CryptoPSBT} from "@keystonehq/bc-ur-registry"; + +describe("KeystoneReader", () => { + function makeInteraction() { + return new KeystoneReader(); + } + + describe("message", () => { + it('should has messages about reader', () => { + const interaction = makeInteraction(); + expect(interaction.hasMessagesFor({ + state: ACTIVE, + level: INFO, + code: "keystone.scanning", + text: "Scan Keystone QR code now.", + })) + }); + }) + + describe("parse", () => { + it('should parse ur', () => { + const interaction = makeInteraction(); + const result = interaction.parse("UR:CRYPTO-ACCOUNT/OEADCYJYLKSWPKAOLYTAADMETAADDLOLAOWKAXHDCLAOBZPKGYIHSTRLLKCHLSRKEEBBBSRDTEUTBGLPMWWDCXNYIDSSHHFXWMLPHGRSFGDNAAHDCXVEVDBKWKSEHEDAFLTAIEHTBWHLSOHKONFDSBAHWKWDVTSSVLDLLFNSMDCYMOGTHDAHTAADEHOEADADAOAEAMTAADDYOTADLOCSDYYKAEYKAEYKAOYKAOCYJYLKSWPKAXAAAYCYTLAHGOCLSEOYAAPE") + expect(result.result.cbor.toString("hex")).toBe("a2011a748cc6aa0281d90191d9012fa602f40358210215aa5165c7b78c1783bb34140fbad3dd128594ea209a62c45c43eb8557bf462b045820e4e70af4c15f2547d9645a135dc959a548cb05f4eae0c4e32f829c951a924d5805d90131a20101020006d90130a301881830f500f500f502f5021a748cc6aa0304081ad5055521"); + }); + }) +}) + +describe('KeystoneExportExtendedPublicKey', () => { + function makeInteraction() { + const network = MAINNET; + const bip32Path = "m/45'"; + const includeXFP = true; + return new KeystoneExportExtendedPublicKey({ + network, + bip32Path, + includeXFP + }); + } + + describe("message", () => { + it('should has messages about export extended public key', () => { + const interaction = makeInteraction(); + expect(interaction.hasMessagesFor({ + state: PENDING, + level: INFO, + code: "keystone.command", + mode: "wallet", + text: "①Please open Keystone, go to Menu > Multisig Wallet > More > Show/Export XPUB.", + })) + expect(interaction.hasMessagesFor({ + state: PENDING, + level: INFO, + code: "keystone.command", + mode: "wallet", + text: "②Click the camera icon above and scan the QR Code of XPUB displays on Keystone", + })) + }); + + it("should has error message if bip32Path is invalid", () => { + const network = MAINNET; + const bip32Path = "m/45'/1'/1'"; + const includeXFP = true; + const interaction = new KeystoneExportExtendedPublicKey({ + network, + bip32Path, + includeXFP + }) + expect(interaction.hasMessagesFor({ + state: PENDING, + level: ERROR, + code: "bip32_path" + })) + }) + }) + + describe('parseResult', () => { + it('should parse wallet', () => { + const interaction = makeInteraction(); + const result = interaction.parseResult({ + xpub: "xpub", + path: "m/45'", + xfp: "xfp" + }); + expect(result).toStrictEqual({ + success: true, + result: { + xpub: "xpub", + bip32Path: "m/45'", + rootFingerprint: "xfp", + } + }) + }); + it('should throw error with invalid wallet info', () => { + const interaction = makeInteraction(); + expect(() => { + interaction.parseResult({ + path: "path", + xfp: "xfp" + }); + }).toThrow(new Error("No Extended PublicKey.")) + expect(() => { + interaction.parseResult({ + xpub: "xpub", + xfp: "xfp" + }); + }).toThrow(new Error("No BIP32 path.")) + expect(() => { + interaction.parseResult({ + xpub: "xpub", + xfp: "xfp", + path: "path" + }); + }).toThrow(new Error("Got wrong bip32 key, expected key: m/45', received key: path, please check the exported key in you Keystone.")) + }); + }); + + describe("parse", () => { + it('should parse wallet qrCode', () => { + const network = MAINNET; + const bip32Path = "m/48'/0'/0'/2'"; + const includeXFP = true; + const interaction = new KeystoneExportExtendedPublicKey({ + network, + bip32Path, + includeXFP + }) + const result = interaction.parse("UR:CRYPTO-ACCOUNT/OEADCYJYLKSWPKAOLYTAADMETAADDLOLAOWKAXHDCLAOBZPKGYIHSTRLLKCHLSRKEEBBBSRDTEUTBGLPMWWDCXNYIDSSHHFXWMLPHGRSFGDNAAHDCXVEVDBKWKSEHEDAFLTAIEHTBWHLSOHKONFDSBAHWKWDVTSSVLDLLFNSMDCYMOGTHDAHTAADEHOEADADAOAEAMTAADDYOTADLOCSDYYKAEYKAEYKAOYKAOCYJYLKSWPKAXAAAYCYTLAHGOCLSEOYAAPE"); + expect(result).toStrictEqual({ + result: { + xpub: "xpub6F6iZVTmc3KMgAUkV9JRNaouxYYwChRswPN1ut7nTfecn6VPRYLXFgXar1gvPUX27QH1zaVECqVEUoA2qMULZu5TjyKrjcWcLTQ6LkhrZAj", + bip32Path: "m/48'/0'/0'/2'", + rootFingerprint: "748cc6aa", + }, + success: true + }) + }); + }) + + describe("parseFile", () => { + it('should parse wallet file', () => { + const interaction = makeInteraction(); + const result = interaction.parseFile(JSON.stringify({ + xpub: "xpub", + path: "m/45'", + xfp: "xfp" + })); + expect(result).toStrictEqual({ + success: true, + result: { + xpub: "xpub", + bip32Path: "m/45'", + rootFingerprint: "xfp", + } + }) + }); + }) +}); + +describe("KeystoneSignMultisigTransaction", () => { + function makeInteraction() { + const fixture = TEST_FIXTURES.transactions[0]; + return new KeystoneSignMultisigTransaction(fixture); + } + + describe("message", () => { + it('should has messages about sign multisig transaction', () => { + const interaction = makeInteraction(); + expect(interaction.hasMessagesFor({ + state: PENDING, + level: INFO, + code: "keystone.command", + mode: "wallet", + text: "Scan this QR code into Keystone and sign the transaction.", + })) + }); + }) + + describe("request", () => { + it('should generate psbt', () => { + const interaction = makeInteraction(); + const psbt = interaction.request(); + expect(psbt).toBe("70736274ff0100c50100000003845266686d5d2473fb09982c72da0d6d66b057c3e13a6eb4bfda304076efe7650100000000ffffffff2a023ec5a05681f4bcb56b9e45884f625a96658e1da16f802e102e31a81a9eae0100000000ffffffff44ae6108a1c6e0eee65edfc7e91b72026263769cb87714a99dd45db8fbc143f20000000000ffffffff02067304000000000017a914e3ba1151b75effbf7adc4673c83c8feec3ddc367876f1d00000000000017a914c34d63a6720866070490a8cb244c6bdc7ce2fa138700000000000100f70200000000010149c912d0e5e46f6ef933038c7fb7e1d665db9ae56b67fa57fe4c3476a95cf954000000001716001400e2f78f987a5a4493cf062994dbde49d040a922feffffff02631418000000000017a914c7ab6d103180a48181847d35732e93e0ce9ab07387a08601000000000017a9148479072d5a550ee0900b5af7e70af575527a879d870247304402202f538752e408b4817e7751ef243eee67d2242ca2061e8e6c9f22873247f10a8d02205b4622314efd733f12fc6557bc2f323ff2cbc1604ad97a351807e1be80875bc8012102e92335f6ecb1862f0eea0b99297f21bdb9beb9a1e8f41113788f5add306ca9fcee9b1800010447522102a8513d9931896d5d3afc8063148db75d8851fd1fc41b1098ba2a6a766db563d42103938dd09bf3dd29ddf41f264858accfa40b330c98e0ed27caf77734fac00139ba52ae220602a8513d9931896d5d3afc8063148db75d8851fd1fc41b1098ba2a6a766db563d418f57ec65d2d00008001000080640000800000000000000000220603938dd09bf3dd29ddf41f264858accfa40b330c98e0ed27caf77734fac00139ba18000000012d00008001000080640000800000000000000000000100f70200000000010101745e1daa28c1705dbf73edd183e5ef91ad0918d97ad3e2ec2c69b548086f4d00000000171600142b0b522ba87db1646898118860449fcb2c69dae3feffffff02329642000000000017a9140f894f7e3b70b8741f830e066b6ef508a9f7479d87a08601000000000017a9148479072d5a550ee0900b5af7e70af575527a879d870247304402202dc887e5d623bd974968285e9c8165cfa9facd943caf0f8472e7acef632fb94302205c60434061e6a4e45360d3b3c901a9c1dd148b38dd6c9623cd8fa2677587e632012102366538692ffb9622e75a05dc2004d85efa0ebc27b99961e694d88f9ede2b57cae49b1800010447522102a8513d9931896d5d3afc8063148db75d8851fd1fc41b1098ba2a6a766db563d42103938dd09bf3dd29ddf41f264858accfa40b330c98e0ed27caf77734fac00139ba52ae220602a8513d9931896d5d3afc8063148db75d8851fd1fc41b1098ba2a6a766db563d418f57ec65d2d00008001000080640000800000000000000000220603938dd09bf3dd29ddf41f264858accfa40b330c98e0ed27caf77734fac00139ba18000000012d00008001000080640000800000000000000000000100f702000000000101e5d6a0ffc5f8387a90c463bf614ae53609b72988c44afc6a577f22666bc971a7000000001716001428386489d15b1cddfd245b506b8ff2d909b18d36feffffff02a08601000000000017a9148479072d5a550ee0900b5af7e70af575527a879d8786ce18050000000017a914d2fb0a8958e55d4c6c3ff58f970fdbba3006ec078702473044022007a7186e6afb93de749b3a905d1c7437f470f97095ea410538b6ac33d15a947802205a66118c7dc2e14d7325a122eb0021f54e1dbd5dfb8fd56b253fa3782716af3d012103f5951ccccf00964d54eefa78280ae083e0f0f0cc6382fd27b3fbfdfeda8dd2c7b29b1800010447522102a8513d9931896d5d3afc8063148db75d8851fd1fc41b1098ba2a6a766db563d42103938dd09bf3dd29ddf41f264858accfa40b330c98e0ed27caf77734fac00139ba52ae220602a8513d9931896d5d3afc8063148db75d8851fd1fc41b1098ba2a6a766db563d418f57ec65d2d00008001000080640000800000000000000000220603938dd09bf3dd29ddf41f264858accfa40b330c98e0ed27caf77734fac00139ba18000000012d0000800100008064000080000000000000000000000100475221021a049747120345fa9017fb42d8ff3d4fb1d2ef4c80546872c5da513babd515852103a00095df48367ed21e5c6edd50af4352311bf060eb100425cb7af4331aa1aad052ae2202021a049747120345fa9017fb42d8ff3d4fb1d2ef4c80546872c5da513babd5158518000000012d00008001000080640000800100000000000000220203a00095df48367ed21e5c6edd50af4352311bf060eb100425cb7af4331aa1aad018f57ec65d2d0000800100008064000080010000000000000000"); + }); + }) + describe("parse", () => { + it('should parse signature from psbt', () => { + const interaction = makeInteraction(); + const signed = TEST_FIXTURES.multisigs[0].psbtPartiallySigned; + const psbt = Buffer.from(signed, 'base64'); + const cryptoPSBT = new CryptoPSBT(psbt); + const ur = cryptoPSBT.toUREncoder(100000).nextPart(); + const result = interaction.parse(ur); + expect(result).toStrictEqual({ + progress: 100, + success: true, + result: + { + '02a8513d9931896d5d3afc8063148db75d8851fd1fc41b1098ba2a6a766db563d4': + [ + '3045022100c82920c7d99e0a4055a8459c53362d15f5f8ce275322be8fd2045b43a5ae7f8d0220478b3856327a4b7809a1f858159bd437e4d93ca480e35bbe21c5cd914b6d722a01', + '304402200464b13a701b9ac16eea29d1604a73d82ba5b3aed1435a8c2c3d4f940a2499ce02206be000a5cc605b284ab6c40039d56d49b7af304fea53079ec9ac838732b8765d01', + '30450221008af4884f2bfbd4565e58c1e7d0f4cb36f8ebc210466d165c48311ddc40df7dc8022017196f4355f66621de0fed97002cfbd6ef7163c882a709f04e5dd0bbe960bcbd01' + ] + }, + } + ) + }); + }) + describe("parse file", () => { + it('should parse signature from psbt file', () => { + const interaction = makeInteraction(); + const result = interaction.parseFile(TEST_FIXTURES.multisigs[0].psbtPartiallySigned); + expect(result).toStrictEqual({ + success: true, + result: + { + '02a8513d9931896d5d3afc8063148db75d8851fd1fc41b1098ba2a6a766db563d4': + [ + '3045022100c82920c7d99e0a4055a8459c53362d15f5f8ce275322be8fd2045b43a5ae7f8d0220478b3856327a4b7809a1f858159bd437e4d93ca480e35bbe21c5cd914b6d722a01', + '304402200464b13a701b9ac16eea29d1604a73d82ba5b3aed1435a8c2c3d4f940a2499ce02206be000a5cc605b284ab6c40039d56d49b7af304fea53079ec9ac838732b8765d01', + '30450221008af4884f2bfbd4565e58c1e7d0f4cb36f8ebc210466d165c48311ddc40df7dc8022017196f4355f66621de0fed97002cfbd6ef7163c882a709f04e5dd0bbe960bcbd01' + ] + }, + type: 'psbt' + } + ) + }); + }) +});