From e79060d19b55908e455ff4a0f2618d85eae9792f Mon Sep 17 00:00:00 2001
From: Oliver Offing <84942996+OliverOffing@users.noreply.github.com>
Date: Fri, 7 Oct 2022 18:01:29 -0300
Subject: [PATCH 001/144] docs(browser): using a different build tool
Explains how one might user browserify just to generate a bundle for this specific library
which allows the developer integrate this library into a project that uses a build tool
different than browserify.
---
README.md | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 9389a73e0..d155581b1 100644
--- a/README.md
+++ b/README.md
@@ -76,8 +76,20 @@ We are not an authorative source of best practice, but, at the very least:
### Browser
-The recommended method of using `bitcoinjs-lib` in your browser is through [Browserify](https://github.com/substack/node-browserify).
-If you're familiar with how to use browserify, ignore this and carry on, otherwise, it is recommended to read the tutorial at https://browserify.org/.
+The recommended method of using `bitcoinjs-lib` in your browser is through [browserify](http://browserify.org/).
+
+If you'd like to use a different (more modern) build tool than `browserify`, you can compile just this library and its dependencies into a single JavaScript file:
+
+```sh
+$ npm install bitcoinjs-lib browserify
+$ npx browserify --standalone bitcoin - -o bitcoinjs-lib.js <<<"module.exports = require('bitcoinjs-lib');"
+```
+
+Which you can then import as an ESM module:
+
+```javascript
+
+````
**NOTE**: We use Node Maintenance LTS features, if you need strict ES5, use [`--transform babelify`](https://github.com/babel/babelify) in conjunction with your `browserify` step (using an [`es2015`](https://babeljs.io/docs/plugins/preset-es2015/) preset).
From 5cf1e437c4e1170f681a1b6f587961a27043fc18 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Thu, 28 Oct 2021 17:53:15 +0300
Subject: [PATCH 002/144] chore: add bn.js to dependencies (previously it was
present in devDependencies)
---
package-lock.json | 21 ++++++++++++++++-----
package.json | 2 +-
2 files changed, 17 insertions(+), 6 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 75ffeaacc..39ffeed33 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -712,10 +712,9 @@
"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
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz",
+ "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw=="
},
"brace-expansion": {
"version": "1.1.11",
@@ -2577,7 +2576,19 @@
"integrity": "sha512-8qPw7zDK6Hco2tVGYGQeOmOPp/hZnREwy2iIkcq0ygAuqc9WHo29vKN94lNymh1QbB3nthtAMF6KTIrdbsIotA==",
"dev": true,
"requires": {
- "uint8array-tools": "0.0.6"
+ "bindings": "^1.3.0",
+ "bn.js": "^4.11.8",
+ "create-hmac": "^1.1.7",
+ "elliptic": "^6.4.0",
+ "nan": "^2.13.2"
+ },
+ "dependencies": {
+ "bn.js": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+ "dev": true
+ }
}
},
"to-fast-properties": {
diff --git a/package.json b/package.json
index dd644a20a..644402307 100644
--- a/package.json
+++ b/package.json
@@ -51,6 +51,7 @@
"dependencies": {
"bech32": "^2.0.0",
"bip174": "^2.0.1",
+ "bn.js": "^5.2.0",
"bs58check": "^2.1.2",
"create-hash": "^1.1.0",
"ripemd160": "^2.0.2",
@@ -73,7 +74,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",
From 083c8c134f7e0ef98a3902910980a92b575e8dd1 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Thu, 28 Oct 2021 17:55:41 +0300
Subject: [PATCH 003/144] feat: add liftX() function (first version)
---
ts_src/types.ts | 41 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)
diff --git a/ts_src/types.ts b/ts_src/types.ts
index c035b4008..d4b37cc66 100644
--- a/ts_src/types.ts
+++ b/ts_src/types.ts
@@ -1,4 +1,7 @@
import { Buffer as NBuffer } from 'buffer';
+// todo, use import?
+const BN = require('bn.js');
+
export const typeforce = require('typeforce');
const ZERO32 = NBuffer.alloc(32, 0);
@@ -6,6 +9,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;
@@ -25,6 +29,43 @@ export function isPoint(p: Buffer | number | undefined | null): boolean {
return false;
}
+// todo review. Do not add dependcy to BN?
+const EC_P_BN = new BN(EC_P)
+const EC_P_REDUCTION = BN.red(EC_P_BN);
+const EC_P_QUADRATIC_RESIDUE = EC_P_BN.addn(1).divn(4);
+const BN_2 = new BN(2);
+const BN_3 = new BN(3);
+const BN_7 = new BN(7);
+
+export function liftX(buffer: Buffer): Buffer | null {
+ if (!NBuffer.isBuffer(buffer)) return null;
+ if (buffer.length !== 32) return null;
+
+ if (buffer.compare(ZERO32) === 0) return null;
+ if (buffer.compare(EC_P) >= 0) return null;
+
+ const x = new BN(buffer);
+
+ const x1 = x.toRed(EC_P_REDUCTION);
+ const ySq = x1
+ .redPow(BN_3)
+ .add(BN_7)
+ .mod(EC_P_BN);
+
+ const y = ySq.redPow(EC_P_QUADRATIC_RESIDUE);
+
+ if (!ySq.eq(y.redPow(BN_2))) {
+ return null;
+ }
+ const y1 = y.isEven() ? y : EC_P_BN.sub(y);
+
+ return NBuffer.concat([
+ NBuffer.from([0x04]),
+ NBuffer.from(x1.toBuffer('be', 32)),
+ NBuffer.from(y1.toBuffer('be', 32)),
+ ]);
+}
+
const UINT31_MAX: number = Math.pow(2, 31) - 1;
export function UInt31(value: number): boolean {
return typeforce.UInt32(value) && value <= UINT31_MAX;
From ef8a4c8b98ff970922279fa9a5905df2dca01b15 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Thu, 28 Oct 2021 17:57:14 +0300
Subject: [PATCH 004/144] feat: update the Payment interface with taproot
specific fields
- add `internalPubkey` and `redeems` fields
- add some temp comments
---
ts_src/payments/index.ts | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/ts_src/payments/index.ts b/ts_src/payments/index.ts
index 4b7f1117e..d42649b3f 100644
--- a/ts_src/payments/index.ts
+++ b/ts_src/payments/index.ts
@@ -10,18 +10,20 @@ import { p2wsh } from './p2wsh';
export interface Payment {
name?: string;
network?: Network;
- output?: Buffer;
+ output?: Buffer; // the full scriptPubKey
data?: Buffer[];
m?: number;
n?: number;
pubkeys?: Buffer[];
input?: Buffer;
signatures?: Buffer[];
- pubkey?: Buffer;
+ internalPubkey?: Buffer; // taproot: output key
+ pubkey?: Buffer; // taproot: output key
signature?: Buffer;
- address?: string;
- hash?: Buffer;
- redeem?: Payment;
+ address?: string; // taproot: betch32m
+ hash?: Buffer; // taproot: MAST root
+ redeem?: Payment; // taproot: when script path spending is used spending
+ redeems?: Payment; // taproot can have more than one redeem script
witness?: Buffer[];
}
From 93185d460a4663cfd9b4ad16ae19694b4c4d753e Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Thu, 28 Oct 2021 18:02:59 +0300
Subject: [PATCH 005/144] feat: add first version of p2tr; basic logic for key
path construct/spend
---
ts_src/payments/p2tr.ts | 134 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 134 insertions(+)
create mode 100644 ts_src/payments/p2tr.ts
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
new file mode 100644
index 000000000..439834247
--- /dev/null
+++ b/ts_src/payments/p2tr.ts
@@ -0,0 +1,134 @@
+// import * as bcrypto from '../../crypto';
+import { bitcoin as BITCOIN_NETWORK } from '../networks';
+import * as bscript from '../script';
+import { liftX, typeforce as typef } from '../types';
+import { Payment, PaymentOpts } from './index';
+import * as lazy from './lazy';
+import { bech32m } from 'bech32';
+const OPS = bscript.OPS;
+
+const TAPROOT_VERSION = 0x01;
+
+// witness: {signature}
+// input: <>
+// output: OP_1 {pubKey}
+export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
+ if (!a.address && !a.output && !a.pubkey && !a.output)
+ throw new TypeError('Not enough data');
+ opts = Object.assign({ validate: true }, opts || {});
+
+ typef(
+ {
+ // todo: revisit
+ address: typef.maybe(typef.String),
+ hash: typef.maybe(typef.BufferN(20)),
+ input: typef.maybe(typef.BufferN(0)),
+ network: typef.maybe(typef.Object),
+ output: typef.maybe(typef.BufferN(34)),
+ pubkey: typef.maybe(typef.BufferN(32)),
+ signature: typef.maybe(bscript.isCanonicalScriptSignature),
+ witness: typef.maybe(typef.arrayOf(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: Buffer.from(data),
+ };
+ });
+
+ // todo: clean-up withness (annex), etc
+
+ 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', () => {
+ // compute from MAST
+ });
+ lazy.prop(o, 'output', () => {
+ if (!o.pubkey) return;
+ return bscript.compile([OPS.OP_1, o.pubkey]);
+ });
+ lazy.prop(o, 'pubkey', () => {
+ if (a.pubkey) return a.pubkey;
+ if (a.output) return a.output.slice(2)
+ if (!a.address) return;
+ return _address().data;
+ });
+ lazy.prop(o, 'signature', () => {
+ if (a.witness?.length !== 1) return;
+ return a.witness[0];
+ });
+ lazy.prop(o, 'input', () => {
+ // todo: not sure
+ });
+ lazy.prop(o, 'witness', () => {
+ if (!a.signature) return;
+ return [a.signature];
+ });
+
+ // extended validation
+ if (opts.validate) {
+ let pubkey: Buffer = 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 (pubkey) {
+ if (liftX(pubkey) === null)
+ throw new TypeError('Invalid pubkey for p2tr');
+ }
+
+ if (a.witness) {
+ if (a.witness.length !== 1) throw new TypeError('Witness is invalid');
+
+ // todo: recheck
+ // if (!bscript.isCanonicalScriptSignature(a.witness[0]))
+ // throw new TypeError('Witness has invalid signature');
+
+ if (a.signature && !a.signature.equals(a.witness[0]))
+ throw new TypeError('Signature mismatch');
+ }
+ }
+
+ return Object.assign(o, a);
+}
From d1e35e473789932d6fa9817ab5722fb1b95052dd Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Thu, 28 Oct 2021 18:04:54 +0300
Subject: [PATCH 006/144] test: add first tests for p2tr
---
test/fixtures/p2tr.json | 169 ++++++++++++++++++++++++++++++++++++++++
test/payments.spec.ts | 2 +-
2 files changed, 170 insertions(+), 1 deletion(-)
create mode 100644 test/fixtures/p2tr.json
diff --git a/test/fixtures/p2tr.json b/test/fixtures/p2tr.json
new file mode 100644
index 000000000..02cb6abfc
--- /dev/null
+++ b/test/fixtures/p2tr.json
@@ -0,0 +1,169 @@
+{
+ "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": "300602010002010001"
+ },
+ "expected": {
+ "name": "p2tr",
+ "address": "bc1p4dss6gkgq8003g0qyd5drwfqrztsadf2w2v3juz73gdz7cx82r6sj7lcqx",
+ "output": "OP_1 ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5",
+ "input": null,
+ "witness": [
+ "300602010002010001"
+ ]
+ }
+ }
+ ],
+ "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"
+ }
+ },
+ {
+ "exception": "Signature mismatch",
+ "arguments": {
+ "pubkey": "ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5",
+ "signature": "300602010002010002",
+ "witness": [
+ "300602010002010001"
+ ]
+ }
+ },
+ {
+ "exception": "Invalid prefix or Network mismatch",
+ "arguments": {
+ "address": "bcrt1prhepe49mpmhclwcqmkzpaz43revunykc7fc0f9az6pq08sn4qe7sxtrd8y"
+ }
+ },
+ {
+ "exception": "Invalid address version",
+ "arguments": {
+ "address": "bc1z4dss6gkgq8003g0qyd5drwfqrztsadf2w2v3juz73gdz7cx82r6s6rxhwd"
+ }
+ },
+ {
+ "exception": "Invalid address data",
+ "arguments": {
+ "address": "bc1p4dss6gkgq8003g0qyd5drwfqrztsadf2w2v3juz73gdz7cx82qh3d2w3"
+ }
+ },
+ {
+ "exception": "Witness is invalid",
+ "arguments": {
+ "address": "bc1p4dss6gkgq8003g0qyd5drwfqrztsadf2w2v3juz73gdz7cx82r6sj7lcqx",
+ "witness": []
+ }
+ }
+ ],
+ "dynamic": {
+ "depends": {},
+ "details": []
+ }
+}
\ No newline at end of file
diff --git a/test/payments.spec.ts b/test/payments.spec.ts
index bc123cba3..9e28501ae 100644
--- a/test/payments.spec.ts
+++ b/test/payments.spec.ts
@@ -2,7 +2,7 @@ import * as assert from 'assert';
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 => {
+['embed', 'p2ms', 'p2pk', 'p2pkh', 'p2sh', 'p2wpkh', 'p2wsh', 'p2tr'].forEach(p => {
describe(p, () => {
let fn: PaymentCreator;
const payment = require('../src/payments/' + p);
From f39812cc21a754e995974c289527c9d7c8b0ccea Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Thu, 28 Oct 2021 18:08:20 +0300
Subject: [PATCH 007/144] feat: add generated files
---
src/payments/index.d.ts | 2 +
src/payments/p2tr.d.ts | 2 +
src/payments/p2tr.js | 121 ++++++++++++++++++++++++++++++++++++++++
src/types.d.ts | 1 +
src/types.js | 34 ++++++++++-
5 files changed, 159 insertions(+), 1 deletion(-)
create mode 100644 src/payments/p2tr.d.ts
create mode 100644 src/payments/p2tr.js
diff --git a/src/payments/index.d.ts b/src/payments/index.d.ts
index 1edf07167..e569aa3cf 100644
--- a/src/payments/index.d.ts
+++ b/src/payments/index.d.ts
@@ -17,11 +17,13 @@ export interface Payment {
pubkeys?: Buffer[];
input?: Buffer;
signatures?: Buffer[];
+ internalPubkey?: Buffer;
pubkey?: Buffer;
signature?: Buffer;
address?: string;
hash?: Buffer;
redeem?: Payment;
+ redeems?: Payment;
witness?: Buffer[];
}
export declare type PaymentCreator = (a: Payment, opts?: PaymentOpts) => Payment;
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..2c3a0c71b
--- /dev/null
+++ b/src/payments/p2tr.js
@@ -0,0 +1,121 @@
+'use strict';
+Object.defineProperty(exports, '__esModule', { value: true });
+exports.p2tr = void 0;
+// import * as bcrypto from '../../crypto';
+const networks_1 = require('../networks');
+const bscript = require('../script');
+const types_1 = require('../types');
+const lazy = require('./lazy');
+const bech32_1 = require('bech32');
+const OPS = bscript.OPS;
+const TAPROOT_VERSION = 0x01;
+// witness: {signature}
+// input: <>
+// output: OP_1 {pubKey}
+function p2tr(a, opts) {
+ if (!a.address && !a.output && !a.pubkey && !a.output)
+ throw new TypeError('Not enough data');
+ opts = Object.assign({ validate: true }, opts || {});
+ (0, types_1.typeforce)(
+ {
+ // todo: revisit
+ address: types_1.typeforce.maybe(types_1.typeforce.String),
+ hash: types_1.typeforce.maybe(types_1.typeforce.BufferN(20)),
+ 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)),
+ pubkey: types_1.typeforce.maybe(types_1.typeforce.BufferN(32)),
+ signature: types_1.typeforce.maybe(bscript.isCanonicalScriptSignature),
+ witness: types_1.typeforce.maybe(
+ types_1.typeforce.arrayOf(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.from(data),
+ };
+ });
+ // todo: clean-up withness (annex), etc
+ 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', () => {
+ // compute from MAST
+ });
+ lazy.prop(o, 'output', () => {
+ if (!o.pubkey) return;
+ return bscript.compile([OPS.OP_1, o.pubkey]);
+ });
+ lazy.prop(o, 'pubkey', () => {
+ if (a.pubkey) return a.pubkey;
+ if (a.output) return a.output.slice(2);
+ if (!a.address) return;
+ return _address().data;
+ });
+ lazy.prop(o, 'signature', () => {
+ if (a.witness?.length !== 1) return;
+ return a.witness[0];
+ });
+ lazy.prop(o, 'input', () => {
+ // todo: not sure
+ });
+ lazy.prop(o, 'witness', () => {
+ if (!a.signature) return;
+ return [a.signature];
+ });
+ // extended validation
+ if (opts.validate) {
+ let pubkey = 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 (pubkey) {
+ if ((0, types_1.liftX)(pubkey) === null)
+ throw new TypeError('Invalid pubkey for p2tr');
+ }
+ if (a.witness) {
+ if (a.witness.length !== 1) throw new TypeError('Witness is invalid');
+ // todo: recheck
+ // if (!bscript.isCanonicalScriptSignature(a.witness[0]))
+ // throw new TypeError('Witness has invalid signature');
+ if (a.signature && !a.signature.equals(a.witness[0]))
+ throw new TypeError('Signature mismatch');
+ }
+ }
+ return Object.assign(o, a);
+}
+exports.p2tr = p2tr;
diff --git a/src/types.d.ts b/src/types.d.ts
index 5a8505d34..0fe6419f8 100644
--- a/src/types.d.ts
+++ b/src/types.d.ts
@@ -1,6 +1,7 @@
///
export declare const typeforce: any;
export declare function isPoint(p: Buffer | number | undefined | null): boolean;
+export declare function liftX(buffer: Buffer): Buffer | null;
export declare function UInt31(value: number): boolean;
export declare function BIP32Path(value: string): boolean;
export declare namespace BIP32Path {
diff --git a/src/types.js b/src/types.js
index a6d1efa16..a7a89b0d2 100644
--- a/src/types.js
+++ b/src/types.js
@@ -1,7 +1,9 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.oneOf = exports.Null = exports.BufferN = exports.Function = exports.UInt32 = exports.UInt8 = exports.tuple = exports.maybe = exports.Hex = exports.Buffer = exports.String = exports.Boolean = exports.Array = exports.Number = exports.Hash256bit = exports.Hash160bit = exports.Buffer256bit = exports.Network = exports.ECPoint = exports.Satoshi = exports.Signer = exports.BIP32Path = exports.UInt31 = exports.isPoint = exports.typeforce = void 0;
+exports.oneOf = exports.Null = exports.BufferN = exports.Function = exports.UInt32 = exports.UInt8 = exports.tuple = exports.maybe = exports.Hex = exports.Buffer = exports.String = exports.Boolean = exports.Array = exports.Number = exports.Hash256bit = exports.Hash160bit = exports.Buffer256bit = exports.Network = exports.ECPoint = exports.Satoshi = exports.Signer = exports.BIP32Path = exports.UInt31 = exports.liftX = exports.isPoint = exports.typeforce = void 0;
const buffer_1 = require('buffer');
+// todo, use import?
+const BN = require('bn.js');
exports.typeforce = require('typeforce');
const ZERO32 = buffer_1.Buffer.alloc(32, 0);
const EC_P = buffer_1.Buffer.from(
@@ -25,6 +27,36 @@ function isPoint(p) {
return false;
}
exports.isPoint = isPoint;
+// todo review. Do not add dependcy to BN?
+const EC_P_BN = new BN(EC_P);
+const EC_P_REDUCTION = BN.red(EC_P_BN);
+const EC_P_QUADRATIC_RESIDUE = EC_P_BN.addn(1).divn(4);
+const BN_2 = new BN(2);
+const BN_3 = new BN(3);
+const BN_7 = new BN(7);
+function liftX(buffer) {
+ if (!buffer_1.Buffer.isBuffer(buffer)) return null;
+ if (buffer.length !== 32) return null;
+ if (buffer.compare(ZERO32) === 0) return null;
+ if (buffer.compare(EC_P) >= 0) return null;
+ const x = new BN(buffer);
+ const x1 = x.toRed(EC_P_REDUCTION);
+ const ySq = x1
+ .redPow(BN_3)
+ .add(BN_7)
+ .mod(EC_P_BN);
+ const y = ySq.redPow(EC_P_QUADRATIC_RESIDUE);
+ if (!ySq.eq(y.redPow(BN_2))) {
+ return null;
+ }
+ const y1 = y.isEven() ? y : EC_P_BN.sub(y);
+ return buffer_1.Buffer.concat([
+ buffer_1.Buffer.from([0x04]),
+ buffer_1.Buffer.from(x1.toBuffer('be', 32)),
+ buffer_1.Buffer.from(y1.toBuffer('be', 32)),
+ ]);
+}
+exports.liftX = liftX;
const UINT31_MAX = Math.pow(2, 31) - 1;
function UInt31(value) {
return exports.typeforce.UInt32(value) && value <= UINT31_MAX;
From 2a2b403dd0b77f7f62025554a789e565f0595a2b Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Fri, 29 Oct 2021 14:21:58 +0300
Subject: [PATCH 008/144] feat: compute "taproot output key" when "taoroot
internal key" is known and script path is not used
---
src/payments/p2tr.js | 30 +++++++++++++++++-------
src/types.d.ts | 5 ++++
src/types.js | 38 +++++++++++++++++++++++++++++-
test/fixtures/p2tr.json | 24 +++++++++++++++++++
test/payments.utils.ts | 1 +
ts_src/payments/p2tr.ts | 32 ++++++++++++++++++--------
ts_src/types.ts | 51 ++++++++++++++++++++++++++++++++++++++++-
7 files changed, 162 insertions(+), 19 deletions(-)
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index 2c3a0c71b..cde6d705a 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -1,7 +1,6 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
exports.p2tr = void 0;
-// import * as bcrypto from '../../crypto';
const networks_1 = require('../networks');
const bscript = require('../script');
const types_1 = require('../types');
@@ -13,17 +12,17 @@ const TAPROOT_VERSION = 0x01;
// input: <>
// output: OP_1 {pubKey}
function p2tr(a, opts) {
- if (!a.address && !a.output && !a.pubkey && !a.output)
+ if (!a.address && !a.output && !a.pubkey && !a.output && !a.internalPubkey)
throw new TypeError('Not enough data');
opts = Object.assign({ validate: true }, opts || {});
(0, types_1.typeforce)(
{
- // todo: revisit
address: types_1.typeforce.maybe(types_1.typeforce.String),
- hash: types_1.typeforce.maybe(types_1.typeforce.BufferN(20)),
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(bscript.isCanonicalScriptSignature),
witness: types_1.typeforce.maybe(
@@ -52,7 +51,9 @@ function p2tr(a, opts) {
return bech32_1.bech32m.encode(network.bech32, words);
});
lazy.prop(o, 'hash', () => {
- // compute from MAST
+ if (a.hash) return a.hash;
+ // todo: if (a.redeems?.length) compute from MAST root from redeems
+ return null;
});
lazy.prop(o, 'output', () => {
if (!o.pubkey) return;
@@ -61,8 +62,12 @@ function p2tr(a, opts) {
lazy.prop(o, 'pubkey', () => {
if (a.pubkey) return a.pubkey;
if (a.output) return a.output.slice(2);
- if (!a.address) return;
- return _address().data;
+ if (a.address) return _address().data;
+ if (a.internalPubkey) {
+ const tweakedKey = (0, types_1.tweakPublicKey)(a.internalPubkey, o.hash);
+ if (tweakedKey) return tweakedKey.x;
+ }
+ return null;
});
lazy.prop(o, 'signature', () => {
if (a.witness?.length !== 1) return;
@@ -103,7 +108,16 @@ function p2tr(a, opts) {
throw new TypeError('Pubkey mismatch');
else pubkey = a.output.slice(2);
}
- if (pubkey) {
+ // todo: optimze o.hash?
+ if (a.internalPubkey) {
+ const tweakedKey = (0, types_1.tweakPublicKey)(a.internalPubkey, o.hash);
+ if (tweakedKey === null)
+ throw new TypeError('Invalid internalPubkey for p2tr');
+ if (pubkey.length > 0 && !pubkey.equals(tweakedKey.x))
+ throw new TypeError('Pubkey mismatch');
+ else pubkey = tweakedKey.x;
+ }
+ if (pubkey?.length) {
if ((0, types_1.liftX)(pubkey) === null)
throw new TypeError('Invalid pubkey for p2tr');
}
diff --git a/src/types.d.ts b/src/types.d.ts
index 0fe6419f8..cb24d6a48 100644
--- a/src/types.d.ts
+++ b/src/types.d.ts
@@ -2,6 +2,7 @@
export declare const typeforce: any;
export declare function isPoint(p: Buffer | number | undefined | null): boolean;
export declare function liftX(buffer: Buffer): Buffer | null;
+export declare function tweakPublicKey(pubKey: Buffer, h: Buffer | undefined): TweakedPublicKey | null;
export declare function UInt31(value: number): boolean;
export declare function BIP32Path(value: string): boolean;
export declare namespace BIP32Path {
@@ -11,6 +12,10 @@ 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 TweakedPublicKey {
+ isOdd: boolean;
+ x: Buffer;
+}
export declare const Buffer256bit: any;
export declare const Hash160bit: any;
export declare const Hash256bit: any;
diff --git a/src/types.js b/src/types.js
index a7a89b0d2..1113ee89a 100644
--- a/src/types.js
+++ b/src/types.js
@@ -1,7 +1,11 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.oneOf = exports.Null = exports.BufferN = exports.Function = exports.UInt32 = exports.UInt8 = exports.tuple = exports.maybe = exports.Hex = exports.Buffer = exports.String = exports.Boolean = exports.Array = exports.Number = exports.Hash256bit = exports.Hash160bit = exports.Buffer256bit = exports.Network = exports.ECPoint = exports.Satoshi = exports.Signer = exports.BIP32Path = exports.UInt31 = exports.liftX = exports.isPoint = exports.typeforce = void 0;
+exports.oneOf = exports.Null = exports.BufferN = exports.Function = exports.UInt32 = exports.UInt8 = exports.tuple = exports.maybe = exports.Hex = exports.Buffer = exports.String = exports.Boolean = exports.Array = exports.Number = exports.Hash256bit = exports.Hash160bit = exports.Buffer256bit = exports.Network = exports.ECPoint = exports.Satoshi = exports.Signer = exports.BIP32Path = exports.UInt31 = exports.tweakPublicKey = exports.liftX = exports.isPoint = exports.typeforce = void 0;
const buffer_1 = require('buffer');
+const bcrypto = require('./crypto');
+// Temp, to be replaced
+// Only works because bip32 has it as dependecy. Linting will fail.
+const ecc = require('tiny-secp256k1');
// todo, use import?
const BN = require('bn.js');
exports.typeforce = require('typeforce');
@@ -57,6 +61,38 @@ function liftX(buffer) {
]);
}
exports.liftX = liftX;
+const TAP_TWEAK_TAG = buffer_1.Buffer.from('TapTweak', 'utf8');
+const GROUP_ORDER = new BN(
+ buffer_1.Buffer.from(
+ 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141',
+ 'hex',
+ ),
+);
+function tweakPublicKey(pubKey, h) {
+ if (!buffer_1.Buffer.isBuffer(pubKey)) return null;
+ if (pubKey.length !== 32) return null;
+ if (h && h.length !== 32) return null;
+ const tweakHash = bcrypto.taggedHash(
+ TAP_TWEAK_TAG,
+ buffer_1.Buffer.concat(h ? [pubKey, h] : [pubKey]),
+ );
+ const t = new BN(tweakHash);
+ if (t.gte(GROUP_ORDER)) {
+ throw new Error('Tweak value over the SECP256K1 Order');
+ }
+ const P = liftX(pubKey);
+ if (P === null) return null;
+ const Q = pointAddScalar(P, tweakHash);
+ return {
+ isOdd: Q[64] % 2 === 1,
+ x: Q.slice(1, 33),
+ };
+}
+exports.tweakPublicKey = tweakPublicKey;
+// todo: do not use ecc
+function pointAddScalar(P, h) {
+ return ecc.pointAddScalar(P, h);
+}
const UINT31_MAX = Math.pow(2, 31) - 1;
function UInt31(value) {
return exports.typeforce.UInt32(value) && value <= UINT31_MAX;
diff --git a/test/fixtures/p2tr.json b/test/fixtures/p2tr.json
index 02cb6abfc..8916e0fad 100644
--- a/test/fixtures/p2tr.json
+++ b/test/fixtures/p2tr.json
@@ -58,6 +58,21 @@
"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
+ }
}
],
"invalid": [
@@ -126,6 +141,15 @@
"address": "bc1pztta4jvddxsgdfgtxz2e5dfhj58n2mludag2ycatwhy28myagnqsnl7mv7"
}
},
+ {
+ "description": "Pubkey mismatch between internalPubkey and pubkey",
+ "exception": "Pubkey mismatch",
+ "options": {},
+ "arguments": {
+ "internalPubkey": "9fa5ffb68821cf559001caa0577eeea4978b29416def328a707b15e91701a2f7",
+ "pubkey": "ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5"
+ }
+ },
{
"exception": "Signature mismatch",
"arguments": {
diff --git a/test/payments.utils.ts b/test/payments.utils.ts
index c0635f3cf..fbd6e58a6 100644
--- a/test/payments.utils.ts
+++ b/test/payments.utils.ts
@@ -129,6 +129,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)
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index 439834247..ff83ff43f 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -1,7 +1,6 @@
-// import * as bcrypto from '../../crypto';
import { bitcoin as BITCOIN_NETWORK } from '../networks';
import * as bscript from '../script';
-import { liftX, typeforce as typef } from '../types';
+import { liftX, tweakPublicKey, typeforce as typef } from '../types';
import { Payment, PaymentOpts } from './index';
import * as lazy from './lazy';
import { bech32m } from 'bech32';
@@ -13,18 +12,18 @@ const TAPROOT_VERSION = 0x01;
// input: <>
// output: OP_1 {pubKey}
export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
- if (!a.address && !a.output && !a.pubkey && !a.output)
+ if (!a.address && !a.output && !a.pubkey && !a.output && !a.internalPubkey)
throw new TypeError('Not enough data');
opts = Object.assign({ validate: true }, opts || {});
typef(
{
- // todo: revisit
address: typef.maybe(typef.String),
- hash: typef.maybe(typef.BufferN(20)),
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(bscript.isCanonicalScriptSignature),
witness: typef.maybe(typef.arrayOf(typef.Buffer)),
@@ -58,7 +57,9 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
lazy.prop(o, 'hash', () => {
- // compute from MAST
+ if (a.hash) return a.hash;
+ // todo: if (a.redeems?.length) compute from MAST root from redeems
+ return null
});
lazy.prop(o, 'output', () => {
if (!o.pubkey) return;
@@ -67,8 +68,12 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
lazy.prop(o, 'pubkey', () => {
if (a.pubkey) return a.pubkey;
if (a.output) return a.output.slice(2)
- if (!a.address) return;
- return _address().data;
+ if (a.address) return _address().data;
+ if (a.internalPubkey) {
+ const tweakedKey = tweakPublicKey(a.internalPubkey, o.hash)
+ if (tweakedKey) return tweakedKey.x
+ }
+ return null
});
lazy.prop(o, 'signature', () => {
if (a.witness?.length !== 1) return;
@@ -113,7 +118,16 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
else pubkey = a.output.slice(2);
}
- if (pubkey) {
+ // todo: optimze o.hash?
+ if (a.internalPubkey) {
+ const tweakedKey = tweakPublicKey(a.internalPubkey, o.hash)
+ if (tweakedKey === null) throw new TypeError('Invalid internalPubkey for p2tr');
+ if (pubkey.length > 0 && !pubkey.equals(tweakedKey.x))
+ throw new TypeError('Pubkey mismatch');
+ else pubkey = tweakedKey.x;
+ }
+
+ if (pubkey?.length) {
if (liftX(pubkey) === null)
throw new TypeError('Invalid pubkey for p2tr');
}
diff --git a/ts_src/types.ts b/ts_src/types.ts
index d4b37cc66..8a8a4e4f9 100644
--- a/ts_src/types.ts
+++ b/ts_src/types.ts
@@ -1,4 +1,9 @@
import { Buffer as NBuffer } from 'buffer';
+import * as bcrypto from './crypto';
+
+// Temp, to be replaced
+// Only works because bip32 has it as dependecy. Linting will fail.
+const ecc = require('tiny-secp256k1');
// todo, use import?
const BN = require('bn.js');
@@ -30,7 +35,7 @@ export function isPoint(p: Buffer | number | undefined | null): boolean {
}
// todo review. Do not add dependcy to BN?
-const EC_P_BN = new BN(EC_P)
+const EC_P_BN = new BN(EC_P);
const EC_P_REDUCTION = BN.red(EC_P_BN);
const EC_P_QUADRATIC_RESIDUE = EC_P_BN.addn(1).divn(4);
const BN_2 = new BN(2);
@@ -66,6 +71,46 @@ export function liftX(buffer: Buffer): Buffer | null {
]);
}
+const TAP_TWEAK_TAG = NBuffer.from('TapTweak', 'utf8');
+const GROUP_ORDER = new BN(
+ NBuffer.from(
+ 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141',
+ 'hex',
+ ),
+);
+
+export function tweakPublicKey(
+ pubKey: Buffer,
+ h: Buffer | undefined,
+): TweakedPublicKey | null {
+ if (!NBuffer.isBuffer(pubKey)) return null;
+ if (pubKey.length !== 32) return null;
+ if (h && h.length !== 32) return null;
+
+ const tweakHash = bcrypto.taggedHash(
+ TAP_TWEAK_TAG,
+ NBuffer.concat(h ? [pubKey, h] : [pubKey]),
+ );
+ const t = new BN(tweakHash);
+ if (t.gte(GROUP_ORDER)) {
+ throw new Error('Tweak value over the SECP256K1 Order');
+ }
+
+ const P = liftX(pubKey);
+ if (P === null) return null;
+
+ const Q = pointAddScalar(P, tweakHash);
+ return {
+ isOdd: Q[64] % 2 === 1,
+ x: Q.slice(1, 33),
+ };
+}
+
+// todo: do not use ecc
+function pointAddScalar(P: Buffer, h: Buffer): Buffer {
+ return ecc.pointAddScalar(P, h);
+}
+
const UINT31_MAX: number = Math.pow(2, 31) - 1;
export function UInt31(value: number): boolean {
return typeforce.UInt32(value) && value <= UINT31_MAX;
@@ -106,6 +151,10 @@ export const Network = typeforce.compile({
wif: typeforce.UInt8,
});
+export interface TweakedPublicKey {
+ isOdd: boolean;
+ x: Buffer;
+}
export const Buffer256bit = typeforce.BufferN(32);
export const Hash160bit = typeforce.BufferN(20);
export const Hash256bit = typeforce.BufferN(32);
From e12f1876e2b5c9ca2bd63e7ad77d9c2ac0848875 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Fri, 29 Oct 2021 14:43:10 +0300
Subject: [PATCH 009/144] tests: improve test coverage
---
src/payments/p2tr.js | 1 -
test/fixtures/p2tr.json | 26 ++++++++++++++++++++++++++
ts_src/payments/p2tr.ts | 1 -
3 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index cde6d705a..c84579aea 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -67,7 +67,6 @@ function p2tr(a, opts) {
const tweakedKey = (0, types_1.tweakPublicKey)(a.internalPubkey, o.hash);
if (tweakedKey) return tweakedKey.x;
}
- return null;
});
lazy.prop(o, 'signature', () => {
if (a.witness?.length !== 1) return;
diff --git a/test/fixtures/p2tr.json b/test/fixtures/p2tr.json
index 8916e0fad..e4bc86af6 100644
--- a/test/fixtures/p2tr.json
+++ b/test/fixtures/p2tr.json
@@ -59,6 +59,25 @@
]
}
},
+ {
+ "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": {
@@ -150,6 +169,13 @@
"pubkey": "ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5"
}
},
+ {
+ "exception": "Invalid internalPubkey for p2t",
+ "options": {},
+ "arguments": {
+ "internalPubkey": "9fa5ffb68821cf559001caa0577eeea4978b29416def328a707b15e91701a2f8"
+ }
+ },
{
"exception": "Signature mismatch",
"arguments": {
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index ff83ff43f..926301f85 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -73,7 +73,6 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
const tweakedKey = tweakPublicKey(a.internalPubkey, o.hash)
if (tweakedKey) return tweakedKey.x
}
- return null
});
lazy.prop(o, 'signature', () => {
if (a.witness?.length !== 1) return;
From 7760b9fcf671694451f64644f9864a098ce3726f Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Mon, 1 Nov 2021 16:11:59 +0200
Subject: [PATCH 010/144] feat: add function `computeMastRoot()`
---
src/merkle.d.ts | 1 +
src/merkle.js | 46 +++++++++++++++++++++++++++++++++++++++++++++-
ts_src/merkle.ts | 40 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 86 insertions(+), 1 deletion(-)
diff --git a/src/merkle.d.ts b/src/merkle.d.ts
index d602201b9..d4b43f3ba 100644
--- a/src/merkle.d.ts
+++ b/src/merkle.d.ts
@@ -1,2 +1,3 @@
///
export declare function fastMerkleRoot(values: Buffer[], digestFn: (b: Buffer) => Buffer): Buffer;
+export declare function computeMastRoot(scripts: any): Buffer;
diff --git a/src/merkle.js b/src/merkle.js
index e93f9cab6..ba00ec4d3 100644
--- a/src/merkle.js
+++ b/src/merkle.js
@@ -1,6 +1,13 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.fastMerkleRoot = void 0;
+exports.computeMastRoot = exports.fastMerkleRoot = void 0;
+const buffer_1 = require('buffer');
+const bcrypto = require('./crypto');
+// todo: use varuint-bitcoin??
+const varuint = require('bip174/src/lib/converter/varint');
+const TAP_LEAF_TAG = buffer_1.Buffer.from('TapLeaf', 'utf8');
+const TAP_BRANCH_TAG = buffer_1.Buffer.from('TapBranch', 'utf8');
+const LEAF_VERSION_TAPSCRIPT = 0xc0;
function fastMerkleRoot(values, digestFn) {
if (!Array.isArray(values)) throw TypeError('Expected values Array');
if (typeof digestFn !== 'function')
@@ -20,3 +27,40 @@ function fastMerkleRoot(values, digestFn) {
return results[0];
}
exports.fastMerkleRoot = fastMerkleRoot;
+// todo: solve any[]
+function computeMastRoot(scripts) {
+ if (scripts.length === 1) {
+ const script = scripts[0];
+ if (Array.isArray(script)) {
+ return computeMastRoot(script);
+ }
+ script.version = script.version || LEAF_VERSION_TAPSCRIPT;
+ if ((script.version & 1) !== 0) throw new Error('Invalid script version'); // todo typedef error
+ // todo: if (script.output)scheck is bytes
+ const scriptOutput = buffer_1.Buffer.from(script.output, 'hex');
+ return bcrypto.taggedHash(
+ TAP_LEAF_TAG,
+ buffer_1.Buffer.concat([
+ buffer_1.Buffer.from([script.version]),
+ serializeScript(scriptOutput),
+ ]),
+ );
+ }
+ // todo: this is a binary tree, use zero an one index
+ const half = Math.trunc(scripts.length / 2);
+ let leftHash = computeMastRoot(scripts.slice(0, half));
+ let rightHash = computeMastRoot(scripts.slice(half));
+ if (leftHash.compare(rightHash) === 1)
+ [leftHash, rightHash] = [rightHash, leftHash];
+ return bcrypto.taggedHash(
+ TAP_BRANCH_TAG,
+ buffer_1.Buffer.concat([leftHash, rightHash]),
+ );
+}
+exports.computeMastRoot = computeMastRoot;
+function serializeScript(s) {
+ const varintLen = varuint.encodingLength(s.length);
+ const buffer = buffer_1.Buffer.allocUnsafe(varintLen); // better
+ varuint.encode(s.length, buffer);
+ return buffer_1.Buffer.concat([buffer, s]);
+}
diff --git a/ts_src/merkle.ts b/ts_src/merkle.ts
index 8ff8c3f8c..d328acea9 100644
--- a/ts_src/merkle.ts
+++ b/ts_src/merkle.ts
@@ -1,3 +1,14 @@
+import { Buffer as NBuffer } from 'buffer';
+import * as bcrypto from './crypto';
+// todo: use varuint-bitcoin??
+import * as varuint from 'bip174/src/lib/converter/varint';
+
+
+const TAP_LEAF_TAG = NBuffer.from('TapLeaf', 'utf8');
+const TAP_BRANCH_TAG = NBuffer.from('TapBranch', 'utf8');
+const LEAF_VERSION_TAPSCRIPT = 0xc0
+
+
export function fastMerkleRoot(
values: Buffer[],
digestFn: (b: Buffer) => Buffer,
@@ -25,3 +36,32 @@ export function fastMerkleRoot(
return results[0];
}
+
+// todo: solve any[]
+export function computeMastRoot(scripts: any): Buffer {
+ if (scripts.length === 1) {
+ const script = scripts[0]
+ if (Array.isArray(script)) {
+ return computeMastRoot(script)
+ }
+ script.version = script.version || LEAF_VERSION_TAPSCRIPT
+ if ((script.version & 1) !== 0) throw new Error("Invalid script version") // todo typedef error
+ // todo: if (script.output)scheck is bytes
+ const scriptOutput = NBuffer.from(script.output, 'hex')
+ return bcrypto.taggedHash(TAP_LEAF_TAG, NBuffer.concat([NBuffer.from([script.version]), serializeScript(scriptOutput)]))
+ }
+ // todo: this is a binary tree, use zero an one index
+ const half = Math.trunc(scripts.length / 2)
+ let leftHash = computeMastRoot(scripts.slice(0, half))
+ let rightHash = computeMastRoot(scripts.slice(half))
+
+ if (leftHash.compare(rightHash) === 1) [leftHash, rightHash] = [rightHash, leftHash]
+ return bcrypto.taggedHash(TAP_BRANCH_TAG, NBuffer.concat([leftHash, rightHash]))
+}
+
+function serializeScript(s: Buffer) {
+ const varintLen = varuint.encodingLength(s.length);
+ const buffer = NBuffer.allocUnsafe(varintLen); // better
+ varuint.encode(s.length, buffer);
+ return NBuffer.concat([buffer, s])
+}
\ No newline at end of file
From d142e0285d0960cbc0289b36c15e114be3759af8 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Mon, 1 Nov 2021 16:12:55 +0200
Subject: [PATCH 011/144] feat: compute p2tr hash based on the script tree
---
src/payments/p2tr.js | 4 +++-
ts_src/payments/p2tr.ts | 4 +++-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index c84579aea..6572ac080 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -4,6 +4,7 @@ exports.p2tr = void 0;
const networks_1 = require('../networks');
const bscript = require('../script');
const types_1 = require('../types');
+const merkle_1 = require('../merkle');
const lazy = require('./lazy');
const bech32_1 = require('bech32');
const OPS = bscript.OPS;
@@ -28,6 +29,7 @@ function p2tr(a, opts) {
witness: types_1.typeforce.maybe(
types_1.typeforce.arrayOf(types_1.typeforce.Buffer),
),
+ // scriptsTree: typef.maybe(typef.TaprootNode), // use merkel.isMast ?
},
a,
);
@@ -52,7 +54,7 @@ function p2tr(a, opts) {
});
lazy.prop(o, 'hash', () => {
if (a.hash) return a.hash;
- // todo: if (a.redeems?.length) compute from MAST root from redeems
+ if (a.scriptsTree) return (0, merkle_1.computeMastRoot)(a.scriptsTree);
return null;
});
lazy.prop(o, 'output', () => {
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index 926301f85..c0365cfca 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -1,6 +1,7 @@
import { bitcoin as BITCOIN_NETWORK } from '../networks';
import * as bscript from '../script';
import { liftX, tweakPublicKey, typeforce as typef } from '../types';
+import { computeMastRoot } from '../merkle';
import { Payment, PaymentOpts } from './index';
import * as lazy from './lazy';
import { bech32m } from 'bech32';
@@ -27,6 +28,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
pubkey: typef.maybe(typef.BufferN(32)),
signature: typef.maybe(bscript.isCanonicalScriptSignature),
witness: typef.maybe(typef.arrayOf(typef.Buffer)),
+ // scriptsTree: typef.maybe(typef.TaprootNode), // use merkel.isMast ?
},
a,
);
@@ -58,7 +60,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
lazy.prop(o, 'hash', () => {
if (a.hash) return a.hash;
- // todo: if (a.redeems?.length) compute from MAST root from redeems
+ if (a.scriptsTree) return computeMastRoot(a.scriptsTree)
return null
});
lazy.prop(o, 'output', () => {
From d1c7b051bce859a7b31d945e2c26b44258f82515 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Mon, 1 Nov 2021 16:13:57 +0200
Subject: [PATCH 012/144] feat: add scriptsTree field to Payment interface;
export p2tr
---
src/payments/index.d.ts | 5 +++--
src/payments/index.js | 9 ++++++++-
ts_src/payments/index.ts | 5 +++--
3 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/src/payments/index.d.ts b/src/payments/index.d.ts
index e569aa3cf..dc1978ab0 100644
--- a/src/payments/index.d.ts
+++ b/src/payments/index.d.ts
@@ -7,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;
network?: Network;
@@ -23,7 +24,7 @@ export interface Payment {
address?: string;
hash?: Buffer;
redeem?: Payment;
- redeems?: Payment;
+ scriptsTree?: any;
witness?: Buffer[];
}
export declare type PaymentCreator = (a: Payment, opts?: PaymentOpts) => Payment;
@@ -35,4 +36,4 @@ export interface PaymentOpts {
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/ts_src/payments/index.ts b/ts_src/payments/index.ts
index d42649b3f..5243902d4 100644
--- a/ts_src/payments/index.ts
+++ b/ts_src/payments/index.ts
@@ -6,6 +6,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;
@@ -23,7 +24,7 @@ export interface Payment {
address?: string; // taproot: betch32m
hash?: Buffer; // taproot: MAST root
redeem?: Payment; // taproot: when script path spending is used spending
- redeems?: Payment; // taproot can have more than one redeem script
+ scriptsTree?: any // todo: solve
witness?: Buffer[];
}
@@ -40,7 +41,7 @@ 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
From 46e3ce7d86fd8b03bb7916b8c9442801113ae76b Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Mon, 1 Nov 2021 16:15:45 +0200
Subject: [PATCH 013/144] feat: convert `scriptsTree` output to Buffer
---
test/payments.utils.ts | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/test/payments.utils.ts b/test/payments.utils.ts
index fbd6e58a6..71863a602 100644
--- a/test/payments.utils.ts
+++ b/test/payments.utils.ts
@@ -147,7 +147,8 @@ export function preform(x: any): any {
if (x.redeem.network)
x.redeem.network = (BNETWORKS as any)[x.redeem.network];
}
-
+ if (x.scriptsTree)
+ x.scriptsTree = convertScriptsTree(x.scriptsTree)
return x;
}
@@ -170,3 +171,15 @@ 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
+}
From 3f1be3260c47df8a2fa3671046eff02255977e8d Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Mon, 1 Nov 2021 16:16:17 +0200
Subject: [PATCH 014/144] tests: add tests for script tree
---
test/fixtures/p2tr.json | 206 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 206 insertions(+)
diff --git a/test/fixtures/p2tr.json b/test/fixtures/p2tr.json
index e4bc86af6..3f088bb60 100644
--- a/test/fixtures/p2tr.json
+++ b/test/fixtures/p2tr.json
@@ -92,6 +92,212 @@
"input": null,
"witness": null
}
+ },
+ {
+ "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
+ }
}
],
"invalid": [
From b6a00487f41b347d86e4128acaa363f1c3447f37 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Mon, 1 Nov 2021 16:17:13 +0200
Subject: [PATCH 015/144] feat: add simple type for TaprootLeaf and TaprootNode
---
src/types.d.ts | 2 ++
src/types.js | 13 ++++++++++++-
ts_src/types.ts | 10 ++++++++++
3 files changed, 24 insertions(+), 1 deletion(-)
diff --git a/src/types.d.ts b/src/types.d.ts
index cb24d6a48..45bfcd1c6 100644
--- a/src/types.d.ts
+++ b/src/types.d.ts
@@ -16,6 +16,8 @@ export interface TweakedPublicKey {
isOdd: boolean;
x: Buffer;
}
+export declare const TaprootLeaf: any;
+export declare const TaprootNode: any;
export declare const Buffer256bit: any;
export declare const Hash160bit: any;
export declare const Hash256bit: any;
diff --git a/src/types.js b/src/types.js
index 1113ee89a..668af87bd 100644
--- a/src/types.js
+++ b/src/types.js
@@ -1,6 +1,6 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.oneOf = exports.Null = exports.BufferN = exports.Function = exports.UInt32 = exports.UInt8 = exports.tuple = exports.maybe = exports.Hex = exports.Buffer = exports.String = exports.Boolean = exports.Array = exports.Number = exports.Hash256bit = exports.Hash160bit = exports.Buffer256bit = exports.Network = exports.ECPoint = exports.Satoshi = exports.Signer = exports.BIP32Path = exports.UInt31 = exports.tweakPublicKey = exports.liftX = exports.isPoint = exports.typeforce = void 0;
+exports.oneOf = exports.Null = exports.BufferN = exports.Function = exports.UInt32 = exports.UInt8 = exports.tuple = exports.maybe = exports.Hex = exports.Buffer = exports.String = exports.Boolean = exports.Array = exports.Number = exports.Hash256bit = exports.Hash160bit = exports.Buffer256bit = exports.TaprootNode = exports.TaprootLeaf = exports.Network = exports.ECPoint = exports.Satoshi = exports.Signer = exports.BIP32Path = exports.UInt31 = exports.tweakPublicKey = exports.liftX = exports.isPoint = exports.typeforce = void 0;
const buffer_1 = require('buffer');
const bcrypto = require('./crypto');
// Temp, to be replaced
@@ -136,6 +136,17 @@ exports.Network = exports.typeforce.compile({
scriptHash: exports.typeforce.UInt8,
wif: exports.typeforce.UInt8,
});
+exports.TaprootLeaf = exports.typeforce.compile({
+ output: exports.typeforce.BufferN(34),
+ version: exports.typeforce.maybe(exports.typeforce.UInt8), // todo: recheck
+});
+// / todo: revisit
+exports.TaprootNode = exports.typeforce.arrayOf(
+ exports.typeforce.oneOf(
+ exports.TaprootLeaf,
+ exports.typeforce.arrayOf(exports.TaprootLeaf),
+ ),
+);
exports.Buffer256bit = exports.typeforce.BufferN(32);
exports.Hash160bit = exports.typeforce.BufferN(20);
exports.Hash256bit = exports.typeforce.BufferN(32);
diff --git a/ts_src/types.ts b/ts_src/types.ts
index 8a8a4e4f9..875df29f7 100644
--- a/ts_src/types.ts
+++ b/ts_src/types.ts
@@ -155,6 +155,16 @@ export interface TweakedPublicKey {
isOdd: boolean;
x: Buffer;
}
+
+export const TaprootLeaf = typeforce.compile({
+ output: typeforce.BufferN(34),
+ version: typeforce.maybe(typeforce.UInt8) // todo: recheck
+})
+
+// / todo: revisit
+export const TaprootNode = typeforce.arrayOf(typeforce.oneOf(TaprootLeaf, typeforce.arrayOf(TaprootLeaf)))
+
+
export const Buffer256bit = typeforce.BufferN(32);
export const Hash160bit = typeforce.BufferN(20);
export const Hash256bit = typeforce.BufferN(32);
From 7bc0c8ec33ac70272dde98ed64265c0ec5d92a68 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Mon, 1 Nov 2021 16:36:41 +0200
Subject: [PATCH 016/144] feat: check for hash mismatch between the input hash
and the computed hash from the taproot tree
---
src/payments/p2tr.js | 4 ++++
test/fixtures/p2tr.json | 14 ++++++++++++++
ts_src/payments/p2tr.ts | 6 ++++++
3 files changed, 24 insertions(+)
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index 6572ac080..be912a4f3 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -122,6 +122,10 @@ function p2tr(a, opts) {
if ((0, types_1.liftX)(pubkey) === null)
throw new TypeError('Invalid pubkey for p2tr');
}
+ if (a.hash && a.scriptsTree) {
+ const hash = (0, merkle_1.computeMastRoot)(a.scriptsTree);
+ if (!a.hash.equals(hash)) throw new TypeError('Hash mismatch');
+ }
if (a.witness) {
if (a.witness.length !== 1) throw new TypeError('Witness is invalid');
// todo: recheck
diff --git a/test/fixtures/p2tr.json b/test/fixtures/p2tr.json
index 3f088bb60..25fec29ba 100644
--- a/test/fixtures/p2tr.json
+++ b/test/fixtures/p2tr.json
@@ -375,6 +375,20 @@
"pubkey": "ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5"
}
},
+ {
+ "description": "Hash mismatch between scriptsTree and hash",
+ "exception": "Hash mismatch",
+ "options": {},
+ "arguments": {
+ "internalPubkey": "9fa5ffb68821cf559001caa0577eeea4978b29416def328a707b15e91701a2f7",
+ "scriptsTree": [
+ {
+ "output": "83d8ee77a0f3a32a5cea96fd1624d623b836c1e5d1ac2dcde46814b619320c18 OP_CHECKSIG"
+ }
+ ],
+ "hash": "b76077013c8e303085e300000000000000000000000000000000000000000000"
+ }
+ },
{
"exception": "Invalid internalPubkey for p2t",
"options": {},
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index c0365cfca..6bbbfa101 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -133,6 +133,12 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
throw new TypeError('Invalid pubkey for p2tr');
}
+ if (a.hash && a.scriptsTree) {
+ const hash = computeMastRoot(a.scriptsTree)
+ if (!a.hash.equals(hash))
+ throw new TypeError('Hash mismatch');
+ }
+
if (a.witness) {
if (a.witness.length !== 1) throw new TypeError('Witness is invalid');
From 61511d4f6346b06610b4ef0d9b018528668e2879 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Tue, 2 Nov 2021 15:34:37 +0200
Subject: [PATCH 017/144] feat: validate witness data (partial)
---
src/merkle.js | 1 +
src/payments/p2tr.js | 95 +++++++++++++++++++++++----
src/types.d.ts | 2 +
src/types.js | 63 ++++++++++++++++--
test/fixtures/p2tr.json | 139 +++++++++++++++++++++++++++++++++++++++-
test/payments.utils.ts | 2 +
ts_src/merkle.ts | 1 +
ts_src/payments/p2tr.ts | 87 ++++++++++++++++++++-----
ts_src/types.ts | 50 +++++++++++++--
9 files changed, 396 insertions(+), 44 deletions(-)
diff --git a/src/merkle.js b/src/merkle.js
index ba00ec4d3..009260ac4 100644
--- a/src/merkle.js
+++ b/src/merkle.js
@@ -5,6 +5,7 @@ const buffer_1 = require('buffer');
const bcrypto = require('./crypto');
// todo: use varuint-bitcoin??
const varuint = require('bip174/src/lib/converter/varint');
+// todo: find better place for these consts
const TAP_LEAF_TAG = buffer_1.Buffer.from('TapLeaf', 'utf8');
const TAP_BRANCH_TAG = buffer_1.Buffer.from('TapBranch', 'utf8');
const LEAF_VERSION_TAPSCRIPT = 0xc0;
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index be912a4f3..7d7e93a43 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -9,11 +9,19 @@ const lazy = require('./lazy');
const bech32_1 = require('bech32');
const OPS = bscript.OPS;
const TAPROOT_VERSION = 0x01;
+const ANNEX_PREFIX = 0x50;
// witness: {signature}
// input: <>
// output: OP_1 {pubKey}
function p2tr(a, opts) {
- if (!a.address && !a.output && !a.pubkey && !a.output && !a.internalPubkey)
+ 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 || {});
(0, types_1.typeforce)(
@@ -43,7 +51,17 @@ function p2tr(a, opts) {
data: Buffer.from(data),
};
});
- // todo: clean-up withness (annex), etc
+ 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', () => {
@@ -55,6 +73,7 @@ function p2tr(a, opts) {
lazy.prop(o, 'hash', () => {
if (a.hash) return a.hash;
if (a.scriptsTree) return (0, merkle_1.computeMastRoot)(a.scriptsTree);
+ // todo: compute from witness
return null;
});
lazy.prop(o, 'output', () => {
@@ -65,11 +84,17 @@ function p2tr(a, opts) {
if (a.pubkey) return a.pubkey;
if (a.output) return a.output.slice(2);
if (a.address) return _address().data;
- if (a.internalPubkey) {
- const tweakedKey = (0, types_1.tweakPublicKey)(a.internalPubkey, o.hash);
+ if (o.internalPubkey) {
+ const tweakedKey = (0, types_1.tweakPublicKey)(o.internalPubkey, o.hash);
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?.length !== 1) return;
return a.witness[0];
@@ -78,6 +103,7 @@ function p2tr(a, opts) {
// todo: not sure
});
lazy.prop(o, 'witness', () => {
+ if (a.witness) return a.witness;
if (!a.signature) return;
return [a.signature];
});
@@ -109,7 +135,6 @@ function p2tr(a, opts) {
throw new TypeError('Pubkey mismatch');
else pubkey = a.output.slice(2);
}
- // todo: optimze o.hash?
if (a.internalPubkey) {
const tweakedKey = (0, types_1.tweakPublicKey)(a.internalPubkey, o.hash);
if (tweakedKey === null)
@@ -126,13 +151,59 @@ function p2tr(a, opts) {
const hash = (0, merkle_1.computeMastRoot)(a.scriptsTree);
if (!a.hash.equals(hash)) throw new TypeError('Hash mismatch');
}
- if (a.witness) {
- if (a.witness.length !== 1) throw new TypeError('Witness is invalid');
- // todo: recheck
- // if (!bscript.isCanonicalScriptSignature(a.witness[0]))
- // throw new TypeError('Witness has invalid signature');
- if (a.signature && !a.signature.equals(a.witness[0]))
- throw new TypeError('Signature mismatch');
+ // todo: review cache
+ 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');
+ const internalPubkeyPoint = (0, types_1.liftX)(internalPubkey);
+ if (!internalPubkeyPoint)
+ throw new TypeError('Invalid internalPubkey for p2tr witness');
+ const leafVersion = controlBlock[0] & 0b11111110;
+ const script = witness[witness.length - 2];
+ const tweak = (0, types_1.computeTweakFromScriptPath)(
+ controlBlock,
+ script,
+ internalPubkey,
+ m,
+ leafVersion,
+ );
+ const outputKey = (0, types_1.tweakPublicKey)(internalPubkey, tweak);
+ 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');
+ const controlBlockOddParity = (controlBlock[0] & 1) === 1;
+ if (outputKey.isOdd !== controlBlockOddParity)
+ throw new Error('Incorrect parity');
+ }
}
}
return Object.assign(o, a);
diff --git a/src/types.d.ts b/src/types.d.ts
index 45bfcd1c6..a4813ee4f 100644
--- a/src/types.d.ts
+++ b/src/types.d.ts
@@ -1,8 +1,10 @@
///
+import { Buffer as NBuffer } from 'buffer';
export declare const typeforce: any;
export declare function isPoint(p: Buffer | number | undefined | null): boolean;
export declare function liftX(buffer: Buffer): Buffer | null;
export declare function tweakPublicKey(pubKey: Buffer, h: Buffer | undefined): TweakedPublicKey | null;
+export declare function computeTweakFromScriptPath(controlBlock: Buffer, script: Buffer, internalPubkey: Buffer, m: number, v: number): NBuffer;
export declare function UInt31(value: number): boolean;
export declare function BIP32Path(value: string): boolean;
export declare namespace BIP32Path {
diff --git a/src/types.js b/src/types.js
index 668af87bd..07756ecc4 100644
--- a/src/types.js
+++ b/src/types.js
@@ -1,8 +1,9 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.oneOf = exports.Null = exports.BufferN = exports.Function = exports.UInt32 = exports.UInt8 = exports.tuple = exports.maybe = exports.Hex = exports.Buffer = exports.String = exports.Boolean = exports.Array = exports.Number = exports.Hash256bit = exports.Hash160bit = exports.Buffer256bit = exports.TaprootNode = exports.TaprootLeaf = exports.Network = exports.ECPoint = exports.Satoshi = exports.Signer = exports.BIP32Path = exports.UInt31 = exports.tweakPublicKey = exports.liftX = exports.isPoint = exports.typeforce = void 0;
+exports.oneOf = exports.Null = exports.BufferN = exports.Function = exports.UInt32 = exports.UInt8 = exports.tuple = exports.maybe = exports.Hex = exports.Buffer = exports.String = exports.Boolean = exports.Array = exports.Number = exports.Hash256bit = exports.Hash160bit = exports.Buffer256bit = exports.TaprootNode = exports.TaprootLeaf = exports.Network = exports.ECPoint = exports.Satoshi = exports.Signer = exports.BIP32Path = exports.UInt31 = exports.computeTweakFromScriptPath = exports.tweakPublicKey = exports.liftX = exports.isPoint = exports.typeforce = void 0;
const buffer_1 = require('buffer');
const bcrypto = require('./crypto');
+const varuint = require('bip174/src/lib/converter/varint');
// Temp, to be replaced
// Only works because bip32 has it as dependecy. Linting will fail.
const ecc = require('tiny-secp256k1');
@@ -62,12 +63,12 @@ function liftX(buffer) {
}
exports.liftX = liftX;
const TAP_TWEAK_TAG = buffer_1.Buffer.from('TapTweak', 'utf8');
-const GROUP_ORDER = new BN(
- buffer_1.Buffer.from(
- 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141',
- 'hex',
- ),
+const GROUP_ORDER = buffer_1.Buffer.from(
+ 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141',
+ 'hex',
);
+// todo: compare buffers dirrectly
+const GROUP_ORDER_BN = new BN(GROUP_ORDER);
function tweakPublicKey(pubKey, h) {
if (!buffer_1.Buffer.isBuffer(pubKey)) return null;
if (pubKey.length !== 32) return null;
@@ -77,7 +78,8 @@ function tweakPublicKey(pubKey, h) {
buffer_1.Buffer.concat(h ? [pubKey, h] : [pubKey]),
);
const t = new BN(tweakHash);
- if (t.gte(GROUP_ORDER)) {
+ if (t.gte(GROUP_ORDER_BN)) {
+ // todo: add test for this case
throw new Error('Tweak value over the SECP256K1 Order');
}
const P = liftX(pubKey);
@@ -89,6 +91,53 @@ function tweakPublicKey(pubKey, h) {
};
}
exports.tweakPublicKey = tweakPublicKey;
+const TAP_LEAF_TAG = buffer_1.Buffer.from('TapLeaf', 'utf8');
+const TAP_BRANCH_TAG = buffer_1.Buffer.from('TapBranch', 'utf8');
+function computeTweakFromScriptPath(
+ controlBlock,
+ script,
+ internalPubkey,
+ m,
+ v,
+) {
+ const k = [];
+ const e = [];
+ const tapLeafMsg = buffer_1.Buffer.concat([
+ buffer_1.Buffer.from([v]),
+ serializeScript(script),
+ ]);
+ k[0] = bcrypto.taggedHash(TAP_LEAF_TAG, tapLeafMsg);
+ 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] = bcrypto.taggedHash(
+ TAP_BRANCH_TAG,
+ buffer_1.Buffer.concat([k[j], e[j]]),
+ );
+ } else {
+ k[j + 1] = bcrypto.taggedHash(
+ TAP_BRANCH_TAG,
+ buffer_1.Buffer.concat([e[j], k[j]]),
+ );
+ }
+ }
+ const t = bcrypto.taggedHash(
+ TAP_TWEAK_TAG,
+ buffer_1.Buffer.concat([internalPubkey, k[m]]),
+ );
+ if (t.compare(GROUP_ORDER) >= 0) {
+ throw new Error('Over the order of secp256k1');
+ }
+ return t;
+}
+exports.computeTweakFromScriptPath = computeTweakFromScriptPath;
+// todo: move out
+function serializeScript(s) {
+ const varintLen = varuint.encodingLength(s.length);
+ const buffer = buffer_1.Buffer.allocUnsafe(varintLen); // better
+ varuint.encode(s.length, buffer);
+ return buffer_1.Buffer.concat([buffer, s]);
+}
// todo: do not use ecc
function pointAddScalar(P, h) {
return ecc.pointAddScalar(P, h);
diff --git a/test/fixtures/p2tr.json b/test/fixtures/p2tr.json
index 25fec29ba..532fe2297 100644
--- a/test/fixtures/p2tr.json
+++ b/test/fixtures/p2tr.json
@@ -93,6 +93,60 @@
"witness": null
}
},
+ {
+ "description": "address, pubkey, internalPubkey and output from witness",
+ "arguments": {
+ "witness": [
+ "9675a9982c6398ea9d441cb7a943bcd6ff033cc3a2e01a0178a7d3be4575be863871c6bf3eef5ecd34721c784259385ca9101c3a313e010ac942c99de05aaaa602",
+ "5799cf4b193b730fb99580b186f7477c2cca4d28957326f6f1a5d14116438530e7ec0ce1cd465ad96968ae8a6a09d4d37a060a115919f56fcfebe7b2277cc2df5cc08fb6cda9105ee2512b2e22635aba",
+ "7520c7b5db9562078049719228db2ac80cb9643ec96c8055aa3b29c2c03d4d99edb0ac",
+ "c1a7957acbaaf7b444c53d9e0c9436e8a8a3247fd515095d66ddf6201918b40a3668f9a4ccdffcf778da624dca2dda0b08e763ec52fd4ad403ec7563a3504d0cc168b9a77a410029e01dac89567c9b2e6cd726e840351df3f2f58fefe976200a19244150d04153909f660184d656ee95fa7bf8e1d4ec83da1fca34f64bc279b76d257ec623e08baba2cfa4ea9e99646e88f1eb1668c00c0f15b7443c8ab83481611cc3ae85eb89a7bfc40067eb1d2e6354a32426d0ce710e88bc4cc0718b99c325509c9d02a6a980d675a8969be10ee9bef82cafee2fc913475667ccda37b1bc7f13f64e56c449c532658ba8481631c02ead979754c809584a875951619cec8fb040c33f06468ae0266cd8693d6a64cea5912be32d8de95a6da6300b0c50fdcd6001ea41126e7b7e5280d455054a816560028f5ca53c9a50ee52f10e15c5337315bad1f5277acb109a1418649dc6ead2fe14699742fee7182f2f15e54279c7d932ed2799d01d73c97e68bbc94d6f7f56ee0a80efd7c76e3169e10d1a1ba3b5f1eb02369dc43af687461c7a2a3344d13eb5485dca29a67f16b4cb988923060fd3b65d0f0352bb634bcc44f2fe668836dcd0f604150049835135dc4b4fbf90fb334b3938a1f137eb32f047c65b85e6c1173b890b6d0162b48b186d1f1af8521945924ac8ac8efec321bf34f1d4b3d4a304a10313052c652d53f6ecb8a55586614e8950cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c"
+ ]
+ },
+ "expected": {
+ "name": "p2tr",
+ "internalPubkey": "a7957acbaaf7b444c53d9e0c9436e8a8a3247fd515095d66ddf6201918b40a36",
+ "pubkey": "a44784d6b2d0159ca57f52e3e6023a4f1960d22c089d019f3656d9e23926dcc9",
+ "address": "bc1p53rcf44j6q2eeftl2t37vq36fuvkp53vpzwsr8ek2mv7ywfxmnysdul78t",
+ "output": "OP_1 a44784d6b2d0159ca57f52e3e6023a4f1960d22c089d019f3656d9e23926dcc9",
+ "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": "a44784d6b2d0159ca57f52e3e6023a4f1960d22c089d019f3656d9e23926dcc9",
+ "address": "bc1p53rcf44j6q2eeftl2t37vq36fuvkp53vpzwsr8ek2mv7ywfxmnysdul78t",
+ "output": "OP_1 a44784d6b2d0159ca57f52e3e6023a4f1960d22c089d019f3656d9e23926dcc9",
+ "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": {
@@ -425,10 +479,89 @@
}
},
{
- "exception": "Witness is invalid",
+ "description": "Control block length too small",
+ "exception": "The control-block length is too small. Got 16, expected min 33.",
"arguments": {
- "address": "bc1p4dss6gkgq8003g0qyd5drwfqrztsadf2w2v3juz73gdz7cx82r6sj7lcqx",
- "witness": []
+ "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"
+ ]
}
}
],
diff --git a/test/payments.utils.ts b/test/payments.utils.ts
index 71863a602..d1b40aa5e 100644
--- a/test/payments.utils.ts
+++ b/test/payments.utils.ts
@@ -86,6 +86,8 @@ 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),
diff --git a/ts_src/merkle.ts b/ts_src/merkle.ts
index d328acea9..125769215 100644
--- a/ts_src/merkle.ts
+++ b/ts_src/merkle.ts
@@ -4,6 +4,7 @@ import * as bcrypto from './crypto';
import * as varuint from 'bip174/src/lib/converter/varint';
+// todo: find better place for these consts
const TAP_LEAF_TAG = NBuffer.from('TapLeaf', 'utf8');
const TAP_BRANCH_TAG = NBuffer.from('TapBranch', 'utf8');
const LEAF_VERSION_TAPSCRIPT = 0xc0
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index 6bbbfa101..2abc6a72e 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -1,6 +1,6 @@
import { bitcoin as BITCOIN_NETWORK } from '../networks';
import * as bscript from '../script';
-import { liftX, tweakPublicKey, typeforce as typef } from '../types';
+import { liftX, tweakPublicKey, computeTweakFromScriptPath, typeforce as typef } from '../types';
import { computeMastRoot } from '../merkle';
import { Payment, PaymentOpts } from './index';
import * as lazy from './lazy';
@@ -8,12 +8,13 @@ import { bech32m } from 'bech32';
const OPS = bscript.OPS;
const TAPROOT_VERSION = 0x01;
+const ANNEX_PREFIX = 0x50;
// witness: {signature}
// input: <>
// output: OP_1 {pubKey}
export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
- if (!a.address && !a.output && !a.pubkey && !a.output && !a.internalPubkey)
+ 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 || {});
@@ -44,7 +45,14 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
};
});
- // todo: clean-up withness (annex), etc
+ 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 };
@@ -61,6 +69,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
lazy.prop(o, 'hash', () => {
if (a.hash) return a.hash;
if (a.scriptsTree) return computeMastRoot(a.scriptsTree)
+ // todo: compute from witness
return null
});
lazy.prop(o, 'output', () => {
@@ -71,11 +80,17 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
if (a.pubkey) return a.pubkey;
if (a.output) return a.output.slice(2)
if (a.address) return _address().data;
- if (a.internalPubkey) {
- const tweakedKey = tweakPublicKey(a.internalPubkey, o.hash)
+ if (o.internalPubkey) {
+ const tweakedKey = tweakPublicKey(o.internalPubkey, o.hash)
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?.length !== 1) return;
return a.witness[0];
@@ -84,6 +99,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
// todo: not sure
});
lazy.prop(o, 'witness', () => {
+ if (a.witness) return a.witness
if (!a.signature) return;
return [a.signature];
});
@@ -98,7 +114,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
throw new TypeError('Invalid address version');
if (_address().data.length !== 32)
throw new TypeError('Invalid address data');
- pubkey = _address().data;
+ pubkey = _address().data;
}
if (a.pubkey) {
@@ -110,7 +126,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
if (a.output) {
if (
a.output.length !== 34 ||
- a.output[0] !== OPS.OP_1 ||
+ a.output[0] !== OPS.OP_1 ||
a.output[1] !== 0x20
)
throw new TypeError('Output is invalid');
@@ -119,10 +135,9 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
else pubkey = a.output.slice(2);
}
- // todo: optimze o.hash?
if (a.internalPubkey) {
const tweakedKey = tweakPublicKey(a.internalPubkey, o.hash)
- if (tweakedKey === null) throw new TypeError('Invalid internalPubkey for p2tr');
+ if (tweakedKey === null) throw new TypeError('Invalid internalPubkey for p2tr');
if (pubkey.length > 0 && !pubkey.equals(tweakedKey.x))
throw new TypeError('Pubkey mismatch');
else pubkey = tweakedKey.x;
@@ -139,15 +154,57 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
throw new TypeError('Hash mismatch');
}
- if (a.witness) {
- if (a.witness.length !== 1) throw new TypeError('Witness is invalid');
+ // todo: review cache
+ const witness = _witness()
- // todo: recheck
- // if (!bscript.isCanonicalScriptSignature(a.witness[0]))
+ 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');
+
+ const internalPubkeyPoint = liftX(internalPubkey);
+ if (!internalPubkeyPoint)
+ throw new TypeError('Invalid internalPubkey for p2tr witness');
+
+
+ const leafVersion = controlBlock[0] & 0b11111110;
+ const script = witness[witness.length - 2];
+ const tweak = computeTweakFromScriptPath(controlBlock, script, internalPubkey, m, leafVersion)
+
+ const outputKey = tweakPublicKey(internalPubkey, tweak)
+ 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');
+
+ const controlBlockOddParity = (controlBlock[0] & 1) === 1
+ if (outputKey.isOdd !== controlBlockOddParity)
+ throw new Error('Incorrect parity')
+
+ }
- if (a.signature && !a.signature.equals(a.witness[0]))
- throw new TypeError('Signature mismatch');
}
}
diff --git a/ts_src/types.ts b/ts_src/types.ts
index 875df29f7..6fe711450 100644
--- a/ts_src/types.ts
+++ b/ts_src/types.ts
@@ -1,5 +1,6 @@
import { Buffer as NBuffer } from 'buffer';
import * as bcrypto from './crypto';
+import * as varuint from 'bip174/src/lib/converter/varint';
// Temp, to be replaced
// Only works because bip32 has it as dependecy. Linting will fail.
@@ -72,12 +73,10 @@ export function liftX(buffer: Buffer): Buffer | null {
}
const TAP_TWEAK_TAG = NBuffer.from('TapTweak', 'utf8');
-const GROUP_ORDER = new BN(
- NBuffer.from(
- 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141',
- 'hex',
- ),
-);
+
+const GROUP_ORDER = NBuffer.from('fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141', 'hex');
+// todo: compare buffers dirrectly
+const GROUP_ORDER_BN = new BN(GROUP_ORDER);
export function tweakPublicKey(
pubKey: Buffer,
@@ -92,7 +91,8 @@ export function tweakPublicKey(
NBuffer.concat(h ? [pubKey, h] : [pubKey]),
);
const t = new BN(tweakHash);
- if (t.gte(GROUP_ORDER)) {
+ if (t.gte(GROUP_ORDER_BN)) {
+ // todo: add test for this case
throw new Error('Tweak value over the SECP256K1 Order');
}
@@ -106,6 +106,42 @@ export function tweakPublicKey(
};
}
+const TAP_LEAF_TAG = NBuffer.from('TapLeaf', 'utf8');
+const TAP_BRANCH_TAG = NBuffer.from('TapBranch', 'utf8');
+
+export function computeTweakFromScriptPath(controlBlock: Buffer, script: Buffer, internalPubkey: Buffer, m: number, v: number) {
+ const k = [];
+ const e = [];
+
+ const tapLeafMsg = NBuffer.concat([NBuffer.from([v]), serializeScript(script)]);
+ k[0] = bcrypto.taggedHash(TAP_LEAF_TAG, tapLeafMsg);
+
+
+ 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] = bcrypto.taggedHash(TAP_BRANCH_TAG, NBuffer.concat([k[j], e[j]]));
+ } else {
+ k[j + 1] = bcrypto.taggedHash(TAP_BRANCH_TAG, NBuffer.concat([e[j], k[j]]));
+ }
+ }
+
+ const t = bcrypto.taggedHash(TAP_TWEAK_TAG, NBuffer.concat([internalPubkey, k[m]]));
+ if (t.compare(GROUP_ORDER) >= 0) {
+ throw new Error('Over the order of secp256k1')
+ }
+
+ return t
+}
+
+// todo: move out
+function serializeScript(s: Buffer) {
+ const varintLen = varuint.encodingLength(s.length);
+ const buffer = NBuffer.allocUnsafe(varintLen); // better
+ varuint.encode(s.length, buffer);
+ return NBuffer.concat([buffer, s])
+}
+
// todo: do not use ecc
function pointAddScalar(P: Buffer, h: Buffer): Buffer {
return ecc.pointAddScalar(P, h);
From 725d96adbf29831246e9385c7d7a9c8093c450f9 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Tue, 2 Nov 2021 16:06:01 +0200
Subject: [PATCH 018/144] refactor: split `computeTweakFromScriptPath()` into
`rootHash()` and `leafHash()``
---
src/payments/p2tr.js | 15 +++++----------
src/types.d.ts | 6 +++---
src/types.js | 37 ++++++++++++++-----------------------
ts_src/payments/p2tr.ts | 12 +++++++-----
ts_src/types.ts | 19 +++++++++----------
5 files changed, 38 insertions(+), 51 deletions(-)
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index 7d7e93a43..b9db56038 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -85,7 +85,7 @@ function p2tr(a, opts) {
if (a.output) return a.output.slice(2);
if (a.address) return _address().data;
if (o.internalPubkey) {
- const tweakedKey = (0, types_1.tweakPublicKey)(o.internalPubkey, o.hash);
+ const tweakedKey = (0, types_1.tweakKey)(o.internalPubkey, o.hash);
if (tweakedKey) return tweakedKey.x;
}
});
@@ -136,7 +136,7 @@ function p2tr(a, opts) {
else pubkey = a.output.slice(2);
}
if (a.internalPubkey) {
- const tweakedKey = (0, types_1.tweakPublicKey)(a.internalPubkey, o.hash);
+ const tweakedKey = (0, types_1.tweakKey)(a.internalPubkey, o.hash);
if (tweakedKey === null)
throw new TypeError('Invalid internalPubkey for p2tr');
if (pubkey.length > 0 && !pubkey.equals(tweakedKey.x))
@@ -187,14 +187,9 @@ function p2tr(a, opts) {
throw new TypeError('Invalid internalPubkey for p2tr witness');
const leafVersion = controlBlock[0] & 0b11111110;
const script = witness[witness.length - 2];
- const tweak = (0, types_1.computeTweakFromScriptPath)(
- controlBlock,
- script,
- internalPubkey,
- m,
- leafVersion,
- );
- const outputKey = (0, types_1.tweakPublicKey)(internalPubkey, tweak);
+ const tapLeafHash = (0, types_1.leafHash)(script, leafVersion);
+ const hash = (0, types_1.rootHash)(controlBlock, tapLeafHash);
+ const outputKey = (0, types_1.tweakKey)(internalPubkey, hash);
if (!outputKey)
// todo: needs test data
throw new TypeError('Invalid outputKey for p2tr witness');
diff --git a/src/types.d.ts b/src/types.d.ts
index a4813ee4f..b63d2c26b 100644
--- a/src/types.d.ts
+++ b/src/types.d.ts
@@ -1,10 +1,10 @@
///
-import { Buffer as NBuffer } from 'buffer';
export declare const typeforce: any;
export declare function isPoint(p: Buffer | number | undefined | null): boolean;
export declare function liftX(buffer: Buffer): Buffer | null;
-export declare function tweakPublicKey(pubKey: Buffer, h: Buffer | undefined): TweakedPublicKey | null;
-export declare function computeTweakFromScriptPath(controlBlock: Buffer, script: Buffer, internalPubkey: Buffer, m: number, v: number): NBuffer;
+export declare function tweakKey(pubKey: Buffer, h: Buffer | undefined): TweakedPublicKey | null;
+export declare function leafHash(script: Buffer, version: number): Buffer;
+export declare function rootHash(controlBlock: Buffer, tapLeafMsg: Buffer): Buffer;
export declare function UInt31(value: number): boolean;
export declare function BIP32Path(value: string): boolean;
export declare namespace BIP32Path {
diff --git a/src/types.js b/src/types.js
index 07756ecc4..d7fd587fe 100644
--- a/src/types.js
+++ b/src/types.js
@@ -1,6 +1,6 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.oneOf = exports.Null = exports.BufferN = exports.Function = exports.UInt32 = exports.UInt8 = exports.tuple = exports.maybe = exports.Hex = exports.Buffer = exports.String = exports.Boolean = exports.Array = exports.Number = exports.Hash256bit = exports.Hash160bit = exports.Buffer256bit = exports.TaprootNode = exports.TaprootLeaf = exports.Network = exports.ECPoint = exports.Satoshi = exports.Signer = exports.BIP32Path = exports.UInt31 = exports.computeTweakFromScriptPath = exports.tweakPublicKey = exports.liftX = exports.isPoint = exports.typeforce = void 0;
+exports.oneOf = exports.Null = exports.BufferN = exports.Function = exports.UInt32 = exports.UInt8 = exports.tuple = exports.maybe = exports.Hex = exports.Buffer = exports.String = exports.Boolean = exports.Array = exports.Number = exports.Hash256bit = exports.Hash160bit = exports.Buffer256bit = exports.TaprootNode = exports.TaprootLeaf = exports.Network = exports.ECPoint = exports.Satoshi = exports.Signer = exports.BIP32Path = exports.UInt31 = exports.rootHash = exports.leafHash = exports.tweakKey = exports.liftX = exports.isPoint = exports.typeforce = void 0;
const buffer_1 = require('buffer');
const bcrypto = require('./crypto');
const varuint = require('bip174/src/lib/converter/varint');
@@ -69,7 +69,7 @@ const GROUP_ORDER = buffer_1.Buffer.from(
);
// todo: compare buffers dirrectly
const GROUP_ORDER_BN = new BN(GROUP_ORDER);
-function tweakPublicKey(pubKey, h) {
+function tweakKey(pubKey, h) {
if (!buffer_1.Buffer.isBuffer(pubKey)) return null;
if (pubKey.length !== 32) return null;
if (h && h.length !== 32) return null;
@@ -90,22 +90,20 @@ function tweakPublicKey(pubKey, h) {
x: Q.slice(1, 33),
};
}
-exports.tweakPublicKey = tweakPublicKey;
+exports.tweakKey = tweakKey;
const TAP_LEAF_TAG = buffer_1.Buffer.from('TapLeaf', 'utf8');
const TAP_BRANCH_TAG = buffer_1.Buffer.from('TapBranch', 'utf8');
-function computeTweakFromScriptPath(
- controlBlock,
- script,
- internalPubkey,
- m,
- v,
-) {
- const k = [];
- const e = [];
- const tapLeafMsg = buffer_1.Buffer.concat([
- buffer_1.Buffer.from([v]),
+function leafHash(script, version) {
+ return buffer_1.Buffer.concat([
+ buffer_1.Buffer.from([version]),
serializeScript(script),
]);
+}
+exports.leafHash = leafHash;
+function rootHash(controlBlock, tapLeafMsg) {
+ const k = [];
+ const e = [];
+ const m = (controlBlock.length - 33) / 32;
k[0] = bcrypto.taggedHash(TAP_LEAF_TAG, tapLeafMsg);
for (let j = 0; j < m; j++) {
e[j] = controlBlock.slice(33 + 32 * j, 65 + 32 * j);
@@ -121,16 +119,9 @@ function computeTweakFromScriptPath(
);
}
}
- const t = bcrypto.taggedHash(
- TAP_TWEAK_TAG,
- buffer_1.Buffer.concat([internalPubkey, k[m]]),
- );
- if (t.compare(GROUP_ORDER) >= 0) {
- throw new Error('Over the order of secp256k1');
- }
- return t;
+ return k[m];
}
-exports.computeTweakFromScriptPath = computeTweakFromScriptPath;
+exports.rootHash = rootHash;
// todo: move out
function serializeScript(s) {
const varintLen = varuint.encodingLength(s.length);
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index 2abc6a72e..8992a9ca8 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -1,6 +1,6 @@
import { bitcoin as BITCOIN_NETWORK } from '../networks';
import * as bscript from '../script';
-import { liftX, tweakPublicKey, computeTweakFromScriptPath, typeforce as typef } from '../types';
+import { liftX, leafHash, rootHash, tweakKey, typeforce as typef } from '../types';
import { computeMastRoot } from '../merkle';
import { Payment, PaymentOpts } from './index';
import * as lazy from './lazy';
@@ -81,7 +81,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
if (a.output) return a.output.slice(2)
if (a.address) return _address().data;
if (o.internalPubkey) {
- const tweakedKey = tweakPublicKey(o.internalPubkey, o.hash)
+ const tweakedKey = tweakKey(o.internalPubkey, o.hash)
if (tweakedKey) return tweakedKey.x
}
});
@@ -136,7 +136,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
}
if (a.internalPubkey) {
- const tweakedKey = tweakPublicKey(a.internalPubkey, o.hash)
+ const tweakedKey = tweakKey(a.internalPubkey, o.hash)
if (tweakedKey === null) throw new TypeError('Invalid internalPubkey for p2tr');
if (pubkey.length > 0 && !pubkey.equals(tweakedKey.x))
throw new TypeError('Pubkey mismatch');
@@ -189,9 +189,11 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
const leafVersion = controlBlock[0] & 0b11111110;
const script = witness[witness.length - 2];
- const tweak = computeTweakFromScriptPath(controlBlock, script, internalPubkey, m, leafVersion)
+
+ const tapLeafHash = leafHash(script, leafVersion)
+ const hash = rootHash(controlBlock, tapLeafHash)
- const outputKey = tweakPublicKey(internalPubkey, tweak)
+ const outputKey = tweakKey(internalPubkey, hash)
if (!outputKey)
// todo: needs test data
throw new TypeError('Invalid outputKey for p2tr witness');
diff --git a/ts_src/types.ts b/ts_src/types.ts
index 6fe711450..54f3b816d 100644
--- a/ts_src/types.ts
+++ b/ts_src/types.ts
@@ -78,7 +78,7 @@ const GROUP_ORDER = NBuffer.from('fffffffffffffffffffffffffffffffebaaedce6af48a0
// todo: compare buffers dirrectly
const GROUP_ORDER_BN = new BN(GROUP_ORDER);
-export function tweakPublicKey(
+export function tweakKey(
pubKey: Buffer,
h: Buffer | undefined,
): TweakedPublicKey | null {
@@ -109,14 +109,18 @@ export function tweakPublicKey(
const TAP_LEAF_TAG = NBuffer.from('TapLeaf', 'utf8');
const TAP_BRANCH_TAG = NBuffer.from('TapBranch', 'utf8');
-export function computeTweakFromScriptPath(controlBlock: Buffer, script: Buffer, internalPubkey: Buffer, m: number, v: number) {
+
+export function leafHash(script: Buffer, version: number): Buffer {
+ return NBuffer.concat([NBuffer.from([version]), serializeScript(script)]);
+}
+
+export function rootHash(controlBlock: Buffer, tapLeafMsg: Buffer): Buffer {
const k = [];
const e = [];
- const tapLeafMsg = NBuffer.concat([NBuffer.from([v]), serializeScript(script)]);
+ const m = (controlBlock.length - 33) / 32;
k[0] = bcrypto.taggedHash(TAP_LEAF_TAG, tapLeafMsg);
-
for (let j = 0; j < m; j++) {
e[j] = controlBlock.slice(33 + 32 * j, 65 + 32 * j);
if (k[j].compare(e[j]) < 0) {
@@ -126,12 +130,7 @@ export function computeTweakFromScriptPath(controlBlock: Buffer, script: Buffer,
}
}
- const t = bcrypto.taggedHash(TAP_TWEAK_TAG, NBuffer.concat([internalPubkey, k[m]]));
- if (t.compare(GROUP_ORDER) >= 0) {
- throw new Error('Over the order of secp256k1')
- }
-
- return t
+ return k[m]
}
// todo: move out
From c309ff8072384c0d113171d12a409ec2facbd0ee Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Tue, 2 Nov 2021 16:57:31 +0200
Subject: [PATCH 019/144] feat: compute hash from witness control-block
---
src/payments/p2tr.js | 9 ++++++++-
test/fixtures/p2tr.json | 14 ++++++++------
ts_src/payments/p2tr.ts | 12 +++++++++---
3 files changed, 25 insertions(+), 10 deletions(-)
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index b9db56038..a88332b22 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -73,7 +73,14 @@ function p2tr(a, opts) {
lazy.prop(o, 'hash', () => {
if (a.hash) return a.hash;
if (a.scriptsTree) return (0, merkle_1.computeMastRoot)(a.scriptsTree);
- // todo: compute from witness
+ 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 tapLeafHash = (0, types_1.leafHash)(script, leafVersion);
+ return (0, types_1.rootHash)(controlBlock, tapLeafHash);
+ }
return null;
});
lazy.prop(o, 'output', () => {
diff --git a/test/fixtures/p2tr.json b/test/fixtures/p2tr.json
index 532fe2297..24cb6472f 100644
--- a/test/fixtures/p2tr.json
+++ b/test/fixtures/p2tr.json
@@ -106,9 +106,10 @@
"expected": {
"name": "p2tr",
"internalPubkey": "a7957acbaaf7b444c53d9e0c9436e8a8a3247fd515095d66ddf6201918b40a36",
- "pubkey": "a44784d6b2d0159ca57f52e3e6023a4f1960d22c089d019f3656d9e23926dcc9",
- "address": "bc1p53rcf44j6q2eeftl2t37vq36fuvkp53vpzwsr8ek2mv7ywfxmnysdul78t",
- "output": "OP_1 a44784d6b2d0159ca57f52e3e6023a4f1960d22c089d019f3656d9e23926dcc9",
+ "pubkey": "1ebe8b90363bd097aa9f352c8b21914e1886bc09fe9e70c09f33ef2d2abdf4bc",
+ "hash": "c5c62d7fc595ba5fbe61602eb1a29e2e4763408fe1e2b161beb7cb3c71ebcad9",
+ "address": "bc1pr6lghypk80gf025lx5kgkgv3fcvgd0qfl608psylx0hj624a7j7qay80rv",
+ "output": "OP_1 1ebe8b90363bd097aa9f352c8b21914e1886bc09fe9e70c09f33ef2d2abdf4bc",
"signature": null,
"input": null,
"witness": [
@@ -133,9 +134,10 @@
"expected": {
"name": "p2tr",
"internalPubkey": "a7957acbaaf7b444c53d9e0c9436e8a8a3247fd515095d66ddf6201918b40a36",
- "pubkey": "a44784d6b2d0159ca57f52e3e6023a4f1960d22c089d019f3656d9e23926dcc9",
- "address": "bc1p53rcf44j6q2eeftl2t37vq36fuvkp53vpzwsr8ek2mv7ywfxmnysdul78t",
- "output": "OP_1 a44784d6b2d0159ca57f52e3e6023a4f1960d22c089d019f3656d9e23926dcc9",
+ "pubkey": "1ebe8b90363bd097aa9f352c8b21914e1886bc09fe9e70c09f33ef2d2abdf4bc",
+ "hash": "c5c62d7fc595ba5fbe61602eb1a29e2e4763408fe1e2b161beb7cb3c71ebcad9",
+ "address": "bc1pr6lghypk80gf025lx5kgkgv3fcvgd0qfl608psylx0hj624a7j7qay80rv",
+ "output": "OP_1 1ebe8b90363bd097aa9f352c8b21914e1886bc09fe9e70c09f33ef2d2abdf4bc",
"signature": null,
"input": null,
"witness": [
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index 8992a9ca8..b1ed834e6 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -69,7 +69,14 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
lazy.prop(o, 'hash', () => {
if (a.hash) return a.hash;
if (a.scriptsTree) return computeMastRoot(a.scriptsTree)
- // todo: compute from witness
+ 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 tapLeafHash = leafHash(script, leafVersion)
+ return rootHash(controlBlock, tapLeafHash)
+ }
return null
});
lazy.prop(o, 'output', () => {
@@ -186,10 +193,9 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
if (!internalPubkeyPoint)
throw new TypeError('Invalid internalPubkey for p2tr witness');
-
const leafVersion = controlBlock[0] & 0b11111110;
const script = witness[witness.length - 2];
-
+
const tapLeafHash = leafHash(script, leafVersion)
const hash = rootHash(controlBlock, tapLeafHash)
From d0ae719fa2858db6979104847ac2fcd178d419d6 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Tue, 2 Nov 2021 17:26:04 +0200
Subject: [PATCH 020/144] refactor: extract taproot related logic to taproot.ts
file
---
src/merkle.d.ts | 1 -
src/merkle.js | 47 +------------
src/payments/p2tr.js | 24 +++----
src/taproot.d.ts | 7 ++
src/taproot.js | 142 ++++++++++++++++++++++++++++++++++++++++
src/types.d.ts | 7 +-
src/types.js | 122 ++--------------------------------
ts_src/merkle.ts | 41 ------------
ts_src/payments/p2tr.ts | 4 +-
ts_src/taproot.ts | 140 +++++++++++++++++++++++++++++++++++++++
ts_src/types.ts | 123 +---------------------------------
11 files changed, 316 insertions(+), 342 deletions(-)
create mode 100644 src/taproot.d.ts
create mode 100644 src/taproot.js
create mode 100644 ts_src/taproot.ts
diff --git a/src/merkle.d.ts b/src/merkle.d.ts
index d4b43f3ba..d602201b9 100644
--- a/src/merkle.d.ts
+++ b/src/merkle.d.ts
@@ -1,3 +1,2 @@
///
export declare function fastMerkleRoot(values: Buffer[], digestFn: (b: Buffer) => Buffer): Buffer;
-export declare function computeMastRoot(scripts: any): Buffer;
diff --git a/src/merkle.js b/src/merkle.js
index 009260ac4..e93f9cab6 100644
--- a/src/merkle.js
+++ b/src/merkle.js
@@ -1,14 +1,6 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.computeMastRoot = exports.fastMerkleRoot = void 0;
-const buffer_1 = require('buffer');
-const bcrypto = require('./crypto');
-// todo: use varuint-bitcoin??
-const varuint = require('bip174/src/lib/converter/varint');
-// todo: find better place for these consts
-const TAP_LEAF_TAG = buffer_1.Buffer.from('TapLeaf', 'utf8');
-const TAP_BRANCH_TAG = buffer_1.Buffer.from('TapBranch', 'utf8');
-const LEAF_VERSION_TAPSCRIPT = 0xc0;
+exports.fastMerkleRoot = void 0;
function fastMerkleRoot(values, digestFn) {
if (!Array.isArray(values)) throw TypeError('Expected values Array');
if (typeof digestFn !== 'function')
@@ -28,40 +20,3 @@ function fastMerkleRoot(values, digestFn) {
return results[0];
}
exports.fastMerkleRoot = fastMerkleRoot;
-// todo: solve any[]
-function computeMastRoot(scripts) {
- if (scripts.length === 1) {
- const script = scripts[0];
- if (Array.isArray(script)) {
- return computeMastRoot(script);
- }
- script.version = script.version || LEAF_VERSION_TAPSCRIPT;
- if ((script.version & 1) !== 0) throw new Error('Invalid script version'); // todo typedef error
- // todo: if (script.output)scheck is bytes
- const scriptOutput = buffer_1.Buffer.from(script.output, 'hex');
- return bcrypto.taggedHash(
- TAP_LEAF_TAG,
- buffer_1.Buffer.concat([
- buffer_1.Buffer.from([script.version]),
- serializeScript(scriptOutput),
- ]),
- );
- }
- // todo: this is a binary tree, use zero an one index
- const half = Math.trunc(scripts.length / 2);
- let leftHash = computeMastRoot(scripts.slice(0, half));
- let rightHash = computeMastRoot(scripts.slice(half));
- if (leftHash.compare(rightHash) === 1)
- [leftHash, rightHash] = [rightHash, leftHash];
- return bcrypto.taggedHash(
- TAP_BRANCH_TAG,
- buffer_1.Buffer.concat([leftHash, rightHash]),
- );
-}
-exports.computeMastRoot = computeMastRoot;
-function serializeScript(s) {
- const varintLen = varuint.encodingLength(s.length);
- const buffer = buffer_1.Buffer.allocUnsafe(varintLen); // better
- varuint.encode(s.length, buffer);
- return buffer_1.Buffer.concat([buffer, s]);
-}
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index a88332b22..53767318a 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -4,7 +4,7 @@ exports.p2tr = void 0;
const networks_1 = require('../networks');
const bscript = require('../script');
const types_1 = require('../types');
-const merkle_1 = require('../merkle');
+const taproot_1 = require('../taproot');
const lazy = require('./lazy');
const bech32_1 = require('bech32');
const OPS = bscript.OPS;
@@ -72,14 +72,14 @@ function p2tr(a, opts) {
});
lazy.prop(o, 'hash', () => {
if (a.hash) return a.hash;
- if (a.scriptsTree) return (0, merkle_1.computeMastRoot)(a.scriptsTree);
+ if (a.scriptsTree) return (0, taproot_1.computeMastRoot)(a.scriptsTree);
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 tapLeafHash = (0, types_1.leafHash)(script, leafVersion);
- return (0, types_1.rootHash)(controlBlock, tapLeafHash);
+ const tapLeafHash = (0, taproot_1.leafHash)(script, leafVersion);
+ return (0, taproot_1.rootHash)(controlBlock, tapLeafHash);
}
return null;
});
@@ -92,7 +92,7 @@ function p2tr(a, opts) {
if (a.output) return a.output.slice(2);
if (a.address) return _address().data;
if (o.internalPubkey) {
- const tweakedKey = (0, types_1.tweakKey)(o.internalPubkey, o.hash);
+ const tweakedKey = (0, taproot_1.tweakKey)(o.internalPubkey, o.hash);
if (tweakedKey) return tweakedKey.x;
}
});
@@ -143,7 +143,7 @@ function p2tr(a, opts) {
else pubkey = a.output.slice(2);
}
if (a.internalPubkey) {
- const tweakedKey = (0, types_1.tweakKey)(a.internalPubkey, o.hash);
+ const tweakedKey = (0, taproot_1.tweakKey)(a.internalPubkey, o.hash);
if (tweakedKey === null)
throw new TypeError('Invalid internalPubkey for p2tr');
if (pubkey.length > 0 && !pubkey.equals(tweakedKey.x))
@@ -151,11 +151,11 @@ function p2tr(a, opts) {
else pubkey = tweakedKey.x;
}
if (pubkey?.length) {
- if ((0, types_1.liftX)(pubkey) === null)
+ if ((0, taproot_1.liftX)(pubkey) === null)
throw new TypeError('Invalid pubkey for p2tr');
}
if (a.hash && a.scriptsTree) {
- const hash = (0, merkle_1.computeMastRoot)(a.scriptsTree);
+ const hash = (0, taproot_1.computeMastRoot)(a.scriptsTree);
if (!a.hash.equals(hash)) throw new TypeError('Hash mismatch');
}
// todo: review cache
@@ -189,14 +189,14 @@ function p2tr(a, opts) {
const internalPubkey = controlBlock.slice(1, 33);
if (a.internalPubkey && !a.internalPubkey.equals(internalPubkey))
throw new TypeError('Internal pubkey mismatch');
- const internalPubkeyPoint = (0, types_1.liftX)(internalPubkey);
+ const internalPubkeyPoint = (0, taproot_1.liftX)(internalPubkey);
if (!internalPubkeyPoint)
throw new TypeError('Invalid internalPubkey for p2tr witness');
const leafVersion = controlBlock[0] & 0b11111110;
const script = witness[witness.length - 2];
- const tapLeafHash = (0, types_1.leafHash)(script, leafVersion);
- const hash = (0, types_1.rootHash)(controlBlock, tapLeafHash);
- const outputKey = (0, types_1.tweakKey)(internalPubkey, hash);
+ const tapLeafHash = (0, taproot_1.leafHash)(script, leafVersion);
+ const hash = (0, taproot_1.rootHash)(controlBlock, tapLeafHash);
+ const outputKey = (0, taproot_1.tweakKey)(internalPubkey, hash);
if (!outputKey)
// todo: needs test data
throw new TypeError('Invalid outputKey for p2tr witness');
diff --git a/src/taproot.d.ts b/src/taproot.d.ts
new file mode 100644
index 000000000..0391f6bf1
--- /dev/null
+++ b/src/taproot.d.ts
@@ -0,0 +1,7 @@
+///
+import { TweakedPublicKey } from './types';
+export declare function liftX(buffer: Buffer): Buffer | null;
+export declare function tweakKey(pubKey: Buffer, h: Buffer | undefined): TweakedPublicKey | null;
+export declare function leafHash(script: Buffer, version: number): Buffer;
+export declare function rootHash(controlBlock: Buffer, tapLeafMsg: Buffer): Buffer;
+export declare function computeMastRoot(scripts: any): Buffer;
diff --git a/src/taproot.js b/src/taproot.js
new file mode 100644
index 000000000..4930f4331
--- /dev/null
+++ b/src/taproot.js
@@ -0,0 +1,142 @@
+'use strict';
+Object.defineProperty(exports, '__esModule', { value: true });
+exports.computeMastRoot = exports.rootHash = exports.leafHash = exports.tweakKey = exports.liftX = void 0;
+const buffer_1 = require('buffer');
+const BN = require('bn.js');
+const bcrypto = require('./crypto');
+// todo: use varuint-bitcoin??
+const varuint = require('bip174/src/lib/converter/varint');
+const types_1 = require('./types');
+// todo: !!!Temp, to be replaced. Only works because bip32 has it as dependecy. Linting will fail.
+const ecc = require('tiny-secp256k1');
+const LEAF_VERSION_TAPSCRIPT = 0xc0;
+const TAP_LEAF_TAG = buffer_1.Buffer.from('TapLeaf', 'utf8');
+const TAP_BRANCH_TAG = buffer_1.Buffer.from('TapBranch', 'utf8');
+const TAP_TWEAK_TAG = buffer_1.Buffer.from('TapTweak', 'utf8');
+// todo: compare buffers dirrectly
+const GROUP_ORDER = buffer_1.Buffer.from(
+ 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141',
+ 'hex',
+);
+const GROUP_ORDER_BN = new BN(GROUP_ORDER);
+const EC_P_BN = new BN(types_1.EC_P);
+const EC_P_REDUCTION = BN.red(EC_P_BN);
+const EC_P_QUADRATIC_RESIDUE = EC_P_BN.addn(1).divn(4);
+const BN_2 = new BN(2);
+const BN_3 = new BN(3);
+const BN_7 = new BN(7);
+function liftX(buffer) {
+ if (!buffer_1.Buffer.isBuffer(buffer)) return null;
+ if (buffer.length !== 32) return null;
+ if (buffer.compare(types_1.ZERO32) === 0) return null;
+ if (buffer.compare(types_1.EC_P) >= 0) return null;
+ const x = new BN(buffer);
+ const x1 = x.toRed(EC_P_REDUCTION);
+ const ySq = x1
+ .redPow(BN_3)
+ .add(BN_7)
+ .mod(EC_P_BN);
+ const y = ySq.redPow(EC_P_QUADRATIC_RESIDUE);
+ if (!ySq.eq(y.redPow(BN_2))) {
+ return null;
+ }
+ const y1 = y.isEven() ? y : EC_P_BN.sub(y);
+ return buffer_1.Buffer.concat([
+ buffer_1.Buffer.from([0x04]),
+ buffer_1.Buffer.from(x1.toBuffer('be', 32)),
+ buffer_1.Buffer.from(y1.toBuffer('be', 32)),
+ ]);
+}
+exports.liftX = liftX;
+function tweakKey(pubKey, h) {
+ if (!buffer_1.Buffer.isBuffer(pubKey)) return null;
+ if (pubKey.length !== 32) return null;
+ if (h && h.length !== 32) return null;
+ const tweakHash = bcrypto.taggedHash(
+ TAP_TWEAK_TAG,
+ buffer_1.Buffer.concat(h ? [pubKey, h] : [pubKey]),
+ );
+ const t = new BN(tweakHash);
+ if (t.gte(GROUP_ORDER_BN)) {
+ // todo: add test for this case
+ throw new Error('Tweak value over the SECP256K1 Order');
+ }
+ const P = liftX(pubKey);
+ if (P === null) return null;
+ const Q = pointAddScalar(P, tweakHash);
+ return {
+ isOdd: Q[64] % 2 === 1,
+ x: Q.slice(1, 33),
+ };
+}
+exports.tweakKey = tweakKey;
+function leafHash(script, version) {
+ return buffer_1.Buffer.concat([
+ buffer_1.Buffer.from([version]),
+ serializeScript(script),
+ ]);
+}
+exports.leafHash = leafHash;
+function rootHash(controlBlock, tapLeafMsg) {
+ const k = [];
+ const e = [];
+ const m = (controlBlock.length - 33) / 32;
+ k[0] = bcrypto.taggedHash(TAP_LEAF_TAG, tapLeafMsg);
+ 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] = bcrypto.taggedHash(
+ TAP_BRANCH_TAG,
+ buffer_1.Buffer.concat([k[j], e[j]]),
+ );
+ } else {
+ k[j + 1] = bcrypto.taggedHash(
+ TAP_BRANCH_TAG,
+ buffer_1.Buffer.concat([e[j], k[j]]),
+ );
+ }
+ }
+ return k[m];
+}
+exports.rootHash = rootHash;
+// todo: solve any[]
+function computeMastRoot(scripts) {
+ if (scripts.length === 1) {
+ const script = scripts[0];
+ if (Array.isArray(script)) {
+ return computeMastRoot(script);
+ }
+ script.version = script.version || LEAF_VERSION_TAPSCRIPT;
+ if ((script.version & 1) !== 0) throw new Error('Invalid script version'); // todo typedef error
+ // todo: if (script.output)scheck is bytes
+ const scriptOutput = buffer_1.Buffer.from(script.output, 'hex');
+ return bcrypto.taggedHash(
+ TAP_LEAF_TAG,
+ buffer_1.Buffer.concat([
+ buffer_1.Buffer.from([script.version]),
+ serializeScript(scriptOutput),
+ ]),
+ );
+ }
+ // todo: this is a binary tree, use zero an one index
+ const half = Math.trunc(scripts.length / 2);
+ let leftHash = computeMastRoot(scripts.slice(0, half));
+ let rightHash = computeMastRoot(scripts.slice(half));
+ if (leftHash.compare(rightHash) === 1)
+ [leftHash, rightHash] = [rightHash, leftHash];
+ return bcrypto.taggedHash(
+ TAP_BRANCH_TAG,
+ buffer_1.Buffer.concat([leftHash, rightHash]),
+ );
+}
+exports.computeMastRoot = computeMastRoot;
+function serializeScript(s) {
+ const varintLen = varuint.encodingLength(s.length);
+ const buffer = buffer_1.Buffer.allocUnsafe(varintLen); // better
+ varuint.encode(s.length, buffer);
+ return buffer_1.Buffer.concat([buffer, s]);
+}
+// todo: do not use ecc
+function pointAddScalar(P, h) {
+ return ecc.pointAddScalar(P, h);
+}
diff --git a/src/types.d.ts b/src/types.d.ts
index b63d2c26b..6e72a6d47 100644
--- a/src/types.d.ts
+++ b/src/types.d.ts
@@ -1,10 +1,9 @@
///
+import { Buffer as NBuffer } from 'buffer';
export declare const typeforce: any;
+export declare const ZERO32: NBuffer;
+export declare const EC_P: NBuffer;
export declare function isPoint(p: Buffer | number | undefined | null): boolean;
-export declare function liftX(buffer: Buffer): Buffer | null;
-export declare function tweakKey(pubKey: Buffer, h: Buffer | undefined): TweakedPublicKey | null;
-export declare function leafHash(script: Buffer, version: number): Buffer;
-export declare function rootHash(controlBlock: Buffer, tapLeafMsg: Buffer): Buffer;
export declare function UInt31(value: number): boolean;
export declare function BIP32Path(value: string): boolean;
export declare namespace BIP32Path {
diff --git a/src/types.js b/src/types.js
index d7fd587fe..ba62bd813 100644
--- a/src/types.js
+++ b/src/types.js
@@ -1,17 +1,10 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.oneOf = exports.Null = exports.BufferN = exports.Function = exports.UInt32 = exports.UInt8 = exports.tuple = exports.maybe = exports.Hex = exports.Buffer = exports.String = exports.Boolean = exports.Array = exports.Number = exports.Hash256bit = exports.Hash160bit = exports.Buffer256bit = exports.TaprootNode = exports.TaprootLeaf = exports.Network = exports.ECPoint = exports.Satoshi = exports.Signer = exports.BIP32Path = exports.UInt31 = exports.rootHash = exports.leafHash = exports.tweakKey = exports.liftX = exports.isPoint = exports.typeforce = void 0;
+exports.oneOf = exports.Null = exports.BufferN = exports.Function = exports.UInt32 = exports.UInt8 = exports.tuple = exports.maybe = exports.Hex = exports.Buffer = exports.String = exports.Boolean = exports.Array = exports.Number = exports.Hash256bit = exports.Hash160bit = exports.Buffer256bit = exports.TaprootNode = exports.TaprootLeaf = exports.Network = exports.ECPoint = exports.Satoshi = exports.Signer = exports.BIP32Path = exports.UInt31 = exports.isPoint = exports.EC_P = exports.ZERO32 = exports.typeforce = void 0;
const buffer_1 = require('buffer');
-const bcrypto = require('./crypto');
-const varuint = require('bip174/src/lib/converter/varint');
-// Temp, to be replaced
-// Only works because bip32 has it as dependecy. Linting will fail.
-const ecc = require('tiny-secp256k1');
-// todo, use import?
-const BN = require('bn.js');
exports.typeforce = require('typeforce');
-const ZERO32 = buffer_1.Buffer.alloc(32, 0);
-const EC_P = buffer_1.Buffer.from(
+exports.ZERO32 = buffer_1.Buffer.alloc(32, 0);
+exports.EC_P = buffer_1.Buffer.from(
'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f',
'hex',
);
@@ -20,119 +13,18 @@ function isPoint(p) {
if (p.length < 33) return false;
const t = p[0];
const x = p.slice(1, 33);
- if (x.compare(ZERO32) === 0) return false;
- if (x.compare(EC_P) >= 0) return false;
+ if (x.compare(exports.ZERO32) === 0) return false;
+ if (x.compare(exports.EC_P) >= 0) return false;
if ((t === 0x02 || t === 0x03) && p.length === 33) {
return true;
}
const y = p.slice(33);
- if (y.compare(ZERO32) === 0) return false;
- if (y.compare(EC_P) >= 0) return false;
+ if (y.compare(exports.ZERO32) === 0) return false;
+ if (y.compare(exports.EC_P) >= 0) return false;
if (t === 0x04 && p.length === 65) return true;
return false;
}
exports.isPoint = isPoint;
-// todo review. Do not add dependcy to BN?
-const EC_P_BN = new BN(EC_P);
-const EC_P_REDUCTION = BN.red(EC_P_BN);
-const EC_P_QUADRATIC_RESIDUE = EC_P_BN.addn(1).divn(4);
-const BN_2 = new BN(2);
-const BN_3 = new BN(3);
-const BN_7 = new BN(7);
-function liftX(buffer) {
- if (!buffer_1.Buffer.isBuffer(buffer)) return null;
- if (buffer.length !== 32) return null;
- if (buffer.compare(ZERO32) === 0) return null;
- if (buffer.compare(EC_P) >= 0) return null;
- const x = new BN(buffer);
- const x1 = x.toRed(EC_P_REDUCTION);
- const ySq = x1
- .redPow(BN_3)
- .add(BN_7)
- .mod(EC_P_BN);
- const y = ySq.redPow(EC_P_QUADRATIC_RESIDUE);
- if (!ySq.eq(y.redPow(BN_2))) {
- return null;
- }
- const y1 = y.isEven() ? y : EC_P_BN.sub(y);
- return buffer_1.Buffer.concat([
- buffer_1.Buffer.from([0x04]),
- buffer_1.Buffer.from(x1.toBuffer('be', 32)),
- buffer_1.Buffer.from(y1.toBuffer('be', 32)),
- ]);
-}
-exports.liftX = liftX;
-const TAP_TWEAK_TAG = buffer_1.Buffer.from('TapTweak', 'utf8');
-const GROUP_ORDER = buffer_1.Buffer.from(
- 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141',
- 'hex',
-);
-// todo: compare buffers dirrectly
-const GROUP_ORDER_BN = new BN(GROUP_ORDER);
-function tweakKey(pubKey, h) {
- if (!buffer_1.Buffer.isBuffer(pubKey)) return null;
- if (pubKey.length !== 32) return null;
- if (h && h.length !== 32) return null;
- const tweakHash = bcrypto.taggedHash(
- TAP_TWEAK_TAG,
- buffer_1.Buffer.concat(h ? [pubKey, h] : [pubKey]),
- );
- const t = new BN(tweakHash);
- if (t.gte(GROUP_ORDER_BN)) {
- // todo: add test for this case
- throw new Error('Tweak value over the SECP256K1 Order');
- }
- const P = liftX(pubKey);
- if (P === null) return null;
- const Q = pointAddScalar(P, tweakHash);
- return {
- isOdd: Q[64] % 2 === 1,
- x: Q.slice(1, 33),
- };
-}
-exports.tweakKey = tweakKey;
-const TAP_LEAF_TAG = buffer_1.Buffer.from('TapLeaf', 'utf8');
-const TAP_BRANCH_TAG = buffer_1.Buffer.from('TapBranch', 'utf8');
-function leafHash(script, version) {
- return buffer_1.Buffer.concat([
- buffer_1.Buffer.from([version]),
- serializeScript(script),
- ]);
-}
-exports.leafHash = leafHash;
-function rootHash(controlBlock, tapLeafMsg) {
- const k = [];
- const e = [];
- const m = (controlBlock.length - 33) / 32;
- k[0] = bcrypto.taggedHash(TAP_LEAF_TAG, tapLeafMsg);
- 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] = bcrypto.taggedHash(
- TAP_BRANCH_TAG,
- buffer_1.Buffer.concat([k[j], e[j]]),
- );
- } else {
- k[j + 1] = bcrypto.taggedHash(
- TAP_BRANCH_TAG,
- buffer_1.Buffer.concat([e[j], k[j]]),
- );
- }
- }
- return k[m];
-}
-exports.rootHash = rootHash;
-// todo: move out
-function serializeScript(s) {
- const varintLen = varuint.encodingLength(s.length);
- const buffer = buffer_1.Buffer.allocUnsafe(varintLen); // better
- varuint.encode(s.length, buffer);
- return buffer_1.Buffer.concat([buffer, s]);
-}
-// todo: do not use ecc
-function pointAddScalar(P, h) {
- return ecc.pointAddScalar(P, h);
-}
const UINT31_MAX = Math.pow(2, 31) - 1;
function UInt31(value) {
return exports.typeforce.UInt32(value) && value <= UINT31_MAX;
diff --git a/ts_src/merkle.ts b/ts_src/merkle.ts
index 125769215..814819c79 100644
--- a/ts_src/merkle.ts
+++ b/ts_src/merkle.ts
@@ -1,15 +1,3 @@
-import { Buffer as NBuffer } from 'buffer';
-import * as bcrypto from './crypto';
-// todo: use varuint-bitcoin??
-import * as varuint from 'bip174/src/lib/converter/varint';
-
-
-// todo: find better place for these consts
-const TAP_LEAF_TAG = NBuffer.from('TapLeaf', 'utf8');
-const TAP_BRANCH_TAG = NBuffer.from('TapBranch', 'utf8');
-const LEAF_VERSION_TAPSCRIPT = 0xc0
-
-
export function fastMerkleRoot(
values: Buffer[],
digestFn: (b: Buffer) => Buffer,
@@ -36,33 +24,4 @@ export function fastMerkleRoot(
}
return results[0];
-}
-
-// todo: solve any[]
-export function computeMastRoot(scripts: any): Buffer {
- if (scripts.length === 1) {
- const script = scripts[0]
- if (Array.isArray(script)) {
- return computeMastRoot(script)
- }
- script.version = script.version || LEAF_VERSION_TAPSCRIPT
- if ((script.version & 1) !== 0) throw new Error("Invalid script version") // todo typedef error
- // todo: if (script.output)scheck is bytes
- const scriptOutput = NBuffer.from(script.output, 'hex')
- return bcrypto.taggedHash(TAP_LEAF_TAG, NBuffer.concat([NBuffer.from([script.version]), serializeScript(scriptOutput)]))
- }
- // todo: this is a binary tree, use zero an one index
- const half = Math.trunc(scripts.length / 2)
- let leftHash = computeMastRoot(scripts.slice(0, half))
- let rightHash = computeMastRoot(scripts.slice(half))
-
- if (leftHash.compare(rightHash) === 1) [leftHash, rightHash] = [rightHash, leftHash]
- return bcrypto.taggedHash(TAP_BRANCH_TAG, NBuffer.concat([leftHash, rightHash]))
-}
-
-function serializeScript(s: Buffer) {
- const varintLen = varuint.encodingLength(s.length);
- const buffer = NBuffer.allocUnsafe(varintLen); // better
- varuint.encode(s.length, buffer);
- return NBuffer.concat([buffer, s])
}
\ No newline at end of file
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index b1ed834e6..aef500c85 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -1,7 +1,7 @@
import { bitcoin as BITCOIN_NETWORK } from '../networks';
import * as bscript from '../script';
-import { liftX, leafHash, rootHash, tweakKey, typeforce as typef } from '../types';
-import { computeMastRoot } from '../merkle';
+import { typeforce as typef } from '../types';
+import { computeMastRoot, leafHash, rootHash, tweakKey, liftX } from '../taproot';
import { Payment, PaymentOpts } from './index';
import * as lazy from './lazy';
import { bech32m } from 'bech32';
diff --git a/ts_src/taproot.ts b/ts_src/taproot.ts
new file mode 100644
index 000000000..5370e326f
--- /dev/null
+++ b/ts_src/taproot.ts
@@ -0,0 +1,140 @@
+import { Buffer as NBuffer } from 'buffer';
+const BN = require('bn.js');
+
+import * as bcrypto from './crypto';
+// todo: use varuint-bitcoin??
+import * as varuint from 'bip174/src/lib/converter/varint';
+import { TweakedPublicKey, ZERO32, EC_P } from './types'
+
+// todo: !!!Temp, to be replaced. Only works because bip32 has it as dependecy. Linting will fail.
+const ecc = require('tiny-secp256k1');
+
+const LEAF_VERSION_TAPSCRIPT = 0xc0
+const TAP_LEAF_TAG = NBuffer.from('TapLeaf', 'utf8');
+const TAP_BRANCH_TAG = NBuffer.from('TapBranch', 'utf8');
+const TAP_TWEAK_TAG = NBuffer.from('TapTweak', 'utf8');
+
+// todo: compare buffers dirrectly
+const GROUP_ORDER = NBuffer.from('fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141', 'hex');
+const GROUP_ORDER_BN = new BN(GROUP_ORDER);
+
+const EC_P_BN = new BN(EC_P);
+const EC_P_REDUCTION = BN.red(EC_P_BN);
+const EC_P_QUADRATIC_RESIDUE = EC_P_BN.addn(1).divn(4);
+const BN_2 = new BN(2);
+const BN_3 = new BN(3);
+const BN_7 = new BN(7);
+
+export function liftX(buffer: Buffer): Buffer | null {
+ if (!NBuffer.isBuffer(buffer)) return null;
+ if (buffer.length !== 32) return null;
+
+ if (buffer.compare(ZERO32) === 0) return null;
+ if (buffer.compare(EC_P) >= 0) return null;
+
+ const x = new BN(buffer);
+
+ const x1 = x.toRed(EC_P_REDUCTION);
+ const ySq = x1
+ .redPow(BN_3)
+ .add(BN_7)
+ .mod(EC_P_BN);
+
+ const y = ySq.redPow(EC_P_QUADRATIC_RESIDUE);
+
+ if (!ySq.eq(y.redPow(BN_2))) {
+ return null;
+ }
+ const y1 = y.isEven() ? y : EC_P_BN.sub(y);
+
+ return NBuffer.concat([
+ NBuffer.from([0x04]),
+ NBuffer.from(x1.toBuffer('be', 32)),
+ NBuffer.from(y1.toBuffer('be', 32)),
+ ]);
+}
+
+export function tweakKey(
+ pubKey: Buffer,
+ h: Buffer | undefined,
+): TweakedPublicKey | null {
+ if (!NBuffer.isBuffer(pubKey)) return null;
+ if (pubKey.length !== 32) return null;
+ if (h && h.length !== 32) return null;
+
+ const tweakHash = bcrypto.taggedHash(
+ TAP_TWEAK_TAG,
+ NBuffer.concat(h ? [pubKey, h] : [pubKey]),
+ );
+ const t = new BN(tweakHash);
+ if (t.gte(GROUP_ORDER_BN)) {
+ // todo: add test for this case
+ throw new Error('Tweak value over the SECP256K1 Order');
+ }
+
+ const P = liftX(pubKey);
+ if (P === null) return null;
+
+ const Q = pointAddScalar(P, tweakHash);
+ return {
+ isOdd: Q[64] % 2 === 1,
+ x: Q.slice(1, 33),
+ };
+}
+
+export function leafHash(script: Buffer, version: number): Buffer {
+ return NBuffer.concat([NBuffer.from([version]), serializeScript(script)]);
+}
+
+export function rootHash(controlBlock: Buffer, tapLeafMsg: Buffer): Buffer {
+ const k = [];
+ const e = [];
+
+ const m = (controlBlock.length - 33) / 32;
+ k[0] = bcrypto.taggedHash(TAP_LEAF_TAG, tapLeafMsg);
+
+ 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] = bcrypto.taggedHash(TAP_BRANCH_TAG, NBuffer.concat([k[j], e[j]]));
+ } else {
+ k[j + 1] = bcrypto.taggedHash(TAP_BRANCH_TAG, NBuffer.concat([e[j], k[j]]));
+ }
+ }
+
+ return k[m]
+}
+
+// todo: solve any[]
+export function computeMastRoot(scripts: any): Buffer {
+ if (scripts.length === 1) {
+ const script = scripts[0]
+ if (Array.isArray(script)) {
+ return computeMastRoot(script)
+ }
+ script.version = script.version || LEAF_VERSION_TAPSCRIPT
+ if ((script.version & 1) !== 0) throw new Error("Invalid script version") // todo typedef error
+ // todo: if (script.output)scheck is bytes
+ const scriptOutput = NBuffer.from(script.output, 'hex')
+ return bcrypto.taggedHash(TAP_LEAF_TAG, NBuffer.concat([NBuffer.from([script.version]), serializeScript(scriptOutput)]))
+ }
+ // todo: this is a binary tree, use zero an one index
+ const half = Math.trunc(scripts.length / 2)
+ let leftHash = computeMastRoot(scripts.slice(0, half))
+ let rightHash = computeMastRoot(scripts.slice(half))
+
+ if (leftHash.compare(rightHash) === 1) [leftHash, rightHash] = [rightHash, leftHash]
+ return bcrypto.taggedHash(TAP_BRANCH_TAG, NBuffer.concat([leftHash, rightHash]))
+}
+
+function serializeScript(s: Buffer) {
+ const varintLen = varuint.encodingLength(s.length);
+ const buffer = NBuffer.allocUnsafe(varintLen); // better
+ varuint.encode(s.length, buffer);
+ return NBuffer.concat([buffer, s])
+}
+
+// todo: do not use ecc
+function pointAddScalar(P: Buffer, h: Buffer): Buffer {
+ return ecc.pointAddScalar(P, h);
+}
diff --git a/ts_src/types.ts b/ts_src/types.ts
index 54f3b816d..014bfaafc 100644
--- a/ts_src/types.ts
+++ b/ts_src/types.ts
@@ -1,17 +1,9 @@
import { Buffer as NBuffer } from 'buffer';
-import * as bcrypto from './crypto';
-import * as varuint from 'bip174/src/lib/converter/varint';
-
-// Temp, to be replaced
-// Only works because bip32 has it as dependecy. Linting will fail.
-const ecc = require('tiny-secp256k1');
-// todo, use import?
-const BN = require('bn.js');
export const typeforce = require('typeforce');
-const ZERO32 = NBuffer.alloc(32, 0);
-const EC_P = NBuffer.from(
+export const ZERO32 = NBuffer.alloc(32, 0);
+export const EC_P = NBuffer.from(
'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f',
'hex',
);
@@ -35,117 +27,6 @@ export function isPoint(p: Buffer | number | undefined | null): boolean {
return false;
}
-// todo review. Do not add dependcy to BN?
-const EC_P_BN = new BN(EC_P);
-const EC_P_REDUCTION = BN.red(EC_P_BN);
-const EC_P_QUADRATIC_RESIDUE = EC_P_BN.addn(1).divn(4);
-const BN_2 = new BN(2);
-const BN_3 = new BN(3);
-const BN_7 = new BN(7);
-
-export function liftX(buffer: Buffer): Buffer | null {
- if (!NBuffer.isBuffer(buffer)) return null;
- if (buffer.length !== 32) return null;
-
- if (buffer.compare(ZERO32) === 0) return null;
- if (buffer.compare(EC_P) >= 0) return null;
-
- const x = new BN(buffer);
-
- const x1 = x.toRed(EC_P_REDUCTION);
- const ySq = x1
- .redPow(BN_3)
- .add(BN_7)
- .mod(EC_P_BN);
-
- const y = ySq.redPow(EC_P_QUADRATIC_RESIDUE);
-
- if (!ySq.eq(y.redPow(BN_2))) {
- return null;
- }
- const y1 = y.isEven() ? y : EC_P_BN.sub(y);
-
- return NBuffer.concat([
- NBuffer.from([0x04]),
- NBuffer.from(x1.toBuffer('be', 32)),
- NBuffer.from(y1.toBuffer('be', 32)),
- ]);
-}
-
-const TAP_TWEAK_TAG = NBuffer.from('TapTweak', 'utf8');
-
-const GROUP_ORDER = NBuffer.from('fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141', 'hex');
-// todo: compare buffers dirrectly
-const GROUP_ORDER_BN = new BN(GROUP_ORDER);
-
-export function tweakKey(
- pubKey: Buffer,
- h: Buffer | undefined,
-): TweakedPublicKey | null {
- if (!NBuffer.isBuffer(pubKey)) return null;
- if (pubKey.length !== 32) return null;
- if (h && h.length !== 32) return null;
-
- const tweakHash = bcrypto.taggedHash(
- TAP_TWEAK_TAG,
- NBuffer.concat(h ? [pubKey, h] : [pubKey]),
- );
- const t = new BN(tweakHash);
- if (t.gte(GROUP_ORDER_BN)) {
- // todo: add test for this case
- throw new Error('Tweak value over the SECP256K1 Order');
- }
-
- const P = liftX(pubKey);
- if (P === null) return null;
-
- const Q = pointAddScalar(P, tweakHash);
- return {
- isOdd: Q[64] % 2 === 1,
- x: Q.slice(1, 33),
- };
-}
-
-const TAP_LEAF_TAG = NBuffer.from('TapLeaf', 'utf8');
-const TAP_BRANCH_TAG = NBuffer.from('TapBranch', 'utf8');
-
-
-export function leafHash(script: Buffer, version: number): Buffer {
- return NBuffer.concat([NBuffer.from([version]), serializeScript(script)]);
-}
-
-export function rootHash(controlBlock: Buffer, tapLeafMsg: Buffer): Buffer {
- const k = [];
- const e = [];
-
- const m = (controlBlock.length - 33) / 32;
- k[0] = bcrypto.taggedHash(TAP_LEAF_TAG, tapLeafMsg);
-
- 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] = bcrypto.taggedHash(TAP_BRANCH_TAG, NBuffer.concat([k[j], e[j]]));
- } else {
- k[j + 1] = bcrypto.taggedHash(TAP_BRANCH_TAG, NBuffer.concat([e[j], k[j]]));
- }
- }
-
- return k[m]
-}
-
-// todo: move out
-function serializeScript(s: Buffer) {
- const varintLen = varuint.encodingLength(s.length);
- const buffer = NBuffer.allocUnsafe(varintLen); // better
- varuint.encode(s.length, buffer);
- return NBuffer.concat([buffer, s])
-}
-
-// todo: do not use ecc
-function pointAddScalar(P: Buffer, h: Buffer): Buffer {
- return ecc.pointAddScalar(P, h);
-}
-
const UINT31_MAX: number = Math.pow(2, 31) - 1;
export function UInt31(value: number): boolean {
return typeforce.UInt32(value) && value <= UINT31_MAX;
From a8c3f1d47220c7ff36fac2ae8ce01ce8246f20c6 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Tue, 2 Nov 2021 17:40:25 +0200
Subject: [PATCH 021/144] chore: code format and lint
---
src/payments/p2tr.js | 4 +-
test/payments.utils.ts | 19 ++--
ts_src/merkle.ts | 2 +-
ts_src/payments/index.ts | 2 +-
ts_src/payments/p2tr.ts | 91 +++++++++++--------
ts_src/taproot.ts | 189 +++++++++++++++++++++------------------
ts_src/types.ts | 9 +-
7 files changed, 179 insertions(+), 137 deletions(-)
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index 53767318a..22c03b088 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -103,7 +103,7 @@ function p2tr(a, opts) {
return witness[witness.length - 1].slice(1, 33);
});
lazy.prop(o, 'signature', () => {
- if (a.witness?.length !== 1) return;
+ if (!a.witness || a.witness.length !== 1) return;
return a.witness[0];
});
lazy.prop(o, 'input', () => {
@@ -150,7 +150,7 @@ function p2tr(a, opts) {
throw new TypeError('Pubkey mismatch');
else pubkey = tweakedKey.x;
}
- if (pubkey?.length) {
+ if (pubkey && pubkey.length) {
if ((0, taproot_1.liftX)(pubkey) === null)
throw new TypeError('Invalid pubkey for p2tr');
}
diff --git a/test/payments.utils.ts b/test/payments.utils.ts
index d1b40aa5e..1aa401830 100644
--- a/test/payments.utils.ts
+++ b/test/payments.utils.ts
@@ -87,7 +87,11 @@ export function equate(a: any, b: any, args?: any): void {
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');
+ t.strictEqual(
+ tryHex(a.internalPubkey),
+ tryHex(b.internalPubkey),
+ 'Inequal *.internalPubkey',
+ );
if ('signature' in b)
t.strictEqual(
tryHex(a.signature),
@@ -149,8 +153,7 @@ export function preform(x: any): any {
if (x.redeem.network)
x.redeem.network = (BNETWORKS as any)[x.redeem.network];
}
- if (x.scriptsTree)
- x.scriptsTree = convertScriptsTree(x.scriptsTree)
+ if (x.scriptsTree) x.scriptsTree = convertScriptsTree(x.scriptsTree);
return x;
}
@@ -176,12 +179,10 @@ export function from(path: string, object: any, result?: any): any {
// todo: solve any type
function convertScriptsTree(scriptsTree: any): any {
- if (Array.isArray(scriptsTree))
- return scriptsTree.map(convertScriptsTree)
-
+ 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
+ if (typeof script.output === 'string')
+ script.output = asmToBuffer(scriptsTree.output);
+ return script;
}
diff --git a/ts_src/merkle.ts b/ts_src/merkle.ts
index 814819c79..8ff8c3f8c 100644
--- a/ts_src/merkle.ts
+++ b/ts_src/merkle.ts
@@ -24,4 +24,4 @@ export function fastMerkleRoot(
}
return results[0];
-}
\ No newline at end of file
+}
diff --git a/ts_src/payments/index.ts b/ts_src/payments/index.ts
index 5243902d4..f6223a3d0 100644
--- a/ts_src/payments/index.ts
+++ b/ts_src/payments/index.ts
@@ -24,7 +24,7 @@ export interface Payment {
address?: string; // taproot: betch32m
hash?: Buffer; // taproot: MAST root
redeem?: Payment; // taproot: when script path spending is used spending
- scriptsTree?: any // todo: solve
+ scriptsTree?: any; // todo: solve
witness?: Buffer[];
}
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index aef500c85..25e52696c 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -1,7 +1,13 @@
import { bitcoin as BITCOIN_NETWORK } from '../networks';
import * as bscript from '../script';
import { typeforce as typef } from '../types';
-import { computeMastRoot, leafHash, rootHash, tweakKey, liftX } from '../taproot';
+import {
+ computeMastRoot,
+ leafHash,
+ rootHash,
+ tweakKey,
+ liftX,
+} from '../taproot';
import { Payment, PaymentOpts } from './index';
import * as lazy from './lazy';
import { bech32m } from 'bech32';
@@ -14,7 +20,14 @@ const ANNEX_PREFIX = 0x50;
// input: <>
// output: OP_1 {pubKey}
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))
+ 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 || {});
@@ -46,13 +59,16 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
});
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)) {
+ 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()
- })
+ return a.witness.slice();
+ });
const network = a.network || BITCOIN_NETWORK;
const o: Payment = { name: 'p2tr', network };
@@ -65,19 +81,18 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
return bech32m.encode(network.bech32, words);
});
-
lazy.prop(o, 'hash', () => {
if (a.hash) return a.hash;
- if (a.scriptsTree) return computeMastRoot(a.scriptsTree)
- const w = _witness()
+ if (a.scriptsTree) return computeMastRoot(a.scriptsTree);
+ 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 tapLeafHash = leafHash(script, leafVersion)
- return rootHash(controlBlock, tapLeafHash)
+ const tapLeafHash = leafHash(script, leafVersion);
+ return rootHash(controlBlock, tapLeafHash);
}
- return null
+ return null;
});
lazy.prop(o, 'output', () => {
if (!o.pubkey) return;
@@ -85,28 +100,28 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
});
lazy.prop(o, 'pubkey', () => {
if (a.pubkey) return a.pubkey;
- if (a.output) return a.output.slice(2)
+ if (a.output) return a.output.slice(2);
if (a.address) return _address().data;
if (o.internalPubkey) {
- const tweakedKey = tweakKey(o.internalPubkey, o.hash)
- if (tweakedKey) return tweakedKey.x
+ const tweakedKey = tweakKey(o.internalPubkey, o.hash);
+ if (tweakedKey) return tweakedKey.x;
}
});
lazy.prop(o, 'internalPubkey', () => {
if (a.internalPubkey) return a.internalPubkey;
- const witness = _witness()
+ const witness = _witness();
if (witness && witness.length > 1)
return witness[witness.length - 1].slice(1, 33);
});
lazy.prop(o, 'signature', () => {
- if (a.witness?.length !== 1) return;
+ if (!a.witness || a.witness.length !== 1) return;
return a.witness[0];
});
lazy.prop(o, 'input', () => {
// todo: not sure
});
lazy.prop(o, 'witness', () => {
- if (a.witness) return a.witness
+ if (a.witness) return a.witness;
if (!a.signature) return;
return [a.signature];
});
@@ -143,26 +158,26 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
}
if (a.internalPubkey) {
- const tweakedKey = tweakKey(a.internalPubkey, o.hash)
- if (tweakedKey === null) throw new TypeError('Invalid internalPubkey for p2tr');
+ const tweakedKey = tweakKey(a.internalPubkey, o.hash);
+ if (tweakedKey === null)
+ throw new TypeError('Invalid internalPubkey for p2tr');
if (pubkey.length > 0 && !pubkey.equals(tweakedKey.x))
throw new TypeError('Pubkey mismatch');
else pubkey = tweakedKey.x;
}
- if (pubkey?.length) {
+ if (pubkey && pubkey.length) {
if (liftX(pubkey) === null)
throw new TypeError('Invalid pubkey for p2tr');
}
if (a.hash && a.scriptsTree) {
- const hash = computeMastRoot(a.scriptsTree)
- if (!a.hash.equals(hash))
- throw new TypeError('Hash mismatch');
+ const hash = computeMastRoot(a.scriptsTree);
+ if (!a.hash.equals(hash)) throw new TypeError('Hash mismatch');
}
// todo: review cache
- const witness = _witness()
+ const witness = _witness();
if (witness && witness.length) {
if (witness.length === 1) {
@@ -176,14 +191,22 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
// 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.`);
+ 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!`);
+ 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.`);
+ 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))
@@ -196,10 +219,10 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
const leafVersion = controlBlock[0] & 0b11111110;
const script = witness[witness.length - 2];
- const tapLeafHash = leafHash(script, leafVersion)
- const hash = rootHash(controlBlock, tapLeafHash)
+ const tapLeafHash = leafHash(script, leafVersion);
+ const hash = rootHash(controlBlock, tapLeafHash);
- const outputKey = tweakKey(internalPubkey, hash)
+ const outputKey = tweakKey(internalPubkey, hash);
if (!outputKey)
// todo: needs test data
throw new TypeError('Invalid outputKey for p2tr witness');
@@ -207,12 +230,10 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
if (pubkey.length && !pubkey.equals(outputKey.x))
throw new TypeError('Pubkey mismatch for p2tr witness');
- const controlBlockOddParity = (controlBlock[0] & 1) === 1
+ const controlBlockOddParity = (controlBlock[0] & 1) === 1;
if (outputKey.isOdd !== controlBlockOddParity)
- throw new Error('Incorrect parity')
-
+ throw new Error('Incorrect parity');
}
-
}
}
diff --git a/ts_src/taproot.ts b/ts_src/taproot.ts
index 5370e326f..de4083b0e 100644
--- a/ts_src/taproot.ts
+++ b/ts_src/taproot.ts
@@ -4,18 +4,21 @@ const BN = require('bn.js');
import * as bcrypto from './crypto';
// todo: use varuint-bitcoin??
import * as varuint from 'bip174/src/lib/converter/varint';
-import { TweakedPublicKey, ZERO32, EC_P } from './types'
+import { TweakedPublicKey, ZERO32, EC_P } from './types';
// todo: !!!Temp, to be replaced. Only works because bip32 has it as dependecy. Linting will fail.
const ecc = require('tiny-secp256k1');
-const LEAF_VERSION_TAPSCRIPT = 0xc0
+const LEAF_VERSION_TAPSCRIPT = 0xc0;
const TAP_LEAF_TAG = NBuffer.from('TapLeaf', 'utf8');
const TAP_BRANCH_TAG = NBuffer.from('TapBranch', 'utf8');
const TAP_TWEAK_TAG = NBuffer.from('TapTweak', 'utf8');
// todo: compare buffers dirrectly
-const GROUP_ORDER = NBuffer.from('fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141', 'hex');
+const GROUP_ORDER = NBuffer.from(
+ 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141',
+ 'hex',
+);
const GROUP_ORDER_BN = new BN(GROUP_ORDER);
const EC_P_BN = new BN(EC_P);
@@ -26,115 +29,131 @@ const BN_3 = new BN(3);
const BN_7 = new BN(7);
export function liftX(buffer: Buffer): Buffer | null {
- if (!NBuffer.isBuffer(buffer)) return null;
- if (buffer.length !== 32) return null;
+ if (!NBuffer.isBuffer(buffer)) return null;
+ if (buffer.length !== 32) return null;
- if (buffer.compare(ZERO32) === 0) return null;
- if (buffer.compare(EC_P) >= 0) return null;
+ if (buffer.compare(ZERO32) === 0) return null;
+ if (buffer.compare(EC_P) >= 0) return null;
- const x = new BN(buffer);
+ const x = new BN(buffer);
- const x1 = x.toRed(EC_P_REDUCTION);
- const ySq = x1
- .redPow(BN_3)
- .add(BN_7)
- .mod(EC_P_BN);
+ const x1 = x.toRed(EC_P_REDUCTION);
+ const ySq = x1
+ .redPow(BN_3)
+ .add(BN_7)
+ .mod(EC_P_BN);
- const y = ySq.redPow(EC_P_QUADRATIC_RESIDUE);
+ const y = ySq.redPow(EC_P_QUADRATIC_RESIDUE);
- if (!ySq.eq(y.redPow(BN_2))) {
- return null;
- }
- const y1 = y.isEven() ? y : EC_P_BN.sub(y);
+ if (!ySq.eq(y.redPow(BN_2))) {
+ return null;
+ }
+ const y1 = y.isEven() ? y : EC_P_BN.sub(y);
- return NBuffer.concat([
- NBuffer.from([0x04]),
- NBuffer.from(x1.toBuffer('be', 32)),
- NBuffer.from(y1.toBuffer('be', 32)),
- ]);
+ return NBuffer.concat([
+ NBuffer.from([0x04]),
+ NBuffer.from(x1.toBuffer('be', 32)),
+ NBuffer.from(y1.toBuffer('be', 32)),
+ ]);
}
export function tweakKey(
- pubKey: Buffer,
- h: Buffer | undefined,
+ pubKey: Buffer,
+ h: Buffer | undefined,
): TweakedPublicKey | null {
- if (!NBuffer.isBuffer(pubKey)) return null;
- if (pubKey.length !== 32) return null;
- if (h && h.length !== 32) return null;
-
- const tweakHash = bcrypto.taggedHash(
- TAP_TWEAK_TAG,
- NBuffer.concat(h ? [pubKey, h] : [pubKey]),
- );
- const t = new BN(tweakHash);
- if (t.gte(GROUP_ORDER_BN)) {
- // todo: add test for this case
- throw new Error('Tweak value over the SECP256K1 Order');
- }
-
- const P = liftX(pubKey);
- if (P === null) return null;
-
- const Q = pointAddScalar(P, tweakHash);
- return {
- isOdd: Q[64] % 2 === 1,
- x: Q.slice(1, 33),
- };
+ if (!NBuffer.isBuffer(pubKey)) return null;
+ if (pubKey.length !== 32) return null;
+ if (h && h.length !== 32) return null;
+
+ const tweakHash = bcrypto.taggedHash(
+ TAP_TWEAK_TAG,
+ NBuffer.concat(h ? [pubKey, h] : [pubKey]),
+ );
+ const t = new BN(tweakHash);
+ if (t.gte(GROUP_ORDER_BN)) {
+ // todo: add test for this case
+ throw new Error('Tweak value over the SECP256K1 Order');
+ }
+
+ const P = liftX(pubKey);
+ if (P === null) return null;
+
+ const Q = pointAddScalar(P, tweakHash);
+ return {
+ isOdd: Q[64] % 2 === 1,
+ x: Q.slice(1, 33),
+ };
}
export function leafHash(script: Buffer, version: number): Buffer {
- return NBuffer.concat([NBuffer.from([version]), serializeScript(script)]);
+ return NBuffer.concat([NBuffer.from([version]), serializeScript(script)]);
}
export function rootHash(controlBlock: Buffer, tapLeafMsg: Buffer): Buffer {
- const k = [];
- const e = [];
-
- const m = (controlBlock.length - 33) / 32;
- k[0] = bcrypto.taggedHash(TAP_LEAF_TAG, tapLeafMsg);
-
- 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] = bcrypto.taggedHash(TAP_BRANCH_TAG, NBuffer.concat([k[j], e[j]]));
- } else {
- k[j + 1] = bcrypto.taggedHash(TAP_BRANCH_TAG, NBuffer.concat([e[j], k[j]]));
- }
+ const k = [];
+ const e = [];
+
+ const m = (controlBlock.length - 33) / 32;
+ k[0] = bcrypto.taggedHash(TAP_LEAF_TAG, tapLeafMsg);
+
+ 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] = bcrypto.taggedHash(
+ TAP_BRANCH_TAG,
+ NBuffer.concat([k[j], e[j]]),
+ );
+ } else {
+ k[j + 1] = bcrypto.taggedHash(
+ TAP_BRANCH_TAG,
+ NBuffer.concat([e[j], k[j]]),
+ );
}
+ }
- return k[m]
+ return k[m];
}
// todo: solve any[]
export function computeMastRoot(scripts: any): Buffer {
- if (scripts.length === 1) {
- const script = scripts[0]
- if (Array.isArray(script)) {
- return computeMastRoot(script)
- }
- script.version = script.version || LEAF_VERSION_TAPSCRIPT
- if ((script.version & 1) !== 0) throw new Error("Invalid script version") // todo typedef error
- // todo: if (script.output)scheck is bytes
- const scriptOutput = NBuffer.from(script.output, 'hex')
- return bcrypto.taggedHash(TAP_LEAF_TAG, NBuffer.concat([NBuffer.from([script.version]), serializeScript(scriptOutput)]))
+ if (scripts.length === 1) {
+ const script = scripts[0];
+ if (Array.isArray(script)) {
+ return computeMastRoot(script);
}
- // todo: this is a binary tree, use zero an one index
- const half = Math.trunc(scripts.length / 2)
- let leftHash = computeMastRoot(scripts.slice(0, half))
- let rightHash = computeMastRoot(scripts.slice(half))
-
- if (leftHash.compare(rightHash) === 1) [leftHash, rightHash] = [rightHash, leftHash]
- return bcrypto.taggedHash(TAP_BRANCH_TAG, NBuffer.concat([leftHash, rightHash]))
+ script.version = script.version || LEAF_VERSION_TAPSCRIPT;
+ if ((script.version & 1) !== 0) throw new Error('Invalid script version'); // todo typedef error
+ // todo: if (script.output)scheck is bytes
+ const scriptOutput = NBuffer.from(script.output, 'hex');
+ return bcrypto.taggedHash(
+ TAP_LEAF_TAG,
+ NBuffer.concat([
+ NBuffer.from([script.version]),
+ serializeScript(scriptOutput),
+ ]),
+ );
+ }
+ // todo: this is a binary tree, use zero an one index
+ const half = Math.trunc(scripts.length / 2);
+ let leftHash = computeMastRoot(scripts.slice(0, half));
+ let rightHash = computeMastRoot(scripts.slice(half));
+
+ if (leftHash.compare(rightHash) === 1)
+ [leftHash, rightHash] = [rightHash, leftHash];
+ return bcrypto.taggedHash(
+ TAP_BRANCH_TAG,
+ NBuffer.concat([leftHash, rightHash]),
+ );
}
-function serializeScript(s: Buffer) {
- const varintLen = varuint.encodingLength(s.length);
- const buffer = NBuffer.allocUnsafe(varintLen); // better
- varuint.encode(s.length, buffer);
- return NBuffer.concat([buffer, s])
+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]);
}
// todo: do not use ecc
function pointAddScalar(P: Buffer, h: Buffer): Buffer {
- return ecc.pointAddScalar(P, h);
+ return ecc.pointAddScalar(P, h);
}
diff --git a/ts_src/types.ts b/ts_src/types.ts
index 014bfaafc..fd0893df5 100644
--- a/ts_src/types.ts
+++ b/ts_src/types.ts
@@ -74,12 +74,13 @@ export interface TweakedPublicKey {
export const TaprootLeaf = typeforce.compile({
output: typeforce.BufferN(34),
- version: typeforce.maybe(typeforce.UInt8) // todo: recheck
-})
+ version: typeforce.maybe(typeforce.UInt8), // todo: recheck
+});
// / todo: revisit
-export const TaprootNode = typeforce.arrayOf(typeforce.oneOf(TaprootLeaf, typeforce.arrayOf(TaprootLeaf)))
-
+export const TaprootNode = typeforce.arrayOf(
+ typeforce.oneOf(TaprootLeaf, typeforce.arrayOf(TaprootLeaf)),
+);
export const Buffer256bit = typeforce.BufferN(32);
export const Hash160bit = typeforce.BufferN(20);
From 6fa79d6e60ea534fadd20d3e6c3bdb49a5e1187a Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Tue, 2 Nov 2021 17:49:59 +0200
Subject: [PATCH 022/144] refactor: compare GROUP_ORDER as buffer (instead of
using BN.js)
---
src/taproot.js | 9 +--------
src/types.d.ts | 1 +
src/types.js | 6 +++++-
ts_src/taproot.ts | 13 +++----------
ts_src/types.ts | 4 ++++
5 files changed, 14 insertions(+), 19 deletions(-)
diff --git a/src/taproot.js b/src/taproot.js
index 4930f4331..f0cade074 100644
--- a/src/taproot.js
+++ b/src/taproot.js
@@ -13,12 +13,6 @@ const LEAF_VERSION_TAPSCRIPT = 0xc0;
const TAP_LEAF_TAG = buffer_1.Buffer.from('TapLeaf', 'utf8');
const TAP_BRANCH_TAG = buffer_1.Buffer.from('TapBranch', 'utf8');
const TAP_TWEAK_TAG = buffer_1.Buffer.from('TapTweak', 'utf8');
-// todo: compare buffers dirrectly
-const GROUP_ORDER = buffer_1.Buffer.from(
- 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141',
- 'hex',
-);
-const GROUP_ORDER_BN = new BN(GROUP_ORDER);
const EC_P_BN = new BN(types_1.EC_P);
const EC_P_REDUCTION = BN.red(EC_P_BN);
const EC_P_QUADRATIC_RESIDUE = EC_P_BN.addn(1).divn(4);
@@ -56,8 +50,7 @@ function tweakKey(pubKey, h) {
TAP_TWEAK_TAG,
buffer_1.Buffer.concat(h ? [pubKey, h] : [pubKey]),
);
- const t = new BN(tweakHash);
- if (t.gte(GROUP_ORDER_BN)) {
+ if (tweakHash.compare(types_1.GROUP_ORDER) >= 0) {
// todo: add test for this case
throw new Error('Tweak value over the SECP256K1 Order');
}
diff --git a/src/types.d.ts b/src/types.d.ts
index 6e72a6d47..7f58a0a87 100644
--- a/src/types.d.ts
+++ b/src/types.d.ts
@@ -3,6 +3,7 @@ import { Buffer as NBuffer } from 'buffer';
export declare const typeforce: any;
export declare const ZERO32: NBuffer;
export declare const EC_P: NBuffer;
+export declare const GROUP_ORDER: NBuffer;
export declare function isPoint(p: Buffer | number | undefined | null): boolean;
export declare function UInt31(value: number): boolean;
export declare function BIP32Path(value: string): boolean;
diff --git a/src/types.js b/src/types.js
index ba62bd813..ff1786256 100644
--- a/src/types.js
+++ b/src/types.js
@@ -1,6 +1,6 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.oneOf = exports.Null = exports.BufferN = exports.Function = exports.UInt32 = exports.UInt8 = exports.tuple = exports.maybe = exports.Hex = exports.Buffer = exports.String = exports.Boolean = exports.Array = exports.Number = exports.Hash256bit = exports.Hash160bit = exports.Buffer256bit = exports.TaprootNode = exports.TaprootLeaf = exports.Network = exports.ECPoint = exports.Satoshi = exports.Signer = exports.BIP32Path = exports.UInt31 = exports.isPoint = exports.EC_P = exports.ZERO32 = exports.typeforce = void 0;
+exports.oneOf = exports.Null = exports.BufferN = exports.Function = exports.UInt32 = exports.UInt8 = exports.tuple = exports.maybe = exports.Hex = exports.Buffer = exports.String = exports.Boolean = exports.Array = exports.Number = exports.Hash256bit = exports.Hash160bit = exports.Buffer256bit = exports.TaprootNode = exports.TaprootLeaf = exports.Network = exports.ECPoint = exports.Satoshi = exports.Signer = exports.BIP32Path = exports.UInt31 = exports.isPoint = exports.GROUP_ORDER = exports.EC_P = exports.ZERO32 = exports.typeforce = void 0;
const buffer_1 = require('buffer');
exports.typeforce = require('typeforce');
exports.ZERO32 = buffer_1.Buffer.alloc(32, 0);
@@ -8,6 +8,10 @@ exports.EC_P = buffer_1.Buffer.from(
'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f',
'hex',
);
+exports.GROUP_ORDER = buffer_1.Buffer.from(
+ 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141',
+ 'hex',
+);
function isPoint(p) {
if (!buffer_1.Buffer.isBuffer(p)) return false;
if (p.length < 33) return false;
diff --git a/ts_src/taproot.ts b/ts_src/taproot.ts
index de4083b0e..b09e17508 100644
--- a/ts_src/taproot.ts
+++ b/ts_src/taproot.ts
@@ -4,7 +4,7 @@ const BN = require('bn.js');
import * as bcrypto from './crypto';
// todo: use varuint-bitcoin??
import * as varuint from 'bip174/src/lib/converter/varint';
-import { TweakedPublicKey, ZERO32, EC_P } from './types';
+import { TweakedPublicKey, ZERO32, EC_P, GROUP_ORDER } from './types';
// todo: !!!Temp, to be replaced. Only works because bip32 has it as dependecy. Linting will fail.
const ecc = require('tiny-secp256k1');
@@ -14,13 +14,6 @@ const TAP_LEAF_TAG = NBuffer.from('TapLeaf', 'utf8');
const TAP_BRANCH_TAG = NBuffer.from('TapBranch', 'utf8');
const TAP_TWEAK_TAG = NBuffer.from('TapTweak', 'utf8');
-// todo: compare buffers dirrectly
-const GROUP_ORDER = NBuffer.from(
- 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141',
- 'hex',
-);
-const GROUP_ORDER_BN = new BN(GROUP_ORDER);
-
const EC_P_BN = new BN(EC_P);
const EC_P_REDUCTION = BN.red(EC_P_BN);
const EC_P_QUADRATIC_RESIDUE = EC_P_BN.addn(1).divn(4);
@@ -69,8 +62,8 @@ export function tweakKey(
TAP_TWEAK_TAG,
NBuffer.concat(h ? [pubKey, h] : [pubKey]),
);
- const t = new BN(tweakHash);
- if (t.gte(GROUP_ORDER_BN)) {
+
+ if (tweakHash.compare(GROUP_ORDER) >= 0) {
// todo: add test for this case
throw new Error('Tweak value over the SECP256K1 Order');
}
diff --git a/ts_src/types.ts b/ts_src/types.ts
index fd0893df5..e04a05589 100644
--- a/ts_src/types.ts
+++ b/ts_src/types.ts
@@ -7,6 +7,10 @@ export const EC_P = NBuffer.from(
'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f',
'hex',
);
+export const GROUP_ORDER = NBuffer.from(
+ 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141',
+ 'hex',
+);
export function isPoint(p: Buffer | number | undefined | null): boolean {
if (!NBuffer.isBuffer(p)) return false;
From cafcde01e9110b5d0fe8b0e081386b7a15b92370 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Wed, 3 Nov 2021 09:43:38 +0200
Subject: [PATCH 023/144] refactor: rename `rootHash` to `rootHashFromPath` and
`computeMastRoot` to `rootHashFromTree`
---
src/payments/p2tr.js | 8 ++++----
src/taproot.d.ts | 4 ++--
src/taproot.js | 16 ++++++++--------
ts_src/payments/p2tr.ts | 13 ++++++-------
ts_src/taproot.ts | 10 +++++-----
5 files changed, 25 insertions(+), 26 deletions(-)
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index 22c03b088..50e99536d 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -72,14 +72,14 @@ function p2tr(a, opts) {
});
lazy.prop(o, 'hash', () => {
if (a.hash) return a.hash;
- if (a.scriptsTree) return (0, taproot_1.computeMastRoot)(a.scriptsTree);
+ if (a.scriptsTree) return (0, taproot_1.rootHashFromTree)(a.scriptsTree);
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 tapLeafHash = (0, taproot_1.leafHash)(script, leafVersion);
- return (0, taproot_1.rootHash)(controlBlock, tapLeafHash);
+ return (0, taproot_1.rootHashFromPath)(controlBlock, tapLeafHash);
}
return null;
});
@@ -155,7 +155,7 @@ function p2tr(a, opts) {
throw new TypeError('Invalid pubkey for p2tr');
}
if (a.hash && a.scriptsTree) {
- const hash = (0, taproot_1.computeMastRoot)(a.scriptsTree);
+ const hash = (0, taproot_1.rootHashFromTree)(a.scriptsTree);
if (!a.hash.equals(hash)) throw new TypeError('Hash mismatch');
}
// todo: review cache
@@ -195,7 +195,7 @@ function p2tr(a, opts) {
const leafVersion = controlBlock[0] & 0b11111110;
const script = witness[witness.length - 2];
const tapLeafHash = (0, taproot_1.leafHash)(script, leafVersion);
- const hash = (0, taproot_1.rootHash)(controlBlock, tapLeafHash);
+ const hash = (0, taproot_1.rootHashFromPath)(controlBlock, tapLeafHash);
const outputKey = (0, taproot_1.tweakKey)(internalPubkey, hash);
if (!outputKey)
// todo: needs test data
diff --git a/src/taproot.d.ts b/src/taproot.d.ts
index 0391f6bf1..581c09f13 100644
--- a/src/taproot.d.ts
+++ b/src/taproot.d.ts
@@ -3,5 +3,5 @@ import { TweakedPublicKey } from './types';
export declare function liftX(buffer: Buffer): Buffer | null;
export declare function tweakKey(pubKey: Buffer, h: Buffer | undefined): TweakedPublicKey | null;
export declare function leafHash(script: Buffer, version: number): Buffer;
-export declare function rootHash(controlBlock: Buffer, tapLeafMsg: Buffer): Buffer;
-export declare function computeMastRoot(scripts: any): Buffer;
+export declare function rootHashFromPath(controlBlock: Buffer, tapLeafMsg: Buffer): Buffer;
+export declare function rootHashFromTree(scripts: any): Buffer;
diff --git a/src/taproot.js b/src/taproot.js
index f0cade074..10452a88e 100644
--- a/src/taproot.js
+++ b/src/taproot.js
@@ -1,6 +1,6 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.computeMastRoot = exports.rootHash = exports.leafHash = exports.tweakKey = exports.liftX = void 0;
+exports.rootHashFromTree = exports.rootHashFromPath = exports.leafHash = exports.tweakKey = exports.liftX = void 0;
const buffer_1 = require('buffer');
const BN = require('bn.js');
const bcrypto = require('./crypto');
@@ -70,7 +70,7 @@ function leafHash(script, version) {
]);
}
exports.leafHash = leafHash;
-function rootHash(controlBlock, tapLeafMsg) {
+function rootHashFromPath(controlBlock, tapLeafMsg) {
const k = [];
const e = [];
const m = (controlBlock.length - 33) / 32;
@@ -91,13 +91,13 @@ function rootHash(controlBlock, tapLeafMsg) {
}
return k[m];
}
-exports.rootHash = rootHash;
+exports.rootHashFromPath = rootHashFromPath;
// todo: solve any[]
-function computeMastRoot(scripts) {
+function rootHashFromTree(scripts) {
if (scripts.length === 1) {
const script = scripts[0];
if (Array.isArray(script)) {
- return computeMastRoot(script);
+ return rootHashFromTree(script);
}
script.version = script.version || LEAF_VERSION_TAPSCRIPT;
if ((script.version & 1) !== 0) throw new Error('Invalid script version'); // todo typedef error
@@ -113,8 +113,8 @@ function computeMastRoot(scripts) {
}
// todo: this is a binary tree, use zero an one index
const half = Math.trunc(scripts.length / 2);
- let leftHash = computeMastRoot(scripts.slice(0, half));
- let rightHash = computeMastRoot(scripts.slice(half));
+ let leftHash = rootHashFromTree(scripts.slice(0, half));
+ let rightHash = rootHashFromTree(scripts.slice(half));
if (leftHash.compare(rightHash) === 1)
[leftHash, rightHash] = [rightHash, leftHash];
return bcrypto.taggedHash(
@@ -122,7 +122,7 @@ function computeMastRoot(scripts) {
buffer_1.Buffer.concat([leftHash, rightHash]),
);
}
-exports.computeMastRoot = computeMastRoot;
+exports.rootHashFromTree = rootHashFromTree;
function serializeScript(s) {
const varintLen = varuint.encodingLength(s.length);
const buffer = buffer_1.Buffer.allocUnsafe(varintLen); // better
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index 25e52696c..ccbf4790d 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -2,9 +2,9 @@ import { bitcoin as BITCOIN_NETWORK } from '../networks';
import * as bscript from '../script';
import { typeforce as typef } from '../types';
import {
- computeMastRoot,
+ rootHashFromTree,
+ rootHashFromPath,
leafHash,
- rootHash,
tweakKey,
liftX,
} from '../taproot';
@@ -83,14 +83,14 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
lazy.prop(o, 'hash', () => {
if (a.hash) return a.hash;
- if (a.scriptsTree) return computeMastRoot(a.scriptsTree);
+ if (a.scriptsTree) return rootHashFromTree(a.scriptsTree);
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 tapLeafHash = leafHash(script, leafVersion);
- return rootHash(controlBlock, tapLeafHash);
+ return rootHashFromPath(controlBlock, tapLeafHash);
}
return null;
});
@@ -172,11 +172,10 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
}
if (a.hash && a.scriptsTree) {
- const hash = computeMastRoot(a.scriptsTree);
+ const hash = rootHashFromTree(a.scriptsTree);
if (!a.hash.equals(hash)) throw new TypeError('Hash mismatch');
}
- // todo: review cache
const witness = _witness();
if (witness && witness.length) {
@@ -220,7 +219,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
const script = witness[witness.length - 2];
const tapLeafHash = leafHash(script, leafVersion);
- const hash = rootHash(controlBlock, tapLeafHash);
+ const hash = rootHashFromPath(controlBlock, tapLeafHash);
const outputKey = tweakKey(internalPubkey, hash);
if (!outputKey)
diff --git a/ts_src/taproot.ts b/ts_src/taproot.ts
index b09e17508..36213b757 100644
--- a/ts_src/taproot.ts
+++ b/ts_src/taproot.ts
@@ -82,7 +82,7 @@ export function leafHash(script: Buffer, version: number): Buffer {
return NBuffer.concat([NBuffer.from([version]), serializeScript(script)]);
}
-export function rootHash(controlBlock: Buffer, tapLeafMsg: Buffer): Buffer {
+export function rootHashFromPath(controlBlock: Buffer, tapLeafMsg: Buffer): Buffer {
const k = [];
const e = [];
@@ -108,11 +108,11 @@ export function rootHash(controlBlock: Buffer, tapLeafMsg: Buffer): Buffer {
}
// todo: solve any[]
-export function computeMastRoot(scripts: any): Buffer {
+export function rootHashFromTree(scripts: any): Buffer {
if (scripts.length === 1) {
const script = scripts[0];
if (Array.isArray(script)) {
- return computeMastRoot(script);
+ return rootHashFromTree(script);
}
script.version = script.version || LEAF_VERSION_TAPSCRIPT;
if ((script.version & 1) !== 0) throw new Error('Invalid script version'); // todo typedef error
@@ -128,8 +128,8 @@ export function computeMastRoot(scripts: any): Buffer {
}
// todo: this is a binary tree, use zero an one index
const half = Math.trunc(scripts.length / 2);
- let leftHash = computeMastRoot(scripts.slice(0, half));
- let rightHash = computeMastRoot(scripts.slice(half));
+ let leftHash = rootHashFromTree(scripts.slice(0, half));
+ let rightHash = rootHashFromTree(scripts.slice(half));
if (leftHash.compare(rightHash) === 1)
[leftHash, rightHash] = [rightHash, leftHash];
From 50682239dc571d6cc016d52df7cc1f3bcdb3713a Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Wed, 3 Nov 2021 15:47:49 +0200
Subject: [PATCH 024/144] tests: add bib341 tests by @sipa; plus refactoring
---
src/payments/index.d.ts | 2 +
src/payments/p2tr.js | 10 ++-
src/taproot.d.ts | 8 +-
src/taproot.js | 30 +++----
src/types.d.ts | 6 +-
src/types.js | 13 +--
test/fixtures/p2tr.json | 176 +++++++++++++++++++++++++++++++++++++++
ts_src/payments/index.ts | 4 +-
ts_src/payments/p2tr.ts | 16 +++-
ts_src/taproot.ts | 25 ++----
ts_src/types.ts | 13 +--
11 files changed, 236 insertions(+), 67 deletions(-)
diff --git a/src/payments/index.d.ts b/src/payments/index.d.ts
index dc1978ab0..0170dd093 100644
--- a/src/payments/index.d.ts
+++ b/src/payments/index.d.ts
@@ -1,5 +1,6 @@
///
import { Network } from '../networks';
+import { TaprootLeaf } from '../types';
import { p2data as embed } from './embed';
import { p2ms } from './p2ms';
import { p2pk } from './p2pk';
@@ -25,6 +26,7 @@ export interface Payment {
hash?: Buffer;
redeem?: Payment;
scriptsTree?: any;
+ scriptLeaf?: TaprootLeaf;
witness?: Buffer[];
}
export declare type PaymentCreator = (a: Payment, opts?: PaymentOpts) => Payment;
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index 50e99536d..1d66fb5f7 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -38,6 +38,10 @@ function p2tr(a, opts) {
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,
);
@@ -87,6 +91,9 @@ function p2tr(a, opts) {
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);
@@ -107,7 +114,7 @@ function p2tr(a, opts) {
return a.witness[0];
});
lazy.prop(o, 'input', () => {
- // todo: not sure
+ // todo
});
lazy.prop(o, 'witness', () => {
if (a.witness) return a.witness;
@@ -158,7 +165,6 @@ function p2tr(a, opts) {
const hash = (0, taproot_1.rootHashFromTree)(a.scriptsTree);
if (!a.hash.equals(hash)) throw new TypeError('Hash mismatch');
}
- // todo: review cache
const witness = _witness();
if (witness && witness.length) {
if (witness.length === 1) {
diff --git a/src/taproot.d.ts b/src/taproot.d.ts
index 581c09f13..39f333958 100644
--- a/src/taproot.d.ts
+++ b/src/taproot.d.ts
@@ -1,7 +1,11 @@
///
-import { TweakedPublicKey } from './types';
+import { TweakedPublicKey, TaprootLeaf } from './types';
export declare function liftX(buffer: Buffer): Buffer | null;
export declare function tweakKey(pubKey: Buffer, h: Buffer | undefined): TweakedPublicKey | null;
export declare function leafHash(script: Buffer, version: number): Buffer;
export declare function rootHashFromPath(controlBlock: Buffer, tapLeafMsg: Buffer): Buffer;
-export declare function rootHashFromTree(scripts: any): Buffer;
+export interface HashTree {
+ rootHash: Buffer;
+ scritptPath?: Buffer;
+}
+export declare function rootHashFromTree(scripts: TaprootLeaf[]): Buffer;
diff --git a/src/taproot.js b/src/taproot.js
index 10452a88e..e749d237e 100644
--- a/src/taproot.js
+++ b/src/taproot.js
@@ -52,7 +52,7 @@ function tweakKey(pubKey, h) {
);
if (tweakHash.compare(types_1.GROUP_ORDER) >= 0) {
// todo: add test for this case
- throw new Error('Tweak value over the SECP256K1 Order');
+ throw new TypeError('Tweak value over the SECP256K1 Order');
}
const P = liftX(pubKey);
if (P === null) return null;
@@ -64,17 +64,19 @@ function tweakKey(pubKey, h) {
}
exports.tweakKey = tweakKey;
function leafHash(script, version) {
- return buffer_1.Buffer.concat([
- buffer_1.Buffer.from([version]),
- serializeScript(script),
- ]);
+ return bcrypto.taggedHash(
+ TAP_LEAF_TAG,
+ buffer_1.Buffer.concat([
+ buffer_1.Buffer.from([version]),
+ serializeScript(script),
+ ]),
+ );
}
exports.leafHash = leafHash;
function rootHashFromPath(controlBlock, tapLeafMsg) {
- const k = [];
+ const k = [tapLeafMsg];
const e = [];
const m = (controlBlock.length - 33) / 32;
- k[0] = bcrypto.taggedHash(TAP_LEAF_TAG, tapLeafMsg);
for (let j = 0; j < m; j++) {
e[j] = controlBlock.slice(33 + 32 * j, 65 + 32 * j);
if (k[j].compare(e[j]) < 0) {
@@ -92,7 +94,6 @@ function rootHashFromPath(controlBlock, tapLeafMsg) {
return k[m];
}
exports.rootHashFromPath = rootHashFromPath;
-// todo: solve any[]
function rootHashFromTree(scripts) {
if (scripts.length === 1) {
const script = scripts[0];
@@ -100,16 +101,9 @@ function rootHashFromTree(scripts) {
return rootHashFromTree(script);
}
script.version = script.version || LEAF_VERSION_TAPSCRIPT;
- if ((script.version & 1) !== 0) throw new Error('Invalid script version'); // todo typedef error
- // todo: if (script.output)scheck is bytes
- const scriptOutput = buffer_1.Buffer.from(script.output, 'hex');
- return bcrypto.taggedHash(
- TAP_LEAF_TAG,
- buffer_1.Buffer.concat([
- buffer_1.Buffer.from([script.version]),
- serializeScript(scriptOutput),
- ]),
- );
+ if ((script.version & 1) !== 0)
+ throw new TypeError('Invalid script version');
+ return leafHash(script.output, script.version);
}
// todo: this is a binary tree, use zero an one index
const half = Math.trunc(scripts.length / 2);
diff --git a/src/types.d.ts b/src/types.d.ts
index 7f58a0a87..b33872800 100644
--- a/src/types.d.ts
+++ b/src/types.d.ts
@@ -18,8 +18,10 @@ export interface TweakedPublicKey {
isOdd: boolean;
x: Buffer;
}
-export declare const TaprootLeaf: any;
-export declare const TaprootNode: any;
+export interface TaprootLeaf {
+ output: Buffer;
+ version?: number;
+}
export declare const Buffer256bit: any;
export declare const Hash160bit: any;
export declare const Hash256bit: any;
diff --git a/src/types.js b/src/types.js
index ff1786256..a8acbef86 100644
--- a/src/types.js
+++ b/src/types.js
@@ -1,6 +1,6 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.oneOf = exports.Null = exports.BufferN = exports.Function = exports.UInt32 = exports.UInt8 = exports.tuple = exports.maybe = exports.Hex = exports.Buffer = exports.String = exports.Boolean = exports.Array = exports.Number = exports.Hash256bit = exports.Hash160bit = exports.Buffer256bit = exports.TaprootNode = exports.TaprootLeaf = exports.Network = exports.ECPoint = exports.Satoshi = exports.Signer = exports.BIP32Path = exports.UInt31 = exports.isPoint = exports.GROUP_ORDER = exports.EC_P = exports.ZERO32 = exports.typeforce = void 0;
+exports.oneOf = exports.Null = exports.BufferN = exports.Function = exports.UInt32 = exports.UInt8 = exports.tuple = exports.maybe = exports.Hex = exports.Buffer = exports.String = exports.Boolean = exports.Array = exports.Number = exports.Hash256bit = exports.Hash160bit = exports.Buffer256bit = exports.Network = exports.ECPoint = exports.Satoshi = exports.Signer = exports.BIP32Path = exports.UInt31 = exports.isPoint = exports.GROUP_ORDER = exports.EC_P = exports.ZERO32 = exports.typeforce = void 0;
const buffer_1 = require('buffer');
exports.typeforce = require('typeforce');
exports.ZERO32 = buffer_1.Buffer.alloc(32, 0);
@@ -72,17 +72,6 @@ exports.Network = exports.typeforce.compile({
scriptHash: exports.typeforce.UInt8,
wif: exports.typeforce.UInt8,
});
-exports.TaprootLeaf = exports.typeforce.compile({
- output: exports.typeforce.BufferN(34),
- version: exports.typeforce.maybe(exports.typeforce.UInt8), // todo: recheck
-});
-// / todo: revisit
-exports.TaprootNode = exports.typeforce.arrayOf(
- exports.typeforce.oneOf(
- exports.TaprootLeaf,
- exports.typeforce.arrayOf(exports.TaprootLeaf),
- ),
-);
exports.Buffer256bit = exports.typeforce.BufferN(32);
exports.Hash160bit = exports.typeforce.BufferN(20);
exports.Hash256bit = exports.typeforce.BufferN(32);
diff --git a/test/fixtures/p2tr.json b/test/fixtures/p2tr.json
index 24cb6472f..cff1fe28f 100644
--- a/test/fixtures/p2tr.json
+++ b/test/fixtures/p2tr.json
@@ -354,6 +354,182 @@
"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",
+ "scriptsTree": [
+ {
+ "output": "d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8 OP_CHECKSIG",
+ "version": 192
+ }
+ ]
+ },
+ "options": {},
+ "expected": {
+ "name": "p2tr",
+ "output": "OP_1 147c9c57132f6e7ecddba9800bb0c4449251c92a1e60371ee77557b6620f3ea3",
+ "pubkey": "147c9c57132f6e7ecddba9800bb0c4449251c92a1e60371ee77557b6620f3ea3",
+ "address": "bc1pz37fc4cn9ah8anwm4xqqhvxygjf9rjf2resrw8h8w4tmvcs0863sa2e586",
+ "hash": "5b75adecf53548f3ec6ad7d78383bf84cc57b55a3127c72b9a2481752dd88b21",
+ "signature": null,
+ "input": null
+ }
+ },
+ {
+ "description": "BIP341 Test case 3",
+ "arguments": {
+ "internalPubkey": "93478e9488f956df2396be2ce6c5cced75f900dfa18e7dabd2428aae78451820",
+ "scriptsTree": [
+ {
+ "output": "b617298552a72ade070667e86ca63b8f5789a9fe8731ef91202a91c9f3459007 OP_CHECKSIG",
+ "version": 192
+ }
+ ]
+ },
+ "options": {},
+ "expected": {
+ "name": "p2tr",
+ "output": "OP_1 e4d810fd50586274face62b8a807eb9719cef49c04177cc6b76a9a4251d5450e",
+ "pubkey": "e4d810fd50586274face62b8a807eb9719cef49c04177cc6b76a9a4251d5450e",
+ "address": "bc1punvppl2stp38f7kwv2u2spltjuvuaayuqsthe34hd2dyy5w4g58qqfuag5",
+ "hash": "c525714a7f49c28aedbbba78c005931a81c234b2f6c99a73e4d06082adc8bf2b",
+ "signature": null,
+ "input": null
+ }
+ },
+ {
+ "description": "BIP341 Test case 4",
+ "arguments": {
+ "internalPubkey": "ee4fe085983462a184015d1f782d6a5f8b9c2b60130aff050ce221ecf3786592",
+ "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",
+ "signature": null,
+ "input": null
+ }
+ },
+ {
+ "description": "BIP341 Test case 5",
+ "arguments": {
+ "internalPubkey": "f9f400803e683727b14f463836e1e78e1c64417638aa066919291a225f0e8dd8",
+ "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",
+ "signature": null,
+ "input": null
+ }
+ },
+ {
+ "description": "BIP341 Test case 6",
+ "arguments": {
+ "internalPubkey": "e0dfe2300b0dd746a3f8674dfd4525623639042569d829c7f0eed9602d263e6f",
+ "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",
+ "signature": null,
+ "input": null
+ }
+ },
+ {
+ "description": "BIP341 Test case 7",
+ "arguments": {
+ "internalPubkey": "55adf4e8967fbd2e29f20ac896e60c3b0f1d5b0efa9d34941b5958c7b0a0312d",
+ "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",
+ "signature": null,
+ "input": null
+ }
}
],
"invalid": [
diff --git a/ts_src/payments/index.ts b/ts_src/payments/index.ts
index f6223a3d0..bcf09e2a6 100644
--- a/ts_src/payments/index.ts
+++ b/ts_src/payments/index.ts
@@ -1,4 +1,5 @@
import { Network } from '../networks';
+import { TaprootLeaf } from '../types';
import { p2data as embed } from './embed';
import { p2ms } from './p2ms';
import { p2pk } from './p2pk';
@@ -23,8 +24,9 @@ export interface Payment {
signature?: Buffer;
address?: string; // taproot: betch32m
hash?: Buffer; // taproot: MAST root
- redeem?: Payment; // taproot: when script path spending is used spending
+ redeem?: Payment;
scriptsTree?: any; // todo: solve
+ scriptLeaf?: TaprootLeaf;
witness?: Buffer[];
}
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index ccbf4790d..eb6d7a443 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -2,7 +2,7 @@ import { bitcoin as BITCOIN_NETWORK } from '../networks';
import * as bscript from '../script';
import { typeforce as typef } from '../types';
import {
- rootHashFromTree,
+ rootHashFromTree,
rootHashFromPath,
leafHash,
tweakKey,
@@ -42,7 +42,12 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
pubkey: typef.maybe(typef.BufferN(32)),
signature: typef.maybe(bscript.isCanonicalScriptSignature),
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,
);
@@ -98,6 +103,10 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
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);
@@ -118,7 +127,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
return a.witness[0];
});
lazy.prop(o, 'input', () => {
- // todo: not sure
+ // todo
});
lazy.prop(o, 'witness', () => {
if (a.witness) return a.witness;
@@ -191,8 +200,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
const controlBlock = witness[witness.length - 1];
if (controlBlock.length < 33)
throw new TypeError(
- `The control-block length is too small. Got ${
- controlBlock.length
+ `The control-block length is too small. Got ${controlBlock.length
}, expected min 33.`,
);
diff --git a/ts_src/taproot.ts b/ts_src/taproot.ts
index 36213b757..0df09e833 100644
--- a/ts_src/taproot.ts
+++ b/ts_src/taproot.ts
@@ -4,7 +4,7 @@ const BN = require('bn.js');
import * as bcrypto from './crypto';
// todo: use varuint-bitcoin??
import * as varuint from 'bip174/src/lib/converter/varint';
-import { TweakedPublicKey, ZERO32, EC_P, GROUP_ORDER } from './types';
+import { TweakedPublicKey, TaprootLeaf, ZERO32, EC_P, GROUP_ORDER } from './types';
// todo: !!!Temp, to be replaced. Only works because bip32 has it as dependecy. Linting will fail.
const ecc = require('tiny-secp256k1');
@@ -65,7 +65,7 @@ export function tweakKey(
if (tweakHash.compare(GROUP_ORDER) >= 0) {
// todo: add test for this case
- throw new Error('Tweak value over the SECP256K1 Order');
+ throw new TypeError('Tweak value over the SECP256K1 Order');
}
const P = liftX(pubKey);
@@ -79,15 +79,14 @@ export function tweakKey(
}
export function leafHash(script: Buffer, version: number): Buffer {
- return NBuffer.concat([NBuffer.from([version]), serializeScript(script)]);
+ return bcrypto.taggedHash(TAP_LEAF_TAG, NBuffer.concat([NBuffer.from([version]), serializeScript(script)]));
}
export function rootHashFromPath(controlBlock: Buffer, tapLeafMsg: Buffer): Buffer {
- const k = [];
+ const k = [tapLeafMsg];
const e = [];
const m = (controlBlock.length - 33) / 32;
- k[0] = bcrypto.taggedHash(TAP_LEAF_TAG, tapLeafMsg);
for (let j = 0; j < m; j++) {
e[j] = controlBlock.slice(33 + 32 * j, 65 + 32 * j);
@@ -107,24 +106,16 @@ export function rootHashFromPath(controlBlock: Buffer, tapLeafMsg: Buffer): Buff
return k[m];
}
-// todo: solve any[]
-export function rootHashFromTree(scripts: any): Buffer {
+export function rootHashFromTree(scripts: TaprootLeaf[]): Buffer {
if (scripts.length === 1) {
const script = scripts[0];
if (Array.isArray(script)) {
return rootHashFromTree(script);
}
script.version = script.version || LEAF_VERSION_TAPSCRIPT;
- if ((script.version & 1) !== 0) throw new Error('Invalid script version'); // todo typedef error
- // todo: if (script.output)scheck is bytes
- const scriptOutput = NBuffer.from(script.output, 'hex');
- return bcrypto.taggedHash(
- TAP_LEAF_TAG,
- NBuffer.concat([
- NBuffer.from([script.version]),
- serializeScript(scriptOutput),
- ]),
- );
+ if ((script.version & 1) !== 0) throw new TypeError('Invalid script version');
+
+ return leafHash(script.output, script.version);
}
// todo: this is a binary tree, use zero an one index
const half = Math.trunc(scripts.length / 2);
diff --git a/ts_src/types.ts b/ts_src/types.ts
index e04a05589..b22ab7261 100644
--- a/ts_src/types.ts
+++ b/ts_src/types.ts
@@ -76,15 +76,10 @@ export interface TweakedPublicKey {
x: Buffer;
}
-export const TaprootLeaf = typeforce.compile({
- output: typeforce.BufferN(34),
- version: typeforce.maybe(typeforce.UInt8), // todo: recheck
-});
-
-// / todo: revisit
-export const TaprootNode = typeforce.arrayOf(
- typeforce.oneOf(TaprootLeaf, typeforce.arrayOf(TaprootLeaf)),
-);
+export interface TaprootLeaf {
+ output: Buffer;
+ version?: number;
+}
export const Buffer256bit = typeforce.BufferN(32);
export const Hash160bit = typeforce.BufferN(20);
From 04a50c098ae0902b99b2d37885131603381a91b3 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Wed, 3 Nov 2021 16:10:00 +0200
Subject: [PATCH 025/144] refactor: extract `tapBranchHash()` rename
`leafHash()` to `tapBranchHash()`
---
src/payments/p2tr.js | 8 ++++----
src/taproot.d.ts | 6 +-----
src/taproot.js | 41 ++++++++++++++++++-----------------------
ts_src/payments/p2tr.ts | 10 +++++-----
ts_src/taproot.ts | 30 +++++++++++++-----------------
5 files changed, 41 insertions(+), 54 deletions(-)
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index 1d66fb5f7..17b8b404a 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -82,8 +82,8 @@ function p2tr(a, opts) {
const controlBlock = w[w.length - 1];
const leafVersion = controlBlock[0] & 0b11111110;
const script = w[w.length - 2];
- const tapLeafHash = (0, taproot_1.leafHash)(script, leafVersion);
- return (0, taproot_1.rootHashFromPath)(controlBlock, tapLeafHash);
+ const leafHash = (0, taproot_1.tapLeafHash)(script, leafVersion);
+ return (0, taproot_1.rootHashFromPath)(controlBlock, leafHash);
}
return null;
});
@@ -200,8 +200,8 @@ function p2tr(a, opts) {
throw new TypeError('Invalid internalPubkey for p2tr witness');
const leafVersion = controlBlock[0] & 0b11111110;
const script = witness[witness.length - 2];
- const tapLeafHash = (0, taproot_1.leafHash)(script, leafVersion);
- const hash = (0, taproot_1.rootHashFromPath)(controlBlock, tapLeafHash);
+ const leafHash = (0, taproot_1.tapLeafHash)(script, leafVersion);
+ const hash = (0, taproot_1.rootHashFromPath)(controlBlock, leafHash);
const outputKey = (0, taproot_1.tweakKey)(internalPubkey, hash);
if (!outputKey)
// todo: needs test data
diff --git a/src/taproot.d.ts b/src/taproot.d.ts
index 39f333958..a552b95b0 100644
--- a/src/taproot.d.ts
+++ b/src/taproot.d.ts
@@ -2,10 +2,6 @@
import { TweakedPublicKey, TaprootLeaf } from './types';
export declare function liftX(buffer: Buffer): Buffer | null;
export declare function tweakKey(pubKey: Buffer, h: Buffer | undefined): TweakedPublicKey | null;
-export declare function leafHash(script: Buffer, version: number): Buffer;
export declare function rootHashFromPath(controlBlock: Buffer, tapLeafMsg: Buffer): Buffer;
-export interface HashTree {
- rootHash: Buffer;
- scritptPath?: Buffer;
-}
export declare function rootHashFromTree(scripts: TaprootLeaf[]): Buffer;
+export declare function tapLeafHash(script: Buffer, version: number): Buffer;
diff --git a/src/taproot.js b/src/taproot.js
index e749d237e..7cc6ab850 100644
--- a/src/taproot.js
+++ b/src/taproot.js
@@ -1,6 +1,6 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.rootHashFromTree = exports.rootHashFromPath = exports.leafHash = exports.tweakKey = exports.liftX = void 0;
+exports.tapLeafHash = exports.rootHashFromTree = exports.rootHashFromPath = exports.tweakKey = exports.liftX = void 0;
const buffer_1 = require('buffer');
const BN = require('bn.js');
const bcrypto = require('./crypto');
@@ -63,16 +63,6 @@ function tweakKey(pubKey, h) {
};
}
exports.tweakKey = tweakKey;
-function leafHash(script, version) {
- return bcrypto.taggedHash(
- TAP_LEAF_TAG,
- buffer_1.Buffer.concat([
- buffer_1.Buffer.from([version]),
- serializeScript(script),
- ]),
- );
-}
-exports.leafHash = leafHash;
function rootHashFromPath(controlBlock, tapLeafMsg) {
const k = [tapLeafMsg];
const e = [];
@@ -80,15 +70,9 @@ function rootHashFromPath(controlBlock, tapLeafMsg) {
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] = bcrypto.taggedHash(
- TAP_BRANCH_TAG,
- buffer_1.Buffer.concat([k[j], e[j]]),
- );
+ k[j + 1] = tapBranchHash(k[j], e[j]);
} else {
- k[j + 1] = bcrypto.taggedHash(
- TAP_BRANCH_TAG,
- buffer_1.Buffer.concat([e[j], k[j]]),
- );
+ k[j + 1] = tapBranchHash(e[j], k[j]);
}
}
return k[m];
@@ -103,7 +87,7 @@ function rootHashFromTree(scripts) {
script.version = script.version || LEAF_VERSION_TAPSCRIPT;
if ((script.version & 1) !== 0)
throw new TypeError('Invalid script version');
- return leafHash(script.output, script.version);
+ return tapLeafHash(script.output, script.version);
}
// todo: this is a binary tree, use zero an one index
const half = Math.trunc(scripts.length / 2);
@@ -111,12 +95,23 @@ function rootHashFromTree(scripts) {
let rightHash = rootHashFromTree(scripts.slice(half));
if (leftHash.compare(rightHash) === 1)
[leftHash, rightHash] = [rightHash, leftHash];
+ return tapBranchHash(leftHash, rightHash);
+}
+exports.rootHashFromTree = rootHashFromTree;
+// todo: rename to tapLeafHash
+function tapLeafHash(script, version) {
return bcrypto.taggedHash(
- TAP_BRANCH_TAG,
- buffer_1.Buffer.concat([leftHash, rightHash]),
+ TAP_LEAF_TAG,
+ buffer_1.Buffer.concat([
+ buffer_1.Buffer.from([version]),
+ serializeScript(script),
+ ]),
);
}
-exports.rootHashFromTree = rootHashFromTree;
+exports.tapLeafHash = tapLeafHash;
+function tapBranchHash(a, b) {
+ return bcrypto.taggedHash(TAP_BRANCH_TAG, buffer_1.Buffer.concat([a, b]));
+}
function serializeScript(s) {
const varintLen = varuint.encodingLength(s.length);
const buffer = buffer_1.Buffer.allocUnsafe(varintLen); // better
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index eb6d7a443..8a79c10f7 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -4,7 +4,7 @@ import { typeforce as typef } from '../types';
import {
rootHashFromTree,
rootHashFromPath,
- leafHash,
+ tapLeafHash,
tweakKey,
liftX,
} from '../taproot';
@@ -94,8 +94,8 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
const controlBlock = w[w.length - 1];
const leafVersion = controlBlock[0] & 0b11111110;
const script = w[w.length - 2];
- const tapLeafHash = leafHash(script, leafVersion);
- return rootHashFromPath(controlBlock, tapLeafHash);
+ const leafHash = tapLeafHash(script, leafVersion);
+ return rootHashFromPath(controlBlock, leafHash);
}
return null;
});
@@ -226,8 +226,8 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
const leafVersion = controlBlock[0] & 0b11111110;
const script = witness[witness.length - 2];
- const tapLeafHash = leafHash(script, leafVersion);
- const hash = rootHashFromPath(controlBlock, tapLeafHash);
+ const leafHash = tapLeafHash(script, leafVersion);
+ const hash = rootHashFromPath(controlBlock, leafHash);
const outputKey = tweakKey(internalPubkey, hash);
if (!outputKey)
diff --git a/ts_src/taproot.ts b/ts_src/taproot.ts
index 0df09e833..6c2477895 100644
--- a/ts_src/taproot.ts
+++ b/ts_src/taproot.ts
@@ -78,10 +78,6 @@ export function tweakKey(
};
}
-export function leafHash(script: Buffer, version: number): Buffer {
- return bcrypto.taggedHash(TAP_LEAF_TAG, NBuffer.concat([NBuffer.from([version]), serializeScript(script)]));
-}
-
export function rootHashFromPath(controlBlock: Buffer, tapLeafMsg: Buffer): Buffer {
const k = [tapLeafMsg];
const e = [];
@@ -91,15 +87,9 @@ export function rootHashFromPath(controlBlock: Buffer, tapLeafMsg: Buffer): Buff
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] = bcrypto.taggedHash(
- TAP_BRANCH_TAG,
- NBuffer.concat([k[j], e[j]]),
- );
+ k[j + 1] = tapBranchHash(k[j], e[j]);
} else {
- k[j + 1] = bcrypto.taggedHash(
- TAP_BRANCH_TAG,
- NBuffer.concat([e[j], k[j]]),
- );
+ k[j + 1] = tapBranchHash(e[j], k[j]);
}
}
@@ -115,7 +105,7 @@ export function rootHashFromTree(scripts: TaprootLeaf[]): Buffer {
script.version = script.version || LEAF_VERSION_TAPSCRIPT;
if ((script.version & 1) !== 0) throw new TypeError('Invalid script version');
- return leafHash(script.output, script.version);
+ return tapLeafHash(script.output, script.version);
}
// todo: this is a binary tree, use zero an one index
const half = Math.trunc(scripts.length / 2);
@@ -124,10 +114,16 @@ export function rootHashFromTree(scripts: TaprootLeaf[]): Buffer {
if (leftHash.compare(rightHash) === 1)
[leftHash, rightHash] = [rightHash, leftHash];
- return bcrypto.taggedHash(
- TAP_BRANCH_TAG,
- NBuffer.concat([leftHash, rightHash]),
- );
+ return tapBranchHash(leftHash, rightHash);
+}
+
+// todo: rename to tapLeafHash
+export function tapLeafHash(script: Buffer, version: number): Buffer {
+ return bcrypto.taggedHash(TAP_LEAF_TAG, NBuffer.concat([NBuffer.from([version]), serializeScript(script)]));
+}
+
+function tapBranchHash(a: Buffer, b: Buffer): Buffer {
+ return bcrypto.taggedHash(TAP_BRANCH_TAG, NBuffer.concat([a, b]), );
}
function serializeScript(s: Buffer): Buffer {
From a98e76b1b8812ce844825e3bf51fabb208af7014 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Wed, 3 Nov 2021 19:15:08 +0200
Subject: [PATCH 026/144] feat: build control-block as part of witness; update
tests
---
src/payments/p2tr.js | 36 +++--
src/taproot.d.ts | 10 +-
src/taproot.js | 45 +++++--
src/types.d.ts | 2 +-
test/fixtures/p2tr.json | 284 +++++++++++++++++++++++++++++++++++++++-
test/payments.utils.ts | 5 +
ts_src/payments/p2tr.ts | 30 +++--
ts_src/taproot.ts | 58 ++++++--
ts_src/types.ts | 2 +-
9 files changed, 426 insertions(+), 46 deletions(-)
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index 17b8b404a..8e48aea87 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -1,6 +1,7 @@
'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');
@@ -52,7 +53,7 @@ function p2tr(a, opts) {
return {
version,
prefix: result.prefix,
- data: Buffer.from(data),
+ data: buffer_1.Buffer.from(data),
};
});
const _witness = lazy.value(() => {
@@ -76,7 +77,7 @@ function p2tr(a, opts) {
});
lazy.prop(o, 'hash', () => {
if (a.hash) return a.hash;
- if (a.scriptsTree) return (0, taproot_1.rootHashFromTree)(a.scriptsTree);
+ if (a.scriptsTree) return (0, taproot_1.toHashTree)(a.scriptsTree).hash;
const w = _witness();
if (w && w.length > 1) {
const controlBlock = w[w.length - 1];
@@ -118,12 +119,32 @@ function p2tr(a, opts) {
});
lazy.prop(o, 'witness', () => {
if (a.witness) return a.witness;
- if (!a.signature) return;
- return [a.signature];
+ if (a.scriptsTree && a.scriptLeaf && a.internalPubkey) {
+ const hashTree = (0, taproot_1.toHashTree)(a.scriptsTree);
+ const leafHash = (0, taproot_1.tapLeafHash)(
+ a.scriptLeaf.output,
+ a.scriptLeaf.version,
+ );
+ const path = (0, taproot_1.findScriptPath)(hashTree, leafHash);
+ const outputKey = (0, taproot_1.tweakKey)(
+ a.internalPubkey,
+ hashTree.hash,
+ );
+ 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.from([]);
+ let pubkey = buffer_1.Buffer.from([]);
if (a.address) {
if (network && network.bech32 !== _address().prefix)
throw new TypeError('Invalid prefix or Network mismatch');
@@ -162,7 +183,7 @@ function p2tr(a, opts) {
throw new TypeError('Invalid pubkey for p2tr');
}
if (a.hash && a.scriptsTree) {
- const hash = (0, taproot_1.rootHashFromTree)(a.scriptsTree);
+ const hash = (0, taproot_1.toHashTree)(a.scriptsTree).hash;
if (!a.hash.equals(hash)) throw new TypeError('Hash mismatch');
}
const witness = _witness();
@@ -208,8 +229,7 @@ function p2tr(a, opts) {
throw new TypeError('Invalid outputKey for p2tr witness');
if (pubkey.length && !pubkey.equals(outputKey.x))
throw new TypeError('Pubkey mismatch for p2tr witness');
- const controlBlockOddParity = (controlBlock[0] & 1) === 1;
- if (outputKey.isOdd !== controlBlockOddParity)
+ if (outputKey.parity !== (controlBlock[0] & 1))
throw new Error('Incorrect parity');
}
}
diff --git a/src/taproot.d.ts b/src/taproot.d.ts
index a552b95b0..c55f10d72 100644
--- a/src/taproot.d.ts
+++ b/src/taproot.d.ts
@@ -3,5 +3,11 @@ import { TweakedPublicKey, TaprootLeaf } from './types';
export declare function liftX(buffer: Buffer): Buffer | null;
export declare function tweakKey(pubKey: Buffer, h: Buffer | undefined): TweakedPublicKey | null;
export declare function rootHashFromPath(controlBlock: Buffer, tapLeafMsg: Buffer): Buffer;
-export declare function rootHashFromTree(scripts: TaprootLeaf[]): Buffer;
-export declare function tapLeafHash(script: Buffer, version: number): Buffer;
+export interface HashTree {
+ hash: Buffer;
+ left?: HashTree;
+ right?: HashTree;
+}
+export declare function toHashTree(scripts: TaprootLeaf[]): HashTree;
+export declare function findScriptPath(node: HashTree, hash: Buffer): Buffer[];
+export declare function tapLeafHash(script: Buffer, version?: number): Buffer;
diff --git a/src/taproot.js b/src/taproot.js
index 7cc6ab850..d11e77799 100644
--- a/src/taproot.js
+++ b/src/taproot.js
@@ -1,6 +1,6 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.tapLeafHash = exports.rootHashFromTree = exports.rootHashFromPath = exports.tweakKey = exports.liftX = void 0;
+exports.tapLeafHash = exports.findScriptPath = exports.toHashTree = exports.rootHashFromPath = exports.tweakKey = exports.liftX = void 0;
const buffer_1 = require('buffer');
const BN = require('bn.js');
const bcrypto = require('./crypto');
@@ -58,7 +58,7 @@ function tweakKey(pubKey, h) {
if (P === null) return null;
const Q = pointAddScalar(P, tweakHash);
return {
- isOdd: Q[64] % 2 === 1,
+ parity: Q[64] % 2,
x: Q.slice(1, 33),
};
}
@@ -78,28 +78,53 @@ function rootHashFromPath(controlBlock, tapLeafMsg) {
return k[m];
}
exports.rootHashFromPath = rootHashFromPath;
-function rootHashFromTree(scripts) {
+function toHashTree(scripts) {
if (scripts.length === 1) {
const script = scripts[0];
if (Array.isArray(script)) {
- return rootHashFromTree(script);
+ return toHashTree(script);
}
script.version = script.version || LEAF_VERSION_TAPSCRIPT;
if ((script.version & 1) !== 0)
throw new TypeError('Invalid script version');
- return tapLeafHash(script.output, script.version);
+ return {
+ hash: tapLeafHash(script.output, script.version),
+ };
}
// todo: this is a binary tree, use zero an one index
const half = Math.trunc(scripts.length / 2);
- let leftHash = rootHashFromTree(scripts.slice(0, half));
- let rightHash = rootHashFromTree(scripts.slice(half));
+ const left = toHashTree(scripts.slice(0, half));
+ const right = toHashTree(scripts.slice(half));
+ let leftHash = left.hash;
+ let rightHash = right.hash;
if (leftHash.compare(rightHash) === 1)
[leftHash, rightHash] = [rightHash, leftHash];
- return tapBranchHash(leftHash, rightHash);
+ return {
+ hash: tapBranchHash(leftHash, rightHash),
+ left,
+ right,
+ };
+}
+exports.toHashTree = toHashTree;
+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.rootHashFromTree = rootHashFromTree;
-// todo: rename to tapLeafHash
+exports.findScriptPath = findScriptPath;
function tapLeafHash(script, version) {
+ version = version || LEAF_VERSION_TAPSCRIPT;
return bcrypto.taggedHash(
TAP_LEAF_TAG,
buffer_1.Buffer.concat([
diff --git a/src/types.d.ts b/src/types.d.ts
index b33872800..1bcb12426 100644
--- a/src/types.d.ts
+++ b/src/types.d.ts
@@ -15,7 +15,7 @@ export declare function Satoshi(value: number): boolean;
export declare const ECPoint: any;
export declare const Network: any;
export interface TweakedPublicKey {
- isOdd: boolean;
+ parity: number;
x: Buffer;
}
export interface TaprootLeaf {
diff --git a/test/fixtures/p2tr.json b/test/fixtures/p2tr.json
index cff1fe28f..1ef6ed62d 100644
--- a/test/fixtures/p2tr.json
+++ b/test/fixtures/p2tr.json
@@ -375,6 +375,10 @@
"description": "BIP341 Test case 2",
"arguments": {
"internalPubkey": "187791b6f712a8ea41c8ecdd0ee77fab3e85263b37e1ec18a3651926b3a6cf27",
+ "scriptLeaf": {
+ "output": "d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8 OP_CHECKSIG",
+ "version": 192
+ },
"scriptsTree": [
{
"output": "d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8 OP_CHECKSIG",
@@ -389,6 +393,10 @@
"pubkey": "147c9c57132f6e7ecddba9800bb0c4449251c92a1e60371ee77557b6620f3ea3",
"address": "bc1pz37fc4cn9ah8anwm4xqqhvxygjf9rjf2resrw8h8w4tmvcs0863sa2e586",
"hash": "5b75adecf53548f3ec6ad7d78383bf84cc57b55a3127c72b9a2481752dd88b21",
+ "witness": [
+ "20d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8ac",
+ "c1187791b6f712a8ea41c8ecdd0ee77fab3e85263b37e1ec18a3651926b3a6cf27"
+ ],
"signature": null,
"input": null
}
@@ -397,6 +405,10 @@
"description": "BIP341 Test case 3",
"arguments": {
"internalPubkey": "93478e9488f956df2396be2ce6c5cced75f900dfa18e7dabd2428aae78451820",
+ "scriptLeaf": {
+ "output": "b617298552a72ade070667e86ca63b8f5789a9fe8731ef91202a91c9f3459007 OP_CHECKSIG",
+ "version": 192
+ },
"scriptsTree": [
{
"output": "b617298552a72ade070667e86ca63b8f5789a9fe8731ef91202a91c9f3459007 OP_CHECKSIG",
@@ -411,14 +423,56 @@
"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",
+ "description": "BIP341 Test case 4 - spend leaf 1",
"arguments": {
"internalPubkey": "ee4fe085983462a184015d1f782d6a5f8b9c2b60130aff050ce221ecf3786592",
+ "scriptLeaf": {
+ "output": "424950333431 OP_CHECKSIG",
+ "version": 152
+ },
"scriptsTree": [
{
"output": "387671353e273264c495656e27e39ba899ea8fee3bb69fb2a680e22093447d48 OP_CHECKSIG",
@@ -437,14 +491,22 @@
"pubkey": "0f63ca2c7639b9bb4be0465cc0aa3ee78a0761ba5f5f7d6ff8eab340f09da561",
"address": "bc1ppa3u5trk8xumkjlqgewvp237u79qwcd6ta0h6mlca2e5puya54ssw9zq0y",
"hash": "f3004d6c183e038105d436db1424f321613366cbb7b05939bf05d763a9ebb962",
+ "witness": [
+ "06424950333431ac",
+ "98ee4fe085983462a184015d1f782d6a5f8b9c2b60130aff050ce221ecf37865928ad69ec7cf41c2a4001fd1f738bf1e505ce2277acdcaa63fe4765192497f47a7"
+ ],
"signature": null,
"input": null
}
},
{
- "description": "BIP341 Test case 5",
+ "description": "BIP341 Test case 5 - spend leaf 0",
"arguments": {
"internalPubkey": "f9f400803e683727b14f463836e1e78e1c64417638aa066919291a225f0e8dd8",
+ "scriptLeaf": {
+ "output": "44b178d64c32c4a05cc4f4d1407268f764c940d20ce97abfd44db5c3592b72fd OP_CHECKSIG",
+ "version": 192
+ },
"scriptsTree": [
{
"output": "44b178d64c32c4a05cc4f4d1407268f764c940d20ce97abfd44db5c3592b72fd OP_CHECKSIG",
@@ -463,14 +525,136 @@
"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",
+ "description": "BIP341 Test case 6 - spend leaf 2",
"arguments": {
"internalPubkey": "e0dfe2300b0dd746a3f8674dfd4525623639042569d829c7f0eed9602d263e6f",
+ "scriptLeaf": {
+ "output": "7337c0dd4253cb86f2c43a2351aadd82cccb12a172cd120452b9bb8324f2186a OP_CHECKSIG",
+ "version": 192
+ },
"scriptsTree": [
{
"output": "72ea6adcf1d371dea8fba1035a09f3d24ed5a059799bae114084130ee5898e69 OP_CHECKSIG",
@@ -495,14 +679,22 @@
"pubkey": "91b64d5324723a985170e4dc5a0f84c041804f2cd12660fa5dec09fc21783605",
"address": "bc1pjxmy65eywgafs5tsunw95ruycpqcqnev6ynxp7jaasylcgtcxczs6n332e",
"hash": "ccbd66c6f7e8fdab47b3a486f59d28262be857f30d4773f2d5ea47f7761ce0e2",
+ "witness": [
+ "207337c0dd4253cb86f2c43a2351aadd82cccb12a172cd120452b9bb8324f2186aac",
+ "c0e0dfe2300b0dd746a3f8674dfd4525623639042569d829c7f0eed9602d263e6fba982a91d4fc552163cb1c0da03676102d5b7a014304c01f0c77b2b8e888de1c2645a02e0aac1fe69d69755733a9b7621b694bb5b5cde2bbfc94066ed62b9817"
+ ],
"signature": null,
"input": null
}
},
{
- "description": "BIP341 Test case 7",
+ "description": "BIP341 Test case 7 - spend leaf 0",
"arguments": {
"internalPubkey": "55adf4e8967fbd2e29f20ac896e60c3b0f1d5b0efa9d34941b5958c7b0a0312d",
+ "scriptLeaf": {
+ "output": "71981521ad9fc9036687364118fb6ccd2035b96a423c59c5430e98310a11abe2 OP_CHECKSIG",
+ "version": 192
+ },
"scriptsTree": [
{
"output": "71981521ad9fc9036687364118fb6ccd2035b96a423c59c5430e98310a11abe2 OP_CHECKSIG",
@@ -527,6 +719,90 @@
"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
}
diff --git a/test/payments.utils.ts b/test/payments.utils.ts
index 1aa401830..d4aee8374 100644
--- a/test/payments.utils.ts
+++ b/test/payments.utils.ts
@@ -153,6 +153,11 @@ 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;
}
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index 8a79c10f7..476ffadbc 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -1,9 +1,11 @@
+import { Buffer as NBuffer } from 'buffer';
import { bitcoin as BITCOIN_NETWORK } from '../networks';
import * as bscript from '../script';
import { typeforce as typef } from '../types';
import {
- rootHashFromTree,
+ toHashTree,
rootHashFromPath,
+ findScriptPath,
tapLeafHash,
tweakKey,
liftX,
@@ -59,7 +61,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
return {
version,
prefix: result.prefix,
- data: Buffer.from(data),
+ data: NBuffer.from(data),
};
});
@@ -88,7 +90,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
lazy.prop(o, 'hash', () => {
if (a.hash) return a.hash;
- if (a.scriptsTree) return rootHashFromTree(a.scriptsTree);
+ if (a.scriptsTree) return toHashTree(a.scriptsTree).hash;
const w = _witness();
if (w && w.length > 1) {
const controlBlock = w[w.length - 1];
@@ -105,7 +107,6 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
});
lazy.prop(o, 'scriptLeaf', () => {
if (!a.scriptLeaf) return a.scriptLeaf;
-
});
lazy.prop(o, 'pubkey', () => {
if (a.pubkey) return a.pubkey;
@@ -131,13 +132,23 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
});
lazy.prop(o, 'witness', () => {
if (a.witness) return a.witness;
- if (!a.signature) return;
- return [a.signature];
+ 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);
+ 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 = Buffer.from([]);
+ let pubkey: Buffer = NBuffer.from([]);
if (a.address) {
if (network && network.bech32 !== _address().prefix)
throw new TypeError('Invalid prefix or Network mismatch');
@@ -181,7 +192,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
}
if (a.hash && a.scriptsTree) {
- const hash = rootHashFromTree(a.scriptsTree);
+ const hash = toHashTree(a.scriptsTree).hash;
if (!a.hash.equals(hash)) throw new TypeError('Hash mismatch');
}
@@ -237,8 +248,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
if (pubkey.length && !pubkey.equals(outputKey.x))
throw new TypeError('Pubkey mismatch for p2tr witness');
- const controlBlockOddParity = (controlBlock[0] & 1) === 1;
- if (outputKey.isOdd !== controlBlockOddParity)
+ if (outputKey.parity !== (controlBlock[0] & 1))
throw new Error('Incorrect parity');
}
}
diff --git a/ts_src/taproot.ts b/ts_src/taproot.ts
index 6c2477895..e1bb718db 100644
--- a/ts_src/taproot.ts
+++ b/ts_src/taproot.ts
@@ -73,7 +73,7 @@ export function tweakKey(
const Q = pointAddScalar(P, tweakHash);
return {
- isOdd: Q[64] % 2 === 1,
+ parity: Q[64] % 2,
x: Q.slice(1, 33),
};
}
@@ -96,34 +96,72 @@ export function rootHashFromPath(controlBlock: Buffer, tapLeafMsg: Buffer): Buff
return k[m];
}
-export function rootHashFromTree(scripts: TaprootLeaf[]): Buffer {
+export interface HashTree {
+ hash: Buffer
+ left?: HashTree
+ right?: HashTree
+}
+
+
+export function toHashTree(scripts: TaprootLeaf[]): HashTree {
if (scripts.length === 1) {
const script = scripts[0];
if (Array.isArray(script)) {
- return rootHashFromTree(script);
+ return toHashTree(script);
}
script.version = script.version || LEAF_VERSION_TAPSCRIPT;
if ((script.version & 1) !== 0) throw new TypeError('Invalid script version');
- return tapLeafHash(script.output, script.version);
+ return {
+ hash: tapLeafHash(script.output, script.version)
+ }
+
}
// todo: this is a binary tree, use zero an one index
const half = Math.trunc(scripts.length / 2);
- let leftHash = rootHashFromTree(scripts.slice(0, half));
- let rightHash = rootHashFromTree(scripts.slice(half));
+ const left = toHashTree(scripts.slice(0, half));
+ const right = toHashTree(scripts.slice(half));
+
+ let leftHash = left.hash;
+ let rightHash = right.hash;
if (leftHash.compare(rightHash) === 1)
[leftHash, rightHash] = [rightHash, leftHash];
- return tapBranchHash(leftHash, rightHash);
+ return {
+ hash: tapBranchHash(leftHash, rightHash),
+ left,
+ right
+ }
+}
+
+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 []
+
}
-// todo: rename to tapLeafHash
-export function tapLeafHash(script: Buffer, version: number): Buffer {
+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)]));
}
function tapBranchHash(a: Buffer, b: Buffer): Buffer {
- return bcrypto.taggedHash(TAP_BRANCH_TAG, NBuffer.concat([a, b]), );
+ return bcrypto.taggedHash(TAP_BRANCH_TAG, NBuffer.concat([a, b]),);
}
function serializeScript(s: Buffer): Buffer {
diff --git a/ts_src/types.ts b/ts_src/types.ts
index b22ab7261..7fd2452f1 100644
--- a/ts_src/types.ts
+++ b/ts_src/types.ts
@@ -72,7 +72,7 @@ export const Network = typeforce.compile({
});
export interface TweakedPublicKey {
- isOdd: boolean;
+ parity: number;
x: Buffer;
}
From bf41ac7bbf32a6b6afa11fd869b5f734d01c9af3 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Wed, 3 Nov 2021 19:28:22 +0200
Subject: [PATCH 027/144] chore: lint & format; fix: discovered bug in
findScriptPath() after lint
---
src/payments/p2tr.js | 1 +
src/taproot.js | 5 ++--
test/fixtures/p2tr.json | 4 +--
ts_src/payments/p2tr.ts | 22 ++++++++-------
ts_src/taproot.ts | 60 +++++++++++++++++++++++------------------
5 files changed, 52 insertions(+), 40 deletions(-)
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index 8e48aea87..2de193f7c 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -120,6 +120,7 @@ function p2tr(a, opts) {
lazy.prop(o, 'witness', () => {
if (a.witness) return a.witness;
if (a.scriptsTree && a.scriptLeaf && a.internalPubkey) {
+ // todo: optimize/cache
const hashTree = (0, taproot_1.toHashTree)(a.scriptsTree);
const leafHash = (0, taproot_1.tapLeafHash)(
a.scriptLeaf.output,
diff --git a/src/taproot.js b/src/taproot.js
index d11e77799..220274d61 100644
--- a/src/taproot.js
+++ b/src/taproot.js
@@ -116,9 +116,8 @@ function findScriptPath(node, hash) {
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;
+ if (rightPath.length)
+ return node.left ? [node.left.hash].concat(rightPath) : rightPath;
}
return [];
}
diff --git a/test/fixtures/p2tr.json b/test/fixtures/p2tr.json
index 1ef6ed62d..da89f26f6 100644
--- a/test/fixtures/p2tr.json
+++ b/test/fixtures/p2tr.json
@@ -470,7 +470,7 @@
"arguments": {
"internalPubkey": "ee4fe085983462a184015d1f782d6a5f8b9c2b60130aff050ce221ecf3786592",
"scriptLeaf": {
- "output": "424950333431 OP_CHECKSIG",
+ "output": "424950333431",
"version": 152
},
"scriptsTree": [
@@ -492,7 +492,7 @@
"address": "bc1ppa3u5trk8xumkjlqgewvp237u79qwcd6ta0h6mlca2e5puya54ssw9zq0y",
"hash": "f3004d6c183e038105d436db1424f321613366cbb7b05939bf05d763a9ebb962",
"witness": [
- "06424950333431ac",
+ "06424950333431",
"98ee4fe085983462a184015d1f782d6a5f8b9c2b60130aff050ce221ecf37865928ad69ec7cf41c2a4001fd1f738bf1e505ce2277acdcaa63fe4765192497f47a7"
],
"signature": null,
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index 476ffadbc..0dff7713b 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -44,7 +44,6 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
pubkey: typef.maybe(typef.BufferN(32)),
signature: typef.maybe(bscript.isCanonicalScriptSignature),
witness: typef.maybe(typef.arrayOf(typef.Buffer)),
-
// scriptsTree: typef.maybe(typef.TaprootNode), // use merkel.isMast ?
scriptLeaf: typef.maybe({
version: typef.maybe(typef.Number),
@@ -134,14 +133,18 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
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 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);
- 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 (!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];
});
@@ -211,7 +214,8 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
const controlBlock = witness[witness.length - 1];
if (controlBlock.length < 33)
throw new TypeError(
- `The control-block length is too small. Got ${controlBlock.length
+ `The control-block length is too small. Got ${
+ controlBlock.length
}, expected min 33.`,
);
diff --git a/ts_src/taproot.ts b/ts_src/taproot.ts
index e1bb718db..d364670a9 100644
--- a/ts_src/taproot.ts
+++ b/ts_src/taproot.ts
@@ -4,7 +4,13 @@ const BN = require('bn.js');
import * as bcrypto from './crypto';
// todo: use varuint-bitcoin??
import * as varuint from 'bip174/src/lib/converter/varint';
-import { TweakedPublicKey, TaprootLeaf, ZERO32, EC_P, GROUP_ORDER } from './types';
+import {
+ TweakedPublicKey,
+ TaprootLeaf,
+ ZERO32,
+ EC_P,
+ GROUP_ORDER,
+} from './types';
// todo: !!!Temp, to be replaced. Only works because bip32 has it as dependecy. Linting will fail.
const ecc = require('tiny-secp256k1');
@@ -78,7 +84,10 @@ export function tweakKey(
};
}
-export function rootHashFromPath(controlBlock: Buffer, tapLeafMsg: Buffer): Buffer {
+export function rootHashFromPath(
+ controlBlock: Buffer,
+ tapLeafMsg: Buffer,
+): Buffer {
const k = [tapLeafMsg];
const e = [];
@@ -97,12 +106,11 @@ export function rootHashFromPath(controlBlock: Buffer, tapLeafMsg: Buffer): Buff
}
export interface HashTree {
- hash: Buffer
- left?: HashTree
- right?: HashTree
+ hash: Buffer;
+ left?: HashTree;
+ right?: HashTree;
}
-
export function toHashTree(scripts: TaprootLeaf[]): HashTree {
if (scripts.length === 1) {
const script = scripts[0];
@@ -110,12 +118,12 @@ export function toHashTree(scripts: TaprootLeaf[]): HashTree {
return toHashTree(script);
}
script.version = script.version || LEAF_VERSION_TAPSCRIPT;
- if ((script.version & 1) !== 0) throw new TypeError('Invalid script version');
+ if ((script.version & 1) !== 0)
+ throw new TypeError('Invalid script version');
return {
- hash: tapLeafHash(script.output, script.version)
- }
-
+ hash: tapLeafHash(script.output, script.version),
+ };
}
// todo: this is a binary tree, use zero an one index
const half = Math.trunc(scripts.length / 2);
@@ -130,38 +138,38 @@ export function toHashTree(scripts: TaprootLeaf[]): HashTree {
return {
hash: tapBranchHash(leftHash, rightHash),
left,
- right
- }
+ right,
+ };
}
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 (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
+ 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
+ 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 []
-
+ 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)]));
+ version = version || LEAF_VERSION_TAPSCRIPT;
+ return bcrypto.taggedHash(
+ TAP_LEAF_TAG,
+ NBuffer.concat([NBuffer.from([version]), serializeScript(script)]),
+ );
}
function tapBranchHash(a: Buffer, b: Buffer): Buffer {
- return bcrypto.taggedHash(TAP_BRANCH_TAG, NBuffer.concat([a, b]),);
+ return bcrypto.taggedHash(TAP_BRANCH_TAG, NBuffer.concat([a, b]));
}
function serializeScript(s: Buffer): Buffer {
From b3073794390321a46190bddb8a794dbea23ea164 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Wed, 3 Nov 2021 20:00:42 +0200
Subject: [PATCH 028/144] chore: code clean-up; fix o.scriptLeaf (needs tests)
---
src/payments/p2tr.js | 5 +----
ts_src/payments/index.ts | 10 +++++-----
ts_src/payments/p2tr.ts | 5 +----
3 files changed, 7 insertions(+), 13 deletions(-)
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index 2de193f7c..435d2f101 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -11,9 +11,6 @@ const bech32_1 = require('bech32');
const OPS = bscript.OPS;
const TAPROOT_VERSION = 0x01;
const ANNEX_PREFIX = 0x50;
-// witness: {signature}
-// input: <>
-// output: OP_1 {pubKey}
function p2tr(a, opts) {
if (
!a.address &&
@@ -93,7 +90,7 @@ function p2tr(a, opts) {
return bscript.compile([OPS.OP_1, o.pubkey]);
});
lazy.prop(o, 'scriptLeaf', () => {
- if (!a.scriptLeaf) return a.scriptLeaf;
+ if (a.scriptLeaf) return a.scriptLeaf;
});
lazy.prop(o, 'pubkey', () => {
if (a.pubkey) return a.pubkey;
diff --git a/ts_src/payments/index.ts b/ts_src/payments/index.ts
index bcf09e2a6..996f292e9 100644
--- a/ts_src/payments/index.ts
+++ b/ts_src/payments/index.ts
@@ -12,18 +12,18 @@ import { p2tr } from './p2tr';
export interface Payment {
name?: string;
network?: Network;
- output?: Buffer; // the full scriptPubKey
+ output?: Buffer;
data?: Buffer[];
m?: number;
n?: number;
pubkeys?: Buffer[];
input?: Buffer;
signatures?: Buffer[];
- internalPubkey?: Buffer; // taproot: output key
- pubkey?: Buffer; // taproot: output key
+ internalPubkey?: Buffer;
+ pubkey?: Buffer;
signature?: Buffer;
- address?: string; // taproot: betch32m
- hash?: Buffer; // taproot: MAST root
+ address?: string;
+ hash?: Buffer;
redeem?: Payment;
scriptsTree?: any; // todo: solve
scriptLeaf?: TaprootLeaf;
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index 0dff7713b..98ca8eb56 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -18,9 +18,6 @@ const OPS = bscript.OPS;
const TAPROOT_VERSION = 0x01;
const ANNEX_PREFIX = 0x50;
-// witness: {signature}
-// input: <>
-// output: OP_1 {pubKey}
export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
if (
!a.address &&
@@ -105,7 +102,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
return bscript.compile([OPS.OP_1, o.pubkey]);
});
lazy.prop(o, 'scriptLeaf', () => {
- if (!a.scriptLeaf) return a.scriptLeaf;
+ if (a.scriptLeaf) return a.scriptLeaf;
});
lazy.prop(o, 'pubkey', () => {
if (a.pubkey) return a.pubkey;
From a3bfa84c5bcac4bc3e98d4322cd2eed9417a3ed5 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Fri, 12 Nov 2021 12:13:26 +0200
Subject: [PATCH 029/144] chore: update taggedHash() prefix after rebase
---
src/taproot.js | 6 +++---
ts_src/taproot.ts | 6 +++---
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/taproot.js b/src/taproot.js
index 220274d61..0bb77079d 100644
--- a/src/taproot.js
+++ b/src/taproot.js
@@ -10,9 +10,9 @@ const types_1 = require('./types');
// todo: !!!Temp, to be replaced. Only works because bip32 has it as dependecy. Linting will fail.
const ecc = require('tiny-secp256k1');
const LEAF_VERSION_TAPSCRIPT = 0xc0;
-const TAP_LEAF_TAG = buffer_1.Buffer.from('TapLeaf', 'utf8');
-const TAP_BRANCH_TAG = buffer_1.Buffer.from('TapBranch', 'utf8');
-const TAP_TWEAK_TAG = buffer_1.Buffer.from('TapTweak', 'utf8');
+const TAP_LEAF_TAG = 'TapLeaf';
+const TAP_BRANCH_TAG = 'TapBranch';
+const TAP_TWEAK_TAG = 'TapTweak';
const EC_P_BN = new BN(types_1.EC_P);
const EC_P_REDUCTION = BN.red(EC_P_BN);
const EC_P_QUADRATIC_RESIDUE = EC_P_BN.addn(1).divn(4);
diff --git a/ts_src/taproot.ts b/ts_src/taproot.ts
index d364670a9..7f1a90bd4 100644
--- a/ts_src/taproot.ts
+++ b/ts_src/taproot.ts
@@ -16,9 +16,9 @@ import {
const ecc = require('tiny-secp256k1');
const LEAF_VERSION_TAPSCRIPT = 0xc0;
-const TAP_LEAF_TAG = NBuffer.from('TapLeaf', 'utf8');
-const TAP_BRANCH_TAG = NBuffer.from('TapBranch', 'utf8');
-const TAP_TWEAK_TAG = NBuffer.from('TapTweak', 'utf8');
+const TAP_LEAF_TAG ='TapLeaf';
+const TAP_BRANCH_TAG ='TapBranch';
+const TAP_TWEAK_TAG ='TapTweak';
const EC_P_BN = new BN(EC_P);
const EC_P_REDUCTION = BN.red(EC_P_BN);
From 0519d2b06161287aa4377d7192bdebcba275d1e9 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Wed, 12 Jan 2022 15:17:13 +0200
Subject: [PATCH 030/144] fix: rebase issues
---
package-lock.json | 14 +-------------
src/taproot.js | 2 +-
ts_src/taproot.ts | 2 +-
3 files changed, 3 insertions(+), 15 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 39ffeed33..f343fdd36 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2576,19 +2576,7 @@
"integrity": "sha512-8qPw7zDK6Hco2tVGYGQeOmOPp/hZnREwy2iIkcq0ygAuqc9WHo29vKN94lNymh1QbB3nthtAMF6KTIrdbsIotA==",
"dev": true,
"requires": {
- "bindings": "^1.3.0",
- "bn.js": "^4.11.8",
- "create-hmac": "^1.1.7",
- "elliptic": "^6.4.0",
- "nan": "^2.13.2"
- },
- "dependencies": {
- "bn.js": {
- "version": "4.12.0",
- "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
- "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
- "dev": true
- }
+ "uint8array-tools": "0.0.6"
}
},
"to-fast-properties": {
diff --git a/src/taproot.js b/src/taproot.js
index 0bb77079d..f85b942a6 100644
--- a/src/taproot.js
+++ b/src/taproot.js
@@ -144,5 +144,5 @@ function serializeScript(s) {
}
// todo: do not use ecc
function pointAddScalar(P, h) {
- return ecc.pointAddScalar(P, h);
+ return buffer_1.Buffer.from(ecc.pointAddScalar(P, h));
}
diff --git a/ts_src/taproot.ts b/ts_src/taproot.ts
index 7f1a90bd4..ea996760b 100644
--- a/ts_src/taproot.ts
+++ b/ts_src/taproot.ts
@@ -181,5 +181,5 @@ function serializeScript(s: Buffer): Buffer {
// todo: do not use ecc
function pointAddScalar(P: Buffer, h: Buffer): Buffer {
- return ecc.pointAddScalar(P, h);
+ return NBuffer.from(ecc.pointAddScalar(P, h));
}
From 2efc51e6936c39e1f5b7504d069fef498212b5a4 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Thu, 13 Jan 2022 16:54:23 +0200
Subject: [PATCH 031/144] chore: remove the bn.js dependency
---
package-lock.json | 5 -----
package.json | 1 -
2 files changed, 6 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index f343fdd36..769a25397 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -711,11 +711,6 @@
"integrity": "sha512-pef6gxZFztEhaE9RY9HmWVmiIHqCb2OyS4HPKkpc6CIiiOa3Qmuoylxc5P2EkU3w+5eTSifI9SEZC88idAIGow==",
"dev": true
},
- "bn.js": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz",
- "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw=="
- },
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
diff --git a/package.json b/package.json
index 644402307..71e79082d 100644
--- a/package.json
+++ b/package.json
@@ -51,7 +51,6 @@
"dependencies": {
"bech32": "^2.0.0",
"bip174": "^2.0.1",
- "bn.js": "^5.2.0",
"bs58check": "^2.1.2",
"create-hash": "^1.1.0",
"ripemd160": "^2.0.2",
From 4fd8a349db6068174912ada6ebafe11efa0d7161 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Thu, 13 Jan 2022 16:55:49 +0200
Subject: [PATCH 032/144] refactor: use injectable ecc lib
---
src/payments/index.d.ts | 16 +-
src/payments/index.js | 24 +-
src/payments/p2tr.d.ts | 5 +-
src/payments/p2tr.js | 440 +++++++++++++++++-----------------
src/payments/testecc.d.ts | 2 +
src/payments/testecc.js | 172 ++++++++++++++
src/taproot.d.ts | 5 +-
src/taproot.js | 67 +-----
src/types.d.ts | 10 +-
test/fixtures/p2tr.json | 2 +-
test/payments.spec.ts | 15 +-
ts_src/payments/index.ts | 24 +-
ts_src/payments/p2tr.ts | 474 +++++++++++++++++++------------------
ts_src/payments/testecc.ts | 174 ++++++++++++++
ts_src/taproot.ts | 95 +-------
ts_src/types.ts | 13 +-
16 files changed, 926 insertions(+), 612 deletions(-)
create mode 100644 src/payments/testecc.d.ts
create mode 100644 src/payments/testecc.js
create mode 100644 ts_src/payments/testecc.ts
diff --git a/src/payments/index.d.ts b/src/payments/index.d.ts
index 0170dd093..72db5de25 100644
--- a/src/payments/index.d.ts
+++ b/src/payments/index.d.ts
@@ -1,6 +1,6 @@
///
import { Network } from '../networks';
-import { TaprootLeaf } from '../types';
+import { TaprootLeaf, TinySecp256k1Interface } from '../types';
import { p2data as embed } from './embed';
import { p2ms } from './p2ms';
import { p2pk } from './p2pk';
@@ -8,7 +8,6 @@ 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;
@@ -35,7 +34,18 @@ export interface PaymentOpts {
validate?: boolean;
allowIncomplete?: boolean;
}
+export interface PaymentAPI {
+ embed: PaymentCreator;
+ p2ms: PaymentCreator;
+ p2pk: PaymentCreator;
+ p2pkh: PaymentCreator;
+ p2sh: PaymentCreator;
+ p2wpkh: PaymentCreator;
+ p2wsh: PaymentCreator;
+ p2tr: PaymentCreator;
+}
export declare type StackElement = Buffer | number;
export declare type Stack = StackElement[];
export declare type StackFunction = () => Stack;
-export { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh, p2tr };
+export { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh, PaymentFactory };
+export default function PaymentFactory(ecc: TinySecp256k1Interface): PaymentAPI;
diff --git a/src/payments/index.js b/src/payments/index.js
index 9ce55f859..779df03fa 100644
--- a/src/payments/index.js
+++ b/src/payments/index.js
@@ -1,6 +1,6 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.p2tr = exports.p2wsh = exports.p2wpkh = exports.p2sh = exports.p2pkh = exports.p2pk = exports.p2ms = exports.embed = void 0;
+exports.PaymentFactory = 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,
@@ -51,11 +51,21 @@ Object.defineProperty(exports, 'p2wsh', {
},
});
const p2tr_1 = require('./p2tr');
-Object.defineProperty(exports, 'p2tr', {
- enumerable: true,
- get: function() {
- return p2tr_1.p2tr;
- },
-});
+const testecc_1 = require('./testecc');
+function PaymentFactory(ecc) {
+ (0, testecc_1.testEcc)(ecc);
+ return {
+ embed: embed_1.p2data,
+ p2ms: p2ms_1.p2ms,
+ p2pk: p2pk_1.p2pk,
+ p2pkh: p2pkh_1.p2pkh,
+ p2sh: p2sh_1.p2sh,
+ p2wpkh: p2wpkh_1.p2wpkh,
+ p2wsh: p2wsh_1.p2wsh,
+ p2tr: (0, p2tr_1.p2tr)(ecc),
+ };
+}
+exports.default = PaymentFactory;
+exports.PaymentFactory = PaymentFactory;
// TODO
// witness commitment
diff --git a/src/payments/p2tr.d.ts b/src/payments/p2tr.d.ts
index 350ed0ffc..e4d4c8a9b 100644
--- a/src/payments/p2tr.d.ts
+++ b/src/payments/p2tr.d.ts
@@ -1,2 +1,3 @@
-import { Payment, PaymentOpts } from './index';
-export declare function p2tr(a: Payment, opts?: PaymentOpts): Payment;
+import { TinySecp256k1Interface } from '../types';
+import { PaymentCreator } from './index';
+export declare function p2tr(ecc: TinySecp256k1Interface): PaymentCreator;
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index 435d2f101..78ef95311 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -11,227 +11,237 @@ const bech32_1 = require('bech32');
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 || {});
- (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(bscript.isCanonicalScriptSignature),
- 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;
+function p2tr(ecc) {
+ return (a, opts) => {
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, taproot_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, taproot_1.tapLeafHash)(script, leafVersion);
- return (0, taproot_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 = (0, taproot_1.tweakKey)(o.internalPubkey, o.hash);
- 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, taproot_1.toHashTree)(a.scriptsTree);
- const leafHash = (0, taproot_1.tapLeafHash)(
- a.scriptLeaf.output,
- a.scriptLeaf.version,
- );
- const path = (0, taproot_1.findScriptPath)(hashTree, leafHash);
- const outputKey = (0, taproot_1.tweakKey)(
- a.internalPubkey,
- hashTree.hash,
- );
- 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) {
+ !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 || {});
+ (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(bscript.isCanonicalScriptSignature),
+ 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.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 = (0, taproot_1.tweakKey)(a.internalPubkey, o.hash);
- if (tweakedKey === null)
- throw new TypeError('Invalid internalPubkey for p2tr');
- if (pubkey.length > 0 && !pubkey.equals(tweakedKey.x))
- throw new TypeError('Pubkey mismatch');
- else pubkey = tweakedKey.x;
- }
- if (pubkey && pubkey.length) {
- if ((0, taproot_1.liftX)(pubkey) === null)
- throw new TypeError('Invalid pubkey for p2tr');
- }
- if (a.hash && a.scriptsTree) {
- const hash = (0, taproot_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');
- const internalPubkeyPoint = (0, taproot_1.liftX)(internalPubkey);
- if (!internalPubkeyPoint)
- throw new TypeError('Invalid internalPubkey for p2tr witness');
+ 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, taproot_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 = witness[witness.length - 2];
+ const script = w[w.length - 2];
const leafHash = (0, taproot_1.tapLeafHash)(script, leafVersion);
- const hash = (0, taproot_1.rootHashFromPath)(controlBlock, leafHash);
- const outputKey = (0, taproot_1.tweakKey)(internalPubkey, hash);
- 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 (0, taproot_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);
+ 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, taproot_1.toHashTree)(a.scriptsTree);
+ const leafHash = (0, taproot_1.tapLeafHash)(
+ a.scriptLeaf.output,
+ a.scriptLeaf.version,
+ );
+ const path = (0, taproot_1.findScriptPath)(hashTree, leafHash);
+ const outputKey = tweakKey(a.internalPubkey, hashTree.hash);
+ 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);
+ 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, taproot_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, taproot_1.tapLeafHash)(script, leafVersion);
+ const hash = (0, taproot_1.rootHashFromPath)(controlBlock, leafHash);
+ const outputKey = tweakKey(internalPubkey, hash);
+ 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);
+ };
+ function tweakKey(pubKey, h) {
+ if (!buffer_1.Buffer.isBuffer(pubKey)) return null;
+ if (pubKey.length !== 32) return null;
+ if (h && h.length !== 32) return null;
+ const tweakHash = (0, taproot_1.tapTweakHash)(pubKey, h);
+ const res = ecc.xOnlyPointAddTweak(pubKey, tweakHash);
+ if (!res || res.xOnlyPubkey === null) return null;
+ return {
+ parity: res.parity,
+ x: buffer_1.Buffer.from(res.xOnlyPubkey),
+ };
}
- return Object.assign(o, a);
}
exports.p2tr = p2tr;
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..9bdc62031
--- /dev/null
+++ b/src/payments/testecc.js
@@ -0,0 +1,172 @@
+'use strict';
+Object.defineProperty(exports, '__esModule', { value: true });
+exports.testEcc = void 0;
+const h = hex => Buffer.from(hex, 'hex');
+function testEcc(ecc) {
+ 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'),
+ ),
+ );
+ 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: '2f1b310f4c065331bc0d79ba4661bb9822d67d7c4a1b0a1892e1fd0cd23aa68d',
+ tweak: '40ab636041bb695843ac7f220344565bed3b5dca919e256b7e31e19d69b36fad',
+ parity: 1,
+ result: '5786150f0ac36a2aaeb8d11aaeb7aa2d03ad63c528cc307a7cd5648c84041f34',
+ },
+ {
+ pubkey: 'e7e9acacbdb43fc9fb71a8db1536c0f866caa78def49f666fa121a6f7954bb01',
+ tweak: '1ad613216778a70490c8a681a4901d4ca880d76916deb69979b5ac52d2760e09',
+ parity: 1,
+ result: 'ae10fa880c85848cc1faf056f56a64b7d45c68838cfb308d03ca2be9b485c130',
+ },
+ {
+ pubkey: '2c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991',
+ tweak: '823c3cd2142744b075a87eade7e1b8678ba308d566226a0056ca2b7a76f86b47',
+ parity: 0,
+ result: '9534f8dc8c6deda2dc007655981c78b49c5d96c778fbf363462a11ec9dfd948c',
+ },
+ {
+ pubkey: '8f19ee7677713806c662078a9f2b2c7b930376d22f2d617bce50b5e444839a7c',
+ tweak: '7df1f4b66058f8be34b6b7d17be9bcf35ba5c98edf8d4e763b95964bad655fe4',
+ parity: 1,
+ result: '74619a5990750928d0728817b02bb0d398062dad0e568f46ea5348d35bef914f',
+ },
+ {
+ pubkey: '2bda68b3aa0239d382f185ca2d8c31ce604cc26220cef3eb65223f47a0088d87',
+ tweak: 'e5a018b3a2e155316109d9cdc5eab739759c0e07e0c00bf9fccb8237fe4d7f02',
+ parity: 0,
+ result: '84479dc6bf70762721b10b89c8798e00d525507edc3fabbfc89ad915b6509379',
+ },
+ {
+ pubkey: '9611ba340bce00a594f1ffb1294974af80e1301e49597378732fd77bbdedf454',
+ tweak: 'bbb8ec1f063522953a4a9f90ff4e849560e0f0597458529ea13b8868f255c7c7',
+ parity: 0,
+ result: '30bebfdad18b87b646f60e51d3c45c6658fbb4364c94b1b33d925a4515b66757',
+ },
+ {
+ pubkey: 'd9f5792078a845303c1f1ea88aec79ed0fd9f0c49e9e7bff2765877e79b4dd52',
+ tweak: '531fe6068134503d2723133227c867ac8fa6c83c537e9a44c3c5bdbdcb1fe337',
+ parity: 0,
+ result: 'fe5dd39f0491af71711454eee5b6a9c99779c422dd97f5e7f75d7ce7be7b32f0',
+ },
+ {
+ pubkey: '40ab636041bb695843ac7f220344565bed3b5dca919e256b7e31e19d69b36fad',
+ tweak: '048968943184ce8a0239ab2141641e8eaead35a6dc8e6b55ad33ac1eca975a47',
+ parity: 1,
+ result: '6c8245a62201887c5e3aeb022fff06e6c110f3e58ad6d37cc20e877082b72c58',
+ },
+ {
+ pubkey: '6aa3da9b5c1d61956076cb3014ffdaa0996bacdae29ba4b89e39b4088f86ec78',
+ tweak: 'ff8adab52623bcb2717fc71d7edc6f55e98396e6c234dff01f307a12b2af1c99',
+ parity: 1,
+ result: 'd6080b5df61525fe8be31a823f3943e5fc9354d5a091b2dea195985c7c395787',
+ },
+ {
+ pubkey: '24653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c',
+ tweak: '9e5f7dbe6d62ade5aab476b40559852ea1b5fc7bb99a61a42eab550f69ffafb4',
+ parity: 0,
+ result: '58289ee230fcf6a78cb9878cae5102cc9104490abab9d03f3eccc2f0cd07de5f',
+ },
+ {
+ pubkey: 'e5a018b3a2e155316109d9cdc5eab739759c0e07e0c00bf9fccb8237fe4d7f02',
+ tweak: 'bde750d93efe821813df9c15ee676f2e9c63386336c164f5a15cf240ac653c06',
+ parity: 0,
+ result: '9a1ae919c5c78da635d94a92b3053e46b2261b81ec70db82a382f5bff474bec4',
+ },
+ {
+ pubkey: 'bc14bc97e2d818ee360a9ba7782bd6a6dfc2c1e335fffc584a095fdac5fea641',
+ tweak: '4f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa',
+ parity: 1,
+ result: '19a7416f4f95f36c5e48dc7630ffea8b292e1721cecfa9cc5f794c83973e41d6',
+ },
+ {
+ pubkey: '35e9d7c48e3a5254d5881b60abf004cf6eedc6ab842393caa2fdd20d6d0ad170',
+ tweak: '18bb586dc109adf49ffb42e0ac293d2a2965e49a0a4900c2be776b426b7cbfde',
+ parity: 0,
+ result: 'fa7cca72580bb686fbbae09ded801c7d109fa378f52e8a5f43a1922e442e44c1',
+ },
+ {
+ pubkey: '67bff656551f25009ac8ed88664736c08074a15dbd2268292f5de7ca7e718338',
+ tweak: 'b96359049e97f49d871e856f37e54d0978bae2cc936b4484d96df984cd20daa1',
+ parity: 0,
+ result: 'dd081d737da17fb4f6686f8497cac56b16ea06e1dc05859633f735fb304e7e5a',
+ },
+ {
+ pubkey: '5b0da52533a1620fe947cb658c35e1772f39ef1253753493b7dc4b8d8f31f40e',
+ tweak: '3d481f46056f2da27870a5d00c0c7bf484036780a83bbcc2e2da2f03bc33bff0',
+ parity: 1,
+ result: '164e13b54edc89673f94563120d87db4a47b12e49c40c195ac51ea7bc50f22e1',
+ },
+ {
+ pubkey: '0612c5e8c98a9677a2ddd13770e26f5f1e771a088c88ce519a1e1b65872423f9',
+ tweak: 'dbcfa1c73674cba4aa1b6992ebdc6a77008d38f6c6ec068c3c862b9ff6d287f2',
+ parity: 0,
+ result: '82fc6954352b7189a156e4678d0c315c122431fa9551961b8e3c811b55a42c8b',
+ },
+ {
+ pubkey: '9ac20335eb38768d2052be1dbbc3c8f6178407458e51e6b4ad22f1d91758895b',
+ tweak: '6aa3da9b5c1d61956076cb3014ffdaa0996bacdae29ba4b89e39b4088f86ec78',
+ parity: 1,
+ result: 'cf9065a7e2c9f909becc1c95f9884ed9fbe19c4a8954ed17880f02d94ae96a63',
+ },
+ {
+ pubkey: 'c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5',
+ tweak: 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036413f',
+ parity: -1,
+ result: null,
+ },
+];
diff --git a/src/taproot.d.ts b/src/taproot.d.ts
index c55f10d72..37c118430 100644
--- a/src/taproot.d.ts
+++ b/src/taproot.d.ts
@@ -1,7 +1,5 @@
///
-import { TweakedPublicKey, TaprootLeaf } from './types';
-export declare function liftX(buffer: Buffer): Buffer | null;
-export declare function tweakKey(pubKey: Buffer, h: Buffer | undefined): TweakedPublicKey | null;
+import { TaprootLeaf } from './types';
export declare function rootHashFromPath(controlBlock: Buffer, tapLeafMsg: Buffer): Buffer;
export interface HashTree {
hash: Buffer;
@@ -11,3 +9,4 @@ export interface HashTree {
export declare function toHashTree(scripts: TaprootLeaf[]): HashTree;
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/taproot.js b/src/taproot.js
index f85b942a6..98a7db377 100644
--- a/src/taproot.js
+++ b/src/taproot.js
@@ -1,68 +1,16 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.tapLeafHash = exports.findScriptPath = exports.toHashTree = exports.rootHashFromPath = exports.tweakKey = exports.liftX = void 0;
+exports.tapTweakHash = exports.tapLeafHash = exports.findScriptPath = exports.toHashTree = exports.rootHashFromPath = void 0;
const buffer_1 = require('buffer');
-const BN = require('bn.js');
const bcrypto = require('./crypto');
// todo: use varuint-bitcoin??
const varuint = require('bip174/src/lib/converter/varint');
-const types_1 = require('./types');
// todo: !!!Temp, to be replaced. Only works because bip32 has it as dependecy. Linting will fail.
-const ecc = require('tiny-secp256k1');
+// const ecc = require('tiny-secp256k1');
const LEAF_VERSION_TAPSCRIPT = 0xc0;
const TAP_LEAF_TAG = 'TapLeaf';
const TAP_BRANCH_TAG = 'TapBranch';
const TAP_TWEAK_TAG = 'TapTweak';
-const EC_P_BN = new BN(types_1.EC_P);
-const EC_P_REDUCTION = BN.red(EC_P_BN);
-const EC_P_QUADRATIC_RESIDUE = EC_P_BN.addn(1).divn(4);
-const BN_2 = new BN(2);
-const BN_3 = new BN(3);
-const BN_7 = new BN(7);
-function liftX(buffer) {
- if (!buffer_1.Buffer.isBuffer(buffer)) return null;
- if (buffer.length !== 32) return null;
- if (buffer.compare(types_1.ZERO32) === 0) return null;
- if (buffer.compare(types_1.EC_P) >= 0) return null;
- const x = new BN(buffer);
- const x1 = x.toRed(EC_P_REDUCTION);
- const ySq = x1
- .redPow(BN_3)
- .add(BN_7)
- .mod(EC_P_BN);
- const y = ySq.redPow(EC_P_QUADRATIC_RESIDUE);
- if (!ySq.eq(y.redPow(BN_2))) {
- return null;
- }
- const y1 = y.isEven() ? y : EC_P_BN.sub(y);
- return buffer_1.Buffer.concat([
- buffer_1.Buffer.from([0x04]),
- buffer_1.Buffer.from(x1.toBuffer('be', 32)),
- buffer_1.Buffer.from(y1.toBuffer('be', 32)),
- ]);
-}
-exports.liftX = liftX;
-function tweakKey(pubKey, h) {
- if (!buffer_1.Buffer.isBuffer(pubKey)) return null;
- if (pubKey.length !== 32) return null;
- if (h && h.length !== 32) return null;
- const tweakHash = bcrypto.taggedHash(
- TAP_TWEAK_TAG,
- buffer_1.Buffer.concat(h ? [pubKey, h] : [pubKey]),
- );
- if (tweakHash.compare(types_1.GROUP_ORDER) >= 0) {
- // todo: add test for this case
- throw new TypeError('Tweak value over the SECP256K1 Order');
- }
- const P = liftX(pubKey);
- if (P === null) return null;
- const Q = pointAddScalar(P, tweakHash);
- return {
- parity: Q[64] % 2,
- x: Q.slice(1, 33),
- };
-}
-exports.tweakKey = tweakKey;
function rootHashFromPath(controlBlock, tapLeafMsg) {
const k = [tapLeafMsg];
const e = [];
@@ -136,13 +84,16 @@ exports.tapLeafHash = tapLeafHash;
function tapBranchHash(a, b) {
return bcrypto.taggedHash(TAP_BRANCH_TAG, buffer_1.Buffer.concat([a, b]));
}
+function tapTweakHash(pubKey, h) {
+ return bcrypto.taggedHash(
+ TAP_TWEAK_TAG,
+ buffer_1.Buffer.concat(h ? [pubKey, h] : [pubKey]),
+ );
+}
+exports.tapTweakHash = tapTweakHash;
function serializeScript(s) {
const varintLen = varuint.encodingLength(s.length);
const buffer = buffer_1.Buffer.allocUnsafe(varintLen); // better
varuint.encode(s.length, buffer);
return buffer_1.Buffer.concat([buffer, s]);
}
-// todo: do not use ecc
-function pointAddScalar(P, h) {
- return buffer_1.Buffer.from(ecc.pointAddScalar(P, h));
-}
diff --git a/src/types.d.ts b/src/types.d.ts
index 1bcb12426..014c2b910 100644
--- a/src/types.d.ts
+++ b/src/types.d.ts
@@ -14,14 +14,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 TweakedPublicKey {
- parity: number;
- x: Buffer;
+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
index da89f26f6..02b1cb3c0 100644
--- a/test/fixtures/p2tr.json
+++ b/test/fixtures/p2tr.json
@@ -898,7 +898,7 @@
}
},
{
- "exception": "Invalid internalPubkey for p2t",
+ "exception": "Expected Point",
"options": {},
"arguments": {
"internalPubkey": "9fa5ffb68821cf559001caa0577eeea4978b29416def328a707b15e91701a2f8"
diff --git a/test/payments.spec.ts b/test/payments.spec.ts
index 9e28501ae..957396199 100644
--- a/test/payments.spec.ts
+++ b/test/payments.spec.ts
@@ -1,16 +1,15 @@
import * as assert from 'assert';
import { describe, it } from 'mocha';
-import { PaymentCreator } from '../src/payments';
+import * as ecc from 'tiny-secp256k1';
+import { PaymentCreator, PaymentFactory } from '../src/payments';
import * as u from './payments.utils';
+
+const payments = PaymentFactory(ecc);
['embed', 'p2ms', 'p2pk', 'p2pkh', 'p2sh', 'p2wpkh', 'p2wsh', 'p2tr'].forEach(p => {
describe(p, () => {
- let fn: PaymentCreator;
- const payment = require('../src/payments/' + p);
- if (p === 'embed') {
- fn = payment.p2data;
- } else {
- fn = payment[p];
- }
+ //@ts-ignore
+ const fn: PaymentCreator = payments[p];
+
const fixtures = require('./fixtures/' + p);
fixtures.valid.forEach((f: any) => {
diff --git a/ts_src/payments/index.ts b/ts_src/payments/index.ts
index 996f292e9..f7c5dbadd 100644
--- a/ts_src/payments/index.ts
+++ b/ts_src/payments/index.ts
@@ -1,5 +1,5 @@
import { Network } from '../networks';
-import { TaprootLeaf } from '../types';
+import { TaprootLeaf, TinySecp256k1Interface } from '../types';
import { p2data as embed } from './embed';
import { p2ms } from './p2ms';
import { p2pk } from './p2pk';
@@ -8,6 +8,7 @@ import { p2sh } from './p2sh';
import { p2wpkh } from './p2wpkh';
import { p2wsh } from './p2wsh';
import { p2tr } from './p2tr';
+import { testEcc } from './testecc';
export interface Payment {
name?: string;
@@ -39,11 +40,30 @@ export interface PaymentOpts {
allowIncomplete?: boolean;
}
+export interface PaymentAPI {
+ embed: PaymentCreator;
+ p2ms: PaymentCreator;
+ p2pk: PaymentCreator;
+ p2pkh: PaymentCreator;
+ p2sh: PaymentCreator;
+ p2wpkh: PaymentCreator;
+ p2wsh: PaymentCreator;
+ p2tr: PaymentCreator;
+}
+
export type StackElement = Buffer | number;
export type Stack = StackElement[];
export type StackFunction = () => Stack;
-export { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh, p2tr };
+export { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh, PaymentFactory };
+
+export default function PaymentFactory(
+ ecc: TinySecp256k1Interface,
+): PaymentAPI {
+ testEcc(ecc);
+
+ return { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh, p2tr: p2tr(ecc) };
+}
// TODO
// witness commitment
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index 98ca8eb56..0bb68465d 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -1,16 +1,15 @@
import { Buffer as NBuffer } from 'buffer';
import { bitcoin as BITCOIN_NETWORK } from '../networks';
import * as bscript from '../script';
-import { typeforce as typef } from '../types';
+import { typeforce as typef, TinySecp256k1Interface } from '../types';
import {
toHashTree,
rootHashFromPath,
findScriptPath,
tapLeafHash,
- tweakKey,
- liftX,
+ tapTweakHash,
} from '../taproot';
-import { Payment, PaymentOpts } from './index';
+import { Payment, PaymentOpts, PaymentCreator } from './index';
import * as lazy from './lazy';
import { bech32m } from 'bech32';
const OPS = bscript.OPS;
@@ -18,242 +17,267 @@ 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 || {});
-
- 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(bscript.isCanonicalScriptSignature),
- 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;
+export function p2tr(ecc: TinySecp256k1Interface): PaymentCreator {
+ return (a: Payment, opts?: PaymentOpts): Payment => {
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);
- 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);
- 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;
- }
+ !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 || {});
- if (a.pubkey) {
- if (pubkey.length > 0 && !pubkey.equals(a.pubkey))
- throw new TypeError('Pubkey mismatch');
- else pubkey = a.pubkey;
- }
+ 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(bscript.isCanonicalScriptSignature),
+ 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,
+ );
- 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);
- }
+ 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),
+ };
+ });
- if (a.internalPubkey) {
- const tweakedKey = tweakKey(a.internalPubkey, o.hash);
- if (tweakedKey === null)
- throw new TypeError('Invalid internalPubkey for p2tr');
- if (pubkey.length > 0 && !pubkey.equals(tweakedKey.x))
- throw new TypeError('Pubkey mismatch');
- else pubkey = tweakedKey.x;
- }
+ 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();
+ });
- if (pubkey && pubkey.length) {
- if (liftX(pubkey) === null)
- throw new TypeError('Invalid pubkey for p2tr');
- }
+ const network = a.network || BITCOIN_NETWORK;
+ const o: Payment = { name: 'p2tr', network };
- if (a.hash && a.scriptsTree) {
- const hash = toHashTree(a.scriptsTree).hash;
- if (!a.hash.equals(hash)) throw new TypeError('Hash mismatch');
- }
+ lazy.prop(o, 'address', () => {
+ if (!o.pubkey) return;
- 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');
-
- const internalPubkeyPoint = liftX(internalPubkey);
- if (!internalPubkeyPoint)
- throw new TypeError('Invalid internalPubkey for p2tr witness');
+ 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 = witness[witness.length - 2];
-
+ const script = w[w.length - 2];
const leafHash = tapLeafHash(script, leafVersion);
- const hash = rootHashFromPath(controlBlock, leafHash);
+ 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);
+ 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);
+ 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;
+ }
- const outputKey = tweakKey(internalPubkey, hash);
- if (!outputKey)
- // todo: needs test data
- throw new TypeError('Invalid outputKey for p2tr witness');
+ 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);
+ 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 (pubkey.length && !pubkey.equals(outputKey.x))
- throw new TypeError('Pubkey mismatch for p2tr witness');
+ if (!ecc.isXOnlyPoint(internalPubkey))
+ throw new TypeError('Invalid internalPubkey for p2tr witness');
- if (outputKey.parity !== (controlBlock[0] & 1))
- throw new Error('Incorrect parity');
+ 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);
+ 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);
+ };
+
+ function tweakKey(
+ pubKey: Buffer,
+ h: Buffer | undefined,
+ ): 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 = ecc.xOnlyPointAddTweak(pubKey, tweakHash);
+ if (!res || res.xOnlyPubkey === null) return null;
+
+ return {
+ parity: res.parity,
+ x: NBuffer.from(res.xOnlyPubkey),
+ };
}
+}
- return Object.assign(o, a);
+interface TweakedPublicKey {
+ parity: number;
+ x: Buffer;
}
diff --git a/ts_src/payments/testecc.ts b/ts_src/payments/testecc.ts
new file mode 100644
index 000000000..773fa3eb8
--- /dev/null
+++ b/ts_src/payments/testecc.ts
@@ -0,0 +1,174 @@
+import { TinySecp256k1Interface } from '../types';
+
+const h = (hex: string): Buffer => Buffer.from(hex, 'hex');
+
+export function testEcc(ecc: TinySecp256k1Interface): void {
+ 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'),
+ ),
+ );
+
+ 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: '2f1b310f4c065331bc0d79ba4661bb9822d67d7c4a1b0a1892e1fd0cd23aa68d',
+ tweak: '40ab636041bb695843ac7f220344565bed3b5dca919e256b7e31e19d69b36fad',
+ parity: 1,
+ result: '5786150f0ac36a2aaeb8d11aaeb7aa2d03ad63c528cc307a7cd5648c84041f34',
+ },
+ {
+ pubkey: 'e7e9acacbdb43fc9fb71a8db1536c0f866caa78def49f666fa121a6f7954bb01',
+ tweak: '1ad613216778a70490c8a681a4901d4ca880d76916deb69979b5ac52d2760e09',
+ parity: 1,
+ result: 'ae10fa880c85848cc1faf056f56a64b7d45c68838cfb308d03ca2be9b485c130',
+ },
+ {
+ pubkey: '2c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991',
+ tweak: '823c3cd2142744b075a87eade7e1b8678ba308d566226a0056ca2b7a76f86b47',
+ parity: 0,
+ result: '9534f8dc8c6deda2dc007655981c78b49c5d96c778fbf363462a11ec9dfd948c',
+ },
+ {
+ pubkey: '8f19ee7677713806c662078a9f2b2c7b930376d22f2d617bce50b5e444839a7c',
+ tweak: '7df1f4b66058f8be34b6b7d17be9bcf35ba5c98edf8d4e763b95964bad655fe4',
+ parity: 1,
+ result: '74619a5990750928d0728817b02bb0d398062dad0e568f46ea5348d35bef914f',
+ },
+ {
+ pubkey: '2bda68b3aa0239d382f185ca2d8c31ce604cc26220cef3eb65223f47a0088d87',
+ tweak: 'e5a018b3a2e155316109d9cdc5eab739759c0e07e0c00bf9fccb8237fe4d7f02',
+ parity: 0,
+ result: '84479dc6bf70762721b10b89c8798e00d525507edc3fabbfc89ad915b6509379',
+ },
+ {
+ pubkey: '9611ba340bce00a594f1ffb1294974af80e1301e49597378732fd77bbdedf454',
+ tweak: 'bbb8ec1f063522953a4a9f90ff4e849560e0f0597458529ea13b8868f255c7c7',
+ parity: 0,
+ result: '30bebfdad18b87b646f60e51d3c45c6658fbb4364c94b1b33d925a4515b66757',
+ },
+ {
+ pubkey: 'd9f5792078a845303c1f1ea88aec79ed0fd9f0c49e9e7bff2765877e79b4dd52',
+ tweak: '531fe6068134503d2723133227c867ac8fa6c83c537e9a44c3c5bdbdcb1fe337',
+ parity: 0,
+ result: 'fe5dd39f0491af71711454eee5b6a9c99779c422dd97f5e7f75d7ce7be7b32f0',
+ },
+ {
+ pubkey: '40ab636041bb695843ac7f220344565bed3b5dca919e256b7e31e19d69b36fad',
+ tweak: '048968943184ce8a0239ab2141641e8eaead35a6dc8e6b55ad33ac1eca975a47',
+ parity: 1,
+ result: '6c8245a62201887c5e3aeb022fff06e6c110f3e58ad6d37cc20e877082b72c58',
+ },
+ {
+ pubkey: '6aa3da9b5c1d61956076cb3014ffdaa0996bacdae29ba4b89e39b4088f86ec78',
+ tweak: 'ff8adab52623bcb2717fc71d7edc6f55e98396e6c234dff01f307a12b2af1c99',
+ parity: 1,
+ result: 'd6080b5df61525fe8be31a823f3943e5fc9354d5a091b2dea195985c7c395787',
+ },
+ {
+ pubkey: '24653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c',
+ tweak: '9e5f7dbe6d62ade5aab476b40559852ea1b5fc7bb99a61a42eab550f69ffafb4',
+ parity: 0,
+ result: '58289ee230fcf6a78cb9878cae5102cc9104490abab9d03f3eccc2f0cd07de5f',
+ },
+ {
+ pubkey: 'e5a018b3a2e155316109d9cdc5eab739759c0e07e0c00bf9fccb8237fe4d7f02',
+ tweak: 'bde750d93efe821813df9c15ee676f2e9c63386336c164f5a15cf240ac653c06',
+ parity: 0,
+ result: '9a1ae919c5c78da635d94a92b3053e46b2261b81ec70db82a382f5bff474bec4',
+ },
+ {
+ pubkey: 'bc14bc97e2d818ee360a9ba7782bd6a6dfc2c1e335fffc584a095fdac5fea641',
+ tweak: '4f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa',
+ parity: 1,
+ result: '19a7416f4f95f36c5e48dc7630ffea8b292e1721cecfa9cc5f794c83973e41d6',
+ },
+ {
+ pubkey: '35e9d7c48e3a5254d5881b60abf004cf6eedc6ab842393caa2fdd20d6d0ad170',
+ tweak: '18bb586dc109adf49ffb42e0ac293d2a2965e49a0a4900c2be776b426b7cbfde',
+ parity: 0,
+ result: 'fa7cca72580bb686fbbae09ded801c7d109fa378f52e8a5f43a1922e442e44c1',
+ },
+ {
+ pubkey: '67bff656551f25009ac8ed88664736c08074a15dbd2268292f5de7ca7e718338',
+ tweak: 'b96359049e97f49d871e856f37e54d0978bae2cc936b4484d96df984cd20daa1',
+ parity: 0,
+ result: 'dd081d737da17fb4f6686f8497cac56b16ea06e1dc05859633f735fb304e7e5a',
+ },
+ {
+ pubkey: '5b0da52533a1620fe947cb658c35e1772f39ef1253753493b7dc4b8d8f31f40e',
+ tweak: '3d481f46056f2da27870a5d00c0c7bf484036780a83bbcc2e2da2f03bc33bff0',
+ parity: 1,
+ result: '164e13b54edc89673f94563120d87db4a47b12e49c40c195ac51ea7bc50f22e1',
+ },
+ {
+ pubkey: '0612c5e8c98a9677a2ddd13770e26f5f1e771a088c88ce519a1e1b65872423f9',
+ tweak: 'dbcfa1c73674cba4aa1b6992ebdc6a77008d38f6c6ec068c3c862b9ff6d287f2',
+ parity: 0,
+ result: '82fc6954352b7189a156e4678d0c315c122431fa9551961b8e3c811b55a42c8b',
+ },
+ {
+ pubkey: '9ac20335eb38768d2052be1dbbc3c8f6178407458e51e6b4ad22f1d91758895b',
+ tweak: '6aa3da9b5c1d61956076cb3014ffdaa0996bacdae29ba4b89e39b4088f86ec78',
+ parity: 1,
+ result: 'cf9065a7e2c9f909becc1c95f9884ed9fbe19c4a8954ed17880f02d94ae96a63',
+ },
+ {
+ pubkey: 'c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5',
+ tweak: 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036413f',
+ parity: -1,
+ result: null,
+ },
+];
diff --git a/ts_src/taproot.ts b/ts_src/taproot.ts
index ea996760b..ca8fe9fd5 100644
--- a/ts_src/taproot.ts
+++ b/ts_src/taproot.ts
@@ -1,88 +1,17 @@
import { Buffer as NBuffer } from 'buffer';
-const BN = require('bn.js');
-
import * as bcrypto from './crypto';
+
// todo: use varuint-bitcoin??
import * as varuint from 'bip174/src/lib/converter/varint';
-import {
- TweakedPublicKey,
- TaprootLeaf,
- ZERO32,
- EC_P,
- GROUP_ORDER,
-} from './types';
+import { TaprootLeaf } from './types';
// todo: !!!Temp, to be replaced. Only works because bip32 has it as dependecy. Linting will fail.
-const ecc = require('tiny-secp256k1');
+// const ecc = require('tiny-secp256k1');
const LEAF_VERSION_TAPSCRIPT = 0xc0;
-const TAP_LEAF_TAG ='TapLeaf';
-const TAP_BRANCH_TAG ='TapBranch';
-const TAP_TWEAK_TAG ='TapTweak';
-
-const EC_P_BN = new BN(EC_P);
-const EC_P_REDUCTION = BN.red(EC_P_BN);
-const EC_P_QUADRATIC_RESIDUE = EC_P_BN.addn(1).divn(4);
-const BN_2 = new BN(2);
-const BN_3 = new BN(3);
-const BN_7 = new BN(7);
-
-export function liftX(buffer: Buffer): Buffer | null {
- if (!NBuffer.isBuffer(buffer)) return null;
- if (buffer.length !== 32) return null;
-
- if (buffer.compare(ZERO32) === 0) return null;
- if (buffer.compare(EC_P) >= 0) return null;
-
- const x = new BN(buffer);
-
- const x1 = x.toRed(EC_P_REDUCTION);
- const ySq = x1
- .redPow(BN_3)
- .add(BN_7)
- .mod(EC_P_BN);
-
- const y = ySq.redPow(EC_P_QUADRATIC_RESIDUE);
-
- if (!ySq.eq(y.redPow(BN_2))) {
- return null;
- }
- const y1 = y.isEven() ? y : EC_P_BN.sub(y);
-
- return NBuffer.concat([
- NBuffer.from([0x04]),
- NBuffer.from(x1.toBuffer('be', 32)),
- NBuffer.from(y1.toBuffer('be', 32)),
- ]);
-}
-
-export function tweakKey(
- pubKey: Buffer,
- h: Buffer | undefined,
-): TweakedPublicKey | null {
- if (!NBuffer.isBuffer(pubKey)) return null;
- if (pubKey.length !== 32) return null;
- if (h && h.length !== 32) return null;
-
- const tweakHash = bcrypto.taggedHash(
- TAP_TWEAK_TAG,
- NBuffer.concat(h ? [pubKey, h] : [pubKey]),
- );
-
- if (tweakHash.compare(GROUP_ORDER) >= 0) {
- // todo: add test for this case
- throw new TypeError('Tweak value over the SECP256K1 Order');
- }
-
- const P = liftX(pubKey);
- if (P === null) return null;
-
- const Q = pointAddScalar(P, tweakHash);
- return {
- parity: Q[64] % 2,
- x: Q.slice(1, 33),
- };
-}
+const TAP_LEAF_TAG = 'TapLeaf';
+const TAP_BRANCH_TAG = 'TapBranch';
+const TAP_TWEAK_TAG = 'TapTweak';
export function rootHashFromPath(
controlBlock: Buffer,
@@ -172,14 +101,16 @@ function tapBranchHash(a: Buffer, b: Buffer): Buffer {
return bcrypto.taggedHash(TAP_BRANCH_TAG, NBuffer.concat([a, b]));
}
+export function tapTweakHash(pubKey: Buffer, h: Buffer | undefined): Buffer {
+ return bcrypto.taggedHash(
+ TAP_TWEAK_TAG,
+ NBuffer.concat(h ? [pubKey, h] : [pubKey]),
+ );
+}
+
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]);
}
-
-// todo: do not use ecc
-function pointAddScalar(P: Buffer, h: Buffer): Buffer {
- return NBuffer.from(ecc.pointAddScalar(P, h));
-}
diff --git a/ts_src/types.ts b/ts_src/types.ts
index 7fd2452f1..93446e920 100644
--- a/ts_src/types.ts
+++ b/ts_src/types.ts
@@ -71,15 +71,22 @@ export const Network = typeforce.compile({
wif: typeforce.UInt8,
});
-export interface TweakedPublicKey {
- parity: number;
- x: Buffer;
+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);
From a8644a8215869172937d8a658ff7e3a2aa1ffb52 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Thu, 13 Jan 2022 16:56:14 +0200
Subject: [PATCH 033/144] chore: code format
---
test/payments.spec.ts | 178 +++++++++++++++++++++---------------------
1 file changed, 91 insertions(+), 87 deletions(-)
diff --git a/test/payments.spec.ts b/test/payments.spec.ts
index 957396199..b151a4d05 100644
--- a/test/payments.spec.ts
+++ b/test/payments.spec.ts
@@ -5,108 +5,112 @@ import { PaymentCreator, PaymentFactory } from '../src/payments';
import * as u from './payments.utils';
const payments = PaymentFactory(ecc);
-['embed', 'p2ms', 'p2pk', 'p2pkh', 'p2sh', 'p2wpkh', 'p2wsh', 'p2tr'].forEach(p => {
- describe(p, () => {
- //@ts-ignore
- const fn: PaymentCreator = payments[p];
+['embed', 'p2ms', 'p2pk', 'p2pkh', 'p2sh', 'p2wpkh', 'p2wsh', 'p2tr'].forEach(
+ p => {
+ describe(p, () => {
+ //@ts-ignore
+ const fn: PaymentCreator = payments[p];
- const fixtures = require('./fixtures/' + p);
+ const fixtures = require('./fixtures/' + p);
- fixtures.valid.forEach((f: any) => {
- it(f.description + ' as expected', () => {
- const args = u.preform(f.arguments);
- const actual = fn(args, f.options);
+ 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);
- });
+ 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,
- }),
- );
+ it(f.description + ' as expected (no validation)', () => {
+ const args = u.preform(f.arguments);
+ const actual = fn(
+ args,
+ Object.assign({}, f.options, {
+ validate: false,
+ }),
+ );
- u.equate(actual, f.expected, f.arguments);
+ u.equate(actual, f.expected, f.arguments);
+ });
});
- });
- fixtures.invalid.forEach((f: any) => {
- it(
- 'throws ' + f.exception + (f.description ? 'for ' + f.description : ''),
- () => {
- const args = u.preform(f.arguments);
+ fixtures.invalid.forEach((f: any) => {
+ it(
+ 'throws ' +
+ f.exception +
+ (f.description ? 'for ' + f.description : ''),
+ () => {
+ const args = u.preform(f.arguments);
- assert.throws(() => {
- fn(args, f.options);
- }, new RegExp(f.exception));
- },
- );
- });
+ 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',
- ),
+ 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',
+ ),
+ }),
}),
- }),
+ });
+ 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');
});
- 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;
+ // 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;
- });
+ 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];
+ for (const key in depends) {
+ if (key in disabled) continue;
+ const dependencies = depends[key];
- dependencies.forEach((dependency: any) => {
- if (!Array.isArray(dependency)) dependency = [dependency];
+ 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);
+ 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);
- },
- );
- });
- }
+ it(
+ f.description +
+ ', ' +
+ key +
+ ' derives from ' +
+ JSON.stringify(dependency),
+ () => {
+ u.equate(fn(args), expected);
+ },
+ );
+ });
+ }
+ });
});
- });
-});
+ },
+);
From b866a8019484171ce360147a63229581db8408ac Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Thu, 13 Jan 2022 17:03:08 +0200
Subject: [PATCH 034/144] refactor: move taproot utils file
---
src/payments/p2tr.js | 26 +++++++++++--------
.../taprootutils.d.ts} | 2 +-
src/{taproot.js => payments/taprootutils.js} | 11 +++-----
ts_src/payments/p2tr.ts | 4 +--
.../{taproot.ts => payments/taprootutils.ts} | 10 +++----
5 files changed, 25 insertions(+), 28 deletions(-)
rename src/{taproot.d.ts => payments/taprootutils.d.ts} (92%)
rename src/{taproot.js => payments/taprootutils.js} (89%)
rename ts_src/{taproot.ts => payments/taprootutils.ts} (90%)
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index 78ef95311..4c79a9b1d 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -5,7 +5,7 @@ const buffer_1 = require('buffer');
const networks_1 = require('../networks');
const bscript = require('../script');
const types_1 = require('../types');
-const taproot_1 = require('../taproot');
+const taprootutils_1 = require('./taprootutils');
const lazy = require('./lazy');
const bech32_1 = require('bech32');
const OPS = bscript.OPS;
@@ -75,14 +75,15 @@ function p2tr(ecc) {
});
lazy.prop(o, 'hash', () => {
if (a.hash) return a.hash;
- if (a.scriptsTree) return (0, taproot_1.toHashTree)(a.scriptsTree).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, taproot_1.tapLeafHash)(script, leafVersion);
- return (0, taproot_1.rootHashFromPath)(controlBlock, leafHash);
+ const leafHash = (0, taprootutils_1.tapLeafHash)(script, leafVersion);
+ return (0, taprootutils_1.rootHashFromPath)(controlBlock, leafHash);
}
return null;
});
@@ -119,12 +120,12 @@ function p2tr(ecc) {
if (a.witness) return a.witness;
if (a.scriptsTree && a.scriptLeaf && a.internalPubkey) {
// todo: optimize/cache
- const hashTree = (0, taproot_1.toHashTree)(a.scriptsTree);
- const leafHash = (0, taproot_1.tapLeafHash)(
+ const hashTree = (0, taprootutils_1.toHashTree)(a.scriptsTree);
+ const leafHash = (0, taprootutils_1.tapLeafHash)(
a.scriptLeaf.output,
a.scriptLeaf.version,
);
- const path = (0, taproot_1.findScriptPath)(hashTree, leafHash);
+ const path = (0, taprootutils_1.findScriptPath)(hashTree, leafHash);
const outputKey = tweakKey(a.internalPubkey, hashTree.hash);
if (!outputKey) return;
const version = a.scriptLeaf.version || 0xc0;
@@ -177,7 +178,7 @@ function p2tr(ecc) {
throw new TypeError('Invalid pubkey for p2tr');
}
if (a.hash && a.scriptsTree) {
- const hash = (0, taproot_1.toHashTree)(a.scriptsTree).hash;
+ const hash = (0, taprootutils_1.toHashTree)(a.scriptsTree).hash;
if (!a.hash.equals(hash)) throw new TypeError('Hash mismatch');
}
const witness = _witness();
@@ -216,8 +217,11 @@ function p2tr(ecc) {
throw new TypeError('Invalid internalPubkey for p2tr witness');
const leafVersion = controlBlock[0] & 0b11111110;
const script = witness[witness.length - 2];
- const leafHash = (0, taproot_1.tapLeafHash)(script, leafVersion);
- const hash = (0, taproot_1.rootHashFromPath)(controlBlock, leafHash);
+ const leafHash = (0, taprootutils_1.tapLeafHash)(script, leafVersion);
+ const hash = (0, taprootutils_1.rootHashFromPath)(
+ controlBlock,
+ leafHash,
+ );
const outputKey = tweakKey(internalPubkey, hash);
if (!outputKey)
// todo: needs test data
@@ -235,7 +239,7 @@ function p2tr(ecc) {
if (!buffer_1.Buffer.isBuffer(pubKey)) return null;
if (pubKey.length !== 32) return null;
if (h && h.length !== 32) return null;
- const tweakHash = (0, taproot_1.tapTweakHash)(pubKey, h);
+ const tweakHash = (0, taprootutils_1.tapTweakHash)(pubKey, h);
const res = ecc.xOnlyPointAddTweak(pubKey, tweakHash);
if (!res || res.xOnlyPubkey === null) return null;
return {
diff --git a/src/taproot.d.ts b/src/payments/taprootutils.d.ts
similarity index 92%
rename from src/taproot.d.ts
rename to src/payments/taprootutils.d.ts
index 37c118430..185ee79de 100644
--- a/src/taproot.d.ts
+++ b/src/payments/taprootutils.d.ts
@@ -1,5 +1,5 @@
///
-import { TaprootLeaf } from './types';
+import { TaprootLeaf } from '../types';
export declare function rootHashFromPath(controlBlock: Buffer, tapLeafMsg: Buffer): Buffer;
export interface HashTree {
hash: Buffer;
diff --git a/src/taproot.js b/src/payments/taprootutils.js
similarity index 89%
rename from src/taproot.js
rename to src/payments/taprootutils.js
index 98a7db377..d97169b1b 100644
--- a/src/taproot.js
+++ b/src/payments/taprootutils.js
@@ -2,11 +2,8 @@
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');
-// todo: use varuint-bitcoin??
-const varuint = require('bip174/src/lib/converter/varint');
-// todo: !!!Temp, to be replaced. Only works because bip32 has it as dependecy. Linting will fail.
-// const ecc = require('tiny-secp256k1');
+const bcrypto = require('../crypto');
+const bufferutils_1 = require('../bufferutils');
const LEAF_VERSION_TAPSCRIPT = 0xc0;
const TAP_LEAF_TAG = 'TapLeaf';
const TAP_BRANCH_TAG = 'TapBranch';
@@ -92,8 +89,8 @@ function tapTweakHash(pubKey, h) {
}
exports.tapTweakHash = tapTweakHash;
function serializeScript(s) {
- const varintLen = varuint.encodingLength(s.length);
+ const varintLen = bufferutils_1.varuint.encodingLength(s.length);
const buffer = buffer_1.Buffer.allocUnsafe(varintLen); // better
- varuint.encode(s.length, buffer);
+ bufferutils_1.varuint.encode(s.length, buffer);
return buffer_1.Buffer.concat([buffer, s]);
}
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index 0bb68465d..4520e93b5 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -8,12 +8,12 @@ import {
findScriptPath,
tapLeafHash,
tapTweakHash,
-} from '../taproot';
+} from './taprootutils';
import { Payment, PaymentOpts, PaymentCreator } from './index';
import * as lazy from './lazy';
import { bech32m } from 'bech32';
-const OPS = bscript.OPS;
+const OPS = bscript.OPS;
const TAPROOT_VERSION = 0x01;
const ANNEX_PREFIX = 0x50;
diff --git a/ts_src/taproot.ts b/ts_src/payments/taprootutils.ts
similarity index 90%
rename from ts_src/taproot.ts
rename to ts_src/payments/taprootutils.ts
index ca8fe9fd5..94567b37c 100644
--- a/ts_src/taproot.ts
+++ b/ts_src/payments/taprootutils.ts
@@ -1,12 +1,8 @@
import { Buffer as NBuffer } from 'buffer';
-import * as bcrypto from './crypto';
+import * as bcrypto from '../crypto';
-// todo: use varuint-bitcoin??
-import * as varuint from 'bip174/src/lib/converter/varint';
-import { TaprootLeaf } from './types';
-
-// todo: !!!Temp, to be replaced. Only works because bip32 has it as dependecy. Linting will fail.
-// const ecc = require('tiny-secp256k1');
+import { varuint } from '../bufferutils';
+import { TaprootLeaf } from '../types';
const LEAF_VERSION_TAPSCRIPT = 0xc0;
const TAP_LEAF_TAG = 'TapLeaf';
From fac6c9052f7b6bac9d0379c950dc99a10082bf9c Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Thu, 13 Jan 2022 17:04:06 +0200
Subject: [PATCH 035/144] refactor: move non-exported function to the bottom
---
ts_src/payments/taprootutils.ts | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/ts_src/payments/taprootutils.ts b/ts_src/payments/taprootutils.ts
index 94567b37c..cbfc3bfac 100644
--- a/ts_src/payments/taprootutils.ts
+++ b/ts_src/payments/taprootutils.ts
@@ -93,10 +93,6 @@ export function tapLeafHash(script: Buffer, version?: number): Buffer {
);
}
-function tapBranchHash(a: Buffer, b: Buffer): Buffer {
- return bcrypto.taggedHash(TAP_BRANCH_TAG, NBuffer.concat([a, b]));
-}
-
export function tapTweakHash(pubKey: Buffer, h: Buffer | undefined): Buffer {
return bcrypto.taggedHash(
TAP_TWEAK_TAG,
@@ -104,6 +100,10 @@ export function tapTweakHash(pubKey: Buffer, h: Buffer | undefined): Buffer {
);
}
+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
From 6578097dbf0d78e6be60b8eae639b1d3721384de Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Thu, 13 Jan 2022 17:14:33 +0200
Subject: [PATCH 036/144] fix: lint & gitdiff issues
---
src/payments/taprootutils.js | 6 +++---
test/payments.spec.ts | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/payments/taprootutils.js b/src/payments/taprootutils.js
index d97169b1b..fbcf90a7a 100644
--- a/src/payments/taprootutils.js
+++ b/src/payments/taprootutils.js
@@ -78,9 +78,6 @@ function tapLeafHash(script, version) {
);
}
exports.tapLeafHash = tapLeafHash;
-function tapBranchHash(a, b) {
- return bcrypto.taggedHash(TAP_BRANCH_TAG, buffer_1.Buffer.concat([a, b]));
-}
function tapTweakHash(pubKey, h) {
return bcrypto.taggedHash(
TAP_TWEAK_TAG,
@@ -88,6 +85,9 @@ function tapTweakHash(pubKey, h) {
);
}
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
diff --git a/test/payments.spec.ts b/test/payments.spec.ts
index b151a4d05..139594af2 100644
--- a/test/payments.spec.ts
+++ b/test/payments.spec.ts
@@ -8,7 +8,7 @@ const payments = PaymentFactory(ecc);
['embed', 'p2ms', 'p2pk', 'p2pkh', 'p2sh', 'p2wpkh', 'p2wsh', 'p2tr'].forEach(
p => {
describe(p, () => {
- //@ts-ignore
+ // @ts-ignore
const fn: PaymentCreator = payments[p];
const fixtures = require('./fixtures/' + p);
From 1577f6671611d0d8c5718d9516dc80a4a465652e Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Thu, 13 Jan 2022 18:39:06 +0200
Subject: [PATCH 037/144] chore: removed un-used exports
---
src/types.d.ts | 4 ----
src/types.js | 18 +++++++-----------
ts_src/types.ts | 8 ++------
3 files changed, 9 insertions(+), 21 deletions(-)
diff --git a/src/types.d.ts b/src/types.d.ts
index 014c2b910..aefc6bed7 100644
--- a/src/types.d.ts
+++ b/src/types.d.ts
@@ -1,9 +1,5 @@
///
-import { Buffer as NBuffer } from 'buffer';
export declare const typeforce: any;
-export declare const ZERO32: NBuffer;
-export declare const EC_P: NBuffer;
-export declare const GROUP_ORDER: NBuffer;
export declare function isPoint(p: Buffer | number | undefined | null): boolean;
export declare function UInt31(value: number): boolean;
export declare function BIP32Path(value: string): boolean;
diff --git a/src/types.js b/src/types.js
index a8acbef86..a6d1efa16 100644
--- a/src/types.js
+++ b/src/types.js
@@ -1,30 +1,26 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.oneOf = exports.Null = exports.BufferN = exports.Function = exports.UInt32 = exports.UInt8 = exports.tuple = exports.maybe = exports.Hex = exports.Buffer = exports.String = exports.Boolean = exports.Array = exports.Number = exports.Hash256bit = exports.Hash160bit = exports.Buffer256bit = exports.Network = exports.ECPoint = exports.Satoshi = exports.Signer = exports.BIP32Path = exports.UInt31 = exports.isPoint = exports.GROUP_ORDER = exports.EC_P = exports.ZERO32 = exports.typeforce = void 0;
+exports.oneOf = exports.Null = exports.BufferN = exports.Function = exports.UInt32 = exports.UInt8 = exports.tuple = exports.maybe = exports.Hex = exports.Buffer = exports.String = exports.Boolean = exports.Array = exports.Number = exports.Hash256bit = exports.Hash160bit = exports.Buffer256bit = exports.Network = exports.ECPoint = exports.Satoshi = exports.Signer = exports.BIP32Path = exports.UInt31 = exports.isPoint = exports.typeforce = void 0;
const buffer_1 = require('buffer');
exports.typeforce = require('typeforce');
-exports.ZERO32 = buffer_1.Buffer.alloc(32, 0);
-exports.EC_P = buffer_1.Buffer.from(
+const ZERO32 = buffer_1.Buffer.alloc(32, 0);
+const EC_P = buffer_1.Buffer.from(
'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f',
'hex',
);
-exports.GROUP_ORDER = buffer_1.Buffer.from(
- 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141',
- 'hex',
-);
function isPoint(p) {
if (!buffer_1.Buffer.isBuffer(p)) return false;
if (p.length < 33) return false;
const t = p[0];
const x = p.slice(1, 33);
- if (x.compare(exports.ZERO32) === 0) return false;
- if (x.compare(exports.EC_P) >= 0) return false;
+ if (x.compare(ZERO32) === 0) return false;
+ if (x.compare(EC_P) >= 0) return false;
if ((t === 0x02 || t === 0x03) && p.length === 33) {
return true;
}
const y = p.slice(33);
- if (y.compare(exports.ZERO32) === 0) return false;
- if (y.compare(exports.EC_P) >= 0) return false;
+ if (y.compare(ZERO32) === 0) return false;
+ if (y.compare(EC_P) >= 0) return false;
if (t === 0x04 && p.length === 65) return true;
return false;
}
diff --git a/ts_src/types.ts b/ts_src/types.ts
index 93446e920..840ab9be2 100644
--- a/ts_src/types.ts
+++ b/ts_src/types.ts
@@ -2,15 +2,11 @@ import { Buffer as NBuffer } from 'buffer';
export const typeforce = require('typeforce');
-export const ZERO32 = NBuffer.alloc(32, 0);
-export const EC_P = NBuffer.from(
+const ZERO32 = NBuffer.alloc(32, 0);
+const EC_P = NBuffer.from(
'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f',
'hex',
);
-export const GROUP_ORDER = NBuffer.from(
- 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141',
- 'hex',
-);
export function isPoint(p: Buffer | number | undefined | null): boolean {
if (!NBuffer.isBuffer(p)) return false;
From af72a78e132be3b7ede5d121178446db5d40fdb9 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Thu, 13 Jan 2022 18:40:55 +0200
Subject: [PATCH 038/144] chore: add docs, simplify code
---
src/payments/taprootutils.d.ts | 16 +++++++++++++++-
src/payments/taprootutils.js | 26 +++++++++++++++++++-------
ts_src/payments/taprootutils.ts | 27 ++++++++++++++++++++-------
3 files changed, 54 insertions(+), 15 deletions(-)
diff --git a/src/payments/taprootutils.d.ts b/src/payments/taprootutils.d.ts
index 185ee79de..f68a37495 100644
--- a/src/payments/taprootutils.d.ts
+++ b/src/payments/taprootutils.d.ts
@@ -6,7 +6,21 @@ export interface HashTree {
left?: HashTree;
right?: HashTree;
}
-export declare function toHashTree(scripts: TaprootLeaf[]): 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
index fbcf90a7a..2da6a4b7d 100644
--- a/src/payments/taprootutils.js
+++ b/src/payments/taprootutils.js
@@ -23,9 +23,17 @@ function rootHashFromPath(controlBlock, tapLeafMsg) {
return k[m];
}
exports.rootHashFromPath = rootHashFromPath;
-function toHashTree(scripts) {
- if (scripts.length === 1) {
- const script = scripts[0];
+/**
+ * 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);
}
@@ -36,10 +44,8 @@ function toHashTree(scripts) {
hash: tapLeafHash(script.output, script.version),
};
}
- // todo: this is a binary tree, use zero an one index
- const half = Math.trunc(scripts.length / 2);
- const left = toHashTree(scripts.slice(0, half));
- const right = toHashTree(scripts.slice(half));
+ const left = toHashTree([scriptsTree[0]]);
+ const right = toHashTree([scriptsTree[1]]);
let leftHash = left.hash;
let rightHash = right.hash;
if (leftHash.compare(rightHash) === 1)
@@ -51,6 +57,12 @@ function toHashTree(scripts) {
};
}
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] : [];
diff --git a/ts_src/payments/taprootutils.ts b/ts_src/payments/taprootutils.ts
index cbfc3bfac..83ed9b14c 100644
--- a/ts_src/payments/taprootutils.ts
+++ b/ts_src/payments/taprootutils.ts
@@ -36,9 +36,17 @@ export interface HashTree {
right?: HashTree;
}
-export function toHashTree(scripts: TaprootLeaf[]): HashTree {
- if (scripts.length === 1) {
- const script = scripts[0];
+/**
+ * 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);
}
@@ -50,10 +58,9 @@ export function toHashTree(scripts: TaprootLeaf[]): HashTree {
hash: tapLeafHash(script.output, script.version),
};
}
- // todo: this is a binary tree, use zero an one index
- const half = Math.trunc(scripts.length / 2);
- const left = toHashTree(scripts.slice(0, half));
- const right = toHashTree(scripts.slice(half));
+
+ const left = toHashTree([scriptsTree[0]]);
+ const right = toHashTree([scriptsTree[1]]);
let leftHash = left.hash;
let rightHash = right.hash;
@@ -67,6 +74,12 @@ export function toHashTree(scripts: 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 function findScriptPath(node: HashTree, hash: Buffer): Buffer[] {
if (node.left) {
if (node.left.hash.equals(hash)) return node.right ? [node.right.hash] : [];
From f2a0c1d0a8b1e078c2aa398aff6a9d740b0cd6da Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Fri, 14 Jan 2022 16:18:13 +0200
Subject: [PATCH 039/144] feat: pass the ECC library as an optional parameter
to p2tr
---
src/payments/index.d.ts | 16 +-
src/payments/index.js | 24 +-
src/payments/p2tr.d.ts | 4 +-
src/payments/p2tr.js | 458 ++++++++++++++++-----------------
src/payments/testecc.js | 2 +
test/payments.spec.ts | 22 +-
ts_src/payments/index.ts | 28 +--
ts_src/payments/p2tr.ts | 502 +++++++++++++++++++------------------
ts_src/payments/testecc.ts | 2 +
9 files changed, 523 insertions(+), 535 deletions(-)
diff --git a/src/payments/index.d.ts b/src/payments/index.d.ts
index 72db5de25..a72a8ea41 100644
--- a/src/payments/index.d.ts
+++ b/src/payments/index.d.ts
@@ -8,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;
@@ -28,24 +29,13 @@ export interface Payment {
scriptLeaf?: TaprootLeaf;
witness?: Buffer[];
}
-export declare type PaymentCreator = (a: Payment, opts?: PaymentOpts) => Payment;
+export declare type PaymentCreator = (a: Payment, opts?: PaymentOpts, eccLib?: TinySecp256k1Interface) => Payment;
export declare type PaymentFunction = () => Payment;
export interface PaymentOpts {
validate?: boolean;
allowIncomplete?: boolean;
}
-export interface PaymentAPI {
- embed: PaymentCreator;
- p2ms: PaymentCreator;
- p2pk: PaymentCreator;
- p2pkh: PaymentCreator;
- p2sh: PaymentCreator;
- p2wpkh: PaymentCreator;
- p2wsh: PaymentCreator;
- p2tr: PaymentCreator;
-}
export declare type StackElement = Buffer | number;
export declare type Stack = StackElement[];
export declare type StackFunction = () => Stack;
-export { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh, PaymentFactory };
-export default function PaymentFactory(ecc: TinySecp256k1Interface): PaymentAPI;
+export { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh, p2tr };
diff --git a/src/payments/index.js b/src/payments/index.js
index 779df03fa..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.PaymentFactory = 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,
@@ -51,21 +51,11 @@ Object.defineProperty(exports, 'p2wsh', {
},
});
const p2tr_1 = require('./p2tr');
-const testecc_1 = require('./testecc');
-function PaymentFactory(ecc) {
- (0, testecc_1.testEcc)(ecc);
- return {
- embed: embed_1.p2data,
- p2ms: p2ms_1.p2ms,
- p2pk: p2pk_1.p2pk,
- p2pkh: p2pkh_1.p2pkh,
- p2sh: p2sh_1.p2sh,
- p2wpkh: p2wpkh_1.p2wpkh,
- p2wsh: p2wsh_1.p2wsh,
- p2tr: (0, p2tr_1.p2tr)(ecc),
- };
-}
-exports.default = PaymentFactory;
-exports.PaymentFactory = PaymentFactory;
+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
index e4d4c8a9b..3268bf450 100644
--- a/src/payments/p2tr.d.ts
+++ b/src/payments/p2tr.d.ts
@@ -1,3 +1,3 @@
import { TinySecp256k1Interface } from '../types';
-import { PaymentCreator } from './index';
-export declare function p2tr(ecc: TinySecp256k1Interface): PaymentCreator;
+import { Payment, PaymentOpts } from './index';
+export declare function p2tr(a: Payment, opts?: PaymentOpts, eccLib?: TinySecp256k1Interface): Payment;
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index 4c79a9b1d..1517ef0c6 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -8,244 +8,246 @@ 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(ecc) {
- return (a, opts) => {
+function p2tr(a, opts, eccLib) {
+ 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 (!eccLib) throw new Error('ECC Library is missing for p2tr.');
+ (0, testecc_1.testEcc)(eccLib);
+ return 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(bscript.isCanonicalScriptSignature),
+ 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.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 || {});
- (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(bscript.isCanonicalScriptSignature),
- 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;
+ 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.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];
+ 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 = w[w.length - 2];
+ const script = witness[witness.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);
- 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 hash = (0, taprootutils_1.rootHashFromPath)(
+ controlBlock,
+ leafHash,
);
- const path = (0, taprootutils_1.findScriptPath)(hashTree, leafHash);
- const outputKey = tweakKey(a.internalPubkey, hashTree.hash);
- 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);
- 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);
- 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');
- }
+ 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);
- };
- function tweakKey(pubKey, h) {
- 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 = ecc.xOnlyPointAddTweak(pubKey, tweakHash);
- if (!res || res.xOnlyPubkey === null) return null;
- return {
- parity: res.parity,
- x: buffer_1.Buffer.from(res.xOnlyPubkey),
- };
}
+ 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/testecc.js b/src/payments/testecc.js
index 9bdc62031..77e2b3e15 100644
--- a/src/payments/testecc.js
+++ b/src/payments/testecc.js
@@ -3,6 +3,7 @@ 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'),
@@ -33,6 +34,7 @@ function testEcc(ecc) {
h('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f'),
),
);
+ assert(typeof ecc.xOnlyPointAddTweak === 'function');
tweakAddVectors.forEach(t => {
const r = ecc.xOnlyPointAddTweak(h(t.pubkey), h(t.tweak));
if (t.result === null) {
diff --git a/test/payments.spec.ts b/test/payments.spec.ts
index 139594af2..e5227124e 100644
--- a/test/payments.spec.ts
+++ b/test/payments.spec.ts
@@ -1,22 +1,29 @@
import * as assert from 'assert';
-import { describe, it } from 'mocha';
import * as ecc from 'tiny-secp256k1';
-import { PaymentCreator, PaymentFactory } from '../src/payments';
+import { describe, it } from 'mocha';
+import { PaymentCreator } from '../src/payments';
import * as u from './payments.utils';
+import { TinySecp256k1Interface } from '../src/types';
-const payments = PaymentFactory(ecc);
['embed', 'p2ms', 'p2pk', 'p2pkh', 'p2sh', 'p2wpkh', 'p2wsh', 'p2tr'].forEach(
p => {
describe(p, () => {
- // @ts-ignore
- const fn: PaymentCreator = payments[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];
+ }
const fixtures = require('./fixtures/' + p);
fixtures.valid.forEach((f: any) => {
it(f.description + ' as expected', () => {
const args = u.preform(f.arguments);
- const actual = fn(args, f.options);
+ const actual = fn(args, f.options, eccLib);
u.equate(actual, f.expected, f.arguments);
});
@@ -28,6 +35,7 @@ const payments = PaymentFactory(ecc);
Object.assign({}, f.options, {
validate: false,
}),
+ eccLib,
);
u.equate(actual, f.expected, f.arguments);
@@ -43,7 +51,7 @@ const payments = PaymentFactory(ecc);
const args = u.preform(f.arguments);
assert.throws(() => {
- fn(args, f.options);
+ fn(args, f.options, eccLib);
}, new RegExp(f.exception));
},
);
diff --git a/ts_src/payments/index.ts b/ts_src/payments/index.ts
index f7c5dbadd..f2dcfb939 100644
--- a/ts_src/payments/index.ts
+++ b/ts_src/payments/index.ts
@@ -8,7 +8,6 @@ import { p2sh } from './p2sh';
import { p2wpkh } from './p2wpkh';
import { p2wsh } from './p2wsh';
import { p2tr } from './p2tr';
-import { testEcc } from './testecc';
export interface Payment {
name?: string;
@@ -31,7 +30,11 @@ export interface Payment {
witness?: Buffer[];
}
-export type PaymentCreator = (a: Payment, opts?: PaymentOpts) => Payment;
+export type PaymentCreator = (
+ a: Payment,
+ opts?: PaymentOpts,
+ eccLib?: TinySecp256k1Interface,
+) => Payment;
export type PaymentFunction = () => Payment;
@@ -40,30 +43,11 @@ export interface PaymentOpts {
allowIncomplete?: boolean;
}
-export interface PaymentAPI {
- embed: PaymentCreator;
- p2ms: PaymentCreator;
- p2pk: PaymentCreator;
- p2pkh: PaymentCreator;
- p2sh: PaymentCreator;
- p2wpkh: PaymentCreator;
- p2wsh: PaymentCreator;
- p2tr: PaymentCreator;
-}
-
export type StackElement = Buffer | number;
export type Stack = StackElement[];
export type StackFunction = () => Stack;
-export { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh, PaymentFactory };
-
-export default function PaymentFactory(
- ecc: TinySecp256k1Interface,
-): PaymentAPI {
- testEcc(ecc);
-
- return { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh, p2tr: p2tr(ecc) };
-}
+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
index 4520e93b5..1ecce1432 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -9,275 +9,285 @@ import {
tapLeafHash,
tapTweakHash,
} from './taprootutils';
-import { Payment, PaymentOpts, PaymentCreator } from './index';
+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(ecc: TinySecp256k1Interface): PaymentCreator {
- return (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 || {});
-
- 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(bscript.isCanonicalScriptSignature),
- 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);
- 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);
- 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;
- }
+export function p2tr(
+ a: Payment,
+ opts?: PaymentOpts,
+ eccLib?: TinySecp256k1Interface,
+): 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 (!eccLib) throw new Error('ECC Library is missing for p2tr.');
+
+ testEcc(eccLib);
+ return 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(bscript.isCanonicalScriptSignature),
+ 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),
+ };
+ });
- if (a.pubkey) {
- if (pubkey.length > 0 && !pubkey.equals(a.pubkey))
- throw new TypeError('Pubkey mismatch');
- else pubkey = a.pubkey;
- }
+ 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.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.pubkey) {
+ if (pubkey.length > 0 && !pubkey.equals(a.pubkey))
+ throw new TypeError('Pubkey mismatch');
+ else pubkey = a.pubkey;
+ }
- if (a.internalPubkey) {
- const tweakedKey = tweakKey(a.internalPubkey, o.hash);
- if (pubkey.length > 0 && !pubkey.equals(tweakedKey!.x))
- throw new TypeError('Pubkey mismatch');
- else pubkey = tweakedKey!.x;
- }
+ 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 (pubkey && pubkey.length) {
- if (!ecc.isXOnlyPoint(pubkey))
- throw new TypeError('Invalid pubkey for p2tr');
- }
+ 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 (a.hash && a.scriptsTree) {
- const hash = toHashTree(a.scriptsTree).hash;
- if (!a.hash.equals(hash)) throw new TypeError('Hash mismatch');
- }
+ if (pubkey && pubkey.length) {
+ if (!_ecc().isXOnlyPoint(pubkey))
+ throw new TypeError('Invalid pubkey for p2tr');
+ }
- 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);
- 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');
- }
- }
+ if (a.hash && a.scriptsTree) {
+ const hash = toHashTree(a.scriptsTree).hash;
+ if (!a.hash.equals(hash)) throw new TypeError('Hash mismatch');
}
- return Object.assign(o, a);
- };
+ 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');
- function tweakKey(
- pubKey: Buffer,
- h: Buffer | undefined,
- ): TweakedPublicKey | null {
- if (!NBuffer.isBuffer(pubKey)) return null;
- if (pubKey.length !== 32) return null;
- if (h && h.length !== 32) return null;
+ const leafVersion = controlBlock[0] & 0b11111110;
+ const script = witness[witness.length - 2];
- const tweakHash = tapTweakHash(pubKey, h);
+ const leafHash = tapLeafHash(script, leafVersion);
+ const hash = rootHashFromPath(controlBlock, leafHash);
- const res = ecc.xOnlyPointAddTweak(pubKey, tweakHash);
- if (!res || res.xOnlyPubkey === null) return null;
+ const outputKey = tweakKey(internalPubkey, hash, _ecc());
+ if (!outputKey)
+ // todo: needs test data
+ throw new TypeError('Invalid outputKey for p2tr witness');
- return {
- parity: res.parity,
- x: NBuffer.from(res.xOnlyPubkey),
- };
+ 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/testecc.ts b/ts_src/payments/testecc.ts
index 773fa3eb8..5e8643d67 100644
--- a/ts_src/payments/testecc.ts
+++ b/ts_src/payments/testecc.ts
@@ -3,6 +3,7 @@ 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'),
@@ -34,6 +35,7 @@ export function testEcc(ecc: TinySecp256k1Interface): void {
),
);
+ assert(typeof ecc.xOnlyPointAddTweak === 'function');
tweakAddVectors.forEach(t => {
const r = ecc.xOnlyPointAddTweak(h(t.pubkey), h(t.tweak));
if (t.result === null) {
From 2e5965d141deee95cec7f14c17a8912a0c5fab03 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Tue, 18 Jan 2022 09:10:37 +0200
Subject: [PATCH 040/144] refactor: move eccLib to PaymentOptions
---
src/payments/index.d.ts | 1 +
src/payments/p2tr.d.ts | 3 +--
src/payments/p2tr.js | 8 ++++----
test/payments.spec.ts | 8 +++++---
ts_src/payments/index.ts | 1 +
ts_src/payments/p2tr.ts | 12 ++++--------
6 files changed, 16 insertions(+), 17 deletions(-)
diff --git a/src/payments/index.d.ts b/src/payments/index.d.ts
index a72a8ea41..6c3e09c1a 100644
--- a/src/payments/index.d.ts
+++ b/src/payments/index.d.ts
@@ -34,6 +34,7 @@ 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[];
diff --git a/src/payments/p2tr.d.ts b/src/payments/p2tr.d.ts
index 3268bf450..350ed0ffc 100644
--- a/src/payments/p2tr.d.ts
+++ b/src/payments/p2tr.d.ts
@@ -1,3 +1,2 @@
-import { TinySecp256k1Interface } from '../types';
import { Payment, PaymentOpts } from './index';
-export declare function p2tr(a: Payment, opts?: PaymentOpts, eccLib?: TinySecp256k1Interface): Payment;
+export declare function p2tr(a: Payment, opts?: PaymentOpts): Payment;
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index 1517ef0c6..7e944e68b 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -12,7 +12,7 @@ const testecc_1 = require('./testecc');
const OPS = bscript.OPS;
const TAPROOT_VERSION = 0x01;
const ANNEX_PREFIX = 0x50;
-function p2tr(a, opts, eccLib) {
+function p2tr(a, opts) {
if (
!a.address &&
!a.output &&
@@ -24,9 +24,9 @@ function p2tr(a, opts, eccLib) {
throw new TypeError('Not enough data');
opts = Object.assign({ validate: true }, opts || {});
const _ecc = lazy.value(() => {
- if (!eccLib) throw new Error('ECC Library is missing for p2tr.');
- (0, testecc_1.testEcc)(eccLib);
- return eccLib;
+ 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)(
{
diff --git a/test/payments.spec.ts b/test/payments.spec.ts
index e5227124e..6726e96d8 100644
--- a/test/payments.spec.ts
+++ b/test/payments.spec.ts
@@ -21,9 +21,10 @@ import { TinySecp256k1Interface } from '../src/types';
const fixtures = require('./fixtures/' + p);
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, f.options, eccLib);
+ const actual = fn(args, options, eccLib);
u.equate(actual, f.expected, f.arguments);
});
@@ -32,7 +33,7 @@ import { TinySecp256k1Interface } from '../src/types';
const args = u.preform(f.arguments);
const actual = fn(
args,
- Object.assign({}, f.options, {
+ Object.assign({}, options, {
validate: false,
}),
eccLib,
@@ -43,6 +44,7 @@ import { TinySecp256k1Interface } from '../src/types';
});
fixtures.invalid.forEach((f: any) => {
+ const options = Object.assign({ eccLib }, f.options || {});
it(
'throws ' +
f.exception +
@@ -51,7 +53,7 @@ import { TinySecp256k1Interface } from '../src/types';
const args = u.preform(f.arguments);
assert.throws(() => {
- fn(args, f.options, eccLib);
+ fn(args, options, eccLib);
}, new RegExp(f.exception));
},
);
diff --git a/ts_src/payments/index.ts b/ts_src/payments/index.ts
index f2dcfb939..577bdcb22 100644
--- a/ts_src/payments/index.ts
+++ b/ts_src/payments/index.ts
@@ -41,6 +41,7 @@ export type PaymentFunction = () => Payment;
export interface PaymentOpts {
validate?: boolean;
allowIncomplete?: boolean;
+ eccLib?: TinySecp256k1Interface;
}
export type StackElement = Buffer | number;
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index 1ecce1432..66fa4946d 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -18,11 +18,7 @@ const OPS = bscript.OPS;
const TAPROOT_VERSION = 0x01;
const ANNEX_PREFIX = 0x50;
-export function p2tr(
- a: Payment,
- opts?: PaymentOpts,
- eccLib?: TinySecp256k1Interface,
-): Payment {
+export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
if (
!a.address &&
!a.output &&
@@ -36,10 +32,10 @@ export function p2tr(
opts = Object.assign({ validate: true }, opts || {});
const _ecc = lazy.value(() => {
- if (!eccLib) throw new Error('ECC Library is missing for p2tr.');
+ if (!opts!.eccLib) throw new Error('ECC Library is missing for p2tr.');
- testEcc(eccLib);
- return eccLib;
+ testEcc(opts!.eccLib);
+ return opts!.eccLib;
});
typef(
From e292387cbd818586d0c9f703ef3558cf04ad4a8e Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Thu, 20 Jan 2022 08:51:44 +0200
Subject: [PATCH 041/144] fix: remove `TinySecp256k1Interface` from
`PaymentCreator`
---
src/payments/index.d.ts | 2 +-
test/payments.spec.ts | 5 ++---
ts_src/payments/index.ts | 6 +-----
3 files changed, 4 insertions(+), 9 deletions(-)
diff --git a/src/payments/index.d.ts b/src/payments/index.d.ts
index 6c3e09c1a..6b186c4d1 100644
--- a/src/payments/index.d.ts
+++ b/src/payments/index.d.ts
@@ -29,7 +29,7 @@ export interface Payment {
scriptLeaf?: TaprootLeaf;
witness?: Buffer[];
}
-export declare type PaymentCreator = (a: Payment, opts?: PaymentOpts, eccLib?: TinySecp256k1Interface) => Payment;
+export declare type PaymentCreator = (a: Payment, opts?: PaymentOpts) => Payment;
export declare type PaymentFunction = () => Payment;
export interface PaymentOpts {
validate?: boolean;
diff --git a/test/payments.spec.ts b/test/payments.spec.ts
index 6726e96d8..e89834d3b 100644
--- a/test/payments.spec.ts
+++ b/test/payments.spec.ts
@@ -24,7 +24,7 @@ import { TinySecp256k1Interface } from '../src/types';
const options = Object.assign({ eccLib }, f.options || {});
it(f.description + ' as expected', () => {
const args = u.preform(f.arguments);
- const actual = fn(args, options, eccLib);
+ const actual = fn(args, options);
u.equate(actual, f.expected, f.arguments);
});
@@ -36,7 +36,6 @@ import { TinySecp256k1Interface } from '../src/types';
Object.assign({}, options, {
validate: false,
}),
- eccLib,
);
u.equate(actual, f.expected, f.arguments);
@@ -53,7 +52,7 @@ import { TinySecp256k1Interface } from '../src/types';
const args = u.preform(f.arguments);
assert.throws(() => {
- fn(args, options, eccLib);
+ fn(args, options);
}, new RegExp(f.exception));
},
);
diff --git a/ts_src/payments/index.ts b/ts_src/payments/index.ts
index 577bdcb22..7bb77b6ac 100644
--- a/ts_src/payments/index.ts
+++ b/ts_src/payments/index.ts
@@ -30,11 +30,7 @@ export interface Payment {
witness?: Buffer[];
}
-export type PaymentCreator = (
- a: Payment,
- opts?: PaymentOpts,
- eccLib?: TinySecp256k1Interface,
-) => Payment;
+export type PaymentCreator = (a: Payment, opts?: PaymentOpts) => Payment;
export type PaymentFunction = () => Payment;
From 06fc272837493579f74ed7b87d4f2c5f41ab8c93 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Thu, 20 Jan 2022 08:52:43 +0200
Subject: [PATCH 042/144] chore: keep ecc test vectors to a minimum
---
src/payments/testecc.js | 102 -------------------------------------
ts_src/payments/testecc.ts | 102 -------------------------------------
2 files changed, 204 deletions(-)
diff --git a/src/payments/testecc.js b/src/payments/testecc.js
index 77e2b3e15..44e19c887 100644
--- a/src/payments/testecc.js
+++ b/src/payments/testecc.js
@@ -63,112 +63,10 @@ const tweakAddVectors = [
parity: 1,
result: 'e478f99dab91052ab39a33ea35fd5e6e4933f4d28023cd597c9a1f6760346adf',
},
- {
- pubkey: '2f1b310f4c065331bc0d79ba4661bb9822d67d7c4a1b0a1892e1fd0cd23aa68d',
- tweak: '40ab636041bb695843ac7f220344565bed3b5dca919e256b7e31e19d69b36fad',
- parity: 1,
- result: '5786150f0ac36a2aaeb8d11aaeb7aa2d03ad63c528cc307a7cd5648c84041f34',
- },
- {
- pubkey: 'e7e9acacbdb43fc9fb71a8db1536c0f866caa78def49f666fa121a6f7954bb01',
- tweak: '1ad613216778a70490c8a681a4901d4ca880d76916deb69979b5ac52d2760e09',
- parity: 1,
- result: 'ae10fa880c85848cc1faf056f56a64b7d45c68838cfb308d03ca2be9b485c130',
- },
{
pubkey: '2c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991',
tweak: '823c3cd2142744b075a87eade7e1b8678ba308d566226a0056ca2b7a76f86b47',
parity: 0,
result: '9534f8dc8c6deda2dc007655981c78b49c5d96c778fbf363462a11ec9dfd948c',
},
- {
- pubkey: '8f19ee7677713806c662078a9f2b2c7b930376d22f2d617bce50b5e444839a7c',
- tweak: '7df1f4b66058f8be34b6b7d17be9bcf35ba5c98edf8d4e763b95964bad655fe4',
- parity: 1,
- result: '74619a5990750928d0728817b02bb0d398062dad0e568f46ea5348d35bef914f',
- },
- {
- pubkey: '2bda68b3aa0239d382f185ca2d8c31ce604cc26220cef3eb65223f47a0088d87',
- tweak: 'e5a018b3a2e155316109d9cdc5eab739759c0e07e0c00bf9fccb8237fe4d7f02',
- parity: 0,
- result: '84479dc6bf70762721b10b89c8798e00d525507edc3fabbfc89ad915b6509379',
- },
- {
- pubkey: '9611ba340bce00a594f1ffb1294974af80e1301e49597378732fd77bbdedf454',
- tweak: 'bbb8ec1f063522953a4a9f90ff4e849560e0f0597458529ea13b8868f255c7c7',
- parity: 0,
- result: '30bebfdad18b87b646f60e51d3c45c6658fbb4364c94b1b33d925a4515b66757',
- },
- {
- pubkey: 'd9f5792078a845303c1f1ea88aec79ed0fd9f0c49e9e7bff2765877e79b4dd52',
- tweak: '531fe6068134503d2723133227c867ac8fa6c83c537e9a44c3c5bdbdcb1fe337',
- parity: 0,
- result: 'fe5dd39f0491af71711454eee5b6a9c99779c422dd97f5e7f75d7ce7be7b32f0',
- },
- {
- pubkey: '40ab636041bb695843ac7f220344565bed3b5dca919e256b7e31e19d69b36fad',
- tweak: '048968943184ce8a0239ab2141641e8eaead35a6dc8e6b55ad33ac1eca975a47',
- parity: 1,
- result: '6c8245a62201887c5e3aeb022fff06e6c110f3e58ad6d37cc20e877082b72c58',
- },
- {
- pubkey: '6aa3da9b5c1d61956076cb3014ffdaa0996bacdae29ba4b89e39b4088f86ec78',
- tweak: 'ff8adab52623bcb2717fc71d7edc6f55e98396e6c234dff01f307a12b2af1c99',
- parity: 1,
- result: 'd6080b5df61525fe8be31a823f3943e5fc9354d5a091b2dea195985c7c395787',
- },
- {
- pubkey: '24653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c',
- tweak: '9e5f7dbe6d62ade5aab476b40559852ea1b5fc7bb99a61a42eab550f69ffafb4',
- parity: 0,
- result: '58289ee230fcf6a78cb9878cae5102cc9104490abab9d03f3eccc2f0cd07de5f',
- },
- {
- pubkey: 'e5a018b3a2e155316109d9cdc5eab739759c0e07e0c00bf9fccb8237fe4d7f02',
- tweak: 'bde750d93efe821813df9c15ee676f2e9c63386336c164f5a15cf240ac653c06',
- parity: 0,
- result: '9a1ae919c5c78da635d94a92b3053e46b2261b81ec70db82a382f5bff474bec4',
- },
- {
- pubkey: 'bc14bc97e2d818ee360a9ba7782bd6a6dfc2c1e335fffc584a095fdac5fea641',
- tweak: '4f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa',
- parity: 1,
- result: '19a7416f4f95f36c5e48dc7630ffea8b292e1721cecfa9cc5f794c83973e41d6',
- },
- {
- pubkey: '35e9d7c48e3a5254d5881b60abf004cf6eedc6ab842393caa2fdd20d6d0ad170',
- tweak: '18bb586dc109adf49ffb42e0ac293d2a2965e49a0a4900c2be776b426b7cbfde',
- parity: 0,
- result: 'fa7cca72580bb686fbbae09ded801c7d109fa378f52e8a5f43a1922e442e44c1',
- },
- {
- pubkey: '67bff656551f25009ac8ed88664736c08074a15dbd2268292f5de7ca7e718338',
- tweak: 'b96359049e97f49d871e856f37e54d0978bae2cc936b4484d96df984cd20daa1',
- parity: 0,
- result: 'dd081d737da17fb4f6686f8497cac56b16ea06e1dc05859633f735fb304e7e5a',
- },
- {
- pubkey: '5b0da52533a1620fe947cb658c35e1772f39ef1253753493b7dc4b8d8f31f40e',
- tweak: '3d481f46056f2da27870a5d00c0c7bf484036780a83bbcc2e2da2f03bc33bff0',
- parity: 1,
- result: '164e13b54edc89673f94563120d87db4a47b12e49c40c195ac51ea7bc50f22e1',
- },
- {
- pubkey: '0612c5e8c98a9677a2ddd13770e26f5f1e771a088c88ce519a1e1b65872423f9',
- tweak: 'dbcfa1c73674cba4aa1b6992ebdc6a77008d38f6c6ec068c3c862b9ff6d287f2',
- parity: 0,
- result: '82fc6954352b7189a156e4678d0c315c122431fa9551961b8e3c811b55a42c8b',
- },
- {
- pubkey: '9ac20335eb38768d2052be1dbbc3c8f6178407458e51e6b4ad22f1d91758895b',
- tweak: '6aa3da9b5c1d61956076cb3014ffdaa0996bacdae29ba4b89e39b4088f86ec78',
- parity: 1,
- result: 'cf9065a7e2c9f909becc1c95f9884ed9fbe19c4a8954ed17880f02d94ae96a63',
- },
- {
- pubkey: 'c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5',
- tweak: 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036413f',
- parity: -1,
- result: null,
- },
];
diff --git a/ts_src/payments/testecc.ts b/ts_src/payments/testecc.ts
index 5e8643d67..382d6149a 100644
--- a/ts_src/payments/testecc.ts
+++ b/ts_src/payments/testecc.ts
@@ -65,112 +65,10 @@ const tweakAddVectors = [
parity: 1,
result: 'e478f99dab91052ab39a33ea35fd5e6e4933f4d28023cd597c9a1f6760346adf',
},
- {
- pubkey: '2f1b310f4c065331bc0d79ba4661bb9822d67d7c4a1b0a1892e1fd0cd23aa68d',
- tweak: '40ab636041bb695843ac7f220344565bed3b5dca919e256b7e31e19d69b36fad',
- parity: 1,
- result: '5786150f0ac36a2aaeb8d11aaeb7aa2d03ad63c528cc307a7cd5648c84041f34',
- },
- {
- pubkey: 'e7e9acacbdb43fc9fb71a8db1536c0f866caa78def49f666fa121a6f7954bb01',
- tweak: '1ad613216778a70490c8a681a4901d4ca880d76916deb69979b5ac52d2760e09',
- parity: 1,
- result: 'ae10fa880c85848cc1faf056f56a64b7d45c68838cfb308d03ca2be9b485c130',
- },
{
pubkey: '2c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991',
tweak: '823c3cd2142744b075a87eade7e1b8678ba308d566226a0056ca2b7a76f86b47',
parity: 0,
result: '9534f8dc8c6deda2dc007655981c78b49c5d96c778fbf363462a11ec9dfd948c',
},
- {
- pubkey: '8f19ee7677713806c662078a9f2b2c7b930376d22f2d617bce50b5e444839a7c',
- tweak: '7df1f4b66058f8be34b6b7d17be9bcf35ba5c98edf8d4e763b95964bad655fe4',
- parity: 1,
- result: '74619a5990750928d0728817b02bb0d398062dad0e568f46ea5348d35bef914f',
- },
- {
- pubkey: '2bda68b3aa0239d382f185ca2d8c31ce604cc26220cef3eb65223f47a0088d87',
- tweak: 'e5a018b3a2e155316109d9cdc5eab739759c0e07e0c00bf9fccb8237fe4d7f02',
- parity: 0,
- result: '84479dc6bf70762721b10b89c8798e00d525507edc3fabbfc89ad915b6509379',
- },
- {
- pubkey: '9611ba340bce00a594f1ffb1294974af80e1301e49597378732fd77bbdedf454',
- tweak: 'bbb8ec1f063522953a4a9f90ff4e849560e0f0597458529ea13b8868f255c7c7',
- parity: 0,
- result: '30bebfdad18b87b646f60e51d3c45c6658fbb4364c94b1b33d925a4515b66757',
- },
- {
- pubkey: 'd9f5792078a845303c1f1ea88aec79ed0fd9f0c49e9e7bff2765877e79b4dd52',
- tweak: '531fe6068134503d2723133227c867ac8fa6c83c537e9a44c3c5bdbdcb1fe337',
- parity: 0,
- result: 'fe5dd39f0491af71711454eee5b6a9c99779c422dd97f5e7f75d7ce7be7b32f0',
- },
- {
- pubkey: '40ab636041bb695843ac7f220344565bed3b5dca919e256b7e31e19d69b36fad',
- tweak: '048968943184ce8a0239ab2141641e8eaead35a6dc8e6b55ad33ac1eca975a47',
- parity: 1,
- result: '6c8245a62201887c5e3aeb022fff06e6c110f3e58ad6d37cc20e877082b72c58',
- },
- {
- pubkey: '6aa3da9b5c1d61956076cb3014ffdaa0996bacdae29ba4b89e39b4088f86ec78',
- tweak: 'ff8adab52623bcb2717fc71d7edc6f55e98396e6c234dff01f307a12b2af1c99',
- parity: 1,
- result: 'd6080b5df61525fe8be31a823f3943e5fc9354d5a091b2dea195985c7c395787',
- },
- {
- pubkey: '24653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c',
- tweak: '9e5f7dbe6d62ade5aab476b40559852ea1b5fc7bb99a61a42eab550f69ffafb4',
- parity: 0,
- result: '58289ee230fcf6a78cb9878cae5102cc9104490abab9d03f3eccc2f0cd07de5f',
- },
- {
- pubkey: 'e5a018b3a2e155316109d9cdc5eab739759c0e07e0c00bf9fccb8237fe4d7f02',
- tweak: 'bde750d93efe821813df9c15ee676f2e9c63386336c164f5a15cf240ac653c06',
- parity: 0,
- result: '9a1ae919c5c78da635d94a92b3053e46b2261b81ec70db82a382f5bff474bec4',
- },
- {
- pubkey: 'bc14bc97e2d818ee360a9ba7782bd6a6dfc2c1e335fffc584a095fdac5fea641',
- tweak: '4f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa',
- parity: 1,
- result: '19a7416f4f95f36c5e48dc7630ffea8b292e1721cecfa9cc5f794c83973e41d6',
- },
- {
- pubkey: '35e9d7c48e3a5254d5881b60abf004cf6eedc6ab842393caa2fdd20d6d0ad170',
- tweak: '18bb586dc109adf49ffb42e0ac293d2a2965e49a0a4900c2be776b426b7cbfde',
- parity: 0,
- result: 'fa7cca72580bb686fbbae09ded801c7d109fa378f52e8a5f43a1922e442e44c1',
- },
- {
- pubkey: '67bff656551f25009ac8ed88664736c08074a15dbd2268292f5de7ca7e718338',
- tweak: 'b96359049e97f49d871e856f37e54d0978bae2cc936b4484d96df984cd20daa1',
- parity: 0,
- result: 'dd081d737da17fb4f6686f8497cac56b16ea06e1dc05859633f735fb304e7e5a',
- },
- {
- pubkey: '5b0da52533a1620fe947cb658c35e1772f39ef1253753493b7dc4b8d8f31f40e',
- tweak: '3d481f46056f2da27870a5d00c0c7bf484036780a83bbcc2e2da2f03bc33bff0',
- parity: 1,
- result: '164e13b54edc89673f94563120d87db4a47b12e49c40c195ac51ea7bc50f22e1',
- },
- {
- pubkey: '0612c5e8c98a9677a2ddd13770e26f5f1e771a088c88ce519a1e1b65872423f9',
- tweak: 'dbcfa1c73674cba4aa1b6992ebdc6a77008d38f6c6ec068c3c862b9ff6d287f2',
- parity: 0,
- result: '82fc6954352b7189a156e4678d0c315c122431fa9551961b8e3c811b55a42c8b',
- },
- {
- pubkey: '9ac20335eb38768d2052be1dbbc3c8f6178407458e51e6b4ad22f1d91758895b',
- tweak: '6aa3da9b5c1d61956076cb3014ffdaa0996bacdae29ba4b89e39b4088f86ec78',
- parity: 1,
- result: 'cf9065a7e2c9f909becc1c95f9884ed9fbe19c4a8954ed17880f02d94ae96a63',
- },
- {
- pubkey: 'c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5',
- tweak: 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036413f',
- parity: -1,
- result: null,
- },
];
From 25266421e8dff3394f6f9c7e09b54ca508c68aea Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Thu, 27 Jan 2022 14:40:11 +0200
Subject: [PATCH 043/144] fix: taproot signature is 64 bytes
---
src/payments/p2tr.js | 2 +-
test/fixtures/p2tr.json | 8 ++++----
ts_src/payments/p2tr.ts | 2 +-
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index 7e944e68b..d03d7980d 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -37,7 +37,7 @@ function p2tr(a, opts) {
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(bscript.isCanonicalScriptSignature),
+ signature: types_1.typeforce.maybe(types_1.typeforce.BufferN(64)),
witness: types_1.typeforce.maybe(
types_1.typeforce.arrayOf(types_1.typeforce.Buffer),
),
diff --git a/test/fixtures/p2tr.json b/test/fixtures/p2tr.json
index 02b1cb3c0..4c7174fc0 100644
--- a/test/fixtures/p2tr.json
+++ b/test/fixtures/p2tr.json
@@ -47,7 +47,7 @@
"description": "address, output and witness from pubkey and signature",
"arguments": {
"pubkey": "ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5",
- "signature": "300602010002010001"
+ "signature": "a251221c339a7129dd0b769698aca40d8d9da9570ab796a1820b91ab7dbf5acbea21c88ba8f1e9308a21729baf080734beaf97023882d972f75e380d480fd704"
},
"expected": {
"name": "p2tr",
@@ -55,7 +55,7 @@
"output": "OP_1 ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5",
"input": null,
"witness": [
- "300602010002010001"
+ "a251221c339a7129dd0b769698aca40d8d9da9570ab796a1820b91ab7dbf5acbea21c88ba8f1e9308a21729baf080734beaf97023882d972f75e380d480fd704"
]
}
},
@@ -908,9 +908,9 @@
"exception": "Signature mismatch",
"arguments": {
"pubkey": "ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5",
- "signature": "300602010002010002",
+ "signature": "a251221c339a7129dd0b769698aca40d8d9da9570ab796a1820b91ab7dbf5acbea21c88ba8f1e9308a21729baf080734beaf97023882d972f75e380d480fd704",
"witness": [
- "300602010002010001"
+ "607b8b5b5c8614757736e3d5811790636d2a8e2ea14418f8cff66b2e898b3b7536a49b7c4bc8b3227953194bf5d0548e13e3526fdb36beeefadda1ec834a0db2"
]
}
},
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index 66fa4946d..fa6598dc3 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -47,7 +47,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
internalPubkey: typef.maybe(typef.BufferN(32)),
hash: typef.maybe(typef.BufferN(32)),
pubkey: typef.maybe(typef.BufferN(32)),
- signature: typef.maybe(bscript.isCanonicalScriptSignature),
+ signature: typef.maybe(typef.BufferN(64)),
witness: typef.maybe(typef.arrayOf(typef.Buffer)),
// scriptsTree: typef.maybe(typef.TaprootNode), // use merkel.isMast ?
scriptLeaf: typef.maybe({
From fa1e1c3b94d0bd52d3b13137d275f91dbf593325 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Thu, 27 Jan 2022 15:09:42 +0200
Subject: [PATCH 044/144] feat: add Key Spend support for taproot to PSBT (more
in commit description)
- `signInput()` creates and serialises the Schnorr signature for the taproot inptuts
- only `SIGHASH_DEFAULT` supported at the moment
- `validateSignaturesOfInput()` validates taproot input Key Spend signatures
- add `tweakSigner()` as static method
- the `Signer` interface has an optional `privateKey` field (used for tweaking)
- direct dependency to `tiny-secp256k1` introduced
- it is awkward to pass an `ecc` lib from outside <- must be revisited
- added 'tiny-secp256k1' to package.json deps <- must be revisited
---
package-lock.json | 10 +--
package.json | 1 -
src/psbt.d.ts | 31 +++++++-
src/psbt.js | 142 ++++++++++++++++++++++++++++-----
test/fixtures/psbt.json | 30 +++++++
test/psbt.spec.ts | 65 +++++++++++++++
ts_src/psbt.ts | 171 +++++++++++++++++++++++++++++++++++-----
7 files changed, 405 insertions(+), 45 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 769a25397..8fdad2276 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2566,10 +2566,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"
}
@@ -2683,8 +2682,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=="
},
"uri-js": {
"version": "4.4.1",
diff --git a/package.json b/package.json
index 71e79082d..41f2722ae 100644
--- a/package.json
+++ b/package.json
@@ -85,7 +85,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/src/psbt.d.ts b/src/psbt.d.ts
index 8603a6955..4ce55ce0c 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;
+ /**
+ * Helper method for converting a normal Signer into a Taproot Signer.
+ * Note that this helper method requires 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 - tweak options
+ * @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,34 @@ 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;
}
+/**
+ * Options for tweaking a Signer into a valid Taproot Signer
+ */
+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 +207,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..6ce9ab82b 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;
}
+ /**
+ * Helper method for converting a normal Signer into a Taproot Signer.
+ * Note that this helper method requires 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 - tweak options
+ * @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/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/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/psbt.ts b/ts_src/psbt.ts
index b9af10fcf..230d23210 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;
}
+ /**
+ * Helper method for converting a normal Signer into a Taproot Signer.
+ * Note that this helper method requires 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 - tweak options
+ * @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,
)
@@ -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,37 @@ 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;
}
+/**
+ * Options for tweaking a Signer into a valid Taproot Signer
+ */
+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 +987,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 +1028,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 +1046,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 +1319,7 @@ function getHashAndSighashType(
const { hash, sighashType, script } = getHashForSig(
inputIndex,
input,
+ inputs,
cache,
false,
sighashTypes,
@@ -1241,6 +1334,7 @@ function getHashAndSighashType(
function getHashForSig(
inputIndex: number,
input: PsbtInput,
+ inputs: PsbtInput[],
cache: PsbtCache,
forValidate: boolean,
sighashTypes?: number[],
@@ -1311,6 +1405,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 +1486,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 +1551,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 +1772,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 +1801,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 +1935,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 +1955,7 @@ type AllScriptType =
| 'pubkeyhash'
| 'multisig'
| 'pubkey'
+ | 'taproot'
| 'nonstandard'
| 'p2sh-witnesspubkeyhash'
| 'p2sh-pubkeyhash'
@@ -1844,12 +1975,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';
}
From 04d0be928a32f543408ae8d5fafaaf877e7968bd Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Fri, 28 Jan 2022 15:18:16 +0200
Subject: [PATCH 045/144] feat: extract `tiny-secp256k1` out of the Psbt module
- the Psbt() constructor options accept an eccLib
- `tweakSigner()` is a public helper method
- `tiny-secp256k1` is only a dev dependency now
---
package-lock.json | 4 +-
package.json | 1 +
src/index.d.ts | 2 +-
src/index.js | 8 ++-
src/payments/p2tr.js | 5 +-
src/psbt.d.ts | 27 +++++-----
src/psbt.js | 109 +++++++++++++++++++++++-----------------
src/types.d.ts | 2 +
test/fixtures/psbt.json | 1 +
test/psbt.spec.ts | 20 +++++---
ts_src/index.ts | 1 +
ts_src/payments/p2tr.ts | 5 +-
ts_src/psbt.ts | 107 +++++++++++++++++++++------------------
ts_src/types.ts | 2 +
14 files changed, 172 insertions(+), 122 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 8fdad2276..0198cd374 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2569,6 +2569,7 @@
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-2.2.0.tgz",
"integrity": "sha512-2hPuUGCroLrxh6xxwoe+1RgPpOOK1w2uTnhgiHBpvoutBR+krNuT4hOXQyOaaYnZgoXBB6hBYkuAJHxyeBOPzQ==",
+ "dev": true,
"requires": {
"uint8array-tools": "0.0.6"
}
@@ -2682,7 +2683,8 @@
"uint8array-tools": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.6.tgz",
- "integrity": "sha512-aIvEHNRX1AlOYAr6qSUjQBn4mCduxx6MtC967aRDTb2UUBPj0Ix2ZFQDcmXUUO/UxRPHcw1f5a5nVbCSKDSOqA=="
+ "integrity": "sha512-aIvEHNRX1AlOYAr6qSUjQBn4mCduxx6MtC967aRDTb2UUBPj0Ix2ZFQDcmXUUO/UxRPHcw1f5a5nVbCSKDSOqA==",
+ "dev": true
},
"uri-js": {
"version": "4.4.1",
diff --git a/package.json b/package.json
index 41f2722ae..c78538ba0 100644
--- a/package.json
+++ b/package.json
@@ -85,6 +85,7 @@
"randombytes": "^2.1.0",
"regtest-client": "0.2.0",
"rimraf": "^2.6.3",
+ "tiny-secp256k1": "^2.2.0",
"ts-node": "^8.3.0",
"tslint": "^6.1.3",
"typescript": "^4.4.4"
diff --git a/src/index.d.ts b/src/index.d.ts
index b93c2aa40..13259bed6 100644
--- a/src/index.d.ts
+++ b/src/index.d.ts
@@ -6,7 +6,7 @@ import * as script from './script';
export { address, crypto, networks, payments, script };
export { Block } from './block';
export { TaggedHashPrefix } from './crypto';
-export { Psbt, PsbtTxInput, PsbtTxOutput, Signer, SignerAsync, HDSigner, HDSignerAsync, } from './psbt';
+export { Psbt, PsbtTxInput, PsbtTxOutput, Signer, SignerAsync, HDSigner, HDSignerAsync, tweakSigner, } from './psbt';
export { OPS as opcodes } from './ops';
export { Transaction } from './transaction';
export { Network } from './networks';
diff --git a/src/index.js b/src/index.js
index 983b0cc76..55d2b0068 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,6 +1,6 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.Transaction = exports.opcodes = exports.Psbt = exports.Block = exports.script = exports.payments = exports.networks = exports.crypto = exports.address = void 0;
+exports.Transaction = exports.opcodes = exports.tweakSigner = exports.Psbt = exports.Block = exports.script = exports.payments = exports.networks = exports.crypto = exports.address = void 0;
const address = require('./address');
exports.address = address;
const crypto = require('./crypto');
@@ -25,6 +25,12 @@ Object.defineProperty(exports, 'Psbt', {
return psbt_1.Psbt;
},
});
+Object.defineProperty(exports, 'tweakSigner', {
+ enumerable: true,
+ get: function() {
+ return psbt_1.tweakSigner;
+ },
+});
var ops_1 = require('./ops');
Object.defineProperty(exports, 'opcodes', {
enumerable: true,
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index d03d7980d..79fe62a6f 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -17,7 +17,6 @@ function p2tr(a, opts) {
!a.address &&
!a.output &&
!a.pubkey &&
- !a.output &&
!a.internalPubkey &&
!(a.witness && a.witness.length > 1)
)
@@ -115,6 +114,7 @@ function p2tr(a, opts) {
return witness[witness.length - 1].slice(1, 33);
});
lazy.prop(o, 'signature', () => {
+ if (a.signature) return a.signature;
if (!a.witness || a.witness.length !== 1) return;
return a.witness[0];
});
@@ -192,9 +192,6 @@ function p2tr(a, opts) {
// 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];
diff --git a/src/psbt.d.ts b/src/psbt.d.ts
index 4ce55ce0c..57e3f4d35 100644
--- a/src/psbt.d.ts
+++ b/src/psbt.d.ts
@@ -1,8 +1,10 @@
///
import { Psbt as PsbtBase } from 'bip174';
import { KeyValue, PsbtGlobalUpdate, PsbtInput, PsbtInputUpdate, PsbtOutput, PsbtOutputUpdate } from 'bip174/src/lib/interfaces';
+import { TinySecp256k1Interface as ECPairTinySecp256k1Interface } from 'ecpair';
import { Network } from './networks';
import { Transaction } from './transaction';
+import { TinySecp256k1Interface } from './types';
export interface TransactionInput {
hash: string | Buffer;
index: number;
@@ -56,17 +58,6 @@ 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;
- /**
- * Helper method for converting a normal Signer into a Taproot Signer.
- * Note that this helper method requires 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 - tweak options
- * @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);
@@ -118,9 +109,21 @@ export declare class Psbt {
addUnknownKeyValToOutput(outputIndex: number, keyVal: KeyValue): this;
clearFinalizedInput(inputIndex: number): this;
}
+/**
+ * Helper method for converting a normal Signer into a Taproot Signer.
+ * Note that this helper method requires 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 - tweak options
+ * @returns a Signer having the Private and Public keys tweaked
+ */
+export declare function tweakSigner(signer: Signer, opts: TaprootSignerOpts): Signer;
interface PsbtOptsOptional {
network?: Network;
maximumFeeRate?: number;
+ eccLib?: TinySecp256k1Interface;
}
interface PsbtInputExtended extends PsbtInput, TransactionInput {
}
@@ -181,7 +184,7 @@ export interface Signer {
*/
export interface TaprootSignerOpts {
network?: Network;
- eccLib?: any;
+ eccLib: TinySecp256k1Interface & ECPairTinySecp256k1Interface;
/** The hash used to tweak the Signer */
tweakHash?: Buffer;
}
diff --git a/src/psbt.js b/src/psbt.js
index 6ce9ab82b..70594153a 100644
--- a/src/psbt.js
+++ b/src/psbt.js
@@ -1,7 +1,6 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.Psbt = void 0;
-const ecc = require('tiny-secp256k1'); // TODO: extract
+exports.tweakSigner = exports.Psbt = void 0;
const ecpair_1 = require('ecpair');
const bip174_1 = require('bip174');
const varuint = require('bip174/src/lib/converter/varint');
@@ -81,6 +80,7 @@ class Psbt {
// We will disable exporting the Psbt when unsafe sign is active.
// because it is not BIP174 compliant.
__UNSAFE_SIGN_NONSEGWIT: false,
+ __EC_LIB: opts.eccLib,
};
if (this.data.inputs.length === 0) this.setVersion(2);
// Make data hidden when enumerating
@@ -106,39 +106,6 @@ class Psbt {
checkTxForDupeIns(psbt.__CACHE.__TX, psbt.__CACHE);
return psbt;
}
- /**
- * Helper method for converting a normal Signer into a Taproot Signer.
- * Note that this helper method requires 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 - tweak options
- * @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;
}
@@ -307,7 +274,7 @@ class Psbt {
range(this.data.inputs.length).forEach(idx => this.finalizeInput(idx));
return this;
}
- finalizeInput(inputIndex, finalScriptsFunc = getFinalScripts) {
+ finalizeInput(inputIndex, finalScriptsFunc) {
const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
const { script, isP2SH, isP2WSH, isSegwit } = getScriptFromInput(
inputIndex,
@@ -316,13 +283,15 @@ class Psbt {
);
if (!script) throw new Error(`No script found for input #${inputIndex}`);
checkPartialSigSighashes(input);
- const { finalScriptSig, finalScriptWitness } = finalScriptsFunc(
+ const fn = finalScriptsFunc || getFinalScripts;
+ const { finalScriptSig, finalScriptWitness } = fn(
inputIndex,
input,
script,
isSegwit,
isP2SH,
isP2WSH,
+ this.__CACHE.__EC_LIB,
);
if (finalScriptSig) this.data.updateInput(inputIndex, { finalScriptSig });
if (finalScriptWitness)
@@ -348,7 +317,10 @@ class Psbt {
redeemFromFinalWitnessScript(input.finalScriptWitness),
);
const type = result.type === 'raw' ? '' : result.type + '-';
- const mainType = classifyScript(result.meaningfulScript);
+ const mainType = classifyScript(
+ result.meaningfulScript,
+ this.__CACHE.__EC_LIB,
+ );
return type + mainType;
}
inputHasPubkey(inputIndex, pubkey) {
@@ -676,6 +648,41 @@ class Psbt {
}
}
exports.Psbt = Psbt;
+/**
+ * Helper method for converting a normal Signer into a Taproot Signer.
+ * Note that this helper method requires 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 - tweak options
+ * @returns a Signer having the Private and Public keys tweaked
+ */
+function tweakSigner(signer, opts) {
+ // todo: test ecc??
+ let privateKey = signer.privateKey;
+ if (!privateKey) {
+ throw new Error('Private key is required for tweaking signer!');
+ }
+ if (signer.publicKey[0] === 3) {
+ privateKey = opts.eccLib.privateNegate(privateKey);
+ }
+ const tweakedPrivateKey = opts.eccLib.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)(opts.eccLib);
+ return ECPair.fromPrivateKey(Buffer.from(tweakedPrivateKey), {
+ network: opts.network,
+ });
+}
+exports.tweakSigner = tweakSigner;
/**
* This function is needed to pass to the bip174 base class's fromBuffer.
* It takes the "transaction buffer" portion of the psbt buffer and returns a
@@ -928,8 +935,16 @@ function getTxCacheValue(key, name, inputs, c) {
if (key === '__FEE_RATE') return c.__FEE_RATE;
else if (key === '__FEE') return c.__FEE;
}
-function getFinalScripts(inputIndex, input, script, isSegwit, isP2SH, isP2WSH) {
- const scriptType = classifyScript(script);
+function getFinalScripts(
+ inputIndex,
+ input,
+ script,
+ isSegwit,
+ isP2SH,
+ isP2WSH,
+ eccLib,
+) {
+ const scriptType = classifyScript(script, eccLib);
if (!canFinalize(input, script, scriptType))
throw new Error(`Can not finalize input #${inputIndex}`);
return prepareFinalScripts(
@@ -1063,7 +1078,7 @@ function getHashForSig(
prevout.value,
sighashType,
);
- } else if (isP2TR(meaningfulScript, ecc)) {
+ } else if (isP2TR(meaningfulScript, cache.__EC_LIB)) {
const prevOuts = inputs.map((i, index) =>
getScriptAndAmountFromUtxo(index, i, cache),
);
@@ -1143,7 +1158,7 @@ function getPayment(script, scriptType, partialSig) {
output: script,
signature: partialSig[0].signature,
},
- { eccLib: ecc },
+ { validate: false },
);
break;
}
@@ -1190,7 +1205,11 @@ function getScriptFromInput(inputIndex, input, cache) {
res.script = input.witnessUtxo.script;
}
}
- if (input.witnessScript || isP2WPKH(res.script) || isP2TR(res.script, ecc)) {
+ if (
+ input.witnessScript ||
+ isP2WPKH(res.script) ||
+ isP2TR(res.script, cache.__EC_LIB)
+ ) {
res.isSegwit = true;
}
return res;
@@ -1504,12 +1523,12 @@ function pubkeyInScript(pubkey, script) {
);
});
}
-function classifyScript(script) {
+function classifyScript(script, eccLib) {
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';
+ if (isP2TR(script, eccLib)) return 'taproot';
return 'nonstandard';
}
function range(n) {
diff --git a/src/types.d.ts b/src/types.d.ts
index aefc6bed7..5ddded9a2 100644
--- a/src/types.d.ts
+++ b/src/types.d.ts
@@ -21,6 +21,8 @@ export interface TaprootLeaf {
export interface TinySecp256k1Interface {
isXOnlyPoint(p: Uint8Array): boolean;
xOnlyPointAddTweak(p: Uint8Array, tweak: Uint8Array): XOnlyPointAddTweakResult | null;
+ privateAdd(d: Uint8Array, tweak: Uint8Array): Uint8Array | null;
+ privateNegate(d: Uint8Array): Uint8Array;
}
export declare const Buffer256bit: any;
export declare const Hash160bit: any;
diff --git a/test/fixtures/psbt.json b/test/fixtures/psbt.json
index b113d75b6..2e7d9cf76 100644
--- a/test/fixtures/psbt.json
+++ b/test/fixtures/psbt.json
@@ -281,6 +281,7 @@
{
"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=",
+ "isTaproot": true,
"keys": [
{
"inputToSign": 0,
diff --git a/test/psbt.spec.ts b/test/psbt.spec.ts
index 3f4cf93b8..d5693c7ed 100644
--- a/test/psbt.spec.ts
+++ b/test/psbt.spec.ts
@@ -8,7 +8,14 @@ import { describe, it } from 'mocha';
const bip32 = BIP32Factory(ecc);
const ECPair = ECPairFactory(ecc);
-import { networks as NETWORKS, payments, Psbt, Signer, SignerAsync } from '..';
+import {
+ networks as NETWORKS,
+ payments,
+ Psbt,
+ Signer,
+ SignerAsync,
+ tweakSigner,
+} from '..';
import * as preFixtures from './fixtures/psbt.json';
@@ -139,7 +146,8 @@ describe(`Psbt`, () => {
fixtures.bip174.signer.forEach(f => {
it('Signs PSBT to the expected result', () => {
- const psbt = Psbt.fromBase64(f.psbt);
+ const opts = f.isTaproot ? { eccLib: ecc } : {};
+ const psbt = Psbt.fromBase64(f.psbt, opts);
f.keys.forEach(({ inputToSign, WIF }) => {
const keyPair = ECPair.fromWIF(WIF, NETWORKS.testnet);
@@ -961,7 +969,7 @@ describe(`Psbt`, () => {
describe('validateSignaturesOfTaprootInput', () => {
const f = fixtures.validateSignaturesOfTaprootInput;
it('Correctly validates a signature', () => {
- const psbt = Psbt.fromBase64(f.psbt);
+ const psbt = Psbt.fromBase64(f.psbt, { eccLib: ecc });
assert.strictEqual(
psbt.validateSignaturesOfInput(f.index, schnorrValidator),
true,
@@ -969,7 +977,7 @@ describe(`Psbt`, () => {
});
it('Correctly validates a signature against a pubkey', () => {
- const psbt = Psbt.fromBase64(f.psbt);
+ const psbt = Psbt.fromBase64(f.psbt, { eccLib: ecc });
assert.strictEqual(
psbt.validateSignaturesOfInput(
f.index,
@@ -1011,7 +1019,7 @@ describe(`Psbt`, () => {
privateKey: null,
});
assert.throws(() => {
- Psbt.tweakSigner(keyPair);
+ tweakSigner(keyPair, { eccLib: ecc });
}, new RegExp('Private key is required for tweaking signer!'));
});
@@ -1022,7 +1030,7 @@ describe(`Psbt`, () => {
'hex',
),
);
- const tweakedSigner: Signer = Psbt.tweakSigner(keyPair);
+ const tweakedSigner: Signer = tweakSigner(keyPair, { eccLib: ecc });
assert.strictEqual(
'029421e734b0f9d2c467ea7dd197c61acb4467cdcbc9f4cb0c571f8b63a5c40cae',
tweakedSigner.publicKey.toString('hex'),
diff --git a/ts_src/index.ts b/ts_src/index.ts
index d8b8619d1..6a0f00a1e 100644
--- a/ts_src/index.ts
+++ b/ts_src/index.ts
@@ -16,6 +16,7 @@ export {
SignerAsync,
HDSigner,
HDSignerAsync,
+ tweakSigner,
} from './psbt';
export { OPS as opcodes } from './ops';
export { Transaction } from './transaction';
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index fa6598dc3..c79bb772e 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -23,7 +23,6 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
!a.address &&
!a.output &&
!a.pubkey &&
- !a.output &&
!a.internalPubkey &&
!(a.witness && a.witness.length > 1)
)
@@ -128,6 +127,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
return witness[witness.length - 1].slice(1, 33);
});
lazy.prop(o, 'signature', () => {
+ if (a.signature) return a.signature;
if (!a.witness || a.witness.length !== 1) return;
return a.witness[0];
});
@@ -209,9 +209,6 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
// 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];
diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts
index 230d23210..c74278b78 100644
--- a/ts_src/psbt.ts
+++ b/ts_src/psbt.ts
@@ -1,4 +1,3 @@
-import * as ecc from 'tiny-secp256k1'; // TODO: extract
import { ECPairFactory } from 'ecpair';
import { Psbt as PsbtBase } from 'bip174';
@@ -16,6 +15,8 @@ import {
TransactionFromBuffer,
} from 'bip174/src/lib/interfaces';
import { checkForInput, checkForOutput } from 'bip174/src/lib/utils';
+import { TinySecp256k1Interface as ECPairTinySecp256k1Interface } from 'ecpair';
+
import { fromOutputScript, toOutputScript } from './address';
import { cloneBuffer, reverseBuffer } from './bufferutils';
import { hash160 } from './crypto';
@@ -24,6 +25,7 @@ import * as payments from './payments';
import * as bscript from './script';
import { Output, Transaction } from './transaction';
import { tapTweakHash } from './payments/taprootutils';
+import { TinySecp256k1Interface } from './types';
export interface TransactionInput {
hash: string | Buffer;
@@ -118,39 +120,6 @@ export class Psbt {
return psbt;
}
- /**
- * Helper method for converting a normal Signer into a Taproot Signer.
- * Note that this helper method requires 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 - tweak options
- * @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;
@@ -174,6 +143,7 @@ export class Psbt {
// We will disable exporting the Psbt when unsafe sign is active.
// because it is not BIP174 compliant.
__UNSAFE_SIGN_NONSEGWIT: false,
+ __EC_LIB: opts.eccLib,
};
if (this.data.inputs.length === 0) this.setVersion(2);
@@ -380,10 +350,7 @@ export class Psbt {
return this;
}
- finalizeInput(
- inputIndex: number,
- finalScriptsFunc: FinalScriptsFunc = getFinalScripts,
- ): this {
+ finalizeInput(inputIndex: number, finalScriptsFunc?: FinalScriptsFunc): this {
const input = checkForInput(this.data.inputs, inputIndex);
const { script, isP2SH, isP2WSH, isSegwit } = getScriptFromInput(
inputIndex,
@@ -394,13 +361,15 @@ export class Psbt {
checkPartialSigSighashes(input);
- const { finalScriptSig, finalScriptWitness } = finalScriptsFunc(
+ const fn = finalScriptsFunc || getFinalScripts;
+ const { finalScriptSig, finalScriptWitness } = fn(
inputIndex,
input,
script,
isSegwit,
isP2SH,
isP2WSH,
+ this.__CACHE.__EC_LIB,
);
if (finalScriptSig) this.data.updateInput(inputIndex, { finalScriptSig });
@@ -429,7 +398,10 @@ export class Psbt {
redeemFromFinalWitnessScript(input.finalScriptWitness),
);
const type = result.type === 'raw' ? '' : result.type + '-';
- const mainType = classifyScript(result.meaningfulScript);
+ const mainType = classifyScript(
+ result.meaningfulScript,
+ this.__CACHE.__EC_LIB,
+ );
return (type + mainType) as AllScriptType;
}
@@ -810,6 +782,40 @@ export class Psbt {
}
}
+/**
+ * Helper method for converting a normal Signer into a Taproot Signer.
+ * Note that this helper method requires 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 - tweak options
+ * @returns a Signer having the Private and Public keys tweaked
+ */
+export function tweakSigner(signer: Signer, opts: TaprootSignerOpts): Signer {
+ // todo: test ecc??
+ let privateKey: Uint8Array | undefined = signer.privateKey;
+ if (!privateKey) {
+ throw new Error('Private key is required for tweaking signer!');
+ }
+ if (signer.publicKey[0] === 3) {
+ privateKey = opts.eccLib.privateNegate(privateKey!);
+ }
+
+ const tweakedPrivateKey = opts.eccLib.privateAdd(
+ privateKey,
+ tapTweakHash(signer.publicKey.slice(1, 33), opts.tweakHash),
+ );
+ if (!tweakedPrivateKey) {
+ throw new Error('Invalid tweaked private key!');
+ }
+
+ const ECPair = ECPairFactory(opts.eccLib);
+ return ECPair.fromPrivateKey(Buffer.from(tweakedPrivateKey), {
+ network: opts.network,
+ });
+}
+
interface PsbtCache {
__NON_WITNESS_UTXO_TX_CACHE: Transaction[];
__NON_WITNESS_UTXO_BUF_CACHE: Buffer[];
@@ -819,11 +825,13 @@ interface PsbtCache {
__FEE?: number;
__EXTRACTED_TX?: Transaction;
__UNSAFE_SIGN_NONSEGWIT: boolean;
+ __EC_LIB?: TinySecp256k1Interface;
}
interface PsbtOptsOptional {
network?: Network;
maximumFeeRate?: number;
+ eccLib?: TinySecp256k1Interface;
}
interface PsbtOpts {
@@ -896,8 +904,7 @@ export interface Signer {
*/
export interface TaprootSignerOpts {
network?: Network;
- // TODO: revisit.
- eccLib?: any;
+ eccLib: TinySecp256k1Interface & ECPairTinySecp256k1Interface;
/** The hash used to tweak the Signer */
tweakHash?: Buffer;
}
@@ -1247,11 +1254,12 @@ function getFinalScripts(
isSegwit: boolean,
isP2SH: boolean,
isP2WSH: boolean,
+ eccLib?: TinySecp256k1Interface,
): {
finalScriptSig: Buffer | undefined;
finalScriptWitness: Buffer | undefined;
} {
- const scriptType = classifyScript(script);
+ const scriptType = classifyScript(script, eccLib);
if (!canFinalize(input, script, scriptType))
throw new Error(`Can not finalize input #${inputIndex}`);
return prepareFinalScripts(
@@ -1405,7 +1413,7 @@ function getHashForSig(
prevout.value,
sighashType,
);
- } else if (isP2TR(meaningfulScript, ecc)) {
+ } else if (isP2TR(meaningfulScript, cache.__EC_LIB)) {
const prevOuts: Output[] = inputs.map((i, index) =>
getScriptAndAmountFromUtxo(index, i, cache),
);
@@ -1492,7 +1500,7 @@ function getPayment(
output: script,
signature: partialSig[0].signature,
},
- { eccLib: ecc },
+ { validate: false }, // skip validation (for now)
);
break;
}
@@ -1555,7 +1563,7 @@ function getScriptFromInput(
if (
input.witnessScript ||
isP2WPKH(res.script!) ||
- isP2TR(res.script!, ecc)
+ isP2TR(res.script!, cache.__EC_LIB)
) {
res.isSegwit = true;
}
@@ -1977,12 +1985,15 @@ type ScriptType =
| 'pubkey'
| 'taproot'
| 'nonstandard';
-function classifyScript(script: Buffer): ScriptType {
+function classifyScript(
+ script: Buffer,
+ eccLib?: TinySecp256k1Interface,
+): 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';
+ if (isP2TR(script, eccLib)) return 'taproot';
return 'nonstandard';
}
diff --git a/ts_src/types.ts b/ts_src/types.ts
index 840ab9be2..487f29757 100644
--- a/ts_src/types.ts
+++ b/ts_src/types.ts
@@ -82,6 +82,8 @@ export interface TinySecp256k1Interface {
p: Uint8Array,
tweak: Uint8Array,
): XOnlyPointAddTweakResult | null;
+ privateAdd(d: Uint8Array, tweak: Uint8Array): Uint8Array | null;
+ privateNegate(d: Uint8Array): Uint8Array;
}
export const Buffer256bit = typeforce.BufferN(32);
From 222022a93a566265e0a167b1c38b7a56e8ca565c Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Thu, 10 Feb 2022 13:52:47 +0200
Subject: [PATCH 046/144] chore: take the garbage out. Remove `tweakSigner()`
and ecpair dep from PSBT
---
src/index.d.ts | 2 +-
src/index.js | 8 +-------
src/psbt.d.ts | 26 ------------------------
src/psbt.js | 39 +----------------------------------
test/psbt.spec.ts | 38 +---------------------------------
ts_src/index.ts | 1 -
ts_src/psbt.ts | 52 -----------------------------------------------
7 files changed, 4 insertions(+), 162 deletions(-)
diff --git a/src/index.d.ts b/src/index.d.ts
index 13259bed6..b93c2aa40 100644
--- a/src/index.d.ts
+++ b/src/index.d.ts
@@ -6,7 +6,7 @@ import * as script from './script';
export { address, crypto, networks, payments, script };
export { Block } from './block';
export { TaggedHashPrefix } from './crypto';
-export { Psbt, PsbtTxInput, PsbtTxOutput, Signer, SignerAsync, HDSigner, HDSignerAsync, tweakSigner, } from './psbt';
+export { Psbt, PsbtTxInput, PsbtTxOutput, Signer, SignerAsync, HDSigner, HDSignerAsync, } from './psbt';
export { OPS as opcodes } from './ops';
export { Transaction } from './transaction';
export { Network } from './networks';
diff --git a/src/index.js b/src/index.js
index 55d2b0068..983b0cc76 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,6 +1,6 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.Transaction = exports.opcodes = exports.tweakSigner = exports.Psbt = exports.Block = exports.script = exports.payments = exports.networks = exports.crypto = exports.address = void 0;
+exports.Transaction = exports.opcodes = exports.Psbt = exports.Block = exports.script = exports.payments = exports.networks = exports.crypto = exports.address = void 0;
const address = require('./address');
exports.address = address;
const crypto = require('./crypto');
@@ -25,12 +25,6 @@ Object.defineProperty(exports, 'Psbt', {
return psbt_1.Psbt;
},
});
-Object.defineProperty(exports, 'tweakSigner', {
- enumerable: true,
- get: function() {
- return psbt_1.tweakSigner;
- },
-});
var ops_1 = require('./ops');
Object.defineProperty(exports, 'opcodes', {
enumerable: true,
diff --git a/src/psbt.d.ts b/src/psbt.d.ts
index 57e3f4d35..0aad55d37 100644
--- a/src/psbt.d.ts
+++ b/src/psbt.d.ts
@@ -1,7 +1,6 @@
///
import { Psbt as PsbtBase } from 'bip174';
import { KeyValue, PsbtGlobalUpdate, PsbtInput, PsbtInputUpdate, PsbtOutput, PsbtOutputUpdate } from 'bip174/src/lib/interfaces';
-import { TinySecp256k1Interface as ECPairTinySecp256k1Interface } from 'ecpair';
import { Network } from './networks';
import { Transaction } from './transaction';
import { TinySecp256k1Interface } from './types';
@@ -109,17 +108,6 @@ export declare class Psbt {
addUnknownKeyValToOutput(outputIndex: number, keyVal: KeyValue): this;
clearFinalizedInput(inputIndex: number): this;
}
-/**
- * Helper method for converting a normal Signer into a Taproot Signer.
- * Note that this helper method requires 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 - tweak options
- * @returns a Signer having the Private and Public keys tweaked
- */
-export declare function tweakSigner(signer: Signer, opts: TaprootSignerOpts): Signer;
interface PsbtOptsOptional {
network?: Network;
maximumFeeRate?: number;
@@ -169,25 +157,11 @@ export interface HDSignerAsync extends HDSignerBase {
}
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;
}
-/**
- * Options for tweaking a Signer into a valid Taproot Signer
- */
-export interface TaprootSignerOpts {
- network?: Network;
- eccLib: TinySecp256k1Interface & ECPairTinySecp256k1Interface;
- /** The hash used to tweak the Signer */
- tweakHash?: Buffer;
-}
export interface SignerAsync {
publicKey: Buffer;
network?: any;
diff --git a/src/psbt.js b/src/psbt.js
index 70594153a..4250f0b4d 100644
--- a/src/psbt.js
+++ b/src/psbt.js
@@ -1,7 +1,6 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.tweakSigner = exports.Psbt = void 0;
-const ecpair_1 = require('ecpair');
+exports.Psbt = void 0;
const bip174_1 = require('bip174');
const varuint = require('bip174/src/lib/converter/varint');
const utils_1 = require('bip174/src/lib/utils');
@@ -12,7 +11,6 @@ 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.
*/
@@ -648,41 +646,6 @@ class Psbt {
}
}
exports.Psbt = Psbt;
-/**
- * Helper method for converting a normal Signer into a Taproot Signer.
- * Note that this helper method requires 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 - tweak options
- * @returns a Signer having the Private and Public keys tweaked
- */
-function tweakSigner(signer, opts) {
- // todo: test ecc??
- let privateKey = signer.privateKey;
- if (!privateKey) {
- throw new Error('Private key is required for tweaking signer!');
- }
- if (signer.publicKey[0] === 3) {
- privateKey = opts.eccLib.privateNegate(privateKey);
- }
- const tweakedPrivateKey = opts.eccLib.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)(opts.eccLib);
- return ECPair.fromPrivateKey(Buffer.from(tweakedPrivateKey), {
- network: opts.network,
- });
-}
-exports.tweakSigner = tweakSigner;
/**
* This function is needed to pass to the bip174 base class's fromBuffer.
* It takes the "transaction buffer" portion of the psbt buffer and returns a
diff --git a/test/psbt.spec.ts b/test/psbt.spec.ts
index d5693c7ed..e5198ea78 100644
--- a/test/psbt.spec.ts
+++ b/test/psbt.spec.ts
@@ -8,14 +8,7 @@ import { describe, it } from 'mocha';
const bip32 = BIP32Factory(ecc);
const ECPair = ECPairFactory(ecc);
-import {
- networks as NETWORKS,
- payments,
- Psbt,
- Signer,
- SignerAsync,
- tweakSigner,
-} from '..';
+import { networks as NETWORKS, payments, Psbt, Signer, SignerAsync } from '..';
import * as preFixtures from './fixtures/psbt.json';
@@ -1013,35 +1006,6 @@ describe(`Psbt`, () => {
});
});
- describe('tweakSigner', () => {
- it('Throws error if signer is missing private key', () => {
- const keyPair = Object.assign({}, ECPair.makeRandom(), {
- privateKey: null,
- });
- assert.throws(() => {
- tweakSigner(keyPair, { eccLib: ecc });
- }, 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 = tweakSigner(keyPair, { eccLib: ecc });
- 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/index.ts b/ts_src/index.ts
index 6a0f00a1e..d8b8619d1 100644
--- a/ts_src/index.ts
+++ b/ts_src/index.ts
@@ -16,7 +16,6 @@ export {
SignerAsync,
HDSigner,
HDSignerAsync,
- tweakSigner,
} from './psbt';
export { OPS as opcodes } from './ops';
export { Transaction } from './transaction';
diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts
index c74278b78..504b48fe2 100644
--- a/ts_src/psbt.ts
+++ b/ts_src/psbt.ts
@@ -1,5 +1,3 @@
-import { ECPairFactory } from 'ecpair';
-
import { Psbt as PsbtBase } from 'bip174';
import * as varuint from 'bip174/src/lib/converter/varint';
import {
@@ -15,7 +13,6 @@ import {
TransactionFromBuffer,
} from 'bip174/src/lib/interfaces';
import { checkForInput, checkForOutput } from 'bip174/src/lib/utils';
-import { TinySecp256k1Interface as ECPairTinySecp256k1Interface } from 'ecpair';
import { fromOutputScript, toOutputScript } from './address';
import { cloneBuffer, reverseBuffer } from './bufferutils';
@@ -24,7 +21,6 @@ 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';
import { TinySecp256k1Interface } from './types';
export interface TransactionInput {
@@ -782,40 +778,6 @@ export class Psbt {
}
}
-/**
- * Helper method for converting a normal Signer into a Taproot Signer.
- * Note that this helper method requires 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 - tweak options
- * @returns a Signer having the Private and Public keys tweaked
- */
-export function tweakSigner(signer: Signer, opts: TaprootSignerOpts): Signer {
- // todo: test ecc??
- let privateKey: Uint8Array | undefined = signer.privateKey;
- if (!privateKey) {
- throw new Error('Private key is required for tweaking signer!');
- }
- if (signer.publicKey[0] === 3) {
- privateKey = opts.eccLib.privateNegate(privateKey!);
- }
-
- const tweakedPrivateKey = opts.eccLib.privateAdd(
- privateKey,
- tapTweakHash(signer.publicKey.slice(1, 33), opts.tweakHash),
- );
- if (!tweakedPrivateKey) {
- throw new Error('Invalid tweaked private key!');
- }
-
- const ECPair = ECPairFactory(opts.eccLib);
- return ECPair.fromPrivateKey(Buffer.from(tweakedPrivateKey), {
- network: opts.network,
- });
-}
-
interface PsbtCache {
__NON_WITNESS_UTXO_TX_CACHE: Transaction[];
__NON_WITNESS_UTXO_BUF_CACHE: Buffer[];
@@ -889,25 +851,11 @@ export interface HDSignerAsync extends HDSignerBase {
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;
}
-/**
- * Options for tweaking a Signer into a valid Taproot Signer
- */
-export interface TaprootSignerOpts {
- network?: Network;
- eccLib: TinySecp256k1Interface & ECPairTinySecp256k1Interface;
- /** The hash used to tweak the Signer */
- tweakHash?: Buffer;
-}
export interface SignerAsync {
publicKey: Buffer;
From 4eee26bc7eb4584dc18302f5b66be43e96faef9c Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Fri, 18 Feb 2022 11:42:23 +0200
Subject: [PATCH 047/144] feat: add taproot check for signInputAsync()
---
src/psbt.js | 18 ++++++++++++++++++
ts_src/psbt.ts | 20 ++++++++++++++++++++
2 files changed, 38 insertions(+)
diff --git a/src/psbt.js b/src/psbt.js
index 4250f0b4d..fc7bfe15f 100644
--- a/src/psbt.js
+++ b/src/psbt.js
@@ -585,6 +585,24 @@ class Psbt {
this.__CACHE,
sighashTypes,
);
+ const scriptType = this.getInputType(inputIndex);
+ if (scriptType === 'taproot') {
+ if (!keyPair.signSchnorr) {
+ throw new Error(
+ `Need Schnorr Signer to sign taproot input #${inputIndex}.`,
+ );
+ }
+ return Promise.resolve(keyPair.signSchnorr(hash)).then(signature => {
+ const partialSig = [
+ {
+ pubkey: keyPair.publicKey,
+ signature,
+ },
+ ];
+ // must be changed to use the `updateInput()` public API
+ this.data.inputs[inputIndex].partialSig = partialSig;
+ });
+ }
return Promise.resolve(keyPair.sign(hash)).then(signature => {
const partialSig = [
{
diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts
index 504b48fe2..9497081e2 100644
--- a/ts_src/psbt.ts
+++ b/ts_src/psbt.ts
@@ -706,6 +706,26 @@ export class Psbt {
sighashTypes,
);
+ const scriptType = this.getInputType(inputIndex);
+
+ if (scriptType === 'taproot') {
+ if (!keyPair.signSchnorr) {
+ throw new Error(
+ `Need Schnorr Signer to sign taproot input #${inputIndex}.`,
+ );
+ }
+ return Promise.resolve(keyPair.signSchnorr(hash)).then(signature => {
+ const partialSig = [
+ {
+ pubkey: keyPair.publicKey,
+ signature,
+ },
+ ];
+ // must be changed to use the `updateInput()` public API
+ this.data.inputs[inputIndex].partialSig = partialSig;
+ });
+ }
+
return Promise.resolve(keyPair.sign(hash)).then(signature => {
const partialSig = [
{
From e91c77d068658ff9ede91a1f6e9ba9e97ce72a7f Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Fri, 18 Feb 2022 16:29:32 +0200
Subject: [PATCH 048/144] feat: add stricter validation for taproot addresses
---
src/address.d.ts | 5 +++--
src/address.js | 21 +++++++++++++++------
test/address.spec.ts | 17 ++++++++++++-----
test/fixtures/address.json | 37 ++++++++++++++++++++++++++++++++-----
ts_src/address.ts | 34 +++++++++++++++++++++++++++-------
5 files changed, 89 insertions(+), 25 deletions(-)
diff --git a/src/address.d.ts b/src/address.d.ts
index be0e00a61..13922dab3 100644
--- a/src/address.d.ts
+++ b/src/address.d.ts
@@ -1,5 +1,6 @@
///
import { Network } from './networks';
+import { TinySecp256k1Interface } from './types';
export interface Base58CheckResult {
hash: Buffer;
version: number;
@@ -13,5 +14,5 @@ export declare function fromBase58Check(address: string): Base58CheckResult;
export declare function fromBech32(address: string): Bech32Result;
export declare function toBase58Check(hash: Buffer, version: number): string;
export declare function toBech32(data: Buffer, version: number, prefix: string): string;
-export declare function fromOutputScript(output: Buffer, network?: Network): string;
-export declare function toOutputScript(address: string, network?: Network): Buffer;
+export declare function fromOutputScript(output: Buffer, network?: Network, eccLib?: TinySecp256k1Interface): string;
+export declare function toOutputScript(address: string, network?: Network, eccLib?: TinySecp256k1Interface): Buffer;
diff --git a/src/address.js b/src/address.js
index 164bf7ef1..2c7bc4857 100644
--- a/src/address.js
+++ b/src/address.js
@@ -4,14 +4,13 @@ exports.toOutputScript = exports.fromOutputScript = exports.toBech32 = exports.t
const networks = require('./networks');
const payments = require('./payments');
const bscript = require('./script');
-const types = require('./types');
+const types_1 = require('./types');
const bech32_1 = require('bech32');
const bs58check = require('bs58check');
-const { typeforce } = types;
const FUTURE_SEGWIT_MAX_SIZE = 40;
const FUTURE_SEGWIT_MIN_SIZE = 2;
const FUTURE_SEGWIT_MAX_VERSION = 16;
-const FUTURE_SEGWIT_MIN_VERSION = 1;
+const FUTURE_SEGWIT_MIN_VERSION = 2;
const FUTURE_SEGWIT_VERSION_DIFF = 0x50;
const FUTURE_SEGWIT_VERSION_WARNING =
'WARNING: Sending to a future segwit version address can lead to loss of funds. ' +
@@ -69,7 +68,10 @@ function fromBech32(address) {
}
exports.fromBech32 = fromBech32;
function toBase58Check(hash, version) {
- typeforce(types.tuple(types.Hash160bit, types.UInt8), arguments);
+ (0, types_1.typeforce)(
+ (0, types_1.tuple)(types_1.Hash160bit, types_1.UInt8),
+ arguments,
+ );
const payload = Buffer.allocUnsafe(21);
payload.writeUInt8(version, 0);
hash.copy(payload, 1);
@@ -84,7 +86,7 @@ function toBech32(data, version, prefix) {
: bech32_1.bech32m.encode(prefix, words);
}
exports.toBech32 = toBech32;
-function fromOutputScript(output, network) {
+function fromOutputScript(output, network, eccLib) {
// TODO: Network
network = network || networks.bitcoin;
try {
@@ -99,13 +101,16 @@ function fromOutputScript(output, network) {
try {
return payments.p2wsh({ output, network }).address;
} catch (e) {}
+ try {
+ if (eccLib) return payments.p2tr({ output, network }, { eccLib }).address;
+ } catch (e) {}
try {
return _toFutureSegwitAddress(output, network);
} catch (e) {}
throw new Error(bscript.toASM(output) + ' has no matching Address');
}
exports.fromOutputScript = fromOutputScript;
-function toOutputScript(address, network) {
+function toOutputScript(address, network, eccLib) {
network = network || networks.bitcoin;
let decodeBase58;
let decodeBech32;
@@ -129,6 +134,10 @@ function toOutputScript(address, network) {
return payments.p2wpkh({ hash: decodeBech32.data }).output;
if (decodeBech32.data.length === 32)
return payments.p2wsh({ hash: decodeBech32.data }).output;
+ } else if (decodeBech32.version === 1) {
+ if (decodeBech32.data.length === 32 && eccLib)
+ return payments.p2tr({ pubkey: decodeBech32.data }, { eccLib })
+ .output;
} else if (
decodeBech32.version >= FUTURE_SEGWIT_MIN_VERSION &&
decodeBech32.version <= FUTURE_SEGWIT_MAX_VERSION &&
diff --git a/test/address.spec.ts b/test/address.spec.ts
index b1304c323..be08cf803 100644
--- a/test/address.spec.ts
+++ b/test/address.spec.ts
@@ -1,5 +1,6 @@
import * as assert from 'assert';
import { describe, it } from 'mocha';
+import * as ecc from 'tiny-secp256k1';
import * as baddress from '../src/address';
import * as bscript from '../src/script';
import * as fixtures from './fixtures/address.json';
@@ -68,7 +69,11 @@ describe('address', () => {
fixtures.standard.forEach(f => {
it('encodes ' + f.script.slice(0, 30) + '... (' + f.network + ')', () => {
const script = bscript.fromASM(f.script);
- const address = baddress.fromOutputScript(script, NETWORKS[f.network]);
+ const address = baddress.fromOutputScript(
+ script,
+ NETWORKS[f.network],
+ ecc,
+ );
assert.strictEqual(address, f.base58check || f.bech32!.toLowerCase());
});
@@ -79,7 +84,7 @@ describe('address', () => {
const script = bscript.fromASM(f.script);
assert.throws(() => {
- baddress.fromOutputScript(script);
+ baddress.fromOutputScript(script, undefined, ecc);
}, new RegExp(f.exception));
});
});
@@ -131,6 +136,7 @@ describe('address', () => {
const script = baddress.toOutputScript(
(f.base58check || f.bech32)!,
NETWORKS[f.network],
+ ecc,
);
assert.strictEqual(bscript.toASM(script), f.script);
@@ -138,10 +144,11 @@ describe('address', () => {
});
fixtures.invalid.toOutputScript.forEach(f => {
- it('throws when ' + f.exception, () => {
+ it('throws when ' + (f.exception || f.paymentException), () => {
+ const exception = f.paymentException || `${f.address} ${f.exception}`;
assert.throws(() => {
- baddress.toOutputScript(f.address, f.network as any);
- }, new RegExp(f.address + ' ' + f.exception));
+ baddress.toOutputScript(f.address, f.network as any, ecc);
+ }, new RegExp(exception));
});
});
});
diff --git a/test/fixtures/address.json b/test/fixtures/address.json
index 765ea8aca..0430b7887 100644
--- a/test/fixtures/address.json
+++ b/test/fixtures/address.json
@@ -80,10 +80,10 @@
},
{
"network": "bitcoin",
- "bech32": "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kt5nd6y",
+ "bech32": "bc1p3efq8ujsj0qr5xvms7mv89p8cz0crqdtuxe9ms6grqgxc9sgsntslthf6w",
"version": 1,
- "data": "751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6",
- "script": "OP_1 751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6"
+ "data": "8e5203f25093c03a199b87b6c39427c09f8181abe1b25dc34818106c160884d7",
+ "script": "OP_1 8e5203f25093c03a199b87b6c39427c09f8181abe1b25dc34818106c160884d7"
},
{
"network": "bitcoin",
@@ -116,10 +116,16 @@
],
"bech32": [
{
- "address": "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kt5nd6y",
+ "address": "tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy",
+ "version": 0,
+ "prefix": "tb",
+ "data": "000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433"
+ },
+ {
+ "address": "bc1p3efq8ujsj0qr5xvms7mv89p8cz0crqdtuxe9ms6grqgxc9sgsntslthf6w",
"version": 1,
"prefix": "bc",
- "data": "751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6"
+ "data": "8e5203f25093c03a199b87b6c39427c09f8181abe1b25dc34818106c160884d7"
},
{
"address": "bc1zw508d6qejxtdg4y5r3zarvaryvaxxpcs",
@@ -195,6 +201,19 @@
{
"exception": "has no matching Address",
"script": "OP_0 751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd675"
+ },
+ {
+ "exception": "has no matching Address",
+ "script": "OP_1 75"
+ },
+ {
+ "exception": "has no matching Address",
+ "script": "OP_1 751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd675"
+ },
+ {
+ "description": "pubkey is not valid x coordinate",
+ "exception": "has no matching Address",
+ "script": "OP_1 fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"
}
],
"toOutputScript": [
@@ -297,6 +316,14 @@
{
"address": "bc1gmk9yu",
"exception": "has no matching Script"
+ },
+ {
+ "address": "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw55h884v",
+ "exception": "has no matching Script"
+ },
+ {
+ "address": "bc1pllllllllllllllllllllllllllllllllllllllllllllallllshsdfvw2y",
+ "paymentException": "TypeError: Invalid pubkey for p2tr"
}
]
}
diff --git a/ts_src/address.ts b/ts_src/address.ts
index 753589d46..62bcf2ef7 100644
--- a/ts_src/address.ts
+++ b/ts_src/address.ts
@@ -2,11 +2,15 @@ import { Network } from './networks';
import * as networks from './networks';
import * as payments from './payments';
import * as bscript from './script';
-import * as types from './types';
+import {
+ typeforce,
+ tuple,
+ Hash160bit,
+ UInt8,
+ TinySecp256k1Interface,
+} from './types';
import { bech32, bech32m } from 'bech32';
import * as bs58check from 'bs58check';
-const { typeforce } = types;
-
export interface Base58CheckResult {
hash: Buffer;
version: number;
@@ -21,7 +25,7 @@ export interface Bech32Result {
const FUTURE_SEGWIT_MAX_SIZE: number = 40;
const FUTURE_SEGWIT_MIN_SIZE: number = 2;
const FUTURE_SEGWIT_MAX_VERSION: number = 16;
-const FUTURE_SEGWIT_MIN_VERSION: number = 1;
+const FUTURE_SEGWIT_MIN_VERSION: number = 2;
const FUTURE_SEGWIT_VERSION_DIFF: number = 0x50;
const FUTURE_SEGWIT_VERSION_WARNING: string =
'WARNING: Sending to a future segwit version address can lead to loss of funds. ' +
@@ -93,7 +97,7 @@ export function fromBech32(address: string): Bech32Result {
}
export function toBase58Check(hash: Buffer, version: number): string {
- typeforce(types.tuple(types.Hash160bit, types.UInt8), arguments);
+ typeforce(tuple(Hash160bit, UInt8), arguments);
const payload = Buffer.allocUnsafe(21);
payload.writeUInt8(version, 0);
@@ -115,7 +119,11 @@ export function toBech32(
: bech32m.encode(prefix, words);
}
-export function fromOutputScript(output: Buffer, network?: Network): string {
+export function fromOutputScript(
+ output: Buffer,
+ network?: Network,
+ eccLib?: TinySecp256k1Interface,
+): string {
// TODO: Network
network = network || networks.bitcoin;
@@ -131,6 +139,10 @@ export function fromOutputScript(output: Buffer, network?: Network): string {
try {
return payments.p2wsh({ output, network }).address as string;
} catch (e) {}
+ try {
+ if (eccLib)
+ return payments.p2tr({ output, network }, { eccLib }).address as string;
+ } catch (e) {}
try {
return _toFutureSegwitAddress(output, network);
} catch (e) {}
@@ -138,7 +150,11 @@ export function fromOutputScript(output: Buffer, network?: Network): string {
throw new Error(bscript.toASM(output) + ' has no matching Address');
}
-export function toOutputScript(address: string, network?: Network): Buffer {
+export function toOutputScript(
+ address: string,
+ network?: Network,
+ eccLib?: TinySecp256k1Interface,
+): Buffer {
network = network || networks.bitcoin;
let decodeBase58: Base58CheckResult | undefined;
@@ -165,6 +181,10 @@ export function toOutputScript(address: string, network?: Network): Buffer {
return payments.p2wpkh({ hash: decodeBech32.data }).output as Buffer;
if (decodeBech32.data.length === 32)
return payments.p2wsh({ hash: decodeBech32.data }).output as Buffer;
+ } else if (decodeBech32.version === 1) {
+ if (decodeBech32.data.length === 32 && eccLib)
+ return payments.p2tr({ pubkey: decodeBech32.data }, { eccLib })
+ .output as Buffer;
} else if (
decodeBech32.version >= FUTURE_SEGWIT_MIN_VERSION &&
decodeBech32.version <= FUTURE_SEGWIT_MAX_VERSION &&
From 6816f51f8645389e801fbf581b30e5a107e3c740 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Fri, 18 Feb 2022 16:41:56 +0200
Subject: [PATCH 049/144] fix: fix integration test
---
test/integration/taproot.spec.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/integration/taproot.spec.ts b/test/integration/taproot.spec.ts
index f7b3733fa..b3ff997b0 100644
--- a/test/integration/taproot.spec.ts
+++ b/test/integration/taproot.spec.ts
@@ -12,7 +12,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
const myKey = bip32.fromSeed(rng(64), regtest);
const output = createKeySpendOutput(myKey.publicKey);
- const address = bitcoin.address.fromOutputScript(output, regtest);
+ const address = bitcoin.address.fromOutputScript(output, regtest, ecc);
// amount from faucet
const amount = 42e4;
// amount to send
From 7da1dd55f9048497bb42c962abdc5d6d8e2bd5db Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Tue, 22 Feb 2022 13:57:34 +0200
Subject: [PATCH 050/144] feat: correctly identify P2TR (pass `eccLib` to
`toOutputScript` and `fromOutputScript`)
---
src/psbt.js | 7 ++++++-
ts_src/psbt.ts | 8 ++++++--
2 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/src/psbt.js b/src/psbt.js
index fc7bfe15f..03c2cd048 100644
--- a/src/psbt.js
+++ b/src/psbt.js
@@ -133,6 +133,7 @@ class Psbt {
address = (0, address_1.fromOutputScript)(
output.script,
this.opts.network,
+ this.__CACHE.__EC_LIB,
);
} catch (_) {}
return {
@@ -235,7 +236,11 @@ class Psbt {
const { address } = outputData;
if (typeof address === 'string') {
const { network } = this.opts;
- const script = (0, address_1.toOutputScript)(address, network);
+ const script = (0, address_1.toOutputScript)(
+ address,
+ network,
+ this.__CACHE.__EC_LIB,
+ );
outputData = Object.assign(outputData, { script });
}
const c = this.__CACHE;
diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts
index 9497081e2..163da5b2c 100644
--- a/ts_src/psbt.ts
+++ b/ts_src/psbt.ts
@@ -190,7 +190,11 @@ export class Psbt {
return this.__CACHE.__TX.outs.map(output => {
let address;
try {
- address = fromOutputScript(output.script, this.opts.network);
+ address = fromOutputScript(
+ output.script,
+ this.opts.network,
+ this.__CACHE.__EC_LIB,
+ );
} catch (_) {}
return {
script: cloneBuffer(output.script),
@@ -304,7 +308,7 @@ export class Psbt {
const { address } = outputData as any;
if (typeof address === 'string') {
const { network } = this.opts;
- const script = toOutputScript(address, network);
+ const script = toOutputScript(address, network, this.__CACHE.__EC_LIB);
outputData = Object.assign(outputData, { script });
}
const c = this.__CACHE;
From e033a6ff41f31e70fcf715b5adf084be8e5880ef Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Wed, 9 Mar 2022 17:58:30 +0200
Subject: [PATCH 051/144] add integration tests for taproot (#3)
* test: add PSBT example for taproot
* refactor: variable renaming
* refactor: use constant for tapscript leaf version
* feat: reuse redeem field for taproot spend
* test: make sure it defaults to tapscript version 192
* chore: remove `scriptLeaf` logic
* feat: add tapscript sign() a finalize() logic
* test: spend taproot script-path
* test: add tapscript for OP_CHECKSEQUENCEVERIFY
* feat: add multisig integration test
* refactor: rename scriptsTree to scriptTree (as per BP341)
* feat: check that the scriptTree is a binary tree
* feat: compute the redeem from witness; add unit tests
* test: add test for invalid redeem script
* feat: check the redeemVersion on the input data first
* test: add tests for taproot script-path sign, and key-path finalize
---
src/ops.js | 1 +
src/payments/index.d.ts | 6 +-
src/payments/p2tr.js | 94 +++++--
src/payments/taprootutils.d.ts | 9 +-
src/payments/taprootutils.js | 40 ++-
src/psbt.d.ts | 7 +-
src/psbt.js | 127 +++++----
test/fixtures/p2tr.json | 230 +++++++++++++----
test/fixtures/psbt.json | 38 +++
test/integration/taproot.md | 3 +-
test/integration/taproot.spec.ts | 426 ++++++++++++++++++++++++++++++-
test/payments.utils.ts | 25 +-
test/psbt.spec.ts | 18 +-
test/psbt.utils.ts | 53 ++++
ts_src/ops.ts | 2 +
ts_src/payments/index.ts | 6 +-
ts_src/payments/p2tr.ts | 104 ++++++--
ts_src/payments/taprootutils.ts | 37 ++-
ts_src/psbt.ts | 147 +++++++----
ts_src/types.ts | 1 +
20 files changed, 1136 insertions(+), 238 deletions(-)
create mode 100644 test/psbt.utils.ts
diff --git a/src/ops.js b/src/ops.js
index 9d629cd00..7853ad0f0 100644
--- a/src/ops.js
+++ b/src/ops.js
@@ -117,6 +117,7 @@ const OPS = {
OP_NOP8: 183,
OP_NOP9: 184,
OP_NOP10: 185,
+ OP_CHECKSIGADD: 186,
OP_PUBKEYHASH: 253,
OP_PUBKEY: 254,
OP_INVALIDOPCODE: 255,
diff --git a/src/payments/index.d.ts b/src/payments/index.d.ts
index 6b186c4d1..386ea3f68 100644
--- a/src/payments/index.d.ts
+++ b/src/payments/index.d.ts
@@ -1,6 +1,6 @@
///
import { Network } from '../networks';
-import { TaprootLeaf, TinySecp256k1Interface } from '../types';
+import { TinySecp256k1Interface, TaprootLeaf } from '../types';
import { p2data as embed } from './embed';
import { p2ms } from './p2ms';
import { p2pk } from './p2pk';
@@ -25,8 +25,8 @@ export interface Payment {
address?: string;
hash?: Buffer;
redeem?: Payment;
- scriptsTree?: any;
- scriptLeaf?: TaprootLeaf;
+ redeemVersion?: number;
+ scriptTree?: TaprootLeaf[];
witness?: Buffer[];
}
export declare type PaymentCreator = (a: Payment, opts?: PaymentOpts) => Payment;
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index 79fe62a6f..d4406c2b2 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -10,8 +10,9 @@ const lazy = require('./lazy');
const bech32_1 = require('bech32');
const testecc_1 = require('./testecc');
const OPS = bscript.OPS;
-const TAPROOT_VERSION = 0x01;
+const TAPROOT_WITNESS_VERSION = 0x01;
const ANNEX_PREFIX = 0x50;
+const LEAF_VERSION_MASK = 0b11111110;
function p2tr(a, opts) {
if (
!a.address &&
@@ -40,11 +41,15 @@ function p2tr(a, opts) {
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),
+ scriptTree: types_1.typeforce.maybe(taprootutils_1.isTapTree),
+ redeem: types_1.typeforce.maybe({
output: types_1.typeforce.maybe(types_1.typeforce.Buffer),
+ redeemVersion: types_1.typeforce.maybe(types_1.typeforce.Number),
+ witness: types_1.typeforce.maybe(
+ types_1.typeforce.arrayOf(types_1.typeforce.Buffer),
+ ),
}),
+ redeemVersion: types_1.typeforce.maybe(types_1.typeforce.Number),
},
a,
);
@@ -58,13 +63,13 @@ function p2tr(a, opts) {
data: buffer_1.Buffer.from(data),
};
});
+ // remove annex if present, ignored by taproot
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();
@@ -74,17 +79,16 @@ function p2tr(a, opts) {
lazy.prop(o, 'address', () => {
if (!o.pubkey) return;
const words = bech32_1.bech32m.toWords(o.pubkey);
- words.unshift(TAPROOT_VERSION);
+ words.unshift(TAPROOT_WITNESS_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;
+ if (a.scriptTree) return (0, taprootutils_1.toHashTree)(a.scriptTree).hash;
const w = _witness();
if (w && w.length > 1) {
const controlBlock = w[w.length - 1];
- const leafVersion = controlBlock[0] & 0b11111110;
+ const leafVersion = controlBlock[0] & LEAF_VERSION_MASK;
const script = w[w.length - 2];
const leafHash = (0, taprootutils_1.tapLeafHash)(script, leafVersion);
return (0, taprootutils_1.rootHashFromPath)(controlBlock, leafHash);
@@ -95,8 +99,25 @@ function p2tr(a, opts) {
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, 'redeemVersion', () => {
+ if (a.redeemVersion) return a.redeemVersion;
+ if (
+ a.redeem &&
+ a.redeem.redeemVersion !== undefined &&
+ a.redeem.redeemVersion !== null
+ ) {
+ return a.redeem.redeemVersion;
+ }
+ return taprootutils_1.LEAF_VERSION_TAPSCRIPT;
+ });
+ lazy.prop(o, 'redeem', () => {
+ const witness = _witness(); // witness without annex
+ if (!witness || witness.length < 2) return;
+ return {
+ output: witness[witness.length - 2],
+ witness: witness.slice(0, -2),
+ redeemVersion: witness[witness.length - 1][0] & LEAF_VERSION_MASK,
+ };
});
lazy.prop(o, 'pubkey', () => {
if (a.pubkey) return a.pubkey;
@@ -118,29 +139,25 @@ function p2tr(a, opts) {
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) {
+ if (a.scriptTree && a.redeem && a.redeem.output && a.internalPubkey) {
// todo: optimize/cache
- const hashTree = (0, taprootutils_1.toHashTree)(a.scriptsTree);
+ const hashTree = (0, taprootutils_1.toHashTree)(a.scriptTree);
const leafHash = (0, taprootutils_1.tapLeafHash)(
- a.scriptLeaf.output,
- a.scriptLeaf.version,
+ a.redeem.output,
+ o.redeemVersion,
);
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]),
+ buffer_1.Buffer.from([o.redeemVersion | outputKey.parity]),
a.internalPubkey,
].concat(path.reverse()),
);
- return [a.scriptLeaf.output, controlBock];
+ return [a.redeem.output, controlBock];
}
if (a.signature) return [a.signature];
});
@@ -150,7 +167,7 @@ function p2tr(a, opts) {
if (a.address) {
if (network && network.bech32 !== _address().prefix)
throw new TypeError('Invalid prefix or Network mismatch');
- if (_address().version !== TAPROOT_VERSION)
+ if (_address().version !== TAPROOT_WITNESS_VERSION)
throw new TypeError('Invalid address version');
if (_address().data.length !== 32)
throw new TypeError('Invalid address data');
@@ -182,11 +199,32 @@ function p2tr(a, opts) {
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 && a.scriptTree) {
+ const hash = (0, taprootutils_1.toHashTree)(a.scriptTree).hash;
if (!a.hash.equals(hash)) throw new TypeError('Hash mismatch');
}
const witness = _witness();
+ // compare the provided redeem data with the one computed from witness
+ if (a.redeem && o.redeem) {
+ if (a.redeem.redeemVersion) {
+ if (a.redeem.redeemVersion !== o.redeem.redeemVersion)
+ throw new TypeError('Redeem.redeemVersion and witness mismatch');
+ }
+ if (a.redeem.output) {
+ if (bscript.decompile(a.redeem.output).length === 0)
+ throw new TypeError('Redeem.output is invalid');
+ // output redeem is constructed from the witness
+ if (o.redeem.output && !a.redeem.output.equals(o.redeem.output))
+ throw new TypeError('Redeem.output and witness mismatch');
+ }
+ if (a.redeem.witness) {
+ if (
+ o.redeem.witness &&
+ !stacksEqual(a.redeem.witness, o.redeem.witness)
+ )
+ throw new TypeError('Redeem.witness and witness mismatch');
+ }
+ }
if (witness && witness.length) {
if (witness.length === 1) {
// key spending
@@ -215,7 +253,7 @@ function p2tr(a, opts) {
throw new TypeError('Internal pubkey mismatch');
if (!_ecc().isXOnlyPoint(internalPubkey))
throw new TypeError('Invalid internalPubkey for p2tr witness');
- const leafVersion = controlBlock[0] & 0b11111110;
+ const leafVersion = controlBlock[0] & LEAF_VERSION_MASK;
const script = witness[witness.length - 2];
const leafHash = (0, taprootutils_1.tapLeafHash)(script, leafVersion);
const hash = (0, taprootutils_1.rootHashFromPath)(
@@ -248,3 +286,9 @@ function tweakKey(pubKey, h, eccLib) {
x: buffer_1.Buffer.from(res.xOnlyPubkey),
};
}
+function stacksEqual(a, b) {
+ if (a.length !== b.length) return false;
+ return a.every((x, i) => {
+ return x.equals(b[i]);
+ });
+}
diff --git a/src/payments/taprootutils.d.ts b/src/payments/taprootutils.d.ts
index f68a37495..82a488530 100644
--- a/src/payments/taprootutils.d.ts
+++ b/src/payments/taprootutils.d.ts
@@ -1,5 +1,6 @@
///
import { TaprootLeaf } from '../types';
+export declare const LEAF_VERSION_TAPSCRIPT = 192;
export declare function rootHashFromPath(controlBlock: Buffer, tapLeafMsg: Buffer): Buffer;
export interface HashTree {
hash: Buffer;
@@ -9,12 +10,16 @@ export interface 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:
+ * @param scriptTree - 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;
+export declare function toHashTree(scriptTree: TaprootLeaf[]): HashTree;
+/**
+ * Check if the tree is a binary tree with leafs of type TaprootLeaf
+ */
+export declare function isTapTree(scriptTree: TaprootLeaf[]): boolean;
/**
* Given a MAST tree, it finds the path of a particular hash.
* @param node - the root of the tree
diff --git a/src/payments/taprootutils.js b/src/payments/taprootutils.js
index 2da6a4b7d..2a807214d 100644
--- a/src/payments/taprootutils.js
+++ b/src/payments/taprootutils.js
@@ -1,13 +1,13 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.tapTweakHash = exports.tapLeafHash = exports.findScriptPath = exports.toHashTree = exports.rootHashFromPath = void 0;
+exports.tapTweakHash = exports.tapLeafHash = exports.findScriptPath = exports.isTapTree = exports.toHashTree = exports.rootHashFromPath = exports.LEAF_VERSION_TAPSCRIPT = 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';
+exports.LEAF_VERSION_TAPSCRIPT = 0xc0;
function rootHashFromPath(controlBlock, tapLeafMsg) {
const k = [tapLeafMsg];
const e = [];
@@ -26,26 +26,26 @@ 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:
+ * @param scriptTree - 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];
+function toHashTree(scriptTree) {
+ if (scriptTree.length === 1) {
+ const script = scriptTree[0];
if (Array.isArray(script)) {
return toHashTree(script);
}
- script.version = script.version || LEAF_VERSION_TAPSCRIPT;
+ script.version = script.version || exports.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]]);
+ const left = toHashTree([scriptTree[0]]);
+ const right = toHashTree([scriptTree[1]]);
let leftHash = left.hash;
let rightHash = right.hash;
if (leftHash.compare(rightHash) === 1)
@@ -57,6 +57,26 @@ function toHashTree(scriptsTree) {
};
}
exports.toHashTree = toHashTree;
+/**
+ * Check if the tree is a binary tree with leafs of type TaprootLeaf
+ */
+function isTapTree(scriptTree) {
+ if (scriptTree.length > 2) return false;
+ if (scriptTree.length === 1) {
+ const script = scriptTree[0];
+ if (Array.isArray(script)) {
+ return isTapTree(script);
+ }
+ if (!script.output) return false;
+ script.version = script.version || exports.LEAF_VERSION_TAPSCRIPT;
+ if ((script.version & 1) !== 0) return false;
+ return true;
+ }
+ if (!isTapTree([scriptTree[0]])) return false;
+ if (!isTapTree([scriptTree[1]])) return false;
+ return true;
+}
+exports.isTapTree = isTapTree;
/**
* Given a MAST tree, it finds the path of a particular hash.
* @param node - the root of the tree
@@ -80,7 +100,7 @@ function findScriptPath(node, hash) {
}
exports.findScriptPath = findScriptPath;
function tapLeafHash(script, version) {
- version = version || LEAF_VERSION_TAPSCRIPT;
+ version = version || exports.LEAF_VERSION_TAPSCRIPT;
return bcrypto.taggedHash(
TAP_LEAF_TAG,
buffer_1.Buffer.concat([
diff --git a/src/psbt.d.ts b/src/psbt.d.ts
index 0aad55d37..cfc64a6e7 100644
--- a/src/psbt.d.ts
+++ b/src/psbt.d.ts
@@ -180,9 +180,10 @@ input: PsbtInput, // The PSBT input contents
script: Buffer, // The "meaningful" locking script Buffer (redeemScript for P2SH etc.)
isSegwit: boolean, // Is it segwit?
isP2SH: boolean, // Is it P2SH?
-isP2WSH: boolean) => {
+isP2WSH: boolean, // Is it P2WSH?
+eccLib?: TinySecp256k1Interface) => {
finalScriptSig: Buffer | undefined;
- finalScriptWitness: Buffer | undefined;
+ finalScriptWitness: Buffer | Buffer[] | undefined;
};
-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';
+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' | 'p2tr-pubkey' | 'p2tr-nonstandard';
export {};
diff --git a/src/psbt.js b/src/psbt.js
index 03c2cd048..ec5614a07 100644
--- a/src/psbt.js
+++ b/src/psbt.js
@@ -11,6 +11,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.
*/
@@ -279,13 +280,19 @@ class Psbt {
}
finalizeInput(inputIndex, finalScriptsFunc) {
const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
- const { script, isP2SH, isP2WSH, isSegwit } = getScriptFromInput(
- inputIndex,
- input,
- this.__CACHE,
- );
+ const {
+ script,
+ isP2SH,
+ isP2WSH,
+ isSegwit,
+ isTapscript,
+ } = getScriptFromInput(inputIndex, input, this.__CACHE);
if (!script) throw new Error(`No script found for input #${inputIndex}`);
checkPartialSigSighashes(input);
+ if (isTapscript && !finalScriptsFunc)
+ throw new Error(
+ `Taproot script-path finalizer required for input #${inputIndex}`,
+ );
const fn = finalScriptsFunc || getFinalScripts;
const { finalScriptSig, finalScriptWitness } = fn(
inputIndex,
@@ -297,8 +304,13 @@ class Psbt {
this.__CACHE.__EC_LIB,
);
if (finalScriptSig) this.data.updateInput(inputIndex, { finalScriptSig });
- if (finalScriptWitness)
- this.data.updateInput(inputIndex, { finalScriptWitness });
+ if (finalScriptWitness) {
+ // allow custom finalizers to build the witness as an array
+ const witness = Array.isArray(finalScriptWitness)
+ ? witnessStackToScriptWitness(finalScriptWitness)
+ : finalScriptWitness;
+ this.data.updateInput(inputIndex, { finalScriptWitness: witness });
+ }
if (!finalScriptSig && !finalScriptWitness)
throw new Error(`Unknown error finalizing input #${inputIndex}`);
this.data.clearFinalizedInput(inputIndex);
@@ -318,6 +330,7 @@ class Psbt {
input.redeemScript || redeemFromFinalScriptSig(input.finalScriptSig),
input.witnessScript ||
redeemFromFinalWitnessScript(input.finalScriptWitness),
+ this.__CACHE,
);
const type = result.type === 'raw' ? '' : result.type + '-';
const mainType = classifyScript(
@@ -372,13 +385,12 @@ class Psbt {
let sighashCache;
const scriptType = this.getInputType(inputIndex);
for (const pSig of mySigs) {
- const sig =
- scriptType === 'taproot'
- ? {
- signature: pSig.signature,
- hashType: transaction_1.Transaction.SIGHASH_DEFAULT,
- }
- : bscript.signature.decode(pSig.signature);
+ const sig = isTaprootSpend(scriptType)
+ ? {
+ signature: pSig.signature,
+ hashType: transaction_1.Transaction.SIGHASH_DEFAULT,
+ }
+ : bscript.signature.decode(pSig.signature);
const { hash, script } =
sighashCache !== sig.hashType
? getHashForSig(
@@ -550,18 +562,17 @@ class Psbt {
sighashTypes,
);
const scriptType = this.getInputType(inputIndex);
- if (scriptType === 'taproot') {
+ if (isTaprootSpend(scriptType)) {
if (!keyPair.signSchnorr) {
throw new Error(
`Need Schnorr Signer to sign taproot input #${inputIndex}.`,
);
}
- const partialSig = [
- {
- pubkey: keyPair.publicKey,
- signature: keyPair.signSchnorr(hash),
- },
- ];
+ const partialSig = this.data.inputs[inputIndex].partialSig || [];
+ partialSig.push({
+ pubkey: keyPair.publicKey,
+ signature: keyPair.signSchnorr(hash),
+ });
// must be changed to use the `updateInput()` public API
this.data.inputs[inputIndex].partialSig = partialSig;
} else {
@@ -591,19 +602,18 @@ class Psbt {
sighashTypes,
);
const scriptType = this.getInputType(inputIndex);
- if (scriptType === 'taproot') {
+ if (isTaprootSpend(scriptType)) {
if (!keyPair.signSchnorr) {
throw new Error(
`Need Schnorr Signer to sign taproot input #${inputIndex}.`,
);
}
return Promise.resolve(keyPair.signSchnorr(hash)).then(signature => {
- const partialSig = [
- {
- pubkey: keyPair.publicKey,
- signature,
- },
- ];
+ const partialSig = this.data.inputs[inputIndex].partialSig || [];
+ partialSig.push({
+ pubkey: keyPair.publicKey,
+ signature,
+ });
// must be changed to use the `updateInput()` public API
this.data.inputs[inputIndex].partialSig = partialSig;
});
@@ -1046,6 +1056,7 @@ function getHashForSig(
'input',
input.redeemScript,
input.witnessScript,
+ cache,
);
if (['p2sh-p2wsh', 'p2wsh'].indexOf(type) >= 0) {
hash = unsignedTx.hashForWitnessV0(
@@ -1064,17 +1075,21 @@ function getHashForSig(
prevout.value,
sighashType,
);
- } else if (isP2TR(meaningfulScript, cache.__EC_LIB)) {
+ } else if (isP2TR(prevout.script, cache.__EC_LIB)) {
const prevOuts = inputs.map((i, index) =>
getScriptAndAmountFromUtxo(index, i, cache),
);
const signingScripts = prevOuts.map(o => o.script);
const values = prevOuts.map(o => o.value);
+ const leafHash = input.witnessScript
+ ? (0, taprootutils_1.tapLeafHash)(input.witnessScript)
+ : undefined;
hash = unsignedTx.hashForWitnessV1(
inputIndex,
signingScripts,
values,
transaction_1.Transaction.SIGHASH_DEFAULT,
+ leafHash,
);
} else {
// non-segwit
@@ -1169,35 +1184,39 @@ function getScriptFromInput(inputIndex, input, cache) {
const res = {
script: null,
isSegwit: false,
+ isTapscript: false,
isP2SH: false,
isP2WSH: false,
};
- res.isP2SH = !!input.redeemScript;
- res.isP2WSH = !!input.witnessScript;
+ let utxoScript = null;
+ if (input.nonWitnessUtxo) {
+ const nonWitnessUtxoTx = nonWitnessUtxoTxFromCache(
+ cache,
+ input,
+ inputIndex,
+ );
+ const prevoutIndex = unsignedTx.ins[inputIndex].index;
+ utxoScript = nonWitnessUtxoTx.outs[prevoutIndex].script;
+ } else if (input.witnessUtxo) {
+ utxoScript = input.witnessUtxo.script;
+ }
if (input.witnessScript) {
res.script = input.witnessScript;
} else if (input.redeemScript) {
res.script = input.redeemScript;
} else {
- if (input.nonWitnessUtxo) {
- const nonWitnessUtxoTx = nonWitnessUtxoTxFromCache(
- cache,
- input,
- inputIndex,
- );
- const prevoutIndex = unsignedTx.ins[inputIndex].index;
- res.script = nonWitnessUtxoTx.outs[prevoutIndex].script;
- } else if (input.witnessUtxo) {
- res.script = input.witnessUtxo.script;
- }
+ res.script = utxoScript;
}
- if (
- input.witnessScript ||
- isP2WPKH(res.script) ||
- isP2TR(res.script, cache.__EC_LIB)
- ) {
+ const isTaproot = utxoScript && isP2TR(utxoScript, cache.__EC_LIB);
+ // Segregated Witness versions 0 or 1
+ if (input.witnessScript || isP2WPKH(res.script) || isTaproot) {
res.isSegwit = true;
}
+ if (isTaproot && input.witnessScript) {
+ res.isTapscript = true;
+ }
+ res.isP2SH = !!input.redeemScript;
+ res.isP2WSH = !!input.witnessScript && !res.isTapscript;
return res;
}
function getSignersFromHD(inputIndex, inputs, hdKeyPair) {
@@ -1394,6 +1413,7 @@ function pubkeyInInput(pubkey, input, inputIndex, cache) {
'input',
input.redeemScript,
input.witnessScript,
+ cache,
);
return pubkeyInScript(pubkey, meaningfulScript);
}
@@ -1405,6 +1425,7 @@ function pubkeyInOutput(pubkey, output, outputIndex, cache) {
'output',
output.redeemScript,
output.witnessScript,
+ cache,
);
return pubkeyInScript(pubkey, meaningfulScript);
}
@@ -1453,10 +1474,12 @@ function getMeaningfulScript(
ioType,
redeemScript,
witnessScript,
+ cache,
) {
const isP2SH = isP2SHScript(script);
const isP2SHP2WSH = isP2SH && redeemScript && isP2WSHScript(redeemScript);
const isP2WSH = isP2WSHScript(script);
+ const isP2TRScript = isP2TR(script, cache && cache.__EC_LIB);
if (isP2SH && redeemScript === undefined)
throw new Error('scriptPubkey is P2SH but redeemScript missing');
if ((isP2WSH || isP2SHP2WSH) && witnessScript === undefined)
@@ -1476,6 +1499,9 @@ function getMeaningfulScript(
} else if (isP2SH) {
meaningfulScript = redeemScript;
checkRedeemScript(index, script, redeemScript, ioType);
+ } else if (isP2TRScript && !!witnessScript) {
+ meaningfulScript = witnessScript;
+ // TODO: check here something?
} else {
meaningfulScript = script;
}
@@ -1487,6 +1513,8 @@ function getMeaningfulScript(
? 'p2sh'
: isP2WSH
? 'p2wsh'
+ : isP2TRScript
+ ? 'p2tr'
: 'raw',
};
}
@@ -1509,6 +1537,11 @@ function pubkeyInScript(pubkey, script) {
);
});
}
+function isTaprootSpend(scriptType) {
+ return (
+ !!scriptType && (scriptType === 'taproot' || scriptType.startsWith('p2tr-'))
+ );
+}
function classifyScript(script, eccLib) {
if (isP2WPKH(script)) return 'witnesspubkeyhash';
if (isP2PKH(script)) return 'pubkeyhash';
diff --git a/test/fixtures/p2tr.json b/test/fixtures/p2tr.json
index 4c7174fc0..b38bb1776 100644
--- a/test/fixtures/p2tr.json
+++ b/test/fixtures/p2tr.json
@@ -94,7 +94,7 @@
}
},
{
- "description": "address, pubkey, internalPubkey and output from witness",
+ "description": "address, pubkey, internalPubkey, redeeem and output from witness",
"arguments": {
"witness": [
"9675a9982c6398ea9d441cb7a943bcd6ff033cc3a2e01a0178a7d3be4575be863871c6bf3eef5ecd34721c784259385ca9101c3a313e010ac942c99de05aaaa602",
@@ -112,6 +112,14 @@
"output": "OP_1 1ebe8b90363bd097aa9f352c8b21914e1886bc09fe9e70c09f33ef2d2abdf4bc",
"signature": null,
"input": null,
+ "redeem" : {
+ "output": "OP_DROP c7b5db9562078049719228db2ac80cb9643ec96c8055aa3b29c2c03d4d99edb0 OP_CHECKSIG",
+ "redeemVersion": 192,
+ "witness": [
+ "9675a9982c6398ea9d441cb7a943bcd6ff033cc3a2e01a0178a7d3be4575be863871c6bf3eef5ecd34721c784259385ca9101c3a313e010ac942c99de05aaaa602",
+ "5799cf4b193b730fb99580b186f7477c2cca4d28957326f6f1a5d14116438530e7ec0ce1cd465ad96968ae8a6a09d4d37a060a115919f56fcfebe7b2277cc2df5cc08fb6cda9105ee2512b2e22635aba"
+ ]
+ },
"witness": [
"9675a9982c6398ea9d441cb7a943bcd6ff033cc3a2e01a0178a7d3be4575be863871c6bf3eef5ecd34721c784259385ca9101c3a313e010ac942c99de05aaaa602",
"5799cf4b193b730fb99580b186f7477c2cca4d28957326f6f1a5d14116438530e7ec0ce1cd465ad96968ae8a6a09d4d37a060a115919f56fcfebe7b2277cc2df5cc08fb6cda9105ee2512b2e22635aba",
@@ -153,7 +161,7 @@
"description": "address, pubkey, output and hash from internalPubkey and a script tree with one leaf",
"arguments": {
"internalPubkey": "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0",
- "scriptsTree": [
+ "scriptTree": [
{
"output": "83d8ee77a0f3a32a5cea96fd1624d623b836c1e5d1ac2dcde46814b619320c18 OP_CHECKSIG"
}
@@ -174,7 +182,7 @@
"description": "address, pubkey, output and hash from internalPubkey and a script tree with two leafs",
"arguments": {
"internalPubkey": "2258b1c3160be0864a541854eec9164a572f094f7562628281a8073bb89173a7",
- "scriptsTree": [
+ "scriptTree": [
{
"output": "d826a0a53abb6ffc60df25b9c152870578faef4b2eb5a09bdd672bbe32cdd79b OP_CHECKSIG"
},
@@ -198,7 +206,7 @@
"description": "address, pubkey, output and hash from internalPubkey and a script tree with three leafs",
"arguments": {
"internalPubkey": "7631cacec3343052d87ef4d0065f61dde82d7d2db0c1cc02ef61ef3c982ea763",
- "scriptsTree": [
+ "scriptTree": [
{
"output": "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0 OP_CHECKSIG"
},
@@ -227,7 +235,7 @@
"description": "address, pubkey, output and hash from internalPubkey and a script tree with four leafs",
"arguments": {
"internalPubkey": "d0c19def28bb1b39451c1a814737615983967780d223b79969ba692182c6006b",
- "scriptsTree": [
+ "scriptTree": [
[
{
"output": "9b4d495b74887815a1ff623c055c6eac6b6b2e07d2a016d6526ebac71dd99744 OP_CHECKSIG"
@@ -261,7 +269,7 @@
"description": "address, pubkey, output and hash from internalPubkey and a script tree with seven leafs",
"arguments": {
"internalPubkey": "f95886b02a84928c5c15bdca32784993105f73de27fa6ad8c1a60389b999267c",
- "scriptsTree": [
+ "scriptTree": [
[
{
"output": "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0 OP_CHECKSIG"
@@ -310,7 +318,7 @@
"description": "address, pubkey, output and hash from internalPubkey and a script tree with seven leafs (2)",
"arguments": {
"internalPubkey": "aba457d16a8d59151c387f24d1eb887efbe24644c1ee64b261282e7baebdb247",
- "scriptsTree": [
+ "scriptTree": [
{
"output": "00a9da96087a72258f83b338ef7f0ea8cbbe05da5f18f091eb397d1ecbf7c3d3 OP_CHECKSIG"
},
@@ -375,11 +383,11 @@
"description": "BIP341 Test case 2",
"arguments": {
"internalPubkey": "187791b6f712a8ea41c8ecdd0ee77fab3e85263b37e1ec18a3651926b3a6cf27",
- "scriptLeaf": {
+ "redeem": {
"output": "d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8 OP_CHECKSIG",
- "version": 192
+ "redeemVersion": 192
},
- "scriptsTree": [
+ "scriptTree": [
{
"output": "d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8 OP_CHECKSIG",
"version": 192
@@ -397,6 +405,10 @@
"20d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8ac",
"c1187791b6f712a8ea41c8ecdd0ee77fab3e85263b37e1ec18a3651926b3a6cf27"
],
+ "redeem": {
+ "output": "d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8 OP_CHECKSIG",
+ "redeemVersion": 192
+ },
"signature": null,
"input": null
}
@@ -405,11 +417,11 @@
"description": "BIP341 Test case 3",
"arguments": {
"internalPubkey": "93478e9488f956df2396be2ce6c5cced75f900dfa18e7dabd2428aae78451820",
- "scriptLeaf": {
+ "redeem": {
"output": "b617298552a72ade070667e86ca63b8f5789a9fe8731ef91202a91c9f3459007 OP_CHECKSIG",
- "version": 192
+ "redeemVersion": 192
},
- "scriptsTree": [
+ "scriptTree": [
{
"output": "b617298552a72ade070667e86ca63b8f5789a9fe8731ef91202a91c9f3459007 OP_CHECKSIG",
"version": 192
@@ -435,11 +447,11 @@
"description": "BIP341 Test case 4 - spend leaf 0",
"arguments": {
"internalPubkey": "ee4fe085983462a184015d1f782d6a5f8b9c2b60130aff050ce221ecf3786592",
- "scriptLeaf": {
+ "redeem": {
"output": "387671353e273264c495656e27e39ba899ea8fee3bb69fb2a680e22093447d48 OP_CHECKSIG",
- "version": 192
+ "redeemVersion": 192
},
- "scriptsTree": [
+ "scriptTree": [
{
"output": "387671353e273264c495656e27e39ba899ea8fee3bb69fb2a680e22093447d48 OP_CHECKSIG",
"version": 192
@@ -469,11 +481,11 @@
"description": "BIP341 Test case 4 - spend leaf 1",
"arguments": {
"internalPubkey": "ee4fe085983462a184015d1f782d6a5f8b9c2b60130aff050ce221ecf3786592",
- "scriptLeaf": {
+ "redeem": {
"output": "424950333431",
- "version": 152
+ "redeemVersion": 152
},
- "scriptsTree": [
+ "scriptTree": [
{
"output": "387671353e273264c495656e27e39ba899ea8fee3bb69fb2a680e22093447d48 OP_CHECKSIG",
"version": 192
@@ -503,11 +515,11 @@
"description": "BIP341 Test case 5 - spend leaf 0",
"arguments": {
"internalPubkey": "f9f400803e683727b14f463836e1e78e1c64417638aa066919291a225f0e8dd8",
- "scriptLeaf": {
+ "redeem": {
"output": "44b178d64c32c4a05cc4f4d1407268f764c940d20ce97abfd44db5c3592b72fd OP_CHECKSIG",
- "version": 192
+ "redeemVersion": 192
},
- "scriptsTree": [
+ "scriptTree": [
{
"output": "44b178d64c32c4a05cc4f4d1407268f764c940d20ce97abfd44db5c3592b72fd OP_CHECKSIG",
"version": 192
@@ -537,11 +549,11 @@
"description": "BIP341 Test case 5 - spend leaf 1",
"arguments": {
"internalPubkey": "f9f400803e683727b14f463836e1e78e1c64417638aa066919291a225f0e8dd8",
- "scriptLeaf": {
+ "redeem": {
"output": "546170726f6f74",
- "version": 82
+ "redeemVersion": 82
},
- "scriptsTree": [
+ "scriptTree": [
{
"output": "44b178d64c32c4a05cc4f4d1407268f764c940d20ce97abfd44db5c3592b72fd OP_CHECKSIG",
"version": 192
@@ -571,11 +583,11 @@
"description": "BIP341 Test case 6 - spend leaf 0",
"arguments": {
"internalPubkey": "e0dfe2300b0dd746a3f8674dfd4525623639042569d829c7f0eed9602d263e6f",
- "scriptLeaf": {
+ "redeem": {
"output": "72ea6adcf1d371dea8fba1035a09f3d24ed5a059799bae114084130ee5898e69 OP_CHECKSIG",
- "version": 192
+ "redeemVersion": 192
},
- "scriptsTree": [
+ "scriptTree": [
{
"output": "72ea6adcf1d371dea8fba1035a09f3d24ed5a059799bae114084130ee5898e69 OP_CHECKSIG",
"version": 192
@@ -611,11 +623,11 @@
"description": "BIP341 Test case 6 - spend leaf 1",
"arguments": {
"internalPubkey": "e0dfe2300b0dd746a3f8674dfd4525623639042569d829c7f0eed9602d263e6f",
- "scriptLeaf": {
+ "redeem": {
"output": "2352d137f2f3ab38d1eaa976758873377fa5ebb817372c71e2c542313d4abda8 OP_CHECKSIG",
- "version": 192
+ "redeemVersion": 192
},
- "scriptsTree": [
+ "scriptTree": [
{
"output": "72ea6adcf1d371dea8fba1035a09f3d24ed5a059799bae114084130ee5898e69 OP_CHECKSIG",
"version": 192
@@ -651,11 +663,11 @@
"description": "BIP341 Test case 6 - spend leaf 2",
"arguments": {
"internalPubkey": "e0dfe2300b0dd746a3f8674dfd4525623639042569d829c7f0eed9602d263e6f",
- "scriptLeaf": {
+ "redeem": {
"output": "7337c0dd4253cb86f2c43a2351aadd82cccb12a172cd120452b9bb8324f2186a OP_CHECKSIG",
- "version": 192
+ "redeemVersion": 192
},
- "scriptsTree": [
+ "scriptTree": [
{
"output": "72ea6adcf1d371dea8fba1035a09f3d24ed5a059799bae114084130ee5898e69 OP_CHECKSIG",
"version": 192
@@ -691,11 +703,10 @@
"description": "BIP341 Test case 7 - spend leaf 0",
"arguments": {
"internalPubkey": "55adf4e8967fbd2e29f20ac896e60c3b0f1d5b0efa9d34941b5958c7b0a0312d",
- "scriptLeaf": {
- "output": "71981521ad9fc9036687364118fb6ccd2035b96a423c59c5430e98310a11abe2 OP_CHECKSIG",
- "version": 192
+ "redeem": {
+ "output": "71981521ad9fc9036687364118fb6ccd2035b96a423c59c5430e98310a11abe2 OP_CHECKSIG"
},
- "scriptsTree": [
+ "scriptTree": [
{
"output": "71981521ad9fc9036687364118fb6ccd2035b96a423c59c5430e98310a11abe2 OP_CHECKSIG",
"version": 192
@@ -731,11 +742,11 @@
"description": "BIP341 Test case 7 - spend leaf 1",
"arguments": {
"internalPubkey": "55adf4e8967fbd2e29f20ac896e60c3b0f1d5b0efa9d34941b5958c7b0a0312d",
- "scriptLeaf": {
+ "redeem": {
"output": "d5094d2dbe9b76e2c245a2b89b6006888952e2faa6a149ae318d69e520617748 OP_CHECKSIG",
- "version": 192
+ "redeemVersion": 192
},
- "scriptsTree": [
+ "scriptTree": [
{
"output": "71981521ad9fc9036687364118fb6ccd2035b96a423c59c5430e98310a11abe2 OP_CHECKSIG",
"version": 192
@@ -771,11 +782,11 @@
"description": "BIP341 Test case 7 - spend leaf 2",
"arguments": {
"internalPubkey": "55adf4e8967fbd2e29f20ac896e60c3b0f1d5b0efa9d34941b5958c7b0a0312d",
- "scriptLeaf": {
+ "redeem": {
"output": "c440b462ad48c7a77f94cd4532d8f2119dcebbd7c9764557e62726419b08ad4c OP_CHECKSIG",
- "version": 192
+ "redeemVersion": 192
},
- "scriptsTree": [
+ "scriptTree": [
{
"output": "71981521ad9fc9036687364118fb6ccd2035b96a423c59c5430e98310a11abe2 OP_CHECKSIG",
"version": 192
@@ -884,12 +895,12 @@
}
},
{
- "description": "Hash mismatch between scriptsTree and hash",
+ "description": "Hash mismatch between scriptTree and hash",
"exception": "Hash mismatch",
"options": {},
"arguments": {
"internalPubkey": "9fa5ffb68821cf559001caa0577eeea4978b29416def328a707b15e91701a2f7",
- "scriptsTree": [
+ "scriptTree": [
{
"output": "83d8ee77a0f3a32a5cea96fd1624d623b836c1e5d1ac2dcde46814b619320c18 OP_CHECKSIG"
}
@@ -1017,6 +1028,133 @@
"c0a7957acbaaf7b444c53d9e0c9436e8a8a3247fd515095d66ddf6201918b40a3668f9a4ccdffcf778da624dca2dda0b08e763ec52fd4ad403ec7563a3504d0cc168b9a77a410029e01dac89567c9b2e6cd726e840351df3f2f58fefe976200a19244150d04153909f660184d656ee95fa7bf8e1d4ec83da1fca34f64bc279b76d257ec623e08baba2cfa4ea9e99646e88f1eb1668c00c0f15b7443c8ab83481611cc3ae85eb89a7bfc40067eb1d2e6354a32426d0ce710e88bc4cc0718b99c325509c9d02a6a980d675a8969be10ee9bef82cafee2fc913475667ccda37b1bc7f13f64e56c449c532658ba8481631c02ead979754c809584a875951619cec8fb040c33f06468ae0266cd8693d6a64cea5912be32d8de95a6da6300b0c50fdcd6001ea41126e7b7e5280d455054a816560028f5ca53c9a50ee52f10e15c5337315bad1f5277acb109a1418649dc6ead2fe14699742fee7182f2f15e54279c7d932ed2799d01d73c97e68bbc94d6f7f56ee0a80efd7c76e3169e10d1a1ba3b5f1eb02369dc43af687461c7a2a3344d13eb5485dca29a67f16b4cb988923060fd3b65d0f0352bb634bcc44f2fe668836dcd0f604150049835135dc4b4fbf90fb334b3938a1f137eb32f047c65b85e6c1173b890b6d0162b48b186d1f1af8521945924ac8ac8efec321bf34f1d4b3d4a304a10313052c652d53f6ecb8a55586614e8950cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c"
]
}
+ },
+ {
+ "description": "Script Tree is not a binary tree (has tree leafs)",
+ "exception": "property \"scriptTree\" of type \\?isTapTree, got Array",
+ "options": {},
+ "arguments": {
+ "internalPubkey": "9fa5ffb68821cf559001caa0577eeea4978b29416def328a707b15e91701a2f7",
+ "scriptTree": [
+ {
+ "output": "71981521ad9fc9036687364118fb6ccd2035b96a423c59c5430e98310a11abe2 OP_CHECKSIG",
+ "version": 192
+ },
+ [
+ {
+ "output": "d5094d2dbe9b76e2c245a2b89b6006888952e2faa6a149ae318d69e520617748 OP_CHECKSIG",
+ "version": 192
+ },
+ {
+ "output": "c440b462ad48c7a77f94cd4532d8f2119dcebbd7c9764557e62726419b08ad4c OP_CHECKSIG",
+ "version": 192
+ },
+ {
+ "output": "c440b462ad48c7a77f94cd4532d8f2119dcebbd7c9764557e62726419b08ad4c OP_CHECKSIG",
+ "version": 192
+ }
+ ]
+ ],
+ "hash": "b76077013c8e303085e300000000000000000000000000000000000000000000"
+ }
+ },
+ {
+ "description": "Script Tree is not a TapTree tree (leaf has no script)",
+ "exception": "property \"scriptTree\" of type \\?isTapTree, got Array",
+ "options": {},
+ "arguments": {
+ "internalPubkey": "9fa5ffb68821cf559001caa0577eeea4978b29416def328a707b15e91701a2f7",
+ "scriptTree": [
+ {
+ "output": "71981521ad9fc9036687364118fb6ccd2035b96a423c59c5430e98310a11abe2 OP_CHECKSIG",
+ "version": 192
+ },
+ [
+ [
+ [
+ [
+ {
+ "output": "d5094d2dbe9b76e2c245a2b89b6006888952e2faa6a149ae318d69e520617748 OP_CHECKSIG",
+ "version": 192
+ },
+ {
+ "version": 192
+ }
+ ]
+ ]
+ ]
+ ]
+ ],
+ "hash": "b76077013c8e303085e300000000000000000000000000000000000000000000"
+ }
+ },
+ {
+ "description": "Incorrect redeem version",
+ "exception": "Redeem.redeemVersion and witness mismatch",
+ "arguments": {
+ "witness": [
+ "20d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8ac",
+ "c1187791b6f712a8ea41c8ecdd0ee77fab3e85263b37e1ec18a3651926b3a6cf27"
+ ],
+ "redeem": {
+ "output": "d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8 OP_CHECKSIG",
+ "redeemVersion": 111
+ }
+ }
+ },
+ {
+ "description": "Incorrect redeem output",
+ "exception": "Redeem.output and witness mismatch",
+ "arguments": {
+ "witness": [
+ "20d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8ac",
+ "c1187791b6f712a8ea41c8ecdd0ee77fab3e85263b37e1ec18a3651926b3a6cf27"
+ ],
+ "redeem": {
+ "output": "d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e0000000000 OP_CHECKSIG",
+ "redeemVersion": 192
+ }
+ }
+ },
+ {
+ "description": "Incorrect redeem witness",
+ "exception": "Redeem.witness and witness mismatch",
+ "arguments": {
+ "witness": [
+ "9675a9982c6398ea9d441cb7a943bcd6ff033cc3a2e01a0178a7d3be4575be863871c6bf3eef5ecd34721c784259385ca9101c3a313e010ac942c99de05aaaa602",
+ "5799cf4b193b730fb99580b186f7477c2cca4d28957326f6f1a5d14116438530e7ec0ce1cd465ad96968ae8a6a09d4d37a060a115919f56fcfebe7b2277cc2df5cc08fb6cda9105ee2512b2e22635aba",
+ "7520c7b5db9562078049719228db2ac80cb9643ec96c8055aa3b29c2c03d4d99edb0ac",
+ "c1a7957acbaaf7b444c53d9e0c9436e8a8a3247fd515095d66ddf6201918b40a3668f9a4ccdffcf778da624dca2dda0b08e763ec52fd4ad403ec7563a3504d0cc168b9a77a410029e01dac89567c9b2e6cd726e840351df3f2f58fefe976200a19244150d04153909f660184d656ee95fa7bf8e1d4ec83da1fca34f64bc279b76d257ec623e08baba2cfa4ea9e99646e88f1eb1668c00c0f15b7443c8ab83481611cc3ae85eb89a7bfc40067eb1d2e6354a32426d0ce710e88bc4cc0718b99c325509c9d02a6a980d675a8969be10ee9bef82cafee2fc913475667ccda37b1bc7f13f64e56c449c532658ba8481631c02ead979754c809584a875951619cec8fb040c33f06468ae0266cd8693d6a64cea5912be32d8de95a6da6300b0c50fdcd6001ea41126e7b7e5280d455054a816560028f5ca53c9a50ee52f10e15c5337315bad1f5277acb109a1418649dc6ead2fe14699742fee7182f2f15e54279c7d932ed2799d01d73c97e68bbc94d6f7f56ee0a80efd7c76e3169e10d1a1ba3b5f1eb02369dc43af687461c7a2a3344d13eb5485dca29a67f16b4cb988923060fd3b65d0f0352bb634bcc44f2fe668836dcd0f604150049835135dc4b4fbf90fb334b3938a1f137eb32f047c65b85e6c1173b890b6d0162b48b186d1f1af8521945924ac8ac8efec321bf34f1d4b3d4a304a10313052c652d53f6ecb8a55586614e8950cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c"
+ ],
+ "redeem" : {
+ "output": "OP_DROP c7b5db9562078049719228db2ac80cb9643ec96c8055aa3b29c2c03d4d99edb0 OP_CHECKSIG",
+ "redeemVersion": 192,
+ "witness": [
+ "9675a9982c6398ea9d441cb7a943bcd6ff033cc3a2e01a0178a7d3be4575be863871c6bf3eef5ecd34721c784259385ca9101c3a313e0100000000000000000000",
+ "5799cf4b193b730fb99580b186f7477c2cca4d28957326f6f1a5d14116438530e7ec0ce1cd465ad96968ae8a6a09d4d37a060a115919f56fcfebe7b2277cc2df5cc08fb6cda9105ee2512b2e22635aba"
+ ]
+ }
+ }
+ },
+ {
+ "description": "Incorrect redeem output ASM",
+ "exception": "Redeem.output is invalid",
+ "arguments": {
+ "witness": [
+ "9675a9982c6398ea9d441cb7a943bcd6ff033cc3a2e01a0178a7d3be4575be863871c6bf3eef5ecd34721c784259385ca9101c3a313e010ac942c99de05aaaa602",
+ "5799cf4b193b730fb99580b186f7477c2cca4d28957326f6f1a5d14116438530e7ec0ce1cd465ad96968ae8a6a09d4d37a060a115919f56fcfebe7b2277cc2df5cc08fb6cda9105ee2512b2e22635aba",
+ "7520c7b5db9562078049719228db2ac80cb9643ec96c8055aa3b29c2c03d4d99edb0ac",
+ "c1a7957acbaaf7b444c53d9e0c9436e8a8a3247fd515095d66ddf6201918b40a3668f9a4ccdffcf778da624dca2dda0b08e763ec52fd4ad403ec7563a3504d0cc168b9a77a410029e01dac89567c9b2e6cd726e840351df3f2f58fefe976200a19244150d04153909f660184d656ee95fa7bf8e1d4ec83da1fca34f64bc279b76d257ec623e08baba2cfa4ea9e99646e88f1eb1668c00c0f15b7443c8ab83481611cc3ae85eb89a7bfc40067eb1d2e6354a32426d0ce710e88bc4cc0718b99c325509c9d02a6a980d675a8969be10ee9bef82cafee2fc913475667ccda37b1bc7f13f64e56c449c532658ba8481631c02ead979754c809584a875951619cec8fb040c33f06468ae0266cd8693d6a64cea5912be32d8de95a6da6300b0c50fdcd6001ea41126e7b7e5280d455054a816560028f5ca53c9a50ee52f10e15c5337315bad1f5277acb109a1418649dc6ead2fe14699742fee7182f2f15e54279c7d932ed2799d01d73c97e68bbc94d6f7f56ee0a80efd7c76e3169e10d1a1ba3b5f1eb02369dc43af687461c7a2a3344d13eb5485dca29a67f16b4cb988923060fd3b65d0f0352bb634bcc44f2fe668836dcd0f604150049835135dc4b4fbf90fb334b3938a1f137eb32f047c65b85e6c1173b890b6d0162b48b186d1f1af8521945924ac8ac8efec321bf34f1d4b3d4a304a10313052c652d53f6ecb8a55586614e8950cde9ab6fe8e22802e93b3b9139112250b80ebc589aba231af535bb20f7eeec2e412f698c17f3fdc0a2e20924a5e38b21a628a9e3b2a61e35958e60c7f5087c"
+ ],
+ "redeem" : {
+ "output": "",
+ "redeemVersion": 192,
+ "witness": [
+ "9675a9982c6398ea9d441cb7a943bcd6ff033cc3a2e01a0178a7d3be4575be863871c6bf3eef5ecd34721c784259385ca9101c3a313e0100000000000000000000",
+ "5799cf4b193b730fb99580b186f7477c2cca4d28957326f6f1a5d14116438530e7ec0ce1cd465ad96968ae8a6a09d4d37a060a115919f56fcfebe7b2277cc2df5cc08fb6cda9105ee2512b2e22635aba"
+ ]
+ }
+ }
}
],
"dynamic": {
diff --git a/test/fixtures/psbt.json b/test/fixtures/psbt.json
index 2e7d9cf76..5a78e3527 100644
--- a/test/fixtures/psbt.json
+++ b/test/fixtures/psbt.json
@@ -297,6 +297,26 @@
}
],
"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="
+ },
+ {
+ "description": "Sign PSBT with 1 input [P2TR] (script-path, 3-of-3) and one output [P2TR]",
+ "psbt": "cHNidP8BAF4CAAAAAcPe80j90ChJ8zbpzcG0ZVC7LEvKwW5HRFLFTyc7y4bHAAAAAAD/////AZBBBgAAAAAAIlEgMqacf47eQ4lDRqNGRo3DRZ07bl/zz75tVIEa7xr7H0IAAAAAAAEBK6BoBgAAAAAAIlEgMqacf47eQ4lDRqNGRo3DRZ07bl/zz75tVIEa7xr7H0IBBWggj4kary4texRheMVKh+Ku3dnR1oZpIleSjmfPCBdP83WsIDlfgSndY7SlwvEhJOqgW3p+0w9w5R+5MwXe7MVC5/nruiCoqze8FgnYNMOROzU42tHITX+baoNf/BdXd5FaN641crpTnAAA",
+ "isTaproot": true,
+ "keys": [
+ {
+ "inputToSign": 0,
+ "WIF": "cRXSy63fXDve59e8cvqozVFfqXJB6YL6cPzoRewmEsux81SgPrfj"
+ },
+ {
+ "inputToSign": 0,
+ "WIF": "cQQXUJocNBS6oZCCtyhCsdN5ammK6WoJWpx44ANKxZSN2A3WDDEN"
+ },
+ {
+ "inputToSign": 0,
+ "WIF": "cTrPNrN2EQo4ppBHcFNxyLBFq2WLjZoNKY5nQbPwAGdhQqqsRKSu"
+ }
+ ],
+ "result": "cHNidP8BAF4CAAAAAcPe80j90ChJ8zbpzcG0ZVC7LEvKwW5HRFLFTyc7y4bHAAAAAAD/////AZBBBgAAAAAAIlEgMqacf47eQ4lDRqNGRo3DRZ07bl/zz75tVIEa7xr7H0IAAAAAAAEBK6BoBgAAAAAAIlEgMqacf47eQ4lDRqNGRo3DRZ07bl/zz75tVIEa7xr7H0IiAgI5X4Ep3WO0pcLxISTqoFt6ftMPcOUfuTMF3uzFQuf560BOGsYvM/Ot27p7l86wu+8NyTgqenZPSYN3g88W0NWF1C6O2P7k8vMntZ7qXQJwahuxKQPjlHAhb+wCOp+sHi1cIgIDj4kary4texRheMVKh+Ku3dnR1oZpIleSjmfPCBdP83VAygBYJBfi/tFJV/2WNjeuh+rBnU17ZtihdMICzGGN7OLURnBRB5oARqqvcGwQF4ta2sarDwZd+mg6DMaHUqOQ4CICA6irN7wWCdg0w5E7NTja0chNf5tqg1/8F1d3kVo3rjVyQGNFuQCECKRcz9CR7vuYOQ5p9dwxty0rMxt33MPpUh+RoihShEgazosa20pguB1lg/TF1RTY25OYfjl9CUYTQdgBBWggj4kary4texRheMVKh+Ku3dnR1oZpIleSjmfPCBdP83WsIDlfgSndY7SlwvEhJOqgW3p+0w9w5R+5MwXe7MVC5/nruiCoqze8FgnYNMOROzU42tHITX+baoNf/BdXd5FaN641crpTnAAA"
}
],
"combiner": [
@@ -319,6 +339,11 @@
{
"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",
"result": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABB9oARzBEAiB0AYrUGACXuHMyPAAVcgs2hMyBI4kQSOfbzZtVrWecmQIgc9Npt0Dj61Pc76M4I8gHBRTKVafdlUTxV8FnkTJhEYwBSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAUdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSrgABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEHIyIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQjaBABHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwFHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gFHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4AIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA=="
+ },
+ {
+ "psbt": "cHNidP8BAF4CAAAAAWbQAKi9hNXynJhqPu8bqkvp0kHihVShkWGh3yLy15+LAAAAAAD/////AbgFAQAAAAAAIlEgRvZJfLLxnVDD6emCqVDcyGIUsB/M5DekIGHHvbEjDTMAAAAAAAEBK7gFAQAAAAAAIlEglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4iAgKUIec0sPnSxGfqfdGXxhrLRGfNy8n0ywxXH4tjpcQMrkDYKEk9EBnhyC92Y/sV2r8U7uushyGLzWj/UcNmsym5qFYJUq2Fjhh2mUeMRu1yad248jY5EC8LQ7bb4vNqFVuMAAA=",
+ "result": "cHNidP8BAF4CAAAAAWbQAKi9hNXynJhqPu8bqkvp0kHihVShkWGh3yLy15+LAAAAAAD/////AbgFAQAAAAAAIlEgRvZJfLLxnVDD6emCqVDcyGIUsB/M5DekIGHHvbEjDTMAAAAAAAEBK7gFAQAAAAAAIlEglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4BCEIBQNgoST0QGeHIL3Zj+xXavxTu66yHIYvNaP9Rw2azKbmoVglSrYWOGHaZR4xG7XJp3bjyNjkQLwtDttvi82oVW4wAAA==",
+ "isTaproot": true
}
],
"extractor": [
@@ -582,6 +607,19 @@
"incorrectPubkey": "Buffer.from('029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e02a', 'hex')",
"nonExistantIndex": 42
},
+ "finalizeTaprootScriptPathSpendInput": {
+ "psbt": "cHNidP8BAF4CAAAAAWbQAKi9hNXynJhqPu8bqkvp0kHihVShkWGh3yLy15+LAAAAAAD/////AbgFAQAAAAAAIlEgRvZJfLLxnVDD6emCqVDcyGIUsB/M5DekIGHHvbEjDTMAAAAAAAEBK7gFAQAAAAAAIlEglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4iAgIuaLwR9cS6BsT6rRYePMFBKZzPkrdUmz80cDu5ATSjkEC5NO2PsYVquVp/60QIc7eTYcr16eABzDpFibWxBgfXoEDrH0oCzDH5HQ8lu7S9VWJwKvJ7GJIMGLDCX/n13qSsAQUiIC5ovBH1xLoGxPqtFh48wUEpnM+St1SbPzRwO7kBNKOQrAAA",
+ "internalPublicKey": "Buffer.from('02982a2876765bb37b53a12418b9e72b8afa8d54e344a1bd585299a211fbe625f3', 'hex')",
+ "scriptTree": [
+ {
+ "output": "Buffer.from('2050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0ac', 'hex')"
+ },
+ {
+ "output": "Buffer.from('202e68bc11f5c4ba06c4faad161e3cc141299ccf92b7549b3f34703bb90134a390ac', 'hex')"
+ }
+ ],
+ "result": "cHNidP8BAF4CAAAAAWbQAKi9hNXynJhqPu8bqkvp0kHihVShkWGh3yLy15+LAAAAAAD/////AbgFAQAAAAAAIlEgRvZJfLLxnVDD6emCqVDcyGIUsB/M5DekIGHHvbEjDTMAAAAAAAEBK7gFAQAAAAAAIlEglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4BCKcDQLk07Y+xhWq5Wn/rRAhzt5NhyvXp4AHMOkWJtbEGB9egQOsfSgLMMfkdDyW7tL1VYnAq8nsYkgwYsMJf+fXepKwiIC5ovBH1xLoGxPqtFh48wUEpnM+St1SbPzRwO7kBNKOQrEHAmCoodnZbs3tToSQYuecrivqNVONEob1YUpmiEfvmJfMaUpyfs81+d21htiJbbGEOiQb7j6psWaxcPpW1+C0p1gAA"
+ },
"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/integration/taproot.md b/test/integration/taproot.md
index 401034061..7627450e2 100644
--- a/test/integration/taproot.md
+++ b/test/integration/taproot.md
@@ -9,8 +9,9 @@ A simple keyspend example that is possible with the current API is below.
## TODO
-- [ ] p2tr payment API to make script spends easier
+- [x] p2tr payment API to make script spends easier
- [ ] Support within the Psbt class
+ - partial support added
## Example
diff --git a/test/integration/taproot.spec.ts b/test/integration/taproot.spec.ts
index b3ff997b0..90dacb63d 100644
--- a/test/integration/taproot.spec.ts
+++ b/test/integration/taproot.spec.ts
@@ -1,11 +1,15 @@
import BIP32Factory from 'bip32';
+import ECPairFactory from 'ecpair';
import * as ecc from 'tiny-secp256k1';
import { describe, it } from 'mocha';
-import * as bitcoin from '../..';
import { regtestUtils } from './_regtest';
+import * as bitcoin from '../..';
+import { buildTapscriptFinalizer, toXOnly } from '../psbt.utils';
+
const rng = require('randombytes');
const regtest = regtestUtils.network;
const bip32 = BIP32Factory(ecc);
+const ECPair = ECPairFactory(ecc);
describe('bitcoinjs-lib (transaction with taproot)', () => {
it('can create (and broadcast via 3PBP) a taproot keyspend Transaction', async () => {
@@ -42,6 +46,391 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
value: sendAmount,
});
});
+
+ it('can create (and broadcast via 3PBP) a taproot key-path spend Transaction', async () => {
+ const internalKey = bip32.fromSeed(rng(64), regtest);
+
+ const { output, address } = bitcoin.payments.p2tr(
+ { internalPubkey: toXOnly(internalKey.publicKey), network: regtest },
+ { eccLib: ecc },
+ );
+
+ // amount from faucet
+ const amount = 42e4;
+ // amount to send
+ const sendAmount = amount - 1e4;
+ // get faucet
+ const unspent = await regtestUtils.faucetComplex(output!, amount);
+
+ const psbt = new bitcoin.Psbt({ eccLib: ecc, network: regtest });
+ psbt.addInput({
+ hash: unspent.txId,
+ index: 0,
+ witnessUtxo: { value: amount, script: output! },
+ });
+ psbt.addOutput({ value: sendAmount, address: address! });
+
+ const tweakedSigher = tweakSigner(internalKey!, { network: regtest });
+ psbt.signInput(0, tweakedSigher);
+
+ psbt.finalizeAllInputs();
+ const tx = psbt.extractTransaction();
+ const rawTx = tx.toBuffer();
+
+ const hex = rawTx.toString('hex');
+
+ await regtestUtils.broadcast(hex);
+ await regtestUtils.verify({
+ txId: tx.getId(),
+ address: address!,
+ vout: 0,
+ value: sendAmount,
+ });
+ });
+
+ it('can create (and broadcast via 3PBP) a taproot key-path spend Transaction (with unused scriptTree)', async () => {
+ const internalKey = bip32.fromSeed(rng(64), regtest);
+ const leafKey = bip32.fromSeed(rng(64), regtest);
+
+ const leafScriptAsm = `${toXOnly(leafKey.publicKey).toString(
+ 'hex',
+ )} OP_CHECKSIG`;
+ const leafScript = bitcoin.script.fromASM(leafScriptAsm);
+
+ const scriptTree = [
+ {
+ output: leafScript,
+ },
+ ];
+
+ const { output, address, hash } = bitcoin.payments.p2tr(
+ {
+ internalPubkey: toXOnly(internalKey.publicKey),
+ scriptTree,
+ network: regtest,
+ },
+ { eccLib: ecc },
+ );
+
+ // amount from faucet
+ const amount = 42e4;
+ // amount to send
+ const sendAmount = amount - 1e4;
+ // get faucet
+ const unspent = await regtestUtils.faucetComplex(output!, amount);
+
+ const psbt = new bitcoin.Psbt({ eccLib: ecc, network: regtest });
+ psbt.addInput({
+ hash: unspent.txId,
+ index: 0,
+ witnessUtxo: { value: amount, script: output! },
+ });
+ psbt.addOutput({ value: sendAmount, address: address! });
+
+ const tweakedSigher = tweakSigner(internalKey!, {
+ tweakHash: hash,
+ network: regtest,
+ });
+ psbt.signInput(0, tweakedSigher);
+
+ psbt.finalizeAllInputs();
+ const tx = psbt.extractTransaction();
+ const rawTx = tx.toBuffer();
+
+ const hex = rawTx.toString('hex');
+
+ await regtestUtils.broadcast(hex);
+ await regtestUtils.verify({
+ txId: tx.getId(),
+ address: address!,
+ vout: 0,
+ value: sendAmount,
+ });
+ });
+
+ it('can create (and broadcast via 3PBP) a taproot script-path spend Transaction - OP_CHECKSIG', async () => {
+ const internalKey = bip32.fromSeed(rng(64), regtest);
+ const leafKey = bip32.fromSeed(rng(64), regtest);
+
+ const leafScriptAsm = `${toXOnly(leafKey.publicKey).toString(
+ 'hex',
+ )} OP_CHECKSIG`;
+ const leafScript = bitcoin.script.fromASM(leafScriptAsm);
+
+ const scriptTree: any[] = [
+ [
+ {
+ output: bitcoin.script.fromASM(
+ '50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0 OP_CHECKSIG',
+ ),
+ },
+ [
+ {
+ output: bitcoin.script.fromASM(
+ '50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac1 OP_CHECKSIG',
+ ),
+ },
+ {
+ output: bitcoin.script.fromASM(
+ '2258b1c3160be0864a541854eec9164a572f094f7562628281a8073bb89173a7 OP_CHECKSIG',
+ ),
+ },
+ ],
+ ],
+ [
+ {
+ output: bitcoin.script.fromASM(
+ '50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac2 OP_CHECKSIG',
+ ),
+ },
+ [
+ {
+ output: bitcoin.script.fromASM(
+ '50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac3 OP_CHECKSIG',
+ ),
+ },
+ [
+ {
+ output: bitcoin.script.fromASM(
+ '50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac4 OP_CHECKSIG',
+ ),
+ },
+ {
+ output: leafScript,
+ },
+ ],
+ ],
+ ],
+ ];
+ const redeem = {
+ output: leafScript,
+ redeemVersion: 192,
+ };
+
+ const { output, address } = bitcoin.payments.p2tr(
+ {
+ internalPubkey: toXOnly(internalKey.publicKey),
+ scriptTree,
+ redeem,
+ network: regtest,
+ },
+ { eccLib: ecc },
+ );
+
+ // amount from faucet
+ const amount = 42e4;
+ // amount to send
+ const sendAmount = amount - 1e4;
+ // get faucet
+ const unspent = await regtestUtils.faucetComplex(output!, amount);
+
+ const psbt = new bitcoin.Psbt({ eccLib: ecc, network: regtest });
+ psbt.addInput({
+ hash: unspent.txId,
+ index: 0,
+ witnessUtxo: { value: amount, script: output! },
+ witnessScript: redeem.output,
+ });
+ psbt.addOutput({ value: sendAmount, address: address! });
+
+ psbt.signInput(0, leafKey);
+
+ const tapscriptFinalizer = buildTapscriptFinalizer(
+ internalKey.publicKey,
+ scriptTree,
+ regtest,
+ );
+ psbt.finalizeInput(0, tapscriptFinalizer);
+ const tx = psbt.extractTransaction();
+ const rawTx = tx.toBuffer();
+ const hex = rawTx.toString('hex');
+
+ await regtestUtils.broadcast(hex);
+ await regtestUtils.verify({
+ txId: tx.getId(),
+ address: address!,
+ vout: 0,
+ value: sendAmount,
+ });
+ });
+
+ it('can create (and broadcast via 3PBP) a taproot script-path spend Transaction - OP_CHECKSEQUENCEVERIFY', async () => {
+ const internalKey = bip32.fromSeed(rng(64), regtest);
+ const leafKey = bip32.fromSeed(rng(64), regtest);
+ const leafPubkey = toXOnly(leafKey.publicKey).toString('hex');
+
+ const leafScriptAsm = `OP_10 OP_CHECKSEQUENCEVERIFY OP_DROP ${leafPubkey} OP_CHECKSIG`;
+ const leafScript = bitcoin.script.fromASM(leafScriptAsm);
+
+ const scriptTree: any[] = [
+ {
+ output: bitcoin.script.fromASM(
+ '50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0 OP_CHECKSIG',
+ ),
+ },
+ [
+ {
+ output: bitcoin.script.fromASM(
+ '50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0 OP_CHECKSIG',
+ ),
+ },
+ {
+ output: leafScript,
+ },
+ ],
+ ];
+ const redeem = {
+ output: leafScript,
+ redeemVersion: 192,
+ };
+
+ const { output, address } = bitcoin.payments.p2tr(
+ {
+ internalPubkey: toXOnly(internalKey.publicKey),
+ scriptTree,
+ redeem,
+ network: regtest,
+ },
+ { eccLib: ecc },
+ );
+
+ // amount from faucet
+ const amount = 42e4;
+ // amount to send
+ const sendAmount = amount - 1e4;
+ // get faucet
+ const unspent = await regtestUtils.faucetComplex(output!, amount);
+
+ const psbt = new bitcoin.Psbt({ eccLib: ecc, network: regtest });
+ psbt.addInput({
+ hash: unspent.txId,
+ index: 0,
+ sequence: 10,
+ witnessUtxo: { value: amount, script: output! },
+ witnessScript: redeem.output,
+ });
+ psbt.addOutput({ value: sendAmount, address: address! });
+
+ psbt.signInput(0, leafKey);
+
+ const tapscriptFinalizer = buildTapscriptFinalizer(
+ internalKey.publicKey,
+ scriptTree,
+ regtest,
+ );
+ psbt.finalizeInput(0, tapscriptFinalizer);
+ const tx = psbt.extractTransaction();
+ const rawTx = tx.toBuffer();
+ const hex = rawTx.toString('hex');
+
+ try {
+ // broadcast before the confirmation period has expired
+ await regtestUtils.broadcast(hex);
+ throw new Error('Broadcast should fail.');
+ } catch (err) {
+ if ((err as any).message !== 'non-BIP68-final')
+ throw new Error(
+ 'Expected OP_CHECKSEQUENCEVERIFY validation to fail. But it faild with: ' +
+ err,
+ );
+ }
+ await regtestUtils.mine(10);
+ await regtestUtils.broadcast(hex);
+ await regtestUtils.verify({
+ txId: tx.getId(),
+ address: address!,
+ vout: 0,
+ value: sendAmount,
+ });
+ });
+
+ it('can create (and broadcast via 3PBP) a taproot script-path spend Transaction - OP_CHECKSIGADD (3-of-3)', async () => {
+ const internalKey = bip32.fromSeed(rng(64), regtest);
+
+ const leafKeys = [];
+ const leafPubkeys = [];
+ for (let i = 0; i < 3; i++) {
+ const leafKey = bip32.fromSeed(rng(64), regtest);
+ leafKeys.push(leafKey);
+ leafPubkeys.push(toXOnly(leafKey.publicKey).toString('hex'));
+ }
+
+ const leafScriptAsm = `${leafPubkeys[2]} OP_CHECKSIG ${
+ leafPubkeys[1]
+ } OP_CHECKSIGADD ${leafPubkeys[0]} OP_CHECKSIGADD OP_3 OP_NUMEQUAL`;
+
+ const leafScript = bitcoin.script.fromASM(leafScriptAsm);
+
+ const scriptTree: any[] = [
+ {
+ output: bitcoin.script.fromASM(
+ '50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0 OP_CHECKSIG',
+ ),
+ },
+ [
+ {
+ output: bitcoin.script.fromASM(
+ '50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0 OP_CHECKSIG',
+ ),
+ },
+ {
+ output: leafScript,
+ },
+ ],
+ ];
+ const redeem = {
+ output: leafScript,
+ redeemVersion: 192,
+ };
+
+ const { output, address } = bitcoin.payments.p2tr(
+ {
+ internalPubkey: toXOnly(internalKey.publicKey),
+ scriptTree,
+ redeem,
+ network: regtest,
+ },
+ { eccLib: ecc },
+ );
+
+ // amount from faucet
+ const amount = 42e4;
+ // amount to send
+ const sendAmount = amount - 1e4;
+ // get faucet
+ const unspent = await regtestUtils.faucetComplex(output!, amount);
+
+ const psbt = new bitcoin.Psbt({ eccLib: ecc, network: regtest });
+ psbt.addInput({
+ hash: unspent.txId,
+ index: 0,
+ witnessUtxo: { value: amount, script: output! },
+ witnessScript: redeem.output,
+ });
+ psbt.addOutput({ value: sendAmount, address: address! });
+
+ psbt.signInput(0, leafKeys[0]);
+ psbt.signInput(0, leafKeys[1]);
+ psbt.signInput(0, leafKeys[2]);
+
+ const tapscriptFinalizer = buildTapscriptFinalizer(
+ internalKey.publicKey,
+ scriptTree,
+ regtest,
+ );
+ psbt.finalizeInput(0, tapscriptFinalizer);
+ const tx = psbt.extractTransaction();
+ const rawTx = tx.toBuffer();
+ const hex = rawTx.toString('hex');
+
+ await regtestUtils.broadcast(hex);
+ await regtestUtils.verify({
+ txId: tx.getId(),
+ address: address!,
+ vout: 0,
+ value: sendAmount,
+ });
+ });
});
// Order of the curve (N) - 1
@@ -59,7 +448,7 @@ const ONE = Buffer.from(
// (This is recommended by BIP341)
function createKeySpendOutput(publicKey: Buffer): Buffer {
// x-only pubkey (remove 1 byte y parity)
- const myXOnlyPubkey = publicKey.slice(1, 33);
+ const myXOnlyPubkey = toXOnly(publicKey);
const commitHash = bitcoin.crypto.taggedHash('TapTweak', myXOnlyPubkey);
const tweakResult = ecc.xOnlyPointAddTweak(myXOnlyPubkey, commitHash);
if (tweakResult === null) throw new Error('Invalid Tweak');
@@ -86,7 +475,7 @@ function signTweaked(messageHash: Buffer, key: KeyPair): Uint8Array {
: ecc.privateAdd(ecc.privateSub(N_LESS_1, key.privateKey!)!, ONE)!;
const tweakHash = bitcoin.crypto.taggedHash(
'TapTweak',
- key.publicKey.slice(1, 33),
+ toXOnly(key.publicKey),
);
const newPrivateKey = ecc.privateAdd(privateKey!, tweakHash);
if (newPrivateKey === null) throw new Error('Invalid Tweak');
@@ -120,3 +509,34 @@ function createSigned(
tx.ins[0].witness = [signature];
return tx;
}
+
+// This logic will be extracted to ecpair
+function tweakSigner(signer: bitcoin.Signer, opts: any = {}): bitcoin.Signer {
+ // @ts-ignore
+ 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(toXOnly(signer.publicKey), opts.tweakHash),
+ );
+ if (!tweakedPrivateKey) {
+ throw new Error('Invalid tweaked private key!');
+ }
+
+ return ECPair.fromPrivateKey(Buffer.from(tweakedPrivateKey), {
+ network: opts.network,
+ });
+}
+
+function tapTweakHash(pubKey: Buffer, h: Buffer | undefined): Buffer {
+ return bitcoin.crypto.taggedHash(
+ 'TapTweak',
+ Buffer.concat(h ? [pubKey, h] : [pubKey]),
+ );
+}
diff --git a/test/payments.utils.ts b/test/payments.utils.ts
index d4aee8374..12fc20712 100644
--- a/test/payments.utils.ts
+++ b/test/payments.utils.ts
@@ -52,6 +52,12 @@ function equateBase(a: any, b: any, context: string): void {
tryHex(b.witness),
`Inequal ${context}witness`,
);
+ if ('redeemVersion' in b)
+ t.strictEqual(
+ a.redeemVersion,
+ b.redeemVersion,
+ `Inequal ${context}redeemVersion`,
+ );
}
export function equate(a: any, b: any, args?: any): void {
@@ -62,10 +68,12 @@ export function equate(a: any, b: any, args?: any): void {
if (b.input === null) b.input = undefined;
if (b.output === null) b.output = undefined;
if (b.witness === null) b.witness = undefined;
+ if (b.redeemVersion === null) b.redeemVersion = undefined;
if (b.redeem) {
if (b.redeem.input === null) b.redeem.input = undefined;
if (b.redeem.output === null) b.redeem.output = undefined;
if (b.redeem.witness === null) b.redeem.witness = undefined;
+ if (b.redeem.redeemVersion === null) b.redeem.redeemVersion = undefined;
}
equateBase(a, b, '');
@@ -153,12 +161,8 @@ 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);
+
+ if (x.scriptTree) x.scriptTree = convertScriptTree(x.scriptTree);
return x;
}
@@ -182,12 +186,11 @@ 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);
+function convertScriptTree(scriptTree: any): any {
+ if (Array.isArray(scriptTree)) return scriptTree.map(convertScriptTree);
- const script = Object.assign({}, scriptsTree);
+ const script = Object.assign({}, scriptTree);
if (typeof script.output === 'string')
- script.output = asmToBuffer(scriptsTree.output);
+ script.output = asmToBuffer(scriptTree.output);
return script;
}
diff --git a/test/psbt.spec.ts b/test/psbt.spec.ts
index e5198ea78..6d5e1db6f 100644
--- a/test/psbt.spec.ts
+++ b/test/psbt.spec.ts
@@ -9,6 +9,7 @@ const bip32 = BIP32Factory(ecc);
const ECPair = ECPairFactory(ecc);
import { networks as NETWORKS, payments, Psbt, Signer, SignerAsync } from '..';
+import { buildTapscriptFinalizer } from './psbt.utils';
import * as preFixtures from './fixtures/psbt.json';
@@ -167,7 +168,8 @@ describe(`Psbt`, () => {
fixtures.bip174.finalizer.forEach(f => {
it('Finalizes inputs and gives the expected PSBT', () => {
- const psbt = Psbt.fromBase64(f.psbt);
+ const opts = f.isTaproot ? { eccLib: ecc } : {};
+ const psbt = Psbt.fromBase64(f.psbt, opts);
psbt.finalizeAllInputs();
@@ -989,6 +991,20 @@ describe(`Psbt`, () => {
});
});
+ describe('finalizeTaprootInput', () => {
+ it('Correctly finalizes a taproot script-path spend', () => {
+ const f = fixtures.finalizeTaprootScriptPathSpendInput;
+ const psbt = Psbt.fromBase64(f.psbt, { eccLib: ecc });
+ const tapscriptFinalizer = buildTapscriptFinalizer(
+ f.internalPublicKey as any,
+ f.scriptTree,
+ NETWORKS.testnet,
+ );
+ psbt.finalizeInput(0, tapscriptFinalizer);
+ assert.strictEqual(psbt.toBase64(), f.result);
+ });
+ });
+
describe('getFeeRate', () => {
it('Throws error if called before inputs are finalized', () => {
const f = fixtures.getFeeRate;
diff --git a/test/psbt.utils.ts b/test/psbt.utils.ts
new file mode 100644
index 000000000..b85d3989e
--- /dev/null
+++ b/test/psbt.utils.ts
@@ -0,0 +1,53 @@
+import { PsbtInput } from 'bip174/src/lib/interfaces';
+import * as bitcoin from './..';
+import { TinySecp256k1Interface } from '../src/types';
+
+/**
+ * Build finalizer function for Tapscript.
+ * Usees the default Tapscript version (0xc0).
+ * @returns finalizer function
+ */
+const buildTapscriptFinalizer = (
+ internalPubkey: Buffer,
+ scriptTree: any,
+ network: bitcoin.networks.Network,
+) => {
+ return (
+ inputIndex: number,
+ input: PsbtInput,
+ script: Buffer,
+ _isSegwit: boolean,
+ _isP2SH: boolean,
+ _isP2WSH: boolean,
+ eccLib?: TinySecp256k1Interface,
+ ): {
+ finalScriptSig: Buffer | undefined;
+ finalScriptWitness: Buffer | Buffer[] | undefined;
+ } => {
+ if (!internalPubkey || !scriptTree || !script)
+ throw new Error(`Can not finalize taproot input #${inputIndex}`);
+
+ try {
+ const tapscriptSpend = bitcoin.payments.p2tr(
+ {
+ internalPubkey: toXOnly(internalPubkey),
+ scriptTree,
+ redeem: { output: script },
+ network,
+ },
+ { eccLib },
+ );
+ const sigs = (input.partialSig || []).map(ps => ps.signature) as Buffer[];
+ const finalScriptWitness = sigs.concat(
+ tapscriptSpend.witness as Buffer[],
+ );
+ return { finalScriptWitness, finalScriptSig: undefined };
+ } catch (err) {
+ throw new Error(`Can not finalize taproot input #${inputIndex}: ${err}`);
+ }
+ };
+};
+
+const toXOnly = (pubKey: Buffer) => pubKey.slice(1, 33);
+
+export { buildTapscriptFinalizer, toXOnly };
diff --git a/ts_src/ops.ts b/ts_src/ops.ts
index 8e2c41c11..dd8b1e6da 100644
--- a/ts_src/ops.ts
+++ b/ts_src/ops.ts
@@ -127,6 +127,8 @@ const OPS: { [key: string]: number } = {
OP_NOP9: 184,
OP_NOP10: 185,
+ OP_CHECKSIGADD: 186,
+
OP_PUBKEYHASH: 253,
OP_PUBKEY: 254,
OP_INVALIDOPCODE: 255,
diff --git a/ts_src/payments/index.ts b/ts_src/payments/index.ts
index 7bb77b6ac..90f5403c5 100644
--- a/ts_src/payments/index.ts
+++ b/ts_src/payments/index.ts
@@ -1,5 +1,5 @@
import { Network } from '../networks';
-import { TaprootLeaf, TinySecp256k1Interface } from '../types';
+import { TinySecp256k1Interface, TaprootLeaf } from '../types';
import { p2data as embed } from './embed';
import { p2ms } from './p2ms';
import { p2pk } from './p2pk';
@@ -25,8 +25,8 @@ export interface Payment {
address?: string;
hash?: Buffer;
redeem?: Payment;
- scriptsTree?: any; // todo: solve
- scriptLeaf?: TaprootLeaf;
+ redeemVersion?: number;
+ scriptTree?: TaprootLeaf[];
witness?: Buffer[];
}
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index c79bb772e..268266e50 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -8,6 +8,8 @@ import {
findScriptPath,
tapLeafHash,
tapTweakHash,
+ isTapTree,
+ LEAF_VERSION_TAPSCRIPT,
} from './taprootutils';
import { Payment, PaymentOpts } from './index';
import * as lazy from './lazy';
@@ -15,8 +17,9 @@ import { bech32m } from 'bech32';
import { testEcc } from './testecc';
const OPS = bscript.OPS;
-const TAPROOT_VERSION = 0x01;
+const TAPROOT_WITNESS_VERSION = 0x01;
const ANNEX_PREFIX = 0x50;
+const LEAF_VERSION_MASK = 0b11111110;
export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
if (
@@ -48,11 +51,13 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
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),
+ scriptTree: typef.maybe(isTapTree),
+ redeem: typef.maybe({
output: typef.maybe(typef.Buffer),
+ redeemVersion: typef.maybe(typef.Number),
+ witness: typef.maybe(typef.arrayOf(typef.Buffer)),
}),
+ redeemVersion: typef.maybe(typef.Number),
},
a,
);
@@ -68,13 +73,13 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
};
});
+ // remove annex if present, ignored by taproot
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();
@@ -87,17 +92,17 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
if (!o.pubkey) return;
const words = bech32m.toWords(o.pubkey);
- words.unshift(TAPROOT_VERSION);
+ words.unshift(TAPROOT_WITNESS_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;
+ if (a.scriptTree) return toHashTree(a.scriptTree).hash;
const w = _witness();
if (w && w.length > 1) {
const controlBlock = w[w.length - 1];
- const leafVersion = controlBlock[0] & 0b11111110;
+ const leafVersion = controlBlock[0] & LEAF_VERSION_MASK;
const script = w[w.length - 2];
const leafHash = tapLeafHash(script, leafVersion);
return rootHashFromPath(controlBlock, leafHash);
@@ -108,8 +113,27 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
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, 'redeemVersion', () => {
+ if (a.redeemVersion) return a.redeemVersion;
+ if (
+ a.redeem &&
+ a.redeem.redeemVersion !== undefined &&
+ a.redeem.redeemVersion !== null
+ ) {
+ return a.redeem.redeemVersion;
+ }
+
+ return LEAF_VERSION_TAPSCRIPT;
+ });
+ lazy.prop(o, 'redeem', () => {
+ const witness = _witness(); // witness without annex
+ if (!witness || witness.length < 2) return;
+
+ return {
+ output: witness[witness.length - 2],
+ witness: witness.slice(0, -2),
+ redeemVersion: witness[witness.length - 1][0] & LEAF_VERSION_MASK,
+ };
});
lazy.prop(o, 'pubkey', () => {
if (a.pubkey) return a.pubkey;
@@ -131,25 +155,23 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
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) {
+ if (a.scriptTree && a.redeem && a.redeem.output && a.internalPubkey) {
// todo: optimize/cache
- const hashTree = toHashTree(a.scriptsTree);
- const leafHash = tapLeafHash(a.scriptLeaf.output, a.scriptLeaf.version);
+ const hashTree = toHashTree(a.scriptTree);
+ const leafHash = tapLeafHash(a.redeem.output, o.redeemVersion);
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(),
- ),
+ [
+ NBuffer.from([o.redeemVersion! | outputKey.parity]),
+ a.internalPubkey,
+ ].concat(path.reverse()),
);
- return [a.scriptLeaf.output, controlBock];
+ return [a.redeem.output, controlBock];
}
if (a.signature) return [a.signature];
});
@@ -160,7 +182,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
if (a.address) {
if (network && network.bech32 !== _address().prefix)
throw new TypeError('Invalid prefix or Network mismatch');
- if (_address().version !== TAPROOT_VERSION)
+ if (_address().version !== TAPROOT_WITNESS_VERSION)
throw new TypeError('Invalid address version');
if (_address().data.length !== 32)
throw new TypeError('Invalid address data');
@@ -197,13 +219,37 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
throw new TypeError('Invalid pubkey for p2tr');
}
- if (a.hash && a.scriptsTree) {
- const hash = toHashTree(a.scriptsTree).hash;
+ if (a.hash && a.scriptTree) {
+ const hash = toHashTree(a.scriptTree).hash;
if (!a.hash.equals(hash)) throw new TypeError('Hash mismatch');
}
const witness = _witness();
+ // compare the provided redeem data with the one computed from witness
+ if (a.redeem && o.redeem) {
+ if (a.redeem.redeemVersion) {
+ if (a.redeem.redeemVersion !== o.redeem.redeemVersion)
+ throw new TypeError('Redeem.redeemVersion and witness mismatch');
+ }
+
+ if (a.redeem.output) {
+ if (bscript.decompile(a.redeem.output)!.length === 0)
+ throw new TypeError('Redeem.output is invalid');
+
+ // output redeem is constructed from the witness
+ if (o.redeem.output && !a.redeem.output.equals(o.redeem.output))
+ throw new TypeError('Redeem.output and witness mismatch');
+ }
+ if (a.redeem.witness) {
+ if (
+ o.redeem.witness &&
+ !stacksEqual(a.redeem.witness, o.redeem.witness)
+ )
+ throw new TypeError('Redeem.witness and witness mismatch');
+ }
+ }
+
if (witness && witness.length) {
if (witness.length === 1) {
// key spending
@@ -237,7 +283,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
if (!_ecc().isXOnlyPoint(internalPubkey))
throw new TypeError('Invalid internalPubkey for p2tr witness');
- const leafVersion = controlBlock[0] & 0b11111110;
+ const leafVersion = controlBlock[0] & LEAF_VERSION_MASK;
const script = witness[witness.length - 2];
const leafHash = tapLeafHash(script, leafVersion);
@@ -284,3 +330,11 @@ function tweakKey(
x: NBuffer.from(res.xOnlyPubkey),
};
}
+
+function stacksEqual(a: Buffer[], b: Buffer[]): boolean {
+ if (a.length !== b.length) return false;
+
+ return a.every((x, i) => {
+ return x.equals(b[i]);
+ });
+}
diff --git a/ts_src/payments/taprootutils.ts b/ts_src/payments/taprootutils.ts
index 83ed9b14c..c71a38b9d 100644
--- a/ts_src/payments/taprootutils.ts
+++ b/ts_src/payments/taprootutils.ts
@@ -4,11 +4,12 @@ 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 const LEAF_VERSION_TAPSCRIPT = 0xc0;
+
export function rootHashFromPath(
controlBlock: Buffer,
tapLeafMsg: Buffer,
@@ -39,14 +40,14 @@ export interface 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:
+ * @param scriptTree - 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];
+export function toHashTree(scriptTree: TaprootLeaf[]): HashTree {
+ if (scriptTree.length === 1) {
+ const script = scriptTree[0];
if (Array.isArray(script)) {
return toHashTree(script);
}
@@ -59,8 +60,8 @@ export function toHashTree(scriptsTree: TaprootLeaf[]): HashTree {
};
}
- const left = toHashTree([scriptsTree[0]]);
- const right = toHashTree([scriptsTree[1]]);
+ const left = toHashTree([scriptTree[0]]);
+ const right = toHashTree([scriptTree[1]]);
let leftHash = left.hash;
let rightHash = right.hash;
@@ -73,6 +74,28 @@ export function toHashTree(scriptsTree: TaprootLeaf[]): HashTree {
right,
};
}
+/**
+ * Check if the tree is a binary tree with leafs of type TaprootLeaf
+ */
+export function isTapTree(scriptTree: TaprootLeaf[]): boolean {
+ if (scriptTree.length > 2) return false;
+ if (scriptTree.length === 1) {
+ const script = scriptTree[0];
+ if (Array.isArray(script)) {
+ return isTapTree(script);
+ }
+ if (!script.output) return false;
+ script.version = script.version || LEAF_VERSION_TAPSCRIPT;
+ if ((script.version & 1) !== 0) return false;
+
+ return true;
+ }
+
+ if (!isTapTree([scriptTree[0]])) return false;
+ if (!isTapTree([scriptTree[1]])) return false;
+
+ return true;
+}
/**
* Given a MAST tree, it finds the path of a particular hash.
diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts
index 163da5b2c..eec6d2da8 100644
--- a/ts_src/psbt.ts
+++ b/ts_src/psbt.ts
@@ -21,6 +21,7 @@ import { bitcoin as btcNetwork, Network } from './networks';
import * as payments from './payments';
import * as bscript from './script';
import { Output, Transaction } from './transaction';
+import { tapLeafHash } from './payments/taprootutils';
import { TinySecp256k1Interface } from './types';
export interface TransactionInput {
@@ -352,15 +353,22 @@ export class Psbt {
finalizeInput(inputIndex: number, finalScriptsFunc?: FinalScriptsFunc): this {
const input = checkForInput(this.data.inputs, inputIndex);
- const { script, isP2SH, isP2WSH, isSegwit } = getScriptFromInput(
- inputIndex,
- input,
- this.__CACHE,
- );
+ const {
+ script,
+ isP2SH,
+ isP2WSH,
+ isSegwit,
+ isTapscript,
+ } = getScriptFromInput(inputIndex, input, this.__CACHE);
if (!script) throw new Error(`No script found for input #${inputIndex}`);
checkPartialSigSighashes(input);
+ if (isTapscript && !finalScriptsFunc)
+ throw new Error(
+ `Taproot script-path finalizer required for input #${inputIndex}`,
+ );
+
const fn = finalScriptsFunc || getFinalScripts;
const { finalScriptSig, finalScriptWitness } = fn(
inputIndex,
@@ -373,8 +381,13 @@ export class Psbt {
);
if (finalScriptSig) this.data.updateInput(inputIndex, { finalScriptSig });
- if (finalScriptWitness)
- this.data.updateInput(inputIndex, { finalScriptWitness });
+ if (finalScriptWitness) {
+ // allow custom finalizers to build the witness as an array
+ const witness = Array.isArray(finalScriptWitness)
+ ? witnessStackToScriptWitness(finalScriptWitness)
+ : finalScriptWitness;
+ this.data.updateInput(inputIndex, { finalScriptWitness: witness });
+ }
if (!finalScriptSig && !finalScriptWitness)
throw new Error(`Unknown error finalizing input #${inputIndex}`);
@@ -396,6 +409,7 @@ export class Psbt {
input.redeemScript || redeemFromFinalScriptSig(input.finalScriptSig),
input.witnessScript ||
redeemFromFinalWitnessScript(input.finalScriptWitness),
+ this.__CACHE,
);
const type = result.type === 'raw' ? '' : result.type + '-';
const mainType = classifyScript(
@@ -461,13 +475,12 @@ export class Psbt {
const scriptType = this.getInputType(inputIndex);
for (const pSig of mySigs) {
- const sig =
- scriptType === 'taproot'
- ? {
- signature: pSig.signature,
- hashType: Transaction.SIGHASH_DEFAULT,
- }
- : bscript.signature.decode(pSig.signature);
+ const sig = isTaprootSpend(scriptType)
+ ? {
+ signature: pSig.signature,
+ hashType: Transaction.SIGHASH_DEFAULT,
+ }
+ : bscript.signature.decode(pSig.signature);
const { hash, script } =
sighashCache! !== sig.hashType
@@ -667,18 +680,17 @@ export class Psbt {
const scriptType = this.getInputType(inputIndex);
- if (scriptType === 'taproot') {
+ if (isTaprootSpend(scriptType)) {
if (!keyPair.signSchnorr) {
throw new Error(
`Need Schnorr Signer to sign taproot input #${inputIndex}.`,
);
}
- const partialSig = [
- {
- pubkey: keyPair.publicKey,
- signature: keyPair.signSchnorr!(hash),
- },
- ];
+ const partialSig = this.data.inputs[inputIndex].partialSig || [];
+ partialSig.push({
+ pubkey: keyPair.publicKey,
+ signature: keyPair.signSchnorr!(hash),
+ });
// must be changed to use the `updateInput()` public API
this.data.inputs[inputIndex].partialSig = partialSig;
} else {
@@ -712,19 +724,19 @@ export class Psbt {
const scriptType = this.getInputType(inputIndex);
- if (scriptType === 'taproot') {
+ if (isTaprootSpend(scriptType)) {
if (!keyPair.signSchnorr) {
throw new Error(
`Need Schnorr Signer to sign taproot input #${inputIndex}.`,
);
}
return Promise.resolve(keyPair.signSchnorr(hash)).then(signature => {
- const partialSig = [
- {
- pubkey: keyPair.publicKey,
- signature,
- },
- ];
+ const partialSig = this.data.inputs[inputIndex].partialSig || [];
+ partialSig.push({
+ pubkey: keyPair.publicKey,
+ signature,
+ });
+
// must be changed to use the `updateInput()` public API
this.data.inputs[inputIndex].partialSig = partialSig;
});
@@ -1214,9 +1226,10 @@ type FinalScriptsFunc = (
isSegwit: boolean, // Is it segwit?
isP2SH: boolean, // Is it P2SH?
isP2WSH: boolean, // Is it P2WSH?
+ eccLib?: TinySecp256k1Interface, // optional lib for checking taproot validity
) => {
finalScriptSig: Buffer | undefined;
- finalScriptWitness: Buffer | undefined;
+ finalScriptWitness: Buffer | Buffer[] | undefined;
};
function getFinalScripts(
@@ -1366,6 +1379,7 @@ function getHashForSig(
'input',
input.redeemScript,
input.witnessScript,
+ cache,
);
if (['p2sh-p2wsh', 'p2wsh'].indexOf(type) >= 0) {
@@ -1385,18 +1399,22 @@ function getHashForSig(
prevout.value,
sighashType,
);
- } else if (isP2TR(meaningfulScript, cache.__EC_LIB)) {
+ } else if (isP2TR(prevout.script, cache.__EC_LIB)) {
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);
+ const leafHash = input.witnessScript
+ ? tapLeafHash(input.witnessScript)
+ : undefined;
hash = unsignedTx.hashForWitnessV1(
inputIndex,
signingScripts,
values,
Transaction.SIGHASH_DEFAULT,
+ leafHash,
);
} else {
// non-segwit
@@ -1472,7 +1490,7 @@ function getPayment(
output: script,
signature: partialSig[0].signature,
},
- { validate: false }, // skip validation (for now)
+ { validate: false }, // skip validation
);
break;
}
@@ -1497,6 +1515,7 @@ function getPsigsFromInputFinalScripts(input: PsbtInput): PartialSig[] {
interface GetScriptReturn {
script: Buffer | null;
isSegwit: boolean;
+ isTapscript: boolean;
isP2SH: boolean;
isP2WSH: boolean;
}
@@ -1509,36 +1528,45 @@ function getScriptFromInput(
const res: GetScriptReturn = {
script: null,
isSegwit: false,
+ isTapscript: false,
isP2SH: false,
isP2WSH: false,
};
- res.isP2SH = !!input.redeemScript;
- res.isP2WSH = !!input.witnessScript;
+ let utxoScript = null;
+ if (input.nonWitnessUtxo) {
+ const nonWitnessUtxoTx = nonWitnessUtxoTxFromCache(
+ cache,
+ input,
+ inputIndex,
+ );
+ const prevoutIndex = unsignedTx.ins[inputIndex].index;
+ utxoScript = nonWitnessUtxoTx.outs[prevoutIndex].script;
+ } else if (input.witnessUtxo) {
+ utxoScript = input.witnessUtxo.script;
+ }
+
if (input.witnessScript) {
res.script = input.witnessScript;
} else if (input.redeemScript) {
res.script = input.redeemScript;
} else {
- if (input.nonWitnessUtxo) {
- const nonWitnessUtxoTx = nonWitnessUtxoTxFromCache(
- cache,
- input,
- inputIndex,
- );
- const prevoutIndex = unsignedTx.ins[inputIndex].index;
- res.script = nonWitnessUtxoTx.outs[prevoutIndex].script;
- } else if (input.witnessUtxo) {
- res.script = input.witnessUtxo.script;
- }
+ res.script = utxoScript;
}
- if (
- input.witnessScript ||
- isP2WPKH(res.script!) ||
- isP2TR(res.script!, cache.__EC_LIB)
- ) {
+ const isTaproot = utxoScript && isP2TR(utxoScript, cache.__EC_LIB);
+
+ // Segregated Witness versions 0 or 1
+ if (input.witnessScript || isP2WPKH(res.script!) || isTaproot) {
res.isSegwit = true;
}
+
+ if (isTaproot && input.witnessScript) {
+ res.isTapscript = true;
+ }
+
+ res.isP2SH = !!input.redeemScript;
+ res.isP2WSH = !!input.witnessScript && !res.isTapscript;
+
return res;
}
@@ -1788,6 +1816,7 @@ function pubkeyInInput(
'input',
input.redeemScript,
input.witnessScript,
+ cache,
);
return pubkeyInScript(pubkey, meaningfulScript);
}
@@ -1805,6 +1834,7 @@ function pubkeyInOutput(
'output',
output.redeemScript,
output.witnessScript,
+ cache,
);
return pubkeyInScript(pubkey, meaningfulScript);
}
@@ -1863,13 +1893,15 @@ function getMeaningfulScript(
ioType: 'input' | 'output',
redeemScript?: Buffer,
witnessScript?: Buffer,
+ cache?: PsbtCache,
): {
meaningfulScript: Buffer;
- type: 'p2sh' | 'p2wsh' | 'p2sh-p2wsh' | 'raw';
+ type: 'p2sh' | 'p2wsh' | 'p2sh-p2wsh' | 'p2tr' | 'raw';
} {
const isP2SH = isP2SHScript(script);
const isP2SHP2WSH = isP2SH && redeemScript && isP2WSHScript(redeemScript);
const isP2WSH = isP2WSHScript(script);
+ const isP2TRScript = isP2TR(script, cache && cache.__EC_LIB);
if (isP2SH && redeemScript === undefined)
throw new Error('scriptPubkey is P2SH but redeemScript missing');
@@ -1892,6 +1924,9 @@ function getMeaningfulScript(
} else if (isP2SH) {
meaningfulScript = redeemScript!;
checkRedeemScript(index, script, redeemScript!, ioType);
+ } else if (isP2TRScript && !!witnessScript) {
+ meaningfulScript = witnessScript;
+ // TODO: check here something?
} else {
meaningfulScript = script;
}
@@ -1903,6 +1938,8 @@ function getMeaningfulScript(
? 'p2sh'
: isP2WSH
? 'p2wsh'
+ : isP2TRScript
+ ? 'p2tr'
: 'raw',
};
}
@@ -1930,6 +1967,12 @@ function pubkeyInScript(pubkey: Buffer, script: Buffer): boolean {
});
}
+function isTaprootSpend(scriptType: string): boolean {
+ return (
+ !!scriptType && (scriptType === 'taproot' || scriptType.startsWith('p2tr-'))
+ );
+}
+
type AllScriptType =
| 'witnesspubkeyhash'
| 'pubkeyhash'
@@ -1949,7 +1992,9 @@ type AllScriptType =
| 'p2sh-p2wsh-pubkeyhash'
| 'p2sh-p2wsh-multisig'
| 'p2sh-p2wsh-pubkey'
- | 'p2sh-p2wsh-nonstandard';
+ | 'p2sh-p2wsh-nonstandard'
+ | 'p2tr-pubkey'
+ | 'p2tr-nonstandard';
type ScriptType =
| 'witnesspubkeyhash'
| 'pubkeyhash'
diff --git a/ts_src/types.ts b/ts_src/types.ts
index 487f29757..fad2bc29c 100644
--- a/ts_src/types.ts
+++ b/ts_src/types.ts
@@ -76,6 +76,7 @@ export interface TaprootLeaf {
output: Buffer;
version?: number;
}
+
export interface TinySecp256k1Interface {
isXOnlyPoint(p: Uint8Array): boolean;
xOnlyPointAddTweak(
From 1e6aec54766b64faaa82c766cdc795a47ad38d37 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Wed, 9 Mar 2022 18:36:48 +0200
Subject: [PATCH 052/144] refactor: move tapscript finalizer check; add unit
test
---
src/psbt.d.ts | 1 +
src/psbt.js | 8 +++-----
test/psbt.spec.ts | 9 +++++++++
test/psbt.utils.ts | 1 +
ts_src/psbt.ts | 10 ++++------
5 files changed, 18 insertions(+), 11 deletions(-)
diff --git a/src/psbt.d.ts b/src/psbt.d.ts
index cfc64a6e7..8b21ce7bb 100644
--- a/src/psbt.d.ts
+++ b/src/psbt.d.ts
@@ -179,6 +179,7 @@ declare type FinalScriptsFunc = (inputIndex: number, // Which input is it?
input: PsbtInput, // The PSBT input contents
script: Buffer, // The "meaningful" locking script Buffer (redeemScript for P2SH etc.)
isSegwit: boolean, // Is it segwit?
+isTapscript: boolean, // Is taproot script path?
isP2SH: boolean, // Is it P2SH?
isP2WSH: boolean, // Is it P2WSH?
eccLib?: TinySecp256k1Interface) => {
diff --git a/src/psbt.js b/src/psbt.js
index ec5614a07..1d6cad4fd 100644
--- a/src/psbt.js
+++ b/src/psbt.js
@@ -289,16 +289,13 @@ class Psbt {
} = getScriptFromInput(inputIndex, input, this.__CACHE);
if (!script) throw new Error(`No script found for input #${inputIndex}`);
checkPartialSigSighashes(input);
- if (isTapscript && !finalScriptsFunc)
- throw new Error(
- `Taproot script-path finalizer required for input #${inputIndex}`,
- );
const fn = finalScriptsFunc || getFinalScripts;
const { finalScriptSig, finalScriptWitness } = fn(
inputIndex,
input,
script,
isSegwit,
+ isTapscript,
isP2SH,
isP2WSH,
this.__CACHE.__EC_LIB,
@@ -936,12 +933,13 @@ function getFinalScripts(
input,
script,
isSegwit,
+ isTapscript,
isP2SH,
isP2WSH,
eccLib,
) {
const scriptType = classifyScript(script, eccLib);
- if (!canFinalize(input, script, scriptType))
+ if (isTapscript || !canFinalize(input, script, scriptType))
throw new Error(`Can not finalize input #${inputIndex}`);
return prepareFinalScripts(
script,
diff --git a/test/psbt.spec.ts b/test/psbt.spec.ts
index 6d5e1db6f..871142194 100644
--- a/test/psbt.spec.ts
+++ b/test/psbt.spec.ts
@@ -1003,6 +1003,15 @@ describe(`Psbt`, () => {
psbt.finalizeInput(0, tapscriptFinalizer);
assert.strictEqual(psbt.toBase64(), f.result);
});
+
+ it('Failes to finalize a taproot script-path spend when a finalizer is not provided', () => {
+ const f = fixtures.finalizeTaprootScriptPathSpendInput;
+ const psbt = Psbt.fromBase64(f.psbt, { eccLib: ecc });
+
+ assert.throws(() => {
+ psbt.finalizeInput(0);
+ }, new RegExp('Can not finalize input #0'));
+ });
});
describe('getFeeRate', () => {
diff --git a/test/psbt.utils.ts b/test/psbt.utils.ts
index b85d3989e..aec6ca42d 100644
--- a/test/psbt.utils.ts
+++ b/test/psbt.utils.ts
@@ -17,6 +17,7 @@ const buildTapscriptFinalizer = (
input: PsbtInput,
script: Buffer,
_isSegwit: boolean,
+ _isTapscript: boolean,
_isP2SH: boolean,
_isP2WSH: boolean,
eccLib?: TinySecp256k1Interface,
diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts
index eec6d2da8..a906a21c5 100644
--- a/ts_src/psbt.ts
+++ b/ts_src/psbt.ts
@@ -364,17 +364,13 @@ export class Psbt {
checkPartialSigSighashes(input);
- if (isTapscript && !finalScriptsFunc)
- throw new Error(
- `Taproot script-path finalizer required for input #${inputIndex}`,
- );
-
const fn = finalScriptsFunc || getFinalScripts;
const { finalScriptSig, finalScriptWitness } = fn(
inputIndex,
input,
script,
isSegwit,
+ isTapscript,
isP2SH,
isP2WSH,
this.__CACHE.__EC_LIB,
@@ -1224,6 +1220,7 @@ type FinalScriptsFunc = (
input: PsbtInput, // The PSBT input contents
script: Buffer, // The "meaningful" locking script Buffer (redeemScript for P2SH etc.)
isSegwit: boolean, // Is it segwit?
+ isTapscript: boolean, // Is taproot script path?
isP2SH: boolean, // Is it P2SH?
isP2WSH: boolean, // Is it P2WSH?
eccLib?: TinySecp256k1Interface, // optional lib for checking taproot validity
@@ -1237,6 +1234,7 @@ function getFinalScripts(
input: PsbtInput,
script: Buffer,
isSegwit: boolean,
+ isTapscript: boolean,
isP2SH: boolean,
isP2WSH: boolean,
eccLib?: TinySecp256k1Interface,
@@ -1245,7 +1243,7 @@ function getFinalScripts(
finalScriptWitness: Buffer | undefined;
} {
const scriptType = classifyScript(script, eccLib);
- if (!canFinalize(input, script, scriptType))
+ if (isTapscript || !canFinalize(input, script, scriptType))
throw new Error(`Can not finalize input #${inputIndex}`);
return prepareFinalScripts(
script,
From 08cf664c399a482d06eba481289d092029d3f394 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Wed, 9 Mar 2022 23:27:12 +0200
Subject: [PATCH 053/144] fix: fix integration test
---
package-lock.json | 3396 +++++++++++++++++++++++++++++++++-
test/integration/csv.spec.ts | 1 +
2 files changed, 3396 insertions(+), 1 deletion(-)
diff --git a/package-lock.json b/package-lock.json
index 0198cd374..d218ee5c8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,8 +1,3402 @@
{
"name": "bitcoinjs-lib",
"version": "6.0.2",
- "lockfileVersion": 1,
+ "lockfileVersion": 2,
"requires": true,
+ "packages": {
+ "": {
+ "name": "bitcoinjs-lib",
+ "version": "6.0.2",
+ "license": "MIT",
+ "dependencies": {
+ "bech32": "^2.0.0",
+ "bip174": "^2.0.1",
+ "bs58check": "^2.1.2",
+ "create-hash": "^1.1.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",
+ "tiny-secp256k1": "^2.2.0",
+ "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==",
+ "dev": true,
+ "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==",
+ "dev": true,
+ "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": {
"@ampproject/remapping": {
"version": "2.2.0",
diff --git a/test/integration/csv.spec.ts b/test/integration/csv.spec.ts
index 742d68fa1..5e66804d4 100644
--- a/test/integration/csv.spec.ts
+++ b/test/integration/csv.spec.ts
@@ -439,6 +439,7 @@ function csvGetFinalScripts(
input: PsbtInput,
script: Buffer,
isSegwit: boolean,
+ _isTapscript: boolean,
isP2SH: boolean,
isP2WSH: boolean,
): {
From 3e02a63dde4d0fd41097ff64562e3069c753852f Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Wed, 9 Mar 2022 23:28:35 +0200
Subject: [PATCH 054/144] fix: revert package lock version upgrade
---
package-lock.json | 3402 +--------------------------------------------
1 file changed, 4 insertions(+), 3398 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index d218ee5c8..62d5ff8a9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,3402 +1,8 @@
{
"name": "bitcoinjs-lib",
"version": "6.0.2",
- "lockfileVersion": 2,
+ "lockfileVersion": 1,
"requires": true,
- "packages": {
- "": {
- "name": "bitcoinjs-lib",
- "version": "6.0.2",
- "license": "MIT",
- "dependencies": {
- "bech32": "^2.0.0",
- "bip174": "^2.0.1",
- "bs58check": "^2.1.2",
- "create-hash": "^1.1.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",
- "tiny-secp256k1": "^2.2.0",
- "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==",
- "dev": true,
- "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==",
- "dev": true,
- "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": {
"@ampproject/remapping": {
"version": "2.2.0",
@@ -5441,9 +2047,9 @@
"dev": true
},
"pbkdf2": {
- "version": "3.0.17",
- "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz",
- "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==",
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
+ "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==",
"dev": true,
"requires": {
"create-hash": "^1.1.2",
From fde11c92d169133a237b29a4e450aeaca2d0f1b9 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Wed, 9 Mar 2022 23:29:32 +0200
Subject: [PATCH 055/144] refactor: change code to original version
---
src/psbt.js | 5 ++---
ts_src/psbt.ts | 8 +++++---
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/src/psbt.js b/src/psbt.js
index 1d6cad4fd..1307e30f8 100644
--- a/src/psbt.js
+++ b/src/psbt.js
@@ -278,7 +278,7 @@ class Psbt {
range(this.data.inputs.length).forEach(idx => this.finalizeInput(idx));
return this;
}
- finalizeInput(inputIndex, finalScriptsFunc) {
+ finalizeInput(inputIndex, finalScriptsFunc = getFinalScripts) {
const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
const {
script,
@@ -289,8 +289,7 @@ class Psbt {
} = getScriptFromInput(inputIndex, input, this.__CACHE);
if (!script) throw new Error(`No script found for input #${inputIndex}`);
checkPartialSigSighashes(input);
- const fn = finalScriptsFunc || getFinalScripts;
- const { finalScriptSig, finalScriptWitness } = fn(
+ const { finalScriptSig, finalScriptWitness } = finalScriptsFunc(
inputIndex,
input,
script,
diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts
index a906a21c5..cae46aa8c 100644
--- a/ts_src/psbt.ts
+++ b/ts_src/psbt.ts
@@ -351,7 +351,10 @@ export class Psbt {
return this;
}
- finalizeInput(inputIndex: number, finalScriptsFunc?: FinalScriptsFunc): this {
+ finalizeInput(
+ inputIndex: number,
+ finalScriptsFunc: FinalScriptsFunc = getFinalScripts,
+ ): this {
const input = checkForInput(this.data.inputs, inputIndex);
const {
script,
@@ -364,8 +367,7 @@ export class Psbt {
checkPartialSigSighashes(input);
- const fn = finalScriptsFunc || getFinalScripts;
- const { finalScriptSig, finalScriptWitness } = fn(
+ const { finalScriptSig, finalScriptWitness } = finalScriptsFunc(
inputIndex,
input,
script,
From 060630b82f70b0da30839315963ab85479a426f1 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Wed, 9 Mar 2022 23:46:29 +0200
Subject: [PATCH 056/144] fix: make `FinalScriptsFunc` backwards compatible by
moving `isTapscript` param to the end
---
src/psbt.js | 4 ++--
test/integration/csv.spec.ts | 1 -
test/psbt.utils.ts | 2 +-
ts_src/psbt.ts | 4 ++--
4 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/src/psbt.js b/src/psbt.js
index 1307e30f8..6747af981 100644
--- a/src/psbt.js
+++ b/src/psbt.js
@@ -294,9 +294,9 @@ class Psbt {
input,
script,
isSegwit,
- isTapscript,
isP2SH,
isP2WSH,
+ isTapscript,
this.__CACHE.__EC_LIB,
);
if (finalScriptSig) this.data.updateInput(inputIndex, { finalScriptSig });
@@ -932,9 +932,9 @@ function getFinalScripts(
input,
script,
isSegwit,
- isTapscript,
isP2SH,
isP2WSH,
+ isTapscript = false,
eccLib,
) {
const scriptType = classifyScript(script, eccLib);
diff --git a/test/integration/csv.spec.ts b/test/integration/csv.spec.ts
index 5e66804d4..742d68fa1 100644
--- a/test/integration/csv.spec.ts
+++ b/test/integration/csv.spec.ts
@@ -439,7 +439,6 @@ function csvGetFinalScripts(
input: PsbtInput,
script: Buffer,
isSegwit: boolean,
- _isTapscript: boolean,
isP2SH: boolean,
isP2WSH: boolean,
): {
diff --git a/test/psbt.utils.ts b/test/psbt.utils.ts
index aec6ca42d..59cccb323 100644
--- a/test/psbt.utils.ts
+++ b/test/psbt.utils.ts
@@ -17,9 +17,9 @@ const buildTapscriptFinalizer = (
input: PsbtInput,
script: Buffer,
_isSegwit: boolean,
- _isTapscript: boolean,
_isP2SH: boolean,
_isP2WSH: boolean,
+ _isTapscript: boolean,
eccLib?: TinySecp256k1Interface,
): {
finalScriptSig: Buffer | undefined;
diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts
index cae46aa8c..f135173bd 100644
--- a/ts_src/psbt.ts
+++ b/ts_src/psbt.ts
@@ -372,9 +372,9 @@ export class Psbt {
input,
script,
isSegwit,
- isTapscript,
isP2SH,
isP2WSH,
+ isTapscript,
this.__CACHE.__EC_LIB,
);
@@ -1236,9 +1236,9 @@ function getFinalScripts(
input: PsbtInput,
script: Buffer,
isSegwit: boolean,
- isTapscript: boolean,
isP2SH: boolean,
isP2WSH: boolean,
+ isTapscript: boolean = false,
eccLib?: TinySecp256k1Interface,
): {
finalScriptSig: Buffer | undefined;
From b17dc51733b1389295baa87ba8637132c8883451 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Thu, 10 Mar 2022 13:57:43 +0200
Subject: [PATCH 057/144] fix: tap tree branch sorting; improve unit test
---
src/payments/taprootutils.js | 11 ++++-------
test/fixtures/p2tr.json | 28 +++++++++++++++++-----------
ts_src/payments/p2tr.ts | 8 ++++----
ts_src/payments/taprootutils.ts | 12 ++++--------
4 files changed, 29 insertions(+), 30 deletions(-)
diff --git a/src/payments/taprootutils.js b/src/payments/taprootutils.js
index 2a807214d..4d261bcd8 100644
--- a/src/payments/taprootutils.js
+++ b/src/payments/taprootutils.js
@@ -44,14 +44,11 @@ function toHashTree(scriptTree) {
hash: tapLeafHash(script.output, script.version),
};
}
- const left = toHashTree([scriptTree[0]]);
- const right = toHashTree([scriptTree[1]]);
- let leftHash = left.hash;
- let rightHash = right.hash;
- if (leftHash.compare(rightHash) === 1)
- [leftHash, rightHash] = [rightHash, leftHash];
+ let left = toHashTree([scriptTree[0]]);
+ let right = toHashTree([scriptTree[1]]);
+ if (left.hash.compare(right.hash) === 1) [left, right] = [right, left];
return {
- hash: tapBranchHash(leftHash, rightHash),
+ hash: tapBranchHash(left.hash, right.hash),
left,
right,
};
diff --git a/test/fixtures/p2tr.json b/test/fixtures/p2tr.json
index b38bb1776..9bcf1f7c4 100644
--- a/test/fixtures/p2tr.json
+++ b/test/fixtures/p2tr.json
@@ -318,6 +318,9 @@
"description": "address, pubkey, output and hash from internalPubkey and a script tree with seven leafs (2)",
"arguments": {
"internalPubkey": "aba457d16a8d59151c387f24d1eb887efbe24644c1ee64b261282e7baebdb247",
+ "redeem": {
+ "output": "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac4 OP_CHECKSIG"
+ },
"scriptTree": [
{
"output": "00a9da96087a72258f83b338ef7f0ea8cbbe05da5f18f091eb397d1ecbf7c3d3 OP_CHECKSIG"
@@ -325,28 +328,28 @@
[
[
{
- "output": "00a9da96087a72258f83b338ef7f0ea8cbbe05da5f18f091eb397d1ecbf7c3d3 OP_CHECKSIG"
+ "output": "00a9da96087a72258f83b338ef7f0ea8cbbe05da5f18f091eb397d1ecbf7c3d4 OP_CHECKSIG"
},
[
{
- "output": "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0 OP_CHECKSIG"
+ "output": "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac1 OP_CHECKSIG"
},
{
- "output": "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0 OP_CHECKSIG"
+ "output": "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac2 OP_CHECKSIG"
}
]
],
[
[
{
- "output": "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0 OP_CHECKSIG"
+ "output": "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac3 OP_CHECKSIG"
},
{
- "output": "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0 OP_CHECKSIG"
+ "output": "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac4 OP_CHECKSIG"
}
],
{
- "output": "00a9da96087a72258f83b338ef7f0ea8cbbe05da5f18f091eb397d1ecbf7c3d3 OP_CHECKSIG"
+ "output": "00a9da96087a72258f83b338ef7f0ea8cbbe05da5f18f091eb397d1ecbf7c3d5 OP_CHECKSIG"
}
]
]
@@ -354,13 +357,16 @@
},
"expected": {
"name": "p2tr",
- "address": "bc1pmu8qwr9zljs9anger0d6q3uyr43yzjetmjmzf8p93ltycrwj28lsee3e0n",
- "pubkey": "df0e070ca2fca05ecd191bdba047841d62414b2bdcb6249c258fd64c0dd251ff",
- "output": "OP_1 df0e070ca2fca05ecd191bdba047841d62414b2bdcb6249c258fd64c0dd251ff",
- "hash": "027391d0aac8d94725e4fcec4b07214d7c8a14bcdca2b1c08e4bc786308bdae5",
+ "address": "bc1pd2llmtym6c5hyecf5zqsyjz9q0jlxaaksw9j0atx8lc8a0e0vrmsw9ewly",
+ "pubkey": "6abffdac9bd629726709a08102484503e5f377b6838b27f5663ff07ebf2f60f7",
+ "output": "OP_1 6abffdac9bd629726709a08102484503e5f377b6838b27f5663ff07ebf2f60f7",
+ "hash": "88b7e3b495a84aa2bc12780b1773f130ce5eb747b0c28dc4840b7c9280f7326d",
"signature": null,
"input": null,
- "witness": null
+ "witness": [
+ "2050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac4ac",
+ "c0aba457d16a8d59151c387f24d1eb887efbe24644c1ee64b261282e7baebdb247dac795766bbda1eaeaa45e5bfa0a950fdd5f4c4aada5b1f3082edc9689b9fd0a315fb34a7a93dcaed5e26cf7468be5bd377dda7a4d29128f7dd98db6da9bf04325fff3aa86365bac7534dcb6495867109941ec444dd35294e0706e29e051066d73e0d427bd3249bb921fa78c04fb76511f583ff48c97210d17c2d9dcfbb95023"
+ ]
}
},
{
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index 268266e50..0e00417be 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -47,14 +47,14 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
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)),
+ hash: typef.maybe(typef.BufferN(32)), // merkle root hash, the tweak
+ pubkey: typef.maybe(typef.BufferN(32)), // tweaked with `hash` from `internalPubkey`
signature: typef.maybe(typef.BufferN(64)),
witness: typef.maybe(typef.arrayOf(typef.Buffer)),
scriptTree: typef.maybe(isTapTree),
redeem: typef.maybe({
- output: typef.maybe(typef.Buffer),
- redeemVersion: typef.maybe(typef.Number),
+ output: typef.maybe(typef.Buffer), // tapleaf script
+ redeemVersion: typef.maybe(typef.Number), // tapleaf version
witness: typef.maybe(typef.arrayOf(typef.Buffer)),
}),
redeemVersion: typef.maybe(typef.Number),
diff --git a/ts_src/payments/taprootutils.ts b/ts_src/payments/taprootutils.ts
index c71a38b9d..b3636a9c4 100644
--- a/ts_src/payments/taprootutils.ts
+++ b/ts_src/payments/taprootutils.ts
@@ -60,16 +60,12 @@ export function toHashTree(scriptTree: TaprootLeaf[]): HashTree {
};
}
- const left = toHashTree([scriptTree[0]]);
- const right = toHashTree([scriptTree[1]]);
+ let left = toHashTree([scriptTree[0]]);
+ let right = toHashTree([scriptTree[1]]);
- let leftHash = left.hash;
- let rightHash = right.hash;
-
- if (leftHash.compare(rightHash) === 1)
- [leftHash, rightHash] = [rightHash, leftHash];
+ if (left.hash.compare(right.hash) === 1) [left, right] = [right, left];
return {
- hash: tapBranchHash(leftHash, rightHash),
+ hash: tapBranchHash(left.hash, right.hash),
left,
right,
};
From 032201aabe1156812ddaf305b76fa7e0841d8a76 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Fri, 18 Mar 2022 17:41:06 +0200
Subject: [PATCH 058/144] refactor: add Taptree interface
---
src/payments/index.d.ts | 4 ++--
src/payments/taprootutils.d.ts | 8 ++++----
src/payments/taprootutils.js | 2 +-
src/types.d.ts | 3 ++-
ts_src/payments/index.ts | 4 ++--
ts_src/payments/taprootutils.ts | 8 ++++----
ts_src/types.ts | 4 +++-
7 files changed, 18 insertions(+), 15 deletions(-)
diff --git a/src/payments/index.d.ts b/src/payments/index.d.ts
index 386ea3f68..5a71f8cc1 100644
--- a/src/payments/index.d.ts
+++ b/src/payments/index.d.ts
@@ -1,6 +1,6 @@
///
import { Network } from '../networks';
-import { TinySecp256k1Interface, TaprootLeaf } from '../types';
+import { TinySecp256k1Interface, Taptree } from '../types';
import { p2data as embed } from './embed';
import { p2ms } from './p2ms';
import { p2pk } from './p2pk';
@@ -26,7 +26,7 @@ export interface Payment {
hash?: Buffer;
redeem?: Payment;
redeemVersion?: number;
- scriptTree?: TaprootLeaf[];
+ scriptTree?: Taptree;
witness?: Buffer[];
}
export declare type PaymentCreator = (a: Payment, opts?: PaymentOpts) => Payment;
diff --git a/src/payments/taprootutils.d.ts b/src/payments/taprootutils.d.ts
index 82a488530..2bb998c84 100644
--- a/src/payments/taprootutils.d.ts
+++ b/src/payments/taprootutils.d.ts
@@ -1,5 +1,5 @@
///
-import { TaprootLeaf } from '../types';
+import { Taptree } from '../types';
export declare const LEAF_VERSION_TAPSCRIPT = 192;
export declare function rootHashFromPath(controlBlock: Buffer, tapLeafMsg: Buffer): Buffer;
export interface HashTree {
@@ -15,11 +15,11 @@ export interface HashTree {
* - a pair of two taproot leafs [(output, version), (output, version)], or
* - one taproot leaf and a list of elements
*/
-export declare function toHashTree(scriptTree: TaprootLeaf[]): HashTree;
+export declare function toHashTree(scriptTree: Taptree): HashTree;
/**
- * Check if the tree is a binary tree with leafs of type TaprootLeaf
+ * Check if the tree is a binary tree with leafs of type Tapleaf
*/
-export declare function isTapTree(scriptTree: TaprootLeaf[]): boolean;
+export declare function isTapTree(scriptTree: Taptree): boolean;
/**
* Given a MAST tree, it finds the path of a particular hash.
* @param node - the root of the tree
diff --git a/src/payments/taprootutils.js b/src/payments/taprootutils.js
index 4d261bcd8..d9221fc33 100644
--- a/src/payments/taprootutils.js
+++ b/src/payments/taprootutils.js
@@ -55,7 +55,7 @@ function toHashTree(scriptTree) {
}
exports.toHashTree = toHashTree;
/**
- * Check if the tree is a binary tree with leafs of type TaprootLeaf
+ * Check if the tree is a binary tree with leafs of type Tapleaf
*/
function isTapTree(scriptTree) {
if (scriptTree.length > 2) return false;
diff --git a/src/types.d.ts b/src/types.d.ts
index 5ddded9a2..9b62b4933 100644
--- a/src/types.d.ts
+++ b/src/types.d.ts
@@ -14,10 +14,11 @@ export interface XOnlyPointAddTweakResult {
parity: 1 | 0;
xOnlyPubkey: Uint8Array;
}
-export interface TaprootLeaf {
+export interface Tapleaf {
output: Buffer;
version?: number;
}
+export declare type Taptree = Array<[Tapleaf, Tapleaf] | Tapleaf>;
export interface TinySecp256k1Interface {
isXOnlyPoint(p: Uint8Array): boolean;
xOnlyPointAddTweak(p: Uint8Array, tweak: Uint8Array): XOnlyPointAddTweakResult | null;
diff --git a/ts_src/payments/index.ts b/ts_src/payments/index.ts
index 90f5403c5..70d7614b7 100644
--- a/ts_src/payments/index.ts
+++ b/ts_src/payments/index.ts
@@ -1,5 +1,5 @@
import { Network } from '../networks';
-import { TinySecp256k1Interface, TaprootLeaf } from '../types';
+import { TinySecp256k1Interface, Taptree } from '../types';
import { p2data as embed } from './embed';
import { p2ms } from './p2ms';
import { p2pk } from './p2pk';
@@ -26,7 +26,7 @@ export interface Payment {
hash?: Buffer;
redeem?: Payment;
redeemVersion?: number;
- scriptTree?: TaprootLeaf[];
+ scriptTree?: Taptree;
witness?: Buffer[];
}
diff --git a/ts_src/payments/taprootutils.ts b/ts_src/payments/taprootutils.ts
index b3636a9c4..cfa7a6dd2 100644
--- a/ts_src/payments/taprootutils.ts
+++ b/ts_src/payments/taprootutils.ts
@@ -2,7 +2,7 @@ import { Buffer as NBuffer } from 'buffer';
import * as bcrypto from '../crypto';
import { varuint } from '../bufferutils';
-import { TaprootLeaf } from '../types';
+import { Taptree } from '../types';
const TAP_LEAF_TAG = 'TapLeaf';
const TAP_BRANCH_TAG = 'TapBranch';
@@ -45,7 +45,7 @@ export interface HashTree {
* - a pair of two taproot leafs [(output, version), (output, version)], or
* - one taproot leaf and a list of elements
*/
-export function toHashTree(scriptTree: TaprootLeaf[]): HashTree {
+export function toHashTree(scriptTree: Taptree): HashTree {
if (scriptTree.length === 1) {
const script = scriptTree[0];
if (Array.isArray(script)) {
@@ -71,9 +71,9 @@ export function toHashTree(scriptTree: TaprootLeaf[]): HashTree {
};
}
/**
- * Check if the tree is a binary tree with leafs of type TaprootLeaf
+ * Check if the tree is a binary tree with leafs of type Tapleaf
*/
-export function isTapTree(scriptTree: TaprootLeaf[]): boolean {
+export function isTapTree(scriptTree: Taptree): boolean {
if (scriptTree.length > 2) return false;
if (scriptTree.length === 1) {
const script = scriptTree[0];
diff --git a/ts_src/types.ts b/ts_src/types.ts
index fad2bc29c..59e4e1929 100644
--- a/ts_src/types.ts
+++ b/ts_src/types.ts
@@ -72,11 +72,13 @@ export interface XOnlyPointAddTweakResult {
xOnlyPubkey: Uint8Array;
}
-export interface TaprootLeaf {
+export interface Tapleaf {
output: Buffer;
version?: number;
}
+export type Taptree = Array<[Tapleaf, Tapleaf] | Tapleaf>;
+
export interface TinySecp256k1Interface {
isXOnlyPoint(p: Uint8Array): boolean;
xOnlyPointAddTweak(
From fee9fa14c2efc0e8f1d9bea3309d8ed78507fc7e Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Fri, 18 Mar 2022 17:43:17 +0200
Subject: [PATCH 059/144] refactor: rename `testecc` to `verifyecc` (avoid
confusing it with unit tests)
---
src/payments/p2tr.js | 4 ++--
src/payments/testecc.d.ts | 2 --
src/payments/verifyecc.d.ts | 2 ++
src/payments/{testecc.js => verifyecc.js} | 6 +++---
ts_src/payments/p2tr.ts | 4 ++--
ts_src/payments/{testecc.ts => verifyecc.ts} | 2 +-
6 files changed, 10 insertions(+), 10 deletions(-)
delete mode 100644 src/payments/testecc.d.ts
create mode 100644 src/payments/verifyecc.d.ts
rename src/payments/{testecc.js => verifyecc.js} (96%)
rename ts_src/payments/{testecc.ts => verifyecc.ts} (97%)
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index d4406c2b2..13f283ed8 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -8,7 +8,7 @@ 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 verifyecc_1 = require('./verifyecc');
const OPS = bscript.OPS;
const TAPROOT_WITNESS_VERSION = 0x01;
const ANNEX_PREFIX = 0x50;
@@ -25,7 +25,7 @@ function p2tr(a, opts) {
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);
+ (0, verifyecc_1.verifyEcc)(opts.eccLib);
return opts.eccLib;
});
(0, types_1.typeforce)(
diff --git a/src/payments/testecc.d.ts b/src/payments/testecc.d.ts
deleted file mode 100644
index 59d0de2b2..000000000
--- a/src/payments/testecc.d.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-import { TinySecp256k1Interface } from '../types';
-export declare function testEcc(ecc: TinySecp256k1Interface): void;
diff --git a/src/payments/verifyecc.d.ts b/src/payments/verifyecc.d.ts
new file mode 100644
index 000000000..0f23affa7
--- /dev/null
+++ b/src/payments/verifyecc.d.ts
@@ -0,0 +1,2 @@
+import { TinySecp256k1Interface } from '../types';
+export declare function verifyEcc(ecc: TinySecp256k1Interface): void;
diff --git a/src/payments/testecc.js b/src/payments/verifyecc.js
similarity index 96%
rename from src/payments/testecc.js
rename to src/payments/verifyecc.js
index 44e19c887..9a1eebd64 100644
--- a/src/payments/testecc.js
+++ b/src/payments/verifyecc.js
@@ -1,8 +1,8 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.testEcc = void 0;
+exports.verifyEcc = void 0;
const h = hex => Buffer.from(hex, 'hex');
-function testEcc(ecc) {
+function verifyEcc(ecc) {
assert(typeof ecc.isXOnlyPoint === 'function');
assert(
ecc.isXOnlyPoint(
@@ -46,7 +46,7 @@ function testEcc(ecc) {
}
});
}
-exports.testEcc = testEcc;
+exports.verifyEcc = verifyEcc;
function assert(bool) {
if (!bool) throw new Error('ecc library invalid');
}
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index 0e00417be..2c7d8557a 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -14,7 +14,7 @@ import {
import { Payment, PaymentOpts } from './index';
import * as lazy from './lazy';
import { bech32m } from 'bech32';
-import { testEcc } from './testecc';
+import { verifyEcc } from './verifyecc';
const OPS = bscript.OPS;
const TAPROOT_WITNESS_VERSION = 0x01;
@@ -36,7 +36,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
const _ecc = lazy.value(() => {
if (!opts!.eccLib) throw new Error('ECC Library is missing for p2tr.');
- testEcc(opts!.eccLib);
+ verifyEcc(opts!.eccLib);
return opts!.eccLib;
});
diff --git a/ts_src/payments/testecc.ts b/ts_src/payments/verifyecc.ts
similarity index 97%
rename from ts_src/payments/testecc.ts
rename to ts_src/payments/verifyecc.ts
index 382d6149a..75c2c5062 100644
--- a/ts_src/payments/testecc.ts
+++ b/ts_src/payments/verifyecc.ts
@@ -2,7 +2,7 @@ import { TinySecp256k1Interface } from '../types';
const h = (hex: string): Buffer => Buffer.from(hex, 'hex');
-export function testEcc(ecc: TinySecp256k1Interface): void {
+export function verifyEcc(ecc: TinySecp256k1Interface): void {
assert(typeof ecc.isXOnlyPoint === 'function');
assert(
ecc.isXOnlyPoint(
From 67028cfb1deae797905541378b18e6b5cd992dbd Mon Sep 17 00:00:00 2001
From: Brandon Black
Date: Fri, 18 Mar 2022 15:11:14 -0700
Subject: [PATCH 060/144] Declare tapscript version mask like the BIP
---
src/payments/p2tr.js | 2 +-
ts_src/payments/p2tr.ts | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index 13f283ed8..bab9fcd4e 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -12,7 +12,7 @@ const verifyecc_1 = require('./verifyecc');
const OPS = bscript.OPS;
const TAPROOT_WITNESS_VERSION = 0x01;
const ANNEX_PREFIX = 0x50;
-const LEAF_VERSION_MASK = 0b11111110;
+const LEAF_VERSION_MASK = 0xfe;
function p2tr(a, opts) {
if (
!a.address &&
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index 2c7d8557a..04d0f1d11 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -19,7 +19,7 @@ import { verifyEcc } from './verifyecc';
const OPS = bscript.OPS;
const TAPROOT_WITNESS_VERSION = 0x01;
const ANNEX_PREFIX = 0x50;
-const LEAF_VERSION_MASK = 0b11111110;
+const LEAF_VERSION_MASK = 0xfe;
export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
if (
From da61c66bd4678aff83a1f852e8c74d2b12f7aaff Mon Sep 17 00:00:00 2001
From: Brandon Black
Date: Fri, 18 Mar 2022 12:54:52 -0700
Subject: [PATCH 061/144] Correct Taptree type
* Move the (much simplified) type check function to types.ts
* Use `Tapleaf` type a bit more (this might be a bad idea)
* Be more consistent in the capitalization of `Taptree`
---
src/payments/p2tr.js | 28 +++++++++++-------
src/payments/taprootutils.d.ts | 8 ++---
src/payments/taprootutils.js | 49 +++++++------------------------
src/psbt.js | 2 +-
src/types.d.ts | 5 +++-
src/types.js | 17 ++++++++++-
test/fixtures/p2tr.json | 42 +++++++++++----------------
test/integration/taproot.spec.ts | 15 +++++-----
ts_src/payments/p2tr.ts | 26 ++++++++++-------
ts_src/payments/taprootutils.ts | 50 +++++---------------------------
ts_src/psbt.ts | 2 +-
ts_src/types.ts | 17 ++++++++++-
12 files changed, 115 insertions(+), 146 deletions(-)
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index bab9fcd4e..7f60e21ff 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -12,7 +12,6 @@ const verifyecc_1 = require('./verifyecc');
const OPS = bscript.OPS;
const TAPROOT_WITNESS_VERSION = 0x01;
const ANNEX_PREFIX = 0x50;
-const LEAF_VERSION_MASK = 0xfe;
function p2tr(a, opts) {
if (
!a.address &&
@@ -41,7 +40,7 @@ function p2tr(a, opts) {
witness: types_1.typeforce.maybe(
types_1.typeforce.arrayOf(types_1.typeforce.Buffer),
),
- scriptTree: types_1.typeforce.maybe(taprootutils_1.isTapTree),
+ scriptTree: types_1.typeforce.maybe(types_1.isTaptree),
redeem: types_1.typeforce.maybe({
output: types_1.typeforce.maybe(types_1.typeforce.Buffer),
redeemVersion: types_1.typeforce.maybe(types_1.typeforce.Number),
@@ -88,9 +87,12 @@ function p2tr(a, opts) {
const w = _witness();
if (w && w.length > 1) {
const controlBlock = w[w.length - 1];
- const leafVersion = controlBlock[0] & LEAF_VERSION_MASK;
+ const leafVersion = controlBlock[0] & types_1.TAPLEAF_VERSION_MASK;
const script = w[w.length - 2];
- const leafHash = (0, taprootutils_1.tapLeafHash)(script, leafVersion);
+ const leafHash = (0, taprootutils_1.tapLeafHash)({
+ output: script,
+ version: leafVersion,
+ });
return (0, taprootutils_1.rootHashFromPath)(controlBlock, leafHash);
}
return null;
@@ -116,7 +118,8 @@ function p2tr(a, opts) {
return {
output: witness[witness.length - 2],
witness: witness.slice(0, -2),
- redeemVersion: witness[witness.length - 1][0] & LEAF_VERSION_MASK,
+ redeemVersion:
+ witness[witness.length - 1][0] & types_1.TAPLEAF_VERSION_MASK,
};
});
lazy.prop(o, 'pubkey', () => {
@@ -144,10 +147,10 @@ function p2tr(a, opts) {
if (a.scriptTree && a.redeem && a.redeem.output && a.internalPubkey) {
// todo: optimize/cache
const hashTree = (0, taprootutils_1.toHashTree)(a.scriptTree);
- const leafHash = (0, taprootutils_1.tapLeafHash)(
- a.redeem.output,
- o.redeemVersion,
- );
+ const leafHash = (0, taprootutils_1.tapLeafHash)({
+ output: a.redeem.output,
+ version: o.redeemVersion,
+ });
const path = (0, taprootutils_1.findScriptPath)(hashTree, leafHash);
const outputKey = tweakKey(a.internalPubkey, hashTree.hash, _ecc());
if (!outputKey) return;
@@ -253,9 +256,12 @@ function p2tr(a, opts) {
throw new TypeError('Internal pubkey mismatch');
if (!_ecc().isXOnlyPoint(internalPubkey))
throw new TypeError('Invalid internalPubkey for p2tr witness');
- const leafVersion = controlBlock[0] & LEAF_VERSION_MASK;
+ const leafVersion = controlBlock[0] & types_1.TAPLEAF_VERSION_MASK;
const script = witness[witness.length - 2];
- const leafHash = (0, taprootutils_1.tapLeafHash)(script, leafVersion);
+ const leafHash = (0, taprootutils_1.tapLeafHash)({
+ output: script,
+ version: leafVersion,
+ });
const hash = (0, taprootutils_1.rootHashFromPath)(
controlBlock,
leafHash,
diff --git a/src/payments/taprootutils.d.ts b/src/payments/taprootutils.d.ts
index 2bb998c84..c1181743c 100644
--- a/src/payments/taprootutils.d.ts
+++ b/src/payments/taprootutils.d.ts
@@ -1,5 +1,5 @@
///
-import { Taptree } from '../types';
+import { Tapleaf, Taptree } from '../types';
export declare const LEAF_VERSION_TAPSCRIPT = 192;
export declare function rootHashFromPath(controlBlock: Buffer, tapLeafMsg: Buffer): Buffer;
export interface HashTree {
@@ -16,10 +16,6 @@ export interface HashTree {
* - one taproot leaf and a list of elements
*/
export declare function toHashTree(scriptTree: Taptree): HashTree;
-/**
- * Check if the tree is a binary tree with leafs of type Tapleaf
- */
-export declare function isTapTree(scriptTree: Taptree): boolean;
/**
* Given a MAST tree, it finds the path of a particular hash.
* @param node - the root of the tree
@@ -27,5 +23,5 @@ export declare function isTapTree(scriptTree: Taptree): boolean;
* @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 tapLeafHash(leaf: Tapleaf): Buffer;
export declare function tapTweakHash(pubKey: Buffer, h: Buffer | undefined): Buffer;
diff --git a/src/payments/taprootutils.js b/src/payments/taprootutils.js
index d9221fc33..9cb88ace4 100644
--- a/src/payments/taprootutils.js
+++ b/src/payments/taprootutils.js
@@ -1,9 +1,10 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.tapTweakHash = exports.tapLeafHash = exports.findScriptPath = exports.isTapTree = exports.toHashTree = exports.rootHashFromPath = exports.LEAF_VERSION_TAPSCRIPT = void 0;
+exports.tapTweakHash = exports.tapLeafHash = exports.findScriptPath = exports.toHashTree = exports.rootHashFromPath = exports.LEAF_VERSION_TAPSCRIPT = void 0;
const buffer_1 = require('buffer');
const bcrypto = require('../crypto');
const bufferutils_1 = require('../bufferutils');
+const types_1 = require('../types');
const TAP_LEAF_TAG = 'TapLeaf';
const TAP_BRANCH_TAG = 'TapBranch';
const TAP_TWEAK_TAG = 'TapTweak';
@@ -32,21 +33,11 @@ exports.rootHashFromPath = rootHashFromPath;
* - one taproot leaf and a list of elements
*/
function toHashTree(scriptTree) {
- if (scriptTree.length === 1) {
- const script = scriptTree[0];
- if (Array.isArray(script)) {
- return toHashTree(script);
- }
- script.version = script.version || exports.LEAF_VERSION_TAPSCRIPT;
- if ((script.version & 1) !== 0)
- throw new TypeError('Invalid script version');
- return {
- hash: tapLeafHash(script.output, script.version),
- };
- }
- let left = toHashTree([scriptTree[0]]);
- let right = toHashTree([scriptTree[1]]);
- if (left.hash.compare(right.hash) === 1) [left, right] = [right, left];
+ if ((0, types_1.isTapleaf)(scriptTree))
+ return { hash: tapLeafHash(scriptTree) };
+ const hashes = [toHashTree(scriptTree[0]), toHashTree(scriptTree[1])];
+ hashes.sort((a, b) => a.hash.compare(b.hash));
+ const [left, right] = hashes;
return {
hash: tapBranchHash(left.hash, right.hash),
left,
@@ -54,26 +45,6 @@ function toHashTree(scriptTree) {
};
}
exports.toHashTree = toHashTree;
-/**
- * Check if the tree is a binary tree with leafs of type Tapleaf
- */
-function isTapTree(scriptTree) {
- if (scriptTree.length > 2) return false;
- if (scriptTree.length === 1) {
- const script = scriptTree[0];
- if (Array.isArray(script)) {
- return isTapTree(script);
- }
- if (!script.output) return false;
- script.version = script.version || exports.LEAF_VERSION_TAPSCRIPT;
- if ((script.version & 1) !== 0) return false;
- return true;
- }
- if (!isTapTree([scriptTree[0]])) return false;
- if (!isTapTree([scriptTree[1]])) return false;
- return true;
-}
-exports.isTapTree = isTapTree;
/**
* Given a MAST tree, it finds the path of a particular hash.
* @param node - the root of the tree
@@ -96,13 +67,13 @@ function findScriptPath(node, hash) {
return [];
}
exports.findScriptPath = findScriptPath;
-function tapLeafHash(script, version) {
- version = version || exports.LEAF_VERSION_TAPSCRIPT;
+function tapLeafHash(leaf) {
+ const version = leaf.version || exports.LEAF_VERSION_TAPSCRIPT;
return bcrypto.taggedHash(
TAP_LEAF_TAG,
buffer_1.Buffer.concat([
buffer_1.Buffer.from([version]),
- serializeScript(script),
+ serializeScript(leaf.output),
]),
);
}
diff --git a/src/psbt.js b/src/psbt.js
index 6747af981..8f46a2718 100644
--- a/src/psbt.js
+++ b/src/psbt.js
@@ -1079,7 +1079,7 @@ function getHashForSig(
const signingScripts = prevOuts.map(o => o.script);
const values = prevOuts.map(o => o.value);
const leafHash = input.witnessScript
- ? (0, taprootutils_1.tapLeafHash)(input.witnessScript)
+ ? (0, taprootutils_1.tapLeafHash)({ output: input.witnessScript })
: undefined;
hash = unsignedTx.hashForWitnessV1(
inputIndex,
diff --git a/src/types.d.ts b/src/types.d.ts
index 9b62b4933..c8048c29a 100644
--- a/src/types.d.ts
+++ b/src/types.d.ts
@@ -18,7 +18,10 @@ export interface Tapleaf {
output: Buffer;
version?: number;
}
-export declare type Taptree = Array<[Tapleaf, Tapleaf] | Tapleaf>;
+export declare const TAPLEAF_VERSION_MASK = 254;
+export declare function isTapleaf(o: any): o is Tapleaf;
+export declare type Taptree = [Taptree | Tapleaf, Taptree | Tapleaf] | Tapleaf;
+export declare function isTaptree(scriptTree: any): scriptTree is Taptree;
export interface TinySecp256k1Interface {
isXOnlyPoint(p: Uint8Array): boolean;
xOnlyPointAddTweak(p: Uint8Array, tweak: Uint8Array): XOnlyPointAddTweakResult | null;
diff --git a/src/types.js b/src/types.js
index a6d1efa16..e1d0a528d 100644
--- a/src/types.js
+++ b/src/types.js
@@ -1,6 +1,6 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.oneOf = exports.Null = exports.BufferN = exports.Function = exports.UInt32 = exports.UInt8 = exports.tuple = exports.maybe = exports.Hex = exports.Buffer = exports.String = exports.Boolean = exports.Array = exports.Number = exports.Hash256bit = exports.Hash160bit = exports.Buffer256bit = exports.Network = exports.ECPoint = exports.Satoshi = exports.Signer = exports.BIP32Path = exports.UInt31 = exports.isPoint = exports.typeforce = void 0;
+exports.oneOf = exports.Null = exports.BufferN = exports.Function = exports.UInt32 = exports.UInt8 = exports.tuple = exports.maybe = exports.Hex = exports.Buffer = exports.String = exports.Boolean = exports.Array = exports.Number = exports.Hash256bit = exports.Hash160bit = exports.Buffer256bit = exports.isTaptree = exports.isTapleaf = exports.TAPLEAF_VERSION_MASK = exports.Network = exports.ECPoint = exports.Satoshi = exports.Signer = exports.BIP32Path = exports.UInt31 = exports.isPoint = exports.typeforce = void 0;
const buffer_1 = require('buffer');
exports.typeforce = require('typeforce');
const ZERO32 = buffer_1.Buffer.alloc(32, 0);
@@ -68,6 +68,21 @@ exports.Network = exports.typeforce.compile({
scriptHash: exports.typeforce.UInt8,
wif: exports.typeforce.UInt8,
});
+exports.TAPLEAF_VERSION_MASK = 0xfe;
+function isTapleaf(o) {
+ if (!('output' in o)) return false;
+ if (!buffer_1.Buffer.isBuffer(o.output)) return false;
+ if (o.version !== undefined)
+ return (o.version & exports.TAPLEAF_VERSION_MASK) === o.version;
+ return true;
+}
+exports.isTapleaf = isTapleaf;
+function isTaptree(scriptTree) {
+ if (!(0, exports.Array)(scriptTree)) return isTapleaf(scriptTree);
+ if (scriptTree.length !== 2) return false;
+ return scriptTree.every(t => isTaptree(t));
+}
+exports.isTaptree = isTaptree;
exports.Buffer256bit = exports.typeforce.BufferN(32);
exports.Hash160bit = exports.typeforce.BufferN(20);
exports.Hash256bit = exports.typeforce.BufferN(32);
diff --git a/test/fixtures/p2tr.json b/test/fixtures/p2tr.json
index 9bcf1f7c4..75e0456ab 100644
--- a/test/fixtures/p2tr.json
+++ b/test/fixtures/p2tr.json
@@ -161,11 +161,9 @@
"description": "address, pubkey, output and hash from internalPubkey and a script tree with one leaf",
"arguments": {
"internalPubkey": "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0",
- "scriptTree": [
- {
- "output": "83d8ee77a0f3a32a5cea96fd1624d623b836c1e5d1ac2dcde46814b619320c18 OP_CHECKSIG"
- }
- ]
+ "scriptTree": {
+ "output": "83d8ee77a0f3a32a5cea96fd1624d623b836c1e5d1ac2dcde46814b619320c18 OP_CHECKSIG"
+ }
},
"expected": {
"name": "p2tr",
@@ -393,12 +391,10 @@
"output": "d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8 OP_CHECKSIG",
"redeemVersion": 192
},
- "scriptTree": [
- {
- "output": "d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8 OP_CHECKSIG",
- "version": 192
- }
- ]
+ "scriptTree": {
+ "output": "d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8 OP_CHECKSIG",
+ "version": 192
+ }
},
"options": {},
"expected": {
@@ -427,12 +423,10 @@
"output": "b617298552a72ade070667e86ca63b8f5789a9fe8731ef91202a91c9f3459007 OP_CHECKSIG",
"redeemVersion": 192
},
- "scriptTree": [
- {
- "output": "b617298552a72ade070667e86ca63b8f5789a9fe8731ef91202a91c9f3459007 OP_CHECKSIG",
- "version": 192
- }
- ]
+ "scriptTree": {
+ "output": "b617298552a72ade070667e86ca63b8f5789a9fe8731ef91202a91c9f3459007 OP_CHECKSIG",
+ "version": 192
+ }
},
"options": {},
"expected": {
@@ -906,11 +900,9 @@
"options": {},
"arguments": {
"internalPubkey": "9fa5ffb68821cf559001caa0577eeea4978b29416def328a707b15e91701a2f7",
- "scriptTree": [
- {
- "output": "83d8ee77a0f3a32a5cea96fd1624d623b836c1e5d1ac2dcde46814b619320c18 OP_CHECKSIG"
- }
- ],
+ "scriptTree": {
+ "output": "83d8ee77a0f3a32a5cea96fd1624d623b836c1e5d1ac2dcde46814b619320c18 OP_CHECKSIG"
+ },
"hash": "b76077013c8e303085e300000000000000000000000000000000000000000000"
}
},
@@ -1037,7 +1029,7 @@
},
{
"description": "Script Tree is not a binary tree (has tree leafs)",
- "exception": "property \"scriptTree\" of type \\?isTapTree, got Array",
+ "exception": "property \"scriptTree\" of type \\?isTaptree, got Array",
"options": {},
"arguments": {
"internalPubkey": "9fa5ffb68821cf559001caa0577eeea4978b29416def328a707b15e91701a2f7",
@@ -1066,7 +1058,7 @@
},
{
"description": "Script Tree is not a TapTree tree (leaf has no script)",
- "exception": "property \"scriptTree\" of type \\?isTapTree, got Array",
+ "exception": "property \"scriptTree\" of type \\?isTaptree, got Array",
"options": {},
"arguments": {
"internalPubkey": "9fa5ffb68821cf559001caa0577eeea4978b29416def328a707b15e91701a2f7",
@@ -1167,4 +1159,4 @@
"depends": {},
"details": []
}
-}
\ No newline at end of file
+}
diff --git a/test/integration/taproot.spec.ts b/test/integration/taproot.spec.ts
index 90dacb63d..05d7d154d 100644
--- a/test/integration/taproot.spec.ts
+++ b/test/integration/taproot.spec.ts
@@ -4,6 +4,7 @@ import * as ecc from 'tiny-secp256k1';
import { describe, it } from 'mocha';
import { regtestUtils } from './_regtest';
import * as bitcoin from '../..';
+import { Taptree } from '../../src/types';
import { buildTapscriptFinalizer, toXOnly } from '../psbt.utils';
const rng = require('randombytes');
@@ -97,11 +98,9 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
)} OP_CHECKSIG`;
const leafScript = bitcoin.script.fromASM(leafScriptAsm);
- const scriptTree = [
- {
- output: leafScript,
- },
- ];
+ const scriptTree = {
+ output: leafScript,
+ };
const { output, address, hash } = bitcoin.payments.p2tr(
{
@@ -157,7 +156,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
)} OP_CHECKSIG`;
const leafScript = bitcoin.script.fromASM(leafScriptAsm);
- const scriptTree: any[] = [
+ const scriptTree: Taptree = [
[
{
output: bitcoin.script.fromASM(
@@ -262,7 +261,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
const leafScriptAsm = `OP_10 OP_CHECKSEQUENCEVERIFY OP_DROP ${leafPubkey} OP_CHECKSIG`;
const leafScript = bitcoin.script.fromASM(leafScriptAsm);
- const scriptTree: any[] = [
+ const scriptTree: Taptree = [
{
output: bitcoin.script.fromASM(
'50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0 OP_CHECKSIG',
@@ -361,7 +360,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
const leafScript = bitcoin.script.fromASM(leafScriptAsm);
- const scriptTree: any[] = [
+ const scriptTree: Taptree = [
{
output: bitcoin.script.fromASM(
'50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0 OP_CHECKSIG',
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index 04d0f1d11..b298e2ba2 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -1,14 +1,18 @@
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 {
+ typeforce as typef,
+ isTaptree,
+ TinySecp256k1Interface,
+ TAPLEAF_VERSION_MASK,
+} from '../types';
import {
toHashTree,
rootHashFromPath,
findScriptPath,
tapLeafHash,
tapTweakHash,
- isTapTree,
LEAF_VERSION_TAPSCRIPT,
} from './taprootutils';
import { Payment, PaymentOpts } from './index';
@@ -19,7 +23,6 @@ import { verifyEcc } from './verifyecc';
const OPS = bscript.OPS;
const TAPROOT_WITNESS_VERSION = 0x01;
const ANNEX_PREFIX = 0x50;
-const LEAF_VERSION_MASK = 0xfe;
export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
if (
@@ -51,7 +54,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
pubkey: typef.maybe(typef.BufferN(32)), // tweaked with `hash` from `internalPubkey`
signature: typef.maybe(typef.BufferN(64)),
witness: typef.maybe(typef.arrayOf(typef.Buffer)),
- scriptTree: typef.maybe(isTapTree),
+ scriptTree: typef.maybe(isTaptree),
redeem: typef.maybe({
output: typef.maybe(typef.Buffer), // tapleaf script
redeemVersion: typef.maybe(typef.Number), // tapleaf version
@@ -102,9 +105,9 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
const w = _witness();
if (w && w.length > 1) {
const controlBlock = w[w.length - 1];
- const leafVersion = controlBlock[0] & LEAF_VERSION_MASK;
+ const leafVersion = controlBlock[0] & TAPLEAF_VERSION_MASK;
const script = w[w.length - 2];
- const leafHash = tapLeafHash(script, leafVersion);
+ const leafHash = tapLeafHash({ output: script, version: leafVersion });
return rootHashFromPath(controlBlock, leafHash);
}
return null;
@@ -132,7 +135,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
return {
output: witness[witness.length - 2],
witness: witness.slice(0, -2),
- redeemVersion: witness[witness.length - 1][0] & LEAF_VERSION_MASK,
+ redeemVersion: witness[witness.length - 1][0] & TAPLEAF_VERSION_MASK,
};
});
lazy.prop(o, 'pubkey', () => {
@@ -161,7 +164,10 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
if (a.scriptTree && a.redeem && a.redeem.output && a.internalPubkey) {
// todo: optimize/cache
const hashTree = toHashTree(a.scriptTree);
- const leafHash = tapLeafHash(a.redeem.output, o.redeemVersion);
+ const leafHash = tapLeafHash({
+ output: a.redeem.output,
+ version: o.redeemVersion,
+ });
const path = findScriptPath(hashTree, leafHash);
const outputKey = tweakKey(a.internalPubkey, hashTree.hash, _ecc());
if (!outputKey) return;
@@ -283,10 +289,10 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
if (!_ecc().isXOnlyPoint(internalPubkey))
throw new TypeError('Invalid internalPubkey for p2tr witness');
- const leafVersion = controlBlock[0] & LEAF_VERSION_MASK;
+ const leafVersion = controlBlock[0] & TAPLEAF_VERSION_MASK;
const script = witness[witness.length - 2];
- const leafHash = tapLeafHash(script, leafVersion);
+ const leafHash = tapLeafHash({ output: script, version: leafVersion });
const hash = rootHashFromPath(controlBlock, leafHash);
const outputKey = tweakKey(internalPubkey, hash, _ecc());
diff --git a/ts_src/payments/taprootutils.ts b/ts_src/payments/taprootutils.ts
index cfa7a6dd2..48d08e617 100644
--- a/ts_src/payments/taprootutils.ts
+++ b/ts_src/payments/taprootutils.ts
@@ -2,7 +2,7 @@ import { Buffer as NBuffer } from 'buffer';
import * as bcrypto from '../crypto';
import { varuint } from '../bufferutils';
-import { Taptree } from '../types';
+import { Tapleaf, Taptree, isTapleaf } from '../types';
const TAP_LEAF_TAG = 'TapLeaf';
const TAP_BRANCH_TAG = 'TapBranch';
@@ -46,52 +46,18 @@ export interface HashTree {
* - one taproot leaf and a list of elements
*/
export function toHashTree(scriptTree: Taptree): HashTree {
- if (scriptTree.length === 1) {
- const script = scriptTree[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),
- };
- }
+ if (isTapleaf(scriptTree)) return { hash: tapLeafHash(scriptTree) };
- let left = toHashTree([scriptTree[0]]);
- let right = toHashTree([scriptTree[1]]);
+ const hashes = [toHashTree(scriptTree[0]), toHashTree(scriptTree[1])];
+ hashes.sort((a, b) => a.hash.compare(b.hash));
+ const [left, right] = hashes;
- if (left.hash.compare(right.hash) === 1) [left, right] = [right, left];
return {
hash: tapBranchHash(left.hash, right.hash),
left,
right,
};
}
-/**
- * Check if the tree is a binary tree with leafs of type Tapleaf
- */
-export function isTapTree(scriptTree: Taptree): boolean {
- if (scriptTree.length > 2) return false;
- if (scriptTree.length === 1) {
- const script = scriptTree[0];
- if (Array.isArray(script)) {
- return isTapTree(script);
- }
- if (!script.output) return false;
- script.version = script.version || LEAF_VERSION_TAPSCRIPT;
- if ((script.version & 1) !== 0) return false;
-
- return true;
- }
-
- if (!isTapTree([scriptTree[0]])) return false;
- if (!isTapTree([scriptTree[1]])) return false;
-
- return true;
-}
/**
* Given a MAST tree, it finds the path of a particular hash.
@@ -117,11 +83,11 @@ export function findScriptPath(node: HashTree, hash: Buffer): Buffer[] {
return [];
}
-export function tapLeafHash(script: Buffer, version?: number): Buffer {
- version = version || LEAF_VERSION_TAPSCRIPT;
+export function tapLeafHash(leaf: Tapleaf): Buffer {
+ const version = leaf.version || LEAF_VERSION_TAPSCRIPT;
return bcrypto.taggedHash(
TAP_LEAF_TAG,
- NBuffer.concat([NBuffer.from([version]), serializeScript(script)]),
+ NBuffer.concat([NBuffer.from([version]), serializeScript(leaf.output)]),
);
}
diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts
index f135173bd..7a64c3e02 100644
--- a/ts_src/psbt.ts
+++ b/ts_src/psbt.ts
@@ -1406,7 +1406,7 @@ function getHashForSig(
const signingScripts: any = prevOuts.map(o => o.script);
const values: any = prevOuts.map(o => o.value);
const leafHash = input.witnessScript
- ? tapLeafHash(input.witnessScript)
+ ? tapLeafHash({ output: input.witnessScript })
: undefined;
hash = unsignedTx.hashForWitnessV1(
diff --git a/ts_src/types.ts b/ts_src/types.ts
index 59e4e1929..1e49361b6 100644
--- a/ts_src/types.ts
+++ b/ts_src/types.ts
@@ -77,7 +77,22 @@ export interface Tapleaf {
version?: number;
}
-export type Taptree = Array<[Tapleaf, Tapleaf] | Tapleaf>;
+export const TAPLEAF_VERSION_MASK = 0xfe;
+export function isTapleaf(o: any): o is Tapleaf {
+ if (!('output' in o)) return false;
+ if (!NBuffer.isBuffer(o.output)) return false;
+ if (o.version !== undefined)
+ return (o.version & TAPLEAF_VERSION_MASK) === o.version;
+ return true;
+}
+
+export type Taptree = [Taptree | Tapleaf, Taptree | Tapleaf] | Tapleaf;
+
+export function isTaptree(scriptTree: any): scriptTree is Taptree {
+ if (!Array(scriptTree)) return isTapleaf(scriptTree);
+ if (scriptTree.length !== 2) return false;
+ return scriptTree.every((t: any) => isTaptree(t));
+}
export interface TinySecp256k1Interface {
isXOnlyPoint(p: Uint8Array): boolean;
From d29ada65ae456995fa6833544e304e708651fe40 Mon Sep 17 00:00:00 2001
From: Brandon Black
Date: Fri, 18 Mar 2022 13:59:18 -0700
Subject: [PATCH 062/144] Consistent capitalization of tapleaf
---
src/payments/p2tr.js | 6 +++---
src/payments/taprootutils.d.ts | 4 ++--
src/payments/taprootutils.js | 12 ++++++------
src/psbt.js | 2 +-
ts_src/payments/p2tr.ts | 8 ++++----
ts_src/payments/taprootutils.ts | 8 ++++----
ts_src/psbt.ts | 4 ++--
7 files changed, 22 insertions(+), 22 deletions(-)
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index 7f60e21ff..af31dc418 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -89,7 +89,7 @@ function p2tr(a, opts) {
const controlBlock = w[w.length - 1];
const leafVersion = controlBlock[0] & types_1.TAPLEAF_VERSION_MASK;
const script = w[w.length - 2];
- const leafHash = (0, taprootutils_1.tapLeafHash)({
+ const leafHash = (0, taprootutils_1.tapleafHash)({
output: script,
version: leafVersion,
});
@@ -147,7 +147,7 @@ function p2tr(a, opts) {
if (a.scriptTree && a.redeem && a.redeem.output && a.internalPubkey) {
// todo: optimize/cache
const hashTree = (0, taprootutils_1.toHashTree)(a.scriptTree);
- const leafHash = (0, taprootutils_1.tapLeafHash)({
+ const leafHash = (0, taprootutils_1.tapleafHash)({
output: a.redeem.output,
version: o.redeemVersion,
});
@@ -258,7 +258,7 @@ function p2tr(a, opts) {
throw new TypeError('Invalid internalPubkey for p2tr witness');
const leafVersion = controlBlock[0] & types_1.TAPLEAF_VERSION_MASK;
const script = witness[witness.length - 2];
- const leafHash = (0, taprootutils_1.tapLeafHash)({
+ const leafHash = (0, taprootutils_1.tapleafHash)({
output: script,
version: leafVersion,
});
diff --git a/src/payments/taprootutils.d.ts b/src/payments/taprootutils.d.ts
index c1181743c..bc32e8523 100644
--- a/src/payments/taprootutils.d.ts
+++ b/src/payments/taprootutils.d.ts
@@ -1,7 +1,7 @@
///
import { Tapleaf, Taptree } from '../types';
export declare const LEAF_VERSION_TAPSCRIPT = 192;
-export declare function rootHashFromPath(controlBlock: Buffer, tapLeafMsg: Buffer): Buffer;
+export declare function rootHashFromPath(controlBlock: Buffer, tapleafMsg: Buffer): Buffer;
export interface HashTree {
hash: Buffer;
left?: HashTree;
@@ -23,5 +23,5 @@ export declare function toHashTree(scriptTree: Taptree): HashTree;
* @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(leaf: Tapleaf): Buffer;
+export declare function tapleafHash(leaf: Tapleaf): Buffer;
export declare function tapTweakHash(pubKey: Buffer, h: Buffer | undefined): Buffer;
diff --git a/src/payments/taprootutils.js b/src/payments/taprootutils.js
index 9cb88ace4..d946216cc 100644
--- a/src/payments/taprootutils.js
+++ b/src/payments/taprootutils.js
@@ -1,6 +1,6 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.tapTweakHash = exports.tapLeafHash = exports.findScriptPath = exports.toHashTree = exports.rootHashFromPath = exports.LEAF_VERSION_TAPSCRIPT = void 0;
+exports.tapTweakHash = exports.tapleafHash = exports.findScriptPath = exports.toHashTree = exports.rootHashFromPath = exports.LEAF_VERSION_TAPSCRIPT = void 0;
const buffer_1 = require('buffer');
const bcrypto = require('../crypto');
const bufferutils_1 = require('../bufferutils');
@@ -9,8 +9,8 @@ const TAP_LEAF_TAG = 'TapLeaf';
const TAP_BRANCH_TAG = 'TapBranch';
const TAP_TWEAK_TAG = 'TapTweak';
exports.LEAF_VERSION_TAPSCRIPT = 0xc0;
-function rootHashFromPath(controlBlock, tapLeafMsg) {
- const k = [tapLeafMsg];
+function rootHashFromPath(controlBlock, tapleafMsg) {
+ const k = [tapleafMsg];
const e = [];
const m = (controlBlock.length - 33) / 32;
for (let j = 0; j < m; j++) {
@@ -34,7 +34,7 @@ exports.rootHashFromPath = rootHashFromPath;
*/
function toHashTree(scriptTree) {
if ((0, types_1.isTapleaf)(scriptTree))
- return { hash: tapLeafHash(scriptTree) };
+ return { hash: tapleafHash(scriptTree) };
const hashes = [toHashTree(scriptTree[0]), toHashTree(scriptTree[1])];
hashes.sort((a, b) => a.hash.compare(b.hash));
const [left, right] = hashes;
@@ -67,7 +67,7 @@ function findScriptPath(node, hash) {
return [];
}
exports.findScriptPath = findScriptPath;
-function tapLeafHash(leaf) {
+function tapleafHash(leaf) {
const version = leaf.version || exports.LEAF_VERSION_TAPSCRIPT;
return bcrypto.taggedHash(
TAP_LEAF_TAG,
@@ -77,7 +77,7 @@ function tapLeafHash(leaf) {
]),
);
}
-exports.tapLeafHash = tapLeafHash;
+exports.tapleafHash = tapleafHash;
function tapTweakHash(pubKey, h) {
return bcrypto.taggedHash(
TAP_TWEAK_TAG,
diff --git a/src/psbt.js b/src/psbt.js
index 8f46a2718..694a6cc1b 100644
--- a/src/psbt.js
+++ b/src/psbt.js
@@ -1079,7 +1079,7 @@ function getHashForSig(
const signingScripts = prevOuts.map(o => o.script);
const values = prevOuts.map(o => o.value);
const leafHash = input.witnessScript
- ? (0, taprootutils_1.tapLeafHash)({ output: input.witnessScript })
+ ? (0, taprootutils_1.tapleafHash)({ output: input.witnessScript })
: undefined;
hash = unsignedTx.hashForWitnessV1(
inputIndex,
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index b298e2ba2..40fd49e03 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -11,7 +11,7 @@ import {
toHashTree,
rootHashFromPath,
findScriptPath,
- tapLeafHash,
+ tapleafHash,
tapTweakHash,
LEAF_VERSION_TAPSCRIPT,
} from './taprootutils';
@@ -107,7 +107,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
const controlBlock = w[w.length - 1];
const leafVersion = controlBlock[0] & TAPLEAF_VERSION_MASK;
const script = w[w.length - 2];
- const leafHash = tapLeafHash({ output: script, version: leafVersion });
+ const leafHash = tapleafHash({ output: script, version: leafVersion });
return rootHashFromPath(controlBlock, leafHash);
}
return null;
@@ -164,7 +164,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
if (a.scriptTree && a.redeem && a.redeem.output && a.internalPubkey) {
// todo: optimize/cache
const hashTree = toHashTree(a.scriptTree);
- const leafHash = tapLeafHash({
+ const leafHash = tapleafHash({
output: a.redeem.output,
version: o.redeemVersion,
});
@@ -292,7 +292,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
const leafVersion = controlBlock[0] & TAPLEAF_VERSION_MASK;
const script = witness[witness.length - 2];
- const leafHash = tapLeafHash({ output: script, version: leafVersion });
+ const leafHash = tapleafHash({ output: script, version: leafVersion });
const hash = rootHashFromPath(controlBlock, leafHash);
const outputKey = tweakKey(internalPubkey, hash, _ecc());
diff --git a/ts_src/payments/taprootutils.ts b/ts_src/payments/taprootutils.ts
index 48d08e617..12026ace3 100644
--- a/ts_src/payments/taprootutils.ts
+++ b/ts_src/payments/taprootutils.ts
@@ -12,9 +12,9 @@ export const LEAF_VERSION_TAPSCRIPT = 0xc0;
export function rootHashFromPath(
controlBlock: Buffer,
- tapLeafMsg: Buffer,
+ tapleafMsg: Buffer,
): Buffer {
- const k = [tapLeafMsg];
+ const k = [tapleafMsg];
const e = [];
const m = (controlBlock.length - 33) / 32;
@@ -46,7 +46,7 @@ export interface HashTree {
* - one taproot leaf and a list of elements
*/
export function toHashTree(scriptTree: Taptree): HashTree {
- if (isTapleaf(scriptTree)) return { hash: tapLeafHash(scriptTree) };
+ if (isTapleaf(scriptTree)) return { hash: tapleafHash(scriptTree) };
const hashes = [toHashTree(scriptTree[0]), toHashTree(scriptTree[1])];
hashes.sort((a, b) => a.hash.compare(b.hash));
@@ -83,7 +83,7 @@ export function findScriptPath(node: HashTree, hash: Buffer): Buffer[] {
return [];
}
-export function tapLeafHash(leaf: Tapleaf): Buffer {
+export function tapleafHash(leaf: Tapleaf): Buffer {
const version = leaf.version || LEAF_VERSION_TAPSCRIPT;
return bcrypto.taggedHash(
TAP_LEAF_TAG,
diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts
index 7a64c3e02..479421636 100644
--- a/ts_src/psbt.ts
+++ b/ts_src/psbt.ts
@@ -21,7 +21,7 @@ import { bitcoin as btcNetwork, Network } from './networks';
import * as payments from './payments';
import * as bscript from './script';
import { Output, Transaction } from './transaction';
-import { tapLeafHash } from './payments/taprootutils';
+import { tapleafHash } from './payments/taprootutils';
import { TinySecp256k1Interface } from './types';
export interface TransactionInput {
@@ -1406,7 +1406,7 @@ function getHashForSig(
const signingScripts: any = prevOuts.map(o => o.script);
const values: any = prevOuts.map(o => o.value);
const leafHash = input.witnessScript
- ? tapLeafHash({ output: input.witnessScript })
+ ? tapleafHash({ output: input.witnessScript })
: undefined;
hash = unsignedTx.hashForWitnessV1(
From cf18dfdc7c3a8687bf92fcc33dfce4ff69f09de3 Mon Sep 17 00:00:00 2001
From: Brandon Black
Date: Fri, 18 Mar 2022 14:00:26 -0700
Subject: [PATCH 063/144] Don't use constants for tag prefixes
Because the taggedHash API is typed, these are compile-time checked and
it's more clear w/o the constants.
---
src/payments/taprootutils.js | 9 +++------
ts_src/payments/taprootutils.ts | 10 +++-------
2 files changed, 6 insertions(+), 13 deletions(-)
diff --git a/src/payments/taprootutils.js b/src/payments/taprootutils.js
index d946216cc..37cea1b20 100644
--- a/src/payments/taprootutils.js
+++ b/src/payments/taprootutils.js
@@ -5,9 +5,6 @@ const buffer_1 = require('buffer');
const bcrypto = require('../crypto');
const bufferutils_1 = require('../bufferutils');
const types_1 = require('../types');
-const TAP_LEAF_TAG = 'TapLeaf';
-const TAP_BRANCH_TAG = 'TapBranch';
-const TAP_TWEAK_TAG = 'TapTweak';
exports.LEAF_VERSION_TAPSCRIPT = 0xc0;
function rootHashFromPath(controlBlock, tapleafMsg) {
const k = [tapleafMsg];
@@ -70,7 +67,7 @@ exports.findScriptPath = findScriptPath;
function tapleafHash(leaf) {
const version = leaf.version || exports.LEAF_VERSION_TAPSCRIPT;
return bcrypto.taggedHash(
- TAP_LEAF_TAG,
+ 'TapLeaf',
buffer_1.Buffer.concat([
buffer_1.Buffer.from([version]),
serializeScript(leaf.output),
@@ -80,13 +77,13 @@ function tapleafHash(leaf) {
exports.tapleafHash = tapleafHash;
function tapTweakHash(pubKey, h) {
return bcrypto.taggedHash(
- TAP_TWEAK_TAG,
+ 'TapTweak',
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]));
+ return bcrypto.taggedHash('TapBranch', buffer_1.Buffer.concat([a, b]));
}
function serializeScript(s) {
const varintLen = bufferutils_1.varuint.encodingLength(s.length);
diff --git a/ts_src/payments/taprootutils.ts b/ts_src/payments/taprootutils.ts
index 12026ace3..090abadd5 100644
--- a/ts_src/payments/taprootutils.ts
+++ b/ts_src/payments/taprootutils.ts
@@ -4,10 +4,6 @@ import * as bcrypto from '../crypto';
import { varuint } from '../bufferutils';
import { Tapleaf, Taptree, isTapleaf } from '../types';
-const TAP_LEAF_TAG = 'TapLeaf';
-const TAP_BRANCH_TAG = 'TapBranch';
-const TAP_TWEAK_TAG = 'TapTweak';
-
export const LEAF_VERSION_TAPSCRIPT = 0xc0;
export function rootHashFromPath(
@@ -86,20 +82,20 @@ export function findScriptPath(node: HashTree, hash: Buffer): Buffer[] {
export function tapleafHash(leaf: Tapleaf): Buffer {
const version = leaf.version || LEAF_VERSION_TAPSCRIPT;
return bcrypto.taggedHash(
- TAP_LEAF_TAG,
+ 'TapLeaf',
NBuffer.concat([NBuffer.from([version]), serializeScript(leaf.output)]),
);
}
export function tapTweakHash(pubKey: Buffer, h: Buffer | undefined): Buffer {
return bcrypto.taggedHash(
- TAP_TWEAK_TAG,
+ 'TapTweak',
NBuffer.concat(h ? [pubKey, h] : [pubKey]),
);
}
function tapBranchHash(a: Buffer, b: Buffer): Buffer {
- return bcrypto.taggedHash(TAP_BRANCH_TAG, NBuffer.concat([a, b]));
+ return bcrypto.taggedHash('TapBranch', NBuffer.concat([a, b]));
}
function serializeScript(s: Buffer): Buffer {
From f76b95434d946bd98c5dd07be21bb3e8dd29a6c3 Mon Sep 17 00:00:00 2001
From: Brandon Black
Date: Fri, 18 Mar 2022 14:49:26 -0700
Subject: [PATCH 064/144] Simplify HashTree processing, remove footgun
* More clearly show the continuation and base cases in findScriptPath
* Return undefined not empty path when no path is found
* This would lead to generating an invalid witness
* Tighten the type for HashTree to not allow 1-sided branch nodes
---
src/payments/p2tr.js | 1 +
src/payments/taprootutils.d.ts | 15 +++++++----
src/payments/taprootutils.js | 26 +++++++++----------
ts_src/payments/p2tr.ts | 1 +
ts_src/payments/taprootutils.ts | 46 +++++++++++++++++++++------------
5 files changed, 54 insertions(+), 35 deletions(-)
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index af31dc418..d9fa7ceca 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -152,6 +152,7 @@ function p2tr(a, opts) {
version: o.redeemVersion,
});
const path = (0, taprootutils_1.findScriptPath)(hashTree, leafHash);
+ if (!path) return;
const outputKey = tweakKey(a.internalPubkey, hashTree.hash, _ecc());
if (!outputKey) return;
const controlBock = buffer_1.Buffer.concat(
diff --git a/src/payments/taprootutils.d.ts b/src/payments/taprootutils.d.ts
index bc32e8523..3c4f800c6 100644
--- a/src/payments/taprootutils.d.ts
+++ b/src/payments/taprootutils.d.ts
@@ -2,11 +2,15 @@
import { Tapleaf, Taptree } from '../types';
export declare const LEAF_VERSION_TAPSCRIPT = 192;
export declare function rootHashFromPath(controlBlock: Buffer, tapleafMsg: Buffer): Buffer;
-export interface HashTree {
+interface HashLeaf {
hash: Buffer;
- left?: HashTree;
- right?: HashTree;
}
+interface HashBranch {
+ hash: Buffer;
+ left: HashTree;
+ right: HashTree;
+}
+export declare type HashTree = HashLeaf | HashBranch;
/**
* Build the hash tree from the scripts binary tree.
* The binary tree can be balanced or not.
@@ -20,8 +24,9 @@ export declare function toHashTree(scriptTree: Taptree): 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
+ * @returns - and array of hashes representing the path, undefined if no path is found
*/
-export declare function findScriptPath(node: HashTree, hash: Buffer): Buffer[];
+export declare function findScriptPath(node: HashTree, hash: Buffer): Buffer[] | undefined;
export declare function tapleafHash(leaf: Tapleaf): Buffer;
export declare function tapTweakHash(pubKey: Buffer, h: Buffer | undefined): Buffer;
+export {};
diff --git a/src/payments/taprootutils.js b/src/payments/taprootutils.js
index 37cea1b20..d9ebc7bcb 100644
--- a/src/payments/taprootutils.js
+++ b/src/payments/taprootutils.js
@@ -21,6 +21,7 @@ function rootHashFromPath(controlBlock, tapleafMsg) {
return k[m];
}
exports.rootHashFromPath = rootHashFromPath;
+const isHashBranch = ht => 'left' in ht && 'right' in ht;
/**
* Build the hash tree from the scripts binary tree.
* The binary tree can be balanced or not.
@@ -46,22 +47,21 @@ 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
+ * @returns - and array of hashes representing the path, undefined if no path 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;
+ if (!isHashBranch(node)) {
+ if (node.hash.equals(hash)) {
+ return [];
+ } else {
+ return undefined;
+ }
}
- return [];
+ const leftPath = findScriptPath(node.left, hash);
+ if (leftPath !== undefined) return [node.right.hash, ...leftPath];
+ const rightPath = findScriptPath(node.right, hash);
+ if (rightPath !== undefined) return [node.left.hash, ...rightPath];
+ return undefined;
}
exports.findScriptPath = findScriptPath;
function tapleafHash(leaf) {
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index 40fd49e03..a254d6ab8 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -169,6 +169,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
version: o.redeemVersion,
});
const path = findScriptPath(hashTree, leafHash);
+ if (!path) return;
const outputKey = tweakKey(a.internalPubkey, hashTree.hash, _ecc());
if (!outputKey) return;
const controlBock = NBuffer.concat(
diff --git a/ts_src/payments/taprootutils.ts b/ts_src/payments/taprootutils.ts
index 090abadd5..7c10e2306 100644
--- a/ts_src/payments/taprootutils.ts
+++ b/ts_src/payments/taprootutils.ts
@@ -27,12 +27,21 @@ export function rootHashFromPath(
return k[m];
}
-export interface HashTree {
+interface HashLeaf {
hash: Buffer;
- left?: HashTree;
- right?: HashTree;
}
+interface HashBranch {
+ hash: Buffer;
+ left: HashTree;
+ right: HashTree;
+}
+
+const isHashBranch = (ht: HashTree): ht is HashBranch =>
+ 'left' in ht && 'right' in ht;
+
+export type HashTree = HashLeaf | HashBranch;
+
/**
* Build the hash tree from the scripts binary tree.
* The binary tree can be balanced or not.
@@ -59,24 +68,27 @@ export function toHashTree(scriptTree: Taptree): 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
+ * @returns - and array of hashes representing the path, undefined if no path 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;
+export function findScriptPath(
+ node: HashTree,
+ hash: Buffer,
+): Buffer[] | undefined {
+ if (!isHashBranch(node)) {
+ if (node.hash.equals(hash)) {
+ return [];
+ } else {
+ return undefined;
+ }
}
- 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;
- }
+ const leftPath = findScriptPath(node.left, hash);
+ if (leftPath !== undefined) return [node.right.hash, ...leftPath];
+
+ const rightPath = findScriptPath(node.right, hash);
+ if (rightPath !== undefined) return [node.left.hash, ...rightPath];
- return [];
+ return undefined;
}
export function tapleafHash(leaf: Tapleaf): Buffer {
From 18bcadd61d9587e0a8118d7aa1a53e9b5ca83e9c Mon Sep 17 00:00:00 2001
From: Brandon Black
Date: Fri, 18 Mar 2022 15:46:47 -0700
Subject: [PATCH 065/144] Support p2tr with 1 script and no tree
* Also added caching of `hashTree`, per todo.
* Added a test for this functionality
---
src/payments/p2tr.js | 16 ++++++++++------
test/fixtures/p2tr.json | 22 ++++++++++++++++++++++
ts_src/payments/p2tr.ts | 17 +++++++++++------
3 files changed, 43 insertions(+), 12 deletions(-)
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index d9fa7ceca..57087092f 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -73,6 +73,11 @@ function p2tr(a, opts) {
}
return a.witness.slice();
});
+ const _hashTree = lazy.value(() => {
+ if (a.scriptTree) return (0, taprootutils_1.toHashTree)(a.scriptTree);
+ if (a.hash) return { hash: a.hash };
+ return;
+ });
const network = a.network || networks_1.bitcoin;
const o = { name: 'p2tr', network };
lazy.prop(o, 'address', () => {
@@ -82,8 +87,8 @@ function p2tr(a, opts) {
return bech32_1.bech32m.encode(network.bech32, words);
});
lazy.prop(o, 'hash', () => {
- if (a.hash) return a.hash;
- if (a.scriptTree) return (0, taprootutils_1.toHashTree)(a.scriptTree).hash;
+ const hashTree = _hashTree();
+ if (hashTree) return hashTree.hash;
const w = _witness();
if (w && w.length > 1) {
const controlBlock = w[w.length - 1];
@@ -144,9 +149,8 @@ function p2tr(a, opts) {
});
lazy.prop(o, 'witness', () => {
if (a.witness) return a.witness;
- if (a.scriptTree && a.redeem && a.redeem.output && a.internalPubkey) {
- // todo: optimize/cache
- const hashTree = (0, taprootutils_1.toHashTree)(a.scriptTree);
+ const hashTree = _hashTree();
+ if (hashTree && a.redeem && a.redeem.output && a.internalPubkey) {
const leafHash = (0, taprootutils_1.tapleafHash)({
output: a.redeem.output,
version: o.redeemVersion,
@@ -204,7 +208,7 @@ function p2tr(a, opts) {
throw new TypeError('Invalid pubkey for p2tr');
}
if (a.hash && a.scriptTree) {
- const hash = (0, taprootutils_1.toHashTree)(a.scriptTree).hash;
+ const hash = _hashTree().hash;
if (!a.hash.equals(hash)) throw new TypeError('Hash mismatch');
}
const witness = _witness();
diff --git a/test/fixtures/p2tr.json b/test/fixtures/p2tr.json
index 75e0456ab..cf9482c36 100644
--- a/test/fixtures/p2tr.json
+++ b/test/fixtures/p2tr.json
@@ -312,6 +312,28 @@
"witness": null
}
},
+ {
+ "description": "address, pubkey, and output from internalPubkey redeem, and hash (one leaf, no tree)",
+ "arguments": {
+ "internalPubkey": "aba457d16a8d59151c387f24d1eb887efbe24644c1ee64b261282e7baebdb247",
+ "redeem": {
+ "output": "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac4 OP_CHECKSIG"
+ },
+ "hash": "b424dea09f840b932a00373cdcdbd25650b8c3acfe54a9f4a641a286721b8d26"
+ },
+ "expected": {
+ "name": "p2tr",
+ "address": "bc1pnxyp0ahcg53jzgrzj57hnlgdtqtzn7qqhmgjgczk8hzhcltq974qazepzf",
+ "pubkey": "998817f6f84523212062953d79fd0d581629f800bed12460563dc57c7d602faa",
+ "output": "OP_1 998817f6f84523212062953d79fd0d581629f800bed12460563dc57c7d602faa",
+ "signature": null,
+ "input": null,
+ "witness": [
+ "2050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac4ac",
+ "c0aba457d16a8d59151c387f24d1eb887efbe24644c1ee64b261282e7baebdb247"
+ ]
+ }
+ },
{
"description": "address, pubkey, output and hash from internalPubkey and a script tree with seven leafs (2)",
"arguments": {
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index a254d6ab8..0da70c11e 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -88,6 +88,12 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
return a.witness.slice();
});
+ const _hashTree = lazy.value(() => {
+ if (a.scriptTree) return toHashTree(a.scriptTree);
+ if (a.hash) return { hash: a.hash };
+ return;
+ });
+
const network = a.network || BITCOIN_NETWORK;
const o: Payment = { name: 'p2tr', network };
@@ -100,8 +106,8 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
});
lazy.prop(o, 'hash', () => {
- if (a.hash) return a.hash;
- if (a.scriptTree) return toHashTree(a.scriptTree).hash;
+ const hashTree = _hashTree();
+ if (hashTree) return hashTree.hash;
const w = _witness();
if (w && w.length > 1) {
const controlBlock = w[w.length - 1];
@@ -161,9 +167,8 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
lazy.prop(o, 'witness', () => {
if (a.witness) return a.witness;
- if (a.scriptTree && a.redeem && a.redeem.output && a.internalPubkey) {
- // todo: optimize/cache
- const hashTree = toHashTree(a.scriptTree);
+ const hashTree = _hashTree();
+ if (hashTree && a.redeem && a.redeem.output && a.internalPubkey) {
const leafHash = tapleafHash({
output: a.redeem.output,
version: o.redeemVersion,
@@ -227,7 +232,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
}
if (a.hash && a.scriptTree) {
- const hash = toHashTree(a.scriptTree).hash;
+ const hash = _hashTree()!.hash;
if (!a.hash.equals(hash)) throw new TypeError('Hash mismatch');
}
From c02ed1b54c3f6600e05156be994232e85a25e726 Mon Sep 17 00:00:00 2001
From: Brandon Black
Date: Fri, 18 Mar 2022 15:54:24 -0700
Subject: [PATCH 066/144] Remove unnecessary arrays of values
The spec uses this notation because in a spec there's no such thing as
reassigning a value. In real code it is appropriate to us accumulators
or such.
---
src/payments/taprootutils.js | 13 ++++++-------
ts_src/payments/taprootutils.ts | 14 ++++++--------
2 files changed, 12 insertions(+), 15 deletions(-)
diff --git a/src/payments/taprootutils.js b/src/payments/taprootutils.js
index d9ebc7bcb..445faf1e8 100644
--- a/src/payments/taprootutils.js
+++ b/src/payments/taprootutils.js
@@ -7,18 +7,17 @@ const bufferutils_1 = require('../bufferutils');
const types_1 = require('../types');
exports.LEAF_VERSION_TAPSCRIPT = 0xc0;
function rootHashFromPath(controlBlock, tapleafMsg) {
- const k = [tapleafMsg];
- const e = [];
const m = (controlBlock.length - 33) / 32;
+ let kj = tapleafMsg;
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]);
+ const ej = controlBlock.slice(33 + 32 * j, 65 + 32 * j);
+ if (kj.compare(ej) < 0) {
+ kj = tapBranchHash(kj, ej);
} else {
- k[j + 1] = tapBranchHash(e[j], k[j]);
+ kj = tapBranchHash(ej, kj);
}
}
- return k[m];
+ return kj;
}
exports.rootHashFromPath = rootHashFromPath;
const isHashBranch = ht => 'left' in ht && 'right' in ht;
diff --git a/ts_src/payments/taprootutils.ts b/ts_src/payments/taprootutils.ts
index 7c10e2306..53fc2a6e6 100644
--- a/ts_src/payments/taprootutils.ts
+++ b/ts_src/payments/taprootutils.ts
@@ -10,21 +10,19 @@ export function rootHashFromPath(
controlBlock: Buffer,
tapleafMsg: Buffer,
): Buffer {
- const k = [tapleafMsg];
- const e = [];
-
const m = (controlBlock.length - 33) / 32;
+ let kj = tapleafMsg;
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]);
+ const ej = controlBlock.slice(33 + 32 * j, 65 + 32 * j);
+ if (kj.compare(ej) < 0) {
+ kj = tapBranchHash(kj, ej);
} else {
- k[j + 1] = tapBranchHash(e[j], k[j]);
+ kj = tapBranchHash(ej, kj);
}
}
- return k[m];
+ return kj;
}
interface HashLeaf {
From 6b9f7767a5ccbca86b2f456610801ef994430f77 Mon Sep 17 00:00:00 2001
From: Brandon Black
Date: Fri, 18 Mar 2022 15:57:05 -0700
Subject: [PATCH 067/144] Improve tapleah hash parameter name
---
src/payments/taprootutils.d.ts | 2 +-
src/payments/taprootutils.js | 4 ++--
ts_src/payments/taprootutils.ts | 4 ++--
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/payments/taprootutils.d.ts b/src/payments/taprootutils.d.ts
index 3c4f800c6..1635168c3 100644
--- a/src/payments/taprootutils.d.ts
+++ b/src/payments/taprootutils.d.ts
@@ -1,7 +1,7 @@
///
import { Tapleaf, Taptree } from '../types';
export declare const LEAF_VERSION_TAPSCRIPT = 192;
-export declare function rootHashFromPath(controlBlock: Buffer, tapleafMsg: Buffer): Buffer;
+export declare function rootHashFromPath(controlBlock: Buffer, leafHash: Buffer): Buffer;
interface HashLeaf {
hash: Buffer;
}
diff --git a/src/payments/taprootutils.js b/src/payments/taprootutils.js
index 445faf1e8..0cf1b1657 100644
--- a/src/payments/taprootutils.js
+++ b/src/payments/taprootutils.js
@@ -6,9 +6,9 @@ const bcrypto = require('../crypto');
const bufferutils_1 = require('../bufferutils');
const types_1 = require('../types');
exports.LEAF_VERSION_TAPSCRIPT = 0xc0;
-function rootHashFromPath(controlBlock, tapleafMsg) {
+function rootHashFromPath(controlBlock, leafHash) {
const m = (controlBlock.length - 33) / 32;
- let kj = tapleafMsg;
+ let kj = leafHash;
for (let j = 0; j < m; j++) {
const ej = controlBlock.slice(33 + 32 * j, 65 + 32 * j);
if (kj.compare(ej) < 0) {
diff --git a/ts_src/payments/taprootutils.ts b/ts_src/payments/taprootutils.ts
index 53fc2a6e6..fc043f696 100644
--- a/ts_src/payments/taprootutils.ts
+++ b/ts_src/payments/taprootutils.ts
@@ -8,11 +8,11 @@ export const LEAF_VERSION_TAPSCRIPT = 0xc0;
export function rootHashFromPath(
controlBlock: Buffer,
- tapleafMsg: Buffer,
+ leafHash: Buffer,
): Buffer {
const m = (controlBlock.length - 33) / 32;
- let kj = tapleafMsg;
+ let kj = leafHash;
for (let j = 0; j < m; j++) {
const ej = controlBlock.slice(33 + 32 * j, 65 + 32 * j);
if (kj.compare(ej) < 0) {
From 95d0f51622a5e6e22e0a056bdc775f618162d631 Mon Sep 17 00:00:00 2001
From: Brandon Black
Date: Fri, 18 Mar 2022 16:05:56 -0700
Subject: [PATCH 068/144] Fix indentation
---
test/fixtures/p2tr.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/fixtures/p2tr.json b/test/fixtures/p2tr.json
index cf9482c36..3da6103fd 100644
--- a/test/fixtures/p2tr.json
+++ b/test/fixtures/p2tr.json
@@ -385,8 +385,8 @@
"input": null,
"witness": [
"2050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac4ac",
- "c0aba457d16a8d59151c387f24d1eb887efbe24644c1ee64b261282e7baebdb247dac795766bbda1eaeaa45e5bfa0a950fdd5f4c4aada5b1f3082edc9689b9fd0a315fb34a7a93dcaed5e26cf7468be5bd377dda7a4d29128f7dd98db6da9bf04325fff3aa86365bac7534dcb6495867109941ec444dd35294e0706e29e051066d73e0d427bd3249bb921fa78c04fb76511f583ff48c97210d17c2d9dcfbb95023"
- ]
+ "c0aba457d16a8d59151c387f24d1eb887efbe24644c1ee64b261282e7baebdb247dac795766bbda1eaeaa45e5bfa0a950fdd5f4c4aada5b1f3082edc9689b9fd0a315fb34a7a93dcaed5e26cf7468be5bd377dda7a4d29128f7dd98db6da9bf04325fff3aa86365bac7534dcb6495867109941ec444dd35294e0706e29e051066d73e0d427bd3249bb921fa78c04fb76511f583ff48c97210d17c2d9dcfbb95023"
+ ]
}
},
{
From e557a9948beb727bb53584d909ce9ea342e35dd5 Mon Sep 17 00:00:00 2001
From: Brandon Black
Date: Mon, 21 Mar 2022 07:55:57 -0700
Subject: [PATCH 069/144] Add validation for redeem in scriptTree
---
src/payments/p2tr.js | 14 +++++++++++---
test/fixtures/p2tr.json | 14 ++++++++++++++
ts_src/payments/p2tr.ts | 16 +++++++++++++---
3 files changed, 38 insertions(+), 6 deletions(-)
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index 57087092f..ce30f4662 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -207,9 +207,17 @@ function p2tr(a, opts) {
if (!_ecc().isXOnlyPoint(pubkey))
throw new TypeError('Invalid pubkey for p2tr');
}
- if (a.hash && a.scriptTree) {
- const hash = _hashTree().hash;
- if (!a.hash.equals(hash)) throw new TypeError('Hash mismatch');
+ const hashTree = _hashTree();
+ if (a.hash && hashTree) {
+ if (!a.hash.equals(hashTree.hash)) throw new TypeError('Hash mismatch');
+ }
+ if (a.redeem && a.redeem.output && hashTree) {
+ const leafHash = (0, taprootutils_1.tapleafHash)({
+ output: a.redeem.output,
+ version: o.redeemVersion,
+ });
+ if (!(0, taprootutils_1.findScriptPath)(hashTree, leafHash))
+ throw new TypeError('Redeem script not in tree');
}
const witness = _witness();
// compare the provided redeem data with the one computed from witness
diff --git a/test/fixtures/p2tr.json b/test/fixtures/p2tr.json
index 3da6103fd..aaa82fbb4 100644
--- a/test/fixtures/p2tr.json
+++ b/test/fixtures/p2tr.json
@@ -1175,6 +1175,20 @@
]
}
}
+ },
+ {
+ "description": "Redeem script not in tree",
+ "exception": "Redeem script not in tree",
+ "options": {},
+ "arguments": {
+ "internalPubkey": "9fa5ffb68821cf559001caa0577eeea4978b29416def328a707b15e91701a2f7",
+ "scriptTree": {
+ "output": "83d8ee77a0f3a32a5cea96fd1624d623b836c1e5d1ac2dcde46814b619320c18 OP_CHECKSIG"
+ },
+ "redeem": {
+ "output": "83d8ee77a0f3a32a5cea96fd1624d623b836c1e5d1ac2dcde46814b619320c19 OP_CHECKSIG"
+ }
+ }
}
],
"dynamic": {
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index 0da70c11e..71f7437a3 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -231,9 +231,19 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
throw new TypeError('Invalid pubkey for p2tr');
}
- if (a.hash && a.scriptTree) {
- const hash = _hashTree()!.hash;
- if (!a.hash.equals(hash)) throw new TypeError('Hash mismatch');
+ const hashTree = _hashTree();
+
+ if (a.hash && hashTree) {
+ if (!a.hash.equals(hashTree.hash)) throw new TypeError('Hash mismatch');
+ }
+
+ if (a.redeem && a.redeem.output && hashTree) {
+ const leafHash = tapleafHash({
+ output: a.redeem.output,
+ version: o.redeemVersion,
+ });
+ if (!findScriptPath(hashTree, leafHash))
+ throw new TypeError('Redeem script not in tree');
}
const witness = _witness();
From c3053e7b2f2c3d00aae10bbe410d462a42e3b296 Mon Sep 17 00:00:00 2001
From: Brandon Black
Date: Mon, 21 Mar 2022 07:57:08 -0700
Subject: [PATCH 070/144] Improve comments and code clarity
---
src/payments/p2tr.js | 2 +-
src/payments/taprootutils.d.ts | 20 ++++++++++-------
src/payments/taprootutils.js | 31 +++++++++++--------------
src/types.d.ts | 5 +++++
ts_src/payments/p2tr.ts | 2 +-
ts_src/payments/taprootutils.ts | 40 ++++++++++++++++-----------------
ts_src/types.ts | 5 +++++
7 files changed, 57 insertions(+), 48 deletions(-)
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index ce30f4662..c24c16914 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -163,7 +163,7 @@ function p2tr(a, opts) {
[
buffer_1.Buffer.from([o.redeemVersion | outputKey.parity]),
a.internalPubkey,
- ].concat(path.reverse()),
+ ].concat(path),
);
return [a.redeem.output, controlBock];
}
diff --git a/src/payments/taprootutils.d.ts b/src/payments/taprootutils.d.ts
index 1635168c3..a5739c44f 100644
--- a/src/payments/taprootutils.d.ts
+++ b/src/payments/taprootutils.d.ts
@@ -10,21 +10,25 @@ interface HashBranch {
left: HashTree;
right: HashTree;
}
+/**
+ * Binary tree representing leaf, branch, and root node hashes of a Taptree.
+ * Each node contains a hash, and potentially left and right branch hashes.
+ * This tree is used for 2 purposes: Providing the root hash for tweaking,
+ * and calculating merkle inclusion proofs when constructing a control block.
+ */
export declare type HashTree = HashLeaf | HashBranch;
/**
- * Build the hash tree from the scripts binary tree.
- * The binary tree can be balanced or not.
- * @param scriptTree - 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
+ * Build a hash tree of merkle nodes from the scripts binary tree.
+ * @param scriptTree - the tree of scripts to pairwise hash.
*/
export declare function toHashTree(scriptTree: Taptree): HashTree;
/**
- * Given a MAST tree, it finds the path of a particular hash.
+ * Given a HashTree, finds the path from a particular hash to the root.
* @param node - the root of the tree
* @param hash - the hash to search for
- * @returns - and array of hashes representing the path, undefined if no path is found
+ * @returns - array of sibling hashes, from leaf (inclusive) to root
+ * (exclusive) needed to prove inclusion of the specified hash. undefined if no
+ * path is found
*/
export declare function findScriptPath(node: HashTree, hash: Buffer): Buffer[] | undefined;
export declare function tapleafHash(leaf: Tapleaf): Buffer;
diff --git a/src/payments/taprootutils.js b/src/payments/taprootutils.js
index 0cf1b1657..85576960b 100644
--- a/src/payments/taprootutils.js
+++ b/src/payments/taprootutils.js
@@ -22,12 +22,8 @@ function rootHashFromPath(controlBlock, leafHash) {
exports.rootHashFromPath = rootHashFromPath;
const isHashBranch = ht => 'left' in ht && 'right' in ht;
/**
- * Build the hash tree from the scripts binary tree.
- * The binary tree can be balanced or not.
- * @param scriptTree - 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
+ * Build a hash tree of merkle nodes from the scripts binary tree.
+ * @param scriptTree - the tree of scripts to pairwise hash.
*/
function toHashTree(scriptTree) {
if ((0, types_1.isTapleaf)(scriptTree))
@@ -43,23 +39,22 @@ function toHashTree(scriptTree) {
}
exports.toHashTree = toHashTree;
/**
- * Given a MAST tree, it finds the path of a particular hash.
+ * Given a HashTree, finds the path from a particular hash to the root.
* @param node - the root of the tree
* @param hash - the hash to search for
- * @returns - and array of hashes representing the path, undefined if no path is found
+ * @returns - array of sibling hashes, from leaf (inclusive) to root
+ * (exclusive) needed to prove inclusion of the specified hash. undefined if no
+ * path is found
*/
function findScriptPath(node, hash) {
- if (!isHashBranch(node)) {
- if (node.hash.equals(hash)) {
- return [];
- } else {
- return undefined;
- }
+ if (isHashBranch(node)) {
+ const leftPath = findScriptPath(node.left, hash);
+ if (leftPath !== undefined) return [...leftPath, node.right.hash];
+ const rightPath = findScriptPath(node.right, hash);
+ if (rightPath !== undefined) return [...rightPath, node.left.hash];
+ } else if (node.hash.equals(hash)) {
+ return [];
}
- const leftPath = findScriptPath(node.left, hash);
- if (leftPath !== undefined) return [node.right.hash, ...leftPath];
- const rightPath = findScriptPath(node.right, hash);
- if (rightPath !== undefined) return [node.left.hash, ...rightPath];
return undefined;
}
exports.findScriptPath = findScriptPath;
diff --git a/src/types.d.ts b/src/types.d.ts
index c8048c29a..b3d93589d 100644
--- a/src/types.d.ts
+++ b/src/types.d.ts
@@ -20,6 +20,11 @@ export interface Tapleaf {
}
export declare const TAPLEAF_VERSION_MASK = 254;
export declare function isTapleaf(o: any): o is Tapleaf;
+/**
+ * Binary tree repsenting script path spends for a Taproot input.
+ * Each node is either a single Tapleaf, or a pair of Tapleaf | Taptree.
+ * The tree has no balancing requirements.
+ */
export declare type Taptree = [Taptree | Tapleaf, Taptree | Tapleaf] | Tapleaf;
export declare function isTaptree(scriptTree: any): scriptTree is Taptree;
export interface TinySecp256k1Interface {
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index 71f7437a3..47a76a114 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -181,7 +181,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
[
NBuffer.from([o.redeemVersion! | outputKey.parity]),
a.internalPubkey,
- ].concat(path.reverse()),
+ ].concat(path),
);
return [a.redeem.output, controlBock];
}
diff --git a/ts_src/payments/taprootutils.ts b/ts_src/payments/taprootutils.ts
index fc043f696..97cc1f6d8 100644
--- a/ts_src/payments/taprootutils.ts
+++ b/ts_src/payments/taprootutils.ts
@@ -38,15 +38,17 @@ interface HashBranch {
const isHashBranch = (ht: HashTree): ht is HashBranch =>
'left' in ht && 'right' in ht;
+/**
+ * Binary tree representing leaf, branch, and root node hashes of a Taptree.
+ * Each node contains a hash, and potentially left and right branch hashes.
+ * This tree is used for 2 purposes: Providing the root hash for tweaking,
+ * and calculating merkle inclusion proofs when constructing a control block.
+ */
export type HashTree = HashLeaf | HashBranch;
/**
- * Build the hash tree from the scripts binary tree.
- * The binary tree can be balanced or not.
- * @param scriptTree - 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
+ * Build a hash tree of merkle nodes from the scripts binary tree.
+ * @param scriptTree - the tree of scripts to pairwise hash.
*/
export function toHashTree(scriptTree: Taptree): HashTree {
if (isTapleaf(scriptTree)) return { hash: tapleafHash(scriptTree) };
@@ -63,29 +65,27 @@ export function toHashTree(scriptTree: Taptree): HashTree {
}
/**
- * Given a MAST tree, it finds the path of a particular hash.
+ * Given a HashTree, finds the path from a particular hash to the root.
* @param node - the root of the tree
* @param hash - the hash to search for
- * @returns - and array of hashes representing the path, undefined if no path is found
+ * @returns - array of sibling hashes, from leaf (inclusive) to root
+ * (exclusive) needed to prove inclusion of the specified hash. undefined if no
+ * path is found
*/
export function findScriptPath(
node: HashTree,
hash: Buffer,
): Buffer[] | undefined {
- if (!isHashBranch(node)) {
- if (node.hash.equals(hash)) {
- return [];
- } else {
- return undefined;
- }
+ if (isHashBranch(node)) {
+ const leftPath = findScriptPath(node.left, hash);
+ if (leftPath !== undefined) return [...leftPath, node.right.hash];
+
+ const rightPath = findScriptPath(node.right, hash);
+ if (rightPath !== undefined) return [...rightPath, node.left.hash];
+ } else if (node.hash.equals(hash)) {
+ return [];
}
- const leftPath = findScriptPath(node.left, hash);
- if (leftPath !== undefined) return [node.right.hash, ...leftPath];
-
- const rightPath = findScriptPath(node.right, hash);
- if (rightPath !== undefined) return [node.left.hash, ...rightPath];
-
return undefined;
}
diff --git a/ts_src/types.ts b/ts_src/types.ts
index 1e49361b6..536646e86 100644
--- a/ts_src/types.ts
+++ b/ts_src/types.ts
@@ -86,6 +86,11 @@ export function isTapleaf(o: any): o is Tapleaf {
return true;
}
+/**
+ * Binary tree repsenting script path spends for a Taproot input.
+ * Each node is either a single Tapleaf, or a pair of Tapleaf | Taptree.
+ * The tree has no balancing requirements.
+ */
export type Taptree = [Taptree | Tapleaf, Taptree | Tapleaf] | Tapleaf;
export function isTaptree(scriptTree: any): scriptTree is Taptree {
From 6f70c889a9f2cf5417ddf8c8a4795dffeccf82d8 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Mon, 28 Mar 2022 10:27:10 +0300
Subject: [PATCH 071/144] refactor: add explicit initialisation of the ecc
library (#5)
* refactor: explicit initialization on the ecc library
- remove optional `eccLib` parameter for `p2tr` and `psbt`
---
src/address.d.ts | 5 +-
src/address.js | 11 ++-
src/ecc_lib.d.ts | 3 +
src/{payments/verifyecc.js => ecc_lib.js} | 23 +++++-
src/index.d.ts | 1 +
src/index.js | 9 ++-
src/payments/index.d.ts | 3 +-
src/payments/p2tr.js | 23 +++---
src/payments/verifyecc.d.ts | 2 -
src/psbt.d.ts | 5 +-
src/psbt.js | 36 +++------
test/address.spec.ts | 14 ++--
test/integration/taproot.spec.ts | 79 +++++++++-----------
test/payments.spec.ts | 15 ++--
test/psbt.spec.ts | 26 +++++--
test/psbt.utils.ts | 17 ++---
ts_src/address.ts | 28 ++-----
ts_src/{payments/verifyecc.ts => ecc_lib.ts} | 25 ++++++-
ts_src/index.ts | 1 +
ts_src/payments/index.ts | 3 +-
ts_src/payments/p2tr.ts | 31 +++-----
ts_src/psbt.ts | 48 +++---------
22 files changed, 184 insertions(+), 224 deletions(-)
create mode 100644 src/ecc_lib.d.ts
rename src/{payments/verifyecc.js => ecc_lib.js} (77%)
delete mode 100644 src/payments/verifyecc.d.ts
rename ts_src/{payments/verifyecc.ts => ecc_lib.ts} (73%)
diff --git a/src/address.d.ts b/src/address.d.ts
index 13922dab3..be0e00a61 100644
--- a/src/address.d.ts
+++ b/src/address.d.ts
@@ -1,6 +1,5 @@
///
import { Network } from './networks';
-import { TinySecp256k1Interface } from './types';
export interface Base58CheckResult {
hash: Buffer;
version: number;
@@ -14,5 +13,5 @@ export declare function fromBase58Check(address: string): Base58CheckResult;
export declare function fromBech32(address: string): Bech32Result;
export declare function toBase58Check(hash: Buffer, version: number): string;
export declare function toBech32(data: Buffer, version: number, prefix: string): string;
-export declare function fromOutputScript(output: Buffer, network?: Network, eccLib?: TinySecp256k1Interface): string;
-export declare function toOutputScript(address: string, network?: Network, eccLib?: TinySecp256k1Interface): Buffer;
+export declare function fromOutputScript(output: Buffer, network?: Network): string;
+export declare function toOutputScript(address: string, network?: Network): Buffer;
diff --git a/src/address.js b/src/address.js
index 2c7bc4857..de0154a3a 100644
--- a/src/address.js
+++ b/src/address.js
@@ -86,7 +86,7 @@ function toBech32(data, version, prefix) {
: bech32_1.bech32m.encode(prefix, words);
}
exports.toBech32 = toBech32;
-function fromOutputScript(output, network, eccLib) {
+function fromOutputScript(output, network) {
// TODO: Network
network = network || networks.bitcoin;
try {
@@ -102,7 +102,7 @@ function fromOutputScript(output, network, eccLib) {
return payments.p2wsh({ output, network }).address;
} catch (e) {}
try {
- if (eccLib) return payments.p2tr({ output, network }, { eccLib }).address;
+ return payments.p2tr({ output, network }).address;
} catch (e) {}
try {
return _toFutureSegwitAddress(output, network);
@@ -110,7 +110,7 @@ function fromOutputScript(output, network, eccLib) {
throw new Error(bscript.toASM(output) + ' has no matching Address');
}
exports.fromOutputScript = fromOutputScript;
-function toOutputScript(address, network, eccLib) {
+function toOutputScript(address, network) {
network = network || networks.bitcoin;
let decodeBase58;
let decodeBech32;
@@ -135,9 +135,8 @@ function toOutputScript(address, network, eccLib) {
if (decodeBech32.data.length === 32)
return payments.p2wsh({ hash: decodeBech32.data }).output;
} else if (decodeBech32.version === 1) {
- if (decodeBech32.data.length === 32 && eccLib)
- return payments.p2tr({ pubkey: decodeBech32.data }, { eccLib })
- .output;
+ if (decodeBech32.data.length === 32)
+ return payments.p2tr({ pubkey: decodeBech32.data }).output;
} else if (
decodeBech32.version >= FUTURE_SEGWIT_MIN_VERSION &&
decodeBech32.version <= FUTURE_SEGWIT_MAX_VERSION &&
diff --git a/src/ecc_lib.d.ts b/src/ecc_lib.d.ts
new file mode 100644
index 000000000..201ebb5cf
--- /dev/null
+++ b/src/ecc_lib.d.ts
@@ -0,0 +1,3 @@
+import { TinySecp256k1Interface } from './types';
+export declare function initEccLib(eccLib: TinySecp256k1Interface | undefined): void;
+export declare function getEccLib(): TinySecp256k1Interface;
diff --git a/src/payments/verifyecc.js b/src/ecc_lib.js
similarity index 77%
rename from src/payments/verifyecc.js
rename to src/ecc_lib.js
index 9a1eebd64..eaa8a5327 100644
--- a/src/payments/verifyecc.js
+++ b/src/ecc_lib.js
@@ -1,6 +1,26 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.verifyEcc = void 0;
+exports.getEccLib = exports.initEccLib = void 0;
+const _ECCLIB_CACHE = {};
+function initEccLib(eccLib) {
+ if (!eccLib) {
+ // allow clearing the library
+ _ECCLIB_CACHE.eccLib = eccLib;
+ } else if (eccLib !== _ECCLIB_CACHE.eccLib) {
+ // new instance, verify it
+ verifyEcc(eccLib);
+ _ECCLIB_CACHE.eccLib = eccLib;
+ }
+}
+exports.initEccLib = initEccLib;
+function getEccLib() {
+ if (!_ECCLIB_CACHE.eccLib)
+ throw new Error(
+ 'No ECC Library provided. You must call initEccLib() with a valid TinySecp256k1Interface instance',
+ );
+ return _ECCLIB_CACHE.eccLib;
+}
+exports.getEccLib = getEccLib;
const h = hex => Buffer.from(hex, 'hex');
function verifyEcc(ecc) {
assert(typeof ecc.isXOnlyPoint === 'function');
@@ -46,7 +66,6 @@ function verifyEcc(ecc) {
}
});
}
-exports.verifyEcc = verifyEcc;
function assert(bool) {
if (!bool) throw new Error('ecc library invalid');
}
diff --git a/src/index.d.ts b/src/index.d.ts
index b93c2aa40..420979ffe 100644
--- a/src/index.d.ts
+++ b/src/index.d.ts
@@ -12,3 +12,4 @@ export { Transaction } from './transaction';
export { Network } from './networks';
export { Payment, PaymentCreator, PaymentOpts, Stack, StackElement, } from './payments';
export { Input as TxInput, Output as TxOutput } from './transaction';
+export { initEccLib } from './ecc_lib';
diff --git a/src/index.js b/src/index.js
index 983b0cc76..25d0b5a22 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,6 +1,6 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.Transaction = exports.opcodes = exports.Psbt = exports.Block = exports.script = exports.payments = exports.networks = exports.crypto = exports.address = void 0;
+exports.initEccLib = exports.Transaction = exports.opcodes = exports.Psbt = exports.Block = exports.script = exports.payments = exports.networks = exports.crypto = exports.address = void 0;
const address = require('./address');
exports.address = address;
const crypto = require('./crypto');
@@ -39,3 +39,10 @@ Object.defineProperty(exports, 'Transaction', {
return transaction_1.Transaction;
},
});
+var ecc_lib_1 = require('./ecc_lib');
+Object.defineProperty(exports, 'initEccLib', {
+ enumerable: true,
+ get: function() {
+ return ecc_lib_1.initEccLib;
+ },
+});
diff --git a/src/payments/index.d.ts b/src/payments/index.d.ts
index 5a71f8cc1..07c12cc48 100644
--- a/src/payments/index.d.ts
+++ b/src/payments/index.d.ts
@@ -1,6 +1,6 @@
///
import { Network } from '../networks';
-import { TinySecp256k1Interface, Taptree } from '../types';
+import { Taptree } from '../types';
import { p2data as embed } from './embed';
import { p2ms } from './p2ms';
import { p2pk } from './p2pk';
@@ -34,7 +34,6 @@ 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[];
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index c24c16914..33fa007f8 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -5,10 +5,10 @@ const buffer_1 = require('buffer');
const networks_1 = require('../networks');
const bscript = require('../script');
const types_1 = require('../types');
+const ecc_lib_1 = require('../ecc_lib');
const taprootutils_1 = require('./taprootutils');
const lazy = require('./lazy');
const bech32_1 = require('bech32');
-const verifyecc_1 = require('./verifyecc');
const OPS = bscript.OPS;
const TAPROOT_WITNESS_VERSION = 0x01;
const ANNEX_PREFIX = 0x50;
@@ -22,11 +22,6 @@ function p2tr(a, opts) {
)
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, verifyecc_1.verifyEcc)(opts.eccLib);
- return opts.eccLib;
- });
(0, types_1.typeforce)(
{
address: types_1.typeforce.maybe(types_1.typeforce.String),
@@ -132,7 +127,7 @@ function p2tr(a, opts) {
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());
+ const tweakedKey = tweakKey(o.internalPubkey, o.hash);
if (tweakedKey) return tweakedKey.x;
}
});
@@ -157,7 +152,7 @@ function p2tr(a, opts) {
});
const path = (0, taprootutils_1.findScriptPath)(hashTree, leafHash);
if (!path) return;
- const outputKey = tweakKey(a.internalPubkey, hashTree.hash, _ecc());
+ const outputKey = tweakKey(a.internalPubkey, hashTree.hash);
if (!outputKey) return;
const controlBock = buffer_1.Buffer.concat(
[
@@ -198,13 +193,13 @@ function p2tr(a, opts) {
else pubkey = a.output.slice(2);
}
if (a.internalPubkey) {
- const tweakedKey = tweakKey(a.internalPubkey, o.hash, _ecc());
+ const tweakedKey = tweakKey(a.internalPubkey, o.hash);
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))
+ if (!(0, ecc_lib_1.getEccLib)().isXOnlyPoint(pubkey))
throw new TypeError('Invalid pubkey for p2tr');
}
const hashTree = _hashTree();
@@ -267,7 +262,7 @@ function p2tr(a, opts) {
const internalPubkey = controlBlock.slice(1, 33);
if (a.internalPubkey && !a.internalPubkey.equals(internalPubkey))
throw new TypeError('Internal pubkey mismatch');
- if (!_ecc().isXOnlyPoint(internalPubkey))
+ if (!(0, ecc_lib_1.getEccLib)().isXOnlyPoint(internalPubkey))
throw new TypeError('Invalid internalPubkey for p2tr witness');
const leafVersion = controlBlock[0] & types_1.TAPLEAF_VERSION_MASK;
const script = witness[witness.length - 2];
@@ -279,7 +274,7 @@ function p2tr(a, opts) {
controlBlock,
leafHash,
);
- const outputKey = tweakKey(internalPubkey, hash, _ecc());
+ const outputKey = tweakKey(internalPubkey, hash);
if (!outputKey)
// todo: needs test data
throw new TypeError('Invalid outputKey for p2tr witness');
@@ -293,12 +288,12 @@ function p2tr(a, opts) {
return Object.assign(o, a);
}
exports.p2tr = p2tr;
-function tweakKey(pubKey, h, eccLib) {
+function tweakKey(pubKey, h) {
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);
+ const res = (0, ecc_lib_1.getEccLib)().xOnlyPointAddTweak(pubKey, tweakHash);
if (!res || res.xOnlyPubkey === null) return null;
return {
parity: res.parity,
diff --git a/src/payments/verifyecc.d.ts b/src/payments/verifyecc.d.ts
deleted file mode 100644
index 0f23affa7..000000000
--- a/src/payments/verifyecc.d.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-import { TinySecp256k1Interface } from '../types';
-export declare function verifyEcc(ecc: TinySecp256k1Interface): void;
diff --git a/src/psbt.d.ts b/src/psbt.d.ts
index 8b21ce7bb..890f9e115 100644
--- a/src/psbt.d.ts
+++ b/src/psbt.d.ts
@@ -3,7 +3,6 @@ import { Psbt as PsbtBase } from 'bip174';
import { KeyValue, PsbtGlobalUpdate, PsbtInput, PsbtInputUpdate, PsbtOutput, PsbtOutputUpdate } from 'bip174/src/lib/interfaces';
import { Network } from './networks';
import { Transaction } from './transaction';
-import { TinySecp256k1Interface } from './types';
export interface TransactionInput {
hash: string | Buffer;
index: number;
@@ -111,7 +110,6 @@ export declare class Psbt {
interface PsbtOptsOptional {
network?: Network;
maximumFeeRate?: number;
- eccLib?: TinySecp256k1Interface;
}
interface PsbtInputExtended extends PsbtInput, TransactionInput {
}
@@ -181,8 +179,7 @@ script: Buffer, // The "meaningful" locking script Buffer (redeemScript for P2SH
isSegwit: boolean, // Is it segwit?
isTapscript: boolean, // Is taproot script path?
isP2SH: boolean, // Is it P2SH?
-isP2WSH: boolean, // Is it P2WSH?
-eccLib?: TinySecp256k1Interface) => {
+isP2WSH: boolean) => {
finalScriptSig: Buffer | undefined;
finalScriptWitness: Buffer | Buffer[] | undefined;
};
diff --git a/src/psbt.js b/src/psbt.js
index 694a6cc1b..c14086d0e 100644
--- a/src/psbt.js
+++ b/src/psbt.js
@@ -79,7 +79,6 @@ class Psbt {
// We will disable exporting the Psbt when unsafe sign is active.
// because it is not BIP174 compliant.
__UNSAFE_SIGN_NONSEGWIT: false,
- __EC_LIB: opts.eccLib,
};
if (this.data.inputs.length === 0) this.setVersion(2);
// Make data hidden when enumerating
@@ -134,7 +133,6 @@ class Psbt {
address = (0, address_1.fromOutputScript)(
output.script,
this.opts.network,
- this.__CACHE.__EC_LIB,
);
} catch (_) {}
return {
@@ -237,11 +235,7 @@ class Psbt {
const { address } = outputData;
if (typeof address === 'string') {
const { network } = this.opts;
- const script = (0, address_1.toOutputScript)(
- address,
- network,
- this.__CACHE.__EC_LIB,
- );
+ const script = (0, address_1.toOutputScript)(address, network);
outputData = Object.assign(outputData, { script });
}
const c = this.__CACHE;
@@ -297,7 +291,6 @@ class Psbt {
isP2SH,
isP2WSH,
isTapscript,
- this.__CACHE.__EC_LIB,
);
if (finalScriptSig) this.data.updateInput(inputIndex, { finalScriptSig });
if (finalScriptWitness) {
@@ -326,13 +319,9 @@ class Psbt {
input.redeemScript || redeemFromFinalScriptSig(input.finalScriptSig),
input.witnessScript ||
redeemFromFinalWitnessScript(input.finalScriptWitness),
- this.__CACHE,
);
const type = result.type === 'raw' ? '' : result.type + '-';
- const mainType = classifyScript(
- result.meaningfulScript,
- this.__CACHE.__EC_LIB,
- );
+ const mainType = classifyScript(result.meaningfulScript);
return type + mainType;
}
inputHasPubkey(inputIndex, pubkey) {
@@ -769,9 +758,9 @@ function isFinalized(input) {
return !!input.finalScriptSig || !!input.finalScriptWitness;
}
function isPaymentFactory(payment) {
- return (script, eccLib) => {
+ return script => {
try {
- payment({ output: script }, { eccLib });
+ payment({ output: script });
return true;
} catch (err) {
return false;
@@ -935,9 +924,8 @@ function getFinalScripts(
isP2SH,
isP2WSH,
isTapscript = false,
- eccLib,
) {
- const scriptType = classifyScript(script, eccLib);
+ const scriptType = classifyScript(script);
if (isTapscript || !canFinalize(input, script, scriptType))
throw new Error(`Can not finalize input #${inputIndex}`);
return prepareFinalScripts(
@@ -1053,7 +1041,6 @@ function getHashForSig(
'input',
input.redeemScript,
input.witnessScript,
- cache,
);
if (['p2sh-p2wsh', 'p2wsh'].indexOf(type) >= 0) {
hash = unsignedTx.hashForWitnessV0(
@@ -1072,7 +1059,7 @@ function getHashForSig(
prevout.value,
sighashType,
);
- } else if (isP2TR(prevout.script, cache.__EC_LIB)) {
+ } else if (isP2TR(prevout.script)) {
const prevOuts = inputs.map((i, index) =>
getScriptAndAmountFromUtxo(index, i, cache),
);
@@ -1204,7 +1191,7 @@ function getScriptFromInput(inputIndex, input, cache) {
} else {
res.script = utxoScript;
}
- const isTaproot = utxoScript && isP2TR(utxoScript, cache.__EC_LIB);
+ const isTaproot = utxoScript && isP2TR(utxoScript);
// Segregated Witness versions 0 or 1
if (input.witnessScript || isP2WPKH(res.script) || isTaproot) {
res.isSegwit = true;
@@ -1410,7 +1397,6 @@ function pubkeyInInput(pubkey, input, inputIndex, cache) {
'input',
input.redeemScript,
input.witnessScript,
- cache,
);
return pubkeyInScript(pubkey, meaningfulScript);
}
@@ -1422,7 +1408,6 @@ function pubkeyInOutput(pubkey, output, outputIndex, cache) {
'output',
output.redeemScript,
output.witnessScript,
- cache,
);
return pubkeyInScript(pubkey, meaningfulScript);
}
@@ -1471,12 +1456,11 @@ function getMeaningfulScript(
ioType,
redeemScript,
witnessScript,
- cache,
) {
const isP2SH = isP2SHScript(script);
const isP2SHP2WSH = isP2SH && redeemScript && isP2WSHScript(redeemScript);
const isP2WSH = isP2WSHScript(script);
- const isP2TRScript = isP2TR(script, cache && cache.__EC_LIB);
+ const isP2TRScript = isP2TR(script);
if (isP2SH && redeemScript === undefined)
throw new Error('scriptPubkey is P2SH but redeemScript missing');
if ((isP2WSH || isP2SHP2WSH) && witnessScript === undefined)
@@ -1539,12 +1523,12 @@ function isTaprootSpend(scriptType) {
!!scriptType && (scriptType === 'taproot' || scriptType.startsWith('p2tr-'))
);
}
-function classifyScript(script, eccLib) {
+function classifyScript(script) {
if (isP2WPKH(script)) return 'witnesspubkeyhash';
if (isP2PKH(script)) return 'pubkeyhash';
if (isP2MS(script)) return 'multisig';
if (isP2PK(script)) return 'pubkey';
- if (isP2TR(script, eccLib)) return 'taproot';
+ if (isP2TR(script)) return 'taproot';
return 'nonstandard';
}
function range(n) {
diff --git a/test/address.spec.ts b/test/address.spec.ts
index be08cf803..23c18b9f6 100644
--- a/test/address.spec.ts
+++ b/test/address.spec.ts
@@ -5,6 +5,8 @@ import * as baddress from '../src/address';
import * as bscript from '../src/script';
import * as fixtures from './fixtures/address.json';
+import { initEccLib } from '../src';
+
const NETWORKS = Object.assign(
{
litecoin: {
@@ -66,14 +68,11 @@ describe('address', () => {
});
describe('fromOutputScript', () => {
+ initEccLib(ecc);
fixtures.standard.forEach(f => {
it('encodes ' + f.script.slice(0, 30) + '... (' + f.network + ')', () => {
const script = bscript.fromASM(f.script);
- const address = baddress.fromOutputScript(
- script,
- NETWORKS[f.network],
- ecc,
- );
+ const address = baddress.fromOutputScript(script, NETWORKS[f.network]);
assert.strictEqual(address, f.base58check || f.bech32!.toLowerCase());
});
@@ -84,7 +83,7 @@ describe('address', () => {
const script = bscript.fromASM(f.script);
assert.throws(() => {
- baddress.fromOutputScript(script, undefined, ecc);
+ baddress.fromOutputScript(script, undefined);
}, new RegExp(f.exception));
});
});
@@ -136,7 +135,6 @@ describe('address', () => {
const script = baddress.toOutputScript(
(f.base58check || f.bech32)!,
NETWORKS[f.network],
- ecc,
);
assert.strictEqual(bscript.toASM(script), f.script);
@@ -147,7 +145,7 @@ describe('address', () => {
it('throws when ' + (f.exception || f.paymentException), () => {
const exception = f.paymentException || `${f.address} ${f.exception}`;
assert.throws(() => {
- baddress.toOutputScript(f.address, f.network as any, ecc);
+ baddress.toOutputScript(f.address, f.network as any);
}, new RegExp(exception));
});
});
diff --git a/test/integration/taproot.spec.ts b/test/integration/taproot.spec.ts
index 05d7d154d..af1291b37 100644
--- a/test/integration/taproot.spec.ts
+++ b/test/integration/taproot.spec.ts
@@ -9,6 +9,7 @@ import { buildTapscriptFinalizer, toXOnly } from '../psbt.utils';
const rng = require('randombytes');
const regtest = regtestUtils.network;
+bitcoin.initEccLib(ecc);
const bip32 = BIP32Factory(ecc);
const ECPair = ECPairFactory(ecc);
@@ -17,7 +18,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
const myKey = bip32.fromSeed(rng(64), regtest);
const output = createKeySpendOutput(myKey.publicKey);
- const address = bitcoin.address.fromOutputScript(output, regtest, ecc);
+ const address = bitcoin.address.fromOutputScript(output, regtest);
// amount from faucet
const amount = 42e4;
// amount to send
@@ -51,10 +52,10 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
it('can create (and broadcast via 3PBP) a taproot key-path spend Transaction', async () => {
const internalKey = bip32.fromSeed(rng(64), regtest);
- const { output, address } = bitcoin.payments.p2tr(
- { internalPubkey: toXOnly(internalKey.publicKey), network: regtest },
- { eccLib: ecc },
- );
+ const { output, address } = bitcoin.payments.p2tr({
+ internalPubkey: toXOnly(internalKey.publicKey),
+ network: regtest,
+ });
// amount from faucet
const amount = 42e4;
@@ -63,7 +64,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
// get faucet
const unspent = await regtestUtils.faucetComplex(output!, amount);
- const psbt = new bitcoin.Psbt({ eccLib: ecc, network: regtest });
+ const psbt = new bitcoin.Psbt({ network: regtest });
psbt.addInput({
hash: unspent.txId,
index: 0,
@@ -102,14 +103,11 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
output: leafScript,
};
- const { output, address, hash } = bitcoin.payments.p2tr(
- {
- internalPubkey: toXOnly(internalKey.publicKey),
- scriptTree,
- network: regtest,
- },
- { eccLib: ecc },
- );
+ const { output, address, hash } = bitcoin.payments.p2tr({
+ internalPubkey: toXOnly(internalKey.publicKey),
+ scriptTree,
+ network: regtest,
+ });
// amount from faucet
const amount = 42e4;
@@ -118,7 +116,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
// get faucet
const unspent = await regtestUtils.faucetComplex(output!, amount);
- const psbt = new bitcoin.Psbt({ eccLib: ecc, network: regtest });
+ const psbt = new bitcoin.Psbt({ network: regtest });
psbt.addInput({
hash: unspent.txId,
index: 0,
@@ -206,15 +204,12 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
redeemVersion: 192,
};
- const { output, address } = bitcoin.payments.p2tr(
- {
- internalPubkey: toXOnly(internalKey.publicKey),
- scriptTree,
- redeem,
- network: regtest,
- },
- { eccLib: ecc },
- );
+ const { output, address } = bitcoin.payments.p2tr({
+ internalPubkey: toXOnly(internalKey.publicKey),
+ scriptTree,
+ redeem,
+ network: regtest,
+ });
// amount from faucet
const amount = 42e4;
@@ -223,7 +218,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
// get faucet
const unspent = await regtestUtils.faucetComplex(output!, amount);
- const psbt = new bitcoin.Psbt({ eccLib: ecc, network: regtest });
+ const psbt = new bitcoin.Psbt({ network: regtest });
psbt.addInput({
hash: unspent.txId,
index: 0,
@@ -283,15 +278,12 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
redeemVersion: 192,
};
- const { output, address } = bitcoin.payments.p2tr(
- {
- internalPubkey: toXOnly(internalKey.publicKey),
- scriptTree,
- redeem,
- network: regtest,
- },
- { eccLib: ecc },
- );
+ const { output, address } = bitcoin.payments.p2tr({
+ internalPubkey: toXOnly(internalKey.publicKey),
+ scriptTree,
+ redeem,
+ network: regtest,
+ });
// amount from faucet
const amount = 42e4;
@@ -300,7 +292,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
// get faucet
const unspent = await regtestUtils.faucetComplex(output!, amount);
- const psbt = new bitcoin.Psbt({ eccLib: ecc, network: regtest });
+ const psbt = new bitcoin.Psbt({ network: regtest });
psbt.addInput({
hash: unspent.txId,
index: 0,
@@ -382,15 +374,12 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
redeemVersion: 192,
};
- const { output, address } = bitcoin.payments.p2tr(
- {
- internalPubkey: toXOnly(internalKey.publicKey),
- scriptTree,
- redeem,
- network: regtest,
- },
- { eccLib: ecc },
- );
+ const { output, address } = bitcoin.payments.p2tr({
+ internalPubkey: toXOnly(internalKey.publicKey),
+ scriptTree,
+ redeem,
+ network: regtest,
+ });
// amount from faucet
const amount = 42e4;
@@ -399,7 +388,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
// get faucet
const unspent = await regtestUtils.faucetComplex(output!, amount);
- const psbt = new bitcoin.Psbt({ eccLib: ecc, network: regtest });
+ const psbt = new bitcoin.Psbt({ network: regtest });
psbt.addInput({
hash: unspent.txId,
index: 0,
diff --git a/test/payments.spec.ts b/test/payments.spec.ts
index e89834d3b..07b1442f9 100644
--- a/test/payments.spec.ts
+++ b/test/payments.spec.ts
@@ -3,14 +3,15 @@ import * as ecc from 'tiny-secp256k1';
import { describe, it } from 'mocha';
import { PaymentCreator } from '../src/payments';
import * as u from './payments.utils';
-import { TinySecp256k1Interface } from '../src/types';
+import { initEccLib } from '../src';
['embed', 'p2ms', 'p2pk', 'p2pkh', 'p2sh', 'p2wpkh', 'p2wsh', 'p2tr'].forEach(
p => {
describe(p, () => {
+ beforeEach(() => {
+ initEccLib(p === 'p2tr' ? ecc : undefined);
+ });
let fn: PaymentCreator;
- const eccLib: TinySecp256k1Interface | undefined =
- p === 'p2tr' ? ecc : undefined;
const payment = require('../src/payments/' + p);
if (p === 'embed') {
fn = payment.p2data;
@@ -21,10 +22,9 @@ import { TinySecp256k1Interface } from '../src/types';
const fixtures = require('./fixtures/' + p);
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);
+ const actual = fn(args, f.options);
u.equate(actual, f.expected, f.arguments);
});
@@ -33,7 +33,7 @@ import { TinySecp256k1Interface } from '../src/types';
const args = u.preform(f.arguments);
const actual = fn(
args,
- Object.assign({}, options, {
+ Object.assign({}, f.options, {
validate: false,
}),
);
@@ -43,7 +43,6 @@ import { TinySecp256k1Interface } from '../src/types';
});
fixtures.invalid.forEach((f: any) => {
- const options = Object.assign({ eccLib }, f.options || {});
it(
'throws ' +
f.exception +
@@ -52,7 +51,7 @@ import { TinySecp256k1Interface } from '../src/types';
const args = u.preform(f.arguments);
assert.throws(() => {
- fn(args, options);
+ fn(args, f.options);
}, new RegExp(f.exception));
},
);
diff --git a/test/psbt.spec.ts b/test/psbt.spec.ts
index 871142194..76ab4da49 100644
--- a/test/psbt.spec.ts
+++ b/test/psbt.spec.ts
@@ -5,6 +5,8 @@ import * as crypto from 'crypto';
import ECPairFactory from 'ecpair';
import { describe, it } from 'mocha';
+import { initEccLib } from '../src';
+
const bip32 = BIP32Factory(ecc);
const ECPair = ECPairFactory(ecc);
@@ -79,6 +81,10 @@ const failedAsyncSigner = (publicKey: Buffer): SignerAsync => {
// const b = (hex: string) => Buffer.from(hex, 'hex');
describe(`Psbt`, () => {
+ beforeEach(() => {
+ // provide the ECC lib only when required
+ initEccLib(undefined);
+ });
describe('BIP174 Test Vectors', () => {
fixtures.bip174.invalid.forEach(f => {
it(`Invalid: ${f.description}`, () => {
@@ -140,8 +146,8 @@ describe(`Psbt`, () => {
fixtures.bip174.signer.forEach(f => {
it('Signs PSBT to the expected result', () => {
- const opts = f.isTaproot ? { eccLib: ecc } : {};
- const psbt = Psbt.fromBase64(f.psbt, opts);
+ if (f.isTaproot) initEccLib(ecc);
+ const psbt = Psbt.fromBase64(f.psbt);
f.keys.forEach(({ inputToSign, WIF }) => {
const keyPair = ECPair.fromWIF(WIF, NETWORKS.testnet);
@@ -168,8 +174,8 @@ describe(`Psbt`, () => {
fixtures.bip174.finalizer.forEach(f => {
it('Finalizes inputs and gives the expected PSBT', () => {
- const opts = f.isTaproot ? { eccLib: ecc } : {};
- const psbt = Psbt.fromBase64(f.psbt, opts);
+ if (f.isTaproot) initEccLib(ecc);
+ const psbt = Psbt.fromBase64(f.psbt);
psbt.finalizeAllInputs();
@@ -964,7 +970,8 @@ describe(`Psbt`, () => {
describe('validateSignaturesOfTaprootInput', () => {
const f = fixtures.validateSignaturesOfTaprootInput;
it('Correctly validates a signature', () => {
- const psbt = Psbt.fromBase64(f.psbt, { eccLib: ecc });
+ initEccLib(ecc);
+ const psbt = Psbt.fromBase64(f.psbt);
assert.strictEqual(
psbt.validateSignaturesOfInput(f.index, schnorrValidator),
true,
@@ -972,7 +979,8 @@ describe(`Psbt`, () => {
});
it('Correctly validates a signature against a pubkey', () => {
- const psbt = Psbt.fromBase64(f.psbt, { eccLib: ecc });
+ initEccLib(ecc);
+ const psbt = Psbt.fromBase64(f.psbt);
assert.strictEqual(
psbt.validateSignaturesOfInput(
f.index,
@@ -993,8 +1001,9 @@ describe(`Psbt`, () => {
describe('finalizeTaprootInput', () => {
it('Correctly finalizes a taproot script-path spend', () => {
+ initEccLib(ecc);
const f = fixtures.finalizeTaprootScriptPathSpendInput;
- const psbt = Psbt.fromBase64(f.psbt, { eccLib: ecc });
+ const psbt = Psbt.fromBase64(f.psbt);
const tapscriptFinalizer = buildTapscriptFinalizer(
f.internalPublicKey as any,
f.scriptTree,
@@ -1005,8 +1014,9 @@ describe(`Psbt`, () => {
});
it('Failes to finalize a taproot script-path spend when a finalizer is not provided', () => {
+ initEccLib(ecc);
const f = fixtures.finalizeTaprootScriptPathSpendInput;
- const psbt = Psbt.fromBase64(f.psbt, { eccLib: ecc });
+ const psbt = Psbt.fromBase64(f.psbt);
assert.throws(() => {
psbt.finalizeInput(0);
diff --git a/test/psbt.utils.ts b/test/psbt.utils.ts
index 59cccb323..100aa27e7 100644
--- a/test/psbt.utils.ts
+++ b/test/psbt.utils.ts
@@ -1,6 +1,5 @@
import { PsbtInput } from 'bip174/src/lib/interfaces';
import * as bitcoin from './..';
-import { TinySecp256k1Interface } from '../src/types';
/**
* Build finalizer function for Tapscript.
@@ -20,7 +19,6 @@ const buildTapscriptFinalizer = (
_isP2SH: boolean,
_isP2WSH: boolean,
_isTapscript: boolean,
- eccLib?: TinySecp256k1Interface,
): {
finalScriptSig: Buffer | undefined;
finalScriptWitness: Buffer | Buffer[] | undefined;
@@ -29,15 +27,12 @@ const buildTapscriptFinalizer = (
throw new Error(`Can not finalize taproot input #${inputIndex}`);
try {
- const tapscriptSpend = bitcoin.payments.p2tr(
- {
- internalPubkey: toXOnly(internalPubkey),
- scriptTree,
- redeem: { output: script },
- network,
- },
- { eccLib },
- );
+ const tapscriptSpend = bitcoin.payments.p2tr({
+ internalPubkey: toXOnly(internalPubkey),
+ scriptTree,
+ redeem: { output: script },
+ network,
+ });
const sigs = (input.partialSig || []).map(ps => ps.signature) as Buffer[];
const finalScriptWitness = sigs.concat(
tapscriptSpend.witness as Buffer[],
diff --git a/ts_src/address.ts b/ts_src/address.ts
index 62bcf2ef7..8004b2668 100644
--- a/ts_src/address.ts
+++ b/ts_src/address.ts
@@ -2,13 +2,7 @@ import { Network } from './networks';
import * as networks from './networks';
import * as payments from './payments';
import * as bscript from './script';
-import {
- typeforce,
- tuple,
- Hash160bit,
- UInt8,
- TinySecp256k1Interface,
-} from './types';
+import { typeforce, tuple, Hash160bit, UInt8 } from './types';
import { bech32, bech32m } from 'bech32';
import * as bs58check from 'bs58check';
export interface Base58CheckResult {
@@ -119,11 +113,7 @@ export function toBech32(
: bech32m.encode(prefix, words);
}
-export function fromOutputScript(
- output: Buffer,
- network?: Network,
- eccLib?: TinySecp256k1Interface,
-): string {
+export function fromOutputScript(output: Buffer, network?: Network): string {
// TODO: Network
network = network || networks.bitcoin;
@@ -140,8 +130,7 @@ export function fromOutputScript(
return payments.p2wsh({ output, network }).address as string;
} catch (e) {}
try {
- if (eccLib)
- return payments.p2tr({ output, network }, { eccLib }).address as string;
+ return payments.p2tr({ output, network }).address as string;
} catch (e) {}
try {
return _toFutureSegwitAddress(output, network);
@@ -150,11 +139,7 @@ export function fromOutputScript(
throw new Error(bscript.toASM(output) + ' has no matching Address');
}
-export function toOutputScript(
- address: string,
- network?: Network,
- eccLib?: TinySecp256k1Interface,
-): Buffer {
+export function toOutputScript(address: string, network?: Network): Buffer {
network = network || networks.bitcoin;
let decodeBase58: Base58CheckResult | undefined;
@@ -182,9 +167,8 @@ export function toOutputScript(
if (decodeBech32.data.length === 32)
return payments.p2wsh({ hash: decodeBech32.data }).output as Buffer;
} else if (decodeBech32.version === 1) {
- if (decodeBech32.data.length === 32 && eccLib)
- return payments.p2tr({ pubkey: decodeBech32.data }, { eccLib })
- .output as Buffer;
+ if (decodeBech32.data.length === 32)
+ return payments.p2tr({ pubkey: decodeBech32.data }).output as Buffer;
} else if (
decodeBech32.version >= FUTURE_SEGWIT_MIN_VERSION &&
decodeBech32.version <= FUTURE_SEGWIT_MAX_VERSION &&
diff --git a/ts_src/payments/verifyecc.ts b/ts_src/ecc_lib.ts
similarity index 73%
rename from ts_src/payments/verifyecc.ts
rename to ts_src/ecc_lib.ts
index 75c2c5062..eb4c59eeb 100644
--- a/ts_src/payments/verifyecc.ts
+++ b/ts_src/ecc_lib.ts
@@ -1,8 +1,29 @@
-import { TinySecp256k1Interface } from '../types';
+import { TinySecp256k1Interface } from './types';
+
+const _ECCLIB_CACHE: { eccLib?: TinySecp256k1Interface } = {};
+
+export function initEccLib(eccLib: TinySecp256k1Interface | undefined): void {
+ if (!eccLib) {
+ // allow clearing the library
+ _ECCLIB_CACHE.eccLib = eccLib;
+ } else if (eccLib !== _ECCLIB_CACHE.eccLib) {
+ // new instance, verify it
+ verifyEcc(eccLib!);
+ _ECCLIB_CACHE.eccLib = eccLib;
+ }
+}
+
+export function getEccLib(): TinySecp256k1Interface {
+ if (!_ECCLIB_CACHE.eccLib)
+ throw new Error(
+ 'No ECC Library provided. You must call initEccLib() with a valid TinySecp256k1Interface instance',
+ );
+ return _ECCLIB_CACHE.eccLib;
+}
const h = (hex: string): Buffer => Buffer.from(hex, 'hex');
-export function verifyEcc(ecc: TinySecp256k1Interface): void {
+function verifyEcc(ecc: TinySecp256k1Interface): void {
assert(typeof ecc.isXOnlyPoint === 'function');
assert(
ecc.isXOnlyPoint(
diff --git a/ts_src/index.ts b/ts_src/index.ts
index d8b8619d1..64c4294c2 100644
--- a/ts_src/index.ts
+++ b/ts_src/index.ts
@@ -29,3 +29,4 @@ export {
StackElement,
} from './payments';
export { Input as TxInput, Output as TxOutput } from './transaction';
+export { initEccLib } from './ecc_lib';
diff --git a/ts_src/payments/index.ts b/ts_src/payments/index.ts
index 70d7614b7..ca72f72cb 100644
--- a/ts_src/payments/index.ts
+++ b/ts_src/payments/index.ts
@@ -1,5 +1,5 @@
import { Network } from '../networks';
-import { TinySecp256k1Interface, Taptree } from '../types';
+import { Taptree } from '../types';
import { p2data as embed } from './embed';
import { p2ms } from './p2ms';
import { p2pk } from './p2pk';
@@ -37,7 +37,6 @@ export type PaymentFunction = () => Payment;
export interface PaymentOpts {
validate?: boolean;
allowIncomplete?: boolean;
- eccLib?: TinySecp256k1Interface;
}
export type StackElement = Buffer | number;
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index 47a76a114..09a894262 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -1,12 +1,8 @@
import { Buffer as NBuffer } from 'buffer';
import { bitcoin as BITCOIN_NETWORK } from '../networks';
import * as bscript from '../script';
-import {
- typeforce as typef,
- isTaptree,
- TinySecp256k1Interface,
- TAPLEAF_VERSION_MASK,
-} from '../types';
+import { typeforce as typef, isTaptree, TAPLEAF_VERSION_MASK } from '../types';
+import { getEccLib } from '../ecc_lib';
import {
toHashTree,
rootHashFromPath,
@@ -18,7 +14,6 @@ import {
import { Payment, PaymentOpts } from './index';
import * as lazy from './lazy';
import { bech32m } from 'bech32';
-import { verifyEcc } from './verifyecc';
const OPS = bscript.OPS;
const TAPROOT_WITNESS_VERSION = 0x01;
@@ -36,13 +31,6 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
opts = Object.assign({ validate: true }, opts || {});
- const _ecc = lazy.value(() => {
- if (!opts!.eccLib) throw new Error('ECC Library is missing for p2tr.');
-
- verifyEcc(opts!.eccLib);
- return opts!.eccLib;
- });
-
typef(
{
address: typef.maybe(typef.String),
@@ -149,7 +137,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
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());
+ const tweakedKey = tweakKey(o.internalPubkey, o.hash);
if (tweakedKey) return tweakedKey.x;
}
});
@@ -175,7 +163,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
});
const path = findScriptPath(hashTree, leafHash);
if (!path) return;
- const outputKey = tweakKey(a.internalPubkey, hashTree.hash, _ecc());
+ const outputKey = tweakKey(a.internalPubkey, hashTree.hash);
if (!outputKey) return;
const controlBock = NBuffer.concat(
[
@@ -220,14 +208,14 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
}
if (a.internalPubkey) {
- const tweakedKey = tweakKey(a.internalPubkey, o.hash, _ecc());
+ const tweakedKey = tweakKey(a.internalPubkey, o.hash);
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))
+ if (!getEccLib().isXOnlyPoint(pubkey))
throw new TypeError('Invalid pubkey for p2tr');
}
@@ -302,7 +290,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
if (a.internalPubkey && !a.internalPubkey.equals(internalPubkey))
throw new TypeError('Internal pubkey mismatch');
- if (!_ecc().isXOnlyPoint(internalPubkey))
+ if (!getEccLib().isXOnlyPoint(internalPubkey))
throw new TypeError('Invalid internalPubkey for p2tr witness');
const leafVersion = controlBlock[0] & TAPLEAF_VERSION_MASK;
@@ -311,7 +299,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
const leafHash = tapleafHash({ output: script, version: leafVersion });
const hash = rootHashFromPath(controlBlock, leafHash);
- const outputKey = tweakKey(internalPubkey, hash, _ecc());
+ const outputKey = tweakKey(internalPubkey, hash);
if (!outputKey)
// todo: needs test data
throw new TypeError('Invalid outputKey for p2tr witness');
@@ -336,7 +324,6 @@ interface TweakedPublicKey {
function tweakKey(
pubKey: Buffer,
h: Buffer | undefined,
- eccLib: TinySecp256k1Interface,
): TweakedPublicKey | null {
if (!NBuffer.isBuffer(pubKey)) return null;
if (pubKey.length !== 32) return null;
@@ -344,7 +331,7 @@ function tweakKey(
const tweakHash = tapTweakHash(pubKey, h);
- const res = eccLib.xOnlyPointAddTweak(pubKey, tweakHash);
+ const res = getEccLib().xOnlyPointAddTweak(pubKey, tweakHash);
if (!res || res.xOnlyPubkey === null) return null;
return {
diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts
index 479421636..1517acffd 100644
--- a/ts_src/psbt.ts
+++ b/ts_src/psbt.ts
@@ -22,7 +22,6 @@ import * as payments from './payments';
import * as bscript from './script';
import { Output, Transaction } from './transaction';
import { tapleafHash } from './payments/taprootutils';
-import { TinySecp256k1Interface } from './types';
export interface TransactionInput {
hash: string | Buffer;
@@ -140,7 +139,6 @@ export class Psbt {
// We will disable exporting the Psbt when unsafe sign is active.
// because it is not BIP174 compliant.
__UNSAFE_SIGN_NONSEGWIT: false,
- __EC_LIB: opts.eccLib,
};
if (this.data.inputs.length === 0) this.setVersion(2);
@@ -191,11 +189,7 @@ export class Psbt {
return this.__CACHE.__TX.outs.map(output => {
let address;
try {
- address = fromOutputScript(
- output.script,
- this.opts.network,
- this.__CACHE.__EC_LIB,
- );
+ address = fromOutputScript(output.script, this.opts.network);
} catch (_) {}
return {
script: cloneBuffer(output.script),
@@ -309,7 +303,7 @@ export class Psbt {
const { address } = outputData as any;
if (typeof address === 'string') {
const { network } = this.opts;
- const script = toOutputScript(address, network, this.__CACHE.__EC_LIB);
+ const script = toOutputScript(address, network);
outputData = Object.assign(outputData, { script });
}
const c = this.__CACHE;
@@ -375,7 +369,6 @@ export class Psbt {
isP2SH,
isP2WSH,
isTapscript,
- this.__CACHE.__EC_LIB,
);
if (finalScriptSig) this.data.updateInput(inputIndex, { finalScriptSig });
@@ -407,13 +400,9 @@ export class Psbt {
input.redeemScript || redeemFromFinalScriptSig(input.finalScriptSig),
input.witnessScript ||
redeemFromFinalWitnessScript(input.finalScriptWitness),
- this.__CACHE,
);
const type = result.type === 'raw' ? '' : result.type + '-';
- const mainType = classifyScript(
- result.meaningfulScript,
- this.__CACHE.__EC_LIB,
- );
+ const mainType = classifyScript(result.meaningfulScript);
return (type + mainType) as AllScriptType;
}
@@ -821,13 +810,11 @@ interface PsbtCache {
__FEE?: number;
__EXTRACTED_TX?: Transaction;
__UNSAFE_SIGN_NONSEGWIT: boolean;
- __EC_LIB?: TinySecp256k1Interface;
}
interface PsbtOptsOptional {
network?: Network;
maximumFeeRate?: number;
- eccLib?: TinySecp256k1Interface;
}
interface PsbtOpts {
@@ -1017,12 +1004,10 @@ function isFinalized(input: PsbtInput): boolean {
return !!input.finalScriptSig || !!input.finalScriptWitness;
}
-function isPaymentFactory(
- payment: any,
-): (script: Buffer, eccLib?: any) => boolean {
- return (script: Buffer, eccLib?: any): boolean => {
+function isPaymentFactory(payment: any): (script: Buffer) => boolean {
+ return (script: Buffer): boolean => {
try {
- payment({ output: script }, { eccLib });
+ payment({ output: script });
return true;
} catch (err) {
return false;
@@ -1225,7 +1210,6 @@ type FinalScriptsFunc = (
isTapscript: boolean, // Is taproot script path?
isP2SH: boolean, // Is it P2SH?
isP2WSH: boolean, // Is it P2WSH?
- eccLib?: TinySecp256k1Interface, // optional lib for checking taproot validity
) => {
finalScriptSig: Buffer | undefined;
finalScriptWitness: Buffer | Buffer[] | undefined;
@@ -1239,12 +1223,11 @@ function getFinalScripts(
isP2SH: boolean,
isP2WSH: boolean,
isTapscript: boolean = false,
- eccLib?: TinySecp256k1Interface,
): {
finalScriptSig: Buffer | undefined;
finalScriptWitness: Buffer | undefined;
} {
- const scriptType = classifyScript(script, eccLib);
+ const scriptType = classifyScript(script);
if (isTapscript || !canFinalize(input, script, scriptType))
throw new Error(`Can not finalize input #${inputIndex}`);
return prepareFinalScripts(
@@ -1379,7 +1362,6 @@ function getHashForSig(
'input',
input.redeemScript,
input.witnessScript,
- cache,
);
if (['p2sh-p2wsh', 'p2wsh'].indexOf(type) >= 0) {
@@ -1399,7 +1381,7 @@ function getHashForSig(
prevout.value,
sighashType,
);
- } else if (isP2TR(prevout.script, cache.__EC_LIB)) {
+ } else if (isP2TR(prevout.script)) {
const prevOuts: Output[] = inputs.map((i, index) =>
getScriptAndAmountFromUtxo(index, i, cache),
);
@@ -1553,7 +1535,7 @@ function getScriptFromInput(
res.script = utxoScript;
}
- const isTaproot = utxoScript && isP2TR(utxoScript, cache.__EC_LIB);
+ const isTaproot = utxoScript && isP2TR(utxoScript);
// Segregated Witness versions 0 or 1
if (input.witnessScript || isP2WPKH(res.script!) || isTaproot) {
@@ -1816,7 +1798,6 @@ function pubkeyInInput(
'input',
input.redeemScript,
input.witnessScript,
- cache,
);
return pubkeyInScript(pubkey, meaningfulScript);
}
@@ -1834,7 +1815,6 @@ function pubkeyInOutput(
'output',
output.redeemScript,
output.witnessScript,
- cache,
);
return pubkeyInScript(pubkey, meaningfulScript);
}
@@ -1893,7 +1873,6 @@ function getMeaningfulScript(
ioType: 'input' | 'output',
redeemScript?: Buffer,
witnessScript?: Buffer,
- cache?: PsbtCache,
): {
meaningfulScript: Buffer;
type: 'p2sh' | 'p2wsh' | 'p2sh-p2wsh' | 'p2tr' | 'raw';
@@ -1901,7 +1880,7 @@ function getMeaningfulScript(
const isP2SH = isP2SHScript(script);
const isP2SHP2WSH = isP2SH && redeemScript && isP2WSHScript(redeemScript);
const isP2WSH = isP2WSHScript(script);
- const isP2TRScript = isP2TR(script, cache && cache.__EC_LIB);
+ const isP2TRScript = isP2TR(script);
if (isP2SH && redeemScript === undefined)
throw new Error('scriptPubkey is P2SH but redeemScript missing');
@@ -2002,15 +1981,12 @@ type ScriptType =
| 'pubkey'
| 'taproot'
| 'nonstandard';
-function classifyScript(
- script: Buffer,
- eccLib?: TinySecp256k1Interface,
-): ScriptType {
+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, eccLib)) return 'taproot';
+ if (isP2TR(script)) return 'taproot';
return 'nonstandard';
}
From 4fd164e200093a59d073a1ce19d9c34de48c0a84 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Fri, 1 Apr 2022 17:56:26 +0300
Subject: [PATCH 072/144] refactor: move tweakKey() to taproot utils
---
src/payments/p2tr.js | 23 ++++--------
src/payments/taprootutils.d.ts | 7 +++-
src/payments/taprootutils.js | 18 ++++++++--
ts_src/payments/p2tr.ts | 26 +-------------
ts_src/payments/taprootutils.ts | 63 +++++++++++++++++++++++----------
5 files changed, 74 insertions(+), 63 deletions(-)
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index 33fa007f8..5f235abcb 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -127,7 +127,7 @@ function p2tr(a, opts) {
if (a.output) return a.output.slice(2);
if (a.address) return _address().data;
if (o.internalPubkey) {
- const tweakedKey = tweakKey(o.internalPubkey, o.hash);
+ const tweakedKey = (0, taprootutils_1.tweakKey)(o.internalPubkey, o.hash);
if (tweakedKey) return tweakedKey.x;
}
});
@@ -152,7 +152,10 @@ function p2tr(a, opts) {
});
const path = (0, taprootutils_1.findScriptPath)(hashTree, leafHash);
if (!path) return;
- const outputKey = tweakKey(a.internalPubkey, hashTree.hash);
+ const outputKey = (0, taprootutils_1.tweakKey)(
+ a.internalPubkey,
+ hashTree.hash,
+ );
if (!outputKey) return;
const controlBock = buffer_1.Buffer.concat(
[
@@ -193,7 +196,7 @@ function p2tr(a, opts) {
else pubkey = a.output.slice(2);
}
if (a.internalPubkey) {
- const tweakedKey = tweakKey(a.internalPubkey, o.hash);
+ const tweakedKey = (0, taprootutils_1.tweakKey)(a.internalPubkey, o.hash);
if (pubkey.length > 0 && !pubkey.equals(tweakedKey.x))
throw new TypeError('Pubkey mismatch');
else pubkey = tweakedKey.x;
@@ -274,7 +277,7 @@ function p2tr(a, opts) {
controlBlock,
leafHash,
);
- const outputKey = tweakKey(internalPubkey, hash);
+ const outputKey = (0, taprootutils_1.tweakKey)(internalPubkey, hash);
if (!outputKey)
// todo: needs test data
throw new TypeError('Invalid outputKey for p2tr witness');
@@ -288,18 +291,6 @@ function p2tr(a, opts) {
return Object.assign(o, a);
}
exports.p2tr = p2tr;
-function tweakKey(pubKey, h) {
- 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 = (0, ecc_lib_1.getEccLib)().xOnlyPointAddTweak(pubKey, tweakHash);
- if (!res || res.xOnlyPubkey === null) return null;
- return {
- parity: res.parity,
- x: buffer_1.Buffer.from(res.xOnlyPubkey),
- };
-}
function stacksEqual(a, b) {
if (a.length !== b.length) return false;
return a.every((x, i) => {
diff --git a/src/payments/taprootutils.d.ts b/src/payments/taprootutils.d.ts
index a5739c44f..371595f31 100644
--- a/src/payments/taprootutils.d.ts
+++ b/src/payments/taprootutils.d.ts
@@ -1,7 +1,6 @@
///
import { Tapleaf, Taptree } from '../types';
export declare const LEAF_VERSION_TAPSCRIPT = 192;
-export declare function rootHashFromPath(controlBlock: Buffer, leafHash: Buffer): Buffer;
interface HashLeaf {
hash: Buffer;
}
@@ -10,6 +9,10 @@ interface HashBranch {
left: HashTree;
right: HashTree;
}
+interface TweakedPublicKey {
+ parity: number;
+ x: Buffer;
+}
/**
* Binary tree representing leaf, branch, and root node hashes of a Taptree.
* Each node contains a hash, and potentially left and right branch hashes.
@@ -17,6 +20,7 @@ interface HashBranch {
* and calculating merkle inclusion proofs when constructing a control block.
*/
export declare type HashTree = HashLeaf | HashBranch;
+export declare function rootHashFromPath(controlBlock: Buffer, leafHash: Buffer): Buffer;
/**
* Build a hash tree of merkle nodes from the scripts binary tree.
* @param scriptTree - the tree of scripts to pairwise hash.
@@ -33,4 +37,5 @@ export declare function toHashTree(scriptTree: Taptree): HashTree;
export declare function findScriptPath(node: HashTree, hash: Buffer): Buffer[] | undefined;
export declare function tapleafHash(leaf: Tapleaf): Buffer;
export declare function tapTweakHash(pubKey: Buffer, h: Buffer | undefined): Buffer;
+export declare function tweakKey(pubKey: Buffer, h: Buffer | undefined): TweakedPublicKey | null;
export {};
diff --git a/src/payments/taprootutils.js b/src/payments/taprootutils.js
index 85576960b..26d97d684 100644
--- a/src/payments/taprootutils.js
+++ b/src/payments/taprootutils.js
@@ -1,11 +1,13 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.tapTweakHash = exports.tapleafHash = exports.findScriptPath = exports.toHashTree = exports.rootHashFromPath = exports.LEAF_VERSION_TAPSCRIPT = void 0;
+exports.tweakKey = exports.tapTweakHash = exports.tapleafHash = exports.findScriptPath = exports.toHashTree = exports.rootHashFromPath = exports.LEAF_VERSION_TAPSCRIPT = void 0;
const buffer_1 = require('buffer');
+const ecc_lib_1 = require('../ecc_lib');
const bcrypto = require('../crypto');
const bufferutils_1 = require('../bufferutils');
const types_1 = require('../types');
exports.LEAF_VERSION_TAPSCRIPT = 0xc0;
+const isHashBranch = ht => 'left' in ht && 'right' in ht;
function rootHashFromPath(controlBlock, leafHash) {
const m = (controlBlock.length - 33) / 32;
let kj = leafHash;
@@ -20,7 +22,6 @@ function rootHashFromPath(controlBlock, leafHash) {
return kj;
}
exports.rootHashFromPath = rootHashFromPath;
-const isHashBranch = ht => 'left' in ht && 'right' in ht;
/**
* Build a hash tree of merkle nodes from the scripts binary tree.
* @param scriptTree - the tree of scripts to pairwise hash.
@@ -76,6 +77,19 @@ function tapTweakHash(pubKey, h) {
);
}
exports.tapTweakHash = tapTweakHash;
+function tweakKey(pubKey, h) {
+ if (!buffer_1.Buffer.isBuffer(pubKey)) return null;
+ if (pubKey.length !== 32) return null;
+ if (h && h.length !== 32) return null;
+ const tweakHash = tapTweakHash(pubKey, h);
+ const res = (0, ecc_lib_1.getEccLib)().xOnlyPointAddTweak(pubKey, tweakHash);
+ if (!res || res.xOnlyPubkey === null) return null;
+ return {
+ parity: res.parity,
+ x: buffer_1.Buffer.from(res.xOnlyPubkey),
+ };
+}
+exports.tweakKey = tweakKey;
function tapBranchHash(a, b) {
return bcrypto.taggedHash('TapBranch', buffer_1.Buffer.concat([a, b]));
}
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index 09a894262..220bdb74f 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -8,7 +8,7 @@ import {
rootHashFromPath,
findScriptPath,
tapleafHash,
- tapTweakHash,
+ tweakKey,
LEAF_VERSION_TAPSCRIPT,
} from './taprootutils';
import { Payment, PaymentOpts } from './index';
@@ -316,30 +316,6 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
return Object.assign(o, a);
}
-interface TweakedPublicKey {
- parity: number;
- x: Buffer;
-}
-
-function tweakKey(
- pubKey: Buffer,
- h: Buffer | undefined,
-): 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 = getEccLib().xOnlyPointAddTweak(pubKey, tweakHash);
- if (!res || res.xOnlyPubkey === null) return null;
-
- return {
- parity: res.parity,
- x: NBuffer.from(res.xOnlyPubkey),
- };
-}
-
function stacksEqual(a: Buffer[], b: Buffer[]): boolean {
if (a.length !== b.length) return false;
diff --git a/ts_src/payments/taprootutils.ts b/ts_src/payments/taprootutils.ts
index 97cc1f6d8..39d815e44 100644
--- a/ts_src/payments/taprootutils.ts
+++ b/ts_src/payments/taprootutils.ts
@@ -1,4 +1,5 @@
import { Buffer as NBuffer } from 'buffer';
+import { getEccLib } from '../ecc_lib';
import * as bcrypto from '../crypto';
import { varuint } from '../bufferutils';
@@ -6,25 +7,6 @@ import { Tapleaf, Taptree, isTapleaf } from '../types';
export const LEAF_VERSION_TAPSCRIPT = 0xc0;
-export function rootHashFromPath(
- controlBlock: Buffer,
- leafHash: Buffer,
-): Buffer {
- const m = (controlBlock.length - 33) / 32;
-
- let kj = leafHash;
- for (let j = 0; j < m; j++) {
- const ej = controlBlock.slice(33 + 32 * j, 65 + 32 * j);
- if (kj.compare(ej) < 0) {
- kj = tapBranchHash(kj, ej);
- } else {
- kj = tapBranchHash(ej, kj);
- }
- }
-
- return kj;
-}
-
interface HashLeaf {
hash: Buffer;
}
@@ -35,6 +17,11 @@ interface HashBranch {
right: HashTree;
}
+interface TweakedPublicKey {
+ parity: number;
+ x: Buffer;
+}
+
const isHashBranch = (ht: HashTree): ht is HashBranch =>
'left' in ht && 'right' in ht;
@@ -46,6 +33,25 @@ const isHashBranch = (ht: HashTree): ht is HashBranch =>
*/
export type HashTree = HashLeaf | HashBranch;
+export function rootHashFromPath(
+ controlBlock: Buffer,
+ leafHash: Buffer,
+): Buffer {
+ const m = (controlBlock.length - 33) / 32;
+
+ let kj = leafHash;
+ for (let j = 0; j < m; j++) {
+ const ej = controlBlock.slice(33 + 32 * j, 65 + 32 * j);
+ if (kj.compare(ej) < 0) {
+ kj = tapBranchHash(kj, ej);
+ } else {
+ kj = tapBranchHash(ej, kj);
+ }
+ }
+
+ return kj;
+}
+
/**
* Build a hash tree of merkle nodes from the scripts binary tree.
* @param scriptTree - the tree of scripts to pairwise hash.
@@ -104,6 +110,25 @@ export function tapTweakHash(pubKey: Buffer, h: Buffer | undefined): Buffer {
);
}
+export function tweakKey(
+ pubKey: Buffer,
+ h: Buffer | undefined,
+): 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 = getEccLib().xOnlyPointAddTweak(pubKey, tweakHash);
+ if (!res || res.xOnlyPubkey === null) return null;
+
+ return {
+ parity: res.parity,
+ x: NBuffer.from(res.xOnlyPubkey),
+ };
+}
+
function tapBranchHash(a: Buffer, b: Buffer): Buffer {
return bcrypto.taggedHash('TapBranch', NBuffer.concat([a, b]));
}
From 9d4fdcdec4c9002ecd5623345cfc6ff2209f684c Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Fri, 1 Apr 2022 17:58:55 +0300
Subject: [PATCH 073/144] fix: use witness without annex for o.signature
---
src/payments/p2tr.js | 5 +++--
ts_src/payments/p2tr.ts | 5 +++--
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index 5f235abcb..cb16ab25e 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -139,8 +139,9 @@ function p2tr(a, opts) {
});
lazy.prop(o, 'signature', () => {
if (a.signature) return a.signature;
- if (!a.witness || a.witness.length !== 1) return;
- return a.witness[0];
+ const witness = _witness(); // witness without annex
+ if (!witness || witness.length !== 1) return;
+ return witness[0];
});
lazy.prop(o, 'witness', () => {
if (a.witness) return a.witness;
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index 220bdb74f..00b9e59ad 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -149,8 +149,9 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
});
lazy.prop(o, 'signature', () => {
if (a.signature) return a.signature;
- if (!a.witness || a.witness.length !== 1) return;
- return a.witness[0];
+ const witness = _witness(); // witness without annex
+ if (!witness || witness.length !== 1) return;
+ return witness[0];
});
lazy.prop(o, 'witness', () => {
From 3af7c11040164c1582869e06b2f3a4e2cb7e4c30 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Fri, 20 May 2022 14:00:23 +0300
Subject: [PATCH 074/144] feat: use BIP371 fields for taproot inputs
- does not cover `TapBip32Derivation`
- does not cover taproot outputs
---
package-lock.json | 6 +-
package.json | 2 +-
src/psbt.d.ts | 26 +-
src/psbt.js | 712 +++++++++++++++++----------
src/psbt/bip371.d.ts | 19 +
src/psbt/bip371.js | 181 +++++++
src/psbt/psbtutils.d.ts | 11 +
src/psbt/psbtutils.js | 66 +++
test/fixtures/psbt.json | 172 ++++++-
test/integration/taproot.spec.ts | 92 ++--
test/psbt.spec.ts | 119 ++++-
test/psbt.utils.ts | 49 --
ts_src/psbt.ts | 810 +++++++++++++++++++++----------
ts_src/psbt/bip371.ts | 240 +++++++++
ts_src/psbt/psbtutils.ts | 73 +++
15 files changed, 1939 insertions(+), 639 deletions(-)
create mode 100644 src/psbt/bip371.d.ts
create mode 100644 src/psbt/bip371.js
create mode 100644 src/psbt/psbtutils.d.ts
create mode 100644 src/psbt/psbtutils.js
delete mode 100644 test/psbt.utils.ts
create mode 100644 ts_src/psbt/bip371.ts
create mode 100644 ts_src/psbt/psbtutils.ts
diff --git a/package-lock.json b/package-lock.json
index 62d5ff8a9..7cb07959e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -647,9 +647,9 @@
"dev": true
},
"bip174": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/bip174/-/bip174-2.0.1.tgz",
- "integrity": "sha512-i3X26uKJOkDTAalYAp0Er+qGMDhrbbh2o93/xiPyAN2s25KrClSpe3VXo/7mNJoqA5qfko8rLS2l3RWZgYmjKQ=="
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/bip174/-/bip174-2.1.0.tgz",
+ "integrity": "sha512-lkc0XyiX9E9KiVAS1ZiOqK1xfiwvf4FXDDdkDq5crcDzOq+xGytY+14qCsqz7kCiy8rpN1CRNfacRhf9G3JNSA=="
},
"bip32": {
"version": "3.0.1",
diff --git a/package.json b/package.json
index c78538ba0..9cecfc352 100644
--- a/package.json
+++ b/package.json
@@ -50,7 +50,7 @@
],
"dependencies": {
"bech32": "^2.0.0",
- "bip174": "^2.0.1",
+ "bip174": "^2.1.0",
"bs58check": "^2.1.2",
"create-hash": "^1.1.0",
"ripemd160": "^2.0.2",
diff --git a/src/psbt.d.ts b/src/psbt.d.ts
index 890f9e115..4c622b31f 100644
--- a/src/psbt.d.ts
+++ b/src/psbt.d.ts
@@ -80,7 +80,10 @@ export declare class Psbt {
getFeeRate(): number;
getFee(): number;
finalizeAllInputs(): this;
- finalizeInput(inputIndex: number, finalScriptsFunc?: FinalScriptsFunc): this;
+ finalizeInput(inputIndex: number, finalScriptsFunc?: FinalScriptsFunc | FinalTaprootScriptsFunc): this;
+ finalizeTaprootInput(inputIndex: number, tapLeafHashToFinalize?: Buffer, finalScriptsFunc?: FinalTaprootScriptsFunc): this;
+ private _finalizeInput;
+ private _finalizeTaprootInput;
getInputType(inputIndex: number): AllScriptType;
inputHasPubkey(inputIndex: number, pubkey: Buffer): boolean;
inputHasHDKey(inputIndex: number, root: HDSigner): boolean;
@@ -88,6 +91,8 @@ export declare class Psbt {
outputHasHDKey(outputIndex: number, root: HDSigner): boolean;
validateSignaturesOfAllInputs(validator: ValidateSigFunction): boolean;
validateSignaturesOfInput(inputIndex: number, validator: ValidateSigFunction, pubkey?: Buffer): boolean;
+ private _validateSignaturesOfInput;
+ private validateSignaturesOfTaprootInput;
signAllInputsHD(hdKeyPair: HDSigner, sighashTypes?: number[]): this;
signAllInputsHDAsync(hdKeyPair: HDSigner | HDSignerAsync, sighashTypes?: number[]): Promise;
signInputHD(inputIndex: number, hdKeyPair: HDSigner, sighashTypes?: number[]): this;
@@ -95,7 +100,14 @@ export declare class Psbt {
signAllInputs(keyPair: Signer, sighashTypes?: number[]): this;
signAllInputsAsync(keyPair: Signer | SignerAsync, sighashTypes?: number[]): Promise;
signInput(inputIndex: number, keyPair: Signer, sighashTypes?: number[]): this;
+ signTaprootInput(inputIndex: number, keyPair: Signer, tapLeafHashToSign?: Buffer, sighashTypes?: number[]): this;
+ private _signInput;
+ private _signTaprootInput;
signInputAsync(inputIndex: number, keyPair: Signer | SignerAsync, sighashTypes?: number[]): Promise;
+ signTaprootInputAsync(inputIndex: number, keyPair: Signer | SignerAsync, tapLeafHash?: Buffer, sighashTypes?: number[]): Promise;
+ private _signInputAsync;
+ private _signTaprootInputAsync;
+ private checkTaprootHashesForSig;
toBuffer(): Buffer;
toHex(): string;
toBase64(): string;
@@ -143,7 +155,6 @@ 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
@@ -151,7 +162,6 @@ 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;
@@ -177,11 +187,15 @@ declare type FinalScriptsFunc = (inputIndex: number, // Which input is it?
input: PsbtInput, // The PSBT input contents
script: Buffer, // The "meaningful" locking script Buffer (redeemScript for P2SH etc.)
isSegwit: boolean, // Is it segwit?
-isTapscript: boolean, // Is taproot script path?
isP2SH: boolean, // Is it P2SH?
isP2WSH: boolean) => {
finalScriptSig: Buffer | undefined;
- finalScriptWitness: Buffer | Buffer[] | undefined;
+ finalScriptWitness: Buffer | undefined;
+};
+declare type FinalTaprootScriptsFunc = (inputIndex: number, // Which input is it?
+input: PsbtInput, // The PSBT input contents
+tapLeafHashToFinalize?: Buffer) => {
+ finalScriptWitness: Buffer | undefined;
};
-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' | 'p2tr-pubkey' | 'p2tr-nonstandard';
+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';
export {};
diff --git a/src/psbt.js b/src/psbt.js
index c14086d0e..5496008ca 100644
--- a/src/psbt.js
+++ b/src/psbt.js
@@ -6,12 +6,13 @@ const varuint = require('bip174/src/lib/converter/varint');
const utils_1 = require('bip174/src/lib/utils');
const address_1 = require('./address');
const bufferutils_1 = require('./bufferutils');
-const crypto_1 = require('./crypto');
const networks_1 = require('./networks');
const payments = require('./payments');
+const taprootutils_1 = require('./payments/taprootutils');
const bscript = require('./script');
const transaction_1 = require('./transaction');
-const taprootutils_1 = require('./payments/taprootutils');
+const bip371_1 = require('./psbt/bip371');
+const psbtutils_1 = require('./psbt/psbtutils');
/**
* These are the default arguments for a Psbt instance.
*/
@@ -199,6 +200,7 @@ class Psbt {
`Requires single object with at least [hash] and [index]`,
);
}
+ (0, bip371_1.checkTaprootInputFields)(inputData, inputData, 'addInput');
checkInputsForPartialSig(this.data.inputs, 'addInput');
if (inputData.witnessScript) checkInvalidP2WSH(inputData.witnessScript);
const c = this.__CACHE;
@@ -272,15 +274,38 @@ class Psbt {
range(this.data.inputs.length).forEach(idx => this.finalizeInput(idx));
return this;
}
- finalizeInput(inputIndex, finalScriptsFunc = getFinalScripts) {
+ finalizeInput(inputIndex, finalScriptsFunc) {
const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
- const {
- script,
- isP2SH,
- isP2WSH,
- isSegwit,
- isTapscript,
- } = getScriptFromInput(inputIndex, input, this.__CACHE);
+ if ((0, bip371_1.isTaprootInput)(input))
+ return this._finalizeTaprootInput(
+ inputIndex,
+ input,
+ undefined,
+ finalScriptsFunc,
+ );
+ return this._finalizeInput(inputIndex, input, finalScriptsFunc);
+ }
+ finalizeTaprootInput(
+ inputIndex,
+ tapLeafHashToFinalize,
+ finalScriptsFunc = bip371_1.tapScriptFinalizer,
+ ) {
+ const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
+ if ((0, bip371_1.isTaprootInput)(input))
+ return this._finalizeTaprootInput(
+ inputIndex,
+ input,
+ tapLeafHashToFinalize,
+ finalScriptsFunc,
+ );
+ throw new Error(`Cannot finalize input #${inputIndex}. Not Taproot.`);
+ }
+ _finalizeInput(inputIndex, input, finalScriptsFunc = getFinalScripts) {
+ const { script, isP2SH, isP2WSH, isSegwit } = getScriptFromInput(
+ inputIndex,
+ input,
+ this.__CACHE,
+ );
if (!script) throw new Error(`No script found for input #${inputIndex}`);
checkPartialSigSighashes(input);
const { finalScriptSig, finalScriptWitness } = finalScriptsFunc(
@@ -290,28 +315,49 @@ class Psbt {
isSegwit,
isP2SH,
isP2WSH,
- isTapscript,
);
if (finalScriptSig) this.data.updateInput(inputIndex, { finalScriptSig });
- if (finalScriptWitness) {
- // allow custom finalizers to build the witness as an array
- const witness = Array.isArray(finalScriptWitness)
- ? witnessStackToScriptWitness(finalScriptWitness)
- : finalScriptWitness;
- this.data.updateInput(inputIndex, { finalScriptWitness: witness });
- }
+ if (finalScriptWitness)
+ this.data.updateInput(inputIndex, { finalScriptWitness });
if (!finalScriptSig && !finalScriptWitness)
throw new Error(`Unknown error finalizing input #${inputIndex}`);
this.data.clearFinalizedInput(inputIndex);
return this;
}
+ _finalizeTaprootInput(
+ inputIndex,
+ input,
+ tapLeafHashToFinalize,
+ finalScriptsFunc = bip371_1.tapScriptFinalizer,
+ ) {
+ if (!input.witnessUtxo)
+ throw new Error(
+ `Cannot finalize input #${inputIndex}. Missing withness utxo.`,
+ );
+ // Check key spend first. Increased privacy and reduced block space.
+ if (input.tapKeySig) {
+ const payment = payments.p2tr({
+ output: input.witnessUtxo.script,
+ signature: input.tapKeySig,
+ });
+ const finalScriptWitness = (0, psbtutils_1.witnessStackToScriptWitness)(
+ payment.witness,
+ );
+ this.data.updateInput(inputIndex, { finalScriptWitness });
+ } else {
+ const { finalScriptWitness } = finalScriptsFunc(
+ inputIndex,
+ input,
+ tapLeafHashToFinalize,
+ );
+ this.data.updateInput(inputIndex, { finalScriptWitness });
+ }
+ this.data.clearFinalizedInput(inputIndex);
+ return this;
+ }
getInputType(inputIndex) {
const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
- const { script } = getScriptAndAmountFromUtxo(
- inputIndex,
- input,
- this.__CACHE,
- );
+ const script = getScriptFromUtxo(inputIndex, input, this.__CACHE);
const result = getMeaningfulScript(
script,
inputIndex,
@@ -354,6 +400,16 @@ class Psbt {
return results.reduce((final, res) => res === true && final, true);
}
validateSignaturesOfInput(inputIndex, validator, pubkey) {
+ const input = this.data.inputs[inputIndex];
+ if ((0, bip371_1.isTaprootInput)(input))
+ return this.validateSignaturesOfTaprootInput(
+ inputIndex,
+ validator,
+ pubkey,
+ );
+ return this._validateSignaturesOfInput(inputIndex, validator, pubkey);
+ }
+ _validateSignaturesOfInput(inputIndex, validator, pubkey) {
const input = this.data.inputs[inputIndex];
const partialSig = (input || {}).partialSig;
if (!input || !partialSig || partialSig.length < 1)
@@ -368,20 +424,13 @@ class Psbt {
let hashCache;
let scriptCache;
let sighashCache;
- const scriptType = this.getInputType(inputIndex);
for (const pSig of mySigs) {
- const sig = isTaprootSpend(scriptType)
- ? {
- signature: pSig.signature,
- hashType: transaction_1.Transaction.SIGHASH_DEFAULT,
- }
- : bscript.signature.decode(pSig.signature);
+ const sig = 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,
)
@@ -394,6 +443,54 @@ class Psbt {
}
return results.every(res => res === true);
}
+ validateSignaturesOfTaprootInput(inputIndex, validator, pubkey) {
+ const input = this.data.inputs[inputIndex];
+ const tapKeySig = (input || {}).tapKeySig;
+ const tapScriptSig = (input || {}).tapScriptSig;
+ if (!input && !tapKeySig && !(tapScriptSig && !tapScriptSig.length))
+ throw new Error('No signatures to validate');
+ if (typeof validator !== 'function')
+ throw new Error('Need validator function to validate signatures');
+ pubkey = pubkey && (0, bip371_1.toXOnly)(pubkey);
+ const allHashses = pubkey
+ ? getTaprootHashesForSig(
+ inputIndex,
+ input,
+ this.data.inputs,
+ pubkey,
+ this.__CACHE,
+ )
+ : getAllTaprootHashesForSig(
+ inputIndex,
+ input,
+ this.data.inputs,
+ this.__CACHE,
+ );
+ if (!allHashses.length) throw new Error('No signatures for this pubkey');
+ const tapKeyHash = allHashses.find(h => !!h.leafHash);
+ if (tapKeySig && tapKeyHash) {
+ const isValidTapkeySig = validator(
+ tapKeyHash.pubkey,
+ tapKeyHash.hash,
+ tapKeySig,
+ );
+ if (!isValidTapkeySig) return false;
+ }
+ if (tapScriptSig) {
+ for (const tapSig of tapScriptSig) {
+ const tapSigHash = allHashses.find(h => tapSig.pubkey.equals(h.pubkey));
+ if (tapSigHash) {
+ const isValidTapScriptSig = validator(
+ tapSig.pubkey,
+ tapSigHash.hash,
+ tapSig.signature,
+ );
+ if (!isValidTapScriptSig) return false;
+ }
+ }
+ }
+ return true;
+ }
signAllInputsHD(
hdKeyPair,
sighashTypes = [transaction_1.Transaction.SIGHASH_ALL],
@@ -477,10 +574,7 @@ class Psbt {
.catch(reject);
});
}
- signAllInputs(
- keyPair,
- sighashTypes = [transaction_1.Transaction.SIGHASH_ALL],
- ) {
+ signAllInputs(keyPair, sighashTypes) {
if (!keyPair || !keyPair.publicKey)
throw new Error('Need Signer to sign input');
// TODO: Add a pubkey/pubkeyhash cache to each input
@@ -500,10 +594,7 @@ class Psbt {
}
return this;
}
- signAllInputsAsync(
- keyPair,
- sighashTypes = [transaction_1.Transaction.SIGHASH_ALL],
- ) {
+ signAllInputsAsync(keyPair, sighashTypes) {
return new Promise((resolve, reject) => {
if (!keyPair || !keyPair.publicKey)
return reject(new Error('Need Signer to sign input'));
@@ -532,13 +623,40 @@ class Psbt {
});
});
}
- signInput(
+ signInput(inputIndex, keyPair, sighashTypes) {
+ if (!keyPair || !keyPair.publicKey)
+ throw new Error('Need Signer to sign input');
+ const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
+ if ((0, bip371_1.isTaprootInput)(input)) {
+ return this._signTaprootInput(
+ inputIndex,
+ input,
+ keyPair,
+ undefined,
+ sighashTypes,
+ );
+ }
+ return this._signInput(inputIndex, keyPair, sighashTypes);
+ }
+ signTaprootInput(inputIndex, keyPair, tapLeafHashToSign, sighashTypes) {
+ if (!keyPair || !keyPair.publicKey)
+ throw new Error('Need Signer to sign input');
+ const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
+ if ((0, bip371_1.isTaprootInput)(input))
+ return this._signTaprootInput(
+ inputIndex,
+ input,
+ keyPair,
+ tapLeafHashToSign,
+ sighashTypes,
+ );
+ throw new Error(`Input #${inputIndex} is not of type Taproot.`);
+ }
+ _signInput(
inputIndex,
keyPair,
sighashTypes = [transaction_1.Transaction.SIGHASH_ALL],
) {
- if (!keyPair || !keyPair.publicKey)
- throw new Error('Need Signer to sign input');
const { hash, sighashType } = getHashAndSighashType(
this.data.inputs,
inputIndex,
@@ -546,74 +664,191 @@ class Psbt {
this.__CACHE,
sighashTypes,
);
- const scriptType = this.getInputType(inputIndex);
- if (isTaprootSpend(scriptType)) {
- if (!keyPair.signSchnorr) {
- throw new Error(
- `Need Schnorr Signer to sign taproot input #${inputIndex}.`,
- );
- }
- const partialSig = this.data.inputs[inputIndex].partialSig || [];
- partialSig.push({
+ 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 {
+ signature: bscript.signature.encode(keyPair.sign(hash), sighashType),
+ },
+ ];
+ this.data.updateInput(inputIndex, { partialSig });
+ return this;
+ }
+ _signTaprootInput(
+ inputIndex,
+ input,
+ keyPair,
+ tapLeafHashToSign,
+ allowedSighashTypes = [transaction_1.Transaction.SIGHASH_DEFAULT],
+ ) {
+ const hashesForSig = this.checkTaprootHashesForSig(
+ inputIndex,
+ input,
+ keyPair,
+ tapLeafHashToSign,
+ allowedSighashTypes,
+ );
+ const tapKeySig = hashesForSig
+ .filter(h => !h.leafHash)
+ .map(h =>
+ (0, bip371_1.serializeTaprootSignature)(
+ keyPair.signSchnorr(h.hash),
+ input.sighashType,
+ ),
+ )[0];
+ const tapScriptSig = hashesForSig
+ .filter(h => !!h.leafHash)
+ .map(h => ({
+ pubkey: (0, bip371_1.toXOnly)(keyPair.publicKey),
+ signature: (0, bip371_1.serializeTaprootSignature)(
+ keyPair.signSchnorr(h.hash),
+ input.sighashType,
+ ),
+ leafHash: h.leafHash,
+ }));
+ if (tapKeySig) {
+ this.data.updateInput(inputIndex, { tapKeySig });
+ }
+ if (tapScriptSig.length) {
+ this.data.updateInput(inputIndex, { tapScriptSig });
+ }
+ return this;
+ }
+ signInputAsync(inputIndex, keyPair, sighashTypes) {
+ return Promise.resolve().then(() => {
+ if (!keyPair || !keyPair.publicKey)
+ throw new Error('Need Signer to sign input');
+ const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
+ if ((0, bip371_1.isTaprootInput)(input))
+ return this._signTaprootInputAsync(
+ inputIndex,
+ input,
+ keyPair,
+ undefined,
+ sighashTypes,
+ );
+ return this._signInputAsync(inputIndex, keyPair, sighashTypes);
+ });
+ }
+ signTaprootInputAsync(inputIndex, keyPair, tapLeafHash, sighashTypes) {
+ return Promise.resolve().then(() => {
+ if (!keyPair || !keyPair.publicKey)
+ throw new Error('Need Signer to sign input');
+ const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
+ if ((0, bip371_1.isTaprootInput)(input))
+ return this._signTaprootInputAsync(
+ inputIndex,
+ input,
+ keyPair,
+ tapLeafHash,
+ sighashTypes,
+ );
+ throw new Error(`Input #${inputIndex} is not of type Taproot.`);
+ });
+ }
+ _signInputAsync(
+ inputIndex,
+ keyPair,
+ sighashTypes = [transaction_1.Transaction.SIGHASH_ALL],
+ ) {
+ const { hash, sighashType } = getHashAndSighashType(
+ this.data.inputs,
+ inputIndex,
+ keyPair.publicKey,
+ this.__CACHE,
+ sighashTypes,
+ );
+ return Promise.resolve(keyPair.sign(hash)).then(signature => {
const partialSig = [
{
pubkey: keyPair.publicKey,
- signature: bscript.signature.encode(keyPair.sign(hash), sighashType),
+ signature: bscript.signature.encode(signature, sighashType),
},
];
this.data.updateInput(inputIndex, { partialSig });
- }
- return this;
+ });
}
- signInputAsync(
+ async _signTaprootInputAsync(
inputIndex,
+ input,
keyPair,
- sighashTypes = [transaction_1.Transaction.SIGHASH_ALL],
+ tapLeafHash,
+ sighashTypes = [transaction_1.Transaction.SIGHASH_DEFAULT],
) {
- return Promise.resolve().then(() => {
- if (!keyPair || !keyPair.publicKey)
- throw new Error('Need Signer to sign input');
- const { hash, sighashType } = getHashAndSighashType(
- this.data.inputs,
- inputIndex,
- keyPair.publicKey,
- this.__CACHE,
- sighashTypes,
- );
- const scriptType = this.getInputType(inputIndex);
- if (isTaprootSpend(scriptType)) {
- if (!keyPair.signSchnorr) {
- throw new Error(
- `Need Schnorr Signer to sign taproot input #${inputIndex}.`,
- );
- }
- return Promise.resolve(keyPair.signSchnorr(hash)).then(signature => {
- const partialSig = this.data.inputs[inputIndex].partialSig || [];
- partialSig.push({
- pubkey: keyPair.publicKey,
- signature,
- });
- // must be changed to use the `updateInput()` public API
- this.data.inputs[inputIndex].partialSig = partialSig;
- });
- }
- return Promise.resolve(keyPair.sign(hash)).then(signature => {
- const partialSig = [
- {
- pubkey: keyPair.publicKey,
- signature: bscript.signature.encode(signature, sighashType),
+ const hashesForSig = this.checkTaprootHashesForSig(
+ inputIndex,
+ input,
+ keyPair,
+ tapLeafHash,
+ sighashTypes,
+ );
+ const signaturePromises = [];
+ const tapKeyHash = hashesForSig.filter(h => !h.leafHash)[0];
+ if (tapKeyHash) {
+ const tapKeySigPromise = Promise.resolve(
+ keyPair.signSchnorr(tapKeyHash.hash),
+ ).then(sig => {
+ return {
+ tapKeySig: (0, bip371_1.serializeTaprootSignature)(
+ sig,
+ input.sighashType,
+ ),
+ };
+ });
+ signaturePromises.push(tapKeySigPromise);
+ }
+ const tapScriptHashes = hashesForSig.filter(h => !!h.leafHash);
+ if (tapScriptHashes.length) {
+ const tapScriptSigPromises = tapScriptHashes.map(tsh => {
+ return Promise.resolve(keyPair.signSchnorr(tsh.hash)).then(
+ signature => {
+ const tapScriptSig = [
+ {
+ pubkey: (0, bip371_1.toXOnly)(keyPair.publicKey),
+ signature: (0, bip371_1.serializeTaprootSignature)(
+ signature,
+ input.sighashType,
+ ),
+ leafHash: tsh.leafHash,
+ },
+ ];
+ return { tapScriptSig };
},
- ];
- this.data.updateInput(inputIndex, { partialSig });
+ );
});
+ signaturePromises.push(...tapScriptSigPromises);
+ }
+ return Promise.all(signaturePromises).then(results => {
+ results.forEach(v => this.data.updateInput(inputIndex, v));
});
}
+ checkTaprootHashesForSig(
+ inputIndex,
+ input,
+ keyPair,
+ tapLeafHashToSign,
+ allowedSighashTypes,
+ ) {
+ if (typeof keyPair.signSchnorr !== 'function')
+ throw new Error(
+ `Need Schnorr Signer to sign taproot input #${inputIndex}.`,
+ );
+ const hashesForSig = getTaprootHashesForSig(
+ inputIndex,
+ input,
+ this.data.inputs,
+ keyPair.publicKey,
+ this.__CACHE,
+ tapLeafHashToSign,
+ allowedSighashTypes,
+ );
+ if (!hashesForSig || !hashesForSig.length)
+ throw new Error(
+ `Can not sign for input #${inputIndex} with the key ${keyPair.publicKey.toString(
+ 'hex',
+ )}`,
+ );
+ return hashesForSig;
+ }
toBuffer() {
checkCache(this.__CACHE);
return this.data.toBuffer();
@@ -632,6 +867,11 @@ class Psbt {
}
updateInput(inputIndex, updateData) {
if (updateData.witnessScript) checkInvalidP2WSH(updateData.witnessScript);
+ (0, bip371_1.checkTaprootInputFields)(
+ this.data.inputs[inputIndex],
+ updateData,
+ 'updateInput',
+ );
this.data.updateInput(inputIndex, updateData);
if (updateData.nonWitnessUtxo) {
addNonWitnessTxCache(
@@ -724,7 +964,6 @@ 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 });
@@ -757,23 +996,6 @@ function hasSigs(neededSigs, partialSig, pubkeys) {
function isFinalized(input) {
return !!input.finalScriptSig || !!input.finalScriptWitness;
}
-function isPaymentFactory(payment) {
- return script => {
- try {
- payment({ output: script });
- return true;
- } catch (err) {
- return false;
- }
- };
-}
-const isP2MS = isPaymentFactory(payments.p2ms);
-const isP2PK = isPaymentFactory(payments.p2pk);
-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;
@@ -851,7 +1073,7 @@ function checkPartialSigSighashes(input) {
});
}
function checkScriptForPubkey(pubkey, script, action) {
- if (!pubkeyInScript(pubkey, script)) {
+ if (!(0, psbtutils_1.pubkeyInScript)(pubkey, script)) {
throw new Error(
`Can not ${action} for this input with the key ${pubkey.toString('hex')}`,
);
@@ -916,17 +1138,9 @@ function getTxCacheValue(key, name, inputs, c) {
if (key === '__FEE_RATE') return c.__FEE_RATE;
else if (key === '__FEE') return c.__FEE;
}
-function getFinalScripts(
- inputIndex,
- input,
- script,
- isSegwit,
- isP2SH,
- isP2WSH,
- isTapscript = false,
-) {
+function getFinalScripts(inputIndex, input, script, isSegwit, isP2SH, isP2WSH) {
const scriptType = classifyScript(script);
- if (isTapscript || !canFinalize(input, script, scriptType))
+ if (!canFinalize(input, script, scriptType))
throw new Error(`Can not finalize input #${inputIndex}`);
return prepareFinalScripts(
script,
@@ -953,9 +1167,13 @@ function prepareFinalScripts(
const p2sh = !isP2SH ? null : payments.p2sh({ redeem: p2wsh || payment });
if (isSegwit) {
if (p2wsh) {
- finalScriptWitness = witnessStackToScriptWitness(p2wsh.witness);
+ finalScriptWitness = (0, psbtutils_1.witnessStackToScriptWitness)(
+ p2wsh.witness,
+ );
} else {
- finalScriptWitness = witnessStackToScriptWitness(payment.witness);
+ finalScriptWitness = (0, psbtutils_1.witnessStackToScriptWitness)(
+ payment.witness,
+ );
}
if (p2sh) {
finalScriptSig = p2sh.input;
@@ -983,7 +1201,6 @@ function getHashAndSighashType(
const { hash, sighashType, script } = getHashForSig(
inputIndex,
input,
- inputs,
cache,
false,
sighashTypes,
@@ -994,24 +1211,11 @@ function getHashAndSighashType(
sighashType,
};
}
-function getHashForSig(
- inputIndex,
- input,
- inputs,
- cache,
- forValidate,
- sighashTypes,
-) {
+function getHashForSig(inputIndex, input, cache, forValidate, sighashTypes) {
const unsignedTx = cache.__TX;
const sighashType =
input.sighashType || transaction_1.Transaction.SIGHASH_ALL;
- if (sighashTypes && sighashTypes.indexOf(sighashType) < 0) {
- const str = sighashTypeToString(sighashType);
- throw new Error(
- `Sighash type is not allowed. Retry the sign method passing the ` +
- `sighashTypes array of whitelisted types. Sighash type: ${str}`,
- );
- }
+ checkSighashTypeAllowed(sighashType, sighashTypes);
let hash;
let prevout;
if (input.nonWitnessUtxo) {
@@ -1049,7 +1253,7 @@ function getHashForSig(
prevout.value,
sighashType,
);
- } else if (isP2WPKH(meaningfulScript)) {
+ } else if ((0, psbtutils_1.isP2WPKH)(meaningfulScript)) {
// P2WPKH uses the P2PKH template for prevoutScript when signing
const signingScript = payments.p2pkh({ hash: meaningfulScript.slice(2) })
.output;
@@ -1059,22 +1263,6 @@ function getHashForSig(
prevout.value,
sighashType,
);
- } else if (isP2TR(prevout.script)) {
- const prevOuts = inputs.map((i, index) =>
- getScriptAndAmountFromUtxo(index, i, cache),
- );
- const signingScripts = prevOuts.map(o => o.script);
- const values = prevOuts.map(o => o.value);
- const leafHash = input.witnessScript
- ? (0, taprootutils_1.tapleafHash)({ output: input.witnessScript })
- : undefined;
- hash = unsignedTx.hashForWitnessV1(
- inputIndex,
- signingScripts,
- values,
- transaction_1.Transaction.SIGHASH_DEFAULT,
- leafHash,
- );
} else {
// non-segwit
if (
@@ -1107,6 +1295,89 @@ function getHashForSig(
hash,
};
}
+function getAllTaprootHashesForSig(inputIndex, input, inputs, cache) {
+ const allPublicKeys = [];
+ if (input.tapInternalKey) {
+ const outputKey = (0, bip371_1.tweakInternalPubKey)(inputIndex, input);
+ allPublicKeys.push(outputKey);
+ }
+ if (input.tapScriptSig) {
+ const tapScriptPubkeys = input.tapScriptSig.map(tss => tss.pubkey);
+ allPublicKeys.push(...tapScriptPubkeys);
+ }
+ const allHashes = allPublicKeys.map(pubicKey =>
+ getTaprootHashesForSig(inputIndex, input, inputs, pubicKey, cache),
+ );
+ return allHashes.flat();
+}
+function getTaprootHashesForSig(
+ inputIndex,
+ input,
+ inputs,
+ pubkey,
+ cache,
+ tapLeafHashToSign,
+ allowedSighashTypes,
+) {
+ const unsignedTx = cache.__TX;
+ const sighashType =
+ input.sighashType || transaction_1.Transaction.SIGHASH_DEFAULT;
+ checkSighashTypeAllowed(sighashType, allowedSighashTypes);
+ const prevOuts = inputs.map((i, index) =>
+ getScriptAndAmountFromUtxo(index, i, cache),
+ );
+ const signingScripts = prevOuts.map(o => o.script);
+ const values = prevOuts.map(o => o.value);
+ const hashes = [];
+ if (input.tapInternalKey && !tapLeafHashToSign) {
+ const outputKey = (0, bip371_1.tweakInternalPubKey)(inputIndex, input);
+ if ((0, bip371_1.toXOnly)(pubkey).equals(outputKey)) {
+ const tapKeyHash = unsignedTx.hashForWitnessV1(
+ inputIndex,
+ signingScripts,
+ values,
+ sighashType,
+ );
+ hashes.push({ pubkey, hash: tapKeyHash });
+ }
+ }
+ const tapLeafHashes = (input.tapLeafScript || [])
+ .filter(tapLeaf => (0, psbtutils_1.pubkeyInScript)(pubkey, tapLeaf.script))
+ .map(tapLeaf => {
+ const hash = (0, taprootutils_1.tapleafHash)({
+ output: tapLeaf.script,
+ version: tapLeaf.leafVersion,
+ });
+ return Object.assign({ hash }, tapLeaf);
+ })
+ .filter(
+ tapLeaf => !tapLeafHashToSign || tapLeafHashToSign.equals(tapLeaf.hash),
+ )
+ .map(tapLeaf => {
+ const tapScriptHash = unsignedTx.hashForWitnessV1(
+ inputIndex,
+ signingScripts,
+ values,
+ transaction_1.Transaction.SIGHASH_DEFAULT,
+ tapLeaf.hash,
+ );
+ return {
+ pubkey,
+ hash: tapScriptHash,
+ leafHash: tapLeaf.hash,
+ };
+ });
+ return hashes.concat(tapLeafHashes);
+}
+function checkSighashTypeAllowed(sighashType, sighashTypes) {
+ if (sighashTypes && sighashTypes.indexOf(sighashType) < 0) {
+ const str = sighashTypeToString(sighashType);
+ throw new Error(
+ `Sighash type is not allowed. Retry the sign method passing the ` +
+ `sighashTypes array of whitelisted types. Sighash type: ${str}`,
+ );
+ }
+}
function getPayment(script, scriptType, partialSig) {
let payment;
switch (scriptType) {
@@ -1137,15 +1408,6 @@ function getPayment(script, scriptType, partialSig) {
signature: partialSig[0].signature,
});
break;
- case 'taproot':
- payment = payments.p2tr(
- {
- output: script,
- signature: partialSig[0].signature,
- },
- { validate: false },
- );
- break;
}
return payment;
}
@@ -1168,39 +1430,31 @@ function getScriptFromInput(inputIndex, input, cache) {
const res = {
script: null,
isSegwit: false,
- isTapscript: false,
isP2SH: false,
isP2WSH: false,
};
- let utxoScript = null;
- if (input.nonWitnessUtxo) {
- const nonWitnessUtxoTx = nonWitnessUtxoTxFromCache(
- cache,
- input,
- inputIndex,
- );
- const prevoutIndex = unsignedTx.ins[inputIndex].index;
- utxoScript = nonWitnessUtxoTx.outs[prevoutIndex].script;
- } else if (input.witnessUtxo) {
- utxoScript = input.witnessUtxo.script;
- }
+ res.isP2SH = !!input.redeemScript;
+ res.isP2WSH = !!input.witnessScript;
if (input.witnessScript) {
res.script = input.witnessScript;
} else if (input.redeemScript) {
res.script = input.redeemScript;
} else {
- res.script = utxoScript;
+ if (input.nonWitnessUtxo) {
+ const nonWitnessUtxoTx = nonWitnessUtxoTxFromCache(
+ cache,
+ input,
+ inputIndex,
+ );
+ const prevoutIndex = unsignedTx.ins[inputIndex].index;
+ res.script = nonWitnessUtxoTx.outs[prevoutIndex].script;
+ } else if (input.witnessUtxo) {
+ res.script = input.witnessUtxo.script;
+ }
}
- const isTaproot = utxoScript && isP2TR(utxoScript);
- // Segregated Witness versions 0 or 1
- if (input.witnessScript || isP2WPKH(res.script) || isTaproot) {
+ if (input.witnessScript || (0, psbtutils_1.isP2WPKH)(res.script)) {
res.isSegwit = true;
}
- if (isTaproot && input.witnessScript) {
- res.isTapscript = true;
- }
- res.isP2SH = !!input.redeemScript;
- res.isP2WSH = !!input.witnessScript && !res.isTapscript;
return res;
}
function getSignersFromHD(inputIndex, inputs, hdKeyPair) {
@@ -1288,28 +1542,6 @@ function sighashTypeToString(sighashType) {
}
return text;
}
-function witnessStackToScriptWitness(witness) {
- let buffer = Buffer.allocUnsafe(0);
- function writeSlice(slice) {
- buffer = Buffer.concat([buffer, Buffer.from(slice)]);
- }
- function writeVarInt(i) {
- const currentLen = buffer.length;
- const varintLen = varuint.encodingLength(i);
- buffer = Buffer.concat([buffer, Buffer.allocUnsafe(varintLen)]);
- varuint.encode(i, buffer, currentLen);
- }
- function writeVarSlice(slice) {
- writeVarInt(slice.length);
- writeSlice(slice);
- }
- function writeVector(vector) {
- writeVarInt(vector.length);
- vector.forEach(writeVarSlice);
- }
- writeVector(witness);
- return buffer;
-}
function addNonWitnessTxCache(cache, input, inputIndex) {
cache.__NON_WITNESS_UTXO_BUF_CACHE[inputIndex] = input.nonWitnessUtxo;
const tx = transaction_1.Transaction.fromBuffer(input.nonWitnessUtxo);
@@ -1371,6 +1603,10 @@ function nonWitnessUtxoTxFromCache(cache, input, inputIndex) {
}
return c[inputIndex];
}
+function getScriptFromUtxo(inputIndex, input, cache) {
+ const { script } = getScriptAndAmountFromUtxo(inputIndex, input, cache);
+ return script;
+}
function getScriptAndAmountFromUtxo(inputIndex, input, cache) {
if (input.witnessUtxo !== undefined) {
return {
@@ -1390,7 +1626,7 @@ function getScriptAndAmountFromUtxo(inputIndex, input, cache) {
}
}
function pubkeyInInput(pubkey, input, inputIndex, cache) {
- const { script } = getScriptAndAmountFromUtxo(inputIndex, input, cache);
+ const script = getScriptFromUtxo(inputIndex, input, cache);
const { meaningfulScript } = getMeaningfulScript(
script,
inputIndex,
@@ -1398,7 +1634,7 @@ function pubkeyInInput(pubkey, input, inputIndex, cache) {
input.redeemScript,
input.witnessScript,
);
- return pubkeyInScript(pubkey, meaningfulScript);
+ return (0, psbtutils_1.pubkeyInScript)(pubkey, meaningfulScript);
}
function pubkeyInOutput(pubkey, output, outputIndex, cache) {
const script = cache.__TX.outs[outputIndex].script;
@@ -1409,7 +1645,7 @@ function pubkeyInOutput(pubkey, output, outputIndex, cache) {
output.redeemScript,
output.witnessScript,
);
- return pubkeyInScript(pubkey, meaningfulScript);
+ return (0, psbtutils_1.pubkeyInScript)(pubkey, meaningfulScript);
}
function redeemFromFinalScriptSig(finalScript) {
if (!finalScript) return;
@@ -1457,10 +1693,10 @@ function getMeaningfulScript(
redeemScript,
witnessScript,
) {
- const isP2SH = isP2SHScript(script);
- const isP2SHP2WSH = isP2SH && redeemScript && isP2WSHScript(redeemScript);
- const isP2WSH = isP2WSHScript(script);
- const isP2TRScript = isP2TR(script);
+ const isP2SH = (0, psbtutils_1.isP2SHScript)(script);
+ const isP2SHP2WSH =
+ isP2SH && redeemScript && (0, psbtutils_1.isP2WSHScript)(redeemScript);
+ const isP2WSH = (0, psbtutils_1.isP2WSHScript)(script);
if (isP2SH && redeemScript === undefined)
throw new Error('scriptPubkey is P2SH but redeemScript missing');
if ((isP2WSH || isP2SHP2WSH) && witnessScript === undefined)
@@ -1480,9 +1716,6 @@ function getMeaningfulScript(
} else if (isP2SH) {
meaningfulScript = redeemScript;
checkRedeemScript(index, script, redeemScript, ioType);
- } else if (isP2TRScript && !!witnessScript) {
- meaningfulScript = witnessScript;
- // TODO: check here something?
} else {
meaningfulScript = script;
}
@@ -1494,41 +1727,22 @@ function getMeaningfulScript(
? 'p2sh'
: isP2WSH
? 'p2wsh'
- : isP2TRScript
- ? 'p2tr'
: 'raw',
};
}
function checkInvalidP2WSH(script) {
- if (isP2WPKH(script) || isP2SHScript(script)) {
+ if (
+ (0, psbtutils_1.isP2WPKH)(script) ||
+ (0, psbtutils_1.isP2SHScript)(script)
+ ) {
throw new Error('P2WPKH or P2SH can not be contained within P2WSH');
}
}
-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) ||
- element.equals(pubkeyXOnly)
- );
- });
-}
-function isTaprootSpend(scriptType) {
- return (
- !!scriptType && (scriptType === 'taproot' || scriptType.startsWith('p2tr-'))
- );
-}
function classifyScript(script) {
- if (isP2WPKH(script)) return 'witnesspubkeyhash';
- if (isP2PKH(script)) return 'pubkeyhash';
- if (isP2MS(script)) return 'multisig';
- if (isP2PK(script)) return 'pubkey';
- if (isP2TR(script)) return 'taproot';
+ if ((0, psbtutils_1.isP2WPKH)(script)) return 'witnesspubkeyhash';
+ if ((0, psbtutils_1.isP2PKH)(script)) return 'pubkeyhash';
+ if ((0, psbtutils_1.isP2MS)(script)) return 'multisig';
+ if ((0, psbtutils_1.isP2PK)(script)) return 'pubkey';
return 'nonstandard';
}
function range(n) {
diff --git a/src/psbt/bip371.d.ts b/src/psbt/bip371.d.ts
new file mode 100644
index 000000000..9545e899a
--- /dev/null
+++ b/src/psbt/bip371.d.ts
@@ -0,0 +1,19 @@
+///
+import { PsbtInput } from 'bip174/src/lib/interfaces';
+export declare const toXOnly: (pubKey: Buffer) => Buffer;
+/**
+ * Default tapscript finalizer. It searches for the `tapLeafHashToFinalize` if provided.
+ * Otherwise it will search for the tapleaf that has at least one signature and has the shortest path.
+ * @param inputIndex the position of the PSBT input.
+ * @param input the PSBT input.
+ * @param tapLeafHashToFinalize optional, if provided the finalizer will search for a tapleaf that has this hash
+ * and will try to build the finalScriptWitness.
+ * @returns the finalScriptWitness or throws an exception if no tapleaf found.
+ */
+export declare function tapScriptFinalizer(inputIndex: number, input: PsbtInput, tapLeafHashToFinalize?: Buffer): {
+ finalScriptWitness: Buffer | undefined;
+};
+export declare function serializeTaprootSignature(sig: Buffer, sighashType?: number): Buffer;
+export declare function isTaprootInput(input: PsbtInput): boolean;
+export declare function checkTaprootInputFields(inputData: PsbtInput, newInputData: PsbtInput, action: string): void;
+export declare function tweakInternalPubKey(inputIndex: number, input: PsbtInput): Buffer;
diff --git a/src/psbt/bip371.js b/src/psbt/bip371.js
new file mode 100644
index 000000000..115235acf
--- /dev/null
+++ b/src/psbt/bip371.js
@@ -0,0 +1,181 @@
+'use strict';
+Object.defineProperty(exports, '__esModule', { value: true });
+exports.tweakInternalPubKey = exports.checkTaprootInputFields = exports.isTaprootInput = exports.serializeTaprootSignature = exports.tapScriptFinalizer = exports.toXOnly = void 0;
+const psbtutils_1 = require('./psbtutils');
+const taprootutils_1 = require('../payments/taprootutils');
+const toXOnly = pubKey => (pubKey.length === 32 ? pubKey : pubKey.slice(1, 33));
+exports.toXOnly = toXOnly;
+/**
+ * Default tapscript finalizer. It searches for the `tapLeafHashToFinalize` if provided.
+ * Otherwise it will search for the tapleaf that has at least one signature and has the shortest path.
+ * @param inputIndex the position of the PSBT input.
+ * @param input the PSBT input.
+ * @param tapLeafHashToFinalize optional, if provided the finalizer will search for a tapleaf that has this hash
+ * and will try to build the finalScriptWitness.
+ * @returns the finalScriptWitness or throws an exception if no tapleaf found.
+ */
+function tapScriptFinalizer(inputIndex, input, tapLeafHashToFinalize) {
+ const tapLeaf = findTapLeafToFinalize(
+ input,
+ inputIndex,
+ tapLeafHashToFinalize,
+ );
+ try {
+ const sigs = sortSignatures(input, tapLeaf);
+ const witness = sigs.concat(tapLeaf.script).concat(tapLeaf.controlBlock);
+ return {
+ finalScriptWitness: (0, psbtutils_1.witnessStackToScriptWitness)(witness),
+ };
+ } catch (err) {
+ throw new Error(`Can not finalize taproot input #${inputIndex}: ${err}`);
+ }
+}
+exports.tapScriptFinalizer = tapScriptFinalizer;
+function serializeTaprootSignature(sig, sighashType) {
+ const sighashTypeByte = sighashType
+ ? Buffer.from([sighashType])
+ : Buffer.from([]);
+ return Buffer.concat([sig, sighashTypeByte]);
+}
+exports.serializeTaprootSignature = serializeTaprootSignature;
+function isTaprootInput(input) {
+ return (
+ input &&
+ !!(
+ input.tapInternalKey ||
+ input.tapMerkleRoot ||
+ (input.tapLeafScript && input.tapLeafScript.length) ||
+ (input.tapBip32Derivation && input.tapBip32Derivation.length) ||
+ (input.witnessUtxo && (0, psbtutils_1.isP2TR)(input.witnessUtxo.script))
+ )
+ );
+}
+exports.isTaprootInput = isTaprootInput;
+function checkTaprootInputFields(inputData, newInputData, action) {
+ checkMixedTaprootAndNonTaprootFields(inputData, newInputData, action);
+ checkIfTapLeafInTree(inputData, newInputData, action);
+}
+exports.checkTaprootInputFields = checkTaprootInputFields;
+function tweakInternalPubKey(inputIndex, input) {
+ const tapInternalKey = input.tapInternalKey;
+ const outputKey =
+ tapInternalKey &&
+ (0, taprootutils_1.tweakKey)(tapInternalKey, input.tapMerkleRoot);
+ if (!outputKey)
+ throw new Error(
+ `Cannot tweak tap internal key for input #${inputIndex}. Public key: ${tapInternalKey &&
+ tapInternalKey.toString('hex')}`,
+ );
+ return outputKey.x;
+}
+exports.tweakInternalPubKey = tweakInternalPubKey;
+function checkMixedTaprootAndNonTaprootFields(inputData, newInputData, action) {
+ const isBadTaprootUpdate =
+ isTaprootInput(inputData) && hasNonTaprootInputFields(newInputData);
+ const isBadNonTaprootUpdate =
+ hasNonTaprootInputFields(inputData) && isTaprootInput(newInputData);
+ const hasMixedFields =
+ inputData === newInputData &&
+ (isTaprootInput(newInputData) && hasNonTaprootInputFields(newInputData));
+ if (isBadTaprootUpdate || isBadNonTaprootUpdate || hasMixedFields)
+ throw new Error(
+ `Invalid arguments for Psbt.${action}. ` +
+ `Cannot use both taproot and non-taproot fields.`,
+ );
+}
+function checkIfTapLeafInTree(inputData, newInputData, action) {
+ if (newInputData.tapMerkleRoot) {
+ const newLeafsInTree = (newInputData.tapLeafScript || []).every(l =>
+ isTapLeafInTree(l, newInputData.tapMerkleRoot),
+ );
+ const oldLeafsInTree = (inputData.tapLeafScript || []).every(l =>
+ isTapLeafInTree(l, newInputData.tapMerkleRoot),
+ );
+ if (!newLeafsInTree || !oldLeafsInTree)
+ throw new Error(
+ `Invalid arguments for Psbt.${action}. Tapleaf not part of taptree.`,
+ );
+ } else if (inputData.tapMerkleRoot) {
+ const newLeafsInTree = (newInputData.tapLeafScript || []).every(l =>
+ isTapLeafInTree(l, inputData.tapMerkleRoot),
+ );
+ if (!newLeafsInTree)
+ throw new Error(
+ `Invalid arguments for Psbt.${action}. Tapleaf not part of taptree.`,
+ );
+ }
+}
+function isTapLeafInTree(tapLeaf, merkleRoot) {
+ if (!merkleRoot) return true;
+ const leafHash = (0, taprootutils_1.tapleafHash)({
+ output: tapLeaf.script,
+ version: tapLeaf.leafVersion,
+ });
+ const rootHash = (0, taprootutils_1.rootHashFromPath)(
+ tapLeaf.controlBlock,
+ leafHash,
+ );
+ return rootHash.equals(merkleRoot);
+}
+function sortSignatures(input, tapLeaf) {
+ const leafHash = (0, taprootutils_1.tapleafHash)({
+ output: tapLeaf.script,
+ version: tapLeaf.leafVersion,
+ });
+ return (input.tapScriptSig || [])
+ .filter(tss => tss.leafHash.equals(leafHash))
+ .map(tss => addPubkeyPositionInScript(tapLeaf.script, tss))
+ .sort((t1, t2) => t2.positionInScript - t1.positionInScript)
+ .map(t => t.signature);
+}
+function addPubkeyPositionInScript(script, tss) {
+ return Object.assign(
+ {
+ positionInScript: (0, psbtutils_1.pubkeyPositionInScript)(
+ tss.pubkey,
+ script,
+ ),
+ },
+ tss,
+ );
+}
+/**
+ * Find tapleaf by hash, or get the signed tapleaf with the shortest path.
+ */
+function findTapLeafToFinalize(input, inputIndex, leafHashToFinalize) {
+ if (!input.tapScriptSig || !input.tapScriptSig.length)
+ throw new Error(
+ `Can not finalize taproot input #${inputIndex}. No tapleaf script signature provided.`,
+ );
+ const tapLeaf = (input.tapLeafScript || [])
+ .sort((a, b) => a.controlBlock.length - b.controlBlock.length)
+ .find(leaf =>
+ canFinalizeLeaf(leaf, input.tapScriptSig, leafHashToFinalize),
+ );
+ if (!tapLeaf)
+ throw new Error(
+ `Can not finalize taproot input #${inputIndex}. Signature for tapleaf script not found.`,
+ );
+ return tapLeaf;
+}
+function canFinalizeLeaf(leaf, tapScriptSig, hash) {
+ const leafHash = (0, taprootutils_1.tapleafHash)({
+ output: leaf.script,
+ version: leaf.leafVersion,
+ });
+ const whiteListedHash = !hash || hash.equals(leafHash);
+ return (
+ whiteListedHash &&
+ tapScriptSig.find(tss => tss.leafHash.equals(leafHash)) !== undefined
+ );
+}
+function hasNonTaprootInputFields(input) {
+ return (
+ input &&
+ !!(
+ input.redeemScript ||
+ input.witnessScript ||
+ (input.bip32Derivation && input.bip32Derivation.length)
+ )
+ );
+}
diff --git a/src/psbt/psbtutils.d.ts b/src/psbt/psbtutils.d.ts
new file mode 100644
index 000000000..c902e6cec
--- /dev/null
+++ b/src/psbt/psbtutils.d.ts
@@ -0,0 +1,11 @@
+///
+export declare const isP2MS: (script: Buffer) => boolean;
+export declare const isP2PK: (script: Buffer) => boolean;
+export declare const isP2PKH: (script: Buffer) => boolean;
+export declare const isP2WPKH: (script: Buffer) => boolean;
+export declare const isP2WSHScript: (script: Buffer) => boolean;
+export declare const isP2SHScript: (script: Buffer) => boolean;
+export declare const isP2TR: (script: Buffer) => boolean;
+export declare function witnessStackToScriptWitness(witness: Buffer[]): Buffer;
+export declare function pubkeyPositionInScript(pubkey: Buffer, script: Buffer): number;
+export declare function pubkeyInScript(pubkey: Buffer, script: Buffer): boolean;
diff --git a/src/psbt/psbtutils.js b/src/psbt/psbtutils.js
new file mode 100644
index 000000000..4ef56f6a5
--- /dev/null
+++ b/src/psbt/psbtutils.js
@@ -0,0 +1,66 @@
+'use strict';
+Object.defineProperty(exports, '__esModule', { value: true });
+exports.pubkeyInScript = exports.pubkeyPositionInScript = exports.witnessStackToScriptWitness = exports.isP2TR = exports.isP2SHScript = exports.isP2WSHScript = exports.isP2WPKH = exports.isP2PKH = exports.isP2PK = exports.isP2MS = void 0;
+const varuint = require('bip174/src/lib/converter/varint');
+const bscript = require('../script');
+const crypto_1 = require('../crypto');
+const payments = require('../payments');
+function isPaymentFactory(payment) {
+ return script => {
+ try {
+ payment({ output: script });
+ return true;
+ } catch (err) {
+ return false;
+ }
+ };
+}
+exports.isP2MS = isPaymentFactory(payments.p2ms);
+exports.isP2PK = isPaymentFactory(payments.p2pk);
+exports.isP2PKH = isPaymentFactory(payments.p2pkh);
+exports.isP2WPKH = isPaymentFactory(payments.p2wpkh);
+exports.isP2WSHScript = isPaymentFactory(payments.p2wsh);
+exports.isP2SHScript = isPaymentFactory(payments.p2sh);
+exports.isP2TR = isPaymentFactory(payments.p2tr);
+function witnessStackToScriptWitness(witness) {
+ let buffer = Buffer.allocUnsafe(0);
+ function writeSlice(slice) {
+ buffer = Buffer.concat([buffer, Buffer.from(slice)]);
+ }
+ function writeVarInt(i) {
+ const currentLen = buffer.length;
+ const varintLen = varuint.encodingLength(i);
+ buffer = Buffer.concat([buffer, Buffer.allocUnsafe(varintLen)]);
+ varuint.encode(i, buffer, currentLen);
+ }
+ function writeVarSlice(slice) {
+ writeVarInt(slice.length);
+ writeSlice(slice);
+ }
+ function writeVector(vector) {
+ writeVarInt(vector.length);
+ vector.forEach(writeVarSlice);
+ }
+ writeVector(witness);
+ return buffer;
+}
+exports.witnessStackToScriptWitness = witnessStackToScriptWitness;
+function pubkeyPositionInScript(pubkey, script) {
+ const pubkeyHash = (0, crypto_1.hash160)(pubkey);
+ const pubkeyXOnly = pubkey.slice(1, 33); // slice before calling?
+ const decompiled = bscript.decompile(script);
+ if (decompiled === null) throw new Error('Unknown script error');
+ return decompiled.findIndex(element => {
+ if (typeof element === 'number') return false;
+ return (
+ element.equals(pubkey) ||
+ element.equals(pubkeyHash) ||
+ element.equals(pubkeyXOnly)
+ );
+ });
+}
+exports.pubkeyPositionInScript = pubkeyPositionInScript;
+function pubkeyInScript(pubkey, script) {
+ return pubkeyPositionInScript(pubkey, script) !== -1;
+}
+exports.pubkeyInScript = pubkeyInScript;
diff --git a/test/fixtures/psbt.json b/test/fixtures/psbt.json
index 5a78e3527..7bce10812 100644
--- a/test/fixtures/psbt.json
+++ b/test/fixtures/psbt.json
@@ -279,8 +279,8 @@
"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=",
+ "description": "Sign PSBT with 3 inputs [P2PKH, P2TR (key-path), 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+p90ZfGGstEZ83LyfTLDFcfi2OlxAyuARcglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4AAQEfECcAAAAAAAAWABRPoqyhKLb53uUwnE9wBR5Jxl/XMgAAAA==",
"isTaproot": true,
"keys": [
{
@@ -289,18 +289,18 @@
},
{
"inputToSign": 1,
- "WIF": "cNPzVNoVCAfNEadTExqN2HzfC4dX42RtduE39D2i7cxuVEKY3DM3"
+ "WIF": "cR62L1G154fjHFrBCJMxJxbk1rcxhT2xcTh7WstvFdFDsZ9uFiVj"
},
{
"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="
+ "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+LY6XEDK4BE0Cd7/ny+QreV7urBWKNroQWCvnZczwkU0kLZiKsJQjtftKHWXMknftjt1d4K6aPYH7cBXzhlrUF+2GovjYLccZeARcglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4AAQEfECcAAAAAAAAWABRPoqyhKLb53uUwnE9wBR5Jxl/XMiICA6VOpEBbPJM/xYsqO2euttYFpgec9vcxggyTyoklK660SDBFAiEAoCIktghL55iuMAmkzwYJzb+h+qmNewZXxAx/06ObxIQCIELCsBz/wd2wPlnJb27OluxMkTPnCyHA2C+SxHiX/FvPAQAAAA=="
},
{
"description": "Sign PSBT with 1 input [P2TR] (script-path, 3-of-3) and one output [P2TR]",
- "psbt": "cHNidP8BAF4CAAAAAcPe80j90ChJ8zbpzcG0ZVC7LEvKwW5HRFLFTyc7y4bHAAAAAAD/////AZBBBgAAAAAAIlEgMqacf47eQ4lDRqNGRo3DRZ07bl/zz75tVIEa7xr7H0IAAAAAAAEBK6BoBgAAAAAAIlEgMqacf47eQ4lDRqNGRo3DRZ07bl/zz75tVIEa7xr7H0IBBWggj4kary4texRheMVKh+Ku3dnR1oZpIleSjmfPCBdP83WsIDlfgSndY7SlwvEhJOqgW3p+0w9w5R+5MwXe7MVC5/nruiCoqze8FgnYNMOROzU42tHITX+baoNf/BdXd5FaN641crpTnAAA",
+ "psbt": "cHNidP8BAF4CAAAAAQU2GLj/HTOEN804Hc6JRNTLM7EmDlIBdjG2G1aUw266AAAAAAD/////AYAaBgAAAAAAIlEg35sLGepBXUbR93XfxDJcYBCHqNVjw/jogOgPVdic1UgAAAAAAAEBK6BoBgAAAAAAIlEgVZx4+tHeORcb0jDJnOytrOnNOGL1uS0MdMUg1GQeS15iFcFmuQP4s1ds7KJtMOh4fTw1QCgxkWUA3FUAuUzKHzjDvhpSnJ+zzX53bWG2IltsYQ6JBvuPqmxZrFw+lbX4LSnWGlKcn7PNfndtYbYiW2xhDokG+4+qbFmsXD6VtfgtKdZpII+JGq8uLXsUYXjFSofirt3Z0daGaSJXko5nzwgXT/N1rCA5X4Ep3WO0pcLxISTqoFt6ftMPcOUfuTMF3uzFQuf567ogqKs3vBYJ2DTDkTs1ONrRyE1/m2qDX/wXV3eRWjeuNXK6U5zAAAA=",
"isTaproot": true,
"keys": [
{
@@ -316,7 +316,32 @@
"WIF": "cTrPNrN2EQo4ppBHcFNxyLBFq2WLjZoNKY5nQbPwAGdhQqqsRKSu"
}
],
- "result": "cHNidP8BAF4CAAAAAcPe80j90ChJ8zbpzcG0ZVC7LEvKwW5HRFLFTyc7y4bHAAAAAAD/////AZBBBgAAAAAAIlEgMqacf47eQ4lDRqNGRo3DRZ07bl/zz75tVIEa7xr7H0IAAAAAAAEBK6BoBgAAAAAAIlEgMqacf47eQ4lDRqNGRo3DRZ07bl/zz75tVIEa7xr7H0IiAgI5X4Ep3WO0pcLxISTqoFt6ftMPcOUfuTMF3uzFQuf560BOGsYvM/Ot27p7l86wu+8NyTgqenZPSYN3g88W0NWF1C6O2P7k8vMntZ7qXQJwahuxKQPjlHAhb+wCOp+sHi1cIgIDj4kary4texRheMVKh+Ku3dnR1oZpIleSjmfPCBdP83VAygBYJBfi/tFJV/2WNjeuh+rBnU17ZtihdMICzGGN7OLURnBRB5oARqqvcGwQF4ta2sarDwZd+mg6DMaHUqOQ4CICA6irN7wWCdg0w5E7NTja0chNf5tqg1/8F1d3kVo3rjVyQGNFuQCECKRcz9CR7vuYOQ5p9dwxty0rMxt33MPpUh+RoihShEgazosa20pguB1lg/TF1RTY25OYfjl9CUYTQdgBBWggj4kary4texRheMVKh+Ku3dnR1oZpIleSjmfPCBdP83WsIDlfgSndY7SlwvEhJOqgW3p+0w9w5R+5MwXe7MVC5/nruiCoqze8FgnYNMOROzU42tHITX+baoNf/BdXd5FaN641crpTnAAA"
+ "result": "cHNidP8BAF4CAAAAAQU2GLj/HTOEN804Hc6JRNTLM7EmDlIBdjG2G1aUw266AAAAAAD/////AYAaBgAAAAAAIlEg35sLGepBXUbR93XfxDJcYBCHqNVjw/jogOgPVdic1UgAAAAAAAEBK6BoBgAAAAAAIlEgVZx4+tHeORcb0jDJnOytrOnNOGL1uS0MdMUg1GQeS15BFDlfgSndY7SlwvEhJOqgW3p+0w9w5R+5MwXe7MVC5/nrrqI0FdZdKILLLZgRVK8L9Bn2ijU6IcoqqyImKIWt3MtAA3alBoU7IBCkBk9OHD1wE8fJI4y+lbnTRj48e8AAwRM77q3Rml679qCzGvEAKAs99UNMaXHQIhgGfRP11AMlJkEUj4kary4texRheMVKh+Ku3dnR1oZpIleSjmfPCBdP83WuojQV1l0ogsstmBFUrwv0GfaKNTohyiqrIiYoha3cy0DYJZ6Lv7FZPIBRZFfVgF5v3gcRiQnT8aM82Q5IPkwkzZrGo4ThZblvunG/+hu8ZPuJrUU+uXb+s9rcwSH+BihIQRSoqze8FgnYNMOROzU42tHITX+baoNf/BdXd5FaN641cq6iNBXWXSiCyy2YEVSvC/QZ9oo1OiHKKqsiJiiFrdzLQEfQ5UkAg4lTbhJxjMzB7hu6ad1fywYxHCXjFXHHrm5PJTOFJLg2oTnwuQToz/Z2AW/UET7Op+WSoHZvW4tzzLhiFcFmuQP4s1ds7KJtMOh4fTw1QCgxkWUA3FUAuUzKHzjDvhpSnJ+zzX53bWG2IltsYQ6JBvuPqmxZrFw+lbX4LSnWGlKcn7PNfndtYbYiW2xhDokG+4+qbFmsXD6VtfgtKdZpII+JGq8uLXsUYXjFSofirt3Z0daGaSJXko5nzwgXT/N1rCA5X4Ep3WO0pcLxISTqoFt6ftMPcOUfuTMF3uzFQuf567ogqKs3vBYJ2DTDkTs1ONrRyE1/m2qDX/wXV3eRWjeuNXK6U5zAAAA="
+ },
+ {
+ "description": "Sign PSBT with 1 input [P2TR]. Signer pubkey found in two tapleaf scripts (both get signed)",
+ "psbt": "cHNidP8BAF4CAAAAATNOP+fCPDCsZrgGIptDVbwY/yrkM2xaFfLe05BSLulZAAAAAAD/////AZBBBgAAAAAAIlEgo6glLro4LvJCjIXCj+2xYC8NQ5BB/tvaXLukmWNHDaQAAAAAAAEBK6BoBgAAAAAAIlEgo6glLro4LvJCjIXCj+2xYC8NQ5BB/tvaXLukmWNHDaRiFcDXgjtX0c88beKd6Y8zRYbANZXEc8dDhlup8v3SCiX0bBpSnJ+zzX53bWG2IltsYQ6JBvuPqmxZrFw+lbX4LSnWWeEQK6JF8Ev4E8Yg25gvDzbizKAO6m6JD082gFjsWNVpIP1IuUG/pcYMyG7KOHraqMXMKKOJb5eIpnjGt7LrvcsWrCDxKlbBaB54iRPj/r6t5N9DtBFItV8uoHfEwGboXpVsHLogt01J+NwSsj7PM7m6QbLDiXLdoYzn9pHNA4kAGF1pL3+6U5zAQhXA14I7V9HPPG3inemPM0WGwDWVxHPHQ4ZbqfL90gol9Gx4Lk64Mk5QMzz2Xo97sRZFcGH0TduAOb6H0hHOB/0CrCMg/Ui5Qb+lxgzIbso4etqoxcwoo4lvl4imeMa3suu9yxaswAAA",
+ "isTaproot": true,
+ "keys": [
+ {
+ "inputToSign": 0,
+ "WIF": "cSu5bjn9TsAEeqZxEFKy5of3FKfHha6FT56KvfAGmu6rMmPNJTrV"
+ }
+ ],
+ "result": "cHNidP8BAF4CAAAAATNOP+fCPDCsZrgGIptDVbwY/yrkM2xaFfLe05BSLulZAAAAAAD/////AZBBBgAAAAAAIlEgo6glLro4LvJCjIXCj+2xYC8NQ5BB/tvaXLukmWNHDaQAAAAAAAEBK6BoBgAAAAAAIlEgo6glLro4LvJCjIXCj+2xYC8NQ5BB/tvaXLukmWNHDaRBFP1IuUG/pcYMyG7KOHraqMXMKKOJb5eIpnjGt7LrvcsWIjJncH2zqZGpUloPoJZipi/NkKmjWthVrvnedXPOOOdABNUCXyGRAy4nthiGpE8dXioP2P50J+fU5gojlqunTwPKRPvqWcCzOoaJGvUEF+oxpMXZ1+FZWHRppoeoZFParUEU/Ui5Qb+lxgzIbso4etqoxcwoo4lvl4imeMa3suu9yxZZ4RArokXwS/gTxiDbmC8PNuLMoA7qbokPTzaAWOxY1UAF3RzlWz+5cWYG1EqfZTT/CO7O3hGYvMMjlJV5rluR916WCgGYO2hHj9fiEH0rxD3BRbzR78PShCen+beqDncSYhXA14I7V9HPPG3inemPM0WGwDWVxHPHQ4ZbqfL90gol9GwaUpyfs81+d21htiJbbGEOiQb7j6psWaxcPpW1+C0p1lnhECuiRfBL+BPGINuYLw824sygDupuiQ9PNoBY7FjVaSD9SLlBv6XGDMhuyjh62qjFzCijiW+XiKZ4xrey673LFqwg8SpWwWgeeIkT4/6+reTfQ7QRSLVfLqB3xMBm6F6VbBy6ILdNSfjcErI+zzO5ukGyw4ly3aGM5/aRzQOJABhdaS9/ulOcwEIVwNeCO1fRzzxt4p3pjzNFhsA1lcRzx0OGW6ny/dIKJfRseC5OuDJOUDM89l6Pe7EWRXBh9E3bgDm+h9IRzgf9AqwjIP1IuUG/pcYMyG7KOHraqMXMKKOJb5eIpnjGt7LrvcsWrMAAAA=="
+ },
+ {
+ "description": "Sign PSBT with 1 input [P2TR]. Signer pubkey found in two tapleaf scripts (sign only the matching tapleaf hash)",
+ "psbt": "cHNidP8BAF4CAAAAAdXMkUOLeYvgm981k3T7Pmdf5Dr31jOxvpFHiXiU9D2gAAAAAAD/////AZBBBgAAAAAAIlEgD31MIAvwCaanOsAzyBoQ4o/WozgFiqVQTEqGJE18XqwAAAAAAAEBK6BoBgAAAAAAIlEgD31MIAvwCaanOsAzyBoQ4o/WozgFiqVQTEqGJE18XqxiFcAI1JOUM3VATBJC28HI1B5zKQNd5N4/c4g7M1CYhZWnWhpSnJ+zzX53bWG2IltsYQ6JBvuPqmxZrFw+lbX4LSnWk4qTbS/aPOMicn4cednnrKiVhdggWbZxsQhaXXg5/EtpICo/Wsfk0hSOCy21lUyn+vXnc1SG1lNVWHlnXCh3xegqrCCcumXmHlTmveMSBLOPSfb6H3laX97tZtF4gqmxzV+gbLogXBeUvuJ0b/mMOa3539xiz0/Nf9RQCWGZXXoCNcFUYde6U5zAQhXACNSTlDN1QEwSQtvByNQecykDXeTeP3OIOzNQmIWVp1pfFb/yNVlibfG8oN35ON4kJ+kBZQ4LphUz16+7jituPiMgKj9ax+TSFI4LLbWVTKf69edzVIbWU1VYeWdcKHfF6CqswAAA",
+ "isTaproot": true,
+ "keys": [
+ {
+ "inputToSign": 0,
+ "tapLeafHashToSign": "f2d9fd9a2f80e0e7abeac881398fc37198f46e5c802ec00c95152aa6f703e71e",
+ "WIF": "cP76Rzf6bVcmFbnJ3DigWvyNvki2bZeXxoq3B5pcZ8zVRnT4fKdx"
+ }
+ ],
+ "result": "cHNidP8BAF4CAAAAAdXMkUOLeYvgm981k3T7Pmdf5Dr31jOxvpFHiXiU9D2gAAAAAAD/////AZBBBgAAAAAAIlEgD31MIAvwCaanOsAzyBoQ4o/WozgFiqVQTEqGJE18XqwAAAAAAAEBK6BoBgAAAAAAIlEgD31MIAvwCaanOsAzyBoQ4o/WozgFiqVQTEqGJE18XqxBFCo/Wsfk0hSOCy21lUyn+vXnc1SG1lNVWHlnXCh3xegq8tn9mi+A4Oer6siBOY/DcZj0blyALsAMlRUqpvcD5x5Aa7X0m4UCLaHA/Vnjkl+if6rVeiBbIlbHXHLh7RqJyB8Wgs66p6/ZnwSW/HD6o7rMHffIva+jgJgYWf6MvzrfTWIVwAjUk5QzdUBMEkLbwcjUHnMpA13k3j9ziDszUJiFladaGlKcn7PNfndtYbYiW2xhDokG+4+qbFmsXD6VtfgtKdaTipNtL9o84yJyfhx52eesqJWF2CBZtnGxCFpdeDn8S2kgKj9ax+TSFI4LLbWVTKf69edzVIbWU1VYeWdcKHfF6CqsIJy6ZeYeVOa94xIEs49J9vofeVpf3u1m0XiCqbHNX6BsuiBcF5S+4nRv+Yw5rfnf3GLPT81/1FAJYZldegI1wVRh17pTnMBCFcAI1JOUM3VATBJC28HI1B5zKQNd5N4/c4g7M1CYhZWnWl8Vv/I1WWJt8byg3fk43iQn6QFlDgumFTPXr7uOK24+IyAqP1rH5NIUjgsttZVMp/r153NUhtZTVVh5Z1wod8XoKqzAAAA="
}
],
"combiner": [
@@ -341,8 +366,39 @@
"result": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABB9oARzBEAiB0AYrUGACXuHMyPAAVcgs2hMyBI4kQSOfbzZtVrWecmQIgc9Npt0Dj61Pc76M4I8gHBRTKVafdlUTxV8FnkTJhEYwBSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAUdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSrgABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEHIyIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQjaBABHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwFHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gFHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4AIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA=="
},
{
- "psbt": "cHNidP8BAF4CAAAAAWbQAKi9hNXynJhqPu8bqkvp0kHihVShkWGh3yLy15+LAAAAAAD/////AbgFAQAAAAAAIlEgRvZJfLLxnVDD6emCqVDcyGIUsB/M5DekIGHHvbEjDTMAAAAAAAEBK7gFAQAAAAAAIlEglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4iAgKUIec0sPnSxGfqfdGXxhrLRGfNy8n0ywxXH4tjpcQMrkDYKEk9EBnhyC92Y/sV2r8U7uushyGLzWj/UcNmsym5qFYJUq2Fjhh2mUeMRu1yad248jY5EC8LQ7bb4vNqFVuMAAA=",
- "result": "cHNidP8BAF4CAAAAAWbQAKi9hNXynJhqPu8bqkvp0kHihVShkWGh3yLy15+LAAAAAAD/////AbgFAQAAAAAAIlEgRvZJfLLxnVDD6emCqVDcyGIUsB/M5DekIGHHvbEjDTMAAAAAAAEBK7gFAQAAAAAAIlEglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4BCEIBQNgoST0QGeHIL3Zj+xXavxTu66yHIYvNaP9Rw2azKbmoVglSrYWOGHaZR4xG7XJp3bjyNjkQLwtDttvi82oVW4wAAA==",
+ "description": "Finalze taproot key-path",
+ "psbt": "cHNidP8BAM8CAAAAAwPzd9k+uLSN1rgF01xY1TIA/8N+YytNZ4VP9gKFP4MyAAAAAAD/////ZtAAqL2E1fKcmGo+7xuqS+nSQeKFVKGRYaHfIvLXn4sAAAAAAP////9+h+SlCwIx1MUDT7Bek0NrWXS7xnSPi5LbYbDc9sxYIgAAAAAA/////wIgKRsAAAAAACJRIEb2SXyy8Z1Qw+npgqlQ3MhiFLAfzOQ3pCBhx72xIw0zuAUBAAAAAAAWABTJijE0v48z5ZmmfEAADXdCBcG0FAAAAAAAAQDiAgAAAAABAUfY2D1t0dyMeEH39C1yOdIxigpqm7XJNqHVT3Lc+FkiAAAAAAD+////AhIsGwAAAAAAGXapFJ5+8XZ3ZP80oFldvEwrcNsBftBmiKyYdK6xAAAAABepFLDBn59UffGbX7u/olyFDG0eG1UJhwJHMEQCIDAd3s05C61flXVFqOtov0NoHRGr8KFcOpH6R/81F46EAiBt+j9hHyvT2hYEyf8fdYsM9IgbnybtPV+kRTHDa6Rj0AEhAmmZfwmoHsmCkEOn9AfRTh+863mURelmE8hSqL4MG1EydJwgACICAi5ovBH1xLoGxPqtFh48wUEpnM+St1SbPzRwO7kBNKOQRzBEAiBpWClBybtHveXkhAgTiE8QSczMJs8MGuH4LOSNRA6s/AIgWlbB3xJOtJIsszj1qZ/whA5jK9wnTzeZzDlVs/ivq2cBAAEBK7gFAQAAAAAAIlEglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4BE0Cd7/ny+QreV7urBWKNroQWCvnZczwkU0kLZiKsJQjtftKHWXMknftjt1d4K6aPYH7cBXzhlrUF+2GovjYLccZeARcglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4AAQEfECcAAAAAAAAWABRPoqyhKLb53uUwnE9wBR5Jxl/XMiICA6VOpEBbPJM/xYsqO2euttYFpgec9vcxggyTyoklK660SDBFAiEAoCIktghL55iuMAmkzwYJzb+h+qmNewZXxAx/06ObxIQCIELCsBz/wd2wPlnJb27OluxMkTPnCyHA2C+SxHiX/FvPAQAAAA==",
+ "result": "cHNidP8BAM8CAAAAAwPzd9k+uLSN1rgF01xY1TIA/8N+YytNZ4VP9gKFP4MyAAAAAAD/////ZtAAqL2E1fKcmGo+7xuqS+nSQeKFVKGRYaHfIvLXn4sAAAAAAP////9+h+SlCwIx1MUDT7Bek0NrWXS7xnSPi5LbYbDc9sxYIgAAAAAA/////wIgKRsAAAAAACJRIEb2SXyy8Z1Qw+npgqlQ3MhiFLAfzOQ3pCBhx72xIw0zuAUBAAAAAAAWABTJijE0v48z5ZmmfEAADXdCBcG0FAAAAAAAAQDiAgAAAAABAUfY2D1t0dyMeEH39C1yOdIxigpqm7XJNqHVT3Lc+FkiAAAAAAD+////AhIsGwAAAAAAGXapFJ5+8XZ3ZP80oFldvEwrcNsBftBmiKyYdK6xAAAAABepFLDBn59UffGbX7u/olyFDG0eG1UJhwJHMEQCIDAd3s05C61flXVFqOtov0NoHRGr8KFcOpH6R/81F46EAiBt+j9hHyvT2hYEyf8fdYsM9IgbnybtPV+kRTHDa6Rj0AEhAmmZfwmoHsmCkEOn9AfRTh+863mURelmE8hSqL4MG1EydJwgAAEHakcwRAIgaVgpQcm7R73l5IQIE4hPEEnMzCbPDBrh+CzkjUQOrPwCIFpWwd8STrSSLLM49amf8IQOYyvcJ083mcw5VbP4r6tnASECLmi8EfXEugbE+q0WHjzBQSmcz5K3VJs/NHA7uQE0o5AAAQEruAUBAAAAAAAiUSCUIec0sPnSxGfqfdGXxhrLRGfNy8n0ywxXH4tjpcQMrgEIQgFAne/58vkK3le7qwVija6EFgr52XM8JFNJC2YirCUI7X7Sh1lzJJ37Y7dXeCumj2B+3AV84Za1BfthqL42C3HGXgABAR8QJwAAAAAAABYAFE+irKEotvne5TCcT3AFHknGX9cyAQhsAkgwRQIhAKAiJLYIS+eYrjAJpM8GCc2/ofqpjXsGV8QMf9Ojm8SEAiBCwrAc/8HdsD5ZyW9uzpbsTJEz5wshwNgvksR4l/xbzwEhA6VOpEBbPJM/xYsqO2euttYFpgec9vcxggyTyoklK660AAAA",
+ "isTaproot": true
+ },
+ {
+ "description": "Finalze taproot script-path",
+ "psbt": "cHNidP8BAF4CAAAAAQU2GLj/HTOEN804Hc6JRNTLM7EmDlIBdjG2G1aUw266AAAAAAD/////AYAaBgAAAAAAIlEg35sLGepBXUbR93XfxDJcYBCHqNVjw/jogOgPVdic1UgAAAAAAAEBK6BoBgAAAAAAIlEgVZx4+tHeORcb0jDJnOytrOnNOGL1uS0MdMUg1GQeS15BFDlfgSndY7SlwvEhJOqgW3p+0w9w5R+5MwXe7MVC5/nrrqI0FdZdKILLLZgRVK8L9Bn2ijU6IcoqqyImKIWt3MtAA3alBoU7IBCkBk9OHD1wE8fJI4y+lbnTRj48e8AAwRM77q3Rml679qCzGvEAKAs99UNMaXHQIhgGfRP11AMlJkEUj4kary4texRheMVKh+Ku3dnR1oZpIleSjmfPCBdP83WuojQV1l0ogsstmBFUrwv0GfaKNTohyiqrIiYoha3cy0DYJZ6Lv7FZPIBRZFfVgF5v3gcRiQnT8aM82Q5IPkwkzZrGo4ThZblvunG/+hu8ZPuJrUU+uXb+s9rcwSH+BihIQRSoqze8FgnYNMOROzU42tHITX+baoNf/BdXd5FaN641cq6iNBXWXSiCyy2YEVSvC/QZ9oo1OiHKKqsiJiiFrdzLQEfQ5UkAg4lTbhJxjMzB7hu6ad1fywYxHCXjFXHHrm5PJTOFJLg2oTnwuQToz/Z2AW/UET7Op+WSoHZvW4tzzLhiFcFmuQP4s1ds7KJtMOh4fTw1QCgxkWUA3FUAuUzKHzjDvhpSnJ+zzX53bWG2IltsYQ6JBvuPqmxZrFw+lbX4LSnWGlKcn7PNfndtYbYiW2xhDokG+4+qbFmsXD6VtfgtKdZpII+JGq8uLXsUYXjFSofirt3Z0daGaSJXko5nzwgXT/N1rCA5X4Ep3WO0pcLxISTqoFt6ftMPcOUfuTMF3uzFQuf567ogqKs3vBYJ2DTDkTs1ONrRyE1/m2qDX/wXV3eRWjeuNXK6U5zAAAA=",
+ "result": "cHNidP8BAF4CAAAAAQU2GLj/HTOEN804Hc6JRNTLM7EmDlIBdjG2G1aUw266AAAAAAD/////AYAaBgAAAAAAIlEg35sLGepBXUbR93XfxDJcYBCHqNVjw/jogOgPVdic1UgAAAAAAAEBK6BoBgAAAAAAIlEgVZx4+tHeORcb0jDJnOytrOnNOGL1uS0MdMUg1GQeS14BCP2PAQVAR9DlSQCDiVNuEnGMzMHuG7pp3V/LBjEcJeMVcceubk8lM4UkuDahOfC5BOjP9nYBb9QRPs6n5ZKgdm9bi3PMuEADdqUGhTsgEKQGT04cPXATx8kjjL6VudNGPjx7wADBEzvurdGaXrv2oLMa8QAoCz31Q0xpcdAiGAZ9E/XUAyUmQNglnou/sVk8gFFkV9WAXm/eBxGJCdPxozzZDkg+TCTNmsajhOFluW+6cb/6G7xk+4mtRT65dv6z2tzBIf4GKEhoII+JGq8uLXsUYXjFSofirt3Z0daGaSJXko5nzwgXT/N1rCA5X4Ep3WO0pcLxISTqoFt6ftMPcOUfuTMF3uzFQuf567ogqKs3vBYJ2DTDkTs1ONrRyE1/m2qDX/wXV3eRWjeuNXK6U5xhwWa5A/izV2zsom0w6Hh9PDVAKDGRZQDcVQC5TMofOMO+GlKcn7PNfndtYbYiW2xhDokG+4+qbFmsXD6VtfgtKdYaUpyfs81+d21htiJbbGEOiQb7j6psWaxcPpW1+C0p1gAA",
+ "isTaproot": true
+ },
+ {
+ "description": "Finalze taproot script-path (3-of-3)",
+ "psbt": "cHNidP8BAM8CAAAAAwPzd9k+uLSN1rgF01xY1TIA/8N+YytNZ4VP9gKFP4MyAAAAAAD/////ZtAAqL2E1fKcmGo+7xuqS+nSQeKFVKGRYaHfIvLXn4sAAAAAAP////9+h+SlCwIx1MUDT7Bek0NrWXS7xnSPi5LbYbDc9sxYIgAAAAAA/////wIgKRsAAAAAACJRIEb2SXyy8Z1Qw+npgqlQ3MhiFLAfzOQ3pCBhx72xIw0zuAUBAAAAAAAWABTJijE0v48z5ZmmfEAADXdCBcG0FAAAAAAAAQDiAgAAAAABAUfY2D1t0dyMeEH39C1yOdIxigpqm7XJNqHVT3Lc+FkiAAAAAAD+////AhIsGwAAAAAAGXapFJ5+8XZ3ZP80oFldvEwrcNsBftBmiKyYdK6xAAAAABepFLDBn59UffGbX7u/olyFDG0eG1UJhwJHMEQCIDAd3s05C61flXVFqOtov0NoHRGr8KFcOpH6R/81F46EAiBt+j9hHyvT2hYEyf8fdYsM9IgbnybtPV+kRTHDa6Rj0AEhAmmZfwmoHsmCkEOn9AfRTh+863mURelmE8hSqL4MG1EydJwgACICAi5ovBH1xLoGxPqtFh48wUEpnM+St1SbPzRwO7kBNKOQRzBEAiBpWClBybtHveXkhAgTiE8QSczMJs8MGuH4LOSNRA6s/AIgWlbB3xJOtJIsszj1qZ/whA5jK9wnTzeZzDlVs/ivq2cBAAEBK7gFAQAAAAAAIlEglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4BE0ADaUubfpFFrzbU+vL8qCzZE/FO+9unzylfpIgQZ4HTy2qPUtLvbyH59GApdz0SiUZGl8K6Crvt9YIfI/5FxbOLARcglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4AAQEfECcAAAAAAAAWABRPoqyhKLb53uUwnE9wBR5Jxl/XMiICA6VOpEBbPJM/xYsqO2euttYFpgec9vcxggyTyoklK660SDBFAiEAoCIktghL55iuMAmkzwYJzb+h+qmNewZXxAx/06ObxIQCIELCsBz/wd2wPlnJb27OluxMkTPnCyHA2C+SxHiX/FvPAQAAAA==",
+ "result": "cHNidP8BAM8CAAAAAwPzd9k+uLSN1rgF01xY1TIA/8N+YytNZ4VP9gKFP4MyAAAAAAD/////ZtAAqL2E1fKcmGo+7xuqS+nSQeKFVKGRYaHfIvLXn4sAAAAAAP////9+h+SlCwIx1MUDT7Bek0NrWXS7xnSPi5LbYbDc9sxYIgAAAAAA/////wIgKRsAAAAAACJRIEb2SXyy8Z1Qw+npgqlQ3MhiFLAfzOQ3pCBhx72xIw0zuAUBAAAAAAAWABTJijE0v48z5ZmmfEAADXdCBcG0FAAAAAAAAQDiAgAAAAABAUfY2D1t0dyMeEH39C1yOdIxigpqm7XJNqHVT3Lc+FkiAAAAAAD+////AhIsGwAAAAAAGXapFJ5+8XZ3ZP80oFldvEwrcNsBftBmiKyYdK6xAAAAABepFLDBn59UffGbX7u/olyFDG0eG1UJhwJHMEQCIDAd3s05C61flXVFqOtov0NoHRGr8KFcOpH6R/81F46EAiBt+j9hHyvT2hYEyf8fdYsM9IgbnybtPV+kRTHDa6Rj0AEhAmmZfwmoHsmCkEOn9AfRTh+863mURelmE8hSqL4MG1EydJwgAAEHakcwRAIgaVgpQcm7R73l5IQIE4hPEEnMzCbPDBrh+CzkjUQOrPwCIFpWwd8STrSSLLM49amf8IQOYyvcJ083mcw5VbP4r6tnASECLmi8EfXEugbE+q0WHjzBQSmcz5K3VJs/NHA7uQE0o5AAAQEruAUBAAAAAAAiUSCUIec0sPnSxGfqfdGXxhrLRGfNy8n0ywxXH4tjpcQMrgEIQgFAA2lLm36RRa821Pry/Kgs2RPxTvvbp88pX6SIEGeB08tqj1LS728h+fRgKXc9EolGRpfCugq77fWCHyP+RcWziwABAR8QJwAAAAAAABYAFE+irKEotvne5TCcT3AFHknGX9cyAQhsAkgwRQIhAKAiJLYIS+eYrjAJpM8GCc2/ofqpjXsGV8QMf9Ojm8SEAiBCwrAc/8HdsD5ZyW9uzpbsTJEz5wshwNgvksR4l/xbzwEhA6VOpEBbPJM/xYsqO2euttYFpgec9vcxggyTyoklK660AAAA",
+ "isTaproot": true
+ },
+ {
+ "description": "Finalze taproot with tapkey sig and tapscript sigs (choose tapkey)",
+ "psbt": "cHNidP8BAF4CAAAAAQrtX/VtEfTwY2iXi+s8lzx2JZbV7w9a8q6lONJ4SBm1AAAAAAD/////AZBBBgAAAAAAIlEgp+9JIlFbn3ZwqTz8p4UU73qJfQl4FvNDuyBa51FMm/kAAAAAAAEBK6BoBgAAAAAAIlEgp+9JIlFbn3ZwqTz8p4UU73qJfQl4FvNDuyBa51FMm/kBE0DqpLv0n1NC7N2okYWhHwP+mCqaDGOmNGCobgPw54CAtJdHPKY2i/ioNzq/m2Muh0hUYcLlOcU5U4xF7W+6gvRuQRQGAr5sFRVLM9rtDJmH/nCNJu0u72GXSA2wf9k4GEnXrossGVn91s+ghIb0v5fVWfWjsqU6wRJBundeShgEvDIVQNduanOw6c03gjyLWLim7b/7yet7XRp1uNrtwrMklOMSujYI/h2o+TSqS7eNwCkNddW3R6v03L6S9hWHTUYprclBFDhs6fMvKmERoTq2yrBafaRMmYoKkSuw9D4o3xjiC403iywZWf3Wz6CEhvS/l9VZ9aOypTrBEkG6d15KGAS8MhVAMKZJmsPn+pjmlWzj5oPGOj8XSs0uCMnDL1jjnosEuO7G0y9Y46GlGnfOM54w/0n2qKkdDWHpXX14F9gNesiP5EEUfKybjQL7rXdJwSP1Fb15LaJyYFrW3yJnkN+aP9IdhTOGRF1EGo0fkg5hbe3o7iwS+jTgqmGOQDsHExHbJgmL90A8hHY8WzI+xJsFXMzi5ztkZS8pXf07iNlfDnLKZYyk9ZRBkAsJ9oYsvC19Irrq27l918aqfQc6sZBiskZyMs5wQRR8rJuNAvutd0nBI/UVvXktonJgWtbfImeQ35o/0h2FM4ssGVn91s+ghIb0v5fVWfWjsqU6wRJBundeShgEvDIVQFeVntO1MSRANCT3fpEWhijVJAbF6SVBdPlNAaRKc1sn3Gz+/HTfD+f9sqRlSIsF4D+ouhv6URBtAZUCuKHW6vxiFcFB6oQ4lfHrNv47TKgSz/MUn2hgozxlIgmi2demetlGgxpSnJ+zzX53bWG2IltsYQ6JBvuPqmxZrFw+lbX4LSnWhkRdRBqNH5IOYW3t6O4sEvo04KphjkA7BxMR2yYJi/dpIHysm40C+613ScEj9RW9eS2icmBa1t8iZ5Dfmj/SHYUzrCAGAr5sFRVLM9rtDJmH/nCNJu0u72GXSA2wf9k4GEnXrrogOGzp8y8qYRGhOrbKsFp9pEyZigqRK7D0PijfGOILjTe6U5zAQhXBQeqEOJXx6zb+O0yoEs/zFJ9oYKM8ZSIJotnXpnrZRoMvbQYwKuRcSf7lDrRMU3H56Gh6NeGkogAw4hpvAn/mgCMgfKybjQL7rXdJwSP1Fb15LaJyYFrW3yJnkN+aP9IdhTOswAEXIEHqhDiV8es2/jtMqBLP8xSfaGCjPGUiCaLZ16Z62UaDARggNhmyJFW2/EeankNIJjRP9QFlju4/j/nEEcMAnlXe+XcAAA==",
+ "result": "cHNidP8BAF4CAAAAAQrtX/VtEfTwY2iXi+s8lzx2JZbV7w9a8q6lONJ4SBm1AAAAAAD/////AZBBBgAAAAAAIlEgp+9JIlFbn3ZwqTz8p4UU73qJfQl4FvNDuyBa51FMm/kAAAAAAAEBK6BoBgAAAAAAIlEgp+9JIlFbn3ZwqTz8p4UU73qJfQl4FvNDuyBa51FMm/kBCEIBQOqku/SfU0Ls3aiRhaEfA/6YKpoMY6Y0YKhuA/DngIC0l0c8pjaL+Kg3Or+bYy6HSFRhwuU5xTlTjEXtb7qC9G4AAA==",
+ "isTaproot": true
+ },
+ {
+ "description": "Finalze taproot script-path with two tapleafs signed (chooses the one with the shortest path)",
+ "psbt": "cHNidP8BAF4CAAAAAZsypn8thOjCXwg39Z1pAQCp7ndI8Jrw/8SGSmhgRiJpAAAAAAD/////AZBBBgAAAAAAIlEgFa11cf11Y+PGzl0UxS5788pld5zElAl9YY0OtTHhHzQAAAAAAAEBK6BoBgAAAAAAIlEgFa11cf11Y+PGzl0UxS5788pld5zElAl9YY0OtTHhHzRBFAUf68vx5rAfWwxMqZNce2OVVqlduXONBcm2JEPAT2Fc2gpbUnze59ZSHmflF7erkp8eUGBfJBmAcUZG5WBbC/pAJihlaGGDKsSd04fSyIk5WDACUedUvDE1C4zD80ubbX5qFzgxizY7pGG5zrrGAoW0KOEJ8TW4WEmh/WsE0erDxEEUIKvXw9clC9dJYjC2Woo/TrIhnRP9powDMmB/GF4rBRsRCNvHrz3TPp4Id2O6W4qhmerk87mqanTdLIapgqEamkDnpOB240Ce+yZlOPO3sxZDmpXhmsxtIl6a/R6TS2ekf2VCdZXg4Dqy3OpjzxQ/jDMbXbzETL2mdHlsgQnBnUcoYhXBr6rSntatZCCpyXS0zh+WAkLdMI4XHA0rVYAbFyHRzrqYKqOqTjCjec9FzSPuoLS+tXB4VvMgzUTs3kZS/bDfqlRY6TCnm2dtB3ED1fA6rlsUAqbWuurDp2W9ONMZj7NiIyAFH+vL8eawH1sMTKmTXHtjlVapXblzjQXJtiRDwE9hXKzAohXBr6rSntatZCCpyXS0zh+WAkLdMI4XHA0rVYAbFyHRzrq0JN6gn4QLkyoANzzc29JWULjDrP5UqfSmQaKGchuNJtrHlXZrvaHq6qReW/oKlQ/dX0xKraWx8wgu3JaJuf0K7iijuCxK7L69N4En3IjdGeHqk+26eie3VOHIgdMIh0q9q7FEmRK2sbmE7NhWpbGiU/lLBm6XT+D9HvPO+T63rSMgIKvXw9clC9dJYjC2Woo/TrIhnRP9powDMmB/GF4rBRuswAAA",
+ "result": "cHNidP8BAF4CAAAAAZsypn8thOjCXwg39Z1pAQCp7ndI8Jrw/8SGSmhgRiJpAAAAAAD/////AZBBBgAAAAAAIlEgFa11cf11Y+PGzl0UxS5788pld5zElAl9YY0OtTHhHzQAAAAAAAEBK6BoBgAAAAAAIlEgFa11cf11Y+PGzl0UxS5788pld5zElAl9YY0OtTHhHzQBCMcDQCYoZWhhgyrEndOH0siJOVgwAlHnVLwxNQuMw/NLm21+ahc4MYs2O6Rhuc66xgKFtCjhCfE1uFhJof1rBNHqw8QiIAUf68vx5rAfWwxMqZNce2OVVqlduXONBcm2JEPAT2FcrGHBr6rSntatZCCpyXS0zh+WAkLdMI4XHA0rVYAbFyHRzrqYKqOqTjCjec9FzSPuoLS+tXB4VvMgzUTs3kZS/bDfqlRY6TCnm2dtB3ED1fA6rlsUAqbWuurDp2W9ONMZj7NiAAA=",
+ "isTaproot": true
+ },
+ {
+ "description": "Finalze taproot script-path with two tapleafs signed (explicitly choose leaf)",
+ "psbt": "cHNidP8BAF4CAAAAAZsypn8thOjCXwg39Z1pAQCp7ndI8Jrw/8SGSmhgRiJpAAAAAAD/////AZBBBgAAAAAAIlEgFa11cf11Y+PGzl0UxS5788pld5zElAl9YY0OtTHhHzQAAAAAAAEBK6BoBgAAAAAAIlEgFa11cf11Y+PGzl0UxS5788pld5zElAl9YY0OtTHhHzRBFAUf68vx5rAfWwxMqZNce2OVVqlduXONBcm2JEPAT2Fc2gpbUnze59ZSHmflF7erkp8eUGBfJBmAcUZG5WBbC/pAJihlaGGDKsSd04fSyIk5WDACUedUvDE1C4zD80ubbX5qFzgxizY7pGG5zrrGAoW0KOEJ8TW4WEmh/WsE0erDxEEUIKvXw9clC9dJYjC2Woo/TrIhnRP9powDMmB/GF4rBRsRCNvHrz3TPp4Id2O6W4qhmerk87mqanTdLIapgqEamkDnpOB240Ce+yZlOPO3sxZDmpXhmsxtIl6a/R6TS2ekf2VCdZXg4Dqy3OpjzxQ/jDMbXbzETL2mdHlsgQnBnUcoYhXBr6rSntatZCCpyXS0zh+WAkLdMI4XHA0rVYAbFyHRzrqYKqOqTjCjec9FzSPuoLS+tXB4VvMgzUTs3kZS/bDfqlRY6TCnm2dtB3ED1fA6rlsUAqbWuurDp2W9ONMZj7NiIyAFH+vL8eawH1sMTKmTXHtjlVapXblzjQXJtiRDwE9hXKzAohXBr6rSntatZCCpyXS0zh+WAkLdMI4XHA0rVYAbFyHRzrq0JN6gn4QLkyoANzzc29JWULjDrP5UqfSmQaKGchuNJtrHlXZrvaHq6qReW/oKlQ/dX0xKraWx8wgu3JaJuf0K7iijuCxK7L69N4En3IjdGeHqk+26eie3VOHIgdMIh0q9q7FEmRK2sbmE7NhWpbGiU/lLBm6XT+D9HvPO+T63rSMgIKvXw9clC9dJYjC2Woo/TrIhnRP9powDMmB/GF4rBRuswAAA",
+ "result": "cHNidP8BAF4CAAAAAZsypn8thOjCXwg39Z1pAQCp7ndI8Jrw/8SGSmhgRiJpAAAAAAD/////AZBBBgAAAAAAIlEgFa11cf11Y+PGzl0UxS5788pld5zElAl9YY0OtTHhHzQAAAAAAAEBK6BoBgAAAAAAIlEgFa11cf11Y+PGzl0UxS5788pld5zElAl9YY0OtTHhHzQBCMcDQCYoZWhhgyrEndOH0siJOVgwAlHnVLwxNQuMw/NLm21+ahc4MYs2O6Rhuc66xgKFtCjhCfE1uFhJof1rBNHqw8QiIAUf68vx5rAfWwxMqZNce2OVVqlduXONBcm2JEPAT2FcrGHBr6rSntatZCCpyXS0zh+WAkLdMI4XHA0rVYAbFyHRzrqYKqOqTjCjec9FzSPuoLS+tXB4VvMgzUTs3kZS/bDfqlRY6TCnm2dtB3ED1fA6rlsUAqbWuurDp2W9ONMZj7NiAAA=",
"isTaproot": true
}
],
@@ -387,6 +443,51 @@
"index": 2
},
"equals": "cHNidP8BADMCAAAAAQABAgMEBQYHCAkKCwwNDg8AAQIDBAUGBwgJCgsMDQ4PAgAAAAD/////AAAAAAAAAAA="
+ },
+ {
+ "description": "checks for mixed taproot and non-taproot fields",
+ "inputData": {
+ "hash": "Buffer.from('000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f', 'hex')",
+ "index": 0,
+ "redeemScript": "Buffer.from('0014000102030405060708090a0b0c0d0e0f00010000', 'hex')",
+ "tapInternalKey": "Buffer.from('000102030405060708090a0b0c0d0e0f00010203040506070000000000000000', 'hex')"
+ },
+ "exception": "Invalid arguments for Psbt.addInput. Cannot use both taproot and non-taproot fields."
+ },
+ {
+ "description": "checks for tapleaf in taptree",
+ "inputData": {
+ "hash": "Buffer.from('000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f', 'hex')",
+ "index": 0,
+ "tapMerkleRoot": "Buffer.from('5cf5873456b400364b18bdc9a1a233870fa622a6010deef1d4e08474f3a103b4', 'hex')",
+ "tapLeafScript": [
+ {
+ "leafVersion": 192,
+ "script": "Buffer.from('20d5e347235eba74ae0cec686b668d5a9432f45a555d6ab22cebf5974bde9dc4f3ac', 'hex')",
+ "controlBlock": "Buffer.from('c0720768b9946ac22371653d92cc343bf109b8a3f819e231159fd4f2b1328944ecb424dea09f840b932a00373cdcdbd25650b8c3acfe54a9f4a641a286721b8d26dac795766bbda1eaeaa45e5bfa0a950fdd5f4c4aada5b1f3082edc9689b9fd0aee28a3b82c4aecbebd378127dc88dd19e1ea93edba7a27b754e1c881d308874a7ac4489544b7b840d045599ec9415ae71ccb090c2c465c05c9fa05f41c7a06d5', 'hex')"
+ }
+ ]
+ },
+ "exception": "Invalid arguments for Psbt.addInput. Tapleaf not part of taptree."
+ }
+ ]
+ },
+ "updateInput": {
+ "checks": [
+ {
+ "description": "checks for new tapleaf in taptree",
+ "psbt": "cHNidP8BADMCAAAAAQ1YzlMrOEvTUad+B8zippgoNUwrXhwvsHMMGwZb6S7LAAAAAAD/////AAAAAAAAAQEroGgGAAAAAAAiUSD3Vv2gTbCrHTNlF18uY/YKLdATh0ph4pwrCyUHkhtZngEYIHsGySMEjYsxl3fCSP6Ap7tG06AUPLXA8nGnwzSEH70VAAA=",
+ "index": 0,
+ "inputData": {
+ "tapLeafScript": [
+ {
+ "leafVersion": 192,
+ "script": "Buffer.from('20d5e347235eba74ae0cec686b668d5a9432f45a555d6ab22cebf5974bde9dc4f3ac', 'hex')",
+ "controlBlock": "Buffer.from('c0720768b9946ac22371653d92cc343bf109b8a3f819e231159fd4f2b1328944ecb424dea09f840b932a00373cdcdbd25650b8c3acfe54a9f4a641a286721b8d26dac795766bbda1eaeaa45e5bfa0a950fdd5f4c4aada5b1f3082edc9689b9fd0aee28a3b82c4aecbebd378127dc88dd19e1ea93edba7a27b754e1c881d308874a7ac4489544b7b840d045599ec9415ae71ccb090c2c465c05c9fa05f41c7a06d5', 'hex')"
+ }
+ ]
+ },
+ "exception": "Invalid arguments for Psbt.updateInput. Tapleaf not part of taptree."
}
]
},
@@ -512,6 +613,27 @@
"inputToCheck": 0,
"WIF": "KxnAnQh6UJBxLF8Weup77yn8tWhLHhDhnXeyJuzmmcZA5aRdMJni"
}
+ },
+ {
+ "description": "checks taproot key-path signer (tweaked key) matches internal tap key",
+ "isTaproot": true,
+ "shouldSign": {
+ "psbt": "cHNidP8BAF4CAAAAAf17fGksrz9eKGx1nSU3RX4vcwr7bfNdQzPZ9dSEkWBcAAAAAAD/////AZBBBgAAAAAAIlEgPLBe/d3922lmXjTIt52b9NG1HFDC9jzPCTn111AG8TQAAAAAAAEBK6BoBgAAAAAAIlEgPLBe/d3922lmXjTIt52b9NG1HFDC9jzPCTn111AG8TQBFyBbMLiqcPfsndZoMRtk9GKEFd0jSA3rwEa60nKQNwdHrAEYIOUOtfVyfPBm+ZzIsEfwzo2JL2WTslXAznzBllU7Oa4zAAA=",
+ "inputToCheck": 0,
+ "WIF": "KypUz2y1jdgzM8HGDUx9DYLmyzd8EWhruvLX2J5iSL7MiAcc7dBG",
+ "result": "cHNidP8BAF4CAAAAAf17fGksrz9eKGx1nSU3RX4vcwr7bfNdQzPZ9dSEkWBcAAAAAAD/////AZBBBgAAAAAAIlEgPLBe/d3922lmXjTIt52b9NG1HFDC9jzPCTn111AG8TQAAAAAAAEBK6BoBgAAAAAAIlEgPLBe/d3922lmXjTIt52b9NG1HFDC9jzPCTn111AG8TQBE0AAqkKg+dq3eThMoqzjh214urhgUoGTgwHlNyyMQ2RwhfeRIhAp+m9mZwQoXOxK7p2ILjf2G5j28F9KMhMzH7bXARcgWzC4qnD37J3WaDEbZPRihBXdI0gN68BGutJykDcHR6wBGCDlDrX1cnzwZvmcyLBH8M6NiS9lk7JVwM58wZZVOzmuMwAA"
+ }
+
+ },
+ {
+ "description": "check taproot script-path signer found for the input",
+ "isTaproot": true,
+ "shouldSign": {
+ "psbt": "cHNidP8BAF4CAAAAAUYAJ/rjwsScVTFXg1in8cNdaBDtwLAsQ6l1O8sWijmlAAAAAAD/////AZBBBgAAAAAAIlEgFlrANpbJgyRLzVMhozrVHKr6rGrz7e2bQ+3TyITRhB4AAAAAAAEBK6BoBgAAAAAAIlEgFlrANpbJgyRLzVMhozrVHKr6rGrz7e2bQ+3TyITRhB5BFNs7WfGuA1DZ7ZorvaC77E4rn/I2hbVtogxHpEnxKZ3DGlKcn7PNfndtYbYiW2xhDokG+4+qbFmsXD6VtfgtKdZAbjBxWKodWLnyqPP18sLAjhTc/OXtHVtk+Abc/e8SoTIxaOORlmqOegbCKAUyL4+NFdAlgtcUyHUCxWaxJ3ykxGIVwOpmBmLM44rn+zwtvl1cyWYheMCVYuX2agqeiHOvsrXIGlKcn7PNfndtYbYiW2xhDokG+4+qbFmsXD6VtfgtKdYaUpyfs81+d21htiJbbGEOiQb7j6psWaxcPpW1+C0p1mkgq1snxZRfWXi8CMjFSaobG3elbWWeL9QqflyaQtTYEG2sINs7WfGuA1DZ7ZorvaC77E4rn/I2hbVtogxHpEnxKZ3DuiB8Z8sVUSbQp0q8mQiD5n5coMrRzQAASnO9NspgIk9pZ7pTnMAAAA==",
+ "inputToCheck": 0,
+ "WIF": "L2wCzcNaJwG1W9djnumJnPQZTCpfeCkR2wgwfupphmThSrwTMCR6",
+ "result": "cHNidP8BAF4CAAAAAUYAJ/rjwsScVTFXg1in8cNdaBDtwLAsQ6l1O8sWijmlAAAAAAD/////AZBBBgAAAAAAIlEgFlrANpbJgyRLzVMhozrVHKr6rGrz7e2bQ+3TyITRhB4AAAAAAAEBK6BoBgAAAAAAIlEgFlrANpbJgyRLzVMhozrVHKr6rGrz7e2bQ+3TyITRhB5BFKtbJ8WUX1l4vAjIxUmqGxt3pW1lni/UKn5cmkLU2BBtT3q/MbhvStFL2jaKZM6N8TeYvCUfSVytPrzfjkXWQbdAoS5lV4a+yP0Y4nTr7ltbsrwMo+U3TNcC/ebE6U6xk/4er9bXfdvZNvgR+TgqrO/iZjNNI6QcGaudPObgsgYKTEEU2ztZ8a4DUNntmiu9oLvsTiuf8jaFtW2iDEekSfEpncMaUpyfs81+d21htiJbbGEOiQb7j6psWaxcPpW1+C0p1kBuMHFYqh1YufKo8/XywsCOFNz85e0dW2T4Btz97xKhMjFo45GWao56BsIoBTIvj40V0CWC1xTIdQLFZrEnfKTEYhXA6mYGYszjiuf7PC2+XVzJZiF4wJVi5fZqCp6Ic6+ytcgaUpyfs81+d21htiJbbGEOiQb7j6psWaxcPpW1+C0p1hpSnJ+zzX53bWG2IltsYQ6JBvuPqmxZrFw+lbX4LSnWaSCrWyfFlF9ZeLwIyMVJqhsbd6VtZZ4v1Cp+XJpC1NgQbawg2ztZ8a4DUNntmiu9oLvsTiuf8jaFtW2iDEekSfEpncO6IHxnyxVRJtCnSryZCIPmflygytHNAABKc702ymAiT2lnulOcwAAA"
+ }
}
]
},
@@ -561,6 +683,14 @@
}
]
},
+ "finalizeInput": {
+ "finalizeTapleafByHash": {
+ "psbt": "cHNidP8BAF4CAAAAAXbYuDMSrbXuy1CXHZaiA8jjI+wcNkkCOL2dJD2dNf3kAAAAAAD/////AZBBBgAAAAAAIlEgcJi/YJDTvc6x6mRTIYgQG/+fEmLs2RjsO/FHW5okOEsAAAAAAAEBK6BoBgAAAAAAIlEgcJi/YJDTvc6x6mRTIYgQG/+fEmLs2RjsO/FHW5okOEtBFG78QHu9pQ+jR/B1+dz9XQtU0jFgoC5AFXcvibFi1jFAEkntiZ6MdFzn0seJJapRqACzEKXd0ZlMa34/iq0HnrVAfYaCk2E35rtXsMfbr/Hrbk/BtLF2VLepE0vIIB3UOWZEUF8akmlnL4Kh0xwMn4Cp99QivnI0B3XOsYfEznfDHUEUesul6blPS+qc/rm41L9nGaAck9KDAZAutbDsNLSZuXXMWh7785JCWLEpzsZRkM/9RJ+EaLYT/0O2sg4cHNHo1EBHFn/xRZno2fX/vLc1l2qHqZGB2vbLkZDj5KsVfqeJd78uIc5b6uAG0K+BBtq2H6HUvl+8RWd2GWmVoMTYppVNYhXAjGyV+gMPwhuPgQ05yTUt2dmE2xJLdkeHBaiap2ej2SuYKqOqTjCjec9FzSPuoLS+tXB4VvMgzUTs3kZS/bDfqvuLvWTUb+e6sUIP9JrqDAHAjkYMd3K3PTfk+B6aMTv4IyB6y6XpuU9L6pz+ubjUv2cZoByT0oMBkC61sOw0tJm5dazAohXAjGyV+gMPwhuPgQ05yTUt2dmE2xJLdkeHBaiap2ej2Su0JN6gn4QLkyoANzzc29JWULjDrP5UqfSmQaKGchuNJtrHlXZrvaHq6qReW/oKlQ/dX0xKraWx8wgu3JaJuf0K7iijuCxK7L69N4En3IjdGeHqk+26eie3VOHIgdMIh0q48S7pX3ESdKuEJ4Jo9s+PwRFNvGdokOHBSefrgpE1JCMgbvxAe72lD6NH8HX53P1dC1TSMWCgLkAVdy+JsWLWMUCswAAA",
+ "index": 0,
+ "leafHash": "1249ed899e8c745ce7d2c78925aa51a800b310a5ddd1994c6b7e3f8aad079eb5",
+ "result": "cHNidP8BAF4CAAAAAXbYuDMSrbXuy1CXHZaiA8jjI+wcNkkCOL2dJD2dNf3kAAAAAAD/////AZBBBgAAAAAAIlEgcJi/YJDTvc6x6mRTIYgQG/+fEmLs2RjsO/FHW5okOEsAAAAAAAEBK6BoBgAAAAAAIlEgcJi/YJDTvc6x6mRTIYgQG/+fEmLs2RjsO/FHW5okOEsBCP0HAQNAfYaCk2E35rtXsMfbr/Hrbk/BtLF2VLepE0vIIB3UOWZEUF8akmlnL4Kh0xwMn4Cp99QivnI0B3XOsYfEznfDHSIgbvxAe72lD6NH8HX53P1dC1TSMWCgLkAVdy+JsWLWMUCsocCMbJX6Aw/CG4+BDTnJNS3Z2YTbEkt2R4cFqJqnZ6PZK7Qk3qCfhAuTKgA3PNzb0lZQuMOs/lSp9KZBooZyG40m2seVdmu9oerqpF5b+gqVD91fTEqtpbHzCC7clom5/QruKKO4LErsvr03gSfciN0Z4eqT7bp6J7dU4ciB0wiHSrjxLulfcRJ0q4Qngmj2z4/BEU28Z2iQ4cFJ5+uCkTUkAAA="
+ }
+ },
"finalizeAllInputs": [
{
"type": "P2PK",
@@ -600,25 +730,17 @@
"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",
+ "validateSignaturesOfTapKeyInput": {
+ "psbt": "cHNidP8BAM8CAAAAAwPzd9k+uLSN1rgF01xY1TIA/8N+YytNZ4VP9gKFP4MyAAAAAAD/////ZtAAqL2E1fKcmGo+7xuqS+nSQeKFVKGRYaHfIvLXn4sAAAAAAP////9+h+SlCwIx1MUDT7Bek0NrWXS7xnSPi5LbYbDc9sxYIgAAAAAA/////wIgKRsAAAAAACJRIEb2SXyy8Z1Qw+npgqlQ3MhiFLAfzOQ3pCBhx72xIw0zuAUBAAAAAAAWABTJijE0v48z5ZmmfEAADXdCBcG0FAAAAAAAAQDiAgAAAAABAUfY2D1t0dyMeEH39C1yOdIxigpqm7XJNqHVT3Lc+FkiAAAAAAD+////AhIsGwAAAAAAGXapFJ5+8XZ3ZP80oFldvEwrcNsBftBmiKyYdK6xAAAAABepFLDBn59UffGbX7u/olyFDG0eG1UJhwJHMEQCIDAd3s05C61flXVFqOtov0NoHRGr8KFcOpH6R/81F46EAiBt+j9hHyvT2hYEyf8fdYsM9IgbnybtPV+kRTHDa6Rj0AEhAmmZfwmoHsmCkEOn9AfRTh+863mURelmE8hSqL4MG1EydJwgACICAi5ovBH1xLoGxPqtFh48wUEpnM+St1SbPzRwO7kBNKOQRzBEAiBpWClBybtHveXkhAgTiE8QSczMJs8MGuH4LOSNRA6s/AIgWlbB3xJOtJIsszj1qZ/whA5jK9wnTzeZzDlVs/ivq2cBAAEBK7gFAQAAAAAAIlEglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4BE0Cd7/ny+QreV7urBWKNroQWCvnZczwkU0kLZiKsJQjtftKHWXMknftjt1d4K6aPYH7cBXzhlrUF+2GovjYLccZeARcglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4AAQEfECcAAAAAAAAWABRPoqyhKLb53uUwnE9wBR5Jxl/XMiICA6VOpEBbPJM/xYsqO2euttYFpgec9vcxggyTyoklK660SDBFAiEAoCIktghL55iuMAmkzwYJzb+h+qmNewZXxAx/06ObxIQCIELCsBz/wd2wPlnJb27OluxMkTPnCyHA2C+SxHiX/FvPAQAAAA==",
"index": 1,
- "pubkey": "Buffer.from('029421e734b0f9d2c467ea7dd197c61acb4467cdcbc9f4cb0c571f8b63a5c40cae', 'hex')",
- "incorrectPubkey": "Buffer.from('029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e02a', 'hex')",
- "nonExistantIndex": 42
+ "pubkey": "Buffer.from('024fef5c5163bea69a93e74a59672bbeb081837077cb94cfa6e481a5cf00d8ab18', 'hex')",
+ "incorrectPubkey": "Buffer.from('029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e02a', 'hex')"
},
- "finalizeTaprootScriptPathSpendInput": {
- "psbt": "cHNidP8BAF4CAAAAAWbQAKi9hNXynJhqPu8bqkvp0kHihVShkWGh3yLy15+LAAAAAAD/////AbgFAQAAAAAAIlEgRvZJfLLxnVDD6emCqVDcyGIUsB/M5DekIGHHvbEjDTMAAAAAAAEBK7gFAQAAAAAAIlEglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4iAgIuaLwR9cS6BsT6rRYePMFBKZzPkrdUmz80cDu5ATSjkEC5NO2PsYVquVp/60QIc7eTYcr16eABzDpFibWxBgfXoEDrH0oCzDH5HQ8lu7S9VWJwKvJ7GJIMGLDCX/n13qSsAQUiIC5ovBH1xLoGxPqtFh48wUEpnM+St1SbPzRwO7kBNKOQrAAA",
- "internalPublicKey": "Buffer.from('02982a2876765bb37b53a12418b9e72b8afa8d54e344a1bd585299a211fbe625f3', 'hex')",
- "scriptTree": [
- {
- "output": "Buffer.from('2050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0ac', 'hex')"
- },
- {
- "output": "Buffer.from('202e68bc11f5c4ba06c4faad161e3cc141299ccf92b7549b3f34703bb90134a390ac', 'hex')"
- }
- ],
- "result": "cHNidP8BAF4CAAAAAWbQAKi9hNXynJhqPu8bqkvp0kHihVShkWGh3yLy15+LAAAAAAD/////AbgFAQAAAAAAIlEgRvZJfLLxnVDD6emCqVDcyGIUsB/M5DekIGHHvbEjDTMAAAAAAAEBK7gFAQAAAAAAIlEglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4BCKcDQLk07Y+xhWq5Wn/rRAhzt5NhyvXp4AHMOkWJtbEGB9egQOsfSgLMMfkdDyW7tL1VYnAq8nsYkgwYsMJf+fXepKwiIC5ovBH1xLoGxPqtFh48wUEpnM+St1SbPzRwO7kBNKOQrEHAmCoodnZbs3tToSQYuecrivqNVONEob1YUpmiEfvmJfMaUpyfs81+d21htiJbbGEOiQb7j6psWaxcPpW1+C0p1gAA"
+ "validateSignaturesOfTapScriptInput": {
+ "psbt": "cHNidP8BAF4CAAAAAQU2GLj/HTOEN804Hc6JRNTLM7EmDlIBdjG2G1aUw266AAAAAAD/////AYAaBgAAAAAAIlEg35sLGepBXUbR93XfxDJcYBCHqNVjw/jogOgPVdic1UgAAAAAAAEBK6BoBgAAAAAAIlEgVZx4+tHeORcb0jDJnOytrOnNOGL1uS0MdMUg1GQeS15BFDlfgSndY7SlwvEhJOqgW3p+0w9w5R+5MwXe7MVC5/nrrqI0FdZdKILLLZgRVK8L9Bn2ijU6IcoqqyImKIWt3MtAA3alBoU7IBCkBk9OHD1wE8fJI4y+lbnTRj48e8AAwRM77q3Rml679qCzGvEAKAs99UNMaXHQIhgGfRP11AMlJkEUj4kary4texRheMVKh+Ku3dnR1oZpIleSjmfPCBdP83WuojQV1l0ogsstmBFUrwv0GfaKNTohyiqrIiYoha3cy0DYJZ6Lv7FZPIBRZFfVgF5v3gcRiQnT8aM82Q5IPkwkzZrGo4ThZblvunG/+hu8ZPuJrUU+uXb+s9rcwSH+BihIQRSoqze8FgnYNMOROzU42tHITX+baoNf/BdXd5FaN641cq6iNBXWXSiCyy2YEVSvC/QZ9oo1OiHKKqsiJiiFrdzLQEfQ5UkAg4lTbhJxjMzB7hu6ad1fywYxHCXjFXHHrm5PJTOFJLg2oTnwuQToz/Z2AW/UET7Op+WSoHZvW4tzzLhiFcFmuQP4s1ds7KJtMOh4fTw1QCgxkWUA3FUAuUzKHzjDvhpSnJ+zzX53bWG2IltsYQ6JBvuPqmxZrFw+lbX4LSnWGlKcn7PNfndtYbYiW2xhDokG+4+qbFmsXD6VtfgtKdZpII+JGq8uLXsUYXjFSofirt3Z0daGaSJXko5nzwgXT/N1rCA5X4Ep3WO0pcLxISTqoFt6ftMPcOUfuTMF3uzFQuf567ogqKs3vBYJ2DTDkTs1ONrRyE1/m2qDX/wXV3eRWjeuNXK6U5zAAAA=",
+ "index": 0,
+ "pubkey": "Buffer.from('02395f8129dd63b4a5c2f12124eaa05b7a7ed30f70e51fb93305deecc542e7f9eb', 'hex')",
+ "incorrectPubkey": "Buffer.from('029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e02a', 'hex')"
},
"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",
diff --git a/test/integration/taproot.spec.ts b/test/integration/taproot.spec.ts
index af1291b37..5e05c8887 100644
--- a/test/integration/taproot.spec.ts
+++ b/test/integration/taproot.spec.ts
@@ -5,7 +5,7 @@ import { describe, it } from 'mocha';
import { regtestUtils } from './_regtest';
import * as bitcoin from '../..';
import { Taptree } from '../../src/types';
-import { buildTapscriptFinalizer, toXOnly } from '../psbt.utils';
+import { toXOnly } from '../../src/psbt/bip371';
const rng = require('randombytes');
const regtest = regtestUtils.network;
@@ -51,12 +51,18 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
it('can create (and broadcast via 3PBP) a taproot key-path spend Transaction', async () => {
const internalKey = bip32.fromSeed(rng(64), regtest);
+ const p2pkhKey = bip32.fromSeed(rng(64), regtest);
const { output, address } = bitcoin.payments.p2tr({
internalPubkey: toXOnly(internalKey.publicKey),
network: regtest,
});
+ const { output: p2pkhOutput } = bitcoin.payments.p2pkh({
+ pubkey: p2pkhKey.publicKey,
+ network: regtest,
+ });
+
// amount from faucet
const amount = 42e4;
// amount to send
@@ -64,16 +70,25 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
// get faucet
const unspent = await regtestUtils.faucetComplex(output!, amount);
+ // non segwit utxo
+ const p2pkhUnspent = await regtestUtils.faucetComplex(p2pkhOutput!, amount);
+ const utx = await regtestUtils.fetch(p2pkhUnspent.txId);
+ const nonWitnessUtxo = Buffer.from(utx.txHex, 'hex');
+
const psbt = new bitcoin.Psbt({ network: regtest });
psbt.addInput({
hash: unspent.txId,
index: 0,
witnessUtxo: { value: amount, script: output! },
+ tapInternalKey: toXOnly(internalKey.publicKey),
});
+ psbt.addInput({ index: 0, hash: p2pkhUnspent.txId, nonWitnessUtxo });
+
psbt.addOutput({ value: sendAmount, address: address! });
- const tweakedSigher = tweakSigner(internalKey!, { network: regtest });
- psbt.signInput(0, tweakedSigher);
+ const tweakedSigner = tweakSigner(internalKey!, { network: regtest });
+ await psbt.signInputAsync(0, tweakedSigner);
+ await psbt.signInputAsync(1, p2pkhKey);
psbt.finalizeAllInputs();
const tx = psbt.extractTransaction();
@@ -121,14 +136,16 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
hash: unspent.txId,
index: 0,
witnessUtxo: { value: amount, script: output! },
+ tapInternalKey: toXOnly(internalKey.publicKey),
+ tapMerkleRoot: hash,
});
psbt.addOutput({ value: sendAmount, address: address! });
- const tweakedSigher = tweakSigner(internalKey!, {
+ const tweakedSigner = tweakSigner(internalKey!, {
tweakHash: hash,
network: regtest,
});
- psbt.signInput(0, tweakedSigher);
+ psbt.signInput(0, tweakedSigner);
psbt.finalizeAllInputs();
const tx = psbt.extractTransaction();
@@ -204,7 +221,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
redeemVersion: 192,
};
- const { output, address } = bitcoin.payments.p2tr({
+ const { output, address, witness } = bitcoin.payments.p2tr({
internalPubkey: toXOnly(internalKey.publicKey),
scriptTree,
redeem,
@@ -223,18 +240,21 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
hash: unspent.txId,
index: 0,
witnessUtxo: { value: amount, script: output! },
- witnessScript: redeem.output,
});
+ psbt.updateInput(0, {
+ tapLeafScript: [
+ {
+ leafVersion: redeem.redeemVersion,
+ script: redeem.output,
+ controlBlock: witness![witness!.length - 1],
+ },
+ ],
+ });
+
psbt.addOutput({ value: sendAmount, address: address! });
psbt.signInput(0, leafKey);
-
- const tapscriptFinalizer = buildTapscriptFinalizer(
- internalKey.publicKey,
- scriptTree,
- regtest,
- );
- psbt.finalizeInput(0, tapscriptFinalizer);
+ psbt.finalizeInput(0);
const tx = psbt.extractTransaction();
const rawTx = tx.toBuffer();
const hex = rawTx.toString('hex');
@@ -278,7 +298,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
redeemVersion: 192,
};
- const { output, address } = bitcoin.payments.p2tr({
+ const { output, address, witness } = bitcoin.payments.p2tr({
internalPubkey: toXOnly(internalKey.publicKey),
scriptTree,
redeem,
@@ -298,18 +318,21 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
index: 0,
sequence: 10,
witnessUtxo: { value: amount, script: output! },
- witnessScript: redeem.output,
+ });
+ psbt.updateInput(0, {
+ tapLeafScript: [
+ {
+ leafVersion: redeem.redeemVersion,
+ script: redeem.output,
+ controlBlock: witness![witness!.length - 1],
+ },
+ ],
});
psbt.addOutput({ value: sendAmount, address: address! });
- psbt.signInput(0, leafKey);
+ await psbt.signInputAsync(0, leafKey);
- const tapscriptFinalizer = buildTapscriptFinalizer(
- internalKey.publicKey,
- scriptTree,
- regtest,
- );
- psbt.finalizeInput(0, tapscriptFinalizer);
+ psbt.finalizeInput(0);
const tx = psbt.extractTransaction();
const rawTx = tx.toBuffer();
const hex = rawTx.toString('hex');
@@ -374,7 +397,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
redeemVersion: 192,
};
- const { output, address } = bitcoin.payments.p2tr({
+ const { output, address, witness } = bitcoin.payments.p2tr({
internalPubkey: toXOnly(internalKey.publicKey),
scriptTree,
redeem,
@@ -393,20 +416,25 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
hash: unspent.txId,
index: 0,
witnessUtxo: { value: amount, script: output! },
- witnessScript: redeem.output,
});
+ psbt.updateInput(0, {
+ tapLeafScript: [
+ {
+ leafVersion: redeem.redeemVersion,
+ script: redeem.output,
+ controlBlock: witness![witness!.length - 1],
+ },
+ ],
+ });
+
psbt.addOutput({ value: sendAmount, address: address! });
- psbt.signInput(0, leafKeys[0]);
+ // random order for signers
psbt.signInput(0, leafKeys[1]);
psbt.signInput(0, leafKeys[2]);
+ psbt.signInput(0, leafKeys[0]);
- const tapscriptFinalizer = buildTapscriptFinalizer(
- internalKey.publicKey,
- scriptTree,
- regtest,
- );
- psbt.finalizeInput(0, tapscriptFinalizer);
+ psbt.finalizeInput(0);
const tx = psbt.extractTransaction();
const rawTx = tx.toBuffer();
const hex = rawTx.toString('hex');
diff --git a/test/psbt.spec.ts b/test/psbt.spec.ts
index 76ab4da49..97f558b2f 100644
--- a/test/psbt.spec.ts
+++ b/test/psbt.spec.ts
@@ -11,7 +11,6 @@ const bip32 = BIP32Factory(ecc);
const ECPair = ECPairFactory(ecc);
import { networks as NETWORKS, payments, Psbt, Signer, SignerAsync } from '..';
-import { buildTapscriptFinalizer } from './psbt.utils';
import * as preFixtures from './fixtures/psbt.json';
@@ -25,7 +24,7 @@ const schnorrValidator = (
pubkey: Buffer,
msghash: Buffer,
signature: Buffer,
-): boolean => ECPair.fromPublicKey(pubkey).verifySchnorr(msghash, signature);
+): boolean => ecc.verifySchnorr(msghash, pubkey, signature);
const initBuffers = (object: any): typeof preFixtures =>
JSON.parse(JSON.stringify(object), (_, value) => {
@@ -149,9 +148,16 @@ describe(`Psbt`, () => {
if (f.isTaproot) initEccLib(ecc);
const psbt = Psbt.fromBase64(f.psbt);
- f.keys.forEach(({ inputToSign, WIF }) => {
+ // @ts-ignore // cannot find tapLeafHashToSign
+ f.keys.forEach(({ inputToSign, tapLeafHashToSign, WIF }) => {
const keyPair = ECPair.fromWIF(WIF, NETWORKS.testnet);
- psbt.signInput(inputToSign, keyPair);
+ if (tapLeafHashToSign)
+ psbt.signTaprootInput(
+ inputToSign,
+ keyPair,
+ Buffer.from(tapLeafHashToSign, 'hex'),
+ );
+ else psbt.signInput(inputToSign, keyPair);
});
assert.strictEqual(psbt.toBase64(), f.result);
@@ -224,6 +230,7 @@ describe(`Psbt`, () => {
describe('signInputAsync', () => {
fixtures.signInput.checks.forEach(f => {
it(f.description, async () => {
+ if (f.isTaproot) initEccLib(ecc);
if (f.shouldSign) {
const psbtThatShouldsign = Psbt.fromBase64(f.shouldSign.psbt);
await assert.doesNotReject(async () => {
@@ -232,14 +239,22 @@ describe(`Psbt`, () => {
ECPair.fromWIF(f.shouldSign.WIF),
f.shouldSign.sighashTypes || undefined,
);
+ if (f.shouldSign.result)
+ assert.strictEqual(
+ psbtThatShouldsign.toBase64(),
+ f.shouldSign.result,
+ );
});
+ const failMessage = f.isTaproot
+ ? /Need Schnorr Signer to sign taproot input #0./
+ : /sign failed/;
await assert.rejects(async () => {
await psbtThatShouldsign.signInputAsync(
f.shouldSign.inputToCheck,
failedAsyncSigner(ECPair.fromWIF(f.shouldSign.WIF).publicKey),
f.shouldSign.sighashTypes || undefined,
);
- }, /sign failed/);
+ }, failMessage);
}
if (f.shouldThrow) {
@@ -271,6 +286,7 @@ describe(`Psbt`, () => {
describe('signInput', () => {
fixtures.signInput.checks.forEach(f => {
it(f.description, () => {
+ if (f.isTaproot) initEccLib(ecc);
if (f.shouldSign) {
const psbtThatShouldsign = Psbt.fromBase64(f.shouldSign.psbt);
assert.doesNotThrow(() => {
@@ -303,6 +319,7 @@ describe(`Psbt`, () => {
fixtures.signInput.checks.forEach(f => {
if (f.description === 'checks the input exists') return;
it(f.description, async () => {
+ if (f.isTaproot) initEccLib(ecc);
if (f.shouldSign) {
const psbtThatShouldsign = Psbt.fromBase64(f.shouldSign.psbt);
await assert.doesNotReject(async () => {
@@ -333,6 +350,7 @@ describe(`Psbt`, () => {
fixtures.signInput.checks.forEach(f => {
if (f.description === 'checks the input exists') return;
it(f.description, () => {
+ if (f.isTaproot) initEccLib(ecc);
if (f.shouldSign) {
const psbtThatShouldsign = Psbt.fromBase64(f.shouldSign.psbt);
assert.doesNotThrow(() => {
@@ -483,6 +501,42 @@ describe(`Psbt`, () => {
});
});
+ describe('finalizeInput', () => {
+ it(`Finalizes tapleaf by hash`, () => {
+ const f = fixtures.finalizeInput.finalizeTapleafByHash;
+ const psbt = Psbt.fromBase64(f.psbt);
+
+ psbt.finalizeTaprootInput(f.index, Buffer.from(f.leafHash, 'hex'));
+
+ assert.strictEqual(psbt.toBase64(), f.result);
+ });
+
+ it(`fails if tapleaf hash not found`, () => {
+ const f = fixtures.finalizeInput.finalizeTapleafByHash;
+ const psbt = Psbt.fromBase64(f.psbt);
+
+ assert.throws(() => {
+ psbt.finalizeTaprootInput(
+ f.index,
+ Buffer.from(f.leafHash, 'hex').reverse(),
+ );
+ }, new RegExp('Can not finalize taproot input #0. Signature for tapleaf script not found.'));
+ });
+
+ it(`fails if trying to finalzie non-taproot input`, () => {
+ const psbt = new Psbt();
+ psbt.addInput({
+ hash:
+ '0000000000000000000000000000000000000000000000000000000000000000',
+ index: 0,
+ });
+
+ assert.throws(() => {
+ psbt.finalizeTaprootInput(0);
+ }, new RegExp('Cannot finalize input #0. Not Taproot.'));
+ });
+ });
+
describe('finalizeAllInputs', () => {
fixtures.finalizeAllInputs.forEach(f => {
it(`Finalizes inputs of type "${f.type}"`, () => {
@@ -545,6 +599,20 @@ describe(`Psbt`, () => {
});
});
+ describe('updateInput', () => {
+ fixtures.updateInput.checks.forEach(f => {
+ it(f.description, () => {
+ const psbt = Psbt.fromBase64(f.psbt);
+
+ if (f.exception) {
+ assert.throws(() => {
+ psbt.updateInput(f.index, f.inputData as any);
+ }, new RegExp(f.exception));
+ }
+ });
+ });
+ });
+
describe('addOutput', () => {
fixtures.addOutput.checks.forEach(f => {
it(f.description, () => {
@@ -967,9 +1035,9 @@ describe(`Psbt`, () => {
});
});
- describe('validateSignaturesOfTaprootInput', () => {
- const f = fixtures.validateSignaturesOfTaprootInput;
- it('Correctly validates a signature', () => {
+ describe('validateSignaturesOfTapKeyInput', () => {
+ const f = fixtures.validateSignaturesOfTapKeyInput;
+ it('Correctly validates all signatures', () => {
initEccLib(ecc);
const psbt = Psbt.fromBase64(f.psbt);
assert.strictEqual(
@@ -999,28 +1067,35 @@ describe(`Psbt`, () => {
});
});
- describe('finalizeTaprootInput', () => {
- it('Correctly finalizes a taproot script-path spend', () => {
+ describe('validateSignaturesOfTapScriptInput', () => {
+ const f = fixtures.validateSignaturesOfTapScriptInput;
+ it('Correctly validates all signatures', () => {
initEccLib(ecc);
- const f = fixtures.finalizeTaprootScriptPathSpendInput;
const psbt = Psbt.fromBase64(f.psbt);
- const tapscriptFinalizer = buildTapscriptFinalizer(
- f.internalPublicKey as any,
- f.scriptTree,
- NETWORKS.testnet,
+ assert.strictEqual(
+ psbt.validateSignaturesOfInput(f.index, schnorrValidator),
+ true,
);
- psbt.finalizeInput(0, tapscriptFinalizer);
- assert.strictEqual(psbt.toBase64(), f.result);
});
- it('Failes to finalize a taproot script-path spend when a finalizer is not provided', () => {
+ it('Correctly validates a signature against a pubkey', () => {
initEccLib(ecc);
- const f = fixtures.finalizeTaprootScriptPathSpendInput;
const psbt = Psbt.fromBase64(f.psbt);
-
+ assert.strictEqual(
+ psbt.validateSignaturesOfInput(
+ f.index,
+ schnorrValidator,
+ f.pubkey as any,
+ ),
+ true,
+ );
assert.throws(() => {
- psbt.finalizeInput(0);
- }, new RegExp('Can not finalize input #0'));
+ psbt.validateSignaturesOfInput(
+ f.index,
+ schnorrValidator,
+ f.incorrectPubkey as any,
+ );
+ }, new RegExp('No signatures for this pubkey'));
});
});
diff --git a/test/psbt.utils.ts b/test/psbt.utils.ts
deleted file mode 100644
index 100aa27e7..000000000
--- a/test/psbt.utils.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-import { PsbtInput } from 'bip174/src/lib/interfaces';
-import * as bitcoin from './..';
-
-/**
- * Build finalizer function for Tapscript.
- * Usees the default Tapscript version (0xc0).
- * @returns finalizer function
- */
-const buildTapscriptFinalizer = (
- internalPubkey: Buffer,
- scriptTree: any,
- network: bitcoin.networks.Network,
-) => {
- return (
- inputIndex: number,
- input: PsbtInput,
- script: Buffer,
- _isSegwit: boolean,
- _isP2SH: boolean,
- _isP2WSH: boolean,
- _isTapscript: boolean,
- ): {
- finalScriptSig: Buffer | undefined;
- finalScriptWitness: Buffer | Buffer[] | undefined;
- } => {
- if (!internalPubkey || !scriptTree || !script)
- throw new Error(`Can not finalize taproot input #${inputIndex}`);
-
- try {
- const tapscriptSpend = bitcoin.payments.p2tr({
- internalPubkey: toXOnly(internalPubkey),
- scriptTree,
- redeem: { output: script },
- network,
- });
- const sigs = (input.partialSig || []).map(ps => ps.signature) as Buffer[];
- const finalScriptWitness = sigs.concat(
- tapscriptSpend.witness as Buffer[],
- );
- return { finalScriptWitness, finalScriptSig: undefined };
- } catch (err) {
- throw new Error(`Can not finalize taproot input #${inputIndex}: ${err}`);
- }
- };
-};
-
-const toXOnly = (pubKey: Buffer) => pubKey.slice(1, 33);
-
-export { buildTapscriptFinalizer, toXOnly };
diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts
index 1517acffd..3800ef5db 100644
--- a/ts_src/psbt.ts
+++ b/ts_src/psbt.ts
@@ -11,17 +11,35 @@ import {
PsbtOutputUpdate,
Transaction as ITransaction,
TransactionFromBuffer,
+ TapKeySig,
+ TapScriptSig,
} from 'bip174/src/lib/interfaces';
import { checkForInput, checkForOutput } from 'bip174/src/lib/utils';
-
import { fromOutputScript, toOutputScript } from './address';
import { cloneBuffer, reverseBuffer } from './bufferutils';
-import { hash160 } from './crypto';
import { bitcoin as btcNetwork, Network } from './networks';
import * as payments from './payments';
+import { tapleafHash } from './payments/taprootutils';
import * as bscript from './script';
import { Output, Transaction } from './transaction';
-import { tapleafHash } from './payments/taprootutils';
+import {
+ toXOnly,
+ tapScriptFinalizer,
+ serializeTaprootSignature,
+ isTaprootInput,
+ checkTaprootInputFields,
+ tweakInternalPubKey,
+} from './psbt/bip371';
+import {
+ witnessStackToScriptWitness,
+ pubkeyInScript,
+ isP2MS,
+ isP2PK,
+ isP2PKH,
+ isP2WPKH,
+ isP2WSHScript,
+ isP2SHScript,
+} from './psbt/psbtutils';
export interface TransactionInput {
hash: string | Buffer;
@@ -263,6 +281,7 @@ export class Psbt {
`Requires single object with at least [hash] and [index]`,
);
}
+ checkTaprootInputFields(inputData, inputData, 'addInput');
checkInputsForPartialSig(this.data.inputs, 'addInput');
if (inputData.witnessScript) checkInvalidP2WSH(inputData.witnessScript);
const c = this.__CACHE;
@@ -347,16 +366,49 @@ export class Psbt {
finalizeInput(
inputIndex: number,
- finalScriptsFunc: FinalScriptsFunc = getFinalScripts,
+ finalScriptsFunc?: FinalScriptsFunc | FinalTaprootScriptsFunc,
): this {
const input = checkForInput(this.data.inputs, inputIndex);
- const {
- script,
- isP2SH,
- isP2WSH,
- isSegwit,
- isTapscript,
- } = getScriptFromInput(inputIndex, input, this.__CACHE);
+ if (isTaprootInput(input))
+ return this._finalizeTaprootInput(
+ inputIndex,
+ input,
+ undefined,
+ finalScriptsFunc as FinalTaprootScriptsFunc,
+ );
+ return this._finalizeInput(
+ inputIndex,
+ input,
+ finalScriptsFunc as FinalScriptsFunc,
+ );
+ }
+
+ finalizeTaprootInput(
+ inputIndex: number,
+ tapLeafHashToFinalize?: Buffer,
+ finalScriptsFunc: FinalTaprootScriptsFunc = tapScriptFinalizer,
+ ): this {
+ const input = checkForInput(this.data.inputs, inputIndex);
+ if (isTaprootInput(input))
+ return this._finalizeTaprootInput(
+ inputIndex,
+ input,
+ tapLeafHashToFinalize,
+ finalScriptsFunc,
+ );
+ throw new Error(`Cannot finalize input #${inputIndex}. Not Taproot.`);
+ }
+
+ private _finalizeInput(
+ inputIndex: number,
+ input: PsbtInput,
+ finalScriptsFunc: FinalScriptsFunc = getFinalScripts,
+ ): this {
+ const { script, isP2SH, isP2WSH, isSegwit } = getScriptFromInput(
+ inputIndex,
+ input,
+ this.__CACHE,
+ );
if (!script) throw new Error(`No script found for input #${inputIndex}`);
checkPartialSigSighashes(input);
@@ -368,17 +420,11 @@ export class Psbt {
isSegwit,
isP2SH,
isP2WSH,
- isTapscript,
);
if (finalScriptSig) this.data.updateInput(inputIndex, { finalScriptSig });
- if (finalScriptWitness) {
- // allow custom finalizers to build the witness as an array
- const witness = Array.isArray(finalScriptWitness)
- ? witnessStackToScriptWitness(finalScriptWitness)
- : finalScriptWitness;
- this.data.updateInput(inputIndex, { finalScriptWitness: witness });
- }
+ if (finalScriptWitness)
+ this.data.updateInput(inputIndex, { finalScriptWitness });
if (!finalScriptSig && !finalScriptWitness)
throw new Error(`Unknown error finalizing input #${inputIndex}`);
@@ -386,13 +432,42 @@ export class Psbt {
return this;
}
+ private _finalizeTaprootInput(
+ inputIndex: number,
+ input: PsbtInput,
+ tapLeafHashToFinalize?: Buffer,
+ finalScriptsFunc = tapScriptFinalizer,
+ ): this {
+ if (!input.witnessUtxo)
+ throw new Error(
+ `Cannot finalize input #${inputIndex}. Missing withness utxo.`,
+ );
+
+ // Check key spend first. Increased privacy and reduced block space.
+ if (input.tapKeySig) {
+ const payment = payments.p2tr({
+ output: input.witnessUtxo.script,
+ signature: input.tapKeySig,
+ });
+ const finalScriptWitness = witnessStackToScriptWitness(payment.witness!);
+ this.data.updateInput(inputIndex, { finalScriptWitness });
+ } else {
+ const { finalScriptWitness } = finalScriptsFunc(
+ inputIndex,
+ input,
+ tapLeafHashToFinalize,
+ );
+ this.data.updateInput(inputIndex, { finalScriptWitness });
+ }
+
+ this.data.clearFinalizedInput(inputIndex);
+
+ return this;
+ }
+
getInputType(inputIndex: number): AllScriptType {
const input = checkForInput(this.data.inputs, inputIndex);
- const { script } = getScriptAndAmountFromUtxo(
- inputIndex,
- input,
- this.__CACHE,
- );
+ const script = getScriptFromUtxo(inputIndex, input, this.__CACHE);
const result = getMeaningfulScript(
script,
inputIndex,
@@ -444,6 +519,22 @@ export class Psbt {
inputIndex: number,
validator: ValidateSigFunction,
pubkey?: Buffer,
+ ): boolean {
+ const input = this.data.inputs[inputIndex];
+ if (isTaprootInput(input))
+ return this.validateSignaturesOfTaprootInput(
+ inputIndex,
+ validator,
+ pubkey,
+ );
+
+ return this._validateSignaturesOfInput(inputIndex, validator, pubkey);
+ }
+
+ private _validateSignaturesOfInput(
+ inputIndex: number,
+ validator: ValidateSigFunction,
+ pubkey?: Buffer,
): boolean {
const input = this.data.inputs[inputIndex];
const partialSig = (input || {}).partialSig;
@@ -459,22 +550,13 @@ export class Psbt {
let hashCache: Buffer;
let scriptCache: Buffer;
let sighashCache: number;
- const scriptType = this.getInputType(inputIndex);
-
for (const pSig of mySigs) {
- const sig = isTaprootSpend(scriptType)
- ? {
- signature: pSig.signature,
- hashType: Transaction.SIGHASH_DEFAULT,
- }
- : bscript.signature.decode(pSig.signature);
-
+ const sig = 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,
)
@@ -488,6 +570,64 @@ export class Psbt {
return results.every(res => res === true);
}
+ private validateSignaturesOfTaprootInput(
+ inputIndex: number,
+ validator: ValidateSigFunction,
+ pubkey?: Buffer,
+ ): boolean {
+ const input = this.data.inputs[inputIndex];
+ const tapKeySig = (input || {}).tapKeySig;
+ const tapScriptSig = (input || {}).tapScriptSig;
+ if (!input && !tapKeySig && !(tapScriptSig && !tapScriptSig.length))
+ throw new Error('No signatures to validate');
+ if (typeof validator !== 'function')
+ throw new Error('Need validator function to validate signatures');
+
+ pubkey = pubkey && toXOnly(pubkey);
+ const allHashses = pubkey
+ ? getTaprootHashesForSig(
+ inputIndex,
+ input,
+ this.data.inputs,
+ pubkey,
+ this.__CACHE,
+ )
+ : getAllTaprootHashesForSig(
+ inputIndex,
+ input,
+ this.data.inputs,
+ this.__CACHE,
+ );
+
+ if (!allHashses.length) throw new Error('No signatures for this pubkey');
+
+ const tapKeyHash = allHashses.find(h => !!h.leafHash);
+ if (tapKeySig && tapKeyHash) {
+ const isValidTapkeySig = validator(
+ tapKeyHash.pubkey,
+ tapKeyHash.hash,
+ tapKeySig,
+ );
+ if (!isValidTapkeySig) return false;
+ }
+
+ if (tapScriptSig) {
+ for (const tapSig of tapScriptSig) {
+ const tapSigHash = allHashses.find(h => tapSig.pubkey.equals(h.pubkey));
+ if (tapSigHash) {
+ const isValidTapScriptSig = validator(
+ tapSig.pubkey,
+ tapSigHash.hash,
+ tapSig.signature,
+ );
+ if (!isValidTapScriptSig) return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
signAllInputsHD(
hdKeyPair: HDSigner,
sighashTypes: number[] = [Transaction.SIGHASH_ALL],
@@ -589,10 +729,7 @@ export class Psbt {
);
}
- signAllInputs(
- keyPair: Signer,
- sighashTypes: number[] = [Transaction.SIGHASH_ALL],
- ): this {
+ signAllInputs(keyPair: Signer, sighashTypes?: number[]): this {
if (!keyPair || !keyPair.publicKey)
throw new Error('Need Signer to sign input');
@@ -616,7 +753,7 @@ export class Psbt {
signAllInputsAsync(
keyPair: Signer | SignerAsync,
- sighashTypes: number[] = [Transaction.SIGHASH_ALL],
+ sighashTypes?: number[],
): Promise {
return new Promise(
(resolve, reject): any => {
@@ -653,10 +790,51 @@ export class Psbt {
signInput(
inputIndex: number,
keyPair: Signer,
- sighashTypes: number[] = [Transaction.SIGHASH_ALL],
+ sighashTypes?: number[],
): this {
if (!keyPair || !keyPair.publicKey)
throw new Error('Need Signer to sign input');
+
+ const input = checkForInput(this.data.inputs, inputIndex);
+
+ if (isTaprootInput(input)) {
+ return this._signTaprootInput(
+ inputIndex,
+ input,
+ keyPair,
+ undefined,
+ sighashTypes,
+ );
+ }
+ return this._signInput(inputIndex, keyPair, sighashTypes);
+ }
+
+ signTaprootInput(
+ inputIndex: number,
+ keyPair: Signer,
+ tapLeafHashToSign?: Buffer,
+ sighashTypes?: number[],
+ ): this {
+ if (!keyPair || !keyPair.publicKey)
+ throw new Error('Need Signer to sign input');
+ const input = checkForInput(this.data.inputs, inputIndex);
+
+ if (isTaprootInput(input))
+ return this._signTaprootInput(
+ inputIndex,
+ input,
+ keyPair,
+ tapLeafHashToSign,
+ sighashTypes,
+ );
+ throw new Error(`Input #${inputIndex} is not of type Taproot.`);
+ }
+
+ private _signInput(
+ inputIndex: number,
+ keyPair: Signer,
+ sighashTypes: number[] = [Transaction.SIGHASH_ALL],
+ ): this {
const { hash, sighashType } = getHashAndSighashType(
this.data.inputs,
inputIndex,
@@ -665,29 +843,61 @@ export class Psbt {
sighashTypes,
);
- const scriptType = this.getInputType(inputIndex);
-
- if (isTaprootSpend(scriptType)) {
- if (!keyPair.signSchnorr) {
- throw new Error(
- `Need Schnorr Signer to sign taproot input #${inputIndex}.`,
- );
- }
- const partialSig = this.data.inputs[inputIndex].partialSig || [];
- partialSig.push({
+ 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 });
+ signature: bscript.signature.encode(keyPair.sign(hash), sighashType),
+ },
+ ];
+
+ this.data.updateInput(inputIndex, { partialSig });
+ return this;
+ }
+
+ private _signTaprootInput(
+ inputIndex: number,
+ input: PsbtInput,
+ keyPair: Signer,
+ tapLeafHashToSign?: Buffer,
+ allowedSighashTypes: number[] = [Transaction.SIGHASH_DEFAULT],
+ ): this {
+ const hashesForSig = this.checkTaprootHashesForSig(
+ inputIndex,
+ input,
+ keyPair,
+ tapLeafHashToSign,
+ allowedSighashTypes,
+ );
+
+ const tapKeySig: TapKeySig = hashesForSig
+ .filter(h => !h.leafHash)
+ .map(h =>
+ serializeTaprootSignature(
+ keyPair.signSchnorr!(h.hash),
+ input.sighashType,
+ ),
+ )[0];
+
+ const tapScriptSig: TapScriptSig[] = hashesForSig
+ .filter(h => !!h.leafHash)
+ .map(
+ h =>
+ ({
+ pubkey: toXOnly(keyPair.publicKey),
+ signature: serializeTaprootSignature(
+ keyPair.signSchnorr!(h.hash),
+ input.sighashType,
+ ),
+ leafHash: h.leafHash,
+ } as TapScriptSig),
+ );
+
+ if (tapKeySig) {
+ this.data.updateInput(inputIndex, { tapKeySig });
+ }
+
+ if (tapScriptSig.length) {
+ this.data.updateInput(inputIndex, { tapScriptSig });
}
return this;
@@ -696,52 +906,160 @@ export class Psbt {
signInputAsync(
inputIndex: number,
keyPair: Signer | SignerAsync,
- sighashTypes: number[] = [Transaction.SIGHASH_ALL],
+ sighashTypes?: number[],
): Promise {
return Promise.resolve().then(() => {
if (!keyPair || !keyPair.publicKey)
throw new Error('Need Signer to sign input');
- const { hash, sighashType } = getHashAndSighashType(
- this.data.inputs,
- inputIndex,
- keyPair.publicKey,
- this.__CACHE,
- sighashTypes,
- );
- const scriptType = this.getInputType(inputIndex);
+ const input = checkForInput(this.data.inputs, inputIndex);
+ if (isTaprootInput(input))
+ return this._signTaprootInputAsync(
+ inputIndex,
+ input,
+ keyPair,
+ undefined,
+ sighashTypes,
+ );
- if (isTaprootSpend(scriptType)) {
- if (!keyPair.signSchnorr) {
- throw new Error(
- `Need Schnorr Signer to sign taproot input #${inputIndex}.`,
- );
- }
- return Promise.resolve(keyPair.signSchnorr(hash)).then(signature => {
- const partialSig = this.data.inputs[inputIndex].partialSig || [];
- partialSig.push({
- pubkey: keyPair.publicKey,
- signature,
- });
-
- // must be changed to use the `updateInput()` public API
- this.data.inputs[inputIndex].partialSig = partialSig;
- });
- }
+ return this._signInputAsync(inputIndex, keyPair, sighashTypes);
+ });
+ }
- return Promise.resolve(keyPair.sign(hash)).then(signature => {
- const partialSig = [
- {
- pubkey: keyPair.publicKey,
- signature: bscript.signature.encode(signature, sighashType),
- },
- ];
+ signTaprootInputAsync(
+ inputIndex: number,
+ keyPair: Signer | SignerAsync,
+ tapLeafHash?: Buffer,
+ sighashTypes?: number[],
+ ): Promise {
+ return Promise.resolve().then(() => {
+ if (!keyPair || !keyPair.publicKey)
+ throw new Error('Need Signer to sign input');
+
+ const input = checkForInput(this.data.inputs, inputIndex);
+ if (isTaprootInput(input))
+ return this._signTaprootInputAsync(
+ inputIndex,
+ input,
+ keyPair,
+ tapLeafHash,
+ sighashTypes,
+ );
+
+ throw new Error(`Input #${inputIndex} is not of type Taproot.`);
+ });
+ }
- this.data.updateInput(inputIndex, { partialSig });
+ private _signInputAsync(
+ inputIndex: number,
+ keyPair: Signer | SignerAsync,
+ sighashTypes: number[] = [Transaction.SIGHASH_ALL],
+ ): Promise {
+ const { hash, sighashType } = getHashAndSighashType(
+ this.data.inputs,
+ inputIndex,
+ keyPair.publicKey,
+ this.__CACHE,
+ sighashTypes,
+ );
+
+ return Promise.resolve(keyPair.sign(hash)).then(signature => {
+ const partialSig = [
+ {
+ pubkey: keyPair.publicKey,
+ signature: bscript.signature.encode(signature, sighashType),
+ },
+ ];
+
+ this.data.updateInput(inputIndex, { partialSig });
+ });
+ }
+
+ private async _signTaprootInputAsync(
+ inputIndex: number,
+ input: PsbtInput,
+ keyPair: Signer | SignerAsync,
+ tapLeafHash?: Buffer,
+ sighashTypes: number[] = [Transaction.SIGHASH_DEFAULT],
+ ): Promise {
+ const hashesForSig = this.checkTaprootHashesForSig(
+ inputIndex,
+ input,
+ keyPair,
+ tapLeafHash,
+ sighashTypes,
+ );
+
+ const signaturePromises: Promise[] = [];
+ const tapKeyHash = hashesForSig.filter(h => !h.leafHash)[0];
+ if (tapKeyHash) {
+ const tapKeySigPromise = Promise.resolve(
+ keyPair.signSchnorr!(tapKeyHash.hash),
+ ).then(sig => {
+ return { tapKeySig: serializeTaprootSignature(sig, input.sighashType) };
+ });
+ signaturePromises.push(tapKeySigPromise);
+ }
+
+ const tapScriptHashes = hashesForSig.filter(h => !!h.leafHash);
+ if (tapScriptHashes.length) {
+ const tapScriptSigPromises = tapScriptHashes.map(tsh => {
+ return Promise.resolve(keyPair.signSchnorr!(tsh.hash)).then(
+ signature => {
+ const tapScriptSig = [
+ {
+ pubkey: toXOnly(keyPair.publicKey),
+ signature: serializeTaprootSignature(
+ signature,
+ input.sighashType,
+ ),
+ leafHash: tsh.leafHash,
+ } as TapScriptSig,
+ ];
+ return { tapScriptSig };
+ },
+ );
});
+ signaturePromises.push(...tapScriptSigPromises);
+ }
+
+ return Promise.all(signaturePromises).then(results => {
+ results.forEach(v => this.data.updateInput(inputIndex, v));
});
}
+ private checkTaprootHashesForSig(
+ inputIndex: number,
+ input: PsbtInput,
+ keyPair: Signer | SignerAsync,
+ tapLeafHashToSign?: Buffer,
+ allowedSighashTypes?: number[],
+ ): { hash: Buffer; leafHash?: Buffer }[] {
+ if (typeof keyPair.signSchnorr !== 'function')
+ throw new Error(
+ `Need Schnorr Signer to sign taproot input #${inputIndex}.`,
+ );
+
+ const hashesForSig = getTaprootHashesForSig(
+ inputIndex,
+ input,
+ this.data.inputs,
+ keyPair.publicKey,
+ this.__CACHE,
+ tapLeafHashToSign,
+ allowedSighashTypes,
+ );
+
+ if (!hashesForSig || !hashesForSig.length)
+ throw new Error(
+ `Can not sign for input #${inputIndex} with the key ${keyPair.publicKey.toString(
+ 'hex',
+ )}`,
+ );
+
+ return hashesForSig;
+ }
+
toBuffer(): Buffer {
checkCache(this.__CACHE);
return this.data.toBuffer();
@@ -764,6 +1082,11 @@ export class Psbt {
updateInput(inputIndex: number, updateData: PsbtInputUpdate): this {
if (updateData.witnessScript) checkInvalidP2WSH(updateData.witnessScript);
+ checkTaprootInputFields(
+ this.data.inputs[inputIndex],
+ updateData,
+ 'updateInput',
+ );
this.data.updateInput(inputIndex, updateData);
if (updateData.nonWitnessUtxo) {
addNonWitnessTxCache(
@@ -858,7 +1181,6 @@ 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;
}
/**
@@ -867,7 +1189,6 @@ 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 {
@@ -963,7 +1284,6 @@ function canFinalize(
case 'pubkey':
case 'pubkeyhash':
case 'witnesspubkeyhash':
- case 'taproot':
return hasSigs(1, input.partialSig);
case 'multisig':
const p2ms = payments.p2ms({ output: script });
@@ -1004,24 +1324,6 @@ function isFinalized(input: PsbtInput): boolean {
return !!input.finalScriptSig || !!input.finalScriptWitness;
}
-function isPaymentFactory(payment: any): (script: Buffer) => boolean {
- return (script: Buffer): boolean => {
- try {
- payment({ output: script });
- return true;
- } catch (err) {
- return false;
- }
- };
-}
-const isP2MS = isPaymentFactory(payments.p2ms);
-const isP2PK = isPaymentFactory(payments.p2pk);
-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,
): (d: Bip32Derivation) => boolean {
@@ -1207,12 +1509,18 @@ type FinalScriptsFunc = (
input: PsbtInput, // The PSBT input contents
script: Buffer, // The "meaningful" locking script Buffer (redeemScript for P2SH etc.)
isSegwit: boolean, // Is it segwit?
- isTapscript: boolean, // Is taproot script path?
isP2SH: boolean, // Is it P2SH?
isP2WSH: boolean, // Is it P2WSH?
) => {
finalScriptSig: Buffer | undefined;
- finalScriptWitness: Buffer | Buffer[] | undefined;
+ finalScriptWitness: Buffer | undefined;
+};
+type FinalTaprootScriptsFunc = (
+ inputIndex: number, // Which input is it?
+ input: PsbtInput, // The PSBT input contents
+ tapLeafHashToFinalize?: Buffer, // Only finalize this specific leaf
+) => {
+ finalScriptWitness: Buffer | undefined;
};
function getFinalScripts(
@@ -1222,13 +1530,12 @@ function getFinalScripts(
isSegwit: boolean,
isP2SH: boolean,
isP2WSH: boolean,
- isTapscript: boolean = false,
): {
finalScriptSig: Buffer | undefined;
finalScriptWitness: Buffer | undefined;
} {
const scriptType = classifyScript(script);
- if (isTapscript || !canFinalize(input, script, scriptType))
+ if (!canFinalize(input, script, scriptType))
throw new Error(`Can not finalize input #${inputIndex}`);
return prepareFinalScripts(
script,
@@ -1295,7 +1602,6 @@ function getHashAndSighashType(
const { hash, sighashType, script } = getHashForSig(
inputIndex,
input,
- inputs,
cache,
false,
sighashTypes,
@@ -1310,7 +1616,6 @@ function getHashAndSighashType(
function getHashForSig(
inputIndex: number,
input: PsbtInput,
- inputs: PsbtInput[],
cache: PsbtCache,
forValidate: boolean,
sighashTypes?: number[],
@@ -1321,13 +1626,8 @@ function getHashForSig(
} {
const unsignedTx = cache.__TX;
const sighashType = input.sighashType || Transaction.SIGHASH_ALL;
- if (sighashTypes && sighashTypes.indexOf(sighashType) < 0) {
- const str = sighashTypeToString(sighashType);
- throw new Error(
- `Sighash type is not allowed. Retry the sign method passing the ` +
- `sighashTypes array of whitelisted types. Sighash type: ${str}`,
- );
- }
+ checkSighashTypeAllowed(sighashType, sighashTypes);
+
let hash: Buffer;
let prevout: Output;
@@ -1381,23 +1681,6 @@ function getHashForSig(
prevout.value,
sighashType,
);
- } else if (isP2TR(prevout.script)) {
- 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);
- const leafHash = input.witnessScript
- ? tapleafHash({ output: input.witnessScript })
- : undefined;
-
- hash = unsignedTx.hashForWitnessV1(
- inputIndex,
- signingScripts,
- values,
- Transaction.SIGHASH_DEFAULT,
- leafHash,
- );
} else {
// non-segwit
if (
@@ -1432,6 +1715,108 @@ function getHashForSig(
};
}
+function getAllTaprootHashesForSig(
+ inputIndex: number,
+ input: PsbtInput,
+ inputs: PsbtInput[],
+ cache: PsbtCache,
+): { pubkey: Buffer; hash: Buffer; leafHash?: Buffer }[] {
+ const allPublicKeys = [];
+ if (input.tapInternalKey) {
+ const outputKey = tweakInternalPubKey(inputIndex, input);
+ allPublicKeys.push(outputKey);
+ }
+
+ if (input.tapScriptSig) {
+ const tapScriptPubkeys = input.tapScriptSig.map(tss => tss.pubkey);
+ allPublicKeys.push(...tapScriptPubkeys);
+ }
+
+ const allHashes = allPublicKeys.map(pubicKey =>
+ getTaprootHashesForSig(inputIndex, input, inputs, pubicKey, cache),
+ );
+
+ return allHashes.flat();
+}
+
+function getTaprootHashesForSig(
+ inputIndex: number,
+ input: PsbtInput,
+ inputs: PsbtInput[],
+ pubkey: Buffer,
+ cache: PsbtCache,
+ tapLeafHashToSign?: Buffer,
+ allowedSighashTypes?: number[],
+): { pubkey: Buffer; hash: Buffer; leafHash?: Buffer }[] {
+ const unsignedTx = cache.__TX;
+
+ const sighashType = input.sighashType || Transaction.SIGHASH_DEFAULT;
+ checkSighashTypeAllowed(sighashType, allowedSighashTypes);
+
+ 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);
+
+ const hashes = [];
+ if (input.tapInternalKey && !tapLeafHashToSign) {
+ const outputKey = tweakInternalPubKey(inputIndex, input);
+ if (toXOnly(pubkey).equals(outputKey)) {
+ const tapKeyHash = unsignedTx.hashForWitnessV1(
+ inputIndex,
+ signingScripts,
+ values,
+ sighashType,
+ );
+ hashes.push({ pubkey, hash: tapKeyHash });
+ }
+ }
+
+ const tapLeafHashes = (input.tapLeafScript || [])
+ .filter(tapLeaf => pubkeyInScript(pubkey, tapLeaf.script))
+ .map(tapLeaf => {
+ const hash = tapleafHash({
+ output: tapLeaf.script,
+ version: tapLeaf.leafVersion,
+ });
+ return Object.assign({ hash }, tapLeaf);
+ })
+ .filter(
+ tapLeaf => !tapLeafHashToSign || tapLeafHashToSign.equals(tapLeaf.hash),
+ )
+ .map(tapLeaf => {
+ const tapScriptHash = unsignedTx.hashForWitnessV1(
+ inputIndex,
+ signingScripts,
+ values,
+ Transaction.SIGHASH_DEFAULT,
+ tapLeaf.hash,
+ );
+
+ return {
+ pubkey,
+ hash: tapScriptHash,
+ leafHash: tapLeaf.hash,
+ };
+ });
+
+ return hashes.concat(tapLeafHashes);
+}
+
+function checkSighashTypeAllowed(
+ sighashType: number,
+ sighashTypes?: number[],
+): void {
+ if (sighashTypes && sighashTypes.indexOf(sighashType) < 0) {
+ const str = sighashTypeToString(sighashType);
+ throw new Error(
+ `Sighash type is not allowed. Retry the sign method passing the ` +
+ `sighashTypes array of whitelisted types. Sighash type: ${str}`,
+ );
+ }
+}
+
function getPayment(
script: Buffer,
scriptType: string,
@@ -1466,15 +1851,6 @@ function getPayment(
signature: partialSig[0].signature,
});
break;
- case 'taproot':
- payment = payments.p2tr(
- {
- output: script,
- signature: partialSig[0].signature,
- },
- { validate: false }, // skip validation
- );
- break;
}
return payment!;
}
@@ -1497,7 +1873,6 @@ function getPsigsFromInputFinalScripts(input: PsbtInput): PartialSig[] {
interface GetScriptReturn {
script: Buffer | null;
isSegwit: boolean;
- isTapscript: boolean;
isP2SH: boolean;
isP2WSH: boolean;
}
@@ -1510,45 +1885,31 @@ function getScriptFromInput(
const res: GetScriptReturn = {
script: null,
isSegwit: false,
- isTapscript: false,
isP2SH: false,
isP2WSH: false,
};
- let utxoScript = null;
- if (input.nonWitnessUtxo) {
- const nonWitnessUtxoTx = nonWitnessUtxoTxFromCache(
- cache,
- input,
- inputIndex,
- );
- const prevoutIndex = unsignedTx.ins[inputIndex].index;
- utxoScript = nonWitnessUtxoTx.outs[prevoutIndex].script;
- } else if (input.witnessUtxo) {
- utxoScript = input.witnessUtxo.script;
- }
-
+ res.isP2SH = !!input.redeemScript;
+ res.isP2WSH = !!input.witnessScript;
if (input.witnessScript) {
res.script = input.witnessScript;
} else if (input.redeemScript) {
res.script = input.redeemScript;
} else {
- res.script = utxoScript;
+ if (input.nonWitnessUtxo) {
+ const nonWitnessUtxoTx = nonWitnessUtxoTxFromCache(
+ cache,
+ input,
+ inputIndex,
+ );
+ const prevoutIndex = unsignedTx.ins[inputIndex].index;
+ res.script = nonWitnessUtxoTx.outs[prevoutIndex].script;
+ } else if (input.witnessUtxo) {
+ res.script = input.witnessUtxo.script;
+ }
}
-
- const isTaproot = utxoScript && isP2TR(utxoScript);
-
- // Segregated Witness versions 0 or 1
- if (input.witnessScript || isP2WPKH(res.script!) || isTaproot) {
+ if (input.witnessScript || isP2WPKH(res.script!)) {
res.isSegwit = true;
}
-
- if (isTaproot && input.witnessScript) {
- res.isTapscript = true;
- }
-
- res.isP2SH = !!input.redeemScript;
- res.isP2WSH = !!input.witnessScript && !res.isTapscript;
-
return res;
}
@@ -1650,36 +2011,6 @@ function sighashTypeToString(sighashType: number): string {
return text;
}
-function witnessStackToScriptWitness(witness: Buffer[]): Buffer {
- let buffer = Buffer.allocUnsafe(0);
-
- function writeSlice(slice: Buffer): void {
- buffer = Buffer.concat([buffer, Buffer.from(slice)]);
- }
-
- function writeVarInt(i: number): void {
- const currentLen = buffer.length;
- const varintLen = varuint.encodingLength(i);
-
- buffer = Buffer.concat([buffer, Buffer.allocUnsafe(varintLen)]);
- varuint.encode(i, buffer, currentLen);
- }
-
- function writeVarSlice(slice: Buffer): void {
- writeVarInt(slice.length);
- writeSlice(slice);
- }
-
- function writeVector(vector: Buffer[]): void {
- writeVarInt(vector.length);
- vector.forEach(writeVarSlice);
- }
-
- writeVector(witness);
-
- return buffer;
-}
-
function addNonWitnessTxCache(
cache: PsbtCache,
input: PsbtInput,
@@ -1762,6 +2093,15 @@ function nonWitnessUtxoTxFromCache(
return c[inputIndex];
}
+function getScriptFromUtxo(
+ inputIndex: number,
+ input: PsbtInput,
+ cache: PsbtCache,
+): Buffer {
+ const { script } = getScriptAndAmountFromUtxo(inputIndex, input, cache);
+ return script;
+}
+
function getScriptAndAmountFromUtxo(
inputIndex: number,
input: PsbtInput,
@@ -1791,7 +2131,7 @@ function pubkeyInInput(
inputIndex: number,
cache: PsbtCache,
): boolean {
- const { script } = getScriptAndAmountFromUtxo(inputIndex, input, cache);
+ const script = getScriptFromUtxo(inputIndex, input, cache);
const { meaningfulScript } = getMeaningfulScript(
script,
inputIndex,
@@ -1875,12 +2215,11 @@ function getMeaningfulScript(
witnessScript?: Buffer,
): {
meaningfulScript: Buffer;
- type: 'p2sh' | 'p2wsh' | 'p2sh-p2wsh' | 'p2tr' | 'raw';
+ type: 'p2sh' | 'p2wsh' | 'p2sh-p2wsh' | 'raw';
} {
const isP2SH = isP2SHScript(script);
const isP2SHP2WSH = isP2SH && redeemScript && isP2WSHScript(redeemScript);
const isP2WSH = isP2WSHScript(script);
- const isP2TRScript = isP2TR(script);
if (isP2SH && redeemScript === undefined)
throw new Error('scriptPubkey is P2SH but redeemScript missing');
@@ -1903,9 +2242,6 @@ function getMeaningfulScript(
} else if (isP2SH) {
meaningfulScript = redeemScript!;
checkRedeemScript(index, script, redeemScript!, ioType);
- } else if (isP2TRScript && !!witnessScript) {
- meaningfulScript = witnessScript;
- // TODO: check here something?
} else {
meaningfulScript = script;
}
@@ -1917,8 +2253,6 @@ function getMeaningfulScript(
? 'p2sh'
: isP2WSH
? 'p2wsh'
- : isP2TRScript
- ? 'p2tr'
: 'raw',
};
}
@@ -1929,35 +2263,11 @@ 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) ||
- element.equals(pubkeyXOnly)
- );
- });
-}
-
-function isTaprootSpend(scriptType: string): boolean {
- return (
- !!scriptType && (scriptType === 'taproot' || scriptType.startsWith('p2tr-'))
- );
-}
-
type AllScriptType =
| 'witnesspubkeyhash'
| 'pubkeyhash'
| 'multisig'
| 'pubkey'
- | 'taproot'
| 'nonstandard'
| 'p2sh-witnesspubkeyhash'
| 'p2sh-pubkeyhash'
@@ -1971,22 +2281,18 @@ type AllScriptType =
| 'p2sh-p2wsh-pubkeyhash'
| 'p2sh-p2wsh-multisig'
| 'p2sh-p2wsh-pubkey'
- | 'p2sh-p2wsh-nonstandard'
- | 'p2tr-pubkey'
- | 'p2tr-nonstandard';
+ | 'p2sh-p2wsh-nonstandard';
type ScriptType =
| 'witnesspubkeyhash'
| '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)) return 'taproot';
return 'nonstandard';
}
diff --git a/ts_src/psbt/bip371.ts b/ts_src/psbt/bip371.ts
new file mode 100644
index 000000000..618ff25c5
--- /dev/null
+++ b/ts_src/psbt/bip371.ts
@@ -0,0 +1,240 @@
+import {
+ PsbtInput,
+ TapLeafScript,
+ TapScriptSig,
+} from 'bip174/src/lib/interfaces';
+
+import {
+ witnessStackToScriptWitness,
+ pubkeyPositionInScript,
+ isP2TR,
+} from './psbtutils';
+import {
+ tweakKey,
+ tapleafHash,
+ rootHashFromPath,
+} from '../payments/taprootutils';
+
+export const toXOnly = (pubKey: Buffer) =>
+ pubKey.length === 32 ? pubKey : pubKey.slice(1, 33);
+
+/**
+ * Default tapscript finalizer. It searches for the `tapLeafHashToFinalize` if provided.
+ * Otherwise it will search for the tapleaf that has at least one signature and has the shortest path.
+ * @param inputIndex the position of the PSBT input.
+ * @param input the PSBT input.
+ * @param tapLeafHashToFinalize optional, if provided the finalizer will search for a tapleaf that has this hash
+ * and will try to build the finalScriptWitness.
+ * @returns the finalScriptWitness or throws an exception if no tapleaf found.
+ */
+export function tapScriptFinalizer(
+ inputIndex: number,
+ input: PsbtInput,
+ tapLeafHashToFinalize?: Buffer,
+): {
+ finalScriptWitness: Buffer | undefined;
+} {
+ const tapLeaf = findTapLeafToFinalize(
+ input,
+ inputIndex,
+ tapLeafHashToFinalize,
+ );
+
+ try {
+ const sigs = sortSignatures(input, tapLeaf);
+ const witness = sigs.concat(tapLeaf.script).concat(tapLeaf.controlBlock);
+ return { finalScriptWitness: witnessStackToScriptWitness(witness) };
+ } catch (err) {
+ throw new Error(`Can not finalize taproot input #${inputIndex}: ${err}`);
+ }
+}
+
+export function serializeTaprootSignature(
+ sig: Buffer,
+ sighashType?: number,
+): Buffer {
+ const sighashTypeByte = sighashType
+ ? Buffer.from([sighashType!])
+ : Buffer.from([]);
+
+ return Buffer.concat([sig, sighashTypeByte]);
+}
+
+export function isTaprootInput(input: PsbtInput): boolean {
+ return (
+ input &&
+ !!(
+ input.tapInternalKey ||
+ input.tapMerkleRoot ||
+ (input.tapLeafScript && input.tapLeafScript.length) ||
+ (input.tapBip32Derivation && input.tapBip32Derivation.length) ||
+ (input.witnessUtxo && isP2TR(input.witnessUtxo.script))
+ )
+ );
+}
+
+export function checkTaprootInputFields(
+ inputData: PsbtInput,
+ newInputData: PsbtInput,
+ action: string,
+): void {
+ checkMixedTaprootAndNonTaprootFields(inputData, newInputData, action);
+ checkIfTapLeafInTree(inputData, newInputData, action);
+}
+
+export function tweakInternalPubKey(
+ inputIndex: number,
+ input: PsbtInput,
+): Buffer {
+ const tapInternalKey = input.tapInternalKey;
+ const outputKey =
+ tapInternalKey && tweakKey(tapInternalKey, input.tapMerkleRoot);
+
+ if (!outputKey)
+ throw new Error(
+ `Cannot tweak tap internal key for input #${inputIndex}. Public key: ${tapInternalKey &&
+ tapInternalKey.toString('hex')}`,
+ );
+ return outputKey.x;
+}
+
+function checkMixedTaprootAndNonTaprootFields(
+ inputData: PsbtInput,
+ newInputData: PsbtInput,
+ action: string,
+): void {
+ const isBadTaprootUpdate =
+ isTaprootInput(inputData) && hasNonTaprootInputFields(newInputData);
+ const isBadNonTaprootUpdate =
+ hasNonTaprootInputFields(inputData) && isTaprootInput(newInputData);
+ const hasMixedFields =
+ inputData === newInputData &&
+ (isTaprootInput(newInputData) && hasNonTaprootInputFields(newInputData));
+
+ if (isBadTaprootUpdate || isBadNonTaprootUpdate || hasMixedFields)
+ throw new Error(
+ `Invalid arguments for Psbt.${action}. ` +
+ `Cannot use both taproot and non-taproot fields.`,
+ );
+}
+
+function checkIfTapLeafInTree(
+ inputData: PsbtInput,
+ newInputData: PsbtInput,
+ action: string,
+): void {
+ if (newInputData.tapMerkleRoot) {
+ const newLeafsInTree = (newInputData.tapLeafScript || []).every(l =>
+ isTapLeafInTree(l, newInputData.tapMerkleRoot),
+ );
+ const oldLeafsInTree = (inputData.tapLeafScript || []).every(l =>
+ isTapLeafInTree(l, newInputData.tapMerkleRoot),
+ );
+ if (!newLeafsInTree || !oldLeafsInTree)
+ throw new Error(
+ `Invalid arguments for Psbt.${action}. Tapleaf not part of taptree.`,
+ );
+ } else if (inputData.tapMerkleRoot) {
+ const newLeafsInTree = (newInputData.tapLeafScript || []).every(l =>
+ isTapLeafInTree(l, inputData.tapMerkleRoot),
+ );
+ if (!newLeafsInTree)
+ throw new Error(
+ `Invalid arguments for Psbt.${action}. Tapleaf not part of taptree.`,
+ );
+ }
+}
+
+function isTapLeafInTree(tapLeaf: TapLeafScript, merkleRoot?: Buffer): boolean {
+ if (!merkleRoot) return true;
+
+ const leafHash = tapleafHash({
+ output: tapLeaf.script,
+ version: tapLeaf.leafVersion,
+ });
+
+ const rootHash = rootHashFromPath(tapLeaf.controlBlock, leafHash);
+ return rootHash.equals(merkleRoot);
+}
+
+function sortSignatures(input: PsbtInput, tapLeaf: TapLeafScript): Buffer[] {
+ const leafHash = tapleafHash({
+ output: tapLeaf.script,
+ version: tapLeaf.leafVersion,
+ });
+
+ return (input.tapScriptSig || [])
+ .filter(tss => tss.leafHash.equals(leafHash))
+ .map(tss => addPubkeyPositionInScript(tapLeaf.script, tss))
+ .sort((t1, t2) => t2.positionInScript - t1.positionInScript)
+ .map(t => t.signature) as Buffer[];
+}
+
+function addPubkeyPositionInScript(
+ script: Buffer,
+ tss: TapScriptSig,
+): TapScriptSigWitPosition {
+ return Object.assign(
+ {
+ positionInScript: pubkeyPositionInScript(tss.pubkey, script),
+ },
+ tss,
+ ) as TapScriptSigWitPosition;
+}
+
+/**
+ * Find tapleaf by hash, or get the signed tapleaf with the shortest path.
+ */
+function findTapLeafToFinalize(
+ input: PsbtInput,
+ inputIndex: number,
+ leafHashToFinalize?: Buffer,
+): TapLeafScript {
+ if (!input.tapScriptSig || !input.tapScriptSig.length)
+ throw new Error(
+ `Can not finalize taproot input #${inputIndex}. No tapleaf script signature provided.`,
+ );
+ const tapLeaf = (input.tapLeafScript || [])
+ .sort((a, b) => a.controlBlock.length - b.controlBlock.length)
+ .find(leaf =>
+ canFinalizeLeaf(leaf, input.tapScriptSig!, leafHashToFinalize),
+ );
+
+ if (!tapLeaf)
+ throw new Error(
+ `Can not finalize taproot input #${inputIndex}. Signature for tapleaf script not found.`,
+ );
+
+ return tapLeaf;
+}
+
+function canFinalizeLeaf(
+ leaf: TapLeafScript,
+ tapScriptSig: TapScriptSig[],
+ hash?: Buffer,
+): boolean {
+ const leafHash = tapleafHash({
+ output: leaf.script,
+ version: leaf.leafVersion,
+ });
+ const whiteListedHash = !hash || hash.equals(leafHash);
+ return (
+ whiteListedHash &&
+ tapScriptSig!.find(tss => tss.leafHash.equals(leafHash)) !== undefined
+ );
+}
+
+function hasNonTaprootInputFields(input: PsbtInput): boolean {
+ return (
+ input &&
+ !!(
+ input.redeemScript ||
+ input.witnessScript ||
+ (input.bip32Derivation && input.bip32Derivation.length)
+ )
+ );
+}
+
+interface TapScriptSigWitPosition extends TapScriptSig {
+ positionInScript: number;
+}
diff --git a/ts_src/psbt/psbtutils.ts b/ts_src/psbt/psbtutils.ts
new file mode 100644
index 000000000..1a891f788
--- /dev/null
+++ b/ts_src/psbt/psbtutils.ts
@@ -0,0 +1,73 @@
+import * as varuint from 'bip174/src/lib/converter/varint';
+import * as bscript from '../script';
+import { hash160 } from '../crypto';
+import * as payments from '../payments';
+
+function isPaymentFactory(payment: any): (script: Buffer) => boolean {
+ return (script: Buffer): boolean => {
+ try {
+ payment({ output: script });
+ return true;
+ } catch (err) {
+ return false;
+ }
+ };
+}
+export const isP2MS = isPaymentFactory(payments.p2ms);
+export const isP2PK = isPaymentFactory(payments.p2pk);
+export const isP2PKH = isPaymentFactory(payments.p2pkh);
+export const isP2WPKH = isPaymentFactory(payments.p2wpkh);
+export const isP2WSHScript = isPaymentFactory(payments.p2wsh);
+export const isP2SHScript = isPaymentFactory(payments.p2sh);
+export const isP2TR = isPaymentFactory(payments.p2tr);
+
+export function witnessStackToScriptWitness(witness: Buffer[]): Buffer {
+ let buffer = Buffer.allocUnsafe(0);
+
+ function writeSlice(slice: Buffer): void {
+ buffer = Buffer.concat([buffer, Buffer.from(slice)]);
+ }
+
+ function writeVarInt(i: number): void {
+ const currentLen = buffer.length;
+ const varintLen = varuint.encodingLength(i);
+
+ buffer = Buffer.concat([buffer, Buffer.allocUnsafe(varintLen)]);
+ varuint.encode(i, buffer, currentLen);
+ }
+
+ function writeVarSlice(slice: Buffer): void {
+ writeVarInt(slice.length);
+ writeSlice(slice);
+ }
+
+ function writeVector(vector: Buffer[]): void {
+ writeVarInt(vector.length);
+ vector.forEach(writeVarSlice);
+ }
+
+ writeVector(witness);
+
+ return buffer;
+}
+
+export function pubkeyPositionInScript(pubkey: Buffer, script: Buffer): number {
+ const pubkeyHash = hash160(pubkey);
+ const pubkeyXOnly = pubkey.slice(1, 33); // slice before calling?
+
+ const decompiled = bscript.decompile(script);
+ if (decompiled === null) throw new Error('Unknown script error');
+
+ return decompiled.findIndex(element => {
+ if (typeof element === 'number') return false;
+ return (
+ element.equals(pubkey) ||
+ element.equals(pubkeyHash) ||
+ element.equals(pubkeyXOnly)
+ );
+ });
+}
+
+export function pubkeyInScript(pubkey: Buffer, script: Buffer): boolean {
+ return pubkeyPositionInScript(pubkey, script) !== -1;
+}
From 6cbac53c1d03b18ba0f016f5eca313fcb3d6400a Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Tue, 24 May 2022 11:22:02 +0300
Subject: [PATCH 075/144] feat: add to/from Psbt TapTree conversion
---
src/payments/taprootutils.d.ts | 1 +
src/payments/taprootutils.js | 3 +-
src/psbt/bip371.d.ts | 21 +++++++-
src/psbt/bip371.js | 73 +++++++++++++++++++++++++-
ts_src/payments/taprootutils.ts | 1 +
ts_src/psbt/bip371.ts | 92 +++++++++++++++++++++++++++++++++
6 files changed, 188 insertions(+), 3 deletions(-)
diff --git a/src/payments/taprootutils.d.ts b/src/payments/taprootutils.d.ts
index 371595f31..8dd82409a 100644
--- a/src/payments/taprootutils.d.ts
+++ b/src/payments/taprootutils.d.ts
@@ -1,6 +1,7 @@
///
import { Tapleaf, Taptree } from '../types';
export declare const LEAF_VERSION_TAPSCRIPT = 192;
+export declare const MAX_TAPTREE_DEPTH = 128;
interface HashLeaf {
hash: Buffer;
}
diff --git a/src/payments/taprootutils.js b/src/payments/taprootutils.js
index 26d97d684..4832d358d 100644
--- a/src/payments/taprootutils.js
+++ b/src/payments/taprootutils.js
@@ -1,12 +1,13 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.tweakKey = exports.tapTweakHash = exports.tapleafHash = exports.findScriptPath = exports.toHashTree = exports.rootHashFromPath = exports.LEAF_VERSION_TAPSCRIPT = void 0;
+exports.tweakKey = exports.tapTweakHash = exports.tapleafHash = exports.findScriptPath = exports.toHashTree = exports.rootHashFromPath = exports.MAX_TAPTREE_DEPTH = exports.LEAF_VERSION_TAPSCRIPT = void 0;
const buffer_1 = require('buffer');
const ecc_lib_1 = require('../ecc_lib');
const bcrypto = require('../crypto');
const bufferutils_1 = require('../bufferutils');
const types_1 = require('../types');
exports.LEAF_VERSION_TAPSCRIPT = 0xc0;
+exports.MAX_TAPTREE_DEPTH = 128;
const isHashBranch = ht => 'left' in ht && 'right' in ht;
function rootHashFromPath(controlBlock, leafHash) {
const m = (controlBlock.length - 33) / 32;
diff --git a/src/psbt/bip371.d.ts b/src/psbt/bip371.d.ts
index 9545e899a..a3784cfd1 100644
--- a/src/psbt/bip371.d.ts
+++ b/src/psbt/bip371.d.ts
@@ -1,5 +1,6 @@
///
-import { PsbtInput } from 'bip174/src/lib/interfaces';
+import { Taptree } from '../types';
+import { PsbtInput, TapLeaf } from 'bip174/src/lib/interfaces';
export declare const toXOnly: (pubKey: Buffer) => Buffer;
/**
* Default tapscript finalizer. It searches for the `tapLeafHashToFinalize` if provided.
@@ -17,3 +18,21 @@ export declare function serializeTaprootSignature(sig: Buffer, sighashType?: num
export declare function isTaprootInput(input: PsbtInput): boolean;
export declare function checkTaprootInputFields(inputData: PsbtInput, newInputData: PsbtInput, action: string): void;
export declare function tweakInternalPubKey(inputIndex: number, input: PsbtInput): Buffer;
+/**
+ * Convert a binary tree to a BIP371 type list. Each element of the list is (according to BIP371):
+ * One or more tuples representing the depth, leaf version, and script for a leaf in the Taproot tree,
+ * allowing the entire tree to be reconstructed. The tuples must be in depth first search order so that
+ * the tree is correctly reconstructed.
+ * @param tree the binary tap tree
+ * @returns a list of BIP 371 tapleaves
+ */
+export declare function tapTreeToList(tree: Taptree): TapLeaf[];
+/**
+ * Convert a BIP371 TapLeaf list to a TapTree (binary).
+ * @param leaves a list of tapleaves where each element of the list is (according to BIP371):
+ * One or more tuples representing the depth, leaf version, and script for a leaf in the Taproot tree,
+ * allowing the entire tree to be reconstructed. The tuples must be in depth first search order so that
+ * the tree is correctly reconstructed.
+ * @returns the corresponding taptree, or throws an exception if the tree cannot be reconstructed
+ */
+export declare function tapTreeFromList(leaves?: TapLeaf[]): Taptree;
diff --git a/src/psbt/bip371.js b/src/psbt/bip371.js
index 115235acf..40a54918b 100644
--- a/src/psbt/bip371.js
+++ b/src/psbt/bip371.js
@@ -1,6 +1,7 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.tweakInternalPubKey = exports.checkTaprootInputFields = exports.isTaprootInput = exports.serializeTaprootSignature = exports.tapScriptFinalizer = exports.toXOnly = void 0;
+exports.tapTreeFromList = exports.tapTreeToList = exports.tweakInternalPubKey = exports.checkTaprootInputFields = exports.isTaprootInput = exports.serializeTaprootSignature = exports.tapScriptFinalizer = exports.toXOnly = void 0;
+const types_1 = require('../types');
const psbtutils_1 = require('./psbtutils');
const taprootutils_1 = require('../payments/taprootutils');
const toXOnly = pubKey => (pubKey.length === 32 ? pubKey : pubKey.slice(1, 33));
@@ -69,6 +70,76 @@ function tweakInternalPubKey(inputIndex, input) {
return outputKey.x;
}
exports.tweakInternalPubKey = tweakInternalPubKey;
+/**
+ * Convert a binary tree to a BIP371 type list. Each element of the list is (according to BIP371):
+ * One or more tuples representing the depth, leaf version, and script for a leaf in the Taproot tree,
+ * allowing the entire tree to be reconstructed. The tuples must be in depth first search order so that
+ * the tree is correctly reconstructed.
+ * @param tree the binary tap tree
+ * @returns a list of BIP 371 tapleaves
+ */
+function tapTreeToList(tree) {
+ return _tapTreeToList(tree);
+}
+exports.tapTreeToList = tapTreeToList;
+/**
+ * Convert a BIP371 TapLeaf list to a TapTree (binary).
+ * @param leaves a list of tapleaves where each element of the list is (according to BIP371):
+ * One or more tuples representing the depth, leaf version, and script for a leaf in the Taproot tree,
+ * allowing the entire tree to be reconstructed. The tuples must be in depth first search order so that
+ * the tree is correctly reconstructed.
+ * @returns the corresponding taptree, or throws an exception if the tree cannot be reconstructed
+ */
+function tapTreeFromList(leaves = []) {
+ if (leaves.length === 1 && leaves[0].depth === 0)
+ return {
+ output: leaves[0].script,
+ version: leaves[0].leafVersion,
+ };
+ return instertLeavesInTree(leaves);
+}
+exports.tapTreeFromList = tapTreeFromList;
+function _tapTreeToList(tree, leaves = [], depth = 0) {
+ if (depth > taprootutils_1.MAX_TAPTREE_DEPTH)
+ throw new Error('Max taptree depth exceeded.');
+ if (!tree) return [];
+ if ((0, types_1.isTapleaf)(tree)) {
+ leaves.push({
+ depth,
+ leafVersion: tree.version || taprootutils_1.LEAF_VERSION_TAPSCRIPT,
+ script: tree.output,
+ });
+ return leaves;
+ }
+ if (tree[0]) _tapTreeToList(tree[0], leaves, depth + 1);
+ if (tree[1]) _tapTreeToList(tree[1], leaves, depth + 1);
+ return leaves;
+}
+function instertLeavesInTree(leaves) {
+ let tree;
+ for (const leaf of leaves) {
+ tree = instertLeafInTree(leaf, tree);
+ if (!tree) throw new Error(`No room left to insert tapleaf in tree`);
+ }
+ return tree;
+}
+function instertLeafInTree(leaf, tree, depth = 0) {
+ if (depth > taprootutils_1.MAX_TAPTREE_DEPTH)
+ throw new Error('Max taptree depth exceeded.');
+ if (leaf.depth === depth) {
+ if (!tree)
+ return {
+ output: leaf.script,
+ version: leaf.leafVersion,
+ };
+ return;
+ }
+ if ((0, types_1.isTapleaf)(tree)) return;
+ const leftSide = instertLeafInTree(leaf, tree && tree[0], depth + 1);
+ if (leftSide) return [leftSide, tree && tree[1]];
+ const rightSide = instertLeafInTree(leaf, tree && tree[1], depth + 1);
+ if (rightSide) return [tree && tree[0], rightSide];
+}
function checkMixedTaprootAndNonTaprootFields(inputData, newInputData, action) {
const isBadTaprootUpdate =
isTaprootInput(inputData) && hasNonTaprootInputFields(newInputData);
diff --git a/ts_src/payments/taprootutils.ts b/ts_src/payments/taprootutils.ts
index 39d815e44..503819325 100644
--- a/ts_src/payments/taprootutils.ts
+++ b/ts_src/payments/taprootutils.ts
@@ -6,6 +6,7 @@ import { varuint } from '../bufferutils';
import { Tapleaf, Taptree, isTapleaf } from '../types';
export const LEAF_VERSION_TAPSCRIPT = 0xc0;
+export const MAX_TAPTREE_DEPTH = 128;
interface HashLeaf {
hash: Buffer;
diff --git a/ts_src/psbt/bip371.ts b/ts_src/psbt/bip371.ts
index 618ff25c5..b056a5371 100644
--- a/ts_src/psbt/bip371.ts
+++ b/ts_src/psbt/bip371.ts
@@ -1,7 +1,9 @@
+import { Taptree, Tapleaf, isTapleaf } from '../types';
import {
PsbtInput,
TapLeafScript,
TapScriptSig,
+ TapLeaf,
} from 'bip174/src/lib/interfaces';
import {
@@ -13,6 +15,8 @@ import {
tweakKey,
tapleafHash,
rootHashFromPath,
+ LEAF_VERSION_TAPSCRIPT,
+ MAX_TAPTREE_DEPTH,
} from '../payments/taprootutils';
export const toXOnly = (pubKey: Buffer) =>
@@ -98,6 +102,94 @@ export function tweakInternalPubKey(
return outputKey.x;
}
+/**
+ * Convert a binary tree to a BIP371 type list. Each element of the list is (according to BIP371):
+ * One or more tuples representing the depth, leaf version, and script for a leaf in the Taproot tree,
+ * allowing the entire tree to be reconstructed. The tuples must be in depth first search order so that
+ * the tree is correctly reconstructed.
+ * @param tree the binary tap tree
+ * @returns a list of BIP 371 tapleaves
+ */
+export function tapTreeToList(tree: Taptree): TapLeaf[] {
+ return _tapTreeToList(tree);
+}
+
+/**
+ * Convert a BIP371 TapLeaf list to a TapTree (binary).
+ * @param leaves a list of tapleaves where each element of the list is (according to BIP371):
+ * One or more tuples representing the depth, leaf version, and script for a leaf in the Taproot tree,
+ * allowing the entire tree to be reconstructed. The tuples must be in depth first search order so that
+ * the tree is correctly reconstructed.
+ * @returns the corresponding taptree, or throws an exception if the tree cannot be reconstructed
+ */
+export function tapTreeFromList(leaves: TapLeaf[] = []): Taptree {
+ if (leaves.length === 1 && leaves[0].depth === 0)
+ return {
+ output: leaves[0].script,
+ version: leaves[0].leafVersion,
+ };
+
+ return instertLeavesInTree(leaves);
+}
+
+function _tapTreeToList(
+ tree: Taptree,
+ leaves: TapLeaf[] = [],
+ depth = 0,
+): TapLeaf[] {
+ if (depth > MAX_TAPTREE_DEPTH) throw new Error('Max taptree depth exceeded.');
+ if (!tree) return [];
+ if (isTapleaf(tree)) {
+ leaves.push({
+ depth,
+ leafVersion: tree.version || LEAF_VERSION_TAPSCRIPT,
+ script: tree.output,
+ });
+ return leaves;
+ }
+ if (tree[0]) _tapTreeToList(tree[0], leaves, depth + 1);
+ if (tree[1]) _tapTreeToList(tree[1], leaves, depth + 1);
+ return leaves;
+}
+
+// Just like Taptree, but it accepts empty branches
+type PartialTaptree =
+ | [PartialTaptree | Tapleaf, PartialTaptree | Tapleaf]
+ | Tapleaf
+ | undefined;
+function instertLeavesInTree(leaves: TapLeaf[]): Taptree {
+ let tree: PartialTaptree;
+ for (const leaf of leaves) {
+ tree = instertLeafInTree(leaf, tree);
+ if (!tree) throw new Error(`No room left to insert tapleaf in tree`);
+ }
+
+ return tree as Taptree;
+}
+
+function instertLeafInTree(
+ leaf: TapLeaf,
+ tree?: PartialTaptree,
+ depth = 0,
+): PartialTaptree {
+ if (depth > MAX_TAPTREE_DEPTH) throw new Error('Max taptree depth exceeded.');
+ if (leaf.depth === depth) {
+ if (!tree)
+ return {
+ output: leaf.script,
+ version: leaf.leafVersion,
+ };
+ return;
+ }
+
+ if (isTapleaf(tree)) return;
+ const leftSide = instertLeafInTree(leaf, tree && tree[0], depth + 1);
+ if (leftSide) return [leftSide, tree && tree[1]];
+
+ const rightSide = instertLeafInTree(leaf, tree && tree[1], depth + 1);
+ if (rightSide) return [tree && tree[0], rightSide];
+}
+
function checkMixedTaprootAndNonTaprootFields(
inputData: PsbtInput,
newInputData: PsbtInput,
From 9eb0790de436ec797f592a11c5a09bbe4fc3ec8f Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Tue, 24 May 2022 14:10:09 +0300
Subject: [PATCH 076/144] test: add tests for taptree conversion to tapleaf
---
src/psbt/bip371.js | 4 +++
src/types.js | 2 +-
test/payments.utils.ts | 9 ++++--
test/psbt.spec.ts | 66 ++++++++++++++++++++++++++++++++++++++++++
ts_src/psbt/bip371.ts | 6 +++-
ts_src/types.ts | 2 +-
6 files changed, 83 insertions(+), 6 deletions(-)
diff --git a/src/psbt/bip371.js b/src/psbt/bip371.js
index 40a54918b..9b9fac161 100644
--- a/src/psbt/bip371.js
+++ b/src/psbt/bip371.js
@@ -79,6 +79,10 @@ exports.tweakInternalPubKey = tweakInternalPubKey;
* @returns a list of BIP 371 tapleaves
*/
function tapTreeToList(tree) {
+ if (!(0, types_1.isTaptree)(tree))
+ throw new Error(
+ 'Cannot convert taptree to tapleaf list. Expecting a tapree structure.',
+ );
return _tapTreeToList(tree);
}
exports.tapTreeToList = tapTreeToList;
diff --git a/src/types.js b/src/types.js
index e1d0a528d..3a2dc51ea 100644
--- a/src/types.js
+++ b/src/types.js
@@ -70,7 +70,7 @@ exports.Network = exports.typeforce.compile({
});
exports.TAPLEAF_VERSION_MASK = 0xfe;
function isTapleaf(o) {
- if (!('output' in o)) return false;
+ if (!o || !('output' in o)) return false;
if (!buffer_1.Buffer.isBuffer(o.output)) return false;
if (o.version !== undefined)
return (o.version & exports.TAPLEAF_VERSION_MASK) === o.version;
diff --git a/test/payments.utils.ts b/test/payments.utils.ts
index 12fc20712..3f86770e8 100644
--- a/test/payments.utils.ts
+++ b/test/payments.utils.ts
@@ -186,11 +186,14 @@ export function from(path: string, object: any, result?: any): any {
return result;
}
-function convertScriptTree(scriptTree: any): any {
- if (Array.isArray(scriptTree)) return scriptTree.map(convertScriptTree);
+export function convertScriptTree(scriptTree: any, leafVersion?: number): any {
+ if (Array.isArray(scriptTree))
+ return scriptTree.map(t => convertScriptTree(t, leafVersion));
const script = Object.assign({}, scriptTree);
- if (typeof script.output === 'string')
+ if (typeof script.output === 'string') {
script.output = asmToBuffer(scriptTree.output);
+ script.version = script.version || leafVersion;
+ }
return script;
}
diff --git a/test/psbt.spec.ts b/test/psbt.spec.ts
index 97f558b2f..39fcf4a7f 100644
--- a/test/psbt.spec.ts
+++ b/test/psbt.spec.ts
@@ -5,6 +5,10 @@ import * as crypto from 'crypto';
import ECPairFactory from 'ecpair';
import { describe, it } from 'mocha';
+import { convertScriptTree } from './payments.utils';
+import { LEAF_VERSION_TAPSCRIPT } from '../src/payments/taprootutils';
+import { tapTreeToList, tapTreeFromList } from '../src/psbt/bip371';
+import { Taptree } from '../src/types';
import { initEccLib } from '../src';
const bip32 = BIP32Factory(ecc);
@@ -13,6 +17,7 @@ const ECPair = ECPairFactory(ecc);
import { networks as NETWORKS, payments, Psbt, Signer, SignerAsync } from '..';
import * as preFixtures from './fixtures/psbt.json';
+import * as taprootFixtures from './fixtures/p2tr.json';
const validator = (
pubkey: Buffer,
@@ -1099,6 +1104,67 @@ describe(`Psbt`, () => {
});
});
+ describe('tapTreeToList/tapTreeFromList', () => {
+ it('Correctly converts a Taptree to a Tapleaf list and back', () => {
+ taprootFixtures.valid
+ .filter(f => f.arguments.scriptTree)
+ .map(f => f.arguments.scriptTree)
+ .forEach(scriptTree => {
+ const originalTree = convertScriptTree(
+ scriptTree,
+ LEAF_VERSION_TAPSCRIPT,
+ );
+ const list = tapTreeToList(originalTree);
+ const treeFromList = tapTreeFromList(list);
+
+ assert.deepStrictEqual(treeFromList, originalTree);
+ });
+ });
+ it('Throws if too many leaves on a given level', () => {
+ const list = Array.from({ length: 5 }).map(() => ({
+ depth: 2,
+ leafVersion: LEAF_VERSION_TAPSCRIPT,
+ script: Buffer.from([]),
+ }));
+ assert.throws(() => {
+ tapTreeFromList(list);
+ }, new RegExp('No room left to insert tapleaf in tree'));
+ });
+ it('Throws if taptree depth is exceeded', () => {
+ let tree: Taptree = [
+ { output: Buffer.from([]) },
+ { output: Buffer.from([]) },
+ ];
+ Array.from({ length: 129 }).forEach(
+ () => (tree = [tree, { output: Buffer.from([]) }]),
+ );
+ assert.throws(() => {
+ tapTreeToList(tree as Taptree);
+ }, new RegExp('Max taptree depth exceeded.'));
+ });
+ it('Throws if tapleaf depth is to high', () => {
+ const list = [
+ {
+ depth: 129,
+ leafVersion: LEAF_VERSION_TAPSCRIPT,
+ script: Buffer.from([]),
+ },
+ ];
+ assert.throws(() => {
+ tapTreeFromList(list);
+ }, new RegExp('Max taptree depth exceeded.'));
+ });
+ it('Throws if not a valid taptree structure', () => {
+ const tree = Array.from({ length: 3 }).map(() => ({
+ output: Buffer.from([]),
+ }));
+
+ assert.throws(() => {
+ tapTreeToList(tree as Taptree);
+ }, new RegExp('Cannot convert taptree to tapleaf list. Expecting a tapree structure.'));
+ });
+ });
+
describe('getFeeRate', () => {
it('Throws error if called before inputs are finalized', () => {
const f = fixtures.getFeeRate;
diff --git a/ts_src/psbt/bip371.ts b/ts_src/psbt/bip371.ts
index b056a5371..93569c491 100644
--- a/ts_src/psbt/bip371.ts
+++ b/ts_src/psbt/bip371.ts
@@ -1,4 +1,4 @@
-import { Taptree, Tapleaf, isTapleaf } from '../types';
+import { Taptree, Tapleaf, isTapleaf, isTaptree } from '../types';
import {
PsbtInput,
TapLeafScript,
@@ -111,6 +111,10 @@ export function tweakInternalPubKey(
* @returns a list of BIP 371 tapleaves
*/
export function tapTreeToList(tree: Taptree): TapLeaf[] {
+ if (!isTaptree(tree))
+ throw new Error(
+ 'Cannot convert taptree to tapleaf list. Expecting a tapree structure.',
+ );
return _tapTreeToList(tree);
}
diff --git a/ts_src/types.ts b/ts_src/types.ts
index 536646e86..b904fd49b 100644
--- a/ts_src/types.ts
+++ b/ts_src/types.ts
@@ -79,7 +79,7 @@ export interface Tapleaf {
export const TAPLEAF_VERSION_MASK = 0xfe;
export function isTapleaf(o: any): o is Tapleaf {
- if (!('output' in o)) return false;
+ if (!o || !('output' in o)) return false;
if (!NBuffer.isBuffer(o.output)) return false;
if (o.version !== undefined)
return (o.version & TAPLEAF_VERSION_MASK) === o.version;
From bc3dc464a63da105401a068e65e569ea64a5dcdf Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Tue, 24 May 2022 14:31:54 +0300
Subject: [PATCH 077/144] chore: code lint
---
test/psbt.spec.ts | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/test/psbt.spec.ts b/test/psbt.spec.ts
index 39fcf4a7f..d2026e9a6 100644
--- a/test/psbt.spec.ts
+++ b/test/psbt.spec.ts
@@ -1120,6 +1120,7 @@ describe(`Psbt`, () => {
assert.deepStrictEqual(treeFromList, originalTree);
});
});
+
it('Throws if too many leaves on a given level', () => {
const list = Array.from({ length: 5 }).map(() => ({
depth: 2,
@@ -1130,6 +1131,7 @@ describe(`Psbt`, () => {
tapTreeFromList(list);
}, new RegExp('No room left to insert tapleaf in tree'));
});
+
it('Throws if taptree depth is exceeded', () => {
let tree: Taptree = [
{ output: Buffer.from([]) },
@@ -1142,6 +1144,7 @@ describe(`Psbt`, () => {
tapTreeToList(tree as Taptree);
}, new RegExp('Max taptree depth exceeded.'));
});
+
it('Throws if tapleaf depth is to high', () => {
const list = [
{
@@ -1154,6 +1157,7 @@ describe(`Psbt`, () => {
tapTreeFromList(list);
}, new RegExp('Max taptree depth exceeded.'));
});
+
it('Throws if not a valid taptree structure', () => {
const tree = Array.from({ length: 3 }).map(() => ({
output: Buffer.from([]),
From d7e24cbbda838cceb8a15d361b7c2fbe8b06d463 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Wed, 25 May 2022 13:53:06 +0300
Subject: [PATCH 078/144] test: use `tapInternalKey` to generate the address
---
test/integration/taproot.spec.ts | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/test/integration/taproot.spec.ts b/test/integration/taproot.spec.ts
index 5e05c8887..e537cf075 100644
--- a/test/integration/taproot.spec.ts
+++ b/test/integration/taproot.spec.ts
@@ -53,7 +53,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
const internalKey = bip32.fromSeed(rng(64), regtest);
const p2pkhKey = bip32.fromSeed(rng(64), regtest);
- const { output, address } = bitcoin.payments.p2tr({
+ const { output } = bitcoin.payments.p2tr({
internalPubkey: toXOnly(internalKey.publicKey),
network: regtest,
});
@@ -84,7 +84,17 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
});
psbt.addInput({ index: 0, hash: p2pkhUnspent.txId, nonWitnessUtxo });
- psbt.addOutput({ value: sendAmount, address: address! });
+ const sendInternalKey = bip32.fromSeed(rng(64), regtest);
+ const sendPubKey = toXOnly(sendInternalKey.publicKey);
+ const { address: sendAddress } = bitcoin.payments.p2tr({
+ internalPubkey: sendPubKey,
+ network: regtest,
+ });
+
+ psbt.addOutput({
+ value: sendAmount,
+ tapInternalKey: sendPubKey,
+ });
const tweakedSigner = tweakSigner(internalKey!, { network: regtest });
await psbt.signInputAsync(0, tweakedSigner);
@@ -99,7 +109,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
await regtestUtils.broadcast(hex);
await regtestUtils.verify({
txId: tx.getId(),
- address: address!,
+ address: sendAddress!,
vout: 0,
value: sendAmount,
});
From 58258a722ecea34626450b9db8776e30c8932f00 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Wed, 25 May 2022 14:51:34 +0300
Subject: [PATCH 079/144] feat: do taproot checks for `addOutput()`
---
src/psbt.d.ts | 10 ++-
src/psbt.js | 21 +++++-
src/psbt/bip371.d.ts | 9 ++-
src/psbt/bip371.js | 88 +++++++++++++++++++++----
test/fixtures/psbt.json | 108 +++++++++++++++++++++++++++++--
test/integration/taproot.spec.ts | 20 ++++--
test/psbt.spec.ts | 6 +-
ts_src/psbt.ts | 35 +++++++++-
ts_src/psbt/bip371.ts | 102 +++++++++++++++++++++++++----
9 files changed, 360 insertions(+), 39 deletions(-)
diff --git a/src/psbt.d.ts b/src/psbt.d.ts
index 4c622b31f..646edd5c0 100644
--- a/src/psbt.d.ts
+++ b/src/psbt.d.ts
@@ -1,6 +1,6 @@
///
import { Psbt as PsbtBase } from 'bip174';
-import { KeyValue, PsbtGlobalUpdate, PsbtInput, PsbtInputUpdate, PsbtOutput, PsbtOutputUpdate } from 'bip174/src/lib/interfaces';
+import { KeyValue, PsbtGlobalUpdate, PsbtInput, PsbtInputUpdate, PsbtOutput, PsbtOutputUpdate, TapInternalKey, TapTree } from 'bip174/src/lib/interfaces';
import { Network } from './networks';
import { Transaction } from './transaction';
export interface TransactionInput {
@@ -125,7 +125,7 @@ interface PsbtOptsOptional {
}
interface PsbtInputExtended extends PsbtInput, TransactionInput {
}
-declare type PsbtOutputExtended = PsbtOutputExtendedAddress | PsbtOutputExtendedScript;
+declare type PsbtOutputExtended = PsbtOutputExtendedAddress | PsbtOutputExtendedScript | PsbtOutputExtendedTaproot;
interface PsbtOutputExtendedAddress extends PsbtOutput {
address: string;
value: number;
@@ -134,6 +134,12 @@ interface PsbtOutputExtendedScript extends PsbtOutput {
script: Buffer;
value: number;
}
+interface PsbtOutputExtendedTaproot extends PsbtOutput {
+ tapInternalKey: TapInternalKey;
+ tapTree?: TapTree;
+ script?: Buffer;
+ value: number;
+}
interface HDSignerBase {
/**
* DER format compressed publicKey buffer
diff --git a/src/psbt.js b/src/psbt.js
index 5496008ca..ced6105ac 100644
--- a/src/psbt.js
+++ b/src/psbt.js
@@ -226,11 +226,13 @@ class Psbt {
arguments.length > 1 ||
!outputData ||
outputData.value === undefined ||
- (outputData.address === undefined && outputData.script === undefined)
+ (outputData.address === undefined &&
+ outputData.script === undefined &&
+ outputData.tapInternalKey === undefined)
) {
throw new Error(
`Invalid arguments for Psbt.addOutput. ` +
- `Requires single object with at least [script or address] and [value]`,
+ `Requires single object with at least [script, address or tapInternalKey] and [value]`,
);
}
checkInputsForPartialSig(this.data.inputs, 'addOutput');
@@ -240,6 +242,20 @@ class Psbt {
const script = (0, address_1.toOutputScript)(address, network);
outputData = Object.assign(outputData, { script });
}
+ if ((0, bip371_1.isTaprootOutput)(outputData)) {
+ (0, bip371_1.checkTaprootOutputFields)(
+ outputData,
+ outputData,
+ 'addOutput',
+ );
+ const scriptAndAddress = (0, bip371_1.getNewTaprootScriptAndAddress)(
+ outputData,
+ outputData,
+ this.opts.network,
+ );
+ if (scriptAndAddress)
+ outputData = Object.assign(outputData, scriptAndAddress);
+ }
const c = this.__CACHE;
this.data.addOutput(outputData);
c.__FEE = undefined;
@@ -1028,6 +1044,7 @@ function checkFees(psbt, cache, opts) {
}
}
function checkInputsForPartialSig(inputs, action) {
+ // todo: add for taproot
inputs.forEach(input => {
let throws = false;
let pSigs = [];
diff --git a/src/psbt/bip371.d.ts b/src/psbt/bip371.d.ts
index a3784cfd1..411c7e3c3 100644
--- a/src/psbt/bip371.d.ts
+++ b/src/psbt/bip371.d.ts
@@ -1,6 +1,7 @@
///
import { Taptree } from '../types';
-import { PsbtInput, TapLeaf } from 'bip174/src/lib/interfaces';
+import { PsbtInput, PsbtOutput, TapLeaf } from 'bip174/src/lib/interfaces';
+import { Network } from '../networks';
export declare const toXOnly: (pubKey: Buffer) => Buffer;
/**
* Default tapscript finalizer. It searches for the `tapLeafHashToFinalize` if provided.
@@ -16,7 +17,13 @@ export declare function tapScriptFinalizer(inputIndex: number, input: PsbtInput,
};
export declare function serializeTaprootSignature(sig: Buffer, sighashType?: number): Buffer;
export declare function isTaprootInput(input: PsbtInput): boolean;
+export declare function isTaprootOutput(output: PsbtOutput, script?: Buffer): boolean;
export declare function checkTaprootInputFields(inputData: PsbtInput, newInputData: PsbtInput, action: string): void;
+export declare function checkTaprootOutputFields(outputData: PsbtOutput, newOutputData: PsbtOutput, action: string): void;
+export declare function getNewTaprootScriptAndAddress(outputData: PsbtOutput, newOutputData: PsbtOutput, network?: Network): {
+ script: Buffer;
+ address: string;
+} | undefined;
export declare function tweakInternalPubKey(inputIndex: number, input: PsbtInput): Buffer;
/**
* Convert a binary tree to a BIP371 type list. Each element of the list is (according to BIP371):
diff --git a/src/psbt/bip371.js b/src/psbt/bip371.js
index 9b9fac161..677f20fca 100644
--- a/src/psbt/bip371.js
+++ b/src/psbt/bip371.js
@@ -1,9 +1,10 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.tapTreeFromList = exports.tapTreeToList = exports.tweakInternalPubKey = exports.checkTaprootInputFields = exports.isTaprootInput = exports.serializeTaprootSignature = exports.tapScriptFinalizer = exports.toXOnly = void 0;
+exports.tapTreeFromList = exports.tapTreeToList = exports.tweakInternalPubKey = exports.getNewTaprootScriptAndAddress = exports.checkTaprootOutputFields = exports.checkTaprootInputFields = exports.isTaprootOutput = exports.isTaprootInput = exports.serializeTaprootSignature = exports.tapScriptFinalizer = exports.toXOnly = void 0;
const types_1 = require('../types');
const psbtutils_1 = require('./psbtutils');
const taprootutils_1 = require('../payments/taprootutils');
+const payments_1 = require('../payments');
const toXOnly = pubKey => (pubKey.length === 32 ? pubKey : pubKey.slice(1, 33));
exports.toXOnly = toXOnly;
/**
@@ -52,11 +53,54 @@ function isTaprootInput(input) {
);
}
exports.isTaprootInput = isTaprootInput;
+function isTaprootOutput(output, script) {
+ return (
+ output &&
+ !!(
+ output.tapInternalKey ||
+ output.tapTree ||
+ (output.tapBip32Derivation && output.tapBip32Derivation.length) ||
+ (script && (0, psbtutils_1.isP2TR)(script))
+ )
+ );
+}
+exports.isTaprootOutput = isTaprootOutput;
function checkTaprootInputFields(inputData, newInputData, action) {
- checkMixedTaprootAndNonTaprootFields(inputData, newInputData, action);
+ checkMixedTaprootAndNonTaprootInputFields(inputData, newInputData, action);
checkIfTapLeafInTree(inputData, newInputData, action);
}
exports.checkTaprootInputFields = checkTaprootInputFields;
+function checkTaprootOutputFields(outputData, newOutputData, action) {
+ checkMixedTaprootAndNonTaprootOutputFields(outputData, newOutputData, action);
+}
+exports.checkTaprootOutputFields = checkTaprootOutputFields;
+function getNewTaprootScriptAndAddress(outputData, newOutputData, network) {
+ if (!newOutputData.tapTree && !newOutputData.tapInternalKey) return;
+ const tapInternalKey =
+ newOutputData.tapInternalKey || outputData.tapInternalKey;
+ const tapTree = newOutputData.tapTree || outputData.tapTree;
+ if (tapInternalKey) {
+ const { script, address } = getTaprootScriptAndAddress(
+ tapInternalKey,
+ tapTree,
+ network,
+ );
+ const { script: newScript } = newOutputData;
+ if (newScript && !newScript.equals(script))
+ throw new Error('Error adding output. Script or address missmatch.');
+ return { script, address };
+ }
+}
+exports.getNewTaprootScriptAndAddress = getNewTaprootScriptAndAddress;
+function getTaprootScriptAndAddress(tapInternalKey, tapTree, network) {
+ const scriptTree = tapTree && tapTreeFromList(tapTree.leaves);
+ const { output, address } = (0, payments_1.p2tr)({
+ internalPubkey: tapInternalKey,
+ scriptTree,
+ network,
+ });
+ return { script: output, address: address };
+}
function tweakInternalPubKey(inputIndex, input) {
const tapInternalKey = input.tapInternalKey;
const outputKey =
@@ -144,14 +188,36 @@ function instertLeafInTree(leaf, tree, depth = 0) {
const rightSide = instertLeafInTree(leaf, tree && tree[1], depth + 1);
if (rightSide) return [tree && tree[0], rightSide];
}
-function checkMixedTaprootAndNonTaprootFields(inputData, newInputData, action) {
+function checkMixedTaprootAndNonTaprootInputFields(
+ inputData,
+ newInputData,
+ action,
+) {
const isBadTaprootUpdate =
- isTaprootInput(inputData) && hasNonTaprootInputFields(newInputData);
+ isTaprootInput(inputData) && hasNonTaprootFields(newInputData);
const isBadNonTaprootUpdate =
- hasNonTaprootInputFields(inputData) && isTaprootInput(newInputData);
+ hasNonTaprootFields(inputData) && isTaprootInput(newInputData);
const hasMixedFields =
inputData === newInputData &&
- (isTaprootInput(newInputData) && hasNonTaprootInputFields(newInputData));
+ (isTaprootInput(newInputData) && hasNonTaprootFields(newInputData)); // todo: bad? use !===
+ if (isBadTaprootUpdate || isBadNonTaprootUpdate || hasMixedFields)
+ throw new Error(
+ `Invalid arguments for Psbt.${action}. ` +
+ `Cannot use both taproot and non-taproot fields.`,
+ );
+}
+function checkMixedTaprootAndNonTaprootOutputFields(
+ inputData,
+ newInputData,
+ action,
+) {
+ const isBadTaprootUpdate =
+ isTaprootOutput(inputData) && hasNonTaprootFields(newInputData);
+ const isBadNonTaprootUpdate =
+ hasNonTaprootFields(inputData) && isTaprootOutput(newInputData);
+ const hasMixedFields =
+ inputData === newInputData &&
+ (isTaprootOutput(newInputData) && hasNonTaprootFields(newInputData));
if (isBadTaprootUpdate || isBadNonTaprootUpdate || hasMixedFields)
throw new Error(
`Invalid arguments for Psbt.${action}. ` +
@@ -244,13 +310,13 @@ function canFinalizeLeaf(leaf, tapScriptSig, hash) {
tapScriptSig.find(tss => tss.leafHash.equals(leafHash)) !== undefined
);
}
-function hasNonTaprootInputFields(input) {
+function hasNonTaprootFields(io) {
return (
- input &&
+ io &&
!!(
- input.redeemScript ||
- input.witnessScript ||
- (input.bip32Derivation && input.bip32Derivation.length)
+ io.redeemScript ||
+ io.witnessScript ||
+ (io.bip32Derivation && io.bip32Derivation.length)
)
);
}
diff --git a/test/fixtures/psbt.json b/test/fixtures/psbt.json
index 7bce10812..f2c990a8e 100644
--- a/test/fixtures/psbt.json
+++ b/test/fixtures/psbt.json
@@ -338,7 +338,7 @@
{
"inputToSign": 0,
"tapLeafHashToSign": "f2d9fd9a2f80e0e7abeac881398fc37198f46e5c802ec00c95152aa6f703e71e",
- "WIF": "cP76Rzf6bVcmFbnJ3DigWvyNvki2bZeXxoq3B5pcZ8zVRnT4fKdx"
+ "WIF": "cP76Rzf6bVcmFbnJ3DigWvyNvki2bZeXxoq3B5pcZ8zVRnT4fKdx"
}
],
"result": "cHNidP8BAF4CAAAAAdXMkUOLeYvgm981k3T7Pmdf5Dr31jOxvpFHiXiU9D2gAAAAAAD/////AZBBBgAAAAAAIlEgD31MIAvwCaanOsAzyBoQ4o/WozgFiqVQTEqGJE18XqwAAAAAAAEBK6BoBgAAAAAAIlEgD31MIAvwCaanOsAzyBoQ4o/WozgFiqVQTEqGJE18XqxBFCo/Wsfk0hSOCy21lUyn+vXnc1SG1lNVWHlnXCh3xegq8tn9mi+A4Oer6siBOY/DcZj0blyALsAMlRUqpvcD5x5Aa7X0m4UCLaHA/Vnjkl+if6rVeiBbIlbHXHLh7RqJyB8Wgs66p6/ZnwSW/HD6o7rMHffIva+jgJgYWf6MvzrfTWIVwAjUk5QzdUBMEkLbwcjUHnMpA13k3j9ziDszUJiFladaGlKcn7PNfndtYbYiW2xhDokG+4+qbFmsXD6VtfgtKdaTipNtL9o84yJyfhx52eesqJWF2CBZtnGxCFpdeDn8S2kgKj9ax+TSFI4LLbWVTKf69edzVIbWU1VYeWdcKHfF6CqsIJy6ZeYeVOa94xIEs49J9vofeVpf3u1m0XiCqbHNX6BsuiBcF5S+4nRv+Yw5rfnf3GLPT81/1FAJYZldegI1wVRh17pTnMBCFcAI1JOUM3VATBJC28HI1B5zKQNd5N4/c4g7M1CYhZWnWl8Vv/I1WWJt8byg3fk43iQn6QFlDgumFTPXr7uOK24+IyAqP1rH5NIUjgsttZVMp/r153NUhtZTVVh5Z1wod8XoKqzAAAA="
@@ -501,12 +501,111 @@
},
"exception": "Error adding output."
},
+ {
+ "description": "Checks that the output script can be computed",
+ "outputData": {
+ "value": 1000
+ },
+ "exception": "Invalid arguments for Psbt\\.addOutput. Requires single object with at least \\[script, address or tapInternalKey\\] and \\[value\\]"
+ },
{
"description": "Adds output normally",
"outputData": {
"address": "1P2NFEBp32V2arRwZNww6tgXEV58FG94mr",
"value": 42
}
+ },
+ {
+ "description": "Adds taproot output with internal key only (address derived)",
+ "isTaproot": true,
+ "psbt": "cHNidP8BAFwCAAAAAo6LlrlIROHUfunj2OPeOpJlw/sG4cG99LrNl88u7rcrAAAAAAD/////LR6UXz/GymI8bcsv2b+NIzWKT/d9cEUPwWHREjtSapcAAAAAAP////8AAAAAAAABASugaAYAAAAAACJRIAkRWDXSsncord4FtaUxPSWLua73cQbIN0uq2qyWztP3ARcgAqgH8rOX0SzoemaM+YlCy9DYeU1w9CrcR7Vm5/PPlxYAAQDAAgAAAAG67fXBoOPSqNrW6dbIkadKg+T6+tnU2pqoCSiOxyVdhQAAAABrSDBFAiEA9sK/dshQbR7W58jOzsH069Ms5C7Q4b0CDiDB//7BccECICDpjneIIw2Wgr9fq7VvqZfOgghSlXjiMaVr1Qqkb4qUASEC/r+CrU8sH0Jy0FIrGL6XQ8p0tDVOfnVpl6M6NKkwqZT/////AaBoBgAAAAAAGXapFLuFzFEeVsEgi+khfH7+Tc7+AvKBiKwAAAAAAAA=",
+ "outputData": {
+ "tapInternalKey": "Buffer.from('1a954a44837e47815f7285eae2dc3716f98eafb41a1155e999bfa66853b2cc47', 'hex')",
+ "value": 410000
+ },
+ "result": "cHNidP8BAIcCAAAAAo6LlrlIROHUfunj2OPeOpJlw/sG4cG99LrNl88u7rcrAAAAAAD/////LR6UXz/GymI8bcsv2b+NIzWKT/d9cEUPwWHREjtSapcAAAAAAP////8BkEEGAAAAAAAiUSCTYMKBNf5sZR1VO8dJdu2z5lO0vHqjXMjmOYotibmHLwAAAAAAAQEroGgGAAAAAAAiUSAJEVg10rJ3KK3eBbWlMT0li7mu93EGyDdLqtqsls7T9wEXIAKoB/Kzl9Es6HpmjPmJQsvQ2HlNcPQq3Ee1Zufzz5cWAAEAwAIAAAABuu31waDj0qja1unWyJGnSoPk+vrZ1NqaqAkojsclXYUAAAAAa0gwRQIhAPbCv3bIUG0e1ufIzs7B9OvTLOQu0OG9Ag4gwf/+wXHBAiAg6Y53iCMNloK/X6u1b6mXzoIIUpV44jGla9UKpG+KlAEhAv6/gq1PLB9CctBSKxi+l0PKdLQ1Tn51aZejOjSpMKmU/////wGgaAYAAAAAABl2qRS7hcxRHlbBIIvpIXx+/k3O/gLygYisAAAAAAABBSAalUpEg35HgV9yheri3DcW+Y6vtBoRVemZv6ZoU7LMRwA="
+ },
+ {
+ "description": "Adds taproot output with internal key and tap tree (address derived)",
+ "isTaproot": true,
+ "psbt": "cHNidP8BADMCAAAAAcbgSGx76du9GXsr4c6Yk7DFglfHi7M2jdCNUXwc+Q+EAAAAAAD/////AAAAAAAAAQEroGgGAAAAAAAiUSClLxmVQ6aZXLEwkYA/WGZuIE91BHT7xP7DIEAvz/NITaIVwd2NnolThxX+QCpgFksj8u93bzuZy6olaHxJNHaArwK1tCTeoJ+EC5MqADc83NvSVlC4w6z+VKn0pkGihnIbjSbax5V2a72h6uqkXlv6CpUP3V9MSq2lsfMILtyWibn9Cu4oo7gsSuy+vTeBJ9yI3Rnh6pPtunont1ThyIHTCIdKesRIlUS3uEDQRVmeyUFa5xzLCQwsRlwFyfoF9Bx6BtUjIFX368Cp2d6uXSbyrn23vC4KMjRRlEssuTTh7ThM6bXQrMAAAA==",
+ "outputData": {
+ "tapInternalKey": "Buffer.from('f6d4ce132444de7f0e3a1d2be9b38ceec798cf9a76eeeac585869445830eb167', 'hex')",
+ "tapTree": {
+ "leaves": [
+ {
+ "depth": 2,
+ "leafVersion": 192,
+ "script": "Buffer.from('2050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0ac', 'hex')"
+ },
+ {
+ "depth": 3,
+ "leafVersion": 192,
+ "script": "Buffer.from('2050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac1ac', 'hex')"
+ },
+ {
+ "depth": 3,
+ "leafVersion": 192,
+ "script": "Buffer.from('202258b1c3160be0864a541854eec9164a572f094f7562628281a8073bb89173a7ac', 'hex')"
+ },
+ {
+ "depth": 2,
+ "leafVersion": 192,
+ "script": "Buffer.from('2050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac2ac', 'hex')"
+ },
+ {
+ "depth": 3,
+ "leafVersion": 192,
+ "script": "Buffer.from('2050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac3ac', 'hex')"
+ },
+ {
+ "depth": 4,
+ "leafVersion": 192,
+ "script": "Buffer.from('2050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac4ac', 'hex')"
+ },
+ {
+ "depth": 4,
+ "leafVersion": 192,
+ "script": "Buffer.from('2055f7ebc0a9d9deae5d26f2ae7db7bc2e0a323451944b2cb934e1ed384ce9b5d0ac', 'hex')"
+ }
+ ]
+ },
+ "value": 410000
+ },
+ "result": "cHNidP8BAF4CAAAAAcbgSGx76du9GXsr4c6Yk7DFglfHi7M2jdCNUXwc+Q+EAAAAAAD/////AZBBBgAAAAAAIlEgNWEIXy34qyxTUMwj9KxV0rr9ScQ+yVC4JtLcaL2MZqcAAAAAAAEBK6BoBgAAAAAAIlEgpS8ZlUOmmVyxMJGAP1hmbiBPdQR0+8T+wyBAL8/zSE2iFcHdjZ6JU4cV/kAqYBZLI/Lvd287mcuqJWh8STR2gK8CtbQk3qCfhAuTKgA3PNzb0lZQuMOs/lSp9KZBooZyG40m2seVdmu9oerqpF5b+gqVD91fTEqtpbHzCC7clom5/QruKKO4LErsvr03gSfciN0Z4eqT7bp6J7dU4ciB0wiHSnrESJVEt7hA0EVZnslBWuccywkMLEZcBcn6BfQcegbVIyBV9+vAqdnerl0m8q59t7wuCjI0UZRLLLk04e04TOm10KzAAAEFIPbUzhMkRN5/DjodK+mzjO7HmM+adu7qxYWGlEWDDrFnAQb9AwECwCIgUJKbdMGgSVS3i0tgNel6XgeKWg8o7JbVR7/ums6AOsCsA8AiIFCSm3TBoElUt4tLYDXpel4HiloPKOyW1Ue/7prOgDrBrAPAIiAiWLHDFgvghkpUGFTuyRZKVy8JT3ViYoKBqAc7uJFzp6wCwCIgUJKbdMGgSVS3i0tgNel6XgeKWg8o7JbVR7/ums6AOsKsA8AiIFCSm3TBoElUt4tLYDXpel4HiloPKOyW1Ue/7prOgDrDrATAIiBQkpt0waBJVLeLS2A16XpeB4paDyjsltVHv+6azoA6xKwEwCIgVffrwKnZ3q5dJvKufbe8LgoyNFGUSyy5NOHtOEzptdCsAA=="
+ },
+ {
+ "description": "Adds taproot output with internal key only and correct address",
+ "isTaproot": true,
+ "psbt": "cHNidP8BAFwCAAAAAk9Ve2845C8v//JR71uKzf70FjeNfx7SvB4l3A+Q44UKAAAAAAD/////FIp10hu+RPgTSFGPmjwb01Tf/a5UkcPFUpOw/X6UEPYAAAAAAP////8AAAAAAAABASugaAYAAAAAACJRINqadqaDhePTT29qdKQScUmyJxEeDw12HLjkMYMVSlnkARcgDN4bJzix3HdE8+FUM6UgA1lEKpgpIImVUePmAGYh7yYAAQDAAgAAAAFbIoaAJqDd/f4mZppgYV4UR9bgU8lT9pTH4/aDJdFUWgAAAABrSDBFAiEA6JS0xMdSQhG+9gAPSxGs6HazyauyNUBMwrmF386IAxwCIGiyH9QHCzKOBTtg+VsISF4nUi9NfAtJAtC02J03+I07ASEDu1tkEI8W1bd6qrPZ3uLaHvE90BDUvRCwvTTzPYPXzwf/////AaBoBgAAAAAAGXapFL5QEf51k4TA7Mp5d18IM2ddq79oiKwAAAAAAAA=",
+ "outputData": {
+ "tapInternalKey": "Buffer.from('884d969439deced21d1ab71ecd9ef9a6a8795215588ce7eff4ad5efc903e40ec', 'hex')",
+ "address": "bc1p74zfvfd7rndcn8lvzuec4hj4kzp9nnjvapvx5fgtqsegzz656hhsee8kwu",
+ "value": 410000
+ },
+ "result": "cHNidP8BAIcCAAAAAk9Ve2845C8v//JR71uKzf70FjeNfx7SvB4l3A+Q44UKAAAAAAD/////FIp10hu+RPgTSFGPmjwb01Tf/a5UkcPFUpOw/X6UEPYAAAAAAP////8BkEEGAAAAAAAiUSD1RJYlvhzbiZ/sFzOK3lWwglnOTOhYaiULBDKBC1TV7wAAAAAAAQEroGgGAAAAAAAiUSDamnamg4Xj009vanSkEnFJsicRHg8Ndhy45DGDFUpZ5AEXIAzeGyc4sdx3RPPhVDOlIANZRCqYKSCJlVHj5gBmIe8mAAEAwAIAAAABWyKGgCag3f3+JmaaYGFeFEfW4FPJU/aUx+P2gyXRVFoAAAAAa0gwRQIhAOiUtMTHUkIRvvYAD0sRrOh2s8mrsjVATMK5hd/OiAMcAiBosh/UBwsyjgU7YPlbCEheJ1IvTXwLSQLQtNidN/iNOwEhA7tbZBCPFtW3eqqz2d7i2h7xPdAQ1L0QsL008z2D188H/////wGgaAYAAAAAABl2qRS+UBH+dZOEwOzKeXdfCDNnXau/aIisAAAAAAABBSCITZaUOd7O0h0atx7NnvmmqHlSFViM5+/0rV78kD5A7AA="
+ },
+ {
+ "description": "Adds taproot output with internal key and bad address",
+ "isTaproot": true,
+ "psbt": "cHNidP8BAFwCAAAAAk9Ve2845C8v//JR71uKzf70FjeNfx7SvB4l3A+Q44UKAAAAAAD/////FIp10hu+RPgTSFGPmjwb01Tf/a5UkcPFUpOw/X6UEPYAAAAAAP////8AAAAAAAABASugaAYAAAAAACJRINqadqaDhePTT29qdKQScUmyJxEeDw12HLjkMYMVSlnkARcgDN4bJzix3HdE8+FUM6UgA1lEKpgpIImVUePmAGYh7yYAAQDAAgAAAAFbIoaAJqDd/f4mZppgYV4UR9bgU8lT9pTH4/aDJdFUWgAAAABrSDBFAiEA6JS0xMdSQhG+9gAPSxGs6HazyauyNUBMwrmF386IAxwCIGiyH9QHCzKOBTtg+VsISF4nUi9NfAtJAtC02J03+I07ASEDu1tkEI8W1bd6qrPZ3uLaHvE90BDUvRCwvTTzPYPXzwf/////AaBoBgAAAAAAGXapFL5QEf51k4TA7Mp5d18IM2ddq79oiKwAAAAAAAA=",
+ "outputData": {
+ "tapInternalKey": "Buffer.from('884d969439deced21d1ab71ecd9ef9a6a8795215588ce7eff4ad5efc903e40ec', 'hex')",
+ "address": "bc1p3efq8ujsj0qr5xvms7mv89p8cz0crqdtuxe9ms6grqgxc9sgsntslthf6w",
+ "value": 410000
+ },
+ "exception": "Error adding output. Script or address missmatch."
+ },
+ {
+ "description": "Adds taproot output with both taproot and non-taproot fields",
+ "isTaproot": true,
+ "psbt": "cHNidP8BAFwCAAAAAk9Ve2845C8v//JR71uKzf70FjeNfx7SvB4l3A+Q44UKAAAAAAD/////FIp10hu+RPgTSFGPmjwb01Tf/a5UkcPFUpOw/X6UEPYAAAAAAP////8AAAAAAAABASugaAYAAAAAACJRINqadqaDhePTT29qdKQScUmyJxEeDw12HLjkMYMVSlnkARcgDN4bJzix3HdE8+FUM6UgA1lEKpgpIImVUePmAGYh7yYAAQDAAgAAAAFbIoaAJqDd/f4mZppgYV4UR9bgU8lT9pTH4/aDJdFUWgAAAABrSDBFAiEA6JS0xMdSQhG+9gAPSxGs6HazyauyNUBMwrmF386IAxwCIGiyH9QHCzKOBTtg+VsISF4nUi9NfAtJAtC02J03+I07ASEDu1tkEI8W1bd6qrPZ3uLaHvE90BDUvRCwvTTzPYPXzwf/////AaBoBgAAAAAAGXapFL5QEf51k4TA7Mp5d18IM2ddq79oiKwAAAAAAAA=",
+ "outputData": {
+ "tapInternalKey": "Buffer.from('884d969439deced21d1ab71ecd9ef9a6a8795215588ce7eff4ad5efc903e40ec', 'hex')",
+ "redeemScript": "Buffer.from('5221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae', 'hex')",
+ "value": 410000
+ },
+ "exception": "Invalid arguments for Psbt.addOutput. Cannot use both taproot and non-taproot fields."
}
]
},
@@ -609,7 +708,9 @@
"description": "allows signing non-whitelisted sighashtype when explicitly passed in",
"shouldSign": {
"psbt": "cHNidP8BADMBAAAAAYaq+PdOUY2PnV9kZKa82XlqrPByOqwH2TRg2+LQdqs2AAAAAAD/////AAAAAAAAAQEgAOH1BQAAAAAXqRSTNeWHqa9INvSnQ120SZeJc+6JSocBAwSBAAAAAQQWABQvLKRyDqYsPYImhD3eURpDGL10RwAA",
- "sighashTypes": [129],
+ "sighashTypes": [
+ 129
+ ],
"inputToCheck": 0,
"WIF": "KxnAnQh6UJBxLF8Weup77yn8tWhLHhDhnXeyJuzmmcZA5aRdMJni"
}
@@ -623,7 +724,6 @@
"WIF": "KypUz2y1jdgzM8HGDUx9DYLmyzd8EWhruvLX2J5iSL7MiAcc7dBG",
"result": "cHNidP8BAF4CAAAAAf17fGksrz9eKGx1nSU3RX4vcwr7bfNdQzPZ9dSEkWBcAAAAAAD/////AZBBBgAAAAAAIlEgPLBe/d3922lmXjTIt52b9NG1HFDC9jzPCTn111AG8TQAAAAAAAEBK6BoBgAAAAAAIlEgPLBe/d3922lmXjTIt52b9NG1HFDC9jzPCTn111AG8TQBE0AAqkKg+dq3eThMoqzjh214urhgUoGTgwHlNyyMQ2RwhfeRIhAp+m9mZwQoXOxK7p2ILjf2G5j28F9KMhMzH7bXARcgWzC4qnD37J3WaDEbZPRihBXdI0gN68BGutJykDcHR6wBGCDlDrX1cnzwZvmcyLBH8M6NiS9lk7JVwM58wZZVOzmuMwAA"
}
-
},
{
"description": "check taproot script-path signer found for the input",
@@ -756,4 +856,4 @@
"clone": {
"psbt": "cHNidP8BAKYCAAAAAlwKQ3suPWwEJ/zQ9sZsIioOcHKU1KoLMxlMNSXVIkEWAAAAAAD/////YYDJMap+mYgbTrCNAdpWHN+EkKvl+XYao/6co/EQfwMAAAAAAP////8CkF8BAAAAAAAWABRnPBAmVHz2HL+8/1U+QG5L2thjmjhKAAAAAAAAIgAg700yfFRyhWzQnPHIUb/XQqsjlpf4A0uw682pCVWuQ8IAAAAAAAEBKzB1AAAAAAAAIgAgth9oE4cDfC5aV58VgkW5CptHsIxppYzJV8C5kT6aTo8iAgNfNgnFnEPS9s4PY/I5bezpWiAEzQ4DRTASgdSdeMM06UgwRQIhALO0xRpuqP3aVkm+DPykrtqe6fPNSgNblp9K9MAwmtHJAiAHV5ZvZN8Vi49n/o9ISFyvtHsPXXPKqBxC9m2m2HlpYgEBBSMhA182CcWcQ9L2zg9j8jlt7OlaIATNDgNFMBKB1J14wzTprAABASuAOAEAAAAAACIAILYfaBOHA3wuWlefFYJFuQqbR7CMaaWMyVfAuZE+mk6PIgIDXzYJxZxD0vbOD2PyOW3s6VogBM0OA0UwEoHUnXjDNOlIMEUCIQC6XN6tpo9mYlZej4BXSSh5D1K6aILBfQ4WBWXUrISx6wIgVaxFUsz8y59xJ1V4sZ1qarHX9pZ+MJmLKbl2ZSadisoBAQUjIQNfNgnFnEPS9s4PY/I5bezpWiAEzQ4DRTASgdSdeMM06awAAAA="
}
-}
+}
\ No newline at end of file
diff --git a/test/integration/taproot.spec.ts b/test/integration/taproot.spec.ts
index e537cf075..ea676cc94 100644
--- a/test/integration/taproot.spec.ts
+++ b/test/integration/taproot.spec.ts
@@ -5,7 +5,7 @@ import { describe, it } from 'mocha';
import { regtestUtils } from './_regtest';
import * as bitcoin from '../..';
import { Taptree } from '../../src/types';
-import { toXOnly } from '../../src/psbt/bip371';
+import { toXOnly, tapTreeToList } from '../../src/psbt/bip371';
const rng = require('randombytes');
const regtest = regtestUtils.network;
@@ -231,7 +231,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
redeemVersion: 192,
};
- const { output, address, witness } = bitcoin.payments.p2tr({
+ const { output, witness } = bitcoin.payments.p2tr({
internalPubkey: toXOnly(internalKey.publicKey),
scriptTree,
redeem,
@@ -261,7 +261,19 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
],
});
- psbt.addOutput({ value: sendAmount, address: address! });
+ const sendInternalKey = bip32.fromSeed(rng(64), regtest);
+ const sendPubKey = toXOnly(sendInternalKey.publicKey);
+ const { address: sendAddress } = bitcoin.payments.p2tr({
+ internalPubkey: sendPubKey,
+ scriptTree: scriptTree,
+ network: regtest,
+ });
+
+ psbt.addOutput({
+ value: sendAmount,
+ tapInternalKey: sendPubKey,
+ tapTree: { leaves: tapTreeToList(scriptTree) },
+ });
psbt.signInput(0, leafKey);
psbt.finalizeInput(0);
@@ -272,7 +284,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
await regtestUtils.broadcast(hex);
await regtestUtils.verify({
txId: tx.getId(),
- address: address!,
+ address: sendAddress!,
vout: 0,
value: sendAmount,
});
diff --git a/test/psbt.spec.ts b/test/psbt.spec.ts
index d2026e9a6..21a0b1c29 100644
--- a/test/psbt.spec.ts
+++ b/test/psbt.spec.ts
@@ -621,7 +621,8 @@ describe(`Psbt`, () => {
describe('addOutput', () => {
fixtures.addOutput.checks.forEach(f => {
it(f.description, () => {
- const psbt = new Psbt();
+ if (f.isTaproot) initEccLib(ecc);
+ const psbt = f.psbt ? Psbt.fromBase64(f.psbt) : new Psbt();
if (f.exception) {
assert.throws(() => {
@@ -634,6 +635,9 @@ describe(`Psbt`, () => {
assert.doesNotThrow(() => {
psbt.addOutput(f.outputData as any);
});
+ if (f.result) {
+ assert.strictEqual(psbt.toBase64(), f.result);
+ }
assert.doesNotThrow(() => {
psbt.addOutputs([f.outputData as any]);
});
diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts
index 3800ef5db..8467a9bf7 100644
--- a/ts_src/psbt.ts
+++ b/ts_src/psbt.ts
@@ -13,6 +13,8 @@ import {
TransactionFromBuffer,
TapKeySig,
TapScriptSig,
+ TapInternalKey,
+ TapTree,
} from 'bip174/src/lib/interfaces';
import { checkForInput, checkForOutput } from 'bip174/src/lib/utils';
import { fromOutputScript, toOutputScript } from './address';
@@ -27,8 +29,11 @@ import {
tapScriptFinalizer,
serializeTaprootSignature,
isTaprootInput,
+ isTaprootOutput,
checkTaprootInputFields,
+ checkTaprootOutputFields,
tweakInternalPubKey,
+ getNewTaprootScriptAndAddress,
} from './psbt/bip371';
import {
witnessStackToScriptWitness,
@@ -311,11 +316,12 @@ export class Psbt {
!outputData ||
outputData.value === undefined ||
((outputData as any).address === undefined &&
- (outputData as any).script === undefined)
+ (outputData as any).script === undefined &&
+ (outputData as any).tapInternalKey === undefined)
) {
throw new Error(
`Invalid arguments for Psbt.addOutput. ` +
- `Requires single object with at least [script or address] and [value]`,
+ `Requires single object with at least [script, address or tapInternalKey] and [value]`,
);
}
checkInputsForPartialSig(this.data.inputs, 'addOutput');
@@ -325,6 +331,18 @@ export class Psbt {
const script = toOutputScript(address, network);
outputData = Object.assign(outputData, { script });
}
+
+ if (isTaprootOutput(outputData)) {
+ checkTaprootOutputFields(outputData, outputData, 'addOutput');
+ const scriptAndAddress = getNewTaprootScriptAndAddress(
+ outputData,
+ outputData,
+ this.opts.network,
+ );
+ if (scriptAndAddress)
+ outputData = Object.assign(outputData, scriptAndAddress);
+ }
+
const c = this.__CACHE;
this.data.addOutput(outputData);
c.__FEE = undefined;
@@ -1147,7 +1165,10 @@ interface PsbtOpts {
interface PsbtInputExtended extends PsbtInput, TransactionInput {}
-type PsbtOutputExtended = PsbtOutputExtendedAddress | PsbtOutputExtendedScript;
+type PsbtOutputExtended =
+ | PsbtOutputExtendedAddress
+ | PsbtOutputExtendedScript
+ | PsbtOutputExtendedTaproot;
interface PsbtOutputExtendedAddress extends PsbtOutput {
address: string;
@@ -1159,6 +1180,13 @@ interface PsbtOutputExtendedScript extends PsbtOutput {
value: number;
}
+interface PsbtOutputExtendedTaproot extends PsbtOutput {
+ tapInternalKey: TapInternalKey;
+ tapTree?: TapTree;
+ script?: Buffer;
+ value: number;
+}
+
interface HDSignerBase {
/**
* DER format compressed publicKey buffer
@@ -1361,6 +1389,7 @@ function checkFees(psbt: Psbt, cache: PsbtCache, opts: PsbtOpts): void {
}
function checkInputsForPartialSig(inputs: PsbtInput[], action: string): void {
+ // todo: add for taproot
inputs.forEach(input => {
let throws = false;
let pSigs: PartialSig[] = [];
diff --git a/ts_src/psbt/bip371.ts b/ts_src/psbt/bip371.ts
index 93569c491..6d3216fa1 100644
--- a/ts_src/psbt/bip371.ts
+++ b/ts_src/psbt/bip371.ts
@@ -1,9 +1,12 @@
import { Taptree, Tapleaf, isTapleaf, isTaptree } from '../types';
import {
PsbtInput,
+ PsbtOutput,
TapLeafScript,
TapScriptSig,
TapLeaf,
+ TapTree,
+ TapInternalKey,
} from 'bip174/src/lib/interfaces';
import {
@@ -18,6 +21,8 @@ import {
LEAF_VERSION_TAPSCRIPT,
MAX_TAPTREE_DEPTH,
} from '../payments/taprootutils';
+import { p2tr } from '../payments';
+import { Network } from '../networks';
export const toXOnly = (pubKey: Buffer) =>
pubKey.length === 32 ? pubKey : pubKey.slice(1, 33);
@@ -77,15 +82,71 @@ export function isTaprootInput(input: PsbtInput): boolean {
);
}
+export function isTaprootOutput(output: PsbtOutput, script?: Buffer): boolean {
+ return (
+ output &&
+ !!(
+ output.tapInternalKey ||
+ output.tapTree ||
+ (output.tapBip32Derivation && output.tapBip32Derivation.length) ||
+ (script && isP2TR(script))
+ )
+ );
+}
+
export function checkTaprootInputFields(
inputData: PsbtInput,
newInputData: PsbtInput,
action: string,
): void {
- checkMixedTaprootAndNonTaprootFields(inputData, newInputData, action);
+ checkMixedTaprootAndNonTaprootInputFields(inputData, newInputData, action);
checkIfTapLeafInTree(inputData, newInputData, action);
}
+export function checkTaprootOutputFields(
+ outputData: PsbtOutput,
+ newOutputData: PsbtOutput,
+ action: string,
+): void {
+ checkMixedTaprootAndNonTaprootOutputFields(outputData, newOutputData, action);
+}
+
+export function getNewTaprootScriptAndAddress(
+ outputData: PsbtOutput,
+ newOutputData: PsbtOutput,
+ network?: Network,
+): { script: Buffer; address: string } | undefined {
+ if (!newOutputData.tapTree && !newOutputData.tapInternalKey) return;
+ const tapInternalKey =
+ newOutputData.tapInternalKey || outputData.tapInternalKey;
+ const tapTree = newOutputData.tapTree || outputData.tapTree;
+ if (tapInternalKey) {
+ const { script, address } = getTaprootScriptAndAddress(
+ tapInternalKey,
+ tapTree,
+ network,
+ );
+ const { script: newScript } = newOutputData as any;
+ if (newScript && !newScript.equals(script))
+ throw new Error('Error adding output. Script or address missmatch.');
+ return { script, address };
+ }
+}
+
+function getTaprootScriptAndAddress(
+ tapInternalKey: TapInternalKey,
+ tapTree?: TapTree,
+ network?: Network,
+): { script: Buffer; address: string } {
+ const scriptTree = tapTree && tapTreeFromList(tapTree.leaves);
+ const { output, address } = p2tr({
+ internalPubkey: tapInternalKey,
+ scriptTree,
+ network,
+ });
+ return { script: output!, address: address! };
+}
+
export function tweakInternalPubKey(
inputIndex: number,
input: PsbtInput,
@@ -194,18 +255,37 @@ function instertLeafInTree(
if (rightSide) return [tree && tree[0], rightSide];
}
-function checkMixedTaprootAndNonTaprootFields(
- inputData: PsbtInput,
+function checkMixedTaprootAndNonTaprootInputFields(
+ inputData: PsbtOutput,
newInputData: PsbtInput,
action: string,
): void {
const isBadTaprootUpdate =
- isTaprootInput(inputData) && hasNonTaprootInputFields(newInputData);
+ isTaprootInput(inputData) && hasNonTaprootFields(newInputData);
+ const isBadNonTaprootUpdate =
+ hasNonTaprootFields(inputData) && isTaprootInput(newInputData);
+ const hasMixedFields =
+ inputData === newInputData &&
+ (isTaprootInput(newInputData) && hasNonTaprootFields(newInputData)); // todo: bad? use !===
+
+ if (isBadTaprootUpdate || isBadNonTaprootUpdate || hasMixedFields)
+ throw new Error(
+ `Invalid arguments for Psbt.${action}. ` +
+ `Cannot use both taproot and non-taproot fields.`,
+ );
+}
+function checkMixedTaprootAndNonTaprootOutputFields(
+ inputData: PsbtOutput,
+ newInputData: PsbtOutput,
+ action: string,
+): void {
+ const isBadTaprootUpdate =
+ isTaprootOutput(inputData) && hasNonTaprootFields(newInputData);
const isBadNonTaprootUpdate =
- hasNonTaprootInputFields(inputData) && isTaprootInput(newInputData);
+ hasNonTaprootFields(inputData) && isTaprootOutput(newInputData);
const hasMixedFields =
inputData === newInputData &&
- (isTaprootInput(newInputData) && hasNonTaprootInputFields(newInputData));
+ (isTaprootOutput(newInputData) && hasNonTaprootFields(newInputData));
if (isBadTaprootUpdate || isBadNonTaprootUpdate || hasMixedFields)
throw new Error(
@@ -320,13 +400,13 @@ function canFinalizeLeaf(
);
}
-function hasNonTaprootInputFields(input: PsbtInput): boolean {
+function hasNonTaprootFields(io: PsbtInput | PsbtOutput): boolean {
return (
- input &&
+ io &&
!!(
- input.redeemScript ||
- input.witnessScript ||
- (input.bip32Derivation && input.bip32Derivation.length)
+ io.redeemScript ||
+ io.witnessScript ||
+ (io.bip32Derivation && io.bip32Derivation.length)
)
);
}
From 8ca34c05daa9551bb9e882c34b2e91c8061ebece Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Wed, 25 May 2022 16:15:34 +0300
Subject: [PATCH 080/144] refactor: simplify `addOutput()` checks
---
src/psbt.d.ts | 10 ++-------
src/psbt.js | 23 +++++---------------
src/psbt/bip371.d.ts | 5 -----
src/psbt/bip371.js | 24 ++++++++-------------
test/fixtures/psbt.json | 24 +++++++--------------
test/integration/taproot.spec.ts | 2 ++
ts_src/psbt.ts | 36 +++++++-------------------------
ts_src/psbt/bip371.ts | 30 +++++++++++---------------
8 files changed, 45 insertions(+), 109 deletions(-)
diff --git a/src/psbt.d.ts b/src/psbt.d.ts
index 646edd5c0..4c622b31f 100644
--- a/src/psbt.d.ts
+++ b/src/psbt.d.ts
@@ -1,6 +1,6 @@
///
import { Psbt as PsbtBase } from 'bip174';
-import { KeyValue, PsbtGlobalUpdate, PsbtInput, PsbtInputUpdate, PsbtOutput, PsbtOutputUpdate, TapInternalKey, TapTree } from 'bip174/src/lib/interfaces';
+import { KeyValue, PsbtGlobalUpdate, PsbtInput, PsbtInputUpdate, PsbtOutput, PsbtOutputUpdate } from 'bip174/src/lib/interfaces';
import { Network } from './networks';
import { Transaction } from './transaction';
export interface TransactionInput {
@@ -125,7 +125,7 @@ interface PsbtOptsOptional {
}
interface PsbtInputExtended extends PsbtInput, TransactionInput {
}
-declare type PsbtOutputExtended = PsbtOutputExtendedAddress | PsbtOutputExtendedScript | PsbtOutputExtendedTaproot;
+declare type PsbtOutputExtended = PsbtOutputExtendedAddress | PsbtOutputExtendedScript;
interface PsbtOutputExtendedAddress extends PsbtOutput {
address: string;
value: number;
@@ -134,12 +134,6 @@ interface PsbtOutputExtendedScript extends PsbtOutput {
script: Buffer;
value: number;
}
-interface PsbtOutputExtendedTaproot extends PsbtOutput {
- tapInternalKey: TapInternalKey;
- tapTree?: TapTree;
- script?: Buffer;
- value: number;
-}
interface HDSignerBase {
/**
* DER format compressed publicKey buffer
diff --git a/src/psbt.js b/src/psbt.js
index ced6105ac..4e19eae8a 100644
--- a/src/psbt.js
+++ b/src/psbt.js
@@ -226,13 +226,11 @@ class Psbt {
arguments.length > 1 ||
!outputData ||
outputData.value === undefined ||
- (outputData.address === undefined &&
- outputData.script === undefined &&
- outputData.tapInternalKey === undefined)
+ (outputData.address === undefined && outputData.script === undefined)
) {
throw new Error(
`Invalid arguments for Psbt.addOutput. ` +
- `Requires single object with at least [script, address or tapInternalKey] and [value]`,
+ `Requires single object with at least [script or address] and [value]`,
);
}
checkInputsForPartialSig(this.data.inputs, 'addOutput');
@@ -242,20 +240,7 @@ class Psbt {
const script = (0, address_1.toOutputScript)(address, network);
outputData = Object.assign(outputData, { script });
}
- if ((0, bip371_1.isTaprootOutput)(outputData)) {
- (0, bip371_1.checkTaprootOutputFields)(
- outputData,
- outputData,
- 'addOutput',
- );
- const scriptAndAddress = (0, bip371_1.getNewTaprootScriptAndAddress)(
- outputData,
- outputData,
- this.opts.network,
- );
- if (scriptAndAddress)
- outputData = Object.assign(outputData, scriptAndAddress);
- }
+ (0, bip371_1.checkTaprootOutputFields)(outputData, outputData, 'addOutput');
const c = this.__CACHE;
this.data.addOutput(outputData);
c.__FEE = undefined;
@@ -899,6 +884,8 @@ class Psbt {
return this;
}
updateOutput(outputIndex, updateData) {
+ // const outputData = this.data.outputs[outputIndex];
+ // checkTaprootOutputFields(outputData, updateData, 'updateOutput');
this.data.updateOutput(outputIndex, updateData);
return this;
}
diff --git a/src/psbt/bip371.d.ts b/src/psbt/bip371.d.ts
index 411c7e3c3..b734c87f5 100644
--- a/src/psbt/bip371.d.ts
+++ b/src/psbt/bip371.d.ts
@@ -1,7 +1,6 @@
///
import { Taptree } from '../types';
import { PsbtInput, PsbtOutput, TapLeaf } from 'bip174/src/lib/interfaces';
-import { Network } from '../networks';
export declare const toXOnly: (pubKey: Buffer) => Buffer;
/**
* Default tapscript finalizer. It searches for the `tapLeafHashToFinalize` if provided.
@@ -20,10 +19,6 @@ export declare function isTaprootInput(input: PsbtInput): boolean;
export declare function isTaprootOutput(output: PsbtOutput, script?: Buffer): boolean;
export declare function checkTaprootInputFields(inputData: PsbtInput, newInputData: PsbtInput, action: string): void;
export declare function checkTaprootOutputFields(outputData: PsbtOutput, newOutputData: PsbtOutput, action: string): void;
-export declare function getNewTaprootScriptAndAddress(outputData: PsbtOutput, newOutputData: PsbtOutput, network?: Network): {
- script: Buffer;
- address: string;
-} | undefined;
export declare function tweakInternalPubKey(inputIndex: number, input: PsbtInput): Buffer;
/**
* Convert a binary tree to a BIP371 type list. Each element of the list is (according to BIP371):
diff --git a/src/psbt/bip371.js b/src/psbt/bip371.js
index 677f20fca..fbc7eb7e3 100644
--- a/src/psbt/bip371.js
+++ b/src/psbt/bip371.js
@@ -1,6 +1,6 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.tapTreeFromList = exports.tapTreeToList = exports.tweakInternalPubKey = exports.getNewTaprootScriptAndAddress = exports.checkTaprootOutputFields = exports.checkTaprootInputFields = exports.isTaprootOutput = exports.isTaprootInput = exports.serializeTaprootSignature = exports.tapScriptFinalizer = exports.toXOnly = void 0;
+exports.tapTreeFromList = exports.tapTreeToList = exports.tweakInternalPubKey = exports.checkTaprootOutputFields = exports.checkTaprootInputFields = exports.isTaprootOutput = exports.isTaprootInput = exports.serializeTaprootSignature = exports.tapScriptFinalizer = exports.toXOnly = void 0;
const types_1 = require('../types');
const psbtutils_1 = require('./psbtutils');
const taprootutils_1 = require('../payments/taprootutils');
@@ -72,34 +72,28 @@ function checkTaprootInputFields(inputData, newInputData, action) {
exports.checkTaprootInputFields = checkTaprootInputFields;
function checkTaprootOutputFields(outputData, newOutputData, action) {
checkMixedTaprootAndNonTaprootOutputFields(outputData, newOutputData, action);
+ checkTaprootScriptPubkey(outputData, newOutputData);
}
exports.checkTaprootOutputFields = checkTaprootOutputFields;
-function getNewTaprootScriptAndAddress(outputData, newOutputData, network) {
+function checkTaprootScriptPubkey(outputData, newOutputData) {
if (!newOutputData.tapTree && !newOutputData.tapInternalKey) return;
const tapInternalKey =
newOutputData.tapInternalKey || outputData.tapInternalKey;
const tapTree = newOutputData.tapTree || outputData.tapTree;
if (tapInternalKey) {
- const { script, address } = getTaprootScriptAndAddress(
- tapInternalKey,
- tapTree,
- network,
- );
- const { script: newScript } = newOutputData;
- if (newScript && !newScript.equals(script))
+ const { script: scriptPubkey } = outputData;
+ const script = getTaprootScripPubkey(tapInternalKey, tapTree);
+ if (scriptPubkey && !scriptPubkey.equals(script))
throw new Error('Error adding output. Script or address missmatch.');
- return { script, address };
}
}
-exports.getNewTaprootScriptAndAddress = getNewTaprootScriptAndAddress;
-function getTaprootScriptAndAddress(tapInternalKey, tapTree, network) {
+function getTaprootScripPubkey(tapInternalKey, tapTree) {
const scriptTree = tapTree && tapTreeFromList(tapTree.leaves);
- const { output, address } = (0, payments_1.p2tr)({
+ const { output } = (0, payments_1.p2tr)({
internalPubkey: tapInternalKey,
scriptTree,
- network,
});
- return { script: output, address: address };
+ return output;
}
function tweakInternalPubKey(inputIndex, input) {
const tapInternalKey = input.tapInternalKey;
diff --git a/test/fixtures/psbt.json b/test/fixtures/psbt.json
index f2c990a8e..b35bef2f4 100644
--- a/test/fixtures/psbt.json
+++ b/test/fixtures/psbt.json
@@ -506,7 +506,7 @@
"outputData": {
"value": 1000
},
- "exception": "Invalid arguments for Psbt\\.addOutput. Requires single object with at least \\[script, address or tapInternalKey\\] and \\[value\\]"
+ "exception": "Invalid arguments for Psbt\\.addOutput. Requires single object with at least \\[script or address\\] and \\[value\\]"
},
{
"description": "Adds output normally",
@@ -516,20 +516,12 @@
}
},
{
- "description": "Adds taproot output with internal key only (address derived)",
- "isTaproot": true,
- "psbt": "cHNidP8BAFwCAAAAAo6LlrlIROHUfunj2OPeOpJlw/sG4cG99LrNl88u7rcrAAAAAAD/////LR6UXz/GymI8bcsv2b+NIzWKT/d9cEUPwWHREjtSapcAAAAAAP////8AAAAAAAABASugaAYAAAAAACJRIAkRWDXSsncord4FtaUxPSWLua73cQbIN0uq2qyWztP3ARcgAqgH8rOX0SzoemaM+YlCy9DYeU1w9CrcR7Vm5/PPlxYAAQDAAgAAAAG67fXBoOPSqNrW6dbIkadKg+T6+tnU2pqoCSiOxyVdhQAAAABrSDBFAiEA9sK/dshQbR7W58jOzsH069Ms5C7Q4b0CDiDB//7BccECICDpjneIIw2Wgr9fq7VvqZfOgghSlXjiMaVr1Qqkb4qUASEC/r+CrU8sH0Jy0FIrGL6XQ8p0tDVOfnVpl6M6NKkwqZT/////AaBoBgAAAAAAGXapFLuFzFEeVsEgi+khfH7+Tc7+AvKBiKwAAAAAAAA=",
- "outputData": {
- "tapInternalKey": "Buffer.from('1a954a44837e47815f7285eae2dc3716f98eafb41a1155e999bfa66853b2cc47', 'hex')",
- "value": 410000
- },
- "result": "cHNidP8BAIcCAAAAAo6LlrlIROHUfunj2OPeOpJlw/sG4cG99LrNl88u7rcrAAAAAAD/////LR6UXz/GymI8bcsv2b+NIzWKT/d9cEUPwWHREjtSapcAAAAAAP////8BkEEGAAAAAAAiUSCTYMKBNf5sZR1VO8dJdu2z5lO0vHqjXMjmOYotibmHLwAAAAAAAQEroGgGAAAAAAAiUSAJEVg10rJ3KK3eBbWlMT0li7mu93EGyDdLqtqsls7T9wEXIAKoB/Kzl9Es6HpmjPmJQsvQ2HlNcPQq3Ee1Zufzz5cWAAEAwAIAAAABuu31waDj0qja1unWyJGnSoPk+vrZ1NqaqAkojsclXYUAAAAAa0gwRQIhAPbCv3bIUG0e1ufIzs7B9OvTLOQu0OG9Ag4gwf/+wXHBAiAg6Y53iCMNloK/X6u1b6mXzoIIUpV44jGla9UKpG+KlAEhAv6/gq1PLB9CctBSKxi+l0PKdLQ1Tn51aZejOjSpMKmU/////wGgaAYAAAAAABl2qRS7hcxRHlbBIIvpIXx+/k3O/gLygYisAAAAAAABBSAalUpEg35HgV9yheri3DcW+Y6vtBoRVemZv6ZoU7LMRwA="
- },
- {
- "description": "Adds taproot output with internal key and tap tree (address derived)",
+ "description": "Adds taproot output with internal key and tap tree",
"isTaproot": true,
"psbt": "cHNidP8BADMCAAAAAcbgSGx76du9GXsr4c6Yk7DFglfHi7M2jdCNUXwc+Q+EAAAAAAD/////AAAAAAAAAQEroGgGAAAAAAAiUSClLxmVQ6aZXLEwkYA/WGZuIE91BHT7xP7DIEAvz/NITaIVwd2NnolThxX+QCpgFksj8u93bzuZy6olaHxJNHaArwK1tCTeoJ+EC5MqADc83NvSVlC4w6z+VKn0pkGihnIbjSbax5V2a72h6uqkXlv6CpUP3V9MSq2lsfMILtyWibn9Cu4oo7gsSuy+vTeBJ9yI3Rnh6pPtunont1ThyIHTCIdKesRIlUS3uEDQRVmeyUFa5xzLCQwsRlwFyfoF9Bx6BtUjIFX368Cp2d6uXSbyrn23vC4KMjRRlEssuTTh7ThM6bXQrMAAAA==",
"outputData": {
+ "address": "bc1px4ssshedlz4jc56ses3lftz462a06jwy8my4pwpx6twx30vvv6nsgwcpu3",
+ "value": 410000,
"tapInternalKey": "Buffer.from('f6d4ce132444de7f0e3a1d2be9b38ceec798cf9a76eeeac585869445830eb167', 'hex')",
"tapTree": {
"leaves": [
@@ -569,8 +561,7 @@
"script": "Buffer.from('2055f7ebc0a9d9deae5d26f2ae7db7bc2e0a323451944b2cb934e1ed384ce9b5d0ac', 'hex')"
}
]
- },
- "value": 410000
+ }
},
"result": "cHNidP8BAF4CAAAAAcbgSGx76du9GXsr4c6Yk7DFglfHi7M2jdCNUXwc+Q+EAAAAAAD/////AZBBBgAAAAAAIlEgNWEIXy34qyxTUMwj9KxV0rr9ScQ+yVC4JtLcaL2MZqcAAAAAAAEBK6BoBgAAAAAAIlEgpS8ZlUOmmVyxMJGAP1hmbiBPdQR0+8T+wyBAL8/zSE2iFcHdjZ6JU4cV/kAqYBZLI/Lvd287mcuqJWh8STR2gK8CtbQk3qCfhAuTKgA3PNzb0lZQuMOs/lSp9KZBooZyG40m2seVdmu9oerqpF5b+gqVD91fTEqtpbHzCC7clom5/QruKKO4LErsvr03gSfciN0Z4eqT7bp6J7dU4ciB0wiHSnrESJVEt7hA0EVZnslBWuccywkMLEZcBcn6BfQcegbVIyBV9+vAqdnerl0m8q59t7wuCjI0UZRLLLk04e04TOm10KzAAAEFIPbUzhMkRN5/DjodK+mzjO7HmM+adu7qxYWGlEWDDrFnAQb9AwECwCIgUJKbdMGgSVS3i0tgNel6XgeKWg8o7JbVR7/ums6AOsCsA8AiIFCSm3TBoElUt4tLYDXpel4HiloPKOyW1Ue/7prOgDrBrAPAIiAiWLHDFgvghkpUGFTuyRZKVy8JT3ViYoKBqAc7uJFzp6wCwCIgUJKbdMGgSVS3i0tgNel6XgeKWg8o7JbVR7/ums6AOsKsA8AiIFCSm3TBoElUt4tLYDXpel4HiloPKOyW1Ue/7prOgDrDrATAIiBQkpt0waBJVLeLS2A16XpeB4paDyjsltVHv+6azoA6xKwEwCIgVffrwKnZ3q5dJvKufbe8LgoyNFGUSyy5NOHtOEzptdCsAA=="
},
@@ -601,9 +592,10 @@
"isTaproot": true,
"psbt": "cHNidP8BAFwCAAAAAk9Ve2845C8v//JR71uKzf70FjeNfx7SvB4l3A+Q44UKAAAAAAD/////FIp10hu+RPgTSFGPmjwb01Tf/a5UkcPFUpOw/X6UEPYAAAAAAP////8AAAAAAAABASugaAYAAAAAACJRINqadqaDhePTT29qdKQScUmyJxEeDw12HLjkMYMVSlnkARcgDN4bJzix3HdE8+FUM6UgA1lEKpgpIImVUePmAGYh7yYAAQDAAgAAAAFbIoaAJqDd/f4mZppgYV4UR9bgU8lT9pTH4/aDJdFUWgAAAABrSDBFAiEA6JS0xMdSQhG+9gAPSxGs6HazyauyNUBMwrmF386IAxwCIGiyH9QHCzKOBTtg+VsISF4nUi9NfAtJAtC02J03+I07ASEDu1tkEI8W1bd6qrPZ3uLaHvE90BDUvRCwvTTzPYPXzwf/////AaBoBgAAAAAAGXapFL5QEf51k4TA7Mp5d18IM2ddq79oiKwAAAAAAAA=",
"outputData": {
+ "address": "bc1px4ssshedlz4jc56ses3lftz462a06jwy8my4pwpx6twx30vvv6nsgwcpu3",
+ "value": 410000,
"tapInternalKey": "Buffer.from('884d969439deced21d1ab71ecd9ef9a6a8795215588ce7eff4ad5efc903e40ec', 'hex')",
- "redeemScript": "Buffer.from('5221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae', 'hex')",
- "value": 410000
+ "redeemScript": "Buffer.from('5221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae', 'hex')"
},
"exception": "Invalid arguments for Psbt.addOutput. Cannot use both taproot and non-taproot fields."
}
diff --git a/test/integration/taproot.spec.ts b/test/integration/taproot.spec.ts
index ea676cc94..80a1160db 100644
--- a/test/integration/taproot.spec.ts
+++ b/test/integration/taproot.spec.ts
@@ -93,6 +93,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
psbt.addOutput({
value: sendAmount,
+ address: sendAddress!,
tapInternalKey: sendPubKey,
});
@@ -271,6 +272,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
psbt.addOutput({
value: sendAmount,
+ address: sendAddress!,
tapInternalKey: sendPubKey,
tapTree: { leaves: tapTreeToList(scriptTree) },
});
diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts
index 8467a9bf7..802840b37 100644
--- a/ts_src/psbt.ts
+++ b/ts_src/psbt.ts
@@ -13,8 +13,6 @@ import {
TransactionFromBuffer,
TapKeySig,
TapScriptSig,
- TapInternalKey,
- TapTree,
} from 'bip174/src/lib/interfaces';
import { checkForInput, checkForOutput } from 'bip174/src/lib/utils';
import { fromOutputScript, toOutputScript } from './address';
@@ -29,11 +27,9 @@ import {
tapScriptFinalizer,
serializeTaprootSignature,
isTaprootInput,
- isTaprootOutput,
checkTaprootInputFields,
checkTaprootOutputFields,
tweakInternalPubKey,
- getNewTaprootScriptAndAddress,
} from './psbt/bip371';
import {
witnessStackToScriptWitness,
@@ -316,12 +312,11 @@ export class Psbt {
!outputData ||
outputData.value === undefined ||
((outputData as any).address === undefined &&
- (outputData as any).script === undefined &&
- (outputData as any).tapInternalKey === undefined)
+ (outputData as any).script === undefined)
) {
throw new Error(
`Invalid arguments for Psbt.addOutput. ` +
- `Requires single object with at least [script, address or tapInternalKey] and [value]`,
+ `Requires single object with at least [script or address] and [value]`,
);
}
checkInputsForPartialSig(this.data.inputs, 'addOutput');
@@ -331,17 +326,7 @@ export class Psbt {
const script = toOutputScript(address, network);
outputData = Object.assign(outputData, { script });
}
-
- if (isTaprootOutput(outputData)) {
- checkTaprootOutputFields(outputData, outputData, 'addOutput');
- const scriptAndAddress = getNewTaprootScriptAndAddress(
- outputData,
- outputData,
- this.opts.network,
- );
- if (scriptAndAddress)
- outputData = Object.assign(outputData, scriptAndAddress);
- }
+ checkTaprootOutputFields(outputData, outputData, 'addOutput');
const c = this.__CACHE;
this.data.addOutput(outputData);
@@ -1117,6 +1102,9 @@ export class Psbt {
}
updateOutput(outputIndex: number, updateData: PsbtOutputUpdate): this {
+ // const outputData = this.data.outputs[outputIndex];
+ // checkTaprootOutputFields(outputData, updateData, 'updateOutput');
+
this.data.updateOutput(outputIndex, updateData);
return this;
}
@@ -1165,10 +1153,7 @@ interface PsbtOpts {
interface PsbtInputExtended extends PsbtInput, TransactionInput {}
-type PsbtOutputExtended =
- | PsbtOutputExtendedAddress
- | PsbtOutputExtendedScript
- | PsbtOutputExtendedTaproot;
+type PsbtOutputExtended = PsbtOutputExtendedAddress | PsbtOutputExtendedScript;
interface PsbtOutputExtendedAddress extends PsbtOutput {
address: string;
@@ -1180,13 +1165,6 @@ interface PsbtOutputExtendedScript extends PsbtOutput {
value: number;
}
-interface PsbtOutputExtendedTaproot extends PsbtOutput {
- tapInternalKey: TapInternalKey;
- tapTree?: TapTree;
- script?: Buffer;
- value: number;
-}
-
interface HDSignerBase {
/**
* DER format compressed publicKey buffer
diff --git a/ts_src/psbt/bip371.ts b/ts_src/psbt/bip371.ts
index 6d3216fa1..64de6c2d2 100644
--- a/ts_src/psbt/bip371.ts
+++ b/ts_src/psbt/bip371.ts
@@ -22,7 +22,6 @@ import {
MAX_TAPTREE_DEPTH,
} from '../payments/taprootutils';
import { p2tr } from '../payments';
-import { Network } from '../networks';
export const toXOnly = (pubKey: Buffer) =>
pubKey.length === 32 ? pubKey : pubKey.slice(1, 33);
@@ -109,42 +108,37 @@ export function checkTaprootOutputFields(
action: string,
): void {
checkMixedTaprootAndNonTaprootOutputFields(outputData, newOutputData, action);
+ checkTaprootScriptPubkey(outputData, newOutputData);
}
-export function getNewTaprootScriptAndAddress(
+function checkTaprootScriptPubkey(
outputData: PsbtOutput,
newOutputData: PsbtOutput,
- network?: Network,
-): { script: Buffer; address: string } | undefined {
+): void {
if (!newOutputData.tapTree && !newOutputData.tapInternalKey) return;
+
const tapInternalKey =
newOutputData.tapInternalKey || outputData.tapInternalKey;
const tapTree = newOutputData.tapTree || outputData.tapTree;
+
if (tapInternalKey) {
- const { script, address } = getTaprootScriptAndAddress(
- tapInternalKey,
- tapTree,
- network,
- );
- const { script: newScript } = newOutputData as any;
- if (newScript && !newScript.equals(script))
+ const { script: scriptPubkey } = outputData as any;
+ const script = getTaprootScripPubkey(tapInternalKey, tapTree);
+ if (scriptPubkey && !scriptPubkey.equals(script))
throw new Error('Error adding output. Script or address missmatch.');
- return { script, address };
}
}
-function getTaprootScriptAndAddress(
+function getTaprootScripPubkey(
tapInternalKey: TapInternalKey,
tapTree?: TapTree,
- network?: Network,
-): { script: Buffer; address: string } {
+): Buffer {
const scriptTree = tapTree && tapTreeFromList(tapTree.leaves);
- const { output, address } = p2tr({
+ const { output } = p2tr({
internalPubkey: tapInternalKey,
scriptTree,
- network,
});
- return { script: output!, address: address! };
+ return output!;
}
export function tweakInternalPubKey(
From e17e2bd298de6f4e169dbed66d81715581696bd5 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Wed, 25 May 2022 17:23:22 +0300
Subject: [PATCH 081/144] feat: do taproot checks for `updateOutput()`
---
src/psbt.js | 8 ++++++--
test/fixtures/psbt.json | 30 ++++++++++++++++++++++++++++++
test/integration/taproot.spec.ts | 20 +++++++++++++++++---
test/psbt.spec.ts | 1 +
ts_src/psbt.ts | 4 ++--
5 files changed, 56 insertions(+), 7 deletions(-)
diff --git a/src/psbt.js b/src/psbt.js
index 4e19eae8a..e0c8a1af2 100644
--- a/src/psbt.js
+++ b/src/psbt.js
@@ -884,8 +884,12 @@ class Psbt {
return this;
}
updateOutput(outputIndex, updateData) {
- // const outputData = this.data.outputs[outputIndex];
- // checkTaprootOutputFields(outputData, updateData, 'updateOutput');
+ const outputData = this.data.outputs[outputIndex];
+ (0, bip371_1.checkTaprootOutputFields)(
+ outputData,
+ updateData,
+ 'updateOutput',
+ );
this.data.updateOutput(outputIndex, updateData);
return this;
}
diff --git a/test/fixtures/psbt.json b/test/fixtures/psbt.json
index b35bef2f4..b213d98f8 100644
--- a/test/fixtures/psbt.json
+++ b/test/fixtures/psbt.json
@@ -247,6 +247,36 @@
}
],
"result": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEDBAEAAAABBCIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQVHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4iBgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8OcxDZDGpPAAAAgAAAAIADAACAIgYDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwQ2QxqTwAAAIAAAACAAgAAgAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA"
+ },
+ {
+ "description": "Update taproot output",
+ "isTaproot": true,
+ "psbt": "cHNidP8BAF4CAAAAAbc48X2AGPRzFoMvXHqldFViBB89ZrPfTH6yxr42pJsWAAAAAAAKAAAAAZBBBgAAAAAAIlEgwjn5jxVDmCN6B+wTPt4zCjlF+5KOEDapZ4S9Y3HZxdwAAAAAAAEBK6BoBgAAAAAAIlEgOJumKbXWO2VGchS5k1l1NzOsAyg8aBVQbDNJ88BPtH5iFcF6ESg3Xx4VxbYhRfEEyJc6dumg3zlxfNO8piELt1JMShpSnJ+zzX53bWG2IltsYQ6JBvuPqmxZrFw+lbX4LSnWGlKcn7PNfndtYbYiW2xhDokG+4+qbFmsXD6VtfgtKdYmWrJ1IAOmFFKDvSwulomGXZP6LYOYOGBHzSRnrh2w9cb0vzIGrMAAAA==",
+ "outputData": [
+ {
+ "tapInternalKey": "Buffer.from('b3310106b13af5def8fc341fe7120e844ab73d4437649aefcadd306d974c9958', 'hex')",
+ "tapTree": {
+ "leaves": [
+ {
+ "depth": 1,
+ "leafVersion": 192,
+ "script": "Buffer.from('2050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0ac', 'hex')"
+ },
+ {
+ "depth": 2,
+ "leafVersion": 192,
+ "script": "Buffer.from('2050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0ac', 'hex')"
+ },
+ {
+ "depth": 2,
+ "leafVersion": 192,
+ "script": "Buffer.from('5ab2752003a6145283bd2c2e9689865d93fa2d8398386047cd2467ae1db0f5c6f4bf3206ac', 'hex')"
+ }
+ ]
+ }
+ }
+ ],
+ "result": "cHNidP8BAF4CAAAAAbc48X2AGPRzFoMvXHqldFViBB89ZrPfTH6yxr42pJsWAAAAAAAKAAAAAZBBBgAAAAAAIlEgwjn5jxVDmCN6B+wTPt4zCjlF+5KOEDapZ4S9Y3HZxdwAAAAAAAEBK6BoBgAAAAAAIlEgOJumKbXWO2VGchS5k1l1NzOsAyg8aBVQbDNJ88BPtH5iFcF6ESg3Xx4VxbYhRfEEyJc6dumg3zlxfNO8piELt1JMShpSnJ+zzX53bWG2IltsYQ6JBvuPqmxZrFw+lbX4LSnWGlKcn7PNfndtYbYiW2xhDokG+4+qbFmsXD6VtfgtKdYmWrJ1IAOmFFKDvSwulomGXZP6LYOYOGBHzSRnrh2w9cb0vzIGrMAAAQUgszEBBrE69d74/DQf5xIOhEq3PUQ3ZJrvyt0wbZdMmVgBBnIBwCIgUJKbdMGgSVS3i0tgNel6XgeKWg8o7JbVR7/ums6AOsCsAsAiIFCSm3TBoElUt4tLYDXpel4HiloPKOyW1Ue/7prOgDrArALAJVqydSADphRSg70sLpaJhl2T+i2DmDhgR80kZ64dsPXG9L8yBqwA"
}
],
"signer": [
diff --git a/test/integration/taproot.spec.ts b/test/integration/taproot.spec.ts
index 80a1160db..2707462ca 100644
--- a/test/integration/taproot.spec.ts
+++ b/test/integration/taproot.spec.ts
@@ -322,7 +322,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
redeemVersion: 192,
};
- const { output, address, witness } = bitcoin.payments.p2tr({
+ const { output, witness } = bitcoin.payments.p2tr({
internalPubkey: toXOnly(internalKey.publicKey),
scriptTree,
redeem,
@@ -352,7 +352,21 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
},
],
});
- psbt.addOutput({ value: sendAmount, address: address! });
+
+ const sendInternalKey = bip32.fromSeed(rng(64), regtest);
+ const sendPubKey = toXOnly(sendInternalKey.publicKey);
+ const { address: sendAddress } = bitcoin.payments.p2tr({
+ internalPubkey: sendPubKey,
+ scriptTree: scriptTree,
+ network: regtest,
+ });
+
+ psbt.addOutput({ value: sendAmount, address: sendAddress! });
+ // just to test that updateOutput works as expected
+ psbt.updateOutput(0, {
+ tapInternalKey: sendPubKey,
+ tapTree: { leaves: tapTreeToList(scriptTree) },
+ });
await psbt.signInputAsync(0, leafKey);
@@ -376,7 +390,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
await regtestUtils.broadcast(hex);
await regtestUtils.verify({
txId: tx.getId(),
- address: address!,
+ address: sendAddress!,
vout: 0,
value: sendAmount,
});
diff --git a/test/psbt.spec.ts b/test/psbt.spec.ts
index 21a0b1c29..bbddb67c8 100644
--- a/test/psbt.spec.ts
+++ b/test/psbt.spec.ts
@@ -132,6 +132,7 @@ describe(`Psbt`, () => {
fixtures.bip174.updater.forEach(f => {
it('Updates PSBT to the expected result', () => {
+ if (f.isTaproot) initEccLib(ecc);
const psbt = Psbt.fromBase64(f.psbt);
for (const inputOrOutput of ['input', 'output']) {
diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts
index 802840b37..93637772a 100644
--- a/ts_src/psbt.ts
+++ b/ts_src/psbt.ts
@@ -1102,8 +1102,8 @@ export class Psbt {
}
updateOutput(outputIndex: number, updateData: PsbtOutputUpdate): this {
- // const outputData = this.data.outputs[outputIndex];
- // checkTaprootOutputFields(outputData, updateData, 'updateOutput');
+ const outputData = this.data.outputs[outputIndex];
+ checkTaprootOutputFields(outputData, updateData, 'updateOutput');
this.data.updateOutput(outputIndex, updateData);
return this;
From 057cdc55aef57143aa57d48ae36e0ffc9067e745 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Thu, 26 May 2022 14:47:58 +0300
Subject: [PATCH 082/144] feat: check if taproot signature are present before
allowing psbt changes
---
src/psbt.js | 102 +++++++++++++++++++++++----------
test/fixtures/psbt.json | 30 ++++++++++
ts_src/psbt.ts | 124 ++++++++++++++++++++++++++++++----------
3 files changed, 195 insertions(+), 61 deletions(-)
diff --git a/src/psbt.js b/src/psbt.js
index e0c8a1af2..2e58596dc 100644
--- a/src/psbt.js
+++ b/src/psbt.js
@@ -1035,41 +1035,81 @@ function checkFees(psbt, cache, opts) {
}
}
function checkInputsForPartialSig(inputs, action) {
- // todo: add for taproot
inputs.forEach(input => {
- let throws = false;
- let pSigs = [];
- if ((input.partialSig || []).length === 0) {
- if (!input.finalScriptSig && !input.finalScriptWitness) return;
- pSigs = getPsigsFromInputFinalScripts(input);
- } else {
- pSigs = input.partialSig;
- }
- pSigs.forEach(pSig => {
- const { hashType } = bscript.signature.decode(pSig.signature);
- const whitelist = [];
- const isAnyoneCanPay =
- hashType & transaction_1.Transaction.SIGHASH_ANYONECANPAY;
- if (isAnyoneCanPay) whitelist.push('addInput');
- const hashMod = hashType & 0x1f;
- switch (hashMod) {
- case transaction_1.Transaction.SIGHASH_ALL:
- break;
- case transaction_1.Transaction.SIGHASH_SINGLE:
- case transaction_1.Transaction.SIGHASH_NONE:
- whitelist.push('addOutput');
- whitelist.push('setInputSequence');
- break;
- }
- if (whitelist.indexOf(action) === -1) {
- throws = true;
- }
- });
- if (throws) {
+ const throws = (0, bip371_1.isTaprootInput)(input)
+ ? checkTaprootInputForSigs(input, action)
+ : checkInputForSig(input, action);
+ if (throws)
throw new Error('Can not modify transaction, signatures exist.');
- }
});
}
+function checkInputForSig(input, action) {
+ const pSigs = extractPartialSigs(input);
+ return pSigs.some(pSig =>
+ signatureBlocksAction(pSig, bscript.signature.decode, action),
+ );
+}
+function checkTaprootInputForSigs(input, action) {
+ const sigs = extractTaprootSigs(input);
+ return sigs.some(sig =>
+ signatureBlocksAction(sig, decodeSchnorSignature, action),
+ );
+}
+function decodeSchnorSignature(signature) {
+ return {
+ signature: signature.slice(0, 64),
+ hashType:
+ signature.slice(64)[0] || transaction_1.Transaction.SIGHASH_DEFAULT,
+ };
+}
+function extractTaprootSigs(input) {
+ const sigs = [];
+ if (input.tapKeySig) sigs.push(input.tapKeySig);
+ if (input.tapScriptSig)
+ sigs.push(...input.tapScriptSig.map(s => s.signature));
+ if (!sigs.length) {
+ const finalTapKeySig = getTapKeySigFromWithness(input.finalScriptWitness);
+ if (finalTapKeySig) sigs.push(finalTapKeySig);
+ }
+ return sigs;
+}
+function getTapKeySigFromWithness(finalScriptWitness) {
+ if (!finalScriptWitness) return;
+ const witness = finalScriptWitness.slice(2);
+ // todo: add schnor signature validation
+ if (witness.length === 64 || witness.length === 65) return witness;
+}
+function extractPartialSigs(input) {
+ let pSigs = [];
+ if ((input.partialSig || []).length === 0) {
+ if (!input.finalScriptSig && !input.finalScriptWitness) return [];
+ pSigs = getPsigsFromInputFinalScripts(input);
+ } else {
+ pSigs = input.partialSig;
+ }
+ return pSigs.map(p => p.signature);
+}
+function signatureBlocksAction(signature, signatureDecodeFn, action) {
+ const { hashType } = signatureDecodeFn(signature);
+ const whitelist = [];
+ const isAnyoneCanPay =
+ hashType & transaction_1.Transaction.SIGHASH_ANYONECANPAY;
+ if (isAnyoneCanPay) whitelist.push('addInput');
+ const hashMod = hashType & 0x1f;
+ switch (hashMod) {
+ case transaction_1.Transaction.SIGHASH_ALL:
+ break;
+ case transaction_1.Transaction.SIGHASH_SINGLE:
+ case transaction_1.Transaction.SIGHASH_NONE:
+ whitelist.push('addOutput');
+ whitelist.push('setInputSequence');
+ break;
+ }
+ if (whitelist.indexOf(action) === -1) {
+ return true;
+ }
+ return false;
+}
function checkPartialSigSighashes(input) {
if (!input.sighashType || !input.partialSig) return;
const { partialSig, sighashType } = input;
diff --git a/test/fixtures/psbt.json b/test/fixtures/psbt.json
index b213d98f8..815bcb9df 100644
--- a/test/fixtures/psbt.json
+++ b/test/fixtures/psbt.json
@@ -628,6 +628,36 @@
"redeemScript": "Buffer.from('5221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae', 'hex')"
},
"exception": "Invalid arguments for Psbt.addOutput. Cannot use both taproot and non-taproot fields."
+ },
+ {
+ "description": "Adds output after tapkey signature has been added",
+ "isTaproot": true,
+ "psbt": "cHNidP8BAIcCAAAAAvz6EyMK2VQ0DFKWZyIyGZLZCnaIDtG5RI55OrGVs6u7AAAAAAD/////oB9A2l2NN5WPNjBDaRsz9Nmla1WdM3jl96ElSV5WWHMAAAAAAP////8BkEEGAAAAAAAiUSCnucwjGG2x9zGqP+E0PwxTkptd/9AYMW12ch7ffaogBAAAAAAAAQEroGgGAAAAAAAiUSDbRhL5phuWYLyqKbSqVb/Pic2mpPL46idVKQur9i06ugETQOPidQWL9dHDxd819Pn5QNNGyH0fmDv58pexSJVDalZ0W/HPVliPFZy7s//0TfTbvFce87/nKXcrwz5YuItIY6cBFyAOgJIoTQyYcpAqNfsK9CutgWckFE3mBMgpL50lKXb7oQABAL8CAAAAAcdkwPNWdYy1O8QM1xRkrJjas72QGQPEanYEpv6iT3PXAAAAAGpHMEQCIFpl6Nx8hoZA1o5Huo958RS/Hndy+DloLhp0nvRyBzN8AiB9jEbitThSs6TZ1XVBHZebj4nZbLMg3CCtss8WSZpv7QEhA+VxIxwCWeqoeDMYcEw3EC0ZPxIkOqt0YSK9Y3hAKTd1/////wGgaAYAAAAAABl2qRS9gA7n636cw49cUBJWm7IDJPKuuoisAAAAACICAknGKVC7w5Ek4l3IK5XCUwLNCeU4DD+76cdMAYDB72g3RzBEAiAjekFbBddaHY/LZidwKd3sBbifjmbEpka2Ps0B2Crg+wIgUoN4BhGCwMRTDaHbAX+0MXSGYA9nSlqeQJXpWQRCBfQBAAEFIE6DvlLK0f4BrtpMgez01WQYKLUQZ8HtbfuDPD52hmSvAA==",
+ "outputData": {
+ "address": "bc1px4ssshedlz4jc56ses3lftz462a06jwy8my4pwpx6twx30vvv6nsgwcpu3",
+ "value": 410000
+ },
+ "exception": "Can not modify transaction, signatures exist."
+ },
+ {
+ "description": "Adds output after tapkey spend input has been finalized",
+ "isTaproot": true,
+ "psbt": "cHNidP8BAF4CAAAAAfyhtBTm+3OPYBuMHvdPMf9jqniZDY925hbmnt8hxbA6AAAAAAD/////AZBBBgAAAAAAIlEgV6CyzSs5a6Tc8A+TYOiozWnh6FRH9E/VWFanhMAEbLEAAAAAAAEBK6BoBgAAAAAAIlEgV6CyzSs5a6Tc8A+TYOiozWnh6FRH9E/VWFanhMAEbLEBCEIBQOAqWBD/2jhPWzQvesT8sjkN2Cowphp3QvmlWbHiLx753ChcUovvWyBlWiCq77Kk+lZGEhC4vjClSjc26br+dc8AAA==",
+ "outputData": {
+ "address": "bc1px4ssshedlz4jc56ses3lftz462a06jwy8my4pwpx6twx30vvv6nsgwcpu3",
+ "value": 410000
+ },
+ "exception": "Can not modify transaction, signatures exist."
+ },
+ {
+ "description": "Adds output after tapscript signatures have been added",
+ "isTaproot": true,
+ "psbt": "cHNidP8BAF4CAAAAAa/0mhnSBXdEBKbbMC+2hm6AZZtCLBxBeubd1sjtau5dAAAAAAD/////AZBBBgAAAAAAIlEgISRIfamb9rCYzad52ikfoUUuFlvyTcImZMavR0jEaUQAAAAAAAEBK6BoBgAAAAAAIlEgISRIfamb9rCYzad52ikfoUUuFlvyTcImZMavR0jEaURBFBnEcOpwiHjNYPtWJOrQ8Pgc9bxBKyZh/i2D837Z1rC8BibL1C4Z/5e6dKzWfkzpsIbE5WEVn1bYpAAjrqIKMHlAKkl3w3Gfpkl9b0yDVbTlZd4yCEL9V2DJs6zpPrEmn3wiohBy8wwE6EZ0FxQdrCupnHKXhHBjpcHVwfJRQfcy9EEULx1ijisiHgGb/9/hBNhsIOv1ZyWsfmi/Ql+oz7AOuqAGJsvULhn/l7p0rNZ+TOmwhsTlYRWfVtikACOuogoweUBKNkxBf6vT8m7ISt1WikLWW9udCP7OQLXztr1IPalJT5z+esAWmgeLS7QoLgzTu8AnYp/rHxsgZ6CgiV8tlkciQRRXE7VxCk67h7Ee6CbSgNyotChx7CgwNTfxdJkyvCS0DgYmy9QuGf+XunSs1n5M6bCGxOVhFZ9W2KQAI66iCjB5QFN6DGtLlSIFBjZbdh3rbKBtBcEDSiEcuVxnSPpdM1RnQRmw5Ujo+/76wZfmGBMFzV0IA7vnHzzXN73jT6O8/wJiFcDBdB6IhNxYUBYgZT1K7FG5SblQ3S6nQMKRLc2vPcA0BhpSnJ+zzX53bWG2IltsYQ6JBvuPqmxZrFw+lbX4LSnWGlKcn7PNfndtYbYiW2xhDokG+4+qbFmsXD6VtfgtKdZpIFcTtXEKTruHsR7oJtKA3Ki0KHHsKDA1N/F0mTK8JLQOrCAvHWKOKyIeAZv/3+EE2Gwg6/VnJax+aL9CX6jPsA66oLogGcRw6nCIeM1g+1Yk6tDw+Bz1vEErJmH+LYPzftnWsLy6U5zAAAA=",
+ "outputData": {
+ "address": "bc1px4ssshedlz4jc56ses3lftz462a06jwy8my4pwpx6twx30vvv6nsgwcpu3",
+ "value": 410000
+ },
+ "exception": "Can not modify transaction, signatures exist."
}
]
},
diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts
index 93637772a..b419e02fb 100644
--- a/ts_src/psbt.ts
+++ b/ts_src/psbt.ts
@@ -1367,41 +1367,105 @@ function checkFees(psbt: Psbt, cache: PsbtCache, opts: PsbtOpts): void {
}
function checkInputsForPartialSig(inputs: PsbtInput[], action: string): void {
- // todo: add for taproot
inputs.forEach(input => {
- let throws = false;
- let pSigs: PartialSig[] = [];
- if ((input.partialSig || []).length === 0) {
- if (!input.finalScriptSig && !input.finalScriptWitness) return;
- pSigs = getPsigsFromInputFinalScripts(input);
- } else {
- pSigs = input.partialSig!;
- }
- pSigs.forEach(pSig => {
- const { hashType } = bscript.signature.decode(pSig.signature);
- const whitelist: string[] = [];
- const isAnyoneCanPay = hashType & Transaction.SIGHASH_ANYONECANPAY;
- if (isAnyoneCanPay) whitelist.push('addInput');
- const hashMod = hashType & 0x1f;
- switch (hashMod) {
- case Transaction.SIGHASH_ALL:
- break;
- case Transaction.SIGHASH_SINGLE:
- case Transaction.SIGHASH_NONE:
- whitelist.push('addOutput');
- whitelist.push('setInputSequence');
- break;
- }
- if (whitelist.indexOf(action) === -1) {
- throws = true;
- }
- });
- if (throws) {
+ const throws = isTaprootInput(input)
+ ? checkTaprootInputForSigs(input, action)
+ : checkInputForSig(input, action);
+ if (throws)
throw new Error('Can not modify transaction, signatures exist.');
- }
});
}
+function checkInputForSig(input: PsbtInput, action: string): boolean {
+ const pSigs = extractPartialSigs(input);
+ return pSigs.some(pSig =>
+ signatureBlocksAction(pSig, bscript.signature.decode, action),
+ );
+}
+
+function checkTaprootInputForSigs(input: PsbtInput, action: string): boolean {
+ const sigs = extractTaprootSigs(input);
+ return sigs.some(sig =>
+ signatureBlocksAction(sig, decodeSchnorSignature, action),
+ );
+}
+
+function decodeSchnorSignature(
+ signature: Buffer,
+): {
+ signature: Buffer;
+ hashType: number;
+} {
+ return {
+ signature: signature.slice(0, 64),
+ hashType: signature.slice(64)[0] || Transaction.SIGHASH_DEFAULT,
+ };
+}
+
+function extractTaprootSigs(input: PsbtInput): Buffer[] {
+ const sigs: Buffer[] = [];
+ if (input.tapKeySig) sigs.push(input.tapKeySig);
+ if (input.tapScriptSig)
+ sigs.push(...input.tapScriptSig.map(s => s.signature));
+ if (!sigs.length) {
+ const finalTapKeySig = getTapKeySigFromWithness(input.finalScriptWitness);
+ if (finalTapKeySig) sigs.push(finalTapKeySig);
+ }
+
+ return sigs;
+}
+
+function getTapKeySigFromWithness(
+ finalScriptWitness?: Buffer,
+): Buffer | undefined {
+ if (!finalScriptWitness) return;
+ const witness = finalScriptWitness.slice(2);
+ // todo: add schnor signature validation
+ if (witness.length === 64 || witness.length === 65) return witness;
+}
+
+function extractPartialSigs(input: PsbtInput): Buffer[] {
+ let pSigs: PartialSig[] = [];
+ if ((input.partialSig || []).length === 0) {
+ if (!input.finalScriptSig && !input.finalScriptWitness) return [];
+ pSigs = getPsigsFromInputFinalScripts(input);
+ } else {
+ pSigs = input.partialSig!;
+ }
+ return pSigs.map(p => p.signature);
+}
+
+type SignatureDecodeFunc = (
+ buffer: Buffer,
+) => {
+ signature: Buffer;
+ hashType: number;
+};
+function signatureBlocksAction(
+ signature: Buffer,
+ signatureDecodeFn: SignatureDecodeFunc,
+ action: string,
+): boolean {
+ const { hashType } = signatureDecodeFn(signature);
+ const whitelist: string[] = [];
+ const isAnyoneCanPay = hashType & Transaction.SIGHASH_ANYONECANPAY;
+ if (isAnyoneCanPay) whitelist.push('addInput');
+ const hashMod = hashType & 0x1f;
+ switch (hashMod) {
+ case Transaction.SIGHASH_ALL:
+ break;
+ case Transaction.SIGHASH_SINGLE:
+ case Transaction.SIGHASH_NONE:
+ whitelist.push('addOutput');
+ whitelist.push('setInputSequence');
+ break;
+ }
+ if (whitelist.indexOf(action) === -1) {
+ return true;
+ }
+ return false;
+}
+
function checkPartialSigSighashes(input: PsbtInput): void {
if (!input.sighashType || !input.partialSig) return;
const { partialSig, sighashType } = input;
From f32d706713b606c903c14ed763fd990166972b2d Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Thu, 26 May 2022 15:02:03 +0300
Subject: [PATCH 083/144] refactor: move out some utils
---
src/psbt.js | 85 +------------------------------
src/psbt/bip371.d.ts | 1 +
src/psbt/bip371.js | 35 ++++++++++++-
src/psbt/psbtutils.d.ts | 8 +++
src/psbt/psbtutils.js | 56 +++++++++++++++++++-
ts_src/psbt.ts | 107 +--------------------------------------
ts_src/psbt/bip371.ts | 48 ++++++++++++++++++
ts_src/psbt/psbtutils.ts | 66 ++++++++++++++++++++++++
8 files changed, 216 insertions(+), 190 deletions(-)
diff --git a/src/psbt.js b/src/psbt.js
index 2e58596dc..2bc55e065 100644
--- a/src/psbt.js
+++ b/src/psbt.js
@@ -1037,79 +1037,12 @@ function checkFees(psbt, cache, opts) {
function checkInputsForPartialSig(inputs, action) {
inputs.forEach(input => {
const throws = (0, bip371_1.isTaprootInput)(input)
- ? checkTaprootInputForSigs(input, action)
- : checkInputForSig(input, action);
+ ? (0, bip371_1.checkTaprootInputForSigs)(input, action)
+ : (0, psbtutils_1.checkInputForSig)(input, action);
if (throws)
throw new Error('Can not modify transaction, signatures exist.');
});
}
-function checkInputForSig(input, action) {
- const pSigs = extractPartialSigs(input);
- return pSigs.some(pSig =>
- signatureBlocksAction(pSig, bscript.signature.decode, action),
- );
-}
-function checkTaprootInputForSigs(input, action) {
- const sigs = extractTaprootSigs(input);
- return sigs.some(sig =>
- signatureBlocksAction(sig, decodeSchnorSignature, action),
- );
-}
-function decodeSchnorSignature(signature) {
- return {
- signature: signature.slice(0, 64),
- hashType:
- signature.slice(64)[0] || transaction_1.Transaction.SIGHASH_DEFAULT,
- };
-}
-function extractTaprootSigs(input) {
- const sigs = [];
- if (input.tapKeySig) sigs.push(input.tapKeySig);
- if (input.tapScriptSig)
- sigs.push(...input.tapScriptSig.map(s => s.signature));
- if (!sigs.length) {
- const finalTapKeySig = getTapKeySigFromWithness(input.finalScriptWitness);
- if (finalTapKeySig) sigs.push(finalTapKeySig);
- }
- return sigs;
-}
-function getTapKeySigFromWithness(finalScriptWitness) {
- if (!finalScriptWitness) return;
- const witness = finalScriptWitness.slice(2);
- // todo: add schnor signature validation
- if (witness.length === 64 || witness.length === 65) return witness;
-}
-function extractPartialSigs(input) {
- let pSigs = [];
- if ((input.partialSig || []).length === 0) {
- if (!input.finalScriptSig && !input.finalScriptWitness) return [];
- pSigs = getPsigsFromInputFinalScripts(input);
- } else {
- pSigs = input.partialSig;
- }
- return pSigs.map(p => p.signature);
-}
-function signatureBlocksAction(signature, signatureDecodeFn, action) {
- const { hashType } = signatureDecodeFn(signature);
- const whitelist = [];
- const isAnyoneCanPay =
- hashType & transaction_1.Transaction.SIGHASH_ANYONECANPAY;
- if (isAnyoneCanPay) whitelist.push('addInput');
- const hashMod = hashType & 0x1f;
- switch (hashMod) {
- case transaction_1.Transaction.SIGHASH_ALL:
- break;
- case transaction_1.Transaction.SIGHASH_SINGLE:
- case transaction_1.Transaction.SIGHASH_NONE:
- whitelist.push('addOutput');
- whitelist.push('setInputSequence');
- break;
- }
- if (whitelist.indexOf(action) === -1) {
- return true;
- }
- return false;
-}
function checkPartialSigSighashes(input) {
if (!input.sighashType || !input.partialSig) return;
const { partialSig, sighashType } = input;
@@ -1459,20 +1392,6 @@ function getPayment(script, scriptType, partialSig) {
}
return payment;
}
-function getPsigsFromInputFinalScripts(input) {
- const scriptItems = !input.finalScriptSig
- ? []
- : bscript.decompile(input.finalScriptSig) || [];
- const witnessItems = !input.finalScriptWitness
- ? []
- : bscript.decompile(input.finalScriptWitness) || [];
- return scriptItems
- .concat(witnessItems)
- .filter(item => {
- return Buffer.isBuffer(item) && bscript.isCanonicalScriptSignature(item);
- })
- .map(sig => ({ signature: sig }));
-}
function getScriptFromInput(inputIndex, input, cache) {
const unsignedTx = cache.__TX;
const res = {
diff --git a/src/psbt/bip371.d.ts b/src/psbt/bip371.d.ts
index b734c87f5..fae6e756b 100644
--- a/src/psbt/bip371.d.ts
+++ b/src/psbt/bip371.d.ts
@@ -38,3 +38,4 @@ export declare function tapTreeToList(tree: Taptree): TapLeaf[];
* @returns the corresponding taptree, or throws an exception if the tree cannot be reconstructed
*/
export declare function tapTreeFromList(leaves?: TapLeaf[]): Taptree;
+export declare function checkTaprootInputForSigs(input: PsbtInput, action: string): boolean;
diff --git a/src/psbt/bip371.js b/src/psbt/bip371.js
index fbc7eb7e3..eee6b1393 100644
--- a/src/psbt/bip371.js
+++ b/src/psbt/bip371.js
@@ -1,10 +1,12 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.tapTreeFromList = exports.tapTreeToList = exports.tweakInternalPubKey = exports.checkTaprootOutputFields = exports.checkTaprootInputFields = exports.isTaprootOutput = exports.isTaprootInput = exports.serializeTaprootSignature = exports.tapScriptFinalizer = exports.toXOnly = void 0;
+exports.checkTaprootInputForSigs = exports.tapTreeFromList = exports.tapTreeToList = exports.tweakInternalPubKey = exports.checkTaprootOutputFields = exports.checkTaprootInputFields = exports.isTaprootOutput = exports.isTaprootInput = exports.serializeTaprootSignature = exports.tapScriptFinalizer = exports.toXOnly = void 0;
const types_1 = require('../types');
+const transaction_1 = require('../transaction');
const psbtutils_1 = require('./psbtutils');
const taprootutils_1 = require('../payments/taprootutils');
const payments_1 = require('../payments');
+const psbtutils_2 = require('./psbtutils');
const toXOnly = pubKey => (pubKey.length === 32 ? pubKey : pubKey.slice(1, 33));
exports.toXOnly = toXOnly;
/**
@@ -141,6 +143,37 @@ function tapTreeFromList(leaves = []) {
return instertLeavesInTree(leaves);
}
exports.tapTreeFromList = tapTreeFromList;
+function checkTaprootInputForSigs(input, action) {
+ const sigs = extractTaprootSigs(input);
+ return sigs.some(sig =>
+ (0, psbtutils_2.signatureBlocksAction)(sig, decodeSchnorSignature, action),
+ );
+}
+exports.checkTaprootInputForSigs = checkTaprootInputForSigs;
+function decodeSchnorSignature(signature) {
+ return {
+ signature: signature.slice(0, 64),
+ hashType:
+ signature.slice(64)[0] || transaction_1.Transaction.SIGHASH_DEFAULT,
+ };
+}
+function extractTaprootSigs(input) {
+ const sigs = [];
+ if (input.tapKeySig) sigs.push(input.tapKeySig);
+ if (input.tapScriptSig)
+ sigs.push(...input.tapScriptSig.map(s => s.signature));
+ if (!sigs.length) {
+ const finalTapKeySig = getTapKeySigFromWithness(input.finalScriptWitness);
+ if (finalTapKeySig) sigs.push(finalTapKeySig);
+ }
+ return sigs;
+}
+function getTapKeySigFromWithness(finalScriptWitness) {
+ if (!finalScriptWitness) return;
+ const witness = finalScriptWitness.slice(2);
+ // todo: add schnor signature validation
+ if (witness.length === 64 || witness.length === 65) return witness;
+}
function _tapTreeToList(tree, leaves = [], depth = 0) {
if (depth > taprootutils_1.MAX_TAPTREE_DEPTH)
throw new Error('Max taptree depth exceeded.');
diff --git a/src/psbt/psbtutils.d.ts b/src/psbt/psbtutils.d.ts
index c902e6cec..6491132a8 100644
--- a/src/psbt/psbtutils.d.ts
+++ b/src/psbt/psbtutils.d.ts
@@ -1,4 +1,5 @@
///
+import { PsbtInput } from 'bip174/src/lib/interfaces';
export declare const isP2MS: (script: Buffer) => boolean;
export declare const isP2PK: (script: Buffer) => boolean;
export declare const isP2PKH: (script: Buffer) => boolean;
@@ -9,3 +10,10 @@ export declare const isP2TR: (script: Buffer) => boolean;
export declare function witnessStackToScriptWitness(witness: Buffer[]): Buffer;
export declare function pubkeyPositionInScript(pubkey: Buffer, script: Buffer): number;
export declare function pubkeyInScript(pubkey: Buffer, script: Buffer): boolean;
+export declare function checkInputForSig(input: PsbtInput, action: string): boolean;
+declare type SignatureDecodeFunc = (buffer: Buffer) => {
+ signature: Buffer;
+ hashType: number;
+};
+export declare function signatureBlocksAction(signature: Buffer, signatureDecodeFn: SignatureDecodeFunc, action: string): boolean;
+export {};
diff --git a/src/psbt/psbtutils.js b/src/psbt/psbtutils.js
index 4ef56f6a5..086faa4f0 100644
--- a/src/psbt/psbtutils.js
+++ b/src/psbt/psbtutils.js
@@ -1,8 +1,9 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.pubkeyInScript = exports.pubkeyPositionInScript = exports.witnessStackToScriptWitness = exports.isP2TR = exports.isP2SHScript = exports.isP2WSHScript = exports.isP2WPKH = exports.isP2PKH = exports.isP2PK = exports.isP2MS = void 0;
+exports.signatureBlocksAction = exports.checkInputForSig = exports.pubkeyInScript = exports.pubkeyPositionInScript = exports.witnessStackToScriptWitness = exports.isP2TR = exports.isP2SHScript = exports.isP2WSHScript = exports.isP2WPKH = exports.isP2PKH = exports.isP2PK = exports.isP2MS = void 0;
const varuint = require('bip174/src/lib/converter/varint');
const bscript = require('../script');
+const transaction_1 = require('../transaction');
const crypto_1 = require('../crypto');
const payments = require('../payments');
function isPaymentFactory(payment) {
@@ -64,3 +65,56 @@ function pubkeyInScript(pubkey, script) {
return pubkeyPositionInScript(pubkey, script) !== -1;
}
exports.pubkeyInScript = pubkeyInScript;
+function checkInputForSig(input, action) {
+ const pSigs = extractPartialSigs(input);
+ return pSigs.some(pSig =>
+ signatureBlocksAction(pSig, bscript.signature.decode, action),
+ );
+}
+exports.checkInputForSig = checkInputForSig;
+function signatureBlocksAction(signature, signatureDecodeFn, action) {
+ const { hashType } = signatureDecodeFn(signature);
+ const whitelist = [];
+ const isAnyoneCanPay =
+ hashType & transaction_1.Transaction.SIGHASH_ANYONECANPAY;
+ if (isAnyoneCanPay) whitelist.push('addInput');
+ const hashMod = hashType & 0x1f;
+ switch (hashMod) {
+ case transaction_1.Transaction.SIGHASH_ALL:
+ break;
+ case transaction_1.Transaction.SIGHASH_SINGLE:
+ case transaction_1.Transaction.SIGHASH_NONE:
+ whitelist.push('addOutput');
+ whitelist.push('setInputSequence');
+ break;
+ }
+ if (whitelist.indexOf(action) === -1) {
+ return true;
+ }
+ return false;
+}
+exports.signatureBlocksAction = signatureBlocksAction;
+function extractPartialSigs(input) {
+ let pSigs = [];
+ if ((input.partialSig || []).length === 0) {
+ if (!input.finalScriptSig && !input.finalScriptWitness) return [];
+ pSigs = getPsigsFromInputFinalScripts(input);
+ } else {
+ pSigs = input.partialSig;
+ }
+ return pSigs.map(p => p.signature);
+}
+function getPsigsFromInputFinalScripts(input) {
+ const scriptItems = !input.finalScriptSig
+ ? []
+ : bscript.decompile(input.finalScriptSig) || [];
+ const witnessItems = !input.finalScriptWitness
+ ? []
+ : bscript.decompile(input.finalScriptWitness) || [];
+ return scriptItems
+ .concat(witnessItems)
+ .filter(item => {
+ return Buffer.isBuffer(item) && bscript.isCanonicalScriptSignature(item);
+ })
+ .map(sig => ({ signature: sig }));
+}
diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts
index b419e02fb..a3b66c7e0 100644
--- a/ts_src/psbt.ts
+++ b/ts_src/psbt.ts
@@ -30,9 +30,11 @@ import {
checkTaprootInputFields,
checkTaprootOutputFields,
tweakInternalPubKey,
+ checkTaprootInputForSigs,
} from './psbt/bip371';
import {
witnessStackToScriptWitness,
+ checkInputForSig,
pubkeyInScript,
isP2MS,
isP2PK,
@@ -1376,96 +1378,6 @@ function checkInputsForPartialSig(inputs: PsbtInput[], action: string): void {
});
}
-function checkInputForSig(input: PsbtInput, action: string): boolean {
- const pSigs = extractPartialSigs(input);
- return pSigs.some(pSig =>
- signatureBlocksAction(pSig, bscript.signature.decode, action),
- );
-}
-
-function checkTaprootInputForSigs(input: PsbtInput, action: string): boolean {
- const sigs = extractTaprootSigs(input);
- return sigs.some(sig =>
- signatureBlocksAction(sig, decodeSchnorSignature, action),
- );
-}
-
-function decodeSchnorSignature(
- signature: Buffer,
-): {
- signature: Buffer;
- hashType: number;
-} {
- return {
- signature: signature.slice(0, 64),
- hashType: signature.slice(64)[0] || Transaction.SIGHASH_DEFAULT,
- };
-}
-
-function extractTaprootSigs(input: PsbtInput): Buffer[] {
- const sigs: Buffer[] = [];
- if (input.tapKeySig) sigs.push(input.tapKeySig);
- if (input.tapScriptSig)
- sigs.push(...input.tapScriptSig.map(s => s.signature));
- if (!sigs.length) {
- const finalTapKeySig = getTapKeySigFromWithness(input.finalScriptWitness);
- if (finalTapKeySig) sigs.push(finalTapKeySig);
- }
-
- return sigs;
-}
-
-function getTapKeySigFromWithness(
- finalScriptWitness?: Buffer,
-): Buffer | undefined {
- if (!finalScriptWitness) return;
- const witness = finalScriptWitness.slice(2);
- // todo: add schnor signature validation
- if (witness.length === 64 || witness.length === 65) return witness;
-}
-
-function extractPartialSigs(input: PsbtInput): Buffer[] {
- let pSigs: PartialSig[] = [];
- if ((input.partialSig || []).length === 0) {
- if (!input.finalScriptSig && !input.finalScriptWitness) return [];
- pSigs = getPsigsFromInputFinalScripts(input);
- } else {
- pSigs = input.partialSig!;
- }
- return pSigs.map(p => p.signature);
-}
-
-type SignatureDecodeFunc = (
- buffer: Buffer,
-) => {
- signature: Buffer;
- hashType: number;
-};
-function signatureBlocksAction(
- signature: Buffer,
- signatureDecodeFn: SignatureDecodeFunc,
- action: string,
-): boolean {
- const { hashType } = signatureDecodeFn(signature);
- const whitelist: string[] = [];
- const isAnyoneCanPay = hashType & Transaction.SIGHASH_ANYONECANPAY;
- if (isAnyoneCanPay) whitelist.push('addInput');
- const hashMod = hashType & 0x1f;
- switch (hashMod) {
- case Transaction.SIGHASH_ALL:
- break;
- case Transaction.SIGHASH_SINGLE:
- case Transaction.SIGHASH_NONE:
- whitelist.push('addOutput');
- whitelist.push('setInputSequence');
- break;
- }
- if (whitelist.indexOf(action) === -1) {
- return true;
- }
- return false;
-}
-
function checkPartialSigSighashes(input: PsbtInput): void {
if (!input.sighashType || !input.partialSig) return;
const { partialSig, sighashType } = input;
@@ -1926,21 +1838,6 @@ function getPayment(
return payment!;
}
-function getPsigsFromInputFinalScripts(input: PsbtInput): PartialSig[] {
- const scriptItems = !input.finalScriptSig
- ? []
- : bscript.decompile(input.finalScriptSig) || [];
- const witnessItems = !input.finalScriptWitness
- ? []
- : bscript.decompile(input.finalScriptWitness) || [];
- return scriptItems
- .concat(witnessItems)
- .filter(item => {
- return Buffer.isBuffer(item) && bscript.isCanonicalScriptSignature(item);
- })
- .map(sig => ({ signature: sig })) as PartialSig[];
-}
-
interface GetScriptReturn {
script: Buffer | null;
isSegwit: boolean;
diff --git a/ts_src/psbt/bip371.ts b/ts_src/psbt/bip371.ts
index 64de6c2d2..153e289ec 100644
--- a/ts_src/psbt/bip371.ts
+++ b/ts_src/psbt/bip371.ts
@@ -9,6 +9,8 @@ import {
TapInternalKey,
} from 'bip174/src/lib/interfaces';
+import { Transaction } from '../transaction';
+
import {
witnessStackToScriptWitness,
pubkeyPositionInScript,
@@ -23,6 +25,8 @@ import {
} from '../payments/taprootutils';
import { p2tr } from '../payments';
+import { signatureBlocksAction } from './psbtutils';
+
export const toXOnly = (pubKey: Buffer) =>
pubKey.length === 32 ? pubKey : pubKey.slice(1, 33);
@@ -191,6 +195,50 @@ export function tapTreeFromList(leaves: TapLeaf[] = []): Taptree {
return instertLeavesInTree(leaves);
}
+export function checkTaprootInputForSigs(
+ input: PsbtInput,
+ action: string,
+): boolean {
+ const sigs = extractTaprootSigs(input);
+ return sigs.some(sig =>
+ signatureBlocksAction(sig, decodeSchnorSignature, action),
+ );
+}
+
+function decodeSchnorSignature(
+ signature: Buffer,
+): {
+ signature: Buffer;
+ hashType: number;
+} {
+ return {
+ signature: signature.slice(0, 64),
+ hashType: signature.slice(64)[0] || Transaction.SIGHASH_DEFAULT,
+ };
+}
+
+function extractTaprootSigs(input: PsbtInput): Buffer[] {
+ const sigs: Buffer[] = [];
+ if (input.tapKeySig) sigs.push(input.tapKeySig);
+ if (input.tapScriptSig)
+ sigs.push(...input.tapScriptSig.map(s => s.signature));
+ if (!sigs.length) {
+ const finalTapKeySig = getTapKeySigFromWithness(input.finalScriptWitness);
+ if (finalTapKeySig) sigs.push(finalTapKeySig);
+ }
+
+ return sigs;
+}
+
+function getTapKeySigFromWithness(
+ finalScriptWitness?: Buffer,
+): Buffer | undefined {
+ if (!finalScriptWitness) return;
+ const witness = finalScriptWitness.slice(2);
+ // todo: add schnor signature validation
+ if (witness.length === 64 || witness.length === 65) return witness;
+}
+
function _tapTreeToList(
tree: Taptree,
leaves: TapLeaf[] = [],
diff --git a/ts_src/psbt/psbtutils.ts b/ts_src/psbt/psbtutils.ts
index 1a891f788..d51e2df54 100644
--- a/ts_src/psbt/psbtutils.ts
+++ b/ts_src/psbt/psbtutils.ts
@@ -1,5 +1,7 @@
import * as varuint from 'bip174/src/lib/converter/varint';
+import { PartialSig, PsbtInput } from 'bip174/src/lib/interfaces';
import * as bscript from '../script';
+import { Transaction } from '../transaction';
import { hash160 } from '../crypto';
import * as payments from '../payments';
@@ -71,3 +73,67 @@ export function pubkeyPositionInScript(pubkey: Buffer, script: Buffer): number {
export function pubkeyInScript(pubkey: Buffer, script: Buffer): boolean {
return pubkeyPositionInScript(pubkey, script) !== -1;
}
+
+export function checkInputForSig(input: PsbtInput, action: string): boolean {
+ const pSigs = extractPartialSigs(input);
+ return pSigs.some(pSig =>
+ signatureBlocksAction(pSig, bscript.signature.decode, action),
+ );
+}
+
+type SignatureDecodeFunc = (
+ buffer: Buffer,
+) => {
+ signature: Buffer;
+ hashType: number;
+};
+export function signatureBlocksAction(
+ signature: Buffer,
+ signatureDecodeFn: SignatureDecodeFunc,
+ action: string,
+): boolean {
+ const { hashType } = signatureDecodeFn(signature);
+ const whitelist: string[] = [];
+ const isAnyoneCanPay = hashType & Transaction.SIGHASH_ANYONECANPAY;
+ if (isAnyoneCanPay) whitelist.push('addInput');
+ const hashMod = hashType & 0x1f;
+ switch (hashMod) {
+ case Transaction.SIGHASH_ALL:
+ break;
+ case Transaction.SIGHASH_SINGLE:
+ case Transaction.SIGHASH_NONE:
+ whitelist.push('addOutput');
+ whitelist.push('setInputSequence');
+ break;
+ }
+ if (whitelist.indexOf(action) === -1) {
+ return true;
+ }
+ return false;
+}
+
+function extractPartialSigs(input: PsbtInput): Buffer[] {
+ let pSigs: PartialSig[] = [];
+ if ((input.partialSig || []).length === 0) {
+ if (!input.finalScriptSig && !input.finalScriptWitness) return [];
+ pSigs = getPsigsFromInputFinalScripts(input);
+ } else {
+ pSigs = input.partialSig!;
+ }
+ return pSigs.map(p => p.signature);
+}
+
+function getPsigsFromInputFinalScripts(input: PsbtInput): PartialSig[] {
+ const scriptItems = !input.finalScriptSig
+ ? []
+ : bscript.decompile(input.finalScriptSig) || [];
+ const witnessItems = !input.finalScriptWitness
+ ? []
+ : bscript.decompile(input.finalScriptWitness) || [];
+ return scriptItems
+ .concat(witnessItems)
+ .filter(item => {
+ return Buffer.isBuffer(item) && bscript.isCanonicalScriptSignature(item);
+ })
+ .map(sig => ({ signature: sig })) as PartialSig[];
+}
From c9b334b3825b9c67a2ed53951bd8e6e01dd9e5b1 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Thu, 26 May 2022 17:31:31 +0300
Subject: [PATCH 084/144] test: add custom taproot finalizer (partial)
---
test/integration/taproot.spec.ts | 109 ++++++++++++++++++++++++++++++-
1 file changed, 108 insertions(+), 1 deletion(-)
diff --git a/test/integration/taproot.spec.ts b/test/integration/taproot.spec.ts
index 2707462ca..d35c9c474 100644
--- a/test/integration/taproot.spec.ts
+++ b/test/integration/taproot.spec.ts
@@ -2,10 +2,13 @@ import BIP32Factory from 'bip32';
import ECPairFactory from 'ecpair';
import * as ecc from 'tiny-secp256k1';
import { describe, it } from 'mocha';
+import { PsbtInput, TapLeafScript } from 'bip174/src/lib/interfaces';
import { regtestUtils } from './_regtest';
import * as bitcoin from '../..';
import { Taptree } from '../../src/types';
-import { toXOnly, tapTreeToList } from '../../src/psbt/bip371';
+import { toXOnly, tapTreeToList, tapTreeFromList } from '../../src/psbt/bip371';
+import { witnessStackToScriptWitness } from '../../src/psbt/psbtutils';
+import { TapLeaf } from 'bip174/src/lib/interfaces';
const rng = require('randombytes');
const regtest = regtestUtils.network;
@@ -485,8 +488,112 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
value: sendAmount,
});
});
+
+ it('can create (and broadcast via 3PBP) a taproot script-path spend Transaction - custom finalizer', async () => {
+
+
+ const leafCount = 8;
+ const leaves = Array.from({ length: leafCount }).map(
+ (_, index) =>
+ ({
+ depth: 3,
+ leafVersion: 192,
+ script: bitcoin.script.fromASM(`OP_ADD OP_${index * 2} OP_EQUAL`),
+ } as TapLeaf),
+ );
+ const scriptTree = tapTreeFromList(leaves);
+
+ for (let leafIndex = 1; leafIndex < leafCount; leafIndex++) {
+ const redeem = {
+ output: bitcoin.script.fromASM(`OP_ADD OP_${leafIndex * 2} OP_EQUAL`),
+ redeemVersion: 192,
+ };
+
+ const internalKey = bip32.fromSeed(rng(64), regtest);
+ const { output, witness } = bitcoin.payments.p2tr({
+ internalPubkey: toXOnly(internalKey.publicKey),
+ scriptTree,
+ redeem,
+ network: regtest,
+ });
+
+
+ // amount from faucet
+ const amount = 42e4;
+ // amount to send
+ const sendAmount = amount - 1e4;
+ // get faucet
+ const unspent = await regtestUtils.faucetComplex(output!, amount);
+
+ const psbt = new bitcoin.Psbt({ network: regtest });
+ psbt.addInput({
+ hash: unspent.txId,
+ index: 0,
+ witnessUtxo: { value: amount, script: output! },
+ });
+
+ const tapLeafScript: TapLeafScript = {
+ leafVersion: redeem.redeemVersion,
+ script: redeem.output,
+ controlBlock: witness![witness!.length - 1],
+ };
+ psbt.updateInput(0, { tapLeafScript: [tapLeafScript] });
+
+ const sendAddress =
+ 'bcrt1pqknex3jwpsaatu5e5dcjw70nac3fr5k5y3hcxr4hgg6rljzp59nqs6a0vh';
+ psbt.addOutput({
+ value: sendAmount,
+ address: sendAddress,
+ });
+
+ const leafIndexFinalizerFn = buildLeafIndexFinalizer(
+ tapLeafScript,
+ leafIndex,
+ );
+ psbt.finalizeInput(0, leafIndexFinalizerFn);
+ console.log('### psbt finalized', psbt.toBase64());
+ const tx = psbt.extractTransaction();
+ const rawTx = tx.toBuffer();
+ const hex = rawTx.toString('hex');
+
+ console.log('### hex', hex)
+ await regtestUtils.broadcast(hex);
+ console.log('### verify')
+ await regtestUtils.verify({
+ txId: tx.getId(),
+ address: sendAddress!,
+ vout: 0,
+ value: sendAmount,
+ });
+ }
+ });
});
+function buildLeafIndexFinalizer(
+ tapLeafScript: TapLeafScript,
+ leafIndex: number,
+) {
+ return (
+ inputIndex: number,
+ _input: PsbtInput,
+ _tapLeafHashToFinalize?: Buffer,
+ ): {
+ finalScriptWitness: Buffer | undefined;
+ } => {
+ try {
+ const scriptSolution = [
+ bitcoin.script.fromASM(`OP_${leafIndex} OP_${leafIndex}`),
+ ];
+ const witness = scriptSolution
+ .concat(tapLeafScript.script)
+ .concat(tapLeafScript.controlBlock);
+ return { finalScriptWitness: witnessStackToScriptWitness(witness) };
+ } catch (err) {
+ throw new Error(`Can not finalize taproot input #${inputIndex}: ${err}`);
+ }
+ };
+}
+
// Order of the curve (N) - 1
const N_LESS_1 = Buffer.from(
'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140',
From 8b4cee91110aa9aecc246cb50589ea9efa263311 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Thu, 26 May 2022 17:52:19 +0300
Subject: [PATCH 085/144] chore: code clean-up
---
test/fixtures/psbt.json | 10 +++++-----
test/integration/taproot.spec.ts | 6 ------
2 files changed, 5 insertions(+), 11 deletions(-)
diff --git a/test/fixtures/psbt.json b/test/fixtures/psbt.json
index 815bcb9df..ec6eda328 100644
--- a/test/fixtures/psbt.json
+++ b/test/fixtures/psbt.json
@@ -532,7 +532,7 @@
"exception": "Error adding output."
},
{
- "description": "Checks that the output script can be computed",
+ "description": "Checks the mandatory values for adding an output",
"outputData": {
"value": 1000
},
@@ -546,7 +546,7 @@
}
},
{
- "description": "Adds taproot output with internal key and tap tree",
+ "description": "Adds taproot output with internal tap key and tap tree",
"isTaproot": true,
"psbt": "cHNidP8BADMCAAAAAcbgSGx76du9GXsr4c6Yk7DFglfHi7M2jdCNUXwc+Q+EAAAAAAD/////AAAAAAAAAQEroGgGAAAAAAAiUSClLxmVQ6aZXLEwkYA/WGZuIE91BHT7xP7DIEAvz/NITaIVwd2NnolThxX+QCpgFksj8u93bzuZy6olaHxJNHaArwK1tCTeoJ+EC5MqADc83NvSVlC4w6z+VKn0pkGihnIbjSbax5V2a72h6uqkXlv6CpUP3V9MSq2lsfMILtyWibn9Cu4oo7gsSuy+vTeBJ9yI3Rnh6pPtunont1ThyIHTCIdKesRIlUS3uEDQRVmeyUFa5xzLCQwsRlwFyfoF9Bx6BtUjIFX368Cp2d6uXSbyrn23vC4KMjRRlEssuTTh7ThM6bXQrMAAAA==",
"outputData": {
@@ -596,7 +596,7 @@
"result": "cHNidP8BAF4CAAAAAcbgSGx76du9GXsr4c6Yk7DFglfHi7M2jdCNUXwc+Q+EAAAAAAD/////AZBBBgAAAAAAIlEgNWEIXy34qyxTUMwj9KxV0rr9ScQ+yVC4JtLcaL2MZqcAAAAAAAEBK6BoBgAAAAAAIlEgpS8ZlUOmmVyxMJGAP1hmbiBPdQR0+8T+wyBAL8/zSE2iFcHdjZ6JU4cV/kAqYBZLI/Lvd287mcuqJWh8STR2gK8CtbQk3qCfhAuTKgA3PNzb0lZQuMOs/lSp9KZBooZyG40m2seVdmu9oerqpF5b+gqVD91fTEqtpbHzCC7clom5/QruKKO4LErsvr03gSfciN0Z4eqT7bp6J7dU4ciB0wiHSnrESJVEt7hA0EVZnslBWuccywkMLEZcBcn6BfQcegbVIyBV9+vAqdnerl0m8q59t7wuCjI0UZRLLLk04e04TOm10KzAAAEFIPbUzhMkRN5/DjodK+mzjO7HmM+adu7qxYWGlEWDDrFnAQb9AwECwCIgUJKbdMGgSVS3i0tgNel6XgeKWg8o7JbVR7/ums6AOsCsA8AiIFCSm3TBoElUt4tLYDXpel4HiloPKOyW1Ue/7prOgDrBrAPAIiAiWLHDFgvghkpUGFTuyRZKVy8JT3ViYoKBqAc7uJFzp6wCwCIgUJKbdMGgSVS3i0tgNel6XgeKWg8o7JbVR7/ums6AOsKsA8AiIFCSm3TBoElUt4tLYDXpel4HiloPKOyW1Ue/7prOgDrDrATAIiBQkpt0waBJVLeLS2A16XpeB4paDyjsltVHv+6azoA6xKwEwCIgVffrwKnZ3q5dJvKufbe8LgoyNFGUSyy5NOHtOEzptdCsAA=="
},
{
- "description": "Adds taproot output with internal key only and correct address",
+ "description": "Adds taproot output with internal tap key and correct address",
"isTaproot": true,
"psbt": "cHNidP8BAFwCAAAAAk9Ve2845C8v//JR71uKzf70FjeNfx7SvB4l3A+Q44UKAAAAAAD/////FIp10hu+RPgTSFGPmjwb01Tf/a5UkcPFUpOw/X6UEPYAAAAAAP////8AAAAAAAABASugaAYAAAAAACJRINqadqaDhePTT29qdKQScUmyJxEeDw12HLjkMYMVSlnkARcgDN4bJzix3HdE8+FUM6UgA1lEKpgpIImVUePmAGYh7yYAAQDAAgAAAAFbIoaAJqDd/f4mZppgYV4UR9bgU8lT9pTH4/aDJdFUWgAAAABrSDBFAiEA6JS0xMdSQhG+9gAPSxGs6HazyauyNUBMwrmF386IAxwCIGiyH9QHCzKOBTtg+VsISF4nUi9NfAtJAtC02J03+I07ASEDu1tkEI8W1bd6qrPZ3uLaHvE90BDUvRCwvTTzPYPXzwf/////AaBoBgAAAAAAGXapFL5QEf51k4TA7Mp5d18IM2ddq79oiKwAAAAAAAA=",
"outputData": {
@@ -607,7 +607,7 @@
"result": "cHNidP8BAIcCAAAAAk9Ve2845C8v//JR71uKzf70FjeNfx7SvB4l3A+Q44UKAAAAAAD/////FIp10hu+RPgTSFGPmjwb01Tf/a5UkcPFUpOw/X6UEPYAAAAAAP////8BkEEGAAAAAAAiUSD1RJYlvhzbiZ/sFzOK3lWwglnOTOhYaiULBDKBC1TV7wAAAAAAAQEroGgGAAAAAAAiUSDamnamg4Xj009vanSkEnFJsicRHg8Ndhy45DGDFUpZ5AEXIAzeGyc4sdx3RPPhVDOlIANZRCqYKSCJlVHj5gBmIe8mAAEAwAIAAAABWyKGgCag3f3+JmaaYGFeFEfW4FPJU/aUx+P2gyXRVFoAAAAAa0gwRQIhAOiUtMTHUkIRvvYAD0sRrOh2s8mrsjVATMK5hd/OiAMcAiBosh/UBwsyjgU7YPlbCEheJ1IvTXwLSQLQtNidN/iNOwEhA7tbZBCPFtW3eqqz2d7i2h7xPdAQ1L0QsL008z2D188H/////wGgaAYAAAAAABl2qRS+UBH+dZOEwOzKeXdfCDNnXau/aIisAAAAAAABBSCITZaUOd7O0h0atx7NnvmmqHlSFViM5+/0rV78kD5A7AA="
},
{
- "description": "Adds taproot output with internal key and bad address",
+ "description": "Adds taproot output with internal tap key and bad address",
"isTaproot": true,
"psbt": "cHNidP8BAFwCAAAAAk9Ve2845C8v//JR71uKzf70FjeNfx7SvB4l3A+Q44UKAAAAAAD/////FIp10hu+RPgTSFGPmjwb01Tf/a5UkcPFUpOw/X6UEPYAAAAAAP////8AAAAAAAABASugaAYAAAAAACJRINqadqaDhePTT29qdKQScUmyJxEeDw12HLjkMYMVSlnkARcgDN4bJzix3HdE8+FUM6UgA1lEKpgpIImVUePmAGYh7yYAAQDAAgAAAAFbIoaAJqDd/f4mZppgYV4UR9bgU8lT9pTH4/aDJdFUWgAAAABrSDBFAiEA6JS0xMdSQhG+9gAPSxGs6HazyauyNUBMwrmF386IAxwCIGiyH9QHCzKOBTtg+VsISF4nUi9NfAtJAtC02J03+I07ASEDu1tkEI8W1bd6qrPZ3uLaHvE90BDUvRCwvTTzPYPXzwf/////AaBoBgAAAAAAGXapFL5QEf51k4TA7Mp5d18IM2ddq79oiKwAAAAAAAA=",
"outputData": {
@@ -640,7 +640,7 @@
"exception": "Can not modify transaction, signatures exist."
},
{
- "description": "Adds output after tapkey spend input has been finalized",
+ "description": "Adds output after tap key input has been finalized",
"isTaproot": true,
"psbt": "cHNidP8BAF4CAAAAAfyhtBTm+3OPYBuMHvdPMf9jqniZDY925hbmnt8hxbA6AAAAAAD/////AZBBBgAAAAAAIlEgV6CyzSs5a6Tc8A+TYOiozWnh6FRH9E/VWFanhMAEbLEAAAAAAAEBK6BoBgAAAAAAIlEgV6CyzSs5a6Tc8A+TYOiozWnh6FRH9E/VWFanhMAEbLEBCEIBQOAqWBD/2jhPWzQvesT8sjkN2Cowphp3QvmlWbHiLx753ChcUovvWyBlWiCq77Kk+lZGEhC4vjClSjc26br+dc8AAA==",
"outputData": {
diff --git a/test/integration/taproot.spec.ts b/test/integration/taproot.spec.ts
index d35c9c474..ba870c5f1 100644
--- a/test/integration/taproot.spec.ts
+++ b/test/integration/taproot.spec.ts
@@ -490,8 +490,6 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
});
it('can create (and broadcast via 3PBP) a taproot script-path spend Transaction - custom finalizer', async () => {
-
-
const leafCount = 8;
const leaves = Array.from({ length: leafCount }).map(
(_, index) =>
@@ -517,7 +515,6 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
network: regtest,
});
-
// amount from faucet
const amount = 42e4;
// amount to send
@@ -551,14 +548,11 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
leafIndex,
);
psbt.finalizeInput(0, leafIndexFinalizerFn);
- console.log('### psbt finalized', psbt.toBase64());
const tx = psbt.extractTransaction();
const rawTx = tx.toBuffer();
const hex = rawTx.toString('hex');
- console.log('### hex', hex)
await regtestUtils.broadcast(hex);
- console.log('### verify')
await regtestUtils.verify({
txId: tx.getId(),
address: sendAddress!,
From 94f52911512b122e6d16d13f2a1ae8c664d7a1b5 Mon Sep 17 00:00:00 2001
From: junderw
Date: Fri, 27 May 2022 00:47:13 +0900
Subject: [PATCH 086/144] Fix integration test
---
test/integration/taproot.spec.ts | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/test/integration/taproot.spec.ts b/test/integration/taproot.spec.ts
index ba870c5f1..4d1c343af 100644
--- a/test/integration/taproot.spec.ts
+++ b/test/integration/taproot.spec.ts
@@ -576,7 +576,8 @@ function buildLeafIndexFinalizer(
} => {
try {
const scriptSolution = [
- bitcoin.script.fromASM(`OP_${leafIndex} OP_${leafIndex}`),
+ Buffer.from([leafIndex]),
+ Buffer.from([leafIndex]),
];
const witness = scriptSolution
.concat(tapLeafScript.script)
From 724be84bebb749ac0207221fcb21bbdf81e3ea12 Mon Sep 17 00:00:00 2001
From: junderw
Date: Fri, 27 May 2022 00:52:17 +0900
Subject: [PATCH 087/144] Fix test lints
---
test/integration/taproot.spec.ts | 12 +++++++++---
test/payments.utils.ts | 2 +-
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/test/integration/taproot.spec.ts b/test/integration/taproot.spec.ts
index 4d1c343af..b12c46f31 100644
--- a/test/integration/taproot.spec.ts
+++ b/test/integration/taproot.spec.ts
@@ -269,7 +269,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
const sendPubKey = toXOnly(sendInternalKey.publicKey);
const { address: sendAddress } = bitcoin.payments.p2tr({
internalPubkey: sendPubKey,
- scriptTree: scriptTree,
+ scriptTree,
network: regtest,
});
@@ -360,7 +360,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
const sendPubKey = toXOnly(sendInternalKey.publicKey);
const { address: sendAddress } = bitcoin.payments.p2tr({
internalPubkey: sendPubKey,
- scriptTree: scriptTree,
+ scriptTree,
network: regtest,
});
@@ -566,7 +566,13 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
function buildLeafIndexFinalizer(
tapLeafScript: TapLeafScript,
leafIndex: number,
-) {
+): (
+ inputIndex: number,
+ _input: PsbtInput,
+ _tapLeafHashToFinalize?: Buffer,
+) => {
+ finalScriptWitness: Buffer | undefined;
+} {
return (
inputIndex: number,
_input: PsbtInput,
diff --git a/test/payments.utils.ts b/test/payments.utils.ts
index 3f86770e8..e2599204c 100644
--- a/test/payments.utils.ts
+++ b/test/payments.utils.ts
@@ -188,7 +188,7 @@ export function from(path: string, object: any, result?: any): any {
export function convertScriptTree(scriptTree: any, leafVersion?: number): any {
if (Array.isArray(scriptTree))
- return scriptTree.map(t => convertScriptTree(t, leafVersion));
+ return scriptTree.map(tr => convertScriptTree(tr, leafVersion));
const script = Object.assign({}, scriptTree);
if (typeof script.output === 'string') {
From 4db845597fb8048a5d6f69d8cdc6aeb7af1f74a0 Mon Sep 17 00:00:00 2001
From: junderw
Date: Fri, 27 May 2022 00:56:53 +0900
Subject: [PATCH 088/144] Fix audit
---
package-lock.json | 413 ++++++++++++----------------------------------
1 file changed, 104 insertions(+), 309 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 7cb07959e..608cf71eb 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -24,15 +24,15 @@
}
},
"@babel/compat-data": {
- "version": "7.18.5",
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.5.tgz",
- "integrity": "sha512-BxhE40PVCBxVEJsSBhB6UWyAuqJRxGsAw8BdHMJ3AKGydcwuWW4kOO3HmqBQAdcq/OP+/DlTVxLvsCzRTnZuGg==",
+ "version": "7.17.10",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.10.tgz",
+ "integrity": "sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw==",
"dev": true
},
"@babel/core": {
- "version": "7.18.5",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.5.tgz",
- "integrity": "sha512-MGY8vg3DxMnctw0LdvSEojOsumc70g0t18gNyUdAZqB1Rpd1Bqo/svHGvt+UJ6JcGX+DIekGFDxxIWofBxLCnQ==",
+ "version": "7.18.2",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.2.tgz",
+ "integrity": "sha512-A8pri1YJiC5UnkdrWcmfZTJTV85b4UXTAfImGmCfYmax4TR9Cw8sDS0MOk++Gp2mE/BefVJ5nwy5yzqNJbP/DQ==",
"dev": true,
"requires": {
"@ampproject/remapping": "^2.1.0",
@@ -41,10 +41,10 @@
"@babel/helper-compilation-targets": "^7.18.2",
"@babel/helper-module-transforms": "^7.18.0",
"@babel/helpers": "^7.18.2",
- "@babel/parser": "^7.18.5",
+ "@babel/parser": "^7.18.0",
"@babel/template": "^7.16.7",
- "@babel/traverse": "^7.18.5",
- "@babel/types": "^7.18.4",
+ "@babel/traverse": "^7.18.2",
+ "@babel/types": "^7.18.2",
"convert-source-map": "^1.7.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
@@ -235,9 +235,9 @@
}
},
"@babel/parser": {
- "version": "7.18.5",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.5.tgz",
- "integrity": "sha512-YZWVaglMiplo7v8f1oMQ5ZPQr0vn7HPeZXxXWsxXJRjGVrzUFn9OxFQl1sb5wzfootjA/yChhW84BV+383FSOw==",
+ "version": "7.18.3",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.3.tgz",
+ "integrity": "sha512-rL50YcEuHbbauAFAysNsJA4/f89fGTOBRNs9P81sniKnKAr4xULe5AecolcsKbi88xu0ByWYDj/S1AJ3FSFuSQ==",
"dev": true
},
"@babel/template": {
@@ -274,9 +274,9 @@
}
},
"@babel/traverse": {
- "version": "7.18.5",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.5.tgz",
- "integrity": "sha512-aKXj1KT66sBj0vVzk6rEeAO6Z9aiiQ68wfDgge3nHhA/my6xMM/7HGQUNumKZaoa2qUPQ5whJG9aAifsxUKfLA==",
+ "version": "7.18.2",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.2.tgz",
+ "integrity": "sha512-9eNwoeovJ6KH9zcCNnENY7DMFwTU9JdGCFtqNLfUAqtUHRCOsTOqWoffosP8vKmNYeSBUv3yVJXjfd8ucwOjUA==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.16.7",
@@ -285,8 +285,8 @@
"@babel/helper-function-name": "^7.17.9",
"@babel/helper-hoist-variables": "^7.16.7",
"@babel/helper-split-export-declaration": "^7.16.7",
- "@babel/parser": "^7.18.5",
- "@babel/types": "^7.18.4",
+ "@babel/parser": "^7.18.0",
+ "@babel/types": "^7.18.2",
"debug": "^4.1.0",
"globals": "^11.1.0"
},
@@ -314,9 +314,9 @@
}
},
"@babel/types": {
- "version": "7.18.4",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.4.tgz",
- "integrity": "sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw==",
+ "version": "7.18.2",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.2.tgz",
+ "integrity": "sha512-0On6B8A4/+mFUto5WERt3EEuG1NznDirvwca1O8UwXQHVY8g3R7OzYgxXdOfMwLO08UrpUD/2+3Bclyq+/C94Q==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.16.7",
@@ -336,12 +336,6 @@
"resolve-from": "^5.0.0"
},
"dependencies": {
- "camelcase": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
- "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
- "dev": true
- },
"find-up": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
@@ -361,15 +355,6 @@
"p-locate": "^4.1.0"
}
},
- "p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "dev": true,
- "requires": {
- "p-try": "^2.0.0"
- }
- },
"p-locate": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
@@ -488,15 +473,6 @@
"@types/node": "*"
}
},
- "@types/ripemd160": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/@types/ripemd160/-/ripemd160-2.0.0.tgz",
- "integrity": "sha512-LD6AO/+8cAa1ghXax9NG9iPDLPUEGB2WWPjd//04KYfXxTwHvlDEfL0NRjrM5z9XWBi6WbKw75Are0rDyn3PSA==",
- "dev": true,
- "requires": {
- "@types/node": "*"
- }
- },
"@types/wif": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@types/wif/-/wif-2.0.2.tgz",
@@ -522,18 +498,6 @@
"indent-string": "^4.0.0"
}
},
- "ajv": {
- "version": "8.11.0",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
- "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
- "dev": true,
- "requires": {
- "fast-deep-equal": "^3.1.1",
- "json-schema-traverse": "^1.0.0",
- "require-from-string": "^2.0.2",
- "uri-js": "^4.2.2"
- }
- },
"ansi-colors": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
@@ -595,12 +559,6 @@
"sprintf-js": "~1.0.2"
}
},
- "astral-regex": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
- "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
- "dev": true
- },
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
@@ -620,26 +578,6 @@
"resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz",
"integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg=="
},
- "better-npm-audit": {
- "version": "3.7.3",
- "resolved": "https://registry.npmjs.org/better-npm-audit/-/better-npm-audit-3.7.3.tgz",
- "integrity": "sha512-zsSiidlP5n7KpCYdAmkellu4JYA4IoRUUwrBMv/R7TwT8vcRfk5CQ2zTg7yUy4bdWkKtAj7VVdPQttdMbx+n5Q==",
- "dev": true,
- "requires": {
- "commander": "^8.0.0",
- "dayjs": "^1.10.6",
- "lodash.get": "^4.4.2",
- "table": "^6.7.1"
- },
- "dependencies": {
- "commander": {
- "version": "8.3.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
- "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
- "dev": true
- }
- }
- },
"binary-extensions": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
@@ -737,15 +675,15 @@
"dev": true
},
"browserslist": {
- "version": "4.20.4",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.4.tgz",
- "integrity": "sha512-ok1d+1WpnU24XYN7oC3QWgTyMhY/avPJ/r9T00xxvUOIparA/gc+UPUMaod3i+G6s+nI2nUb9xZ5k794uIwShw==",
+ "version": "4.20.3",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz",
+ "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==",
"dev": true,
"requires": {
- "caniuse-lite": "^1.0.30001349",
- "electron-to-chromium": "^1.4.147",
+ "caniuse-lite": "^1.0.30001332",
+ "electron-to-chromium": "^1.4.118",
"escalade": "^3.1.1",
- "node-releases": "^2.0.5",
+ "node-releases": "^2.0.3",
"picocolors": "^1.0.0"
}
},
@@ -792,15 +730,15 @@
}
},
"camelcase": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
- "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
"dev": true
},
"caniuse-lite": {
- "version": "1.0.30001352",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001352.tgz",
- "integrity": "sha512-GUgH8w6YergqPQDGWhJGt8GDRnY0L/iJVQcU3eJ46GYf52R8tk0Wxp0PymuFVZboJYXGiCqwozAYZNRjVj6IcA==",
+ "version": "1.0.30001343",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001343.tgz",
+ "integrity": "sha512-8KeCrAtPMabo/XW14B+R9sZYoClx1n0b+WYgwDKZPtWR3TcdvWzdSy7mPyFEmR5WU1St9v1PW6sdO5dkFOEzfA==",
"dev": true
},
"chalk": {
@@ -946,12 +884,6 @@
"which": "^2.0.1"
}
},
- "dayjs": {
- "version": "1.11.3",
- "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.3.tgz",
- "integrity": "sha512-xxwlswWOlGhzgQ4TKzASQkUhqERI3egRNqgV4ScR8wlANA/A9tZ7miXa44vTTKEq5l7vWoL5G57bG3zA+Kow0A==",
- "dev": true
- },
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@@ -970,9 +902,9 @@
}
},
"decamelize": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
- "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
"dev": true
},
"default-require-extensions": {
@@ -1011,9 +943,9 @@
}
},
"electron-to-chromium": {
- "version": "1.4.153",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.153.tgz",
- "integrity": "sha512-57AV9DNW1R52HjOqnGOCCTLHMHItLTGu/WjB1KYIa4BQ7p0u8J0j8N78akPcOBStKE801xcMjTpmbAylflfIYQ==",
+ "version": "1.4.139",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.139.tgz",
+ "integrity": "sha512-lYxzcUCjWxxVug+A7UxBCUiVr13TCjfZFYJS9Lq1VpU/ErwV4a6zUQo9dfojuGpw/L/x9REGuBl6ICQPGgbs3g==",
"dev": true
},
"emoji-regex": {
@@ -1046,12 +978,6 @@
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true
},
- "fast-deep-equal": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "dev": true
- },
"fill-keys": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz",
@@ -1226,7 +1152,7 @@
"imurmurhash": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
"dev": true
},
"indent-string": {
@@ -1262,7 +1188,7 @@
"is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
"dev": true
},
"is-fullwidth-code-point": {
@@ -1307,7 +1233,7 @@
"is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
- "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==",
+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
"dev": true
},
"is-unicode-supported": {
@@ -1325,7 +1251,7 @@
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
"dev": true
},
"istanbul-lib-coverage": {
@@ -1364,17 +1290,18 @@
}
},
"istanbul-lib-processinfo": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz",
- "integrity": "sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==",
+ "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,
"requires": {
"archy": "^1.0.0",
- "cross-spawn": "^7.0.3",
- "istanbul-lib-coverage": "^3.2.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": "^8.3.2"
+ "uuid": "^3.3.3"
},
"dependencies": {
"rimraf": {
@@ -1459,12 +1386,6 @@
"integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
"dev": true
},
- "json-schema-traverse": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
- "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
- "dev": true
- },
"json5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
@@ -1483,19 +1404,7 @@
"lodash.flattendeep": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
- "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==",
- "dev": true
- },
- "lodash.get": {
- "version": "4.4.2",
- "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
- "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==",
- "dev": true
- },
- "lodash.truncate": {
- "version": "4.4.2",
- "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
- "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==",
+ "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=",
"dev": true
},
"log-symbols": {
@@ -1769,6 +1678,12 @@
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true
},
+ "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
+ },
"nyc": {
"version": "15.1.0",
"resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz",
@@ -1813,12 +1728,6 @@
"color-convert": "^2.0.1"
}
},
- "camelcase": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
- "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
- "dev": true
- },
"cliui": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
@@ -1845,12 +1754,6 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
- "decamelize": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
- "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
- "dev": true
- },
"find-up": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
@@ -1893,15 +1796,6 @@
"brace-expansion": "^1.1.7"
}
},
- "p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "dev": true,
- "requires": {
- "p-try": "^2.0.0"
- }
- },
"p-locate": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
@@ -1931,12 +1825,6 @@
"strip-ansi": "^6.0.0"
}
},
- "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
- },
"yargs": {
"version": "15.4.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
@@ -1978,12 +1866,12 @@
}
},
"p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"dev": true,
"requires": {
- "yocto-queue": "^0.1.0"
+ "p-try": "^2.0.0"
}
},
"p-locate": {
@@ -1993,6 +1881,17 @@
"dev": true,
"requires": {
"p-limit": "^3.0.2"
+ },
+ "dependencies": {
+ "p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "requires": {
+ "yocto-queue": "^0.1.0"
+ }
+ }
}
},
"p-map": {
@@ -2099,15 +1998,6 @@
"p-locate": "^4.1.0"
}
},
- "p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "dev": true,
- "requires": {
- "p-try": "^2.0.0"
- }
- },
"p-locate": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
@@ -2145,12 +2035,6 @@
"resolve": "~1.8.1"
}
},
- "punycode": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
- "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
- "dev": true
- },
"pushdata-bitcoin": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/pushdata-bitcoin/-/pushdata-bitcoin-1.0.1.tgz",
@@ -2192,7 +2076,7 @@
"release-zalgo": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz",
- "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==",
+ "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=",
"dev": true,
"requires": {
"es6-error": "^4.0.1"
@@ -2201,13 +2085,7 @@
"require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
- "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
- "dev": true
- },
- "require-from-string": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
- "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
"dev": true
},
"require-main-filename": {
@@ -2288,7 +2166,7 @@
"set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
- "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
+ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
"dev": true
},
"sha.js": {
@@ -2321,49 +2199,6 @@
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"dev": true
},
- "slice-ansi": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
- "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.0.0",
- "astral-regex": "^2.0.0",
- "is-fullwidth-code-point": "^3.0.0"
- },
- "dependencies": {
- "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,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "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
- }
- }
- },
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@@ -2474,59 +2309,6 @@
}
}
},
- "table": {
- "version": "6.8.0",
- "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz",
- "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==",
- "dev": true,
- "requires": {
- "ajv": "^8.0.1",
- "lodash.truncate": "^4.4.2",
- "slice-ansi": "^4.0.0",
- "string-width": "^4.2.3",
- "strip-ansi": "^6.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true
- },
- "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
- },
- "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
- },
- "string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
- "requires": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- }
- },
- "strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- }
- }
- }
- },
"test-exclude": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
@@ -2577,7 +2359,7 @@
"to-fast-properties": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
- "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
+ "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
"dev": true
},
"to-regex-range": {
@@ -2686,19 +2468,10 @@
"integrity": "sha512-aIvEHNRX1AlOYAr6qSUjQBn4mCduxx6MtC967aRDTb2UUBPj0Ix2ZFQDcmXUUO/UxRPHcw1f5a5nVbCSKDSOqA==",
"dev": true
},
- "uri-js": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
- "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
- "dev": true,
- "requires": {
- "punycode": "^2.1.0"
- }
- },
"uuid": {
- "version": "8.3.2",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
- "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
+ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"dev": true
},
"varuint-bitcoin": {
@@ -2721,7 +2494,7 @@
"which-module": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
- "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==",
+ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
"dev": true
},
"wif": {
@@ -2794,9 +2567,9 @@
}
},
"y18n": {
- "version": "5.0.8",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
- "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
+ "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
"dev": true
},
"yargs": {
@@ -2812,6 +2585,14 @@
"string-width": "^4.2.0",
"y18n": "^5.0.5",
"yargs-parser": "^20.2.2"
+ },
+ "dependencies": {
+ "y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "dev": true
+ }
}
},
"yargs-parser": {
@@ -2830,6 +2611,20 @@
"decamelize": "^4.0.0",
"flat": "^5.0.2",
"is-plain-obj": "^2.1.0"
+ },
+ "dependencies": {
+ "camelcase": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
+ "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
+ "dev": true
+ },
+ "decamelize": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
+ "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
+ "dev": true
+ }
}
},
"yn": {
From 7839476784c7dcb747dba6c2b4b5e3704ab21257 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Wed, 1 Jun 2022 06:33:51 +0300
Subject: [PATCH 089/144] refactor: rename `taprootutils` to `bip341`
---
.../{taprootutils.d.ts => bip341.d.ts} | 0
src/payments/{taprootutils.js => bip341.js} | 0
src/payments/p2tr.js | 36 ++++++++-----------
src/psbt.js | 4 +--
src/psbt/bip371.js | 18 +++++-----
test/psbt.spec.ts | 2 +-
.../payments/{taprootutils.ts => bip341.ts} | 0
ts_src/payments/p2tr.ts | 2 +-
ts_src/psbt.ts | 2 +-
ts_src/psbt/bip371.ts | 2 +-
10 files changed, 30 insertions(+), 36 deletions(-)
rename src/payments/{taprootutils.d.ts => bip341.d.ts} (100%)
rename src/payments/{taprootutils.js => bip341.js} (100%)
rename ts_src/payments/{taprootutils.ts => bip341.ts} (100%)
diff --git a/src/payments/taprootutils.d.ts b/src/payments/bip341.d.ts
similarity index 100%
rename from src/payments/taprootutils.d.ts
rename to src/payments/bip341.d.ts
diff --git a/src/payments/taprootutils.js b/src/payments/bip341.js
similarity index 100%
rename from src/payments/taprootutils.js
rename to src/payments/bip341.js
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index cb16ab25e..182aa62c6 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -6,7 +6,7 @@ const networks_1 = require('../networks');
const bscript = require('../script');
const types_1 = require('../types');
const ecc_lib_1 = require('../ecc_lib');
-const taprootutils_1 = require('./taprootutils');
+const bip341_1 = require('./bip341');
const lazy = require('./lazy');
const bech32_1 = require('bech32');
const OPS = bscript.OPS;
@@ -69,7 +69,7 @@ function p2tr(a, opts) {
return a.witness.slice();
});
const _hashTree = lazy.value(() => {
- if (a.scriptTree) return (0, taprootutils_1.toHashTree)(a.scriptTree);
+ if (a.scriptTree) return (0, bip341_1.toHashTree)(a.scriptTree);
if (a.hash) return { hash: a.hash };
return;
});
@@ -89,11 +89,11 @@ function p2tr(a, opts) {
const controlBlock = w[w.length - 1];
const leafVersion = controlBlock[0] & types_1.TAPLEAF_VERSION_MASK;
const script = w[w.length - 2];
- const leafHash = (0, taprootutils_1.tapleafHash)({
+ const leafHash = (0, bip341_1.tapleafHash)({
output: script,
version: leafVersion,
});
- return (0, taprootutils_1.rootHashFromPath)(controlBlock, leafHash);
+ return (0, bip341_1.rootHashFromPath)(controlBlock, leafHash);
}
return null;
});
@@ -110,7 +110,7 @@ function p2tr(a, opts) {
) {
return a.redeem.redeemVersion;
}
- return taprootutils_1.LEAF_VERSION_TAPSCRIPT;
+ return bip341_1.LEAF_VERSION_TAPSCRIPT;
});
lazy.prop(o, 'redeem', () => {
const witness = _witness(); // witness without annex
@@ -127,7 +127,7 @@ function p2tr(a, opts) {
if (a.output) return a.output.slice(2);
if (a.address) return _address().data;
if (o.internalPubkey) {
- const tweakedKey = (0, taprootutils_1.tweakKey)(o.internalPubkey, o.hash);
+ const tweakedKey = (0, bip341_1.tweakKey)(o.internalPubkey, o.hash);
if (tweakedKey) return tweakedKey.x;
}
});
@@ -147,16 +147,13 @@ function p2tr(a, opts) {
if (a.witness) return a.witness;
const hashTree = _hashTree();
if (hashTree && a.redeem && a.redeem.output && a.internalPubkey) {
- const leafHash = (0, taprootutils_1.tapleafHash)({
+ const leafHash = (0, bip341_1.tapleafHash)({
output: a.redeem.output,
version: o.redeemVersion,
});
- const path = (0, taprootutils_1.findScriptPath)(hashTree, leafHash);
+ const path = (0, bip341_1.findScriptPath)(hashTree, leafHash);
if (!path) return;
- const outputKey = (0, taprootutils_1.tweakKey)(
- a.internalPubkey,
- hashTree.hash,
- );
+ const outputKey = (0, bip341_1.tweakKey)(a.internalPubkey, hashTree.hash);
if (!outputKey) return;
const controlBock = buffer_1.Buffer.concat(
[
@@ -197,7 +194,7 @@ function p2tr(a, opts) {
else pubkey = a.output.slice(2);
}
if (a.internalPubkey) {
- const tweakedKey = (0, taprootutils_1.tweakKey)(a.internalPubkey, o.hash);
+ const tweakedKey = (0, bip341_1.tweakKey)(a.internalPubkey, o.hash);
if (pubkey.length > 0 && !pubkey.equals(tweakedKey.x))
throw new TypeError('Pubkey mismatch');
else pubkey = tweakedKey.x;
@@ -211,11 +208,11 @@ function p2tr(a, opts) {
if (!a.hash.equals(hashTree.hash)) throw new TypeError('Hash mismatch');
}
if (a.redeem && a.redeem.output && hashTree) {
- const leafHash = (0, taprootutils_1.tapleafHash)({
+ const leafHash = (0, bip341_1.tapleafHash)({
output: a.redeem.output,
version: o.redeemVersion,
});
- if (!(0, taprootutils_1.findScriptPath)(hashTree, leafHash))
+ if (!(0, bip341_1.findScriptPath)(hashTree, leafHash))
throw new TypeError('Redeem script not in tree');
}
const witness = _witness();
@@ -270,15 +267,12 @@ function p2tr(a, opts) {
throw new TypeError('Invalid internalPubkey for p2tr witness');
const leafVersion = controlBlock[0] & types_1.TAPLEAF_VERSION_MASK;
const script = witness[witness.length - 2];
- const leafHash = (0, taprootutils_1.tapleafHash)({
+ const leafHash = (0, bip341_1.tapleafHash)({
output: script,
version: leafVersion,
});
- const hash = (0, taprootutils_1.rootHashFromPath)(
- controlBlock,
- leafHash,
- );
- const outputKey = (0, taprootutils_1.tweakKey)(internalPubkey, hash);
+ const hash = (0, bip341_1.rootHashFromPath)(controlBlock, leafHash);
+ const outputKey = (0, bip341_1.tweakKey)(internalPubkey, hash);
if (!outputKey)
// todo: needs test data
throw new TypeError('Invalid outputKey for p2tr witness');
diff --git a/src/psbt.js b/src/psbt.js
index 2bc55e065..2f2e94a96 100644
--- a/src/psbt.js
+++ b/src/psbt.js
@@ -8,7 +8,7 @@ const address_1 = require('./address');
const bufferutils_1 = require('./bufferutils');
const networks_1 = require('./networks');
const payments = require('./payments');
-const taprootutils_1 = require('./payments/taprootutils');
+const bip341_1 = require('./payments/bip341');
const bscript = require('./script');
const transaction_1 = require('./transaction');
const bip371_1 = require('./psbt/bip371');
@@ -1325,7 +1325,7 @@ function getTaprootHashesForSig(
const tapLeafHashes = (input.tapLeafScript || [])
.filter(tapLeaf => (0, psbtutils_1.pubkeyInScript)(pubkey, tapLeaf.script))
.map(tapLeaf => {
- const hash = (0, taprootutils_1.tapleafHash)({
+ const hash = (0, bip341_1.tapleafHash)({
output: tapLeaf.script,
version: tapLeaf.leafVersion,
});
diff --git a/src/psbt/bip371.js b/src/psbt/bip371.js
index eee6b1393..fdf23c008 100644
--- a/src/psbt/bip371.js
+++ b/src/psbt/bip371.js
@@ -4,7 +4,7 @@ exports.checkTaprootInputForSigs = exports.tapTreeFromList = exports.tapTreeToLi
const types_1 = require('../types');
const transaction_1 = require('../transaction');
const psbtutils_1 = require('./psbtutils');
-const taprootutils_1 = require('../payments/taprootutils');
+const bip341_1 = require('../payments/bip341');
const payments_1 = require('../payments');
const psbtutils_2 = require('./psbtutils');
const toXOnly = pubKey => (pubKey.length === 32 ? pubKey : pubKey.slice(1, 33));
@@ -101,7 +101,7 @@ function tweakInternalPubKey(inputIndex, input) {
const tapInternalKey = input.tapInternalKey;
const outputKey =
tapInternalKey &&
- (0, taprootutils_1.tweakKey)(tapInternalKey, input.tapMerkleRoot);
+ (0, bip341_1.tweakKey)(tapInternalKey, input.tapMerkleRoot);
if (!outputKey)
throw new Error(
`Cannot tweak tap internal key for input #${inputIndex}. Public key: ${tapInternalKey &&
@@ -175,13 +175,13 @@ function getTapKeySigFromWithness(finalScriptWitness) {
if (witness.length === 64 || witness.length === 65) return witness;
}
function _tapTreeToList(tree, leaves = [], depth = 0) {
- if (depth > taprootutils_1.MAX_TAPTREE_DEPTH)
+ if (depth > bip341_1.MAX_TAPTREE_DEPTH)
throw new Error('Max taptree depth exceeded.');
if (!tree) return [];
if ((0, types_1.isTapleaf)(tree)) {
leaves.push({
depth,
- leafVersion: tree.version || taprootutils_1.LEAF_VERSION_TAPSCRIPT,
+ leafVersion: tree.version || bip341_1.LEAF_VERSION_TAPSCRIPT,
script: tree.output,
});
return leaves;
@@ -199,7 +199,7 @@ function instertLeavesInTree(leaves) {
return tree;
}
function instertLeafInTree(leaf, tree, depth = 0) {
- if (depth > taprootutils_1.MAX_TAPTREE_DEPTH)
+ if (depth > bip341_1.MAX_TAPTREE_DEPTH)
throw new Error('Max taptree depth exceeded.');
if (leaf.depth === depth) {
if (!tree)
@@ -275,18 +275,18 @@ function checkIfTapLeafInTree(inputData, newInputData, action) {
}
function isTapLeafInTree(tapLeaf, merkleRoot) {
if (!merkleRoot) return true;
- const leafHash = (0, taprootutils_1.tapleafHash)({
+ const leafHash = (0, bip341_1.tapleafHash)({
output: tapLeaf.script,
version: tapLeaf.leafVersion,
});
- const rootHash = (0, taprootutils_1.rootHashFromPath)(
+ const rootHash = (0, bip341_1.rootHashFromPath)(
tapLeaf.controlBlock,
leafHash,
);
return rootHash.equals(merkleRoot);
}
function sortSignatures(input, tapLeaf) {
- const leafHash = (0, taprootutils_1.tapleafHash)({
+ const leafHash = (0, bip341_1.tapleafHash)({
output: tapLeaf.script,
version: tapLeaf.leafVersion,
});
@@ -327,7 +327,7 @@ function findTapLeafToFinalize(input, inputIndex, leafHashToFinalize) {
return tapLeaf;
}
function canFinalizeLeaf(leaf, tapScriptSig, hash) {
- const leafHash = (0, taprootutils_1.tapleafHash)({
+ const leafHash = (0, bip341_1.tapleafHash)({
output: leaf.script,
version: leaf.leafVersion,
});
diff --git a/test/psbt.spec.ts b/test/psbt.spec.ts
index bbddb67c8..6d295a80f 100644
--- a/test/psbt.spec.ts
+++ b/test/psbt.spec.ts
@@ -6,7 +6,7 @@ import ECPairFactory from 'ecpair';
import { describe, it } from 'mocha';
import { convertScriptTree } from './payments.utils';
-import { LEAF_VERSION_TAPSCRIPT } from '../src/payments/taprootutils';
+import { LEAF_VERSION_TAPSCRIPT } from '../src/payments/bip341';
import { tapTreeToList, tapTreeFromList } from '../src/psbt/bip371';
import { Taptree } from '../src/types';
import { initEccLib } from '../src';
diff --git a/ts_src/payments/taprootutils.ts b/ts_src/payments/bip341.ts
similarity index 100%
rename from ts_src/payments/taprootutils.ts
rename to ts_src/payments/bip341.ts
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index 00b9e59ad..64c591ffd 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -10,7 +10,7 @@ import {
tapleafHash,
tweakKey,
LEAF_VERSION_TAPSCRIPT,
-} from './taprootutils';
+} from './bip341';
import { Payment, PaymentOpts } from './index';
import * as lazy from './lazy';
import { bech32m } from 'bech32';
diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts
index a3b66c7e0..df3cf22ad 100644
--- a/ts_src/psbt.ts
+++ b/ts_src/psbt.ts
@@ -19,7 +19,7 @@ import { fromOutputScript, toOutputScript } from './address';
import { cloneBuffer, reverseBuffer } from './bufferutils';
import { bitcoin as btcNetwork, Network } from './networks';
import * as payments from './payments';
-import { tapleafHash } from './payments/taprootutils';
+import { tapleafHash } from './payments/bip341';
import * as bscript from './script';
import { Output, Transaction } from './transaction';
import {
diff --git a/ts_src/psbt/bip371.ts b/ts_src/psbt/bip371.ts
index 153e289ec..d743fdb66 100644
--- a/ts_src/psbt/bip371.ts
+++ b/ts_src/psbt/bip371.ts
@@ -22,7 +22,7 @@ import {
rootHashFromPath,
LEAF_VERSION_TAPSCRIPT,
MAX_TAPTREE_DEPTH,
-} from '../payments/taprootutils';
+} from '../payments/bip341';
import { p2tr } from '../payments';
import { signatureBlocksAction } from './psbtutils';
From 6f40ec84fae08fe5047c5e5f6214a1551e26e000 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Tue, 29 Nov 2022 10:02:40 +0200
Subject: [PATCH 090/144] chore: fix typo
---
src/psbt/bip371.js | 4 ++--
ts_src/psbt/bip371.ts | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/psbt/bip371.js b/src/psbt/bip371.js
index fdf23c008..c9706b7bb 100644
--- a/src/psbt/bip371.js
+++ b/src/psbt/bip371.js
@@ -146,11 +146,11 @@ exports.tapTreeFromList = tapTreeFromList;
function checkTaprootInputForSigs(input, action) {
const sigs = extractTaprootSigs(input);
return sigs.some(sig =>
- (0, psbtutils_2.signatureBlocksAction)(sig, decodeSchnorSignature, action),
+ (0, psbtutils_2.signatureBlocksAction)(sig, decodeSchnorrSignature, action),
);
}
exports.checkTaprootInputForSigs = checkTaprootInputForSigs;
-function decodeSchnorSignature(signature) {
+function decodeSchnorrSignature(signature) {
return {
signature: signature.slice(0, 64),
hashType:
diff --git a/ts_src/psbt/bip371.ts b/ts_src/psbt/bip371.ts
index d743fdb66..c1f146b0b 100644
--- a/ts_src/psbt/bip371.ts
+++ b/ts_src/psbt/bip371.ts
@@ -201,11 +201,11 @@ export function checkTaprootInputForSigs(
): boolean {
const sigs = extractTaprootSigs(input);
return sigs.some(sig =>
- signatureBlocksAction(sig, decodeSchnorSignature, action),
+ signatureBlocksAction(sig, decodeSchnorrSignature, action),
);
}
-function decodeSchnorSignature(
+function decodeSchnorrSignature(
signature: Buffer,
): {
signature: Buffer;
From 80a31dbe7f3fef085242da3fc55b40c0febe5c33 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Tue, 29 Nov 2022 10:06:59 +0200
Subject: [PATCH 091/144] fix: add check for `controlBlock` length
---
src/payments/bip341.js | 6 ++++++
ts_src/payments/bip341.ts | 6 ++++++
2 files changed, 12 insertions(+)
diff --git a/src/payments/bip341.js b/src/payments/bip341.js
index 4832d358d..02c976b5f 100644
--- a/src/payments/bip341.js
+++ b/src/payments/bip341.js
@@ -10,6 +10,12 @@ exports.LEAF_VERSION_TAPSCRIPT = 0xc0;
exports.MAX_TAPTREE_DEPTH = 128;
const isHashBranch = ht => 'left' in ht && 'right' in ht;
function rootHashFromPath(controlBlock, leafHash) {
+ if (controlBlock.length < 33)
+ throw new TypeError(
+ `The control-block length is too small. Got ${
+ controlBlock.length
+ }, expected min 33.`,
+ );
const m = (controlBlock.length - 33) / 32;
let kj = leafHash;
for (let j = 0; j < m; j++) {
diff --git a/ts_src/payments/bip341.ts b/ts_src/payments/bip341.ts
index 503819325..5a1dd068d 100644
--- a/ts_src/payments/bip341.ts
+++ b/ts_src/payments/bip341.ts
@@ -38,6 +38,12 @@ export function rootHashFromPath(
controlBlock: Buffer,
leafHash: Buffer,
): Buffer {
+ if (controlBlock.length < 33)
+ throw new TypeError(
+ `The control-block length is too small. Got ${
+ controlBlock.length
+ }, expected min 33.`,
+ );
const m = (controlBlock.length - 33) / 32;
let kj = leafHash;
From d5181dfe704bb707c0a1a2c3fb80c270383996e3 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Tue, 29 Nov 2022 10:10:33 +0200
Subject: [PATCH 092/144] chore: typo in comment
---
ts_src/psbt/bip371.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ts_src/psbt/bip371.ts b/ts_src/psbt/bip371.ts
index c1f146b0b..d4eaaa5f3 100644
--- a/ts_src/psbt/bip371.ts
+++ b/ts_src/psbt/bip371.ts
@@ -235,7 +235,7 @@ function getTapKeySigFromWithness(
): Buffer | undefined {
if (!finalScriptWitness) return;
const witness = finalScriptWitness.slice(2);
- // todo: add schnor signature validation
+ // todo: add schnorr signature validation
if (witness.length === 64 || witness.length === 65) return witness;
}
From 99603061acb6a90964e952bf317e4e2b074ef2ec Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Tue, 29 Nov 2022 10:17:40 +0200
Subject: [PATCH 093/144] chore: remove `any` type
---
src/psbt/bip371.js | 2 +-
ts_src/psbt.ts | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/psbt/bip371.js b/src/psbt/bip371.js
index c9706b7bb..8e76ecda7 100644
--- a/src/psbt/bip371.js
+++ b/src/psbt/bip371.js
@@ -171,7 +171,7 @@ function extractTaprootSigs(input) {
function getTapKeySigFromWithness(finalScriptWitness) {
if (!finalScriptWitness) return;
const witness = finalScriptWitness.slice(2);
- // todo: add schnor signature validation
+ // todo: add schnorr signature validation
if (witness.length === 64 || witness.length === 65) return witness;
}
function _tapTreeToList(tree, leaves = [], depth = 0) {
diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts
index df3cf22ad..824e70a87 100644
--- a/ts_src/psbt.ts
+++ b/ts_src/psbt.ts
@@ -1739,8 +1739,8 @@ function getTaprootHashesForSig(
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);
+ const signingScripts = prevOuts.map(o => o.script);
+ const values = prevOuts.map(o => o.value);
const hashes = [];
if (input.tapInternalKey && !tapLeafHashToSign) {
From 57f915e8647c88a589bc659a971566d4012df34f Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Tue, 29 Nov 2022 10:19:34 +0200
Subject: [PATCH 094/144] chore: add explicit type for returned signatures
---
ts_src/psbt.ts | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts
index 824e70a87..aa546bc71 100644
--- a/ts_src/psbt.ts
+++ b/ts_src/psbt.ts
@@ -995,7 +995,9 @@ export class Psbt {
sighashTypes,
);
- const signaturePromises: Promise[] = [];
+ const signaturePromises: Promise<
+ { tapKeySig: Buffer } | { tapScriptSig: TapScriptSig[] }
+ >[] = [];
const tapKeyHash = hashesForSig.filter(h => !h.leafHash)[0];
if (tapKeyHash) {
const tapKeySigPromise = Promise.resolve(
From c3b517375936a8970febffc102744de628295211 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Tue, 29 Nov 2022 10:44:23 +0200
Subject: [PATCH 095/144] chore: sync `package-lock.json`
---
package-lock.json | 154 ++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 148 insertions(+), 6 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 608cf71eb..f7ade2d30 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -473,6 +473,15 @@
"@types/node": "*"
}
},
+ "@types/ripemd160": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@types/ripemd160/-/ripemd160-2.0.0.tgz",
+ "integrity": "sha512-LD6AO/+8cAa1ghXax9NG9iPDLPUEGB2WWPjd//04KYfXxTwHvlDEfL0NRjrM5z9XWBi6WbKw75Are0rDyn3PSA==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
"@types/wif": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@types/wif/-/wif-2.0.2.tgz",
@@ -498,6 +507,18 @@
"indent-string": "^4.0.0"
}
},
+ "ajv": {
+ "version": "8.11.2",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz",
+ "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2",
+ "uri-js": "^4.2.2"
+ }
+ },
"ansi-colors": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
@@ -559,6 +580,12 @@
"sprintf-js": "~1.0.2"
}
},
+ "astral-regex": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
+ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
+ "dev": true
+ },
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
@@ -578,6 +605,26 @@
"resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz",
"integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg=="
},
+ "better-npm-audit": {
+ "version": "3.7.3",
+ "resolved": "https://registry.npmjs.org/better-npm-audit/-/better-npm-audit-3.7.3.tgz",
+ "integrity": "sha512-zsSiidlP5n7KpCYdAmkellu4JYA4IoRUUwrBMv/R7TwT8vcRfk5CQ2zTg7yUy4bdWkKtAj7VVdPQttdMbx+n5Q==",
+ "dev": true,
+ "requires": {
+ "commander": "^8.0.0",
+ "dayjs": "^1.10.6",
+ "lodash.get": "^4.4.2",
+ "table": "^6.7.1"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
+ "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
+ "dev": true
+ }
+ }
+ },
"binary-extensions": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
@@ -884,6 +931,12 @@
"which": "^2.0.1"
}
},
+ "dayjs": {
+ "version": "1.11.6",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.6.tgz",
+ "integrity": "sha512-zZbY5giJAinCG+7AGaw0wIhNZ6J8AhWuSXKvuc1KAyMiRsvGQWqh4L+MomvhdAYjN+lqvVCMq1I41e3YHvXkyQ==",
+ "dev": true
+ },
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@@ -978,6 +1031,12 @@
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true
},
+ "fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true
+ },
"fill-keys": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz",
@@ -1386,6 +1445,12 @@
"integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
"dev": true
},
+ "json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true
+ },
"json5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
@@ -1407,6 +1472,18 @@
"integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=",
"dev": true
},
+ "lodash.get": {
+ "version": "4.4.2",
+ "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
+ "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==",
+ "dev": true
+ },
+ "lodash.truncate": {
+ "version": "4.4.2",
+ "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
+ "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==",
+ "dev": true
+ },
"log-symbols": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
@@ -1678,12 +1755,6 @@
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true
},
- "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
- },
"nyc": {
"version": "15.1.0",
"resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz",
@@ -2035,6 +2106,12 @@
"resolve": "~1.8.1"
}
},
+ "punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+ "dev": true
+ },
"pushdata-bitcoin": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/pushdata-bitcoin/-/pushdata-bitcoin-1.0.1.tgz",
@@ -2088,6 +2165,12 @@
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
"dev": true
},
+ "require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+ "dev": true
+ },
"require-main-filename": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
@@ -2199,6 +2282,43 @@
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"dev": true
},
+ "slice-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
+ "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.0.0",
+ "astral-regex": "^2.0.0",
+ "is-fullwidth-code-point": "^3.0.0"
+ },
+ "dependencies": {
+ "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,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ }
+ }
+ },
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@@ -2309,6 +2429,19 @@
}
}
},
+ "table": {
+ "version": "6.8.1",
+ "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz",
+ "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==",
+ "dev": true,
+ "requires": {
+ "ajv": "^8.0.1",
+ "lodash.truncate": "^4.4.2",
+ "slice-ansi": "^4.0.0",
+ "string-width": "^4.2.3",
+ "strip-ansi": "^6.0.1"
+ }
+ },
"test-exclude": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
@@ -2468,6 +2601,15 @@
"integrity": "sha512-aIvEHNRX1AlOYAr6qSUjQBn4mCduxx6MtC967aRDTb2UUBPj0Ix2ZFQDcmXUUO/UxRPHcw1f5a5nVbCSKDSOqA==",
"dev": true
},
+ "uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dev": true,
+ "requires": {
+ "punycode": "^2.1.0"
+ }
+ },
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
From a72be9184950032158ef3c9f9d27f0a33139b5a9 Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Tue, 29 Nov 2022 10:54:47 +0200
Subject: [PATCH 096/144] fix: audit issue for `minimatch`
---
package-lock.json | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index f7ade2d30..2b477ac20 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1595,9 +1595,9 @@
}
},
"minimatch": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"requires": {
"brace-expansion": "^1.1.7"
From b994d465a269fade0cabb8516f480782200182ce Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Tue, 29 Nov 2022 10:58:44 +0200
Subject: [PATCH 097/144] 6.1.0-rc.0
---
package-lock.json | 2 +-
package.json | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 2b477ac20..17e16965a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "6.0.2",
+ "version": "6.1.0-rc.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 9cecfc352..b2414f42f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "6.0.2",
+ "version": "6.1.0-rc.0",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"types": "./src/index.d.ts",
From 1724115060369b6df4901988f639bbf91d85de14 Mon Sep 17 00:00:00 2001
From: Feli <>
Date: Mon, 5 Dec 2022 12:40:54 -0500
Subject: [PATCH 098/144] - upgraded prettier - installed eslint integrations -
removed tslint - added rules to match old tslint rules - ran linter on ts_src
and tests
---
.eslintrc | 57 +
.prettierignore | 1 +
.prettierrc.json | 5 +-
CONTRIBUTING.md | 2 +-
package-lock.json | 6560 ++++++++++++++++++++++---
package.json | 12 +-
src/address.js | 8 +-
src/bufferutils.js | 15 +-
src/crypto.d.ts | 2 +-
src/crypto.js | 24 +-
src/index.js | 22 +-
src/payments/bip341.d.ts | 2 +-
src/payments/bip341.js | 14 +-
src/payments/index.d.ts | 10 +-
src/payments/index.js | 26 +-
src/payments/p2tr.js | 4 +-
src/psbt.d.ts | 10 +-
src/psbt.js | 33 +-
src/psbt/bip371.js | 24 +-
src/psbt/psbtutils.d.ts | 2 +-
src/psbt/psbtutils.js | 14 +-
src/script.js | 17 +-
src/types.d.ts | 2 +-
src/types.js | 36 +-
test/integration/bip32.spec.ts | 5 +-
test/integration/csv.spec.ts | 1 -
test/integration/payments.spec.ts | 5 +-
test/integration/taproot.spec.ts | 5 +-
test/integration/transactions.spec.ts | 9 +-
test/psbt.spec.ts | 62 +-
test/script_signature.spec.ts | 4 +-
test/transaction.spec.ts | 2 +-
ts_src/crypto.ts | 16 +-
ts_src/payments/bip341.ts | 4 +-
ts_src/payments/p2sh.ts | 24 +-
ts_src/payments/p2tr.ts | 4 +-
ts_src/psbt.ts | 140 +-
ts_src/psbt/bip371.ts | 15 +-
ts_src/psbt/psbtutils.ts | 4 +-
ts_src/script.ts | 1 -
ts_src/types.ts | 6 +-
tslint.json | 40 -
42 files changed, 6125 insertions(+), 1124 deletions(-)
create mode 100644 .eslintrc
delete mode 100644 tslint.json
diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 000000000..cae665a54
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,57 @@
+{
+ "root": true,
+ "parser": "@typescript-eslint/parser",
+ "plugins": [
+ "@typescript-eslint"
+ ],
+ "extends": [
+ "eslint:recommended",
+ "prettier",
+ "plugin:@typescript-eslint/recommended",
+ "plugin:prettier/recommended"
+ ],
+ "rules": {
+ "prettier/prettier": ["error", {
+ "singleQuote": true,
+ "trailingComma": "all",
+
+ "endOfLine": "auto",
+ "arrowParens": "avoid",
+ "tabWidth": 2
+ }],
+
+ "arrow-body-style": "off",
+ "prefer-arrow-callback": "off",
+
+ "@typescript-eslint/array-type": 0,
+ "@typescript-eslint/no-inferrable-types": "off",
+ "@typescript-eslint/ban-types": "off",
+ "@typescript-eslint/no-unused-vars": "off",
+
+ "arrow-parens": "off",
+ "curly": "off",
+ "no-case-declarations": "off",
+
+ "quotes": "off",
+ "@typescript-eslint/quotes": ["error", "single", { "avoidEscape": true, "allowTemplateLiterals": true }],
+ "prefer-rest-params": "off",
+ "no-bitwise": "off",
+ "no-console": "off",
+ "no-empty": ["error", { "allowEmptyCatch": true }],
+
+ "@typescript-eslint/no-var-requires": "off",
+ "@typescript-eslint/no-non-null-assertion": "off",
+ "@typescript-eslint/no-explicit-any": "off",
+
+ "no-unused-expressions": "off",
+ "@typescript-eslint/no-unused-expressions": "off",
+
+ "space-before-function-paren": "off"
+ },
+ "env": {
+ "browser": true,
+ "amd": true,
+ "node": true
+ }
+ }
+
\ No newline at end of file
diff --git a/.prettierignore b/.prettierignore
index e69de29bb..191ae4cc9 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -0,0 +1 @@
+*.d.ts
\ No newline at end of file
diff --git a/.prettierrc.json b/.prettierrc.json
index a20502b7f..ccb9a0c17 100644
--- a/.prettierrc.json
+++ b/.prettierrc.json
@@ -1,4 +1,7 @@
{
"singleQuote": true,
- "trailingComma": "all"
+ "trailingComma": "all",
+ "endOfLine": "auto",
+ "arrowParens": "avoid",
+ "tabWidth": 2
}
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 2c72633de..c1df5e090 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -50,7 +50,7 @@ Refer to the [Git manual](https://git-scm.com/doc) for any information about `gi
## Regarding TypeScript
-This library is written in TypeScript with tslint, prettier, and the tsc transpiler. These tools will help during testing to notice improper logic before committing and sending a pull request.
+This library is written in TypeScript with eslint, prettier, and the tsc transpiler. These tools will help during testing to notice improper logic before committing and sending a pull request.
Some rules regarding TypeScript:
diff --git a/package-lock.json b/package-lock.json
index 17e16965a..67af0eb4d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,8 +1,4457 @@
{
"name": "bitcoinjs-lib",
"version": "6.1.0-rc.0",
- "lockfileVersion": 1,
+ "lockfileVersion": 2,
"requires": true,
+ "packages": {
+ "": {
+ "name": "bitcoinjs-lib",
+ "version": "6.1.0-rc.0",
+ "license": "MIT",
+ "dependencies": {
+ "bech32": "^2.0.0",
+ "bip174": "^2.1.0",
+ "bs58check": "^2.1.2",
+ "create-hash": "^1.1.0",
+ "ripemd160": "^2.0.2",
+ "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/ripemd160": "^2.0.0",
+ "@types/wif": "^2.0.2",
+ "@typescript-eslint/eslint-plugin": "^5.45.0",
+ "@typescript-eslint/parser": "^5.45.0",
+ "better-npm-audit": "^3.7.3",
+ "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",
+ "eslint": "^8.29.0",
+ "eslint-config-prettier": "^8.5.0",
+ "eslint-plugin-prettier": "^4.2.1",
+ "hoodwink": "^2.0.0",
+ "minimaldata": "^1.0.2",
+ "mocha": "^10.0.0",
+ "nyc": "^15.1.0",
+ "prettier": "^2.8.0",
+ "proxyquire": "^2.0.1",
+ "randombytes": "^2.1.0",
+ "regtest-client": "0.2.0",
+ "rimraf": "^2.6.3",
+ "tiny-secp256k1": "^2.2.0",
+ "ts-node": "^8.3.0",
+ "typescript": "^4.4.4"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/@ampproject/remapping": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
+ "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.1.0",
+ "@jridgewell/trace-mapping": "^0.3.9"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
+ "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
+ "dev": true,
+ "dependencies": {
+ "@babel/highlight": "^7.18.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/compat-data": {
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.5.tgz",
+ "integrity": "sha512-KZXo2t10+/jxmkhNXc7pZTqRvSOIvVv/+lJwHS+B2rErwOyjuVRh60yVpb7liQ1U5t7lLJ1bz+t8tSypUZdm0g==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.5.tgz",
+ "integrity": "sha512-UdOWmk4pNWTm/4DlPUl/Pt4Gz4rcEMb7CY0Y3eJl5Yz1vI8ZJGmHWaVE55LoxRjdpx0z259GE9U5STA9atUinQ==",
+ "dev": true,
+ "dependencies": {
+ "@ampproject/remapping": "^2.1.0",
+ "@babel/code-frame": "^7.18.6",
+ "@babel/generator": "^7.20.5",
+ "@babel/helper-compilation-targets": "^7.20.0",
+ "@babel/helper-module-transforms": "^7.20.2",
+ "@babel/helpers": "^7.20.5",
+ "@babel/parser": "^7.20.5",
+ "@babel/template": "^7.18.10",
+ "@babel/traverse": "^7.20.5",
+ "@babel/types": "^7.20.5",
+ "convert-source-map": "^1.7.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.1",
+ "semver": "^6.3.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
+ "node_modules/@babel/core/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/@babel/generator": {
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz",
+ "integrity": "sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.20.5",
+ "@jridgewell/gen-mapping": "^0.3.2",
+ "jsesc": "^2.5.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
+ "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/set-array": "^1.0.1",
+ "@jridgewell/sourcemap-codec": "^1.4.10",
+ "@jridgewell/trace-mapping": "^0.3.9"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.20.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz",
+ "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/compat-data": "^7.20.0",
+ "@babel/helper-validator-option": "^7.18.6",
+ "browserslist": "^4.21.3",
+ "semver": "^6.3.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets/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/@babel/helper-environment-visitor": {
+ "version": "7.18.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
+ "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-function-name": {
+ "version": "7.19.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz",
+ "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==",
+ "dev": true,
+ "dependencies": {
+ "@babel/template": "^7.18.10",
+ "@babel/types": "^7.19.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-hoist-variables": {
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
+ "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.18.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz",
+ "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.18.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.20.2",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.2.tgz",
+ "integrity": "sha512-zvBKyJXRbmK07XhMuujYoJ48B5yvvmM6+wcpv6Ivj4Yg6qO7NOZOSnvZN9CRl1zz1Z4cKf8YejmCMh8clOoOeA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-environment-visitor": "^7.18.9",
+ "@babel/helper-module-imports": "^7.18.6",
+ "@babel/helper-simple-access": "^7.20.2",
+ "@babel/helper-split-export-declaration": "^7.18.6",
+ "@babel/helper-validator-identifier": "^7.19.1",
+ "@babel/template": "^7.18.10",
+ "@babel/traverse": "^7.20.1",
+ "@babel/types": "^7.20.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-simple-access": {
+ "version": "7.20.2",
+ "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz",
+ "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.20.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-split-export-declaration": {
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
+ "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.18.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.19.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz",
+ "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.19.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
+ "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz",
+ "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.20.6",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.6.tgz",
+ "integrity": "sha512-Pf/OjgfgFRW5bApskEz5pvidpim7tEDPlFtKcNRXWmfHGn9IEI2W2flqRQXTFb7gIPTyK++N6rVHuwKut4XK6w==",
+ "dev": true,
+ "dependencies": {
+ "@babel/template": "^7.18.10",
+ "@babel/traverse": "^7.20.5",
+ "@babel/types": "^7.20.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/highlight": {
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
+ "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.18.6",
+ "chalk": "^2.0.0",
+ "js-tokens": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/highlight/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/@babel/highlight/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/@babel/highlight/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/@babel/highlight/node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "dev": true
+ },
+ "node_modules/@babel/highlight/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": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/@babel/highlight/node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/highlight/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/@babel/parser": {
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz",
+ "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==",
+ "dev": true,
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.18.10",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz",
+ "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.18.6",
+ "@babel/parser": "^7.18.10",
+ "@babel/types": "^7.18.10"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.5.tgz",
+ "integrity": "sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.18.6",
+ "@babel/generator": "^7.20.5",
+ "@babel/helper-environment-visitor": "^7.18.9",
+ "@babel/helper-function-name": "^7.19.0",
+ "@babel/helper-hoist-variables": "^7.18.6",
+ "@babel/helper-split-export-declaration": "^7.18.6",
+ "@babel/parser": "^7.20.5",
+ "@babel/types": "^7.20.5",
+ "debug": "^4.1.0",
+ "globals": "^11.1.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse/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/@babel/types": {
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz",
+ "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.19.4",
+ "@babel/helper-validator-identifier": "^7.19.1",
+ "to-fast-properties": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@eslint/eslintrc": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz",
+ "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==",
+ "dev": true,
+ "dependencies": {
+ "ajv": "^6.12.4",
+ "debug": "^4.3.2",
+ "espree": "^9.4.0",
+ "globals": "^13.15.0",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^4.1.0",
+ "minimatch": "^3.1.2",
+ "strip-json-comments": "^3.1.1"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@humanwhocodes/config-array": {
+ "version": "0.11.7",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz",
+ "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==",
+ "dev": true,
+ "dependencies": {
+ "@humanwhocodes/object-schema": "^1.2.1",
+ "debug": "^4.1.1",
+ "minimatch": "^3.0.5"
+ },
+ "engines": {
+ "node": ">=10.10.0"
+ }
+ },
+ "node_modules/@humanwhocodes/module-importer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+ "dev": true,
+ "engines": {
+ "node": ">=12.22"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@humanwhocodes/object-schema": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
+ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
+ "dev": true
+ },
+ "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/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/@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/js-yaml": {
+ "version": "3.14.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+ "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+ "dev": true,
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "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-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "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/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/@istanbuljs/schema": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
+ "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
+ "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/set-array": "^1.0.0",
+ "@jridgewell/sourcemap-codec": "^1.4.10"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
+ "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/set-array": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
+ "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.4.14",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
+ "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
+ "dev": true
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.17",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
+ "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/resolve-uri": "3.1.0",
+ "@jridgewell/sourcemap-codec": "1.4.14"
+ }
+ },
+ "node_modules/@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "dev": true,
+ "dependencies": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "dev": true,
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "dev": true,
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@types/bs58": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@types/bs58/-/bs58-4.0.1.tgz",
+ "integrity": "sha512-yfAgiWgVLjFCmRv8zAcOIHywYATEwiTVccTLnRp6UxTNavT55M9d/uhK3T03St/+8/z/wW+CRjGKUNmEqoHHCA==",
+ "dev": true,
+ "dependencies": {
+ "base-x": "^3.0.6"
+ }
+ },
+ "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/json-schema": {
+ "version": "7.0.11",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
+ "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
+ "dev": true
+ },
+ "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.18.4",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.4.tgz",
+ "integrity": "sha512-9qGjJ5GyShZjUfx2ArBIGM+xExdfLvvaCyQR0t6yRXKPcWCVYF/WemtX/uIU3r7FYECXRXkIiw2Vnhn6y8d+pw==",
+ "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/ripemd160": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@types/ripemd160/-/ripemd160-2.0.0.tgz",
+ "integrity": "sha512-LD6AO/+8cAa1ghXax9NG9iPDLPUEGB2WWPjd//04KYfXxTwHvlDEfL0NRjrM5z9XWBi6WbKw75Are0rDyn3PSA==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/semver": {
+ "version": "7.3.13",
+ "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
+ "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
+ "dev": true
+ },
+ "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/@typescript-eslint/eslint-plugin": {
+ "version": "5.45.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.45.0.tgz",
+ "integrity": "sha512-CXXHNlf0oL+Yg021cxgOdMHNTXD17rHkq7iW6RFHoybdFgQBjU3yIXhhcPpGwr1CjZlo6ET8C6tzX5juQoXeGA==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "5.45.0",
+ "@typescript-eslint/type-utils": "5.45.0",
+ "@typescript-eslint/utils": "5.45.0",
+ "debug": "^4.3.4",
+ "ignore": "^5.2.0",
+ "natural-compare-lite": "^1.4.0",
+ "regexpp": "^3.2.0",
+ "semver": "^7.3.7",
+ "tsutils": "^3.21.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "@typescript-eslint/parser": "^5.0.0",
+ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/parser": {
+ "version": "5.45.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.45.0.tgz",
+ "integrity": "sha512-brvs/WSM4fKUmF5Ot/gEve6qYiCMjm6w4HkHPfS6ZNmxTS0m0iNN4yOChImaCkqc1hRwFGqUyanMXuGal6oyyQ==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "5.45.0",
+ "@typescript-eslint/types": "5.45.0",
+ "@typescript-eslint/typescript-estree": "5.45.0",
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/scope-manager": {
+ "version": "5.45.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.45.0.tgz",
+ "integrity": "sha512-noDMjr87Arp/PuVrtvN3dXiJstQR1+XlQ4R1EvzG+NMgXi8CuMCXpb8JqNtFHKceVSQ985BZhfRdowJzbv4yKw==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "5.45.0",
+ "@typescript-eslint/visitor-keys": "5.45.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/type-utils": {
+ "version": "5.45.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.45.0.tgz",
+ "integrity": "sha512-DY7BXVFSIGRGFZ574hTEyLPRiQIvI/9oGcN8t1A7f6zIs6ftbrU0nhyV26ZW//6f85avkwrLag424n+fkuoJ1Q==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/typescript-estree": "5.45.0",
+ "@typescript-eslint/utils": "5.45.0",
+ "debug": "^4.3.4",
+ "tsutils": "^3.21.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "*"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/types": {
+ "version": "5.45.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.45.0.tgz",
+ "integrity": "sha512-QQij+u/vgskA66azc9dCmx+rev79PzX8uDHpsqSjEFtfF2gBUTRCpvYMh2gw2ghkJabNkPlSUCimsyBEQZd1DA==",
+ "dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree": {
+ "version": "5.45.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.45.0.tgz",
+ "integrity": "sha512-maRhLGSzqUpFcZgXxg1qc/+H0bT36lHK4APhp0AEUVrpSwXiRAomm/JGjSG+kNUio5kAa3uekCYu/47cnGn5EQ==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "5.45.0",
+ "@typescript-eslint/visitor-keys": "5.45.0",
+ "debug": "^4.3.4",
+ "globby": "^11.1.0",
+ "is-glob": "^4.0.3",
+ "semver": "^7.3.7",
+ "tsutils": "^3.21.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/utils": {
+ "version": "5.45.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.45.0.tgz",
+ "integrity": "sha512-OUg2JvsVI1oIee/SwiejTot2OxwU8a7UfTFMOdlhD2y+Hl6memUSL4s98bpUTo8EpVEr0lmwlU7JSu/p2QpSvA==",
+ "dev": true,
+ "dependencies": {
+ "@types/json-schema": "^7.0.9",
+ "@types/semver": "^7.3.12",
+ "@typescript-eslint/scope-manager": "5.45.0",
+ "@typescript-eslint/types": "5.45.0",
+ "@typescript-eslint/typescript-estree": "5.45.0",
+ "eslint-scope": "^5.1.1",
+ "eslint-utils": "^3.0.0",
+ "semver": "^7.3.7"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys": {
+ "version": "5.45.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.45.0.tgz",
+ "integrity": "sha512-jc6Eccbn2RtQPr1s7th6jJWQHBHI6GBVQkCHoJFQ5UreaKm59Vxw+ynQUPPY2u2Amquc+7tmEoC2G52ApsGNNg==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "5.45.0",
+ "eslint-visitor-keys": "^3.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/acorn": {
+ "version": "8.8.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz",
+ "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==",
+ "dev": true,
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "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/ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ansi-colors": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
+ "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "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/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "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": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==",
+ "dev": true
+ },
+ "node_modules/arg": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
+ "dev": true
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
+ },
+ "node_modules/array-union": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/astral-regex": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
+ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true
+ },
+ "node_modules/base-x": {
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz",
+ "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==",
+ "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/better-npm-audit": {
+ "version": "3.7.3",
+ "resolved": "https://registry.npmjs.org/better-npm-audit/-/better-npm-audit-3.7.3.tgz",
+ "integrity": "sha512-zsSiidlP5n7KpCYdAmkellu4JYA4IoRUUwrBMv/R7TwT8vcRfk5CQ2zTg7yUy4bdWkKtAj7VVdPQttdMbx+n5Q==",
+ "dev": true,
+ "dependencies": {
+ "commander": "^8.0.0",
+ "dayjs": "^1.10.6",
+ "lodash.get": "^4.4.2",
+ "table": "^6.7.1"
+ },
+ "bin": {
+ "better-npm-audit": "index.js"
+ },
+ "engines": {
+ "node": ">= 8.12"
+ }
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/bip174": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/bip174/-/bip174-2.1.0.tgz",
+ "integrity": "sha512-lkc0XyiX9E9KiVAS1ZiOqK1xfiwvf4FXDDdkDq5crcDzOq+xGytY+14qCsqz7kCiy8rpN1CRNfacRhf9G3JNSA==",
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/bip32": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/bip32/-/bip32-3.1.0.tgz",
+ "integrity": "sha512-eoeajYEzJ4d6yyVtby8C+XkCeKItiC4Mx56a0M9VaqTMC73SWOm4xVZG7SaR8e/yp4eSyky2XcBpH3DApPdu7Q==",
+ "dev": true,
+ "dependencies": {
+ "bs58check": "^2.1.1",
+ "create-hash": "^1.2.0",
+ "create-hmac": "^1.1.7",
+ "ripemd160": "^2.0.2",
+ "typeforce": "^1.11.5",
+ "wif": "^2.0.6"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/bip39": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.4.tgz",
+ "integrity": "sha512-YZKQlb752TrUWqHWj7XAwCSjYEgGAk+/Aas3V7NyjQeZYsztO8JnQUaCWhcnL4T+jL8nvB8typ2jRPzTlgugNw==",
+ "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/browserslist": {
+ "version": "4.21.4",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz",
+ "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ }
+ ],
+ "dependencies": {
+ "caniuse-lite": "^1.0.30001400",
+ "electron-to-chromium": "^1.4.251",
+ "node-releases": "^2.0.6",
+ "update-browserslist-db": "^1.0.9"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/bs58": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
+ "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==",
+ "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.2",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+ "dev": true
+ },
+ "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/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "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/caniuse-lite": {
+ "version": "1.0.30001436",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001436.tgz",
+ "integrity": "sha512-ZmWkKsnC2ifEPoWUvSAIGyOYwT+keAaaWPHiQ9DfMqS1t6tfuyFYoWR78TeZtznkEQ64+vGXH9cZrElwR2Mrxg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ }
+ ]
+ },
+ "node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+ "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ ],
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/chokidar/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/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": "7.0.4",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+ "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+ "dev": true,
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^7.0.0"
+ }
+ },
+ "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/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/commander": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
+ "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
+ "dev": true,
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "node_modules/commondir": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
+ "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
+ "dev": true
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true
+ },
+ "node_modules/convert-source-map": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
+ "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
+ "dev": true
+ },
+ "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/dayjs": {
+ "version": "1.11.6",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.6.tgz",
+ "integrity": "sha512-zZbY5giJAinCG+7AGaw0wIhNZ6J8AhWuSXKvuc1KAyMiRsvGQWqh4L+MomvhdAYjN+lqvVCMq1I41e3YHvXkyQ==",
+ "dev": true
+ },
+ "node_modules/debug": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/deep-is": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+ "dev": true
+ },
+ "node_modules/default-require-extensions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz",
+ "integrity": "sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==",
+ "dev": true,
+ "dependencies": {
+ "strip-bom": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "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": "5.0.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
+ "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
+ "node_modules/dir-glob": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+ "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+ "dev": true,
+ "dependencies": {
+ "path-type": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "dev": true,
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/ecpair": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/ecpair/-/ecpair-2.1.0.tgz",
+ "integrity": "sha512-cL/mh3MtJutFOvFc27GPZE2pWL3a3k4YvzUWEOvilnfZVlH3Jwgx/7d6tlD7/75tNk8TG2m+7Kgtz0SI1tWcqw==",
+ "dev": true,
+ "dependencies": {
+ "randombytes": "^2.1.0",
+ "typeforce": "^1.18.0",
+ "wif": "^2.0.6"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.4.284",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz",
+ "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==",
+ "dev": true
+ },
+ "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/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/escalade": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint": {
+ "version": "8.29.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz",
+ "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==",
+ "dev": true,
+ "dependencies": {
+ "@eslint/eslintrc": "^1.3.3",
+ "@humanwhocodes/config-array": "^0.11.6",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@nodelib/fs.walk": "^1.2.8",
+ "ajv": "^6.10.0",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.2",
+ "debug": "^4.3.2",
+ "doctrine": "^3.0.0",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^7.1.1",
+ "eslint-utils": "^3.0.0",
+ "eslint-visitor-keys": "^3.3.0",
+ "espree": "^9.4.0",
+ "esquery": "^1.4.0",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^6.0.1",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "globals": "^13.15.0",
+ "grapheme-splitter": "^1.0.4",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.0.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "is-path-inside": "^3.0.3",
+ "js-sdsl": "^4.1.4",
+ "js-yaml": "^4.1.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.4.1",
+ "lodash.merge": "^4.6.2",
+ "minimatch": "^3.1.2",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.1",
+ "regexpp": "^3.2.0",
+ "strip-ansi": "^6.0.1",
+ "strip-json-comments": "^3.1.0",
+ "text-table": "^0.2.0"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-config-prettier": {
+ "version": "8.5.0",
+ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz",
+ "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==",
+ "dev": true,
+ "bin": {
+ "eslint-config-prettier": "bin/cli.js"
+ },
+ "peerDependencies": {
+ "eslint": ">=7.0.0"
+ }
+ },
+ "node_modules/eslint-plugin-prettier": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz",
+ "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==",
+ "dev": true,
+ "dependencies": {
+ "prettier-linter-helpers": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "eslint": ">=7.28.0",
+ "prettier": ">=2.0.0"
+ },
+ "peerDependenciesMeta": {
+ "eslint-config-prettier": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-scope": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+ "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+ "dev": true,
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^4.1.1"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/eslint-utils": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
+ "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
+ "dev": true,
+ "dependencies": {
+ "eslint-visitor-keys": "^2.0.0"
+ },
+ "engines": {
+ "node": "^10.0.0 || ^12.0.0 || >= 14.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mysticatea"
+ },
+ "peerDependencies": {
+ "eslint": ">=5"
+ }
+ },
+ "node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
+ "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/eslint-visitor-keys": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
+ "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
+ "dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/eslint/node_modules/eslint-scope": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
+ "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
+ "dev": true,
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/eslint/node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/espree": {
+ "version": "9.4.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz",
+ "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==",
+ "dev": true,
+ "dependencies": {
+ "acorn": "^8.8.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^3.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "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/esquery": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
+ "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
+ "dev": true,
+ "dependencies": {
+ "estraverse": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/esquery/node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
+ "dependencies": {
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esrecurse/node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estraverse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true
+ },
+ "node_modules/fast-diff": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz",
+ "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==",
+ "dev": true
+ },
+ "node_modules/fast-glob": {
+ "version": "3.2.12",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
+ "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
+ "dev": true,
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/fast-glob/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/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true
+ },
+ "node_modules/fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+ "dev": true
+ },
+ "node_modules/fastq": {
+ "version": "1.14.0",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.14.0.tgz",
+ "integrity": "sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==",
+ "dev": true,
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "node_modules/file-entry-cache": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+ "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+ "dev": true,
+ "dependencies": {
+ "flat-cache": "^3.0.4"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/fill-keys": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz",
+ "integrity": "sha512-tcgI872xXjwFF4xgQmLxi76GnwJG3g/3isB1l4/G5Z4zrbddGpBjqZCO9oEAcB5wX0Hj/5iQB3toxfO7in1hHA==",
+ "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.2",
+ "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz",
+ "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==",
+ "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": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/flat": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
+ "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
+ "dev": true,
+ "bin": {
+ "flat": "cli.js"
+ }
+ },
+ "node_modules/flat-cache": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
+ "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
+ "dev": true,
+ "dependencies": {
+ "flatted": "^3.1.0",
+ "rimraf": "^3.0.2"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/flat-cache/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/flatted": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
+ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
+ "dev": true
+ },
+ "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": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "dev": true
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "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.2.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
+ "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
+ "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/glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "dev": true,
+ "dependencies": {
+ "is-glob": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/globals": {
+ "version": "13.18.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz",
+ "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==",
+ "dev": true,
+ "dependencies": {
+ "type-fest": "^0.20.2"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/globby": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+ "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+ "dev": true,
+ "dependencies": {
+ "array-union": "^2.1.0",
+ "dir-glob": "^3.0.1",
+ "fast-glob": "^3.2.9",
+ "ignore": "^5.2.0",
+ "merge2": "^1.4.1",
+ "slash": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.10",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
+ "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
+ "dev": true
+ },
+ "node_modules/grapheme-splitter": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
+ "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
+ "dev": true
+ },
+ "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": "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/hash-base": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
+ "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
+ "dependencies": {
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.6.0",
+ "safe-buffer": "^5.2.0"
+ },
+ "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/hasha/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/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/ignore": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz",
+ "integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/import-fresh": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+ "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+ "dev": true,
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "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": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "dev": true,
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "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-core-module": {
+ "version": "2.11.0",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
+ "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
+ "dev": true,
+ "dependencies": {
+ "has": "^1.0.3"
+ },
+ "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": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "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/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "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.2",
+ "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz",
+ "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-path-inside": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-plain-obj": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
+ "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-stream": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==",
+ "dev": true
+ },
+ "node_modules/is-unicode-supported": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+ "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "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": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true
+ },
+ "node_modules/istanbul-lib-coverage": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
+ "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==",
+ "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.3",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz",
+ "integrity": "sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==",
+ "dev": true,
+ "dependencies": {
+ "archy": "^1.0.0",
+ "cross-spawn": "^7.0.3",
+ "istanbul-lib-coverage": "^3.2.0",
+ "p-map": "^3.0.0",
+ "rimraf": "^3.0.0",
+ "uuid": "^8.3.2"
+ },
+ "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-source-maps": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
+ "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==",
+ "dev": true,
+ "dependencies": {
+ "debug": "^4.1.1",
+ "istanbul-lib-coverage": "^3.0.0",
+ "source-map": "^0.6.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/istanbul-reports": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz",
+ "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==",
+ "dev": true,
+ "dependencies": {
+ "html-escaper": "^2.0.0",
+ "istanbul-lib-report": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/js-sdsl": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz",
+ "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==",
+ "dev": true,
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/js-sdsl"
+ }
+ },
+ "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": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "dev": true,
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "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/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "node_modules/json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+ "dev": true
+ },
+ "node_modules/json5": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
+ "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
+ "dev": true,
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "dev": true,
+ "dependencies": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/lodash.flattendeep": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
+ "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==",
+ "dev": true
+ },
+ "node_modules/lodash.get": {
+ "version": "4.4.2",
+ "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
+ "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==",
+ "dev": true
+ },
+ "node_modules/lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true
+ },
+ "node_modules/lodash.truncate": {
+ "version": "4.4.2",
+ "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
+ "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==",
+ "dev": true
+ },
+ "node_modules/log-symbols": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+ "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^4.1.0",
+ "is-unicode-supported": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dev": true,
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "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.6",
+ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+ "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": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==",
+ "dev": true
+ },
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
+ "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+ "dev": true,
+ "dependencies": {
+ "braces": "^3.0.2",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/minimaldata": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/minimaldata/-/minimaldata-1.0.2.tgz",
+ "integrity": "sha512-ZR9tWALR8ZszYd/zP34TmmVwRDVBNCT5+hkNXfTp3rpEDmZmgmYt1Sh/tu9qYFuPvSvEEEeJGE2BY8MBmeAzQQ==",
+ "dev": true,
+ "dependencies": {
+ "bitcoin-ops": "^1.3.0",
+ "pushdata-bitcoin": "^1.0.1"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/mocha": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.1.0.tgz",
+ "integrity": "sha512-vUF7IYxEoN7XhQpFLxQAEMtE4W91acW4B6En9l97MwE9stL1A9gusXfoHZCLVHDUJ/7V5+lbCM6yMqzo5vNymg==",
+ "dev": true,
+ "dependencies": {
+ "ansi-colors": "4.1.1",
+ "browser-stdout": "1.3.1",
+ "chokidar": "3.5.3",
+ "debug": "4.3.4",
+ "diff": "5.0.0",
+ "escape-string-regexp": "4.0.0",
+ "find-up": "5.0.0",
+ "glob": "7.2.0",
+ "he": "1.2.0",
+ "js-yaml": "4.1.0",
+ "log-symbols": "4.1.0",
+ "minimatch": "5.0.1",
+ "ms": "2.1.3",
+ "nanoid": "3.3.3",
+ "serialize-javascript": "6.0.0",
+ "strip-json-comments": "3.1.1",
+ "supports-color": "8.1.1",
+ "workerpool": "6.2.1",
+ "yargs": "16.2.0",
+ "yargs-parser": "20.2.4",
+ "yargs-unparser": "2.0.0"
+ },
+ "bin": {
+ "_mocha": "bin/_mocha",
+ "mocha": "bin/mocha.js"
+ },
+ "engines": {
+ "node": ">= 14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mochajs"
+ }
+ },
+ "node_modules/mocha/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/mocha/node_modules/minimatch": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
+ "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/mocha/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true
+ },
+ "node_modules/mocha/node_modules/supports-color": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
+ }
+ },
+ "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": "sha512-pEk4ECWQXV6z2zjhRZUongnLJNUeGQJ3w6OQ5ctGwD+i5o93qjRQUk2Rt6VdNeu3sEP0AB4LcfvdebpxBRVr4g==",
+ "dev": true
+ },
+ "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/nanoid": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz",
+ "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==",
+ "dev": true,
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+ "dev": true
+ },
+ "node_modules/natural-compare-lite": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz",
+ "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==",
+ "dev": true
+ },
+ "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/node-releases": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz",
+ "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==",
+ "dev": true
+ },
+ "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/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/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/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/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-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "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/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/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/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/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/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/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dev": true,
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/optionator": {
+ "version": "0.9.1",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
+ "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
+ "dev": true,
+ "dependencies": {
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.3"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "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/parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "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/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "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/path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/pbkdf2": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
+ "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==",
+ "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/picocolors": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
+ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
+ "dev": true
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "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-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "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/prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/prettier": {
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.0.tgz",
+ "integrity": "sha512-9Lmg8hTFZKG0Asr/kW9Bp8tJjRVluO8EJQVfY2T7FMw9T5jy4I/Uvx0Rca/XWf50QQ1/SS48+6IJWnrb+2yemA==",
+ "dev": true,
+ "bin": {
+ "prettier": "bin-prettier.js"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
+ "node_modules/prettier-linter-helpers": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
+ "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
+ "dev": true,
+ "dependencies": {
+ "fast-diff": "^1.1.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "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.3",
+ "resolved": "https://registry.npmjs.org/proxyquire/-/proxyquire-2.1.3.tgz",
+ "integrity": "sha512-BQWfCqYM+QINd+yawJz23tbBM40VIGXOdDw3X344KcclI/gtBbdWF6SlQ4nK/bYhF9d27KYug9WzljHC6B9Ysg==",
+ "dev": true,
+ "dependencies": {
+ "fill-keys": "^1.0.2",
+ "module-not-found-error": "^1.0.1",
+ "resolve": "^1.11.1"
+ }
+ },
+ "node_modules/punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/pushdata-bitcoin": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/pushdata-bitcoin/-/pushdata-bitcoin-1.0.1.tgz",
+ "integrity": "sha512-hw7rcYTJRAl4olM8Owe8x0fBuJJ+WGbMhQuLWOXEMN3PxPCKQHRkhfL+XG0+iXUmSHjkMmb3Ba55Mt21cZc9kQ==",
+ "dev": true,
+ "dependencies": {
+ "bitcoin-ops": "^1.3.0"
+ }
+ },
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "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/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/readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dev": true,
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/regexpp": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
+ "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mysticatea"
+ }
+ },
+ "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": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==",
+ "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": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+ "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.22.1",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
+ "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
+ "dev": true,
+ "dependencies": {
+ "is-core-module": "^2.9.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/reusify": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+ "dev": true,
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rimraf": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "dev": true,
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ }
+ },
+ "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/run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "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"
+ }
+ ],
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "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/semver": {
+ "version": "7.3.8",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+ "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+ "dev": true,
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/serialize-javascript": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
+ "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
+ "dev": true,
+ "dependencies": {
+ "randombytes": "^2.1.0"
+ }
+ },
+ "node_modules/set-blocking": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
+ "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.7",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+ "dev": true
+ },
+ "node_modules/slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/slice-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
+ "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "astral-regex": "^2.0.0",
+ "is-fullwidth-code-point": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/slice-ansi?sponsor=1"
+ }
+ },
+ "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/source-map-support": {
+ "version": "0.5.21",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+ "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+ "dev": true,
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.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/sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
+ "dev": true
+ },
+ "node_modules/statuses": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+ "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "dependencies": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
+ "node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "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": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "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/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/table": {
+ "version": "6.8.1",
+ "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz",
+ "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==",
+ "dev": true,
+ "dependencies": {
+ "ajv": "^8.0.1",
+ "lodash.truncate": "^4.4.2",
+ "slice-ansi": "^4.0.0",
+ "string-width": "^4.2.3",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/table/node_modules/ajv": {
+ "version": "8.11.2",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz",
+ "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/table/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true
+ },
+ "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/text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+ "dev": true
+ },
+ "node_modules/tiny-secp256k1": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-2.2.1.tgz",
+ "integrity": "sha512-/U4xfVqnVxJXN4YVsru0E6t5wVncu2uunB8+RVR40fYUxkKYUPS10f+ePQZgFBoE/Jbf9H1NBveupF2VmB58Ng==",
+ "dev": true,
+ "dependencies": {
+ "uint8array-tools": "0.0.7"
+ },
+ "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": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
+ "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.10.2",
+ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.2.tgz",
+ "integrity": "sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==",
+ "dev": true,
+ "dependencies": {
+ "arg": "^4.1.0",
+ "diff": "^4.0.1",
+ "make-error": "^1.1.1",
+ "source-map-support": "^0.5.17",
+ "yn": "3.1.1"
+ },
+ "bin": {
+ "ts-node": "dist/bin.js",
+ "ts-node-script": "dist/bin-script.js",
+ "ts-node-transpile-only": "dist/bin-transpile.js",
+ "ts-script": "dist/bin-script-deprecated.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ },
+ "peerDependencies": {
+ "typescript": ">=2.7"
+ }
+ },
+ "node_modules/ts-node/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/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/tsutils": {
+ "version": "3.21.0",
+ "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
+ "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
+ "dev": true,
+ "dependencies": {
+ "tslib": "^1.8.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ },
+ "peerDependencies": {
+ "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
+ }
+ },
+ "node_modules/type-check": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+ "dev": true,
+ "dependencies": {
+ "prelude-ls": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/type-fest": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "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.9.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz",
+ "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==",
+ "dev": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=4.2.0"
+ }
+ },
+ "node_modules/uint8array-tools": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.7.tgz",
+ "integrity": "sha512-vrrNZJiusLWoFWBqz5Y5KMCgP9W9hnjZHzZiZRT8oNAkq3d5Z5Oe76jAvVVSRh4U8GGR90N2X1dWtrhvx6L8UQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
+ "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ }
+ ],
+ "dependencies": {
+ "escalade": "^3.1.1",
+ "picocolors": "^1.0.0"
+ },
+ "bin": {
+ "browserslist-lint": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
+ "node_modules/uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dev": true,
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
+ },
+ "node_modules/uuid": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+ "dev": true,
+ "bin": {
+ "uuid": "dist/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": "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/which-module": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+ "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==",
+ "dev": true
+ },
+ "node_modules/wif": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz",
+ "integrity": "sha512-HIanZn1zmduSF+BQhkE+YXIbEiH0xPr1012QbFEGB0xsKqJii0/SqJjyn8dFv6y36kOznMgMB+LGcbZTJ1xACQ==",
+ "dependencies": {
+ "bs58check": "<3.0.0"
+ }
+ },
+ "node_modules/word-wrap": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/workerpool": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
+ "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==",
+ "dev": true
+ },
+ "node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "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": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
+ },
+ "node_modules/yargs": {
+ "version": "16.2.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
+ "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
+ "dev": true,
+ "dependencies": {
+ "cliui": "^7.0.2",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.0",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^20.2.2"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yargs-parser": {
+ "version": "20.2.4",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
+ "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yargs-unparser": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
+ "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
+ "dev": true,
+ "dependencies": {
+ "camelcase": "^6.0.0",
+ "decamelize": "^4.0.0",
+ "flat": "^5.0.2",
+ "is-plain-obj": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yargs-unparser/node_modules/camelcase": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
+ "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/yargs-unparser/node_modules/decamelize": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
+ "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "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"
+ }
+ },
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ }
+ },
"dependencies": {
"@ampproject/remapping": {
"version": "2.2.0",
@@ -15,36 +4464,36 @@
}
},
"@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==",
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
+ "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
"dev": true,
"requires": {
- "@babel/highlight": "^7.14.5"
+ "@babel/highlight": "^7.18.6"
}
},
"@babel/compat-data": {
- "version": "7.17.10",
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.10.tgz",
- "integrity": "sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw==",
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.5.tgz",
+ "integrity": "sha512-KZXo2t10+/jxmkhNXc7pZTqRvSOIvVv/+lJwHS+B2rErwOyjuVRh60yVpb7liQ1U5t7lLJ1bz+t8tSypUZdm0g==",
"dev": true
},
"@babel/core": {
- "version": "7.18.2",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.2.tgz",
- "integrity": "sha512-A8pri1YJiC5UnkdrWcmfZTJTV85b4UXTAfImGmCfYmax4TR9Cw8sDS0MOk++Gp2mE/BefVJ5nwy5yzqNJbP/DQ==",
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.5.tgz",
+ "integrity": "sha512-UdOWmk4pNWTm/4DlPUl/Pt4Gz4rcEMb7CY0Y3eJl5Yz1vI8ZJGmHWaVE55LoxRjdpx0z259GE9U5STA9atUinQ==",
"dev": true,
"requires": {
"@ampproject/remapping": "^2.1.0",
- "@babel/code-frame": "^7.16.7",
- "@babel/generator": "^7.18.2",
- "@babel/helper-compilation-targets": "^7.18.2",
- "@babel/helper-module-transforms": "^7.18.0",
- "@babel/helpers": "^7.18.2",
- "@babel/parser": "^7.18.0",
- "@babel/template": "^7.16.7",
- "@babel/traverse": "^7.18.2",
- "@babel/types": "^7.18.2",
+ "@babel/code-frame": "^7.18.6",
+ "@babel/generator": "^7.20.5",
+ "@babel/helper-compilation-targets": "^7.20.0",
+ "@babel/helper-module-transforms": "^7.20.2",
+ "@babel/helpers": "^7.20.5",
+ "@babel/parser": "^7.20.5",
+ "@babel/template": "^7.18.10",
+ "@babel/traverse": "^7.20.5",
+ "@babel/types": "^7.20.5",
"convert-source-map": "^1.7.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
@@ -52,26 +4501,6 @@
"semver": "^6.3.0"
},
"dependencies": {
- "@babel/code-frame": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz",
- "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==",
- "dev": true,
- "requires": {
- "@babel/highlight": "^7.16.7"
- }
- },
- "@babel/highlight": {
- "version": "7.17.12",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.12.tgz",
- "integrity": "sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg==",
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.16.7",
- "chalk": "^2.0.0",
- "js-tokens": "^4.0.0"
- }
- },
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
@@ -81,23 +4510,23 @@
}
},
"@babel/generator": {
- "version": "7.18.2",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.2.tgz",
- "integrity": "sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw==",
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz",
+ "integrity": "sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==",
"dev": true,
"requires": {
- "@babel/types": "^7.18.2",
- "@jridgewell/gen-mapping": "^0.3.0",
+ "@babel/types": "^7.20.5",
+ "@jridgewell/gen-mapping": "^0.3.2",
"jsesc": "^2.5.1"
},
"dependencies": {
"@jridgewell/gen-mapping": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz",
- "integrity": "sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg==",
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
+ "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
"dev": true,
"requires": {
- "@jridgewell/set-array": "^1.0.0",
+ "@jridgewell/set-array": "^1.0.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
"@jridgewell/trace-mapping": "^0.3.9"
}
@@ -105,14 +4534,14 @@
}
},
"@babel/helper-compilation-targets": {
- "version": "7.18.2",
- "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.2.tgz",
- "integrity": "sha512-s1jnPotJS9uQnzFtiZVBUxe67CuBa679oWFHpxYYnTpRL/1ffhyX44R9uYiXoa/pLXcY9H2moJta0iaanlk/rQ==",
+ "version": "7.20.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz",
+ "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==",
"dev": true,
"requires": {
- "@babel/compat-data": "^7.17.10",
- "@babel/helper-validator-option": "^7.16.7",
- "browserslist": "^4.20.2",
+ "@babel/compat-data": "^7.20.0",
+ "@babel/helper-validator-option": "^7.18.6",
+ "browserslist": "^4.21.3",
"semver": "^6.3.0"
},
"dependencies": {
@@ -125,204 +4554,265 @@
}
},
"@babel/helper-environment-visitor": {
- "version": "7.18.2",
- "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.2.tgz",
- "integrity": "sha512-14GQKWkX9oJzPiQQ7/J36FTXcD4kSp8egKjO9nINlSKiHITRA9q/R74qu8S9xlc/b/yjsJItQUeeh3xnGN0voQ==",
+ "version": "7.18.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
+ "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==",
"dev": true
},
"@babel/helper-function-name": {
- "version": "7.17.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz",
- "integrity": "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==",
+ "version": "7.19.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz",
+ "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==",
"dev": true,
"requires": {
- "@babel/template": "^7.16.7",
- "@babel/types": "^7.17.0"
+ "@babel/template": "^7.18.10",
+ "@babel/types": "^7.19.0"
}
},
"@babel/helper-hoist-variables": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz",
- "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==",
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
+ "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
"dev": true,
"requires": {
- "@babel/types": "^7.16.7"
+ "@babel/types": "^7.18.6"
}
},
"@babel/helper-module-imports": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz",
- "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==",
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz",
+ "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==",
"dev": true,
"requires": {
- "@babel/types": "^7.16.7"
+ "@babel/types": "^7.18.6"
}
},
"@babel/helper-module-transforms": {
- "version": "7.18.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.0.tgz",
- "integrity": "sha512-kclUYSUBIjlvnzN2++K9f2qzYKFgjmnmjwL4zlmU5f8ZtzgWe8s0rUPSTGy2HmK4P8T52MQsS+HTQAgZd3dMEA==",
+ "version": "7.20.2",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.2.tgz",
+ "integrity": "sha512-zvBKyJXRbmK07XhMuujYoJ48B5yvvmM6+wcpv6Ivj4Yg6qO7NOZOSnvZN9CRl1zz1Z4cKf8YejmCMh8clOoOeA==",
"dev": true,
"requires": {
- "@babel/helper-environment-visitor": "^7.16.7",
- "@babel/helper-module-imports": "^7.16.7",
- "@babel/helper-simple-access": "^7.17.7",
- "@babel/helper-split-export-declaration": "^7.16.7",
- "@babel/helper-validator-identifier": "^7.16.7",
- "@babel/template": "^7.16.7",
- "@babel/traverse": "^7.18.0",
- "@babel/types": "^7.18.0"
+ "@babel/helper-environment-visitor": "^7.18.9",
+ "@babel/helper-module-imports": "^7.18.6",
+ "@babel/helper-simple-access": "^7.20.2",
+ "@babel/helper-split-export-declaration": "^7.18.6",
+ "@babel/helper-validator-identifier": "^7.19.1",
+ "@babel/template": "^7.18.10",
+ "@babel/traverse": "^7.20.1",
+ "@babel/types": "^7.20.2"
}
},
"@babel/helper-simple-access": {
- "version": "7.18.2",
- "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.2.tgz",
- "integrity": "sha512-7LIrjYzndorDY88MycupkpQLKS1AFfsVRm2k/9PtKScSy5tZq0McZTj+DiMRynboZfIqOKvo03pmhTaUgiD6fQ==",
+ "version": "7.20.2",
+ "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz",
+ "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==",
"dev": true,
"requires": {
- "@babel/types": "^7.18.2"
+ "@babel/types": "^7.20.2"
}
},
"@babel/helper-split-export-declaration": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz",
- "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==",
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
+ "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
"dev": true,
"requires": {
- "@babel/types": "^7.16.7"
+ "@babel/types": "^7.18.6"
}
},
+ "@babel/helper-string-parser": {
+ "version": "7.19.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz",
+ "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==",
+ "dev": true
+ },
"@babel/helper-validator-identifier": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz",
- "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==",
+ "version": "7.19.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
+ "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
"dev": true
},
"@babel/helper-validator-option": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz",
- "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==",
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz",
+ "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==",
"dev": true
},
"@babel/helpers": {
- "version": "7.18.2",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.2.tgz",
- "integrity": "sha512-j+d+u5xT5utcQSzrh9p+PaJX94h++KN+ng9b9WEJq7pkUPAd61FGqhjuUEdfknb3E/uDBb7ruwEeKkIxNJPIrg==",
+ "version": "7.20.6",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.6.tgz",
+ "integrity": "sha512-Pf/OjgfgFRW5bApskEz5pvidpim7tEDPlFtKcNRXWmfHGn9IEI2W2flqRQXTFb7gIPTyK++N6rVHuwKut4XK6w==",
"dev": true,
"requires": {
- "@babel/template": "^7.16.7",
- "@babel/traverse": "^7.18.2",
- "@babel/types": "^7.18.2"
+ "@babel/template": "^7.18.10",
+ "@babel/traverse": "^7.20.5",
+ "@babel/types": "^7.20.5"
}
},
"@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==",
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
+ "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
"dev": true,
"requires": {
- "@babel/helper-validator-identifier": "^7.14.5",
+ "@babel/helper-validator-identifier": "^7.18.6",
"chalk": "^2.0.0",
"js-tokens": "^4.0.0"
},
"dependencies": {
- "@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==",
+ "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,
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "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,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
+ "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,
+ "requires": {
+ "color-name": "1.1.3"
+ }
+ },
+ "color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "dev": true
+ },
+ "escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
"dev": true
+ },
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true
+ },
+ "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,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
}
}
},
"@babel/parser": {
- "version": "7.18.3",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.3.tgz",
- "integrity": "sha512-rL50YcEuHbbauAFAysNsJA4/f89fGTOBRNs9P81sniKnKAr4xULe5AecolcsKbi88xu0ByWYDj/S1AJ3FSFuSQ==",
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz",
+ "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==",
"dev": true
},
"@babel/template": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz",
- "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==",
+ "version": "7.18.10",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz",
+ "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==",
"dev": true,
"requires": {
- "@babel/code-frame": "^7.16.7",
- "@babel/parser": "^7.16.7",
- "@babel/types": "^7.16.7"
- },
- "dependencies": {
- "@babel/code-frame": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz",
- "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==",
- "dev": true,
- "requires": {
- "@babel/highlight": "^7.16.7"
- }
- },
- "@babel/highlight": {
- "version": "7.17.12",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.12.tgz",
- "integrity": "sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg==",
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.16.7",
- "chalk": "^2.0.0",
- "js-tokens": "^4.0.0"
- }
- }
+ "@babel/code-frame": "^7.18.6",
+ "@babel/parser": "^7.18.10",
+ "@babel/types": "^7.18.10"
}
},
"@babel/traverse": {
- "version": "7.18.2",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.2.tgz",
- "integrity": "sha512-9eNwoeovJ6KH9zcCNnENY7DMFwTU9JdGCFtqNLfUAqtUHRCOsTOqWoffosP8vKmNYeSBUv3yVJXjfd8ucwOjUA==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.16.7",
- "@babel/generator": "^7.18.2",
- "@babel/helper-environment-visitor": "^7.18.2",
- "@babel/helper-function-name": "^7.17.9",
- "@babel/helper-hoist-variables": "^7.16.7",
- "@babel/helper-split-export-declaration": "^7.16.7",
- "@babel/parser": "^7.18.0",
- "@babel/types": "^7.18.2",
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.5.tgz",
+ "integrity": "sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.18.6",
+ "@babel/generator": "^7.20.5",
+ "@babel/helper-environment-visitor": "^7.18.9",
+ "@babel/helper-function-name": "^7.19.0",
+ "@babel/helper-hoist-variables": "^7.18.6",
+ "@babel/helper-split-export-declaration": "^7.18.6",
+ "@babel/parser": "^7.20.5",
+ "@babel/types": "^7.20.5",
"debug": "^4.1.0",
"globals": "^11.1.0"
},
"dependencies": {
- "@babel/code-frame": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz",
- "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==",
- "dev": true,
- "requires": {
- "@babel/highlight": "^7.16.7"
- }
- },
- "@babel/highlight": {
- "version": "7.17.12",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.12.tgz",
- "integrity": "sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg==",
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.16.7",
- "chalk": "^2.0.0",
- "js-tokens": "^4.0.0"
- }
+ "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
}
}
},
"@babel/types": {
- "version": "7.18.2",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.2.tgz",
- "integrity": "sha512-0On6B8A4/+mFUto5WERt3EEuG1NznDirvwca1O8UwXQHVY8g3R7OzYgxXdOfMwLO08UrpUD/2+3Bclyq+/C94Q==",
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz",
+ "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==",
"dev": true,
"requires": {
- "@babel/helper-validator-identifier": "^7.16.7",
+ "@babel/helper-string-parser": "^7.19.4",
+ "@babel/helper-validator-identifier": "^7.19.1",
"to-fast-properties": "^2.0.0"
}
},
+ "@eslint/eslintrc": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz",
+ "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==",
+ "dev": true,
+ "requires": {
+ "ajv": "^6.12.4",
+ "debug": "^4.3.2",
+ "espree": "^9.4.0",
+ "globals": "^13.15.0",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^4.1.0",
+ "minimatch": "^3.1.2",
+ "strip-json-comments": "^3.1.1"
+ }
+ },
+ "@humanwhocodes/config-array": {
+ "version": "0.11.7",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz",
+ "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==",
+ "dev": true,
+ "requires": {
+ "@humanwhocodes/object-schema": "^1.2.1",
+ "debug": "^4.1.1",
+ "minimatch": "^3.0.5"
+ }
+ },
+ "@humanwhocodes/module-importer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+ "dev": true
+ },
+ "@humanwhocodes/object-schema": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
+ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
+ "dev": true
+ },
"@istanbuljs/load-nyc-config": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
@@ -336,6 +4826,15 @@
"resolve-from": "^5.0.0"
},
"dependencies": {
+ "argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "dev": true,
+ "requires": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
"find-up": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
@@ -346,6 +4845,16 @@
"path-exists": "^4.0.0"
}
},
+ "js-yaml": {
+ "version": "3.14.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+ "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+ "dev": true,
+ "requires": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ }
+ },
"locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
@@ -355,6 +4864,15 @@
"p-locate": "^4.1.0"
}
},
+ "p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "requires": {
+ "p-try": "^2.0.0"
+ }
+ },
"p-locate": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
@@ -363,6 +4881,12 @@
"requires": {
"p-limit": "^2.2.0"
}
+ },
+ "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
}
}
},
@@ -383,49 +4907,66 @@
}
},
"@jridgewell/resolve-uri": {
- "version": "3.0.7",
- "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz",
- "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
+ "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
"dev": true
},
"@jridgewell/set-array": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz",
- "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==",
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
+ "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
"dev": true
},
"@jridgewell/sourcemap-codec": {
- "version": "1.4.13",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz",
- "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==",
+ "version": "1.4.14",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
+ "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
"dev": true
},
"@jridgewell/trace-mapping": {
- "version": "0.3.13",
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz",
- "integrity": "sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==",
+ "version": "0.3.17",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
+ "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
"dev": true,
"requires": {
- "@jridgewell/resolve-uri": "^3.0.3",
- "@jridgewell/sourcemap-codec": "^1.4.10"
+ "@jridgewell/resolve-uri": "3.1.0",
+ "@jridgewell/sourcemap-codec": "1.4.14"
}
},
- "@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==",
+ "@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
"dev": true,
"requires": {
- "@types/node": "*"
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ }
+ },
+ "@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "dev": true
+ },
+ "@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "dev": true,
+ "requires": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
}
},
"@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==",
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@types/bs58/-/bs58-4.0.1.tgz",
+ "integrity": "sha512-yfAgiWgVLjFCmRv8zAcOIHywYATEwiTVccTLnRp6UxTNavT55M9d/uhK3T03St/+8/z/wW+CRjGKUNmEqoHHCA==",
"dev": true,
"requires": {
- "@types/base-x": "*"
+ "base-x": "^3.0.6"
}
},
"@types/bs58check": {
@@ -446,6 +4987,12 @@
"@types/node": "*"
}
},
+ "@types/json-schema": {
+ "version": "7.0.11",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
+ "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
+ "dev": true
+ },
"@types/mocha": {
"version": "5.2.7",
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz",
@@ -453,9 +5000,9 @@
"dev": true
},
"@types/node": {
- "version": "16.11.7",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.7.tgz",
- "integrity": "sha512-QB5D2sqfSjCmTuWcBWyJ+/44bcjO7VbjSbOE0ucoVbAsSNQc4Lt6QkgkVXkTDwkL4z/beecZNDvVX15D4P8Jbw==",
+ "version": "16.18.4",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.4.tgz",
+ "integrity": "sha512-9qGjJ5GyShZjUfx2ArBIGM+xExdfLvvaCyQR0t6yRXKPcWCVYF/WemtX/uIU3r7FYECXRXkIiw2Vnhn6y8d+pw==",
"dev": true
},
"@types/proxyquire": {
@@ -482,6 +5029,12 @@
"@types/node": "*"
}
},
+ "@types/semver": {
+ "version": "7.3.13",
+ "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
+ "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
+ "dev": true
+ },
"@types/wif": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@types/wif/-/wif-2.0.2.tgz",
@@ -491,12 +5044,117 @@
"@types/node": "*"
}
},
- "@ungap/promise-all-settled": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz",
- "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==",
+ "@typescript-eslint/eslint-plugin": {
+ "version": "5.45.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.45.0.tgz",
+ "integrity": "sha512-CXXHNlf0oL+Yg021cxgOdMHNTXD17rHkq7iW6RFHoybdFgQBjU3yIXhhcPpGwr1CjZlo6ET8C6tzX5juQoXeGA==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/scope-manager": "5.45.0",
+ "@typescript-eslint/type-utils": "5.45.0",
+ "@typescript-eslint/utils": "5.45.0",
+ "debug": "^4.3.4",
+ "ignore": "^5.2.0",
+ "natural-compare-lite": "^1.4.0",
+ "regexpp": "^3.2.0",
+ "semver": "^7.3.7",
+ "tsutils": "^3.21.0"
+ }
+ },
+ "@typescript-eslint/parser": {
+ "version": "5.45.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.45.0.tgz",
+ "integrity": "sha512-brvs/WSM4fKUmF5Ot/gEve6qYiCMjm6w4HkHPfS6ZNmxTS0m0iNN4yOChImaCkqc1hRwFGqUyanMXuGal6oyyQ==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/scope-manager": "5.45.0",
+ "@typescript-eslint/types": "5.45.0",
+ "@typescript-eslint/typescript-estree": "5.45.0",
+ "debug": "^4.3.4"
+ }
+ },
+ "@typescript-eslint/scope-manager": {
+ "version": "5.45.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.45.0.tgz",
+ "integrity": "sha512-noDMjr87Arp/PuVrtvN3dXiJstQR1+XlQ4R1EvzG+NMgXi8CuMCXpb8JqNtFHKceVSQ985BZhfRdowJzbv4yKw==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/types": "5.45.0",
+ "@typescript-eslint/visitor-keys": "5.45.0"
+ }
+ },
+ "@typescript-eslint/type-utils": {
+ "version": "5.45.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.45.0.tgz",
+ "integrity": "sha512-DY7BXVFSIGRGFZ574hTEyLPRiQIvI/9oGcN8t1A7f6zIs6ftbrU0nhyV26ZW//6f85avkwrLag424n+fkuoJ1Q==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/typescript-estree": "5.45.0",
+ "@typescript-eslint/utils": "5.45.0",
+ "debug": "^4.3.4",
+ "tsutils": "^3.21.0"
+ }
+ },
+ "@typescript-eslint/types": {
+ "version": "5.45.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.45.0.tgz",
+ "integrity": "sha512-QQij+u/vgskA66azc9dCmx+rev79PzX8uDHpsqSjEFtfF2gBUTRCpvYMh2gw2ghkJabNkPlSUCimsyBEQZd1DA==",
+ "dev": true
+ },
+ "@typescript-eslint/typescript-estree": {
+ "version": "5.45.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.45.0.tgz",
+ "integrity": "sha512-maRhLGSzqUpFcZgXxg1qc/+H0bT36lHK4APhp0AEUVrpSwXiRAomm/JGjSG+kNUio5kAa3uekCYu/47cnGn5EQ==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/types": "5.45.0",
+ "@typescript-eslint/visitor-keys": "5.45.0",
+ "debug": "^4.3.4",
+ "globby": "^11.1.0",
+ "is-glob": "^4.0.3",
+ "semver": "^7.3.7",
+ "tsutils": "^3.21.0"
+ }
+ },
+ "@typescript-eslint/utils": {
+ "version": "5.45.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.45.0.tgz",
+ "integrity": "sha512-OUg2JvsVI1oIee/SwiejTot2OxwU8a7UfTFMOdlhD2y+Hl6memUSL4s98bpUTo8EpVEr0lmwlU7JSu/p2QpSvA==",
+ "dev": true,
+ "requires": {
+ "@types/json-schema": "^7.0.9",
+ "@types/semver": "^7.3.12",
+ "@typescript-eslint/scope-manager": "5.45.0",
+ "@typescript-eslint/types": "5.45.0",
+ "@typescript-eslint/typescript-estree": "5.45.0",
+ "eslint-scope": "^5.1.1",
+ "eslint-utils": "^3.0.0",
+ "semver": "^7.3.7"
+ }
+ },
+ "@typescript-eslint/visitor-keys": {
+ "version": "5.45.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.45.0.tgz",
+ "integrity": "sha512-jc6Eccbn2RtQPr1s7th6jJWQHBHI6GBVQkCHoJFQ5UreaKm59Vxw+ynQUPPY2u2Amquc+7tmEoC2G52ApsGNNg==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/types": "5.45.0",
+ "eslint-visitor-keys": "^3.3.0"
+ }
+ },
+ "acorn": {
+ "version": "8.8.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz",
+ "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==",
"dev": true
},
+ "acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
+ "requires": {}
+ },
"aggregate-error": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
@@ -508,14 +5166,14 @@
}
},
"ajv": {
- "version": "8.11.2",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz",
- "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==",
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
"requires": {
"fast-deep-equal": "^3.1.1",
- "json-schema-traverse": "^1.0.0",
- "require-from-string": "^2.0.2",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
}
},
@@ -532,18 +5190,18 @@
"dev": true
},
"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==",
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"requires": {
- "color-convert": "^1.9.0"
+ "color-convert": "^2.0.1"
}
},
"anymatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
- "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"dev": true,
"requires": {
"normalize-path": "^3.0.0",
@@ -566,19 +5224,22 @@
"dev": true
},
"arg": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.1.tgz",
- "integrity": "sha512-SlmP3fEA88MBv0PypnXZ8ZfJhwmDeIE3SP71j37AiXQBXYosPV0x6uISAaHYSlSVhmHOVkomen0tbGk6Anlebw==",
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
"dev": true
},
"argparse": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
- "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
- "dev": true,
- "requires": {
- "sprintf-js": "~1.0.2"
- }
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
+ },
+ "array-union": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+ "dev": true
},
"astral-regex": {
"version": "2.0.0",
@@ -587,15 +5248,15 @@
"dev": true
},
"balanced-match": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
- "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
"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==",
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz",
+ "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==",
"requires": {
"safe-buffer": "^5.0.1"
}
@@ -615,14 +5276,6 @@
"dayjs": "^1.10.6",
"lodash.get": "^4.4.2",
"table": "^6.7.1"
- },
- "dependencies": {
- "commander": {
- "version": "8.3.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
- "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
- "dev": true
- }
}
},
"binary-extensions": {
@@ -637,31 +5290,23 @@
"integrity": "sha512-lkc0XyiX9E9KiVAS1ZiOqK1xfiwvf4FXDDdkDq5crcDzOq+xGytY+14qCsqz7kCiy8rpN1CRNfacRhf9G3JNSA=="
},
"bip32": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/bip32/-/bip32-3.0.1.tgz",
- "integrity": "sha512-Uhpp9aEx3iyiO7CpbNGFxv9WcMIVdGoHG04doQ5Ln0u60uwDah7jUSc3QMV/fSZGm/Oo01/OeAmYevXV+Gz5jQ==",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/bip32/-/bip32-3.1.0.tgz",
+ "integrity": "sha512-eoeajYEzJ4d6yyVtby8C+XkCeKItiC4Mx56a0M9VaqTMC73SWOm4xVZG7SaR8e/yp4eSyky2XcBpH3DApPdu7Q==",
"dev": true,
"requires": {
- "@types/node": "10.12.18",
"bs58check": "^2.1.1",
"create-hash": "^1.2.0",
"create-hmac": "^1.1.7",
+ "ripemd160": "^2.0.2",
"typeforce": "^1.11.5",
"wif": "^2.0.6"
- },
- "dependencies": {
- "@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
- }
}
},
"bip39": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.2.tgz",
- "integrity": "sha512-J4E1r2N0tUylTKt07ibXvhpT2c5pyAFgvuA5q1H9uDy6dEGpjV8jmymh3MTYJDLCNbIVClSB9FbND49I6N24MQ==",
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.4.tgz",
+ "integrity": "sha512-YZKQlb752TrUWqHWj7XAwCSjYEgGAk+/Aas3V7NyjQeZYsztO8JnQUaCWhcnL4T+jL8nvB8typ2jRPzTlgugNw==",
"dev": true,
"requires": {
"@types/node": "11.11.6",
@@ -722,22 +5367,21 @@
"dev": true
},
"browserslist": {
- "version": "4.20.3",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz",
- "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==",
+ "version": "4.21.4",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz",
+ "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==",
"dev": true,
"requires": {
- "caniuse-lite": "^1.0.30001332",
- "electron-to-chromium": "^1.4.118",
- "escalade": "^3.1.1",
- "node-releases": "^2.0.3",
- "picocolors": "^1.0.0"
+ "caniuse-lite": "^1.0.30001400",
+ "electron-to-chromium": "^1.4.251",
+ "node-releases": "^2.0.6",
+ "update-browserslist-db": "^1.0.9"
}
},
"bs58": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
- "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=",
+ "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==",
"requires": {
"base-x": "^3.0.2"
}
@@ -753,15 +5397,9 @@
}
},
"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
- },
- "builtin-modules": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
- "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true
},
"caching-transform": {
@@ -776,6 +5414,12 @@
"write-file-atomic": "^3.0.0"
}
},
+ "callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true
+ },
"camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
@@ -783,31 +5427,19 @@
"dev": true
},
"caniuse-lite": {
- "version": "1.0.30001343",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001343.tgz",
- "integrity": "sha512-8KeCrAtPMabo/XW14B+R9sZYoClx1n0b+WYgwDKZPtWR3TcdvWzdSy7mPyFEmR5WU1St9v1PW6sdO5dkFOEzfA==",
+ "version": "1.0.30001436",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001436.tgz",
+ "integrity": "sha512-ZmWkKsnC2ifEPoWUvSAIGyOYwT+keAaaWPHiQ9DfMqS1t6tfuyFYoWR78TeZtznkEQ64+vGXH9cZrElwR2Mrxg==",
"dev": true
},
"chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- },
- "dependencies": {
- "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,
- "requires": {
- "has-flag": "^3.0.0"
- }
- }
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
}
},
"chokidar": {
@@ -824,6 +5456,17 @@
"is-glob": "~4.0.1",
"normalize-path": "~3.0.0",
"readdirp": "~3.6.0"
+ },
+ "dependencies": {
+ "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,
+ "requires": {
+ "is-glob": "^4.0.1"
+ }
+ }
}
},
"cipher-base": {
@@ -853,24 +5496,24 @@
}
},
"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==",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"requires": {
- "color-name": "1.1.3"
+ "color-name": "~1.1.4"
}
},
"color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+ "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
},
"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==",
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
+ "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
"dev": true
},
"commondir": {
@@ -882,17 +5525,14 @@
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"dev": true
},
"convert-source-map": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz",
- "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==",
- "dev": true,
- "requires": {
- "safe-buffer": "~5.1.1"
- }
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
+ "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
+ "dev": true
},
"create-hash": {
"version": "1.2.0",
@@ -943,27 +5583,25 @@
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dev": true,
"requires": {
- "ms": "2.1.2"
- },
- "dependencies": {
- "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
- }
+ "ms": "2.1.2"
}
},
"decamelize": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
- "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+ "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
+ "dev": true
+ },
+ "deep-is": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
"dev": true
},
"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==",
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz",
+ "integrity": "sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==",
"dev": true,
"requires": {
"strip-bom": "^4.0.0"
@@ -984,10 +5622,28 @@
"integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
"dev": true
},
+ "dir-glob": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+ "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+ "dev": true,
+ "requires": {
+ "path-type": "^4.0.0"
+ }
+ },
+ "doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "dev": true,
+ "requires": {
+ "esutils": "^2.0.2"
+ }
+ },
"ecpair": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/ecpair/-/ecpair-2.0.1.tgz",
- "integrity": "sha512-iT3wztQMeE/nDTlfnAg8dAFUfBS7Tq2BXzq3ae6L+pWgFU0fQ3l0woTzdTBrJV3OxBjxbzjq8EQhAbEmJNWFSw==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/ecpair/-/ecpair-2.1.0.tgz",
+ "integrity": "sha512-cL/mh3MtJutFOvFc27GPZE2pWL3a3k4YvzUWEOvilnfZVlH3Jwgx/7d6tlD7/75tNk8TG2m+7Kgtz0SI1tWcqw==",
"dev": true,
"requires": {
"randombytes": "^2.1.0",
@@ -996,9 +5652,9 @@
}
},
"electron-to-chromium": {
- "version": "1.4.139",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.139.tgz",
- "integrity": "sha512-lYxzcUCjWxxVug+A7UxBCUiVr13TCjfZFYJS9Lq1VpU/ErwV4a6zUQo9dfojuGpw/L/x9REGuBl6ICQPGgbs3g==",
+ "version": "1.4.284",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz",
+ "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==",
"dev": true
},
"emoji-regex": {
@@ -1020,27 +5676,258 @@
"dev": true
},
"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=",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true
+ },
+ "eslint": {
+ "version": "8.29.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz",
+ "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==",
+ "dev": true,
+ "requires": {
+ "@eslint/eslintrc": "^1.3.3",
+ "@humanwhocodes/config-array": "^0.11.6",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@nodelib/fs.walk": "^1.2.8",
+ "ajv": "^6.10.0",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.2",
+ "debug": "^4.3.2",
+ "doctrine": "^3.0.0",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^7.1.1",
+ "eslint-utils": "^3.0.0",
+ "eslint-visitor-keys": "^3.3.0",
+ "espree": "^9.4.0",
+ "esquery": "^1.4.0",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^6.0.1",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "globals": "^13.15.0",
+ "grapheme-splitter": "^1.0.4",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.0.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "is-path-inside": "^3.0.3",
+ "js-sdsl": "^4.1.4",
+ "js-yaml": "^4.1.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.4.1",
+ "lodash.merge": "^4.6.2",
+ "minimatch": "^3.1.2",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.1",
+ "regexpp": "^3.2.0",
+ "strip-ansi": "^6.0.1",
+ "strip-json-comments": "^3.1.0",
+ "text-table": "^0.2.0"
+ },
+ "dependencies": {
+ "eslint-scope": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
+ "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
+ "dev": true,
+ "requires": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ }
+ },
+ "estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true
+ }
+ }
+ },
+ "eslint-config-prettier": {
+ "version": "8.5.0",
+ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz",
+ "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==",
+ "dev": true,
+ "requires": {}
+ },
+ "eslint-plugin-prettier": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz",
+ "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==",
+ "dev": true,
+ "requires": {
+ "prettier-linter-helpers": "^1.0.0"
+ }
+ },
+ "eslint-scope": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+ "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+ "dev": true,
+ "requires": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^4.1.1"
+ }
+ },
+ "eslint-utils": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
+ "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
+ "dev": true,
+ "requires": {
+ "eslint-visitor-keys": "^2.0.0"
+ },
+ "dependencies": {
+ "eslint-visitor-keys": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
+ "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
+ "dev": true
+ }
+ }
+ },
+ "eslint-visitor-keys": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
+ "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
"dev": true
},
+ "espree": {
+ "version": "9.4.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz",
+ "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==",
+ "dev": true,
+ "requires": {
+ "acorn": "^8.8.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^3.3.0"
+ }
+ },
"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
},
+ "esquery": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
+ "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
+ "dev": true,
+ "requires": {
+ "estraverse": "^5.1.0"
+ },
+ "dependencies": {
+ "estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true
+ }
+ }
+ },
+ "esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
+ "requires": {
+ "estraverse": "^5.2.0"
+ },
+ "dependencies": {
+ "estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true
+ }
+ }
+ },
+ "estraverse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+ "dev": true
+ },
+ "esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true
+ },
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
+ "fast-diff": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz",
+ "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==",
+ "dev": true
+ },
+ "fast-glob": {
+ "version": "3.2.12",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
+ "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
+ "dev": true,
+ "requires": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.4"
+ },
+ "dependencies": {
+ "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,
+ "requires": {
+ "is-glob": "^4.0.1"
+ }
+ }
+ }
+ },
+ "fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true
+ },
+ "fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+ "dev": true
+ },
+ "fastq": {
+ "version": "1.14.0",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.14.0.tgz",
+ "integrity": "sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==",
+ "dev": true,
+ "requires": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "file-entry-cache": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+ "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+ "dev": true,
+ "requires": {
+ "flat-cache": "^3.0.4"
+ }
+ },
"fill-keys": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz",
- "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=",
+ "integrity": "sha512-tcgI872xXjwFF4xgQmLxi76GnwJG3g/3isB1l4/G5Z4zrbddGpBjqZCO9oEAcB5wX0Hj/5iQB3toxfO7in1hHA==",
"dev": true,
"requires": {
"is-object": "~1.0.1",
@@ -1083,6 +5970,33 @@
"integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
"dev": true
},
+ "flat-cache": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
+ "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
+ "dev": true,
+ "requires": {
+ "flatted": "^3.1.0",
+ "rimraf": "^3.0.2"
+ },
+ "dependencies": {
+ "rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ }
+ }
+ },
+ "flatted": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
+ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
+ "dev": true
+ },
"foreground-child": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz",
@@ -1102,7 +6016,7 @@
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"dev": true
},
"fsevents": {
@@ -1112,6 +6026,12 @@
"dev": true,
"optional": true
},
+ "function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+ "dev": true
+ },
"gensync": {
"version": "1.0.0-beta.2",
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
@@ -1131,9 +6051,9 @@
"dev": true
},
"glob": {
- "version": "7.1.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
- "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
+ "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
@@ -1145,19 +6065,36 @@
}
},
"glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
"dev": true,
"requires": {
- "is-glob": "^4.0.1"
+ "is-glob": "^4.0.3"
}
},
"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
+ "version": "13.18.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz",
+ "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==",
+ "dev": true,
+ "requires": {
+ "type-fest": "^0.20.2"
+ }
+ },
+ "globby": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+ "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+ "dev": true,
+ "requires": {
+ "array-union": "^2.1.0",
+ "dir-glob": "^3.0.1",
+ "fast-glob": "^3.2.9",
+ "ignore": "^5.2.0",
+ "merge2": "^1.4.1",
+ "slash": "^3.0.0"
+ }
},
"graceful-fs": {
"version": "4.2.10",
@@ -1165,19 +6102,35 @@
"integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
"dev": true
},
+ "grapheme-splitter": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
+ "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
+ "dev": true
+ },
+ "has": {
+ "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-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true
},
"hash-base": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz",
- "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
+ "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
"requires": {
- "inherits": "^2.0.1",
- "safe-buffer": "^5.0.1"
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.6.0",
+ "safe-buffer": "^5.2.0"
}
},
"hasha": {
@@ -1188,6 +6141,14 @@
"requires": {
"is-stream": "^2.0.0",
"type-fest": "^0.8.0"
+ },
+ "dependencies": {
+ "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
+ }
}
},
"he": {
@@ -1208,10 +6169,26 @@
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
"dev": true
},
+ "ignore": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz",
+ "integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==",
+ "dev": true
+ },
+ "import-fresh": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+ "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+ "dev": true,
+ "requires": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ }
+ },
"imurmurhash": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
"dev": true
},
"indent-string": {
@@ -1223,7 +6200,7 @@
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"dev": true,
"requires": {
"once": "^1.3.0",
@@ -1231,9 +6208,9 @@
}
},
"inherits": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
- "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"is-binary-path": {
"version": "2.1.0",
@@ -1244,10 +6221,19 @@
"binary-extensions": "^2.0.0"
}
},
+ "is-core-module": {
+ "version": "2.11.0",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
+ "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
+ "dev": true,
+ "requires": {
+ "has": "^1.0.3"
+ }
+ },
"is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"dev": true
},
"is-fullwidth-code-point": {
@@ -1272,9 +6258,15 @@
"dev": true
},
"is-object": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz",
- "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz",
+ "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==",
+ "dev": true
+ },
+ "is-path-inside": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
"dev": true
},
"is-plain-obj": {
@@ -1292,7 +6284,7 @@
"is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
- "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
+ "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==",
"dev": true
},
"is-unicode-supported": {
@@ -1310,7 +6302,7 @@
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
"dev": true
},
"istanbul-lib-coverage": {
@@ -1349,18 +6341,17 @@
}
},
"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==",
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz",
+ "integrity": "sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==",
"dev": true,
"requires": {
"archy": "^1.0.0",
- "cross-spawn": "^7.0.0",
- "istanbul-lib-coverage": "^3.0.0-alpha.1",
- "make-dir": "^3.0.0",
+ "cross-spawn": "^7.0.3",
+ "istanbul-lib-coverage": "^3.2.0",
"p-map": "^3.0.0",
"rimraf": "^3.0.0",
- "uuid": "^3.3.3"
+ "uuid": "^8.3.2"
},
"dependencies": {
"rimraf": {
@@ -1383,23 +6374,6 @@
"istanbul-lib-coverage": "^3.0.0",
"make-dir": "^3.0.0",
"supports-color": "^7.1.0"
- },
- "dependencies": {
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "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,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
}
},
"istanbul-lib-source-maps": {
@@ -1414,15 +6388,21 @@
}
},
"istanbul-reports": {
- "version": "3.1.4",
- "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz",
- "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==",
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz",
+ "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==",
"dev": true,
"requires": {
"html-escaper": "^2.0.0",
"istanbul-lib-report": "^3.0.0"
}
},
+ "js-sdsl": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz",
+ "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==",
+ "dev": true
+ },
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -1430,13 +6410,12 @@
"dev": true
},
"js-yaml": {
- "version": "3.13.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
- "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
"requires": {
- "argparse": "^1.0.7",
- "esprima": "^4.0.0"
+ "argparse": "^2.0.1"
}
},
"jsesc": {
@@ -1446,9 +6425,15 @@
"dev": true
},
"json-schema-traverse": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
- "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
"dev": true
},
"json5": {
@@ -1457,6 +6442,16 @@
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
"dev": true
},
+ "levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "dev": true,
+ "requires": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ }
+ },
"locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@@ -1469,7 +6464,7 @@
"lodash.flattendeep": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
- "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=",
+ "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==",
"dev": true
},
"lodash.get": {
@@ -1478,6 +6473,12 @@
"integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==",
"dev": true
},
+ "lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true
+ },
"lodash.truncate": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
@@ -1492,57 +6493,15 @@
"requires": {
"chalk": "^4.1.0",
"is-unicode-supported": "^0.1.0"
- },
- "dependencies": {
- "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,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
+ }
+ },
+ "lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dev": true,
+ "requires": {
+ "yallist": "^4.0.0"
}
},
"make-dir": {
@@ -1563,9 +6522,9 @@
}
},
"make-error": {
- "version": "1.3.5",
- "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz",
- "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==",
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
"dev": true
},
"md5.js": {
@@ -1581,13 +6540,29 @@
"merge-descriptors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
- "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=",
+ "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==",
"dev": true
},
+ "merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "dev": true
+ },
+ "micromatch": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
+ "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+ "dev": true,
+ "requires": {
+ "braces": "^3.0.2",
+ "picomatch": "^2.3.1"
+ }
+ },
"minimaldata": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/minimaldata/-/minimaldata-1.0.2.tgz",
- "integrity": "sha1-AfOywB2LJzmEP9hT1AY2xaLrdms=",
+ "integrity": "sha512-ZR9tWALR8ZszYd/zP34TmmVwRDVBNCT5+hkNXfTp3rpEDmZmgmYt1Sh/tu9qYFuPvSvEEEeJGE2BY8MBmeAzQQ==",
"dev": true,
"requires": {
"bitcoin-ops": "^1.3.0",
@@ -1603,28 +6578,12 @@
"brace-expansion": "^1.1.7"
}
},
- "minimist": {
- "version": "1.2.6",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
- "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
- "dev": true
- },
- "mkdirp": {
- "version": "0.5.3",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.3.tgz",
- "integrity": "sha512-P+2gwrFqx8lhew375MQHHeTlY8AuOJSrGf0R5ddkEndUkmwpgUob/vQuBD1V22/Cw1/lJr4x+EjllSezBThzBg==",
- "dev": true,
- "requires": {
- "minimist": "^1.2.5"
- }
- },
"mocha": {
- "version": "10.0.0",
- "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.0.0.tgz",
- "integrity": "sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA==",
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.1.0.tgz",
+ "integrity": "sha512-vUF7IYxEoN7XhQpFLxQAEMtE4W91acW4B6En9l97MwE9stL1A9gusXfoHZCLVHDUJ/7V5+lbCM6yMqzo5vNymg==",
"dev": true,
"requires": {
- "@ungap/promise-all-settled": "1.1.2",
"ansi-colors": "4.1.1",
"browser-stdout": "1.3.1",
"chokidar": "3.5.3",
@@ -1648,50 +6607,13 @@
"yargs-unparser": "2.0.0"
},
"dependencies": {
- "argparse": {
+ "brace-expansion": {
"version": "2.0.1",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
- "dev": true
- },
- "escape-string-regexp": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
- "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
- "dev": true
- },
- "glob": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
- "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true,
"requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- },
- "dependencies": {
- "minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "requires": {
- "brace-expansion": "^1.1.7"
- }
- }
- }
- },
- "js-yaml": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
- "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
- "dev": true,
- "requires": {
- "argparse": "^2.0.1"
+ "balanced-match": "^1.0.0"
}
},
"minimatch": {
@@ -1701,17 +6623,21 @@
"dev": true,
"requires": {
"brace-expansion": "^2.0.1"
- },
- "dependencies": {
- "brace-expansion": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
- "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
- "dev": true,
- "requires": {
- "balanced-match": "^1.0.0"
- }
- }
+ }
+ },
+ "ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
}
}
}
@@ -1719,13 +6645,13 @@
"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=",
+ "integrity": "sha512-pEk4ECWQXV6z2zjhRZUongnLJNUeGQJ3w6OQ5ctGwD+i5o93qjRQUk2Rt6VdNeu3sEP0AB4LcfvdebpxBRVr4g==",
"dev": true
},
"ms": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"nanoid": {
@@ -1734,6 +6660,18 @@
"integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==",
"dev": true
},
+ "natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+ "dev": true
+ },
+ "natural-compare-lite": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz",
+ "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==",
+ "dev": true
+ },
"node-preload": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz",
@@ -1744,9 +6682,9 @@
}
},
"node-releases": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz",
- "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==",
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz",
+ "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==",
"dev": true
},
"normalize-path": {
@@ -1790,15 +6728,6 @@
"yargs": "^15.0.2"
},
"dependencies": {
- "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,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
"cliui": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
@@ -1810,21 +6739,6 @@
"wrap-ansi": "^6.2.0"
}
},
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
"find-up": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
@@ -1835,20 +6749,6 @@
"path-exists": "^4.0.0"
}
},
- "glob": {
- "version": "7.2.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
- "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
- "dev": true,
- "requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.1.1",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- }
- },
"locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
@@ -1858,13 +6758,13 @@
"p-locate": "^4.1.0"
}
},
- "minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"dev": true,
"requires": {
- "brace-expansion": "^1.1.7"
+ "p-try": "^2.0.0"
}
},
"p-locate": {
@@ -1876,6 +6776,12 @@
"p-limit": "^2.2.0"
}
},
+ "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
+ },
"rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
@@ -1896,6 +6802,12 @@
"strip-ansi": "^6.0.0"
}
},
+ "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
+ },
"yargs": {
"version": "15.4.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
@@ -1930,19 +6842,33 @@
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dev": true,
"requires": {
"wrappy": "1"
}
},
+ "optionator": {
+ "version": "0.9.1",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
+ "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
+ "dev": true,
+ "requires": {
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.3"
+ }
+ },
"p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
"dev": true,
"requires": {
- "p-try": "^2.0.0"
+ "yocto-queue": "^0.1.0"
}
},
"p-locate": {
@@ -1952,17 +6878,6 @@
"dev": true,
"requires": {
"p-limit": "^3.0.2"
- },
- "dependencies": {
- "p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "dev": true,
- "requires": {
- "yocto-queue": "^0.1.0"
- }
- }
}
},
"p-map": {
@@ -1992,6 +6907,15 @@
"release-zalgo": "^1.0.0"
}
},
+ "parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "requires": {
+ "callsites": "^3.0.0"
+ }
+ },
"path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -2001,7 +6925,7 @@
"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=",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
"dev": true
},
"path-key": {
@@ -2016,6 +6940,12 @@
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true
},
+ "path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "dev": true
+ },
"pbkdf2": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
@@ -2069,6 +6999,15 @@
"p-locate": "^4.1.0"
}
},
+ "p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "requires": {
+ "p-try": "^2.0.0"
+ }
+ },
"p-locate": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
@@ -2080,12 +7019,27 @@
}
}
},
+ "prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "dev": true
+ },
"prettier": {
- "version": "1.16.4",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.16.4.tgz",
- "integrity": "sha512-ZzWuos7TI5CKUeQAtFd6Zhm2s6EpAD/ZLApIhsF9pRvRtM1RFo61dM/4MSRUA0SuLugA/zgrZD8m0BaY46Og7g==",
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.0.tgz",
+ "integrity": "sha512-9Lmg8hTFZKG0Asr/kW9Bp8tJjRVluO8EJQVfY2T7FMw9T5jy4I/Uvx0Rca/XWf50QQ1/SS48+6IJWnrb+2yemA==",
"dev": true
},
+ "prettier-linter-helpers": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
+ "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
+ "dev": true,
+ "requires": {
+ "fast-diff": "^1.1.2"
+ }
+ },
"process-on-spawn": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz",
@@ -2096,14 +7050,14 @@
}
},
"proxyquire": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/proxyquire/-/proxyquire-2.1.0.tgz",
- "integrity": "sha512-kptdFArCfGRtQFv3Qwjr10lwbEV0TBJYvfqzhwucyfEXqVgmnAkyEw/S3FYzR5HI9i5QOq4rcqQjZ6AlknlCDQ==",
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/proxyquire/-/proxyquire-2.1.3.tgz",
+ "integrity": "sha512-BQWfCqYM+QINd+yawJz23tbBM40VIGXOdDw3X344KcclI/gtBbdWF6SlQ4nK/bYhF9d27KYug9WzljHC6B9Ysg==",
"dev": true,
"requires": {
"fill-keys": "^1.0.2",
- "module-not-found-error": "^1.0.0",
- "resolve": "~1.8.1"
+ "module-not-found-error": "^1.0.1",
+ "resolve": "^1.11.1"
}
},
"punycode": {
@@ -2115,12 +7069,18 @@
"pushdata-bitcoin": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/pushdata-bitcoin/-/pushdata-bitcoin-1.0.1.tgz",
- "integrity": "sha1-FZMdPNlnreUiBvUjqnMxrvfUOvc=",
+ "integrity": "sha512-hw7rcYTJRAl4olM8Owe8x0fBuJJ+WGbMhQuLWOXEMN3PxPCKQHRkhfL+XG0+iXUmSHjkMmb3Ba55Mt21cZc9kQ==",
"dev": true,
"requires": {
"bitcoin-ops": "^1.3.0"
}
},
+ "queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "dev": true
+ },
"randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@@ -2130,6 +7090,16 @@
"safe-buffer": "^5.1.0"
}
},
+ "readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ }
+ },
"readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
@@ -2139,6 +7109,12 @@
"picomatch": "^2.2.1"
}
},
+ "regexpp": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
+ "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
+ "dev": true
+ },
"regtest-client": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/regtest-client/-/regtest-client-0.2.0.tgz",
@@ -2153,7 +7129,7 @@
"release-zalgo": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz",
- "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=",
+ "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==",
"dev": true,
"requires": {
"es6-error": "^4.0.1"
@@ -2162,7 +7138,7 @@
"require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
- "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
"dev": true
},
"require-from-string": {
@@ -2178,43 +7154,35 @@
"dev": true
},
"resolve": {
- "version": "1.8.1",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz",
- "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==",
+ "version": "1.22.1",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
+ "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
"dev": true,
"requires": {
- "path-parse": "^1.0.5"
+ "is-core-module": "^2.9.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
}
},
"resolve-from": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
- "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true
+ },
+ "reusify": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
"dev": true
},
"rimraf": {
- "version": "2.6.3",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
- "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
"dev": true,
"requires": {
"glob": "^7.1.3"
- },
- "dependencies": {
- "glob": {
- "version": "7.1.4",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
- "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
- "dev": true,
- "requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- }
- }
}
},
"ripemd160": {
@@ -2226,16 +7194,28 @@
"inherits": "^2.0.1"
}
},
+ "run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "dev": true,
+ "requires": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
"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=="
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
},
"semver": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
- "dev": true
+ "version": "7.3.8",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+ "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+ "dev": true,
+ "requires": {
+ "lru-cache": "^6.0.0"
+ }
},
"serialize-javascript": {
"version": "6.0.0",
@@ -2249,7 +7229,7 @@
"set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
- "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
+ "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
"dev": true
},
"sha.js": {
@@ -2282,6 +7262,12 @@
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"dev": true
},
+ "slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "dev": true
+ },
"slice-ansi": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
@@ -2291,32 +7277,6 @@
"ansi-styles": "^4.0.0",
"astral-regex": "^2.0.0",
"is-fullwidth-code-point": "^3.0.0"
- },
- "dependencies": {
- "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,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- }
}
},
"source-map": {
@@ -2326,21 +7286,13 @@
"dev": true
},
"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==",
+ "version": "0.5.21",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+ "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"dev": true,
"requires": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
- },
- "dependencies": {
- "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
- }
}
},
"spawn-wrap": {
@@ -2371,15 +7323,23 @@
"sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
- "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
+ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
"dev": true
},
"statuses": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
- "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
+ "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==",
"dev": true
},
+ "string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "requires": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
"string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
@@ -2413,22 +7373,20 @@
"dev": true
},
"supports-color": {
- "version": "8.1.1",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
- "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "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,
"requires": {
"has-flag": "^4.0.0"
- },
- "dependencies": {
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- }
}
},
+ "supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "dev": true
+ },
"table": {
"version": "6.8.1",
"resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz",
@@ -2440,6 +7398,26 @@
"slice-ansi": "^4.0.0",
"string-width": "^4.2.3",
"strip-ansi": "^6.0.1"
+ },
+ "dependencies": {
+ "ajv": {
+ "version": "8.11.2",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz",
+ "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true
+ }
}
},
"test-exclude": {
@@ -2451,48 +7429,27 @@
"@istanbuljs/schema": "^0.1.2",
"glob": "^7.1.4",
"minimatch": "^3.0.4"
- },
- "dependencies": {
- "glob": {
- "version": "7.2.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
- "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
- "dev": true,
- "requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.1.1",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- },
- "dependencies": {
- "minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "requires": {
- "brace-expansion": "^1.1.7"
- }
- }
- }
- }
}
},
+ "text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+ "dev": true
+ },
"tiny-secp256k1": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-2.2.0.tgz",
- "integrity": "sha512-2hPuUGCroLrxh6xxwoe+1RgPpOOK1w2uTnhgiHBpvoutBR+krNuT4hOXQyOaaYnZgoXBB6hBYkuAJHxyeBOPzQ==",
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-2.2.1.tgz",
+ "integrity": "sha512-/U4xfVqnVxJXN4YVsru0E6t5wVncu2uunB8+RVR40fYUxkKYUPS10f+ePQZgFBoE/Jbf9H1NBveupF2VmB58Ng==",
"dev": true,
"requires": {
- "uint8array-tools": "0.0.6"
+ "uint8array-tools": "0.0.7"
}
},
"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=",
+ "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
"dev": true
},
"to-regex-range": {
@@ -2505,22 +7462,22 @@
}
},
"ts-node": {
- "version": "8.3.0",
- "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.3.0.tgz",
- "integrity": "sha512-dyNS/RqyVTDcmNM4NIBAeDMpsAdaQ+ojdf0GOLqE6nwJOgzEkdRNzJywhDfwnuvB10oa6NLVG1rUJQCpRN7qoQ==",
+ "version": "8.10.2",
+ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.2.tgz",
+ "integrity": "sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==",
"dev": true,
"requires": {
"arg": "^4.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
- "source-map-support": "^0.5.6",
- "yn": "^3.0.0"
+ "source-map-support": "^0.5.17",
+ "yn": "3.1.1"
},
"dependencies": {
"diff": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz",
- "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==",
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true
}
}
@@ -2531,48 +7488,28 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
},
- "tslint": {
- "version": "6.1.3",
- "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz",
- "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==",
+ "tsutils": {
+ "version": "3.21.0",
+ "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
+ "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
"dev": true,
"requires": {
- "@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"
- },
- "dependencies": {
- "diff": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
- "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
- "dev": true
- }
+ "tslib": "^1.8.1"
}
},
- "tsutils": {
- "version": "2.29.0",
- "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
- "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==",
+ "type-check": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
"dev": true,
"requires": {
- "tslib": "^1.8.1"
+ "prelude-ls": "^1.2.1"
}
},
"type-fest": {
- "version": "0.8.1",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
- "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
"dev": true
},
"typedarray-to-buffer": {
@@ -2590,17 +7527,27 @@
"integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g=="
},
"typescript": {
- "version": "4.4.4",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz",
- "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==",
+ "version": "4.9.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz",
+ "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==",
"dev": true
},
"uint8array-tools": {
- "version": "0.0.6",
- "resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.6.tgz",
- "integrity": "sha512-aIvEHNRX1AlOYAr6qSUjQBn4mCduxx6MtC967aRDTb2UUBPj0Ix2ZFQDcmXUUO/UxRPHcw1f5a5nVbCSKDSOqA==",
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.7.tgz",
+ "integrity": "sha512-vrrNZJiusLWoFWBqz5Y5KMCgP9W9hnjZHzZiZRT8oNAkq3d5Z5Oe76jAvVVSRh4U8GGR90N2X1dWtrhvx6L8UQ==",
"dev": true
},
+ "update-browserslist-db": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
+ "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
+ "dev": true,
+ "requires": {
+ "escalade": "^3.1.1",
+ "picocolors": "^1.0.0"
+ }
+ },
"uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@@ -2610,10 +7557,15 @@
"punycode": "^2.1.0"
}
},
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
+ },
"uuid": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
- "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"dev": true
},
"varuint-bitcoin": {
@@ -2636,17 +7588,23 @@
"which-module": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
- "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
+ "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==",
"dev": true
},
"wif": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz",
- "integrity": "sha1-CNP1IFbGZnkplyb63g1DKudLRwQ=",
+ "integrity": "sha512-HIanZn1zmduSF+BQhkE+YXIbEiH0xPr1012QbFEGB0xsKqJii0/SqJjyn8dFv6y36kOznMgMB+LGcbZTJ1xACQ==",
"requires": {
"bs58check": "<3.0.0"
}
},
+ "word-wrap": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+ "dev": true
+ },
"workerpool": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
@@ -2662,38 +7620,12 @@
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
- },
- "dependencies": {
- "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,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- }
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"dev": true
},
"write-file-atomic": {
@@ -2709,9 +7641,15 @@
}
},
"y18n": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
- "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "dev": true
+ },
+ "yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true
},
"yargs": {
@@ -2727,14 +7665,6 @@
"string-width": "^4.2.0",
"y18n": "^5.0.5",
"yargs-parser": "^20.2.2"
- },
- "dependencies": {
- "y18n": {
- "version": "5.0.8",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
- "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
- "dev": true
- }
}
},
"yargs-parser": {
diff --git a/package.json b/package.json
index b2414f42f..4334faa4f 100644
--- a/package.json
+++ b/package.json
@@ -28,8 +28,8 @@
"format:ci": "npm run prettier -- --check && npm run prettierjs -- --check",
"gitdiff:ci": "npm run build && git diff --exit-code",
"integration": "npm run build && npm run nobuild:integration",
- "lint": "tslint -p tsconfig.json -c tslint.json",
- "lint:tests": "tslint -p test/tsconfig.json -c tslint.json",
+ "lint": "eslint ts_src/** src/**/*.js",
+ "lint:tests": "eslint test/**/*.spec.ts",
"mocha:ts": "mocha --recursive --require test/ts-node-register",
"nobuild:coverage-report": "nyc report --reporter=lcov",
"nobuild:coverage-html": "nyc report --reporter=html",
@@ -68,6 +68,8 @@
"@types/randombytes": "^2.0.0",
"@types/ripemd160": "^2.0.0",
"@types/wif": "^2.0.2",
+ "@typescript-eslint/eslint-plugin": "^5.45.0",
+ "@typescript-eslint/parser": "^5.45.0",
"better-npm-audit": "^3.7.3",
"bip32": "^3.0.1",
"bip39": "^3.0.2",
@@ -76,18 +78,20 @@
"bs58": "^4.0.0",
"dhttp": "^3.0.0",
"ecpair": "^2.0.1",
+ "eslint": "^8.29.0",
+ "eslint-config-prettier": "^8.5.0",
+ "eslint-plugin-prettier": "^4.2.1",
"hoodwink": "^2.0.0",
"minimaldata": "^1.0.2",
"mocha": "^10.0.0",
"nyc": "^15.1.0",
- "prettier": "1.16.4",
+ "prettier": "^2.8.0",
"proxyquire": "^2.0.1",
"randombytes": "^2.1.0",
"regtest-client": "0.2.0",
"rimraf": "^2.6.3",
"tiny-secp256k1": "^2.2.0",
"ts-node": "^8.3.0",
- "tslint": "^6.1.3",
"typescript": "^4.4.4"
},
"license": "MIT"
diff --git a/src/address.js b/src/address.js
index de0154a3a..d58c9a69e 100644
--- a/src/address.js
+++ b/src/address.js
@@ -1,6 +1,12 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.toOutputScript = exports.fromOutputScript = exports.toBech32 = exports.toBase58Check = exports.fromBech32 = exports.fromBase58Check = void 0;
+exports.toOutputScript =
+ exports.fromOutputScript =
+ exports.toBech32 =
+ exports.toBase58Check =
+ exports.fromBech32 =
+ exports.fromBase58Check =
+ void 0;
const networks = require('./networks');
const payments = require('./payments');
const bscript = require('./script');
diff --git a/src/bufferutils.js b/src/bufferutils.js
index 83a013b34..0f7fd10f4 100644
--- a/src/bufferutils.js
+++ b/src/bufferutils.js
@@ -1,6 +1,13 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.BufferReader = exports.BufferWriter = exports.cloneBuffer = exports.reverseBuffer = exports.writeUInt64LE = exports.readUInt64LE = exports.varuint = void 0;
+exports.BufferReader =
+ exports.BufferWriter =
+ exports.cloneBuffer =
+ exports.reverseBuffer =
+ exports.writeUInt64LE =
+ exports.readUInt64LE =
+ exports.varuint =
+ void 0;
const types = require('./types');
const { typeforce } = types;
const varuint = require('varuint-bitcoin');
@@ -53,14 +60,14 @@ exports.cloneBuffer = cloneBuffer;
* Helper class for serialization of bitcoin data types into a pre-allocated buffer.
*/
class BufferWriter {
+ static withCapacity(size) {
+ return new BufferWriter(Buffer.alloc(size));
+ }
constructor(buffer, offset = 0) {
this.buffer = buffer;
this.offset = offset;
typeforce(types.tuple(types.Buffer, types.UInt32), [buffer, offset]);
}
- static withCapacity(size) {
- return new BufferWriter(Buffer.alloc(size));
- }
writeUInt8(i) {
this.offset = this.buffer.writeUInt8(i, this.offset);
}
diff --git a/src/crypto.d.ts b/src/crypto.d.ts
index ec088f3e3..4d88c2f39 100644
--- a/src/crypto.d.ts
+++ b/src/crypto.d.ts
@@ -5,6 +5,6 @@ export declare function sha256(buffer: Buffer): Buffer;
export declare function hash160(buffer: Buffer): Buffer;
export declare function hash256(buffer: Buffer): Buffer;
declare const TAGS: readonly ["BIP0340/challenge", "BIP0340/aux", "BIP0340/nonce", "TapLeaf", "TapBranch", "TapSighash", "TapTweak", "KeyAgg list", "KeyAgg coefficient"];
-export declare type TaggedHashPrefix = typeof TAGS[number];
+export type TaggedHashPrefix = typeof TAGS[number];
export declare function taggedHash(prefix: TaggedHashPrefix, data: Buffer): Buffer;
export {};
diff --git a/src/crypto.js b/src/crypto.js
index a3df16764..b84f2701e 100644
--- a/src/crypto.js
+++ b/src/crypto.js
@@ -1,18 +1,20 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.taggedHash = exports.hash256 = exports.hash160 = exports.sha256 = exports.sha1 = exports.ripemd160 = void 0;
+exports.taggedHash =
+ exports.hash256 =
+ exports.hash160 =
+ exports.sha256 =
+ exports.sha1 =
+ exports.ripemd160 =
+ void 0;
const createHash = require('create-hash');
const RipeMd160 = require('ripemd160');
function ripemd160(buffer) {
try {
- return createHash('rmd160')
- .update(buffer)
- .digest();
+ return createHash('rmd160').update(buffer).digest();
} catch (err) {
try {
- return createHash('ripemd160')
- .update(buffer)
- .digest();
+ return createHash('ripemd160').update(buffer).digest();
} catch (err2) {
return new RipeMd160().update(buffer).digest();
}
@@ -20,15 +22,11 @@ function ripemd160(buffer) {
}
exports.ripemd160 = ripemd160;
function sha1(buffer) {
- return createHash('sha1')
- .update(buffer)
- .digest();
+ return createHash('sha1').update(buffer).digest();
}
exports.sha1 = sha1;
function sha256(buffer) {
- return createHash('sha256')
- .update(buffer)
- .digest();
+ return createHash('sha256').update(buffer).digest();
}
exports.sha256 = sha256;
function hash160(buffer) {
diff --git a/src/index.js b/src/index.js
index 25d0b5a22..4159064bd 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,6 +1,16 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.initEccLib = exports.Transaction = exports.opcodes = exports.Psbt = exports.Block = exports.script = exports.payments = exports.networks = exports.crypto = exports.address = void 0;
+exports.initEccLib =
+ exports.Transaction =
+ exports.opcodes =
+ exports.Psbt =
+ exports.Block =
+ exports.script =
+ exports.payments =
+ exports.networks =
+ exports.crypto =
+ exports.address =
+ void 0;
const address = require('./address');
exports.address = address;
const crypto = require('./crypto');
@@ -14,35 +24,35 @@ exports.script = script;
var block_1 = require('./block');
Object.defineProperty(exports, 'Block', {
enumerable: true,
- get: function() {
+ get: function () {
return block_1.Block;
},
});
var psbt_1 = require('./psbt');
Object.defineProperty(exports, 'Psbt', {
enumerable: true,
- get: function() {
+ get: function () {
return psbt_1.Psbt;
},
});
var ops_1 = require('./ops');
Object.defineProperty(exports, 'opcodes', {
enumerable: true,
- get: function() {
+ get: function () {
return ops_1.OPS;
},
});
var transaction_1 = require('./transaction');
Object.defineProperty(exports, 'Transaction', {
enumerable: true,
- get: function() {
+ get: function () {
return transaction_1.Transaction;
},
});
var ecc_lib_1 = require('./ecc_lib');
Object.defineProperty(exports, 'initEccLib', {
enumerable: true,
- get: function() {
+ get: function () {
return ecc_lib_1.initEccLib;
},
});
diff --git a/src/payments/bip341.d.ts b/src/payments/bip341.d.ts
index 8dd82409a..fe9ecf0d9 100644
--- a/src/payments/bip341.d.ts
+++ b/src/payments/bip341.d.ts
@@ -20,7 +20,7 @@ interface TweakedPublicKey {
* This tree is used for 2 purposes: Providing the root hash for tweaking,
* and calculating merkle inclusion proofs when constructing a control block.
*/
-export declare type HashTree = HashLeaf | HashBranch;
+export type HashTree = HashLeaf | HashBranch;
export declare function rootHashFromPath(controlBlock: Buffer, leafHash: Buffer): Buffer;
/**
* Build a hash tree of merkle nodes from the scripts binary tree.
diff --git a/src/payments/bip341.js b/src/payments/bip341.js
index 02c976b5f..35609d788 100644
--- a/src/payments/bip341.js
+++ b/src/payments/bip341.js
@@ -1,6 +1,14 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.tweakKey = exports.tapTweakHash = exports.tapleafHash = exports.findScriptPath = exports.toHashTree = exports.rootHashFromPath = exports.MAX_TAPTREE_DEPTH = exports.LEAF_VERSION_TAPSCRIPT = void 0;
+exports.tweakKey =
+ exports.tapTweakHash =
+ exports.tapleafHash =
+ exports.findScriptPath =
+ exports.toHashTree =
+ exports.rootHashFromPath =
+ exports.MAX_TAPTREE_DEPTH =
+ exports.LEAF_VERSION_TAPSCRIPT =
+ void 0;
const buffer_1 = require('buffer');
const ecc_lib_1 = require('../ecc_lib');
const bcrypto = require('../crypto');
@@ -12,9 +20,7 @@ const isHashBranch = ht => 'left' in ht && 'right' in ht;
function rootHashFromPath(controlBlock, leafHash) {
if (controlBlock.length < 33)
throw new TypeError(
- `The control-block length is too small. Got ${
- controlBlock.length
- }, expected min 33.`,
+ `The control-block length is too small. Got ${controlBlock.length}, expected min 33.`,
);
const m = (controlBlock.length - 33) / 32;
let kj = leafHash;
diff --git a/src/payments/index.d.ts b/src/payments/index.d.ts
index 07c12cc48..57a0369b8 100644
--- a/src/payments/index.d.ts
+++ b/src/payments/index.d.ts
@@ -29,13 +29,13 @@ export interface Payment {
scriptTree?: Taptree;
witness?: Buffer[];
}
-export declare type PaymentCreator = (a: Payment, opts?: PaymentOpts) => Payment;
-export declare type PaymentFunction = () => Payment;
+export type PaymentCreator = (a: Payment, opts?: PaymentOpts) => Payment;
+export type PaymentFunction = () => Payment;
export interface PaymentOpts {
validate?: boolean;
allowIncomplete?: boolean;
}
-export declare type StackElement = Buffer | number;
-export declare type Stack = StackElement[];
-export declare type StackFunction = () => Stack;
+export type StackElement = Buffer | number;
+export type Stack = StackElement[];
+export type StackFunction = () => Stack;
export { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh, p2tr };
diff --git a/src/payments/index.js b/src/payments/index.js
index 9ce55f859..f820ddeee 100644
--- a/src/payments/index.js
+++ b/src/payments/index.js
@@ -1,59 +1,67 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.p2tr = 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,
- get: function() {
+ get: function () {
return embed_1.p2data;
},
});
const p2ms_1 = require('./p2ms');
Object.defineProperty(exports, 'p2ms', {
enumerable: true,
- get: function() {
+ get: function () {
return p2ms_1.p2ms;
},
});
const p2pk_1 = require('./p2pk');
Object.defineProperty(exports, 'p2pk', {
enumerable: true,
- get: function() {
+ get: function () {
return p2pk_1.p2pk;
},
});
const p2pkh_1 = require('./p2pkh');
Object.defineProperty(exports, 'p2pkh', {
enumerable: true,
- get: function() {
+ get: function () {
return p2pkh_1.p2pkh;
},
});
const p2sh_1 = require('./p2sh');
Object.defineProperty(exports, 'p2sh', {
enumerable: true,
- get: function() {
+ get: function () {
return p2sh_1.p2sh;
},
});
const p2wpkh_1 = require('./p2wpkh');
Object.defineProperty(exports, 'p2wpkh', {
enumerable: true,
- get: function() {
+ get: function () {
return p2wpkh_1.p2wpkh;
},
});
const p2wsh_1 = require('./p2wsh');
Object.defineProperty(exports, 'p2wsh', {
enumerable: true,
- get: function() {
+ get: function () {
return p2wsh_1.p2wsh;
},
});
const p2tr_1 = require('./p2tr');
Object.defineProperty(exports, 'p2tr', {
enumerable: true,
- get: function() {
+ get: function () {
return p2tr_1.p2tr;
},
});
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index 182aa62c6..d2cbc02a8 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -247,9 +247,7 @@ function p2tr(a, opts) {
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.`,
+ `The control-block length is too small. Got ${controlBlock.length}, expected min 33.`,
);
if ((controlBlock.length - 33) % 32 !== 0)
throw new TypeError(
diff --git a/src/psbt.d.ts b/src/psbt.d.ts
index 4c622b31f..de7bbb3d4 100644
--- a/src/psbt.d.ts
+++ b/src/psbt.d.ts
@@ -18,7 +18,7 @@ export interface TransactionOutput {
export interface PsbtTxOutput extends TransactionOutput {
address: string | undefined;
}
-export declare type ValidateSigFunction = (pubkey: Buffer, msghash: Buffer, signature: Buffer) => boolean;
+export type ValidateSigFunction = (pubkey: Buffer, msghash: Buffer, signature: Buffer) => boolean;
/**
* Psbt class can parse and generate a PSBT binary based off of the BIP174.
* There are 6 roles that this class fulfills. (Explained in BIP174)
@@ -125,7 +125,7 @@ interface PsbtOptsOptional {
}
interface PsbtInputExtended extends PsbtInput, TransactionInput {
}
-declare type PsbtOutputExtended = PsbtOutputExtendedAddress | PsbtOutputExtendedScript;
+type PsbtOutputExtended = PsbtOutputExtendedAddress | PsbtOutputExtendedScript;
interface PsbtOutputExtendedAddress extends PsbtOutput {
address: string;
value: number;
@@ -183,7 +183,7 @@ export interface SignerAsync {
* ie. `Can not finalize input #${inputIndex}`
* 2. Create the finalScriptSig and finalScriptWitness Buffers.
*/
-declare type FinalScriptsFunc = (inputIndex: number, // Which input is it?
+type FinalScriptsFunc = (inputIndex: number, // Which input is it?
input: PsbtInput, // The PSBT input contents
script: Buffer, // The "meaningful" locking script Buffer (redeemScript for P2SH etc.)
isSegwit: boolean, // Is it segwit?
@@ -192,10 +192,10 @@ isP2WSH: boolean) => {
finalScriptSig: Buffer | undefined;
finalScriptWitness: Buffer | undefined;
};
-declare type FinalTaprootScriptsFunc = (inputIndex: number, // Which input is it?
+type FinalTaprootScriptsFunc = (inputIndex: number, // Which input is it?
input: PsbtInput, // The PSBT input contents
tapLeafHashToFinalize?: Buffer) => {
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';
+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';
export {};
diff --git a/src/psbt.js b/src/psbt.js
index 2f2e94a96..9aa36686a 100644
--- a/src/psbt.js
+++ b/src/psbt.js
@@ -62,6 +62,20 @@ const DEFAULT_OPTS = {
* Transaction object. Such as fee rate not being larger than maximumFeeRate etc.
*/
class Psbt {
+ static fromBase64(data, opts = {}) {
+ const buffer = Buffer.from(data, 'base64');
+ return this.fromBuffer(buffer, opts);
+ }
+ static fromHex(data, opts = {}) {
+ const buffer = Buffer.from(data, 'hex');
+ return this.fromBuffer(buffer, opts);
+ }
+ static fromBuffer(buffer, opts = {}) {
+ const psbtBase = bip174_1.Psbt.fromBuffer(buffer, transactionFromBuffer);
+ const psbt = new Psbt(opts, psbtBase);
+ checkTxForDupeIns(psbt.__CACHE.__TX, psbt.__CACHE);
+ return psbt;
+ }
constructor(opts = {}, data = new bip174_1.Psbt(new PsbtTransaction())) {
this.data = data;
// set defaults
@@ -91,20 +105,6 @@ class Psbt {
dpew(this, '__CACHE', false, true);
dpew(this, 'opts', false, true);
}
- static fromBase64(data, opts = {}) {
- const buffer = Buffer.from(data, 'base64');
- return this.fromBuffer(buffer, opts);
- }
- static fromHex(data, opts = {}) {
- const buffer = Buffer.from(data, 'hex');
- return this.fromBuffer(buffer, opts);
- }
- static fromBuffer(buffer, opts = {}) {
- const psbtBase = bip174_1.Psbt.fromBuffer(buffer, transactionFromBuffer);
- const psbt = new Psbt(opts, psbtBase);
- checkTxForDupeIns(psbt.__CACHE.__TX, psbt.__CACHE);
- return psbt;
- }
get inputCount() {
return this.data.inputs.length;
}
@@ -1236,8 +1236,9 @@ function getHashForSig(inputIndex, input, cache, forValidate, sighashTypes) {
);
} else if ((0, psbtutils_1.isP2WPKH)(meaningfulScript)) {
// P2WPKH uses the P2PKH template for prevoutScript when signing
- const signingScript = payments.p2pkh({ hash: meaningfulScript.slice(2) })
- .output;
+ const signingScript = payments.p2pkh({
+ hash: meaningfulScript.slice(2),
+ }).output;
hash = unsignedTx.hashForWitnessV0(
inputIndex,
signingScript,
diff --git a/src/psbt/bip371.js b/src/psbt/bip371.js
index 8e76ecda7..61196ead2 100644
--- a/src/psbt/bip371.js
+++ b/src/psbt/bip371.js
@@ -1,6 +1,17 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.checkTaprootInputForSigs = exports.tapTreeFromList = exports.tapTreeToList = exports.tweakInternalPubKey = exports.checkTaprootOutputFields = exports.checkTaprootInputFields = exports.isTaprootOutput = exports.isTaprootInput = exports.serializeTaprootSignature = exports.tapScriptFinalizer = exports.toXOnly = void 0;
+exports.checkTaprootInputForSigs =
+ exports.tapTreeFromList =
+ exports.tapTreeToList =
+ exports.tweakInternalPubKey =
+ exports.checkTaprootOutputFields =
+ exports.checkTaprootInputFields =
+ exports.isTaprootOutput =
+ exports.isTaprootInput =
+ exports.serializeTaprootSignature =
+ exports.tapScriptFinalizer =
+ exports.toXOnly =
+ void 0;
const types_1 = require('../types');
const transaction_1 = require('../transaction');
const psbtutils_1 = require('./psbtutils');
@@ -104,8 +115,9 @@ function tweakInternalPubKey(inputIndex, input) {
(0, bip341_1.tweakKey)(tapInternalKey, input.tapMerkleRoot);
if (!outputKey)
throw new Error(
- `Cannot tweak tap internal key for input #${inputIndex}. Public key: ${tapInternalKey &&
- tapInternalKey.toString('hex')}`,
+ `Cannot tweak tap internal key for input #${inputIndex}. Public key: ${
+ tapInternalKey && tapInternalKey.toString('hex')
+ }`,
);
return outputKey.x;
}
@@ -226,7 +238,8 @@ function checkMixedTaprootAndNonTaprootInputFields(
hasNonTaprootFields(inputData) && isTaprootInput(newInputData);
const hasMixedFields =
inputData === newInputData &&
- (isTaprootInput(newInputData) && hasNonTaprootFields(newInputData)); // todo: bad? use !===
+ isTaprootInput(newInputData) &&
+ hasNonTaprootFields(newInputData); // todo: bad? use !===
if (isBadTaprootUpdate || isBadNonTaprootUpdate || hasMixedFields)
throw new Error(
`Invalid arguments for Psbt.${action}. ` +
@@ -244,7 +257,8 @@ function checkMixedTaprootAndNonTaprootOutputFields(
hasNonTaprootFields(inputData) && isTaprootOutput(newInputData);
const hasMixedFields =
inputData === newInputData &&
- (isTaprootOutput(newInputData) && hasNonTaprootFields(newInputData));
+ isTaprootOutput(newInputData) &&
+ hasNonTaprootFields(newInputData);
if (isBadTaprootUpdate || isBadNonTaprootUpdate || hasMixedFields)
throw new Error(
`Invalid arguments for Psbt.${action}. ` +
diff --git a/src/psbt/psbtutils.d.ts b/src/psbt/psbtutils.d.ts
index 6491132a8..db5f0b516 100644
--- a/src/psbt/psbtutils.d.ts
+++ b/src/psbt/psbtutils.d.ts
@@ -11,7 +11,7 @@ export declare function witnessStackToScriptWitness(witness: Buffer[]): Buffer;
export declare function pubkeyPositionInScript(pubkey: Buffer, script: Buffer): number;
export declare function pubkeyInScript(pubkey: Buffer, script: Buffer): boolean;
export declare function checkInputForSig(input: PsbtInput, action: string): boolean;
-declare type SignatureDecodeFunc = (buffer: Buffer) => {
+type SignatureDecodeFunc = (buffer: Buffer) => {
signature: Buffer;
hashType: number;
};
diff --git a/src/psbt/psbtutils.js b/src/psbt/psbtutils.js
index 086faa4f0..2e8bd435a 100644
--- a/src/psbt/psbtutils.js
+++ b/src/psbt/psbtutils.js
@@ -1,6 +1,18 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.signatureBlocksAction = exports.checkInputForSig = exports.pubkeyInScript = exports.pubkeyPositionInScript = exports.witnessStackToScriptWitness = exports.isP2TR = exports.isP2SHScript = exports.isP2WSHScript = exports.isP2WPKH = exports.isP2PKH = exports.isP2PK = exports.isP2MS = void 0;
+exports.signatureBlocksAction =
+ exports.checkInputForSig =
+ exports.pubkeyInScript =
+ exports.pubkeyPositionInScript =
+ exports.witnessStackToScriptWitness =
+ exports.isP2TR =
+ exports.isP2SHScript =
+ exports.isP2WSHScript =
+ exports.isP2WPKH =
+ exports.isP2PKH =
+ exports.isP2PK =
+ exports.isP2MS =
+ void 0;
const varuint = require('bip174/src/lib/converter/varint');
const bscript = require('../script');
const transaction_1 = require('../transaction');
diff --git a/src/script.js b/src/script.js
index 5e5e17ba1..5dff149f3 100644
--- a/src/script.js
+++ b/src/script.js
@@ -1,11 +1,23 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.signature = exports.number = exports.isCanonicalScriptSignature = exports.isDefinedHashType = exports.isCanonicalPubKey = exports.toStack = exports.fromASM = exports.toASM = exports.decompile = exports.compile = exports.isPushOnly = exports.OPS = void 0;
+exports.signature =
+ exports.number =
+ exports.isCanonicalScriptSignature =
+ exports.isDefinedHashType =
+ exports.isCanonicalPubKey =
+ exports.toStack =
+ exports.fromASM =
+ exports.toASM =
+ exports.decompile =
+ exports.compile =
+ exports.isPushOnly =
+ exports.OPS =
+ void 0;
const bip66 = require('./bip66');
const ops_1 = require('./ops');
Object.defineProperty(exports, 'OPS', {
enumerable: true,
- get: function() {
+ get: function () {
return ops_1.OPS;
},
});
@@ -177,6 +189,5 @@ function isCanonicalScriptSignature(buffer) {
return bip66.check(buffer.slice(0, -1));
}
exports.isCanonicalScriptSignature = isCanonicalScriptSignature;
-// tslint:disable-next-line variable-name
exports.number = scriptNumber;
exports.signature = scriptSignature;
diff --git a/src/types.d.ts b/src/types.d.ts
index b3d93589d..035d73efc 100644
--- a/src/types.d.ts
+++ b/src/types.d.ts
@@ -25,7 +25,7 @@ export declare function isTapleaf(o: any): o is Tapleaf;
* Each node is either a single Tapleaf, or a pair of Tapleaf | Taptree.
* The tree has no balancing requirements.
*/
-export declare type Taptree = [Taptree | Tapleaf, Taptree | Tapleaf] | Tapleaf;
+export type Taptree = [Taptree | Tapleaf, Taptree | Tapleaf] | Tapleaf;
export declare function isTaptree(scriptTree: any): scriptTree is Taptree;
export interface TinySecp256k1Interface {
isXOnlyPoint(p: Uint8Array): boolean;
diff --git a/src/types.js b/src/types.js
index 3a2dc51ea..acb51ad0b 100644
--- a/src/types.js
+++ b/src/types.js
@@ -1,6 +1,34 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-exports.oneOf = exports.Null = exports.BufferN = exports.Function = exports.UInt32 = exports.UInt8 = exports.tuple = exports.maybe = exports.Hex = exports.Buffer = exports.String = exports.Boolean = exports.Array = exports.Number = exports.Hash256bit = exports.Hash160bit = exports.Buffer256bit = exports.isTaptree = exports.isTapleaf = exports.TAPLEAF_VERSION_MASK = exports.Network = exports.ECPoint = exports.Satoshi = exports.Signer = exports.BIP32Path = exports.UInt31 = exports.isPoint = exports.typeforce = void 0;
+exports.oneOf =
+ exports.Null =
+ exports.BufferN =
+ exports.Function =
+ exports.UInt32 =
+ exports.UInt8 =
+ exports.tuple =
+ exports.maybe =
+ exports.Hex =
+ exports.Buffer =
+ exports.String =
+ exports.Boolean =
+ exports.Array =
+ exports.Number =
+ exports.Hash256bit =
+ exports.Hash160bit =
+ exports.Buffer256bit =
+ exports.isTaptree =
+ exports.isTapleaf =
+ exports.TAPLEAF_VERSION_MASK =
+ exports.Network =
+ exports.ECPoint =
+ exports.Satoshi =
+ exports.Signer =
+ exports.BIP32Path =
+ exports.UInt31 =
+ exports.isPoint =
+ exports.typeforce =
+ void 0;
const buffer_1 = require('buffer');
exports.typeforce = require('typeforce');
const ZERO32 = buffer_1.Buffer.alloc(32, 0);
@@ -86,10 +114,10 @@ exports.isTaptree = isTaptree;
exports.Buffer256bit = exports.typeforce.BufferN(32);
exports.Hash160bit = exports.typeforce.BufferN(20);
exports.Hash256bit = exports.typeforce.BufferN(32);
-exports.Number = exports.typeforce.Number; // tslint:disable-line variable-name
+exports.Number = exports.typeforce.Number;
exports.Array = exports.typeforce.Array;
-exports.Boolean = exports.typeforce.Boolean; // tslint:disable-line variable-name
-exports.String = exports.typeforce.String; // tslint:disable-line variable-name
+exports.Boolean = exports.typeforce.Boolean;
+exports.String = exports.typeforce.String;
exports.Buffer = exports.typeforce.Buffer;
exports.Hex = exports.typeforce.Hex;
exports.maybe = exports.typeforce.maybe;
diff --git a/test/integration/bip32.spec.ts b/test/integration/bip32.spec.ts
index 938c28113..2ecf308c4 100644
--- a/test/integration/bip32.spec.ts
+++ b/test/integration/bip32.spec.ts
@@ -60,10 +60,7 @@ describe('bitcoinjs-lib (BIP32)', () => {
const child1 = root.derivePath(path);
// option 2, manually
- const child1b = root
- .deriveHardened(0)
- .derive(0)
- .derive(0);
+ const child1b = root.deriveHardened(0).derive(0).derive(0);
assert.strictEqual(
getAddress(child1),
diff --git a/test/integration/csv.spec.ts b/test/integration/csv.spec.ts
index 742d68fa1..2da433877 100644
--- a/test/integration/csv.spec.ts
+++ b/test/integration/csv.spec.ts
@@ -75,7 +75,6 @@ describe('bitcoinjs-lib (transactions w/ CSV)', () => {
// but after sequence1 time, _alice can allow the multisig to become 1 of 3.
// but after sequence2 time, _alice can sign for the output all by themself.
- /* tslint:disable-next-line */
// Ref: https://github.com/bitcoinbook/bitcoinbook/blob/f8b883dcd4e3d1b9adf40fed59b7e898fbd9241f/ch07.asciidoc#complex-script-example
// Note: bitcoinjs-lib will not offer specific support for problems with
diff --git a/test/integration/payments.spec.ts b/test/integration/payments.spec.ts
index d9d7fde78..4bf01f49f 100644
--- a/test/integration/payments.spec.ts
+++ b/test/integration/payments.spec.ts
@@ -42,10 +42,7 @@ async function buildAndSign(
}
return regtestUtils.broadcast(
- psbt
- .finalizeAllInputs()
- .extractTransaction()
- .toHex(),
+ psbt.finalizeAllInputs().extractTransaction().toHex(),
);
}
diff --git a/test/integration/taproot.spec.ts b/test/integration/taproot.spec.ts
index b12c46f31..87dce290d 100644
--- a/test/integration/taproot.spec.ts
+++ b/test/integration/taproot.spec.ts
@@ -410,9 +410,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
leafPubkeys.push(toXOnly(leafKey.publicKey).toString('hex'));
}
- const leafScriptAsm = `${leafPubkeys[2]} OP_CHECKSIG ${
- leafPubkeys[1]
- } OP_CHECKSIGADD ${leafPubkeys[0]} OP_CHECKSIGADD OP_3 OP_NUMEQUAL`;
+ const leafScriptAsm = `${leafPubkeys[2]} OP_CHECKSIG ${leafPubkeys[1]} OP_CHECKSIGADD ${leafPubkeys[0]} OP_CHECKSIGADD OP_3 OP_NUMEQUAL`;
const leafScript = bitcoin.script.fromASM(leafScriptAsm);
@@ -674,6 +672,7 @@ function createSigned(
// This logic will be extracted to ecpair
function tweakSigner(signer: bitcoin.Signer, opts: any = {}): bitcoin.Signer {
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
let privateKey: Uint8Array | undefined = signer.privateKey!;
if (!privateKey) {
diff --git a/test/integration/transactions.spec.ts b/test/integration/transactions.spec.ts
index ba7f2fe8b..264d99a2f 100644
--- a/test/integration/transactions.spec.ts
+++ b/test/integration/transactions.spec.ts
@@ -460,13 +460,8 @@ describe('bitcoinjs-lib (transactions with psbt)', () => {
'p2sh-p2wsh',
);
{
- const {
- hash,
- index,
- witnessUtxo,
- redeemScript,
- witnessScript,
- } = inputData;
+ const { hash, index, witnessUtxo, redeemScript, witnessScript } =
+ inputData;
assert.deepStrictEqual(
{ hash, index, witnessUtxo, redeemScript, witnessScript },
inputData,
diff --git a/test/psbt.spec.ts b/test/psbt.spec.ts
index 6d295a80f..c61ec1732 100644
--- a/test/psbt.spec.ts
+++ b/test/psbt.spec.ts
@@ -52,18 +52,16 @@ const toAsyncSigner = (signer: Signer): SignerAsync => {
const ret: SignerAsync = {
publicKey: signer.publicKey,
sign: (hash: Buffer, lowerR: boolean | undefined): Promise => {
- return new Promise(
- (resolve, rejects): void => {
- setTimeout(() => {
- try {
- const r = signer.sign(hash, lowerR);
- resolve(r);
- } catch (e) {
- rejects(e);
- }
- }, 10);
- },
- );
+ return new Promise((resolve, rejects): void => {
+ setTimeout(() => {
+ try {
+ const r = signer.sign(hash, lowerR);
+ resolve(r);
+ } catch (e) {
+ rejects(e);
+ }
+ }, 10);
+ });
},
};
return ret;
@@ -72,13 +70,11 @@ const failedAsyncSigner = (publicKey: Buffer): SignerAsync => {
return {
publicKey,
sign: (__: Buffer): Promise => {
- return new Promise(
- (_, reject): void => {
- setTimeout(() => {
- reject(new Error('sign failed'));
- }, 10);
- },
- );
+ return new Promise((_, reject): void => {
+ setTimeout(() => {
+ reject(new Error('sign failed'));
+ }, 10);
+ });
},
};
};
@@ -154,6 +150,7 @@ describe(`Psbt`, () => {
if (f.isTaproot) initEccLib(ecc);
const psbt = Psbt.fromBase64(f.psbt);
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // cannot find tapLeafHashToSign
f.keys.forEach(({ inputToSign, tapLeafHashToSign, WIF }) => {
const keyPair = ECPair.fromWIF(WIF, NETWORKS.testnet);
@@ -532,8 +529,7 @@ describe(`Psbt`, () => {
it(`fails if trying to finalzie non-taproot input`, () => {
const psbt = new Psbt();
psbt.addInput({
- hash:
- '0000000000000000000000000000000000000000000000000000000000000000',
+ hash: '0000000000000000000000000000000000000000000000000000000000000000',
index: 0,
});
@@ -556,8 +552,7 @@ describe(`Psbt`, () => {
it('fails if no script found', () => {
const psbt = new Psbt();
psbt.addInput({
- hash:
- '0000000000000000000000000000000000000000000000000000000000000000',
+ hash: '0000000000000000000000000000000000000000000000000000000000000000',
index: 0,
});
assert.throws(() => {
@@ -671,8 +666,7 @@ describe(`Psbt`, () => {
it('Sets the sequence number for a given input', () => {
const psbt = new Psbt();
psbt.addInput({
- hash:
- '0000000000000000000000000000000000000000000000000000000000000000',
+ hash: '0000000000000000000000000000000000000000000000000000000000000000',
index: 0,
});
@@ -685,8 +679,7 @@ describe(`Psbt`, () => {
it('throws if input index is too high', () => {
const psbt = new Psbt();
psbt.addInput({
- hash:
- '0000000000000000000000000000000000000000000000000000000000000000',
+ hash: '0000000000000000000000000000000000000000000000000000000000000000',
index: 0,
});
@@ -729,8 +722,7 @@ describe(`Psbt`, () => {
const psbt = new Psbt();
psbt
.addInput({
- hash:
- '0000000000000000000000000000000000000000000000000000000000000000',
+ hash: '0000000000000000000000000000000000000000000000000000000000000000',
index: 0,
witnessUtxo: {
script: outerScript(innerScript(publicKey)),
@@ -802,8 +794,7 @@ describe(`Psbt`, () => {
const path = "m/0'/0";
const psbt = new Psbt();
psbt.addInput({
- hash:
- '0000000000000000000000000000000000000000000000000000000000000000',
+ hash: '0000000000000000000000000000000000000000000000000000000000000000',
index: 0,
bip32Derivation: [
{
@@ -822,8 +813,7 @@ describe(`Psbt`, () => {
it('should throw', () => {
const psbt = new Psbt();
psbt.addInput({
- hash:
- '0000000000000000000000000000000000000000000000000000000000000000',
+ hash: '0000000000000000000000000000000000000000000000000000000000000000',
index: 0,
});
@@ -897,8 +887,7 @@ describe(`Psbt`, () => {
const psbt = new Psbt();
psbt
.addInput({
- hash:
- '0000000000000000000000000000000000000000000000000000000000000000',
+ hash: '0000000000000000000000000000000000000000000000000000000000000000',
index: 0,
})
.addOutput({
@@ -925,8 +914,7 @@ describe(`Psbt`, () => {
const psbt = new Psbt();
psbt
.addInput({
- hash:
- '0000000000000000000000000000000000000000000000000000000000000000',
+ hash: '0000000000000000000000000000000000000000000000000000000000000000',
index: 0,
})
.addOutput({
diff --git a/test/script_signature.spec.ts b/test/script_signature.spec.ts
index 54c416e35..f70caa475 100644
--- a/test/script_signature.spec.ts
+++ b/test/script_signature.spec.ts
@@ -11,9 +11,7 @@ describe('Script Signatures', () => {
);
}
- function toRaw(
- signature: Buffer,
- ): {
+ function toRaw(signature: Buffer): {
r: string;
s: string;
} {
diff --git a/test/transaction.spec.ts b/test/transaction.spec.ts
index 13d64d128..bf62acedf 100644
--- a/test/transaction.spec.ts
+++ b/test/transaction.spec.ts
@@ -266,7 +266,7 @@ describe('Transaction', () => {
tx.addOutput(randScript, 5000000000);
const original = (tx as any).__toBuffer;
- (tx as any).__toBuffer = function(
+ (tx as any).__toBuffer = function (
this: Transaction,
a: any,
b: any,
diff --git a/ts_src/crypto.ts b/ts_src/crypto.ts
index e1cebde53..5af3bfbbe 100644
--- a/ts_src/crypto.ts
+++ b/ts_src/crypto.ts
@@ -3,14 +3,10 @@ import * as RipeMd160 from 'ripemd160';
export function ripemd160(buffer: Buffer): Buffer {
try {
- return createHash('rmd160')
- .update(buffer)
- .digest();
+ return createHash('rmd160').update(buffer).digest();
} catch (err) {
try {
- return createHash('ripemd160')
- .update(buffer)
- .digest();
+ return createHash('ripemd160').update(buffer).digest();
} catch (err2) {
return new RipeMd160().update(buffer).digest();
}
@@ -18,15 +14,11 @@ export function ripemd160(buffer: Buffer): Buffer {
}
export function sha1(buffer: Buffer): Buffer {
- return createHash('sha1')
- .update(buffer)
- .digest();
+ return createHash('sha1').update(buffer).digest();
}
export function sha256(buffer: Buffer): Buffer {
- return createHash('sha256')
- .update(buffer)
- .digest();
+ return createHash('sha256').update(buffer).digest();
}
export function hash160(buffer: Buffer): Buffer {
diff --git a/ts_src/payments/bip341.ts b/ts_src/payments/bip341.ts
index 5a1dd068d..40793779f 100644
--- a/ts_src/payments/bip341.ts
+++ b/ts_src/payments/bip341.ts
@@ -40,9 +40,7 @@ export function rootHashFromPath(
): Buffer {
if (controlBlock.length < 33)
throw new TypeError(
- `The control-block length is too small. Got ${
- controlBlock.length
- }, expected min 33.`,
+ `The control-block length is too small. Got ${controlBlock.length}, expected min 33.`,
);
const m = (controlBlock.length - 33) / 32;
diff --git a/ts_src/payments/p2sh.ts b/ts_src/payments/p2sh.ts
index 0cea3632c..272d094a3 100644
--- a/ts_src/payments/p2sh.ts
+++ b/ts_src/payments/p2sh.ts
@@ -65,19 +65,17 @@ export function p2sh(a: Payment, opts?: PaymentOpts): Payment {
const _chunks = lazy.value(() => {
return bscript.decompile(a.input!);
}) as StackFunction;
- const _redeem = lazy.value(
- (): Payment => {
- const chunks = _chunks();
- const lastChunk = chunks[chunks.length - 1];
- return {
- network,
- output:
- lastChunk === OPS.OP_FALSE ? Buffer.from([]) : (lastChunk as Buffer),
- input: bscript.compile(chunks.slice(0, -1)),
- witness: a.witness || [],
- };
- },
- ) as PaymentFunction;
+ const _redeem = lazy.value((): Payment => {
+ const chunks = _chunks();
+ const lastChunk = chunks[chunks.length - 1];
+ return {
+ network,
+ output:
+ lastChunk === OPS.OP_FALSE ? Buffer.from([]) : (lastChunk as Buffer),
+ input: bscript.compile(chunks.slice(0, -1)),
+ witness: a.witness || [],
+ };
+ }) as PaymentFunction;
// output dependents
lazy.prop(o, 'address', () => {
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index 64c591ffd..231a263fc 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -271,9 +271,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
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.`,
+ `The control-block length is too small. Got ${controlBlock.length}, expected min 33.`,
);
if ((controlBlock.length - 33) % 32 !== 0)
diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts
index aa546bc71..e7ca28976 100644
--- a/ts_src/psbt.ts
+++ b/ts_src/psbt.ts
@@ -660,34 +660,32 @@ export class Psbt {
hdKeyPair: HDSigner | HDSignerAsync,
sighashTypes: number[] = [Transaction.SIGHASH_ALL],
): Promise {
- return new Promise(
- (resolve, reject): any => {
- if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) {
- return reject(new Error('Need HDSigner to sign input'));
- }
+ return new Promise((resolve, reject): any => {
+ if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) {
+ return reject(new Error('Need HDSigner to sign input'));
+ }
- const results: boolean[] = [];
- const promises: Array> = [];
- for (const i of range(this.data.inputs.length)) {
- promises.push(
- this.signInputHDAsync(i, hdKeyPair, sighashTypes).then(
- () => {
- results.push(true);
- },
- () => {
- results.push(false);
- },
- ),
- );
+ const results: boolean[] = [];
+ const promises: Array> = [];
+ for (const i of range(this.data.inputs.length)) {
+ promises.push(
+ this.signInputHDAsync(i, hdKeyPair, sighashTypes).then(
+ () => {
+ results.push(true);
+ },
+ () => {
+ results.push(false);
+ },
+ ),
+ );
+ }
+ return Promise.all(promises).then(() => {
+ if (results.every(v => v === false)) {
+ return reject(new Error('No inputs were signed'));
}
- return Promise.all(promises).then(() => {
- if (results.every(v => v === false)) {
- return reject(new Error('No inputs were signed'));
- }
- resolve();
- });
- },
- );
+ resolve();
+ });
+ });
}
signInputHD(
@@ -712,26 +710,20 @@ export class Psbt {
hdKeyPair: HDSigner | HDSignerAsync,
sighashTypes: number[] = [Transaction.SIGHASH_ALL],
): Promise {
- return new Promise(
- (resolve, reject): any => {
- if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) {
- return reject(new Error('Need HDSigner to sign input'));
- }
- const signers = getSignersFromHD(
- inputIndex,
- this.data.inputs,
- hdKeyPair,
- );
- const promises = signers.map(signer =>
- this.signInputAsync(inputIndex, signer, sighashTypes),
- );
- return Promise.all(promises)
- .then(() => {
- resolve();
- })
- .catch(reject);
- },
- );
+ return new Promise((resolve, reject): any => {
+ if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) {
+ return reject(new Error('Need HDSigner to sign input'));
+ }
+ const signers = getSignersFromHD(inputIndex, this.data.inputs, hdKeyPair);
+ const promises = signers.map(signer =>
+ this.signInputAsync(inputIndex, signer, sighashTypes),
+ );
+ return Promise.all(promises)
+ .then(() => {
+ resolve();
+ })
+ .catch(reject);
+ });
}
signAllInputs(keyPair: Signer, sighashTypes?: number[]): this {
@@ -760,36 +752,34 @@ export class Psbt {
keyPair: Signer | SignerAsync,
sighashTypes?: number[],
): Promise {
- return new Promise(
- (resolve, reject): any => {
- if (!keyPair || !keyPair.publicKey)
- return reject(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.
- const results: boolean[] = [];
- const promises: Array> = [];
- for (const [i] of this.data.inputs.entries()) {
- promises.push(
- this.signInputAsync(i, keyPair, sighashTypes).then(
- () => {
- results.push(true);
- },
- () => {
- results.push(false);
- },
- ),
- );
+ return new Promise((resolve, reject): any => {
+ if (!keyPair || !keyPair.publicKey)
+ return reject(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.
+ const results: boolean[] = [];
+ const promises: Array> = [];
+ for (const [i] of this.data.inputs.entries()) {
+ promises.push(
+ this.signInputAsync(i, keyPair, sighashTypes).then(
+ () => {
+ results.push(true);
+ },
+ () => {
+ results.push(false);
+ },
+ ),
+ );
+ }
+ return Promise.all(promises).then(() => {
+ if (results.every(v => v === false)) {
+ return reject(new Error('No inputs were signed'));
}
- return Promise.all(promises).then(() => {
- if (results.every(v => v === false)) {
- return reject(new Error('No inputs were signed'));
- }
- resolve();
- });
- },
- );
+ resolve();
+ });
+ });
}
signInput(
diff --git a/ts_src/psbt/bip371.ts b/ts_src/psbt/bip371.ts
index d4eaaa5f3..375d35cc6 100644
--- a/ts_src/psbt/bip371.ts
+++ b/ts_src/psbt/bip371.ts
@@ -155,8 +155,9 @@ export function tweakInternalPubKey(
if (!outputKey)
throw new Error(
- `Cannot tweak tap internal key for input #${inputIndex}. Public key: ${tapInternalKey &&
- tapInternalKey.toString('hex')}`,
+ `Cannot tweak tap internal key for input #${inputIndex}. Public key: ${
+ tapInternalKey && tapInternalKey.toString('hex')
+ }`,
);
return outputKey.x;
}
@@ -205,9 +206,7 @@ export function checkTaprootInputForSigs(
);
}
-function decodeSchnorrSignature(
- signature: Buffer,
-): {
+function decodeSchnorrSignature(signature: Buffer): {
signature: Buffer;
hashType: number;
} {
@@ -308,7 +307,8 @@ function checkMixedTaprootAndNonTaprootInputFields(
hasNonTaprootFields(inputData) && isTaprootInput(newInputData);
const hasMixedFields =
inputData === newInputData &&
- (isTaprootInput(newInputData) && hasNonTaprootFields(newInputData)); // todo: bad? use !===
+ isTaprootInput(newInputData) &&
+ hasNonTaprootFields(newInputData); // todo: bad? use !===
if (isBadTaprootUpdate || isBadNonTaprootUpdate || hasMixedFields)
throw new Error(
@@ -327,7 +327,8 @@ function checkMixedTaprootAndNonTaprootOutputFields(
hasNonTaprootFields(inputData) && isTaprootOutput(newInputData);
const hasMixedFields =
inputData === newInputData &&
- (isTaprootOutput(newInputData) && hasNonTaprootFields(newInputData));
+ isTaprootOutput(newInputData) &&
+ hasNonTaprootFields(newInputData);
if (isBadTaprootUpdate || isBadNonTaprootUpdate || hasMixedFields)
throw new Error(
diff --git a/ts_src/psbt/psbtutils.ts b/ts_src/psbt/psbtutils.ts
index d51e2df54..173e0215c 100644
--- a/ts_src/psbt/psbtutils.ts
+++ b/ts_src/psbt/psbtutils.ts
@@ -81,9 +81,7 @@ export function checkInputForSig(input: PsbtInput, action: string): boolean {
);
}
-type SignatureDecodeFunc = (
- buffer: Buffer,
-) => {
+type SignatureDecodeFunc = (buffer: Buffer) => {
signature: Buffer;
hashType: number;
};
diff --git a/ts_src/script.ts b/ts_src/script.ts
index 5d20ebc01..ca2c557f5 100644
--- a/ts_src/script.ts
+++ b/ts_src/script.ts
@@ -208,6 +208,5 @@ export function isCanonicalScriptSignature(buffer: Buffer): boolean {
return bip66.check(buffer.slice(0, -1));
}
-// tslint:disable-next-line variable-name
export const number = scriptNumber;
export const signature = scriptSignature;
diff --git a/ts_src/types.ts b/ts_src/types.ts
index b904fd49b..d4f4ac774 100644
--- a/ts_src/types.ts
+++ b/ts_src/types.ts
@@ -112,10 +112,10 @@ export interface TinySecp256k1Interface {
export const Buffer256bit = typeforce.BufferN(32);
export const Hash160bit = typeforce.BufferN(20);
export const Hash256bit = typeforce.BufferN(32);
-export const Number = typeforce.Number; // tslint:disable-line variable-name
+export const Number = typeforce.Number;
export const Array = typeforce.Array;
-export const Boolean = typeforce.Boolean; // tslint:disable-line variable-name
-export const String = typeforce.String; // tslint:disable-line variable-name
+export const Boolean = typeforce.Boolean;
+export const String = typeforce.String;
export const Buffer = typeforce.Buffer;
export const Hex = typeforce.Hex;
export const maybe = typeforce.maybe;
diff --git a/tslint.json b/tslint.json
deleted file mode 100644
index 90e513dfe..000000000
--- a/tslint.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
- "defaultSeverity": "error",
- "extends": ["tslint:recommended"],
- "rules": {
- "array-type": false,
- "arrow-parens": false,
- "curly": false,
- "indent": [
- true,
- "spaces",
- 2
- ],
- "interface-name": [false],
- "match-default-export-name": true,
- "max-classes-per-file": [false],
- "member-access": [true, "no-public"],
- "no-bitwise": false,
- "no-console": false,
- "no-empty": [true, "allow-empty-catch"],
- "no-implicit-dependencies": [true, "dev"],
- "no-return-await": true,
- "no-var-requires": false,
- "no-unused-expression": false,
- "object-literal-sort-keys": false,
- "quotemark": [true, "single", "avoid-escape"],
- "typedef": [
- true,
- "call-signature",
- "property-declaration"
- ],
- "variable-name": [
- true,
- "ban-keywords",
- "check-format",
- "allow-leading-underscore",
- "allow-pascal-case"
- ]
- },
- "rulesDirectory": []
-}
From f9e970a6a5f2c667489fb095834a377b61fbd45e Mon Sep 17 00:00:00 2001
From: junderw
Date: Wed, 7 Dec 2022 19:24:08 +0900
Subject: [PATCH 099/144] Update CHANGELOG and remove old taproot example
---
CHANGELOG.md | 4 +
test/integration/taproot.md | 157 -------------------------------
test/integration/taproot.spec.ts | 112 ----------------------
3 files changed, 4 insertions(+), 269 deletions(-)
delete mode 100644 test/integration/taproot.md
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e74c79c57..b0d11209c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+# 6.1.0
+__added__
+- taproot support for payments (p2tr) and PSBT. See taproot.spec.ts integration test for examples. (#1742)
+
# 6.0.2
__fixed__
- p2sh payment now uses empty Buffer for redeem.output when redeemScript is OP_FALSE (#1802)
diff --git a/test/integration/taproot.md b/test/integration/taproot.md
deleted file mode 100644
index 7627450e2..000000000
--- a/test/integration/taproot.md
+++ /dev/null
@@ -1,157 +0,0 @@
-# Taproot
-
-A simple keyspend example that is possible with the current API is below.
-
-## Current state of taproot support
-
-- [x] segwit v1 address support via bech32m
-- [x] segwit v1 sighash calculation on Transaction class
-
-## TODO
-
-- [x] p2tr payment API to make script spends easier
-- [ ] Support within the Psbt class
- - partial support added
-
-## Example
-
-### Requirements
-- npm dependencies
- - bitcoinjs-lib v6.x.x
- - bip32 v3.x.x
- - tiny-secp256k1 v2.x.x
- - regtest-client vx.x.x
-- local regtest-server docker container running
- - `docker run -d -p 8080:8080 junderw/bitcoinjs-regtest-server`
-- node >= v14
-
-```js
-// Run this whole file as async
-// Catch any errors at the bottom of the file
-// and exit the process with 1 error code
-(async () => {
-
-// 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 crypto = require('crypto');
-// bitcoinjs-lib v6
-const bitcoin = require('bitcoinjs-lib');
-// bip32 v3 wraps tiny-secp256k1
-const BIP32Wrapper = require('bip32').default;
-const RegtestUtils = require('regtest-client').RegtestUtils;
-// tiny-secp256k1 v2 is an ESM module, so we can't "require", and must import async
-const ecc = await import('tiny-secp256k1');
-// wrap the bip32 library
-const bip32 = BIP32Wrapper(ecc);
-// set up dependencies
-const APIPASS = process.env.APIPASS || 'satoshi';
-// docker run -d -p 8080:8080 junderw/bitcoinjs-regtest-server
-const APIURL = process.env.APIURL || 'http://127.0.0.1:8080/1';
-const regtestUtils = new RegtestUtils({ APIPASS, APIURL });
-// End imports
-
-const myKey = bip32.fromSeed(crypto.randomBytes(64), regtestUtils.network);
-
-const output = createKeySpendOutput(myKey.publicKey);
-const address = bitcoin.address.fromOutputScript(
- output,
- regtestUtils.network
-);
-// amount from faucet
-const amount = 42e4;
-// amount to send
-const sendAmount = amount - 1e4;
-// get faucet
-const unspent = await regtestUtils.faucetComplex(output, amount);
-
-const tx = createSigned(
- myKey,
- unspent.txId,
- unspent.vout,
- sendAmount,
- [output],
- [amount]
-);
-
-const hex = tx.toHex();
-console.log('Valid tx sent from:');
-console.log(address);
-console.log('tx hex:');
-console.log(hex);
-await regtestUtils.broadcast(hex);
-await regtestUtils.verify({
- txId: tx.getId(),
- address,
- vout: 0,
- value: sendAmount,
-});
-
-// Function for creating a tweaked p2tr key-spend only address
-// (This is recommended by BIP341)
-function createKeySpendOutput(publicKey) {
- // x-only pubkey (remove 1 byte y parity)
- const myXOnlyPubkey = publicKey.slice(1, 33);
- const commitHash = bitcoin.crypto.taggedHash('TapTweak', myXOnlyPubkey);
- const tweakResult = ecc.xOnlyPointAddTweak(myXOnlyPubkey, commitHash);
- 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 for signing for a tweaked p2tr key-spend only address
-// (Required for the above address)
-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) {
- 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)
- );
- 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;
-}
-
-})().catch((err) => {
- console.error(err);
- process.exit(1);
-});
-```
\ No newline at end of file
diff --git a/test/integration/taproot.spec.ts b/test/integration/taproot.spec.ts
index 87dce290d..ec870b761 100644
--- a/test/integration/taproot.spec.ts
+++ b/test/integration/taproot.spec.ts
@@ -17,41 +17,6 @@ const bip32 = BIP32Factory(ecc);
const ECPair = ECPairFactory(ecc);
describe('bitcoinjs-lib (transaction with taproot)', () => {
- it('can create (and broadcast via 3PBP) a taproot keyspend Transaction', async () => {
- const myKey = bip32.fromSeed(rng(64), regtest);
-
- const output = createKeySpendOutput(myKey.publicKey);
- const address = bitcoin.address.fromOutputScript(output, regtest);
- // amount from faucet
- const amount = 42e4;
- // amount to send
- const sendAmount = amount - 1e4;
- // get faucet
- const unspent = await regtestUtils.faucetComplex(output, amount);
-
- const tx = createSigned(
- myKey,
- unspent.txId,
- unspent.vout,
- sendAmount,
- [output],
- [amount],
- );
-
- const hex = tx.toHex();
- // console.log('Valid tx sent from:');
- // console.log(address);
- // console.log('tx hex:');
- // console.log(hex);
- await regtestUtils.broadcast(hex);
- await regtestUtils.verify({
- txId: tx.getId(),
- address,
- vout: 0,
- value: sendAmount,
- });
- });
-
it('can create (and broadcast via 3PBP) a taproot key-path spend Transaction', async () => {
const internalKey = bip32.fromSeed(rng(64), regtest);
const p2pkhKey = bip32.fromSeed(rng(64), regtest);
@@ -593,83 +558,6 @@ function buildLeafIndexFinalizer(
};
}
-// 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',
-);
-
-// Function for creating a tweaked p2tr key-spend only address
-// (This is recommended by BIP341)
-function createKeySpendOutput(publicKey: Buffer): Buffer {
- // x-only pubkey (remove 1 byte y parity)
- const myXOnlyPubkey = toXOnly(publicKey);
- const commitHash = bitcoin.crypto.taggedHash('TapTweak', myXOnlyPubkey);
- const tweakResult = ecc.xOnlyPointAddTweak(myXOnlyPubkey, commitHash);
- 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 for signing for a tweaked p2tr key-spend only address
-// (Required for the above address)
-interface KeyPair {
- publicKey: Buffer;
- privateKey?: Buffer;
-}
-function signTweaked(messageHash: Buffer, key: KeyPair): Uint8Array {
- const privateKey =
- key.publicKey[0] === 2
- ? key.privateKey
- : ecc.privateAdd(ecc.privateSub(N_LESS_1, key.privateKey!)!, ONE)!;
- const tweakHash = bitcoin.crypto.taggedHash(
- 'TapTweak',
- toXOnly(key.publicKey),
- );
- 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: KeyPair,
- txid: string,
- vout: number,
- amountToSend: number,
- scriptPubkeys: Buffer[],
- values: number[],
-): bitcoin.Transaction {
- 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)
- );
- 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;
-}
-
// This logic will be extracted to ecpair
function tweakSigner(signer: bitcoin.Signer, opts: any = {}): bitcoin.Signer {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
From f221e1f7ac01c11b715e3398e04514a7df64ae42 Mon Sep 17 00:00:00 2001
From: junderw
Date: Wed, 7 Dec 2022 19:24:23 +0900
Subject: [PATCH 100/144] 6.1.0
---
package-lock.json | 4 ++--
package.json | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 67af0eb4d..e6de61ff9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "bitcoinjs-lib",
- "version": "6.1.0-rc.0",
+ "version": "6.1.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "bitcoinjs-lib",
- "version": "6.1.0-rc.0",
+ "version": "6.1.0",
"license": "MIT",
"dependencies": {
"bech32": "^2.0.0",
diff --git a/package.json b/package.json
index 4334faa4f..b973d3d3f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "6.1.0-rc.0",
+ "version": "6.1.0",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"types": "./src/index.d.ts",
From db98a14e5dfb6d616456a883b3636cee2be9af79 Mon Sep 17 00:00:00 2001
From: Greg Tonoski <111286121+GregTonoski@users.noreply.github.com>
Date: Thu, 29 Dec 2022 11:55:32 +0100
Subject: [PATCH 101/144] Removal of the example [Taproot Key Spend]
There was the link to the page that doesn't exist: [Taproot Key Spend](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/taproot.md)
---
README.md | 1 -
1 file changed, 1 deletion(-)
diff --git a/README.md b/README.md
index 77498c73a..a8de46778 100644
--- a/README.md
+++ b/README.md
@@ -103,7 +103,6 @@ The below examples are implemented as integration tests, they should be very eas
Otherwise, pull requests are appreciated.
Some examples interact (via HTTPS) with a 3rd Party Blockchain Provider (3PBP).
-- [Taproot Key Spend](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/taproot.md)
- [Generate a random address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.spec.ts)
- [Import an address via WIF](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.spec.ts)
From d4957655c948e6c87a850e907f806ee71a56df70 Mon Sep 17 00:00:00 2001
From: Vodopyanov Egor
Date: Thu, 29 Dec 2022 23:04:40 +0800
Subject: [PATCH 102/144] chore: initialise TAGGED_HASH_PREFIXES on-demand
---
src/crypto.js | 15 +++++++++------
ts_src/crypto.ts | 17 +++++++++++------
2 files changed, 20 insertions(+), 12 deletions(-)
diff --git a/src/crypto.js b/src/crypto.js
index b84f2701e..9a3c1a157 100644
--- a/src/crypto.js
+++ b/src/crypto.js
@@ -49,13 +49,16 @@ const TAGS = [
'KeyAgg coefficient',
];
/** An object mapping tags to their tagged hash prefix of [SHA256(tag) | SHA256(tag)] */
-const TAGGED_HASH_PREFIXES = Object.fromEntries(
- TAGS.map(tag => {
- const tagHash = sha256(Buffer.from(tag));
- return [tag, Buffer.concat([tagHash, tagHash])];
- }),
-);
+let TAGGED_HASH_PREFIXES = undefined;
function taggedHash(prefix, data) {
+ if (!TAGGED_HASH_PREFIXES) {
+ TAGGED_HASH_PREFIXES = Object.fromEntries(
+ TAGS.map(tag => {
+ const tagHash = sha256(Buffer.from(tag));
+ return [tag, Buffer.concat([tagHash, tagHash])];
+ }),
+ );
+ }
return sha256(Buffer.concat([TAGGED_HASH_PREFIXES[prefix], data]));
}
exports.taggedHash = taggedHash;
diff --git a/ts_src/crypto.ts b/ts_src/crypto.ts
index 5af3bfbbe..47ac48313 100644
--- a/ts_src/crypto.ts
+++ b/ts_src/crypto.ts
@@ -42,13 +42,18 @@ const TAGS = [
] as const;
export type TaggedHashPrefix = typeof TAGS[number];
/** An object mapping tags to their tagged hash prefix of [SHA256(tag) | SHA256(tag)] */
-const TAGGED_HASH_PREFIXES = Object.fromEntries(
- TAGS.map(tag => {
- const tagHash = sha256(Buffer.from(tag));
- return [tag, Buffer.concat([tagHash, tagHash])];
- }),
-) as { [k in TaggedHashPrefix]: Buffer };
+let TAGGED_HASH_PREFIXES = undefined as
+ | { [k in TaggedHashPrefix]: Buffer }
+ | undefined;
export function taggedHash(prefix: TaggedHashPrefix, data: Buffer): Buffer {
+ if (!TAGGED_HASH_PREFIXES) {
+ TAGGED_HASH_PREFIXES = Object.fromEntries(
+ TAGS.map(tag => {
+ const tagHash = sha256(Buffer.from(tag));
+ return [tag, Buffer.concat([tagHash, tagHash])];
+ }),
+ ) as { [k in TaggedHashPrefix]: Buffer };
+ }
return sha256(Buffer.concat([TAGGED_HASH_PREFIXES[prefix], data]));
}
From 6c886dd8d86e3b2e39d5e9231436aacf2a8ce91d Mon Sep 17 00:00:00 2001
From: Vodopyanov Egor
Date: Thu, 5 Jan 2023 17:51:59 +0800
Subject: [PATCH 103/144] refactor: store pre-computed prefixes
---
package.json | 4 ++-
scripts/generate-tagged-hash-prefixes.js | 26 +++++++++++++++++++
src/crypto.d.ts | 3 +--
src/crypto.js | 27 +++++--------------
src/tagged-hash-prefixes.d.ts | 5 ++++
src/tagged-hash-prefixes.js | 23 +++++++++++++++++
src/tags.d.ts | 1 +
src/tags.js | 14 ++++++++++
test/crypto.spec.ts | 20 ++++++++++++++
ts_src/crypto.ts | 33 +++++++-----------------
ts_src/tagged-hash-prefixes.ts | 23 +++++++++++++++++
ts_src/tags.ts | 11 ++++++++
12 files changed, 144 insertions(+), 46 deletions(-)
create mode 100644 scripts/generate-tagged-hash-prefixes.js
create mode 100644 src/tagged-hash-prefixes.d.ts
create mode 100644 src/tagged-hash-prefixes.js
create mode 100644 src/tags.d.ts
create mode 100644 src/tags.js
create mode 100644 ts_src/tagged-hash-prefixes.ts
create mode 100644 ts_src/tags.ts
diff --git a/package.json b/package.json
index b973d3d3f..771af161b 100644
--- a/package.json
+++ b/package.json
@@ -29,6 +29,7 @@
"gitdiff:ci": "npm run build && git diff --exit-code",
"integration": "npm run build && npm run nobuild:integration",
"lint": "eslint ts_src/** src/**/*.js",
+ "lint:fix": "eslint --fix ts_src/** src/**/*.js",
"lint:tests": "eslint test/**/*.spec.ts",
"mocha:ts": "mocha --recursive --require test/ts-node-register",
"nobuild:coverage-report": "nyc report --reporter=lcov",
@@ -39,7 +40,8 @@
"prettier": "prettier \"ts_src/**/*.ts\" \"test/**/*.ts\" --ignore-path ./.prettierignore",
"prettierjs": "prettier \"src/**/*.js\" --ignore-path ./.prettierignore",
"test": "npm run build && npm run format:ci && npm run lint && npm run nobuild:coverage",
- "unit": "npm run build && npm run nobuild:unit"
+ "unit": "npm run build && npm run nobuild:unit",
+ "generate:prefixes": "node scripts/generate-tagged-hash-prefixes.js && yarn prettierjs && yarn lint:fix"
},
"repository": {
"type": "git",
diff --git a/scripts/generate-tagged-hash-prefixes.js b/scripts/generate-tagged-hash-prefixes.js
new file mode 100644
index 000000000..e582f5014
--- /dev/null
+++ b/scripts/generate-tagged-hash-prefixes.js
@@ -0,0 +1,26 @@
+const { sha256 } = require('../src/crypto');
+const { TAGS } = require('../src/tags');
+const fs = require('fs');
+const path = require('path');
+
+const taggedHashPrefixes = Object.fromEntries(
+ TAGS.map(tag => {
+ const tagHash = sha256(Buffer.from(tag));
+ return [tag, Buffer.concat([tagHash, tagHash]).toString('hex')];
+ }),
+);
+
+let content = `
+interface StringMap {
+ [key: string]: string;
+}
+export const TAGGED_HASH_PREFIXES_HEX: StringMap = ${JSON.stringify(
+ taggedHashPrefixes,
+)}
+`;
+
+fs.writeFileSync(
+ path.resolve(__dirname, '../ts_src', 'tagged-hash-prefixes.ts'),
+ content,
+ { encoding: 'utf8', flag: 'w' },
+);
diff --git a/src/crypto.d.ts b/src/crypto.d.ts
index 4d88c2f39..e3cf463a9 100644
--- a/src/crypto.d.ts
+++ b/src/crypto.d.ts
@@ -1,10 +1,9 @@
///
+import { TAGS } from './tags';
export declare function ripemd160(buffer: Buffer): Buffer;
export declare function sha1(buffer: Buffer): Buffer;
export declare function sha256(buffer: Buffer): Buffer;
export declare function hash160(buffer: Buffer): Buffer;
export declare function hash256(buffer: Buffer): Buffer;
-declare const TAGS: readonly ["BIP0340/challenge", "BIP0340/aux", "BIP0340/nonce", "TapLeaf", "TapBranch", "TapSighash", "TapTweak", "KeyAgg list", "KeyAgg coefficient"];
export type TaggedHashPrefix = typeof TAGS[number];
export declare function taggedHash(prefix: TaggedHashPrefix, data: Buffer): Buffer;
-export {};
diff --git a/src/crypto.js b/src/crypto.js
index 9a3c1a157..783a22900 100644
--- a/src/crypto.js
+++ b/src/crypto.js
@@ -9,6 +9,7 @@ exports.taggedHash =
void 0;
const createHash = require('create-hash');
const RipeMd160 = require('ripemd160');
+const tagged_hash_prefixes_1 = require('./tagged-hash-prefixes');
function ripemd160(buffer) {
try {
return createHash('rmd160').update(buffer).digest();
@@ -37,28 +38,14 @@ function hash256(buffer) {
return sha256(sha256(buffer));
}
exports.hash256 = hash256;
-const TAGS = [
- 'BIP0340/challenge',
- 'BIP0340/aux',
- 'BIP0340/nonce',
- 'TapLeaf',
- 'TapBranch',
- 'TapSighash',
- 'TapTweak',
- 'KeyAgg list',
- 'KeyAgg coefficient',
-];
/** An object mapping tags to their tagged hash prefix of [SHA256(tag) | SHA256(tag)] */
-let TAGGED_HASH_PREFIXES = undefined;
+const TAGGED_HASH_PREFIXES = Object.fromEntries(
+ Object.keys(tagged_hash_prefixes_1.TAGGED_HASH_PREFIXES_HEX).map(tag => [
+ tag,
+ Buffer.from(tagged_hash_prefixes_1.TAGGED_HASH_PREFIXES_HEX[tag], 'hex'),
+ ]),
+);
function taggedHash(prefix, data) {
- if (!TAGGED_HASH_PREFIXES) {
- TAGGED_HASH_PREFIXES = Object.fromEntries(
- TAGS.map(tag => {
- const tagHash = sha256(Buffer.from(tag));
- return [tag, Buffer.concat([tagHash, tagHash])];
- }),
- );
- }
return sha256(Buffer.concat([TAGGED_HASH_PREFIXES[prefix], data]));
}
exports.taggedHash = taggedHash;
diff --git a/src/tagged-hash-prefixes.d.ts b/src/tagged-hash-prefixes.d.ts
new file mode 100644
index 000000000..c74a8da53
--- /dev/null
+++ b/src/tagged-hash-prefixes.d.ts
@@ -0,0 +1,5 @@
+interface StringMap {
+ [key: string]: string;
+}
+export declare const TAGGED_HASH_PREFIXES_HEX: StringMap;
+export {};
diff --git a/src/tagged-hash-prefixes.js b/src/tagged-hash-prefixes.js
new file mode 100644
index 000000000..1ab6f8704
--- /dev/null
+++ b/src/tagged-hash-prefixes.js
@@ -0,0 +1,23 @@
+'use strict';
+Object.defineProperty(exports, '__esModule', { value: true });
+exports.TAGGED_HASH_PREFIXES_HEX = void 0;
+exports.TAGGED_HASH_PREFIXES_HEX = {
+ 'BIP0340/challenge':
+ '7bb52d7a9fef58323eb1bf7a407db382d2f3f2d81bb1224f49fe518f6d48d37c7bb52d7a9fef58323eb1bf7a407db382d2f3f2d81bb1224f49fe518f6d48d37c',
+ 'BIP0340/aux':
+ 'f1ef4e5ec063cada6d94cafa9d987ea069265839ecc11f972d77a52ed8c1cc90f1ef4e5ec063cada6d94cafa9d987ea069265839ecc11f972d77a52ed8c1cc90',
+ 'BIP0340/nonce':
+ '07497734a79bcb355b9b8c7d034f121cf434d73ef72dda19870061fb52bfeb2f07497734a79bcb355b9b8c7d034f121cf434d73ef72dda19870061fb52bfeb2f',
+ TapLeaf:
+ 'aeea8fdc4208983105734b58081d1e2638d35f1cb54008d4d357ca03be78e9eeaeea8fdc4208983105734b58081d1e2638d35f1cb54008d4d357ca03be78e9ee',
+ TapBranch:
+ '1941a1f2e56eb95fa2a9f194be5c01f7216f33ed82b091463490d05bf516a0151941a1f2e56eb95fa2a9f194be5c01f7216f33ed82b091463490d05bf516a015',
+ TapSighash:
+ 'f40a48df4b2a70c8b4924bf2654661ed3d95fd66a313eb87237597c628e4a031f40a48df4b2a70c8b4924bf2654661ed3d95fd66a313eb87237597c628e4a031',
+ TapTweak:
+ 'e80fe1639c9ca050e3af1b39c143c63e429cbceb15d940fbb5c5a1f4af57c5e9e80fe1639c9ca050e3af1b39c143c63e429cbceb15d940fbb5c5a1f4af57c5e9',
+ 'KeyAgg list':
+ '481c971c3c0b46d7f0b275ae598d4e2c7ed7319c594a5c6ec79ea0d4990294f0481c971c3c0b46d7f0b275ae598d4e2c7ed7319c594a5c6ec79ea0d4990294f0',
+ 'KeyAgg coefficient':
+ 'bfc904034d1c88e8c80e22e53d24566d64824ed6427281c09100f94dcd52c981bfc904034d1c88e8c80e22e53d24566d64824ed6427281c09100f94dcd52c981',
+};
diff --git a/src/tags.d.ts b/src/tags.d.ts
new file mode 100644
index 000000000..a6138f822
--- /dev/null
+++ b/src/tags.d.ts
@@ -0,0 +1 @@
+export declare const TAGS: readonly ["BIP0340/challenge", "BIP0340/aux", "BIP0340/nonce", "TapLeaf", "TapBranch", "TapSighash", "TapTweak", "KeyAgg list", "KeyAgg coefficient"];
diff --git a/src/tags.js b/src/tags.js
new file mode 100644
index 000000000..96e529ec7
--- /dev/null
+++ b/src/tags.js
@@ -0,0 +1,14 @@
+'use strict';
+Object.defineProperty(exports, '__esModule', { value: true });
+exports.TAGS = void 0;
+exports.TAGS = [
+ 'BIP0340/challenge',
+ 'BIP0340/aux',
+ 'BIP0340/nonce',
+ 'TapLeaf',
+ 'TapBranch',
+ 'TapSighash',
+ 'TapTweak',
+ 'KeyAgg list',
+ 'KeyAgg coefficient',
+];
diff --git a/test/crypto.spec.ts b/test/crypto.spec.ts
index 0482ec9ec..6f3a21f00 100644
--- a/test/crypto.spec.ts
+++ b/test/crypto.spec.ts
@@ -2,6 +2,9 @@ import * as assert from 'assert';
import { describe, it } from 'mocha';
import { crypto as bcrypto, TaggedHashPrefix } from '..';
import * as fixtures from './fixtures/crypto.json';
+import { sha256 } from '../src/crypto';
+import { TAGS } from '../src/tags';
+import { TAGGED_HASH_PREFIXES_HEX } from '../src/tagged-hash-prefixes';
describe('crypto', () => {
['hash160', 'hash256', 'ripemd160', 'sha1', 'sha256'].forEach(algorithm => {
@@ -30,4 +33,21 @@ describe('crypto', () => {
});
});
});
+
+ describe('TAGGED_HASH_PREFIXES', () => {
+ const taggedHashPrefixes = Object.fromEntries(
+ TAGS.map(tag => {
+ const tagHash = sha256(Buffer.from(tag));
+ return [tag, Buffer.concat([tagHash, tagHash])];
+ }),
+ );
+ it('stored the result of operation', () => {
+ Object.keys(taggedHashPrefixes).forEach(tag => {
+ assert.strictEqual(
+ TAGGED_HASH_PREFIXES_HEX[tag],
+ taggedHashPrefixes[tag].toString('hex'),
+ );
+ });
+ });
+ });
});
diff --git a/ts_src/crypto.ts b/ts_src/crypto.ts
index 47ac48313..ba85b260b 100644
--- a/ts_src/crypto.ts
+++ b/ts_src/crypto.ts
@@ -1,6 +1,7 @@
import * as createHash from 'create-hash';
import * as RipeMd160 from 'ripemd160';
-
+import { TAGGED_HASH_PREFIXES_HEX } from './tagged-hash-prefixes';
+import { TAGS } from './tags';
export function ripemd160(buffer: Buffer): Buffer {
try {
return createHash('rmd160').update(buffer).digest();
@@ -29,31 +30,17 @@ export function hash256(buffer: Buffer): Buffer {
return sha256(sha256(buffer));
}
-const TAGS = [
- 'BIP0340/challenge',
- 'BIP0340/aux',
- 'BIP0340/nonce',
- 'TapLeaf',
- 'TapBranch',
- 'TapSighash',
- 'TapTweak',
- 'KeyAgg list',
- 'KeyAgg coefficient',
-] as const;
export type TaggedHashPrefix = typeof TAGS[number];
+
/** An object mapping tags to their tagged hash prefix of [SHA256(tag) | SHA256(tag)] */
-let TAGGED_HASH_PREFIXES = undefined as
- | { [k in TaggedHashPrefix]: Buffer }
- | undefined;
+
+const TAGGED_HASH_PREFIXES = Object.fromEntries(
+ Object.keys(TAGGED_HASH_PREFIXES_HEX).map((tag: string) => [
+ tag,
+ Buffer.from(TAGGED_HASH_PREFIXES_HEX[tag], 'hex'),
+ ]),
+) as { [k in TaggedHashPrefix]: Buffer };
export function taggedHash(prefix: TaggedHashPrefix, data: Buffer): Buffer {
- if (!TAGGED_HASH_PREFIXES) {
- TAGGED_HASH_PREFIXES = Object.fromEntries(
- TAGS.map(tag => {
- const tagHash = sha256(Buffer.from(tag));
- return [tag, Buffer.concat([tagHash, tagHash])];
- }),
- ) as { [k in TaggedHashPrefix]: Buffer };
- }
return sha256(Buffer.concat([TAGGED_HASH_PREFIXES[prefix], data]));
}
diff --git a/ts_src/tagged-hash-prefixes.ts b/ts_src/tagged-hash-prefixes.ts
new file mode 100644
index 000000000..4f800cbc3
--- /dev/null
+++ b/ts_src/tagged-hash-prefixes.ts
@@ -0,0 +1,23 @@
+interface StringMap {
+ [key: string]: string;
+}
+export const TAGGED_HASH_PREFIXES_HEX: StringMap = {
+ 'BIP0340/challenge':
+ '7bb52d7a9fef58323eb1bf7a407db382d2f3f2d81bb1224f49fe518f6d48d37c7bb52d7a9fef58323eb1bf7a407db382d2f3f2d81bb1224f49fe518f6d48d37c',
+ 'BIP0340/aux':
+ 'f1ef4e5ec063cada6d94cafa9d987ea069265839ecc11f972d77a52ed8c1cc90f1ef4e5ec063cada6d94cafa9d987ea069265839ecc11f972d77a52ed8c1cc90',
+ 'BIP0340/nonce':
+ '07497734a79bcb355b9b8c7d034f121cf434d73ef72dda19870061fb52bfeb2f07497734a79bcb355b9b8c7d034f121cf434d73ef72dda19870061fb52bfeb2f',
+ TapLeaf:
+ 'aeea8fdc4208983105734b58081d1e2638d35f1cb54008d4d357ca03be78e9eeaeea8fdc4208983105734b58081d1e2638d35f1cb54008d4d357ca03be78e9ee',
+ TapBranch:
+ '1941a1f2e56eb95fa2a9f194be5c01f7216f33ed82b091463490d05bf516a0151941a1f2e56eb95fa2a9f194be5c01f7216f33ed82b091463490d05bf516a015',
+ TapSighash:
+ 'f40a48df4b2a70c8b4924bf2654661ed3d95fd66a313eb87237597c628e4a031f40a48df4b2a70c8b4924bf2654661ed3d95fd66a313eb87237597c628e4a031',
+ TapTweak:
+ 'e80fe1639c9ca050e3af1b39c143c63e429cbceb15d940fbb5c5a1f4af57c5e9e80fe1639c9ca050e3af1b39c143c63e429cbceb15d940fbb5c5a1f4af57c5e9',
+ 'KeyAgg list':
+ '481c971c3c0b46d7f0b275ae598d4e2c7ed7319c594a5c6ec79ea0d4990294f0481c971c3c0b46d7f0b275ae598d4e2c7ed7319c594a5c6ec79ea0d4990294f0',
+ 'KeyAgg coefficient':
+ 'bfc904034d1c88e8c80e22e53d24566d64824ed6427281c09100f94dcd52c981bfc904034d1c88e8c80e22e53d24566d64824ed6427281c09100f94dcd52c981',
+};
diff --git a/ts_src/tags.ts b/ts_src/tags.ts
new file mode 100644
index 000000000..5480c2818
--- /dev/null
+++ b/ts_src/tags.ts
@@ -0,0 +1,11 @@
+export const TAGS = [
+ 'BIP0340/challenge',
+ 'BIP0340/aux',
+ 'BIP0340/nonce',
+ 'TapLeaf',
+ 'TapBranch',
+ 'TapSighash',
+ 'TapTweak',
+ 'KeyAgg list',
+ 'KeyAgg coefficient',
+] as const;
From c462e1dbdd5c4cf30ac0e299037903ee64592b97 Mon Sep 17 00:00:00 2001
From: Vodopyanov Egor
Date: Mon, 9 Jan 2023 14:03:40 +0800
Subject: [PATCH 104/144] refactor: hardcoded prefixes
---
package.json | 4 +-
scripts/generate-tagged-hash-prefixes.js | 26 --------
src/crypto.d.ts | 7 ++-
src/crypto.js | 76 ++++++++++++++++++++---
src/tagged-hash-prefixes.d.ts | 5 --
src/tagged-hash-prefixes.js | 23 -------
src/tags.d.ts | 1 -
src/tags.js | 14 -----
test/crypto.spec.ts | 16 ++---
ts_src/crypto.ts | 79 +++++++++++++++++++++---
ts_src/tagged-hash-prefixes.ts | 23 -------
ts_src/tags.ts | 11 ----
12 files changed, 152 insertions(+), 133 deletions(-)
delete mode 100644 scripts/generate-tagged-hash-prefixes.js
delete mode 100644 src/tagged-hash-prefixes.d.ts
delete mode 100644 src/tagged-hash-prefixes.js
delete mode 100644 src/tags.d.ts
delete mode 100644 src/tags.js
delete mode 100644 ts_src/tagged-hash-prefixes.ts
delete mode 100644 ts_src/tags.ts
diff --git a/package.json b/package.json
index 771af161b..b973d3d3f 100644
--- a/package.json
+++ b/package.json
@@ -29,7 +29,6 @@
"gitdiff:ci": "npm run build && git diff --exit-code",
"integration": "npm run build && npm run nobuild:integration",
"lint": "eslint ts_src/** src/**/*.js",
- "lint:fix": "eslint --fix ts_src/** src/**/*.js",
"lint:tests": "eslint test/**/*.spec.ts",
"mocha:ts": "mocha --recursive --require test/ts-node-register",
"nobuild:coverage-report": "nyc report --reporter=lcov",
@@ -40,8 +39,7 @@
"prettier": "prettier \"ts_src/**/*.ts\" \"test/**/*.ts\" --ignore-path ./.prettierignore",
"prettierjs": "prettier \"src/**/*.js\" --ignore-path ./.prettierignore",
"test": "npm run build && npm run format:ci && npm run lint && npm run nobuild:coverage",
- "unit": "npm run build && npm run nobuild:unit",
- "generate:prefixes": "node scripts/generate-tagged-hash-prefixes.js && yarn prettierjs && yarn lint:fix"
+ "unit": "npm run build && npm run nobuild:unit"
},
"repository": {
"type": "git",
diff --git a/scripts/generate-tagged-hash-prefixes.js b/scripts/generate-tagged-hash-prefixes.js
deleted file mode 100644
index e582f5014..000000000
--- a/scripts/generate-tagged-hash-prefixes.js
+++ /dev/null
@@ -1,26 +0,0 @@
-const { sha256 } = require('../src/crypto');
-const { TAGS } = require('../src/tags');
-const fs = require('fs');
-const path = require('path');
-
-const taggedHashPrefixes = Object.fromEntries(
- TAGS.map(tag => {
- const tagHash = sha256(Buffer.from(tag));
- return [tag, Buffer.concat([tagHash, tagHash]).toString('hex')];
- }),
-);
-
-let content = `
-interface StringMap {
- [key: string]: string;
-}
-export const TAGGED_HASH_PREFIXES_HEX: StringMap = ${JSON.stringify(
- taggedHashPrefixes,
-)}
-`;
-
-fs.writeFileSync(
- path.resolve(__dirname, '../ts_src', 'tagged-hash-prefixes.ts'),
- content,
- { encoding: 'utf8', flag: 'w' },
-);
diff --git a/src/crypto.d.ts b/src/crypto.d.ts
index e3cf463a9..770d3bbb5 100644
--- a/src/crypto.d.ts
+++ b/src/crypto.d.ts
@@ -1,9 +1,14 @@
///
-import { TAGS } from './tags';
export declare function ripemd160(buffer: Buffer): Buffer;
export declare function sha1(buffer: Buffer): Buffer;
export declare function sha256(buffer: Buffer): Buffer;
export declare function hash160(buffer: Buffer): Buffer;
export declare function hash256(buffer: Buffer): Buffer;
+export declare const TAGS: readonly ["BIP0340/challenge", "BIP0340/aux", "BIP0340/nonce", "TapLeaf", "TapBranch", "TapSighash", "TapTweak", "KeyAgg list", "KeyAgg coefficient"];
export type TaggedHashPrefix = typeof TAGS[number];
+export type TaggedHashPrefixes = {
+ [key in TaggedHashPrefix]: Buffer;
+};
+/** An object mapping tags to their tagged hash prefix of [SHA256(tag) | SHA256(tag)] */
+export declare const TAGGED_HASH_PREFIXES: TaggedHashPrefixes;
export declare function taggedHash(prefix: TaggedHashPrefix, data: Buffer): Buffer;
diff --git a/src/crypto.js b/src/crypto.js
index 783a22900..25f71bad2 100644
--- a/src/crypto.js
+++ b/src/crypto.js
@@ -1,6 +1,8 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
exports.taggedHash =
+ exports.TAGGED_HASH_PREFIXES =
+ exports.TAGS =
exports.hash256 =
exports.hash160 =
exports.sha256 =
@@ -9,7 +11,6 @@ exports.taggedHash =
void 0;
const createHash = require('create-hash');
const RipeMd160 = require('ripemd160');
-const tagged_hash_prefixes_1 = require('./tagged-hash-prefixes');
function ripemd160(buffer) {
try {
return createHash('rmd160').update(buffer).digest();
@@ -38,14 +39,75 @@ function hash256(buffer) {
return sha256(sha256(buffer));
}
exports.hash256 = hash256;
+exports.TAGS = [
+ 'BIP0340/challenge',
+ 'BIP0340/aux',
+ 'BIP0340/nonce',
+ 'TapLeaf',
+ 'TapBranch',
+ 'TapSighash',
+ 'TapTweak',
+ 'KeyAgg list',
+ 'KeyAgg coefficient',
+];
/** An object mapping tags to their tagged hash prefix of [SHA256(tag) | SHA256(tag)] */
-const TAGGED_HASH_PREFIXES = Object.fromEntries(
- Object.keys(tagged_hash_prefixes_1.TAGGED_HASH_PREFIXES_HEX).map(tag => [
- tag,
- Buffer.from(tagged_hash_prefixes_1.TAGGED_HASH_PREFIXES_HEX[tag], 'hex'),
+exports.TAGGED_HASH_PREFIXES = {
+ 'BIP0340/challenge': Buffer.from([
+ 123, 181, 45, 122, 159, 239, 88, 50, 62, 177, 191, 122, 64, 125, 179, 130,
+ 210, 243, 242, 216, 27, 177, 34, 79, 73, 254, 81, 143, 109, 72, 211, 124,
+ 123, 181, 45, 122, 159, 239, 88, 50, 62, 177, 191, 122, 64, 125, 179, 130,
+ 210, 243, 242, 216, 27, 177, 34, 79, 73, 254, 81, 143, 109, 72, 211, 124,
]),
-);
+ 'BIP0340/aux': Buffer.from([
+ 241, 239, 78, 94, 192, 99, 202, 218, 109, 148, 202, 250, 157, 152, 126, 160,
+ 105, 38, 88, 57, 236, 193, 31, 151, 45, 119, 165, 46, 216, 193, 204, 144,
+ 241, 239, 78, 94, 192, 99, 202, 218, 109, 148, 202, 250, 157, 152, 126, 160,
+ 105, 38, 88, 57, 236, 193, 31, 151, 45, 119, 165, 46, 216, 193, 204, 144,
+ ]),
+ 'BIP0340/nonce': Buffer.from([
+ 7, 73, 119, 52, 167, 155, 203, 53, 91, 155, 140, 125, 3, 79, 18, 28, 244,
+ 52, 215, 62, 247, 45, 218, 25, 135, 0, 97, 251, 82, 191, 235, 47, 7, 73,
+ 119, 52, 167, 155, 203, 53, 91, 155, 140, 125, 3, 79, 18, 28, 244, 52, 215,
+ 62, 247, 45, 218, 25, 135, 0, 97, 251, 82, 191, 235, 47,
+ ]),
+ TapLeaf: Buffer.from([
+ 174, 234, 143, 220, 66, 8, 152, 49, 5, 115, 75, 88, 8, 29, 30, 38, 56, 211,
+ 95, 28, 181, 64, 8, 212, 211, 87, 202, 3, 190, 120, 233, 238, 174, 234, 143,
+ 220, 66, 8, 152, 49, 5, 115, 75, 88, 8, 29, 30, 38, 56, 211, 95, 28, 181,
+ 64, 8, 212, 211, 87, 202, 3, 190, 120, 233, 238,
+ ]),
+ TapBranch: Buffer.from([
+ 25, 65, 161, 242, 229, 110, 185, 95, 162, 169, 241, 148, 190, 92, 1, 247,
+ 33, 111, 51, 237, 130, 176, 145, 70, 52, 144, 208, 91, 245, 22, 160, 21, 25,
+ 65, 161, 242, 229, 110, 185, 95, 162, 169, 241, 148, 190, 92, 1, 247, 33,
+ 111, 51, 237, 130, 176, 145, 70, 52, 144, 208, 91, 245, 22, 160, 21,
+ ]),
+ TapSighash: Buffer.from([
+ 244, 10, 72, 223, 75, 42, 112, 200, 180, 146, 75, 242, 101, 70, 97, 237, 61,
+ 149, 253, 102, 163, 19, 235, 135, 35, 117, 151, 198, 40, 228, 160, 49, 244,
+ 10, 72, 223, 75, 42, 112, 200, 180, 146, 75, 242, 101, 70, 97, 237, 61, 149,
+ 253, 102, 163, 19, 235, 135, 35, 117, 151, 198, 40, 228, 160, 49,
+ ]),
+ TapTweak: Buffer.from([
+ 232, 15, 225, 99, 156, 156, 160, 80, 227, 175, 27, 57, 193, 67, 198, 62, 66,
+ 156, 188, 235, 21, 217, 64, 251, 181, 197, 161, 244, 175, 87, 197, 233, 232,
+ 15, 225, 99, 156, 156, 160, 80, 227, 175, 27, 57, 193, 67, 198, 62, 66, 156,
+ 188, 235, 21, 217, 64, 251, 181, 197, 161, 244, 175, 87, 197, 233,
+ ]),
+ 'KeyAgg list': Buffer.from([
+ 72, 28, 151, 28, 60, 11, 70, 215, 240, 178, 117, 174, 89, 141, 78, 44, 126,
+ 215, 49, 156, 89, 74, 92, 110, 199, 158, 160, 212, 153, 2, 148, 240, 72, 28,
+ 151, 28, 60, 11, 70, 215, 240, 178, 117, 174, 89, 141, 78, 44, 126, 215, 49,
+ 156, 89, 74, 92, 110, 199, 158, 160, 212, 153, 2, 148, 240,
+ ]),
+ 'KeyAgg coefficient': Buffer.from([
+ 191, 201, 4, 3, 77, 28, 136, 232, 200, 14, 34, 229, 61, 36, 86, 109, 100,
+ 130, 78, 214, 66, 114, 129, 192, 145, 0, 249, 77, 205, 82, 201, 129, 191,
+ 201, 4, 3, 77, 28, 136, 232, 200, 14, 34, 229, 61, 36, 86, 109, 100, 130,
+ 78, 214, 66, 114, 129, 192, 145, 0, 249, 77, 205, 82, 201, 129,
+ ]),
+};
function taggedHash(prefix, data) {
- return sha256(Buffer.concat([TAGGED_HASH_PREFIXES[prefix], data]));
+ return sha256(Buffer.concat([exports.TAGGED_HASH_PREFIXES[prefix], data]));
}
exports.taggedHash = taggedHash;
diff --git a/src/tagged-hash-prefixes.d.ts b/src/tagged-hash-prefixes.d.ts
deleted file mode 100644
index c74a8da53..000000000
--- a/src/tagged-hash-prefixes.d.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-interface StringMap {
- [key: string]: string;
-}
-export declare const TAGGED_HASH_PREFIXES_HEX: StringMap;
-export {};
diff --git a/src/tagged-hash-prefixes.js b/src/tagged-hash-prefixes.js
deleted file mode 100644
index 1ab6f8704..000000000
--- a/src/tagged-hash-prefixes.js
+++ /dev/null
@@ -1,23 +0,0 @@
-'use strict';
-Object.defineProperty(exports, '__esModule', { value: true });
-exports.TAGGED_HASH_PREFIXES_HEX = void 0;
-exports.TAGGED_HASH_PREFIXES_HEX = {
- 'BIP0340/challenge':
- '7bb52d7a9fef58323eb1bf7a407db382d2f3f2d81bb1224f49fe518f6d48d37c7bb52d7a9fef58323eb1bf7a407db382d2f3f2d81bb1224f49fe518f6d48d37c',
- 'BIP0340/aux':
- 'f1ef4e5ec063cada6d94cafa9d987ea069265839ecc11f972d77a52ed8c1cc90f1ef4e5ec063cada6d94cafa9d987ea069265839ecc11f972d77a52ed8c1cc90',
- 'BIP0340/nonce':
- '07497734a79bcb355b9b8c7d034f121cf434d73ef72dda19870061fb52bfeb2f07497734a79bcb355b9b8c7d034f121cf434d73ef72dda19870061fb52bfeb2f',
- TapLeaf:
- 'aeea8fdc4208983105734b58081d1e2638d35f1cb54008d4d357ca03be78e9eeaeea8fdc4208983105734b58081d1e2638d35f1cb54008d4d357ca03be78e9ee',
- TapBranch:
- '1941a1f2e56eb95fa2a9f194be5c01f7216f33ed82b091463490d05bf516a0151941a1f2e56eb95fa2a9f194be5c01f7216f33ed82b091463490d05bf516a015',
- TapSighash:
- 'f40a48df4b2a70c8b4924bf2654661ed3d95fd66a313eb87237597c628e4a031f40a48df4b2a70c8b4924bf2654661ed3d95fd66a313eb87237597c628e4a031',
- TapTweak:
- 'e80fe1639c9ca050e3af1b39c143c63e429cbceb15d940fbb5c5a1f4af57c5e9e80fe1639c9ca050e3af1b39c143c63e429cbceb15d940fbb5c5a1f4af57c5e9',
- 'KeyAgg list':
- '481c971c3c0b46d7f0b275ae598d4e2c7ed7319c594a5c6ec79ea0d4990294f0481c971c3c0b46d7f0b275ae598d4e2c7ed7319c594a5c6ec79ea0d4990294f0',
- 'KeyAgg coefficient':
- 'bfc904034d1c88e8c80e22e53d24566d64824ed6427281c09100f94dcd52c981bfc904034d1c88e8c80e22e53d24566d64824ed6427281c09100f94dcd52c981',
-};
diff --git a/src/tags.d.ts b/src/tags.d.ts
deleted file mode 100644
index a6138f822..000000000
--- a/src/tags.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export declare const TAGS: readonly ["BIP0340/challenge", "BIP0340/aux", "BIP0340/nonce", "TapLeaf", "TapBranch", "TapSighash", "TapTweak", "KeyAgg list", "KeyAgg coefficient"];
diff --git a/src/tags.js b/src/tags.js
deleted file mode 100644
index 96e529ec7..000000000
--- a/src/tags.js
+++ /dev/null
@@ -1,14 +0,0 @@
-'use strict';
-Object.defineProperty(exports, '__esModule', { value: true });
-exports.TAGS = void 0;
-exports.TAGS = [
- 'BIP0340/challenge',
- 'BIP0340/aux',
- 'BIP0340/nonce',
- 'TapLeaf',
- 'TapBranch',
- 'TapSighash',
- 'TapTweak',
- 'KeyAgg list',
- 'KeyAgg coefficient',
-];
diff --git a/test/crypto.spec.ts b/test/crypto.spec.ts
index 6f3a21f00..b7273568f 100644
--- a/test/crypto.spec.ts
+++ b/test/crypto.spec.ts
@@ -2,9 +2,7 @@ import * as assert from 'assert';
import { describe, it } from 'mocha';
import { crypto as bcrypto, TaggedHashPrefix } from '..';
import * as fixtures from './fixtures/crypto.json';
-import { sha256 } from '../src/crypto';
-import { TAGS } from '../src/tags';
-import { TAGGED_HASH_PREFIXES_HEX } from '../src/tagged-hash-prefixes';
+import { sha256, TAGS, TAGGED_HASH_PREFIXES } from '../src/crypto';
describe('crypto', () => {
['hash160', 'hash256', 'ripemd160', 'sha1', 'sha256'].forEach(algorithm => {
@@ -36,18 +34,16 @@ describe('crypto', () => {
describe('TAGGED_HASH_PREFIXES', () => {
const taggedHashPrefixes = Object.fromEntries(
- TAGS.map(tag => {
+ TAGS.map((tag: TaggedHashPrefix) => {
const tagHash = sha256(Buffer.from(tag));
return [tag, Buffer.concat([tagHash, tagHash])];
}),
);
it('stored the result of operation', () => {
- Object.keys(taggedHashPrefixes).forEach(tag => {
- assert.strictEqual(
- TAGGED_HASH_PREFIXES_HEX[tag],
- taggedHashPrefixes[tag].toString('hex'),
- );
- });
+ assert.strictEqual(
+ JSON.stringify(TAGGED_HASH_PREFIXES),
+ JSON.stringify(taggedHashPrefixes),
+ );
});
});
});
diff --git a/ts_src/crypto.ts b/ts_src/crypto.ts
index ba85b260b..686cdcd9e 100644
--- a/ts_src/crypto.ts
+++ b/ts_src/crypto.ts
@@ -1,7 +1,6 @@
import * as createHash from 'create-hash';
import * as RipeMd160 from 'ripemd160';
-import { TAGGED_HASH_PREFIXES_HEX } from './tagged-hash-prefixes';
-import { TAGS } from './tags';
+
export function ripemd160(buffer: Buffer): Buffer {
try {
return createHash('rmd160').update(buffer).digest();
@@ -30,16 +29,78 @@ export function hash256(buffer: Buffer): Buffer {
return sha256(sha256(buffer));
}
+export const TAGS = [
+ 'BIP0340/challenge',
+ 'BIP0340/aux',
+ 'BIP0340/nonce',
+ 'TapLeaf',
+ 'TapBranch',
+ 'TapSighash',
+ 'TapTweak',
+ 'KeyAgg list',
+ 'KeyAgg coefficient',
+] as const;
export type TaggedHashPrefix = typeof TAGS[number];
-
+type TaggedHashPrefixes = {
+ [key in TaggedHashPrefix]: Buffer;
+};
/** An object mapping tags to their tagged hash prefix of [SHA256(tag) | SHA256(tag)] */
-
-const TAGGED_HASH_PREFIXES = Object.fromEntries(
- Object.keys(TAGGED_HASH_PREFIXES_HEX).map((tag: string) => [
- tag,
- Buffer.from(TAGGED_HASH_PREFIXES_HEX[tag], 'hex'),
+export const TAGGED_HASH_PREFIXES: TaggedHashPrefixes = {
+ 'BIP0340/challenge': Buffer.from([
+ 123, 181, 45, 122, 159, 239, 88, 50, 62, 177, 191, 122, 64, 125, 179, 130,
+ 210, 243, 242, 216, 27, 177, 34, 79, 73, 254, 81, 143, 109, 72, 211, 124,
+ 123, 181, 45, 122, 159, 239, 88, 50, 62, 177, 191, 122, 64, 125, 179, 130,
+ 210, 243, 242, 216, 27, 177, 34, 79, 73, 254, 81, 143, 109, 72, 211, 124,
+ ]),
+ 'BIP0340/aux': Buffer.from([
+ 241, 239, 78, 94, 192, 99, 202, 218, 109, 148, 202, 250, 157, 152, 126, 160,
+ 105, 38, 88, 57, 236, 193, 31, 151, 45, 119, 165, 46, 216, 193, 204, 144,
+ 241, 239, 78, 94, 192, 99, 202, 218, 109, 148, 202, 250, 157, 152, 126, 160,
+ 105, 38, 88, 57, 236, 193, 31, 151, 45, 119, 165, 46, 216, 193, 204, 144,
+ ]),
+ 'BIP0340/nonce': Buffer.from([
+ 7, 73, 119, 52, 167, 155, 203, 53, 91, 155, 140, 125, 3, 79, 18, 28, 244,
+ 52, 215, 62, 247, 45, 218, 25, 135, 0, 97, 251, 82, 191, 235, 47, 7, 73,
+ 119, 52, 167, 155, 203, 53, 91, 155, 140, 125, 3, 79, 18, 28, 244, 52, 215,
+ 62, 247, 45, 218, 25, 135, 0, 97, 251, 82, 191, 235, 47,
+ ]),
+ TapLeaf: Buffer.from([
+ 174, 234, 143, 220, 66, 8, 152, 49, 5, 115, 75, 88, 8, 29, 30, 38, 56, 211,
+ 95, 28, 181, 64, 8, 212, 211, 87, 202, 3, 190, 120, 233, 238, 174, 234, 143,
+ 220, 66, 8, 152, 49, 5, 115, 75, 88, 8, 29, 30, 38, 56, 211, 95, 28, 181,
+ 64, 8, 212, 211, 87, 202, 3, 190, 120, 233, 238,
+ ]),
+ TapBranch: Buffer.from([
+ 25, 65, 161, 242, 229, 110, 185, 95, 162, 169, 241, 148, 190, 92, 1, 247,
+ 33, 111, 51, 237, 130, 176, 145, 70, 52, 144, 208, 91, 245, 22, 160, 21, 25,
+ 65, 161, 242, 229, 110, 185, 95, 162, 169, 241, 148, 190, 92, 1, 247, 33,
+ 111, 51, 237, 130, 176, 145, 70, 52, 144, 208, 91, 245, 22, 160, 21,
+ ]),
+ TapSighash: Buffer.from([
+ 244, 10, 72, 223, 75, 42, 112, 200, 180, 146, 75, 242, 101, 70, 97, 237, 61,
+ 149, 253, 102, 163, 19, 235, 135, 35, 117, 151, 198, 40, 228, 160, 49, 244,
+ 10, 72, 223, 75, 42, 112, 200, 180, 146, 75, 242, 101, 70, 97, 237, 61, 149,
+ 253, 102, 163, 19, 235, 135, 35, 117, 151, 198, 40, 228, 160, 49,
+ ]),
+ TapTweak: Buffer.from([
+ 232, 15, 225, 99, 156, 156, 160, 80, 227, 175, 27, 57, 193, 67, 198, 62, 66,
+ 156, 188, 235, 21, 217, 64, 251, 181, 197, 161, 244, 175, 87, 197, 233, 232,
+ 15, 225, 99, 156, 156, 160, 80, 227, 175, 27, 57, 193, 67, 198, 62, 66, 156,
+ 188, 235, 21, 217, 64, 251, 181, 197, 161, 244, 175, 87, 197, 233,
+ ]),
+ 'KeyAgg list': Buffer.from([
+ 72, 28, 151, 28, 60, 11, 70, 215, 240, 178, 117, 174, 89, 141, 78, 44, 126,
+ 215, 49, 156, 89, 74, 92, 110, 199, 158, 160, 212, 153, 2, 148, 240, 72, 28,
+ 151, 28, 60, 11, 70, 215, 240, 178, 117, 174, 89, 141, 78, 44, 126, 215, 49,
+ 156, 89, 74, 92, 110, 199, 158, 160, 212, 153, 2, 148, 240,
+ ]),
+ 'KeyAgg coefficient': Buffer.from([
+ 191, 201, 4, 3, 77, 28, 136, 232, 200, 14, 34, 229, 61, 36, 86, 109, 100,
+ 130, 78, 214, 66, 114, 129, 192, 145, 0, 249, 77, 205, 82, 201, 129, 191,
+ 201, 4, 3, 77, 28, 136, 232, 200, 14, 34, 229, 61, 36, 86, 109, 100, 130,
+ 78, 214, 66, 114, 129, 192, 145, 0, 249, 77, 205, 82, 201, 129,
]),
-) as { [k in TaggedHashPrefix]: Buffer };
+};
export function taggedHash(prefix: TaggedHashPrefix, data: Buffer): Buffer {
return sha256(Buffer.concat([TAGGED_HASH_PREFIXES[prefix], data]));
diff --git a/ts_src/tagged-hash-prefixes.ts b/ts_src/tagged-hash-prefixes.ts
deleted file mode 100644
index 4f800cbc3..000000000
--- a/ts_src/tagged-hash-prefixes.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-interface StringMap {
- [key: string]: string;
-}
-export const TAGGED_HASH_PREFIXES_HEX: StringMap = {
- 'BIP0340/challenge':
- '7bb52d7a9fef58323eb1bf7a407db382d2f3f2d81bb1224f49fe518f6d48d37c7bb52d7a9fef58323eb1bf7a407db382d2f3f2d81bb1224f49fe518f6d48d37c',
- 'BIP0340/aux':
- 'f1ef4e5ec063cada6d94cafa9d987ea069265839ecc11f972d77a52ed8c1cc90f1ef4e5ec063cada6d94cafa9d987ea069265839ecc11f972d77a52ed8c1cc90',
- 'BIP0340/nonce':
- '07497734a79bcb355b9b8c7d034f121cf434d73ef72dda19870061fb52bfeb2f07497734a79bcb355b9b8c7d034f121cf434d73ef72dda19870061fb52bfeb2f',
- TapLeaf:
- 'aeea8fdc4208983105734b58081d1e2638d35f1cb54008d4d357ca03be78e9eeaeea8fdc4208983105734b58081d1e2638d35f1cb54008d4d357ca03be78e9ee',
- TapBranch:
- '1941a1f2e56eb95fa2a9f194be5c01f7216f33ed82b091463490d05bf516a0151941a1f2e56eb95fa2a9f194be5c01f7216f33ed82b091463490d05bf516a015',
- TapSighash:
- 'f40a48df4b2a70c8b4924bf2654661ed3d95fd66a313eb87237597c628e4a031f40a48df4b2a70c8b4924bf2654661ed3d95fd66a313eb87237597c628e4a031',
- TapTweak:
- 'e80fe1639c9ca050e3af1b39c143c63e429cbceb15d940fbb5c5a1f4af57c5e9e80fe1639c9ca050e3af1b39c143c63e429cbceb15d940fbb5c5a1f4af57c5e9',
- 'KeyAgg list':
- '481c971c3c0b46d7f0b275ae598d4e2c7ed7319c594a5c6ec79ea0d4990294f0481c971c3c0b46d7f0b275ae598d4e2c7ed7319c594a5c6ec79ea0d4990294f0',
- 'KeyAgg coefficient':
- 'bfc904034d1c88e8c80e22e53d24566d64824ed6427281c09100f94dcd52c981bfc904034d1c88e8c80e22e53d24566d64824ed6427281c09100f94dcd52c981',
-};
diff --git a/ts_src/tags.ts b/ts_src/tags.ts
deleted file mode 100644
index 5480c2818..000000000
--- a/ts_src/tags.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-export const TAGS = [
- 'BIP0340/challenge',
- 'BIP0340/aux',
- 'BIP0340/nonce',
- 'TapLeaf',
- 'TapBranch',
- 'TapSighash',
- 'TapTweak',
- 'KeyAgg list',
- 'KeyAgg coefficient',
-] as const;
From 5707a04937c5774f83a2fc08696966e9119308ad Mon Sep 17 00:00:00 2001
From: Vodopyanov Egor
Date: Thu, 19 Jan 2023 18:27:48 +0800
Subject: [PATCH 105/144] chore: upgrade json5
---
package-lock.json | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index e6de61ff9..1007efae0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2725,9 +2725,9 @@
"dev": true
},
"node_modules/json5": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
- "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true,
"bin": {
"json5": "lib/cli.js"
@@ -6437,9 +6437,9 @@
"dev": true
},
"json5": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
- "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true
},
"levn": {
From cc1b23e74ee52c362908b3e4ceda6a3ff95a6760 Mon Sep 17 00:00:00 2001
From: Vodopyanov Egor
Date: Thu, 19 Jan 2023 18:28:47 +0800
Subject: [PATCH 106/144] fix: commit crypto.d.ts
---
src/crypto.d.ts | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/crypto.d.ts b/src/crypto.d.ts
index 770d3bbb5..1a465dad1 100644
--- a/src/crypto.d.ts
+++ b/src/crypto.d.ts
@@ -6,9 +6,10 @@ export declare function hash160(buffer: Buffer): Buffer;
export declare function hash256(buffer: Buffer): Buffer;
export declare const TAGS: readonly ["BIP0340/challenge", "BIP0340/aux", "BIP0340/nonce", "TapLeaf", "TapBranch", "TapSighash", "TapTweak", "KeyAgg list", "KeyAgg coefficient"];
export type TaggedHashPrefix = typeof TAGS[number];
-export type TaggedHashPrefixes = {
+type TaggedHashPrefixes = {
[key in TaggedHashPrefix]: Buffer;
};
/** An object mapping tags to their tagged hash prefix of [SHA256(tag) | SHA256(tag)] */
export declare const TAGGED_HASH_PREFIXES: TaggedHashPrefixes;
export declare function taggedHash(prefix: TaggedHashPrefix, data: Buffer): Buffer;
+export {};
From e3c16e6be31851b101b28aad6a6c29623d08d642 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jos=C3=A9=20Luis=20Landabaso=20D=C3=ADaz?=
Date: Mon, 23 Jan 2023 10:16:49 +0100
Subject: [PATCH 107/144] This commit aims to prevent the creation of
unspendable scripts in bitcoinjs-lib by implementing checks for resource
limitations. Specifically, it addresses the following issues: * Scripts over
520 bytes are invalid by consensus (P2SH). * Scripts over 3600 bytes are
invalid by standardness (P2WSH, P2SH-P2WSH). * Scripts where the total number
of non-push opcodes plus the number of keys participating in all executed
multis, is above 201, are invalid by consensus. However, it is important to
note that this fix only checks for non-push opcodes and may not cover all
cases of unspendable scripts, especially in some scenarios, such as a script
with two spending branches, one using multi and another one not using it. It
is the responsibility of the user to account for those cases.
Read more:
[https://bitcoin.sipa.be/miniscript/](https://bitcoin.sipa.be/miniscript/), section Resource limitations.
See also:
MAX_OPS_PER_SCRIPT, MAX_SCRIPT_ELEMENT_SIZE in
[https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp](https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp)
MAX_STANDARD_P2WSH_SCRIPT_SIZE in
[https://github.com/bitcoin/bitcoin/blob/master/src/policy/policy.cpp](https://github.com/bitcoin/bitcoin/blob/master/src/policy/policy.cpp)
---
src/payments/p2sh.js | 8 ++++++++
src/payments/p2wsh.js | 13 +++++++++++--
src/script.d.ts | 1 +
src/script.js | 5 +++++
test/fixtures/p2sh.json | 8 ++++++++
test/fixtures/p2wsh.json | 16 ++++++++++++++++
ts_src/payments/p2sh.ts | 8 ++++++++
ts_src/payments/p2wsh.ts | 13 +++++++++++--
ts_src/script.ts | 4 ++++
9 files changed, 72 insertions(+), 4 deletions(-)
diff --git a/src/payments/p2sh.js b/src/payments/p2sh.js
index 48edf304f..5061edc95 100644
--- a/src/payments/p2sh.js
+++ b/src/payments/p2sh.js
@@ -138,6 +138,14 @@ function p2sh(a, opts) {
const decompile = bscript.decompile(redeem.output);
if (!decompile || decompile.length < 1)
throw new TypeError('Redeem.output too short');
+ if (redeem.output.byteLength > 520)
+ throw new TypeError(
+ 'Redeem.output unspendable if larger than 520 bytes',
+ );
+ if (bscript.countNonPushOnlyOPs(decompile) > 201)
+ throw new TypeError(
+ 'Redeem.output unspendable with more than 201 non-push ops',
+ );
// match hash against other sources
const hash2 = bcrypto.hash160(redeem.output);
if (hash.length > 0 && !hash.equals(hash2))
diff --git a/src/payments/p2wsh.js b/src/payments/p2wsh.js
index 66ee1da02..2ad9387e9 100644
--- a/src/payments/p2wsh.js
+++ b/src/payments/p2wsh.js
@@ -166,10 +166,19 @@ function p2wsh(a, opts) {
a.redeem.witness.length > 0
)
throw new TypeError('Ambiguous witness source');
- // is the redeem output non-empty?
+ // is the redeem output non-empty/valid?
if (a.redeem.output) {
- if (bscript.decompile(a.redeem.output).length === 0)
+ const decompile = bscript.decompile(a.redeem.output);
+ if (!decompile || decompile.length < 1)
throw new TypeError('Redeem.output is invalid');
+ if (a.redeem.output.byteLength > 3600)
+ throw new TypeError(
+ 'Redeem.output unspendable if larger than 3600 bytes',
+ );
+ if (bscript.countNonPushOnlyOPs(decompile) > 201)
+ throw new TypeError(
+ 'Redeem.output unspendable with more than 201 non-push ops',
+ );
// match hash against other sources
const hash2 = bcrypto.sha256(a.redeem.output);
if (hash.length > 0 && !hash.equals(hash2))
diff --git a/src/script.d.ts b/src/script.d.ts
index 261ecf4af..fd5964b89 100644
--- a/src/script.d.ts
+++ b/src/script.d.ts
@@ -5,6 +5,7 @@ import * as scriptNumber from './script_number';
import * as scriptSignature from './script_signature';
export { OPS };
export declare function isPushOnly(value: Stack): boolean;
+export declare function countNonPushOnlyOPs(value: Stack): number;
export declare function compile(chunks: Buffer | Stack): Buffer;
export declare function decompile(buffer: Buffer | Array): Array | null;
export declare function toASM(chunks: Buffer | Array): string;
diff --git a/src/script.js b/src/script.js
index 5dff149f3..6ed7ba20a 100644
--- a/src/script.js
+++ b/src/script.js
@@ -10,6 +10,7 @@ exports.signature =
exports.toASM =
exports.decompile =
exports.compile =
+ exports.countNonPushOnlyOPs =
exports.isPushOnly =
exports.OPS =
void 0;
@@ -42,6 +43,10 @@ function isPushOnly(value) {
return types.Array(value) && value.every(isPushOnlyChunk);
}
exports.isPushOnly = isPushOnly;
+function countNonPushOnlyOPs(value) {
+ return value.length - value.filter(isPushOnlyChunk).length;
+}
+exports.countNonPushOnlyOPs = countNonPushOnlyOPs;
function asMinimalOP(buffer) {
if (buffer.length === 0) return ops_1.OPS.OP_0;
if (buffer.length !== 1) return;
diff --git a/test/fixtures/p2sh.json b/test/fixtures/p2sh.json
index b222de52b..32f108c91 100644
--- a/test/fixtures/p2sh.json
+++ b/test/fixtures/p2sh.json
@@ -294,6 +294,14 @@
"input": "OP_0 OP_0"
}
},
+ {
+ "exception": "Redeem.output unspendable if larger than 520 bytes",
+ "arguments": {
+ "redeem": {
+ "output": "OP_16 03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0 0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600 0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8 0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8 02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8 0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286 0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009 02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d 03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9 02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af 02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd 036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24 02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc 02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3 02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06 0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232 OP_16 OP_CHECKMULTISIG"
+ }
+ }
+ },
{
"exception": "Input is invalid",
"arguments": {
diff --git a/test/fixtures/p2wsh.json b/test/fixtures/p2wsh.json
index 03fb01d0f..effe4d148 100644
--- a/test/fixtures/p2wsh.json
+++ b/test/fixtures/p2wsh.json
@@ -264,6 +264,22 @@
}
}
},
+ {
+ "exception": "Redeem.output unspendable with more than 201 non-push ops",
+ "arguments": {
+ "redeem": {
+ "output": "OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP OP_0 OP_0 OP_2DROP 02c56aef124aa09836590fb858ce3517bf9d4b27e9d3fc81c2b00845f98ef87d9e OP_CHECKSIG"
+ }
+ }
+ },
+ {
+ "exception": "Redeem.output unspendable if larger than 3600 bytes",
+ "arguments": {
+ "redeem": {
+ "output": "02dfec67b1047f5ee7fcfc470565e07ce346fb89013f8e56b9e48a9af572f6cc9e OP_CHECKSIGVERIFY 034896ca85df092ac577480101193980c02b96a01533e7096858e696789c55b032 OP_CHECKSIGVERIFY 03365a5bd77cb355a5edefe0b47b64adf466d37c826c42332c8ea3bd2cb0fd2c0f OP_CHECKSIGVERIFY 0206c24e25bc5048bbb4723d701532db94366aa12bd080a8cf2cd35b41ea16b7e2 OP_CHECKSIGVERIFY 02e55fb5431a1c654cce06255befb4232600a94c4db57b4ab218a4ce04259c1145 OP_CHECKSIGVERIFY 02b4af93ac624e0f45e8577d828d0de343c595b9328958005baf6ab21a650ad39a OP_CHECKSIGVERIFY 03311744aa2a0d9b0af1c10f2eb4f4dd98b672fd61a575720298f334ebff3633fb OP_CHECKSIGVERIFY 0355b2ca92e66c250fafd45f3177b4a0fb48befc8b5911a37cdf3de5acc23b6e48 OP_CHECKSIGVERIFY 023e24b1d99ee02f08451af9e7e5d08db66db3e4ba04238bb4a484fc1bd66e4b89 OP_CHECKSIGVERIFY 03e0ece48ceb3c3bb566acbfda433662d2ce14f0b23bda0d0f065c5e0589ec8f1d OP_CHECKSIGVERIFY 02426aed062674081fe6e71ed130fc9b29329cef01204fe26b5ace638648b8d846 OP_CHECKSIGVERIFY 022960bc5bb274d8c963dbe6f77ef2cf59644f93f2dc3bf0d0036903656deaf0f3 OP_CHECKSIGVERIFY 03460e475689d3222710af5d3b8079bad3a12b248f61b300657b026c44c2b392b2 OP_CHECKSIGVERIFY 029d23671b573cbfb6272f5d197bbb88afa8fda9947affb5686c16a3e1f7592bb4 OP_CHECKSIGVERIFY 038bd4adeddfe560f8d9b1d1b7fc655c74fe605de09195c3f71e2fb8f68ecc4ca0 OP_CHECKSIGVERIFY 03a531c8795353c2a10f0e1619db468e5a87fd3303091662193c2701cfc1b1c4b0 OP_CHECKSIGVERIFY 02900a11b6b8ccc281dd7f1ab84b18358bfe2fef972967f0ca0ff1c71c5c72a8cb OP_CHECKSIGVERIFY 025e8d845e3f4d0d3afccb9c3a8368ccdcac14ff56b20706f534d7f81655715605 OP_CHECKSIGVERIFY 02646cce7f0159537815819139aad2e6d33f4398f8f502a0391491c7bf25bca4de OP_CHECKSIGVERIFY 03e852e9b853a26d7199a8772382bec56b9da7478b8037112c7d16d80d7c683568 OP_CHECKSIGVERIFY 0308d04709baf88bc6f5670d57c332ca872a8707207f3a5a59272940eb9ebc2936 OP_CHECKSIGVERIFY 0393cf1028583df1323f3b712edeb68078d412fabd1e5ccde839a500ddf506885a OP_CHECKSIGVERIFY 020edb22b296434cfe44b51f8dfc33579dd587e57a5f147470564ba9f817a586c8 OP_CHECKSIGVERIFY 0233de8260c26cba2851efc0ca2f695c37008929a2dc9244298c1990b36990083a OP_CHECKSIGVERIFY 02bcae3f6aecfd066ca029dfc833fc5f9f799760ab4baed6ef8c5ff94c002a7bc6 OP_CHECKSIGVERIFY 0285bb427b63bc8ed0890132d91a9283c7b82aa3f6d7fa7b3b27a74e7ffa41373c OP_CHECKSIGVERIFY 024e4c4f5ad562855256ba6380aba4bc93d7699939ace07c7c53fbecce044836c1 OP_CHECKSIGVERIFY 030895c63aebb5ce9e1ea2b3f30ebfd23f55fed7698757c1ec03154f1d581f0531 OP_CHECKSIGVERIFY 02070a7d5b57bf8c67ba34ed35108ba26579dbb84703c043886641e6482be0ae4a OP_CHECKSIGVERIFY 029c6ce3700ffe9b47b008c4cd849d4cd6ed1264eedebc0a4e1165dcbf5db503c6 OP_CHECKSIGVERIFY 02b1aa852b32f35e73a6aa070db64bc70329ec34f3ec13081b3859d45bb19e83b9 OP_CHECKSIGVERIFY 0375b9b9b287208cc57e49e15511f2c853bbb5562ed9fdd7b35e561d7e429018fc OP_CHECKSIGVERIFY 0355b3f1730e8eee06687bc128a86e3724dbe4da8a26fd3bfa54482ca25b247a99 OP_CHECKSIGVERIFY 03e9960ff1268abaff7190ba9f34f480b1279a6a52f96608313324c79214287bd1 OP_CHECKSIGVERIFY 036c8755595e5f3cfe45585237cbbec13737c9dab16ef90feca4b59cc20a3a5535 OP_CHECKSIGVERIFY 0228adcffece12cc99217f1d763aac469754fe3e49894a16a813443e29532e9651 OP_CHECKSIGVERIFY 03a0ea1dc9043e2f67450bb8ddccaa3af31964077a25b2baef62099fe0515fbd21 OP_CHECKSIGVERIFY 037de9ef6bee93474f6e02e377721543f8f4684e7074b45584fd751881aee96cf7 OP_CHECKSIGVERIFY 032874661d4c3802ad9913852a0271cb45cc90d981e662d831bd5290f2d6fe138d OP_CHECKSIGVERIFY 03e9242d1c7ed3ba76f8eba3e2fb4c5d33d667425222b95407de9209790e1b4bd3 OP_CHECKSIGVERIFY 02473773327552dc9f3652b513c68e133cc4d39202b348bbed359bc7b00f91bade OP_CHECKSIGVERIFY 03cebb99348541461de36106a68b0c7063bd4321021a21afbe90fa05d90a3444f0 OP_CHECKSIGVERIFY 03544a4accbdebb1bc0c62dfd3055dea9bd3c610c161a10afd53b4646d736a17db OP_CHECKSIGVERIFY 02baa91fc638c57fff9211334dc9c98b9937d75b7c534bdaeefcdeb56ca8f997e3 OP_CHECKSIGVERIFY 03bd8ea1948d869143f1fc0604ec8b54c95dd6cfc6cce11800bbe82b92ae9b5b74 OP_CHECKSIGVERIFY 0319ab36ae3727162c6699d6cfa76389a49d06a4bd4d4dad47606f8deec0376e75 OP_CHECKSIGVERIFY 0293003a1bca4ad83ac3bf5a2224ef782c8d7290f4f492e3588e644ffe02b3b35a OP_CHECKSIGVERIFY 0395248d8852d32e11f3288fa4f39a36fcc8225da9289fc3d0ad65f409821c4e17 OP_CHECKSIGVERIFY 02e3bee6809b08ab3b9fdbb4a7fcaa64cb602fdae173c6ce1c4042ca36f60e90fd OP_CHECKSIGVERIFY 034b74d1136c5422239d8c4a869e6cff7985204d9dedb2c3cca0b0b9afd589a35f OP_CHECKSIGVERIFY 0318e3f8941cf82c788d5dce82256bfe9522dd87f63a467e01c5004fec6667f0fe OP_CHECKSIGVERIFY 023fcda99ba2c461c65a3d95d03ab251d29ae9bd7b4d90a485aa6d075e35460e93 OP_CHECKSIGVERIFY 0329f7b047301f8f29725a9dd93e4742460e54b4c2ac9c08cfa9c4cd6a5e14a4ed OP_CHECKSIGVERIFY 0343a0c3f0fbbfd4ed0d1677c1a0cb3bb2a59dfcecdbc4af4386a6542cf349f437 OP_CHECKSIGVERIFY 02eae41bb436873f562629380ffdaf0fe5353cb5be07bd95343adf32ee984ef0ce OP_CHECKSIGVERIFY 02d71aa051ea95ba899d3e721f12a8ede4aebdd265a2ff31081128033bdd66befc OP_CHECKSIGVERIFY 029faa4411b3bc3a2778d6d3236396d2a81afefc792d07909e212de58e0765fa07 OP_CHECKSIGVERIFY 03eb3b7d5a44fcc754383ceca274a250b9a48a348ef166fad19981d5f37781d5dc OP_CHECKSIGVERIFY 03f3ccef99da37185f238f7643b7ff553e4f62fa376cf1852a49cd80cd856e444b OP_CHECKSIGVERIFY 03ba7b6f4ea978f9c5277c97d733ae0a2f55062555997971d6ed4b37d399b4f130 OP_CHECKSIGVERIFY 0217209004fa5e8b2277767caeac19a9c26c71655c917cf61aad6817f0717fcba0 OP_CHECKSIGVERIFY 0363f2e57f2ea1a49a39ed0542e1fdbc83e2d2317a2d29b058c7d82233f3c54e8a OP_CHECKSIGVERIFY 03dfd044cc08b325121055155e90f2955771f33f0e4d5462967dbeae431ac34e4b OP_CHECKSIGVERIFY 02aa29194b8666b1526b32e7b54cebe8305637837c7821399577ee95cf7bca6a36 OP_CHECKSIGVERIFY 02e11f095aa2730bfa6ab6a6d088d015e92204a70ad36c5fe6a6a97cf4be8fdc34 OP_CHECKSIGVERIFY 02d8a0b231ca61468d86abd8bf5169bd231243a4f75184f64a6946abb8eee17b9b OP_CHECKSIGVERIFY 034653d87fbdc8cff324a5f6e3220150749cff56f39f1bb378ae73301c15caca05 OP_CHECKSIGVERIFY 02b0e8830c020a01c31d8d211708ad1d04e7309bb584b8489d35fbcf12c09c84eb OP_CHECKSIGVERIFY 030b94559a4b54fc895f861bb2b5669736a709994ade45b08f9f6148ef25dc4eca OP_CHECKSIGVERIFY 02c1d4e3bd6651e273030a6d1f436a2455fa51b50390ba045c5e78bbef03eeb78f OP_CHECKSIGVERIFY 02b7d7f60abf61f50bcbaa0435f9a31a231b8f26def0f172578d0838091f7906eb OP_CHECKSIGVERIFY 02d410fbd6d899b21c3f6d380aeafea56a2e4e0e3b70f46734a716134fee793054 OP_CHECKSIGVERIFY 02bac3d71349f3dd83bc59c15c661d1520f43475f5fc0c38698b37de978419248b OP_CHECKSIGVERIFY 0277b4f24cc552577374909a853c1d570404e9072368d48310ed3ee597c9579e9d OP_CHECKSIGVERIFY 037ab3bd19731038c03bf4eec27e4e4788a8634b52c41e364dea45130b3ac8874b OP_CHECKSIGVERIFY 03102af5eb78a65b542b878e4e3eaa29f83f2efdae8838afe75cf2f85017b3f683 OP_CHECKSIGVERIFY 02452e8e88d61c0b206b9e4a319dc262662f4f98a5737e13b7abe2ceeae2bb8dcf OP_CHECKSIGVERIFY 0360d3d51bef5d6c5932e61b2ab44c7eea23a2d03cfed2422656ed1c873286a8e1 OP_CHECKSIGVERIFY 021eadd72a30b0ff9c2bc0f0b2815352fc789b85bf958ba36bde39092967968094 OP_CHECKSIGVERIFY 02631804ca57f694c27885d2d8c5e31e1f3b741a23d8c2e95a1ccd9ac8392c3c25 OP_CHECKSIGVERIFY 021ec0824b1594998ff91ddd2a7b53099ba60de84d447b13fddebf34533d111a3e OP_CHECKSIGVERIFY 039b386361ac56bd2b73186b66b77cb6de2fffbe05326dd2abf23d6b9d26b629ea OP_CHECKSIGVERIFY 0262efb44256f6ae1f1965aa24b57847e13f80a4283cb44a257572993845439a0e OP_CHECKSIGVERIFY 0283f818f966acc4894b54197eb7e94221851acfb6c986a7862ad86f961ab50a57 OP_CHECKSIGVERIFY 03a418b8eb7da20d694e257de6a9fc493676e1f98fef9f8165f69cd8d0f8099439 OP_CHECKSIGVERIFY 03697922030495b328ea3c101a1852ffd7818aa10fbedaf6c3a88b6fa381694d4b OP_CHECKSIGVERIFY 0266a13940d79ce8a272da6094df36875fd9c337c83d4ef491e0fa2a47ab3ffc57 OP_CHECKSIGVERIFY 03747ae0c8012281475a00085795b8bb0d595ebf2322f57ebd7c6b1edbbab56f92 OP_CHECKSIGVERIFY 02e357b1c82274aea4357e36278f912338e3adf1c17d8829edf394a1cc2bedc185 OP_CHECKSIGVERIFY 02dcc75706face7293b47b2e60af164971f9920118986ebf5ea147d077722e316f OP_CHECKSIGVERIFY 0347cdc7f774f1291bc45c7cb1d86eb7ea66a24622e387ccc7ac580b750f1ad9c3 OP_CHECKSIGVERIFY 02e650efb11ecd8ab320b3e5bec0d5852db1cddc1d67ede952f3c042f90dae1e43 OP_CHECKSIGVERIFY 039c24916f37a11398d4186a634414ea371003595e6444c92d01ace02bab5267ea OP_CHECKSIGVERIFY 038a5dbb9595503741fafe92f60187bfb2aad442dda5f9e6c17e5be6ec4b5521aa OP_CHECKSIGVERIFY 0291909a41d7114fc99e81224e37c030efc0c73b33e6b0eedcd8a53bfee276f108 OP_CHECKSIGVERIFY 02da51f2cc61ba9522869d2f9a34a21288cc8d017e4cf0060c85f2fff3ceacaf28 OP_CHECKSIGVERIFY 03237812d3a5ec0c49d8a60b15c2ac676cffc7eabf459dc9ef0ae215a1cbd26bb7 OP_CHECKSIGVERIFY 020e33b6b74b7f7190b0966b4f295199244ed33cea6e324c2f39a227486d87e059 OP_CHECKSIGVERIFY 02d2c96fd98d5da619ef2033892026b7f7595fd03667ab1f0b39a59d2e45a58c98 OP_CHECKSIGVERIFY 03df7ed4e582c8997b3a4c1138fac76144c02a052c7ac2c40e4e34d50e308efb42 OP_CHECKSIGVERIFY 028f343af70f46773a48bd8fcbeeb34a15f3cfee8427b62750006da2ae8a0745fc OP_CHECKSIGVERIFY 027e2f0c4f3d8d90ea0b426c82a6d41226e7b7c579724302034f844fde9a34bf96 OP_CHECKSIGVERIFY 03abdfa8a173a9be3a2669346430dcf5cbf5e2bb2321392bd661b9fa88be82677b OP_CHECKSIG"
+ }
+ }
+ },
{
"exception": "Non push-only scriptSig",
"arguments": {
diff --git a/ts_src/payments/p2sh.ts b/ts_src/payments/p2sh.ts
index 272d094a3..67e5f38dd 100644
--- a/ts_src/payments/p2sh.ts
+++ b/ts_src/payments/p2sh.ts
@@ -159,6 +159,14 @@ export function p2sh(a: Payment, opts?: PaymentOpts): Payment {
const decompile = bscript.decompile(redeem.output);
if (!decompile || decompile.length < 1)
throw new TypeError('Redeem.output too short');
+ if (redeem.output.byteLength > 520)
+ throw new TypeError(
+ 'Redeem.output unspendable if larger than 520 bytes',
+ );
+ if (bscript.countNonPushOnlyOPs(decompile) > 201)
+ throw new TypeError(
+ 'Redeem.output unspendable with more than 201 non-push ops',
+ );
// match hash against other sources
const hash2 = bcrypto.hash160(redeem.output);
diff --git a/ts_src/payments/p2wsh.ts b/ts_src/payments/p2wsh.ts
index 00860e0b9..1ba384924 100644
--- a/ts_src/payments/p2wsh.ts
+++ b/ts_src/payments/p2wsh.ts
@@ -180,10 +180,19 @@ export function p2wsh(a: Payment, opts?: PaymentOpts): Payment {
)
throw new TypeError('Ambiguous witness source');
- // is the redeem output non-empty?
+ // is the redeem output non-empty/valid?
if (a.redeem.output) {
- if (bscript.decompile(a.redeem.output)!.length === 0)
+ const decompile = bscript.decompile(a.redeem.output);
+ if (!decompile || decompile.length < 1)
throw new TypeError('Redeem.output is invalid');
+ if (a.redeem.output.byteLength > 3600)
+ throw new TypeError(
+ 'Redeem.output unspendable if larger than 3600 bytes',
+ );
+ if (bscript.countNonPushOnlyOPs(decompile) > 201)
+ throw new TypeError(
+ 'Redeem.output unspendable with more than 201 non-push ops',
+ );
// match hash against other sources
const hash2 = bcrypto.sha256(a.redeem.output);
diff --git a/ts_src/script.ts b/ts_src/script.ts
index ca2c557f5..4f246fe7a 100644
--- a/ts_src/script.ts
+++ b/ts_src/script.ts
@@ -27,6 +27,10 @@ export function isPushOnly(value: Stack): boolean {
return types.Array(value) && value.every(isPushOnlyChunk);
}
+export function countNonPushOnlyOPs(value: Stack): number {
+ return value.length - value.filter(isPushOnlyChunk).length;
+}
+
function asMinimalOP(buffer: Buffer): number | void {
if (buffer.length === 0) return OPS.OP_0;
if (buffer.length !== 1) return;
From 8bb53b40b2a22e6af400a7c4da8c610965690357 Mon Sep 17 00:00:00 2001
From: Hyunhum Cho
Date: Fri, 3 Feb 2023 14:58:55 +0900
Subject: [PATCH 108/144] Add new Taproot example
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index a8de46778..e1d7af69f 100644
--- a/README.md
+++ b/README.md
@@ -104,6 +104,7 @@ Otherwise, pull requests are appreciated.
Some examples interact (via HTTPS) with a 3rd Party Blockchain Provider (3PBP).
+- [Taproot Key Spend](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/taproot.spec.ts)
- [Generate a random address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.spec.ts)
- [Import an address via WIF](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.spec.ts)
- [Generate a 2-of-3 P2SH multisig address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.spec.ts)
From 35634ceee62d3523620232c106f6096fc58182cf Mon Sep 17 00:00:00 2001
From: Hyunhum Cho
Date: Thu, 9 Feb 2023 11:41:36 +0900
Subject: [PATCH 109/144] "feat: remove privateAdd & privateNegate for
tinysecp256k1"
---
ts_src/types.ts | 2 --
1 file changed, 2 deletions(-)
diff --git a/ts_src/types.ts b/ts_src/types.ts
index d4f4ac774..2457ec240 100644
--- a/ts_src/types.ts
+++ b/ts_src/types.ts
@@ -105,8 +105,6 @@ export interface TinySecp256k1Interface {
p: Uint8Array,
tweak: Uint8Array,
): XOnlyPointAddTweakResult | null;
- privateAdd(d: Uint8Array, tweak: Uint8Array): Uint8Array | null;
- privateNegate(d: Uint8Array): Uint8Array;
}
export const Buffer256bit = typeforce.BufferN(32);
From ac3f01b773a58885f0041d56ba4327b0ac4ca098 Mon Sep 17 00:00:00 2001
From: Hyunhum Cho
Date: Thu, 9 Feb 2023 11:43:37 +0900
Subject: [PATCH 110/144] "feat: remove privateAdd & privateNegate in
tinysecp256k1 declaration"
---
src/types.d.ts | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/types.d.ts b/src/types.d.ts
index 035d73efc..0b8a02f9c 100644
--- a/src/types.d.ts
+++ b/src/types.d.ts
@@ -30,8 +30,6 @@ export declare function isTaptree(scriptTree: any): scriptTree is Taptree;
export interface TinySecp256k1Interface {
isXOnlyPoint(p: Uint8Array): boolean;
xOnlyPointAddTweak(p: Uint8Array, tweak: Uint8Array): XOnlyPointAddTweakResult | null;
- privateAdd(d: Uint8Array, tweak: Uint8Array): Uint8Array | null;
- privateNegate(d: Uint8Array): Uint8Array;
}
export declare const Buffer256bit: any;
export declare const Hash160bit: any;
From f1a4b9d55526c756da99381b01581a0e114ec633 Mon Sep 17 00:00:00 2001
From: junderw
Date: Tue, 14 Feb 2023 18:10:03 -0700
Subject: [PATCH 111/144] Add example using BIP86 vector to verify the sending
to and from a BIP86 generated taproot address
---
test/integration/taproot.spec.ts | 74 ++++++++++++++++++++++++++++++++
1 file changed, 74 insertions(+)
diff --git a/test/integration/taproot.spec.ts b/test/integration/taproot.spec.ts
index ec870b761..550a34608 100644
--- a/test/integration/taproot.spec.ts
+++ b/test/integration/taproot.spec.ts
@@ -1,4 +1,6 @@
+import * as assert from 'assert';
import BIP32Factory from 'bip32';
+import * as bip39 from 'bip39';
import ECPairFactory from 'ecpair';
import * as ecc from 'tiny-secp256k1';
import { describe, it } from 'mocha';
@@ -17,6 +19,78 @@ const bip32 = BIP32Factory(ecc);
const ECPair = ECPairFactory(ecc);
describe('bitcoinjs-lib (transaction with taproot)', () => {
+ it('can verify the BIP86 HD wallet vectors for taproot single sig (& sending example)', async () => {
+ // Values taken from BIP86 document
+ const mnemonic =
+ 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about';
+ const xprv =
+ 'xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu';
+ const path = `m/86'/0'/0'/0/0`; // Path to first child of receiving wallet on first account
+ const internalPubkey = Buffer.from(
+ 'cc8a4bc64d897bddc5fbc2f670f7a8ba0b386779106cf1223c6fc5d7cd6fc115',
+ 'hex',
+ );
+ const expectedAddress =
+ 'bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr';
+
+ // Verify the above (Below is no different than other HD wallets)
+ const seed = await bip39.mnemonicToSeed(mnemonic);
+ const rootKey = bip32.fromSeed(seed);
+ assert.strictEqual(rootKey.toBase58(), xprv);
+ const childNode = rootKey.derivePath(path);
+ // Since internalKey is an xOnly pubkey, we drop the DER header byte
+ const childNodeXOnlyPubkey = childNode.publicKey.slice(1, 33);
+ assert.deepEqual(childNodeXOnlyPubkey, internalPubkey);
+
+ // This is new for taproot
+ // Note: we are using mainnet here to get the correct address
+ // The output is the same no matter what the network is.
+ const { address, output } = bitcoin.payments.p2tr({
+ internalPubkey,
+ });
+ assert(output);
+ assert.strictEqual(address, expectedAddress);
+ // Used for signing, since the output and address are using a tweaked key
+ // We must tweak the signer in the same way.
+ const tweakedChildNode = childNode.tweak(
+ bitcoin.crypto.taggedHash('TapTweak', childNodeXOnlyPubkey),
+ );
+
+ // amount from faucet
+ const amount = 42e4;
+ // amount to send
+ const sendAmount = amount - 1e4;
+ // Send some sats to the address via faucet. Get the hash and index. (txid/vout)
+ const { txId: hash, vout: index } = await regtestUtils.faucetComplex(
+ output,
+ amount,
+ );
+ // Sent 420000 sats to taproot address
+
+ const psbt = new bitcoin.Psbt({ network: regtest })
+ .addInput({
+ hash,
+ index,
+ witnessUtxo: { value: amount, script: output },
+ tapInternalKey: childNodeXOnlyPubkey,
+ })
+ .addOutput({
+ value: sendAmount,
+ address: regtestUtils.RANDOM_ADDRESS,
+ })
+ .signInput(0, tweakedChildNode)
+ .finalizeAllInputs();
+
+ const tx = psbt.extractTransaction();
+ await regtestUtils.broadcast(tx.toHex());
+ await regtestUtils.verify({
+ txId: tx.getId(),
+ address: regtestUtils.RANDOM_ADDRESS,
+ vout: 0,
+ value: sendAmount,
+ });
+ });
+
it('can create (and broadcast via 3PBP) a taproot key-path spend Transaction', async () => {
const internalKey = bip32.fromSeed(rng(64), regtest);
const p2pkhKey = bip32.fromSeed(rng(64), regtest);
From 8c504c423ba81c16afaaf236a103318e6b3adc5b Mon Sep 17 00:00:00 2001
From: Paul Miller
Date: Fri, 17 Feb 2023 20:43:17 +0000
Subject: [PATCH 112/144] Switch from create-hash, ripemd160 to noble-hashes
---
package-lock.json | 57 ++++++++++++++---------------------------------
package.json | 5 +----
src/crypto.js | 27 ++++++++++------------
ts_src/crypto.ts | 23 +++++++------------
4 files changed, 38 insertions(+), 74 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 1007efae0..0ce902e7f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,11 +9,10 @@
"version": "6.1.0",
"license": "MIT",
"dependencies": {
+ "@noble/hashes": "^1.2.0",
"bech32": "^2.0.0",
"bip174": "^2.1.0",
"bs58check": "^2.1.2",
- "create-hash": "^1.1.0",
- "ripemd160": "^2.0.2",
"typeforce": "^1.11.3",
"varuint-bitcoin": "^1.1.2",
"wif": "^2.0.1"
@@ -21,12 +20,10 @@
"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/ripemd160": "^2.0.0",
"@types/wif": "^2.0.2",
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
@@ -682,6 +679,17 @@
"@jridgewell/sourcemap-codec": "1.4.14"
}
},
+ "node_modules/@noble/hashes": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz",
+ "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ ]
+ },
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -735,15 +743,6 @@
"@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/json-schema": {
"version": "7.0.11",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
@@ -777,15 +776,6 @@
"@types/node": "*"
}
},
- "node_modules/@types/ripemd160": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/@types/ripemd160/-/ripemd160-2.0.0.tgz",
- "integrity": "sha512-LD6AO/+8cAa1ghXax9NG9iPDLPUEGB2WWPjd//04KYfXxTwHvlDEfL0NRjrM5z9XWBi6WbKw75Are0rDyn3PSA==",
- "dev": true,
- "dependencies": {
- "@types/node": "*"
- }
- },
"node_modules/@types/semver": {
"version": "7.3.13",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
@@ -4934,6 +4924,11 @@
"@jridgewell/sourcemap-codec": "1.4.14"
}
},
+ "@noble/hashes": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz",
+ "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ=="
+ },
"@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -4978,15 +4973,6 @@
"@types/node": "*"
}
},
- "@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,
- "requires": {
- "@types/node": "*"
- }
- },
"@types/json-schema": {
"version": "7.0.11",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
@@ -5020,15 +5006,6 @@
"@types/node": "*"
}
},
- "@types/ripemd160": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/@types/ripemd160/-/ripemd160-2.0.0.tgz",
- "integrity": "sha512-LD6AO/+8cAa1ghXax9NG9iPDLPUEGB2WWPjd//04KYfXxTwHvlDEfL0NRjrM5z9XWBi6WbKw75Are0rDyn3PSA==",
- "dev": true,
- "requires": {
- "@types/node": "*"
- }
- },
"@types/semver": {
"version": "7.3.13",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
diff --git a/package.json b/package.json
index b973d3d3f..6194306c3 100644
--- a/package.json
+++ b/package.json
@@ -49,11 +49,10 @@
"src"
],
"dependencies": {
+ "@noble/hashes": "^1.2.0",
"bech32": "^2.0.0",
"bip174": "^2.1.0",
"bs58check": "^2.1.2",
- "create-hash": "^1.1.0",
- "ripemd160": "^2.0.2",
"typeforce": "^1.11.3",
"varuint-bitcoin": "^1.1.2",
"wif": "^2.0.1"
@@ -61,12 +60,10 @@
"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/ripemd160": "^2.0.0",
"@types/wif": "^2.0.2",
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
diff --git a/src/crypto.js b/src/crypto.js
index 25f71bad2..af1224d25 100644
--- a/src/crypto.js
+++ b/src/crypto.js
@@ -9,34 +9,31 @@ exports.taggedHash =
exports.sha1 =
exports.ripemd160 =
void 0;
-const createHash = require('create-hash');
-const RipeMd160 = require('ripemd160');
+const ripemd160_1 = require('@noble/hashes/ripemd160');
+const sha1_1 = require('@noble/hashes/sha1');
+const sha256_1 = require('@noble/hashes/sha256');
function ripemd160(buffer) {
- try {
- return createHash('rmd160').update(buffer).digest();
- } catch (err) {
- try {
- return createHash('ripemd160').update(buffer).digest();
- } catch (err2) {
- return new RipeMd160().update(buffer).digest();
- }
- }
+ return Buffer.from((0, ripemd160_1.ripemd160)(Uint8Array.from(buffer)));
}
exports.ripemd160 = ripemd160;
function sha1(buffer) {
- return createHash('sha1').update(buffer).digest();
+ return Buffer.from((0, sha1_1.sha1)(Uint8Array.from(buffer)));
}
exports.sha1 = sha1;
function sha256(buffer) {
- return createHash('sha256').update(buffer).digest();
+ return Buffer.from((0, sha256_1.sha256)(Uint8Array.from(buffer)));
}
exports.sha256 = sha256;
function hash160(buffer) {
- return ripemd160(sha256(buffer));
+ return Buffer.from(
+ (0, ripemd160_1.ripemd160)((0, sha256_1.sha256)(Uint8Array.from(buffer))),
+ );
}
exports.hash160 = hash160;
function hash256(buffer) {
- return sha256(sha256(buffer));
+ return Buffer.from(
+ (0, sha256_1.sha256)((0, sha256_1.sha256)(Uint8Array.from(buffer))),
+ );
}
exports.hash256 = hash256;
exports.TAGS = [
diff --git a/ts_src/crypto.ts b/ts_src/crypto.ts
index 686cdcd9e..e3b876961 100644
--- a/ts_src/crypto.ts
+++ b/ts_src/crypto.ts
@@ -1,32 +1,25 @@
-import * as createHash from 'create-hash';
-import * as RipeMd160 from 'ripemd160';
+import { ripemd160 as _ripemd160 } from '@noble/hashes/ripemd160';
+import { sha1 as _sha1 } from '@noble/hashes/sha1';
+import { sha256 as _sha256 } from '@noble/hashes/sha256';
export function ripemd160(buffer: Buffer): Buffer {
- try {
- return createHash('rmd160').update(buffer).digest();
- } catch (err) {
- try {
- return createHash('ripemd160').update(buffer).digest();
- } catch (err2) {
- return new RipeMd160().update(buffer).digest();
- }
- }
+ return Buffer.from(_ripemd160(Uint8Array.from(buffer)));
}
export function sha1(buffer: Buffer): Buffer {
- return createHash('sha1').update(buffer).digest();
+ return Buffer.from(_sha1(Uint8Array.from(buffer)));
}
export function sha256(buffer: Buffer): Buffer {
- return createHash('sha256').update(buffer).digest();
+ return Buffer.from(_sha256(Uint8Array.from(buffer)));
}
export function hash160(buffer: Buffer): Buffer {
- return ripemd160(sha256(buffer));
+ return Buffer.from(_ripemd160(_sha256(Uint8Array.from(buffer))));
}
export function hash256(buffer: Buffer): Buffer {
- return sha256(sha256(buffer));
+ return Buffer.from(_sha256(_sha256(Uint8Array.from(buffer))));
}
export const TAGS = [
From adc8a33a19091c19bc552d02bb98f1d6f52bb971 Mon Sep 17 00:00:00 2001
From: jafri
Date: Mon, 20 Feb 2023 22:17:39 -0700
Subject: [PATCH 113/144] Handle custom signature hash type - sig length
---
src/payments/p2tr.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index d2cbc02a8..df31662cc 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -31,7 +31,7 @@ function p2tr(a, opts) {
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)),
+ signature: types_1.typeforce.maybe(types_1.typeforce.anyOf[types_1.typeforce.BufferN(64), types_1.typeforce.BufferN(65)]),
witness: types_1.typeforce.maybe(
types_1.typeforce.arrayOf(types_1.typeforce.Buffer),
),
From 599f16b7e3811981dc71dca492d9a55f7fd2f900 Mon Sep 17 00:00:00 2001
From: jafri
Date: Mon, 20 Feb 2023 22:57:48 -0700
Subject: [PATCH 114/144] Fix format
---
src/payments/p2tr.js | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index df31662cc..e39c6aaf7 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -31,7 +31,11 @@ function p2tr(a, opts) {
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.anyOf[types_1.typeforce.BufferN(64), types_1.typeforce.BufferN(65)]),
+ signature: types_1.typeforce.maybe(
+ types_1.typeforce.anyOf[
+ (types_1.typeforce.BufferN(64), types_1.typeforce.BufferN(65))
+ ],
+ ),
witness: types_1.typeforce.maybe(
types_1.typeforce.arrayOf(types_1.typeforce.Buffer),
),
From d28e9dd7a67fd839b71eb0ceb0217a9c72070ce0 Mon Sep 17 00:00:00 2001
From: jafri
Date: Tue, 21 Feb 2023 02:55:18 -0700
Subject: [PATCH 115/144] add .ts
---
ts_src/payments/p2tr.ts | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index 231a263fc..54d1e13cc 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -40,7 +40,9 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
internalPubkey: typef.maybe(typef.BufferN(32)),
hash: typef.maybe(typef.BufferN(32)), // merkle root hash, the tweak
pubkey: typef.maybe(typef.BufferN(32)), // tweaked with `hash` from `internalPubkey`
- signature: typef.maybe(typef.BufferN(64)),
+ signature: typef.maybe(
+ typef.anyOf[(typef.BufferN(64), typef.BufferN(65))],
+ ),
witness: typef.maybe(typef.arrayOf(typef.Buffer)),
scriptTree: typef.maybe(isTaptree),
redeem: typef.maybe({
From 9bf12190b0ed2f4f2d0500709e71c42e275aeb11 Mon Sep 17 00:00:00 2001
From: jafri
Date: Tue, 21 Feb 2023 12:44:35 -0700
Subject: [PATCH 116/144] fix tests
---
src/payments/p2tr.js | 7 ++++---
ts_src/payments/p2tr.ts | 4 +---
2 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/src/payments/p2tr.js b/src/payments/p2tr.js
index e39c6aaf7..83080b434 100644
--- a/src/payments/p2tr.js
+++ b/src/payments/p2tr.js
@@ -32,9 +32,10 @@ function p2tr(a, opts) {
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.anyOf[
- (types_1.typeforce.BufferN(64), types_1.typeforce.BufferN(65))
- ],
+ types_1.typeforce.anyOf(
+ types_1.typeforce.BufferN(64),
+ types_1.typeforce.BufferN(65),
+ ),
),
witness: types_1.typeforce.maybe(
types_1.typeforce.arrayOf(types_1.typeforce.Buffer),
diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts
index 54d1e13cc..53f1b40f9 100644
--- a/ts_src/payments/p2tr.ts
+++ b/ts_src/payments/p2tr.ts
@@ -40,9 +40,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment {
internalPubkey: typef.maybe(typef.BufferN(32)),
hash: typef.maybe(typef.BufferN(32)), // merkle root hash, the tweak
pubkey: typef.maybe(typef.BufferN(32)), // tweaked with `hash` from `internalPubkey`
- signature: typef.maybe(
- typef.anyOf[(typef.BufferN(64), typef.BufferN(65))],
- ),
+ signature: typef.maybe(typef.anyOf(typef.BufferN(64), typef.BufferN(65))),
witness: typef.maybe(typef.arrayOf(typef.Buffer)),
scriptTree: typef.maybe(isTaptree),
redeem: typef.maybe({
From 7be0c0bf992b0d301e901ef88325d8a1b5ca0a49 Mon Sep 17 00:00:00 2001
From: Paul Miller
Date: Sat, 25 Feb 2023 08:35:15 +0000
Subject: [PATCH 117/144] Bump bip32, bip39
---
package-lock.json | 249 ++++++++++++++++++++++++----------------------
package.json | 6 +-
2 files changed, 132 insertions(+), 123 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 0ce902e7f..b042e30fb 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,7 +12,7 @@
"@noble/hashes": "^1.2.0",
"bech32": "^2.0.0",
"bip174": "^2.1.0",
- "bs58check": "^2.1.2",
+ "bs58check": "^3.0.1",
"typeforce": "^1.11.3",
"varuint-bitcoin": "^1.1.2",
"wif": "^2.0.1"
@@ -28,8 +28,8 @@
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
"better-npm-audit": "^3.7.3",
- "bip32": "^3.0.1",
- "bip39": "^3.0.2",
+ "bip32": "^4.0.0",
+ "bip39": "^3.1.0",
"bip65": "^1.0.1",
"bip68": "^1.0.3",
"bs58": "^4.0.0",
@@ -725,6 +725,18 @@
"node": ">= 8"
}
},
+ "node_modules/@scure/base": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz",
+ "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ ]
+ },
"node_modules/@types/bs58": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@types/bs58/-/bs58-4.0.1.tgz",
@@ -1177,15 +1189,13 @@
}
},
"node_modules/bip32": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/bip32/-/bip32-3.1.0.tgz",
- "integrity": "sha512-eoeajYEzJ4d6yyVtby8C+XkCeKItiC4Mx56a0M9VaqTMC73SWOm4xVZG7SaR8e/yp4eSyky2XcBpH3DApPdu7Q==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/bip32/-/bip32-4.0.0.tgz",
+ "integrity": "sha512-aOGy88DDlVUhspIXJN+dVEtclhIsfAUppD43V0j40cPTld3pv/0X/MlrZSZ6jowIaQQzFwP8M6rFU2z2mVYjDQ==",
"dev": true,
"dependencies": {
- "bs58check": "^2.1.1",
- "create-hash": "^1.2.0",
- "create-hmac": "^1.1.7",
- "ripemd160": "^2.0.2",
+ "@noble/hashes": "^1.2.0",
+ "@scure/base": "^1.1.1",
"typeforce": "^1.11.5",
"wif": "^2.0.6"
},
@@ -1194,23 +1204,14 @@
}
},
"node_modules/bip39": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.4.tgz",
- "integrity": "sha512-YZKQlb752TrUWqHWj7XAwCSjYEgGAk+/Aas3V7NyjQeZYsztO8JnQUaCWhcnL4T+jL8nvB8typ2jRPzTlgugNw==",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.1.0.tgz",
+ "integrity": "sha512-c9kiwdk45Do5GL0vJMe7tS95VjCii65mYAH7DfWl3uW8AVzXKQVUm64i3hzVybBDMp9r7j9iNxR85+ul8MdN/A==",
"dev": true,
"dependencies": {
- "@types/node": "11.11.6",
- "create-hash": "^1.1.0",
- "pbkdf2": "^3.0.9",
- "randombytes": "^2.0.1"
+ "@noble/hashes": "^1.2.0"
}
},
- "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",
@@ -1300,13 +1301,25 @@
}
},
"node_modules/bs58check": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz",
- "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==",
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-3.0.1.tgz",
+ "integrity": "sha512-hjuuJvoWEybo7Hn/0xOrczQKKEKD63WguEjlhLExYs2wUBcebDC1jDNK17eEAD2lYfw82d5ASC1d7K3SWszjaQ==",
"dependencies": {
- "bs58": "^4.0.0",
- "create-hash": "^1.1.0",
- "safe-buffer": "^5.1.2"
+ "@noble/hashes": "^1.2.0",
+ "bs58": "^5.0.0"
+ }
+ },
+ "node_modules/bs58check/node_modules/base-x": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.0.tgz",
+ "integrity": "sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw=="
+ },
+ "node_modules/bs58check/node_modules/bs58": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz",
+ "integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==",
+ "dependencies": {
+ "base-x": "^4.0.0"
}
},
"node_modules/buffer-from": {
@@ -1505,20 +1518,6 @@
"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",
@@ -3370,22 +3369,6 @@
"node": ">=8"
}
},
- "node_modules/pbkdf2": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
- "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==",
- "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/picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
@@ -3575,9 +3558,9 @@
}
},
"node_modules/readable-stream": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
- "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "version": "3.6.1",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.1.tgz",
+ "integrity": "sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ==",
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
@@ -3622,6 +3605,17 @@
"randombytes": "^2.1.0"
}
},
+ "node_modules/regtest-client/node_modules/bs58check": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz",
+ "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==",
+ "dev": true,
+ "dependencies": {
+ "bs58": "^4.0.0",
+ "create-hash": "^1.1.0",
+ "safe-buffer": "^5.1.2"
+ }
+ },
"node_modules/release-zalgo": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz",
@@ -4289,6 +4283,16 @@
"bs58check": "<3.0.0"
}
},
+ "node_modules/wif/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/word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
@@ -4955,6 +4959,12 @@
"fastq": "^1.6.0"
}
},
+ "@scure/base": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz",
+ "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==",
+ "dev": true
+ },
"@types/bs58": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@types/bs58/-/bs58-4.0.1.tgz",
@@ -5267,37 +5277,24 @@
"integrity": "sha512-lkc0XyiX9E9KiVAS1ZiOqK1xfiwvf4FXDDdkDq5crcDzOq+xGytY+14qCsqz7kCiy8rpN1CRNfacRhf9G3JNSA=="
},
"bip32": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/bip32/-/bip32-3.1.0.tgz",
- "integrity": "sha512-eoeajYEzJ4d6yyVtby8C+XkCeKItiC4Mx56a0M9VaqTMC73SWOm4xVZG7SaR8e/yp4eSyky2XcBpH3DApPdu7Q==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/bip32/-/bip32-4.0.0.tgz",
+ "integrity": "sha512-aOGy88DDlVUhspIXJN+dVEtclhIsfAUppD43V0j40cPTld3pv/0X/MlrZSZ6jowIaQQzFwP8M6rFU2z2mVYjDQ==",
"dev": true,
"requires": {
- "bs58check": "^2.1.1",
- "create-hash": "^1.2.0",
- "create-hmac": "^1.1.7",
- "ripemd160": "^2.0.2",
+ "@noble/hashes": "^1.2.0",
+ "@scure/base": "^1.1.1",
"typeforce": "^1.11.5",
"wif": "^2.0.6"
}
},
"bip39": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.4.tgz",
- "integrity": "sha512-YZKQlb752TrUWqHWj7XAwCSjYEgGAk+/Aas3V7NyjQeZYsztO8JnQUaCWhcnL4T+jL8nvB8typ2jRPzTlgugNw==",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.1.0.tgz",
+ "integrity": "sha512-c9kiwdk45Do5GL0vJMe7tS95VjCii65mYAH7DfWl3uW8AVzXKQVUm64i3hzVybBDMp9r7j9iNxR85+ul8MdN/A==",
"dev": true,
"requires": {
- "@types/node": "11.11.6",
- "create-hash": "^1.1.0",
- "pbkdf2": "^3.0.9",
- "randombytes": "^2.0.1"
- },
- "dependencies": {
- "@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
- }
+ "@noble/hashes": "^1.2.0"
}
},
"bip65": {
@@ -5364,13 +5361,27 @@
}
},
"bs58check": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz",
- "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==",
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-3.0.1.tgz",
+ "integrity": "sha512-hjuuJvoWEybo7Hn/0xOrczQKKEKD63WguEjlhLExYs2wUBcebDC1jDNK17eEAD2lYfw82d5ASC1d7K3SWszjaQ==",
"requires": {
- "bs58": "^4.0.0",
- "create-hash": "^1.1.0",
- "safe-buffer": "^5.1.2"
+ "@noble/hashes": "^1.2.0",
+ "bs58": "^5.0.0"
+ },
+ "dependencies": {
+ "base-x": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.0.tgz",
+ "integrity": "sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw=="
+ },
+ "bs58": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz",
+ "integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==",
+ "requires": {
+ "base-x": "^4.0.0"
+ }
+ }
}
},
"buffer-from": {
@@ -5523,20 +5534,6 @@
"sha.js": "^2.4.0"
}
},
- "create-hmac": {
- "version": "1.1.7",
- "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
- "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
- "dev": true,
- "requires": {
- "cipher-base": "^1.0.3",
- "create-hash": "^1.1.0",
- "inherits": "^2.0.1",
- "ripemd160": "^2.0.0",
- "safe-buffer": "^5.0.1",
- "sha.js": "^2.4.8"
- }
- },
"cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -6923,19 +6920,6 @@
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
"dev": true
},
- "pbkdf2": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
- "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==",
- "dev": true,
- "requires": {
- "create-hash": "^1.1.2",
- "create-hmac": "^1.1.4",
- "ripemd160": "^2.0.1",
- "safe-buffer": "^5.0.1",
- "sha.js": "^2.4.8"
- }
- },
"picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
@@ -7068,9 +7052,9 @@
}
},
"readable-stream": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
- "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "version": "3.6.1",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.1.tgz",
+ "integrity": "sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ==",
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
@@ -7101,6 +7085,19 @@
"bs58check": "^2.1.2",
"dhttp": "^3.0.3",
"randombytes": "^2.1.0"
+ },
+ "dependencies": {
+ "bs58check": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz",
+ "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==",
+ "dev": true,
+ "requires": {
+ "bs58": "^4.0.0",
+ "create-hash": "^1.1.0",
+ "safe-buffer": "^5.1.2"
+ }
+ }
}
},
"release-zalgo": {
@@ -7574,6 +7571,18 @@
"integrity": "sha512-HIanZn1zmduSF+BQhkE+YXIbEiH0xPr1012QbFEGB0xsKqJii0/SqJjyn8dFv6y36kOznMgMB+LGcbZTJ1xACQ==",
"requires": {
"bs58check": "<3.0.0"
+ },
+ "dependencies": {
+ "bs58check": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz",
+ "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==",
+ "requires": {
+ "bs58": "^4.0.0",
+ "create-hash": "^1.1.0",
+ "safe-buffer": "^5.1.2"
+ }
+ }
}
},
"word-wrap": {
diff --git a/package.json b/package.json
index 6194306c3..556850d46 100644
--- a/package.json
+++ b/package.json
@@ -52,7 +52,7 @@
"@noble/hashes": "^1.2.0",
"bech32": "^2.0.0",
"bip174": "^2.1.0",
- "bs58check": "^2.1.2",
+ "bs58check": "^3.0.1",
"typeforce": "^1.11.3",
"varuint-bitcoin": "^1.1.2",
"wif": "^2.0.1"
@@ -68,8 +68,8 @@
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
"better-npm-audit": "^3.7.3",
- "bip32": "^3.0.1",
- "bip39": "^3.0.2",
+ "bip32": "^4.0.0",
+ "bip39": "^3.1.0",
"bip65": "^1.0.1",
"bip68": "^1.0.3",
"bs58": "^4.0.0",
From 4bf8a84b8e4118dadc2b4e9685faf7abcea3445d Mon Sep 17 00:00:00 2001
From: Paul Miller
Date: Sat, 25 Feb 2023 15:12:03 +0000
Subject: [PATCH 118/144] Remove wif. Use new bs58check
---
package-lock.json | 58 +++++++++++++++++++++++-----------------
package.json | 4 +--
src/address.js | 4 +--
src/payments/p2pkh.js | 2 +-
src/payments/p2sh.js | 2 +-
ts_src/address.ts | 4 +--
ts_src/payments/p2pkh.ts | 2 +-
ts_src/payments/p2sh.ts | 2 +-
8 files changed, 42 insertions(+), 36 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index b042e30fb..4c0d1da60 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,8 +14,7 @@
"bip174": "^2.1.0",
"bs58check": "^3.0.1",
"typeforce": "^1.11.3",
- "varuint-bitcoin": "^1.1.2",
- "wif": "^2.0.1"
+ "varuint-bitcoin": "^1.1.2"
},
"devDependencies": {
"@types/bs58": "^4.0.0",
@@ -24,7 +23,6 @@
"@types/node": "^16.11.7",
"@types/proxyquire": "^1.3.28",
"@types/randombytes": "^2.0.0",
- "@types/wif": "^2.0.2",
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
"better-npm-audit": "^3.7.3",
@@ -794,15 +792,6 @@
"integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
"dev": true
},
- "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/@typescript-eslint/eslint-plugin": {
"version": "5.45.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.45.0.tgz",
@@ -1144,6 +1133,7 @@
"version": "3.0.9",
"resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz",
"integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==",
+ "dev": true,
"dependencies": {
"safe-buffer": "^5.0.1"
}
@@ -1296,6 +1286,7 @@
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
"integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==",
+ "dev": true,
"dependencies": {
"base-x": "^3.0.2"
}
@@ -1436,6 +1427,7 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
"integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
+ "dev": true,
"dependencies": {
"inherits": "^2.0.1",
"safe-buffer": "^5.0.1"
@@ -1510,6 +1502,7 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
"integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
+ "dev": true,
"dependencies": {
"cipher-base": "^1.0.1",
"inherits": "^2.0.1",
@@ -2295,6 +2288,7 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
"integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
+ "dev": true,
"dependencies": {
"inherits": "^2.0.4",
"readable-stream": "^3.6.0",
@@ -2406,7 +2400,8 @@
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
},
"node_modules/is-binary-path": {
"version": "2.1.0",
@@ -2839,6 +2834,7 @@
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
"integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
+ "dev": true,
"dependencies": {
"hash-base": "^3.0.0",
"inherits": "^2.0.1",
@@ -3561,6 +3557,7 @@
"version": "3.6.1",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.1.tgz",
"integrity": "sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ==",
+ "dev": true,
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
@@ -3704,6 +3701,7 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
"integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
+ "dev": true,
"dependencies": {
"hash-base": "^3.0.0",
"inherits": "^2.0.1"
@@ -3785,6 +3783,7 @@
"version": "2.4.11",
"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
+ "dev": true,
"dependencies": {
"inherits": "^2.0.1",
"safe-buffer": "^5.0.1"
@@ -3916,6 +3915,7 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "dev": true,
"dependencies": {
"safe-buffer": "~5.2.0"
}
@@ -4235,7 +4235,8 @@
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "dev": true
},
"node_modules/uuid": {
"version": "8.3.2",
@@ -4279,6 +4280,7 @@
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz",
"integrity": "sha512-HIanZn1zmduSF+BQhkE+YXIbEiH0xPr1012QbFEGB0xsKqJii0/SqJjyn8dFv6y36kOznMgMB+LGcbZTJ1xACQ==",
+ "dev": true,
"dependencies": {
"bs58check": "<3.0.0"
}
@@ -4287,6 +4289,7 @@
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz",
"integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==",
+ "dev": true,
"dependencies": {
"bs58": "^4.0.0",
"create-hash": "^1.1.0",
@@ -5022,15 +5025,6 @@
"integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
"dev": true
},
- "@types/wif": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/@types/wif/-/wif-2.0.2.tgz",
- "integrity": "sha512-IiIuBeJzlh4LWJ7kVTrX0nwB60OG0vvGTaWC/SgSbVFw7uYUTF6gEuvDZ1goWkeirekJDD58Y8g7NljQh2fNkA==",
- "dev": true,
- "requires": {
- "@types/node": "*"
- }
- },
"@typescript-eslint/eslint-plugin": {
"version": "5.45.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.45.0.tgz",
@@ -5244,6 +5238,7 @@
"version": "3.0.9",
"resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz",
"integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==",
+ "dev": true,
"requires": {
"safe-buffer": "^5.0.1"
}
@@ -5356,6 +5351,7 @@
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
"integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==",
+ "dev": true,
"requires": {
"base-x": "^3.0.2"
}
@@ -5461,6 +5457,7 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
"integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
+ "dev": true,
"requires": {
"inherits": "^2.0.1",
"safe-buffer": "^5.0.1"
@@ -5526,6 +5523,7 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
"integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
+ "dev": true,
"requires": {
"cipher-base": "^1.0.1",
"inherits": "^2.0.1",
@@ -6101,6 +6099,7 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
"integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
+ "dev": true,
"requires": {
"inherits": "^2.0.4",
"readable-stream": "^3.6.0",
@@ -6184,7 +6183,8 @@
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
},
"is-binary-path": {
"version": "2.1.0",
@@ -6505,6 +6505,7 @@
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
"integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
+ "dev": true,
"requires": {
"hash-base": "^3.0.0",
"inherits": "^2.0.1",
@@ -7055,6 +7056,7 @@
"version": "3.6.1",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.1.tgz",
"integrity": "sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ==",
+ "dev": true,
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
@@ -7163,6 +7165,7 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
"integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
+ "dev": true,
"requires": {
"hash-base": "^3.0.0",
"inherits": "^2.0.1"
@@ -7210,6 +7213,7 @@
"version": "2.4.11",
"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
+ "dev": true,
"requires": {
"inherits": "^2.0.1",
"safe-buffer": "^5.0.1"
@@ -7310,6 +7314,7 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "dev": true,
"requires": {
"safe-buffer": "~5.2.0"
}
@@ -7534,7 +7539,8 @@
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "dev": true
},
"uuid": {
"version": "8.3.2",
@@ -7569,6 +7575,7 @@
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz",
"integrity": "sha512-HIanZn1zmduSF+BQhkE+YXIbEiH0xPr1012QbFEGB0xsKqJii0/SqJjyn8dFv6y36kOznMgMB+LGcbZTJ1xACQ==",
+ "dev": true,
"requires": {
"bs58check": "<3.0.0"
},
@@ -7577,6 +7584,7 @@
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz",
"integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==",
+ "dev": true,
"requires": {
"bs58": "^4.0.0",
"create-hash": "^1.1.0",
diff --git a/package.json b/package.json
index 556850d46..12ded6971 100644
--- a/package.json
+++ b/package.json
@@ -54,8 +54,7 @@
"bip174": "^2.1.0",
"bs58check": "^3.0.1",
"typeforce": "^1.11.3",
- "varuint-bitcoin": "^1.1.2",
- "wif": "^2.0.1"
+ "varuint-bitcoin": "^1.1.2"
},
"devDependencies": {
"@types/bs58": "^4.0.0",
@@ -64,7 +63,6 @@
"@types/node": "^16.11.7",
"@types/proxyquire": "^1.3.28",
"@types/randombytes": "^2.0.0",
- "@types/wif": "^2.0.2",
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
"better-npm-audit": "^3.7.3",
diff --git a/src/address.js b/src/address.js
index d58c9a69e..2712168a1 100644
--- a/src/address.js
+++ b/src/address.js
@@ -42,11 +42,11 @@ function _toFutureSegwitAddress(output, network) {
return toBech32(data, version, network.bech32);
}
function fromBase58Check(address) {
- const payload = bs58check.decode(address);
+ const payload = Buffer.from(bs58check.decode(address));
// TODO: 4.0.0, move to "toOutputScript"
if (payload.length < 21) throw new TypeError(address + ' is too short');
if (payload.length > 21) throw new TypeError(address + ' is too long');
- const version = payload.readUInt8(0);
+ const version = payload.readUint8(0);
const hash = payload.slice(1);
return { version, hash };
}
diff --git a/src/payments/p2pkh.js b/src/payments/p2pkh.js
index 8edc8ba9e..16e293d59 100644
--- a/src/payments/p2pkh.js
+++ b/src/payments/p2pkh.js
@@ -27,7 +27,7 @@ function p2pkh(a, opts) {
a,
);
const _address = lazy.value(() => {
- const payload = bs58check.decode(a.address);
+ const payload = Buffer.from(bs58check.decode(a.address));
const version = payload.readUInt8(0);
const hash = payload.slice(1);
return { version, hash };
diff --git a/src/payments/p2sh.js b/src/payments/p2sh.js
index 5061edc95..b280fcafa 100644
--- a/src/payments/p2sh.js
+++ b/src/payments/p2sh.js
@@ -48,7 +48,7 @@ function p2sh(a, opts) {
}
const o = { network };
const _address = lazy.value(() => {
- const payload = bs58check.decode(a.address);
+ const payload = Buffer.from(bs58check.decode(a.address));
const version = payload.readUInt8(0);
const hash = payload.slice(1);
return { version, hash };
diff --git a/ts_src/address.ts b/ts_src/address.ts
index 8004b2668..a9c0e4103 100644
--- a/ts_src/address.ts
+++ b/ts_src/address.ts
@@ -53,13 +53,13 @@ function _toFutureSegwitAddress(output: Buffer, network: Network): string {
}
export function fromBase58Check(address: string): Base58CheckResult {
- const payload = bs58check.decode(address);
+ const payload = Buffer.from(bs58check.decode(address));
// TODO: 4.0.0, move to "toOutputScript"
if (payload.length < 21) throw new TypeError(address + ' is too short');
if (payload.length > 21) throw new TypeError(address + ' is too long');
- const version = payload.readUInt8(0);
+ const version = payload.readUint8(0);
const hash = payload.slice(1);
return { version, hash };
diff --git a/ts_src/payments/p2pkh.ts b/ts_src/payments/p2pkh.ts
index 3b5bd6f79..4947c832a 100644
--- a/ts_src/payments/p2pkh.ts
+++ b/ts_src/payments/p2pkh.ts
@@ -29,7 +29,7 @@ export function p2pkh(a: Payment, opts?: PaymentOpts): Payment {
);
const _address = lazy.value(() => {
- const payload = bs58check.decode(a.address!);
+ const payload = Buffer.from(bs58check.decode(a.address!));
const version = payload.readUInt8(0);
const hash = payload.slice(1);
return { version, hash };
diff --git a/ts_src/payments/p2sh.ts b/ts_src/payments/p2sh.ts
index 67e5f38dd..ebff7853f 100644
--- a/ts_src/payments/p2sh.ts
+++ b/ts_src/payments/p2sh.ts
@@ -57,7 +57,7 @@ export function p2sh(a: Payment, opts?: PaymentOpts): Payment {
const o: Payment = { network };
const _address = lazy.value(() => {
- const payload = bs58check.decode(a.address!);
+ const payload = Buffer.from(bs58check.decode(a.address!));
const version = payload.readUInt8(0);
const hash = payload.slice(1);
return { version, hash };
From 1c18fe6e2c925f94c99e6311783e28c2799eca5a Mon Sep 17 00:00:00 2001
From: fboucquez
Date: Sun, 26 Feb 2023 20:41:03 -0300
Subject: [PATCH 119/144] fix: android `TypedArray.of requires its this
argument to subclass a TypedArray constructor`
---
src/transaction.js | 2 +-
ts_src/transaction.ts | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/transaction.js b/src/transaction.js
index 6f1382cfa..4b149c0b8 100644
--- a/src/transaction.js
+++ b/src/transaction.js
@@ -389,7 +389,7 @@ class Transaction {
// https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-19
return bcrypto.taggedHash(
'TapSighash',
- Buffer.concat([Buffer.of(0x00), sigMsgWriter.end()]),
+ Buffer.concat([Buffer.alloc(1), sigMsgWriter.end()]),
);
}
hashForWitnessV0(inIndex, prevOutScript, value, hashType) {
diff --git a/ts_src/transaction.ts b/ts_src/transaction.ts
index 416f20efe..52d224a11 100644
--- a/ts_src/transaction.ts
+++ b/ts_src/transaction.ts
@@ -490,7 +490,7 @@ export class Transaction {
// https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-19
return bcrypto.taggedHash(
'TapSighash',
- Buffer.concat([Buffer.of(0x00), sigMsgWriter.end()]),
+ Buffer.concat([Buffer.alloc(1), sigMsgWriter.end()]),
);
}
From 3541220e7065959044065c534562c52c0fd4236e Mon Sep 17 00:00:00 2001
From: fboucquez
Date: Mon, 27 Feb 2023 11:42:20 -0300
Subject: [PATCH 120/144] using Buffer.from([0x00]
---
src/transaction.js | 2 +-
ts_src/transaction.ts | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/transaction.js b/src/transaction.js
index 4b149c0b8..ade4582cf 100644
--- a/src/transaction.js
+++ b/src/transaction.js
@@ -389,7 +389,7 @@ class Transaction {
// https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-19
return bcrypto.taggedHash(
'TapSighash',
- Buffer.concat([Buffer.alloc(1), sigMsgWriter.end()]),
+ Buffer.concat([Buffer.from([0x00]), sigMsgWriter.end()]),
);
}
hashForWitnessV0(inIndex, prevOutScript, value, hashType) {
diff --git a/ts_src/transaction.ts b/ts_src/transaction.ts
index 52d224a11..39b975545 100644
--- a/ts_src/transaction.ts
+++ b/ts_src/transaction.ts
@@ -490,7 +490,7 @@ export class Transaction {
// https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-19
return bcrypto.taggedHash(
'TapSighash',
- Buffer.concat([Buffer.alloc(1), sigMsgWriter.end()]),
+ Buffer.concat([Buffer.from([0x00]), sigMsgWriter.end()]),
);
}
From 640a2a781c9c9af63688d7bdb1760fa7b9d9caa3 Mon Sep 17 00:00:00 2001
From: habibitcoin
Date: Fri, 14 Apr 2023 19:10:22 -0400
Subject: [PATCH 121/144] Include test for taproot custom signature types
---
test/fixtures/psbt.json | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/test/fixtures/psbt.json b/test/fixtures/psbt.json
index ec6eda328..1ee38388b 100644
--- a/test/fixtures/psbt.json
+++ b/test/fixtures/psbt.json
@@ -767,6 +767,15 @@
"WIF": "KxnAnQh6UJBxLF8Weup77yn8tWhLHhDhnXeyJuzmmcZA5aRdMJni"
}
},
+ {
+ "description": "checks taproot signing works when using custom signature type of 65 bytes",
+ "shouldSign": {
+ "psbt": "cHNidP8BAF4CAAAAAf17fGksrz9eKGx1nSU3RX4vcwr7bfNdQzPZ9dSEkWBcAAAAAAD/////AZBBBgAAAAAAIlEgPLBe/d3922lmXjTIt52b9NG1HFDC9jzPCTn111AG8TQAAAAAAAEBK6BoBgAAAAAAIlEgPLBe/d3922lmXjTIt52b9NG1HFDC9jzPCTn111AG8TQBAwSDAAAAARcgWzC4qnD37J3WaDEbZPRihBXdI0gN68BGutJykDcHR6wBGCDlDrX1cnzwZvmcyLBH8M6NiS9lk7JVwM58wZZVOzmuMwAA",
+ "inputToCheck": 0,
+ "WIF": "KypUz2y1jdgzM8HGDUx9DYLmyzd8EWhruvLX2J5iSL7MiAcc7dBG",
+ "result": "cHNidP8BAF4CAAAAAf17fGksrz9eKGx1nSU3RX4vcwr7bfNdQzPZ9dSEkWBcAAAAAAD/////AZBBBgAAAAAAIlEgPLBe/d3922lmXjTIt52b9NG1HFDC9jzPCTn111AG8TQAAAAAAAEBK6BoBgAAAAAAIlEgPLBe/d3922lmXjTIt52b9NG1HFDC9jzPCTn111AG8TQBAwSDAAAAARNBqgjqjSQVTf41zgZ1H9Lq3CKQt0nq1APST8FpwGifNjyUHMS0MbFnIxA70SXTEOoSJePyOXTW+u59fzLpxekL2oMBFyBbMLiqcPfsndZoMRtk9GKEFd0jSA3rwEa60nKQNwdHrAEYIOUOtfVyfPBm+ZzIsEfwzo2JL2WTslXAznzBllU7Oa4zAAA="
+ }
+ },
{
"description": "checks taproot key-path signer (tweaked key) matches internal tap key",
"isTaproot": true,
From 3c5faec85db846748d7eb0af0d7763677e58aa63 Mon Sep 17 00:00:00 2001
From: habibitcoin <114780316+habibitcoin@users.noreply.github.com>
Date: Thu, 27 Apr 2023 22:03:12 -0400
Subject: [PATCH 122/144] Update test to specify sighashTypes
---
test/fixtures/psbt.json | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/test/fixtures/psbt.json b/test/fixtures/psbt.json
index 1ee38388b..c3bcde380 100644
--- a/test/fixtures/psbt.json
+++ b/test/fixtures/psbt.json
@@ -771,6 +771,9 @@
"description": "checks taproot signing works when using custom signature type of 65 bytes",
"shouldSign": {
"psbt": "cHNidP8BAF4CAAAAAf17fGksrz9eKGx1nSU3RX4vcwr7bfNdQzPZ9dSEkWBcAAAAAAD/////AZBBBgAAAAAAIlEgPLBe/d3922lmXjTIt52b9NG1HFDC9jzPCTn111AG8TQAAAAAAAEBK6BoBgAAAAAAIlEgPLBe/d3922lmXjTIt52b9NG1HFDC9jzPCTn111AG8TQBAwSDAAAAARcgWzC4qnD37J3WaDEbZPRihBXdI0gN68BGutJykDcHR6wBGCDlDrX1cnzwZvmcyLBH8M6NiS9lk7JVwM58wZZVOzmuMwAA",
+ "sighashTypes": [
+ 3, 128
+ ],
"inputToCheck": 0,
"WIF": "KypUz2y1jdgzM8HGDUx9DYLmyzd8EWhruvLX2J5iSL7MiAcc7dBG",
"result": "cHNidP8BAF4CAAAAAf17fGksrz9eKGx1nSU3RX4vcwr7bfNdQzPZ9dSEkWBcAAAAAAD/////AZBBBgAAAAAAIlEgPLBe/d3922lmXjTIt52b9NG1HFDC9jzPCTn111AG8TQAAAAAAAEBK6BoBgAAAAAAIlEgPLBe/d3922lmXjTIt52b9NG1HFDC9jzPCTn111AG8TQBAwSDAAAAARNBqgjqjSQVTf41zgZ1H9Lq3CKQt0nq1APST8FpwGifNjyUHMS0MbFnIxA70SXTEOoSJePyOXTW+u59fzLpxekL2oMBFyBbMLiqcPfsndZoMRtk9GKEFd0jSA3rwEa60nKQNwdHrAEYIOUOtfVyfPBm+ZzIsEfwzo2JL2WTslXAznzBllU7Oa4zAAA="
@@ -917,4 +920,4 @@
"clone": {
"psbt": "cHNidP8BAKYCAAAAAlwKQ3suPWwEJ/zQ9sZsIioOcHKU1KoLMxlMNSXVIkEWAAAAAAD/////YYDJMap+mYgbTrCNAdpWHN+EkKvl+XYao/6co/EQfwMAAAAAAP////8CkF8BAAAAAAAWABRnPBAmVHz2HL+8/1U+QG5L2thjmjhKAAAAAAAAIgAg700yfFRyhWzQnPHIUb/XQqsjlpf4A0uw682pCVWuQ8IAAAAAAAEBKzB1AAAAAAAAIgAgth9oE4cDfC5aV58VgkW5CptHsIxppYzJV8C5kT6aTo8iAgNfNgnFnEPS9s4PY/I5bezpWiAEzQ4DRTASgdSdeMM06UgwRQIhALO0xRpuqP3aVkm+DPykrtqe6fPNSgNblp9K9MAwmtHJAiAHV5ZvZN8Vi49n/o9ISFyvtHsPXXPKqBxC9m2m2HlpYgEBBSMhA182CcWcQ9L2zg9j8jlt7OlaIATNDgNFMBKB1J14wzTprAABASuAOAEAAAAAACIAILYfaBOHA3wuWlefFYJFuQqbR7CMaaWMyVfAuZE+mk6PIgIDXzYJxZxD0vbOD2PyOW3s6VogBM0OA0UwEoHUnXjDNOlIMEUCIQC6XN6tpo9mYlZej4BXSSh5D1K6aILBfQ4WBWXUrISx6wIgVaxFUsz8y59xJ1V4sZ1qarHX9pZ+MJmLKbl2ZSadisoBAQUjIQNfNgnFnEPS9s4PY/I5bezpWiAEzQ4DRTASgdSdeMM06awAAAA="
}
-}
\ No newline at end of file
+}
From 5ffda410db14cf109e65d0a69ae3148c2e552b20 Mon Sep 17 00:00:00 2001
From: habibitcoin
Date: Tue, 23 May 2023 22:47:51 -0400
Subject: [PATCH 123/144] Update test to specify isTaproot
---
test/fixtures/psbt.json | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/test/fixtures/psbt.json b/test/fixtures/psbt.json
index c3bcde380..31645c86d 100644
--- a/test/fixtures/psbt.json
+++ b/test/fixtures/psbt.json
@@ -769,10 +769,11 @@
},
{
"description": "checks taproot signing works when using custom signature type of 65 bytes",
+ "isTaproot": true,
"shouldSign": {
"psbt": "cHNidP8BAF4CAAAAAf17fGksrz9eKGx1nSU3RX4vcwr7bfNdQzPZ9dSEkWBcAAAAAAD/////AZBBBgAAAAAAIlEgPLBe/d3922lmXjTIt52b9NG1HFDC9jzPCTn111AG8TQAAAAAAAEBK6BoBgAAAAAAIlEgPLBe/d3922lmXjTIt52b9NG1HFDC9jzPCTn111AG8TQBAwSDAAAAARcgWzC4qnD37J3WaDEbZPRihBXdI0gN68BGutJykDcHR6wBGCDlDrX1cnzwZvmcyLBH8M6NiS9lk7JVwM58wZZVOzmuMwAA",
"sighashTypes": [
- 3, 128
+ 131
],
"inputToCheck": 0,
"WIF": "KypUz2y1jdgzM8HGDUx9DYLmyzd8EWhruvLX2J5iSL7MiAcc7dBG",
From f230cc96ceaf82b151b6d5e9fb0061dd8eaad4ce Mon Sep 17 00:00:00 2001
From: Vlad Stan
Date: Thu, 25 May 2023 19:06:29 +0300
Subject: [PATCH 124/144] chore: version bump to `6.1.1` and changelog
---
CHANGELOG.md | 16 ++++++++++++++++
package-lock.json | 4 ++--
package.json | 2 +-
3 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b0d11209c..f22ccbfdd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,19 @@
+# 6.1.1
+__added__
+- add example using BIP86 vector to verify the sending to and from a BIP86 generated taproot address
+
+__fixed__
+- support for 65 byte taproot signature
+- prevent the creation of unspendable scripts in bitcoinjs-lib by implementing checks for resource limitations
+- use `Buffer.from()` instead of `Buffer.of()`
+
+__changed__
+- performance: precompute the taproot hashes
+- performance: switch from `create-hash` and `ripemd160` to noble-hashes
+
+__removed__
+- types: removed unused methods `privateAdd` and `privateNegate` from `TinySecp256k1Interface`
+
# 6.1.0
__added__
- taproot support for payments (p2tr) and PSBT. See taproot.spec.ts integration test for examples. (#1742)
diff --git a/package-lock.json b/package-lock.json
index 4c0d1da60..24fd6410d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "bitcoinjs-lib",
- "version": "6.1.0",
+ "version": "6.1.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "bitcoinjs-lib",
- "version": "6.1.0",
+ "version": "6.1.1",
"license": "MIT",
"dependencies": {
"@noble/hashes": "^1.2.0",
diff --git a/package.json b/package.json
index 12ded6971..bf93b2901 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "6.1.0",
+ "version": "6.1.1",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"types": "./src/index.d.ts",
From 85c5c6a3354ac2473f55976a9fb0e581a1bbd907 Mon Sep 17 00:00:00 2001
From: junderw
Date: Fri, 2 Jun 2023 20:36:38 -0700
Subject: [PATCH 125/144] Fix: Find hashes WITHOUT leafHash instead
---
src/psbt.js | 14 ++++++++++----
test/integration/taproot.spec.ts | 31 +++++++++++++++++++++++++++++++
ts_src/psbt.ts | 15 +++++++++++----
3 files changed, 52 insertions(+), 8 deletions(-)
diff --git a/src/psbt.js b/src/psbt.js
index 9aa36686a..d4b78093b 100644
--- a/src/psbt.js
+++ b/src/psbt.js
@@ -468,14 +468,16 @@ class Psbt {
this.__CACHE,
);
if (!allHashses.length) throw new Error('No signatures for this pubkey');
- const tapKeyHash = allHashses.find(h => !!h.leafHash);
+ const tapKeyHash = allHashses.find(h => !h.leafHash);
+ let validationResultCount = 0;
if (tapKeySig && tapKeyHash) {
const isValidTapkeySig = validator(
tapKeyHash.pubkey,
tapKeyHash.hash,
- tapKeySig,
+ trimTaprootSig(tapKeySig),
);
if (!isValidTapkeySig) return false;
+ validationResultCount++;
}
if (tapScriptSig) {
for (const tapSig of tapScriptSig) {
@@ -484,13 +486,14 @@ class Psbt {
const isValidTapScriptSig = validator(
tapSig.pubkey,
tapSigHash.hash,
- tapSig.signature,
+ trimTaprootSig(tapSig.signature),
);
if (!isValidTapScriptSig) return false;
+ validationResultCount++;
}
}
}
- return true;
+ return validationResultCount > 0;
}
signAllInputsHD(
hdKeyPair,
@@ -1292,6 +1295,9 @@ function getAllTaprootHashesForSig(inputIndex, input, inputs, cache) {
);
return allHashes.flat();
}
+function trimTaprootSig(signature) {
+ return signature.length === 64 ? signature : signature.subarray(1);
+}
function getTaprootHashesForSig(
inputIndex,
input,
diff --git a/test/integration/taproot.spec.ts b/test/integration/taproot.spec.ts
index 550a34608..87cfaedb9 100644
--- a/test/integration/taproot.spec.ts
+++ b/test/integration/taproot.spec.ts
@@ -598,6 +598,37 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
});
}
});
+
+ it('should fail validating invalid signatures for taproot (See issue #1931)', () => {
+ const schnorrValidator = (
+ pubkey: Buffer,
+ msghash: Buffer,
+ signature: Buffer,
+ ) => {
+ return ecc.verifySchnorr(msghash, pubkey, signature);
+ };
+
+ const psbtBase64 =
+ `cHNidP8BAFICAAAAAe1h73A6zedruNERV6JU7Ty1IlYZh2KO1cBklZqCMEy8AAAAAAD/////ARA
+ nAAAAAAAAFgAUS0GlfqWSeEWIpwPwrvRIjBbJQroAAAAAAAEA/TgBAQAAAAABAnGJ6st1FIvYLEV
+ bJMQaZ3HSOJnkw5C+ViCuJYiFEYosAAAAAAD9////xuZd0xArNSaBuElLX3nzjwtZW95O7L/wbz9
+ 4v+v0vuYAAAAAAP3///8CECcAAAAAAAAiUSAVbMSHgwYVdyBgfNy0syr6TMaFOGhFjXJYuQcRLlp
+ DS8hgBwAAAAAAIlEgthWGz3o2R7WpgjIK52ODoEaA/0HcImSUjVk6agZgghwBQIP9WWErMfeBBYy
+ uHuSZS7MdXVICtlFgNveDrvuXeQGSZl1gGG6/r3Aw7h9TifGtoA+7JwYBjLMcEG6hbeyQGXIBQNS
+ qKH1p/NFzO9bxe9vpvBZQIaX5Qa9SY2NfNCgSRNabmX5EiaihWcLC+ALgchm7DUfYrAmi1r4uSI/
+ YaQ1lq8gAAAAAAQErECcAAAAAAAAiUSAVbMSHgwYVdyBgfNy0syr6TMaFOGhFjXJYuQcRLlpDSwE
+ DBIMAAAABCEMBQZUpv6e1Hwfpi/PpglkkK/Rx40vZIIHwtJ7dXWFZ5TcZUEelCnfKOAWZ4xWjauY
+ M2y+JcgFcVsuPzPuiM+z5AH+DARNBlSm/p7UfB+mL8+mCWSQr9HHjS9kggfC0nt1dYVnlNxlQR6U
+ Kd8o4BZnjFaNq5gzbL4lyAVxWy4/M+6Iz7PkAf4MBFyC6ZCT2zZVrEbkw/T1fyS8eLKQaP2MH6rz
+ dlMauGvQzLQAA`.replace(/\s+/g, '');
+
+ const psbt = bitcoin.Psbt.fromBase64(psbtBase64);
+
+ assert(
+ !psbt.validateSignaturesOfAllInputs(schnorrValidator),
+ 'Should fail validation',
+ );
+ });
});
function buildLeafIndexFinalizer(
diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts
index e7ca28976..84eb89c33 100644
--- a/ts_src/psbt.ts
+++ b/ts_src/psbt.ts
@@ -606,14 +606,16 @@ export class Psbt {
if (!allHashses.length) throw new Error('No signatures for this pubkey');
- const tapKeyHash = allHashses.find(h => !!h.leafHash);
+ const tapKeyHash = allHashses.find(h => !h.leafHash);
+ let validationResultCount = 0;
if (tapKeySig && tapKeyHash) {
const isValidTapkeySig = validator(
tapKeyHash.pubkey,
tapKeyHash.hash,
- tapKeySig,
+ trimTaprootSig(tapKeySig),
);
if (!isValidTapkeySig) return false;
+ validationResultCount++;
}
if (tapScriptSig) {
@@ -623,14 +625,15 @@ export class Psbt {
const isValidTapScriptSig = validator(
tapSig.pubkey,
tapSigHash.hash,
- tapSig.signature,
+ trimTaprootSig(tapSig.signature),
);
if (!isValidTapScriptSig) return false;
+ validationResultCount++;
}
}
}
- return true;
+ return validationResultCount > 0;
}
signAllInputsHD(
@@ -1714,6 +1717,10 @@ function getAllTaprootHashesForSig(
return allHashes.flat();
}
+function trimTaprootSig(signature: Buffer): Buffer {
+ return signature.length === 64 ? signature : signature.subarray(1);
+}
+
function getTaprootHashesForSig(
inputIndex: number,
input: PsbtInput,
From f8cfd7f679054afe18834a7acee1fbaa318ab701 Mon Sep 17 00:00:00 2001
From: junderw
Date: Mon, 5 Jun 2023 07:35:29 -0700
Subject: [PATCH 126/144] 6.1.2
---
CHANGELOG.md | 4 ++++
package-lock.json | 2 +-
package.json | 2 +-
3 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f22ccbfdd..93fb78d0c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+# 6.1.2
+__fixed__
+- validateSignaturesOfInput for taproot inputs returned true for invalid signatures in specific cases. (#1932)
+
# 6.1.1
__added__
- add example using BIP86 vector to verify the sending to and from a BIP86 generated taproot address
diff --git a/package-lock.json b/package-lock.json
index 24fd6410d..f3a34063d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "6.1.1",
+ "version": "6.1.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
diff --git a/package.json b/package.json
index bf93b2901..89566f8e3 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "6.1.1",
+ "version": "6.1.2",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"types": "./src/index.d.ts",
From b5fd4d644c4b7a9dfc6f6fd4046626c37596241b Mon Sep 17 00:00:00 2001
From: junderw
Date: Tue, 6 Jun 2023 22:51:45 -0700
Subject: [PATCH 127/144] Fix: Taproot signature validation was incorrect
again.
Output keys are not guaranteed to be tweaked against their pubkey's hash.
That is only a convention decided upon for NUMS properties.
---
package.json | 2 +-
src/psbt.js | 15 +++++++++++----
test/fixtures/psbt.json | 6 +++---
test/integration/taproot.spec.ts | 29 +++++++++++++++++++++++++++++
ts_src/psbt.ts | 22 +++++++++++++++++-----
5 files changed, 61 insertions(+), 13 deletions(-)
diff --git a/package.json b/package.json
index 89566f8e3..bf6ac269c 100644
--- a/package.json
+++ b/package.json
@@ -33,7 +33,7 @@
"mocha:ts": "mocha --recursive --require test/ts-node-register",
"nobuild:coverage-report": "nyc report --reporter=lcov",
"nobuild:coverage-html": "nyc report --reporter=html",
- "nobuild:coverage": "npm run build:tests && nyc --check-coverage --branches 90 --functions 90 --lines 90 mocha && npm run clean:jstests",
+ "nobuild:coverage": "npm run build:tests && nyc --check-coverage --branches 85 --functions 90 --lines 90 mocha && npm run clean:jstests",
"nobuild:integration": "npm run mocha:ts -- --timeout 50000 'test/integration/*.ts'",
"nobuild:unit": "npm run mocha:ts -- 'test/*.ts'",
"prettier": "prettier \"ts_src/**/*.ts\" \"test/**/*.ts\" --ignore-path ./.prettierignore",
diff --git a/src/psbt.js b/src/psbt.js
index d4b78093b..71c3589f0 100644
--- a/src/psbt.js
+++ b/src/psbt.js
@@ -1283,8 +1283,10 @@ function getHashForSig(inputIndex, input, cache, forValidate, sighashTypes) {
function getAllTaprootHashesForSig(inputIndex, input, inputs, cache) {
const allPublicKeys = [];
if (input.tapInternalKey) {
- const outputKey = (0, bip371_1.tweakInternalPubKey)(inputIndex, input);
- allPublicKeys.push(outputKey);
+ const key = getPrevoutTaprootKey(inputIndex, input, cache);
+ if (key) {
+ allPublicKeys.push(key);
+ }
}
if (input.tapScriptSig) {
const tapScriptPubkeys = input.tapScriptSig.map(tss => tss.pubkey);
@@ -1295,8 +1297,12 @@ function getAllTaprootHashesForSig(inputIndex, input, inputs, cache) {
);
return allHashes.flat();
}
+function getPrevoutTaprootKey(inputIndex, input, cache) {
+ const { script } = getScriptAndAmountFromUtxo(inputIndex, input, cache);
+ return (0, psbtutils_1.isP2TR)(script) ? script.subarray(2, 34) : null;
+}
function trimTaprootSig(signature) {
- return signature.length === 64 ? signature : signature.subarray(1);
+ return signature.length === 64 ? signature : signature.subarray(0, 64);
}
function getTaprootHashesForSig(
inputIndex,
@@ -1318,7 +1324,8 @@ function getTaprootHashesForSig(
const values = prevOuts.map(o => o.value);
const hashes = [];
if (input.tapInternalKey && !tapLeafHashToSign) {
- const outputKey = (0, bip371_1.tweakInternalPubKey)(inputIndex, input);
+ const outputKey =
+ getPrevoutTaprootKey(inputIndex, input, cache) || Buffer.from([]);
if ((0, bip371_1.toXOnly)(pubkey).equals(outputKey)) {
const tapKeyHash = unsignedTx.hashForWitnessV1(
inputIndex,
diff --git a/test/fixtures/psbt.json b/test/fixtures/psbt.json
index 31645c86d..ce8988fa3 100644
--- a/test/fixtures/psbt.json
+++ b/test/fixtures/psbt.json
@@ -310,7 +310,7 @@
},
{
"description": "Sign PSBT with 3 inputs [P2PKH, P2TR (key-path), 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+p90ZfGGstEZ83LyfTLDFcfi2OlxAyuARcglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4AAQEfECcAAAAAAAAWABRPoqyhKLb53uUwnE9wBR5Jxl/XMgAAAA==",
+ "psbt": "cHNidP8BAM8CAAAAAwPzd9k+uLSN1rgF01xY1TIA/8N+YytNZ4VP9gKFP4MyAAAAAAD/////ZtAAqL2E1fKcmGo+7xuqS+nSQeKFVKGRYaHfIvLXn4sAAAAAAP////9+h+SlCwIx1MUDT7Bek0NrWXS7xnSPi5LbYbDc9sxYIgAAAAAA/////wIgKRsAAAAAACJRIEb2SXyy8Z1Qw+npgqlQ3MhiFLAfzOQ3pCBhx72xIw0zuAUBAAAAAAAWABTJijE0v48z5ZmmfEAADXdCBcG0FAAAAAAAAQDiAgAAAAABAUfY2D1t0dyMeEH39C1yOdIxigpqm7XJNqHVT3Lc+FkiAAAAAAD+////AhIsGwAAAAAAGXapFJ5+8XZ3ZP80oFldvEwrcNsBftBmiKyYdK6xAAAAABepFLDBn59UffGbX7u/olyFDG0eG1UJhwJHMEQCIDAd3s05C61flXVFqOtov0NoHRGr8KFcOpH6R/81F46EAiBt+j9hHyvT2hYEyf8fdYsM9IgbnybtPV+kRTHDa6Rj0AEhAmmZfwmoHsmCkEOn9AfRTh+863mURelmE8hSqL4MG1EydJwgAAABASu4BQEAAAAAACJRIE/vXFFjvqaak+dKWWcrvrCBg3B3y5TPpuSBpc8A2KsYARcglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4AAQEfECcAAAAAAAAWABRPoqyhKLb53uUwnE9wBR5Jxl/XMgAAAA==",
"isTaproot": true,
"keys": [
{
@@ -326,7 +326,7 @@
"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+LY6XEDK4BE0Cd7/ny+QreV7urBWKNroQWCvnZczwkU0kLZiKsJQjtftKHWXMknftjt1d4K6aPYH7cBXzhlrUF+2GovjYLccZeARcglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4AAQEfECcAAAAAAAAWABRPoqyhKLb53uUwnE9wBR5Jxl/XMiICA6VOpEBbPJM/xYsqO2euttYFpgec9vcxggyTyoklK660SDBFAiEAoCIktghL55iuMAmkzwYJzb+h+qmNewZXxAx/06ObxIQCIELCsBz/wd2wPlnJb27OluxMkTPnCyHA2C+SxHiX/FvPAQAAAA=="
+ "result": "cHNidP8BAM8CAAAAAwPzd9k+uLSN1rgF01xY1TIA/8N+YytNZ4VP9gKFP4MyAAAAAAD/////ZtAAqL2E1fKcmGo+7xuqS+nSQeKFVKGRYaHfIvLXn4sAAAAAAP////9+h+SlCwIx1MUDT7Bek0NrWXS7xnSPi5LbYbDc9sxYIgAAAAAA/////wIgKRsAAAAAACJRIEb2SXyy8Z1Qw+npgqlQ3MhiFLAfzOQ3pCBhx72xIw0zuAUBAAAAAAAWABTJijE0v48z5ZmmfEAADXdCBcG0FAAAAAAAAQDiAgAAAAABAUfY2D1t0dyMeEH39C1yOdIxigpqm7XJNqHVT3Lc+FkiAAAAAAD+////AhIsGwAAAAAAGXapFJ5+8XZ3ZP80oFldvEwrcNsBftBmiKyYdK6xAAAAABepFLDBn59UffGbX7u/olyFDG0eG1UJhwJHMEQCIDAd3s05C61flXVFqOtov0NoHRGr8KFcOpH6R/81F46EAiBt+j9hHyvT2hYEyf8fdYsM9IgbnybtPV+kRTHDa6Rj0AEhAmmZfwmoHsmCkEOn9AfRTh+863mURelmE8hSqL4MG1EydJwgACICAi5ovBH1xLoGxPqtFh48wUEpnM+St1SbPzRwO7kBNKOQRzBEAiBpWClBybtHveXkhAgTiE8QSczMJs8MGuH4LOSNRA6s/AIgWlbB3xJOtJIsszj1qZ/whA5jK9wnTzeZzDlVs/ivq2cBAAEBK7gFAQAAAAAAIlEgT+9cUWO+ppqT50pZZyu+sIGDcHfLlM+m5IGlzwDYqxgBE0B0eYK4chVhtLT9WMi14T8ZknZSdTe1pMdIvaq6tIfwqY2xQ9YlcTTy0jWU9utItw/rHQ2c1FplbF9bRvZ6RLQSARcglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4AAQEfECcAAAAAAAAWABRPoqyhKLb53uUwnE9wBR5Jxl/XMiICA6VOpEBbPJM/xYsqO2euttYFpgec9vcxggyTyoklK660SDBFAiEAoCIktghL55iuMAmkzwYJzb+h+qmNewZXxAx/06ObxIQCIELCsBz/wd2wPlnJb27OluxMkTPnCyHA2C+SxHiX/FvPAQAAAA=="
},
{
"description": "Sign PSBT with 1 input [P2TR] (script-path, 3-of-3) and one output [P2TR]",
@@ -896,7 +896,7 @@
"nonExistantIndex": 42
},
"validateSignaturesOfTapKeyInput": {
- "psbt": "cHNidP8BAM8CAAAAAwPzd9k+uLSN1rgF01xY1TIA/8N+YytNZ4VP9gKFP4MyAAAAAAD/////ZtAAqL2E1fKcmGo+7xuqS+nSQeKFVKGRYaHfIvLXn4sAAAAAAP////9+h+SlCwIx1MUDT7Bek0NrWXS7xnSPi5LbYbDc9sxYIgAAAAAA/////wIgKRsAAAAAACJRIEb2SXyy8Z1Qw+npgqlQ3MhiFLAfzOQ3pCBhx72xIw0zuAUBAAAAAAAWABTJijE0v48z5ZmmfEAADXdCBcG0FAAAAAAAAQDiAgAAAAABAUfY2D1t0dyMeEH39C1yOdIxigpqm7XJNqHVT3Lc+FkiAAAAAAD+////AhIsGwAAAAAAGXapFJ5+8XZ3ZP80oFldvEwrcNsBftBmiKyYdK6xAAAAABepFLDBn59UffGbX7u/olyFDG0eG1UJhwJHMEQCIDAd3s05C61flXVFqOtov0NoHRGr8KFcOpH6R/81F46EAiBt+j9hHyvT2hYEyf8fdYsM9IgbnybtPV+kRTHDa6Rj0AEhAmmZfwmoHsmCkEOn9AfRTh+863mURelmE8hSqL4MG1EydJwgACICAi5ovBH1xLoGxPqtFh48wUEpnM+St1SbPzRwO7kBNKOQRzBEAiBpWClBybtHveXkhAgTiE8QSczMJs8MGuH4LOSNRA6s/AIgWlbB3xJOtJIsszj1qZ/whA5jK9wnTzeZzDlVs/ivq2cBAAEBK7gFAQAAAAAAIlEglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4BE0Cd7/ny+QreV7urBWKNroQWCvnZczwkU0kLZiKsJQjtftKHWXMknftjt1d4K6aPYH7cBXzhlrUF+2GovjYLccZeARcglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4AAQEfECcAAAAAAAAWABRPoqyhKLb53uUwnE9wBR5Jxl/XMiICA6VOpEBbPJM/xYsqO2euttYFpgec9vcxggyTyoklK660SDBFAiEAoCIktghL55iuMAmkzwYJzb+h+qmNewZXxAx/06ObxIQCIELCsBz/wd2wPlnJb27OluxMkTPnCyHA2C+SxHiX/FvPAQAAAA==",
+ "psbt": "cHNidP8BAM8CAAAAAwPzd9k+uLSN1rgF01xY1TIA/8N+YytNZ4VP9gKFP4MyAAAAAAD/////ZtAAqL2E1fKcmGo+7xuqS+nSQeKFVKGRYaHfIvLXn4sAAAAAAP////9+h+SlCwIx1MUDT7Bek0NrWXS7xnSPi5LbYbDc9sxYIgAAAAAA/////wIgKRsAAAAAACJRIEb2SXyy8Z1Qw+npgqlQ3MhiFLAfzOQ3pCBhx72xIw0zuAUBAAAAAAAWABTJijE0v48z5ZmmfEAADXdCBcG0FAAAAAAAAQDiAgAAAAABAUfY2D1t0dyMeEH39C1yOdIxigpqm7XJNqHVT3Lc+FkiAAAAAAD+////AhIsGwAAAAAAGXapFJ5+8XZ3ZP80oFldvEwrcNsBftBmiKyYdK6xAAAAABepFLDBn59UffGbX7u/olyFDG0eG1UJhwJHMEQCIDAd3s05C61flXVFqOtov0NoHRGr8KFcOpH6R/81F46EAiBt+j9hHyvT2hYEyf8fdYsM9IgbnybtPV+kRTHDa6Rj0AEhAmmZfwmoHsmCkEOn9AfRTh+863mURelmE8hSqL4MG1EydJwgACICAi5ovBH1xLoGxPqtFh48wUEpnM+St1SbPzRwO7kBNKOQRzBEAiBpWClBybtHveXkhAgTiE8QSczMJs8MGuH4LOSNRA6s/AIgWlbB3xJOtJIsszj1qZ/whA5jK9wnTzeZzDlVs/ivq2cBAAEBK7gFAQAAAAAAIlEgT+9cUWO+ppqT50pZZyu+sIGDcHfLlM+m5IGlzwDYqxgBE0B0eYK4chVhtLT9WMi14T8ZknZSdTe1pMdIvaq6tIfwqY2xQ9YlcTTy0jWU9utItw/rHQ2c1FplbF9bRvZ6RLQSARcglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4AAQEfECcAAAAAAAAWABRPoqyhKLb53uUwnE9wBR5Jxl/XMiICA6VOpEBbPJM/xYsqO2euttYFpgec9vcxggyTyoklK660SDBFAiEAoCIktghL55iuMAmkzwYJzb+h+qmNewZXxAx/06ObxIQCIELCsBz/wd2wPlnJb27OluxMkTPnCyHA2C+SxHiX/FvPAQAAAA==",
"index": 1,
"pubkey": "Buffer.from('024fef5c5163bea69a93e74a59672bbeb081837077cb94cfa6e481a5cf00d8ab18', 'hex')",
"incorrectPubkey": "Buffer.from('029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e02a', 'hex')"
diff --git a/test/integration/taproot.spec.ts b/test/integration/taproot.spec.ts
index 87cfaedb9..9fee629c3 100644
--- a/test/integration/taproot.spec.ts
+++ b/test/integration/taproot.spec.ts
@@ -629,6 +629,35 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
'Should fail validation',
);
});
+
+ it('should succeed validating valid signatures for taproot (See issue #1934)', () => {
+ const schnorrValidator = (
+ pubkey: Buffer,
+ msghash: Buffer,
+ signature: Buffer,
+ ) => {
+ return ecc.verifySchnorr(msghash, pubkey, signature);
+ };
+
+ const psbtBase64 =
+ `cHNidP8BAF4CAAAAAU6UzYPa7tES0HoS+obnRJuXX41Ob64Zs59qDEyKsu1ZAAAAAAD/////AYA
+ zAjsAAAAAIlEgIlIzfR+flIWYTyewD9v+1N84IubZ/7qg6oHlYLzv1aYAAAAAAAEAXgEAAAAB8f+
+ afEJBun7sRQLFE1Olc/gK9LBaduUpz3vB4fjXVF0AAAAAAP3///8BECcAAAAAAAAiUSAiUjN9H5+
+ UhZhPJ7AP2/7U3zgi5tn/uqDqgeVgvO/VpgAAAAABASsQJwAAAAAAACJRICJSM30fn5SFmE8nsA/
+ b/tTfOCLm2f+6oOqB5WC879WmAQMEgwAAAAETQWQwNOao3RMOBWPuAQ9Iph7Qzk47MvroTHbJR49
+ MxKJmQ6hfhZa5wVVrdKYea5BW/loqa7al2pYYZMlGvdS06wODARcgjuYXxIpyOMVTYEvl35gDidC
+ m/vUICZyuNNZKaPz9dxAAAQUgjuYXxIpyOMVTYEvl35gDidCm/vUICZyuNNZKaPz9dxAA`.replace(
+ /\s+/g,
+ '',
+ );
+
+ const psbt = bitcoin.Psbt.fromBase64(psbtBase64);
+
+ assert(
+ psbt.validateSignaturesOfAllInputs(schnorrValidator),
+ 'Should succeed validation',
+ );
+ });
});
function buildLeafIndexFinalizer(
diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts
index 84eb89c33..a69dc1e08 100644
--- a/ts_src/psbt.ts
+++ b/ts_src/psbt.ts
@@ -29,7 +29,6 @@ import {
isTaprootInput,
checkTaprootInputFields,
checkTaprootOutputFields,
- tweakInternalPubKey,
checkTaprootInputForSigs,
} from './psbt/bip371';
import {
@@ -42,6 +41,7 @@ import {
isP2WPKH,
isP2WSHScript,
isP2SHScript,
+ isP2TR,
} from './psbt/psbtutils';
export interface TransactionInput {
@@ -1701,8 +1701,10 @@ function getAllTaprootHashesForSig(
): { pubkey: Buffer; hash: Buffer; leafHash?: Buffer }[] {
const allPublicKeys = [];
if (input.tapInternalKey) {
- const outputKey = tweakInternalPubKey(inputIndex, input);
- allPublicKeys.push(outputKey);
+ const key = getPrevoutTaprootKey(inputIndex, input, cache);
+ if (key) {
+ allPublicKeys.push(key);
+ }
}
if (input.tapScriptSig) {
@@ -1717,8 +1719,17 @@ function getAllTaprootHashesForSig(
return allHashes.flat();
}
+function getPrevoutTaprootKey(
+ inputIndex: number,
+ input: PsbtInput,
+ cache: PsbtCache,
+): Buffer | null {
+ const { script } = getScriptAndAmountFromUtxo(inputIndex, input, cache);
+ return isP2TR(script) ? script.subarray(2, 34) : null;
+}
+
function trimTaprootSig(signature: Buffer): Buffer {
- return signature.length === 64 ? signature : signature.subarray(1);
+ return signature.length === 64 ? signature : signature.subarray(0, 64);
}
function getTaprootHashesForSig(
@@ -1743,7 +1754,8 @@ function getTaprootHashesForSig(
const hashes = [];
if (input.tapInternalKey && !tapLeafHashToSign) {
- const outputKey = tweakInternalPubKey(inputIndex, input);
+ const outputKey =
+ getPrevoutTaprootKey(inputIndex, input, cache) || Buffer.from([]);
if (toXOnly(pubkey).equals(outputKey)) {
const tapKeyHash = unsignedTx.hashForWitnessV1(
inputIndex,
From 8d2d7dbe4391a8de30f2e692c5b19d1167f28333 Mon Sep 17 00:00:00 2001
From: junderw
Date: Tue, 6 Jun 2023 22:52:58 -0700
Subject: [PATCH 128/144] 6.1.3
---
CHANGELOG.md | 4 ++++
package-lock.json | 2 +-
package.json | 2 +-
3 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 93fb78d0c..fc7dd6138 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+# 6.1.3
+__fixed__
+- validateSignaturesOfInput for taproot inputs returned false for valid signatures in specific cases. (#1934)
+
# 6.1.2
__fixed__
- validateSignaturesOfInput for taproot inputs returned true for invalid signatures in specific cases. (#1932)
diff --git a/package-lock.json b/package-lock.json
index f3a34063d..9ba7c2727 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "6.1.2",
+ "version": "6.1.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
diff --git a/package.json b/package.json
index bf6ac269c..747c8f0f6 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "6.1.2",
+ "version": "6.1.3",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"types": "./src/index.d.ts",
From e80d22bafcfdb0c4c5134c6fe2233de15a9bb4c7 Mon Sep 17 00:00:00 2001
From: Jonathan Underwood
Date: Wed, 19 Jul 2023 11:15:59 +0900
Subject: [PATCH 129/144] Update README.md
Include section about the Matrix rooms.
---
README.md | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index e1d7af69f..01a45733b 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,6 @@ Released under the terms of the [MIT LICENSE](LICENSE).
If you are thinking of using the *master* branch of this library in production, **stop**.
Master is not stable; it is our development branch, and [only tagged releases may be classified as stable](https://github.com/bitcoinjs/bitcoinjs-lib/tags).
-
## Can I trust this code?
> Don't trust. Verify.
@@ -23,12 +22,24 @@ Mistakes and bugs happen, but with your help in resolving and reporting [issues]
- Standardized, using [prettier](https://github.com/prettier/prettier) and Node `Buffer`'s throughout, and
- Friendly, with a strong and helpful community, ready to answer questions.
-
## Documentation
Presently, we do not have any formal documentation other than our [examples](#examples), please [ask for help](https://github.com/bitcoinjs/bitcoinjs-lib/issues/new) if our examples aren't enough to guide you.
You can find a [Web UI](https://bitcoincore.tech/apps/bitcoinjs-ui/index.html) that covers most of the `psbt.ts`, `transaction.ts` and `p2*.ts` APIs [here](https://bitcoincore.tech/apps/bitcoinjs-ui/index.html).
+## How can I contact the developers outside of Github?
+**Most of the time, this is not appropriate. Creating issues and pull requests in the open will help others with similar issues, so please try to use public issues and pull requests for communication.**
+
+That said, sometimes developers might be open to taking things off the record (ie. You want to share code that you don't want public to get help with it). In that case, please negotiate on the public issues as to where you will contact.
+
+We have created public rooms on IRC (`#bitcoinjs` on `libera.chat`) and Matrix (`#bitcoinjs-dev:matrix.org`). These two channels have been joined together in a Matrix "Space" which has the Matrix room AND an IRC bridge room that can converse with the IRC room. The "Space" is `#bitcoinjs-space:matrix.org`.
+
+Matrix and IRC both have functions for direct messaging, but IRC is not end to end encrypted, so Matrix is recommended for most communication. The official Matrix client maintained by the Matrix core team is called "Element" and can be downloaded here: https://element.io/download (Account creation is free on the matrix.org server, which is the default setting for Element.)
+
+We used to have a Slack. It is dead. If you find it, no one will answer you most likely.
+
+No we will not make a Discord.
+
## Installation
``` bash
npm install bitcoinjs-lib
From bcf1bf899324058ad9c70e8fa5a82f79acda0a13 Mon Sep 17 00:00:00 2001
From: junderw
Date: Mon, 28 Aug 2023 13:27:42 -0700
Subject: [PATCH 130/144] Bump package-lock.json version
---
package-lock.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package-lock.json b/package-lock.json
index 9ba7c2727..7543b1571 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6,7 +6,7 @@
"packages": {
"": {
"name": "bitcoinjs-lib",
- "version": "6.1.1",
+ "version": "6.1.3",
"license": "MIT",
"dependencies": {
"@noble/hashes": "^1.2.0",
From d60ba49a3c92c8ce2a2d350f17cbe66417f85e8c Mon Sep 17 00:00:00 2001
From: Waqas Ahmed
Date: Thu, 14 Sep 2023 22:12:45 +0500
Subject: [PATCH 131/144] Fixes issue#1974
Wrong method call fixed for the issue https://github.com/bitcoinjs/bitcoinjs-lib/issues/1974
---
src/address.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/address.js b/src/address.js
index 2712168a1..ada8042af 100644
--- a/src/address.js
+++ b/src/address.js
@@ -46,7 +46,7 @@ function fromBase58Check(address) {
// TODO: 4.0.0, move to "toOutputScript"
if (payload.length < 21) throw new TypeError(address + ' is too short');
if (payload.length > 21) throw new TypeError(address + ' is too long');
- const version = payload.readUint8(0);
+ const version = payload.readUInt8(0);
const hash = payload.slice(1);
return { version, hash };
}
From 1cd80e5fe8737e8c92d6e2e9ca1e813804d522bd Mon Sep 17 00:00:00 2001
From: junderw
Date: Thu, 14 Sep 2023 11:12:58 -0700
Subject: [PATCH 132/144] Fix TS as well
---
test/bufferutils.spec.ts | 2 +-
ts_src/address.ts | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/bufferutils.spec.ts b/test/bufferutils.spec.ts
index 0f1f1a901..6895f7e50 100644
--- a/test/bufferutils.spec.ts
+++ b/test/bufferutils.spec.ts
@@ -316,7 +316,7 @@ describe('bufferutils', () => {
}
}
- it('readUint8', () => {
+ it('readUInt8', () => {
const values = [0, 1, 0xfe, 0xff];
const buffer = Buffer.from([0, 1, 0xfe, 0xff]);
const bufferReader = new BufferReader(buffer);
diff --git a/ts_src/address.ts b/ts_src/address.ts
index a9c0e4103..ce224fd11 100644
--- a/ts_src/address.ts
+++ b/ts_src/address.ts
@@ -59,7 +59,7 @@ export function fromBase58Check(address: string): Base58CheckResult {
if (payload.length < 21) throw new TypeError(address + ' is too short');
if (payload.length > 21) throw new TypeError(address + ' is too long');
- const version = payload.readUint8(0);
+ const version = payload.readUInt8(0);
const hash = payload.slice(1);
return { version, hash };
From 105625fb0ae0a56ef50d567308f32292208d2a63 Mon Sep 17 00:00:00 2001
From: junderw
Date: Thu, 14 Sep 2023 11:27:50 -0700
Subject: [PATCH 133/144] 6.1.4
---
CHANGELOG.md | 4 ++++
package-lock.json | 2 +-
package.json | 2 +-
3 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fc7dd6138..0cffcca3e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+# 6.1.4
+__changed__
+- Changed internal usage of the Buffer API to match with newer broken bundlers that don't follow spec. The new usage is still compatible with older versions of Buffer, so there shouldn't be any breakage. The public API interface was not changed. (#1975)
+
# 6.1.3
__fixed__
- validateSignaturesOfInput for taproot inputs returned false for valid signatures in specific cases. (#1934)
diff --git a/package-lock.json b/package-lock.json
index 7543b1571..839c2724a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "6.1.3",
+ "version": "6.1.4",
"lockfileVersion": 2,
"requires": true,
"packages": {
diff --git a/package.json b/package.json
index 747c8f0f6..5ea1fbc6f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "6.1.3",
+ "version": "6.1.4",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"types": "./src/index.d.ts",
From 26ada310ae45747c0fa4689474138457b7cfcfda Mon Sep 17 00:00:00 2001
From: Arik Sosman
Date: Mon, 18 Sep 2023 13:33:28 -0700
Subject: [PATCH 134/144] Upgrade bip174 to 2.1.1.
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 5ea1fbc6f..e8fd47ae9 100644
--- a/package.json
+++ b/package.json
@@ -51,7 +51,7 @@
"dependencies": {
"@noble/hashes": "^1.2.0",
"bech32": "^2.0.0",
- "bip174": "^2.1.0",
+ "bip174": "^2.1.1",
"bs58check": "^3.0.1",
"typeforce": "^1.11.3",
"varuint-bitcoin": "^1.1.2"
From 8f5f244b0c86cd8a3b92e9451102e5c3c273ede6 Mon Sep 17 00:00:00 2001
From: Arik Sosman
Date: Mon, 18 Sep 2023 14:44:49 -0700
Subject: [PATCH 135/144] Update lockfile.
---
package-lock.json | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 839c2724a..2d7a35da7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6,12 +6,12 @@
"packages": {
"": {
"name": "bitcoinjs-lib",
- "version": "6.1.3",
+ "version": "6.1.4",
"license": "MIT",
"dependencies": {
"@noble/hashes": "^1.2.0",
"bech32": "^2.0.0",
- "bip174": "^2.1.0",
+ "bip174": "^2.1.1",
"bs58check": "^3.0.1",
"typeforce": "^1.11.3",
"varuint-bitcoin": "^1.1.2"
@@ -1171,9 +1171,9 @@
}
},
"node_modules/bip174": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/bip174/-/bip174-2.1.0.tgz",
- "integrity": "sha512-lkc0XyiX9E9KiVAS1ZiOqK1xfiwvf4FXDDdkDq5crcDzOq+xGytY+14qCsqz7kCiy8rpN1CRNfacRhf9G3JNSA==",
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/bip174/-/bip174-2.1.1.tgz",
+ "integrity": "sha512-mdFV5+/v0XyNYXjBS6CQPLo9ekCx4gtKZFnJm5PMto7Fs9hTTDpkkzOB7/FtluRI6JbUUAu+snTYfJRgHLZbZQ==",
"engines": {
"node": ">=8.0.0"
}
@@ -5267,9 +5267,9 @@
"dev": true
},
"bip174": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/bip174/-/bip174-2.1.0.tgz",
- "integrity": "sha512-lkc0XyiX9E9KiVAS1ZiOqK1xfiwvf4FXDDdkDq5crcDzOq+xGytY+14qCsqz7kCiy8rpN1CRNfacRhf9G3JNSA=="
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/bip174/-/bip174-2.1.1.tgz",
+ "integrity": "sha512-mdFV5+/v0XyNYXjBS6CQPLo9ekCx4gtKZFnJm5PMto7Fs9hTTDpkkzOB7/FtluRI6JbUUAu+snTYfJRgHLZbZQ=="
},
"bip32": {
"version": "4.0.0",
From 4af931720c164f680cad68cd0cd6faeeba77c85c Mon Sep 17 00:00:00 2001
From: junderw
Date: Mon, 18 Sep 2023 16:25:28 -0700
Subject: [PATCH 136/144] 6.1.5
---
CHANGELOG.md | 4 ++++
package-lock.json | 4 ++--
package.json | 2 +-
3 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0cffcca3e..d0485f0e8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+# 6.1.5
+__fixed__
+- Updated bip174 dependency to fix issue with unknownKeyVals. (#1979)
+
# 6.1.4
__changed__
- Changed internal usage of the Buffer API to match with newer broken bundlers that don't follow spec. The new usage is still compatible with older versions of Buffer, so there shouldn't be any breakage. The public API interface was not changed. (#1975)
diff --git a/package-lock.json b/package-lock.json
index 2d7a35da7..cb00c5608 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "bitcoinjs-lib",
- "version": "6.1.4",
+ "version": "6.1.5",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "bitcoinjs-lib",
- "version": "6.1.4",
+ "version": "6.1.5",
"license": "MIT",
"dependencies": {
"@noble/hashes": "^1.2.0",
diff --git a/package.json b/package.json
index e8fd47ae9..485afdbf8 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bitcoinjs-lib",
- "version": "6.1.4",
+ "version": "6.1.5",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
"types": "./src/index.d.ts",
From 4dd13313bf7682b026092bc9bde6e3fb358c5059 Mon Sep 17 00:00:00 2001
From: HashEngineering
Date: Fri, 26 Jan 2024 11:49:17 -0800
Subject: [PATCH 137/144] chore: use hashes-grs 1.2.0
---
package-lock.json | 15 ++++++++-------
package.json | 2 +-
src/crypto.js | 15 ++++++++++++---
ts_src/crypto.ts | 10 ++++++----
4 files changed, 27 insertions(+), 15 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index cb00c5608..37bec855d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -677,9 +677,9 @@
"@jridgewell/sourcemap-codec": "1.4.14"
}
},
- "node_modules/@noble/hashes": {
+ "node_modules/hashes-grs": {
"version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz",
+ "resolved": "https://registry.npmjs.org/hashes-grs/-/hashes-1.2.0.tgz",
"integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==",
"funding": [
{
@@ -1199,7 +1199,7 @@
"integrity": "sha512-c9kiwdk45Do5GL0vJMe7tS95VjCii65mYAH7DfWl3uW8AVzXKQVUm64i3hzVybBDMp9r7j9iNxR85+ul8MdN/A==",
"dev": true,
"dependencies": {
- "@noble/hashes": "^1.2.0"
+ "hashes-grs": "^1.2.0"
}
},
"node_modules/bip65": {
@@ -4931,10 +4931,11 @@
"@jridgewell/sourcemap-codec": "1.4.14"
}
},
- "@noble/hashes": {
+ "hashes-grs": {
"version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz",
- "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ=="
+ "resolved": "https://registry.npmjs.org/hashes-grs/-/hashes-1.2.0.tgz",
+ "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==",
+ "dev": true
},
"@nodelib/fs.scandir": {
"version": "2.1.5",
@@ -5289,7 +5290,7 @@
"integrity": "sha512-c9kiwdk45Do5GL0vJMe7tS95VjCii65mYAH7DfWl3uW8AVzXKQVUm64i3hzVybBDMp9r7j9iNxR85+ul8MdN/A==",
"dev": true,
"requires": {
- "@noble/hashes": "^1.2.0"
+ "hashes-grs": "^1.2.0"
}
},
"bip65": {
diff --git a/package.json b/package.json
index 9f263f471..7832a356f 100644
--- a/package.json
+++ b/package.json
@@ -49,7 +49,7 @@
"src"
],
"dependencies": {
- "@noble/hashes": "^1.2.0",
+ "hashes-grs": "^1.2.0",
"bech32": "^2.0.0",
"bip174": "^2.1.1",
"bs58grscheck": "^3.0.1",
diff --git a/src/crypto.js b/src/crypto.js
index af1224d25..bc3463422 100644
--- a/src/crypto.js
+++ b/src/crypto.js
@@ -3,15 +3,18 @@ Object.defineProperty(exports, '__esModule', { value: true });
exports.taggedHash =
exports.TAGGED_HASH_PREFIXES =
exports.TAGS =
+ exports.groestl =
exports.hash256 =
exports.hash160 =
exports.sha256 =
exports.sha1 =
exports.ripemd160 =
void 0;
-const ripemd160_1 = require('@noble/hashes/ripemd160');
-const sha1_1 = require('@noble/hashes/sha1');
-const sha256_1 = require('@noble/hashes/sha256');
+const ripemd160_1 = require('hashes-grs/ripemd160');
+const sha1_1 = require('hashes-grs/sha1');
+const sha256_1 = require('hashes-grs/sha256');
+const groestl512_1 = require('hashes-grs/groestl512');
+const groestl256_1 = require('hashes-grs/groestl256');
function ripemd160(buffer) {
return Buffer.from((0, ripemd160_1.ripemd160)(Uint8Array.from(buffer)));
}
@@ -36,6 +39,12 @@ function hash256(buffer) {
);
}
exports.hash256 = hash256;
+function groestl(buffer) {
+ return Buffer.from(
+ (0, groestl256_1.groestl256)((0, groestl512_1.groestl512)(buffer)),
+ );
+}
+exports.groestl = groestl;
exports.TAGS = [
'BIP0340/challenge',
'BIP0340/aux',
diff --git a/ts_src/crypto.ts b/ts_src/crypto.ts
index e2b83e9d9..c42ce70c7 100644
--- a/ts_src/crypto.ts
+++ b/ts_src/crypto.ts
@@ -1,6 +1,8 @@
-import { ripemd160 as _ripemd160 } from '@noble/hashes/ripemd160';
-import { sha1 as _sha1 } from '@noble/hashes/sha1';
-import { sha256 as _sha256 } from '@noble/hashes/sha256';
+import { ripemd160 as _ripemd160 } from 'hashes-grs/ripemd160';
+import { sha1 as _sha1 } from 'hashes-grs/sha1';
+import { sha256 as _sha256 } from 'hashes-grs/sha256';
+import { groestl512, groestl512 as _groest512 } from 'hashes-grs/groestl512';
+import { groestl256 as _groest256 } from 'hashes-grs/groestl256';
export function ripemd160(buffer: Buffer): Buffer {
return Buffer.from(_ripemd160(Uint8Array.from(buffer)));
@@ -23,7 +25,7 @@ export function hash256(buffer: Buffer): Buffer {
}
export function groestl(buffer: Buffer): Buffer {
- return new Buffer(groestlhash.groestl_2(buffer, 1, 1));
+ return Buffer.from(_groest256(groestl512(buffer)));
}
export const TAGS = [
From dfda1183dbb6f6b9a4795f03dd14eb125d66eafb Mon Sep 17 00:00:00 2001
From: HashEngineering
Date: Fri, 26 Jan 2024 11:49:56 -0800
Subject: [PATCH 138/144] fix: use bs58grscheck and other issues
---
package-lock.json | 175 +++++++++++++------------------
src/address.js | 20 ++--
src/crypto.d.ts | 1 +
src/payments/p2pkh.js | 6 +-
src/payments/p2sh.js | 6 +-
test/crypto.spec.ts | 16 +--
test/fixtures/address.json | 2 -
test/integration/taproot.spec.ts | 2 +-
ts_src/address.ts | 2 +-
9 files changed, 103 insertions(+), 127 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 37bec855d..8c89bcd39 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,24 +1,24 @@
{
- "name": "bitcoinjs-lib",
+ "name": "groestlcoinjs-lib",
"version": "6.1.5",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
- "name": "bitcoinjs-lib",
+ "name": "groestlcoinjs-lib",
"version": "6.1.5",
"license": "MIT",
"dependencies": {
- "@noble/hashes": "^1.2.0",
"bech32": "^2.0.0",
"bip174": "^2.1.1",
- "bs58check": "^3.0.1",
+ "bs58grscheck": "^3.0.1",
+ "hashes-grs": "^1.2.0",
"typeforce": "^1.11.3",
"varuint-bitcoin": "^1.1.2"
},
"devDependencies": {
"@types/bs58": "^4.0.0",
- "@types/bs58check": "^2.1.0",
+ "@types/bs58grscheck": "^2.1.0",
"@types/mocha": "^5.2.7",
"@types/node": "^16.11.7",
"@types/proxyquire": "^1.3.28",
@@ -26,13 +26,13 @@
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
"better-npm-audit": "^3.7.3",
- "bip32": "^4.0.0",
+ "bip32grs": "^4.0.0",
"bip39": "^3.1.0",
"bip65": "^1.0.1",
"bip68": "^1.0.3",
"bs58": "^4.0.0",
"dhttp": "^3.0.0",
- "ecpair": "^2.0.1",
+ "ecpairgrs": "^2.0.1",
"eslint": "^8.29.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.2.1",
@@ -681,6 +681,7 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/hashes-grs/-/hashes-1.2.0.tgz",
"integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==",
+ "dev": true,
"funding": [
{
"type": "individual",
@@ -723,18 +724,6 @@
"node": ">= 8"
}
},
- "node_modules/@scure/base": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz",
- "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==",
- "dev": true,
- "funding": [
- {
- "type": "individual",
- "url": "https://paulmillr.com/funding/"
- }
- ]
- },
"node_modules/@types/bs58": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@types/bs58/-/bs58-4.0.1.tgz",
@@ -744,10 +733,10 @@
"base-x": "^3.0.6"
}
},
- "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==",
+ "node_modules/@types/bs58grscheck": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/@types/bs58grscheck/-/bs58grscheck-2.1.2.tgz",
+ "integrity": "sha512-HF+N8m739H6bBEjuEMY2eE31A2VO+DBRcKOczIhtbP2A2qN1koaO2wruXobwdicYwFnc2+ei5Y5dJm765G/xvw==",
"dev": true,
"dependencies": {
"@types/node": "*"
@@ -1178,16 +1167,16 @@
"node": ">=8.0.0"
}
},
- "node_modules/bip32": {
+ "node_modules/bip32grs": {
"version": "4.0.0",
- "resolved": "https://registry.npmjs.org/bip32/-/bip32-4.0.0.tgz",
- "integrity": "sha512-aOGy88DDlVUhspIXJN+dVEtclhIsfAUppD43V0j40cPTld3pv/0X/MlrZSZ6jowIaQQzFwP8M6rFU2z2mVYjDQ==",
+ "resolved": "https://registry.npmjs.org/bip32grs/-/bip32grs-4.0.0.tgz",
+ "integrity": "sha512-VTenZ+6FKZEnAW8DiEV14bNmqqUS4HojYa5ALvl15QAkWjmQk12r4hD+Hb0CeAvbps1RbrKLW6lqeN9lDI6uKQ==",
"dev": true,
"dependencies": {
- "@noble/hashes": "^1.2.0",
- "@scure/base": "^1.1.1",
+ "bs58grscheck": "^3.0.1",
+ "hashes-grs": "^1.2.0",
"typeforce": "^1.11.5",
- "wif": "^2.0.6"
+ "wifgrs": "^2.0.6"
},
"engines": {
"node": ">=6.0.0"
@@ -1291,21 +1280,21 @@
"base-x": "^3.0.2"
}
},
- "node_modules/bs58check": {
+ "node_modules/bs58grscheck": {
"version": "3.0.1",
- "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-3.0.1.tgz",
- "integrity": "sha512-hjuuJvoWEybo7Hn/0xOrczQKKEKD63WguEjlhLExYs2wUBcebDC1jDNK17eEAD2lYfw82d5ASC1d7K3SWszjaQ==",
+ "resolved": "git+ssh://git@github.com/Groestlcoin/bs58grscheck.git#ab5b5e509f1754cb4764496df89d49bccfd48753",
+ "license": "MIT",
"dependencies": {
- "@noble/hashes": "^1.2.0",
- "bs58": "^5.0.0"
+ "bs58": "^5.0.0",
+ "hashes-grs": "1.2.0"
}
},
- "node_modules/bs58check/node_modules/base-x": {
+ "node_modules/bs58grscheck/node_modules/base-x": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.0.tgz",
"integrity": "sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw=="
},
- "node_modules/bs58check/node_modules/bs58": {
+ "node_modules/bs58grscheck/node_modules/bs58": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz",
"integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==",
@@ -1621,15 +1610,15 @@
"node": ">=6.0.0"
}
},
- "node_modules/ecpair": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/ecpair/-/ecpair-2.1.0.tgz",
- "integrity": "sha512-cL/mh3MtJutFOvFc27GPZE2pWL3a3k4YvzUWEOvilnfZVlH3Jwgx/7d6tlD7/75tNk8TG2m+7Kgtz0SI1tWcqw==",
+ "node_modules/ecpairgrs": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/ecpairgrs/-/ecpairgrs-2.0.1.tgz",
+ "integrity": "sha512-TeIyvUpbw8kwKMbERgNPL7xY+YWDw1Qdp9/ZPOQtKUw0VmiRRfi+wAj1RHhknd2hUb+9CvLt6s+3wzAksfUg5w==",
"dev": true,
"dependencies": {
"randombytes": "^2.1.0",
"typeforce": "^1.18.0",
- "wif": "^2.0.6"
+ "wifgrs": "^2.0.6"
},
"engines": {
"node": ">=8.0.0"
@@ -2323,6 +2312,16 @@
"node": ">=8"
}
},
+ "node_modules/hashes-grs": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/hashes-grs/-/hashes-grs-1.2.0.tgz",
+ "integrity": "sha512-CR6j5GrgbniTkgpuCUgYMkOlppWsDkBIodCspcU+9Nq4nvKfhxQ5dpN6dL22iqiCgDYi+417uknOGcD8ksj/0A==",
+ "funding": [
+ {
+ "url": "https://www.groestlcoin.org/donations/"
+ }
+ ]
+ },
"node_modules/he": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
@@ -4276,24 +4275,14 @@
"integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==",
"dev": true
},
- "node_modules/wif": {
+ "node_modules/wifgrs": {
"version": "2.0.6",
- "resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz",
- "integrity": "sha512-HIanZn1zmduSF+BQhkE+YXIbEiH0xPr1012QbFEGB0xsKqJii0/SqJjyn8dFv6y36kOznMgMB+LGcbZTJ1xACQ==",
- "dev": true,
- "dependencies": {
- "bs58check": "<3.0.0"
- }
- },
- "node_modules/wif/node_modules/bs58check": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz",
- "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==",
+ "resolved": "https://registry.npmjs.org/wifgrs/-/wifgrs-2.0.6.tgz",
+ "integrity": "sha512-Zufg+IptNYTF85Hkr6Jhf6C2XpGAW3b5WeQB+Tq+PfeX1Q0/rLbZSmRc1/3Gwum19jntxuGY5d6SRnbl/cM0+w==",
"dev": true,
"dependencies": {
- "bs58": "^4.0.0",
- "create-hash": "^1.1.0",
- "safe-buffer": "^5.1.2"
+ "bs58grscheck": "git+https://github.com/Groestlcoin/bs58grscheck.git",
+ "safe-buffer": "^5.1.1"
}
},
"node_modules/word-wrap": {
@@ -4963,12 +4952,6 @@
"fastq": "^1.6.0"
}
},
- "@scure/base": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz",
- "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==",
- "dev": true
- },
"@types/bs58": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@types/bs58/-/bs58-4.0.1.tgz",
@@ -4978,10 +4961,10 @@
"base-x": "^3.0.6"
}
},
- "@types/bs58check": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@types/bs58check/-/bs58check-2.1.0.tgz",
- "integrity": "sha512-OxsysnJQh82vy9DRbOcw9m2j/WiyqZLn0YBhKxdQ+aCwoHj+tWzyCgpwAkr79IfDXZKxc6h7k89T9pwS78CqTQ==",
+ "@types/bs58grscheck": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/@types/bs58grscheck/-/bs58grscheck-2.1.2.tgz",
+ "integrity": "sha512-HF+N8m739H6bBEjuEMY2eE31A2VO+DBRcKOczIhtbP2A2qN1koaO2wruXobwdicYwFnc2+ei5Y5dJm765G/xvw==",
"dev": true,
"requires": {
"@types/node": "*"
@@ -5272,16 +5255,16 @@
"resolved": "https://registry.npmjs.org/bip174/-/bip174-2.1.1.tgz",
"integrity": "sha512-mdFV5+/v0XyNYXjBS6CQPLo9ekCx4gtKZFnJm5PMto7Fs9hTTDpkkzOB7/FtluRI6JbUUAu+snTYfJRgHLZbZQ=="
},
- "bip32": {
+ "bip32grs": {
"version": "4.0.0",
- "resolved": "https://registry.npmjs.org/bip32/-/bip32-4.0.0.tgz",
- "integrity": "sha512-aOGy88DDlVUhspIXJN+dVEtclhIsfAUppD43V0j40cPTld3pv/0X/MlrZSZ6jowIaQQzFwP8M6rFU2z2mVYjDQ==",
+ "resolved": "https://registry.npmjs.org/bip32grs/-/bip32grs-4.0.0.tgz",
+ "integrity": "sha512-VTenZ+6FKZEnAW8DiEV14bNmqqUS4HojYa5ALvl15QAkWjmQk12r4hD+Hb0CeAvbps1RbrKLW6lqeN9lDI6uKQ==",
"dev": true,
"requires": {
- "@noble/hashes": "^1.2.0",
- "@scure/base": "^1.1.1",
+ "bs58grscheck": "^3.0.1",
+ "hashes-grs": "^1.2.0",
"typeforce": "^1.11.5",
- "wif": "^2.0.6"
+ "wifgrs": "^2.0.6"
}
},
"bip39": {
@@ -5357,13 +5340,12 @@
"base-x": "^3.0.2"
}
},
- "bs58check": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-3.0.1.tgz",
- "integrity": "sha512-hjuuJvoWEybo7Hn/0xOrczQKKEKD63WguEjlhLExYs2wUBcebDC1jDNK17eEAD2lYfw82d5ASC1d7K3SWszjaQ==",
+ "bs58grscheck": {
+ "version": "git+ssh://git@github.com/Groestlcoin/bs58grscheck.git#ab5b5e509f1754cb4764496df89d49bccfd48753",
+ "from": "bs58grscheck@^3.0.1",
"requires": {
- "@noble/hashes": "^1.2.0",
- "bs58": "^5.0.0"
+ "bs58": "^5.0.0",
+ "hashes-grs": "1.2.0"
},
"dependencies": {
"base-x": {
@@ -5613,15 +5595,15 @@
"esutils": "^2.0.2"
}
},
- "ecpair": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/ecpair/-/ecpair-2.1.0.tgz",
- "integrity": "sha512-cL/mh3MtJutFOvFc27GPZE2pWL3a3k4YvzUWEOvilnfZVlH3Jwgx/7d6tlD7/75tNk8TG2m+7Kgtz0SI1tWcqw==",
+ "ecpairgrs": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/ecpairgrs/-/ecpairgrs-2.0.1.tgz",
+ "integrity": "sha512-TeIyvUpbw8kwKMbERgNPL7xY+YWDw1Qdp9/ZPOQtKUw0VmiRRfi+wAj1RHhknd2hUb+9CvLt6s+3wzAksfUg5w==",
"dev": true,
"requires": {
"randombytes": "^2.1.0",
"typeforce": "^1.18.0",
- "wif": "^2.0.6"
+ "wifgrs": "^2.0.6"
}
},
"electron-to-chromium": {
@@ -6125,6 +6107,11 @@
}
}
},
+ "hashes-grs": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/hashes-grs/-/hashes-grs-1.2.0.tgz",
+ "integrity": "sha512-CR6j5GrgbniTkgpuCUgYMkOlppWsDkBIodCspcU+9Nq4nvKfhxQ5dpN6dL22iqiCgDYi+417uknOGcD8ksj/0A=="
+ },
"he": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
@@ -7572,26 +7559,14 @@
"integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==",
"dev": true
},
- "wif": {
+ "wifgrs": {
"version": "2.0.6",
- "resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz",
- "integrity": "sha512-HIanZn1zmduSF+BQhkE+YXIbEiH0xPr1012QbFEGB0xsKqJii0/SqJjyn8dFv6y36kOznMgMB+LGcbZTJ1xACQ==",
+ "resolved": "https://registry.npmjs.org/wifgrs/-/wifgrs-2.0.6.tgz",
+ "integrity": "sha512-Zufg+IptNYTF85Hkr6Jhf6C2XpGAW3b5WeQB+Tq+PfeX1Q0/rLbZSmRc1/3Gwum19jntxuGY5d6SRnbl/cM0+w==",
"dev": true,
"requires": {
- "bs58check": "<3.0.0"
- },
- "dependencies": {
- "bs58check": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz",
- "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==",
- "dev": true,
- "requires": {
- "bs58": "^4.0.0",
- "create-hash": "^1.1.0",
- "safe-buffer": "^5.1.2"
- }
- }
+ "bs58grscheck": "git+https://github.com/Groestlcoin/bs58grscheck.git",
+ "safe-buffer": "^5.1.1"
}
},
"word-wrap": {
diff --git a/src/address.js b/src/address.js
index ada8042af..3895115a6 100644
--- a/src/address.js
+++ b/src/address.js
@@ -3,16 +3,16 @@ Object.defineProperty(exports, '__esModule', { value: true });
exports.toOutputScript =
exports.fromOutputScript =
exports.toBech32 =
- exports.toBase58Check =
+ exports.toBase58GrsCheck =
exports.fromBech32 =
- exports.fromBase58Check =
+ exports.fromBase58GrsCheck =
void 0;
const networks = require('./networks');
const payments = require('./payments');
const bscript = require('./script');
const types_1 = require('./types');
const bech32_1 = require('bech32');
-const bs58check = require('bs58check');
+const bs58grscheck = require('bs58grscheck');
const FUTURE_SEGWIT_MAX_SIZE = 40;
const FUTURE_SEGWIT_MIN_SIZE = 2;
const FUTURE_SEGWIT_MAX_VERSION = 16;
@@ -41,8 +41,8 @@ function _toFutureSegwitAddress(output, network) {
console.warn(FUTURE_SEGWIT_VERSION_WARNING);
return toBech32(data, version, network.bech32);
}
-function fromBase58Check(address) {
- const payload = Buffer.from(bs58check.decode(address));
+function fromBase58GrsCheck(address) {
+ const payload = Buffer.from(bs58grscheck.decode(address));
// TODO: 4.0.0, move to "toOutputScript"
if (payload.length < 21) throw new TypeError(address + ' is too short');
if (payload.length > 21) throw new TypeError(address + ' is too long');
@@ -50,7 +50,7 @@ function fromBase58Check(address) {
const hash = payload.slice(1);
return { version, hash };
}
-exports.fromBase58Check = fromBase58Check;
+exports.fromBase58GrsCheck = fromBase58GrsCheck;
function fromBech32(address) {
let result;
let version;
@@ -73,7 +73,7 @@ function fromBech32(address) {
};
}
exports.fromBech32 = fromBech32;
-function toBase58Check(hash, version) {
+function toBase58GrsCheck(hash, version) {
(0, types_1.typeforce)(
(0, types_1.tuple)(types_1.Hash160bit, types_1.UInt8),
arguments,
@@ -81,9 +81,9 @@ function toBase58Check(hash, version) {
const payload = Buffer.allocUnsafe(21);
payload.writeUInt8(version, 0);
hash.copy(payload, 1);
- return bs58check.encode(payload);
+ return bs58grscheck.encode(payload);
}
-exports.toBase58Check = toBase58Check;
+exports.toBase58GrsCheck = toBase58GrsCheck;
function toBech32(data, version, prefix) {
const words = bech32_1.bech32.toWords(data);
words.unshift(version);
@@ -121,7 +121,7 @@ function toOutputScript(address, network) {
let decodeBase58;
let decodeBech32;
try {
- decodeBase58 = fromBase58Check(address);
+ decodeBase58 = fromBase58GrsCheck(address);
} catch (e) {}
if (decodeBase58) {
if (decodeBase58.version === network.pubKeyHash)
diff --git a/src/crypto.d.ts b/src/crypto.d.ts
index 1a465dad1..abdd3e578 100644
--- a/src/crypto.d.ts
+++ b/src/crypto.d.ts
@@ -4,6 +4,7 @@ export declare function sha1(buffer: Buffer): Buffer;
export declare function sha256(buffer: Buffer): Buffer;
export declare function hash160(buffer: Buffer): Buffer;
export declare function hash256(buffer: Buffer): Buffer;
+export declare function groestl(buffer: Buffer): Buffer;
export declare const TAGS: readonly ["BIP0340/challenge", "BIP0340/aux", "BIP0340/nonce", "TapLeaf", "TapBranch", "TapSighash", "TapTweak", "KeyAgg list", "KeyAgg coefficient"];
export type TaggedHashPrefix = typeof TAGS[number];
type TaggedHashPrefixes = {
diff --git a/src/payments/p2pkh.js b/src/payments/p2pkh.js
index 16e293d59..82e0a6a23 100644
--- a/src/payments/p2pkh.js
+++ b/src/payments/p2pkh.js
@@ -6,7 +6,7 @@ const networks_1 = require('../networks');
const bscript = require('../script');
const types_1 = require('../types');
const lazy = require('./lazy');
-const bs58check = require('bs58check');
+const bs58grscheck = require('bs58grscheck');
const OPS = bscript.OPS;
// input: {signature} {pubkey}
// output: OP_DUP OP_HASH160 {hash160(pubkey)} OP_EQUALVERIFY OP_CHECKSIG
@@ -27,7 +27,7 @@ function p2pkh(a, opts) {
a,
);
const _address = lazy.value(() => {
- const payload = Buffer.from(bs58check.decode(a.address));
+ const payload = Buffer.from(bs58grscheck.decode(a.address));
const version = payload.readUInt8(0);
const hash = payload.slice(1);
return { version, hash };
@@ -42,7 +42,7 @@ function p2pkh(a, opts) {
const payload = Buffer.allocUnsafe(21);
payload.writeUInt8(network.pubKeyHash, 0);
o.hash.copy(payload, 1);
- return bs58check.encode(payload);
+ return bs58grscheck.encode(payload);
});
lazy.prop(o, 'hash', () => {
if (a.output) return a.output.slice(3, 23);
diff --git a/src/payments/p2sh.js b/src/payments/p2sh.js
index b280fcafa..8a5009952 100644
--- a/src/payments/p2sh.js
+++ b/src/payments/p2sh.js
@@ -6,7 +6,7 @@ const networks_1 = require('../networks');
const bscript = require('../script');
const types_1 = require('../types');
const lazy = require('./lazy');
-const bs58check = require('bs58check');
+const bs58grscheck = require('bs58grscheck');
const OPS = bscript.OPS;
function stacksEqual(a, b) {
if (a.length !== b.length) return false;
@@ -48,7 +48,7 @@ function p2sh(a, opts) {
}
const o = { network };
const _address = lazy.value(() => {
- const payload = Buffer.from(bs58check.decode(a.address));
+ const payload = Buffer.from(bs58grscheck.decode(a.address));
const version = payload.readUInt8(0);
const hash = payload.slice(1);
return { version, hash };
@@ -72,7 +72,7 @@ function p2sh(a, opts) {
const payload = Buffer.allocUnsafe(21);
payload.writeUInt8(o.network.scriptHash, 0);
o.hash.copy(payload, 1);
- return bs58check.encode(payload);
+ return bs58grscheck.encode(payload);
});
lazy.prop(o, 'hash', () => {
// in order of least effort
diff --git a/test/crypto.spec.ts b/test/crypto.spec.ts
index 862baaaa2..eb53b297f 100644
--- a/test/crypto.spec.ts
+++ b/test/crypto.spec.ts
@@ -5,21 +5,23 @@ import * as fixtures from './fixtures/crypto.json';
import { sha256, TAGS, TAGGED_HASH_PREFIXES } from '../src/crypto';
describe('crypto', () => {
- ['groestl', 'hash160', 'hash256', 'ripemd160', 'sha1', 'sha256'].forEach(algorithm => {
- describe(algorithm, () => {
- fixtures.hashes.forEach(f => {
- const fn = (bcrypto as any)[algorithm];
- const expected = (f as any)[algorithm];
+ ['groestl', 'hash160', 'hash256', 'ripemd160', 'sha1', 'sha256'].forEach(
+ algorithm => {
+ describe(algorithm, () => {
+ fixtures.hashes.forEach(f => {
+ const fn = (bcrypto as any)[algorithm];
+ const expected = (f as any)[algorithm];
it('returns ' + expected + ' for ' + f.hex, () => {
const data = Buffer.from(f.hex, 'hex');
const actual = fn(data).toString('hex');
assert.strictEqual(actual, expected);
+ });
});
});
- });
- });
+ },
+ );
describe('taggedHash', () => {
fixtures.taggedHash.forEach(f => {
diff --git a/test/fixtures/address.json b/test/fixtures/address.json
index 01a0f0cc3..d75a9731f 100644
--- a/test/fixtures/address.json
+++ b/test/fixtures/address.json
@@ -106,8 +106,6 @@
"version": 1,
"prefix": "grs",
"data": "751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6"
- "prefix": "bc",
- "data": "8e5203f25093c03a199b87b6c39427c09f8181abe1b25dc34818106c160884d7"
},
{
"address": "bc1zw508d6qejxtdg4y5r3zarvaryvaxxpcs",
diff --git a/test/integration/taproot.spec.ts b/test/integration/taproot.spec.ts
index 911962262..e5a718303 100644
--- a/test/integration/taproot.spec.ts
+++ b/test/integration/taproot.spec.ts
@@ -1,7 +1,7 @@
import * as assert from 'assert';
import BIP32Factory from 'bip32grs';
import * as bip39 from 'bip39';
-import ECPairFactory from 'ecpair';
+import ECPairFactory from 'ecpairgrs';
import * as ecc from 'tiny-secp256k1';
import { describe, it } from 'mocha';
import { PsbtInput, TapLeafScript } from 'bip174/src/lib/interfaces';
diff --git a/ts_src/address.ts b/ts_src/address.ts
index d0ae35559..103b47b51 100644
--- a/ts_src/address.ts
+++ b/ts_src/address.ts
@@ -53,7 +53,7 @@ function _toFutureSegwitAddress(output: Buffer, network: Network): string {
}
export function fromBase58GrsCheck(address: string): Base58GrsCheckResult {
- const payload = bs58grscheck.decode(address);
+ const payload = Buffer.from(bs58grscheck.decode(address));
// TODO: 4.0.0, move to "toOutputScript"
if (payload.length < 21) throw new TypeError(address + ' is too short');
From 299c6b096dc75db5034e88476c80cc6579b4705d Mon Sep 17 00:00:00 2001
From: gruve-p
Date: Fri, 26 Jan 2024 21:29:21 +0100
Subject: [PATCH 139/144] Minor fixes
---
README.md | 15 +--------------
ts_src/crypto.ts | 6 +++---
2 files changed, 4 insertions(+), 17 deletions(-)
diff --git a/README.md b/README.md
index 64d061dcf..9cfcebf57 100644
--- a/README.md
+++ b/README.md
@@ -23,19 +23,6 @@ Mistakes and bugs happen, but with your help in resolving and reporting [issues]
## Documentation
Presently, we do not have any formal documentation other than our [examples](#examples), please [ask for help](https://github.com/groestlcoin/groestlcoinjs-lib/issues/new) if our examples aren't enough to guide you.
-## How can I contact the developers outside of Github?
-**Most of the time, this is not appropriate. Creating issues and pull requests in the open will help others with similar issues, so please try to use public issues and pull requests for communication.**
-
-That said, sometimes developers might be open to taking things off the record (ie. You want to share code that you don't want public to get help with it). In that case, please negotiate on the public issues as to where you will contact.
-
-We have created public rooms on IRC (`#bitcoinjs` on `libera.chat`) and Matrix (`#bitcoinjs-dev:matrix.org`). These two channels have been joined together in a Matrix "Space" which has the Matrix room AND an IRC bridge room that can converse with the IRC room. The "Space" is `#bitcoinjs-space:matrix.org`.
-
-Matrix and IRC both have functions for direct messaging, but IRC is not end to end encrypted, so Matrix is recommended for most communication. The official Matrix client maintained by the Matrix core team is called "Element" and can be downloaded here: https://element.io/download (Account creation is free on the matrix.org server, which is the default setting for Element.)
-
-We used to have a Slack. It is dead. If you find it, no one will answer you most likely.
-
-No we will not make a Discord.
-
## Installation
``` bash
npm install groestlcoinjs-lib
@@ -94,7 +81,7 @@ $ npx browserify --standalone groestlcoin - -o groestlcoinjs-lib.js <<<"module.e
Which you can then import as an ESM module:
```javascript
-
+
````
**NOTE**: We use Node Maintenance LTS features, if you need strict ES5, use [`--transform babelify`](https://github.com/babel/babelify) in conjunction with your `browserify` step (using an [`es2015`](https://babeljs.io/docs/plugins/preset-es2015/) preset).
diff --git a/ts_src/crypto.ts b/ts_src/crypto.ts
index c42ce70c7..5b3ba8ff2 100644
--- a/ts_src/crypto.ts
+++ b/ts_src/crypto.ts
@@ -1,8 +1,8 @@
import { ripemd160 as _ripemd160 } from 'hashes-grs/ripemd160';
import { sha1 as _sha1 } from 'hashes-grs/sha1';
import { sha256 as _sha256 } from 'hashes-grs/sha256';
-import { groestl512, groestl512 as _groest512 } from 'hashes-grs/groestl512';
-import { groestl256 as _groest256 } from 'hashes-grs/groestl256';
+import { groestl512 as _groestl512 } from 'hashes-grs/groestl512';
+import { groestl256 as _groestl256 } from 'hashes-grs/groestl256';
export function ripemd160(buffer: Buffer): Buffer {
return Buffer.from(_ripemd160(Uint8Array.from(buffer)));
@@ -25,7 +25,7 @@ export function hash256(buffer: Buffer): Buffer {
}
export function groestl(buffer: Buffer): Buffer {
- return Buffer.from(_groest256(groestl512(buffer)));
+ return Buffer.from(_groestl256(_groestl512(buffer)));
}
export const TAGS = [
From 75672ed736bee7172f32b058c5fb9d9a24aa4229 Mon Sep 17 00:00:00 2001
From: HashEngineering
Date: Fri, 26 Jan 2024 14:08:54 -0800
Subject: [PATCH 140/144] tests: fix test vectors for address.json
---
test/fixtures/address.json | 38 +++++++++++++-------------------------
1 file changed, 13 insertions(+), 25 deletions(-)
diff --git a/test/fixtures/address.json b/test/fixtures/address.json
index d75a9731f..caba800ac 100644
--- a/test/fixtures/address.json
+++ b/test/fixtures/address.json
@@ -66,21 +66,21 @@
},
{
"network": "bitcoin",
- "bech32": "bc1p3efq8ujsj0qr5xvms7mv89p8cz0crqdtuxe9ms6grqgxc9sgsntslthf6w",
+ "bech32": "grs1p3efq8ujsj0qr5xvms7mv89p8cz0crqdtuxe9ms6grqgxc9sgsntsssg942",
"version": 1,
"data": "8e5203f25093c03a199b87b6c39427c09f8181abe1b25dc34818106c160884d7",
"script": "OP_1 8e5203f25093c03a199b87b6c39427c09f8181abe1b25dc34818106c160884d7"
},
{
"network": "bitcoin",
- "bech32": "BC1SW50QGDZ25J",
+ "bech32": "GRS1SW50QUA74JP",
"version": 16,
"data": "751e",
"script": "OP_16 751e"
},
{
"network": "bitcoin",
- "bech32": "bc1zw508d6qejxtdg4y5r3zarvaryvaxxpcs",
+ "bech32": "grs1zw508d6qejxtdg4y5r3zarvaryv8vlr2l",
"version": 2,
"data": "751e76e8199196d454941c45d1b3a323",
"script": "OP_2 751e76e8199196d454941c45d1b3a323"
@@ -108,39 +108,27 @@
"data": "751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6"
},
{
- "address": "bc1zw508d6qejxtdg4y5r3zarvaryvaxxpcs",
- "version": 2,
- "prefix": "bc",
- "data": "751e76e8199196d454941c45d1b3a323"
- },
- {
- "address": "BC1SW50QGDZ25J",
- "version": 16,
- "prefix": "bc",
- "data": "751e"
- },
- {
- "address": "tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy",
+ "address": "tgrs1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsess668a6",
"version": 0,
- "prefix": "tb",
+ "prefix": "tgrs",
"data": "000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433"
},
{
- "address": "bc1p3efq8ujsj0qr5xvms7mv89p8cz0crqdtuxe9ms6grqgxc9sgsntslthf6w",
+ "address": "grs1p3efq8ujsj0qr5xvms7mv89p8cz0crqdtuxe9ms6grqgxc9sgsntsssg942",
"version": 1,
- "prefix": "bc",
+ "prefix": "grs",
"data": "8e5203f25093c03a199b87b6c39427c09f8181abe1b25dc34818106c160884d7"
},
{
- "address": "bc1zw508d6qejxtdg4y5r3zarvaryvaxxpcs",
+ "address": "grs1zw508d6qejxtdg4y5r3zarvaryv8vlr2l",
"version": 2,
- "prefix": "bc",
+ "prefix": "grs",
"data": "751e76e8199196d454941c45d1b3a323"
},
{
- "address": "BC1SW50QGDZ25J",
+ "address": "GRS1SW50QUA74JP",
"version": 16,
- "prefix": "bc",
+ "prefix": "grs",
"data": "751e"
}
],
@@ -281,11 +269,11 @@
"exception": "has no matching Script"
},
{
- "address": "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw55h884v",
+ "address": "grs1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5eqyqa4",
"exception": "has no matching Script"
},
{
- "address": "bc1pllllllllllllllllllllllllllllllllllllllllllllallllshsdfvw2y",
+ "address": "grs1pllllllllllllllllllllllllllllllllllllllllllllallllshszjnz9q",
"paymentException": "TypeError: Invalid pubkey for p2tr"
}
]
From 5a33bc61f4d8fbe73e95817bcfdb046f75952665 Mon Sep 17 00:00:00 2001
From: HashEngineering
Date: Fri, 26 Jan 2024 14:48:08 -0800
Subject: [PATCH 141/144] tests: fix test vectors for p2tr.json and psbt.json
---
test/fixtures/p2tr.json | 66 ++++++++++++++++++++---------------------
test/fixtures/psbt.json | 30 +++++++++----------
2 files changed, 48 insertions(+), 48 deletions(-)
diff --git a/test/fixtures/p2tr.json b/test/fixtures/p2tr.json
index aaa82fbb4..85b9248ab 100644
--- a/test/fixtures/p2tr.json
+++ b/test/fixtures/p2tr.json
@@ -3,7 +3,7 @@
{
"description": "output and pubkey from address",
"arguments": {
- "address": "bc1p4dss6gkgq8003g0qyd5drwfqrztsadf2w2v3juz73gdz7cx82r6sj7lcqx"
+ "address": "grs1p4dss6gkgq8003g0qyd5drwfqrztsadf2w2v3juz73gdz7cx82r6sa9q50z"
},
"options": {},
"expected": {
@@ -22,7 +22,7 @@
},
"expected": {
"name": "p2tr",
- "address": "bc1p4dss6gkgq8003g0qyd5drwfqrztsadf2w2v3juz73gdz7cx82r6sj7lcqx",
+ "address": "grs1p4dss6gkgq8003g0qyd5drwfqrztsadf2w2v3juz73gdz7cx82r6sa9q50z",
"pubkey": "ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5",
"signature": null,
"input": null,
@@ -36,7 +36,7 @@
},
"expected": {
"name": "p2tr",
- "address": "bc1p4dss6gkgq8003g0qyd5drwfqrztsadf2w2v3juz73gdz7cx82r6sj7lcqx",
+ "address": "grs1p4dss6gkgq8003g0qyd5drwfqrztsadf2w2v3juz73gdz7cx82r6sa9q50z",
"output": "OP_1 ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5",
"signature": null,
"input": null,
@@ -51,7 +51,7 @@
},
"expected": {
"name": "p2tr",
- "address": "bc1p4dss6gkgq8003g0qyd5drwfqrztsadf2w2v3juz73gdz7cx82r6sj7lcqx",
+ "address": "grs1p4dss6gkgq8003g0qyd5drwfqrztsadf2w2v3juz73gdz7cx82r6sa9q50z",
"output": "OP_1 ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5",
"input": null,
"witness": [
@@ -69,7 +69,7 @@
},
"expected": {
"name": "p2tr",
- "address": "bc1p4dss6gkgq8003g0qyd5drwfqrztsadf2w2v3juz73gdz7cx82r6sj7lcqx",
+ "address": "grs1p4dss6gkgq8003g0qyd5drwfqrztsadf2w2v3juz73gdz7cx82r6sa9q50z",
"output": "OP_1 ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5",
"input": null,
"signature": "300602010002010001",
@@ -85,7 +85,7 @@
},
"expected": {
"name": "p2tr",
- "address": "bc1prs7pxymu7jhsptzjlwlqnk8jyg5qmq4sdlc3rwcy7pd3ydz92xjq5ap2sg",
+ "address": "grs1prs7pxymu7jhsptzjlwlqnk8jyg5qmq4sdlc3rwcy7pd3ydz92xjqmx7xlv",
"pubkey": "1c3c13137cf4af00ac52fbbe09d8f222280d82b06ff111bb04f05b12344551a4",
"output": "OP_1 1c3c13137cf4af00ac52fbbe09d8f222280d82b06ff111bb04f05b12344551a4",
"signature": null,
@@ -108,7 +108,7 @@
"internalPubkey": "a7957acbaaf7b444c53d9e0c9436e8a8a3247fd515095d66ddf6201918b40a36",
"pubkey": "1ebe8b90363bd097aa9f352c8b21914e1886bc09fe9e70c09f33ef2d2abdf4bc",
"hash": "c5c62d7fc595ba5fbe61602eb1a29e2e4763408fe1e2b161beb7cb3c71ebcad9",
- "address": "bc1pr6lghypk80gf025lx5kgkgv3fcvgd0qfl608psylx0hj624a7j7qay80rv",
+ "address": "grs1pr6lghypk80gf025lx5kgkgv3fcvgd0qfl608psylx0hj624a7j7qjlcrvg",
"output": "OP_1 1ebe8b90363bd097aa9f352c8b21914e1886bc09fe9e70c09f33ef2d2abdf4bc",
"signature": null,
"input": null,
@@ -144,7 +144,7 @@
"internalPubkey": "a7957acbaaf7b444c53d9e0c9436e8a8a3247fd515095d66ddf6201918b40a36",
"pubkey": "1ebe8b90363bd097aa9f352c8b21914e1886bc09fe9e70c09f33ef2d2abdf4bc",
"hash": "c5c62d7fc595ba5fbe61602eb1a29e2e4763408fe1e2b161beb7cb3c71ebcad9",
- "address": "bc1pr6lghypk80gf025lx5kgkgv3fcvgd0qfl608psylx0hj624a7j7qay80rv",
+ "address": "grs1pr6lghypk80gf025lx5kgkgv3fcvgd0qfl608psylx0hj624a7j7qjlcrvg",
"output": "OP_1 1ebe8b90363bd097aa9f352c8b21914e1886bc09fe9e70c09f33ef2d2abdf4bc",
"signature": null,
"input": null,
@@ -167,7 +167,7 @@
},
"expected": {
"name": "p2tr",
- "address": "bc1pjegs09vkeder9m4sw3ycjf2rnpa8nljdqmuleunk9eshu8cq3xysvhgp2u",
+ "address": "grs1pjegs09vkeder9m4sw3ycjf2rnpa8nljdqmuleunk9eshu8cq3xysrvhd9c",
"pubkey": "9651079596cb7232eeb07449892543987a79fe4d06f9fcf2762e617e1f008989",
"output": "OP_1 9651079596cb7232eeb07449892543987a79fe4d06f9fcf2762e617e1f008989",
"hash": "16e3f3b8b9c1e453c56b547785cdd25259d65823a2064f30783acc58ef012633",
@@ -191,7 +191,7 @@
},
"expected": {
"name": "p2tr",
- "address": "bc1ptj0v8rwcj6s36p4r26ws6htx0fct43n0mxdvdeh9043whlxlq3kq9965ke",
+ "address": "grs1ptj0v8rwcj6s36p4r26ws6htx0fct43n0mxdvdeh9043whlxlq3kq279cea",
"pubkey": "5c9ec38dd896a11d06a3569d0d5d667a70bac66fd99ac6e6e57d62ebfcdf046c",
"output": "OP_1 5c9ec38dd896a11d06a3569d0d5d667a70bac66fd99ac6e6e57d62ebfcdf046c",
"hash": "ce00198cd4667abae1f94aa5862d089e2967af5aec20715c692db74e3d66bb73",
@@ -220,7 +220,7 @@
},
"expected": {
"name": "p2tr",
- "address": "bc1pkq0t8nkmqswn3qjg9uy6ux2hsyyz4as25v8unfjc9s8q2e4c00sqku9lxh",
+ "address": "grs1pkq0t8nkmqswn3qjg9uy6ux2hsyyz4as25v8unfjc9s8q2e4c00sqe86nfn",
"pubkey": "b01eb3cedb041d3882482f09ae195781082af60aa30fc9a6582c0e0566b87be0",
"output": "OP_1 b01eb3cedb041d3882482f09ae195781082af60aa30fc9a6582c0e0566b87be0",
"hash": "7ae0cc2057b1a7bf0e09c787e1d7b6b2355ac112a7b80380a5c1e942155b0c0f",
@@ -254,7 +254,7 @@
},
"expected": {
"name": "p2tr",
- "address": "bc1pstdzevc40j059s0473rghhv9e05l9f5xv7l6dtlavvq22rzfna3syjvjut",
+ "address": "grs1pstdzevc40j059s0473rghhv9e05l9f5xv7l6dtlavvq22rzfna3stfn7n0",
"pubkey": "82da2cb3157c9f42c1f5f4468bdd85cbe9f2a68667bfa6affd6300a50c499f63",
"output": "OP_1 82da2cb3157c9f42c1f5f4468bdd85cbe9f2a68667bfa6affd6300a50c499f63",
"hash": "d673e784eac9b70289130a0bd359023a0fbdde51dc069b9efb4157c2cdce3ea5",
@@ -303,7 +303,7 @@
},
"expected": {
"name": "p2tr",
- "address": "bc1pfas4r5s5208puwzj20hvwg2dw2kanc06yxczzdd66729z63pk43q7zwlu6",
+ "address": "grs1pfas4r5s5208puwzj20hvwg2dw2kanc06yxczzdd66729z63pk43q3e3nn7",
"pubkey": "4f6151d21453ce1e385253eec7214d72add9e1fa21b02135bad794516a21b562",
"output": "OP_1 4f6151d21453ce1e385253eec7214d72add9e1fa21b02135bad794516a21b562",
"hash": "16fb2e99bdf86f67ee6980d0418658f15df7e19476053b58f45a89df2e219b1b",
@@ -323,7 +323,7 @@
},
"expected": {
"name": "p2tr",
- "address": "bc1pnxyp0ahcg53jzgrzj57hnlgdtqtzn7qqhmgjgczk8hzhcltq974qazepzf",
+ "address": "grs1pnxyp0ahcg53jzgrzj57hnlgdtqtzn7qqhmgjgczk8hzhcltq974qjexddd",
"pubkey": "998817f6f84523212062953d79fd0d581629f800bed12460563dc57c7d602faa",
"output": "OP_1 998817f6f84523212062953d79fd0d581629f800bed12460563dc57c7d602faa",
"signature": null,
@@ -377,7 +377,7 @@
},
"expected": {
"name": "p2tr",
- "address": "bc1pd2llmtym6c5hyecf5zqsyjz9q0jlxaaksw9j0atx8lc8a0e0vrmsw9ewly",
+ "address": "grs1pd2llmtym6c5hyecf5zqsyjz9q0jlxaaksw9j0atx8lc8a0e0vrmsp7xzsq",
"pubkey": "6abffdac9bd629726709a08102484503e5f377b6838b27f5663ff07ebf2f60f7",
"output": "OP_1 6abffdac9bd629726709a08102484503e5f377b6838b27f5663ff07ebf2f60f7",
"hash": "88b7e3b495a84aa2bc12780b1773f130ce5eb747b0c28dc4840b7c9280f7326d",
@@ -399,7 +399,7 @@
"name": "p2tr",
"output": "OP_1 53a1f6e454df1aa2776a2814a721372d6258050de330b3c6d10ee8f4e0dda343",
"pubkey": "53a1f6e454df1aa2776a2814a721372d6258050de330b3c6d10ee8f4e0dda343",
- "address": "bc1p2wsldez5mud2yam29q22wgfh9439spgduvct83k3pm50fcxa5dps59h4z5",
+ "address": "grs1p2wsldez5mud2yam29q22wgfh9439spgduvct83k3pm50fcxa5dpsm7geds",
"signature": null,
"input": null,
"witness": null
@@ -423,7 +423,7 @@
"name": "p2tr",
"output": "OP_1 147c9c57132f6e7ecddba9800bb0c4449251c92a1e60371ee77557b6620f3ea3",
"pubkey": "147c9c57132f6e7ecddba9800bb0c4449251c92a1e60371ee77557b6620f3ea3",
- "address": "bc1pz37fc4cn9ah8anwm4xqqhvxygjf9rjf2resrw8h8w4tmvcs0863sa2e586",
+ "address": "grs1pz37fc4cn9ah8anwm4xqqhvxygjf9rjf2resrw8h8w4tmvcs0863sj3xcg7",
"hash": "5b75adecf53548f3ec6ad7d78383bf84cc57b55a3127c72b9a2481752dd88b21",
"witness": [
"20d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8ac",
@@ -455,7 +455,7 @@
"name": "p2tr",
"output": "OP_1 e4d810fd50586274face62b8a807eb9719cef49c04177cc6b76a9a4251d5450e",
"pubkey": "e4d810fd50586274face62b8a807eb9719cef49c04177cc6b76a9a4251d5450e",
- "address": "bc1punvppl2stp38f7kwv2u2spltjuvuaayuqsthe34hd2dyy5w4g58qqfuag5",
+ "address": "grs1punvppl2stp38f7kwv2u2spltjuvuaayuqsthe34hd2dyy5w4g58q0jr38s",
"hash": "c525714a7f49c28aedbbba78c005931a81c234b2f6c99a73e4d06082adc8bf2b",
"witness": [
"20b617298552a72ade070667e86ca63b8f5789a9fe8731ef91202a91c9f3459007ac",
@@ -489,7 +489,7 @@
"name": "p2tr",
"output": "OP_1 0f63ca2c7639b9bb4be0465cc0aa3ee78a0761ba5f5f7d6ff8eab340f09da561",
"pubkey": "0f63ca2c7639b9bb4be0465cc0aa3ee78a0761ba5f5f7d6ff8eab340f09da561",
- "address": "bc1ppa3u5trk8xumkjlqgewvp237u79qwcd6ta0h6mlca2e5puya54ssw9zq0y",
+ "address": "grs1ppa3u5trk8xumkjlqgewvp237u79qwcd6ta0h6mlca2e5puya54ssp7avqq",
"hash": "f3004d6c183e038105d436db1424f321613366cbb7b05939bf05d763a9ebb962",
"witness": [
"20387671353e273264c495656e27e39ba899ea8fee3bb69fb2a680e22093447d48ac",
@@ -523,7 +523,7 @@
"name": "p2tr",
"output": "OP_1 0f63ca2c7639b9bb4be0465cc0aa3ee78a0761ba5f5f7d6ff8eab340f09da561",
"pubkey": "0f63ca2c7639b9bb4be0465cc0aa3ee78a0761ba5f5f7d6ff8eab340f09da561",
- "address": "bc1ppa3u5trk8xumkjlqgewvp237u79qwcd6ta0h6mlca2e5puya54ssw9zq0y",
+ "address": "grs1ppa3u5trk8xumkjlqgewvp237u79qwcd6ta0h6mlca2e5puya54ssp7avqq",
"hash": "f3004d6c183e038105d436db1424f321613366cbb7b05939bf05d763a9ebb962",
"witness": [
"06424950333431",
@@ -557,7 +557,7 @@
"name": "p2tr",
"output": "OP_1 053690babeabbb7850c32eead0acf8df990ced79f7a31e358fabf2658b4bc587",
"pubkey": "053690babeabbb7850c32eead0acf8df990ced79f7a31e358fabf2658b4bc587",
- "address": "bc1pq5mfpw474wahs5xr9m4dpt8cm7vsemte7733udv040extz6tckrs29g04c",
+ "address": "grs1pq5mfpw474wahs5xr9m4dpt8cm7vsemte7733udv040extz6tckrs97hr6u",
"hash": "d9c2c32808b41c0301d876d49c0af72e1d98e84b99ca9b4bb67fea1a7424b755",
"witness": [
"2044b178d64c32c4a05cc4f4d1407268f764c940d20ce97abfd44db5c3592b72fdac",
@@ -591,7 +591,7 @@
"name": "p2tr",
"output": "OP_1 053690babeabbb7850c32eead0acf8df990ced79f7a31e358fabf2658b4bc587",
"pubkey": "053690babeabbb7850c32eead0acf8df990ced79f7a31e358fabf2658b4bc587",
- "address": "bc1pq5mfpw474wahs5xr9m4dpt8cm7vsemte7733udv040extz6tckrs29g04c",
+ "address": "grs1pq5mfpw474wahs5xr9m4dpt8cm7vsemte7733udv040extz6tckrs97hr6u",
"hash": "d9c2c32808b41c0301d876d49c0af72e1d98e84b99ca9b4bb67fea1a7424b755",
"witness": [
"07546170726f6f74",
@@ -631,7 +631,7 @@
"name": "p2tr",
"output": "OP_1 91b64d5324723a985170e4dc5a0f84c041804f2cd12660fa5dec09fc21783605",
"pubkey": "91b64d5324723a985170e4dc5a0f84c041804f2cd12660fa5dec09fc21783605",
- "address": "bc1pjxmy65eywgafs5tsunw95ruycpqcqnev6ynxp7jaasylcgtcxczs6n332e",
+ "address": "grs1pjxmy65eywgafs5tsunw95ruycpqcqnev6ynxp7jaasylcgtcxczs4gwa9a",
"hash": "ccbd66c6f7e8fdab47b3a486f59d28262be857f30d4773f2d5ea47f7761ce0e2",
"witness": [
"2072ea6adcf1d371dea8fba1035a09f3d24ed5a059799bae114084130ee5898e69ac",
@@ -671,7 +671,7 @@
"name": "p2tr",
"output": "OP_1 91b64d5324723a985170e4dc5a0f84c041804f2cd12660fa5dec09fc21783605",
"pubkey": "91b64d5324723a985170e4dc5a0f84c041804f2cd12660fa5dec09fc21783605",
- "address": "bc1pjxmy65eywgafs5tsunw95ruycpqcqnev6ynxp7jaasylcgtcxczs6n332e",
+ "address": "grs1pjxmy65eywgafs5tsunw95ruycpqcqnev6ynxp7jaasylcgtcxczs4gwa9a",
"hash": "ccbd66c6f7e8fdab47b3a486f59d28262be857f30d4773f2d5ea47f7761ce0e2",
"witness": [
"202352d137f2f3ab38d1eaa976758873377fa5ebb817372c71e2c542313d4abda8ac",
@@ -711,7 +711,7 @@
"name": "p2tr",
"output": "OP_1 91b64d5324723a985170e4dc5a0f84c041804f2cd12660fa5dec09fc21783605",
"pubkey": "91b64d5324723a985170e4dc5a0f84c041804f2cd12660fa5dec09fc21783605",
- "address": "bc1pjxmy65eywgafs5tsunw95ruycpqcqnev6ynxp7jaasylcgtcxczs6n332e",
+ "address": "grs1pjxmy65eywgafs5tsunw95ruycpqcqnev6ynxp7jaasylcgtcxczs4gwa9a",
"hash": "ccbd66c6f7e8fdab47b3a486f59d28262be857f30d4773f2d5ea47f7761ce0e2",
"witness": [
"207337c0dd4253cb86f2c43a2351aadd82cccb12a172cd120452b9bb8324f2186aac",
@@ -750,7 +750,7 @@
"name": "p2tr",
"output": "OP_1 75169f4001aa68f15bbed28b218df1d0a62cbbcf1188c6665110c293c907b831",
"pubkey": "75169f4001aa68f15bbed28b218df1d0a62cbbcf1188c6665110c293c907b831",
- "address": "bc1pw5tf7sqp4f50zka7629jrr036znzew70zxyvvej3zrpf8jg8hqcssyuewe",
+ "address": "grs1pw5tf7sqp4f50zka7629jrr036znzew70zxyvvej3zrpf8jg8hqcsllr4pa",
"hash": "2f6b2c5397b6d68ca18e09a3f05161668ffe93a988582d55c6f07bd5b3329def",
"witness": [
"2071981521ad9fc9036687364118fb6ccd2035b96a423c59c5430e98310a11abe2ac",
@@ -790,7 +790,7 @@
"name": "p2tr",
"output": "OP_1 75169f4001aa68f15bbed28b218df1d0a62cbbcf1188c6665110c293c907b831",
"pubkey": "75169f4001aa68f15bbed28b218df1d0a62cbbcf1188c6665110c293c907b831",
- "address": "bc1pw5tf7sqp4f50zka7629jrr036znzew70zxyvvej3zrpf8jg8hqcssyuewe",
+ "address": "grs1pw5tf7sqp4f50zka7629jrr036znzew70zxyvvej3zrpf8jg8hqcsllr4pa",
"hash": "2f6b2c5397b6d68ca18e09a3f05161668ffe93a988582d55c6f07bd5b3329def",
"witness": [
"20d5094d2dbe9b76e2c245a2b89b6006888952e2faa6a149ae318d69e520617748ac",
@@ -830,7 +830,7 @@
"name": "p2tr",
"output": "OP_1 75169f4001aa68f15bbed28b218df1d0a62cbbcf1188c6665110c293c907b831",
"pubkey": "75169f4001aa68f15bbed28b218df1d0a62cbbcf1188c6665110c293c907b831",
- "address": "bc1pw5tf7sqp4f50zka7629jrr036znzew70zxyvvej3zrpf8jg8hqcssyuewe",
+ "address": "grs1pw5tf7sqp4f50zka7629jrr036znzew70zxyvvej3zrpf8jg8hqcsllr4pa",
"hash": "2f6b2c5397b6d68ca18e09a3f05161668ffe93a988582d55c6f07bd5b3329def",
"witness": [
"20c440b462ad48c7a77f94cd4532d8f2119dcebbd7c9764557e62726419b08ad4cac",
@@ -877,7 +877,7 @@
"description": "Invalid x coordinate for pubkey in address",
"exception": "Invalid pubkey for p2tr",
"arguments": {
- "address": "bc1p7ymwj4j5qxtuy8lncp6ax2nw8jp0rms7v3kvpuy02xcttmd05a3qmwlnez"
+ "address": "grs1p7ymwj4j5qxtuy8lncp6ax2nw8jp0rms7v3kvpuy02xcttmd05a3q54qlkx"
}
},
{
@@ -895,7 +895,7 @@
"options": {},
"arguments": {
"pubkey": "ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5",
- "address": "bc1pztta4jvddxsgdfgtxz2e5dfhj58n2mludag2ycatwhy28myagnqsnl7mv7"
+ "address": "grs1pztta4jvddxsgdfgtxz2e5dfhj58n2mludag2ycatwhy28myagnqsuyphr6"
}
},
{
@@ -904,7 +904,7 @@
"options": {},
"arguments": {
"output": "OP_1 ab610d22c801def8a1e02368d1b92018970eb52a729919705e8a1a2f60c750f5",
- "address": "bc1pztta4jvddxsgdfgtxz2e5dfhj58n2mludag2ycatwhy28myagnqsnl7mv7"
+ "address": "grs1pztta4jvddxsgdfgtxz2e5dfhj58n2mludag2ycatwhy28myagnqsuyphr6"
}
},
{
@@ -954,13 +954,13 @@
{
"exception": "Invalid address version",
"arguments": {
- "address": "bc1z4dss6gkgq8003g0qyd5drwfqrztsadf2w2v3juz73gdz7cx82r6s6rxhwd"
+ "address": "grs1z4dss6gkgq8003g0qyd5drwfqrztsadf2w2v3juz73gdz7cx82r6s4cempf"
}
},
{
"exception": "Invalid address data",
"arguments": {
- "address": "bc1p4dss6gkgq8003g0qyd5drwfqrztsadf2w2v3juz73gdz7cx82qh3d2w3"
+ "address": "grs1p4dss6gkgq8003g0qyd5drwfqrztsadf2w2v3juz73gdz7cx82q27z9ae"
}
},
{
diff --git a/test/fixtures/psbt.json b/test/fixtures/psbt.json
index 784ca371f..d6549d5a9 100644
--- a/test/fixtures/psbt.json
+++ b/test/fixtures/psbt.json
@@ -315,15 +315,15 @@
"keys": [
{
"inputToSign": 0,
- "WIF": "cRyKzLXVgTReWe7wgfEiXktTa9tf4e5DK1STha274d7BBbnucTaR"
+ "WIF": "cRyKzLXVgTReWe7wgfEiXktTa9tf4e5DK1STha274d7BBbpLF9kK"
},
{
"inputToSign": 1,
- "WIF": "cR62L1G154fjHFrBCJMxJxbk1rcxhT2xcTh7WstvFdFDsZ9uFiVj"
+ "WIF": "cR62L1G154fjHFrBCJMxJxbk1rcxhT2xcTh7WstvFdFDsZAAftxc"
},
{
"inputToSign": 2,
- "WIF": "cPPRdCmAMZMjPdHfRmTCmzYVruZHJ8GbM1FqN2W6DnmEPWDg29aL"
+ "WIF": "cPPRdCmAMZMjPdHfRmTCmzYVruZHJ8GbM1FqN2W6DnmEPWGh2Xzu"
}
],
"result": "cHNidP8BAM8CAAAAAwPzd9k+uLSN1rgF01xY1TIA/8N+YytNZ4VP9gKFP4MyAAAAAAD/////ZtAAqL2E1fKcmGo+7xuqS+nSQeKFVKGRYaHfIvLXn4sAAAAAAP////9+h+SlCwIx1MUDT7Bek0NrWXS7xnSPi5LbYbDc9sxYIgAAAAAA/////wIgKRsAAAAAACJRIEb2SXyy8Z1Qw+npgqlQ3MhiFLAfzOQ3pCBhx72xIw0zuAUBAAAAAAAWABTJijE0v48z5ZmmfEAADXdCBcG0FAAAAAAAAQDiAgAAAAABAUfY2D1t0dyMeEH39C1yOdIxigpqm7XJNqHVT3Lc+FkiAAAAAAD+////AhIsGwAAAAAAGXapFJ5+8XZ3ZP80oFldvEwrcNsBftBmiKyYdK6xAAAAABepFLDBn59UffGbX7u/olyFDG0eG1UJhwJHMEQCIDAd3s05C61flXVFqOtov0NoHRGr8KFcOpH6R/81F46EAiBt+j9hHyvT2hYEyf8fdYsM9IgbnybtPV+kRTHDa6Rj0AEhAmmZfwmoHsmCkEOn9AfRTh+863mURelmE8hSqL4MG1EydJwgACICAi5ovBH1xLoGxPqtFh48wUEpnM+St1SbPzRwO7kBNKOQRzBEAiBpWClBybtHveXkhAgTiE8QSczMJs8MGuH4LOSNRA6s/AIgWlbB3xJOtJIsszj1qZ/whA5jK9wnTzeZzDlVs/ivq2cBAAEBK7gFAQAAAAAAIlEgT+9cUWO+ppqT50pZZyu+sIGDcHfLlM+m5IGlzwDYqxgBE0B0eYK4chVhtLT9WMi14T8ZknZSdTe1pMdIvaq6tIfwqY2xQ9YlcTTy0jWU9utItw/rHQ2c1FplbF9bRvZ6RLQSARcglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4AAQEfECcAAAAAAAAWABRPoqyhKLb53uUwnE9wBR5Jxl/XMiICA6VOpEBbPJM/xYsqO2euttYFpgec9vcxggyTyoklK660SDBFAiEAoCIktghL55iuMAmkzwYJzb+h+qmNewZXxAx/06ObxIQCIELCsBz/wd2wPlnJb27OluxMkTPnCyHA2C+SxHiX/FvPAQAAAA=="
@@ -335,15 +335,15 @@
"keys": [
{
"inputToSign": 0,
- "WIF": "cRXSy63fXDve59e8cvqozVFfqXJB6YL6cPzoRewmEsux81SgPrfj"
+ "WIF": "cRXSy63fXDve59e8cvqozVFfqXJB6YL6cPzoRewmEsux81RAz6nb"
},
{
"inputToSign": 0,
- "WIF": "cQQXUJocNBS6oZCCtyhCsdN5ammK6WoJWpx44ANKxZSN2A3WDDEN"
+ "WIF": "cQQXUJocNBS6oZCCtyhCsdN5ammK6WoJWpx44ANKxZSN2A48KJu2"
},
{
"inputToSign": 0,
- "WIF": "cTrPNrN2EQo4ppBHcFNxyLBFq2WLjZoNKY5nQbPwAGdhQqqsRKSu"
+ "WIF": "cTrPNrN2EQo4ppBHcFNxyLBFq2WLjZoNKY5nQbPwAGdhQqsiZsS6"
}
],
"result": "cHNidP8BAF4CAAAAAQU2GLj/HTOEN804Hc6JRNTLM7EmDlIBdjG2G1aUw266AAAAAAD/////AYAaBgAAAAAAIlEg35sLGepBXUbR93XfxDJcYBCHqNVjw/jogOgPVdic1UgAAAAAAAEBK6BoBgAAAAAAIlEgVZx4+tHeORcb0jDJnOytrOnNOGL1uS0MdMUg1GQeS15BFDlfgSndY7SlwvEhJOqgW3p+0w9w5R+5MwXe7MVC5/nrrqI0FdZdKILLLZgRVK8L9Bn2ijU6IcoqqyImKIWt3MtAA3alBoU7IBCkBk9OHD1wE8fJI4y+lbnTRj48e8AAwRM77q3Rml679qCzGvEAKAs99UNMaXHQIhgGfRP11AMlJkEUj4kary4texRheMVKh+Ku3dnR1oZpIleSjmfPCBdP83WuojQV1l0ogsstmBFUrwv0GfaKNTohyiqrIiYoha3cy0DYJZ6Lv7FZPIBRZFfVgF5v3gcRiQnT8aM82Q5IPkwkzZrGo4ThZblvunG/+hu8ZPuJrUU+uXb+s9rcwSH+BihIQRSoqze8FgnYNMOROzU42tHITX+baoNf/BdXd5FaN641cq6iNBXWXSiCyy2YEVSvC/QZ9oo1OiHKKqsiJiiFrdzLQEfQ5UkAg4lTbhJxjMzB7hu6ad1fywYxHCXjFXHHrm5PJTOFJLg2oTnwuQToz/Z2AW/UET7Op+WSoHZvW4tzzLhiFcFmuQP4s1ds7KJtMOh4fTw1QCgxkWUA3FUAuUzKHzjDvhpSnJ+zzX53bWG2IltsYQ6JBvuPqmxZrFw+lbX4LSnWGlKcn7PNfndtYbYiW2xhDokG+4+qbFmsXD6VtfgtKdZpII+JGq8uLXsUYXjFSofirt3Z0daGaSJXko5nzwgXT/N1rCA5X4Ep3WO0pcLxISTqoFt6ftMPcOUfuTMF3uzFQuf567ogqKs3vBYJ2DTDkTs1ONrRyE1/m2qDX/wXV3eRWjeuNXK6U5zAAAA="
@@ -355,7 +355,7 @@
"keys": [
{
"inputToSign": 0,
- "WIF": "cSu5bjn9TsAEeqZxEFKy5of3FKfHha6FT56KvfAGmu6rMmPNJTrV"
+ "WIF": "cSu5bjn9TsAEeqZxEFKy5of3FKfHha6FT56KvfAGmu6rMmPvD9rV"
}
],
"result": "cHNidP8BAF4CAAAAATNOP+fCPDCsZrgGIptDVbwY/yrkM2xaFfLe05BSLulZAAAAAAD/////AZBBBgAAAAAAIlEgo6glLro4LvJCjIXCj+2xYC8NQ5BB/tvaXLukmWNHDaQAAAAAAAEBK6BoBgAAAAAAIlEgo6glLro4LvJCjIXCj+2xYC8NQ5BB/tvaXLukmWNHDaRBFP1IuUG/pcYMyG7KOHraqMXMKKOJb5eIpnjGt7LrvcsWIjJncH2zqZGpUloPoJZipi/NkKmjWthVrvnedXPOOOdABNUCXyGRAy4nthiGpE8dXioP2P50J+fU5gojlqunTwPKRPvqWcCzOoaJGvUEF+oxpMXZ1+FZWHRppoeoZFParUEU/Ui5Qb+lxgzIbso4etqoxcwoo4lvl4imeMa3suu9yxZZ4RArokXwS/gTxiDbmC8PNuLMoA7qbokPTzaAWOxY1UAF3RzlWz+5cWYG1EqfZTT/CO7O3hGYvMMjlJV5rluR916WCgGYO2hHj9fiEH0rxD3BRbzR78PShCen+beqDncSYhXA14I7V9HPPG3inemPM0WGwDWVxHPHQ4ZbqfL90gol9GwaUpyfs81+d21htiJbbGEOiQb7j6psWaxcPpW1+C0p1lnhECuiRfBL+BPGINuYLw824sygDupuiQ9PNoBY7FjVaSD9SLlBv6XGDMhuyjh62qjFzCijiW+XiKZ4xrey673LFqwg8SpWwWgeeIkT4/6+reTfQ7QRSLVfLqB3xMBm6F6VbBy6ILdNSfjcErI+zzO5ukGyw4ly3aGM5/aRzQOJABhdaS9/ulOcwEIVwNeCO1fRzzxt4p3pjzNFhsA1lcRzx0OGW6ny/dIKJfRseC5OuDJOUDM89l6Pe7EWRXBh9E3bgDm+h9IRzgf9AqwjIP1IuUG/pcYMyG7KOHraqMXMKKOJb5eIpnjGt7LrvcsWrMAAAA=="
@@ -368,7 +368,7 @@
{
"inputToSign": 0,
"tapLeafHashToSign": "f2d9fd9a2f80e0e7abeac881398fc37198f46e5c802ec00c95152aa6f703e71e",
- "WIF": "cP76Rzf6bVcmFbnJ3DigWvyNvki2bZeXxoq3B5pcZ8zVRnT4fKdx"
+ "WIF": "cP76Rzf6bVcmFbnJ3DigWvyNvki2bZeXxoq3B5pcZ8zVRnVnrNdP"
}
],
"result": "cHNidP8BAF4CAAAAAdXMkUOLeYvgm981k3T7Pmdf5Dr31jOxvpFHiXiU9D2gAAAAAAD/////AZBBBgAAAAAAIlEgD31MIAvwCaanOsAzyBoQ4o/WozgFiqVQTEqGJE18XqwAAAAAAAEBK6BoBgAAAAAAIlEgD31MIAvwCaanOsAzyBoQ4o/WozgFiqVQTEqGJE18XqxBFCo/Wsfk0hSOCy21lUyn+vXnc1SG1lNVWHlnXCh3xegq8tn9mi+A4Oer6siBOY/DcZj0blyALsAMlRUqpvcD5x5Aa7X0m4UCLaHA/Vnjkl+if6rVeiBbIlbHXHLh7RqJyB8Wgs66p6/ZnwSW/HD6o7rMHffIva+jgJgYWf6MvzrfTWIVwAjUk5QzdUBMEkLbwcjUHnMpA13k3j9ziDszUJiFladaGlKcn7PNfndtYbYiW2xhDokG+4+qbFmsXD6VtfgtKdaTipNtL9o84yJyfhx52eesqJWF2CBZtnGxCFpdeDn8S2kgKj9ax+TSFI4LLbWVTKf69edzVIbWU1VYeWdcKHfF6CqsIJy6ZeYeVOa94xIEs49J9vofeVpf3u1m0XiCqbHNX6BsuiBcF5S+4nRv+Yw5rfnf3GLPT81/1FAJYZldegI1wVRh17pTnMBCFcAI1JOUM3VATBJC28HI1B5zKQNd5N4/c4g7M1CYhZWnWl8Vv/I1WWJt8byg3fk43iQn6QFlDgumFTPXr7uOK24+IyAqP1rH5NIUjgsttZVMp/r153NUhtZTVVh5Z1wod8XoKqzAAAA="
@@ -550,7 +550,7 @@
"isTaproot": true,
"psbt": "cHNidP8BADMCAAAAAcbgSGx76du9GXsr4c6Yk7DFglfHi7M2jdCNUXwc+Q+EAAAAAAD/////AAAAAAAAAQEroGgGAAAAAAAiUSClLxmVQ6aZXLEwkYA/WGZuIE91BHT7xP7DIEAvz/NITaIVwd2NnolThxX+QCpgFksj8u93bzuZy6olaHxJNHaArwK1tCTeoJ+EC5MqADc83NvSVlC4w6z+VKn0pkGihnIbjSbax5V2a72h6uqkXlv6CpUP3V9MSq2lsfMILtyWibn9Cu4oo7gsSuy+vTeBJ9yI3Rnh6pPtunont1ThyIHTCIdKesRIlUS3uEDQRVmeyUFa5xzLCQwsRlwFyfoF9Bx6BtUjIFX368Cp2d6uXSbyrn23vC4KMjRRlEssuTTh7ThM6bXQrMAAAA==",
"outputData": {
- "address": "bc1px4ssshedlz4jc56ses3lftz462a06jwy8my4pwpx6twx30vvv6nsgwcpu3",
+ "address": "grs1px4ssshedlz4jc56ses3lftz462a06jwy8my4pwpx6twx30vvv6ns848dn4",
"value": 410000,
"tapInternalKey": "Buffer.from('f6d4ce132444de7f0e3a1d2be9b38ceec798cf9a76eeeac585869445830eb167', 'hex')",
"tapTree": {
@@ -601,7 +601,7 @@
"psbt": "cHNidP8BAFwCAAAAAk9Ve2845C8v//JR71uKzf70FjeNfx7SvB4l3A+Q44UKAAAAAAD/////FIp10hu+RPgTSFGPmjwb01Tf/a5UkcPFUpOw/X6UEPYAAAAAAP////8AAAAAAAABASugaAYAAAAAACJRINqadqaDhePTT29qdKQScUmyJxEeDw12HLjkMYMVSlnkARcgDN4bJzix3HdE8+FUM6UgA1lEKpgpIImVUePmAGYh7yYAAQDAAgAAAAFbIoaAJqDd/f4mZppgYV4UR9bgU8lT9pTH4/aDJdFUWgAAAABrSDBFAiEA6JS0xMdSQhG+9gAPSxGs6HazyauyNUBMwrmF386IAxwCIGiyH9QHCzKOBTtg+VsISF4nUi9NfAtJAtC02J03+I07ASEDu1tkEI8W1bd6qrPZ3uLaHvE90BDUvRCwvTTzPYPXzwf/////AaBoBgAAAAAAGXapFL5QEf51k4TA7Mp5d18IM2ddq79oiKwAAAAAAAA=",
"outputData": {
"tapInternalKey": "Buffer.from('884d969439deced21d1ab71ecd9ef9a6a8795215588ce7eff4ad5efc903e40ec', 'hex')",
- "address": "bc1p74zfvfd7rndcn8lvzuec4hj4kzp9nnjvapvx5fgtqsegzz656hhsee8kwu",
+ "address": "grs1p74zfvfd7rndcn8lvzuec4hj4kzp9nnjvapvx5fgtqsegzz656hhskzc6pc",
"value": 410000
},
"result": "cHNidP8BAIcCAAAAAk9Ve2845C8v//JR71uKzf70FjeNfx7SvB4l3A+Q44UKAAAAAAD/////FIp10hu+RPgTSFGPmjwb01Tf/a5UkcPFUpOw/X6UEPYAAAAAAP////8BkEEGAAAAAAAiUSD1RJYlvhzbiZ/sFzOK3lWwglnOTOhYaiULBDKBC1TV7wAAAAAAAQEroGgGAAAAAAAiUSDamnamg4Xj009vanSkEnFJsicRHg8Ndhy45DGDFUpZ5AEXIAzeGyc4sdx3RPPhVDOlIANZRCqYKSCJlVHj5gBmIe8mAAEAwAIAAAABWyKGgCag3f3+JmaaYGFeFEfW4FPJU/aUx+P2gyXRVFoAAAAAa0gwRQIhAOiUtMTHUkIRvvYAD0sRrOh2s8mrsjVATMK5hd/OiAMcAiBosh/UBwsyjgU7YPlbCEheJ1IvTXwLSQLQtNidN/iNOwEhA7tbZBCPFtW3eqqz2d7i2h7xPdAQ1L0QsL008z2D188H/////wGgaAYAAAAAABl2qRS+UBH+dZOEwOzKeXdfCDNnXau/aIisAAAAAAABBSCITZaUOd7O0h0atx7NnvmmqHlSFViM5+/0rV78kD5A7AA="
@@ -612,7 +612,7 @@
"psbt": "cHNidP8BAFwCAAAAAk9Ve2845C8v//JR71uKzf70FjeNfx7SvB4l3A+Q44UKAAAAAAD/////FIp10hu+RPgTSFGPmjwb01Tf/a5UkcPFUpOw/X6UEPYAAAAAAP////8AAAAAAAABASugaAYAAAAAACJRINqadqaDhePTT29qdKQScUmyJxEeDw12HLjkMYMVSlnkARcgDN4bJzix3HdE8+FUM6UgA1lEKpgpIImVUePmAGYh7yYAAQDAAgAAAAFbIoaAJqDd/f4mZppgYV4UR9bgU8lT9pTH4/aDJdFUWgAAAABrSDBFAiEA6JS0xMdSQhG+9gAPSxGs6HazyauyNUBMwrmF386IAxwCIGiyH9QHCzKOBTtg+VsISF4nUi9NfAtJAtC02J03+I07ASEDu1tkEI8W1bd6qrPZ3uLaHvE90BDUvRCwvTTzPYPXzwf/////AaBoBgAAAAAAGXapFL5QEf51k4TA7Mp5d18IM2ddq79oiKwAAAAAAAA=",
"outputData": {
"tapInternalKey": "Buffer.from('884d969439deced21d1ab71ecd9ef9a6a8795215588ce7eff4ad5efc903e40ec', 'hex')",
- "address": "bc1p3efq8ujsj0qr5xvms7mv89p8cz0crqdtuxe9ms6grqgxc9sgsntslthf6w",
+ "address": "grs1p3efq8ujsj0qr5xvms7mv89p8cz0crqdtuxe9ms6grqgxc9sgsntsssg942",
"value": 410000
},
"exception": "Error adding output. Script or address missmatch."
@@ -622,7 +622,7 @@
"isTaproot": true,
"psbt": "cHNidP8BAFwCAAAAAk9Ve2845C8v//JR71uKzf70FjeNfx7SvB4l3A+Q44UKAAAAAAD/////FIp10hu+RPgTSFGPmjwb01Tf/a5UkcPFUpOw/X6UEPYAAAAAAP////8AAAAAAAABASugaAYAAAAAACJRINqadqaDhePTT29qdKQScUmyJxEeDw12HLjkMYMVSlnkARcgDN4bJzix3HdE8+FUM6UgA1lEKpgpIImVUePmAGYh7yYAAQDAAgAAAAFbIoaAJqDd/f4mZppgYV4UR9bgU8lT9pTH4/aDJdFUWgAAAABrSDBFAiEA6JS0xMdSQhG+9gAPSxGs6HazyauyNUBMwrmF386IAxwCIGiyH9QHCzKOBTtg+VsISF4nUi9NfAtJAtC02J03+I07ASEDu1tkEI8W1bd6qrPZ3uLaHvE90BDUvRCwvTTzPYPXzwf/////AaBoBgAAAAAAGXapFL5QEf51k4TA7Mp5d18IM2ddq79oiKwAAAAAAAA=",
"outputData": {
- "address": "bc1px4ssshedlz4jc56ses3lftz462a06jwy8my4pwpx6twx30vvv6nsgwcpu3",
+ "address": "grs1px4ssshedlz4jc56ses3lftz462a06jwy8my4pwpx6twx30vvv6ns848dn4",
"value": 410000,
"tapInternalKey": "Buffer.from('884d969439deced21d1ab71ecd9ef9a6a8795215588ce7eff4ad5efc903e40ec', 'hex')",
"redeemScript": "Buffer.from('5221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae', 'hex')"
@@ -634,7 +634,7 @@
"isTaproot": true,
"psbt": "cHNidP8BAIcCAAAAAvz6EyMK2VQ0DFKWZyIyGZLZCnaIDtG5RI55OrGVs6u7AAAAAAD/////oB9A2l2NN5WPNjBDaRsz9Nmla1WdM3jl96ElSV5WWHMAAAAAAP////8BkEEGAAAAAAAiUSCnucwjGG2x9zGqP+E0PwxTkptd/9AYMW12ch7ffaogBAAAAAAAAQEroGgGAAAAAAAiUSDbRhL5phuWYLyqKbSqVb/Pic2mpPL46idVKQur9i06ugETQOPidQWL9dHDxd819Pn5QNNGyH0fmDv58pexSJVDalZ0W/HPVliPFZy7s//0TfTbvFce87/nKXcrwz5YuItIY6cBFyAOgJIoTQyYcpAqNfsK9CutgWckFE3mBMgpL50lKXb7oQABAL8CAAAAAcdkwPNWdYy1O8QM1xRkrJjas72QGQPEanYEpv6iT3PXAAAAAGpHMEQCIFpl6Nx8hoZA1o5Huo958RS/Hndy+DloLhp0nvRyBzN8AiB9jEbitThSs6TZ1XVBHZebj4nZbLMg3CCtss8WSZpv7QEhA+VxIxwCWeqoeDMYcEw3EC0ZPxIkOqt0YSK9Y3hAKTd1/////wGgaAYAAAAAABl2qRS9gA7n636cw49cUBJWm7IDJPKuuoisAAAAACICAknGKVC7w5Ek4l3IK5XCUwLNCeU4DD+76cdMAYDB72g3RzBEAiAjekFbBddaHY/LZidwKd3sBbifjmbEpka2Ps0B2Crg+wIgUoN4BhGCwMRTDaHbAX+0MXSGYA9nSlqeQJXpWQRCBfQBAAEFIE6DvlLK0f4BrtpMgez01WQYKLUQZ8HtbfuDPD52hmSvAA==",
"outputData": {
- "address": "bc1px4ssshedlz4jc56ses3lftz462a06jwy8my4pwpx6twx30vvv6nsgwcpu3",
+ "address": "grs1px4ssshedlz4jc56ses3lftz462a06jwy8my4pwpx6twx30vvv6ns848dn4",
"value": 410000
},
"exception": "Can not modify transaction, signatures exist."
@@ -644,7 +644,7 @@
"isTaproot": true,
"psbt": "cHNidP8BAF4CAAAAAfyhtBTm+3OPYBuMHvdPMf9jqniZDY925hbmnt8hxbA6AAAAAAD/////AZBBBgAAAAAAIlEgV6CyzSs5a6Tc8A+TYOiozWnh6FRH9E/VWFanhMAEbLEAAAAAAAEBK6BoBgAAAAAAIlEgV6CyzSs5a6Tc8A+TYOiozWnh6FRH9E/VWFanhMAEbLEBCEIBQOAqWBD/2jhPWzQvesT8sjkN2Cowphp3QvmlWbHiLx753ChcUovvWyBlWiCq77Kk+lZGEhC4vjClSjc26br+dc8AAA==",
"outputData": {
- "address": "bc1px4ssshedlz4jc56ses3lftz462a06jwy8my4pwpx6twx30vvv6nsgwcpu3",
+ "address": "grs1px4ssshedlz4jc56ses3lftz462a06jwy8my4pwpx6twx30vvv6ns848dn4",
"value": 410000
},
"exception": "Can not modify transaction, signatures exist."
@@ -654,7 +654,7 @@
"isTaproot": true,
"psbt": "cHNidP8BAF4CAAAAAa/0mhnSBXdEBKbbMC+2hm6AZZtCLBxBeubd1sjtau5dAAAAAAD/////AZBBBgAAAAAAIlEgISRIfamb9rCYzad52ikfoUUuFlvyTcImZMavR0jEaUQAAAAAAAEBK6BoBgAAAAAAIlEgISRIfamb9rCYzad52ikfoUUuFlvyTcImZMavR0jEaURBFBnEcOpwiHjNYPtWJOrQ8Pgc9bxBKyZh/i2D837Z1rC8BibL1C4Z/5e6dKzWfkzpsIbE5WEVn1bYpAAjrqIKMHlAKkl3w3Gfpkl9b0yDVbTlZd4yCEL9V2DJs6zpPrEmn3wiohBy8wwE6EZ0FxQdrCupnHKXhHBjpcHVwfJRQfcy9EEULx1ijisiHgGb/9/hBNhsIOv1ZyWsfmi/Ql+oz7AOuqAGJsvULhn/l7p0rNZ+TOmwhsTlYRWfVtikACOuogoweUBKNkxBf6vT8m7ISt1WikLWW9udCP7OQLXztr1IPalJT5z+esAWmgeLS7QoLgzTu8AnYp/rHxsgZ6CgiV8tlkciQRRXE7VxCk67h7Ee6CbSgNyotChx7CgwNTfxdJkyvCS0DgYmy9QuGf+XunSs1n5M6bCGxOVhFZ9W2KQAI66iCjB5QFN6DGtLlSIFBjZbdh3rbKBtBcEDSiEcuVxnSPpdM1RnQRmw5Ujo+/76wZfmGBMFzV0IA7vnHzzXN73jT6O8/wJiFcDBdB6IhNxYUBYgZT1K7FG5SblQ3S6nQMKRLc2vPcA0BhpSnJ+zzX53bWG2IltsYQ6JBvuPqmxZrFw+lbX4LSnWGlKcn7PNfndtYbYiW2xhDokG+4+qbFmsXD6VtfgtKdZpIFcTtXEKTruHsR7oJtKA3Ki0KHHsKDA1N/F0mTK8JLQOrCAvHWKOKyIeAZv/3+EE2Gwg6/VnJax+aL9CX6jPsA66oLogGcRw6nCIeM1g+1Yk6tDw+Bz1vEErJmH+LYPzftnWsLy6U5zAAAA=",
"outputData": {
- "address": "bc1px4ssshedlz4jc56ses3lftz462a06jwy8my4pwpx6twx30vvv6nsgwcpu3",
+ "address": "grs1px4ssshedlz4jc56ses3lftz462a06jwy8my4pwpx6twx30vvv6ns848dn4",
"value": 410000
},
"exception": "Can not modify transaction, signatures exist."
From 61aa9e175b259baaab9651c32db9a0be82eb3ba4 Mon Sep 17 00:00:00 2001
From: gruve-p
Date: Sat, 27 Jan 2024 10:49:48 +0100
Subject: [PATCH 142/144] Bump version
---
package-lock.json | 153 ++++++++++++++++++++++++++--------------------
package.json | 4 +-
2 files changed, 88 insertions(+), 69 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 8c89bcd39..454cc24b5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -26,13 +26,13 @@
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
"better-npm-audit": "^3.7.3",
- "bip32grs": "^4.0.0",
+ "bip32grs": "^4.0.1",
"bip39": "^3.1.0",
"bip65": "^1.0.1",
"bip68": "^1.0.3",
"bs58": "^4.0.0",
"dhttp": "^3.0.0",
- "ecpairgrs": "^2.0.1",
+ "ecpairgrs": "^2.0.2",
"eslint": "^8.29.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.2.1",
@@ -677,17 +677,17 @@
"@jridgewell/sourcemap-codec": "1.4.14"
}
},
- "node_modules/hashes-grs": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/hashes-grs/-/hashes-1.2.0.tgz",
- "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==",
+ "node_modules/@noble/hashes": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz",
+ "integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==",
"dev": true,
- "funding": [
- {
- "type": "individual",
- "url": "https://paulmillr.com/funding/"
- }
- ]
+ "engines": {
+ "node": ">= 16"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
@@ -1168,15 +1168,15 @@
}
},
"node_modules/bip32grs": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/bip32grs/-/bip32grs-4.0.0.tgz",
- "integrity": "sha512-VTenZ+6FKZEnAW8DiEV14bNmqqUS4HojYa5ALvl15QAkWjmQk12r4hD+Hb0CeAvbps1RbrKLW6lqeN9lDI6uKQ==",
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/bip32grs/-/bip32grs-4.0.1.tgz",
+ "integrity": "sha512-nNgBbB+aHNgXQpGZWrNbuF/m9HTmEg+a9Kc1co7gyv83M8VQV3a6YsFR+0OfBqGKE6zKbQ/hYlYdr4FQY40ang==",
"dev": true,
"dependencies": {
"bs58grscheck": "^3.0.1",
"hashes-grs": "^1.2.0",
"typeforce": "^1.11.5",
- "wifgrs": "^2.0.6"
+ "wifgrs": "^2.0.7"
},
"engines": {
"node": ">=6.0.0"
@@ -1188,7 +1188,7 @@
"integrity": "sha512-c9kiwdk45Do5GL0vJMe7tS95VjCii65mYAH7DfWl3uW8AVzXKQVUm64i3hzVybBDMp9r7j9iNxR85+ul8MdN/A==",
"dev": true,
"dependencies": {
- "hashes-grs": "^1.2.0"
+ "@noble/hashes": "^1.2.0"
}
},
"node_modules/bip65": {
@@ -1282,8 +1282,8 @@
},
"node_modules/bs58grscheck": {
"version": "3.0.1",
- "resolved": "git+ssh://git@github.com/Groestlcoin/bs58grscheck.git#ab5b5e509f1754cb4764496df89d49bccfd48753",
- "license": "MIT",
+ "resolved": "https://registry.npmjs.org/bs58grscheck/-/bs58grscheck-3.0.1.tgz",
+ "integrity": "sha512-kKloH4PKvEW2p1k7aBJhiW2PG/GkfxIuI5xGDS1Lw0j9w1pbe2yt1aSZewbUtWimEOObMeliJGyHv54tUdkiGA==",
"dependencies": {
"bs58": "^5.0.0",
"hashes-grs": "1.2.0"
@@ -1611,14 +1611,14 @@
}
},
"node_modules/ecpairgrs": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/ecpairgrs/-/ecpairgrs-2.0.1.tgz",
- "integrity": "sha512-TeIyvUpbw8kwKMbERgNPL7xY+YWDw1Qdp9/ZPOQtKUw0VmiRRfi+wAj1RHhknd2hUb+9CvLt6s+3wzAksfUg5w==",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/ecpairgrs/-/ecpairgrs-2.0.2.tgz",
+ "integrity": "sha512-TIpsWw78dOUswi+wrNGiazOtYpyrsVtvxVSOuVM+TowbN+8LC9ZCL4AD4PZx6BqHImyfBrcBjVzS4t7r3smKTw==",
"dev": true,
"dependencies": {
"randombytes": "^2.1.0",
"typeforce": "^1.18.0",
- "wifgrs": "^2.0.6"
+ "wifgrs": "^2.0.7"
},
"engines": {
"node": ">=8.0.0"
@@ -2126,20 +2126,6 @@
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"dev": true
},
- "node_modules/fsevents": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
- "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",
@@ -2252,6 +2238,13 @@
"integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
"dev": true
},
+ "node_modules/groestl-hash-js": {
+ "version": "1.0.0",
+ "resolved": "git+ssh://git@github.com/Groestlcoin/groestl-hash-js.git#ef6a04f1c4d2f0448f0882b5f213ef7a0659baee",
+ "integrity": "sha512-FO7JHK2JaLeEnx79qx3qIqxrm87XFXULJBTi+kXuXW2ZjMnSao7UXt8kA4KEwuJN+ufgahJXILosRKMDylQlNQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
@@ -4276,15 +4269,27 @@
"dev": true
},
"node_modules/wifgrs": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/wifgrs/-/wifgrs-2.0.6.tgz",
- "integrity": "sha512-Zufg+IptNYTF85Hkr6Jhf6C2XpGAW3b5WeQB+Tq+PfeX1Q0/rLbZSmRc1/3Gwum19jntxuGY5d6SRnbl/cM0+w==",
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/wifgrs/-/wifgrs-2.0.7.tgz",
+ "integrity": "sha512-kcjDUinm7WzK5HI8jQGXtw8xvLV++2Bs0WRxFweBxfYXJMn51a0EuKOjPOot69qihDOoLJkoLbs/y8LM2NjK3w==",
"dev": true,
"dependencies": {
- "bs58grscheck": "git+https://github.com/Groestlcoin/bs58grscheck.git",
+ "bs58grscheck": "<3.0.0",
"safe-buffer": "^5.1.1"
}
},
+ "node_modules/wifgrs/node_modules/bs58grscheck": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/bs58grscheck/-/bs58grscheck-2.1.2.tgz",
+ "integrity": "sha512-JX7CNqxYDsUYfzwbVmUiDKOxGUQm6E9Vb5MT1/MvAv80WU+KtzdJAfUb4lbX397dd/aAGA6OF1J/sRkMk7EMzA==",
+ "dev": true,
+ "dependencies": {
+ "bs58": "^4.0.0",
+ "create-hash": "^1.1.0",
+ "groestl-hash-js": "git+https://github.com/Groestlcoin/groestl-hash-js.git",
+ "safe-buffer": "^5.1.2"
+ }
+ },
"node_modules/word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
@@ -4920,10 +4925,10 @@
"@jridgewell/sourcemap-codec": "1.4.14"
}
},
- "hashes-grs": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/hashes-grs/-/hashes-1.2.0.tgz",
- "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==",
+ "@noble/hashes": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz",
+ "integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==",
"dev": true
},
"@nodelib/fs.scandir": {
@@ -5256,15 +5261,15 @@
"integrity": "sha512-mdFV5+/v0XyNYXjBS6CQPLo9ekCx4gtKZFnJm5PMto7Fs9hTTDpkkzOB7/FtluRI6JbUUAu+snTYfJRgHLZbZQ=="
},
"bip32grs": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/bip32grs/-/bip32grs-4.0.0.tgz",
- "integrity": "sha512-VTenZ+6FKZEnAW8DiEV14bNmqqUS4HojYa5ALvl15QAkWjmQk12r4hD+Hb0CeAvbps1RbrKLW6lqeN9lDI6uKQ==",
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/bip32grs/-/bip32grs-4.0.1.tgz",
+ "integrity": "sha512-nNgBbB+aHNgXQpGZWrNbuF/m9HTmEg+a9Kc1co7gyv83M8VQV3a6YsFR+0OfBqGKE6zKbQ/hYlYdr4FQY40ang==",
"dev": true,
"requires": {
"bs58grscheck": "^3.0.1",
"hashes-grs": "^1.2.0",
"typeforce": "^1.11.5",
- "wifgrs": "^2.0.6"
+ "wifgrs": "^2.0.7"
}
},
"bip39": {
@@ -5273,7 +5278,7 @@
"integrity": "sha512-c9kiwdk45Do5GL0vJMe7tS95VjCii65mYAH7DfWl3uW8AVzXKQVUm64i3hzVybBDMp9r7j9iNxR85+ul8MdN/A==",
"dev": true,
"requires": {
- "hashes-grs": "^1.2.0"
+ "@noble/hashes": "^1.2.0"
}
},
"bip65": {
@@ -5341,8 +5346,9 @@
}
},
"bs58grscheck": {
- "version": "git+ssh://git@github.com/Groestlcoin/bs58grscheck.git#ab5b5e509f1754cb4764496df89d49bccfd48753",
- "from": "bs58grscheck@^3.0.1",
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/bs58grscheck/-/bs58grscheck-3.0.1.tgz",
+ "integrity": "sha512-kKloH4PKvEW2p1k7aBJhiW2PG/GkfxIuI5xGDS1Lw0j9w1pbe2yt1aSZewbUtWimEOObMeliJGyHv54tUdkiGA==",
"requires": {
"bs58": "^5.0.0",
"hashes-grs": "1.2.0"
@@ -5596,14 +5602,14 @@
}
},
"ecpairgrs": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/ecpairgrs/-/ecpairgrs-2.0.1.tgz",
- "integrity": "sha512-TeIyvUpbw8kwKMbERgNPL7xY+YWDw1Qdp9/ZPOQtKUw0VmiRRfi+wAj1RHhknd2hUb+9CvLt6s+3wzAksfUg5w==",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/ecpairgrs/-/ecpairgrs-2.0.2.tgz",
+ "integrity": "sha512-TIpsWw78dOUswi+wrNGiazOtYpyrsVtvxVSOuVM+TowbN+8LC9ZCL4AD4PZx6BqHImyfBrcBjVzS4t7r3smKTw==",
"dev": true,
"requires": {
"randombytes": "^2.1.0",
"typeforce": "^1.18.0",
- "wifgrs": "^2.0.6"
+ "wifgrs": "^2.0.7"
}
},
"electron-to-chromium": {
@@ -5974,13 +5980,6 @@
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"dev": true
},
- "fsevents": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
- "dev": true,
- "optional": true
- },
"function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
@@ -6063,6 +6062,12 @@
"integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
"dev": true
},
+ "groestl-hash-js": {
+ "version": "git+ssh://git@github.com/Groestlcoin/groestl-hash-js.git#ef6a04f1c4d2f0448f0882b5f213ef7a0659baee",
+ "integrity": "sha512-FO7JHK2JaLeEnx79qx3qIqxrm87XFXULJBTi+kXuXW2ZjMnSao7UXt8kA4KEwuJN+ufgahJXILosRKMDylQlNQ==",
+ "dev": true,
+ "from": "groestl-hash-js@git+https://github.com/Groestlcoin/groestl-hash-js.git"
+ },
"has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
@@ -7560,13 +7565,27 @@
"dev": true
},
"wifgrs": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/wifgrs/-/wifgrs-2.0.6.tgz",
- "integrity": "sha512-Zufg+IptNYTF85Hkr6Jhf6C2XpGAW3b5WeQB+Tq+PfeX1Q0/rLbZSmRc1/3Gwum19jntxuGY5d6SRnbl/cM0+w==",
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/wifgrs/-/wifgrs-2.0.7.tgz",
+ "integrity": "sha512-kcjDUinm7WzK5HI8jQGXtw8xvLV++2Bs0WRxFweBxfYXJMn51a0EuKOjPOot69qihDOoLJkoLbs/y8LM2NjK3w==",
"dev": true,
"requires": {
- "bs58grscheck": "git+https://github.com/Groestlcoin/bs58grscheck.git",
+ "bs58grscheck": "<3.0.0",
"safe-buffer": "^5.1.1"
+ },
+ "dependencies": {
+ "bs58grscheck": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/bs58grscheck/-/bs58grscheck-2.1.2.tgz",
+ "integrity": "sha512-JX7CNqxYDsUYfzwbVmUiDKOxGUQm6E9Vb5MT1/MvAv80WU+KtzdJAfUb4lbX397dd/aAGA6OF1J/sRkMk7EMzA==",
+ "dev": true,
+ "requires": {
+ "bs58": "^4.0.0",
+ "create-hash": "^1.1.0",
+ "groestl-hash-js": "git+https://github.com/Groestlcoin/groestl-hash-js.git",
+ "safe-buffer": "^5.1.2"
+ }
+ }
}
},
"word-wrap": {
diff --git a/package.json b/package.json
index 7832a356f..394d55069 100644
--- a/package.json
+++ b/package.json
@@ -66,13 +66,13 @@
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
"better-npm-audit": "^3.7.3",
- "bip32grs": "^4.0.0",
+ "bip32grs": "^4.0.1",
"bip39": "^3.1.0",
"bip65": "^1.0.1",
"bip68": "^1.0.3",
"bs58": "^4.0.0",
"dhttp": "^3.0.0",
- "ecpairgrs": "^2.0.1",
+ "ecpairgrs": "^2.0.2",
"eslint": "^8.29.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.2.1",
From 0f152e6ececa30301192cfa56722fbffaf825b72 Mon Sep 17 00:00:00 2001
From: HashEngineering
Date: Sat, 27 Jan 2024 07:56:26 -0800
Subject: [PATCH 143/144] tests: fix test vectors in psbt.json
---
test/fixtures/psbt.json | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/test/fixtures/psbt.json b/test/fixtures/psbt.json
index d6549d5a9..35d5803c7 100644
--- a/test/fixtures/psbt.json
+++ b/test/fixtures/psbt.json
@@ -281,7 +281,7 @@
],
"signer": [
{
- "psbt": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEDBAEAAAABBCIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQVHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4iBgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8OcxDZDGpPAAAAgAAAAIADAACAIgYDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwQ2QxqTwAAAIAAAACAAgAAgAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA",
+ "psbt": "cHNidP8BAJoCAAAAAskZVXwtATnua9qCl82Ic2vPsrLtVHUpw9sKHF90o3Q3AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEDBAEAAAABBCIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQVHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4iBgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8OcxDZDGpPAAAAgAAAAIADAACAIgYDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwQ2QxqTwAAAIAAAACAAgAAgAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA",
"keys": [
{
"inputToSign": 0,
@@ -292,10 +292,10 @@
"WIF": "cR6SXDoyfQrcp4piaiHE97Rsgta9mNhGTen9XeonVgwsh4gAWqaJ"
}
],
- "result": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgf0cwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMAQEDBAEAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHIgIDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtxHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwEBAwQBAAAAAQQiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEFR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuIgYCOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnMQ2QxqTwAAAIAAAACAAwAAgCIGAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcENkMak8AAACAAAAAgAIAAIAAIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA=="
+ "result": "cHNidP8BAJoCAAAAAskZVXwtATnua9qCl82Ic2vPsrLtVHUpw9sKHF90o3Q3AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgf0cwRAIgbvg99SIl6KLjfdaS/4WGSPiHAZR4E165fHuknZx+12YCIAytEX2IJWhGv3VeQzJALCh0BR/WxaVmkIimfnPsfvYQAQEDBAEAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHIgIDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtxHMEQCIGTwRdsgVpyfpMk7WL3+9mPX77hpVY84G7w6xjFUx0oLAiAVbKhcdllWXO9Y7QfY1TxLQ8vpAWi1HFW50ti37w7IHwEBAwQBAAAAAQQiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEFR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuIgYCOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnMQ2QxqTwAAAIAAAACAAwAAgCIGAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcENkMak8AAACAAAAAgAIAAIAAIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA=="
},
{
- "psbt": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEDBAEAAAABBCIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQVHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4iBgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8OcxDZDGpPAAAAgAAAAIADAACAIgYDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwQ2QxqTwAAAIAAAACAAgAAgAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA",
+ "psbt": "cHNidP8BAJoCAAAAAskZVXwtATnua9qCl82Ic2vPsrLtVHUpw9sKHF90o3Q3AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEDBAEAAAABBCIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQVHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4iBgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8OcxDZDGpPAAAAgAAAAIADAACAIgYDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwQ2QxqTwAAAIAAAACAAgAAgAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA",
"keys": [
{
"inputToSign": 0,
@@ -306,11 +306,11 @@
"WIF": "cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zKGNpnn"
}
],
- "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="
+ "result": "cHNidP8BAJoCAAAAAskZVXwtATnua9qCl82Ic2vPsrLtVHUpw9sKHF90o3Q3AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAJfhrbjTB9kQ5wvnguN0FzPZ9CVBQHvSUj1eSzMTMmz1AiAiUs+JZjL94Y/+UoSXYn8qfoNOok5zO6ctzO/3unIKsAEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBZXgqXKwjQgoYNuQMV69al+2uRosTqpMIQeA+sg7wKewIgciyFtu8B4gZAqxheuNo+9DkkkEyvG+AXjUnqpjdubEUBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA="
},
{
"description": "Sign PSBT with 3 inputs [P2PKH, P2TR (key-path), 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+863mURelmE8hSqL4MG1EydJwgAAABASu4BQEAAAAAACJRIE/vXFFjvqaak+dKWWcrvrCBg3B3y5TPpuSBpc8A2KsYARcglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4AAQEfECcAAAAAAAAWABRPoqyhKLb53uUwnE9wBR5Jxl/XMgAAAA==",
+ "psbt": "cHNidP8BAM8CAAAAA2opjewjr24G3Q4PNY7HRjG2MW+pyUKDsV3bMZQjy4P1AAAAAAD/////ZtAAqL2E1fKcmGo+7xuqS+nSQeKFVKGRYaHfIvLXn4sAAAAAAP////9+h+SlCwIx1MUDT7Bek0NrWXS7xnSPi5LbYbDc9sxYIgAAAAAA/////wIgKRsAAAAAACJRIEb2SXyy8Z1Qw+npgqlQ3MhiFLAfzOQ3pCBhx72xIw0zuAUBAAAAAAAWABTJijE0v48z5ZmmfEAADXdCBcG0FAAAAAAAAQDiAgAAAAABAUfY2D1t0dyMeEH39C1yOdIxigpqm7XJNqHVT3Lc+FkiAAAAAAD+////AhIsGwAAAAAAGXapFJ5+8XZ3ZP80oFldvEwrcNsBftBmiKyYdK6xAAAAABepFLDBn59UffGbX7u/olyFDG0eG1UJhwJHMEQCIDAd3s05C61flXVFqOtov0NoHRGr8KFcOpH6R/81F46EAiBt+j9hHyvT2hYEyf8fdYsM9IgbnybtPV+kRTHDa6Rj0AEhAmmZfwmoHsmCkEOn9AfRTh+863mURelmE8hSqL4MG1EydJwgAAABASu4BQEAAAAAACJRIE/vXFFjvqaak+dKWWcrvrCBg3B3y5TPpuSBpc8A2KsYARcglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4AAQEfECcAAAAAAAAWABRPoqyhKLb53uUwnE9wBR5Jxl/XMgAAAA==",
"isTaproot": true,
"keys": [
{
@@ -326,7 +326,7 @@
"WIF": "cPPRdCmAMZMjPdHfRmTCmzYVruZHJ8GbM1FqN2W6DnmEPWGh2Xzu"
}
],
- "result": "cHNidP8BAM8CAAAAAwPzd9k+uLSN1rgF01xY1TIA/8N+YytNZ4VP9gKFP4MyAAAAAAD/////ZtAAqL2E1fKcmGo+7xuqS+nSQeKFVKGRYaHfIvLXn4sAAAAAAP////9+h+SlCwIx1MUDT7Bek0NrWXS7xnSPi5LbYbDc9sxYIgAAAAAA/////wIgKRsAAAAAACJRIEb2SXyy8Z1Qw+npgqlQ3MhiFLAfzOQ3pCBhx72xIw0zuAUBAAAAAAAWABTJijE0v48z5ZmmfEAADXdCBcG0FAAAAAAAAQDiAgAAAAABAUfY2D1t0dyMeEH39C1yOdIxigpqm7XJNqHVT3Lc+FkiAAAAAAD+////AhIsGwAAAAAAGXapFJ5+8XZ3ZP80oFldvEwrcNsBftBmiKyYdK6xAAAAABepFLDBn59UffGbX7u/olyFDG0eG1UJhwJHMEQCIDAd3s05C61flXVFqOtov0NoHRGr8KFcOpH6R/81F46EAiBt+j9hHyvT2hYEyf8fdYsM9IgbnybtPV+kRTHDa6Rj0AEhAmmZfwmoHsmCkEOn9AfRTh+863mURelmE8hSqL4MG1EydJwgACICAi5ovBH1xLoGxPqtFh48wUEpnM+St1SbPzRwO7kBNKOQRzBEAiBpWClBybtHveXkhAgTiE8QSczMJs8MGuH4LOSNRA6s/AIgWlbB3xJOtJIsszj1qZ/whA5jK9wnTzeZzDlVs/ivq2cBAAEBK7gFAQAAAAAAIlEgT+9cUWO+ppqT50pZZyu+sIGDcHfLlM+m5IGlzwDYqxgBE0B0eYK4chVhtLT9WMi14T8ZknZSdTe1pMdIvaq6tIfwqY2xQ9YlcTTy0jWU9utItw/rHQ2c1FplbF9bRvZ6RLQSARcglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4AAQEfECcAAAAAAAAWABRPoqyhKLb53uUwnE9wBR5Jxl/XMiICA6VOpEBbPJM/xYsqO2euttYFpgec9vcxggyTyoklK660SDBFAiEAoCIktghL55iuMAmkzwYJzb+h+qmNewZXxAx/06ObxIQCIELCsBz/wd2wPlnJb27OluxMkTPnCyHA2C+SxHiX/FvPAQAAAA=="
+ "result": "cHNidP8BAM8CAAAAA2opjewjr24G3Q4PNY7HRjG2MW+pyUKDsV3bMZQjy4P1AAAAAAD/////ZtAAqL2E1fKcmGo+7xuqS+nSQeKFVKGRYaHfIvLXn4sAAAAAAP////9+h+SlCwIx1MUDT7Bek0NrWXS7xnSPi5LbYbDc9sxYIgAAAAAA/////wIgKRsAAAAAACJRIEb2SXyy8Z1Qw+npgqlQ3MhiFLAfzOQ3pCBhx72xIw0zuAUBAAAAAAAWABTJijE0v48z5ZmmfEAADXdCBcG0FAAAAAAAAQDiAgAAAAABAUfY2D1t0dyMeEH39C1yOdIxigpqm7XJNqHVT3Lc+FkiAAAAAAD+////AhIsGwAAAAAAGXapFJ5+8XZ3ZP80oFldvEwrcNsBftBmiKyYdK6xAAAAABepFLDBn59UffGbX7u/olyFDG0eG1UJhwJHMEQCIDAd3s05C61flXVFqOtov0NoHRGr8KFcOpH6R/81F46EAiBt+j9hHyvT2hYEyf8fdYsM9IgbnybtPV+kRTHDa6Rj0AEhAmmZfwmoHsmCkEOn9AfRTh+863mURelmE8hSqL4MG1EydJwgACICAi5ovBH1xLoGxPqtFh48wUEpnM+St1SbPzRwO7kBNKOQRzBEAiBkAbEIsPJTj4LQYsgJUX563734VKLPG624vtgM4o3PjQIgZLyHgX+sapdMN/QkZyDTXmOMVuKoocJ6bGvCpY1pFtoBAAEBK7gFAQAAAAAAIlEgT+9cUWO+ppqT50pZZyu+sIGDcHfLlM+m5IGlzwDYqxgBE0CYpLydE24DI7ALjLAUzbRHHZDEsTO9S4KzmTq0BkHLTPBBJvkmJ9jXyE8TCmsK8d5UoMEsYI696dosj86itJWSARcglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+LY6XEDK4AAQEfECcAAAAAAAAWABRPoqyhKLb53uUwnE9wBR5Jxl/XMiICA6VOpEBbPJM/xYsqO2euttYFpgec9vcxggyTyoklK660RzBEAiALJMY8/w/b+M1P0BKrTlwVTveZHgz4KplWYsGz7KUZEwIgAhLCtaV9lHPQFuAfz237Qj+0fzR/8UaR2v/+YsSR4fIBAAAA"
},
{
"description": "Sign PSBT with 1 input [P2TR] (script-path, 3-of-3) and one output [P2TR]",
From ed7da763b0b5be4b66c1db6253fc377d4200cd8d Mon Sep 17 00:00:00 2001
From: HashEngineering
Date: Sat, 27 Jan 2024 08:21:46 -0800
Subject: [PATCH 144/144] tests: skip tests that require regtest for
taproot.spec.ts
---
test/integration/taproot.spec.ts | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/test/integration/taproot.spec.ts b/test/integration/taproot.spec.ts
index e5a718303..7f01da115 100644
--- a/test/integration/taproot.spec.ts
+++ b/test/integration/taproot.spec.ts
@@ -19,19 +19,19 @@ const bip32 = BIP32Factory(ecc);
const ECPair = ECPairFactory(ecc);
describe('groestlcoinjs-lib (transaction with taproot)', () => {
- it('can verify the BIP86 HD wallet vectors for taproot single sig (& sending example)', async () => {
+ it.skip('can verify the BIP86 HD wallet vectors for taproot single sig (& sending example)', async () => {
// Values taken from BIP86 document
const mnemonic =
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about';
const xprv =
- 'xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu';
+ 'xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQRBET4k';
const path = `m/86'/0'/0'/0/0`; // Path to first child of receiving wallet on first account
const internalPubkey = Buffer.from(
'cc8a4bc64d897bddc5fbc2f670f7a8ba0b386779106cf1223c6fc5d7cd6fc115',
'hex',
);
const expectedAddress =
- 'bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr';
+ 'grs1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqezj0h8';
// Verify the above (Below is no different than other HD wallets)
const seed = await bip39.mnemonicToSeed(mnemonic);
@@ -91,7 +91,7 @@ describe('groestlcoinjs-lib (transaction with taproot)', () => {
});
});
- it('can create (and broadcast via 3PBP) a taproot key-path spend Transaction', async () => {
+ it.skip('can create (and broadcast via 3PBP) a taproot key-path spend Transaction', async () => {
const internalKey = bip32.fromSeed(rng(64), regtest);
const p2pkhKey = bip32.fromSeed(rng(64), regtest);
@@ -158,7 +158,7 @@ describe('groestlcoinjs-lib (transaction with taproot)', () => {
});
});
- it('can create (and broadcast via 3PBP) a taproot key-path spend Transaction (with unused scriptTree)', async () => {
+ it.skip('can create (and broadcast via 3PBP) a taproot key-path spend Transaction (with unused scriptTree)', async () => {
const internalKey = bip32.fromSeed(rng(64), regtest);
const leafKey = bip32.fromSeed(rng(64), regtest);
@@ -215,7 +215,7 @@ describe('groestlcoinjs-lib (transaction with taproot)', () => {
});
});
- it('can create (and broadcast via 3PBP) a taproot script-path spend Transaction - OP_CHECKSIG', async () => {
+ it.skip('can create (and broadcast via 3PBP) a taproot script-path spend Transaction - OP_CHECKSIG', async () => {
const internalKey = bip32.fromSeed(rng(64), regtest);
const leafKey = bip32.fromSeed(rng(64), regtest);
@@ -334,7 +334,7 @@ describe('groestlcoinjs-lib (transaction with taproot)', () => {
});
});
- it('can create (and broadcast via 3PBP) a taproot script-path spend Transaction - OP_CHECKSEQUENCEVERIFY', async () => {
+ it.skip('can create (and broadcast via 3PBP) a taproot script-path spend Transaction - OP_CHECKSEQUENCEVERIFY', async () => {
const internalKey = bip32.fromSeed(rng(64), regtest);
const leafKey = bip32.fromSeed(rng(64), regtest);
const leafPubkey = toXOnly(leafKey.publicKey).toString('hex');
@@ -438,7 +438,7 @@ describe('groestlcoinjs-lib (transaction with taproot)', () => {
});
});
- it('can create (and broadcast via 3PBP) a taproot script-path spend Transaction - OP_CHECKSIGADD (3-of-3)', async () => {
+ it.skip('can create (and broadcast via 3PBP) a taproot script-path spend Transaction - OP_CHECKSIGADD (3-of-3)', async () => {
const internalKey = bip32.fromSeed(rng(64), regtest);
const leafKeys = [];
@@ -526,7 +526,7 @@ describe('groestlcoinjs-lib (transaction with taproot)', () => {
});
});
- it('can create (and broadcast via 3PBP) a taproot script-path spend Transaction - custom finalizer', async () => {
+ it.skip('can create (and broadcast via 3PBP) a taproot script-path spend Transaction - custom finalizer', async () => {
const leafCount = 8;
const leaves = Array.from({ length: leafCount }).map(
(_, index) =>