From 6148ad83e0b9843548a7e7d00ce5e521b82d93aa Mon Sep 17 00:00:00 2001 From: ayman Date: Wed, 21 Aug 2024 20:51:36 +0530 Subject: [PATCH 1/6] feat: move to esm varuint-bitcoin --- package-lock.json | 43 +++++++++++++++++++++++++++------------ package.json | 2 +- src/block.js | 4 ++-- src/bufferutils.d.ts | 4 ++-- src/bufferutils.js | 32 ++++++++++++++++------------- src/payments/bip341.js | 1 + src/psbt.js | 6 +++--- src/psbt/psbtutils.js | 2 +- test/bufferutils.spec.ts | 4 ++-- ts_src/block.ts | 8 ++++++-- ts_src/bufferutils.ts | 39 +++++++++++++++++++---------------- ts_src/payments/bip341.ts | 1 + ts_src/psbt.ts | 6 +++--- ts_src/psbt/psbtutils.ts | 2 +- 14 files changed, 93 insertions(+), 61 deletions(-) diff --git a/package-lock.json b/package-lock.json index 57c3a4b2b..43b403e6b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "bip174": "^2.1.1", "bs58check": "^3.0.1", "typeforce": "^1.11.3", - "varuint-bitcoin": "^1.1.2" + "varuint-bitcoin": "../varuint-bitcoin" }, "devDependencies": { "@types/bs58": "^4.0.0", @@ -54,6 +54,21 @@ "node": ">=8.0.0" } }, + "../varuint-bitcoin": { + "version": "1.1.2", + "license": "MIT", + "dependencies": { + "uint8array-tools": "^0.0.8" + }, + "devDependencies": { + "@types/node": "^20.14.8", + "c8": "^10.1.2", + "rimraf": "^5.0.7", + "tape": "^5.3.0", + "ts-standard": "^12.0.2", + "typescript": "^5.1.6" + } + }, "node_modules/@ampproject/remapping": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", @@ -3829,6 +3844,7 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, "funding": [ { "type": "github", @@ -4394,12 +4410,8 @@ } }, "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" - } + "resolved": "../varuint-bitcoin", + "link": true }, "node_modules/vscode-oniguruma": { "version": "1.7.0", @@ -7416,7 +7428,8 @@ "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==" + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true }, "semver": { "version": "7.6.2", @@ -7823,11 +7836,15 @@ "dev": true }, "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==", - "requires": { - "safe-buffer": "^5.1.1" + "version": "file:../varuint-bitcoin", + "requires": { + "@types/node": "^20.14.8", + "c8": "^10.1.2", + "rimraf": "^5.0.7", + "tape": "^5.3.0", + "ts-standard": "^12.0.2", + "typescript": "^5.1.6", + "uint8array-tools": "^0.0.8" } }, "vscode-oniguruma": { diff --git a/package.json b/package.json index 609f99b94..d700b8482 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "bip174": "^2.1.1", "bs58check": "^3.0.1", "typeforce": "^1.11.3", - "varuint-bitcoin": "^1.1.2" + "varuint-bitcoin": "../varuint-bitcoin" }, "devDependencies": { "@types/bs58": "^4.0.0", diff --git a/src/block.js b/src/block.js index 2c130c3bc..eeea4a38d 100644 --- a/src/block.js +++ b/src/block.js @@ -143,12 +143,12 @@ class Block { bufferWriter.writeUInt32(this.bits); bufferWriter.writeUInt32(this.nonce); if (headersOnly || !this.transactions) return buffer; - bufferutils_1.varuint.encode( + const { bytes } = bufferutils_1.varuint.encode( this.transactions.length, buffer, bufferWriter.offset, ); - bufferWriter.offset += bufferutils_1.varuint.encode.bytes; + bufferWriter.offset += bytes; this.transactions.forEach(tx => { const txSize = tx.byteLength(); // TODO: extract from toBuffer? tx.toBuffer(buffer, bufferWriter.offset); diff --git a/src/bufferutils.d.ts b/src/bufferutils.d.ts index b76bae0e3..3de71fd30 100644 --- a/src/bufferutils.d.ts +++ b/src/bufferutils.d.ts @@ -47,8 +47,8 @@ export declare class BufferReader { readInt32(): number; readUInt32(): number; readUInt64(): number; - readVarInt(): number; - readSlice(n: number): Buffer; + readVarInt(): bigint; + readSlice(n: number | bigint): Buffer; readVarSlice(): Buffer; readVector(): Buffer[]; } diff --git a/src/bufferutils.js b/src/bufferutils.js index cf11f02b4..687e71d8b 100644 --- a/src/bufferutils.js +++ b/src/bufferutils.js @@ -12,21 +12,23 @@ const types = require('./types'); const { typeforce } = types; const varuint = require('varuint-bitcoin'); exports.varuint = varuint; +const MAX_JS_NUMBER = 0x001fffffffffffff; // https://github.com/feross/buffer/blob/master/index.js#L1127 function verifuint(value, max) { - if (typeof value !== 'number') + if (typeof value !== 'number' && typeof value !== 'bigint') throw new Error('cannot write a non-number as a number'); - if (value < 0) + if (value < 0 && value < BigInt(0)) throw new Error('specified a negative value for writing an unsigned value'); - if (value > max) throw new Error('RangeError: value out of range'); - if (Math.floor(value) !== value) + if (value > max && value > BigInt(max)) + throw new Error('RangeError: value out of range'); + if (Math.floor(Number(value)) !== Number(value)) throw new Error('value has a fractional component'); } function readUInt64LE(buffer, offset) { const a = buffer.readUInt32LE(offset); let b = buffer.readUInt32LE(offset + 4); b *= 0x100000000; - verifuint(b + a, 0x001fffffffffffff); + verifuint(b + a, MAX_JS_NUMBER); return b + a; } exports.readUInt64LE = readUInt64LE; @@ -39,7 +41,7 @@ exports.readUInt64LE = readUInt64LE; * @returns The new offset after writing the value. */ function writeUInt64LE(buffer, value, offset) { - verifuint(value, 0x001fffffffffffff); + verifuint(value, MAX_JS_NUMBER); buffer.writeInt32LE(value & -1, offset); buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4); return offset + 8; @@ -94,8 +96,8 @@ class BufferWriter { this.offset = writeUInt64LE(this.buffer, i, this.offset); } writeVarInt(i) { - varuint.encode(i, this.buffer, this.offset); - this.offset += varuint.encode.bytes; + const { bytes } = varuint.encode(i, this.buffer, this.offset); + this.offset += bytes; } writeSlice(slice) { if (this.buffer.length < this.offset + slice.length) { @@ -149,16 +151,18 @@ class BufferReader { return result; } readVarInt() { - const vi = varuint.decode(this.buffer, this.offset); - this.offset += varuint.decode.bytes; - return vi; + const { bigintValue, bytes } = varuint.decode(this.buffer, this.offset); + this.offset += bytes; + return bigintValue; } readSlice(n) { - if (this.buffer.length < this.offset + n) { + verifuint(n, MAX_JS_NUMBER); + const num = Number(n); + if (this.buffer.length < this.offset + num) { throw new Error('Cannot read slice out of bounds'); } - const result = this.buffer.slice(this.offset, this.offset + n); - this.offset += n; + const result = this.buffer.slice(this.offset, this.offset + num); + this.offset += num; return result; } readVarSlice() { diff --git a/src/payments/bip341.js b/src/payments/bip341.js index 926af6bf2..59eea4612 100644 --- a/src/payments/bip341.js +++ b/src/payments/bip341.js @@ -114,6 +114,7 @@ function tapBranchHash(a, b) { return bcrypto.taggedHash('TapBranch', buffer_1.Buffer.concat([a, b])); } function serializeScript(s) { + /* global BigInt */ const varintLen = bufferutils_1.varuint.encodingLength(s.length); const buffer = buffer_1.Buffer.allocUnsafe(varintLen); // better bufferutils_1.varuint.encode(s.length, buffer); diff --git a/src/psbt.js b/src/psbt.js index b071f374f..01c98b30e 100644 --- a/src/psbt.js +++ b/src/psbt.js @@ -2,7 +2,7 @@ Object.defineProperty(exports, '__esModule', { value: true }); exports.Psbt = void 0; const bip174_1 = require('bip174'); -const varuint = require('bip174/src/lib/converter/varint'); +const varuint = require('varuint-bitcoin'); const utils_1 = require('bip174/src/lib/utils'); const address_1 = require('./address'); const bufferutils_1 = require('./bufferutils'); @@ -1495,8 +1495,8 @@ function scriptWitnessToWitnessStack(buffer) { } function readVarInt() { const vi = varuint.decode(buffer, offset); - offset += varuint.decode.bytes; - return vi; + offset += varuint.encodingLength(vi.bigintValue); + return vi.numberValue; } function readVarSlice() { return readSlice(readVarInt()); diff --git a/src/psbt/psbtutils.js b/src/psbt/psbtutils.js index 8173e81d9..73ee89db5 100644 --- a/src/psbt/psbtutils.js +++ b/src/psbt/psbtutils.js @@ -13,7 +13,7 @@ exports.signatureBlocksAction = exports.isP2PK = exports.isP2MS = void 0; -const varuint = require('bip174/src/lib/converter/varint'); +const varuint = require('varuint-bitcoin'); const bscript = require('../script'); const transaction_1 = require('../transaction'); const crypto_1 = require('../crypto'); diff --git a/test/bufferutils.spec.ts b/test/bufferutils.spec.ts index 6895f7e50..21a97ad4b 100644 --- a/test/bufferutils.spec.ts +++ b/test/bufferutils.spec.ts @@ -4,7 +4,7 @@ import * as bufferutils from '../src/bufferutils'; import { BufferReader, BufferWriter } from '../src/bufferutils'; import * as fixtures from './fixtures/bufferutils.json'; -const varuint = require('varuint-bitcoin'); +import varuint = require('varuint-bitcoin'); describe('bufferutils', () => { function concatToBuffer(values: number[][]): Buffer { @@ -427,7 +427,7 @@ describe('bufferutils', () => { values.forEach((value: number) => { const expectedOffset = bufferReader.offset + varuint.encodingLength(value); - const val = bufferReader.readVarInt(); + const val = Number(bufferReader.readVarInt()); testValue(bufferReader, val, value, expectedOffset); }); }); diff --git a/ts_src/block.ts b/ts_src/block.ts index c73477e02..f851c2d11 100644 --- a/ts_src/block.ts +++ b/ts_src/block.ts @@ -178,8 +178,12 @@ export class Block { if (headersOnly || !this.transactions) return buffer; - varuint.encode(this.transactions.length, buffer, bufferWriter.offset); - bufferWriter.offset += varuint.encode.bytes; + const { bytes } = varuint.encode( + this.transactions.length, + buffer, + bufferWriter.offset, + ); + bufferWriter.offset += bytes; this.transactions.forEach(tx => { const txSize = tx.byteLength(); // TODO: extract from toBuffer? diff --git a/ts_src/bufferutils.ts b/ts_src/bufferutils.ts index b73ce1502..1e46a49b5 100644 --- a/ts_src/bufferutils.ts +++ b/ts_src/bufferutils.ts @@ -3,14 +3,17 @@ const { typeforce } = types; import * as varuint from 'varuint-bitcoin'; export { varuint }; +const MAX_JS_NUMBER = 0x001fffffffffffff; + // https://github.com/feross/buffer/blob/master/index.js#L1127 -function verifuint(value: number, max: number): void { - if (typeof value !== 'number') +function verifuint(value: number | bigint, max: number): void { + if (typeof value !== 'number' && typeof value !== 'bigint') throw new Error('cannot write a non-number as a number'); - if (value < 0) + if (value < 0 && value < BigInt(0)) throw new Error('specified a negative value for writing an unsigned value'); - if (value > max) throw new Error('RangeError: value out of range'); - if (Math.floor(value) !== value) + if (value > max && value > BigInt(max)) + throw new Error('RangeError: value out of range'); + if (Math.floor(Number(value)) !== Number(value)) throw new Error('value has a fractional component'); } @@ -19,7 +22,7 @@ export function readUInt64LE(buffer: Buffer, offset: number): number { let b = buffer.readUInt32LE(offset + 4); b *= 0x100000000; - verifuint(b + a, 0x001fffffffffffff); + verifuint(b + a, MAX_JS_NUMBER); return b + a; } @@ -36,7 +39,7 @@ export function writeUInt64LE( value: number, offset: number, ): number { - verifuint(value, 0x001fffffffffffff); + verifuint(value, MAX_JS_NUMBER); buffer.writeInt32LE(value & -1, offset); buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4); @@ -96,8 +99,8 @@ export class BufferWriter { } writeVarInt(i: number): void { - varuint.encode(i, this.buffer, this.offset); - this.offset += varuint.encode.bytes; + const { bytes } = varuint.encode(i, this.buffer, this.offset); + this.offset += bytes; } writeSlice(slice: Buffer): void { @@ -157,18 +160,20 @@ export class BufferReader { return result; } - readVarInt(): number { - const vi = varuint.decode(this.buffer, this.offset); - this.offset += varuint.decode.bytes; - return vi; + readVarInt(): bigint { + const { bigintValue, bytes } = varuint.decode(this.buffer, this.offset); + this.offset += bytes; + return bigintValue; } - readSlice(n: number): Buffer { - if (this.buffer.length < this.offset + n) { + readSlice(n: number | bigint): Buffer { + verifuint(n, MAX_JS_NUMBER); + const num = Number(n); + if (this.buffer.length < this.offset + num) { throw new Error('Cannot read slice out of bounds'); } - const result = this.buffer.slice(this.offset, this.offset + n); - this.offset += n; + const result = this.buffer.slice(this.offset, this.offset + num); + this.offset += num; return result; } diff --git a/ts_src/payments/bip341.ts b/ts_src/payments/bip341.ts index af9b1f171..8c7a36108 100644 --- a/ts_src/payments/bip341.ts +++ b/ts_src/payments/bip341.ts @@ -146,6 +146,7 @@ function tapBranchHash(a: Buffer, b: Buffer): Buffer { } function serializeScript(s: Buffer): Buffer { + /* global BigInt */ const varintLen = varuint.encodingLength(s.length); const buffer = NBuffer.allocUnsafe(varintLen); // better varuint.encode(s.length, buffer); diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts index c73574035..892382352 100644 --- a/ts_src/psbt.ts +++ b/ts_src/psbt.ts @@ -1,5 +1,5 @@ import { Psbt as PsbtBase } from 'bip174'; -import * as varuint from 'bip174/src/lib/converter/varint'; +import * as varuint from 'varuint-bitcoin'; import { Bip32Derivation, KeyValue, @@ -1957,8 +1957,8 @@ function scriptWitnessToWitnessStack(buffer: Buffer): Buffer[] { function readVarInt(): number { const vi = varuint.decode(buffer, offset); - offset += (varuint.decode as any).bytes; - return vi; + offset += varuint.encodingLength(vi.bigintValue); + return vi.numberValue!; } function readVarSlice(): Buffer { diff --git a/ts_src/psbt/psbtutils.ts b/ts_src/psbt/psbtutils.ts index bc72db595..d9e678eb9 100644 --- a/ts_src/psbt/psbtutils.ts +++ b/ts_src/psbt/psbtutils.ts @@ -1,4 +1,4 @@ -import * as varuint from 'bip174/src/lib/converter/varint'; +import * as varuint from 'varuint-bitcoin'; import { PartialSig, PsbtInput } from 'bip174/src/lib/interfaces'; import * as bscript from '../script'; import { Transaction } from '../transaction'; From 9c3e8cc3635dc6f5d8b5c632eb2d250b112c8fb7 Mon Sep 17 00:00:00 2001 From: ayman Date: Fri, 23 Aug 2024 08:56:09 +0530 Subject: [PATCH 2/6] feat: use read-write integer methods from uint8array-tools --- package-lock.json | 162 ++- package.json | 8 +- src/{ => cjs}/address.d.ts | 0 src/{ => cjs}/address.js | 52 +- src/{ => cjs}/bip66.d.ts | 0 src/{ => cjs}/bip66.js | 0 src/{ => cjs}/block.d.ts | 0 src/cjs/block.js | 262 ++++ src/{ => cjs}/bufferutils.d.ts | 0 src/cjs/bufferutils.js | 226 ++++ src/{ => cjs}/crypto.d.ts | 0 src/{ => cjs}/crypto.js | 0 src/{ => cjs}/ecc_lib.d.ts | 0 src/{ => cjs}/ecc_lib.js | 0 src/{ => cjs}/index.d.ts | 0 src/cjs/index.js | 103 ++ src/{ => cjs}/merkle.d.ts | 0 src/{ => cjs}/merkle.js | 0 src/{ => cjs}/networks.d.ts | 0 src/{ => cjs}/networks.js | 0 src/{ => cjs}/ops.d.ts | 0 src/{ => cjs}/ops.js | 0 src/{ => cjs}/payments/bip341.d.ts | 0 src/{ => cjs}/payments/bip341.js | 46 +- src/{ => cjs}/payments/embed.d.ts | 0 src/cjs/payments/embed.js | 97 ++ src/{ => cjs}/payments/index.d.ts | 0 src/{ => cjs}/payments/index.js | 0 src/{ => cjs}/payments/lazy.d.ts | 0 src/{ => cjs}/payments/lazy.js | 0 src/{ => cjs}/payments/p2ms.d.ts | 0 src/{ => cjs}/payments/p2ms.js | 48 +- src/{ => cjs}/payments/p2pk.d.ts | 0 src/cjs/payments/p2pk.js | 124 ++ src/{ => cjs}/payments/p2pkh.d.ts | 0 src/cjs/payments/p2pkh.js | 184 +++ src/{ => cjs}/payments/p2sh.d.ts | 0 src/{ => cjs}/payments/p2sh.js | 52 +- src/{ => cjs}/payments/p2tr.d.ts | 0 src/{ => cjs}/payments/p2tr.js | 48 +- src/{ => cjs}/payments/p2wpkh.d.ts | 0 src/{ => cjs}/payments/p2wpkh.js | 50 +- src/{ => cjs}/payments/p2wsh.d.ts | 0 src/{ => cjs}/payments/p2wsh.js | 50 +- src/{ => cjs}/psbt.d.ts | 0 src/{ => cjs}/psbt.js | 54 +- src/{ => cjs}/psbt/bip371.d.ts | 0 src/{ => cjs}/psbt/bip371.js | 0 src/{ => cjs}/psbt/psbtutils.d.ts | 0 src/{ => cjs}/psbt/psbtutils.js | 50 +- src/{ => cjs}/push_data.d.ts | 0 src/{ => cjs}/push_data.js | 0 src/{ => cjs}/script.d.ts | 0 src/{ => cjs}/script.js | 54 +- src/{ => cjs}/script_number.d.ts | 0 src/{ => cjs}/script_number.js | 0 src/{ => cjs}/script_signature.d.ts | 0 src/cjs/script_signature.js | 123 ++ src/{ => cjs}/transaction.d.ts | 0 src/{ => cjs}/transaction.js | 80 +- src/{ => cjs}/types.d.ts | 0 src/{ => cjs}/types.js | 0 src/esm/address.js | 162 +++ src/esm/bip66.js | 96 ++ src/{ => esm}/block.js | 55 +- src/{ => esm}/bufferutils.js | 38 +- src/esm/crypto.js | 98 ++ src/esm/ecc_lib.js | 105 ++ src/esm/index.js | 12 + src/esm/merkle.js | 26 + src/esm/networks.js | 68 ++ src/esm/ops.js | 127 ++ src/esm/payments/bip341.js | 101 ++ src/{ => esm}/payments/embed.js | 30 +- src/esm/payments/index.js | 11 + src/esm/payments/lazy.js | 27 + src/esm/payments/p2ms.js | 142 +++ src/{ => esm}/payments/p2pk.js | 31 +- src/{ => esm}/payments/p2pkh.js | 39 +- src/esm/payments/p2sh.js | 192 +++ src/esm/payments/p2tr.js | 285 +++++ src/esm/payments/p2wpkh.js | 134 +++ src/esm/payments/p2wsh.js | 215 ++++ src/esm/psbt.js | 1715 +++++++++++++++++++++++++++ src/esm/psbt/bip371.js | 484 ++++++++ src/esm/psbt/psbtutils.js | 165 +++ src/esm/push_data.js | 76 ++ src/esm/script.js | 198 ++++ src/esm/script_number.js | 73 ++ src/{ => esm}/script_signature.js | 19 +- src/esm/transaction.js | 533 +++++++++ src/esm/types.js | 74 ++ src/index.js | 59 - ts_src/address.ts | 26 +- ts_src/bip66.ts | 10 +- ts_src/bufferutils.ts | 110 +- ts_src/crypto.ts | 30 +- ts_src/payments/index.ts | 22 +- ts_src/psbt.ts | 88 +- ts_src/psbt/psbtutils.ts | 36 +- ts_src/push_data.ts | 42 +- ts_src/script.ts | 47 +- ts_src/script_signature.ts | 38 +- ts_src/transaction.ts | 109 +- tsconfig.base.json | 24 + tsconfig.cjs.json | 9 + tsconfig.json | 25 +- 107 files changed, 7333 insertions(+), 546 deletions(-) rename src/{ => cjs}/address.d.ts (100%) rename src/{ => cjs}/address.js (81%) rename src/{ => cjs}/bip66.d.ts (100%) rename src/{ => cjs}/bip66.js (100%) rename src/{ => cjs}/block.d.ts (100%) create mode 100644 src/cjs/block.js rename src/{ => cjs}/bufferutils.d.ts (100%) create mode 100644 src/cjs/bufferutils.js rename src/{ => cjs}/crypto.d.ts (100%) rename src/{ => cjs}/crypto.js (100%) rename src/{ => cjs}/ecc_lib.d.ts (100%) rename src/{ => cjs}/ecc_lib.js (100%) rename src/{ => cjs}/index.d.ts (100%) create mode 100644 src/cjs/index.js rename src/{ => cjs}/merkle.d.ts (100%) rename src/{ => cjs}/merkle.js (100%) rename src/{ => cjs}/networks.d.ts (100%) rename src/{ => cjs}/networks.js (100%) rename src/{ => cjs}/ops.d.ts (100%) rename src/{ => cjs}/ops.js (100%) rename src/{ => cjs}/payments/bip341.d.ts (100%) rename src/{ => cjs}/payments/bip341.js (75%) rename src/{ => cjs}/payments/embed.d.ts (100%) create mode 100644 src/cjs/payments/embed.js rename src/{ => cjs}/payments/index.d.ts (100%) rename src/{ => cjs}/payments/index.js (100%) rename src/{ => cjs}/payments/lazy.d.ts (100%) rename src/{ => cjs}/payments/lazy.js (100%) rename src/{ => cjs}/payments/p2ms.d.ts (100%) rename src/{ => cjs}/payments/p2ms.js (78%) rename src/{ => cjs}/payments/p2pk.d.ts (100%) create mode 100644 src/cjs/payments/p2pk.js rename src/{ => cjs}/payments/p2pkh.d.ts (100%) create mode 100644 src/cjs/payments/p2pkh.js rename src/{ => cjs}/payments/p2sh.d.ts (100%) rename src/{ => cjs}/payments/p2sh.js (82%) rename src/{ => cjs}/payments/p2tr.d.ts (100%) rename src/{ => cjs}/payments/p2tr.js (88%) rename src/{ => cjs}/payments/p2wpkh.d.ts (100%) rename src/{ => cjs}/payments/p2wpkh.js (77%) rename src/{ => cjs}/payments/p2wsh.d.ts (100%) rename src/{ => cjs}/payments/p2wsh.js (84%) rename src/{ => cjs}/psbt.d.ts (100%) rename src/{ => cjs}/psbt.js (97%) rename src/{ => cjs}/psbt/bip371.d.ts (100%) rename src/{ => cjs}/psbt/bip371.js (100%) rename src/{ => cjs}/psbt/psbtutils.d.ts (100%) rename src/{ => cjs}/psbt/psbtutils.js (82%) rename src/{ => cjs}/push_data.d.ts (100%) rename src/{ => cjs}/push_data.js (100%) rename src/{ => cjs}/script.d.ts (100%) rename src/{ => cjs}/script.js (81%) rename src/{ => cjs}/script_number.d.ts (100%) rename src/{ => cjs}/script_number.js (100%) rename src/{ => cjs}/script_signature.d.ts (100%) create mode 100644 src/cjs/script_signature.js rename src/{ => cjs}/transaction.d.ts (100%) rename src/{ => cjs}/transaction.js (91%) rename src/{ => cjs}/types.d.ts (100%) rename src/{ => cjs}/types.js (100%) create mode 100644 src/esm/address.js create mode 100644 src/esm/bip66.js rename src/{ => esm}/block.js (85%) rename src/{ => esm}/bufferutils.js (85%) create mode 100644 src/esm/crypto.js create mode 100644 src/esm/ecc_lib.js create mode 100644 src/esm/index.js create mode 100644 src/esm/merkle.js create mode 100644 src/esm/networks.js create mode 100644 src/esm/ops.js create mode 100644 src/esm/payments/bip341.js rename src/{ => esm}/payments/embed.js (58%) create mode 100644 src/esm/payments/index.js create mode 100644 src/esm/payments/lazy.js create mode 100644 src/esm/payments/p2ms.js rename src/{ => esm}/payments/p2pk.js (70%) rename src/{ => esm}/payments/p2pkh.js (78%) create mode 100644 src/esm/payments/p2sh.js create mode 100644 src/esm/payments/p2tr.js create mode 100644 src/esm/payments/p2wpkh.js create mode 100644 src/esm/payments/p2wsh.js create mode 100644 src/esm/psbt.js create mode 100644 src/esm/psbt/bip371.js create mode 100644 src/esm/psbt/psbtutils.js create mode 100644 src/esm/push_data.js create mode 100644 src/esm/script.js create mode 100644 src/esm/script_number.js rename src/{ => esm}/script_signature.js (82%) create mode 100644 src/esm/transaction.js create mode 100644 src/esm/types.js delete mode 100644 src/index.js create mode 100644 tsconfig.base.json create mode 100644 tsconfig.cjs.json diff --git a/package-lock.json b/package-lock.json index 43b403e6b..ed2883af3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,9 +11,10 @@ "dependencies": { "@noble/hashes": "^1.2.0", "bech32": "^2.0.0", - "bip174": "^2.1.1", - "bs58check": "^3.0.1", + "bip174": "../bip174", + "bs58check": "^4.0.0", "typeforce": "^1.11.3", + "uint8array-tools": "../uint8array-tools", "varuint-bitcoin": "../varuint-bitcoin" }, "devDependencies": { @@ -54,8 +55,50 @@ "node": ">=8.0.0" } }, + "../bip174": { + "version": "2.1.1", + "license": "MIT", + "dependencies": { + "uint8array-tools": "../uint8array-tools", + "varuint-bitcoin": "../varuint-bitcoin" + }, + "devDependencies": { + "@types/node": "12.0.8", + "@types/tape": "4.2.33", + "bitcoinjs-lib": "^5.0.5", + "c8": "^10.1.2", + "prettier": "^1.18.2", + "rimraf": "^2.6.3", + "tape": "^5.3.0", + "tslint": "5.17.0", + "typescript": "3.5.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../uint8array-tools": { + "version": "0.0.8", + "license": "MIT", + "devDependencies": { + "@types/jest": "27.0.2", + "@types/node": "16.11.1", + "@typescript-eslint/eslint-plugin": "5.0.0", + "@typescript-eslint/parser": "5.0.0", + "eslint": "8.0.1", + "eslint-config-prettier": "8.3.0", + "eslint-plugin-prettier": "4.0.0", + "jest": "27.2.5", + "prettier": "2.4.1", + "ts-jest": "27.0.7", + "typescript": "4.4.4" + }, + "engines": { + "node": ">=14.0.0" + } + }, "../varuint-bitcoin": { - "version": "1.1.2", + "version": "2.0.0", "license": "MIT", "dependencies": { "uint8array-tools": "^0.0.8" @@ -1266,12 +1309,8 @@ } }, "node_modules/bip174": { - "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" - } + "resolved": "../bip174", + "link": true }, "node_modules/bip32": { "version": "4.0.0", @@ -1387,25 +1426,25 @@ } }, "node_modules/bs58check": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-3.0.1.tgz", - "integrity": "sha512-hjuuJvoWEybo7Hn/0xOrczQKKEKD63WguEjlhLExYs2wUBcebDC1jDNK17eEAD2lYfw82d5ASC1d7K3SWszjaQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-4.0.0.tgz", + "integrity": "sha512-FsGDOnFg9aVI9erdriULkd/JjEWONV/lQE5aYziB5PoBsXRind56lh8doIZIc9X4HoxT5x4bLjMWN1/NB8Zp5g==", "dependencies": { "@noble/hashes": "^1.2.0", - "bs58": "^5.0.0" + "bs58": "^6.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==" + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.0.tgz", + "integrity": "sha512-sMW3VGSX1QWVFA6l8U62MLKz29rRfpTlYdCqLdpLo1/Yd4zZwSbnUaDfciIAowAqvq7YFnWq9hrhdg1KYgc1lQ==" }, "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==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-6.0.0.tgz", + "integrity": "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==", "dependencies": { - "base-x": "^4.0.0" + "base-x": "^5.0.0" } }, "node_modules/buffer-from": { @@ -4181,6 +4220,15 @@ "node": ">=14.0.0" } }, + "node_modules/tiny-secp256k1/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/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -4351,13 +4399,8 @@ } }, "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" - } + "resolved": "../uint8array-tools", + "link": true }, "node_modules/update-browserslist-db": { "version": "1.0.10", @@ -5497,9 +5540,20 @@ "dev": true }, "bip174": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bip174/-/bip174-2.1.1.tgz", - "integrity": "sha512-mdFV5+/v0XyNYXjBS6CQPLo9ekCx4gtKZFnJm5PMto7Fs9hTTDpkkzOB7/FtluRI6JbUUAu+snTYfJRgHLZbZQ==" + "version": "file:../bip174", + "requires": { + "@types/node": "12.0.8", + "@types/tape": "4.2.33", + "bitcoinjs-lib": "^5.0.5", + "c8": "^10.1.2", + "prettier": "^1.18.2", + "rimraf": "^2.6.3", + "tape": "^5.3.0", + "tslint": "5.17.0", + "typescript": "3.5.2", + "uint8array-tools": "../uint8array-tools", + "varuint-bitcoin": "../varuint-bitcoin" + } }, "bip32": { "version": "4.0.0", @@ -5587,25 +5641,25 @@ } }, "bs58check": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-3.0.1.tgz", - "integrity": "sha512-hjuuJvoWEybo7Hn/0xOrczQKKEKD63WguEjlhLExYs2wUBcebDC1jDNK17eEAD2lYfw82d5ASC1d7K3SWszjaQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-4.0.0.tgz", + "integrity": "sha512-FsGDOnFg9aVI9erdriULkd/JjEWONV/lQE5aYziB5PoBsXRind56lh8doIZIc9X4HoxT5x4bLjMWN1/NB8Zp5g==", "requires": { "@noble/hashes": "^1.2.0", - "bs58": "^5.0.0" + "bs58": "^6.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==" + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.0.tgz", + "integrity": "sha512-sMW3VGSX1QWVFA6l8U62MLKz29rRfpTlYdCqLdpLo1/Yd4zZwSbnUaDfciIAowAqvq7YFnWq9hrhdg1KYgc1lQ==" }, "bs58": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz", - "integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-6.0.0.tgz", + "integrity": "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==", "requires": { - "base-x": "^4.0.0" + "base-x": "^5.0.0" } } } @@ -7678,6 +7732,14 @@ "dev": true, "requires": { "uint8array-tools": "0.0.7" + }, + "dependencies": { + "uint8array-tools": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.7.tgz", + "integrity": "sha512-vrrNZJiusLWoFWBqz5Y5KMCgP9W9hnjZHzZiZRT8oNAkq3d5Z5Oe76jAvVVSRh4U8GGR90N2X1dWtrhvx6L8UQ==", + "dev": true + } } }, "to-fast-properties": { @@ -7799,10 +7861,20 @@ "dev": true }, "uint8array-tools": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.7.tgz", - "integrity": "sha512-vrrNZJiusLWoFWBqz5Y5KMCgP9W9hnjZHzZiZRT8oNAkq3d5Z5Oe76jAvVVSRh4U8GGR90N2X1dWtrhvx6L8UQ==", - "dev": true + "version": "file:../uint8array-tools", + "requires": { + "@types/jest": "27.0.2", + "@types/node": "16.11.1", + "@typescript-eslint/eslint-plugin": "5.0.0", + "@typescript-eslint/parser": "5.0.0", + "eslint": "8.0.1", + "eslint-config-prettier": "8.3.0", + "eslint-plugin-prettier": "4.0.0", + "jest": "27.2.5", + "prettier": "2.4.1", + "ts-jest": "27.0.7", + "typescript": "4.4.4" + } }, "update-browserslist-db": { "version": "1.0.10", diff --git a/package.json b/package.json index d700b8482..880120bee 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "bitcoinjs-lib", "version": "6.1.6", "description": "Client-side Bitcoin JavaScript library", + "type": "module", "main": "./src/index.js", "types": "./src/index.d.ts", "engines": { @@ -16,7 +17,7 @@ ], "scripts": { "audit": "better-npm-audit audit -l high", - "build": "npm run clean && tsc -p ./tsconfig.json && npm run formatjs", + "build": "npm run clean && tsc -p ./tsconfig.json && tsc -p ./tsconfig.cjs.json && npm run formatjs", "build:tests": "npm run clean:jstests && tsc -p ./test/tsconfig.json", "clean": "rimraf src", "clean:jstests": "rimraf 'test/**/!(ts-node-register)*.js'", @@ -52,9 +53,10 @@ "dependencies": { "@noble/hashes": "^1.2.0", "bech32": "^2.0.0", - "bip174": "^2.1.1", - "bs58check": "^3.0.1", + "bip174": "../bip174", + "bs58check": "^4.0.0", "typeforce": "^1.11.3", + "uint8array-tools": "../uint8array-tools", "varuint-bitcoin": "../varuint-bitcoin" }, "devDependencies": { diff --git a/src/address.d.ts b/src/cjs/address.d.ts similarity index 100% rename from src/address.d.ts rename to src/cjs/address.d.ts diff --git a/src/address.js b/src/cjs/address.js similarity index 81% rename from src/address.js rename to src/cjs/address.js index ad3ceeb1a..c67ae30dd 100644 --- a/src/address.js +++ b/src/cjs/address.js @@ -1,4 +1,48 @@ 'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if ( + !desc || + ('get' in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, 'default', { enumerable: true, value: v }); + } + : function (o, v) { + o['default'] = v; + }); +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k in mod) + if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; + }; Object.defineProperty(exports, '__esModule', { value: true }); exports.toOutputScript = exports.fromOutputScript = @@ -7,12 +51,12 @@ exports.toOutputScript = exports.fromBech32 = exports.fromBase58Check = void 0; -const networks = require('./networks'); -const payments = require('./payments'); -const bscript = require('./script'); +const networks = __importStar(require('./networks')); +const payments = __importStar(require('./payments')); +const bscript = __importStar(require('./script')); const types_1 = require('./types'); const bech32_1 = require('bech32'); -const bs58check = require('bs58check'); +const bs58check = __importStar(require('bs58check')); const FUTURE_SEGWIT_MAX_SIZE = 40; const FUTURE_SEGWIT_MIN_SIZE = 2; const FUTURE_SEGWIT_MAX_VERSION = 16; diff --git a/src/bip66.d.ts b/src/cjs/bip66.d.ts similarity index 100% rename from src/bip66.d.ts rename to src/cjs/bip66.d.ts diff --git a/src/bip66.js b/src/cjs/bip66.js similarity index 100% rename from src/bip66.js rename to src/cjs/bip66.js diff --git a/src/block.d.ts b/src/cjs/block.d.ts similarity index 100% rename from src/block.d.ts rename to src/cjs/block.d.ts diff --git a/src/cjs/block.js b/src/cjs/block.js new file mode 100644 index 000000000..25d20ac0b --- /dev/null +++ b/src/cjs/block.js @@ -0,0 +1,262 @@ +'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if ( + !desc || + ('get' in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, 'default', { enumerable: true, value: v }); + } + : function (o, v) { + o['default'] = v; + }); +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k in mod) + if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; + }; +Object.defineProperty(exports, '__esModule', { value: true }); +exports.Block = void 0; +const bufferutils_1 = require('./bufferutils'); +const bcrypto = __importStar(require('./crypto')); +const merkle_1 = require('./merkle'); +const transaction_1 = require('./transaction'); +const types = __importStar(require('./types')); +const { typeforce } = types; +const errorMerkleNoTxes = new TypeError( + 'Cannot compute merkle root for zero transactions', +); +const errorWitnessNotSegwit = new TypeError( + 'Cannot compute witness commit for non-segwit block', +); +class Block { + static fromBuffer(buffer) { + if (buffer.length < 80) throw new Error('Buffer too small (< 80 bytes)'); + const bufferReader = new bufferutils_1.BufferReader(buffer); + const block = new Block(); + block.version = bufferReader.readInt32(); + block.prevHash = bufferReader.readSlice(32); + block.merkleRoot = bufferReader.readSlice(32); + block.timestamp = bufferReader.readUInt32(); + block.bits = bufferReader.readUInt32(); + block.nonce = bufferReader.readUInt32(); + if (buffer.length === 80) return block; + const readTransaction = () => { + const tx = transaction_1.Transaction.fromBuffer( + bufferReader.buffer.slice(bufferReader.offset), + true, + ); + bufferReader.offset += tx.byteLength(); + return tx; + }; + const nTransactions = bufferReader.readVarInt(); + block.transactions = []; + for (let i = 0; i < nTransactions; ++i) { + const tx = readTransaction(); + block.transactions.push(tx); + } + const witnessCommit = block.getWitnessCommit(); + // This Block contains a witness commit + if (witnessCommit) block.witnessCommit = witnessCommit; + return block; + } + static fromHex(hex) { + return Block.fromBuffer(Buffer.from(hex, 'hex')); + } + static calculateTarget(bits) { + const exponent = ((bits & 0xff000000) >> 24) - 3; + const mantissa = bits & 0x007fffff; + const target = Buffer.alloc(32, 0); + target.writeUIntBE(mantissa, 29 - exponent, 3); + return target; + } + static calculateMerkleRoot(transactions, forWitness) { + typeforce([{ getHash: types.Function }], transactions); + if (transactions.length === 0) throw errorMerkleNoTxes; + if (forWitness && !txesHaveWitnessCommit(transactions)) + throw errorWitnessNotSegwit; + const hashes = transactions.map(transaction => + transaction.getHash(forWitness), + ); + const rootHash = (0, merkle_1.fastMerkleRoot)(hashes, bcrypto.hash256); + return forWitness + ? bcrypto.hash256( + Buffer.concat([rootHash, transactions[0].ins[0].witness[0]]), + ) + : rootHash; + } + version = 1; + prevHash = undefined; + merkleRoot = undefined; + timestamp = 0; + witnessCommit = undefined; + bits = 0; + nonce = 0; + transactions = undefined; + getWitnessCommit() { + if (!txesHaveWitnessCommit(this.transactions)) return null; + // The merkle root for the witness data is in an OP_RETURN output. + // There is no rule for the index of the output, so use filter to find it. + // The root is prepended with 0xaa21a9ed so check for 0x6a24aa21a9ed + // If multiple commits are found, the output with highest index is assumed. + const witnessCommits = this.transactions[0].outs + .filter(out => + out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex')), + ) + .map(out => out.script.slice(6, 38)); + if (witnessCommits.length === 0) return null; + // Use the commit with the highest output (should only be one though) + const result = witnessCommits[witnessCommits.length - 1]; + if (!(result instanceof Buffer && result.length === 32)) return null; + return result; + } + hasWitnessCommit() { + if ( + this.witnessCommit instanceof Buffer && + this.witnessCommit.length === 32 + ) + return true; + if (this.getWitnessCommit() !== null) return true; + return false; + } + hasWitness() { + return anyTxHasWitness(this.transactions); + } + weight() { + const base = this.byteLength(false, false); + const total = this.byteLength(false, true); + return base * 3 + total; + } + byteLength(headersOnly, allowWitness = true) { + if (headersOnly || !this.transactions) return 80; + return ( + 80 + + bufferutils_1.varuint.encodingLength(this.transactions.length) + + this.transactions.reduce((a, x) => a + x.byteLength(allowWitness), 0) + ); + } + getHash() { + return bcrypto.hash256(this.toBuffer(true)); + } + getId() { + return (0, bufferutils_1.reverseBuffer)(this.getHash()).toString('hex'); + } + getUTCDate() { + const date = new Date(0); // epoch + date.setUTCSeconds(this.timestamp); + return date; + } + // TODO: buffer, offset compatibility + toBuffer(headersOnly) { + const buffer = Buffer.allocUnsafe(this.byteLength(headersOnly)); + const bufferWriter = new bufferutils_1.BufferWriter(buffer); + bufferWriter.writeInt32(this.version); + bufferWriter.writeSlice(this.prevHash); + bufferWriter.writeSlice(this.merkleRoot); + bufferWriter.writeUInt32(this.timestamp); + bufferWriter.writeUInt32(this.bits); + bufferWriter.writeUInt32(this.nonce); + if (headersOnly || !this.transactions) return buffer; + const { bytes } = bufferutils_1.varuint.encode( + this.transactions.length, + buffer, + bufferWriter.offset, + ); + bufferWriter.offset += bytes; + this.transactions.forEach(tx => { + const txSize = tx.byteLength(); // TODO: extract from toBuffer? + tx.toBuffer(buffer, bufferWriter.offset); + bufferWriter.offset += txSize; + }); + return buffer; + } + toHex(headersOnly) { + return this.toBuffer(headersOnly).toString('hex'); + } + checkTxRoots() { + // If the Block has segwit transactions but no witness commit, + // there's no way it can be valid, so fail the check. + const hasWitnessCommit = this.hasWitnessCommit(); + if (!hasWitnessCommit && this.hasWitness()) return false; + return ( + this.__checkMerkleRoot() && + (hasWitnessCommit ? this.__checkWitnessCommit() : true) + ); + } + checkProofOfWork() { + const hash = (0, bufferutils_1.reverseBuffer)(this.getHash()); + const target = Block.calculateTarget(this.bits); + return hash.compare(target) <= 0; + } + __checkMerkleRoot() { + if (!this.transactions) throw errorMerkleNoTxes; + const actualMerkleRoot = Block.calculateMerkleRoot(this.transactions); + return this.merkleRoot.compare(actualMerkleRoot) === 0; + } + __checkWitnessCommit() { + if (!this.transactions) throw errorMerkleNoTxes; + if (!this.hasWitnessCommit()) throw errorWitnessNotSegwit; + const actualWitnessCommit = Block.calculateMerkleRoot( + this.transactions, + true, + ); + return this.witnessCommit.compare(actualWitnessCommit) === 0; + } +} +exports.Block = Block; +function txesHaveWitnessCommit(transactions) { + return ( + transactions instanceof Array && + transactions[0] && + transactions[0].ins && + transactions[0].ins instanceof Array && + transactions[0].ins[0] && + transactions[0].ins[0].witness && + transactions[0].ins[0].witness instanceof Array && + transactions[0].ins[0].witness.length > 0 + ); +} +function anyTxHasWitness(transactions) { + return ( + transactions instanceof Array && + transactions.some( + tx => + typeof tx === 'object' && + tx.ins instanceof Array && + tx.ins.some( + input => + typeof input === 'object' && + input.witness instanceof Array && + input.witness.length > 0, + ), + ) + ); +} diff --git a/src/bufferutils.d.ts b/src/cjs/bufferutils.d.ts similarity index 100% rename from src/bufferutils.d.ts rename to src/cjs/bufferutils.d.ts diff --git a/src/cjs/bufferutils.js b/src/cjs/bufferutils.js new file mode 100644 index 000000000..e838b1d06 --- /dev/null +++ b/src/cjs/bufferutils.js @@ -0,0 +1,226 @@ +'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if ( + !desc || + ('get' in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, 'default', { enumerable: true, value: v }); + } + : function (o, v) { + o['default'] = v; + }); +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k in mod) + if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; + }; +Object.defineProperty(exports, '__esModule', { value: true }); +exports.BufferReader = + exports.BufferWriter = + exports.cloneBuffer = + exports.reverseBuffer = + exports.writeUInt64LE = + exports.readUInt64LE = + exports.varuint = + void 0; +const types = __importStar(require('./types')); +const { typeforce } = types; +const varuint = __importStar(require('varuint-bitcoin')); +exports.varuint = varuint; +const MAX_JS_NUMBER = 0x001fffffffffffff; +// https://github.com/feross/buffer/blob/master/index.js#L1127 +function verifuint(value, max) { + if (typeof value !== 'number' && typeof value !== 'bigint') + throw new Error('cannot write a non-number as a number'); + if (value < 0 && value < BigInt(0)) + throw new Error('specified a negative value for writing an unsigned value'); + if (value > max && value > BigInt(max)) + throw new Error('RangeError: value out of range'); + if (Math.floor(Number(value)) !== Number(value)) + throw new Error('value has a fractional component'); +} +function readUInt64LE(buffer, offset) { + const a = buffer.readUInt32LE(offset); + let b = buffer.readUInt32LE(offset + 4); + b *= 0x100000000; + verifuint(b + a, MAX_JS_NUMBER); + return b + a; +} +exports.readUInt64LE = readUInt64LE; +/** + * Writes a 64-bit unsigned integer in little-endian format to the specified buffer at the given offset. + * + * @param buffer - The buffer to write the value to. + * @param value - The 64-bit unsigned integer value to write. + * @param offset - The offset in the buffer where the value should be written. + * @returns The new offset after writing the value. + */ +function writeUInt64LE(buffer, value, offset) { + verifuint(value, MAX_JS_NUMBER); + buffer.writeInt32LE(value & -1, offset); + buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4); + return offset + 8; +} +exports.writeUInt64LE = writeUInt64LE; +/** + * Reverses the order of bytes in a buffer. + * @param buffer - The buffer to reverse. + * @returns A new buffer with the bytes reversed. + */ +function reverseBuffer(buffer) { + if (buffer.length < 1) return buffer; + let j = buffer.length - 1; + let tmp = 0; + for (let i = 0; i < buffer.length / 2; i++) { + tmp = buffer[i]; + buffer[i] = buffer[j]; + buffer[j] = tmp; + j--; + } + return buffer; +} +exports.reverseBuffer = reverseBuffer; +function cloneBuffer(buffer) { + const clone = Buffer.allocUnsafe(buffer.length); + buffer.copy(clone); + return clone; +} +exports.cloneBuffer = cloneBuffer; +/** + * Helper class for serialization of bitcoin data types into a pre-allocated buffer. + */ +class BufferWriter { + buffer; + offset; + 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]); + } + writeUInt8(i) { + this.offset = this.buffer.writeUInt8(i, this.offset); + } + writeInt32(i) { + this.offset = this.buffer.writeInt32LE(i, this.offset); + } + writeUInt32(i) { + this.offset = this.buffer.writeUInt32LE(i, this.offset); + } + writeUInt64(i) { + this.offset = writeUInt64LE(this.buffer, i, this.offset); + } + writeVarInt(i) { + const { bytes } = varuint.encode(i, this.buffer, this.offset); + this.offset += bytes; + } + writeSlice(slice) { + if (this.buffer.length < this.offset + slice.length) { + throw new Error('Cannot write slice out of bounds'); + } + this.offset += slice.copy(this.buffer, this.offset); + } + writeVarSlice(slice) { + this.writeVarInt(slice.length); + this.writeSlice(slice); + } + writeVector(vector) { + this.writeVarInt(vector.length); + vector.forEach(buf => this.writeVarSlice(buf)); + } + end() { + if (this.buffer.length === this.offset) { + return this.buffer; + } + throw new Error(`buffer size ${this.buffer.length}, offset ${this.offset}`); + } +} +exports.BufferWriter = BufferWriter; +/** + * Helper class for reading of bitcoin data types from a buffer. + */ +class BufferReader { + buffer; + offset; + constructor(buffer, offset = 0) { + this.buffer = buffer; + this.offset = offset; + typeforce(types.tuple(types.Buffer, types.UInt32), [buffer, offset]); + } + readUInt8() { + const result = this.buffer.readUInt8(this.offset); + this.offset++; + return result; + } + readInt32() { + const result = this.buffer.readInt32LE(this.offset); + this.offset += 4; + return result; + } + readUInt32() { + const result = this.buffer.readUInt32LE(this.offset); + this.offset += 4; + return result; + } + readUInt64() { + const result = readUInt64LE(this.buffer, this.offset); + this.offset += 8; + return result; + } + readVarInt() { + const { bigintValue, bytes } = varuint.decode(this.buffer, this.offset); + this.offset += bytes; + return bigintValue; + } + readSlice(n) { + verifuint(n, MAX_JS_NUMBER); + const num = Number(n); + if (this.buffer.length < this.offset + num) { + throw new Error('Cannot read slice out of bounds'); + } + const result = this.buffer.slice(this.offset, this.offset + num); + this.offset += num; + return result; + } + readVarSlice() { + return this.readSlice(this.readVarInt()); + } + readVector() { + const count = this.readVarInt(); + const vector = []; + for (let i = 0; i < count; i++) vector.push(this.readVarSlice()); + return vector; + } +} +exports.BufferReader = BufferReader; diff --git a/src/crypto.d.ts b/src/cjs/crypto.d.ts similarity index 100% rename from src/crypto.d.ts rename to src/cjs/crypto.d.ts diff --git a/src/crypto.js b/src/cjs/crypto.js similarity index 100% rename from src/crypto.js rename to src/cjs/crypto.js diff --git a/src/ecc_lib.d.ts b/src/cjs/ecc_lib.d.ts similarity index 100% rename from src/ecc_lib.d.ts rename to src/cjs/ecc_lib.d.ts diff --git a/src/ecc_lib.js b/src/cjs/ecc_lib.js similarity index 100% rename from src/ecc_lib.js rename to src/cjs/ecc_lib.js diff --git a/src/index.d.ts b/src/cjs/index.d.ts similarity index 100% rename from src/index.d.ts rename to src/cjs/index.d.ts diff --git a/src/cjs/index.js b/src/cjs/index.js new file mode 100644 index 000000000..97984c902 --- /dev/null +++ b/src/cjs/index.js @@ -0,0 +1,103 @@ +'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if ( + !desc || + ('get' in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, 'default', { enumerable: true, value: v }); + } + : function (o, v) { + o['default'] = v; + }); +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k in mod) + if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; + }; +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; +const address = __importStar(require('./address')); +exports.address = address; +const crypto = __importStar(require('./crypto')); +exports.crypto = crypto; +const networks = __importStar(require('./networks')); +exports.networks = networks; +const payments = __importStar(require('./payments')); +exports.payments = payments; +const script = __importStar(require('./script')); +exports.script = script; +var block_1 = require('./block'); +Object.defineProperty(exports, 'Block', { + enumerable: true, + get: function () { + return block_1.Block; + }, +}); +var psbt_1 = require('./psbt'); +Object.defineProperty(exports, 'Psbt', { + enumerable: true, + get: function () { + return psbt_1.Psbt; + }, +}); +/** @hidden */ +var ops_1 = require('./ops'); +Object.defineProperty(exports, 'opcodes', { + enumerable: true, + get: function () { + return ops_1.OPS; + }, +}); +var transaction_1 = require('./transaction'); +Object.defineProperty(exports, 'Transaction', { + enumerable: true, + get: function () { + 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/merkle.d.ts b/src/cjs/merkle.d.ts similarity index 100% rename from src/merkle.d.ts rename to src/cjs/merkle.d.ts diff --git a/src/merkle.js b/src/cjs/merkle.js similarity index 100% rename from src/merkle.js rename to src/cjs/merkle.js diff --git a/src/networks.d.ts b/src/cjs/networks.d.ts similarity index 100% rename from src/networks.d.ts rename to src/cjs/networks.d.ts diff --git a/src/networks.js b/src/cjs/networks.js similarity index 100% rename from src/networks.js rename to src/cjs/networks.js diff --git a/src/ops.d.ts b/src/cjs/ops.d.ts similarity index 100% rename from src/ops.d.ts rename to src/cjs/ops.d.ts diff --git a/src/ops.js b/src/cjs/ops.js similarity index 100% rename from src/ops.js rename to src/cjs/ops.js diff --git a/src/payments/bip341.d.ts b/src/cjs/payments/bip341.d.ts similarity index 100% rename from src/payments/bip341.d.ts rename to src/cjs/payments/bip341.d.ts diff --git a/src/payments/bip341.js b/src/cjs/payments/bip341.js similarity index 75% rename from src/payments/bip341.js rename to src/cjs/payments/bip341.js index 59eea4612..04ea1861a 100644 --- a/src/payments/bip341.js +++ b/src/cjs/payments/bip341.js @@ -1,4 +1,48 @@ 'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if ( + !desc || + ('get' in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, 'default', { enumerable: true, value: v }); + } + : function (o, v) { + o['default'] = v; + }); +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k in mod) + if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; + }; Object.defineProperty(exports, '__esModule', { value: true }); exports.tweakKey = exports.tapTweakHash = @@ -11,7 +55,7 @@ exports.tweakKey = void 0; const buffer_1 = require('buffer'); const ecc_lib_1 = require('../ecc_lib'); -const bcrypto = require('../crypto'); +const bcrypto = __importStar(require('../crypto')); const bufferutils_1 = require('../bufferutils'); const types_1 = require('../types'); exports.LEAF_VERSION_TAPSCRIPT = 0xc0; diff --git a/src/payments/embed.d.ts b/src/cjs/payments/embed.d.ts similarity index 100% rename from src/payments/embed.d.ts rename to src/cjs/payments/embed.d.ts diff --git a/src/cjs/payments/embed.js b/src/cjs/payments/embed.js new file mode 100644 index 000000000..800b4d4eb --- /dev/null +++ b/src/cjs/payments/embed.js @@ -0,0 +1,97 @@ +'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if ( + !desc || + ('get' in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, 'default', { enumerable: true, value: v }); + } + : function (o, v) { + o['default'] = v; + }); +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k in mod) + if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; + }; +Object.defineProperty(exports, '__esModule', { value: true }); +exports.p2data = void 0; +const networks_1 = require('../networks'); +const bscript = __importStar(require('../script')); +const types_1 = require('../types'); +const lazy = __importStar(require('./lazy')); +const OPS = bscript.OPS; +// output: OP_RETURN ... +/** + * Embeds data in a Bitcoin payment. + * @param a - The payment object. + * @param opts - Optional payment options. + * @returns The modified payment object. + * @throws {TypeError} If there is not enough data or if the output is invalid. + */ +function p2data(a, opts) { + if (!a.data && !a.output) throw new TypeError('Not enough data'); + opts = Object.assign({ validate: true }, opts || {}); + (0, types_1.typeforce)( + { + network: types_1.typeforce.maybe(types_1.typeforce.Object), + output: types_1.typeforce.maybe(types_1.typeforce.Buffer), + data: types_1.typeforce.maybe( + types_1.typeforce.arrayOf(types_1.typeforce.Buffer), + ), + }, + a, + ); + const network = a.network || networks_1.bitcoin; + const o = { name: 'embed', network }; + lazy.prop(o, 'output', () => { + if (!a.data) return; + return bscript.compile([OPS.OP_RETURN].concat(a.data)); + }); + lazy.prop(o, 'data', () => { + if (!a.output) return; + return bscript.decompile(a.output).slice(1); + }); + // extended validation + if (opts.validate) { + if (a.output) { + const chunks = bscript.decompile(a.output); + if (chunks[0] !== OPS.OP_RETURN) throw new TypeError('Output is invalid'); + if (!chunks.slice(1).every(types_1.typeforce.Buffer)) + throw new TypeError('Output is invalid'); + if (a.data && !(0, types_1.stacksEqual)(a.data, o.data)) + throw new TypeError('Data mismatch'); + } + } + return Object.assign(o, a); +} +exports.p2data = p2data; diff --git a/src/payments/index.d.ts b/src/cjs/payments/index.d.ts similarity index 100% rename from src/payments/index.d.ts rename to src/cjs/payments/index.d.ts diff --git a/src/payments/index.js b/src/cjs/payments/index.js similarity index 100% rename from src/payments/index.js rename to src/cjs/payments/index.js diff --git a/src/payments/lazy.d.ts b/src/cjs/payments/lazy.d.ts similarity index 100% rename from src/payments/lazy.d.ts rename to src/cjs/payments/lazy.d.ts diff --git a/src/payments/lazy.js b/src/cjs/payments/lazy.js similarity index 100% rename from src/payments/lazy.js rename to src/cjs/payments/lazy.js diff --git a/src/payments/p2ms.d.ts b/src/cjs/payments/p2ms.d.ts similarity index 100% rename from src/payments/p2ms.d.ts rename to src/cjs/payments/p2ms.d.ts diff --git a/src/payments/p2ms.js b/src/cjs/payments/p2ms.js similarity index 78% rename from src/payments/p2ms.js rename to src/cjs/payments/p2ms.js index dfa0c8dd7..617e93fef 100644 --- a/src/payments/p2ms.js +++ b/src/cjs/payments/p2ms.js @@ -1,10 +1,54 @@ 'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if ( + !desc || + ('get' in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, 'default', { enumerable: true, value: v }); + } + : function (o, v) { + o['default'] = v; + }); +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k in mod) + if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; + }; Object.defineProperty(exports, '__esModule', { value: true }); exports.p2ms = void 0; const networks_1 = require('../networks'); -const bscript = require('../script'); +const bscript = __importStar(require('../script')); const types_1 = require('../types'); -const lazy = require('./lazy'); +const lazy = __importStar(require('./lazy')); const OPS = bscript.OPS; const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1 // input: OP_0 [signatures ...] diff --git a/src/payments/p2pk.d.ts b/src/cjs/payments/p2pk.d.ts similarity index 100% rename from src/payments/p2pk.d.ts rename to src/cjs/payments/p2pk.d.ts diff --git a/src/cjs/payments/p2pk.js b/src/cjs/payments/p2pk.js new file mode 100644 index 000000000..8954ac720 --- /dev/null +++ b/src/cjs/payments/p2pk.js @@ -0,0 +1,124 @@ +'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if ( + !desc || + ('get' in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, 'default', { enumerable: true, value: v }); + } + : function (o, v) { + o['default'] = v; + }); +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k in mod) + if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; + }; +Object.defineProperty(exports, '__esModule', { value: true }); +exports.p2pk = void 0; +const networks_1 = require('../networks'); +const bscript = __importStar(require('../script')); +const types_1 = require('../types'); +const lazy = __importStar(require('./lazy')); +const OPS = bscript.OPS; +// input: {signature} +// output: {pubKey} OP_CHECKSIG +/** + * Creates a pay-to-public-key (P2PK) payment object. + * + * @param a - The payment object containing the necessary data. + * @param opts - Optional payment options. + * @returns The P2PK payment object. + * @throws {TypeError} If the required data is not provided or if the data is invalid. + */ +function p2pk(a, opts) { + if (!a.input && !a.output && !a.pubkey && !a.input && !a.signature) + throw new TypeError('Not enough data'); + opts = Object.assign({ validate: true }, opts || {}); + (0, types_1.typeforce)( + { + network: types_1.typeforce.maybe(types_1.typeforce.Object), + output: types_1.typeforce.maybe(types_1.typeforce.Buffer), + pubkey: types_1.typeforce.maybe(types_1.isPoint), + signature: types_1.typeforce.maybe(bscript.isCanonicalScriptSignature), + input: types_1.typeforce.maybe(types_1.typeforce.Buffer), + }, + a, + ); + const _chunks = lazy.value(() => { + return bscript.decompile(a.input); + }); + const network = a.network || networks_1.bitcoin; + const o = { name: 'p2pk', network }; + lazy.prop(o, 'output', () => { + if (!a.pubkey) return; + return bscript.compile([a.pubkey, OPS.OP_CHECKSIG]); + }); + lazy.prop(o, 'pubkey', () => { + if (!a.output) return; + return a.output.slice(1, -1); + }); + lazy.prop(o, 'signature', () => { + if (!a.input) return; + return _chunks()[0]; + }); + lazy.prop(o, 'input', () => { + if (!a.signature) return; + return bscript.compile([a.signature]); + }); + lazy.prop(o, 'witness', () => { + if (!o.input) return; + return []; + }); + // extended validation + if (opts.validate) { + if (a.output) { + if (a.output[a.output.length - 1] !== OPS.OP_CHECKSIG) + throw new TypeError('Output is invalid'); + if (!(0, types_1.isPoint)(o.pubkey)) + throw new TypeError('Output pubkey is invalid'); + if (a.pubkey && !a.pubkey.equals(o.pubkey)) + throw new TypeError('Pubkey mismatch'); + } + if (a.signature) { + if (a.input && !a.input.equals(o.input)) + throw new TypeError('Signature mismatch'); + } + if (a.input) { + if (_chunks().length !== 1) throw new TypeError('Input is invalid'); + if (!bscript.isCanonicalScriptSignature(o.signature)) + throw new TypeError('Input has invalid signature'); + } + } + return Object.assign(o, a); +} +exports.p2pk = p2pk; diff --git a/src/payments/p2pkh.d.ts b/src/cjs/payments/p2pkh.d.ts similarity index 100% rename from src/payments/p2pkh.d.ts rename to src/cjs/payments/p2pkh.d.ts diff --git a/src/cjs/payments/p2pkh.js b/src/cjs/payments/p2pkh.js new file mode 100644 index 000000000..6989cc31a --- /dev/null +++ b/src/cjs/payments/p2pkh.js @@ -0,0 +1,184 @@ +'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if ( + !desc || + ('get' in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, 'default', { enumerable: true, value: v }); + } + : function (o, v) { + o['default'] = v; + }); +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k in mod) + if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; + }; +Object.defineProperty(exports, '__esModule', { value: true }); +exports.p2pkh = void 0; +const bcrypto = __importStar(require('../crypto')); +const networks_1 = require('../networks'); +const bscript = __importStar(require('../script')); +const types_1 = require('../types'); +const lazy = __importStar(require('./lazy')); +const bs58check = __importStar(require('bs58check')); +const OPS = bscript.OPS; +// input: {signature} {pubkey} +// output: OP_DUP OP_HASH160 {hash160(pubkey)} OP_EQUALVERIFY OP_CHECKSIG +/** + * Creates a Pay-to-Public-Key-Hash (P2PKH) payment object. + * + * @param a - The payment object containing the necessary data. + * @param opts - Optional payment options. + * @returns The P2PKH payment object. + * @throws {TypeError} If the required data is not provided or if the data is invalid. + */ +function p2pkh(a, opts) { + if (!a.address && !a.hash && !a.output && !a.pubkey && !a.input) + throw new TypeError('Not enough data'); + opts = Object.assign({ validate: true }, opts || {}); + (0, types_1.typeforce)( + { + network: types_1.typeforce.maybe(types_1.typeforce.Object), + address: types_1.typeforce.maybe(types_1.typeforce.String), + hash: types_1.typeforce.maybe(types_1.typeforce.BufferN(20)), + output: types_1.typeforce.maybe(types_1.typeforce.BufferN(25)), + pubkey: types_1.typeforce.maybe(types_1.isPoint), + signature: types_1.typeforce.maybe(bscript.isCanonicalScriptSignature), + input: types_1.typeforce.maybe(types_1.typeforce.Buffer), + }, + a, + ); + const _address = lazy.value(() => { + const payload = Buffer.from(bs58check.decode(a.address)); + const version = payload.readUInt8(0); + const hash = payload.slice(1); + return { version, hash }; + }); + const _chunks = lazy.value(() => { + return bscript.decompile(a.input); + }); + const network = a.network || networks_1.bitcoin; + const o = { name: 'p2pkh', network }; + lazy.prop(o, 'address', () => { + if (!o.hash) return; + const payload = Buffer.allocUnsafe(21); + payload.writeUInt8(network.pubKeyHash, 0); + o.hash.copy(payload, 1); + return bs58check.encode(payload); + }); + lazy.prop(o, 'hash', () => { + if (a.output) return a.output.slice(3, 23); + if (a.address) return _address().hash; + if (a.pubkey || o.pubkey) return bcrypto.hash160(a.pubkey || o.pubkey); + }); + lazy.prop(o, 'output', () => { + if (!o.hash) return; + return bscript.compile([ + OPS.OP_DUP, + OPS.OP_HASH160, + o.hash, + OPS.OP_EQUALVERIFY, + OPS.OP_CHECKSIG, + ]); + }); + lazy.prop(o, 'pubkey', () => { + if (!a.input) return; + return _chunks()[1]; + }); + lazy.prop(o, 'signature', () => { + if (!a.input) return; + return _chunks()[0]; + }); + lazy.prop(o, 'input', () => { + if (!a.pubkey) return; + if (!a.signature) return; + return bscript.compile([a.signature, a.pubkey]); + }); + lazy.prop(o, 'witness', () => { + if (!o.input) return; + return []; + }); + // extended validation + if (opts.validate) { + let hash = Buffer.from([]); + if (a.address) { + if (_address().version !== network.pubKeyHash) + throw new TypeError('Invalid version or Network mismatch'); + if (_address().hash.length !== 20) throw new TypeError('Invalid address'); + hash = _address().hash; + } + if (a.hash) { + if (hash.length > 0 && !hash.equals(a.hash)) + throw new TypeError('Hash mismatch'); + else hash = a.hash; + } + if (a.output) { + if ( + a.output.length !== 25 || + a.output[0] !== OPS.OP_DUP || + a.output[1] !== OPS.OP_HASH160 || + a.output[2] !== 0x14 || + a.output[23] !== OPS.OP_EQUALVERIFY || + a.output[24] !== OPS.OP_CHECKSIG + ) + throw new TypeError('Output is invalid'); + const hash2 = a.output.slice(3, 23); + if (hash.length > 0 && !hash.equals(hash2)) + throw new TypeError('Hash mismatch'); + else hash = hash2; + } + if (a.pubkey) { + const pkh = bcrypto.hash160(a.pubkey); + if (hash.length > 0 && !hash.equals(pkh)) + throw new TypeError('Hash mismatch'); + else hash = pkh; + } + if (a.input) { + const chunks = _chunks(); + if (chunks.length !== 2) throw new TypeError('Input is invalid'); + if (!bscript.isCanonicalScriptSignature(chunks[0])) + throw new TypeError('Input has invalid signature'); + if (!(0, types_1.isPoint)(chunks[1])) + throw new TypeError('Input has invalid pubkey'); + if (a.signature && !a.signature.equals(chunks[0])) + throw new TypeError('Signature mismatch'); + if (a.pubkey && !a.pubkey.equals(chunks[1])) + throw new TypeError('Pubkey mismatch'); + const pkh = bcrypto.hash160(chunks[1]); + if (hash.length > 0 && !hash.equals(pkh)) + throw new TypeError('Hash mismatch'); + } + } + return Object.assign(o, a); +} +exports.p2pkh = p2pkh; diff --git a/src/payments/p2sh.d.ts b/src/cjs/payments/p2sh.d.ts similarity index 100% rename from src/payments/p2sh.d.ts rename to src/cjs/payments/p2sh.d.ts diff --git a/src/payments/p2sh.js b/src/cjs/payments/p2sh.js similarity index 82% rename from src/payments/p2sh.js rename to src/cjs/payments/p2sh.js index 1386966be..b1b261a43 100644 --- a/src/payments/p2sh.js +++ b/src/cjs/payments/p2sh.js @@ -1,12 +1,56 @@ 'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if ( + !desc || + ('get' in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, 'default', { enumerable: true, value: v }); + } + : function (o, v) { + o['default'] = v; + }); +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k in mod) + if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; + }; Object.defineProperty(exports, '__esModule', { value: true }); exports.p2sh = void 0; -const bcrypto = require('../crypto'); +const bcrypto = __importStar(require('../crypto')); const networks_1 = require('../networks'); -const bscript = require('../script'); +const bscript = __importStar(require('../script')); const types_1 = require('../types'); -const lazy = require('./lazy'); -const bs58check = require('bs58check'); +const lazy = __importStar(require('./lazy')); +const bs58check = __importStar(require('bs58check')); const OPS = bscript.OPS; // input: [redeemScriptSig ...] {redeemScript} // witness: diff --git a/src/payments/p2tr.d.ts b/src/cjs/payments/p2tr.d.ts similarity index 100% rename from src/payments/p2tr.d.ts rename to src/cjs/payments/p2tr.d.ts diff --git a/src/payments/p2tr.js b/src/cjs/payments/p2tr.js similarity index 88% rename from src/payments/p2tr.js rename to src/cjs/payments/p2tr.js index 33fedb464..11f160815 100644 --- a/src/payments/p2tr.js +++ b/src/cjs/payments/p2tr.js @@ -1,13 +1,57 @@ 'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if ( + !desc || + ('get' in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, 'default', { enumerable: true, value: v }); + } + : function (o, v) { + o['default'] = v; + }); +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k in mod) + if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; + }; 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 bscript = __importStar(require('../script')); const types_1 = require('../types'); const ecc_lib_1 = require('../ecc_lib'); const bip341_1 = require('./bip341'); -const lazy = require('./lazy'); +const lazy = __importStar(require('./lazy')); const bech32_1 = require('bech32'); const address_1 = require('../address'); const OPS = bscript.OPS; diff --git a/src/payments/p2wpkh.d.ts b/src/cjs/payments/p2wpkh.d.ts similarity index 100% rename from src/payments/p2wpkh.d.ts rename to src/cjs/payments/p2wpkh.d.ts diff --git a/src/payments/p2wpkh.js b/src/cjs/payments/p2wpkh.js similarity index 77% rename from src/payments/p2wpkh.js rename to src/cjs/payments/p2wpkh.js index 1c6073e9b..02a78c4e6 100644 --- a/src/payments/p2wpkh.js +++ b/src/cjs/payments/p2wpkh.js @@ -1,11 +1,55 @@ 'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if ( + !desc || + ('get' in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, 'default', { enumerable: true, value: v }); + } + : function (o, v) { + o['default'] = v; + }); +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k in mod) + if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; + }; Object.defineProperty(exports, '__esModule', { value: true }); exports.p2wpkh = void 0; -const bcrypto = require('../crypto'); +const bcrypto = __importStar(require('../crypto')); const networks_1 = require('../networks'); -const bscript = require('../script'); +const bscript = __importStar(require('../script')); const types_1 = require('../types'); -const lazy = require('./lazy'); +const lazy = __importStar(require('./lazy')); const bech32_1 = require('bech32'); const OPS = bscript.OPS; const EMPTY_BUFFER = Buffer.alloc(0); diff --git a/src/payments/p2wsh.d.ts b/src/cjs/payments/p2wsh.d.ts similarity index 100% rename from src/payments/p2wsh.d.ts rename to src/cjs/payments/p2wsh.d.ts diff --git a/src/payments/p2wsh.js b/src/cjs/payments/p2wsh.js similarity index 84% rename from src/payments/p2wsh.js rename to src/cjs/payments/p2wsh.js index a3422e50a..7e683ab1d 100644 --- a/src/payments/p2wsh.js +++ b/src/cjs/payments/p2wsh.js @@ -1,11 +1,55 @@ 'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if ( + !desc || + ('get' in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, 'default', { enumerable: true, value: v }); + } + : function (o, v) { + o['default'] = v; + }); +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k in mod) + if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; + }; Object.defineProperty(exports, '__esModule', { value: true }); exports.p2wsh = void 0; -const bcrypto = require('../crypto'); +const bcrypto = __importStar(require('../crypto')); const networks_1 = require('../networks'); -const bscript = require('../script'); +const bscript = __importStar(require('../script')); const types_1 = require('../types'); -const lazy = require('./lazy'); +const lazy = __importStar(require('./lazy')); const bech32_1 = require('bech32'); const OPS = bscript.OPS; const EMPTY_BUFFER = Buffer.alloc(0); diff --git a/src/psbt.d.ts b/src/cjs/psbt.d.ts similarity index 100% rename from src/psbt.d.ts rename to src/cjs/psbt.d.ts diff --git a/src/psbt.js b/src/cjs/psbt.js similarity index 97% rename from src/psbt.js rename to src/cjs/psbt.js index 01c98b30e..e82bf0522 100644 --- a/src/psbt.js +++ b/src/cjs/psbt.js @@ -1,15 +1,59 @@ 'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if ( + !desc || + ('get' in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, 'default', { enumerable: true, value: v }); + } + : function (o, v) { + o['default'] = v; + }); +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k in mod) + if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; + }; Object.defineProperty(exports, '__esModule', { value: true }); exports.Psbt = void 0; const bip174_1 = require('bip174'); -const varuint = require('varuint-bitcoin'); +const varuint = __importStar(require('varuint-bitcoin')); const utils_1 = require('bip174/src/lib/utils'); const address_1 = require('./address'); const bufferutils_1 = require('./bufferutils'); const networks_1 = require('./networks'); -const payments = require('./payments'); +const payments = __importStar(require('./payments')); const bip341_1 = require('./payments/bip341'); -const bscript = require('./script'); +const bscript = __importStar(require('./script')); const transaction_1 = require('./transaction'); const bip371_1 = require('./psbt/bip371'); const psbtutils_1 = require('./psbt/psbtutils'); @@ -67,6 +111,7 @@ const DEFAULT_OPTS = { * Transaction object. Such as fee rate not being larger than maximumFeeRate etc. */ class Psbt { + data; static fromBase64(data, opts = {}) { const buffer = Buffer.from(data, 'base64'); return this.fromBuffer(buffer, opts); @@ -81,6 +126,8 @@ class Psbt { checkTxForDupeIns(psbt.__CACHE.__TX, psbt.__CACHE); return psbt; } + __CACHE; + opts; constructor(opts = {}, data = new bip174_1.Psbt(new PsbtTransaction())) { this.data = data; // set defaults @@ -930,6 +977,7 @@ const transactionFromBuffer = buffer => new PsbtTransaction(buffer); * It contains a bitcoinjs-lib Transaction object. */ class PsbtTransaction { + tx; constructor(buffer = Buffer.from([2, 0, 0, 0, 0, 0, 0, 0, 0, 0])) { this.tx = transaction_1.Transaction.fromBuffer(buffer); checkTxEmpty(this.tx); diff --git a/src/psbt/bip371.d.ts b/src/cjs/psbt/bip371.d.ts similarity index 100% rename from src/psbt/bip371.d.ts rename to src/cjs/psbt/bip371.d.ts diff --git a/src/psbt/bip371.js b/src/cjs/psbt/bip371.js similarity index 100% rename from src/psbt/bip371.js rename to src/cjs/psbt/bip371.js diff --git a/src/psbt/psbtutils.d.ts b/src/cjs/psbt/psbtutils.d.ts similarity index 100% rename from src/psbt/psbtutils.d.ts rename to src/cjs/psbt/psbtutils.d.ts diff --git a/src/psbt/psbtutils.js b/src/cjs/psbt/psbtutils.js similarity index 82% rename from src/psbt/psbtutils.js rename to src/cjs/psbt/psbtutils.js index 73ee89db5..0d5cd1688 100644 --- a/src/psbt/psbtutils.js +++ b/src/cjs/psbt/psbtutils.js @@ -1,4 +1,48 @@ 'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if ( + !desc || + ('get' in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, 'default', { enumerable: true, value: v }); + } + : function (o, v) { + o['default'] = v; + }); +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k in mod) + if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; + }; Object.defineProperty(exports, '__esModule', { value: true }); exports.signatureBlocksAction = exports.checkInputForSig = @@ -13,11 +57,11 @@ exports.signatureBlocksAction = exports.isP2PK = exports.isP2MS = void 0; -const varuint = require('varuint-bitcoin'); -const bscript = require('../script'); +const varuint = __importStar(require('varuint-bitcoin')); +const bscript = __importStar(require('../script')); const transaction_1 = require('../transaction'); const crypto_1 = require('../crypto'); -const payments = require('../payments'); +const payments = __importStar(require('../payments')); /** * Checks if a given payment factory can generate a payment script from a given script. * @param payment The payment factory to check. diff --git a/src/push_data.d.ts b/src/cjs/push_data.d.ts similarity index 100% rename from src/push_data.d.ts rename to src/cjs/push_data.d.ts diff --git a/src/push_data.js b/src/cjs/push_data.js similarity index 100% rename from src/push_data.js rename to src/cjs/push_data.js diff --git a/src/script.d.ts b/src/cjs/script.d.ts similarity index 100% rename from src/script.d.ts rename to src/cjs/script.d.ts diff --git a/src/script.js b/src/cjs/script.js similarity index 81% rename from src/script.js rename to src/cjs/script.js index c95f0cc67..8f0546f4e 100644 --- a/src/script.js +++ b/src/cjs/script.js @@ -1,4 +1,48 @@ 'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if ( + !desc || + ('get' in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, 'default', { enumerable: true, value: v }); + } + : function (o, v) { + o['default'] = v; + }); +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k in mod) + if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; + }; Object.defineProperty(exports, '__esModule', { value: true }); exports.signature = exports.number = @@ -18,7 +62,7 @@ exports.signature = * Script tools, including decompile, compile, toASM, fromASM, toStack, isCanonicalPubKey, isCanonicalScriptSignature * @packageDocumentation */ -const bip66 = require('./bip66'); +const bip66 = __importStar(require('./bip66')); const ops_1 = require('./ops'); Object.defineProperty(exports, 'OPS', { enumerable: true, @@ -26,10 +70,10 @@ Object.defineProperty(exports, 'OPS', { return ops_1.OPS; }, }); -const pushdata = require('./push_data'); -const scriptNumber = require('./script_number'); -const scriptSignature = require('./script_signature'); -const types = require('./types'); +const pushdata = __importStar(require('./push_data')); +const scriptNumber = __importStar(require('./script_number')); +const scriptSignature = __importStar(require('./script_signature')); +const types = __importStar(require('./types')); const { typeforce } = types; const OP_INT_BASE = ops_1.OPS.OP_RESERVED; // OP_1 - 1 function isOPInt(value) { diff --git a/src/script_number.d.ts b/src/cjs/script_number.d.ts similarity index 100% rename from src/script_number.d.ts rename to src/cjs/script_number.d.ts diff --git a/src/script_number.js b/src/cjs/script_number.js similarity index 100% rename from src/script_number.js rename to src/cjs/script_number.js diff --git a/src/script_signature.d.ts b/src/cjs/script_signature.d.ts similarity index 100% rename from src/script_signature.d.ts rename to src/cjs/script_signature.d.ts diff --git a/src/cjs/script_signature.js b/src/cjs/script_signature.js new file mode 100644 index 000000000..74f4dce85 --- /dev/null +++ b/src/cjs/script_signature.js @@ -0,0 +1,123 @@ +'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if ( + !desc || + ('get' in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, 'default', { enumerable: true, value: v }); + } + : function (o, v) { + o['default'] = v; + }); +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k in mod) + if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; + }; +Object.defineProperty(exports, '__esModule', { value: true }); +exports.encode = exports.decode = void 0; +const bip66 = __importStar(require('./bip66')); +const script_1 = require('./script'); +const types = __importStar(require('./types')); +const { typeforce } = types; +const ZERO = Buffer.alloc(1, 0); +/** + * Converts a buffer to a DER-encoded buffer. + * @param x - The buffer to be converted. + * @returns The DER-encoded buffer. + */ +function toDER(x) { + let i = 0; + while (x[i] === 0) ++i; + if (i === x.length) return ZERO; + x = x.slice(i); + if (x[0] & 0x80) return Buffer.concat([ZERO, x], 1 + x.length); + return x; +} +/** + * Converts a DER-encoded signature to a buffer. + * If the first byte of the input buffer is 0x00, it is skipped. + * The resulting buffer is 32 bytes long, filled with zeros if necessary. + * @param x - The DER-encoded signature. + * @returns The converted buffer. + */ +function fromDER(x) { + if (x[0] === 0x00) x = x.slice(1); + const buffer = Buffer.alloc(32, 0); + const bstart = Math.max(0, 32 - x.length); + x.copy(buffer, bstart); + return buffer; +} +// BIP62: 1 byte hashType flag (only 0x01, 0x02, 0x03, 0x81, 0x82 and 0x83 are allowed) +/** + * Decodes a buffer into a ScriptSignature object. + * @param buffer - The buffer to decode. + * @returns The decoded ScriptSignature object. + * @throws Error if the hashType is invalid. + */ +function decode(buffer) { + const hashType = buffer.readUInt8(buffer.length - 1); + if (!(0, script_1.isDefinedHashType)(hashType)) { + throw new Error('Invalid hashType ' + hashType); + } + const decoded = bip66.decode(buffer.slice(0, -1)); + const r = fromDER(decoded.r); + const s = fromDER(decoded.s); + const signature = Buffer.concat([r, s], 64); + return { signature, hashType }; +} +exports.decode = decode; +/** + * Encodes a signature and hash type into a buffer. + * @param signature - The signature to encode. + * @param hashType - The hash type to encode. + * @returns The encoded buffer. + * @throws Error if the hashType is invalid. + */ +function encode(signature, hashType) { + typeforce( + { + signature: types.BufferN(64), + hashType: types.UInt8, + }, + { signature, hashType }, + ); + if (!(0, script_1.isDefinedHashType)(hashType)) { + throw new Error('Invalid hashType ' + hashType); + } + const hashTypeBuffer = Buffer.allocUnsafe(1); + hashTypeBuffer.writeUInt8(hashType, 0); + const r = toDER(signature.slice(0, 32)); + const s = toDER(signature.slice(32, 64)); + return Buffer.concat([bip66.encode(r, s), hashTypeBuffer]); +} +exports.encode = encode; diff --git a/src/transaction.d.ts b/src/cjs/transaction.d.ts similarity index 100% rename from src/transaction.d.ts rename to src/cjs/transaction.d.ts diff --git a/src/transaction.js b/src/cjs/transaction.js similarity index 91% rename from src/transaction.js rename to src/cjs/transaction.js index ea0179bd4..0361e93fc 100644 --- a/src/transaction.js +++ b/src/cjs/transaction.js @@ -1,11 +1,55 @@ 'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if ( + !desc || + ('get' in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, 'default', { enumerable: true, value: v }); + } + : function (o, v) { + o['default'] = v; + }); +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k in mod) + if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; + }; Object.defineProperty(exports, '__esModule', { value: true }); exports.Transaction = void 0; const bufferutils_1 = require('./bufferutils'); -const bcrypto = require('./crypto'); -const bscript = require('./script'); +const bcrypto = __importStar(require('./crypto')); +const bscript = __importStar(require('./script')); const script_1 = require('./script'); -const types = require('./types'); +const types = __importStar(require('./types')); const { typeforce } = types; function varSliceSize(someScript) { const length = someScript.length; @@ -42,12 +86,16 @@ function isOutput(out) { * Represents a Bitcoin transaction. */ class Transaction { - constructor() { - this.version = 1; - this.locktime = 0; - this.ins = []; - this.outs = []; - } + static DEFAULT_SEQUENCE = 0xffffffff; + static SIGHASH_DEFAULT = 0x00; + static SIGHASH_ALL = 0x01; + static SIGHASH_NONE = 0x02; + static SIGHASH_SINGLE = 0x03; + static SIGHASH_ANYONECANPAY = 0x80; + static SIGHASH_OUTPUT_MASK = 0x03; + static SIGHASH_INPUT_MASK = 0x80; + static ADVANCED_TRANSACTION_MARKER = 0x00; + static ADVANCED_TRANSACTION_FLAG = 0x01; static fromBuffer(buffer, _NO_STRICT) { const bufferReader = new bufferutils_1.BufferReader(buffer); const tx = new Transaction(); @@ -104,6 +152,10 @@ class Transaction { } return true; } + version = 1; + locktime = 0; + ins = []; + outs = []; isCoinbase() { return ( this.ins.length === 1 && Transaction.isCoinbaseHash(this.ins[0].hash) @@ -535,13 +587,3 @@ class Transaction { } } exports.Transaction = Transaction; -Transaction.DEFAULT_SEQUENCE = 0xffffffff; -Transaction.SIGHASH_DEFAULT = 0x00; -Transaction.SIGHASH_ALL = 0x01; -Transaction.SIGHASH_NONE = 0x02; -Transaction.SIGHASH_SINGLE = 0x03; -Transaction.SIGHASH_ANYONECANPAY = 0x80; -Transaction.SIGHASH_OUTPUT_MASK = 0x03; -Transaction.SIGHASH_INPUT_MASK = 0x80; -Transaction.ADVANCED_TRANSACTION_MARKER = 0x00; -Transaction.ADVANCED_TRANSACTION_FLAG = 0x01; diff --git a/src/types.d.ts b/src/cjs/types.d.ts similarity index 100% rename from src/types.d.ts rename to src/cjs/types.d.ts diff --git a/src/types.js b/src/cjs/types.js similarity index 100% rename from src/types.js rename to src/cjs/types.js diff --git a/src/esm/address.js b/src/esm/address.js new file mode 100644 index 000000000..7faecedcd --- /dev/null +++ b/src/esm/address.js @@ -0,0 +1,162 @@ +import * as networks from './networks'; +import * as payments from './payments'; +import * as bscript from './script'; +import { typeforce, tuple, Hash160bit, UInt8 } from './types'; +import { bech32, bech32m } from 'bech32'; +import * as bs58check from 'bs58check'; +const FUTURE_SEGWIT_MAX_SIZE = 40; +const FUTURE_SEGWIT_MIN_SIZE = 2; +const FUTURE_SEGWIT_MAX_VERSION = 16; +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. ' + + 'End users MUST be warned carefully in the GUI and asked if they wish to proceed ' + + 'with caution. Wallets should verify the segwit version from the output of fromBech32, ' + + 'then decide when it is safe to use which version of segwit.'; +function _toFutureSegwitAddress(output, network) { + const data = output.slice(2); + if ( + data.length < FUTURE_SEGWIT_MIN_SIZE || + data.length > FUTURE_SEGWIT_MAX_SIZE + ) + throw new TypeError('Invalid program length for segwit address'); + const version = output[0] - FUTURE_SEGWIT_VERSION_DIFF; + if ( + version < FUTURE_SEGWIT_MIN_VERSION || + version > FUTURE_SEGWIT_MAX_VERSION + ) + throw new TypeError('Invalid version for segwit address'); + if (output[1] !== data.length) + throw new TypeError('Invalid script for segwit address'); + console.warn(FUTURE_SEGWIT_VERSION_WARNING); + return toBech32(data, version, network.bech32); +} +/** + * decode address with base58 specification, return address version and address hash if valid + */ +export function fromBase58Check(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 hash = payload.slice(1); + return { version, hash }; +} +/** + * decode address with bech32 specification, return address version、address prefix and address data if valid + */ +export function fromBech32(address) { + let result; + let version; + try { + result = bech32.decode(address); + } catch (e) {} + if (result) { + version = result.words[0]; + if (version !== 0) throw new TypeError(address + ' uses wrong encoding'); + } else { + result = bech32m.decode(address); + version = result.words[0]; + if (version === 0) throw new TypeError(address + ' uses wrong encoding'); + } + const data = bech32.fromWords(result.words.slice(1)); + return { + version, + prefix: result.prefix, + data: Buffer.from(data), + }; +} +/** + * encode address hash to base58 address with version + */ +export function toBase58Check(hash, version) { + typeforce(tuple(Hash160bit, UInt8), arguments); + const payload = Buffer.allocUnsafe(21); + payload.writeUInt8(version, 0); + hash.copy(payload, 1); + return bs58check.encode(payload); +} +/** + * encode address hash to bech32 address with version and prefix + */ +export function toBech32(data, version, prefix) { + const words = bech32.toWords(data); + words.unshift(version); + return version === 0 + ? bech32.encode(prefix, words) + : bech32m.encode(prefix, words); +} +/** + * decode address from output script with network, return address if matched + */ +export function fromOutputScript(output, network) { + // TODO: Network + network = network || networks.bitcoin; + try { + return payments.p2pkh({ output, network }).address; + } catch (e) {} + try { + return payments.p2sh({ output, network }).address; + } catch (e) {} + try { + return payments.p2wpkh({ output, network }).address; + } catch (e) {} + try { + return payments.p2wsh({ output, network }).address; + } catch (e) {} + try { + return payments.p2tr({ output, network }).address; + } catch (e) {} + try { + return _toFutureSegwitAddress(output, network); + } catch (e) {} + throw new Error(bscript.toASM(output) + ' has no matching Address'); +} +/** + * encodes address to output script with network, return output script if address matched + */ +export function toOutputScript(address, network) { + network = network || networks.bitcoin; + let decodeBase58; + let decodeBech32; + try { + decodeBase58 = fromBase58Check(address); + } catch (e) {} + if (decodeBase58) { + if (decodeBase58.version === network.pubKeyHash) + return payments.p2pkh({ hash: decodeBase58.hash }).output; + if (decodeBase58.version === network.scriptHash) + return payments.p2sh({ hash: decodeBase58.hash }).output; + } else { + try { + decodeBech32 = fromBech32(address); + } catch (e) {} + if (decodeBech32) { + if (decodeBech32.prefix !== network.bech32) + throw new Error(address + ' has an invalid prefix'); + if (decodeBech32.version === 0) { + if (decodeBech32.data.length === 20) + 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) + return payments.p2tr({ pubkey: decodeBech32.data }).output; + } else if ( + decodeBech32.version >= FUTURE_SEGWIT_MIN_VERSION && + decodeBech32.version <= FUTURE_SEGWIT_MAX_VERSION && + decodeBech32.data.length >= FUTURE_SEGWIT_MIN_SIZE && + decodeBech32.data.length <= FUTURE_SEGWIT_MAX_SIZE + ) { + console.warn(FUTURE_SEGWIT_VERSION_WARNING); + return bscript.compile([ + decodeBech32.version + FUTURE_SEGWIT_VERSION_DIFF, + decodeBech32.data, + ]); + } + } + } + throw new Error(address + ' has no matching Script'); +} diff --git a/src/esm/bip66.js b/src/esm/bip66.js new file mode 100644 index 000000000..c7a3a2269 --- /dev/null +++ b/src/esm/bip66.js @@ -0,0 +1,96 @@ +// Reference https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki +// Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] +// NOTE: SIGHASH byte ignored AND restricted, truncate before use +export function check(buffer) { + if (buffer.length < 8) return false; + if (buffer.length > 72) return false; + if (buffer[0] !== 0x30) return false; + if (buffer[1] !== buffer.length - 2) return false; + if (buffer[2] !== 0x02) return false; + const lenR = buffer[3]; + if (lenR === 0) return false; + if (5 + lenR >= buffer.length) return false; + if (buffer[4 + lenR] !== 0x02) return false; + const lenS = buffer[5 + lenR]; + if (lenS === 0) return false; + if (6 + lenR + lenS !== buffer.length) return false; + if (buffer[4] & 0x80) return false; + if (lenR > 1 && buffer[4] === 0x00 && !(buffer[5] & 0x80)) return false; + if (buffer[lenR + 6] & 0x80) return false; + if (lenS > 1 && buffer[lenR + 6] === 0x00 && !(buffer[lenR + 7] & 0x80)) + return false; + return true; +} +export function decode(buffer) { + if (buffer.length < 8) throw new Error('DER sequence length is too short'); + if (buffer.length > 72) throw new Error('DER sequence length is too long'); + if (buffer[0] !== 0x30) throw new Error('Expected DER sequence'); + if (buffer[1] !== buffer.length - 2) + throw new Error('DER sequence length is invalid'); + if (buffer[2] !== 0x02) throw new Error('Expected DER integer'); + const lenR = buffer[3]; + if (lenR === 0) throw new Error('R length is zero'); + if (5 + lenR >= buffer.length) throw new Error('R length is too long'); + if (buffer[4 + lenR] !== 0x02) throw new Error('Expected DER integer (2)'); + const lenS = buffer[5 + lenR]; + if (lenS === 0) throw new Error('S length is zero'); + if (6 + lenR + lenS !== buffer.length) throw new Error('S length is invalid'); + if (buffer[4] & 0x80) throw new Error('R value is negative'); + if (lenR > 1 && buffer[4] === 0x00 && !(buffer[5] & 0x80)) + throw new Error('R value excessively padded'); + if (buffer[lenR + 6] & 0x80) throw new Error('S value is negative'); + if (lenS > 1 && buffer[lenR + 6] === 0x00 && !(buffer[lenR + 7] & 0x80)) + throw new Error('S value excessively padded'); + // non-BIP66 - extract R, S values + return { + r: buffer.slice(4, 4 + lenR), + s: buffer.slice(6 + lenR), + }; +} +/* + * Expects r and s to be positive DER integers. + * + * The DER format uses the most significant bit as a sign bit (& 0x80). + * If the significant bit is set AND the integer is positive, a 0x00 is prepended. + * + * Examples: + * + * 0 => 0x00 + * 1 => 0x01 + * -1 => 0xff + * 127 => 0x7f + * -127 => 0x81 + * 128 => 0x0080 + * -128 => 0x80 + * 255 => 0x00ff + * -255 => 0xff01 + * 16300 => 0x3fac + * -16300 => 0xc054 + * 62300 => 0x00f35c + * -62300 => 0xff0ca4 + */ +export function encode(r, s) { + const lenR = r.length; + const lenS = s.length; + if (lenR === 0) throw new Error('R length is zero'); + if (lenS === 0) throw new Error('S length is zero'); + if (lenR > 33) throw new Error('R length is too long'); + if (lenS > 33) throw new Error('S length is too long'); + if (r[0] & 0x80) throw new Error('R value is negative'); + if (s[0] & 0x80) throw new Error('S value is negative'); + if (lenR > 1 && r[0] === 0x00 && !(r[1] & 0x80)) + throw new Error('R value excessively padded'); + if (lenS > 1 && s[0] === 0x00 && !(s[1] & 0x80)) + throw new Error('S value excessively padded'); + const signature = Buffer.allocUnsafe(6 + lenR + lenS); + // 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] + signature[0] = 0x30; + signature[1] = signature.length - 2; + signature[2] = 0x02; + signature[3] = r.length; + r.copy(signature, 4); + signature[4 + lenR] = 0x02; + signature[5 + lenR] = s.length; + s.copy(signature, 6 + lenR); + return signature; +} diff --git a/src/block.js b/src/esm/block.js similarity index 85% rename from src/block.js rename to src/esm/block.js index eeea4a38d..fe01cdf22 100644 --- a/src/block.js +++ b/src/esm/block.js @@ -1,11 +1,13 @@ -'use strict'; -Object.defineProperty(exports, '__esModule', { value: true }); -exports.Block = void 0; -const bufferutils_1 = require('./bufferutils'); -const bcrypto = require('./crypto'); -const merkle_1 = require('./merkle'); -const transaction_1 = require('./transaction'); -const types = require('./types'); +import { + BufferReader, + BufferWriter, + reverseBuffer, + varuint, +} from './bufferutils'; +import * as bcrypto from './crypto'; +import { fastMerkleRoot } from './merkle'; +import { Transaction } from './transaction'; +import * as types from './types'; const { typeforce } = types; const errorMerkleNoTxes = new TypeError( 'Cannot compute merkle root for zero transactions', @@ -13,20 +15,10 @@ const errorMerkleNoTxes = new TypeError( const errorWitnessNotSegwit = new TypeError( 'Cannot compute witness commit for non-segwit block', ); -class Block { - constructor() { - this.version = 1; - this.prevHash = undefined; - this.merkleRoot = undefined; - this.timestamp = 0; - this.witnessCommit = undefined; - this.bits = 0; - this.nonce = 0; - this.transactions = undefined; - } +export class Block { static fromBuffer(buffer) { if (buffer.length < 80) throw new Error('Buffer too small (< 80 bytes)'); - const bufferReader = new bufferutils_1.BufferReader(buffer); + const bufferReader = new BufferReader(buffer); const block = new Block(); block.version = bufferReader.readInt32(); block.prevHash = bufferReader.readSlice(32); @@ -36,7 +28,7 @@ class Block { block.nonce = bufferReader.readUInt32(); if (buffer.length === 80) return block; const readTransaction = () => { - const tx = transaction_1.Transaction.fromBuffer( + const tx = Transaction.fromBuffer( bufferReader.buffer.slice(bufferReader.offset), true, ); @@ -72,13 +64,21 @@ class Block { const hashes = transactions.map(transaction => transaction.getHash(forWitness), ); - const rootHash = (0, merkle_1.fastMerkleRoot)(hashes, bcrypto.hash256); + const rootHash = fastMerkleRoot(hashes, bcrypto.hash256); return forWitness ? bcrypto.hash256( Buffer.concat([rootHash, transactions[0].ins[0].witness[0]]), ) : rootHash; } + version = 1; + prevHash = undefined; + merkleRoot = undefined; + timestamp = 0; + witnessCommit = undefined; + bits = 0; + nonce = 0; + transactions = undefined; getWitnessCommit() { if (!txesHaveWitnessCommit(this.transactions)) return null; // The merkle root for the witness data is in an OP_RETURN output. @@ -117,7 +117,7 @@ class Block { if (headersOnly || !this.transactions) return 80; return ( 80 + - bufferutils_1.varuint.encodingLength(this.transactions.length) + + varuint.encodingLength(this.transactions.length) + this.transactions.reduce((a, x) => a + x.byteLength(allowWitness), 0) ); } @@ -125,7 +125,7 @@ class Block { return bcrypto.hash256(this.toBuffer(true)); } getId() { - return (0, bufferutils_1.reverseBuffer)(this.getHash()).toString('hex'); + return reverseBuffer(this.getHash()).toString('hex'); } getUTCDate() { const date = new Date(0); // epoch @@ -135,7 +135,7 @@ class Block { // TODO: buffer, offset compatibility toBuffer(headersOnly) { const buffer = Buffer.allocUnsafe(this.byteLength(headersOnly)); - const bufferWriter = new bufferutils_1.BufferWriter(buffer); + const bufferWriter = new BufferWriter(buffer); bufferWriter.writeInt32(this.version); bufferWriter.writeSlice(this.prevHash); bufferWriter.writeSlice(this.merkleRoot); @@ -143,7 +143,7 @@ class Block { bufferWriter.writeUInt32(this.bits); bufferWriter.writeUInt32(this.nonce); if (headersOnly || !this.transactions) return buffer; - const { bytes } = bufferutils_1.varuint.encode( + const { bytes } = varuint.encode( this.transactions.length, buffer, bufferWriter.offset, @@ -170,7 +170,7 @@ class Block { ); } checkProofOfWork() { - const hash = (0, bufferutils_1.reverseBuffer)(this.getHash()); + const hash = reverseBuffer(this.getHash()); const target = Block.calculateTarget(this.bits); return hash.compare(target) <= 0; } @@ -189,7 +189,6 @@ class Block { return this.witnessCommit.compare(actualWitnessCommit) === 0; } } -exports.Block = Block; function txesHaveWitnessCommit(transactions) { return ( transactions instanceof Array && diff --git a/src/bufferutils.js b/src/esm/bufferutils.js similarity index 85% rename from src/bufferutils.js rename to src/esm/bufferutils.js index 687e71d8b..ea23cc490 100644 --- a/src/bufferutils.js +++ b/src/esm/bufferutils.js @@ -1,17 +1,7 @@ -'use strict'; -Object.defineProperty(exports, '__esModule', { value: true }); -exports.BufferReader = - exports.BufferWriter = - exports.cloneBuffer = - exports.reverseBuffer = - exports.writeUInt64LE = - exports.readUInt64LE = - exports.varuint = - void 0; -const types = require('./types'); +import * as types from './types'; const { typeforce } = types; -const varuint = require('varuint-bitcoin'); -exports.varuint = varuint; +import * as varuint from 'varuint-bitcoin'; +export { varuint }; const MAX_JS_NUMBER = 0x001fffffffffffff; // https://github.com/feross/buffer/blob/master/index.js#L1127 function verifuint(value, max) { @@ -24,14 +14,13 @@ function verifuint(value, max) { if (Math.floor(Number(value)) !== Number(value)) throw new Error('value has a fractional component'); } -function readUInt64LE(buffer, offset) { +export function readUInt64LE(buffer, offset) { const a = buffer.readUInt32LE(offset); let b = buffer.readUInt32LE(offset + 4); b *= 0x100000000; verifuint(b + a, MAX_JS_NUMBER); return b + a; } -exports.readUInt64LE = readUInt64LE; /** * Writes a 64-bit unsigned integer in little-endian format to the specified buffer at the given offset. * @@ -40,19 +29,18 @@ exports.readUInt64LE = readUInt64LE; * @param offset - The offset in the buffer where the value should be written. * @returns The new offset after writing the value. */ -function writeUInt64LE(buffer, value, offset) { +export function writeUInt64LE(buffer, value, offset) { verifuint(value, MAX_JS_NUMBER); buffer.writeInt32LE(value & -1, offset); buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4); return offset + 8; } -exports.writeUInt64LE = writeUInt64LE; /** * Reverses the order of bytes in a buffer. * @param buffer - The buffer to reverse. * @returns A new buffer with the bytes reversed. */ -function reverseBuffer(buffer) { +export function reverseBuffer(buffer) { if (buffer.length < 1) return buffer; let j = buffer.length - 1; let tmp = 0; @@ -64,17 +52,17 @@ function reverseBuffer(buffer) { } return buffer; } -exports.reverseBuffer = reverseBuffer; -function cloneBuffer(buffer) { +export function cloneBuffer(buffer) { const clone = Buffer.allocUnsafe(buffer.length); buffer.copy(clone); return clone; } -exports.cloneBuffer = cloneBuffer; /** * Helper class for serialization of bitcoin data types into a pre-allocated buffer. */ -class BufferWriter { +export class BufferWriter { + buffer; + offset; static withCapacity(size) { return new BufferWriter(Buffer.alloc(size)); } @@ -120,11 +108,12 @@ class BufferWriter { throw new Error(`buffer size ${this.buffer.length}, offset ${this.offset}`); } } -exports.BufferWriter = BufferWriter; /** * Helper class for reading of bitcoin data types from a buffer. */ -class BufferReader { +export class BufferReader { + buffer; + offset; constructor(buffer, offset = 0) { this.buffer = buffer; this.offset = offset; @@ -175,4 +164,3 @@ class BufferReader { return vector; } } -exports.BufferReader = BufferReader; diff --git a/src/esm/crypto.js b/src/esm/crypto.js new file mode 100644 index 000000000..211891cef --- /dev/null +++ b/src/esm/crypto.js @@ -0,0 +1,98 @@ +/** + * A module for hashing functions. + * include ripemd160、sha1、sha256、hash160、hash256、taggedHash + * + * @packageDocumentation + */ +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) { + return Buffer.from(_ripemd160(Uint8Array.from(buffer))); +} +export function sha1(buffer) { + return Buffer.from(_sha1(Uint8Array.from(buffer))); +} +export function sha256(buffer) { + return Buffer.from(_sha256(Uint8Array.from(buffer))); +} +export function hash160(buffer) { + return Buffer.from(_ripemd160(_sha256(Uint8Array.from(buffer)))); +} +export function hash256(buffer) { + return Buffer.from(_sha256(_sha256(Uint8Array.from(buffer)))); +} +export 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)] */ +/** + * Defines the tagged hash prefixes used in the crypto module. + */ +export const 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, + ]), +}; +export function taggedHash(prefix, data) { + return sha256(Buffer.concat([TAGGED_HASH_PREFIXES[prefix], data])); +} diff --git a/src/esm/ecc_lib.js b/src/esm/ecc_lib.js new file mode 100644 index 000000000..b02701594 --- /dev/null +++ b/src/esm/ecc_lib.js @@ -0,0 +1,105 @@ +const _ECCLIB_CACHE = {}; +/** + * Initializes the ECC library with the provided instance. + * If `eccLib` is `undefined`, the library will be cleared. + * If `eccLib` is a new instance, it will be verified before setting it as the active library. + * + * @param eccLib The instance of the ECC library to initialize. + */ +export 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; + } +} +/** + * Retrieves the ECC Library instance. + * Throws an error if the ECC Library is not provided. + * You must call initEccLib() with a valid TinySecp256k1Interface instance before calling this function. + * @returns The ECC Library instance. + * @throws Error if the ECC Library is not provided. + */ +export 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; +} +const h = hex => Buffer.from(hex, 'hex'); +/** + * Verifies the ECC functionality. + * + * @param ecc - The TinySecp256k1Interface object. + */ +function verifyEcc(ecc) { + assert(typeof ecc.isXOnlyPoint === 'function'); + assert( + ecc.isXOnlyPoint( + h('79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798'), + ), + ); + assert( + ecc.isXOnlyPoint( + h('fffffffffffffffffffffffffffffffffffffffffffffffffffffffeeffffc2e'), + ), + ); + assert( + ecc.isXOnlyPoint( + h('f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9'), + ), + ); + assert( + ecc.isXOnlyPoint( + h('0000000000000000000000000000000000000000000000000000000000000001'), + ), + ); + assert( + !ecc.isXOnlyPoint( + h('0000000000000000000000000000000000000000000000000000000000000000'), + ), + ); + assert( + !ecc.isXOnlyPoint( + h('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f'), + ), + ); + assert(typeof ecc.xOnlyPointAddTweak === 'function'); + tweakAddVectors.forEach(t => { + const r = ecc.xOnlyPointAddTweak(h(t.pubkey), h(t.tweak)); + if (t.result === null) { + assert(r === null); + } else { + assert(r !== null); + assert(r.parity === t.parity); + assert(Buffer.from(r.xOnlyPubkey).equals(h(t.result))); + } + }); +} +function assert(bool) { + if (!bool) throw new Error('ecc library invalid'); +} +const tweakAddVectors = [ + { + pubkey: '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', + tweak: 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140', + parity: -1, + result: null, + }, + { + pubkey: '1617d38ed8d8657da4d4761e8057bc396ea9e4b9d29776d4be096016dbd2509b', + tweak: 'a8397a935f0dfceba6ba9618f6451ef4d80637abf4e6af2669fbc9de6a8fd2ac', + parity: 1, + result: 'e478f99dab91052ab39a33ea35fd5e6e4933f4d28023cd597c9a1f6760346adf', + }, + { + pubkey: '2c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991', + tweak: '823c3cd2142744b075a87eade7e1b8678ba308d566226a0056ca2b7a76f86b47', + parity: 0, + result: '9534f8dc8c6deda2dc007655981c78b49c5d96c778fbf363462a11ec9dfd948c', + }, +]; diff --git a/src/esm/index.js b/src/esm/index.js new file mode 100644 index 000000000..44660a3aa --- /dev/null +++ b/src/esm/index.js @@ -0,0 +1,12 @@ +import * as address from './address'; +import * as crypto from './crypto'; +import * as networks from './networks'; +import * as payments from './payments'; +import * as script from './script'; +export { address, crypto, networks, payments, script }; +export { Block } from './block'; +export { Psbt } from './psbt'; +/** @hidden */ +export { OPS as opcodes } from './ops'; +export { Transaction } from './transaction'; +export { initEccLib } from './ecc_lib'; diff --git a/src/esm/merkle.js b/src/esm/merkle.js new file mode 100644 index 000000000..701a28acd --- /dev/null +++ b/src/esm/merkle.js @@ -0,0 +1,26 @@ +/** + * Calculates the Merkle root of an array of buffers using a specified digest function. + * + * @param values - The array of buffers. + * @param digestFn - The digest function used to calculate the hash of the concatenated buffers. + * @returns The Merkle root as a buffer. + * @throws {TypeError} If the values parameter is not an array or the digestFn parameter is not a function. + */ +export function fastMerkleRoot(values, digestFn) { + if (!Array.isArray(values)) throw TypeError('Expected values Array'); + if (typeof digestFn !== 'function') + throw TypeError('Expected digest Function'); + let length = values.length; + const results = values.concat(); + while (length > 1) { + let j = 0; + for (let i = 0; i < length; i += 2, ++j) { + const left = results[i]; + const right = i + 1 === length ? left : results[i + 1]; + const data = Buffer.concat([left, right]); + results[j] = digestFn(data); + } + length = j; + } + return results[0]; +} diff --git a/src/esm/networks.js b/src/esm/networks.js new file mode 100644 index 000000000..c415efd46 --- /dev/null +++ b/src/esm/networks.js @@ -0,0 +1,68 @@ +// https://en.bitcoin.it/wiki/List_of_address_prefixes +// Dogecoin BIP32 is a proposed standard: https://bitcointalk.org/index.php?topic=409731 +/** + * Represents the Bitcoin network configuration. + */ +export const bitcoin = { + /** + * The message prefix used for signing Bitcoin messages. + */ + messagePrefix: '\x18Bitcoin Signed Message:\n', + /** + * The Bech32 prefix used for Bitcoin addresses. + */ + bech32: 'bc', + /** + * The BIP32 key prefixes for Bitcoin. + */ + bip32: { + /** + * The public key prefix for BIP32 extended public keys. + */ + public: 0x0488b21e, + /** + * The private key prefix for BIP32 extended private keys. + */ + private: 0x0488ade4, + }, + /** + * The prefix for Bitcoin public key hashes. + */ + pubKeyHash: 0x00, + /** + * The prefix for Bitcoin script hashes. + */ + scriptHash: 0x05, + /** + * The prefix for Bitcoin Wallet Import Format (WIF) private keys. + */ + wif: 0x80, +}; +/** + * Represents the regtest network configuration. + */ +export const regtest = { + messagePrefix: '\x18Bitcoin Signed Message:\n', + bech32: 'bcrt', + bip32: { + public: 0x043587cf, + private: 0x04358394, + }, + pubKeyHash: 0x6f, + scriptHash: 0xc4, + wif: 0xef, +}; +/** + * Represents the testnet network configuration. + */ +export const testnet = { + messagePrefix: '\x18Bitcoin Signed Message:\n', + bech32: 'tb', + bip32: { + public: 0x043587cf, + private: 0x04358394, + }, + pubKeyHash: 0x6f, + scriptHash: 0xc4, + wif: 0xef, +}; diff --git a/src/esm/ops.js b/src/esm/ops.js new file mode 100644 index 000000000..9e24a7c94 --- /dev/null +++ b/src/esm/ops.js @@ -0,0 +1,127 @@ +const OPS = { + OP_FALSE: 0, + OP_0: 0, + OP_PUSHDATA1: 76, + OP_PUSHDATA2: 77, + OP_PUSHDATA4: 78, + OP_1NEGATE: 79, + OP_RESERVED: 80, + OP_TRUE: 81, + OP_1: 81, + OP_2: 82, + OP_3: 83, + OP_4: 84, + OP_5: 85, + OP_6: 86, + OP_7: 87, + OP_8: 88, + OP_9: 89, + OP_10: 90, + OP_11: 91, + OP_12: 92, + OP_13: 93, + OP_14: 94, + OP_15: 95, + OP_16: 96, + OP_NOP: 97, + OP_VER: 98, + OP_IF: 99, + OP_NOTIF: 100, + OP_VERIF: 101, + OP_VERNOTIF: 102, + OP_ELSE: 103, + OP_ENDIF: 104, + OP_VERIFY: 105, + OP_RETURN: 106, + OP_TOALTSTACK: 107, + OP_FROMALTSTACK: 108, + OP_2DROP: 109, + OP_2DUP: 110, + OP_3DUP: 111, + OP_2OVER: 112, + OP_2ROT: 113, + OP_2SWAP: 114, + OP_IFDUP: 115, + OP_DEPTH: 116, + OP_DROP: 117, + OP_DUP: 118, + OP_NIP: 119, + OP_OVER: 120, + OP_PICK: 121, + OP_ROLL: 122, + OP_ROT: 123, + OP_SWAP: 124, + OP_TUCK: 125, + OP_CAT: 126, + OP_SUBSTR: 127, + OP_LEFT: 128, + OP_RIGHT: 129, + OP_SIZE: 130, + OP_INVERT: 131, + OP_AND: 132, + OP_OR: 133, + OP_XOR: 134, + OP_EQUAL: 135, + OP_EQUALVERIFY: 136, + OP_RESERVED1: 137, + OP_RESERVED2: 138, + OP_1ADD: 139, + OP_1SUB: 140, + OP_2MUL: 141, + OP_2DIV: 142, + OP_NEGATE: 143, + OP_ABS: 144, + OP_NOT: 145, + OP_0NOTEQUAL: 146, + OP_ADD: 147, + OP_SUB: 148, + OP_MUL: 149, + OP_DIV: 150, + OP_MOD: 151, + OP_LSHIFT: 152, + OP_RSHIFT: 153, + OP_BOOLAND: 154, + OP_BOOLOR: 155, + OP_NUMEQUAL: 156, + OP_NUMEQUALVERIFY: 157, + OP_NUMNOTEQUAL: 158, + OP_LESSTHAN: 159, + OP_GREATERTHAN: 160, + OP_LESSTHANOREQUAL: 161, + OP_GREATERTHANOREQUAL: 162, + OP_MIN: 163, + OP_MAX: 164, + OP_WITHIN: 165, + OP_RIPEMD160: 166, + OP_SHA1: 167, + OP_SHA256: 168, + OP_HASH160: 169, + OP_HASH256: 170, + OP_CODESEPARATOR: 171, + OP_CHECKSIG: 172, + OP_CHECKSIGVERIFY: 173, + OP_CHECKMULTISIG: 174, + OP_CHECKMULTISIGVERIFY: 175, + OP_NOP1: 176, + OP_NOP2: 177, + OP_CHECKLOCKTIMEVERIFY: 177, + OP_NOP3: 178, + OP_CHECKSEQUENCEVERIFY: 178, + OP_NOP4: 179, + OP_NOP5: 180, + OP_NOP6: 181, + OP_NOP7: 182, + OP_NOP8: 183, + OP_NOP9: 184, + OP_NOP10: 185, + OP_CHECKSIGADD: 186, + OP_PUBKEYHASH: 253, + OP_PUBKEY: 254, + OP_INVALIDOPCODE: 255, +}; +const REVERSE_OPS = {}; +for (const op of Object.keys(OPS)) { + const code = OPS[op]; + REVERSE_OPS[code] = op; +} +export { OPS, REVERSE_OPS }; diff --git a/src/esm/payments/bip341.js b/src/esm/payments/bip341.js new file mode 100644 index 000000000..489b7c3eb --- /dev/null +++ b/src/esm/payments/bip341.js @@ -0,0 +1,101 @@ +import { Buffer as NBuffer } from 'buffer'; +import { getEccLib } from '../ecc_lib'; +import * as bcrypto from '../crypto'; +import { varuint } from '../bufferutils'; +import { isTapleaf } from '../types'; +export const LEAF_VERSION_TAPSCRIPT = 0xc0; +export const MAX_TAPTREE_DEPTH = 128; +const isHashBranch = ht => 'left' in ht && 'right' in ht; +/** + * Calculates the root hash from a given control block and leaf hash. + * @param controlBlock - The control block buffer. + * @param leafHash - The leaf hash buffer. + * @returns The root hash buffer. + * @throws {TypeError} If the control block length is less than 33. + */ +export 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++) { + 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. + */ +export function toHashTree(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)); + const [left, right] = hashes; + return { + hash: tapBranchHash(left.hash, right.hash), + left, + right, + }; +} +/** + * 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 - 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, hash) { + 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 []; + } + return undefined; +} +export function tapleafHash(leaf) { + const version = leaf.version || LEAF_VERSION_TAPSCRIPT; + return bcrypto.taggedHash( + 'TapLeaf', + NBuffer.concat([NBuffer.from([version]), serializeScript(leaf.output)]), + ); +} +export function tapTweakHash(pubKey, h) { + return bcrypto.taggedHash( + 'TapTweak', + NBuffer.concat(h ? [pubKey, h] : [pubKey]), + ); +} +export function tweakKey(pubKey, h) { + 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, b) { + return bcrypto.taggedHash('TapBranch', NBuffer.concat([a, b])); +} +function serializeScript(s) { + /* global BigInt */ + const varintLen = varuint.encodingLength(s.length); + const buffer = NBuffer.allocUnsafe(varintLen); // better + varuint.encode(s.length, buffer); + return NBuffer.concat([buffer, s]); +} diff --git a/src/payments/embed.js b/src/esm/payments/embed.js similarity index 58% rename from src/payments/embed.js rename to src/esm/payments/embed.js index 92bbb572f..00084fa1e 100644 --- a/src/payments/embed.js +++ b/src/esm/payments/embed.js @@ -1,10 +1,7 @@ -'use strict'; -Object.defineProperty(exports, '__esModule', { value: true }); -exports.p2data = void 0; -const networks_1 = require('../networks'); -const bscript = require('../script'); -const types_1 = require('../types'); -const lazy = require('./lazy'); +import { bitcoin as BITCOIN_NETWORK } from '../networks'; +import * as bscript from '../script'; +import { typeforce as typef, stacksEqual } from '../types'; +import * as lazy from './lazy'; const OPS = bscript.OPS; // output: OP_RETURN ... /** @@ -14,20 +11,18 @@ const OPS = bscript.OPS; * @returns The modified payment object. * @throws {TypeError} If there is not enough data or if the output is invalid. */ -function p2data(a, opts) { +export function p2data(a, opts) { if (!a.data && !a.output) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - (0, types_1.typeforce)( + typef( { - network: types_1.typeforce.maybe(types_1.typeforce.Object), - output: types_1.typeforce.maybe(types_1.typeforce.Buffer), - data: types_1.typeforce.maybe( - types_1.typeforce.arrayOf(types_1.typeforce.Buffer), - ), + network: typef.maybe(typef.Object), + output: typef.maybe(typef.Buffer), + data: typef.maybe(typef.arrayOf(typef.Buffer)), }, a, ); - const network = a.network || networks_1.bitcoin; + const network = a.network || BITCOIN_NETWORK; const o = { name: 'embed', network }; lazy.prop(o, 'output', () => { if (!a.data) return; @@ -42,12 +37,11 @@ function p2data(a, opts) { if (a.output) { const chunks = bscript.decompile(a.output); if (chunks[0] !== OPS.OP_RETURN) throw new TypeError('Output is invalid'); - if (!chunks.slice(1).every(types_1.typeforce.Buffer)) + if (!chunks.slice(1).every(typef.Buffer)) throw new TypeError('Output is invalid'); - if (a.data && !(0, types_1.stacksEqual)(a.data, o.data)) + if (a.data && !stacksEqual(a.data, o.data)) throw new TypeError('Data mismatch'); } } return Object.assign(o, a); } -exports.p2data = p2data; diff --git a/src/esm/payments/index.js b/src/esm/payments/index.js new file mode 100644 index 000000000..e2436ce68 --- /dev/null +++ b/src/esm/payments/index.js @@ -0,0 +1,11 @@ +import { p2data as embed } from './embed'; +import { p2ms } from './p2ms'; +import { p2pk } from './p2pk'; +import { p2pkh } from './p2pkh'; +import { p2sh } from './p2sh'; +import { p2wpkh } from './p2wpkh'; +import { p2wsh } from './p2wsh'; +import { p2tr } from './p2tr'; +export { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh, p2tr }; +// TODO +// witness commitment diff --git a/src/esm/payments/lazy.js b/src/esm/payments/lazy.js new file mode 100644 index 000000000..cc66c9163 --- /dev/null +++ b/src/esm/payments/lazy.js @@ -0,0 +1,27 @@ +export function prop(object, name, f) { + Object.defineProperty(object, name, { + configurable: true, + enumerable: true, + get() { + const _value = f.call(this); + this[name] = _value; + return _value; + }, + set(_value) { + Object.defineProperty(this, name, { + configurable: true, + enumerable: true, + value: _value, + writable: true, + }); + }, + }); +} +export function value(f) { + let _value; + return () => { + if (_value !== undefined) return _value; + _value = f(); + return _value; + }; +} diff --git a/src/esm/payments/p2ms.js b/src/esm/payments/p2ms.js new file mode 100644 index 000000000..c64386738 --- /dev/null +++ b/src/esm/payments/p2ms.js @@ -0,0 +1,142 @@ +import { bitcoin as BITCOIN_NETWORK } from '../networks'; +import * as bscript from '../script'; +import { isPoint, typeforce as typef, stacksEqual } from '../types'; +import * as lazy from './lazy'; +const OPS = bscript.OPS; +const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1 +// input: OP_0 [signatures ...] +// output: m [pubKeys ...] n OP_CHECKMULTISIG +/** + * Represents a function that creates a Pay-to-Multisig (P2MS) payment object. + * @param a - The payment object. + * @param opts - Optional payment options. + * @returns The created payment object. + * @throws {TypeError} If the provided data is not valid. + */ +export function p2ms(a, opts) { + if ( + !a.input && + !a.output && + !(a.pubkeys && a.m !== undefined) && + !a.signatures + ) + throw new TypeError('Not enough data'); + opts = Object.assign({ validate: true }, opts || {}); + function isAcceptableSignature(x) { + return ( + bscript.isCanonicalScriptSignature(x) || + (opts.allowIncomplete && x === OPS.OP_0) !== undefined + ); + } + typef( + { + network: typef.maybe(typef.Object), + m: typef.maybe(typef.Number), + n: typef.maybe(typef.Number), + output: typef.maybe(typef.Buffer), + pubkeys: typef.maybe(typef.arrayOf(isPoint)), + signatures: typef.maybe(typef.arrayOf(isAcceptableSignature)), + input: typef.maybe(typef.Buffer), + }, + a, + ); + const network = a.network || BITCOIN_NETWORK; + const o = { network }; + let chunks = []; + let decoded = false; + function decode(output) { + if (decoded) return; + decoded = true; + chunks = bscript.decompile(output); + o.m = chunks[0] - OP_INT_BASE; + o.n = chunks[chunks.length - 2] - OP_INT_BASE; + o.pubkeys = chunks.slice(1, -2); + } + lazy.prop(o, 'output', () => { + if (!a.m) return; + if (!o.n) return; + if (!a.pubkeys) return; + return bscript.compile( + [].concat( + OP_INT_BASE + a.m, + a.pubkeys, + OP_INT_BASE + o.n, + OPS.OP_CHECKMULTISIG, + ), + ); + }); + lazy.prop(o, 'm', () => { + if (!o.output) return; + decode(o.output); + return o.m; + }); + lazy.prop(o, 'n', () => { + if (!o.pubkeys) return; + return o.pubkeys.length; + }); + lazy.prop(o, 'pubkeys', () => { + if (!a.output) return; + decode(a.output); + return o.pubkeys; + }); + lazy.prop(o, 'signatures', () => { + if (!a.input) return; + return bscript.decompile(a.input).slice(1); + }); + lazy.prop(o, 'input', () => { + if (!a.signatures) return; + return bscript.compile([OPS.OP_0].concat(a.signatures)); + }); + lazy.prop(o, 'witness', () => { + if (!o.input) return; + return []; + }); + lazy.prop(o, 'name', () => { + if (!o.m || !o.n) return; + return `p2ms(${o.m} of ${o.n})`; + }); + // extended validation + if (opts.validate) { + if (a.output) { + decode(a.output); + if (!typef.Number(chunks[0])) throw new TypeError('Output is invalid'); + if (!typef.Number(chunks[chunks.length - 2])) + throw new TypeError('Output is invalid'); + if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG) + throw new TypeError('Output is invalid'); + if (o.m <= 0 || o.n > 16 || o.m > o.n || o.n !== chunks.length - 3) + throw new TypeError('Output is invalid'); + if (!o.pubkeys.every(x => isPoint(x))) + throw new TypeError('Output is invalid'); + if (a.m !== undefined && a.m !== o.m) throw new TypeError('m mismatch'); + if (a.n !== undefined && a.n !== o.n) throw new TypeError('n mismatch'); + if (a.pubkeys && !stacksEqual(a.pubkeys, o.pubkeys)) + throw new TypeError('Pubkeys mismatch'); + } + if (a.pubkeys) { + if (a.n !== undefined && a.n !== a.pubkeys.length) + throw new TypeError('Pubkey count mismatch'); + o.n = a.pubkeys.length; + if (o.n < o.m) throw new TypeError('Pubkey count cannot be less than m'); + } + if (a.signatures) { + if (a.signatures.length < o.m) + throw new TypeError('Not enough signatures provided'); + if (a.signatures.length > o.m) + throw new TypeError('Too many signatures provided'); + } + if (a.input) { + if (a.input[0] !== OPS.OP_0) throw new TypeError('Input is invalid'); + if ( + o.signatures.length === 0 || + !o.signatures.every(isAcceptableSignature) + ) + throw new TypeError('Input has invalid signature(s)'); + if (a.signatures && !stacksEqual(a.signatures, o.signatures)) + throw new TypeError('Signature mismatch'); + if (a.m !== undefined && a.m !== a.signatures.length) + throw new TypeError('Signature count mismatch'); + } + } + return Object.assign(o, a); +} diff --git a/src/payments/p2pk.js b/src/esm/payments/p2pk.js similarity index 70% rename from src/payments/p2pk.js rename to src/esm/payments/p2pk.js index cd6702f53..1560f1cfa 100644 --- a/src/payments/p2pk.js +++ b/src/esm/payments/p2pk.js @@ -1,10 +1,7 @@ -'use strict'; -Object.defineProperty(exports, '__esModule', { value: true }); -exports.p2pk = void 0; -const networks_1 = require('../networks'); -const bscript = require('../script'); -const types_1 = require('../types'); -const lazy = require('./lazy'); +import { bitcoin as BITCOIN_NETWORK } from '../networks'; +import * as bscript from '../script'; +import { isPoint, typeforce as typef } from '../types'; +import * as lazy from './lazy'; const OPS = bscript.OPS; // input: {signature} // output: {pubKey} OP_CHECKSIG @@ -16,24 +13,24 @@ const OPS = bscript.OPS; * @returns The P2PK payment object. * @throws {TypeError} If the required data is not provided or if the data is invalid. */ -function p2pk(a, opts) { +export function p2pk(a, opts) { if (!a.input && !a.output && !a.pubkey && !a.input && !a.signature) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - (0, types_1.typeforce)( + typef( { - network: types_1.typeforce.maybe(types_1.typeforce.Object), - output: types_1.typeforce.maybe(types_1.typeforce.Buffer), - pubkey: types_1.typeforce.maybe(types_1.isPoint), - signature: types_1.typeforce.maybe(bscript.isCanonicalScriptSignature), - input: types_1.typeforce.maybe(types_1.typeforce.Buffer), + network: typef.maybe(typef.Object), + output: typef.maybe(typef.Buffer), + pubkey: typef.maybe(isPoint), + signature: typef.maybe(bscript.isCanonicalScriptSignature), + input: typef.maybe(typef.Buffer), }, a, ); const _chunks = lazy.value(() => { return bscript.decompile(a.input); }); - const network = a.network || networks_1.bitcoin; + const network = a.network || BITCOIN_NETWORK; const o = { name: 'p2pk', network }; lazy.prop(o, 'output', () => { if (!a.pubkey) return; @@ -60,8 +57,7 @@ function p2pk(a, opts) { if (a.output) { if (a.output[a.output.length - 1] !== OPS.OP_CHECKSIG) throw new TypeError('Output is invalid'); - if (!(0, types_1.isPoint)(o.pubkey)) - throw new TypeError('Output pubkey is invalid'); + if (!isPoint(o.pubkey)) throw new TypeError('Output pubkey is invalid'); if (a.pubkey && !a.pubkey.equals(o.pubkey)) throw new TypeError('Pubkey mismatch'); } @@ -77,4 +73,3 @@ function p2pk(a, opts) { } return Object.assign(o, a); } -exports.p2pk = p2pk; diff --git a/src/payments/p2pkh.js b/src/esm/payments/p2pkh.js similarity index 78% rename from src/payments/p2pkh.js rename to src/esm/payments/p2pkh.js index bc35e878e..9e79dc5ab 100644 --- a/src/payments/p2pkh.js +++ b/src/esm/payments/p2pkh.js @@ -1,12 +1,9 @@ -'use strict'; -Object.defineProperty(exports, '__esModule', { value: true }); -exports.p2pkh = void 0; -const bcrypto = require('../crypto'); -const networks_1 = require('../networks'); -const bscript = require('../script'); -const types_1 = require('../types'); -const lazy = require('./lazy'); -const bs58check = require('bs58check'); +import * as bcrypto from '../crypto'; +import { bitcoin as BITCOIN_NETWORK } from '../networks'; +import * as bscript from '../script'; +import { isPoint, typeforce as typef } from '../types'; +import * as lazy from './lazy'; +import * as bs58check from 'bs58check'; const OPS = bscript.OPS; // input: {signature} {pubkey} // output: OP_DUP OP_HASH160 {hash160(pubkey)} OP_EQUALVERIFY OP_CHECKSIG @@ -18,19 +15,19 @@ const OPS = bscript.OPS; * @returns The P2PKH payment object. * @throws {TypeError} If the required data is not provided or if the data is invalid. */ -function p2pkh(a, opts) { +export function p2pkh(a, opts) { if (!a.address && !a.hash && !a.output && !a.pubkey && !a.input) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - (0, types_1.typeforce)( + typef( { - network: types_1.typeforce.maybe(types_1.typeforce.Object), - address: types_1.typeforce.maybe(types_1.typeforce.String), - hash: types_1.typeforce.maybe(types_1.typeforce.BufferN(20)), - output: types_1.typeforce.maybe(types_1.typeforce.BufferN(25)), - pubkey: types_1.typeforce.maybe(types_1.isPoint), - signature: types_1.typeforce.maybe(bscript.isCanonicalScriptSignature), - input: types_1.typeforce.maybe(types_1.typeforce.Buffer), + network: typef.maybe(typef.Object), + address: typef.maybe(typef.String), + hash: typef.maybe(typef.BufferN(20)), + output: typef.maybe(typef.BufferN(25)), + pubkey: typef.maybe(isPoint), + signature: typef.maybe(bscript.isCanonicalScriptSignature), + input: typef.maybe(typef.Buffer), }, a, ); @@ -43,7 +40,7 @@ function p2pkh(a, opts) { const _chunks = lazy.value(() => { return bscript.decompile(a.input); }); - const network = a.network || networks_1.bitcoin; + const network = a.network || BITCOIN_NETWORK; const o = { name: 'p2pkh', network }; lazy.prop(o, 'address', () => { if (!o.hash) return; @@ -124,8 +121,7 @@ function p2pkh(a, opts) { if (chunks.length !== 2) throw new TypeError('Input is invalid'); if (!bscript.isCanonicalScriptSignature(chunks[0])) throw new TypeError('Input has invalid signature'); - if (!(0, types_1.isPoint)(chunks[1])) - throw new TypeError('Input has invalid pubkey'); + if (!isPoint(chunks[1])) throw new TypeError('Input has invalid pubkey'); if (a.signature && !a.signature.equals(chunks[0])) throw new TypeError('Signature mismatch'); if (a.pubkey && !a.pubkey.equals(chunks[1])) @@ -137,4 +133,3 @@ function p2pkh(a, opts) { } return Object.assign(o, a); } -exports.p2pkh = p2pkh; diff --git a/src/esm/payments/p2sh.js b/src/esm/payments/p2sh.js new file mode 100644 index 000000000..f652ab7cb --- /dev/null +++ b/src/esm/payments/p2sh.js @@ -0,0 +1,192 @@ +import * as bcrypto from '../crypto'; +import { bitcoin as BITCOIN_NETWORK } from '../networks'; +import * as bscript from '../script'; +import { typeforce as typef, stacksEqual } from '../types'; +import * as lazy from './lazy'; +import * as bs58check from 'bs58check'; +const OPS = bscript.OPS; +// input: [redeemScriptSig ...] {redeemScript} +// witness: +// output: OP_HASH160 {hash160(redeemScript)} OP_EQUAL +/** + * Creates a Pay-to-Script-Hash (P2SH) payment object. + * + * @param a - The payment object containing the necessary data. + * @param opts - Optional payment options. + * @returns The P2SH payment object. + * @throws {TypeError} If the required data is not provided or if the data is invalid. + */ +export function p2sh(a, opts) { + if (!a.address && !a.hash && !a.output && !a.redeem && !a.input) + throw new TypeError('Not enough data'); + opts = Object.assign({ validate: true }, opts || {}); + typef( + { + network: typef.maybe(typef.Object), + address: typef.maybe(typef.String), + hash: typef.maybe(typef.BufferN(20)), + output: typef.maybe(typef.BufferN(23)), + redeem: typef.maybe({ + network: typef.maybe(typef.Object), + output: typef.maybe(typef.Buffer), + input: typef.maybe(typef.Buffer), + witness: typef.maybe(typef.arrayOf(typef.Buffer)), + }), + input: typef.maybe(typef.Buffer), + witness: typef.maybe(typef.arrayOf(typef.Buffer)), + }, + a, + ); + let network = a.network; + if (!network) { + network = (a.redeem && a.redeem.network) || BITCOIN_NETWORK; + } + const o = { network }; + const _address = lazy.value(() => { + const payload = Buffer.from(bs58check.decode(a.address)); + const version = payload.readUInt8(0); + const hash = payload.slice(1); + return { version, hash }; + }); + const _chunks = lazy.value(() => { + return bscript.decompile(a.input); + }); + const _redeem = lazy.value(() => { + const chunks = _chunks(); + const lastChunk = chunks[chunks.length - 1]; + return { + network, + output: lastChunk === OPS.OP_FALSE ? Buffer.from([]) : lastChunk, + input: bscript.compile(chunks.slice(0, -1)), + witness: a.witness || [], + }; + }); + // output dependents + lazy.prop(o, 'address', () => { + if (!o.hash) return; + const payload = Buffer.allocUnsafe(21); + payload.writeUInt8(o.network.scriptHash, 0); + o.hash.copy(payload, 1); + return bs58check.encode(payload); + }); + lazy.prop(o, 'hash', () => { + // in order of least effort + if (a.output) return a.output.slice(2, 22); + if (a.address) return _address().hash; + if (o.redeem && o.redeem.output) return bcrypto.hash160(o.redeem.output); + }); + lazy.prop(o, 'output', () => { + if (!o.hash) return; + return bscript.compile([OPS.OP_HASH160, o.hash, OPS.OP_EQUAL]); + }); + // input dependents + lazy.prop(o, 'redeem', () => { + if (!a.input) return; + return _redeem(); + }); + lazy.prop(o, 'input', () => { + if (!a.redeem || !a.redeem.input || !a.redeem.output) return; + return bscript.compile( + [].concat(bscript.decompile(a.redeem.input), a.redeem.output), + ); + }); + lazy.prop(o, 'witness', () => { + if (o.redeem && o.redeem.witness) return o.redeem.witness; + if (o.input) return []; + }); + lazy.prop(o, 'name', () => { + const nameParts = ['p2sh']; + if (o.redeem !== undefined && o.redeem.name !== undefined) + nameParts.push(o.redeem.name); + return nameParts.join('-'); + }); + if (opts.validate) { + let hash = Buffer.from([]); + if (a.address) { + if (_address().version !== network.scriptHash) + throw new TypeError('Invalid version or Network mismatch'); + if (_address().hash.length !== 20) throw new TypeError('Invalid address'); + hash = _address().hash; + } + if (a.hash) { + if (hash.length > 0 && !hash.equals(a.hash)) + throw new TypeError('Hash mismatch'); + else hash = a.hash; + } + if (a.output) { + if ( + a.output.length !== 23 || + a.output[0] !== OPS.OP_HASH160 || + a.output[1] !== 0x14 || + a.output[22] !== OPS.OP_EQUAL + ) + throw new TypeError('Output is invalid'); + const hash2 = a.output.slice(2, 22); + if (hash.length > 0 && !hash.equals(hash2)) + throw new TypeError('Hash mismatch'); + else hash = hash2; + } + // inlined to prevent 'no-inner-declarations' failing + const checkRedeem = redeem => { + // is the redeem output empty/invalid? + if (redeem.output) { + 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)) + throw new TypeError('Hash mismatch'); + else hash = hash2; + } + if (redeem.input) { + const hasInput = redeem.input.length > 0; + const hasWitness = redeem.witness && redeem.witness.length > 0; + if (!hasInput && !hasWitness) throw new TypeError('Empty input'); + if (hasInput && hasWitness) + throw new TypeError('Input and witness provided'); + if (hasInput) { + const richunks = bscript.decompile(redeem.input); + if (!bscript.isPushOnly(richunks)) + throw new TypeError('Non push-only scriptSig'); + } + } + }; + if (a.input) { + const chunks = _chunks(); + if (!chunks || chunks.length < 1) throw new TypeError('Input too short'); + if (!Buffer.isBuffer(_redeem().output)) + throw new TypeError('Input is invalid'); + checkRedeem(_redeem()); + } + if (a.redeem) { + if (a.redeem.network && a.redeem.network !== network) + throw new TypeError('Network mismatch'); + if (a.input) { + const redeem = _redeem(); + if (a.redeem.output && !a.redeem.output.equals(redeem.output)) + throw new TypeError('Redeem.output mismatch'); + if (a.redeem.input && !a.redeem.input.equals(redeem.input)) + throw new TypeError('Redeem.input mismatch'); + } + checkRedeem(a.redeem); + } + if (a.witness) { + if ( + a.redeem && + a.redeem.witness && + !stacksEqual(a.redeem.witness, a.witness) + ) + throw new TypeError('Witness and redeem.witness mismatch'); + } + } + return Object.assign(o, a); +} diff --git a/src/esm/payments/p2tr.js b/src/esm/payments/p2tr.js new file mode 100644 index 000000000..eaa09c562 --- /dev/null +++ b/src/esm/payments/p2tr.js @@ -0,0 +1,285 @@ +import { Buffer as NBuffer } from 'buffer'; +import { bitcoin as BITCOIN_NETWORK } from '../networks'; +import * as bscript from '../script'; +import { + typeforce as typef, + isTaptree, + TAPLEAF_VERSION_MASK, + stacksEqual, +} from '../types'; +import { getEccLib } from '../ecc_lib'; +import { + toHashTree, + rootHashFromPath, + findScriptPath, + tapleafHash, + tweakKey, + LEAF_VERSION_TAPSCRIPT, +} from './bip341'; +import * as lazy from './lazy'; +import { bech32m } from 'bech32'; +import { fromBech32 } from '../address'; +const OPS = bscript.OPS; +const TAPROOT_WITNESS_VERSION = 0x01; +const ANNEX_PREFIX = 0x50; +/** + * Creates a Pay-to-Taproot (P2TR) payment object. + * + * @param a - The payment object containing the necessary data for P2TR. + * @param opts - Optional payment options. + * @returns The P2TR payment object. + * @throws {TypeError} If the provided data is invalid or insufficient. + */ +export function p2tr(a, opts) { + if ( + !a.address && + !a.output && + !a.pubkey && + !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(typef.anyOf(typef.BufferN(64), typef.BufferN(65))), + witness: typef.maybe(typef.arrayOf(typef.Buffer)), + 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, + ); + const _address = lazy.value(() => { + return fromBech32(a.address); + }); + // 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 + ) { + return a.witness.slice(0, -1); + } + 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 = { name: 'p2tr', network }; + lazy.prop(o, 'address', () => { + if (!o.pubkey) return; + const words = bech32m.toWords(o.pubkey); + words.unshift(TAPROOT_WITNESS_VERSION); + return bech32m.encode(network.bech32, words); + }); + lazy.prop(o, 'hash', () => { + const hashTree = _hashTree(); + if (hashTree) return hashTree.hash; + const w = _witness(); + if (w && w.length > 1) { + 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 }); + 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, '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] & TAPLEAF_VERSION_MASK, + }; + }); + 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.signature) return a.signature; + 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; + const hashTree = _hashTree(); + if (hashTree && a.redeem && a.redeem.output && a.internalPubkey) { + const leafHash = tapleafHash({ + output: a.redeem.output, + version: o.redeemVersion, + }); + const path = findScriptPath(hashTree, leafHash); + if (!path) return; + const outputKey = tweakKey(a.internalPubkey, hashTree.hash); + if (!outputKey) return; + const controlBock = NBuffer.concat( + [ + NBuffer.from([o.redeemVersion | outputKey.parity]), + a.internalPubkey, + ].concat(path), + ); + return [a.redeem.output, controlBock]; + } + if (a.signature) return [a.signature]; + }); + // extended validation + if (opts.validate) { + let pubkey = NBuffer.from([]); + if (a.address) { + if (network && network.bech32 !== _address().prefix) + throw new TypeError('Invalid prefix or Network mismatch'); + if (_address().version !== TAPROOT_WITNESS_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 (!getEccLib().isXOnlyPoint(pubkey)) + throw new TypeError('Invalid pubkey for p2tr'); + } + 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(); + // 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 + if (a.signature && !a.signature.equals(witness[0])) + throw new TypeError('Signature mismatch'); + } 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 (!getEccLib().isXOnlyPoint(internalPubkey)) + throw new TypeError('Invalid internalPubkey for p2tr witness'); + const leafVersion = controlBlock[0] & TAPLEAF_VERSION_MASK; + const script = witness[witness.length - 2]; + const leafHash = tapleafHash({ output: script, version: 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); +} diff --git a/src/esm/payments/p2wpkh.js b/src/esm/payments/p2wpkh.js new file mode 100644 index 000000000..4c6a85309 --- /dev/null +++ b/src/esm/payments/p2wpkh.js @@ -0,0 +1,134 @@ +import * as bcrypto from '../crypto'; +import { bitcoin as BITCOIN_NETWORK } from '../networks'; +import * as bscript from '../script'; +import { isPoint, typeforce as typef } from '../types'; +import * as lazy from './lazy'; +import { bech32 } from 'bech32'; +const OPS = bscript.OPS; +const EMPTY_BUFFER = Buffer.alloc(0); +// witness: {signature} {pubKey} +// input: <> +// output: OP_0 {pubKeyHash} +/** + * Creates a pay-to-witness-public-key-hash (p2wpkh) payment object. + * + * @param a - The payment object containing the necessary data. + * @param opts - Optional payment options. + * @returns The p2wpkh payment object. + * @throws {TypeError} If the required data is missing or invalid. + */ +export function p2wpkh(a, opts) { + if (!a.address && !a.hash && !a.output && !a.pubkey && !a.witness) + throw new TypeError('Not enough data'); + opts = Object.assign({ validate: true }, opts || {}); + typef( + { + 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(22)), + pubkey: typef.maybe(isPoint), + signature: typef.maybe(bscript.isCanonicalScriptSignature), + witness: typef.maybe(typef.arrayOf(typef.Buffer)), + }, + a, + ); + const _address = lazy.value(() => { + const result = bech32.decode(a.address); + const version = result.words.shift(); + const data = bech32.fromWords(result.words); + return { + version, + prefix: result.prefix, + data: Buffer.from(data), + }; + }); + const network = a.network || BITCOIN_NETWORK; + const o = { name: 'p2wpkh', network }; + lazy.prop(o, 'address', () => { + if (!o.hash) return; + const words = bech32.toWords(o.hash); + words.unshift(0x00); + return bech32.encode(network.bech32, words); + }); + lazy.prop(o, 'hash', () => { + if (a.output) return a.output.slice(2, 22); + if (a.address) return _address().data; + if (a.pubkey || o.pubkey) return bcrypto.hash160(a.pubkey || o.pubkey); + }); + lazy.prop(o, 'output', () => { + if (!o.hash) return; + return bscript.compile([OPS.OP_0, o.hash]); + }); + lazy.prop(o, 'pubkey', () => { + if (a.pubkey) return a.pubkey; + if (!a.witness) return; + return a.witness[1]; + }); + lazy.prop(o, 'signature', () => { + if (!a.witness) return; + return a.witness[0]; + }); + lazy.prop(o, 'input', () => { + if (!o.witness) return; + return EMPTY_BUFFER; + }); + lazy.prop(o, 'witness', () => { + if (!a.pubkey) return; + if (!a.signature) return; + return [a.signature, a.pubkey]; + }); + // extended validation + if (opts.validate) { + let hash = Buffer.from([]); + if (a.address) { + if (network && network.bech32 !== _address().prefix) + throw new TypeError('Invalid prefix or Network mismatch'); + if (_address().version !== 0x00) + throw new TypeError('Invalid address version'); + if (_address().data.length !== 20) + throw new TypeError('Invalid address data'); + hash = _address().data; + } + if (a.hash) { + if (hash.length > 0 && !hash.equals(a.hash)) + throw new TypeError('Hash mismatch'); + else hash = a.hash; + } + if (a.output) { + if ( + a.output.length !== 22 || + a.output[0] !== OPS.OP_0 || + a.output[1] !== 0x14 + ) + throw new TypeError('Output is invalid'); + if (hash.length > 0 && !hash.equals(a.output.slice(2))) + throw new TypeError('Hash mismatch'); + else hash = a.output.slice(2); + } + if (a.pubkey) { + const pkh = bcrypto.hash160(a.pubkey); + if (hash.length > 0 && !hash.equals(pkh)) + throw new TypeError('Hash mismatch'); + else hash = pkh; + if (!isPoint(a.pubkey) || a.pubkey.length !== 33) + throw new TypeError('Invalid pubkey for p2wpkh'); + } + if (a.witness) { + if (a.witness.length !== 2) throw new TypeError('Witness is invalid'); + if (!bscript.isCanonicalScriptSignature(a.witness[0])) + throw new TypeError('Witness has invalid signature'); + if (!isPoint(a.witness[1]) || a.witness[1].length !== 33) + throw new TypeError('Witness has invalid pubkey'); + if (a.signature && !a.signature.equals(a.witness[0])) + throw new TypeError('Signature mismatch'); + if (a.pubkey && !a.pubkey.equals(a.witness[1])) + throw new TypeError('Pubkey mismatch'); + const pkh = bcrypto.hash160(a.witness[1]); + if (hash.length > 0 && !hash.equals(pkh)) + throw new TypeError('Hash mismatch'); + } + } + return Object.assign(o, a); +} diff --git a/src/esm/payments/p2wsh.js b/src/esm/payments/p2wsh.js new file mode 100644 index 000000000..f8b71706c --- /dev/null +++ b/src/esm/payments/p2wsh.js @@ -0,0 +1,215 @@ +import * as bcrypto from '../crypto'; +import { bitcoin as BITCOIN_NETWORK } from '../networks'; +import * as bscript from '../script'; +import { isPoint, typeforce as typef, stacksEqual } from '../types'; +import * as lazy from './lazy'; +import { bech32 } from 'bech32'; +const OPS = bscript.OPS; +const EMPTY_BUFFER = Buffer.alloc(0); +function chunkHasUncompressedPubkey(chunk) { + if ( + Buffer.isBuffer(chunk) && + chunk.length === 65 && + chunk[0] === 0x04 && + isPoint(chunk) + ) { + return true; + } else { + return false; + } +} +// input: <> +// witness: [redeemScriptSig ...] {redeemScript} +// output: OP_0 {sha256(redeemScript)} +/** + * Creates a Pay-to-Witness-Script-Hash (P2WSH) payment object. + * + * @param a - The payment object containing the necessary data. + * @param opts - Optional payment options. + * @returns The P2WSH payment object. + * @throws {TypeError} If the required data is missing or invalid. + */ +export function p2wsh(a, opts) { + if (!a.address && !a.hash && !a.output && !a.redeem && !a.witness) + throw new TypeError('Not enough data'); + opts = Object.assign({ validate: true }, opts || {}); + typef( + { + network: typef.maybe(typef.Object), + address: typef.maybe(typef.String), + hash: typef.maybe(typef.BufferN(32)), + output: typef.maybe(typef.BufferN(34)), + redeem: typef.maybe({ + input: typef.maybe(typef.Buffer), + network: typef.maybe(typef.Object), + output: typef.maybe(typef.Buffer), + witness: typef.maybe(typef.arrayOf(typef.Buffer)), + }), + input: typef.maybe(typef.BufferN(0)), + witness: typef.maybe(typef.arrayOf(typef.Buffer)), + }, + a, + ); + const _address = lazy.value(() => { + const result = bech32.decode(a.address); + const version = result.words.shift(); + const data = bech32.fromWords(result.words); + return { + version, + prefix: result.prefix, + data: Buffer.from(data), + }; + }); + const _rchunks = lazy.value(() => { + return bscript.decompile(a.redeem.input); + }); + let network = a.network; + if (!network) { + network = (a.redeem && a.redeem.network) || BITCOIN_NETWORK; + } + const o = { network }; + lazy.prop(o, 'address', () => { + if (!o.hash) return; + const words = bech32.toWords(o.hash); + words.unshift(0x00); + return bech32.encode(network.bech32, words); + }); + lazy.prop(o, 'hash', () => { + if (a.output) return a.output.slice(2); + if (a.address) return _address().data; + if (o.redeem && o.redeem.output) return bcrypto.sha256(o.redeem.output); + }); + lazy.prop(o, 'output', () => { + if (!o.hash) return; + return bscript.compile([OPS.OP_0, o.hash]); + }); + lazy.prop(o, 'redeem', () => { + if (!a.witness) return; + return { + output: a.witness[a.witness.length - 1], + input: EMPTY_BUFFER, + witness: a.witness.slice(0, -1), + }; + }); + lazy.prop(o, 'input', () => { + if (!o.witness) return; + return EMPTY_BUFFER; + }); + lazy.prop(o, 'witness', () => { + // transform redeem input to witness stack? + if ( + a.redeem && + a.redeem.input && + a.redeem.input.length > 0 && + a.redeem.output && + a.redeem.output.length > 0 + ) { + const stack = bscript.toStack(_rchunks()); + // assign, and blank the existing input + o.redeem = Object.assign({ witness: stack }, a.redeem); + o.redeem.input = EMPTY_BUFFER; + return [].concat(stack, a.redeem.output); + } + if (!a.redeem) return; + if (!a.redeem.output) return; + if (!a.redeem.witness) return; + return [].concat(a.redeem.witness, a.redeem.output); + }); + lazy.prop(o, 'name', () => { + const nameParts = ['p2wsh']; + if (o.redeem !== undefined && o.redeem.name !== undefined) + nameParts.push(o.redeem.name); + return nameParts.join('-'); + }); + // extended validation + if (opts.validate) { + let hash = Buffer.from([]); + if (a.address) { + if (_address().prefix !== network.bech32) + throw new TypeError('Invalid prefix or Network mismatch'); + if (_address().version !== 0x00) + throw new TypeError('Invalid address version'); + if (_address().data.length !== 32) + throw new TypeError('Invalid address data'); + hash = _address().data; + } + if (a.hash) { + if (hash.length > 0 && !hash.equals(a.hash)) + throw new TypeError('Hash mismatch'); + else hash = a.hash; + } + if (a.output) { + if ( + a.output.length !== 34 || + a.output[0] !== OPS.OP_0 || + a.output[1] !== 0x20 + ) + throw new TypeError('Output is invalid'); + const hash2 = a.output.slice(2); + if (hash.length > 0 && !hash.equals(hash2)) + throw new TypeError('Hash mismatch'); + else hash = hash2; + } + if (a.redeem) { + if (a.redeem.network && a.redeem.network !== network) + throw new TypeError('Network mismatch'); + // is there two redeem sources? + if ( + a.redeem.input && + a.redeem.input.length > 0 && + a.redeem.witness && + a.redeem.witness.length > 0 + ) + throw new TypeError('Ambiguous witness source'); + // is the redeem output non-empty/valid? + if (a.redeem.output) { + 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)) + throw new TypeError('Hash mismatch'); + else hash = hash2; + } + if (a.redeem.input && !bscript.isPushOnly(_rchunks())) + throw new TypeError('Non push-only scriptSig'); + if ( + a.witness && + a.redeem.witness && + !stacksEqual(a.witness, a.redeem.witness) + ) + throw new TypeError('Witness and redeem.witness mismatch'); + if ( + (a.redeem.input && _rchunks().some(chunkHasUncompressedPubkey)) || + (a.redeem.output && + (bscript.decompile(a.redeem.output) || []).some( + chunkHasUncompressedPubkey, + )) + ) { + throw new TypeError( + 'redeem.input or redeem.output contains uncompressed pubkey', + ); + } + } + if (a.witness && a.witness.length > 0) { + const wScript = a.witness[a.witness.length - 1]; + if (a.redeem && a.redeem.output && !a.redeem.output.equals(wScript)) + throw new TypeError('Witness and redeem.output mismatch'); + if ( + a.witness.some(chunkHasUncompressedPubkey) || + (bscript.decompile(wScript) || []).some(chunkHasUncompressedPubkey) + ) + throw new TypeError('Witness contains uncompressed pubkey'); + } + } + return Object.assign(o, a); +} diff --git a/src/esm/psbt.js b/src/esm/psbt.js new file mode 100644 index 000000000..1167257b9 --- /dev/null +++ b/src/esm/psbt.js @@ -0,0 +1,1715 @@ +import { Psbt as PsbtBase } from 'bip174'; +import * as varuint from 'varuint-bitcoin'; +import { checkForInput, checkForOutput } from 'bip174/src/lib/utils'; +import { fromOutputScript, toOutputScript } from './address'; +import { cloneBuffer, reverseBuffer } from './bufferutils'; +import { bitcoin as btcNetwork } from './networks'; +import * as payments from './payments'; +import { tapleafHash } from './payments/bip341'; +import * as bscript from './script'; +import { Transaction } from './transaction'; +import { + toXOnly, + tapScriptFinalizer, + serializeTaprootSignature, + isTaprootInput, + checkTaprootInputFields, + checkTaprootOutputFields, + checkTaprootInputForSigs, +} from './psbt/bip371'; +import { + witnessStackToScriptWitness, + checkInputForSig, + pubkeyInScript, + isP2MS, + isP2PK, + isP2PKH, + isP2WPKH, + isP2WSHScript, + isP2SHScript, + isP2TR, +} from './psbt/psbtutils'; +/** + * These are the default arguments for a Psbt instance. + */ +const DEFAULT_OPTS = { + /** + * A bitcoinjs Network object. This is only used if you pass an `address` + * parameter to addOutput. Otherwise it is not needed and can be left default. + */ + network: btcNetwork, + /** + * When extractTransaction is called, the fee rate is checked. + * THIS IS NOT TO BE RELIED ON. + * It is only here as a last ditch effort to prevent sending a 500 BTC fee etc. + */ + maximumFeeRate: 5000, // satoshi per byte +}; +/** + * 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) + * + * Creator: This can be done with `new Psbt()` + * + * Updater: This can be done with `psbt.addInput(input)`, `psbt.addInputs(inputs)`, + * `psbt.addOutput(output)`, `psbt.addOutputs(outputs)` when you are looking to + * add new inputs and outputs to the PSBT, and `psbt.updateGlobal(itemObject)`, + * `psbt.updateInput(itemObject)`, `psbt.updateOutput(itemObject)` + * addInput requires hash: Buffer | string; and index: number; as attributes + * and can also include any attributes that are used in updateInput method. + * addOutput requires script: Buffer; and value: number; and likewise can include + * data for updateOutput. + * For a list of what attributes should be what types. Check the bip174 library. + * Also, check the integration tests for some examples of usage. + * + * Signer: There are a few methods. signAllInputs and signAllInputsAsync, which will search all input + * information for your pubkey or pubkeyhash, and only sign inputs where it finds + * your info. Or you can explicitly sign a specific input with signInput and + * signInputAsync. For the async methods you can create a SignerAsync object + * and use something like a hardware wallet to sign with. (You must implement this) + * + * Combiner: psbts can be combined easily with `psbt.combine(psbt2, psbt3, psbt4 ...)` + * the psbt calling combine will always have precedence when a conflict occurs. + * Combine checks if the internal bitcoin transaction is the same, so be sure that + * all sequences, version, locktime, etc. are the same before combining. + * + * Input Finalizer: This role is fairly important. Not only does it need to construct + * the input scriptSigs and witnesses, but it SHOULD verify the signatures etc. + * Before running `psbt.finalizeAllInputs()` please run `psbt.validateSignaturesOfAllInputs()` + * Running any finalize method will delete any data in the input(s) that are no longer + * needed due to the finalized scripts containing the information. + * + * Transaction Extractor: This role will perform some checks before returning a + * Transaction object. Such as fee rate not being larger than maximumFeeRate etc. + */ +export class Psbt { + data; + 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 = PsbtBase.fromBuffer(buffer, transactionFromBuffer); + const psbt = new Psbt(opts, psbtBase); + checkTxForDupeIns(psbt.__CACHE.__TX, psbt.__CACHE); + return psbt; + } + __CACHE; + opts; + constructor(opts = {}, data = new PsbtBase(new PsbtTransaction())) { + this.data = data; + // set defaults + this.opts = Object.assign({}, DEFAULT_OPTS, opts); + this.__CACHE = { + __NON_WITNESS_UTXO_TX_CACHE: [], + __NON_WITNESS_UTXO_BUF_CACHE: [], + __TX_IN_CACHE: {}, + __TX: this.data.globalMap.unsignedTx.tx, + // Psbt's predecessor (TransactionBuilder - now removed) behavior + // was to not confirm input values before signing. + // Even though we highly encourage people to get + // the full parent transaction to verify values, the ability to + // sign non-segwit inputs without the full transaction was often + // requested. So the only way to activate is to use @ts-ignore. + // We will disable exporting the Psbt when unsafe sign is active. + // because it is not BIP174 compliant. + __UNSAFE_SIGN_NONSEGWIT: false, + }; + if (this.data.inputs.length === 0) this.setVersion(2); + // Make data hidden when enumerating + const dpew = (obj, attr, enumerable, writable) => + Object.defineProperty(obj, attr, { + enumerable, + writable, + }); + dpew(this, '__CACHE', false, true); + dpew(this, 'opts', false, true); + } + get inputCount() { + return this.data.inputs.length; + } + get version() { + return this.__CACHE.__TX.version; + } + set version(version) { + this.setVersion(version); + } + get locktime() { + return this.__CACHE.__TX.locktime; + } + set locktime(locktime) { + this.setLocktime(locktime); + } + get txInputs() { + return this.__CACHE.__TX.ins.map(input => ({ + hash: cloneBuffer(input.hash), + index: input.index, + sequence: input.sequence, + })); + } + get txOutputs() { + return this.__CACHE.__TX.outs.map(output => { + let address; + try { + address = fromOutputScript(output.script, this.opts.network); + } catch (_) {} + return { + script: cloneBuffer(output.script), + value: output.value, + address, + }; + }); + } + combine(...those) { + this.data.combine(...those.map(o => o.data)); + return this; + } + clone() { + // TODO: more efficient cloning + const res = Psbt.fromBuffer(this.data.toBuffer()); + res.opts = JSON.parse(JSON.stringify(this.opts)); + return res; + } + setMaximumFeeRate(satoshiPerByte) { + check32Bit(satoshiPerByte); // 42.9 BTC per byte IS excessive... so throw + this.opts.maximumFeeRate = satoshiPerByte; + } + setVersion(version) { + check32Bit(version); + checkInputsForPartialSig(this.data.inputs, 'setVersion'); + const c = this.__CACHE; + c.__TX.version = version; + c.__EXTRACTED_TX = undefined; + return this; + } + setLocktime(locktime) { + check32Bit(locktime); + checkInputsForPartialSig(this.data.inputs, 'setLocktime'); + const c = this.__CACHE; + c.__TX.locktime = locktime; + c.__EXTRACTED_TX = undefined; + return this; + } + setInputSequence(inputIndex, sequence) { + check32Bit(sequence); + checkInputsForPartialSig(this.data.inputs, 'setInputSequence'); + const c = this.__CACHE; + if (c.__TX.ins.length <= inputIndex) { + throw new Error('Input index too high'); + } + c.__TX.ins[inputIndex].sequence = sequence; + c.__EXTRACTED_TX = undefined; + return this; + } + addInputs(inputDatas) { + inputDatas.forEach(inputData => this.addInput(inputData)); + return this; + } + addInput(inputData) { + if ( + arguments.length > 1 || + !inputData || + inputData.hash === undefined || + inputData.index === undefined + ) { + throw new Error( + `Invalid arguments for Psbt.addInput. ` + + `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; + this.data.addInput(inputData); + const txIn = c.__TX.ins[c.__TX.ins.length - 1]; + checkTxInputCache(c, txIn); + const inputIndex = this.data.inputs.length - 1; + const input = this.data.inputs[inputIndex]; + if (input.nonWitnessUtxo) { + addNonWitnessTxCache(this.__CACHE, input, inputIndex); + } + c.__FEE = undefined; + c.__FEE_RATE = undefined; + c.__EXTRACTED_TX = undefined; + return this; + } + addOutputs(outputDatas) { + outputDatas.forEach(outputData => this.addOutput(outputData)); + return this; + } + addOutput(outputData) { + if ( + arguments.length > 1 || + !outputData || + outputData.value === undefined || + (outputData.address === undefined && outputData.script === undefined) + ) { + throw new Error( + `Invalid arguments for Psbt.addOutput. ` + + `Requires single object with at least [script or address] and [value]`, + ); + } + checkInputsForPartialSig(this.data.inputs, 'addOutput'); + const { address } = outputData; + if (typeof address === 'string') { + const { network } = this.opts; + const script = toOutputScript(address, network); + outputData = Object.assign({}, outputData, { script }); + } + checkTaprootOutputFields(outputData, outputData, 'addOutput'); + const c = this.__CACHE; + this.data.addOutput(outputData); + c.__FEE = undefined; + c.__FEE_RATE = undefined; + c.__EXTRACTED_TX = undefined; + return this; + } + extractTransaction(disableFeeCheck) { + if (!this.data.inputs.every(isFinalized)) throw new Error('Not finalized'); + const c = this.__CACHE; + if (!disableFeeCheck) { + checkFees(this, c, this.opts); + } + if (c.__EXTRACTED_TX) return c.__EXTRACTED_TX; + const tx = c.__TX.clone(); + inputFinalizeGetAmts(this.data.inputs, tx, c, true); + return tx; + } + getFeeRate() { + return getTxCacheValue( + '__FEE_RATE', + 'fee rate', + this.data.inputs, + this.__CACHE, + ); + } + getFee() { + return getTxCacheValue('__FEE', 'fee', this.data.inputs, this.__CACHE); + } + finalizeAllInputs() { + checkForInput(this.data.inputs, 0); // making sure we have at least one + range(this.data.inputs.length).forEach(idx => this.finalizeInput(idx)); + return this; + } + finalizeInput(inputIndex, finalScriptsFunc) { + const input = checkForInput(this.data.inputs, inputIndex); + if (isTaprootInput(input)) + return this._finalizeTaprootInput( + inputIndex, + input, + undefined, + finalScriptsFunc, + ); + return this._finalizeInput(inputIndex, input, finalScriptsFunc); + } + finalizeTaprootInput( + inputIndex, + tapLeafHashToFinalize, + finalScriptsFunc = tapScriptFinalizer, + ) { + 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.`); + } + _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( + inputIndex, + input, + script, + isSegwit, + isP2SH, + isP2WSH, + ); + if (finalScriptSig) this.data.updateInput(inputIndex, { finalScriptSig }); + 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 = 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 = 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 = checkForInput(this.data.inputs, inputIndex); + const script = getScriptFromUtxo(inputIndex, input, this.__CACHE); + const result = getMeaningfulScript( + script, + inputIndex, + 'input', + input.redeemScript || redeemFromFinalScriptSig(input.finalScriptSig), + input.witnessScript || + redeemFromFinalWitnessScript(input.finalScriptWitness), + ); + const type = result.type === 'raw' ? '' : result.type + '-'; + const mainType = classifyScript(result.meaningfulScript); + return type + mainType; + } + inputHasPubkey(inputIndex, pubkey) { + const input = checkForInput(this.data.inputs, inputIndex); + return pubkeyInInput(pubkey, input, inputIndex, this.__CACHE); + } + inputHasHDKey(inputIndex, root) { + const input = checkForInput(this.data.inputs, inputIndex); + const derivationIsMine = bip32DerivationIsMine(root); + return ( + !!input.bip32Derivation && input.bip32Derivation.some(derivationIsMine) + ); + } + outputHasPubkey(outputIndex, pubkey) { + const output = checkForOutput(this.data.outputs, outputIndex); + return pubkeyInOutput(pubkey, output, outputIndex, this.__CACHE); + } + outputHasHDKey(outputIndex, root) { + const output = checkForOutput(this.data.outputs, outputIndex); + const derivationIsMine = bip32DerivationIsMine(root); + return ( + !!output.bip32Derivation && output.bip32Derivation.some(derivationIsMine) + ); + } + validateSignaturesOfAllInputs(validator) { + checkForInput(this.data.inputs, 0); // making sure we have at least one + const results = range(this.data.inputs.length).map(idx => + this.validateSignaturesOfInput(idx, validator), + ); + return results.reduce((final, res) => res === true && final, true); + } + validateSignaturesOfInput(inputIndex, validator, pubkey) { + const input = this.data.inputs[inputIndex]; + if (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) + throw new Error('No signatures to validate'); + if (typeof validator !== 'function') + throw new Error('Need validator function to validate signatures'); + const mySigs = pubkey + ? partialSig.filter(sig => sig.pubkey.equals(pubkey)) + : partialSig; + if (mySigs.length < 1) throw new Error('No signatures for this pubkey'); + const results = []; + let hashCache; + let scriptCache; + let sighashCache; + for (const pSig of mySigs) { + const sig = bscript.signature.decode(pSig.signature); + const { hash, script } = + sighashCache !== sig.hashType + ? getHashForSig( + inputIndex, + Object.assign({}, input, { sighashType: sig.hashType }), + this.__CACHE, + true, + ) + : { hash: hashCache, script: scriptCache }; + sighashCache = sig.hashType; + hashCache = hash; + scriptCache = script; + checkScriptForPubkey(pSig.pubkey, script, 'verify'); + results.push(validator(pSig.pubkey, hash, sig.signature)); + } + 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 && 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); + let validationResultCount = 0; + if (tapKeySig && tapKeyHash) { + const isValidTapkeySig = validator( + tapKeyHash.pubkey, + tapKeyHash.hash, + trimTaprootSig(tapKeySig), + ); + if (!isValidTapkeySig) return false; + validationResultCount++; + } + 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, + trimTaprootSig(tapSig.signature), + ); + if (!isValidTapScriptSig) return false; + validationResultCount++; + } + } + } + return validationResultCount > 0; + } + signAllInputsHD(hdKeyPair, sighashTypes = [Transaction.SIGHASH_ALL]) { + if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) { + throw new Error('Need HDSigner to sign input'); + } + const results = []; + for (const i of range(this.data.inputs.length)) { + try { + this.signInputHD(i, hdKeyPair, sighashTypes); + results.push(true); + } catch (err) { + results.push(false); + } + } + if (results.every(v => v === false)) { + throw new Error('No inputs were signed'); + } + return this; + } + signAllInputsHDAsync(hdKeyPair, sighashTypes = [Transaction.SIGHASH_ALL]) { + return new Promise((resolve, reject) => { + if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) { + return reject(new Error('Need HDSigner to sign input')); + } + const results = []; + const promises = []; + 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')); + } + resolve(); + }); + }); + } + signInputHD(inputIndex, hdKeyPair, sighashTypes = [Transaction.SIGHASH_ALL]) { + if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) { + throw new Error('Need HDSigner to sign input'); + } + const signers = getSignersFromHD(inputIndex, this.data.inputs, hdKeyPair); + signers.forEach(signer => this.signInput(inputIndex, signer, sighashTypes)); + return this; + } + signInputHDAsync( + inputIndex, + hdKeyPair, + sighashTypes = [Transaction.SIGHASH_ALL], + ) { + return new Promise((resolve, reject) => { + 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, sighashTypes) { + if (!keyPair || !keyPair.publicKey) + throw new Error('Need Signer to sign input'); + // TODO: Add a pubkey/pubkeyhash cache to each input + // as input information is added, then eventually + // optimize this method. + const results = []; + for (const i of range(this.data.inputs.length)) { + try { + this.signInput(i, keyPair, sighashTypes); + results.push(true); + } catch (err) { + results.push(false); + } + } + if (results.every(v => v === false)) { + throw new Error('No inputs were signed'); + } + return this; + } + signAllInputsAsync(keyPair, sighashTypes) { + return new Promise((resolve, reject) => { + 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 = []; + const promises = []; + 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')); + } + resolve(); + }); + }); + } + signInput(inputIndex, keyPair, sighashTypes) { + 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, keyPair, tapLeafHashToSign, sighashTypes) { + 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.`); + } + _signInput(inputIndex, keyPair, sighashTypes = [Transaction.SIGHASH_ALL]) { + const { hash, sighashType } = getHashAndSighashType( + this.data.inputs, + inputIndex, + keyPair.publicKey, + this.__CACHE, + sighashTypes, + ); + const partialSig = [ + { + pubkey: keyPair.publicKey, + signature: bscript.signature.encode(keyPair.sign(hash), sighashType), + }, + ]; + this.data.updateInput(inputIndex, { partialSig }); + return this; + } + _signTaprootInput( + inputIndex, + input, + keyPair, + tapLeafHashToSign, + allowedSighashTypes = [Transaction.SIGHASH_DEFAULT], + ) { + const hashesForSig = this.checkTaprootHashesForSig( + inputIndex, + input, + keyPair, + tapLeafHashToSign, + allowedSighashTypes, + ); + const tapKeySig = hashesForSig + .filter(h => !h.leafHash) + .map(h => + serializeTaprootSignature( + keyPair.signSchnorr(h.hash), + input.sighashType, + ), + )[0]; + const tapScriptSig = hashesForSig + .filter(h => !!h.leafHash) + .map(h => ({ + pubkey: toXOnly(keyPair.publicKey), + signature: 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 = checkForInput(this.data.inputs, inputIndex); + if (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 = 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.`); + }); + } + _signInputAsync( + inputIndex, + keyPair, + sighashTypes = [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(signature, sighashType), + }, + ]; + this.data.updateInput(inputIndex, { partialSig }); + }); + } + async _signTaprootInputAsync( + inputIndex, + input, + keyPair, + tapLeafHash, + sighashTypes = [Transaction.SIGHASH_DEFAULT], + ) { + 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: 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, + }, + ]; + return { tapScriptSig }; + }, + ); + }); + 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(); + } + toHex() { + checkCache(this.__CACHE); + return this.data.toHex(); + } + toBase64() { + checkCache(this.__CACHE); + return this.data.toBase64(); + } + updateGlobal(updateData) { + this.data.updateGlobal(updateData); + return this; + } + updateInput(inputIndex, updateData) { + if (updateData.witnessScript) checkInvalidP2WSH(updateData.witnessScript); + checkTaprootInputFields( + this.data.inputs[inputIndex], + updateData, + 'updateInput', + ); + this.data.updateInput(inputIndex, updateData); + if (updateData.nonWitnessUtxo) { + addNonWitnessTxCache( + this.__CACHE, + this.data.inputs[inputIndex], + inputIndex, + ); + } + return this; + } + updateOutput(outputIndex, updateData) { + const outputData = this.data.outputs[outputIndex]; + checkTaprootOutputFields(outputData, updateData, 'updateOutput'); + this.data.updateOutput(outputIndex, updateData); + return this; + } + addUnknownKeyValToGlobal(keyVal) { + this.data.addUnknownKeyValToGlobal(keyVal); + return this; + } + addUnknownKeyValToInput(inputIndex, keyVal) { + this.data.addUnknownKeyValToInput(inputIndex, keyVal); + return this; + } + addUnknownKeyValToOutput(outputIndex, keyVal) { + this.data.addUnknownKeyValToOutput(outputIndex, keyVal); + return this; + } + clearFinalizedInput(inputIndex) { + this.data.clearFinalizedInput(inputIndex); + return this; + } +} +/** + * 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 + * Transaction (From the bip174 library) interface. + */ +const transactionFromBuffer = buffer => new PsbtTransaction(buffer); +/** + * This class implements the Transaction interface from bip174 library. + * It contains a bitcoinjs-lib Transaction object. + */ +class PsbtTransaction { + tx; + constructor(buffer = Buffer.from([2, 0, 0, 0, 0, 0, 0, 0, 0, 0])) { + this.tx = Transaction.fromBuffer(buffer); + checkTxEmpty(this.tx); + Object.defineProperty(this, 'tx', { + enumerable: false, + writable: true, + }); + } + getInputOutputCounts() { + return { + inputCount: this.tx.ins.length, + outputCount: this.tx.outs.length, + }; + } + addInput(input) { + if ( + input.hash === undefined || + input.index === undefined || + (!Buffer.isBuffer(input.hash) && typeof input.hash !== 'string') || + typeof input.index !== 'number' + ) { + throw new Error('Error adding input.'); + } + const hash = + typeof input.hash === 'string' + ? reverseBuffer(Buffer.from(input.hash, 'hex')) + : input.hash; + this.tx.addInput(hash, input.index, input.sequence); + } + addOutput(output) { + if ( + output.script === undefined || + output.value === undefined || + !Buffer.isBuffer(output.script) || + typeof output.value !== 'number' + ) { + throw new Error('Error adding output.'); + } + this.tx.addOutput(output.script, output.value); + } + toBuffer() { + return this.tx.toBuffer(); + } +} +function canFinalize(input, script, scriptType) { + switch (scriptType) { + case 'pubkey': + case 'pubkeyhash': + case 'witnesspubkeyhash': + return hasSigs(1, input.partialSig); + case 'multisig': + const p2ms = payments.p2ms({ output: script }); + return hasSigs(p2ms.m, input.partialSig, p2ms.pubkeys); + default: + return false; + } +} +function checkCache(cache) { + if (cache.__UNSAFE_SIGN_NONSEGWIT !== false) { + throw new Error('Not BIP174 compliant, can not export'); + } +} +function hasSigs(neededSigs, partialSig, pubkeys) { + if (!partialSig) return false; + let sigs; + if (pubkeys) { + sigs = pubkeys + .map(pkey => { + const pubkey = compressPubkey(pkey); + return partialSig.find(pSig => pSig.pubkey.equals(pubkey)); + }) + .filter(v => !!v); + } else { + sigs = partialSig; + } + if (sigs.length > neededSigs) throw new Error('Too many signatures'); + return sigs.length === neededSigs; +} +function isFinalized(input) { + return !!input.finalScriptSig || !!input.finalScriptWitness; +} +function bip32DerivationIsMine(root) { + return d => { + if (!d.masterFingerprint.equals(root.fingerprint)) return false; + if (!root.derivePath(d.path).publicKey.equals(d.pubkey)) return false; + return true; + }; +} +function check32Bit(num) { + if ( + typeof num !== 'number' || + num !== Math.floor(num) || + num > 0xffffffff || + num < 0 + ) { + throw new Error('Invalid 32 bit integer'); + } +} +function checkFees(psbt, cache, opts) { + const feeRate = cache.__FEE_RATE || psbt.getFeeRate(); + const vsize = cache.__EXTRACTED_TX.virtualSize(); + const satoshis = feeRate * vsize; + if (feeRate >= opts.maximumFeeRate) { + throw new Error( + `Warning: You are paying around ${(satoshis / 1e8).toFixed(8)} in ` + + `fees, which is ${feeRate} satoshi per byte for a transaction ` + + `with a VSize of ${vsize} bytes (segwit counted as 0.25 byte per ` + + `byte). Use setMaximumFeeRate method to raise your threshold, or ` + + `pass true to the first arg of extractTransaction.`, + ); + } +} +function checkInputsForPartialSig(inputs, action) { + inputs.forEach(input => { + const throws = isTaprootInput(input) + ? checkTaprootInputForSigs(input, action) + : checkInputForSig(input, action); + if (throws) + throw new Error('Can not modify transaction, signatures exist.'); + }); +} +function checkPartialSigSighashes(input) { + if (!input.sighashType || !input.partialSig) return; + const { partialSig, sighashType } = input; + partialSig.forEach(pSig => { + const { hashType } = bscript.signature.decode(pSig.signature); + if (sighashType !== hashType) { + throw new Error('Signature sighash does not match input sighash type'); + } + }); +} +function checkScriptForPubkey(pubkey, script, action) { + if (!pubkeyInScript(pubkey, script)) { + throw new Error( + `Can not ${action} for this input with the key ${pubkey.toString('hex')}`, + ); + } +} +function checkTxEmpty(tx) { + const isEmpty = tx.ins.every( + input => + input.script && + input.script.length === 0 && + input.witness && + input.witness.length === 0, + ); + if (!isEmpty) { + throw new Error('Format Error: Transaction ScriptSigs are not empty'); + } +} +function checkTxForDupeIns(tx, cache) { + tx.ins.forEach(input => { + checkTxInputCache(cache, input); + }); +} +function checkTxInputCache(cache, input) { + const key = + reverseBuffer(Buffer.from(input.hash)).toString('hex') + ':' + input.index; + if (cache.__TX_IN_CACHE[key]) throw new Error('Duplicate input detected.'); + cache.__TX_IN_CACHE[key] = 1; +} +function scriptCheckerFactory(payment, paymentScriptName) { + return (inputIndex, scriptPubKey, redeemScript, ioType) => { + const redeemScriptOutput = payment({ + redeem: { output: redeemScript }, + }).output; + if (!scriptPubKey.equals(redeemScriptOutput)) { + throw new Error( + `${paymentScriptName} for ${ioType} #${inputIndex} doesn't match the scriptPubKey in the prevout`, + ); + } + }; +} +const checkRedeemScript = scriptCheckerFactory(payments.p2sh, 'Redeem script'); +const checkWitnessScript = scriptCheckerFactory( + payments.p2wsh, + 'Witness script', +); +function getTxCacheValue(key, name, inputs, c) { + if (!inputs.every(isFinalized)) + throw new Error(`PSBT must be finalized to calculate ${name}`); + if (key === '__FEE_RATE' && c.__FEE_RATE) return c.__FEE_RATE; + if (key === '__FEE' && c.__FEE) return c.__FEE; + let tx; + let mustFinalize = true; + if (c.__EXTRACTED_TX) { + tx = c.__EXTRACTED_TX; + mustFinalize = false; + } else { + tx = c.__TX.clone(); + } + inputFinalizeGetAmts(inputs, tx, c, mustFinalize); + 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); + if (!canFinalize(input, script, scriptType)) + throw new Error(`Can not finalize input #${inputIndex}`); + return prepareFinalScripts( + script, + scriptType, + input.partialSig, + isSegwit, + isP2SH, + isP2WSH, + ); +} +function prepareFinalScripts( + script, + scriptType, + partialSig, + isSegwit, + isP2SH, + isP2WSH, +) { + let finalScriptSig; + let finalScriptWitness; + // Wow, the payments API is very handy + const payment = getPayment(script, scriptType, partialSig); + const p2wsh = !isP2WSH ? null : payments.p2wsh({ redeem: payment }); + const p2sh = !isP2SH ? null : payments.p2sh({ redeem: p2wsh || payment }); + if (isSegwit) { + if (p2wsh) { + finalScriptWitness = witnessStackToScriptWitness(p2wsh.witness); + } else { + finalScriptWitness = witnessStackToScriptWitness(payment.witness); + } + if (p2sh) { + finalScriptSig = p2sh.input; + } + } else { + if (p2sh) { + finalScriptSig = p2sh.input; + } else { + finalScriptSig = payment.input; + } + } + return { + finalScriptSig, + finalScriptWitness, + }; +} +function getHashAndSighashType( + inputs, + inputIndex, + pubkey, + cache, + sighashTypes, +) { + const input = checkForInput(inputs, inputIndex); + const { hash, sighashType, script } = getHashForSig( + inputIndex, + input, + cache, + false, + sighashTypes, + ); + checkScriptForPubkey(pubkey, script, 'sign'); + return { + hash, + sighashType, + }; +} +function getHashForSig(inputIndex, input, cache, forValidate, sighashTypes) { + const unsignedTx = cache.__TX; + const sighashType = input.sighashType || Transaction.SIGHASH_ALL; + checkSighashTypeAllowed(sighashType, sighashTypes); + let hash; + let prevout; + if (input.nonWitnessUtxo) { + const nonWitnessUtxoTx = nonWitnessUtxoTxFromCache( + cache, + input, + inputIndex, + ); + const prevoutHash = unsignedTx.ins[inputIndex].hash; + const utxoHash = nonWitnessUtxoTx.getHash(); + // If a non-witness UTXO is provided, its hash must match the hash specified in the prevout + if (!prevoutHash.equals(utxoHash)) { + throw new Error( + `Non-witness UTXO hash for input #${inputIndex} doesn't match the hash specified in the prevout`, + ); + } + const prevoutIndex = unsignedTx.ins[inputIndex].index; + prevout = nonWitnessUtxoTx.outs[prevoutIndex]; + } else if (input.witnessUtxo) { + prevout = input.witnessUtxo; + } else { + throw new Error('Need a Utxo input item for signing'); + } + const { meaningfulScript, type } = getMeaningfulScript( + prevout.script, + inputIndex, + 'input', + input.redeemScript, + input.witnessScript, + ); + if (['p2sh-p2wsh', 'p2wsh'].indexOf(type) >= 0) { + hash = unsignedTx.hashForWitnessV0( + inputIndex, + meaningfulScript, + prevout.value, + sighashType, + ); + } else if (isP2WPKH(meaningfulScript)) { + // P2WPKH uses the P2PKH template for prevoutScript when signing + const signingScript = payments.p2pkh({ + hash: meaningfulScript.slice(2), + }).output; + hash = unsignedTx.hashForWitnessV0( + inputIndex, + signingScript, + prevout.value, + sighashType, + ); + } else { + // non-segwit + if ( + input.nonWitnessUtxo === undefined && + cache.__UNSAFE_SIGN_NONSEGWIT === false + ) + throw new Error( + `Input #${inputIndex} has witnessUtxo but non-segwit script: ` + + `${meaningfulScript.toString('hex')}`, + ); + if (!forValidate && cache.__UNSAFE_SIGN_NONSEGWIT !== false) + console.warn( + 'Warning: Signing non-segwit inputs without the full parent transaction ' + + 'means there is a chance that a miner could feed you incorrect information ' + + "to trick you into paying large fees. This behavior is the same as Psbt's predecessor " + + '(TransactionBuilder - now removed) when signing non-segwit scripts. You are not ' + + 'able to export this Psbt with toBuffer|toBase64|toHex since it is not ' + + 'BIP174 compliant.\n*********************\nPROCEED WITH CAUTION!\n' + + '*********************', + ); + hash = unsignedTx.hashForSignature( + inputIndex, + meaningfulScript, + sighashType, + ); + } + return { + script: meaningfulScript, + sighashType, + hash, + }; +} +function getAllTaprootHashesForSig(inputIndex, input, inputs, cache) { + const allPublicKeys = []; + if (input.tapInternalKey) { + const key = getPrevoutTaprootKey(inputIndex, input, cache); + if (key) { + allPublicKeys.push(key); + } + } + 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 getPrevoutTaprootKey(inputIndex, input, cache) { + const { script } = getScriptAndAmountFromUtxo(inputIndex, input, cache); + return isP2TR(script) ? script.subarray(2, 34) : null; +} +function trimTaprootSig(signature) { + return signature.length === 64 ? signature : signature.subarray(0, 64); +} +function getTaprootHashesForSig( + inputIndex, + input, + inputs, + pubkey, + cache, + tapLeafHashToSign, + allowedSighashTypes, +) { + const unsignedTx = cache.__TX; + const sighashType = input.sighashType || 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 = + getPrevoutTaprootKey(inputIndex, input, cache) || Buffer.from([]); + 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, + sighashType, + 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) { + case 'multisig': + const sigs = getSortedSigs(script, partialSig); + payment = payments.p2ms({ + output: script, + signatures: sigs, + }); + break; + case 'pubkey': + payment = payments.p2pk({ + output: script, + signature: partialSig[0].signature, + }); + break; + case 'pubkeyhash': + payment = payments.p2pkh({ + output: script, + pubkey: partialSig[0].pubkey, + signature: partialSig[0].signature, + }); + break; + case 'witnesspubkeyhash': + payment = payments.p2wpkh({ + output: script, + pubkey: partialSig[0].pubkey, + signature: partialSig[0].signature, + }); + break; + } + return payment; +} +function getScriptFromInput(inputIndex, input, cache) { + const unsignedTx = cache.__TX; + const res = { + script: null, + isSegwit: false, + isP2SH: false, + isP2WSH: false, + }; + res.isP2SH = !!input.redeemScript; + res.isP2WSH = !!input.witnessScript; + 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; + } + } + if (input.witnessScript || isP2WPKH(res.script)) { + res.isSegwit = true; + } + return res; +} +function getSignersFromHD(inputIndex, inputs, hdKeyPair) { + const input = checkForInput(inputs, inputIndex); + if (!input.bip32Derivation || input.bip32Derivation.length === 0) { + throw new Error('Need bip32Derivation to sign with HD'); + } + const myDerivations = input.bip32Derivation + .map(bipDv => { + if (bipDv.masterFingerprint.equals(hdKeyPair.fingerprint)) { + return bipDv; + } else { + return; + } + }) + .filter(v => !!v); + if (myDerivations.length === 0) { + throw new Error( + 'Need one bip32Derivation masterFingerprint to match the HDSigner fingerprint', + ); + } + const signers = myDerivations.map(bipDv => { + const node = hdKeyPair.derivePath(bipDv.path); + if (!bipDv.pubkey.equals(node.publicKey)) { + throw new Error('pubkey did not match bip32Derivation'); + } + return node; + }); + return signers; +} +function getSortedSigs(script, partialSig) { + const p2ms = payments.p2ms({ output: script }); + // for each pubkey in order of p2ms script + return p2ms.pubkeys + .map(pk => { + // filter partialSig array by pubkey being equal + return ( + partialSig.filter(ps => { + return ps.pubkey.equals(pk); + })[0] || {} + ).signature; + // Any pubkey without a match will return undefined + // this last filter removes all the undefined items in the array. + }) + .filter(v => !!v); +} +function scriptWitnessToWitnessStack(buffer) { + let offset = 0; + function readSlice(n) { + offset += n; + return buffer.slice(offset - n, offset); + } + function readVarInt() { + const vi = varuint.decode(buffer, offset); + offset += varuint.encodingLength(vi.bigintValue); + return vi.numberValue; + } + function readVarSlice() { + return readSlice(readVarInt()); + } + function readVector() { + const count = readVarInt(); + const vector = []; + for (let i = 0; i < count; i++) vector.push(readVarSlice()); + return vector; + } + return readVector(); +} +function sighashTypeToString(sighashType) { + let text = + sighashType & Transaction.SIGHASH_ANYONECANPAY + ? 'SIGHASH_ANYONECANPAY | ' + : ''; + const sigMod = sighashType & 0x1f; + switch (sigMod) { + case Transaction.SIGHASH_ALL: + text += 'SIGHASH_ALL'; + break; + case Transaction.SIGHASH_SINGLE: + text += 'SIGHASH_SINGLE'; + break; + case Transaction.SIGHASH_NONE: + text += 'SIGHASH_NONE'; + break; + } + return text; +} +function addNonWitnessTxCache(cache, input, inputIndex) { + cache.__NON_WITNESS_UTXO_BUF_CACHE[inputIndex] = input.nonWitnessUtxo; + const tx = Transaction.fromBuffer(input.nonWitnessUtxo); + cache.__NON_WITNESS_UTXO_TX_CACHE[inputIndex] = tx; + const self = cache; + const selfIndex = inputIndex; + delete input.nonWitnessUtxo; + Object.defineProperty(input, 'nonWitnessUtxo', { + enumerable: true, + get() { + const buf = self.__NON_WITNESS_UTXO_BUF_CACHE[selfIndex]; + const txCache = self.__NON_WITNESS_UTXO_TX_CACHE[selfIndex]; + if (buf !== undefined) { + return buf; + } else { + const newBuf = txCache.toBuffer(); + self.__NON_WITNESS_UTXO_BUF_CACHE[selfIndex] = newBuf; + return newBuf; + } + }, + set(data) { + self.__NON_WITNESS_UTXO_BUF_CACHE[selfIndex] = data; + }, + }); +} +function inputFinalizeGetAmts(inputs, tx, cache, mustFinalize) { + let inputAmount = 0; + inputs.forEach((input, idx) => { + if (mustFinalize && input.finalScriptSig) + tx.ins[idx].script = input.finalScriptSig; + if (mustFinalize && input.finalScriptWitness) { + tx.ins[idx].witness = scriptWitnessToWitnessStack( + input.finalScriptWitness, + ); + } + if (input.witnessUtxo) { + inputAmount += input.witnessUtxo.value; + } else if (input.nonWitnessUtxo) { + const nwTx = nonWitnessUtxoTxFromCache(cache, input, idx); + const vout = tx.ins[idx].index; + const out = nwTx.outs[vout]; + inputAmount += out.value; + } + }); + const outputAmount = tx.outs.reduce((total, o) => total + o.value, 0); + const fee = inputAmount - outputAmount; + if (fee < 0) { + throw new Error('Outputs are spending more than Inputs'); + } + const bytes = tx.virtualSize(); + cache.__FEE = fee; + cache.__EXTRACTED_TX = tx; + cache.__FEE_RATE = Math.floor(fee / bytes); +} +function nonWitnessUtxoTxFromCache(cache, input, inputIndex) { + const c = cache.__NON_WITNESS_UTXO_TX_CACHE; + if (!c[inputIndex]) { + addNonWitnessTxCache(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 { + script: input.witnessUtxo.script, + value: input.witnessUtxo.value, + }; + } else if (input.nonWitnessUtxo !== undefined) { + const nonWitnessUtxoTx = nonWitnessUtxoTxFromCache( + cache, + input, + inputIndex, + ); + 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 { meaningfulScript } = getMeaningfulScript( + script, + inputIndex, + 'input', + input.redeemScript, + input.witnessScript, + ); + return pubkeyInScript(pubkey, meaningfulScript); +} +function pubkeyInOutput(pubkey, output, outputIndex, cache) { + const script = cache.__TX.outs[outputIndex].script; + const { meaningfulScript } = getMeaningfulScript( + script, + outputIndex, + 'output', + output.redeemScript, + output.witnessScript, + ); + return pubkeyInScript(pubkey, meaningfulScript); +} +function redeemFromFinalScriptSig(finalScript) { + if (!finalScript) return; + const decomp = bscript.decompile(finalScript); + if (!decomp) return; + const lastItem = decomp[decomp.length - 1]; + if ( + !Buffer.isBuffer(lastItem) || + isPubkeyLike(lastItem) || + isSigLike(lastItem) + ) + return; + const sDecomp = bscript.decompile(lastItem); + if (!sDecomp) return; + return lastItem; +} +function redeemFromFinalWitnessScript(finalScript) { + if (!finalScript) return; + const decomp = scriptWitnessToWitnessStack(finalScript); + const lastItem = decomp[decomp.length - 1]; + if (isPubkeyLike(lastItem)) return; + const sDecomp = bscript.decompile(lastItem); + if (!sDecomp) return; + return lastItem; +} +function compressPubkey(pubkey) { + if (pubkey.length === 65) { + const parity = pubkey[64] & 1; + const newKey = pubkey.slice(0, 33); + newKey[0] = 2 | parity; + return newKey; + } + return pubkey.slice(); +} +function isPubkeyLike(buf) { + return buf.length === 33 && bscript.isCanonicalPubKey(buf); +} +function isSigLike(buf) { + return bscript.isCanonicalScriptSignature(buf); +} +function getMeaningfulScript( + script, + index, + ioType, + redeemScript, + witnessScript, +) { + const isP2SH = isP2SHScript(script); + const isP2SHP2WSH = isP2SH && redeemScript && isP2WSHScript(redeemScript); + const isP2WSH = isP2WSHScript(script); + if (isP2SH && redeemScript === undefined) + throw new Error('scriptPubkey is P2SH but redeemScript missing'); + if ((isP2WSH || isP2SHP2WSH) && witnessScript === undefined) + throw new Error( + 'scriptPubkey or redeemScript is P2WSH but witnessScript missing', + ); + let meaningfulScript; + if (isP2SHP2WSH) { + meaningfulScript = witnessScript; + checkRedeemScript(index, script, redeemScript, ioType); + checkWitnessScript(index, redeemScript, witnessScript, ioType); + checkInvalidP2WSH(meaningfulScript); + } else if (isP2WSH) { + meaningfulScript = witnessScript; + checkWitnessScript(index, script, witnessScript, ioType); + checkInvalidP2WSH(meaningfulScript); + } else if (isP2SH) { + meaningfulScript = redeemScript; + checkRedeemScript(index, script, redeemScript, ioType); + } else { + meaningfulScript = script; + } + return { + meaningfulScript, + type: isP2SHP2WSH + ? 'p2sh-p2wsh' + : isP2SH + ? 'p2sh' + : isP2WSH + ? 'p2wsh' + : 'raw', + }; +} +function checkInvalidP2WSH(script) { + if (isP2WPKH(script) || isP2SHScript(script)) { + throw new Error('P2WPKH or P2SH can not be contained within P2WSH'); + } +} +function classifyScript(script) { + if (isP2WPKH(script)) return 'witnesspubkeyhash'; + if (isP2PKH(script)) return 'pubkeyhash'; + if (isP2MS(script)) return 'multisig'; + if (isP2PK(script)) return 'pubkey'; + return 'nonstandard'; +} +function range(n) { + return [...Array(n).keys()]; +} diff --git a/src/esm/psbt/bip371.js b/src/esm/psbt/bip371.js new file mode 100644 index 000000000..1e32299d6 --- /dev/null +++ b/src/esm/psbt/bip371.js @@ -0,0 +1,484 @@ +import { isTapleaf, isTaptree } from '../types'; +import { Transaction } from '../transaction'; +import { + witnessStackToScriptWitness, + pubkeyPositionInScript, + isP2TR, +} from './psbtutils'; +import { + tweakKey, + tapleafHash, + rootHashFromPath, + LEAF_VERSION_TAPSCRIPT, + MAX_TAPTREE_DEPTH, +} from '../payments/bip341'; +import { p2tr } from '../payments'; +import { signatureBlocksAction } from './psbtutils'; +/** + * Converts a public key to an X-only public key. + * @param pubKey The public key to convert. + * @returns The X-only public key. + */ +export const toXOnly = pubKey => + 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, 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: witnessStackToScriptWitness(witness) }; + } catch (err) { + throw new Error(`Can not finalize taproot input #${inputIndex}: ${err}`); + } +} +/** + * Serializes a taproot signature. + * @param sig The signature to serialize. + * @param sighashType The sighash type. Optional. + * @returns The serialized taproot signature. + */ +export function serializeTaprootSignature(sig, sighashType) { + const sighashTypeByte = sighashType + ? Buffer.from([sighashType]) + : Buffer.from([]); + return Buffer.concat([sig, sighashTypeByte]); +} +/** + * Checks if a PSBT input is a taproot input. + * @param input The PSBT input to check. + * @returns True if the input is a taproot input, false otherwise. + */ +export function isTaprootInput(input) { + return ( + input && + !!( + input.tapInternalKey || + input.tapMerkleRoot || + (input.tapLeafScript && input.tapLeafScript.length) || + (input.tapBip32Derivation && input.tapBip32Derivation.length) || + (input.witnessUtxo && isP2TR(input.witnessUtxo.script)) + ) + ); +} +/** + * Checks if a PSBT output is a taproot output. + * @param output The PSBT output to check. + * @param script The script to check. Optional. + * @returns True if the output is a taproot output, false otherwise. + */ +export function isTaprootOutput(output, script) { + return ( + output && + !!( + output.tapInternalKey || + output.tapTree || + (output.tapBip32Derivation && output.tapBip32Derivation.length) || + (script && isP2TR(script)) + ) + ); +} +/** + * Checks the taproot input fields for consistency. + * @param inputData The original input data. + * @param newInputData The new input data. + * @param action The action being performed. + * @throws Throws an error if the input fields are inconsistent. + */ +export function checkTaprootInputFields(inputData, newInputData, action) { + checkMixedTaprootAndNonTaprootInputFields(inputData, newInputData, action); + checkIfTapLeafInTree(inputData, newInputData, action); +} +/** + * Checks the taproot output fields for consistency. + * @param outputData The original output data. + * @param newOutputData The new output data. + * @param action The action being performed. + * @throws Throws an error if the output fields are inconsistent. + */ +export function checkTaprootOutputFields(outputData, newOutputData, action) { + checkMixedTaprootAndNonTaprootOutputFields(outputData, newOutputData, action); + checkTaprootScriptPubkey(outputData, newOutputData); +} +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: scriptPubkey } = outputData; + const script = getTaprootScripPubkey(tapInternalKey, tapTree); + if (scriptPubkey && !scriptPubkey.equals(script)) + throw new Error('Error adding output. Script or address mismatch.'); + } +} +/** + * Returns the Taproot script public key. + * + * @param tapInternalKey - The Taproot internal key. + * @param tapTree - The Taproot tree (optional). + * @returns The Taproot script public key. + */ +function getTaprootScripPubkey(tapInternalKey, tapTree) { + const scriptTree = tapTree && tapTreeFromList(tapTree.leaves); + const { output } = p2tr({ + internalPubkey: tapInternalKey, + scriptTree, + }); + return output; +} +/** + * Tweak the internal public key for a specific input. + * @param inputIndex - The index of the input. + * @param input - The PsbtInput object representing the input. + * @returns The tweaked internal public key. + * @throws Error if the tap internal key cannot be tweaked. + */ +export function tweakInternalPubKey(inputIndex, input) { + 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; +} +/** + * 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) { + if (!isTaptree(tree)) + throw new Error( + 'Cannot convert taptree to tapleaf list. Expecting a tapree structure.', + ); + 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 = []) { + if (leaves.length === 1 && leaves[0].depth === 0) + return { + output: leaves[0].script, + version: leaves[0].leafVersion, + }; + return instertLeavesInTree(leaves); +} +/** + * Checks the taproot input for signatures. + * @param input The PSBT input to check. + * @param action The action being performed. + * @returns True if the input has taproot signatures, false otherwise. + */ +export function checkTaprootInputForSigs(input, action) { + const sigs = extractTaprootSigs(input); + return sigs.some(sig => + signatureBlocksAction(sig, decodeSchnorrSignature, action), + ); +} +/** + * Decodes a Schnorr signature. + * @param signature The signature to decode. + * @returns The decoded Schnorr signature. + */ +function decodeSchnorrSignature(signature) { + return { + signature: signature.slice(0, 64), + hashType: signature.slice(64)[0] || Transaction.SIGHASH_DEFAULT, + }; +} +/** + * Extracts taproot signatures from a PSBT input. + * @param input The PSBT input to extract signatures from. + * @returns An array of taproot signatures. + */ +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; +} +/** + * Gets the taproot signature from the witness. + * @param finalScriptWitness The final script witness. + * @returns The taproot signature, or undefined if not found. + */ +function getTapKeySigFromWithness(finalScriptWitness) { + if (!finalScriptWitness) return; + const witness = finalScriptWitness.slice(2); + // todo: add schnorr signature validation + if (witness.length === 64 || witness.length === 65) return witness; +} +/** + * Converts a binary tree to a BIP371 type list. + * @param tree The binary tap tree. + * @param leaves A list of tapleaves. Optional. + * @param depth The current depth. Optional. + * @returns A list of BIP 371 tapleaves. + * @throws Throws an error if the taptree cannot be converted to a tapleaf list. + */ +function _tapTreeToList(tree, leaves = [], depth = 0) { + 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; +} +/** + * Inserts the tapleaves into the taproot tree. + * @param leaves The tapleaves to insert. + * @returns The taproot tree. + * @throws Throws an error if there is no room left to insert a tapleaf in the tree. + */ +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; +} +/** + * Inserts a tapleaf into the taproot tree. + * @param leaf The tapleaf to insert. + * @param tree The taproot tree. + * @param depth The current depth. Optional. + * @returns The updated taproot tree. + */ +function instertLeafInTree(leaf, tree, depth = 0) { + 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]; +} +/** + * Checks the input fields for mixed taproot and non-taproot fields. + * @param inputData The original input data. + * @param newInputData The new input data. + * @param action The action being performed. + * @throws Throws an error if the input fields are inconsistent. + */ +function checkMixedTaprootAndNonTaprootInputFields( + inputData, + newInputData, + action, +) { + const isBadTaprootUpdate = + 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.`, + ); +} +/** + * Checks the output fields for mixed taproot and non-taproot fields. + * @param inputData The original output data. + * @param newInputData The new output data. + * @param action The action being performed. + * @throws Throws an error if the output fields are inconsistent. + */ +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}. ` + + `Cannot use both taproot and non-taproot fields.`, + ); +} +/** + * Checks if the tap leaf is part of the tap tree for the given input data. + * Throws an error if the tap leaf is not part of the tap tree. + * @param inputData - The original PsbtInput data. + * @param newInputData - The new PsbtInput data. + * @param action - The action being performed. + * @throws {Error} - If the tap leaf is not part of the tap tree. + */ +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.`, + ); + } +} +/** + * Checks if a TapLeafScript is present in a Merkle tree. + * @param tapLeaf The TapLeafScript to check. + * @param merkleRoot The Merkle root of the tree. If not provided, the function assumes the TapLeafScript is present. + * @returns A boolean indicating whether the TapLeafScript is present in the tree. + */ +function isTapLeafInTree(tapLeaf, merkleRoot) { + if (!merkleRoot) return true; + const leafHash = tapleafHash({ + output: tapLeaf.script, + version: tapLeaf.leafVersion, + }); + const rootHash = rootHashFromPath(tapLeaf.controlBlock, leafHash); + return rootHash.equals(merkleRoot); +} +/** + * Sorts the signatures in the input's tapScriptSig array based on their position in the tapLeaf script. + * + * @param input - The PsbtInput object. + * @param tapLeaf - The TapLeafScript object. + * @returns An array of sorted signatures as Buffers. + */ +function sortSignatures(input, tapLeaf) { + 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); +} +/** + * Adds the position of a public key in a script to a TapScriptSig object. + * @param script The script in which to find the position of the public key. + * @param tss The TapScriptSig object to add the position to. + * @returns A TapScriptSigWitPosition object with the added position. + */ +function addPubkeyPositionInScript(script, tss) { + return Object.assign( + { + positionInScript: 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; +} +/** + * Determines whether a TapLeafScript can be finalized. + * + * @param leaf - The TapLeafScript to check. + * @param tapScriptSig - The array of TapScriptSig objects. + * @param hash - The optional hash to compare with the leaf hash. + * @returns A boolean indicating whether the TapLeafScript can be finalized. + */ +function canFinalizeLeaf(leaf, tapScriptSig, hash) { + 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 + ); +} +/** + * Checks if the given PsbtInput or PsbtOutput has non-taproot fields. + * Non-taproot fields include redeemScript, witnessScript, and bip32Derivation. + * @param io The PsbtInput or PsbtOutput to check. + * @returns A boolean indicating whether the given input or output has non-taproot fields. + */ +function hasNonTaprootFields(io) { + return ( + io && + !!( + io.redeemScript || + io.witnessScript || + (io.bip32Derivation && io.bip32Derivation.length) + ) + ); +} diff --git a/src/esm/psbt/psbtutils.js b/src/esm/psbt/psbtutils.js new file mode 100644 index 000000000..31fb62a8c --- /dev/null +++ b/src/esm/psbt/psbtutils.js @@ -0,0 +1,165 @@ +import * as varuint from 'varuint-bitcoin'; +import * as bscript from '../script'; +import { Transaction } from '../transaction'; +import { hash160 } from '../crypto'; +import * as payments from '../payments'; +/** + * Checks if a given payment factory can generate a payment script from a given script. + * @param payment The payment factory to check. + * @returns A function that takes a script and returns a boolean indicating whether the payment factory can generate a payment script from the script. + */ +function isPaymentFactory(payment) { + return script => { + 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); +/** + * Converts a witness stack to a script witness. + * @param witness The witness stack to convert. + * @returns The script witness as a Buffer. + */ +export 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; +} +/** + * Finds the position of a public key in a script. + * @param pubkey The public key to search for. + * @param script The script to search in. + * @returns The index of the public key in the script, or -1 if not found. + * @throws {Error} If there is an unknown script error. + */ +export function pubkeyPositionInScript(pubkey, script) { + 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) + ); + }); +} +/** + * Checks if a public key is present in a script. + * @param pubkey The public key to check. + * @param script The script to search in. + * @returns A boolean indicating whether the public key is present in the script. + */ +export function pubkeyInScript(pubkey, script) { + return pubkeyPositionInScript(pubkey, script) !== -1; +} +/** + * Checks if an input contains a signature for a specific action. + * @param input - The input to check. + * @param action - The action to check for. + * @returns A boolean indicating whether the input contains a signature for the specified action. + */ +export function checkInputForSig(input, action) { + const pSigs = extractPartialSigs(input); + return pSigs.some(pSig => + signatureBlocksAction(pSig, bscript.signature.decode, action), + ); +} +/** + * Determines if a given action is allowed for a signature block. + * @param signature - The signature block. + * @param signatureDecodeFn - The function used to decode the signature. + * @param action - The action to be checked. + * @returns True if the action is allowed, false otherwise. + */ +export function signatureBlocksAction(signature, signatureDecodeFn, action) { + const { hashType } = signatureDecodeFn(signature); + const whitelist = []; + 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; +} +/** + * Extracts the signatures from a PsbtInput object. + * If the input has partial signatures, it returns an array of the signatures. + * If the input does not have partial signatures, it checks if it has a finalScriptSig or finalScriptWitness. + * If it does, it extracts the signatures from the final scripts and returns them. + * If none of the above conditions are met, it returns an empty array. + * + * @param input - The PsbtInput object from which to extract the signatures. + * @returns An array of signatures extracted from the PsbtInput object. + */ +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); +} +/** + * Retrieves the partial signatures (Psigs) from the input's final scripts. + * Psigs are extracted from both the final scriptSig and final scriptWitness of the input. + * Only canonical script signatures are considered. + * + * @param input - The PsbtInput object representing the input. + * @returns An array of PartialSig objects containing the extracted Psigs. + */ +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/src/esm/push_data.js b/src/esm/push_data.js new file mode 100644 index 000000000..14aee8926 --- /dev/null +++ b/src/esm/push_data.js @@ -0,0 +1,76 @@ +import { OPS } from './ops'; +/** + * Calculates the encoding length of a number used for push data in Bitcoin transactions. + * @param i The number to calculate the encoding length for. + * @returns The encoding length of the number. + */ +export function encodingLength(i) { + return i < OPS.OP_PUSHDATA1 ? 1 : i <= 0xff ? 2 : i <= 0xffff ? 3 : 5; +} +/** + * Encodes a number into a buffer using a variable-length encoding scheme. + * The encoded buffer is written starting at the specified offset. + * Returns the size of the encoded buffer. + * + * @param buffer - The buffer to write the encoded data into. + * @param num - The number to encode. + * @param offset - The offset at which to start writing the encoded buffer. + * @returns The size of the encoded buffer. + */ +export function encode(buffer, num, offset) { + const size = encodingLength(num); + // ~6 bit + if (size === 1) { + buffer.writeUInt8(num, offset); + // 8 bit + } else if (size === 2) { + buffer.writeUInt8(OPS.OP_PUSHDATA1, offset); + buffer.writeUInt8(num, offset + 1); + // 16 bit + } else if (size === 3) { + buffer.writeUInt8(OPS.OP_PUSHDATA2, offset); + buffer.writeUInt16LE(num, offset + 1); + // 32 bit + } else { + buffer.writeUInt8(OPS.OP_PUSHDATA4, offset); + buffer.writeUInt32LE(num, offset + 1); + } + return size; +} +/** + * Decodes a buffer and returns information about the opcode, number, and size. + * @param buffer - The buffer to decode. + * @param offset - The offset within the buffer to start decoding. + * @returns An object containing the opcode, number, and size, or null if decoding fails. + */ +export function decode(buffer, offset) { + const opcode = buffer.readUInt8(offset); + let num; + let size; + // ~6 bit + if (opcode < OPS.OP_PUSHDATA1) { + num = opcode; + size = 1; + // 8 bit + } else if (opcode === OPS.OP_PUSHDATA1) { + if (offset + 2 > buffer.length) return null; + num = buffer.readUInt8(offset + 1); + size = 2; + // 16 bit + } else if (opcode === OPS.OP_PUSHDATA2) { + if (offset + 3 > buffer.length) return null; + num = buffer.readUInt16LE(offset + 1); + size = 3; + // 32 bit + } else { + if (offset + 5 > buffer.length) return null; + if (opcode !== OPS.OP_PUSHDATA4) throw new Error('Unexpected opcode'); + num = buffer.readUInt32LE(offset + 1); + size = 5; + } + return { + opcode, + number: num, + size, + }; +} diff --git a/src/esm/script.js b/src/esm/script.js new file mode 100644 index 000000000..7992da950 --- /dev/null +++ b/src/esm/script.js @@ -0,0 +1,198 @@ +/** + * Script tools, including decompile, compile, toASM, fromASM, toStack, isCanonicalPubKey, isCanonicalScriptSignature + * @packageDocumentation + */ +import * as bip66 from './bip66'; +import { OPS, REVERSE_OPS } from './ops'; +import * as pushdata from './push_data'; +import * as scriptNumber from './script_number'; +import * as scriptSignature from './script_signature'; +import * as types from './types'; +const { typeforce } = types; +const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1 +export { OPS }; +function isOPInt(value) { + return ( + types.Number(value) && + (value === OPS.OP_0 || + (value >= OPS.OP_1 && value <= OPS.OP_16) || + value === OPS.OP_1NEGATE) + ); +} +function isPushOnlyChunk(value) { + return types.Buffer(value) || isOPInt(value); +} +export function isPushOnly(value) { + return types.Array(value) && value.every(isPushOnlyChunk); +} +export function countNonPushOnlyOPs(value) { + return value.length - value.filter(isPushOnlyChunk).length; +} +function asMinimalOP(buffer) { + if (buffer.length === 0) return OPS.OP_0; + if (buffer.length !== 1) return; + if (buffer[0] >= 1 && buffer[0] <= 16) return OP_INT_BASE + buffer[0]; + if (buffer[0] === 0x81) return OPS.OP_1NEGATE; +} +function chunksIsBuffer(buf) { + return Buffer.isBuffer(buf); +} +function chunksIsArray(buf) { + return types.Array(buf); +} +function singleChunkIsBuffer(buf) { + return Buffer.isBuffer(buf); +} +/** + * Compiles an array of chunks into a Buffer. + * + * @param chunks - The array of chunks to compile. + * @returns The compiled Buffer. + * @throws Error if the compilation fails. + */ +export function compile(chunks) { + // TODO: remove me + if (chunksIsBuffer(chunks)) return chunks; + typeforce(types.Array, chunks); + const bufferSize = chunks.reduce((accum, chunk) => { + // data chunk + if (singleChunkIsBuffer(chunk)) { + // adhere to BIP62.3, minimal push policy + if (chunk.length === 1 && asMinimalOP(chunk) !== undefined) { + return accum + 1; + } + return accum + pushdata.encodingLength(chunk.length) + chunk.length; + } + // opcode + return accum + 1; + }, 0.0); + const buffer = Buffer.allocUnsafe(bufferSize); + let offset = 0; + chunks.forEach(chunk => { + // data chunk + if (singleChunkIsBuffer(chunk)) { + // adhere to BIP62.3, minimal push policy + const opcode = asMinimalOP(chunk); + if (opcode !== undefined) { + buffer.writeUInt8(opcode, offset); + offset += 1; + return; + } + offset += pushdata.encode(buffer, chunk.length, offset); + chunk.copy(buffer, offset); + offset += chunk.length; + // opcode + } else { + buffer.writeUInt8(chunk, offset); + offset += 1; + } + }); + if (offset !== buffer.length) throw new Error('Could not decode chunks'); + return buffer; +} +export function decompile(buffer) { + // TODO: remove me + if (chunksIsArray(buffer)) return buffer; + typeforce(types.Buffer, buffer); + const chunks = []; + let i = 0; + while (i < buffer.length) { + const opcode = buffer[i]; + // data chunk + if (opcode > OPS.OP_0 && opcode <= OPS.OP_PUSHDATA4) { + const d = pushdata.decode(buffer, i); + // did reading a pushDataInt fail? + if (d === null) return null; + i += d.size; + // attempt to read too much data? + if (i + d.number > buffer.length) return null; + const data = buffer.slice(i, i + d.number); + i += d.number; + // decompile minimally + const op = asMinimalOP(data); + if (op !== undefined) { + chunks.push(op); + } else { + chunks.push(data); + } + // opcode + } else { + chunks.push(opcode); + i += 1; + } + } + return chunks; +} +/** + * Converts the given chunks into an ASM (Assembly) string representation. + * If the chunks parameter is a Buffer, it will be decompiled into a Stack before conversion. + * @param chunks - The chunks to convert into ASM. + * @returns The ASM string representation of the chunks. + */ +export function toASM(chunks) { + if (chunksIsBuffer(chunks)) { + chunks = decompile(chunks); + } + if (!chunks) { + throw new Error('Could not convert invalid chunks to ASM'); + } + return chunks + .map(chunk => { + // data? + if (singleChunkIsBuffer(chunk)) { + const op = asMinimalOP(chunk); + if (op === undefined) return chunk.toString('hex'); + chunk = op; + } + // opcode! + return REVERSE_OPS[chunk]; + }) + .join(' '); +} +/** + * Converts an ASM string to a Buffer. + * @param asm The ASM string to convert. + * @returns The converted Buffer. + */ +export function fromASM(asm) { + typeforce(types.String, asm); + return compile( + asm.split(' ').map(chunkStr => { + // opcode? + if (OPS[chunkStr] !== undefined) return OPS[chunkStr]; + typeforce(types.Hex, chunkStr); + // data! + return Buffer.from(chunkStr, 'hex'); + }), + ); +} +/** + * Converts the given chunks into a stack of buffers. + * + * @param chunks - The chunks to convert. + * @returns The stack of buffers. + */ +export function toStack(chunks) { + chunks = decompile(chunks); + typeforce(isPushOnly, chunks); + return chunks.map(op => { + if (singleChunkIsBuffer(op)) return op; + if (op === OPS.OP_0) return Buffer.allocUnsafe(0); + return scriptNumber.encode(op - OP_INT_BASE); + }); +} +export function isCanonicalPubKey(buffer) { + return types.isPoint(buffer); +} +export function isDefinedHashType(hashType) { + const hashTypeMod = hashType & ~0x80; + // return hashTypeMod > SIGHASH_ALL && hashTypeMod < SIGHASH_SINGLE + return hashTypeMod > 0x00 && hashTypeMod < 0x04; +} +export function isCanonicalScriptSignature(buffer) { + if (!Buffer.isBuffer(buffer)) return false; + if (!isDefinedHashType(buffer[buffer.length - 1])) return false; + return bip66.check(buffer.slice(0, -1)); +} +export const number = scriptNumber; +export const signature = scriptSignature; diff --git a/src/esm/script_number.js b/src/esm/script_number.js new file mode 100644 index 000000000..1d8cd34d5 --- /dev/null +++ b/src/esm/script_number.js @@ -0,0 +1,73 @@ +/** + * Decodes a script number from a buffer. + * + * @param buffer - The buffer containing the script number. + * @param maxLength - The maximum length of the script number. Defaults to 4. + * @param minimal - Whether the script number should be minimal. Defaults to true. + * @returns The decoded script number. + * @throws {TypeError} If the script number overflows the maximum length. + * @throws {Error} If the script number is not minimally encoded when minimal is true. + */ +export function decode(buffer, maxLength, minimal) { + maxLength = maxLength || 4; + minimal = minimal === undefined ? true : minimal; + const length = buffer.length; + if (length === 0) return 0; + if (length > maxLength) throw new TypeError('Script number overflow'); + if (minimal) { + if ((buffer[length - 1] & 0x7f) === 0) { + if (length <= 1 || (buffer[length - 2] & 0x80) === 0) + throw new Error('Non-minimally encoded script number'); + } + } + // 40-bit + if (length === 5) { + const a = buffer.readUInt32LE(0); + const b = buffer.readUInt8(4); + if (b & 0x80) return -((b & ~0x80) * 0x100000000 + a); + return b * 0x100000000 + a; + } + // 32-bit / 24-bit / 16-bit / 8-bit + let result = 0; + for (let i = 0; i < length; ++i) { + result |= buffer[i] << (8 * i); + } + if (buffer[length - 1] & 0x80) + return -(result & ~(0x80 << (8 * (length - 1)))); + return result; +} +function scriptNumSize(i) { + return i > 0x7fffffff + ? 5 + : i > 0x7fffff + ? 4 + : i > 0x7fff + ? 3 + : i > 0x7f + ? 2 + : i > 0x00 + ? 1 + : 0; +} +/** + * Encodes a number into a Buffer using a specific format. + * + * @param _number - The number to encode. + * @returns The encoded number as a Buffer. + */ +export function encode(_number) { + let value = Math.abs(_number); + const size = scriptNumSize(value); + const buffer = Buffer.allocUnsafe(size); + const negative = _number < 0; + for (let i = 0; i < size; ++i) { + buffer.writeUInt8(value & 0xff, i); + value >>= 8; + } + if (buffer[size - 1] & 0x80) { + buffer.writeUInt8(negative ? 0x80 : 0x00, size - 1); + } else if (negative) { + buffer[size - 1] |= 0x80; + } + return buffer; +} diff --git a/src/script_signature.js b/src/esm/script_signature.js similarity index 82% rename from src/script_signature.js rename to src/esm/script_signature.js index 61624b630..8db94dc5a 100644 --- a/src/script_signature.js +++ b/src/esm/script_signature.js @@ -1,9 +1,6 @@ -'use strict'; -Object.defineProperty(exports, '__esModule', { value: true }); -exports.encode = exports.decode = void 0; -const bip66 = require('./bip66'); -const script_1 = require('./script'); -const types = require('./types'); +import * as bip66 from './bip66'; +import { isDefinedHashType } from './script'; +import * as types from './types'; const { typeforce } = types; const ZERO = Buffer.alloc(1, 0); /** @@ -40,9 +37,9 @@ function fromDER(x) { * @returns The decoded ScriptSignature object. * @throws Error if the hashType is invalid. */ -function decode(buffer) { +export function decode(buffer) { const hashType = buffer.readUInt8(buffer.length - 1); - if (!(0, script_1.isDefinedHashType)(hashType)) { + if (!isDefinedHashType(hashType)) { throw new Error('Invalid hashType ' + hashType); } const decoded = bip66.decode(buffer.slice(0, -1)); @@ -51,7 +48,6 @@ function decode(buffer) { const signature = Buffer.concat([r, s], 64); return { signature, hashType }; } -exports.decode = decode; /** * Encodes a signature and hash type into a buffer. * @param signature - The signature to encode. @@ -59,7 +55,7 @@ exports.decode = decode; * @returns The encoded buffer. * @throws Error if the hashType is invalid. */ -function encode(signature, hashType) { +export function encode(signature, hashType) { typeforce( { signature: types.BufferN(64), @@ -67,7 +63,7 @@ function encode(signature, hashType) { }, { signature, hashType }, ); - if (!(0, script_1.isDefinedHashType)(hashType)) { + if (!isDefinedHashType(hashType)) { throw new Error('Invalid hashType ' + hashType); } const hashTypeBuffer = Buffer.allocUnsafe(1); @@ -76,4 +72,3 @@ function encode(signature, hashType) { const s = toDER(signature.slice(32, 64)); return Buffer.concat([bip66.encode(r, s), hashTypeBuffer]); } -exports.encode = encode; diff --git a/src/esm/transaction.js b/src/esm/transaction.js new file mode 100644 index 000000000..ade02be31 --- /dev/null +++ b/src/esm/transaction.js @@ -0,0 +1,533 @@ +import { + BufferReader, + BufferWriter, + reverseBuffer, + varuint, +} from './bufferutils'; +import * as bcrypto from './crypto'; +import * as bscript from './script'; +import { OPS as opcodes } from './script'; +import * as types from './types'; +const { typeforce } = types; +function varSliceSize(someScript) { + const length = someScript.length; + return varuint.encodingLength(length) + length; +} +function vectorSize(someVector) { + const length = someVector.length; + return ( + varuint.encodingLength(length) + + someVector.reduce((sum, witness) => { + return sum + varSliceSize(witness); + }, 0) + ); +} +const EMPTY_BUFFER = Buffer.allocUnsafe(0); +const EMPTY_WITNESS = []; +const ZERO = Buffer.from( + '0000000000000000000000000000000000000000000000000000000000000000', + 'hex', +); +const ONE = Buffer.from( + '0000000000000000000000000000000000000000000000000000000000000001', + 'hex', +); +const VALUE_UINT64_MAX = Buffer.from('ffffffffffffffff', 'hex'); +const BLANK_OUTPUT = { + script: EMPTY_BUFFER, + valueBuffer: VALUE_UINT64_MAX, +}; +function isOutput(out) { + return out.value !== undefined; +} +/** + * Represents a Bitcoin transaction. + */ +export class Transaction { + static DEFAULT_SEQUENCE = 0xffffffff; + static SIGHASH_DEFAULT = 0x00; + static SIGHASH_ALL = 0x01; + static SIGHASH_NONE = 0x02; + static SIGHASH_SINGLE = 0x03; + static SIGHASH_ANYONECANPAY = 0x80; + static SIGHASH_OUTPUT_MASK = 0x03; + static SIGHASH_INPUT_MASK = 0x80; + static ADVANCED_TRANSACTION_MARKER = 0x00; + static ADVANCED_TRANSACTION_FLAG = 0x01; + static fromBuffer(buffer, _NO_STRICT) { + const bufferReader = new BufferReader(buffer); + const tx = new Transaction(); + tx.version = bufferReader.readInt32(); + const marker = bufferReader.readUInt8(); + const flag = bufferReader.readUInt8(); + let hasWitnesses = false; + if ( + marker === Transaction.ADVANCED_TRANSACTION_MARKER && + flag === Transaction.ADVANCED_TRANSACTION_FLAG + ) { + hasWitnesses = true; + } else { + bufferReader.offset -= 2; + } + const vinLen = bufferReader.readVarInt(); + for (let i = 0; i < vinLen; ++i) { + tx.ins.push({ + hash: bufferReader.readSlice(32), + index: bufferReader.readUInt32(), + script: bufferReader.readVarSlice(), + sequence: bufferReader.readUInt32(), + witness: EMPTY_WITNESS, + }); + } + const voutLen = bufferReader.readVarInt(); + for (let i = 0; i < voutLen; ++i) { + tx.outs.push({ + value: bufferReader.readUInt64(), + script: bufferReader.readVarSlice(), + }); + } + if (hasWitnesses) { + for (let i = 0; i < vinLen; ++i) { + tx.ins[i].witness = bufferReader.readVector(); + } + // was this pointless? + if (!tx.hasWitnesses()) + throw new Error('Transaction has superfluous witness data'); + } + tx.locktime = bufferReader.readUInt32(); + if (_NO_STRICT) return tx; + if (bufferReader.offset !== buffer.length) + throw new Error('Transaction has unexpected data'); + return tx; + } + static fromHex(hex) { + return Transaction.fromBuffer(Buffer.from(hex, 'hex'), false); + } + static isCoinbaseHash(buffer) { + typeforce(types.Hash256bit, buffer); + for (let i = 0; i < 32; ++i) { + if (buffer[i] !== 0) return false; + } + return true; + } + version = 1; + locktime = 0; + ins = []; + outs = []; + isCoinbase() { + return ( + this.ins.length === 1 && Transaction.isCoinbaseHash(this.ins[0].hash) + ); + } + addInput(hash, index, sequence, scriptSig) { + typeforce( + types.tuple( + types.Hash256bit, + types.UInt32, + types.maybe(types.UInt32), + types.maybe(types.Buffer), + ), + arguments, + ); + if (types.Null(sequence)) { + sequence = Transaction.DEFAULT_SEQUENCE; + } + // Add the input and return the input's index + return ( + this.ins.push({ + hash, + index, + script: scriptSig || EMPTY_BUFFER, + sequence: sequence, + witness: EMPTY_WITNESS, + }) - 1 + ); + } + addOutput(scriptPubKey, value) { + typeforce(types.tuple(types.Buffer, types.Satoshi), arguments); + // Add the output and return the output's index + return ( + this.outs.push({ + script: scriptPubKey, + value, + }) - 1 + ); + } + hasWitnesses() { + return this.ins.some(x => { + return x.witness.length !== 0; + }); + } + weight() { + const base = this.byteLength(false); + const total = this.byteLength(true); + return base * 3 + total; + } + virtualSize() { + return Math.ceil(this.weight() / 4); + } + byteLength(_ALLOW_WITNESS = true) { + const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses(); + return ( + (hasWitnesses ? 10 : 8) + + varuint.encodingLength(this.ins.length) + + varuint.encodingLength(this.outs.length) + + this.ins.reduce((sum, input) => { + return sum + 40 + varSliceSize(input.script); + }, 0) + + this.outs.reduce((sum, output) => { + return sum + 8 + varSliceSize(output.script); + }, 0) + + (hasWitnesses + ? this.ins.reduce((sum, input) => { + return sum + vectorSize(input.witness); + }, 0) + : 0) + ); + } + clone() { + const newTx = new Transaction(); + newTx.version = this.version; + newTx.locktime = this.locktime; + newTx.ins = this.ins.map(txIn => { + return { + hash: txIn.hash, + index: txIn.index, + script: txIn.script, + sequence: txIn.sequence, + witness: txIn.witness, + }; + }); + newTx.outs = this.outs.map(txOut => { + return { + script: txOut.script, + value: txOut.value, + }; + }); + return newTx; + } + /** + * Hash transaction for signing a specific input. + * + * Bitcoin uses a different hash for each signed transaction input. + * This method copies the transaction, makes the necessary changes based on the + * hashType, and then hashes the result. + * This hash can then be used to sign the provided transaction input. + */ + hashForSignature(inIndex, prevOutScript, hashType) { + typeforce( + types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), + arguments, + ); + // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L29 + if (inIndex >= this.ins.length) return ONE; + // ignore OP_CODESEPARATOR + const ourScript = bscript.compile( + bscript.decompile(prevOutScript).filter(x => { + return x !== opcodes.OP_CODESEPARATOR; + }), + ); + const txTmp = this.clone(); + // SIGHASH_NONE: ignore all outputs? (wildcard payee) + if ((hashType & 0x1f) === Transaction.SIGHASH_NONE) { + txTmp.outs = []; + // ignore sequence numbers (except at inIndex) + txTmp.ins.forEach((input, i) => { + if (i === inIndex) return; + input.sequence = 0; + }); + // SIGHASH_SINGLE: ignore all outputs, except at the same index? + } else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE) { + // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L60 + if (inIndex >= this.outs.length) return ONE; + // truncate outputs after + txTmp.outs.length = inIndex + 1; + // "blank" outputs before + for (let i = 0; i < inIndex; i++) { + txTmp.outs[i] = BLANK_OUTPUT; + } + // ignore sequence numbers (except at inIndex) + txTmp.ins.forEach((input, y) => { + if (y === inIndex) return; + input.sequence = 0; + }); + } + // SIGHASH_ANYONECANPAY: ignore inputs entirely? + if (hashType & Transaction.SIGHASH_ANYONECANPAY) { + txTmp.ins = [txTmp.ins[inIndex]]; + txTmp.ins[0].script = ourScript; + // SIGHASH_ALL: only ignore input scripts + } else { + // "blank" others input scripts + txTmp.ins.forEach(input => { + input.script = EMPTY_BUFFER; + }); + txTmp.ins[inIndex].script = ourScript; + } + // serialize and hash + const buffer = Buffer.allocUnsafe(txTmp.byteLength(false) + 4); + buffer.writeInt32LE(hashType, buffer.length - 4); + txTmp.__toBuffer(buffer, 0, false); + return bcrypto.hash256(buffer); + } + hashForWitnessV1(inIndex, prevOutScripts, values, hashType, leafHash, annex) { + // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#common-signature-message + typeforce( + types.tuple( + types.UInt32, + typeforce.arrayOf(types.Buffer), + typeforce.arrayOf(types.Satoshi), + types.UInt32, + ), + arguments, + ); + if ( + values.length !== this.ins.length || + prevOutScripts.length !== this.ins.length + ) { + throw new Error('Must supply prevout script and value for all inputs'); + } + const outputType = + hashType === Transaction.SIGHASH_DEFAULT + ? Transaction.SIGHASH_ALL + : hashType & Transaction.SIGHASH_OUTPUT_MASK; + const inputType = hashType & Transaction.SIGHASH_INPUT_MASK; + const isAnyoneCanPay = inputType === Transaction.SIGHASH_ANYONECANPAY; + const isNone = outputType === Transaction.SIGHASH_NONE; + const isSingle = outputType === Transaction.SIGHASH_SINGLE; + let hashPrevouts = EMPTY_BUFFER; + let hashAmounts = EMPTY_BUFFER; + let hashScriptPubKeys = EMPTY_BUFFER; + let hashSequences = EMPTY_BUFFER; + let hashOutputs = EMPTY_BUFFER; + if (!isAnyoneCanPay) { + let bufferWriter = BufferWriter.withCapacity(36 * this.ins.length); + this.ins.forEach(txIn => { + bufferWriter.writeSlice(txIn.hash); + bufferWriter.writeUInt32(txIn.index); + }); + hashPrevouts = bcrypto.sha256(bufferWriter.end()); + bufferWriter = BufferWriter.withCapacity(8 * this.ins.length); + values.forEach(value => bufferWriter.writeUInt64(value)); + hashAmounts = bcrypto.sha256(bufferWriter.end()); + bufferWriter = BufferWriter.withCapacity( + prevOutScripts.map(varSliceSize).reduce((a, b) => a + b), + ); + prevOutScripts.forEach(prevOutScript => + bufferWriter.writeVarSlice(prevOutScript), + ); + hashScriptPubKeys = bcrypto.sha256(bufferWriter.end()); + bufferWriter = BufferWriter.withCapacity(4 * this.ins.length); + this.ins.forEach(txIn => bufferWriter.writeUInt32(txIn.sequence)); + hashSequences = bcrypto.sha256(bufferWriter.end()); + } + if (!(isNone || isSingle)) { + if (!this.outs.length) + throw new Error('Add outputs to the transaction before signing.'); + const txOutsSize = this.outs + .map(output => 8 + varSliceSize(output.script)) + .reduce((a, b) => a + b); + const bufferWriter = BufferWriter.withCapacity(txOutsSize); + this.outs.forEach(out => { + bufferWriter.writeUInt64(out.value); + bufferWriter.writeVarSlice(out.script); + }); + hashOutputs = bcrypto.sha256(bufferWriter.end()); + } else if (isSingle && inIndex < this.outs.length) { + const output = this.outs[inIndex]; + const bufferWriter = BufferWriter.withCapacity( + 8 + varSliceSize(output.script), + ); + bufferWriter.writeUInt64(output.value); + bufferWriter.writeVarSlice(output.script); + hashOutputs = bcrypto.sha256(bufferWriter.end()); + } + const spendType = (leafHash ? 2 : 0) + (annex ? 1 : 0); + // Length calculation from: + // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-14 + // With extension from: + // https://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki#signature-validation + const sigMsgSize = + 174 - + (isAnyoneCanPay ? 49 : 0) - + (isNone ? 32 : 0) + + (annex ? 32 : 0) + + (leafHash ? 37 : 0); + const sigMsgWriter = BufferWriter.withCapacity(sigMsgSize); + sigMsgWriter.writeUInt8(hashType); + // Transaction + sigMsgWriter.writeInt32(this.version); + sigMsgWriter.writeUInt32(this.locktime); + sigMsgWriter.writeSlice(hashPrevouts); + sigMsgWriter.writeSlice(hashAmounts); + sigMsgWriter.writeSlice(hashScriptPubKeys); + sigMsgWriter.writeSlice(hashSequences); + if (!(isNone || isSingle)) { + sigMsgWriter.writeSlice(hashOutputs); + } + // Input + sigMsgWriter.writeUInt8(spendType); + if (isAnyoneCanPay) { + const input = this.ins[inIndex]; + sigMsgWriter.writeSlice(input.hash); + sigMsgWriter.writeUInt32(input.index); + sigMsgWriter.writeUInt64(values[inIndex]); + sigMsgWriter.writeVarSlice(prevOutScripts[inIndex]); + sigMsgWriter.writeUInt32(input.sequence); + } else { + sigMsgWriter.writeUInt32(inIndex); + } + if (annex) { + const bufferWriter = BufferWriter.withCapacity(varSliceSize(annex)); + bufferWriter.writeVarSlice(annex); + sigMsgWriter.writeSlice(bcrypto.sha256(bufferWriter.end())); + } + // Output + if (isSingle) { + sigMsgWriter.writeSlice(hashOutputs); + } + // BIP342 extension + if (leafHash) { + sigMsgWriter.writeSlice(leafHash); + sigMsgWriter.writeUInt8(0); + sigMsgWriter.writeUInt32(0xffffffff); + } + // Extra zero byte because: + // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-19 + return bcrypto.taggedHash( + 'TapSighash', + Buffer.concat([Buffer.from([0x00]), sigMsgWriter.end()]), + ); + } + hashForWitnessV0(inIndex, prevOutScript, value, hashType) { + typeforce( + types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), + arguments, + ); + let tbuffer = Buffer.from([]); + let bufferWriter; + let hashOutputs = ZERO; + let hashPrevouts = ZERO; + let hashSequence = ZERO; + if (!(hashType & Transaction.SIGHASH_ANYONECANPAY)) { + tbuffer = Buffer.allocUnsafe(36 * this.ins.length); + bufferWriter = new BufferWriter(tbuffer, 0); + this.ins.forEach(txIn => { + bufferWriter.writeSlice(txIn.hash); + bufferWriter.writeUInt32(txIn.index); + }); + hashPrevouts = bcrypto.hash256(tbuffer); + } + if ( + !(hashType & Transaction.SIGHASH_ANYONECANPAY) && + (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && + (hashType & 0x1f) !== Transaction.SIGHASH_NONE + ) { + tbuffer = Buffer.allocUnsafe(4 * this.ins.length); + bufferWriter = new BufferWriter(tbuffer, 0); + this.ins.forEach(txIn => { + bufferWriter.writeUInt32(txIn.sequence); + }); + hashSequence = bcrypto.hash256(tbuffer); + } + if ( + (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && + (hashType & 0x1f) !== Transaction.SIGHASH_NONE + ) { + const txOutsSize = this.outs.reduce((sum, output) => { + return sum + 8 + varSliceSize(output.script); + }, 0); + tbuffer = Buffer.allocUnsafe(txOutsSize); + bufferWriter = new BufferWriter(tbuffer, 0); + this.outs.forEach(out => { + bufferWriter.writeUInt64(out.value); + bufferWriter.writeVarSlice(out.script); + }); + hashOutputs = bcrypto.hash256(tbuffer); + } else if ( + (hashType & 0x1f) === Transaction.SIGHASH_SINGLE && + inIndex < this.outs.length + ) { + const output = this.outs[inIndex]; + tbuffer = Buffer.allocUnsafe(8 + varSliceSize(output.script)); + bufferWriter = new BufferWriter(tbuffer, 0); + bufferWriter.writeUInt64(output.value); + bufferWriter.writeVarSlice(output.script); + hashOutputs = bcrypto.hash256(tbuffer); + } + tbuffer = Buffer.allocUnsafe(156 + varSliceSize(prevOutScript)); + bufferWriter = new BufferWriter(tbuffer, 0); + const input = this.ins[inIndex]; + bufferWriter.writeInt32(this.version); + bufferWriter.writeSlice(hashPrevouts); + bufferWriter.writeSlice(hashSequence); + bufferWriter.writeSlice(input.hash); + bufferWriter.writeUInt32(input.index); + bufferWriter.writeVarSlice(prevOutScript); + bufferWriter.writeUInt64(value); + bufferWriter.writeUInt32(input.sequence); + bufferWriter.writeSlice(hashOutputs); + bufferWriter.writeUInt32(this.locktime); + bufferWriter.writeUInt32(hashType); + return bcrypto.hash256(tbuffer); + } + getHash(forWitness) { + // wtxid for coinbase is always 32 bytes of 0x00 + if (forWitness && this.isCoinbase()) return Buffer.alloc(32, 0); + return bcrypto.hash256(this.__toBuffer(undefined, undefined, forWitness)); + } + getId() { + // transaction hash's are displayed in reverse order + return reverseBuffer(this.getHash(false)).toString('hex'); + } + toBuffer(buffer, initialOffset) { + return this.__toBuffer(buffer, initialOffset, true); + } + toHex() { + return this.toBuffer(undefined, undefined).toString('hex'); + } + setInputScript(index, scriptSig) { + typeforce(types.tuple(types.Number, types.Buffer), arguments); + this.ins[index].script = scriptSig; + } + setWitness(index, witness) { + typeforce(types.tuple(types.Number, [types.Buffer]), arguments); + this.ins[index].witness = witness; + } + __toBuffer(buffer, initialOffset, _ALLOW_WITNESS = false) { + if (!buffer) buffer = Buffer.allocUnsafe(this.byteLength(_ALLOW_WITNESS)); + const bufferWriter = new BufferWriter(buffer, initialOffset || 0); + bufferWriter.writeInt32(this.version); + const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses(); + if (hasWitnesses) { + bufferWriter.writeUInt8(Transaction.ADVANCED_TRANSACTION_MARKER); + bufferWriter.writeUInt8(Transaction.ADVANCED_TRANSACTION_FLAG); + } + bufferWriter.writeVarInt(this.ins.length); + this.ins.forEach(txIn => { + bufferWriter.writeSlice(txIn.hash); + bufferWriter.writeUInt32(txIn.index); + bufferWriter.writeVarSlice(txIn.script); + bufferWriter.writeUInt32(txIn.sequence); + }); + bufferWriter.writeVarInt(this.outs.length); + this.outs.forEach(txOut => { + if (isOutput(txOut)) { + bufferWriter.writeUInt64(txOut.value); + } else { + bufferWriter.writeSlice(txOut.valueBuffer); + } + bufferWriter.writeVarSlice(txOut.script); + }); + if (hasWitnesses) { + this.ins.forEach(input => { + bufferWriter.writeVector(input.witness); + }); + } + bufferWriter.writeUInt32(this.locktime); + // avoid slicing unless necessary + if (initialOffset !== undefined) + return buffer.slice(initialOffset, bufferWriter.offset); + return buffer; + } +} diff --git a/src/esm/types.js b/src/esm/types.js new file mode 100644 index 000000000..d896a1f5c --- /dev/null +++ b/src/esm/types.js @@ -0,0 +1,74 @@ +import { Buffer as NBuffer } from 'buffer'; +export const typeforce = require('typeforce'); +const ZERO32 = NBuffer.alloc(32, 0); +const EC_P = NBuffer.from( + 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', + 'hex', +); +/** + * Checks if two arrays of Buffers are equal. + * @param a - The first array of Buffers. + * @param b - The second array of Buffers. + * @returns True if the arrays are equal, false otherwise. + */ +export function stacksEqual(a, b) { + if (a.length !== b.length) return false; + return a.every((x, i) => { + return x.equals(b[i]); + }); +} +/** + * Checks if the given value is a valid elliptic curve point. + * @param p - The value to check. + * @returns True if the value is a valid elliptic curve point, false otherwise. + */ +export function isPoint(p) { + if (!NBuffer.isBuffer(p)) return false; + 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 ((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 (t === 0x04 && p.length === 65) return true; + return false; +} +const SATOSHI_MAX = 21 * 1e14; +export function Satoshi(value) { + return typeforce.UInt53(value) && value <= SATOSHI_MAX; +} +export const TAPLEAF_VERSION_MASK = 0xfe; +export function isTapleaf(o) { + 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; + return true; +} +export function isTaptree(scriptTree) { + if (!Array(scriptTree)) return isTapleaf(scriptTree); + if (scriptTree.length !== 2) return false; + return scriptTree.every(t => isTaptree(t)); +} +export const Buffer256bit = typeforce.BufferN(32); +export const Hash160bit = typeforce.BufferN(20); +export const Hash256bit = typeforce.BufferN(32); +export const Number = typeforce.Number; +export const Array = typeforce.Array; +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; +export const tuple = typeforce.tuple; +export const UInt8 = typeforce.UInt8; +export const UInt32 = typeforce.UInt32; +export const Function = typeforce.Function; +export const BufferN = typeforce.BufferN; +export const Null = typeforce.Null; +export const oneOf = typeforce.oneOf; diff --git a/src/index.js b/src/index.js deleted file mode 100644 index c742ceef6..000000000 --- a/src/index.js +++ /dev/null @@ -1,59 +0,0 @@ -'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; -const address = require('./address'); -exports.address = address; -const crypto = require('./crypto'); -exports.crypto = crypto; -const networks = require('./networks'); -exports.networks = networks; -const payments = require('./payments'); -exports.payments = payments; -const script = require('./script'); -exports.script = script; -var block_1 = require('./block'); -Object.defineProperty(exports, 'Block', { - enumerable: true, - get: function () { - return block_1.Block; - }, -}); -var psbt_1 = require('./psbt'); -Object.defineProperty(exports, 'Psbt', { - enumerable: true, - get: function () { - return psbt_1.Psbt; - }, -}); -/** @hidden */ -var ops_1 = require('./ops'); -Object.defineProperty(exports, 'opcodes', { - enumerable: true, - get: function () { - return ops_1.OPS; - }, -}); -var transaction_1 = require('./transaction'); -Object.defineProperty(exports, 'Transaction', { - enumerable: true, - get: function () { - 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/ts_src/address.ts b/ts_src/address.ts index cbd03da1f..957e9b868 100644 --- a/ts_src/address.ts +++ b/ts_src/address.ts @@ -7,18 +7,19 @@ * * @packageDocumentation */ -import { Network } from './networks'; -import * as networks from './networks'; -import * as payments from './payments'; -import * as bscript from './script'; -import { typeforce, tuple, Hash160bit, UInt8 } from './types'; +import { Network } from './networks.js'; +import * as networks from './networks.js'; +import * as payments from './payments/index.js'; +import * as bscript from './script.js'; +import { typeforce, tuple, Hash160bit, UInt8 } from './types.js'; import { bech32, bech32m } from 'bech32'; -import * as bs58check from 'bs58check'; +import bs58check from 'bs58check'; +import * as tools from "uint8array-tools"; /** base58check decode result */ export interface Base58CheckResult { /** address hash */ - hash: Buffer; + hash: Uint8Array; /** address version: 0x00 for P2PKH, 0x05 for P2SH */ version: number; } @@ -44,7 +45,7 @@ const FUTURE_SEGWIT_VERSION_WARNING: string = 'with caution. Wallets should verify the segwit version from the output of fromBech32, ' + 'then decide when it is safe to use which version of segwit.'; -function _toFutureSegwitAddress(output: Buffer, network: Network): string { +function _toFutureSegwitAddress(output: Uint8Array, network: Network): string { const data = output.slice(2); if ( @@ -73,13 +74,14 @@ function _toFutureSegwitAddress(output: Buffer, network: Network): string { * decode address with base58 specification, return address version and address hash if valid */ export function fromBase58Check(address: string): Base58CheckResult { - const payload = Buffer.from(bs58check.decode(address)); + const payload = 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 version = tools.readUInt8(payload, 0); const hash = payload.slice(1); return { version, hash }; @@ -130,7 +132,7 @@ export function toBase58Check(hash: Buffer, version: number): string { * encode address hash to bech32 address with version and prefix */ export function toBech32( - data: Buffer, + data: Uint8Array, version: number, prefix: string, ): string { @@ -145,7 +147,7 @@ export function toBech32( /** * decode address from output script with network, return address if matched */ -export function fromOutputScript(output: Buffer, network?: Network): string { +export function fromOutputScript(output: Uint8Array, network?: Network): string { // TODO: Network network = network || networks.bitcoin; diff --git a/ts_src/bip66.ts b/ts_src/bip66.ts index ab76a4fd3..47d9f7552 100644 --- a/ts_src/bip66.ts +++ b/ts_src/bip66.ts @@ -27,7 +27,7 @@ export function check(buffer: Buffer): boolean { return true; } -export function decode(buffer: Buffer): { r: Buffer; s: Buffer } { +export function decode(buffer: Uint8Array): { r: Uint8Array; s: Uint8Array } { if (buffer.length < 8) throw new Error('DER sequence length is too short'); if (buffer.length > 72) throw new Error('DER sequence length is too long'); if (buffer[0] !== 0x30) throw new Error('Expected DER sequence'); @@ -81,7 +81,7 @@ export function decode(buffer: Buffer): { r: Buffer; s: Buffer } { * 62300 => 0x00f35c * -62300 => 0xff0ca4 */ -export function encode(r: Buffer, s: Buffer): Buffer { +export function encode(r: Uint8Array, s: Uint8Array): Buffer { const lenR = r.length; const lenS = s.length; if (lenR === 0) throw new Error('R length is zero'); @@ -102,10 +102,12 @@ export function encode(r: Buffer, s: Buffer): Buffer { signature[1] = signature.length - 2; signature[2] = 0x02; signature[3] = r.length; - r.copy(signature, 4); + // r.copy(signature, 4); + signature.set(r, 4); signature[4 + lenR] = 0x02; signature[5 + lenR] = s.length; - s.copy(signature, 6 + lenR); + // s.copy(signature, 6 + lenR); + signature.set(s, 6 + lenR); return signature; } diff --git a/ts_src/bufferutils.ts b/ts_src/bufferutils.ts index 1e46a49b5..3d7725e08 100644 --- a/ts_src/bufferutils.ts +++ b/ts_src/bufferutils.ts @@ -1,7 +1,8 @@ -import * as types from './types'; +import * as types from './types.js'; const { typeforce } = types; import * as varuint from 'varuint-bitcoin'; export { varuint }; +import * as tools from "uint8array-tools"; const MAX_JS_NUMBER = 0x001fffffffffffff; @@ -17,14 +18,14 @@ function verifuint(value: number | bigint, max: number): void { throw new Error('value has a fractional component'); } -export function readUInt64LE(buffer: Buffer, offset: number): number { - const a = buffer.readUInt32LE(offset); - let b = buffer.readUInt32LE(offset + 4); - b *= 0x100000000; +// export function readUInt64LE(buffer: Buffer, offset: number): number { +// const a = buffer.readUInt32LE(offset); +// let b = buffer.readUInt32LE(offset + 4); +// b *= 0x100000000; - verifuint(b + a, MAX_JS_NUMBER); - return b + a; -} +// verifuint(b + a, MAX_JS_NUMBER); +// return b + a; +// } /** * Writes a 64-bit unsigned integer in little-endian format to the specified buffer at the given offset. @@ -46,12 +47,37 @@ export function writeUInt64LE( return offset + 8; } +/** + * Reads a 64-bit signed integer from a Uint8Array in little-endian format. + * + * @param {Uint8Array} buffer - The buffer to read the value from. + * @param {number} offset - The offset in the buffer where the value starts. + * @return {number} The 64-bit signed integer value. + */ +export function readInt64LE( + buffer: Uint8Array, + offset: number +): number { + if((buffer[offset + 7] & 0x7f) > 0) throw new Error("RangeError: value out of range, greater than int64"); + + return ( + buffer[offset] | + (buffer[offset + 1] << 8) | + (buffer[offset + 2] << 16) | + (buffer[offset + 3] << 24) | + (buffer[offset + 4] << 32) | + (buffer[offset + 5] << 40) | + (buffer[offset + 6] << 48) | + (buffer[offset + 7] << 56) + ); +} + /** * Reverses the order of bytes in a buffer. * @param buffer - The buffer to reverse. * @returns A new buffer with the bytes reversed. */ -export function reverseBuffer(buffer: Buffer): Buffer { +export function reverseBuffer(buffer: Uint8Array): Uint8Array { if (buffer.length < 1) return buffer; let j = buffer.length - 1; let tmp = 0; @@ -64,9 +90,9 @@ export function reverseBuffer(buffer: Buffer): Buffer { return buffer; } -export function cloneBuffer(buffer: Buffer): Buffer { - const clone = Buffer.allocUnsafe(buffer.length); - buffer.copy(clone); +export function cloneBuffer(buffer: Uint8Array): Uint8Array { + const clone = new Uint8Array(buffer.length); + clone.set(buffer); return clone; } @@ -75,27 +101,35 @@ export function cloneBuffer(buffer: Buffer): Buffer { */ export class BufferWriter { static withCapacity(size: number): BufferWriter { - return new BufferWriter(Buffer.alloc(size)); + return new BufferWriter(new Uint8Array(size)); } - constructor(public buffer: Buffer, public offset: number = 0) { + constructor(public buffer: Uint8Array, public offset: number = 0) { typeforce(types.tuple(types.Buffer, types.UInt32), [buffer, offset]); } writeUInt8(i: number): void { - this.offset = this.buffer.writeUInt8(i, this.offset); + // this.offset = this.buffer.writeUInt8(i, this.offset); + this.offset = tools.writeUInt8(this.buffer, i, this.offset); } writeInt32(i: number): void { - this.offset = this.buffer.writeInt32LE(i, this.offset); + // this.offset = this.buffer.writeInt32LE(i, this.offset); + this.offset = tools.writeInt32(this.buffer, i, this.offset, "LE"); + } + + writeInt64(i: number | bigint): void { + this.offset = tools.writeInt64(this.buffer, BigInt(i), this.offset, "LE"); } writeUInt32(i: number): void { - this.offset = this.buffer.writeUInt32LE(i, this.offset); + // this.offset = this.buffer.writeUInt32LE(i, this.offset); + this.offset = tools.writeUInt32(this.buffer, i, this.offset, "LE"); } - writeUInt64(i: number): void { - this.offset = writeUInt64LE(this.buffer, i, this.offset); + writeUInt64(i: number | bigint): void { + // this.offset = writeUInt64LE(this.buffer, i, this.offset); + this.offset = tools.writeUInt64(this.buffer, this.offset, BigInt(i), "LE"); } writeVarInt(i: number): void { @@ -103,24 +137,26 @@ export class BufferWriter { this.offset += bytes; } - writeSlice(slice: Buffer): void { + writeSlice(slice: Uint8Array): void { if (this.buffer.length < this.offset + slice.length) { throw new Error('Cannot write slice out of bounds'); } - this.offset += slice.copy(this.buffer, this.offset); + // this.offset += slice.copy(this.buffer, this.offset); + this.buffer.set(slice, this.offset); + this.offset += slice.length; } - writeVarSlice(slice: Buffer): void { + writeVarSlice(slice: Uint8Array): void { this.writeVarInt(slice.length); this.writeSlice(slice); } - writeVector(vector: Buffer[]): void { + writeVector(vector: Uint8Array[]): void { this.writeVarInt(vector.length); - vector.forEach((buf: Buffer) => this.writeVarSlice(buf)); + vector.forEach((buf: Uint8Array) => this.writeVarSlice(buf)); } - end(): Buffer { + end(): Uint8Array { if (this.buffer.length === this.offset) { return this.buffer; } @@ -132,30 +168,34 @@ export class BufferWriter { * Helper class for reading of bitcoin data types from a buffer. */ export class BufferReader { - constructor(public buffer: Buffer, public offset: number = 0) { + constructor(public buffer: Uint8Array, public offset: number = 0) { typeforce(types.tuple(types.Buffer, types.UInt32), [buffer, offset]); } readUInt8(): number { - const result = this.buffer.readUInt8(this.offset); + // const result = this.buffer.readUInt8(this.offset); + const result = tools.readUInt8(this.buffer, this.offset); this.offset++; return result; } readInt32(): number { - const result = this.buffer.readInt32LE(this.offset); + // const result = readInt32LE(this.buffer, this.offset); + const result = tools.readInt32(this.buffer, this.offset, "LE"); this.offset += 4; return result; } readUInt32(): number { - const result = this.buffer.readUInt32LE(this.offset); + // const result = this.buffer.readUInt32LE(this.offset); + const result = tools.readUInt32(this.buffer, this.offset, "LE"); this.offset += 4; return result; } - readUInt64(): number { - const result = readUInt64LE(this.buffer, this.offset); + readUInt64(): bigint { + // const result = readUInt64LE(this.buffer, this.offset); + const result = tools.readUInt64(this.buffer, this.offset, "LE"); this.offset += 8; return result; } @@ -166,7 +206,7 @@ export class BufferReader { return bigintValue; } - readSlice(n: number | bigint): Buffer { + readSlice(n: number | bigint): Uint8Array { verifuint(n, MAX_JS_NUMBER); const num = Number(n); if (this.buffer.length < this.offset + num) { @@ -177,13 +217,13 @@ export class BufferReader { return result; } - readVarSlice(): Buffer { + readVarSlice(): Uint8Array { return this.readSlice(this.readVarInt()); } - readVector(): Buffer[] { + readVector(): Uint8Array[] { const count = this.readVarInt(); - const vector: Buffer[] = []; + const vector: Uint8Array[] = []; for (let i = 0; i < count; i++) vector.push(this.readVarSlice()); return vector; } diff --git a/ts_src/crypto.ts b/ts_src/crypto.ts index 223305a11..2e534664c 100644 --- a/ts_src/crypto.ts +++ b/ts_src/crypto.ts @@ -4,28 +4,16 @@ * * @packageDocumentation */ -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 } from '@noble/hashes/ripemd160'; +import { sha256 } from '@noble/hashes/sha256'; +import * as tools from "uint8array-tools"; -export function ripemd160(buffer: Buffer): Buffer { - return Buffer.from(_ripemd160(Uint8Array.from(buffer))); +export function hash160(buffer: Uint8Array): Uint8Array { + return ripemd160(sha256(buffer)); } -export function sha1(buffer: Buffer): Buffer { - return Buffer.from(_sha1(Uint8Array.from(buffer))); -} - -export function sha256(buffer: Buffer): Buffer { - return Buffer.from(_sha256(Uint8Array.from(buffer))); -} - -export function hash160(buffer: Buffer): Buffer { - return Buffer.from(_ripemd160(_sha256(Uint8Array.from(buffer)))); -} - -export function hash256(buffer: Buffer): Buffer { - return Buffer.from(_sha256(_sha256(Uint8Array.from(buffer)))); +export function hash256(buffer: Uint8Array): Uint8Array { + return sha256(sha256(buffer)); } export const TAGS = [ @@ -104,6 +92,6 @@ export const TAGGED_HASH_PREFIXES: TaggedHashPrefixes = { ]), }; -export function taggedHash(prefix: TaggedHashPrefix, data: Buffer): Buffer { - return sha256(Buffer.concat([TAGGED_HASH_PREFIXES[prefix], data])); +export function taggedHash(prefix: TaggedHashPrefix, data: Uint8Array): Uint8Array { + return sha256(tools.concat([TAGGED_HASH_PREFIXES[prefix], data])); } diff --git a/ts_src/payments/index.ts b/ts_src/payments/index.ts index bd1ac0d84..3e6d6b9b1 100644 --- a/ts_src/payments/index.ts +++ b/ts_src/payments/index.ts @@ -5,16 +5,16 @@ * * @packageDocumentation */ -import { Network } from '../networks'; -import { Taptree } from '../types'; -import { p2data as embed } from './embed'; -import { p2ms } from './p2ms'; -import { p2pk } from './p2pk'; -import { p2pkh } from './p2pkh'; -import { p2sh } from './p2sh'; -import { p2wpkh } from './p2wpkh'; -import { p2wsh } from './p2wsh'; -import { p2tr } from './p2tr'; +import { Network } from '../networks.js'; +import { Taptree } from '../types.js'; +import { p2data as embed } from './embed.js'; +import { p2ms } from './p2ms.js'; +import { p2pk } from './p2pk.js'; +import { p2pkh } from './p2pkh.js'; +import { p2sh } from './p2sh.js'; +import { p2wpkh } from './p2wpkh.js'; +import { p2wsh } from './p2wsh.js'; +import { p2tr } from './p2tr.js'; export interface Payment { name?: string; @@ -46,7 +46,7 @@ export interface PaymentOpts { allowIncomplete?: boolean; } -export type StackElement = Buffer | number; +export type StackElement = Uint8Array | number; export type Stack = StackElement[]; export type StackFunction = () => Stack; diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts index 892382352..6433b1831 100644 --- a/ts_src/psbt.ts +++ b/ts_src/psbt.ts @@ -13,15 +13,15 @@ import { 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 { bitcoin as btcNetwork, Network } from './networks'; -import * as payments from './payments'; -import { tapleafHash } from './payments/bip341'; -import * as bscript from './script'; -import { Output, Transaction } from './transaction'; +} from 'bip174/lib/interfaces'; +import { checkForInput, checkForOutput } from 'bip174/lib/utils'; +import { fromOutputScript, toOutputScript } from './address.js'; +import { cloneBuffer, reverseBuffer } from './bufferutils.js'; +import { bitcoin as btcNetwork, Network } from './networks.js'; +import * as payments from './payments/index.js'; +import { tapleafHash } from './payments/bip341.js'; +import * as bscript from './script.js'; +import { Output, Transaction } from './transaction.js'; import { toXOnly, tapScriptFinalizer, @@ -30,7 +30,7 @@ import { checkTaprootInputFields, checkTaprootOutputFields, checkTaprootInputForSigs, -} from './psbt/bip371'; +} from './psbt/bip371.js'; import { witnessStackToScriptWitness, checkInputForSig, @@ -42,21 +42,22 @@ import { isP2WSHScript, isP2SHScript, isP2TR, -} from './psbt/psbtutils'; +} from './psbt/psbtutils.js'; +import * as tools from "uint8array-tools"; export interface TransactionInput { - hash: string | Buffer; + hash: string | Uint8Array; index: number; sequence?: number; } export interface PsbtTxInput extends TransactionInput { - hash: Buffer; + hash: Uint8Array; } export interface TransactionOutput { - script: Buffer; - value: number; + script: Uint8Array; + value: bigint; } export interface PsbtTxOutput extends TransactionOutput { @@ -65,9 +66,9 @@ export interface PsbtTxOutput extends TransactionOutput { // msghash is 32 byte hash of preimage, signature is 64 byte compact signature (r,s 32 bytes each) export type ValidateSigFunction = ( - pubkey: Buffer, - msghash: Buffer, - signature: Buffer, + pubkey: Uint8Array, + msghash: Uint8Array, + signature: Uint8Array, ) => boolean; /** @@ -135,7 +136,7 @@ export class Psbt { return this.fromBuffer(buffer, opts); } - static fromBuffer(buffer: Buffer, opts: PsbtOptsOptional = {}): Psbt { + static fromBuffer(buffer: Uint8Array, opts: PsbtOptsOptional = {}): Psbt { const psbtBase = PsbtBase.fromBuffer(buffer, transactionFromBuffer); const psbt = new Psbt(opts, psbtBase); checkTxForDupeIns(psbt.__CACHE.__TX, psbt.__CACHE); @@ -544,16 +545,16 @@ export class Psbt { private _validateSignaturesOfInput( inputIndex: number, validator: ValidateSigFunction, - pubkey?: Buffer, + pubkey?: Uint8Array, ): boolean { const input = this.data.inputs[inputIndex]; - const partialSig = (input || {}).partialSig; + const partialSig = (input || {}).partialSig as PartialSig[]; if (!input || !partialSig || partialSig.length < 1) throw new Error('No signatures to validate'); if (typeof validator !== 'function') throw new Error('Need validator function to validate signatures'); const mySigs = pubkey - ? partialSig.filter(sig => sig.pubkey.equals(pubkey)) + ? partialSig.filter(sig => tools.compare(sig.pubkey, pubkey) === 0) : partialSig; if (mySigs.length < 1) throw new Error('No signatures for this pubkey'); const results: boolean[] = []; @@ -1065,7 +1066,7 @@ export class Psbt { return hashesForSig; } - toBuffer(): Buffer { + toBuffer(): Uint8Array { checkCache(this.__CACHE); return this.data.toBuffer(); } @@ -1221,7 +1222,7 @@ export interface SignerAsync { * Transaction (From the bip174 library) interface. */ const transactionFromBuffer: TransactionFromBuffer = ( - buffer: Buffer, + buffer: Uint8Array, ): ITransaction => new PsbtTransaction(buffer); /** @@ -1230,7 +1231,7 @@ const transactionFromBuffer: TransactionFromBuffer = ( */ class PsbtTransaction implements ITransaction { tx: Transaction; - constructor(buffer: Buffer = Buffer.from([2, 0, 0, 0, 0, 0, 0, 0, 0, 0])) { + constructor(buffer: Uint8Array = Uint8Array.from([2, 0, 0, 0, 0, 0, 0, 0, 0, 0])) { this.tx = Transaction.fromBuffer(buffer); checkTxEmpty(this.tx); Object.defineProperty(this, 'tx', { @@ -1278,7 +1279,7 @@ class PsbtTransaction implements ITransaction { this.tx.addOutput(output.script, output.value); } - toBuffer(): Buffer { + toBuffer(): Uint8Array { return this.tx.toBuffer(); } } @@ -1336,7 +1337,8 @@ function bip32DerivationIsMine( root: HDSigner, ): (d: Bip32Derivation) => boolean { return (d: Bip32Derivation): boolean => { - if (!d.masterFingerprint.equals(root.fingerprint)) return false; + // if (!d.masterFingerprint.equals(root.fingerprint)) return false; + if(tools.compare(root.fingerprint, d.masterFingerprint)) return false; if (!root.derivePath(d.path).publicKey.equals(d.pubkey)) return false; return true; }; @@ -1390,13 +1392,13 @@ function checkPartialSigSighashes(input: PsbtInput): void { } function checkScriptForPubkey( - pubkey: Buffer, - script: Buffer, + pubkey: Uint8Array, + script: Uint8Array, action: string, ): void { if (!pubkeyInScript(pubkey, script)) { throw new Error( - `Can not ${action} for this input with the key ${pubkey.toString('hex')}`, + `Can not ${action} for this input with the key ${tools.toHex(pubkey)}`, ); } } @@ -1422,10 +1424,10 @@ function checkTxForDupeIns(tx: Transaction, cache: PsbtCache): void { function checkTxInputCache( cache: PsbtCache, - input: { hash: Buffer; index: number }, + input: { hash: Uint8Array; index: number }, ): void { const key = - reverseBuffer(Buffer.from(input.hash)).toString('hex') + ':' + input.index; + tools.toHex(reverseBuffer(input.hash)) + ':' + input.index; if (cache.__TX_IN_CACHE[key]) throw new Error('Duplicate input detected.'); cache.__TX_IN_CACHE[key] = 1; } @@ -1433,18 +1435,19 @@ function checkTxInputCache( function scriptCheckerFactory( payment: any, paymentScriptName: string, -): (idx: number, spk: Buffer, rs: Buffer, ioType: 'input' | 'output') => void { +): (idx: number, spk: Uint8Array, rs: Buffer, ioType: 'input' | 'output') => void { return ( inputIndex: number, - scriptPubKey: Buffer, - redeemScript: Buffer, + scriptPubKey: Uint8Array, + redeemScript: Uint8Array, ioType: 'input' | 'output', ): void => { const redeemScriptOutput = payment({ redeem: { output: redeemScript }, }).output as Buffer; - if (!scriptPubKey.equals(redeemScriptOutput)) { + // if (!scriptPubKey.equals(redeemScriptOutput)) { + if (tools.compare(scriptPubKey, redeemScriptOutput)) { throw new Error( `${paymentScriptName} for ${ioType} #${inputIndex} doesn't match the scriptPubKey in the prevout`, ); @@ -1625,7 +1628,8 @@ function getHashForSig( const utxoHash = nonWitnessUtxoTx.getHash(); // If a non-witness UTXO is provided, its hash must match the hash specified in the prevout - if (!prevoutHash.equals(utxoHash)) { + // if (!prevoutHash.equals(utxoHash)) { + if (tools.compare(prevoutHash, utxoHash) !== 0) { throw new Error( `Non-witness UTXO hash for input #${inputIndex} doesn't match the hash specified in the prevout`, ); @@ -2192,11 +2196,11 @@ function isSigLike(buf: Buffer): boolean { } function getMeaningfulScript( - script: Buffer, + script: Uint8Array, index: number, ioType: 'input' | 'output', - redeemScript?: Buffer, - witnessScript?: Buffer, + redeemScript?: Uint8Array, + witnessScript?: Uint8Array, ): { meaningfulScript: Buffer; type: 'p2sh' | 'p2wsh' | 'p2sh-p2wsh' | 'raw'; @@ -2212,7 +2216,7 @@ function getMeaningfulScript( 'scriptPubkey or redeemScript is P2WSH but witnessScript missing', ); - let meaningfulScript: Buffer; + let meaningfulScript: Uint8Array; if (isP2SHP2WSH) { meaningfulScript = witnessScript!; @@ -2241,7 +2245,7 @@ function getMeaningfulScript( }; } -function checkInvalidP2WSH(script: Buffer): void { +function checkInvalidP2WSH(script: Uint8Array): void { if (isP2WPKH(script) || isP2SHScript(script)) { throw new Error('P2WPKH or P2SH can not be contained within P2WSH'); } diff --git a/ts_src/psbt/psbtutils.ts b/ts_src/psbt/psbtutils.ts index d9e678eb9..4bfeff164 100644 --- a/ts_src/psbt/psbtutils.ts +++ b/ts_src/psbt/psbtutils.ts @@ -1,17 +1,18 @@ import * as varuint from 'varuint-bitcoin'; -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'; +import { PartialSig, PsbtInput } from 'bip174/lib/interfaces'; +import * as bscript from '../script.js'; +import { Transaction } from '../transaction.js'; +import { hash160 } from '../crypto.js'; +import * as payments from '../payments/index.js'; +import * as tools from "uint8array-tools"; /** * Checks if a given payment factory can generate a payment script from a given script. * @param payment The payment factory to check. * @returns A function that takes a script and returns a boolean indicating whether the payment factory can generate a payment script from the script. */ -function isPaymentFactory(payment: any): (script: Buffer) => boolean { - return (script: Buffer): boolean => { +function isPaymentFactory(payment: any): (script: Uint8Array) => boolean { + return (script: Uint8Array): boolean => { try { payment({ output: script }); return true; @@ -71,7 +72,7 @@ export function witnessStackToScriptWitness(witness: Buffer[]): Buffer { * @returns The index of the public key in the script, or -1 if not found. * @throws {Error} If there is an unknown script error. */ -export function pubkeyPositionInScript(pubkey: Buffer, script: Buffer): number { +export function pubkeyPositionInScript(pubkey: Uint8Array, script: Uint8Array): number { const pubkeyHash = hash160(pubkey); const pubkeyXOnly = pubkey.slice(1, 33); // slice before calling? @@ -81,9 +82,12 @@ export function pubkeyPositionInScript(pubkey: Buffer, script: Buffer): number { return decompiled.findIndex(element => { if (typeof element === 'number') return false; return ( - element.equals(pubkey) || - element.equals(pubkeyHash) || - element.equals(pubkeyXOnly) + // element.equals(pubkey) || + // element.equals(pubkeyHash) || + // element.equals(pubkeyXOnly) + tools.compare(pubkey, element) === 0 || + tools.compare(pubkeyHash, element) === 0 || + tools.compare(pubkeyXOnly, element) === 0 ); }); } @@ -94,7 +98,7 @@ export function pubkeyPositionInScript(pubkey: Buffer, script: Buffer): number { * @param script The script to search in. * @returns A boolean indicating whether the public key is present in the script. */ -export function pubkeyInScript(pubkey: Buffer, script: Buffer): boolean { +export function pubkeyInScript(pubkey: Uint8Array, script: Uint8Array): boolean { return pubkeyPositionInScript(pubkey, script) !== -1; } @@ -111,8 +115,8 @@ export function checkInputForSig(input: PsbtInput, action: string): boolean { ); } -type SignatureDecodeFunc = (buffer: Buffer) => { - signature: Buffer; +type SignatureDecodeFunc = (buffer: Uint8Array) => { + signature: Uint8Array; hashType: number; }; @@ -124,7 +128,7 @@ type SignatureDecodeFunc = (buffer: Buffer) => { * @returns True if the action is allowed, false otherwise. */ export function signatureBlocksAction( - signature: Buffer, + signature: Uint8Array, signatureDecodeFn: SignatureDecodeFunc, action: string, ): boolean { @@ -158,7 +162,7 @@ export function signatureBlocksAction( * @param input - The PsbtInput object from which to extract the signatures. * @returns An array of signatures extracted from the PsbtInput object. */ -function extractPartialSigs(input: PsbtInput): Buffer[] { +function extractPartialSigs(input: PsbtInput): Uint8Array[] { let pSigs: PartialSig[] = []; if ((input.partialSig || []).length === 0) { if (!input.finalScriptSig && !input.finalScriptWitness) return []; diff --git a/ts_src/push_data.ts b/ts_src/push_data.ts index ade5f82f9..d78a31beb 100644 --- a/ts_src/push_data.ts +++ b/ts_src/push_data.ts @@ -1,4 +1,5 @@ -import { OPS } from './ops'; +import { OPS } from './ops.js'; +import * as tools from "uint8array-tools"; /** * Calculates the encoding length of a number used for push data in Bitcoin transactions. @@ -19,27 +20,32 @@ export function encodingLength(i: number): number { * @param offset - The offset at which to start writing the encoded buffer. * @returns The size of the encoded buffer. */ -export function encode(buffer: Buffer, num: number, offset: number): number { +export function encode(buffer: Uint8Array, num: number, offset: number): number { const size = encodingLength(num); // ~6 bit if (size === 1) { - buffer.writeUInt8(num, offset); - + // buffer.writeUInt8(num, offset); + tools.writeUInt8(buffer, num, offset); // 8 bit } else if (size === 2) { - buffer.writeUInt8(OPS.OP_PUSHDATA1, offset); - buffer.writeUInt8(num, offset + 1); + // buffer.writeUInt8(OPS.OP_PUSHDATA1, offset); + tools.writeUInt8(buffer, OPS.OP_PUSHDATA1, offset); + // buffer.writeUInt8(num, offset + 1); + tools.writeUInt8(buffer, num, offset + 1); // 16 bit } else if (size === 3) { - buffer.writeUInt8(OPS.OP_PUSHDATA2, offset); - buffer.writeUInt16LE(num, offset + 1); - + // buffer.writeUInt8(OPS.OP_PUSHDATA2, offset); + tools.writeUInt8(buffer, OPS.OP_PUSHDATA2, offset); + // buffer.writeUInt16LE(num, offset + 1); + tools.writeUInt16(buffer, num, offset + 1, "LE"); // 32 bit } else { - buffer.writeUInt8(OPS.OP_PUSHDATA4, offset); - buffer.writeUInt32LE(num, offset + 1); + // buffer.writeUInt8(OPS.OP_PUSHDATA4, offset); + tools.writeUInt8(buffer, OPS.OP_PUSHDATA4, offset); + // buffer.writeUInt32LE(num, offset + 1); + tools.writeUInt32(buffer, num, offset + 1, "LE"); } return size; @@ -52,14 +58,15 @@ export function encode(buffer: Buffer, num: number, offset: number): number { * @returns An object containing the opcode, number, and size, or null if decoding fails. */ export function decode( - buffer: Buffer, + buffer: Uint8Array, offset: number, ): { opcode: number; number: number; size: number; } | null { - const opcode = buffer.readUInt8(offset); + // const opcode = buffer.readUInt8(offset); + const opcode = tools.readUInt8(buffer, offset); let num: number; let size: number; @@ -71,13 +78,15 @@ export function decode( // 8 bit } else if (opcode === OPS.OP_PUSHDATA1) { if (offset + 2 > buffer.length) return null; - num = buffer.readUInt8(offset + 1); + // num = buffer.readUInt8(offset + 1); + num = tools.readUInt8(buffer, offset + 1); size = 2; // 16 bit } else if (opcode === OPS.OP_PUSHDATA2) { if (offset + 3 > buffer.length) return null; - num = buffer.readUInt16LE(offset + 1); + // num = buffer.readUInt16LE(offset + 1); + num = tools.readUInt16(buffer, offset + 1, "LE"); size = 3; // 32 bit @@ -85,7 +94,8 @@ export function decode( if (offset + 5 > buffer.length) return null; if (opcode !== OPS.OP_PUSHDATA4) throw new Error('Unexpected opcode'); - num = buffer.readUInt32LE(offset + 1); + // num = buffer.readUInt32LE(offset + 1); + num = tools.readUInt32(buffer, offset + 1, "LE"); size = 5; } diff --git a/ts_src/script.ts b/ts_src/script.ts index c2a033569..0f81a5912 100644 --- a/ts_src/script.ts +++ b/ts_src/script.ts @@ -2,14 +2,15 @@ * Script tools, including decompile, compile, toASM, fromASM, toStack, isCanonicalPubKey, isCanonicalScriptSignature * @packageDocumentation */ -import * as bip66 from './bip66'; -import { OPS, REVERSE_OPS } from './ops'; -import { Stack } from './payments'; -import * as pushdata from './push_data'; -import * as scriptNumber from './script_number'; -import * as scriptSignature from './script_signature'; -import * as types from './types'; +import * as bip66 from './bip66.js'; +import { OPS, REVERSE_OPS } from './ops.js'; +import { Stack } from './payments/index.js'; +import * as pushdata from './push_data.js'; +import * as scriptNumber from './script_number.js'; +import * as scriptSignature from './script_signature.js'; +import * as types from './types.js'; const { typeforce } = types; +import * as tools from "uint8array-tools"; const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1 export { OPS }; @@ -23,7 +24,7 @@ function isOPInt(value: number): boolean { ); } -function isPushOnlyChunk(value: number | Buffer): boolean { +function isPushOnlyChunk(value: number | Uint8Array): boolean { return types.Buffer(value) || isOPInt(value as number); } @@ -35,23 +36,24 @@ export function countNonPushOnlyOPs(value: Stack): number { return value.length - value.filter(isPushOnlyChunk).length; } -function asMinimalOP(buffer: Buffer): number | void { +function asMinimalOP(buffer: Uint8Array): number | void { if (buffer.length === 0) return OPS.OP_0; if (buffer.length !== 1) return; if (buffer[0] >= 1 && buffer[0] <= 16) return OP_INT_BASE + buffer[0]; if (buffer[0] === 0x81) return OPS.OP_1NEGATE; } -function chunksIsBuffer(buf: Buffer | Stack): buf is Buffer { - return Buffer.isBuffer(buf); +function chunksIsBuffer(buf: Uint8Array | Stack): buf is Buffer { + // return Buffer.isBuffer(buf); + return buf instanceof Buffer; } -function chunksIsArray(buf: Buffer | Stack): buf is Stack { +function chunksIsArray(buf: Uint8Array | Stack): buf is Stack { return types.Array(buf); } -function singleChunkIsBuffer(buf: number | Buffer): buf is Buffer { - return Buffer.isBuffer(buf); +function singleChunkIsBuffer(buf: number | Uint8Array): buf is Uint8Array { + return buf instanceof Uint8Array; } /** @@ -97,7 +99,8 @@ export function compile(chunks: Buffer | Stack): Buffer { } offset += pushdata.encode(buffer, chunk.length, offset); - chunk.copy(buffer, offset); + // chunk.copy(buffer, offset); + buffer.set(chunk, offset); offset += chunk.length; // opcode @@ -112,14 +115,14 @@ export function compile(chunks: Buffer | Stack): Buffer { } export function decompile( - buffer: Buffer | Array, -): Array | null { + buffer: Uint8Array | Array, +): Array | null { // TODO: remove me if (chunksIsArray(buffer)) return buffer; typeforce(types.Buffer, buffer); - const chunks: Array = []; + const chunks: Array = []; let i = 0; while (i < buffer.length) { @@ -164,19 +167,19 @@ export function decompile( * @param chunks - The chunks to convert into ASM. * @returns The ASM string representation of the chunks. */ -export function toASM(chunks: Buffer | Array): string { +export function toASM(chunks: Uint8Array | Array): string { if (chunksIsBuffer(chunks)) { chunks = decompile(chunks) as Stack; } if (!chunks) { throw new Error('Could not convert invalid chunks to ASM'); } - return chunks + return (chunks as Stack) .map(chunk => { // data? if (singleChunkIsBuffer(chunk)) { const op = asMinimalOP(chunk); - if (op === undefined) return chunk.toString('hex'); + if (op === undefined) return tools.toHex(chunk); chunk = op as number; } @@ -212,7 +215,7 @@ export function fromASM(asm: string): Buffer { * @param chunks - The chunks to convert. * @returns The stack of buffers. */ -export function toStack(chunks: Buffer | Array): Buffer[] { +export function toStack(chunks: Uint8Array | Array): Uint8Array[] { chunks = decompile(chunks) as Stack; typeforce(isPushOnly, chunks); diff --git a/ts_src/script_signature.ts b/ts_src/script_signature.ts index 571720607..dc0981189 100644 --- a/ts_src/script_signature.ts +++ b/ts_src/script_signature.ts @@ -1,6 +1,7 @@ -import * as bip66 from './bip66'; -import { isDefinedHashType } from './script'; -import * as types from './types'; +import * as bip66 from './bip66.js'; +import { isDefinedHashType } from './script.js'; +import * as types from './types.js'; +import * as tools from "uint8array-tools"; const { typeforce } = types; const ZERO = Buffer.alloc(1, 0); @@ -9,12 +10,12 @@ const ZERO = Buffer.alloc(1, 0); * @param x - The buffer to be converted. * @returns The DER-encoded buffer. */ -function toDER(x: Buffer): Buffer { +function toDER(x: Uint8Array): Uint8Array { let i = 0; while (x[i] === 0) ++i; if (i === x.length) return ZERO; x = x.slice(i); - if (x[0] & 0x80) return Buffer.concat([ZERO, x], 1 + x.length); + if (x[0] & 0x80) return tools.concat([ZERO, x]); return x; } @@ -25,16 +26,17 @@ function toDER(x: Buffer): Buffer { * @param x - The DER-encoded signature. * @returns The converted buffer. */ -function fromDER(x: Buffer): Buffer { +function fromDER(x: Uint8Array): Uint8Array { if (x[0] === 0x00) x = x.slice(1); - const buffer = Buffer.alloc(32, 0); + const buffer = new Uint8Array(32); const bstart = Math.max(0, 32 - x.length); - x.copy(buffer, bstart); + // x.copy(buffer, bstart); + buffer.set(x, bstart); return buffer; } interface ScriptSignature { - signature: Buffer; + signature: Uint8Array; hashType: number; } @@ -45,13 +47,14 @@ interface ScriptSignature { * @returns The decoded ScriptSignature object. * @throws Error if the hashType is invalid. */ -export function decode(buffer: Buffer): ScriptSignature { - const hashType = buffer.readUInt8(buffer.length - 1); +export function decode(buffer: Uint8Array): ScriptSignature { + // const hashType = buffer.readUInt8(buffer.length - 1); + const hashType = tools.readUInt8(buffer, buffer.length - 1); if (!isDefinedHashType(hashType)) { throw new Error('Invalid hashType ' + hashType); } - const decoded = bip66.decode(buffer.slice(0, -1)); + const decoded = bip66.decode(buffer.subarray(0, -1)); const r = fromDER(decoded.r); const s = fromDER(decoded.s); const signature = Buffer.concat([r, s], 64); @@ -66,7 +69,7 @@ export function decode(buffer: Buffer): ScriptSignature { * @returns The encoded buffer. * @throws Error if the hashType is invalid. */ -export function encode(signature: Buffer, hashType: number): Buffer { +export function encode(signature: Uint8Array, hashType: number): Uint8Array { typeforce( { signature: types.BufferN(64), @@ -79,11 +82,14 @@ export function encode(signature: Buffer, hashType: number): Buffer { throw new Error('Invalid hashType ' + hashType); } - const hashTypeBuffer = Buffer.allocUnsafe(1); - hashTypeBuffer.writeUInt8(hashType, 0); + // const hashTypeBuffer = Buffer.allocUnsafe(1); + const hashTypeBuffer = new Uint8Array(1); + // hashTypeBuffer.writeUInt8(hashType, 0); + tools.writeUInt8(hashTypeBuffer, hashType, 0); const r = toDER(signature.slice(0, 32)); const s = toDER(signature.slice(32, 64)); - return Buffer.concat([bip66.encode(r, s), hashTypeBuffer]); + // return Buffer.concat([bip66.encode(r, s), hashTypeBuffer]); + return tools.concat([bip66.encode(r, s), hashTypeBuffer]); } diff --git a/ts_src/transaction.ts b/ts_src/transaction.ts index 48f68e54f..2ef8db45a 100644 --- a/ts_src/transaction.ts +++ b/ts_src/transaction.ts @@ -3,20 +3,22 @@ import { BufferWriter, reverseBuffer, varuint, -} from './bufferutils'; -import * as bcrypto from './crypto'; -import * as bscript from './script'; -import { OPS as opcodes } from './script'; -import * as types from './types'; +} from './bufferutils.js'; +import * as bcrypto from './crypto.js'; +import { sha256 } from '@noble/hashes/sha256'; +import * as bscript from './script.js'; +import { OPS as opcodes } from './script.js'; +import * as types from './types.js'; +import * as tools from "uint8array-tools"; const { typeforce } = types; -function varSliceSize(someScript: Buffer): number { +function varSliceSize(someScript: Uint8Array): number { const length = someScript.length; return varuint.encodingLength(length) + length; } -function vectorSize(someVector: Buffer[]): number { +function vectorSize(someVector: Uint8Array[]): number { const length = someVector.length; return ( @@ -27,16 +29,18 @@ function vectorSize(someVector: Buffer[]): number { ); } -const EMPTY_BUFFER: Buffer = Buffer.allocUnsafe(0); -const EMPTY_WITNESS: Buffer[] = []; -const ZERO: Buffer = Buffer.from( - '0000000000000000000000000000000000000000000000000000000000000000', - 'hex', -); -const ONE: Buffer = Buffer.from( - '0000000000000000000000000000000000000000000000000000000000000001', - 'hex', -); +const EMPTY_BUFFER = new Uint8Array(0); +const EMPTY_WITNESS: Uint8Array[] = []; +// const ZERO: Buffer = Buffer.from( +// '0000000000000000000000000000000000000000000000000000000000000000', +// 'hex', +// ); +const ZERO = tools.fromHex('0000000000000000000000000000000000000000000000000000000000000000'); +// const ONE: Buffer = Buffer.from( +// '0000000000000000000000000000000000000000000000000000000000000001', +// 'hex', +// ); +const ONE = tools.fromHex('0000000000000000000000000000000000000000000000000000000000000001'); const VALUE_UINT64_MAX: Buffer = Buffer.from('ffffffffffffffff', 'hex'); const BLANK_OUTPUT = { script: EMPTY_BUFFER, @@ -48,16 +52,16 @@ function isOutput(out: Output): boolean { } export interface Output { - script: Buffer; - value: number; + script: Uint8Array; + value: bigint; } export interface Input { - hash: Buffer; + hash: Uint8Array; index: number; - script: Buffer; + script: Uint8Array; sequence: number; - witness: Buffer[]; + witness: Uint8Array[]; } /** @@ -75,7 +79,7 @@ export class Transaction { static readonly ADVANCED_TRANSACTION_MARKER = 0x00; static readonly ADVANCED_TRANSACTION_FLAG = 0x01; - static fromBuffer(buffer: Buffer, _NO_STRICT?: boolean): Transaction { + static fromBuffer(buffer: Uint8Array, _NO_STRICT?: boolean): Transaction { const bufferReader = new BufferReader(buffer); const tx = new Transaction(); @@ -136,7 +140,7 @@ export class Transaction { return Transaction.fromBuffer(Buffer.from(hex, 'hex'), false); } - static isCoinbaseHash(buffer: Buffer): boolean { + static isCoinbaseHash(buffer: Uint8Array): boolean { typeforce(types.Hash256bit, buffer); for (let i = 0; i < 32; ++i) { if (buffer[i] !== 0) return false; @@ -187,14 +191,14 @@ export class Transaction { ); } - addOutput(scriptPubKey: Buffer, value: number): number { + addOutput(scriptPubKey: Buffer, value: number | bigint): number { typeforce(types.tuple(types.Buffer, types.Satoshi), arguments); // Add the output and return the output's index return ( this.outs.push({ script: scriptPubKey, - value, + value: BigInt(value), }) - 1 ); } @@ -271,9 +275,9 @@ export class Transaction { */ hashForSignature( inIndex: number, - prevOutScript: Buffer, + prevOutScript: Uint8Array, hashType: number, - ): Buffer { + ): Uint8Array { typeforce( types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), arguments, @@ -347,12 +351,12 @@ export class Transaction { hashForWitnessV1( inIndex: number, - prevOutScripts: Buffer[], + prevOutScripts: Uint8Array[], values: number[], hashType: number, - leafHash?: Buffer, - annex?: Buffer, - ): Buffer { + leafHash?: Uint8Array, + annex?: Uint8Array, + ): Uint8Array { // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#common-signature-message typeforce( types.tuple( @@ -394,11 +398,11 @@ export class Transaction { bufferWriter.writeSlice(txIn.hash); bufferWriter.writeUInt32(txIn.index); }); - hashPrevouts = bcrypto.sha256(bufferWriter.end()); + hashPrevouts = sha256(bufferWriter.end()); bufferWriter = BufferWriter.withCapacity(8 * this.ins.length); values.forEach(value => bufferWriter.writeUInt64(value)); - hashAmounts = bcrypto.sha256(bufferWriter.end()); + hashAmounts = sha256(bufferWriter.end()); bufferWriter = BufferWriter.withCapacity( prevOutScripts.map(varSliceSize).reduce((a, b) => a + b), @@ -406,11 +410,11 @@ export class Transaction { prevOutScripts.forEach(prevOutScript => bufferWriter.writeVarSlice(prevOutScript), ); - hashScriptPubKeys = bcrypto.sha256(bufferWriter.end()); + hashScriptPubKeys = sha256(bufferWriter.end()); bufferWriter = BufferWriter.withCapacity(4 * this.ins.length); this.ins.forEach(txIn => bufferWriter.writeUInt32(txIn.sequence)); - hashSequences = bcrypto.sha256(bufferWriter.end()); + hashSequences = sha256(bufferWriter.end()); } if (!(isNone || isSingle)) { @@ -422,11 +426,12 @@ export class Transaction { const bufferWriter = BufferWriter.withCapacity(txOutsSize); this.outs.forEach(out => { - bufferWriter.writeUInt64(out.value); + // bufferWriter.writeUInt64(out.value); + bufferWriter.writeInt64(out.value) bufferWriter.writeVarSlice(out.script); }); - hashOutputs = bcrypto.sha256(bufferWriter.end()); + hashOutputs = sha256(bufferWriter.end()); } else if (isSingle && inIndex < this.outs.length) { const output = this.outs[inIndex]; @@ -435,7 +440,7 @@ export class Transaction { ); bufferWriter.writeUInt64(output.value); bufferWriter.writeVarSlice(output.script); - hashOutputs = bcrypto.sha256(bufferWriter.end()); + hashOutputs = sha256(bufferWriter.end()); } const spendType = (leafHash ? 2 : 0) + (annex ? 1 : 0); @@ -478,7 +483,7 @@ export class Transaction { if (annex) { const bufferWriter = BufferWriter.withCapacity(varSliceSize(annex)); bufferWriter.writeVarSlice(annex); - sigMsgWriter.writeSlice(bcrypto.sha256(bufferWriter.end())); + sigMsgWriter.writeSlice(sha256(bufferWriter.end())); } // Output if (isSingle) { @@ -501,16 +506,16 @@ export class Transaction { hashForWitnessV0( inIndex: number, - prevOutScript: Buffer, - value: number, + prevOutScript: Uint8Array, + value: bigint, hashType: number, - ): Buffer { + ): Uint8Array { typeforce( types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), arguments, ); - let tbuffer: Buffer = Buffer.from([]); + let tbuffer: Uint8Array = Uint8Array.from([]); let bufferWriter: BufferWriter; let hashOutputs = ZERO; @@ -593,23 +598,23 @@ export class Transaction { return bcrypto.hash256(tbuffer); } - getHash(forWitness?: boolean): Buffer { + getHash(forWitness?: boolean): Uint8Array { // wtxid for coinbase is always 32 bytes of 0x00 - if (forWitness && this.isCoinbase()) return Buffer.alloc(32, 0); + if (forWitness && this.isCoinbase()) return new Uint8Array(32); return bcrypto.hash256(this.__toBuffer(undefined, undefined, forWitness)); } getId(): string { // transaction hash's are displayed in reverse order - return reverseBuffer(this.getHash(false)).toString('hex'); + return tools.toHex(reverseBuffer(this.getHash(false))); } - toBuffer(buffer?: Buffer, initialOffset?: number): Buffer { + toBuffer(buffer?: Uint8Array, initialOffset?: number): Uint8Array { return this.__toBuffer(buffer, initialOffset, true); } toHex(): string { - return this.toBuffer(undefined, undefined).toString('hex'); + return tools.toHex(this.toBuffer(undefined, undefined)); } setInputScript(index: number, scriptSig: Buffer): void { @@ -625,12 +630,12 @@ export class Transaction { } private __toBuffer( - buffer?: Buffer, + buffer?: Uint8Array, initialOffset?: number, _ALLOW_WITNESS: boolean = false, - ): Buffer { + ): Uint8Array { if (!buffer) - buffer = Buffer.allocUnsafe(this.byteLength(_ALLOW_WITNESS)) as Buffer; + buffer = new Uint8Array(this.byteLength(_ALLOW_WITNESS)) as Buffer; const bufferWriter = new BufferWriter(buffer, initialOffset || 0); diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 000000000..38997b07f --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "commonjs", + "outDir": "./src", + "rootDir": "./ts_src", + "types": ["node"], + "allowJs": false, + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "strictBindCallApply": true, + "strictPropertyInitialization": true, + "noImplicitThis": true, + "alwaysStrict": true, + "esModuleInterop": true, + "noUnusedLocals": true, + "noUnusedParameters": true + }, + "include": ["ts_src/**/*.ts"], + "exclude": ["node_modules/**/*"] + } + \ No newline at end of file diff --git a/tsconfig.cjs.json b/tsconfig.cjs.json new file mode 100644 index 000000000..705d59dea --- /dev/null +++ b/tsconfig.cjs.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.base.json", + "compilerOptions": { + "declaration": true, + "outDir": "src/cjs", + "module": "commonjs", + } + } + \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index be06379a7..25e32d29b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,24 +1,9 @@ { + "extends": "./tsconfig.base.json", "compilerOptions": { - "target": "ES2020", - "module": "commonjs", - "outDir": "./src", - "declaration": true, - "rootDir": "./ts_src", - "types": [ - "node" - ], - "allowJs": false, - "strict": true, - "esModuleInterop": false, - "noUnusedLocals": true, - "noUnusedParameters": true + "outDir": "src/esm", + "resolveJsonModule": true, + "module": "NodeNext", + "moduleResolution": "NodeNext" }, - "include": [ - "ts_src/**/*.ts" - ], - "exclude": [ - "**/*.spec.ts", - "node_modules/**/*" - ] } From 847090cbb2e42206481f48f8c29d4813e6a029e8 Mon Sep 17 00:00:00 2001 From: ayman Date: Mon, 26 Aug 2024 17:00:27 +0530 Subject: [PATCH 3/6] feat: add valibot, switch to uint8array, support esm --- .eslintrc | 57 - .mocharc.json | 4 + eslint.config.js | 78 + fixup.cjs | 25 + package-lock.json | 6893 ++++------------- package.json | 54 +- src/cjs/{address.js => address.cjs} | 61 +- src/cjs/address.d.ts | 15 +- src/cjs/{bip66.js => bip66.cjs} | 15 +- src/cjs/bip66.d.ts | 11 +- src/cjs/{block.js => block.cjs} | 70 +- src/cjs/block.d.ts | 21 +- src/cjs/{bufferutils.js => bufferutils.cjs} | 122 +- src/cjs/bufferutils.d.ts | 41 +- src/cjs/{crypto.js => crypto.cjs} | 104 +- src/cjs/crypto.d.ts | 14 +- src/cjs/{ecc_lib.js => ecc_lib.cjs} | 54 +- src/cjs/ecc_lib.d.ts | 2 +- src/cjs/{index.js => index.cjs} | 30 +- src/cjs/index.d.ts | 28 +- src/cjs/merkle.cjs | 74 + src/cjs/merkle.d.ts | 3 +- src/cjs/merkle.js | 30 - src/cjs/{networks.js => networks.cjs} | 0 src/cjs/{ops.js => ops.cjs} | 0 src/cjs/payments/{bip341.js => bip341.cjs} | 71 +- src/cjs/payments/bip341.d.ts | 19 +- src/cjs/payments/{embed.js => embed.cjs} | 42 +- src/cjs/payments/embed.d.ts | 2 +- src/cjs/payments/{index.js => index.cjs} | 32 +- src/cjs/payments/index.d.ts | 43 +- src/cjs/payments/{lazy.js => lazy.cjs} | 5 +- src/cjs/payments/lazy.d.ts | 2 +- src/cjs/payments/{p2ms.js => p2ms.cjs} | 78 +- src/cjs/payments/p2ms.d.ts | 2 +- src/cjs/payments/{p2pk.js => p2pk.cjs} | 54 +- src/cjs/payments/p2pk.d.ts | 2 +- src/cjs/payments/{p2pkh.js => p2pkh.cjs} | 95 +- src/cjs/payments/p2pkh.d.ts | 2 +- src/cjs/payments/{p2sh.js => p2sh.cjs} | 116 +- src/cjs/payments/p2sh.d.ts | 2 +- src/cjs/payments/{p2tr.js => p2tr.cjs} | 177 +- src/cjs/payments/p2tr.d.ts | 2 +- src/cjs/payments/{p2wpkh.js => p2wpkh.cjs} | 84 +- src/cjs/payments/p2wpkh.d.ts | 2 +- src/cjs/payments/{p2wsh.js => p2wsh.cjs} | 100 +- src/cjs/payments/p2wsh.d.ts | 2 +- src/cjs/{psbt.js => psbt.cjs} | 280 +- src/cjs/psbt.d.ts | 75 +- src/cjs/psbt/{bip371.js => bip371.cjs} | 168 +- src/cjs/psbt/bip371.d.ts | 17 +- src/cjs/psbt/{psbtutils.js => psbtutils.cjs} | 57 +- src/cjs/psbt/psbtutils.d.ts | 29 +- src/cjs/push_data.cjs | 144 + src/cjs/push_data.d.ts | 5 +- src/cjs/push_data.js | 82 - src/cjs/{script.js => script.cjs} | 121 +- src/cjs/script.d.ts | 23 +- src/cjs/script_number.cjs | 126 + src/cjs/script_number.d.ts | 9 +- src/cjs/script_number.js | 78 - ...ript_signature.js => script_signature.cjs} | 60 +- src/cjs/script_signature.d.ts | 7 +- src/cjs/{transaction.js => transaction.cjs} | 220 +- src/cjs/transaction.d.ts | 33 +- src/cjs/types.cjs | 157 + src/cjs/types.d.ts | 37 +- src/cjs/types.js | 106 - src/esm/address.js | 29 +- src/esm/bip66.js | 8 +- src/esm/block.js | 56 +- src/esm/bufferutils.js | 107 +- src/esm/crypto.js | 39 +- src/esm/ecc_lib.js | 5 +- src/esm/index.js | 20 +- src/esm/merkle.js | 3 +- src/esm/payments/bip341.js | 35 +- src/esm/payments/embed.js | 33 +- src/esm/payments/index.js | 16 +- src/esm/payments/p2ms.js | 56 +- src/esm/payments/p2pk.js | 47 +- src/esm/payments/p2pkh.js | 86 +- src/esm/payments/p2sh.js | 100 +- src/esm/payments/p2tr.js | 122 +- src/esm/payments/p2wpkh.js | 73 +- src/esm/payments/p2wsh.js | 93 +- src/esm/psbt.js | 114 +- src/esm/psbt/bip371.js | 48 +- src/esm/psbt/psbtutils.js | 30 +- src/esm/push_data.js | 36 +- src/esm/script.js | 66 +- src/esm/script_number.js | 35 +- src/esm/script_signature.js | 51 +- src/esm/transaction.js | 177 +- src/esm/types.js | 87 +- test/address.spec.ts | 54 +- test/bitcoin.core.spec.ts | 14 +- test/block.spec.ts | 22 +- test/bufferutils.spec.ts | 115 +- test/crypto.spec.ts | 21 +- test/fixtures/crypto.json | 20 +- test/fixtures/p2pk.json | 2 +- test/fixtures/p2pkh.json | 2 +- test/fixtures/p2sh.json | 2 +- test/fixtures/p2tr.json | 4 +- test/fixtures/psbt.json | 2 +- test/fixtures/script.json | 2 +- test/fixtures/transaction.json | 4 +- test/integration/bip32.spec.ts | 2 +- test/integration/cltv.spec.ts | 32 +- test/integration/csv.spec.ts | 74 +- test/integration/payments.spec.ts | 5 +- test/integration/taproot.spec.ts | 233 +- test/integration/transactions.spec.ts | 55 +- test/payments.spec.ts | 252 +- test/payments.utils.ts | 22 +- test/psbt.spec.ts | 119 +- test/script.spec.ts | 31 +- test/script_number.spec.ts | 7 +- test/script_signature.spec.ts | 24 +- test/transaction.spec.ts | 35 +- test/ts-node-register.js | 5 - test/tsconfig.json | 40 - test/types.spec.ts | 40 +- ts_src/address.ts | 41 +- ts_src/bip66.ts | 6 +- ts_src/block.ts | 77 +- ts_src/bufferutils.ts | 98 +- ts_src/crypto.ts | 29 +- ts_src/ecc_lib.ts | 7 +- ts_src/index.ts | 28 +- ts_src/merkle.ts | 10 +- ts_src/payments/bip341.ts | 66 +- ts_src/payments/embed.ts | 39 +- ts_src/payments/index.ts | 20 +- ts_src/payments/lazy.ts | 2 +- ts_src/payments/p2ms.ts | 73 +- ts_src/payments/p2pk.ts | 56 +- ts_src/payments/p2pkh.ts | 106 +- ts_src/payments/p2sh.ts | 110 +- ts_src/payments/p2tr.ts | 125 +- ts_src/payments/p2wpkh.ts | 82 +- ts_src/payments/p2wsh.ts | 103 +- ts_src/psbt.ts | 302 +- ts_src/psbt/bip371.ts | 98 +- ts_src/psbt/psbtutils.ts | 38 +- ts_src/push_data.ts | 26 +- ts_src/script.ts | 65 +- ts_src/script_number.ts | 40 +- ts_src/script_signature.ts | 29 +- ts_src/transaction.ts | 154 +- ts_src/types.ts | 96 +- tsconfig.base.json | 4 +- tsconfig.cjs.json | 3 +- tsconfig.json | 3 +- 155 files changed, 6561 insertions(+), 8761 deletions(-) delete mode 100644 .eslintrc create mode 100644 .mocharc.json create mode 100644 eslint.config.js create mode 100755 fixup.cjs rename src/cjs/{address.js => address.cjs} (86%) rename src/cjs/{bip66.js => bip66.cjs} (95%) rename src/cjs/{block.js => block.cjs} (75%) rename src/cjs/{bufferutils.js => bufferutils.cjs} (60%) rename src/cjs/{crypto.js => crypto.cjs} (66%) rename src/cjs/{ecc_lib.js => ecc_lib.cjs} (70%) rename src/cjs/{index.js => index.cjs} (76%) create mode 100644 src/cjs/merkle.cjs delete mode 100644 src/cjs/merkle.js rename src/cjs/{networks.js => networks.cjs} (100%) rename src/cjs/{ops.js => ops.cjs} (100%) rename src/cjs/payments/{bip341.js => bip341.cjs} (75%) rename src/cjs/payments/{embed.js => embed.cjs} (74%) rename src/cjs/payments/{index.js => index.cjs} (63%) rename src/cjs/payments/{lazy.js => lazy.cjs} (94%) rename src/cjs/payments/{p2ms.js => p2ms.cjs} (73%) rename src/cjs/payments/{p2pk.js => p2pk.cjs} (70%) rename src/cjs/payments/{p2pkh.js => p2pkh.cjs} (64%) rename src/cjs/payments/{p2sh.js => p2sh.cjs} (67%) rename src/cjs/payments/{p2tr.js => p2tr.cjs} (60%) rename src/cjs/payments/{p2wpkh.js => p2wpkh.cjs} (66%) rename src/cjs/payments/{p2wsh.js => p2wsh.cjs} (73%) rename src/cjs/{psbt.js => psbt.cjs} (85%) rename src/cjs/psbt/{bip371.js => bip371.cjs} (80%) rename src/cjs/psbt/{psbtutils.js => psbtutils.cjs} (85%) create mode 100644 src/cjs/push_data.cjs delete mode 100644 src/cjs/push_data.js rename src/cjs/{script.js => script.cjs} (72%) create mode 100644 src/cjs/script_number.cjs delete mode 100644 src/cjs/script_number.js rename src/cjs/{script_signature.js => script_signature.cjs} (68%) rename src/cjs/{transaction.js => transaction.cjs} (73%) create mode 100644 src/cjs/types.cjs delete mode 100644 src/cjs/types.js delete mode 100644 test/ts-node-register.js delete mode 100644 test/tsconfig.json diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index cae665a54..000000000 --- a/.eslintrc +++ /dev/null @@ -1,57 +0,0 @@ -{ - "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/.mocharc.json b/.mocharc.json new file mode 100644 index 000000000..3cfb40bae --- /dev/null +++ b/.mocharc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://json.schemastore.org/mocharc.json", + "require": "tsx" +} \ No newline at end of file diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 000000000..a361d046e --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,78 @@ +import typescriptEslint from "@typescript-eslint/eslint-plugin"; +import globals from "globals"; +import tsParser from "@typescript-eslint/parser"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import js from "@eslint/js"; +import { FlatCompat } from "@eslint/eslintrc"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, + allConfig: js.configs.all +}); + +export default [...compat.extends( + "eslint:recommended", + "prettier", + "plugin:@typescript-eslint/recommended", + "plugin:prettier/recommended", +), { + plugins: { + "@typescript-eslint": typescriptEslint, + }, + + languageOptions: { + globals: { + ...globals.browser, + ...globals.amd, + ...globals.node, + }, + + parser: tsParser, + }, + + 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", + + "@/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", + "@typescript-eslint/no-empty-object-type": "off", + "space-before-function-paren": "off", + }, +}]; \ No newline at end of file diff --git a/fixup.cjs b/fixup.cjs new file mode 100755 index 000000000..98fbe68c3 --- /dev/null +++ b/fixup.cjs @@ -0,0 +1,25 @@ +const fs = require('fs'); +const path = require('path'); + +const updateRequires = (filePath) => { + let content = fs.readFileSync(filePath, 'utf8'); + //replace local imports eg. require("./ecpair.js") to require("ecpair.cjs") + content = content.replace(/require\('\.\/([^']*)\.js'\)/g, "require('./$1.cjs')"); + content = content.replace(/require\('\.\.\/([^']*)\.js'\)/g, "require('../$1.cjs')"); + + fs.writeFileSync(filePath, content, 'utf8'); +}; + +const processFiles = (dir) => { + fs.readdirSync(dir).forEach((file) => { + const filePath = path.join(dir, file); + if (fs.lstatSync(filePath).isDirectory()) { + processFiles(filePath); + } else if (filePath.endsWith('.cjs')) { + updateRequires(filePath); + } + }); +}; + +const dir = path.join(__dirname, 'src', 'cjs'); +processFiles(dir); diff --git a/package-lock.json b/package-lock.json index ed2883af3..dddd21d9f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,7 +1,7 @@ { "name": "bitcoinjs-lib", "version": "6.1.6", - "lockfileVersion": 2, + "lockfileVersion": 3, "requires": true, "packages": { "": { @@ -15,44 +15,49 @@ "bs58check": "^4.0.0", "typeforce": "^1.11.3", "uint8array-tools": "../uint8array-tools", + "valibot": "^0.38.0", "varuint-bitcoin": "../varuint-bitcoin" }, "devDependencies": { + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "^9.9.1", "@types/bs58": "^4.0.0", "@types/bs58check": "^2.1.0", "@types/mocha": "^5.2.7", - "@types/node": "^16.11.7", + "@types/node": "^18.7.14", "@types/proxyquire": "^1.3.28", "@types/randombytes": "^2.0.0", - "@typescript-eslint/eslint-plugin": "^5.45.0", - "@typescript-eslint/parser": "^5.45.0", + "@typescript-eslint/eslint-plugin": "^8.2.0", + "@typescript-eslint/parser": "^8.2.0", "better-npm-audit": "^3.7.3", - "bip32": "^4.0.0", + "bip32": "../bip32", "bip39": "^3.1.0", "bip65": "^1.0.1", "bip68": "^1.0.3", "bs58": "^4.0.0", + "c8": "^10.1.2", "dhttp": "^3.0.0", - "ecpair": "^2.0.1", - "eslint": "^8.29.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-prettier": "^4.2.1", + "ecpair": "../ecpair", + "eslint": "^9.9.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.2.1", + "globals": "^15.9.0", "hoodwink": "^2.0.0", "minimaldata": "^1.0.2", "mocha": "^10.6.0", - "nyc": "^15.1.0", - "prettier": "^2.8.0", + "prettier": "^3.0.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", - "typedoc": "^0.25.1", - "typescript": "^4.4.4" + "tsx": "^4.17.0", + "typedoc": "^0.26.6", + "typescript": "^5.0.4" }, "engines": { - "node": ">=8.0.0" + "node": ">=18.0.0" } }, "../bip174": { @@ -77,6 +82,71 @@ "node": ">=18.0.0" } }, + "../bip32": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.2.0", + "@scure/base": "^1.1.1", + "uint8array-tools": "^0.0.8", + "valibot": "^0.37.0", + "wif": "^5.0.0" + }, + "devDependencies": { + "@types/node": "18.x", + "@types/tape": "^5.6.4", + "c8": "^10.1.2", + "prettier": "1.16.4", + "tape": "^5.3.0", + "tiny-secp256k1": "^2.2.1", + "tslint": "^6.1.0", + "typescript": "^5.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../ecpair": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "uint8array-tools": "^0.0.8", + "valibot": "^0.37.0", + "wif": "^5.0.0" + }, + "devDependencies": { + "@types/create-hash": "^1.2.2", + "@types/mocha": "^5.2.7", + "@types/node": "^20.14.2", + "@types/proxyquire": "^1.3.28", + "@types/randombytes": "^2.0.0", + "@types/wif": "^2.0.2", + "bip39": "^3.0.2", + "bip65": "^1.0.1", + "bip68": "^1.0.3", + "bn.js": "^4.11.8", + "bs58": "^4.0.0", + "c8": "^10.1.2", + "create-hash": "^1.2.0", + "dhttp": "^3.0.0", + "ecpair": ".", + "minimaldata": "^1.0.2", + "mocha": "^10.0.4", + "npm-audit-whitelister": "^1.0.2", + "prettier": "^3.3.3", + "proxyquire": "^2.0.1", + "rimraf": "^2.6.3", + "tiny-secp256k1": "^2.2.1", + "tslint": "^6.1.3", + "tsx": "^4.16.5", + "typescript": "^5.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, "../uint8array-tools": { "version": "0.0.8", "license": "MIT", @@ -112,645 +182,607 @@ "typescript": "^5.1.6" } }, - "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/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true }, - "node_modules/@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "node_modules/@esbuild/aix-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz", + "integrity": "sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==", + "cpu": [ + "ppc64" + ], "dev": true, - "dependencies": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" - }, + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/code-frame/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==", + "node_modules/@esbuild/android-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.1.tgz", + "integrity": "sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==", + "cpu": [ + "arm" + ], "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=4" + "node": ">=18" } }, - "node_modules/@babel/code-frame/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==", + "node_modules/@esbuild/android-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz", + "integrity": "sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=4" + "node": ">=18" } }, - "node_modules/@babel/code-frame/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==", + "node_modules/@esbuild/android-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.1.tgz", + "integrity": "sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "color-name": "1.1.3" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@babel/code-frame/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/code-frame/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==", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz", + "integrity": "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==", + "cpu": [ + "arm64" + ], "dev": true, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=0.8.0" + "node": ">=18" } }, - "node_modules/@babel/code-frame/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==", + "node_modules/@esbuild/darwin-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz", + "integrity": "sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==", + "cpu": [ + "x64" + ], "dev": true, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=4" + "node": ">=18" } }, - "node_modules/@babel/code-frame/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==", + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz", + "integrity": "sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=4" + "node": ">=18" } }, - "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==", + "node_modules/@esbuild/freebsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz", + "integrity": "sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==", + "cpu": [ + "x64" + ], "dev": true, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "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==", + "node_modules/@esbuild/linux-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz", + "integrity": "sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==", + "cpu": [ + "arm" + ], "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" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" + "node": ">=18" } }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "node_modules/@esbuild/linux-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz", + "integrity": "sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==", + "cpu": [ + "arm64" + ], "dev": true, - "bin": { - "semver": "bin/semver.js" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@babel/generator": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", - "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", + "node_modules/@esbuild/linux-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz", + "integrity": "sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==", + "cpu": [ + "ia32" + ], "dev": true, - "dependencies": { - "@babel/types": "^7.23.0", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "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==", + "node_modules/@esbuild/linux-loong64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz", + "integrity": "sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==", + "cpu": [ + "loong64" + ], "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.0.0" + "node": ">=18" } }, - "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==", + "node_modules/@esbuild/linux-mips64el": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz", + "integrity": "sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==", + "cpu": [ + "mips64el" + ], "dev": true, - "dependencies": { - "@babel/compat-data": "^7.20.0", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "semver": "^6.3.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=18" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "node_modules/@esbuild/linux-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz", + "integrity": "sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==", + "cpu": [ + "ppc64" + ], "dev": true, - "bin": { - "semver": "bin/semver.js" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "node_modules/@esbuild/linux-riscv64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz", + "integrity": "sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==", + "cpu": [ + "riscv64" + ], "dev": true, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "node_modules/@esbuild/linux-s390x": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz", + "integrity": "sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==", + "cpu": [ + "s390x" + ], "dev": true, - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "node_modules/@esbuild/linux-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz", + "integrity": "sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "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==", + "node_modules/@esbuild/netbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz", + "integrity": "sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "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==", + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz", + "integrity": "sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==", + "cpu": [ + "arm64" + ], "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" - }, + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "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==", + "node_modules/@esbuild/openbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz", + "integrity": "sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "@babel/types": "^7.20.2" - }, + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "node_modules/@esbuild/sunos-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz", + "integrity": "sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, + "optional": true, + "os": [ + "sunos" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "node_modules/@esbuild/win32-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz", + "integrity": "sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==", + "cpu": [ + "arm64" + ], "dev": true, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "node_modules/@esbuild/win32-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz", + "integrity": "sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==", + "cpu": [ + "ia32" + ], "dev": true, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "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==", + "node_modules/@esbuild/win32-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz", + "integrity": "sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==", + "cpu": [ + "x64" + ], "dev": true, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "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==", + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", "dev": true, "dependencies": { - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.5", - "@babel/types": "^7.20.5" + "eslint-visitor-keys": "^3.3.0" }, "engines": { - "node": ">=6.9.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "node_modules/@eslint-community/regexpp": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, "engines": { - "node": ">=6.9.0" + "node": "^12.0.0 || ^14.0.0 || >=16.0.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==", + "node_modules/@eslint/config-array": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", + "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", "dev": true, "dependencies": { - "color-convert": "^1.9.0" + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" }, "engines": { - "node": ">=4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "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==", + "node_modules/@eslint/eslintrc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", "dev": true, "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.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": ">=4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "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==", + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, - "dependencies": { - "color-name": "1.1.3" + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "node_modules/@eslint/js": { + "version": "9.9.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.9.1.tgz", + "integrity": "sha512-xIDQRsfg5hNBqHz04H1R3scSVwmI+KUbqjsQKHKQ1DAUSaUjYPReZZmS/5PNiKu1fUvzDd6H7DEDKACSEhu+TQ==", "dev": true, "engines": { - "node": ">=0.8.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.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==", + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", "dev": true, "engines": { - "node": ">=4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "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==", + "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, - "dependencies": { - "has-flag": "^3.0.0" - }, "engines": { - "node": ">=4" + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@babel/parser": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", + "node_modules/@humanwhocodes/retry": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", + "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, "engines": { - "node": ">=6.0.0" + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" }, "engines": { - "node": ">=6.9.0" + "node": ">=12" } }, - "node_modules/@babel/traverse": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", - "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.0", - "@babel/types": "^7.23.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, "engines": { - "node": ">=6.9.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "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==", + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, "engines": { - "node": ">=4" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true }, - "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==", + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "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" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=12" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" + "ansi-regex": "^6.0.1" }, "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" + "node": ">=12" }, "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" + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "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==", + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, "dependencies": { - "p-try": "^2.0.0" + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=6" + "node": ">=12" }, "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" + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/@istanbuljs/schema": { @@ -762,63 +794,41 @@ "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==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "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==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "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==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" + "@jridgewell/resolve-uri": "^3.1.0", + "@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/" - } - ] + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", @@ -855,40 +865,69 @@ "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==", + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ] + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@shikijs/core": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.14.1.tgz", + "integrity": "sha512-KyHIIpKNaT20FtFPFjCQB5WVSTpLR/n+jQXhWHWVUMm9MaOaG9BGOG0MSyt7yA4+Lm+4c9rTc03tt3nYzeYSfw==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.4" + } }, "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==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/bs58/-/bs58-4.0.4.tgz", + "integrity": "sha512-0IEpMFXXQi2zXaXl9GJ3sRwQo0uEkD+yFOv+FnAU5lkPtcu6h61xb7jc2CFPEZ5BUOaiP13ThuGc9HD4R8lR5g==", "dev": true, "dependencies": { + "@types/node": "*", "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==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@types/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-xpXaQlOIY1KoXlA/ytHGHpEIU87PJt+g9SH7nC6HdCgaBwT2IEZIwBMHbjuX6BpnfbiUMlmwqurdLDwXpcdmSA==", "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==", + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dev": true, + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", "dev": true }, "node_modules/@types/mocha": { @@ -898,58 +937,61 @@ "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 + "version": "18.19.46", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.46.tgz", + "integrity": "sha512-vnRgMS7W6cKa1/0G3/DTtQYpVrZ8c0Xm6UkLaVFrb9jtcVC3okokW09Ki1Qdrj9ISokszD69nY4WDLRlvHlhAA==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } }, "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==", + "version": "1.3.31", + "resolved": "https://registry.npmjs.org/@types/proxyquire/-/proxyquire-1.3.31.tgz", + "integrity": "sha512-uALowNG2TSM1HNPMMOR0AJwv4aPYPhqB0xlEhkeRTMuto5hjoSPZkvgu1nbPUkz3gEPAHv4sy4DmKsurZiEfRQ==", "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==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/randombytes/-/randombytes-2.0.3.tgz", + "integrity": "sha512-+NRgihTfuURllWCiIAhm1wsJqzsocnqXM77V/CalsdJIYSRGEHMnritxh+6EsBklshC+clo1KgnN14qgSGeQdw==", "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==", + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", "dev": true }, "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" + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.2.0.tgz", + "integrity": "sha512-02tJIs655em7fvt9gps/+4k4OsKULYGtLBPJfOsmOq1+3cdClYiF0+d6mHu6qDnTcg88wJBkcPLpQhq7FyDz0A==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.2.0", + "@typescript-eslint/type-utils": "8.2.0", + "@typescript-eslint/utils": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.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" + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -958,25 +1000,26 @@ } }, "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==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.2.0.tgz", + "integrity": "sha512-j3Di+o0lHgPrb7FxL3fdEy6LJ/j2NE8u+AP/5cQ9SKb+JLH6V6UHDqJ+e0hXBkHP1wn1YDFjYCS9LBQsZDlDEg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.45.0", - "@typescript-eslint/types": "5.45.0", - "@typescript-eslint/typescript-estree": "5.45.0", + "@typescript-eslint/scope-manager": "8.2.0", + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/typescript-estree": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", "debug": "^4.3.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^8.57.0 || ^9.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -985,16 +1028,16 @@ } }, "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==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.2.0.tgz", + "integrity": "sha512-OFn80B38yD6WwpoHU2Tz/fTz7CgFqInllBoC3WP+/jLbTb4gGPTy9HBSTsbDWkMdN55XlVU0mMDYAtgvlUspGw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.45.0", - "@typescript-eslint/visitor-keys": "5.45.0" + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -1002,26 +1045,23 @@ } }, "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==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.2.0.tgz", + "integrity": "sha512-g1CfXGFMQdT5S+0PSO0fvGXUaiSkl73U1n9LTK5aRAFnPlJ8dLKkXr4AaLFvPedW8lVDoMgLLE3JN98ZZfsj0w==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.45.0", - "@typescript-eslint/utils": "5.45.0", + "@typescript-eslint/typescript-estree": "8.2.0", + "@typescript-eslint/utils": "8.2.0", "debug": "^4.3.4", - "tsutils": "^3.21.0" + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependencies": { - "eslint": "*" - }, "peerDependenciesMeta": { "typescript": { "optional": true @@ -1029,12 +1069,12 @@ } }, "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==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.2.0.tgz", + "integrity": "sha512-6a9QSK396YqmiBKPkJtxsgZZZVjYQ6wQ/TlI0C65z7vInaETuC6HAHD98AGLC8DyIPqHytvNuS8bBVvNLKyqvQ==", "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -1042,21 +1082,22 @@ } }, "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==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.2.0.tgz", + "integrity": "sha512-kiG4EDUT4dImplOsbh47B1QnNmXSoUqOjWDvCJw/o8LgfD0yr7k2uy54D5Wm0j4t71Ge1NkynGhpWdS0dEIAUA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.45.0", - "@typescript-eslint/visitor-keys": "5.45.0", + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/visitor-keys": "8.2.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -1068,43 +1109,63 @@ } } }, + "node_modules/@typescript-eslint/typescript-estree/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/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "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==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.2.0.tgz", + "integrity": "sha512-O46eaYKDlV3TvAVDNcoDzd5N550ckSe8G4phko++OCSC1dYIb9LTc3HDGYdWqWIAT5qDUKphO6sd9RrpIJJPfg==", "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" + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.2.0", + "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/typescript-estree": "8.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^8.57.0 || ^9.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==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.2.0.tgz", + "integrity": "sha512-sbgsPMW9yLvS7IhCi8IpuK1oBmtbWUNP+hBdwl/I9nzqVsszGnNGti5r9dUtF5RLivHUFFIdRvLiTsPhzSyJ3Q==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.45.0", - "eslint-visitor-keys": "^3.3.0" + "@typescript-eslint/types": "8.2.0", + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -1112,9 +1173,9 @@ } }, "node_modules/acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1132,19 +1193,6 @@ "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", @@ -1179,12 +1227,6 @@ "node": ">=8" } }, - "node_modules/ansi-sequence-parser": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz", - "integrity": "sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==", - "dev": true - }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -1213,24 +1255,6 @@ "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", @@ -1268,9 +1292,9 @@ "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==", + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.10.tgz", + "integrity": "sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==", "dev": true, "dependencies": { "safe-buffer": "^5.0.1" @@ -1282,14 +1306,15 @@ "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==", + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/better-npm-audit/-/better-npm-audit-3.8.3.tgz", + "integrity": "sha512-DY1VwwxUF/Bc5Rgh1kP0S8Jg63YyBICG+6/KGYjo9cqZ50jzF+bMSqez3yQ6Bvvf4vd9TRs/nw/GT/ZZEaLbvg==", "dev": true, "dependencies": { "commander": "^8.0.0", "dayjs": "^1.10.6", "lodash.get": "^4.4.2", + "semver": "^7.6.3", "table": "^6.7.1" }, "bin": { @@ -1300,12 +1325,15 @@ } }, "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==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/bip174": { @@ -1313,19 +1341,8 @@ "link": true }, "node_modules/bip32": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/bip32/-/bip32-4.0.0.tgz", - "integrity": "sha512-aOGy88DDlVUhspIXJN+dVEtclhIsfAUppD43V0j40cPTld3pv/0X/MlrZSZ6jowIaQQzFwP8M6rFU2z2mVYjDQ==", - "dev": true, - "dependencies": { - "@noble/hashes": "^1.2.0", - "@scure/base": "^1.1.1", - "typeforce": "^1.11.5", - "wif": "^2.0.6" - }, - "engines": { - "node": ">=6.0.0" - } + "resolved": "../bip32", + "link": true }, "node_modules/bip39": { "version": "3.1.0", @@ -1388,34 +1405,6 @@ "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", @@ -1453,19 +1442,37 @@ "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==", + "node_modules/c8": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/c8/-/c8-10.1.2.tgz", + "integrity": "sha512-Qr6rj76eSshu5CgRYvktW0uM0CFY0yi4Fd5D0duDXO6sYinyopmftUiJVuzBQxQcwQLor7JWDVRP+dUfCmzgJw==", "dev": true, "dependencies": { - "hasha": "^5.0.0", - "make-dir": "^3.0.0", - "package-hash": "^4.0.0", - "write-file-atomic": "^3.0.0" + "@bcoe/v8-coverage": "^0.2.3", + "@istanbuljs/schema": "^0.1.3", + "find-up": "^5.0.0", + "foreground-child": "^3.1.1", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.1.6", + "test-exclude": "^7.0.1", + "v8-to-istanbul": "^9.0.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1" + }, + "bin": { + "c8": "bin/c8.js" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "peerDependencies": { + "monocart-coverage-reports": "^2" + }, + "peerDependenciesMeta": { + "monocart-coverage-reports": { + "optional": true + } } }, "node_modules/callsites": { @@ -1478,30 +1485,17 @@ } }, "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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", @@ -1519,16 +1513,10 @@ } }, "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -1541,6 +1529,9 @@ "engines": { "node": ">= 8.10.0" }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, "optionalDependencies": { "fsevents": "~2.3.2" } @@ -1567,24 +1558,18 @@ "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==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "dependencies": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" } }, "node_modules/color-convert": { @@ -1614,12 +1599,6 @@ "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", @@ -1627,9 +1606,9 @@ "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==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, "node_modules/create-hash": { @@ -1660,15 +1639,15 @@ } }, "node_modules/dayjs": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.6.tgz", - "integrity": "sha512-zZbY5giJAinCG+7AGaw0wIhNZ6J8AhWuSXKvuc1KAyMiRsvGQWqh4L+MomvhdAYjN+lqvVCMq1I41e3YHvXkyQ==", + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", "dev": true }, "node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -1683,12 +1662,15 @@ } }, "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==", + "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": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/deep-is": { @@ -1697,21 +1679,6 @@ "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", @@ -1743,37 +1710,15 @@ "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/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true }, "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 + "resolved": "../ecpair", + "link": true }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -1781,16 +1726,61 @@ "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/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/esbuild": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz", + "integrity": "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.23.1", + "@esbuild/android-arm": "0.23.1", + "@esbuild/android-arm64": "0.23.1", + "@esbuild/android-x64": "0.23.1", + "@esbuild/darwin-arm64": "0.23.1", + "@esbuild/darwin-x64": "0.23.1", + "@esbuild/freebsd-arm64": "0.23.1", + "@esbuild/freebsd-x64": "0.23.1", + "@esbuild/linux-arm": "0.23.1", + "@esbuild/linux-arm64": "0.23.1", + "@esbuild/linux-ia32": "0.23.1", + "@esbuild/linux-loong64": "0.23.1", + "@esbuild/linux-mips64el": "0.23.1", + "@esbuild/linux-ppc64": "0.23.1", + "@esbuild/linux-riscv64": "0.23.1", + "@esbuild/linux-s390x": "0.23.1", + "@esbuild/linux-x64": "0.23.1", + "@esbuild/netbsd-x64": "0.23.1", + "@esbuild/openbsd-arm64": "0.23.1", + "@esbuild/openbsd-x64": "0.23.1", + "@esbuild/sunos-x64": "0.23.1", + "@esbuild/win32-arm64": "0.23.1", + "@esbuild/win32-ia32": "0.23.1", + "@esbuild/win32-x64": "0.23.1" + } }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true, "engines": { "node": ">=6" @@ -1809,65 +1799,68 @@ } }, "node_modules/eslint": { - "version": "8.29.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz", - "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==", + "version": "9.9.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.9.1.tgz", + "integrity": "sha512-dHvhrbfr4xFQ9/dq+jcVneZMyRYLjggWjk6RVsIiHsP8Rz6yZ8LvZ//iU4TrZF+SXWG+JkNF2OyiZRvzgRDqMg==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.11.6", + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.18.0", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.9.1", "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.0", "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", + "ajv": "^6.12.4", "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", + "eslint-scope": "^8.0.2", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "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", + "optionator": "^0.9.3", "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" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, "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==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", "dev": true, "bin": { "eslint-config-prettier": "bin/cli.js" @@ -1877,131 +1870,108 @@ } }, "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==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz", + "integrity": "sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==", "dev": true, "dependencies": { - "prettier-linter-helpers": "^1.0.0" + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.9.1" }, "engines": { - "node": ">=12.0.0" + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" }, "peerDependencies": { - "eslint": ">=7.28.0", - "prettier": ">=2.0.0" + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" }, "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, "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==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", + "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", "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" + "estraverse": "^5.2.0" }, "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.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" + "url": "https://opencollective.com/eslint" } }, "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==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "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" + "funding": { + "url": "https://opencollective.com/eslint" } }, - "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==", + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", "dev": true, "engines": { - "node": ">=4.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", "dev": true, "dependencies": { - "acorn": "^8.8.0", + "acorn": "^8.12.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^4.0.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.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==", + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, "engines": { - "node": ">=4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, "dependencies": { "estraverse": "^5.1.0" @@ -2010,15 +1980,6 @@ "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", @@ -2031,7 +1992,7 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { + "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", @@ -2040,15 +2001,6 @@ "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", @@ -2065,15 +2017,15 @@ "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==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", "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==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -2110,25 +2062,31 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fast-uri": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", + "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==", + "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==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "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==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" } }, "node_modules/fill-keys": { @@ -2156,23 +2114,6 @@ "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", @@ -2199,72 +2140,40 @@ } }, "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" + "flatted": "^3.2.9", + "keyv": "^4.5.4" }, "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": ">=16" } }, "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==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "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==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", "dev": true, "dependencies": { "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" + "signal-exit": "^4.0.1" }, "engines": { - "node": ">=8.0.0" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "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", @@ -2272,9 +2181,9 @@ "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==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, "optional": true, @@ -2286,18 +2195,12 @@ } }, "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==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, - "engines": { - "node": ">=6.9.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/get-caller-file": { @@ -2309,30 +2212,33 @@ "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==", + "node_modules/get-tsconfig": { + "version": "4.7.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.6.tgz", + "integrity": "sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA==", "dev": true, - "engines": { - "node": ">=8.0.0" + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", "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" + "minimatch": "^5.0.1", + "once": "^1.3.0" }, "engines": { - "node": "*" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -2350,27 +2256,45 @@ "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==", + "node_modules/glob/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": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "balanced-match": "^1.0.0" } }, - "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": { + "node_modules/glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/globals": { + "version": "15.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.9.0.tgz", + "integrity": "sha512-SmSKyLLKFbSr6rptvP8izbyxJL4ILwqO9Jg23UA0sDlGlu58V59D1//I3vlc0KJphVdUR7vMjHIplYnzBxorQA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "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", @@ -2385,30 +2309,12 @@ "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==", + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "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", @@ -2432,29 +2338,16 @@ "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==", + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, "dependencies": { - "is-stream": "^2.0.0", - "type-fest": "^0.8.0" - }, - "engines": { - "node": ">=8" + "function-bind": "^1.1.2" }, - "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": ">= 0.4" } }, "node_modules/he": { @@ -2479,9 +2372,9 @@ "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==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "engines": { "node": ">= 4" @@ -2512,19 +2405,11 @@ "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==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, "dependencies": { "once": "^1.3.0", @@ -2550,12 +2435,15 @@ } }, "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==", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", "dev": true, "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2627,24 +2515,6 @@ "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", @@ -2657,15 +2527,6 @@ "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", @@ -2673,114 +2534,32 @@ "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.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "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==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "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==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, "dependencies": { "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", + "make-dir": "^4.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==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", "dev": true, "dependencies": { "html-escaper": "^2.0.0", @@ -2790,22 +2569,21 @@ "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==", + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" } }, - "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", @@ -2818,17 +2596,11 @@ "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-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true }, "node_modules/json-schema-traverse": { "version": "0.4.1", @@ -2842,24 +2614,15 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" + "dependencies": { + "json-buffer": "3.0.1" } }, - "node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmmirror.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -2873,6 +2636,15 @@ "node": ">= 0.8.0" } }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "dev": true, + "dependencies": { + "uc.micro": "^2.0.0" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -2888,12 +2660,6 @@ "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", @@ -2928,52 +2694,54 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, "node_modules/lunr": { "version": "2.3.9", - "resolved": "https://registry.npmmirror.com/lunr/-/lunr-2.3.9.tgz", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", "dev": true }, "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==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, "dependencies": { - "semver": "^6.0.0" + "semver": "^7.5.3" }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "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/marked": { - "version": "4.3.0", - "resolved": "https://registry.npmmirror.com/marked/-/marked-4.3.0.tgz", - "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "node_modules/markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", "dev": true, - "bin": { - "marked": "bin/marked.js" + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" }, - "engines": { - "node": ">= 12" + "bin": { + "markdown-it": "bin/markdown-it.mjs" } }, "node_modules/md5.js": { @@ -2987,12 +2755,21 @@ "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==", + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", "dev": true }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -3003,12 +2780,12 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -3037,10 +2814,19 @@ "node": "*" } }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/mocha": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.6.0.tgz", - "integrity": "sha512-hxjt4+EEB0SA0ZDygSS015t65lJw/I2yRCS3Ae+SJ5FrbzrXgfYwJr96f0OvIXdj7h4lv/vLCrH3rkiuizFSvw==", + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.7.3.tgz", + "integrity": "sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A==", "dev": true, "dependencies": { "ansi-colors": "^4.1.3", @@ -3081,24 +2867,15 @@ "balanced-match": "^1.0.0" } }, - "node_modules/mocha/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "node_modules/mocha/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": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, "node_modules/mocha/node_modules/minimatch": { @@ -3134,6 +2911,33 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/mocha/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/mocha/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "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", @@ -3152,30 +2956,6 @@ "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", @@ -3185,189 +2965,6 @@ "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", @@ -3378,9 +2975,9 @@ } }, "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "dependencies": { "deep-is": "^0.1.3", @@ -3388,7 +2985,7 @@ "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" @@ -3424,41 +3021,11 @@ "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/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "dev": true }, "node_modules/parent-module": { "version": "1.0.1", @@ -3505,6 +3072,22 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -3514,12 +3097,6 @@ "node": ">=8" } }, - "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", @@ -3532,70 +3109,6 @@ "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", @@ -3606,15 +3119,15 @@ } }, "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==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", "dev": true, "bin": { - "prettier": "bin-prettier.js" + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">=10.13.0" + "node": ">=14" }, "funding": { "url": "https://github.com/prettier/prettier?sponsor=1" @@ -3632,18 +3145,6 @@ "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", @@ -3656,9 +3157,18 @@ } }, "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==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", "dev": true, "engines": { "node": ">=6" @@ -3703,9 +3213,9 @@ } }, "node_modules/readable-stream": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.1.tgz", - "integrity": "sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, "dependencies": { "inherits": "^2.0.3", @@ -3728,18 +3238,6 @@ "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", @@ -3762,18 +3260,6 @@ "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", - "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", @@ -3792,19 +3278,13 @@ "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==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "dependencies": { - "is-core-module": "^2.9.0", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -3824,6 +3304,15 @@ "node": ">=4" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -3838,6 +3327,7 @@ "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "dependencies": { "glob": "^7.1.3" @@ -3846,6 +3336,27 @@ "rimraf": "bin.js" } }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "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" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/ripemd160": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", @@ -3900,9 +3411,9 @@ ] }, "node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -3920,12 +3431,6 @@ "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", @@ -3961,22 +3466,26 @@ } }, "node_modules/shiki": { - "version": "0.14.4", - "resolved": "https://registry.npmmirror.com/shiki/-/shiki-0.14.4.tgz", - "integrity": "sha512-IXCRip2IQzKwxArNNq1S+On4KPML3Yyn8Zzs/xRgcgOWIr8ntIK3IKzjFPfjy/7kt9ZMjc+FItfqHRBg8b6tNQ==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.14.1.tgz", + "integrity": "sha512-FujAN40NEejeXdzPt+3sZ3F2dx1U24BY2XTY01+MG8mbxCiA2XukXdcbyMyLAHJ/1AUUnQd1tZlvIjefWWEJeA==", "dev": true, "dependencies": { - "ansi-sequence-parser": "^1.1.0", - "jsonc-parser": "^3.2.0", - "vscode-oniguruma": "^1.7.0", - "vscode-textmate": "^8.0.0" + "@shikijs/core": "1.14.1", + "@types/hast": "^3.0.4" } }, "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 + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, "node_modules/slash": { "version": "3.0.0", @@ -4023,51 +3532,13 @@ "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==", + "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, - "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": ">= 0.6" } }, "node_modules/string_decoder": { @@ -4093,6 +3564,21 @@ "node": ">=8" } }, + "node_modules/string-width-cjs": { + "name": "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", @@ -4105,11 +3591,15 @@ "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==", + "node_modules/strip-ansi-cjs": { + "name": "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" } @@ -4150,10 +3640,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/synckit": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.1.tgz", + "integrity": "sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==", + "dev": true, + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "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==", + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz", + "integrity": "sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==", "dev": true, "dependencies": { "ajv": "^8.0.1", @@ -4167,15 +3673,15 @@ } }, "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==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "dependencies": { - "fast-deep-equal": "^3.1.1", + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -4189,17 +3695,61 @@ "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==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", + "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", "dev": true, "dependencies": { "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" + "glob": "^10.4.1", + "minimatch": "^9.0.4" }, "engines": { - "node": ">=8" + "node": ">=18" + } + }, + "node_modules/test-exclude/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/test-exclude/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/text-table": { @@ -4209,9 +3759,9 @@ "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==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-2.2.3.tgz", + "integrity": "sha512-SGcL07SxcPN2nGKHTCvRMkQLYPSoeFcvArUSCYtjVARiFAWU44cCIqYS0mYAU6nY7XfvwURuTIGo2Omt3ZQr0Q==", "dev": true, "dependencies": { "uint8array-tools": "0.0.7" @@ -4229,15 +3779,6 @@ "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", @@ -4250,6 +3791,18 @@ "node": ">=8.0" } }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, "node_modules/ts-node": { "version": "8.10.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.2.tgz", @@ -4285,24 +3838,28 @@ } }, "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", "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==", + "node_modules/tsx": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.18.0.tgz", + "integrity": "sha512-a1jaKBSVQkd6yEc1/NI7G6yHFfefIcuf3QJST7ZEyn4oQnxLYrZR5uZAM8UrwUa3Ge8suiZHcNS1gNrEvmobqg==", "dev": true, "dependencies": { - "tslib": "^1.8.1" + "esbuild": "~0.23.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" }, "engines": { - "node": ">= 6" + "node": ">=18.0.0" }, - "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" + "optionalDependencies": { + "fsevents": "~2.3.3" } }, "node_modules/type-check": { @@ -4317,51 +3874,31 @@ "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/typedoc": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.1.tgz", - "integrity": "sha512-c2ye3YUtGIadxN2O6YwPEXgrZcvhlZ6HlhWZ8jQRNzwLPn2ylhdGqdR8HbyDRyALP8J6lmSANILCkkIdNPFxqA==", + "version": "0.26.6", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.26.6.tgz", + "integrity": "sha512-SfEU3SH3wHNaxhFPjaZE2kNl/NFtLNW5c1oHsg7mti7GjmUj1Roq6osBQeMd+F4kL0BoRBBr8gQAuqBlfFu8LA==", "dev": true, "dependencies": { "lunr": "^2.3.9", - "marked": "^4.3.0", - "minimatch": "^9.0.3", - "shiki": "^0.14.1" + "markdown-it": "^14.1.0", + "minimatch": "^9.0.5", + "shiki": "^1.9.1", + "yaml": "^2.4.5" }, "bin": { "typedoc": "bin/typedoc" }, "engines": { - "node": ">= 16" + "node": ">= 18" }, "peerDependencies": { - "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x" + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x" } }, "node_modules/typedoc/node_modules/brace-expansion": { "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "dependencies": { @@ -4369,15 +3906,18 @@ } }, "node_modules/typedoc/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/typeforce": { @@ -4386,47 +3926,33 @@ "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, + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "devOptional": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true + }, "node_modules/uint8array-tools": { "resolved": "../uint8array-tools", "link": true }, - "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/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true }, "node_modules/uri-js": { "version": "4.4.1", @@ -4443,31 +3969,37 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, - "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==", + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", "dev": true, - "bin": { - "uuid": "dist/bin/uuid" + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/valibot": { + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/valibot/-/valibot-0.38.0.tgz", + "integrity": "sha512-RCJa0fetnzp+h+KN9BdgYOgtsMAG9bfoJ9JSjIhFHobKWVWyzM3jjaeNTdpFK9tQtf3q1sguXeERJ/LcmdFE7w==", + "peerDependencies": { + "typescript": ">=5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/varuint-bitcoin": { "resolved": "../varuint-bitcoin", "link": true }, - "node_modules/vscode-oniguruma": { - "version": "1.7.0", - "resolved": "https://registry.npmmirror.com/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", - "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", - "dev": true - }, - "node_modules/vscode-textmate": { - "version": "8.0.0", - "resolved": "https://registry.npmmirror.com/vscode-textmate/-/vscode-textmate-8.0.0.tgz", - "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", - "dev": true - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -4483,32 +4015,6 @@ "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==", - "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==", - "dev": true, - "dependencies": { - "bs58": "^4.0.0", - "create-hash": "^1.1.0", - "safe-buffer": "^5.1.2" - } - }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -4541,24 +4047,30 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs": { + "name": "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", @@ -4568,31 +4080,43 @@ "node": ">=10" } }, + "node_modules/yaml": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz", + "integrity": "sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==", + "dev": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "dependencies": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.1.1" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/yargs-unparser": { @@ -4610,30 +4134,6 @@ "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", @@ -4655,3424 +4155,5 @@ "url": "https://github.com/sponsors/sindresorhus" } } - }, - "dependencies": { - "@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", - "dev": true, - "requires": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "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/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 - }, - "@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, - "requires": { - "@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" - }, - "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", - "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", - "dev": true, - "requires": { - "@babel/types": "^7.23.0", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - }, - "dependencies": { - "@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, - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - } - } - }, - "@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, - "requires": { - "@babel/compat-data": "^7.20.0", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - } - } - }, - "@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "dev": true - }, - "@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "dev": true, - "requires": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dev": true, - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@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, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@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, - "requires": { - "@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.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.20.2" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dev": true, - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "dev": true - }, - "@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 - }, - "@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, - "requires": { - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.5", - "@babel/types": "^7.20.5" - } - }, - "@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "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.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", - "dev": true - }, - "@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" - } - }, - "@babel/traverse": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", - "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.0", - "@babel/types": "^7.23.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "dependencies": { - "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.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "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", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "requires": { - "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" - }, - "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", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "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", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "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", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "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 - } - } - }, - "@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 - }, - "@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, - "requires": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@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 - }, - "@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 - }, - "@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 - }, - "@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, - "requires": { - "@jridgewell/resolve-uri": "3.1.0", - "@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", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@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" - } - }, - "@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", - "integrity": "sha512-yfAgiWgVLjFCmRv8zAcOIHywYATEwiTVccTLnRp6UxTNavT55M9d/uhK3T03St/+8/z/wW+CRjGKUNmEqoHHCA==", - "dev": true, - "requires": { - "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==", - "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", - "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", - "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==", - "dev": true - }, - "@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 - }, - "@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 - }, - "@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, - "requires": { - "@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 - }, - "@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", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, - "ajv": { - "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", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true - }, - "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 - }, - "ansi-sequence-parser": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz", - "integrity": "sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==", - "dev": true - }, - "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" - } - }, - "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, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "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, - "requires": { - "default-require-extensions": "^3.0.0" - } - }, - "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 - }, - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "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 - }, - "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", - "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.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.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" - } - }, - "bech32": { - "version": "2.0.0", - "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" - } - }, - "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 - }, - "bip174": { - "version": "file:../bip174", - "requires": { - "@types/node": "12.0.8", - "@types/tape": "4.2.33", - "bitcoinjs-lib": "^5.0.5", - "c8": "^10.1.2", - "prettier": "^1.18.2", - "rimraf": "^2.6.3", - "tape": "^5.3.0", - "tslint": "5.17.0", - "typescript": "3.5.2", - "uint8array-tools": "../uint8array-tools", - "varuint-bitcoin": "../varuint-bitcoin" - } - }, - "bip32": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/bip32/-/bip32-4.0.0.tgz", - "integrity": "sha512-aOGy88DDlVUhspIXJN+dVEtclhIsfAUppD43V0j40cPTld3pv/0X/MlrZSZ6jowIaQQzFwP8M6rFU2z2mVYjDQ==", - "dev": true, - "requires": { - "@noble/hashes": "^1.2.0", - "@scure/base": "^1.1.1", - "typeforce": "^1.11.5", - "wif": "^2.0.6" - } - }, - "bip39": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.1.0.tgz", - "integrity": "sha512-c9kiwdk45Do5GL0vJMe7tS95VjCii65mYAH7DfWl3uW8AVzXKQVUm64i3hzVybBDMp9r7j9iNxR85+ul8MdN/A==", - "dev": true, - "requires": { - "@noble/hashes": "^1.2.0" - } - }, - "bip65": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/bip65/-/bip65-1.0.3.tgz", - "integrity": "sha512-RQ1nc7xtnLa5XltnCqkoR2zmhuz498RjMJwrLKQzOE049D1HUqnYfon7cVSbwS5UGm0/EQlC2CH+NY3MyITA4Q==", - "dev": true - }, - "bip68": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/bip68/-/bip68-1.0.4.tgz", - "integrity": "sha512-O1htyufFTYy3EO0JkHg2CLykdXEtV2ssqw47Gq9A0WByp662xpJnMEB9m43LZjsSDjIAOozWRExlFQk2hlV1XQ==", - "dev": true - }, - "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 - }, - "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, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "requires": { - "fill-range": "^7.1.1" - } - }, - "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 - }, - "browserslist": { - "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.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": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", - "dev": true, - "requires": { - "base-x": "^3.0.2" - } - }, - "bs58check": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-4.0.0.tgz", - "integrity": "sha512-FsGDOnFg9aVI9erdriULkd/JjEWONV/lQE5aYziB5PoBsXRind56lh8doIZIc9X4HoxT5x4bLjMWN1/NB8Zp5g==", - "requires": { - "@noble/hashes": "^1.2.0", - "bs58": "^6.0.0" - }, - "dependencies": { - "base-x": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.0.tgz", - "integrity": "sha512-sMW3VGSX1QWVFA6l8U62MLKz29rRfpTlYdCqLdpLo1/Yd4zZwSbnUaDfciIAowAqvq7YFnWq9hrhdg1KYgc1lQ==" - }, - "bs58": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-6.0.0.tgz", - "integrity": "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==", - "requires": { - "base-x": "^5.0.0" - } - } - } - }, - "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 - }, - "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, - "requires": { - "hasha": "^5.0.0", - "make-dir": "^3.0.0", - "package-hash": "^4.0.0", - "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", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "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 - }, - "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" - } - }, - "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.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" - }, - "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": { - "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" - } - }, - "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 - }, - "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, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.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 - }, - "commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "dev": true - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "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 - }, - "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==", - "dev": true, - "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "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, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "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.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "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 - }, - "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.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" - } - }, - "dhttp": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/dhttp/-/dhttp-3.0.3.tgz", - "integrity": "sha512-map1b8iyvxSv0uEw3DUDDK5XvH3aYA7QU9DcXy8e3FBIXSwHPHTZWVrOot7Iu9mieWq5XcrZemEJlob6IdCBmg==", - "dev": true, - "requires": { - "statuses": "^1.5.0" - } - }, - "diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", - "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.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", - "typeforce": "^1.18.0", - "wif": "^2.0.6" - } - }, - "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 - }, - "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 - }, - "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 - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "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 - }, - "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": "sha512-tcgI872xXjwFF4xgQmLxi76GnwJG3g/3isB1l4/G5Z4zrbddGpBjqZCO9oEAcB5wX0Hj/5iQB3toxfO7in1hHA==", - "dev": true, - "requires": { - "is-object": "~1.0.1", - "merge-descriptors": "~1.0.0" - } - }, - "fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "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, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - } - }, - "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, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "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", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" - } - }, - "fromentries": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", - "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", - "dev": true - }, - "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 - }, - "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", - "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", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, - "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 - }, - "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 - }, - "glob": { - "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", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "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, - "requires": { - "is-glob": "^4.0.3" - } - }, - "globals": { - "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", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "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": "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.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", - "safe-buffer": "^5.2.0" - } - }, - "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, - "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": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, - "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 - }, - "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 - }, - "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": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true - }, - "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 - }, - "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, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "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, - "requires": { - "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": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "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 - }, - "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, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "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 - }, - "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 - }, - "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": { - "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 - }, - "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 - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, - "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 - }, - "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 - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "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 - }, - "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, - "requires": { - "append-transform": "^2.0.0" - } - }, - "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, - "requires": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - } - } - }, - "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, - "requires": { - "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" - }, - "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" - } - } - } - }, - "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, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - } - }, - "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, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - } - }, - "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, - "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", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "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" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "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 - }, - "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": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true - }, - "jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmmirror.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "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", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "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.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", - "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", - "dev": true - }, - "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, - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - } - }, - "lunr": { - "version": "2.3.9", - "resolved": "https://registry.npmmirror.com/lunr/-/lunr-2.3.9.tgz", - "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", - "dev": true - }, - "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, - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - } - } - }, - "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 - }, - "marked": { - "version": "4.3.0", - "resolved": "https://registry.npmmirror.com/marked/-/marked-4.3.0.tgz", - "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", - "dev": true - }, - "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==", - "dev": true, - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "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 - }, - "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": "sha512-ZR9tWALR8ZszYd/zP34TmmVwRDVBNCT5+hkNXfTp3rpEDmZmgmYt1Sh/tu9qYFuPvSvEEEeJGE2BY8MBmeAzQQ==", - "dev": true, - "requires": { - "bitcoin-ops": "^1.3.0", - "pushdata-bitcoin": "^1.0.1" - } - }, - "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" - } - }, - "mocha": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.6.0.tgz", - "integrity": "sha512-hxjt4+EEB0SA0ZDygSS015t65lJw/I2yRCS3Ae+SJ5FrbzrXgfYwJr96f0OvIXdj7h4lv/vLCrH3rkiuizFSvw==", - "dev": true, - "requires": { - "ansi-colors": "^4.1.3", - "browser-stdout": "^1.3.1", - "chokidar": "^3.5.3", - "debug": "^4.3.5", - "diff": "^5.2.0", - "escape-string-regexp": "^4.0.0", - "find-up": "^5.0.0", - "glob": "^8.1.0", - "he": "^1.2.0", - "js-yaml": "^4.1.0", - "log-symbols": "^4.1.0", - "minimatch": "^5.1.6", - "ms": "^2.1.3", - "serialize-javascript": "^6.0.2", - "strip-json-comments": "^3.1.1", - "supports-color": "^8.1.1", - "workerpool": "^6.5.1", - "yargs": "^16.2.0", - "yargs-parser": "^20.2.9", - "yargs-unparser": "^2.0.0" - }, - "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" - } - }, - "glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - } - }, - "minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - }, - "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" - } - } - } - }, - "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 - }, - "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 - }, - "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", - "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", - "dev": true, - "requires": { - "process-on-spawn": "^1.0.0" - } - }, - "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 - }, - "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 - }, - "nyc": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", - "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", - "dev": true, - "requires": { - "@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" - }, - "dependencies": { - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "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, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "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, - "requires": { - "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", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "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 - }, - "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" - } - }, - "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, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "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", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "requires": { - "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" - } - }, - "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, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } - }, - "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, - "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": "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-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, - "requires": { - "p-limit": "^3.0.2" - } - }, - "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, - "requires": { - "aggregate-error": "^3.0.0" - } - }, - "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 - }, - "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, - "requires": { - "graceful-fs": "^4.1.15", - "hasha": "^5.0.0", - "lodash.flattendeep": "^4.4.0", - "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", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "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 - }, - "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 - }, - "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 - }, - "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 - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "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, - "requires": { - "find-up": "^4.0.0" - }, - "dependencies": { - "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, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "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, - "requires": { - "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", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - } - } - }, - "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": "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", - "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", - "dev": true, - "requires": { - "fromentries": "^1.2.0" - } - }, - "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, - "requires": { - "fill-keys": "^1.0.2", - "module-not-found-error": "^1.0.1", - "resolve": "^1.11.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", - "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", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "readable-stream": { - "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", - "util-deprecate": "^1.0.1" - } - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "requires": { - "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", - "integrity": "sha512-eIcC8Kle/wjS47pRlw7nJpstrJDWp0bkvVPl2KJpJcK3JDNW0fMxJgE/CGpMEUSjhhFXW1rtJMN6kyKw5NIzqg==", - "dev": true, - "requires": { - "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": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", - "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==", - "dev": true, - "requires": { - "es6-error": "^4.0.1" - } - }, - "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==", - "dev": true - }, - "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 - }, - "resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "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 - }, - "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.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "ripemd160": { - "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" - } - }, - "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.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - }, - "semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", - "dev": true - }, - "serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "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 - }, - "sha.js": { - "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" - } - }, - "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, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "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 - }, - "shiki": { - "version": "0.14.4", - "resolved": "https://registry.npmmirror.com/shiki/-/shiki-0.14.4.tgz", - "integrity": "sha512-IXCRip2IQzKwxArNNq1S+On4KPML3Yyn8Zzs/xRgcgOWIr8ntIK3IKzjFPfjy/7kt9ZMjc+FItfqHRBg8b6tNQ==", - "dev": true, - "requires": { - "ansi-sequence-parser": "^1.1.0", - "jsonc-parser": "^3.2.0", - "vscode-oniguruma": "^1.7.0", - "vscode-textmate": "^8.0.0" - } - }, - "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 - }, - "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", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - } - }, - "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 - }, - "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, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "spawn-wrap": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", - "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", - "dev": true, - "requires": { - "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" - }, - "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" - } - } - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "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 - }, - "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==", - "dev": true, - "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", - "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" - } - }, - "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 - }, - "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 - }, - "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" - } - }, - "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", - "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" - }, - "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": { - "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, - "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - } - }, - "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.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.7" - }, - "dependencies": { - "uint8array-tools": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.7.tgz", - "integrity": "sha512-vrrNZJiusLWoFWBqz5Y5KMCgP9W9hnjZHzZiZRT8oNAkq3d5Z5Oe76jAvVVSRh4U8GGR90N2X1dWtrhvx6L8UQ==", - "dev": true - } - } - }, - "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 - }, - "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, - "requires": { - "is-number": "^7.0.0" - } - }, - "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, - "requires": { - "arg": "^4.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "source-map-support": "^0.5.17", - "yn": "3.1.1" - }, - "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": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - }, - "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": { - "prelude-ls": "^1.2.1" - } - }, - "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 - }, - "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, - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "typedoc": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.1.tgz", - "integrity": "sha512-c2ye3YUtGIadxN2O6YwPEXgrZcvhlZ6HlhWZ8jQRNzwLPn2ylhdGqdR8HbyDRyALP8J6lmSANILCkkIdNPFxqA==", - "dev": true, - "requires": { - "lunr": "^2.3.9", - "marked": "^4.3.0", - "minimatch": "^9.0.3", - "shiki": "^0.14.1" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - } - } - }, - "typeforce": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz", - "integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g==" - }, - "typescript": { - "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": "file:../uint8array-tools", - "requires": { - "@types/jest": "27.0.2", - "@types/node": "16.11.1", - "@typescript-eslint/eslint-plugin": "5.0.0", - "@typescript-eslint/parser": "5.0.0", - "eslint": "8.0.1", - "eslint-config-prettier": "8.3.0", - "eslint-plugin-prettier": "4.0.0", - "jest": "27.2.5", - "prettier": "2.4.1", - "ts-jest": "27.0.7", - "typescript": "4.4.4" - } - }, - "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", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "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==", - "dev": true - }, - "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 - }, - "varuint-bitcoin": { - "version": "file:../varuint-bitcoin", - "requires": { - "@types/node": "^20.14.8", - "c8": "^10.1.2", - "rimraf": "^5.0.7", - "tape": "^5.3.0", - "ts-standard": "^12.0.2", - "typescript": "^5.1.6", - "uint8array-tools": "^0.0.8" - } - }, - "vscode-oniguruma": { - "version": "1.7.0", - "resolved": "https://registry.npmmirror.com/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", - "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", - "dev": true - }, - "vscode-textmate": { - "version": "8.0.0", - "resolved": "https://registry.npmmirror.com/vscode-textmate/-/vscode-textmate-8.0.0.tgz", - "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "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": "sha512-HIanZn1zmduSF+BQhkE+YXIbEiH0xPr1012QbFEGB0xsKqJii0/SqJjyn8dFv6y36kOznMgMB+LGcbZTJ1xACQ==", - "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" - } - } - } - }, - "word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true - }, - "workerpool": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", - "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", - "dev": true - }, - "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, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "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 - }, - "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, - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "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": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "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" - } - }, - "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true - }, - "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, - "requires": { - "camelcase": "^6.0.0", - "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": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true - }, - "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 - } } } diff --git a/package.json b/package.json index 880120bee..44f4fbbcd 100644 --- a/package.json +++ b/package.json @@ -3,10 +3,18 @@ "version": "6.1.6", "description": "Client-side Bitcoin JavaScript library", "type": "module", - "main": "./src/index.js", - "types": "./src/index.d.ts", + "main": "./src/cjs/index.cjs", + "module": "./src/esm/index.js", + "types": "./src/cjs/index.d.ts", + "exports": { + ".": { + "require": "./src/cjs/index.cjs", + "import": "./src/esm/index.js", + "types": "./src/cjs/index.d.ts" + } + }, "engines": { - "node": ">=8.0.0" + "node": ">=18.0.0" }, "keywords": [ "bitcoinjs", @@ -18,9 +26,8 @@ "scripts": { "audit": "better-npm-audit audit -l high", "build": "npm run clean && tsc -p ./tsconfig.json && tsc -p ./tsconfig.cjs.json && npm run formatjs", - "build:tests": "npm run clean:jstests && tsc -p ./test/tsconfig.json", + "postbuild": "find src/cjs -type f -name \"*.js\" -exec bash -c 'mv \"$0\" \"${0%.js}.cjs\"' {} \\; && chmod +x ./fixup.cjs && node fixup.cjs", "clean": "rimraf src", - "clean:jstests": "rimraf 'test/**/!(ts-node-register)*.js'", "coverage-report": "npm run build && npm run nobuild:coverage-report", "coverage-html": "npm run build && npm run nobuild:coverage-html", "coverage": "npm run build && npm run nobuild:coverage", @@ -32,10 +39,10 @@ "integration": "npm run build && npm run nobuild:integration", "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", - "nobuild:coverage": "npm run build:tests && nyc --check-coverage --branches 85 --functions 90 --lines 90 mocha && npm run clean:jstests", + "mocha:ts": "mocha --recursive", + "nobuild:coverage-report": "c8 report --reporter=lcov", + "nobuild:coverage-html": "c8 report --reporter=html", + "nobuild:coverage": "c8 --check-coverage --branches 85 --functions 90 --lines 90 npm run nobuild:unit", "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", @@ -57,41 +64,46 @@ "bs58check": "^4.0.0", "typeforce": "^1.11.3", "uint8array-tools": "../uint8array-tools", + "valibot": "^0.38.0", "varuint-bitcoin": "../varuint-bitcoin" }, "devDependencies": { + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "^9.9.1", "@types/bs58": "^4.0.0", "@types/bs58check": "^2.1.0", "@types/mocha": "^5.2.7", - "@types/node": "^16.11.7", + "@types/node": "^18.7.14", "@types/proxyquire": "^1.3.28", "@types/randombytes": "^2.0.0", - "@typescript-eslint/eslint-plugin": "^5.45.0", - "@typescript-eslint/parser": "^5.45.0", + "@typescript-eslint/eslint-plugin": "^8.2.0", + "@typescript-eslint/parser": "^8.2.0", "better-npm-audit": "^3.7.3", - "bip32": "^4.0.0", + "bip32": "../bip32", "bip39": "^3.1.0", "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", + "ecpair": "../ecpair", + "eslint": "^9.9.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.2.1", + "globals": "^15.9.0", "hoodwink": "^2.0.0", "minimaldata": "^1.0.2", "mocha": "^10.6.0", - "nyc": "^15.1.0", - "prettier": "^2.8.0", + "c8": "^10.1.2", + "prettier": "^3.0.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", - "typedoc": "^0.25.1", - "typescript": "^4.4.4" + "tsx": "^4.17.0", + "typedoc": "^0.26.6", + "typescript": "^5.0.4" }, "license": "MIT" } diff --git a/src/cjs/address.js b/src/cjs/address.cjs similarity index 86% rename from src/cjs/address.js rename to src/cjs/address.cjs index c67ae30dd..57eee4e24 100644 --- a/src/cjs/address.js +++ b/src/cjs/address.cjs @@ -43,20 +43,26 @@ var __importStar = __setModuleDefault(result, mod); return result; }; +var __importDefault = + (this && this.__importDefault) || + function (mod) { + return mod && mod.__esModule ? mod : { default: mod }; + }; Object.defineProperty(exports, '__esModule', { value: true }); -exports.toOutputScript = - exports.fromOutputScript = - exports.toBech32 = - exports.toBase58Check = - exports.fromBech32 = - exports.fromBase58Check = - void 0; -const networks = __importStar(require('./networks')); -const payments = __importStar(require('./payments')); -const bscript = __importStar(require('./script')); -const types_1 = require('./types'); +exports.fromBase58Check = fromBase58Check; +exports.fromBech32 = fromBech32; +exports.toBase58Check = toBase58Check; +exports.toBech32 = toBech32; +exports.fromOutputScript = fromOutputScript; +exports.toOutputScript = toOutputScript; +const networks = __importStar(require('./networks.cjs')); +const payments = __importStar(require('./payments/index.cjs')); +const bscript = __importStar(require('./script.cjs')); +const types_js_1 = require('./types.cjs'); const bech32_1 = require('bech32'); -const bs58check = __importStar(require('bs58check')); +const bs58check_1 = __importDefault(require('bs58check')); +const tools = __importStar(require('uint8array-tools')); +const v = __importStar(require('valibot')); const FUTURE_SEGWIT_MAX_SIZE = 40; const FUTURE_SEGWIT_MIN_SIZE = 2; const FUTURE_SEGWIT_MAX_VERSION = 16; @@ -89,15 +95,15 @@ function _toFutureSegwitAddress(output, network) { * decode address with base58 specification, return address version and address hash if valid */ function fromBase58Check(address) { - const payload = Buffer.from(bs58check.decode(address)); + const payload = bs58check_1.default.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 version = tools.readUInt8(payload, 0); const hash = payload.slice(1); return { version, hash }; } -exports.fromBase58Check = fromBase58Check; /** * decode address with bech32 specification, return address version、address prefix and address data if valid */ @@ -119,24 +125,24 @@ function fromBech32(address) { return { version, prefix: result.prefix, - data: Buffer.from(data), + data: Uint8Array.from(data), }; } -exports.fromBech32 = fromBech32; /** * encode address hash to base58 address with version */ function toBase58Check(hash, version) { - (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); - return bs58check.encode(payload); + v.parse(v.tuple([types_js_1.Hash160bitSchema, types_js_1.UInt8Schema]), [ + hash, + version, + ]); + const payload = new Uint8Array(21); + // payload.writeUInt8(version, 0); + tools.writeUInt8(payload, 0, version); + // hash.copy(payload, 1); + payload.set(hash, 1); + return bs58check_1.default.encode(payload); } -exports.toBase58Check = toBase58Check; /** * encode address hash to bech32 address with version and prefix */ @@ -147,7 +153,6 @@ function toBech32(data, version, prefix) { ? bech32_1.bech32.encode(prefix, words) : bech32_1.bech32m.encode(prefix, words); } -exports.toBech32 = toBech32; /** * decode address from output script with network, return address if matched */ @@ -174,7 +179,6 @@ function fromOutputScript(output, network) { } catch (e) {} throw new Error(bscript.toASM(output) + ' has no matching Address'); } -exports.fromOutputScript = fromOutputScript; /** * encodes address to output script with network, return output script if address matched */ @@ -221,4 +225,3 @@ function toOutputScript(address, network) { } throw new Error(address + ' has no matching Script'); } -exports.toOutputScript = toOutputScript; diff --git a/src/cjs/address.d.ts b/src/cjs/address.d.ts index 6b5bc9c2a..46306cc42 100644 --- a/src/cjs/address.d.ts +++ b/src/cjs/address.d.ts @@ -1,4 +1,3 @@ -/// /** * bitcoin address decode and encode tools, include base58、bech32 and output script * @@ -8,11 +7,11 @@ * * @packageDocumentation */ -import { Network } from './networks'; +import { Network } from './networks.js'; /** base58check decode result */ export interface Base58CheckResult { /** address hash */ - hash: Buffer; + hash: Uint8Array; /** address version: 0x00 for P2PKH, 0x05 for P2SH */ version: number; } @@ -23,7 +22,7 @@ export interface Bech32Result { /** address prefix: bc for P2WPKH、P2WSH、P2TR */ prefix: string; /** address data:20 bytes for P2WPKH, 32 bytes for P2WSH、P2TR */ - data: Buffer; + data: Uint8Array; } /** * decode address with base58 specification, return address version and address hash if valid @@ -36,16 +35,16 @@ export declare function fromBech32(address: string): Bech32Result; /** * encode address hash to base58 address with version */ -export declare function toBase58Check(hash: Buffer, version: number): string; +export declare function toBase58Check(hash: Uint8Array, version: number): string; /** * encode address hash to bech32 address with version and prefix */ -export declare function toBech32(data: Buffer, version: number, prefix: string): string; +export declare function toBech32(data: Uint8Array, version: number, prefix: string): string; /** * decode address from output script with network, return address if matched */ -export declare function fromOutputScript(output: Buffer, network?: Network): string; +export declare function fromOutputScript(output: Uint8Array, network?: Network): string; /** * encodes address to output script with network, return output script if address matched */ -export declare function toOutputScript(address: string, network?: Network): Buffer; +export declare function toOutputScript(address: string, network?: Network): Uint8Array; diff --git a/src/cjs/bip66.js b/src/cjs/bip66.cjs similarity index 95% rename from src/cjs/bip66.js rename to src/cjs/bip66.cjs index 0070f998c..1e0f47984 100644 --- a/src/cjs/bip66.js +++ b/src/cjs/bip66.cjs @@ -3,7 +3,9 @@ // Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] // NOTE: SIGHASH byte ignored AND restricted, truncate before use Object.defineProperty(exports, '__esModule', { value: true }); -exports.encode = exports.decode = exports.check = void 0; +exports.check = check; +exports.decode = decode; +exports.encode = encode; function check(buffer) { if (buffer.length < 8) return false; if (buffer.length > 72) return false; @@ -24,7 +26,6 @@ function check(buffer) { return false; return true; } -exports.check = check; function decode(buffer) { if (buffer.length < 8) throw new Error('DER sequence length is too short'); if (buffer.length > 72) throw new Error('DER sequence length is too long'); @@ -51,7 +52,6 @@ function decode(buffer) { s: buffer.slice(6 + lenR), }; } -exports.decode = decode; /* * Expects r and s to be positive DER integers. * @@ -87,16 +87,17 @@ function encode(r, s) { throw new Error('R value excessively padded'); if (lenS > 1 && s[0] === 0x00 && !(s[1] & 0x80)) throw new Error('S value excessively padded'); - const signature = Buffer.allocUnsafe(6 + lenR + lenS); + const signature = new Uint8Array(6 + lenR + lenS); // 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] signature[0] = 0x30; signature[1] = signature.length - 2; signature[2] = 0x02; signature[3] = r.length; - r.copy(signature, 4); + // r.copy(signature, 4); + signature.set(r, 4); signature[4 + lenR] = 0x02; signature[5 + lenR] = s.length; - s.copy(signature, 6 + lenR); + // s.copy(signature, 6 + lenR); + signature.set(s, 6 + lenR); return signature; } -exports.encode = encode; diff --git a/src/cjs/bip66.d.ts b/src/cjs/bip66.d.ts index 547c57f78..8888e1bad 100644 --- a/src/cjs/bip66.d.ts +++ b/src/cjs/bip66.d.ts @@ -1,7 +1,6 @@ -/// -export declare function check(buffer: Buffer): boolean; -export declare function decode(buffer: Buffer): { - r: Buffer; - s: Buffer; +export declare function check(buffer: Uint8Array): boolean; +export declare function decode(buffer: Uint8Array): { + r: Uint8Array; + s: Uint8Array; }; -export declare function encode(r: Buffer, s: Buffer): Buffer; +export declare function encode(r: Uint8Array, s: Uint8Array): Uint8Array; diff --git a/src/cjs/block.js b/src/cjs/block.cjs similarity index 75% rename from src/cjs/block.js rename to src/cjs/block.cjs index 25d20ac0b..158b37ef3 100644 --- a/src/cjs/block.js +++ b/src/cjs/block.cjs @@ -45,12 +45,13 @@ var __importStar = }; Object.defineProperty(exports, '__esModule', { value: true }); exports.Block = void 0; -const bufferutils_1 = require('./bufferutils'); -const bcrypto = __importStar(require('./crypto')); -const merkle_1 = require('./merkle'); -const transaction_1 = require('./transaction'); -const types = __importStar(require('./types')); -const { typeforce } = types; +const bufferutils_js_1 = require('./bufferutils.cjs'); +const bcrypto = __importStar(require('./crypto.cjs')); +const merkle_js_1 = require('./merkle.cjs'); +const transaction_js_1 = require('./transaction.cjs'); +const v = __importStar(require('valibot')); +const tools = __importStar(require('uint8array-tools')); +// const { typeforce } = types; const errorMerkleNoTxes = new TypeError( 'Cannot compute merkle root for zero transactions', ); @@ -60,7 +61,7 @@ const errorWitnessNotSegwit = new TypeError( class Block { static fromBuffer(buffer) { if (buffer.length < 80) throw new Error('Buffer too small (< 80 bytes)'); - const bufferReader = new bufferutils_1.BufferReader(buffer); + const bufferReader = new bufferutils_js_1.BufferReader(buffer); const block = new Block(); block.version = bufferReader.readInt32(); block.prevHash = bufferReader.readSlice(32); @@ -70,7 +71,7 @@ class Block { block.nonce = bufferReader.readUInt32(); if (buffer.length === 80) return block; const readTransaction = () => { - const tx = transaction_1.Transaction.fromBuffer( + const tx = transaction_js_1.Transaction.fromBuffer( bufferReader.buffer.slice(bufferReader.offset), true, ); @@ -89,27 +90,32 @@ class Block { return block; } static fromHex(hex) { - return Block.fromBuffer(Buffer.from(hex, 'hex')); + // return Block.fromBuffer(Buffer.from(hex, 'hex')); + return Block.fromBuffer(tools.fromHex(hex)); } static calculateTarget(bits) { const exponent = ((bits & 0xff000000) >> 24) - 3; const mantissa = bits & 0x007fffff; - const target = Buffer.alloc(32, 0); - target.writeUIntBE(mantissa, 29 - exponent, 3); + const target = new Uint8Array(32); + // target.writeUIntBE(mantissa, 29 - exponent, 3); + target[29 - exponent] = (mantissa >> 16) & 0xff; + target[30 - exponent] = (mantissa >> 8) & 0xff; + target[31 - exponent] = mantissa & 0xff; return target; } static calculateMerkleRoot(transactions, forWitness) { - typeforce([{ getHash: types.Function }], transactions); + // typeforce([{ getHash: types.Function }], transactions); + v.parse(v.array(v.object({ getHash: v.function() })), transactions); if (transactions.length === 0) throw errorMerkleNoTxes; if (forWitness && !txesHaveWitnessCommit(transactions)) throw errorWitnessNotSegwit; const hashes = transactions.map(transaction => transaction.getHash(forWitness), ); - const rootHash = (0, merkle_1.fastMerkleRoot)(hashes, bcrypto.hash256); + const rootHash = (0, merkle_js_1.fastMerkleRoot)(hashes, bcrypto.hash256); return forWitness ? bcrypto.hash256( - Buffer.concat([rootHash, transactions[0].ins[0].witness[0]]), + tools.concat([rootHash, transactions[0].ins[0].witness[0]]), ) : rootHash; } @@ -128,19 +134,24 @@ class Block { // The root is prepended with 0xaa21a9ed so check for 0x6a24aa21a9ed // If multiple commits are found, the output with highest index is assumed. const witnessCommits = this.transactions[0].outs - .filter(out => - out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex')), + .filter( + out => + // out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex')), + tools.compare( + out.script.slice(0, 6), + Uint8Array.from([0x6a, 0x24, 0xaa, 0x21, 0xa9, 0xed]), + ) === 0, ) .map(out => out.script.slice(6, 38)); if (witnessCommits.length === 0) return null; // Use the commit with the highest output (should only be one though) const result = witnessCommits[witnessCommits.length - 1]; - if (!(result instanceof Buffer && result.length === 32)) return null; + if (!(result instanceof Uint8Array && result.length === 32)) return null; return result; } hasWitnessCommit() { if ( - this.witnessCommit instanceof Buffer && + this.witnessCommit instanceof Uint8Array && this.witnessCommit.length === 32 ) return true; @@ -159,7 +170,7 @@ class Block { if (headersOnly || !this.transactions) return 80; return ( 80 + - bufferutils_1.varuint.encodingLength(this.transactions.length) + + bufferutils_js_1.varuint.encodingLength(this.transactions.length) + this.transactions.reduce((a, x) => a + x.byteLength(allowWitness), 0) ); } @@ -167,7 +178,7 @@ class Block { return bcrypto.hash256(this.toBuffer(true)); } getId() { - return (0, bufferutils_1.reverseBuffer)(this.getHash()).toString('hex'); + return tools.toHex((0, bufferutils_js_1.reverseBuffer)(this.getHash())); } getUTCDate() { const date = new Date(0); // epoch @@ -176,8 +187,8 @@ class Block { } // TODO: buffer, offset compatibility toBuffer(headersOnly) { - const buffer = Buffer.allocUnsafe(this.byteLength(headersOnly)); - const bufferWriter = new bufferutils_1.BufferWriter(buffer); + const buffer = new Uint8Array(this.byteLength(headersOnly)); + const bufferWriter = new bufferutils_js_1.BufferWriter(buffer); bufferWriter.writeInt32(this.version); bufferWriter.writeSlice(this.prevHash); bufferWriter.writeSlice(this.merkleRoot); @@ -185,7 +196,7 @@ class Block { bufferWriter.writeUInt32(this.bits); bufferWriter.writeUInt32(this.nonce); if (headersOnly || !this.transactions) return buffer; - const { bytes } = bufferutils_1.varuint.encode( + const { bytes } = bufferutils_js_1.varuint.encode( this.transactions.length, buffer, bufferWriter.offset, @@ -199,7 +210,7 @@ class Block { return buffer; } toHex(headersOnly) { - return this.toBuffer(headersOnly).toString('hex'); + return tools.toHex(this.toBuffer(headersOnly)); } checkTxRoots() { // If the Block has segwit transactions but no witness commit, @@ -212,14 +223,16 @@ class Block { ); } checkProofOfWork() { - const hash = (0, bufferutils_1.reverseBuffer)(this.getHash()); + const hash = (0, bufferutils_js_1.reverseBuffer)(this.getHash()); const target = Block.calculateTarget(this.bits); - return hash.compare(target) <= 0; + // return hash.compare(target) <= 0; + return tools.compare(hash, target) <= 0; } __checkMerkleRoot() { if (!this.transactions) throw errorMerkleNoTxes; const actualMerkleRoot = Block.calculateMerkleRoot(this.transactions); - return this.merkleRoot.compare(actualMerkleRoot) === 0; + // return this.merkleRoot!.compare(actualMerkleRoot) === 0; + return tools.compare(this.merkleRoot, actualMerkleRoot) === 0; } __checkWitnessCommit() { if (!this.transactions) throw errorMerkleNoTxes; @@ -228,7 +241,8 @@ class Block { this.transactions, true, ); - return this.witnessCommit.compare(actualWitnessCommit) === 0; + // return this.witnessCommit!.compare(actualWitnessCommit) === 0; + return tools.compare(this.witnessCommit, actualWitnessCommit) === 0; } } exports.Block = Block; diff --git a/src/cjs/block.d.ts b/src/cjs/block.d.ts index 1d90c13c4..8afce2735 100644 --- a/src/cjs/block.d.ts +++ b/src/cjs/block.d.ts @@ -1,27 +1,26 @@ -/// -import { Transaction } from './transaction'; +import { Transaction } from './transaction.js'; export declare class Block { - static fromBuffer(buffer: Buffer): Block; + static fromBuffer(buffer: Uint8Array): Block; static fromHex(hex: string): Block; - static calculateTarget(bits: number): Buffer; - static calculateMerkleRoot(transactions: Transaction[], forWitness?: boolean): Buffer; + static calculateTarget(bits: number): Uint8Array; + static calculateMerkleRoot(transactions: Transaction[], forWitness?: boolean): Uint8Array; version: number; - prevHash?: Buffer; - merkleRoot?: Buffer; + prevHash?: Uint8Array; + merkleRoot?: Uint8Array; timestamp: number; - witnessCommit?: Buffer; + witnessCommit?: Uint8Array; bits: number; nonce: number; transactions?: Transaction[]; - getWitnessCommit(): Buffer | null; + getWitnessCommit(): Uint8Array | null; hasWitnessCommit(): boolean; hasWitness(): boolean; weight(): number; byteLength(headersOnly?: boolean, allowWitness?: boolean): number; - getHash(): Buffer; + getHash(): Uint8Array; getId(): string; getUTCDate(): Date; - toBuffer(headersOnly?: boolean): Buffer; + toBuffer(headersOnly?: boolean): Uint8Array; toHex(headersOnly?: boolean): string; checkTxRoots(): boolean; checkProofOfWork(): boolean; diff --git a/src/cjs/bufferutils.js b/src/cjs/bufferutils.cjs similarity index 60% rename from src/cjs/bufferutils.js rename to src/cjs/bufferutils.cjs index e838b1d06..9023d1ef0 100644 --- a/src/cjs/bufferutils.js +++ b/src/cjs/bufferutils.cjs @@ -44,18 +44,14 @@ var __importStar = return result; }; Object.defineProperty(exports, '__esModule', { value: true }); -exports.BufferReader = - exports.BufferWriter = - exports.cloneBuffer = - exports.reverseBuffer = - exports.writeUInt64LE = - exports.readUInt64LE = - exports.varuint = - void 0; -const types = __importStar(require('./types')); -const { typeforce } = types; +exports.BufferReader = exports.BufferWriter = exports.varuint = void 0; +exports.reverseBuffer = reverseBuffer; +exports.cloneBuffer = cloneBuffer; +const types = __importStar(require('./types.cjs')); const varuint = __importStar(require('varuint-bitcoin')); exports.varuint = varuint; +const v = __importStar(require('valibot')); +const tools = __importStar(require('uint8array-tools')); const MAX_JS_NUMBER = 0x001fffffffffffff; // https://github.com/feross/buffer/blob/master/index.js#L1127 function verifuint(value, max) { @@ -68,14 +64,13 @@ function verifuint(value, max) { if (Math.floor(Number(value)) !== Number(value)) throw new Error('value has a fractional component'); } -function readUInt64LE(buffer, offset) { - const a = buffer.readUInt32LE(offset); - let b = buffer.readUInt32LE(offset + 4); - b *= 0x100000000; - verifuint(b + a, MAX_JS_NUMBER); - return b + a; -} -exports.readUInt64LE = readUInt64LE; +// export function readUInt64LE(buffer: Buffer, offset: number): number { +// const a = buffer.readUInt32LE(offset); +// let b = buffer.readUInt32LE(offset + 4); +// b *= 0x100000000; +// verifuint(b + a, MAX_JS_NUMBER); +// return b + a; +// } /** * Writes a 64-bit unsigned integer in little-endian format to the specified buffer at the given offset. * @@ -84,13 +79,39 @@ exports.readUInt64LE = readUInt64LE; * @param offset - The offset in the buffer where the value should be written. * @returns The new offset after writing the value. */ -function writeUInt64LE(buffer, value, offset) { - verifuint(value, MAX_JS_NUMBER); - buffer.writeInt32LE(value & -1, offset); - buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4); - return offset + 8; -} -exports.writeUInt64LE = writeUInt64LE; +// export function writeUInt64LE( +// buffer: Buffer, +// value: number, +// offset: number, +// ): number { +// verifuint(value, MAX_JS_NUMBER); +// buffer.writeInt32LE(value & -1, offset); +// buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4); +// return offset + 8; +// } +/** + * Reads a 64-bit signed integer from a Uint8Array in little-endian format. + * + * @param {Uint8Array} buffer - The buffer to read the value from. + * @param {number} offset - The offset in the buffer where the value starts. + * @return {number} The 64-bit signed integer value. + */ +// export function readInt64LE( +// buffer: Uint8Array, +// offset: number +// ): number { +// if((buffer[offset + 7] & 0x7f) > 0) throw new Error("RangeError: value out of range, greater than int64"); +// return ( +// buffer[offset] | +// (buffer[offset + 1] << 8) | +// (buffer[offset + 2] << 16) | +// (buffer[offset + 3] << 24) | +// (buffer[offset + 4] << 32) | +// (buffer[offset + 5] << 40) | +// (buffer[offset + 6] << 48) | +// (buffer[offset + 7] << 56) +// ); +// } /** * Reverses the order of bytes in a buffer. * @param buffer - The buffer to reverse. @@ -108,13 +129,11 @@ function reverseBuffer(buffer) { } return buffer; } -exports.reverseBuffer = reverseBuffer; function cloneBuffer(buffer) { - const clone = Buffer.allocUnsafe(buffer.length); - buffer.copy(clone); + const clone = new Uint8Array(buffer.length); + clone.set(buffer); return clone; } -exports.cloneBuffer = cloneBuffer; /** * Helper class for serialization of bitcoin data types into a pre-allocated buffer. */ @@ -122,24 +141,35 @@ class BufferWriter { buffer; offset; static withCapacity(size) { - return new BufferWriter(Buffer.alloc(size)); + return new BufferWriter(new Uint8Array(size)); } constructor(buffer, offset = 0) { this.buffer = buffer; this.offset = offset; - typeforce(types.tuple(types.Buffer, types.UInt32), [buffer, offset]); + // typeforce(types.tuple(types.Buffer, types.UInt32), [buffer, offset]); + v.parse(v.tuple([types.BufferSchema, types.UInt32Schema]), [ + buffer, + offset, + ]); } writeUInt8(i) { - this.offset = this.buffer.writeUInt8(i, this.offset); + // this.offset = this.buffer.writeUInt8(i, this.offset); + this.offset = tools.writeUInt8(this.buffer, this.offset, i); } writeInt32(i) { - this.offset = this.buffer.writeInt32LE(i, this.offset); + // this.offset = this.buffer.writeInt32LE(i, this.offset); + this.offset = tools.writeInt32(this.buffer, i, this.offset, 'LE'); + } + writeInt64(i) { + this.offset = tools.writeInt64(this.buffer, BigInt(i), this.offset, 'LE'); } writeUInt32(i) { - this.offset = this.buffer.writeUInt32LE(i, this.offset); + // this.offset = this.buffer.writeUInt32LE(i, this.offset); + this.offset = tools.writeUInt32(this.buffer, this.offset, i, 'LE'); } writeUInt64(i) { - this.offset = writeUInt64LE(this.buffer, i, this.offset); + // this.offset = writeUInt64LE(this.buffer, i, this.offset); + this.offset = tools.writeUInt64(this.buffer, this.offset, BigInt(i), 'LE'); } writeVarInt(i) { const { bytes } = varuint.encode(i, this.buffer, this.offset); @@ -149,7 +179,9 @@ class BufferWriter { if (this.buffer.length < this.offset + slice.length) { throw new Error('Cannot write slice out of bounds'); } - this.offset += slice.copy(this.buffer, this.offset); + // this.offset += slice.copy(this.buffer, this.offset); + this.buffer.set(slice, this.offset); + this.offset += slice.length; } writeVarSlice(slice) { this.writeVarInt(slice.length); @@ -176,25 +208,33 @@ class BufferReader { constructor(buffer, offset = 0) { this.buffer = buffer; this.offset = offset; - typeforce(types.tuple(types.Buffer, types.UInt32), [buffer, offset]); + // typeforce(types.tuple(types.Buffer, types.UInt32), [buffer, offset]); + v.parse(v.tuple([types.BufferSchema, types.UInt32Schema]), [ + buffer, + offset, + ]); } readUInt8() { - const result = this.buffer.readUInt8(this.offset); + // const result = this.buffer.readUInt8(this.offset); + const result = tools.readUInt8(this.buffer, this.offset); this.offset++; return result; } readInt32() { - const result = this.buffer.readInt32LE(this.offset); + // const result = readInt32LE(this.buffer, this.offset); + const result = tools.readInt32(this.buffer, this.offset, 'LE'); this.offset += 4; return result; } readUInt32() { - const result = this.buffer.readUInt32LE(this.offset); + // const result = this.buffer.readUInt32LE(this.offset); + const result = tools.readUInt32(this.buffer, this.offset, 'LE'); this.offset += 4; return result; } readUInt64() { - const result = readUInt64LE(this.buffer, this.offset); + // const result = readUInt64LE(this.buffer, this.offset); + const result = tools.readUInt64(this.buffer, this.offset, 'LE'); this.offset += 8; return result; } diff --git a/src/cjs/bufferutils.d.ts b/src/cjs/bufferutils.d.ts index 3de71fd30..ecfd943d2 100644 --- a/src/cjs/bufferutils.d.ts +++ b/src/cjs/bufferutils.d.ts @@ -1,7 +1,5 @@ -/// import * as varuint from 'varuint-bitcoin'; export { varuint }; -export declare function readUInt64LE(buffer: Buffer, offset: number): number; /** * Writes a 64-bit unsigned integer in little-endian format to the specified buffer at the given offset. * @@ -10,45 +8,52 @@ export declare function readUInt64LE(buffer: Buffer, offset: number): number; * @param offset - The offset in the buffer where the value should be written. * @returns The new offset after writing the value. */ -export declare function writeUInt64LE(buffer: Buffer, value: number, offset: number): number; +/** + * Reads a 64-bit signed integer from a Uint8Array in little-endian format. + * + * @param {Uint8Array} buffer - The buffer to read the value from. + * @param {number} offset - The offset in the buffer where the value starts. + * @return {number} The 64-bit signed integer value. + */ /** * Reverses the order of bytes in a buffer. * @param buffer - The buffer to reverse. * @returns A new buffer with the bytes reversed. */ -export declare function reverseBuffer(buffer: Buffer): Buffer; -export declare function cloneBuffer(buffer: Buffer): Buffer; +export declare function reverseBuffer(buffer: Uint8Array): Uint8Array; +export declare function cloneBuffer(buffer: Uint8Array): Uint8Array; /** * Helper class for serialization of bitcoin data types into a pre-allocated buffer. */ export declare class BufferWriter { - buffer: Buffer; + buffer: Uint8Array; offset: number; static withCapacity(size: number): BufferWriter; - constructor(buffer: Buffer, offset?: number); + constructor(buffer: Uint8Array, offset?: number); writeUInt8(i: number): void; writeInt32(i: number): void; + writeInt64(i: number | bigint): void; writeUInt32(i: number): void; - writeUInt64(i: number): void; + writeUInt64(i: number | bigint): void; writeVarInt(i: number): void; - writeSlice(slice: Buffer): void; - writeVarSlice(slice: Buffer): void; - writeVector(vector: Buffer[]): void; - end(): Buffer; + writeSlice(slice: Uint8Array): void; + writeVarSlice(slice: Uint8Array): void; + writeVector(vector: Uint8Array[]): void; + end(): Uint8Array; } /** * Helper class for reading of bitcoin data types from a buffer. */ export declare class BufferReader { - buffer: Buffer; + buffer: Uint8Array; offset: number; - constructor(buffer: Buffer, offset?: number); + constructor(buffer: Uint8Array, offset?: number); readUInt8(): number; readInt32(): number; readUInt32(): number; - readUInt64(): number; + readUInt64(): bigint; readVarInt(): bigint; - readSlice(n: number | bigint): Buffer; - readVarSlice(): Buffer; - readVector(): Buffer[]; + readSlice(n: number | bigint): Uint8Array; + readVarSlice(): Uint8Array; + readVector(): Uint8Array[]; } diff --git a/src/cjs/crypto.js b/src/cjs/crypto.cjs similarity index 66% rename from src/cjs/crypto.js rename to src/cjs/crypto.cjs index a7a5936d9..54d5771d3 100644 --- a/src/cjs/crypto.js +++ b/src/cjs/crypto.cjs @@ -1,14 +1,53 @@ 'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if ( + !desc || + ('get' in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, 'default', { enumerable: true, value: v }); + } + : function (o, v) { + o['default'] = v; + }); +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k in mod) + if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; + }; Object.defineProperty(exports, '__esModule', { value: true }); -exports.taggedHash = - exports.TAGGED_HASH_PREFIXES = - exports.TAGS = - exports.hash256 = - exports.hash160 = - exports.sha256 = - exports.sha1 = - exports.ripemd160 = - void 0; +exports.TAGGED_HASH_PREFIXES = exports.TAGS = void 0; +exports.hash160 = hash160; +exports.hash256 = hash256; +exports.taggedHash = taggedHash; /** * A module for hashing functions. * include ripemd160、sha1、sha256、hash160、hash256、taggedHash @@ -16,32 +55,14 @@ exports.taggedHash = * @packageDocumentation */ const ripemd160_1 = require('@noble/hashes/ripemd160'); -const sha1_1 = require('@noble/hashes/sha1'); const sha256_1 = require('@noble/hashes/sha256'); -function ripemd160(buffer) { - return Buffer.from((0, ripemd160_1.ripemd160)(Uint8Array.from(buffer))); -} -exports.ripemd160 = ripemd160; -function sha1(buffer) { - return Buffer.from((0, sha1_1.sha1)(Uint8Array.from(buffer))); -} -exports.sha1 = sha1; -function sha256(buffer) { - return Buffer.from((0, sha256_1.sha256)(Uint8Array.from(buffer))); -} -exports.sha256 = sha256; +const tools = __importStar(require('uint8array-tools')); function hash160(buffer) { - return Buffer.from( - (0, ripemd160_1.ripemd160)((0, sha256_1.sha256)(Uint8Array.from(buffer))), - ); + return (0, ripemd160_1.ripemd160)((0, sha256_1.sha256)(buffer)); } -exports.hash160 = hash160; function hash256(buffer) { - return Buffer.from( - (0, sha256_1.sha256)((0, sha256_1.sha256)(Uint8Array.from(buffer))), - ); + return (0, sha256_1.sha256)((0, sha256_1.sha256)(buffer)); } -exports.hash256 = hash256; exports.TAGS = [ 'BIP0340/challenge', 'BIP0340/aux', @@ -58,55 +79,55 @@ exports.TAGS = [ * Defines the tagged hash prefixes used in the crypto module. */ exports.TAGGED_HASH_PREFIXES = { - 'BIP0340/challenge': Buffer.from([ + 'BIP0340/challenge': Uint8Array.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([ + 'BIP0340/aux': Uint8Array.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([ + 'BIP0340/nonce': Uint8Array.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([ + TapLeaf: Uint8Array.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([ + TapBranch: Uint8Array.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([ + TapSighash: Uint8Array.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([ + TapTweak: Uint8Array.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([ + 'KeyAgg list': Uint8Array.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([ + 'KeyAgg coefficient': Uint8Array.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, @@ -114,6 +135,7 @@ exports.TAGGED_HASH_PREFIXES = { ]), }; function taggedHash(prefix, data) { - return sha256(Buffer.concat([exports.TAGGED_HASH_PREFIXES[prefix], data])); + return (0, sha256_1.sha256)( + tools.concat([exports.TAGGED_HASH_PREFIXES[prefix], data]), + ); } -exports.taggedHash = taggedHash; diff --git a/src/cjs/crypto.d.ts b/src/cjs/crypto.d.ts index 6692df1ee..5429162a7 100644 --- a/src/cjs/crypto.d.ts +++ b/src/cjs/crypto.d.ts @@ -1,18 +1,14 @@ -/// -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 function hash160(buffer: Uint8Array): Uint8Array; +export declare function hash256(buffer: Uint8Array): Uint8Array; 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 TaggedHashPrefix = (typeof TAGS)[number]; type TaggedHashPrefixes = { - [key in TaggedHashPrefix]: Buffer; + [key in TaggedHashPrefix]: Uint8Array; }; /** An object mapping tags to their tagged hash prefix of [SHA256(tag) | SHA256(tag)] */ /** * Defines the tagged hash prefixes used in the crypto module. */ export declare const TAGGED_HASH_PREFIXES: TaggedHashPrefixes; -export declare function taggedHash(prefix: TaggedHashPrefix, data: Buffer): Buffer; +export declare function taggedHash(prefix: TaggedHashPrefix, data: Uint8Array): Uint8Array; export {}; diff --git a/src/cjs/ecc_lib.js b/src/cjs/ecc_lib.cjs similarity index 70% rename from src/cjs/ecc_lib.js rename to src/cjs/ecc_lib.cjs index 22202da98..9b6dc7f7f 100644 --- a/src/cjs/ecc_lib.js +++ b/src/cjs/ecc_lib.cjs @@ -1,6 +1,52 @@ 'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if ( + !desc || + ('get' in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, 'default', { enumerable: true, value: v }); + } + : function (o, v) { + o['default'] = v; + }); +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k in mod) + if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; + }; Object.defineProperty(exports, '__esModule', { value: true }); -exports.getEccLib = exports.initEccLib = void 0; +exports.initEccLib = initEccLib; +exports.getEccLib = getEccLib; +const tools = __importStar(require('uint8array-tools')); const _ECCLIB_CACHE = {}; /** * Initializes the ECC library with the provided instance. @@ -19,7 +65,6 @@ function initEccLib(eccLib) { _ECCLIB_CACHE.eccLib = eccLib; } } -exports.initEccLib = initEccLib; /** * Retrieves the ECC Library instance. * Throws an error if the ECC Library is not provided. @@ -34,8 +79,7 @@ function getEccLib() { ); return _ECCLIB_CACHE.eccLib; } -exports.getEccLib = getEccLib; -const h = hex => Buffer.from(hex, 'hex'); +const h = hex => tools.fromHex(hex); /** * Verifies the ECC functionality. * @@ -81,7 +125,7 @@ function verifyEcc(ecc) { } else { assert(r !== null); assert(r.parity === t.parity); - assert(Buffer.from(r.xOnlyPubkey).equals(h(t.result))); + assert(tools.compare(r.xOnlyPubkey, h(t.result)) === 0); } }); } diff --git a/src/cjs/ecc_lib.d.ts b/src/cjs/ecc_lib.d.ts index abb750a32..108f6ccba 100644 --- a/src/cjs/ecc_lib.d.ts +++ b/src/cjs/ecc_lib.d.ts @@ -1,4 +1,4 @@ -import { TinySecp256k1Interface } from './types'; +import { TinySecp256k1Interface } from './types.js'; /** * Initializes the ECC library with the provided instance. * If `eccLib` is `undefined`, the library will be cleared. diff --git a/src/cjs/index.js b/src/cjs/index.cjs similarity index 76% rename from src/cjs/index.js rename to src/cjs/index.cjs index 97984c902..30033351a 100644 --- a/src/cjs/index.js +++ b/src/cjs/index.cjs @@ -55,49 +55,49 @@ exports.initEccLib = exports.crypto = exports.address = void 0; -const address = __importStar(require('./address')); +const address = __importStar(require('./address.cjs')); exports.address = address; -const crypto = __importStar(require('./crypto')); +const crypto = __importStar(require('./crypto.cjs')); exports.crypto = crypto; -const networks = __importStar(require('./networks')); +const networks = __importStar(require('./networks.cjs')); exports.networks = networks; -const payments = __importStar(require('./payments')); +const payments = __importStar(require('./payments/index.cjs')); exports.payments = payments; -const script = __importStar(require('./script')); +const script = __importStar(require('./script.cjs')); exports.script = script; -var block_1 = require('./block'); +var block_js_1 = require('./block.cjs'); Object.defineProperty(exports, 'Block', { enumerable: true, get: function () { - return block_1.Block; + return block_js_1.Block; }, }); -var psbt_1 = require('./psbt'); +var psbt_js_1 = require('./psbt.cjs'); Object.defineProperty(exports, 'Psbt', { enumerable: true, get: function () { - return psbt_1.Psbt; + return psbt_js_1.Psbt; }, }); /** @hidden */ -var ops_1 = require('./ops'); +var ops_js_1 = require('./ops.cjs'); Object.defineProperty(exports, 'opcodes', { enumerable: true, get: function () { - return ops_1.OPS; + return ops_js_1.OPS; }, }); -var transaction_1 = require('./transaction'); +var transaction_js_1 = require('./transaction.cjs'); Object.defineProperty(exports, 'Transaction', { enumerable: true, get: function () { - return transaction_1.Transaction; + return transaction_js_1.Transaction; }, }); -var ecc_lib_1 = require('./ecc_lib'); +var ecc_lib_js_1 = require('./ecc_lib.cjs'); Object.defineProperty(exports, 'initEccLib', { enumerable: true, get: function () { - return ecc_lib_1.initEccLib; + return ecc_lib_js_1.initEccLib; }, }); diff --git a/src/cjs/index.d.ts b/src/cjs/index.d.ts index 3655f4560..dc4335db9 100644 --- a/src/cjs/index.d.ts +++ b/src/cjs/index.d.ts @@ -1,19 +1,19 @@ -import * as address from './address'; -import * as crypto from './crypto'; -import * as networks from './networks'; -import * as payments from './payments'; -import * as script from './script'; +import * as address from './address.js'; +import * as crypto from './crypto.js'; +import * as networks from './networks.js'; +import * as payments from './payments/index.js'; +import * as script from './script.js'; export { address, crypto, networks, payments, script }; -export { Block } from './block'; +export { Block } from './block.js'; /** @hidden */ -export { TaggedHashPrefix } from './crypto'; -export { Psbt, PsbtTxInput, PsbtTxOutput, Signer, SignerAsync, HDSigner, HDSignerAsync, } from './psbt'; +export { TaggedHashPrefix } from './crypto.js'; +export { Psbt, PsbtTxInput, PsbtTxOutput, Signer, SignerAsync, HDSigner, HDSignerAsync, } from './psbt.js'; /** @hidden */ -export { OPS as opcodes } from './ops'; -export { Transaction } from './transaction'; +export { OPS as opcodes } from './ops.js'; +export { Transaction } from './transaction.js'; /** @hidden */ -export { Network } from './networks'; +export { Network } from './networks.js'; /** @hidden */ -export { Payment, PaymentCreator, PaymentOpts, Stack, StackElement, } from './payments'; -export { Input as TxInput, Output as TxOutput } from './transaction'; -export { initEccLib } from './ecc_lib'; +export { Payment, PaymentCreator, PaymentOpts, Stack, StackElement, } from './payments/index.js'; +export { Input as TxInput, Output as TxOutput } from './transaction.js'; +export { initEccLib } from './ecc_lib.js'; diff --git a/src/cjs/merkle.cjs b/src/cjs/merkle.cjs new file mode 100644 index 000000000..a94e9721e --- /dev/null +++ b/src/cjs/merkle.cjs @@ -0,0 +1,74 @@ +'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if ( + !desc || + ('get' in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, 'default', { enumerable: true, value: v }); + } + : function (o, v) { + o['default'] = v; + }); +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k in mod) + if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; + }; +Object.defineProperty(exports, '__esModule', { value: true }); +exports.fastMerkleRoot = fastMerkleRoot; +const tools = __importStar(require('uint8array-tools')); +/** + * Calculates the Merkle root of an array of buffers using a specified digest function. + * + * @param values - The array of buffers. + * @param digestFn - The digest function used to calculate the hash of the concatenated buffers. + * @returns The Merkle root as a buffer. + * @throws {TypeError} If the values parameter is not an array or the digestFn parameter is not a function. + */ +function fastMerkleRoot(values, digestFn) { + if (!Array.isArray(values)) throw TypeError('Expected values Array'); + if (typeof digestFn !== 'function') + throw TypeError('Expected digest Function'); + let length = values.length; + const results = values.concat(); + while (length > 1) { + let j = 0; + for (let i = 0; i < length; i += 2, ++j) { + const left = results[i]; + const right = i + 1 === length ? left : results[i + 1]; + const data = tools.concat([left, right]); + results[j] = digestFn(data); + } + length = j; + } + return results[0]; +} diff --git a/src/cjs/merkle.d.ts b/src/cjs/merkle.d.ts index a911ca525..b98fe066a 100644 --- a/src/cjs/merkle.d.ts +++ b/src/cjs/merkle.d.ts @@ -1,4 +1,3 @@ -/// /** * Calculates the Merkle root of an array of buffers using a specified digest function. * @@ -7,4 +6,4 @@ * @returns The Merkle root as a buffer. * @throws {TypeError} If the values parameter is not an array or the digestFn parameter is not a function. */ -export declare function fastMerkleRoot(values: Buffer[], digestFn: (b: Buffer) => Buffer): Buffer; +export declare function fastMerkleRoot(values: Uint8Array[], digestFn: (b: Uint8Array) => Uint8Array): Uint8Array; diff --git a/src/cjs/merkle.js b/src/cjs/merkle.js deleted file mode 100644 index c326c53af..000000000 --- a/src/cjs/merkle.js +++ /dev/null @@ -1,30 +0,0 @@ -'use strict'; -Object.defineProperty(exports, '__esModule', { value: true }); -exports.fastMerkleRoot = void 0; -/** - * Calculates the Merkle root of an array of buffers using a specified digest function. - * - * @param values - The array of buffers. - * @param digestFn - The digest function used to calculate the hash of the concatenated buffers. - * @returns The Merkle root as a buffer. - * @throws {TypeError} If the values parameter is not an array or the digestFn parameter is not a function. - */ -function fastMerkleRoot(values, digestFn) { - if (!Array.isArray(values)) throw TypeError('Expected values Array'); - if (typeof digestFn !== 'function') - throw TypeError('Expected digest Function'); - let length = values.length; - const results = values.concat(); - while (length > 1) { - let j = 0; - for (let i = 0; i < length; i += 2, ++j) { - const left = results[i]; - const right = i + 1 === length ? left : results[i + 1]; - const data = Buffer.concat([left, right]); - results[j] = digestFn(data); - } - length = j; - } - return results[0]; -} -exports.fastMerkleRoot = fastMerkleRoot; diff --git a/src/cjs/networks.js b/src/cjs/networks.cjs similarity index 100% rename from src/cjs/networks.js rename to src/cjs/networks.cjs diff --git a/src/cjs/ops.js b/src/cjs/ops.cjs similarity index 100% rename from src/cjs/ops.js rename to src/cjs/ops.cjs diff --git a/src/cjs/payments/bip341.js b/src/cjs/payments/bip341.cjs similarity index 75% rename from src/cjs/payments/bip341.js rename to src/cjs/payments/bip341.cjs index 04ea1861a..791bfe6b9 100644 --- a/src/cjs/payments/bip341.js +++ b/src/cjs/payments/bip341.cjs @@ -44,20 +44,19 @@ var __importStar = return result; }; 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; -const buffer_1 = require('buffer'); -const ecc_lib_1 = require('../ecc_lib'); -const bcrypto = __importStar(require('../crypto')); -const bufferutils_1 = require('../bufferutils'); -const types_1 = require('../types'); +exports.MAX_TAPTREE_DEPTH = exports.LEAF_VERSION_TAPSCRIPT = void 0; +exports.rootHashFromPath = rootHashFromPath; +exports.toHashTree = toHashTree; +exports.findScriptPath = findScriptPath; +exports.tapleafHash = tapleafHash; +exports.tapTweakHash = tapTweakHash; +exports.tweakKey = tweakKey; +// import { Buffer as NBuffer } from 'buffer'; +const ecc_lib_js_1 = require('../ecc_lib.cjs'); +const bcrypto = __importStar(require('../crypto.cjs')); +const bufferutils_js_1 = require('../bufferutils.cjs'); +const types_js_1 = require('../types.cjs'); +const tools = __importStar(require('uint8array-tools')); exports.LEAF_VERSION_TAPSCRIPT = 0xc0; exports.MAX_TAPTREE_DEPTH = 128; const isHashBranch = ht => 'left' in ht && 'right' in ht; @@ -77,7 +76,8 @@ function rootHashFromPath(controlBlock, leafHash) { 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) { + // if (kj.compare(ej) < 0) { + if (tools.compare(kj, ej) < 0) { kj = tapBranchHash(kj, ej); } else { kj = tapBranchHash(ej, kj); @@ -85,16 +85,16 @@ function rootHashFromPath(controlBlock, leafHash) { } return kj; } -exports.rootHashFromPath = rootHashFromPath; /** * 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)) + if ((0, types_js_1.isTapleaf)(scriptTree)) return { hash: tapleafHash(scriptTree) }; const hashes = [toHashTree(scriptTree[0]), toHashTree(scriptTree[1])]; - hashes.sort((a, b) => a.hash.compare(b.hash)); + // hashes.sort((a, b) => a.hash.compare(b.hash)); + hashes.sort((a, b) => tools.compare(a.hash, b.hash)); const [left, right] = hashes; return { hash: tapBranchHash(left.hash, right.hash), @@ -102,7 +102,6 @@ function toHashTree(scriptTree) { right, }; } -exports.toHashTree = toHashTree; /** * Given a HashTree, finds the path from a particular hash to the root. * @param node - the root of the tree @@ -117,50 +116,48 @@ function findScriptPath(node, 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)) { + // } else if (node.hash.equals(hash)) { + } else if (tools.compare(node.hash, hash) === 0) { return []; } return undefined; } -exports.findScriptPath = findScriptPath; function tapleafHash(leaf) { const version = leaf.version || exports.LEAF_VERSION_TAPSCRIPT; return bcrypto.taggedHash( 'TapLeaf', - buffer_1.Buffer.concat([ - buffer_1.Buffer.from([version]), - serializeScript(leaf.output), - ]), + tools.concat([Uint8Array.from([version]), serializeScript(leaf.output)]), ); } -exports.tapleafHash = tapleafHash; function tapTweakHash(pubKey, h) { return bcrypto.taggedHash( 'TapTweak', - buffer_1.Buffer.concat(h ? [pubKey, h] : [pubKey]), + tools.concat(h ? [pubKey, h] : [pubKey]), ); } -exports.tapTweakHash = tapTweakHash; function tweakKey(pubKey, h) { - if (!buffer_1.Buffer.isBuffer(pubKey)) return null; + if (!(pubKey instanceof Uint8Array)) 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); + const res = (0, ecc_lib_js_1.getEccLib)().xOnlyPointAddTweak( + pubKey, + tweakHash, + ); if (!res || res.xOnlyPubkey === null) return null; return { parity: res.parity, - x: buffer_1.Buffer.from(res.xOnlyPubkey), + x: Uint8Array.from(res.xOnlyPubkey), }; } -exports.tweakKey = tweakKey; function tapBranchHash(a, b) { - return bcrypto.taggedHash('TapBranch', buffer_1.Buffer.concat([a, b])); + return bcrypto.taggedHash('TapBranch', tools.concat([a, b])); } function serializeScript(s) { /* global BigInt */ - const varintLen = bufferutils_1.varuint.encodingLength(s.length); - const buffer = buffer_1.Buffer.allocUnsafe(varintLen); // better - bufferutils_1.varuint.encode(s.length, buffer); - return buffer_1.Buffer.concat([buffer, s]); + const varintLen = bufferutils_js_1.varuint.encodingLength(s.length); + // const buffer = NBuffer.allocUnsafe(varintLen); // better + const buffer = new Uint8Array(varintLen); + bufferutils_js_1.varuint.encode(s.length, buffer); + return tools.concat([buffer, s]); } diff --git a/src/cjs/payments/bip341.d.ts b/src/cjs/payments/bip341.d.ts index 676021e4c..72f00b8d0 100644 --- a/src/cjs/payments/bip341.d.ts +++ b/src/cjs/payments/bip341.d.ts @@ -1,18 +1,17 @@ -/// -import { Tapleaf, Taptree } from '../types'; +import { Tapleaf, Taptree } from '../types.js'; export declare const LEAF_VERSION_TAPSCRIPT = 192; export declare const MAX_TAPTREE_DEPTH = 128; interface HashLeaf { - hash: Buffer; + hash: Uint8Array; } interface HashBranch { - hash: Buffer; + hash: Uint8Array; left: HashTree; right: HashTree; } interface TweakedPublicKey { parity: number; - x: Buffer; + x: Uint8Array; } /** * Binary tree representing leaf, branch, and root node hashes of a Taptree. @@ -28,7 +27,7 @@ export type HashTree = HashLeaf | HashBranch; * @returns The root hash buffer. * @throws {TypeError} If the control block length is less than 33. */ -export declare function rootHashFromPath(controlBlock: Buffer, leafHash: Buffer): Buffer; +export declare function rootHashFromPath(controlBlock: Uint8Array, leafHash: Uint8Array): Uint8Array; /** * Build a hash tree of merkle nodes from the scripts binary tree. * @param scriptTree - the tree of scripts to pairwise hash. @@ -42,8 +41,8 @@ export declare function toHashTree(scriptTree: Taptree): HashTree; * (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; -export declare function tapTweakHash(pubKey: Buffer, h: Buffer | undefined): Buffer; -export declare function tweakKey(pubKey: Buffer, h: Buffer | undefined): TweakedPublicKey | null; +export declare function findScriptPath(node: HashTree, hash: Uint8Array): Uint8Array[] | undefined; +export declare function tapleafHash(leaf: Tapleaf): Uint8Array; +export declare function tapTweakHash(pubKey: Uint8Array, h: Uint8Array | undefined): Uint8Array; +export declare function tweakKey(pubKey: Uint8Array, h: Uint8Array | undefined): TweakedPublicKey | null; export {}; diff --git a/src/cjs/payments/embed.js b/src/cjs/payments/embed.cjs similarity index 74% rename from src/cjs/payments/embed.js rename to src/cjs/payments/embed.cjs index 800b4d4eb..eddcafff2 100644 --- a/src/cjs/payments/embed.js +++ b/src/cjs/payments/embed.cjs @@ -44,11 +44,12 @@ var __importStar = return result; }; Object.defineProperty(exports, '__esModule', { value: true }); -exports.p2data = void 0; -const networks_1 = require('../networks'); -const bscript = __importStar(require('../script')); -const types_1 = require('../types'); -const lazy = __importStar(require('./lazy')); +exports.p2data = p2data; +const networks_js_1 = require('../networks.cjs'); +const bscript = __importStar(require('../script.cjs')); +const types_js_1 = require('../types.cjs'); +const lazy = __importStar(require('./lazy.cjs')); +const v = __importStar(require('valibot')); const OPS = bscript.OPS; // output: OP_RETURN ... /** @@ -61,17 +62,25 @@ const OPS = bscript.OPS; function p2data(a, opts) { if (!a.data && !a.output) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - (0, types_1.typeforce)( - { - network: types_1.typeforce.maybe(types_1.typeforce.Object), - output: types_1.typeforce.maybe(types_1.typeforce.Buffer), - data: types_1.typeforce.maybe( - types_1.typeforce.arrayOf(types_1.typeforce.Buffer), - ), - }, + // typef( + // { + // network: typef.maybe(typef.Object), + // output: typef.maybe(typef.Buffer), + // data: typef.maybe(typef.arrayOf(typef.Buffer)), + // }, + // a, + // ); + v.parse( + v.partial( + v.object({ + network: v.object({}), + output: types_js_1.BufferSchema, + data: v.array(types_js_1.BufferSchema), + }), + ), a, ); - const network = a.network || networks_1.bitcoin; + const network = a.network || networks_js_1.bitcoin; const o = { name: 'embed', network }; lazy.prop(o, 'output', () => { if (!a.data) return; @@ -86,12 +95,11 @@ function p2data(a, opts) { if (a.output) { const chunks = bscript.decompile(a.output); if (chunks[0] !== OPS.OP_RETURN) throw new TypeError('Output is invalid'); - if (!chunks.slice(1).every(types_1.typeforce.Buffer)) + if (!chunks.slice(1).every(chunk => v.is(types_js_1.BufferSchema, chunk))) throw new TypeError('Output is invalid'); - if (a.data && !(0, types_1.stacksEqual)(a.data, o.data)) + if (a.data && !(0, types_js_1.stacksEqual)(a.data, o.data)) throw new TypeError('Data mismatch'); } } return Object.assign(o, a); } -exports.p2data = p2data; diff --git a/src/cjs/payments/embed.d.ts b/src/cjs/payments/embed.d.ts index d5f5785e1..790c13d06 100644 --- a/src/cjs/payments/embed.d.ts +++ b/src/cjs/payments/embed.d.ts @@ -1,4 +1,4 @@ -import { Payment, PaymentOpts } from './index'; +import { Payment, PaymentOpts } from './index.js'; /** * Embeds data in a Bitcoin payment. * @param a - The payment object. diff --git a/src/cjs/payments/index.js b/src/cjs/payments/index.cjs similarity index 63% rename from src/cjs/payments/index.js rename to src/cjs/payments/index.cjs index f820ddeee..2db18ed77 100644 --- a/src/cjs/payments/index.js +++ b/src/cjs/payments/index.cjs @@ -9,60 +9,60 @@ exports.p2tr = exports.p2ms = exports.embed = void 0; -const embed_1 = require('./embed'); +const embed_js_1 = require('./embed.cjs'); Object.defineProperty(exports, 'embed', { enumerable: true, get: function () { - return embed_1.p2data; + return embed_js_1.p2data; }, }); -const p2ms_1 = require('./p2ms'); +const p2ms_js_1 = require('./p2ms.cjs'); Object.defineProperty(exports, 'p2ms', { enumerable: true, get: function () { - return p2ms_1.p2ms; + return p2ms_js_1.p2ms; }, }); -const p2pk_1 = require('./p2pk'); +const p2pk_js_1 = require('./p2pk.cjs'); Object.defineProperty(exports, 'p2pk', { enumerable: true, get: function () { - return p2pk_1.p2pk; + return p2pk_js_1.p2pk; }, }); -const p2pkh_1 = require('./p2pkh'); +const p2pkh_js_1 = require('./p2pkh.cjs'); Object.defineProperty(exports, 'p2pkh', { enumerable: true, get: function () { - return p2pkh_1.p2pkh; + return p2pkh_js_1.p2pkh; }, }); -const p2sh_1 = require('./p2sh'); +const p2sh_js_1 = require('./p2sh.cjs'); Object.defineProperty(exports, 'p2sh', { enumerable: true, get: function () { - return p2sh_1.p2sh; + return p2sh_js_1.p2sh; }, }); -const p2wpkh_1 = require('./p2wpkh'); +const p2wpkh_js_1 = require('./p2wpkh.cjs'); Object.defineProperty(exports, 'p2wpkh', { enumerable: true, get: function () { - return p2wpkh_1.p2wpkh; + return p2wpkh_js_1.p2wpkh; }, }); -const p2wsh_1 = require('./p2wsh'); +const p2wsh_js_1 = require('./p2wsh.cjs'); Object.defineProperty(exports, 'p2wsh', { enumerable: true, get: function () { - return p2wsh_1.p2wsh; + return p2wsh_js_1.p2wsh; }, }); -const p2tr_1 = require('./p2tr'); +const p2tr_js_1 = require('./p2tr.cjs'); Object.defineProperty(exports, 'p2tr', { enumerable: true, get: function () { - return p2tr_1.p2tr; + return p2tr_js_1.p2tr; }, }); // TODO diff --git a/src/cjs/payments/index.d.ts b/src/cjs/payments/index.d.ts index 8eafc319e..ce4b42437 100644 --- a/src/cjs/payments/index.d.ts +++ b/src/cjs/payments/index.d.ts @@ -1,4 +1,3 @@ -/// /** * Represents a payment object, which is used to create a payment. * @@ -6,35 +5,35 @@ * * @packageDocumentation */ -import { Network } from '../networks'; -import { Taptree } from '../types'; -import { p2data as embed } from './embed'; -import { p2ms } from './p2ms'; -import { p2pk } from './p2pk'; -import { p2pkh } from './p2pkh'; -import { p2sh } from './p2sh'; -import { p2wpkh } from './p2wpkh'; -import { p2wsh } from './p2wsh'; -import { p2tr } from './p2tr'; +import { Network } from '../networks.js'; +import { Taptree } from '../types.js'; +import { p2data as embed } from './embed.js'; +import { p2ms } from './p2ms.js'; +import { p2pk } from './p2pk.js'; +import { p2pkh } from './p2pkh.js'; +import { p2sh } from './p2sh.js'; +import { p2wpkh } from './p2wpkh.js'; +import { p2wsh } from './p2wsh.js'; +import { p2tr } from './p2tr.js'; export interface Payment { name?: string; network?: Network; - output?: Buffer; - data?: Buffer[]; + output?: Uint8Array; + data?: Uint8Array[]; m?: number; n?: number; - pubkeys?: Buffer[]; - input?: Buffer; - signatures?: Buffer[]; - internalPubkey?: Buffer; - pubkey?: Buffer; - signature?: Buffer; + pubkeys?: Uint8Array[]; + input?: Uint8Array; + signatures?: Uint8Array[]; + internalPubkey?: Uint8Array; + pubkey?: Uint8Array; + signature?: Uint8Array; address?: string; - hash?: Buffer; + hash?: Uint8Array; redeem?: Payment; redeemVersion?: number; scriptTree?: Taptree; - witness?: Buffer[]; + witness?: Uint8Array[]; } export type PaymentCreator = (a: Payment, opts?: PaymentOpts) => Payment; export type PaymentFunction = () => Payment; @@ -42,7 +41,7 @@ export interface PaymentOpts { validate?: boolean; allowIncomplete?: boolean; } -export type StackElement = Buffer | number; +export type StackElement = Uint8Array | number; export type Stack = StackElement[]; export type StackFunction = () => Stack; export { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh, p2tr }; diff --git a/src/cjs/payments/lazy.js b/src/cjs/payments/lazy.cjs similarity index 94% rename from src/cjs/payments/lazy.js rename to src/cjs/payments/lazy.cjs index e620c72a9..489d45991 100644 --- a/src/cjs/payments/lazy.js +++ b/src/cjs/payments/lazy.cjs @@ -1,6 +1,7 @@ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); -exports.value = exports.prop = void 0; +exports.prop = prop; +exports.value = value; function prop(object, name, f) { Object.defineProperty(object, name, { configurable: true, @@ -20,7 +21,6 @@ function prop(object, name, f) { }, }); } -exports.prop = prop; function value(f) { let _value; return () => { @@ -29,4 +29,3 @@ function value(f) { return _value; }; } -exports.value = value; diff --git a/src/cjs/payments/lazy.d.ts b/src/cjs/payments/lazy.d.ts index 3463906d8..88bb89a39 100644 --- a/src/cjs/payments/lazy.d.ts +++ b/src/cjs/payments/lazy.d.ts @@ -1,2 +1,2 @@ -export declare function prop(object: {}, name: string, f: () => any): void; +export declare function prop(object: object, name: string, f: () => any): void; export declare function value(f: () => T): () => T; diff --git a/src/cjs/payments/p2ms.js b/src/cjs/payments/p2ms.cjs similarity index 73% rename from src/cjs/payments/p2ms.js rename to src/cjs/payments/p2ms.cjs index 617e93fef..d7efe41af 100644 --- a/src/cjs/payments/p2ms.js +++ b/src/cjs/payments/p2ms.cjs @@ -44,11 +44,12 @@ var __importStar = return result; }; Object.defineProperty(exports, '__esModule', { value: true }); -exports.p2ms = void 0; -const networks_1 = require('../networks'); -const bscript = __importStar(require('../script')); -const types_1 = require('../types'); -const lazy = __importStar(require('./lazy')); +exports.p2ms = p2ms; +const networks_js_1 = require('../networks.cjs'); +const bscript = __importStar(require('../script.cjs')); +const types_js_1 = require('../types.cjs'); +const lazy = __importStar(require('./lazy.cjs')); +const v = __importStar(require('valibot')); const OPS = bscript.OPS; const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1 // input: OP_0 [signatures ...] @@ -75,23 +76,39 @@ function p2ms(a, opts) { (opts.allowIncomplete && x === OPS.OP_0) !== undefined ); } - (0, types_1.typeforce)( - { - network: types_1.typeforce.maybe(types_1.typeforce.Object), - m: types_1.typeforce.maybe(types_1.typeforce.Number), - n: types_1.typeforce.maybe(types_1.typeforce.Number), - output: types_1.typeforce.maybe(types_1.typeforce.Buffer), - pubkeys: types_1.typeforce.maybe( - types_1.typeforce.arrayOf(types_1.isPoint), - ), - signatures: types_1.typeforce.maybe( - types_1.typeforce.arrayOf(isAcceptableSignature), - ), - input: types_1.typeforce.maybe(types_1.typeforce.Buffer), - }, + // typef( + // { + // network: typef.maybe(typef.Object), + // m: typef.maybe(typef.Number), + // n: typef.maybe(typef.Number), + // output: typef.maybe(typef.Buffer), + // pubkeys: typef.maybe(typef.arrayOf(isPoint)), + // signatures: typef.maybe(typef.arrayOf(isAcceptableSignature)), + // input: typef.maybe(typef.Buffer), + // }, + // a, + // ); + v.parse( + v.partial( + v.object({ + network: v.object({}), + m: v.number(), + n: v.number(), + output: types_js_1.BufferSchema, + pubkeys: v.array( + v.custom(types_js_1.isPoint), + 'Received invalid pubkey', + ), + signatures: v.array( + v.custom(isAcceptableSignature), + 'Expected signature to be of type isAcceptableSignature', + ), + input: types_js_1.BufferSchema, + }), + ), a, ); - const network = a.network || networks_1.bitcoin; + const network = a.network || networks_js_1.bitcoin; const o = { network }; let chunks = []; let decoded = false; @@ -150,19 +167,22 @@ function p2ms(a, opts) { if (opts.validate) { if (a.output) { decode(a.output); - if (!types_1.typeforce.Number(chunks[0])) - throw new TypeError('Output is invalid'); - if (!types_1.typeforce.Number(chunks[chunks.length - 2])) - throw new TypeError('Output is invalid'); + // if (!typef.Number(chunks[0])) throw new TypeError('Output is invalid'); + v.parse(v.number(), chunks[0], { message: 'Output is invalid' }); + // if (!typef.Number(chunks[chunks.length - 2])) + // throw new TypeError('Output is invalid'); + v.parse(v.number(), chunks[chunks.length - 2], { + message: 'Output is invalid', + }); if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG) throw new TypeError('Output is invalid'); if (o.m <= 0 || o.n > 16 || o.m > o.n || o.n !== chunks.length - 3) throw new TypeError('Output is invalid'); - if (!o.pubkeys.every(x => (0, types_1.isPoint)(x))) + if (!o.pubkeys.every(x => (0, types_js_1.isPoint)(x))) throw new TypeError('Output is invalid'); if (a.m !== undefined && a.m !== o.m) throw new TypeError('m mismatch'); if (a.n !== undefined && a.n !== o.n) throw new TypeError('n mismatch'); - if (a.pubkeys && !(0, types_1.stacksEqual)(a.pubkeys, o.pubkeys)) + if (a.pubkeys && !(0, types_js_1.stacksEqual)(a.pubkeys, o.pubkeys)) throw new TypeError('Pubkeys mismatch'); } if (a.pubkeys) { @@ -184,7 +204,10 @@ function p2ms(a, opts) { !o.signatures.every(isAcceptableSignature) ) throw new TypeError('Input has invalid signature(s)'); - if (a.signatures && !(0, types_1.stacksEqual)(a.signatures, o.signatures)) + if ( + a.signatures && + !(0, types_js_1.stacksEqual)(a.signatures, o.signatures) + ) throw new TypeError('Signature mismatch'); if (a.m !== undefined && a.m !== a.signatures.length) throw new TypeError('Signature count mismatch'); @@ -192,4 +215,3 @@ function p2ms(a, opts) { } return Object.assign(o, a); } -exports.p2ms = p2ms; diff --git a/src/cjs/payments/p2ms.d.ts b/src/cjs/payments/p2ms.d.ts index ff761c1fc..4ec9b69fb 100644 --- a/src/cjs/payments/p2ms.d.ts +++ b/src/cjs/payments/p2ms.d.ts @@ -1,4 +1,4 @@ -import { Payment, PaymentOpts } from './index'; +import { Payment, PaymentOpts } from './index.js'; /** * Represents a function that creates a Pay-to-Multisig (P2MS) payment object. * @param a - The payment object. diff --git a/src/cjs/payments/p2pk.js b/src/cjs/payments/p2pk.cjs similarity index 70% rename from src/cjs/payments/p2pk.js rename to src/cjs/payments/p2pk.cjs index 8954ac720..61fb41ef4 100644 --- a/src/cjs/payments/p2pk.js +++ b/src/cjs/payments/p2pk.cjs @@ -44,11 +44,13 @@ var __importStar = return result; }; Object.defineProperty(exports, '__esModule', { value: true }); -exports.p2pk = void 0; -const networks_1 = require('../networks'); -const bscript = __importStar(require('../script')); -const types_1 = require('../types'); -const lazy = __importStar(require('./lazy')); +exports.p2pk = p2pk; +const networks_js_1 = require('../networks.cjs'); +const bscript = __importStar(require('../script.cjs')); +const types_js_1 = require('../types.cjs'); +const lazy = __importStar(require('./lazy.cjs')); +const tools = __importStar(require('uint8array-tools')); +const v = __importStar(require('valibot')); const OPS = bscript.OPS; // input: {signature} // output: {pubKey} OP_CHECKSIG @@ -64,20 +66,35 @@ function p2pk(a, opts) { if (!a.input && !a.output && !a.pubkey && !a.input && !a.signature) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - (0, types_1.typeforce)( - { - network: types_1.typeforce.maybe(types_1.typeforce.Object), - output: types_1.typeforce.maybe(types_1.typeforce.Buffer), - pubkey: types_1.typeforce.maybe(types_1.isPoint), - signature: types_1.typeforce.maybe(bscript.isCanonicalScriptSignature), - input: types_1.typeforce.maybe(types_1.typeforce.Buffer), - }, + // typef( + // { + // network: typef.maybe(typef.Object), + // output: typef.maybe(typef.Buffer), + // pubkey: typef.maybe(isPoint), + // signature: typef.maybe(bscript.isCanonicalScriptSignature), + // input: typef.maybe(typef.Buffer), + // }, + // a, + // ); + v.parse( + v.partial( + v.object({ + network: v.object({}), + output: types_js_1.BufferSchema, + pubkey: v.custom(types_js_1.isPoint, 'invalid pubkey'), + signature: v.custom( + bscript.isCanonicalScriptSignature, + 'Expected signature to be of type isCanonicalScriptSignature', + ), + input: types_js_1.BufferSchema, + }), + ), a, ); const _chunks = lazy.value(() => { return bscript.decompile(a.input); }); - const network = a.network || networks_1.bitcoin; + const network = a.network || networks_js_1.bitcoin; const o = { name: 'p2pk', network }; lazy.prop(o, 'output', () => { if (!a.pubkey) return; @@ -104,13 +121,15 @@ function p2pk(a, opts) { if (a.output) { if (a.output[a.output.length - 1] !== OPS.OP_CHECKSIG) throw new TypeError('Output is invalid'); - if (!(0, types_1.isPoint)(o.pubkey)) + if (!(0, types_js_1.isPoint)(o.pubkey)) throw new TypeError('Output pubkey is invalid'); - if (a.pubkey && !a.pubkey.equals(o.pubkey)) + // if (a.pubkey && !a.pubkey.equals(o.pubkey!)) + if (a.pubkey && tools.compare(a.pubkey, o.pubkey) !== 0) throw new TypeError('Pubkey mismatch'); } if (a.signature) { - if (a.input && !a.input.equals(o.input)) + // if (a.input && !a.input.equals(o.input!)) + if (a.input && tools.compare(a.input, o.input) !== 0) throw new TypeError('Signature mismatch'); } if (a.input) { @@ -121,4 +140,3 @@ function p2pk(a, opts) { } return Object.assign(o, a); } -exports.p2pk = p2pk; diff --git a/src/cjs/payments/p2pk.d.ts b/src/cjs/payments/p2pk.d.ts index 862ea90df..6f4b13c74 100644 --- a/src/cjs/payments/p2pk.d.ts +++ b/src/cjs/payments/p2pk.d.ts @@ -1,4 +1,4 @@ -import { Payment, PaymentOpts } from './index'; +import { Payment, PaymentOpts } from './index.js'; /** * Creates a pay-to-public-key (P2PK) payment object. * diff --git a/src/cjs/payments/p2pkh.js b/src/cjs/payments/p2pkh.cjs similarity index 64% rename from src/cjs/payments/p2pkh.js rename to src/cjs/payments/p2pkh.cjs index 6989cc31a..ce8bc75e5 100644 --- a/src/cjs/payments/p2pkh.js +++ b/src/cjs/payments/p2pkh.cjs @@ -43,14 +43,21 @@ var __importStar = __setModuleDefault(result, mod); return result; }; +var __importDefault = + (this && this.__importDefault) || + function (mod) { + return mod && mod.__esModule ? mod : { default: mod }; + }; Object.defineProperty(exports, '__esModule', { value: true }); -exports.p2pkh = void 0; -const bcrypto = __importStar(require('../crypto')); -const networks_1 = require('../networks'); -const bscript = __importStar(require('../script')); -const types_1 = require('../types'); -const lazy = __importStar(require('./lazy')); -const bs58check = __importStar(require('bs58check')); +exports.p2pkh = p2pkh; +const bcrypto = __importStar(require('../crypto.cjs')); +const networks_js_1 = require('../networks.cjs'); +const bscript = __importStar(require('../script.cjs')); +const types_js_1 = require('../types.cjs'); +const lazy = __importStar(require('./lazy.cjs')); +const bs58check_1 = __importDefault(require('bs58check')); +const tools = __importStar(require('uint8array-tools')); +const v = __importStar(require('valibot')); const OPS = bscript.OPS; // input: {signature} {pubkey} // output: OP_DUP OP_HASH160 {hash160(pubkey)} OP_EQUALVERIFY OP_CHECKSIG @@ -66,35 +73,52 @@ function p2pkh(a, opts) { if (!a.address && !a.hash && !a.output && !a.pubkey && !a.input) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - (0, types_1.typeforce)( - { - network: types_1.typeforce.maybe(types_1.typeforce.Object), - address: types_1.typeforce.maybe(types_1.typeforce.String), - hash: types_1.typeforce.maybe(types_1.typeforce.BufferN(20)), - output: types_1.typeforce.maybe(types_1.typeforce.BufferN(25)), - pubkey: types_1.typeforce.maybe(types_1.isPoint), - signature: types_1.typeforce.maybe(bscript.isCanonicalScriptSignature), - input: types_1.typeforce.maybe(types_1.typeforce.Buffer), - }, + // typef( + // { + // network: typef.maybe(typef.Object), + // address: typef.maybe(typef.String), + // hash: typef.maybe(typef.BufferN(20)), + // output: typef.maybe(typef.BufferN(25)), + // pubkey: typef.maybe(isPoint), + // signature: typef.maybe(bscript.isCanonicalScriptSignature), + // input: typef.maybe(typef.Buffer), + // }, + // a, + // ); + v.parse( + v.partial( + v.object({ + network: v.object({}), + address: v.string(), + hash: types_js_1.Hash160bitSchema, + output: (0, types_js_1.NBufferSchemaFactory)(25), + pubkey: v.custom(types_js_1.isPoint), + signature: v.custom(bscript.isCanonicalScriptSignature), + input: types_js_1.BufferSchema, + }), + ), a, ); const _address = lazy.value(() => { - const payload = Buffer.from(bs58check.decode(a.address)); - const version = payload.readUInt8(0); + const payload = bs58check_1.default.decode(a.address); + // const version = payload.readUInt8(0); + const version = tools.readUInt8(payload, 0); const hash = payload.slice(1); return { version, hash }; }); const _chunks = lazy.value(() => { return bscript.decompile(a.input); }); - const network = a.network || networks_1.bitcoin; + const network = a.network || networks_js_1.bitcoin; const o = { name: 'p2pkh', network }; lazy.prop(o, 'address', () => { if (!o.hash) return; - const payload = Buffer.allocUnsafe(21); - payload.writeUInt8(network.pubKeyHash, 0); - o.hash.copy(payload, 1); - return bs58check.encode(payload); + const payload = new Uint8Array(21); + // payload.writeUInt8(network.pubKeyHash, 0); + tools.writeUInt8(payload, 0, network.pubKeyHash); + // o.hash.copy(payload, 1); + payload.set(o.hash, 1); + return bs58check_1.default.encode(payload); }); lazy.prop(o, 'hash', () => { if (a.output) return a.output.slice(3, 23); @@ -130,7 +154,7 @@ function p2pkh(a, opts) { }); // extended validation if (opts.validate) { - let hash = Buffer.from([]); + let hash = Uint8Array.from([]); if (a.address) { if (_address().version !== network.pubKeyHash) throw new TypeError('Invalid version or Network mismatch'); @@ -138,7 +162,8 @@ function p2pkh(a, opts) { hash = _address().hash; } if (a.hash) { - if (hash.length > 0 && !hash.equals(a.hash)) + // if (hash.length > 0 && !hash.equals(a.hash)) + if (hash.length > 0 && tools.compare(hash, a.hash) !== 0) throw new TypeError('Hash mismatch'); else hash = a.hash; } @@ -153,13 +178,15 @@ function p2pkh(a, opts) { ) throw new TypeError('Output is invalid'); const hash2 = a.output.slice(3, 23); - if (hash.length > 0 && !hash.equals(hash2)) + // if (hash.length > 0 && !hash.equals(hash2)) + if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; } if (a.pubkey) { const pkh = bcrypto.hash160(a.pubkey); - if (hash.length > 0 && !hash.equals(pkh)) + // if (hash.length > 0 && !hash.equals(pkh)) + if (hash.length > 0 && tools.compare(hash, pkh) !== 0) throw new TypeError('Hash mismatch'); else hash = pkh; } @@ -168,17 +195,19 @@ function p2pkh(a, opts) { if (chunks.length !== 2) throw new TypeError('Input is invalid'); if (!bscript.isCanonicalScriptSignature(chunks[0])) throw new TypeError('Input has invalid signature'); - if (!(0, types_1.isPoint)(chunks[1])) + if (!(0, types_js_1.isPoint)(chunks[1])) throw new TypeError('Input has invalid pubkey'); - if (a.signature && !a.signature.equals(chunks[0])) + // if (a.signature && !a.signature.equals(chunks[0])) + if (a.signature && tools.compare(a.signature, chunks[0]) !== 0) throw new TypeError('Signature mismatch'); - if (a.pubkey && !a.pubkey.equals(chunks[1])) + // if (a.pubkey && !a.pubkey.equals(chunks[1] as Buffer)) + if (a.pubkey && tools.compare(a.pubkey, chunks[1]) !== 0) throw new TypeError('Pubkey mismatch'); const pkh = bcrypto.hash160(chunks[1]); - if (hash.length > 0 && !hash.equals(pkh)) + // if (hash.length > 0 && !hash.equals(pkh)) + if (hash.length > 0 && tools.compare(hash, pkh) !== 0) throw new TypeError('Hash mismatch'); } } return Object.assign(o, a); } -exports.p2pkh = p2pkh; diff --git a/src/cjs/payments/p2pkh.d.ts b/src/cjs/payments/p2pkh.d.ts index 1c5b76b5b..e2bdafb1d 100644 --- a/src/cjs/payments/p2pkh.d.ts +++ b/src/cjs/payments/p2pkh.d.ts @@ -1,4 +1,4 @@ -import { Payment, PaymentOpts } from './index'; +import { Payment, PaymentOpts } from './index.js'; /** * Creates a Pay-to-Public-Key-Hash (P2PKH) payment object. * diff --git a/src/cjs/payments/p2sh.js b/src/cjs/payments/p2sh.cjs similarity index 67% rename from src/cjs/payments/p2sh.js rename to src/cjs/payments/p2sh.cjs index b1b261a43..650fe86de 100644 --- a/src/cjs/payments/p2sh.js +++ b/src/cjs/payments/p2sh.cjs @@ -43,14 +43,21 @@ var __importStar = __setModuleDefault(result, mod); return result; }; +var __importDefault = + (this && this.__importDefault) || + function (mod) { + return mod && mod.__esModule ? mod : { default: mod }; + }; Object.defineProperty(exports, '__esModule', { value: true }); -exports.p2sh = void 0; -const bcrypto = __importStar(require('../crypto')); -const networks_1 = require('../networks'); -const bscript = __importStar(require('../script')); -const types_1 = require('../types'); -const lazy = __importStar(require('./lazy')); -const bs58check = __importStar(require('bs58check')); +exports.p2sh = p2sh; +const bcrypto = __importStar(require('../crypto.cjs')); +const networks_js_1 = require('../networks.cjs'); +const bscript = __importStar(require('../script.cjs')); +const types_js_1 = require('../types.cjs'); +const lazy = __importStar(require('./lazy.cjs')); +const bs58check_1 = __importDefault(require('bs58check')); +const tools = __importStar(require('uint8array-tools')); +const v = __importStar(require('valibot')); const OPS = bscript.OPS; // input: [redeemScriptSig ...] {redeemScript} // witness: @@ -67,35 +74,53 @@ function p2sh(a, opts) { if (!a.address && !a.hash && !a.output && !a.redeem && !a.input) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - (0, types_1.typeforce)( - { - network: types_1.typeforce.maybe(types_1.typeforce.Object), - address: types_1.typeforce.maybe(types_1.typeforce.String), - hash: types_1.typeforce.maybe(types_1.typeforce.BufferN(20)), - output: types_1.typeforce.maybe(types_1.typeforce.BufferN(23)), - redeem: types_1.typeforce.maybe({ - network: types_1.typeforce.maybe(types_1.typeforce.Object), - output: types_1.typeforce.maybe(types_1.typeforce.Buffer), - input: types_1.typeforce.maybe(types_1.typeforce.Buffer), - witness: types_1.typeforce.maybe( - types_1.typeforce.arrayOf(types_1.typeforce.Buffer), + // typef( + // { + // network: typef.maybe(typef.Object), + // address: typef.maybe(typef.String), + // hash: typef.maybe(typef.BufferN(20)), + // output: typef.maybe(typef.BufferN(23)), + // redeem: typef.maybe({ + // network: typef.maybe(typef.Object), + // output: typef.maybe(typef.Buffer), + // input: typef.maybe(typef.Buffer), + // witness: typef.maybe(typef.arrayOf(typef.Buffer)), + // }), + // input: typef.maybe(typef.Buffer), + // witness: typef.maybe(typef.arrayOf(typef.Buffer)), + // }, + // a, + // ); + v.parse( + v.partial( + v.object({ + network: v.object({}), + address: v.string(), + hash: (0, types_js_1.NBufferSchemaFactory)(20), + output: (0, types_js_1.NBufferSchemaFactory)(23), + redeem: v.partial( + v.object({ + network: v.object({}), + output: types_js_1.BufferSchema, + input: types_js_1.BufferSchema, + witness: v.array(types_js_1.BufferSchema), + }), ), + input: types_js_1.BufferSchema, + witness: v.array(types_js_1.BufferSchema), }), - input: types_1.typeforce.maybe(types_1.typeforce.Buffer), - witness: types_1.typeforce.maybe( - types_1.typeforce.arrayOf(types_1.typeforce.Buffer), - ), - }, + ), a, ); let network = a.network; if (!network) { - network = (a.redeem && a.redeem.network) || networks_1.bitcoin; + network = (a.redeem && a.redeem.network) || networks_js_1.bitcoin; } const o = { network }; const _address = lazy.value(() => { - const payload = Buffer.from(bs58check.decode(a.address)); - const version = payload.readUInt8(0); + const payload = bs58check_1.default.decode(a.address); + // const version = payload.readUInt8(0); + const version = tools.readUInt8(payload, 0); const hash = payload.slice(1); return { version, hash }; }); @@ -107,7 +132,7 @@ function p2sh(a, opts) { const lastChunk = chunks[chunks.length - 1]; return { network, - output: lastChunk === OPS.OP_FALSE ? Buffer.from([]) : lastChunk, + output: lastChunk === OPS.OP_FALSE ? Uint8Array.from([]) : lastChunk, input: bscript.compile(chunks.slice(0, -1)), witness: a.witness || [], }; @@ -115,10 +140,12 @@ function p2sh(a, opts) { // output dependents lazy.prop(o, 'address', () => { if (!o.hash) return; - const payload = Buffer.allocUnsafe(21); - payload.writeUInt8(o.network.scriptHash, 0); - o.hash.copy(payload, 1); - return bs58check.encode(payload); + const payload = new Uint8Array(21); + // payload.writeUInt8(o.network!.scriptHash, 0); + tools.writeUInt8(payload, 0, o.network.scriptHash); + // o.hash.copy(payload, 1); + payload.set(o.hash, 1); + return bs58check_1.default.encode(payload); }); lazy.prop(o, 'hash', () => { // in order of least effort @@ -152,7 +179,7 @@ function p2sh(a, opts) { return nameParts.join('-'); }); if (opts.validate) { - let hash = Buffer.from([]); + let hash = Uint8Array.from([]); if (a.address) { if (_address().version !== network.scriptHash) throw new TypeError('Invalid version or Network mismatch'); @@ -160,7 +187,8 @@ function p2sh(a, opts) { hash = _address().hash; } if (a.hash) { - if (hash.length > 0 && !hash.equals(a.hash)) + // if (hash.length > 0 && !hash.equals(a.hash)) + if (hash.length > 0 && tools.compare(hash, a.hash) !== 0) throw new TypeError('Hash mismatch'); else hash = a.hash; } @@ -173,7 +201,8 @@ function p2sh(a, opts) { ) throw new TypeError('Output is invalid'); const hash2 = a.output.slice(2, 22); - if (hash.length > 0 && !hash.equals(hash2)) + // if (hash.length > 0 && !hash.equals(hash2)) + if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; } @@ -194,7 +223,8 @@ function p2sh(a, opts) { ); // match hash against other sources const hash2 = bcrypto.hash160(redeem.output); - if (hash.length > 0 && !hash.equals(hash2)) + // if (hash.length > 0 && !hash.equals(hash2)) + if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; } @@ -214,7 +244,7 @@ function p2sh(a, opts) { if (a.input) { const chunks = _chunks(); if (!chunks || chunks.length < 1) throw new TypeError('Input too short'); - if (!Buffer.isBuffer(_redeem().output)) + if (!(_redeem().output instanceof Uint8Array)) throw new TypeError('Input is invalid'); checkRedeem(_redeem()); } @@ -223,9 +253,14 @@ function p2sh(a, opts) { throw new TypeError('Network mismatch'); if (a.input) { const redeem = _redeem(); - if (a.redeem.output && !a.redeem.output.equals(redeem.output)) + // if (a.redeem.output && !a.redeem.output.equals(redeem.output!)) + if ( + a.redeem.output && + tools.compare(a.redeem.output, redeem.output) !== 0 + ) throw new TypeError('Redeem.output mismatch'); - if (a.redeem.input && !a.redeem.input.equals(redeem.input)) + // if (a.redeem.input && !a.redeem.input.equals(redeem.input!)) + if (a.redeem.input && tools.compare(a.redeem.input, redeem.input) !== 0) throw new TypeError('Redeem.input mismatch'); } checkRedeem(a.redeem); @@ -234,11 +269,10 @@ function p2sh(a, opts) { if ( a.redeem && a.redeem.witness && - !(0, types_1.stacksEqual)(a.redeem.witness, a.witness) + !(0, types_js_1.stacksEqual)(a.redeem.witness, a.witness) ) throw new TypeError('Witness and redeem.witness mismatch'); } } return Object.assign(o, a); } -exports.p2sh = p2sh; diff --git a/src/cjs/payments/p2sh.d.ts b/src/cjs/payments/p2sh.d.ts index c82d040cc..444c3940a 100644 --- a/src/cjs/payments/p2sh.d.ts +++ b/src/cjs/payments/p2sh.d.ts @@ -1,4 +1,4 @@ -import { Payment, PaymentOpts } from './index'; +import { Payment, PaymentOpts } from './index.js'; /** * Creates a Pay-to-Script-Hash (P2SH) payment object. * diff --git a/src/cjs/payments/p2tr.js b/src/cjs/payments/p2tr.cjs similarity index 60% rename from src/cjs/payments/p2tr.js rename to src/cjs/payments/p2tr.cjs index 11f160815..728893b19 100644 --- a/src/cjs/payments/p2tr.js +++ b/src/cjs/payments/p2tr.cjs @@ -44,16 +44,18 @@ var __importStar = return result; }; Object.defineProperty(exports, '__esModule', { value: true }); -exports.p2tr = void 0; -const buffer_1 = require('buffer'); -const networks_1 = require('../networks'); -const bscript = __importStar(require('../script')); -const types_1 = require('../types'); -const ecc_lib_1 = require('../ecc_lib'); -const bip341_1 = require('./bip341'); -const lazy = __importStar(require('./lazy')); +exports.p2tr = p2tr; +// import { Buffer as NBuffer } from 'buffer'; +const networks_js_1 = require('../networks.cjs'); +const bscript = __importStar(require('../script.cjs')); +const types_js_1 = require('../types.cjs'); +const ecc_lib_js_1 = require('../ecc_lib.cjs'); +const bip341_js_1 = require('./bip341.cjs'); +const lazy = __importStar(require('./lazy.cjs')); const bech32_1 = require('bech32'); -const address_1 = require('../address'); +const address_js_1 = require('../address.cjs'); +const tools = __importStar(require('uint8array-tools')); +const v = __importStar(require('valibot')); const OPS = bscript.OPS; const TAPROOT_WITNESS_VERSION = 0x01; const ANNEX_PREFIX = 0x50; @@ -75,38 +77,60 @@ function p2tr(a, opts) { ) 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( - types_1.typeforce.anyOf( - types_1.typeforce.BufferN(64), - types_1.typeforce.BufferN(65), + // 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)), // 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))), + // witness: typef.maybe(typef.arrayOf(typef.Buffer)), + // scriptTree: typef.maybe(isTaptree), + // redeem: typef.maybe({ + // 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), + // }, + // a, + // ); + v.parse( + v.partial( + v.object({ + address: v.string(), + input: (0, types_js_1.NBufferSchemaFactory)(0), + network: v.object({}), + output: (0, types_js_1.NBufferSchemaFactory)(34), + internalPubkey: (0, types_js_1.NBufferSchemaFactory)(32), + hash: (0, types_js_1.NBufferSchemaFactory)(32), // merkle root hash, the tweak + pubkey: (0, types_js_1.NBufferSchemaFactory)(32), // tweaked with `hash` from `internalPubkey` + signature: v.union([ + (0, types_js_1.NBufferSchemaFactory)(64), + (0, types_js_1.NBufferSchemaFactory)(65), + ]), + witness: v.array(types_js_1.BufferSchema), + scriptTree: v.custom( + types_js_1.isTaptree, + 'Taptree is not of type isTaptree', ), - ), - witness: types_1.typeforce.maybe( - types_1.typeforce.arrayOf(types_1.typeforce.Buffer), - ), - 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), - witness: types_1.typeforce.maybe( - types_1.typeforce.arrayOf(types_1.typeforce.Buffer), + redeem: v.partial( + v.object({ + output: types_js_1.BufferSchema, // tapleaf script + redeemVersion: v.number(), // tapleaf version + witness: v.array(types_js_1.BufferSchema), + }), ), + redeemVersion: v.number(), }), - redeemVersion: types_1.typeforce.maybe(types_1.typeforce.Number), - }, + ), a, ); const _address = lazy.value(() => { - return (0, address_1.fromBech32)(a.address); + return (0, address_js_1.fromBech32)(a.address); }); // remove annex if present, ignored by taproot const _witness = lazy.value(() => { @@ -120,11 +144,11 @@ function p2tr(a, opts) { return a.witness.slice(); }); const _hashTree = lazy.value(() => { - if (a.scriptTree) return (0, bip341_1.toHashTree)(a.scriptTree); + if (a.scriptTree) return (0, bip341_js_1.toHashTree)(a.scriptTree); if (a.hash) return { hash: a.hash }; return; }); - const network = a.network || networks_1.bitcoin; + const network = a.network || networks_js_1.bitcoin; const o = { name: 'p2tr', network }; lazy.prop(o, 'address', () => { if (!o.pubkey) return; @@ -138,13 +162,13 @@ function p2tr(a, opts) { const w = _witness(); if (w && w.length > 1) { const controlBlock = w[w.length - 1]; - const leafVersion = controlBlock[0] & types_1.TAPLEAF_VERSION_MASK; + const leafVersion = controlBlock[0] & types_js_1.TAPLEAF_VERSION_MASK; const script = w[w.length - 2]; - const leafHash = (0, bip341_1.tapleafHash)({ + const leafHash = (0, bip341_js_1.tapleafHash)({ output: script, version: leafVersion, }); - return (0, bip341_1.rootHashFromPath)(controlBlock, leafHash); + return (0, bip341_js_1.rootHashFromPath)(controlBlock, leafHash); } return null; }); @@ -161,7 +185,7 @@ function p2tr(a, opts) { ) { return a.redeem.redeemVersion; } - return bip341_1.LEAF_VERSION_TAPSCRIPT; + return bip341_js_1.LEAF_VERSION_TAPSCRIPT; }); lazy.prop(o, 'redeem', () => { const witness = _witness(); // witness without annex @@ -170,7 +194,7 @@ function p2tr(a, opts) { output: witness[witness.length - 2], witness: witness.slice(0, -2), redeemVersion: - witness[witness.length - 1][0] & types_1.TAPLEAF_VERSION_MASK, + witness[witness.length - 1][0] & types_js_1.TAPLEAF_VERSION_MASK, }; }); lazy.prop(o, 'pubkey', () => { @@ -178,7 +202,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, bip341_1.tweakKey)(o.internalPubkey, o.hash); + const tweakedKey = (0, bip341_js_1.tweakKey)(o.internalPubkey, o.hash); if (tweakedKey) return tweakedKey.x; } }); @@ -198,17 +222,20 @@ 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, bip341_1.tapleafHash)({ + const leafHash = (0, bip341_js_1.tapleafHash)({ output: a.redeem.output, version: o.redeemVersion, }); - const path = (0, bip341_1.findScriptPath)(hashTree, leafHash); + const path = (0, bip341_js_1.findScriptPath)(hashTree, leafHash); if (!path) return; - const outputKey = (0, bip341_1.tweakKey)(a.internalPubkey, hashTree.hash); + const outputKey = (0, bip341_js_1.tweakKey)( + a.internalPubkey, + hashTree.hash, + ); if (!outputKey) return; - const controlBock = buffer_1.Buffer.concat( + const controlBock = tools.concat( [ - buffer_1.Buffer.from([o.redeemVersion | outputKey.parity]), + Uint8Array.from([o.redeemVersion | outputKey.parity]), a.internalPubkey, ].concat(path), ); @@ -218,7 +245,7 @@ function p2tr(a, opts) { }); // extended validation if (opts.validate) { - let pubkey = buffer_1.Buffer.from([]); + let pubkey = Uint8Array.from([]); if (a.address) { if (network && network.bech32 !== _address().prefix) throw new TypeError('Invalid prefix or Network mismatch'); @@ -229,7 +256,8 @@ function p2tr(a, opts) { pubkey = _address().data; } if (a.pubkey) { - if (pubkey.length > 0 && !pubkey.equals(a.pubkey)) + // if (pubkey.length > 0 && !pubkey.equals(a.pubkey)) + if (pubkey.length > 0 && tools.compare(pubkey, a.pubkey) !== 0) throw new TypeError('Pubkey mismatch'); else pubkey = a.pubkey; } @@ -240,30 +268,34 @@ function p2tr(a, opts) { a.output[1] !== 0x20 ) throw new TypeError('Output is invalid'); - if (pubkey.length > 0 && !pubkey.equals(a.output.slice(2))) + // if (pubkey.length > 0 && !pubkey.equals(a.output.slice(2))) + if (pubkey.length > 0 && tools.compare(pubkey, a.output.slice(2)) !== 0) throw new TypeError('Pubkey mismatch'); else pubkey = a.output.slice(2); } if (a.internalPubkey) { - const tweakedKey = (0, bip341_1.tweakKey)(a.internalPubkey, o.hash); - if (pubkey.length > 0 && !pubkey.equals(tweakedKey.x)) + const tweakedKey = (0, bip341_js_1.tweakKey)(a.internalPubkey, o.hash); + // if (pubkey.length > 0 && !pubkey.equals(tweakedKey!.x)) + if (pubkey.length > 0 && tools.compare(pubkey, tweakedKey.x) !== 0) throw new TypeError('Pubkey mismatch'); else pubkey = tweakedKey.x; } if (pubkey && pubkey.length) { - if (!(0, ecc_lib_1.getEccLib)().isXOnlyPoint(pubkey)) + if (!(0, ecc_lib_js_1.getEccLib)().isXOnlyPoint(pubkey)) throw new TypeError('Invalid pubkey for p2tr'); } const hashTree = _hashTree(); if (a.hash && hashTree) { - if (!a.hash.equals(hashTree.hash)) throw new TypeError('Hash mismatch'); + // if (!a.hash.equals(hashTree.hash)) throw new TypeError('Hash mismatch'); + if (tools.compare(a.hash, hashTree.hash) !== 0) + throw new TypeError('Hash mismatch'); } if (a.redeem && a.redeem.output && hashTree) { - const leafHash = (0, bip341_1.tapleafHash)({ + const leafHash = (0, bip341_js_1.tapleafHash)({ output: a.redeem.output, version: o.redeemVersion, }); - if (!(0, bip341_1.findScriptPath)(hashTree, leafHash)) + if (!(0, bip341_js_1.findScriptPath)(hashTree, leafHash)) throw new TypeError('Redeem script not in tree'); } const witness = _witness(); @@ -277,13 +309,17 @@ function p2tr(a, opts) { 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)) + // if (o.redeem.output && !a.redeem.output.equals(o.redeem.output)) + if ( + o.redeem.output && + tools.compare(a.redeem.output, o.redeem.output) !== 0 + ) throw new TypeError('Redeem.output and witness mismatch'); } if (a.redeem.witness) { if ( o.redeem.witness && - !(0, types_1.stacksEqual)(a.redeem.witness, o.redeem.witness) + !(0, types_js_1.stacksEqual)(a.redeem.witness, o.redeem.witness) ) throw new TypeError('Redeem.witness and witness mismatch'); } @@ -291,7 +327,8 @@ function p2tr(a, opts) { if (witness && witness.length) { if (witness.length === 1) { // key spending - if (a.signature && !a.signature.equals(witness[0])) + // if (a.signature && !a.signature.equals(witness[0])) + if (a.signature && tools.compare(a.signature, witness[0]) !== 0) throw new TypeError('Signature mismatch'); } else { // script path spending @@ -310,22 +347,27 @@ function p2tr(a, opts) { `The script path is too long. Got ${m}, expected max 128.`, ); const internalPubkey = controlBlock.slice(1, 33); - if (a.internalPubkey && !a.internalPubkey.equals(internalPubkey)) + // if (a.internalPubkey && !a.internalPubkey.equals(internalPubkey)) + if ( + a.internalPubkey && + tools.compare(a.internalPubkey, internalPubkey) !== 0 + ) throw new TypeError('Internal pubkey mismatch'); - if (!(0, ecc_lib_1.getEccLib)().isXOnlyPoint(internalPubkey)) + if (!(0, ecc_lib_js_1.getEccLib)().isXOnlyPoint(internalPubkey)) throw new TypeError('Invalid internalPubkey for p2tr witness'); - const leafVersion = controlBlock[0] & types_1.TAPLEAF_VERSION_MASK; + const leafVersion = controlBlock[0] & types_js_1.TAPLEAF_VERSION_MASK; const script = witness[witness.length - 2]; - const leafHash = (0, bip341_1.tapleafHash)({ + const leafHash = (0, bip341_js_1.tapleafHash)({ output: script, version: leafVersion, }); - const hash = (0, bip341_1.rootHashFromPath)(controlBlock, leafHash); - const outputKey = (0, bip341_1.tweakKey)(internalPubkey, hash); + const hash = (0, bip341_js_1.rootHashFromPath)(controlBlock, leafHash); + const outputKey = (0, bip341_js_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)) + // if (pubkey.length && !pubkey.equals(outputKey.x)) + if (pubkey.length && tools.compare(pubkey, outputKey.x) !== 0) throw new TypeError('Pubkey mismatch for p2tr witness'); if (outputKey.parity !== (controlBlock[0] & 1)) throw new Error('Incorrect parity'); @@ -334,4 +376,3 @@ function p2tr(a, opts) { } return Object.assign(o, a); } -exports.p2tr = p2tr; diff --git a/src/cjs/payments/p2tr.d.ts b/src/cjs/payments/p2tr.d.ts index 97b2e0eb2..2030f62e7 100644 --- a/src/cjs/payments/p2tr.d.ts +++ b/src/cjs/payments/p2tr.d.ts @@ -1,4 +1,4 @@ -import { Payment, PaymentOpts } from './index'; +import { Payment, PaymentOpts } from './index.js'; /** * Creates a Pay-to-Taproot (P2TR) payment object. * diff --git a/src/cjs/payments/p2wpkh.js b/src/cjs/payments/p2wpkh.cjs similarity index 66% rename from src/cjs/payments/p2wpkh.js rename to src/cjs/payments/p2wpkh.cjs index 02a78c4e6..9905ac6d0 100644 --- a/src/cjs/payments/p2wpkh.js +++ b/src/cjs/payments/p2wpkh.cjs @@ -44,15 +44,17 @@ var __importStar = return result; }; Object.defineProperty(exports, '__esModule', { value: true }); -exports.p2wpkh = void 0; -const bcrypto = __importStar(require('../crypto')); -const networks_1 = require('../networks'); -const bscript = __importStar(require('../script')); -const types_1 = require('../types'); -const lazy = __importStar(require('./lazy')); +exports.p2wpkh = p2wpkh; +const bcrypto = __importStar(require('../crypto.cjs')); +const networks_js_1 = require('../networks.cjs'); +const bscript = __importStar(require('../script.cjs')); +const types_js_1 = require('../types.cjs'); +const lazy = __importStar(require('./lazy.cjs')); const bech32_1 = require('bech32'); +const tools = __importStar(require('uint8array-tools')); +const v = __importStar(require('valibot')); const OPS = bscript.OPS; -const EMPTY_BUFFER = Buffer.alloc(0); +const EMPTY_BUFFER = new Uint8Array(0); // witness: {signature} {pubKey} // input: <> // output: OP_0 {pubKeyHash} @@ -68,19 +70,32 @@ function p2wpkh(a, opts) { if (!a.address && !a.hash && !a.output && !a.pubkey && !a.witness) 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), - 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(22)), - pubkey: types_1.typeforce.maybe(types_1.isPoint), - signature: types_1.typeforce.maybe(bscript.isCanonicalScriptSignature), - witness: types_1.typeforce.maybe( - types_1.typeforce.arrayOf(types_1.typeforce.Buffer), - ), - }, + // typef( + // { + // 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(22)), + // pubkey: typef.maybe(isPoint), + // signature: typef.maybe(bscript.isCanonicalScriptSignature), + // witness: typef.maybe(typef.arrayOf(typef.Buffer)), + // }, + // a, + // ); + v.parse( + v.partial( + v.object({ + address: v.string(), + hash: (0, types_js_1.NBufferSchemaFactory)(20), + input: (0, types_js_1.NBufferSchemaFactory)(0), + network: v.object({}), + output: (0, types_js_1.NBufferSchemaFactory)(22), + pubkey: v.custom(types_js_1.isPoint, 'Not a valid pubkey'), + signature: v.custom(bscript.isCanonicalScriptSignature), + witness: v.array(types_js_1.BufferSchema), + }), + ), a, ); const _address = lazy.value(() => { @@ -90,10 +105,10 @@ function p2wpkh(a, opts) { return { version, prefix: result.prefix, - data: Buffer.from(data), + data: Uint8Array.from(data), }; }); - const network = a.network || networks_1.bitcoin; + const network = a.network || networks_js_1.bitcoin; const o = { name: 'p2wpkh', network }; lazy.prop(o, 'address', () => { if (!o.hash) return; @@ -130,7 +145,7 @@ function p2wpkh(a, opts) { }); // extended validation if (opts.validate) { - let hash = Buffer.from([]); + let hash = Uint8Array.from([]); if (a.address) { if (network && network.bech32 !== _address().prefix) throw new TypeError('Invalid prefix or Network mismatch'); @@ -141,7 +156,8 @@ function p2wpkh(a, opts) { hash = _address().data; } if (a.hash) { - if (hash.length > 0 && !hash.equals(a.hash)) + // if (hash.length > 0 && !hash.equals(a.hash)) + if (hash.length > 0 && tools.compare(hash, a.hash) !== 0) throw new TypeError('Hash mismatch'); else hash = a.hash; } @@ -152,33 +168,37 @@ function p2wpkh(a, opts) { a.output[1] !== 0x14 ) throw new TypeError('Output is invalid'); - if (hash.length > 0 && !hash.equals(a.output.slice(2))) + // if (hash.length > 0 && !hash.equals(a.output.slice(2))) + if (hash.length > 0 && tools.compare(hash, a.output.slice(2)) !== 0) throw new TypeError('Hash mismatch'); else hash = a.output.slice(2); } if (a.pubkey) { const pkh = bcrypto.hash160(a.pubkey); - if (hash.length > 0 && !hash.equals(pkh)) + // if (hash.length > 0 && !hash.equals(pkh)) + if (hash.length > 0 && tools.compare(hash, pkh) !== 0) throw new TypeError('Hash mismatch'); else hash = pkh; - if (!(0, types_1.isPoint)(a.pubkey) || a.pubkey.length !== 33) + if (!(0, types_js_1.isPoint)(a.pubkey) || a.pubkey.length !== 33) throw new TypeError('Invalid pubkey for p2wpkh'); } if (a.witness) { if (a.witness.length !== 2) throw new TypeError('Witness is invalid'); if (!bscript.isCanonicalScriptSignature(a.witness[0])) throw new TypeError('Witness has invalid signature'); - if (!(0, types_1.isPoint)(a.witness[1]) || a.witness[1].length !== 33) + if (!(0, types_js_1.isPoint)(a.witness[1]) || a.witness[1].length !== 33) throw new TypeError('Witness has invalid pubkey'); - if (a.signature && !a.signature.equals(a.witness[0])) + // if (a.signature && !a.signature.equals(a.witness[0])) + if (a.signature && tools.compare(a.signature, a.witness[0]) !== 0) throw new TypeError('Signature mismatch'); - if (a.pubkey && !a.pubkey.equals(a.witness[1])) + // if (a.pubkey && !a.pubkey.equals(a.witness[1])) + if (a.pubkey && tools.compare(a.pubkey, a.witness[1]) !== 0) throw new TypeError('Pubkey mismatch'); const pkh = bcrypto.hash160(a.witness[1]); - if (hash.length > 0 && !hash.equals(pkh)) + // if (hash.length > 0 && !hash.equals(pkh)) + if (hash.length > 0 && tools.compare(hash, pkh) !== 0) throw new TypeError('Hash mismatch'); } } return Object.assign(o, a); } -exports.p2wpkh = p2wpkh; diff --git a/src/cjs/payments/p2wpkh.d.ts b/src/cjs/payments/p2wpkh.d.ts index 5108e2912..e4817a112 100644 --- a/src/cjs/payments/p2wpkh.d.ts +++ b/src/cjs/payments/p2wpkh.d.ts @@ -1,4 +1,4 @@ -import { Payment, PaymentOpts } from './index'; +import { Payment, PaymentOpts } from './index.js'; /** * Creates a pay-to-witness-public-key-hash (p2wpkh) payment object. * diff --git a/src/cjs/payments/p2wsh.js b/src/cjs/payments/p2wsh.cjs similarity index 73% rename from src/cjs/payments/p2wsh.js rename to src/cjs/payments/p2wsh.cjs index 7e683ab1d..3633d32bf 100644 --- a/src/cjs/payments/p2wsh.js +++ b/src/cjs/payments/p2wsh.cjs @@ -44,21 +44,24 @@ var __importStar = return result; }; Object.defineProperty(exports, '__esModule', { value: true }); -exports.p2wsh = void 0; -const bcrypto = __importStar(require('../crypto')); -const networks_1 = require('../networks'); -const bscript = __importStar(require('../script')); -const types_1 = require('../types'); -const lazy = __importStar(require('./lazy')); +exports.p2wsh = p2wsh; +const sha256_1 = require('@noble/hashes/sha256'); +const networks_js_1 = require('../networks.cjs'); +const bscript = __importStar(require('../script.cjs')); +const types_js_1 = require('../types.cjs'); +const lazy = __importStar(require('./lazy.cjs')); const bech32_1 = require('bech32'); +const tools = __importStar(require('uint8array-tools')); +const v = __importStar(require('valibot')); const OPS = bscript.OPS; -const EMPTY_BUFFER = Buffer.alloc(0); +const EMPTY_BUFFER = new Uint8Array(0); function chunkHasUncompressedPubkey(chunk) { if ( - Buffer.isBuffer(chunk) && + // Buffer.isBuffer(chunk) && + chunk instanceof Uint8Array && chunk.length === 65 && chunk[0] === 0x04 && - (0, types_1.isPoint)(chunk) + (0, types_js_1.isPoint)(chunk) ) { return true; } else { @@ -80,25 +83,38 @@ function p2wsh(a, opts) { if (!a.address && !a.hash && !a.output && !a.redeem && !a.witness) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - (0, types_1.typeforce)( - { - network: types_1.typeforce.maybe(types_1.typeforce.Object), - address: types_1.typeforce.maybe(types_1.typeforce.String), - hash: types_1.typeforce.maybe(types_1.typeforce.BufferN(32)), - output: types_1.typeforce.maybe(types_1.typeforce.BufferN(34)), - redeem: types_1.typeforce.maybe({ - input: types_1.typeforce.maybe(types_1.typeforce.Buffer), - network: types_1.typeforce.maybe(types_1.typeforce.Object), - output: types_1.typeforce.maybe(types_1.typeforce.Buffer), - witness: types_1.typeforce.maybe( - types_1.typeforce.arrayOf(types_1.typeforce.Buffer), - ), + // typef( + // { + // network: typef.maybe(typef.Object), + // address: typef.maybe(typef.String), + // hash: typef.maybe(typef.BufferN(32)), + // output: typef.maybe(typef.BufferN(34)), + // redeem: typef.maybe({ + // input: typef.maybe(typef.Buffer), + // network: typef.maybe(typef.Object), + // output: typef.maybe(typef.Buffer), + // witness: typef.maybe(typef.arrayOf(typef.Buffer)), + // }), + // input: typef.maybe(typef.BufferN(0)), + // witness: typef.maybe(typef.arrayOf(typef.Buffer)), + // }, + // a, + // ); + v.parse( + (0, types_js_1.NullablePartial)({ + network: v.object({}), + address: v.string(), + hash: types_js_1.Buffer256bitSchema, + output: (0, types_js_1.NBufferSchemaFactory)(34), + redeem: (0, types_js_1.NullablePartial)({ + input: types_js_1.BufferSchema, + network: v.object({}), + output: types_js_1.BufferSchema, + witness: v.array(types_js_1.BufferSchema), }), - input: types_1.typeforce.maybe(types_1.typeforce.BufferN(0)), - witness: types_1.typeforce.maybe( - types_1.typeforce.arrayOf(types_1.typeforce.Buffer), - ), - }, + input: (0, types_js_1.NBufferSchemaFactory)(0), + witness: v.array(types_js_1.BufferSchema), + }), a, ); const _address = lazy.value(() => { @@ -108,7 +124,7 @@ function p2wsh(a, opts) { return { version, prefix: result.prefix, - data: Buffer.from(data), + data: Uint8Array.from(data), }; }); const _rchunks = lazy.value(() => { @@ -116,7 +132,7 @@ function p2wsh(a, opts) { }); let network = a.network; if (!network) { - network = (a.redeem && a.redeem.network) || networks_1.bitcoin; + network = (a.redeem && a.redeem.network) || networks_js_1.bitcoin; } const o = { network }; lazy.prop(o, 'address', () => { @@ -128,7 +144,8 @@ function p2wsh(a, opts) { lazy.prop(o, 'hash', () => { if (a.output) return a.output.slice(2); if (a.address) return _address().data; - if (o.redeem && o.redeem.output) return bcrypto.sha256(o.redeem.output); + if (o.redeem && o.redeem.output) + return (0, sha256_1.sha256)(o.redeem.output); }); lazy.prop(o, 'output', () => { if (!o.hash) return; @@ -174,7 +191,7 @@ function p2wsh(a, opts) { }); // extended validation if (opts.validate) { - let hash = Buffer.from([]); + let hash = Uint8Array.from([]); if (a.address) { if (_address().prefix !== network.bech32) throw new TypeError('Invalid prefix or Network mismatch'); @@ -185,7 +202,8 @@ function p2wsh(a, opts) { hash = _address().data; } if (a.hash) { - if (hash.length > 0 && !hash.equals(a.hash)) + // if (hash.length > 0 && !hash.equals(a.hash)) + if (hash.length > 0 && tools.compare(hash, a.hash) !== 0) throw new TypeError('Hash mismatch'); else hash = a.hash; } @@ -197,7 +215,8 @@ function p2wsh(a, opts) { ) throw new TypeError('Output is invalid'); const hash2 = a.output.slice(2); - if (hash.length > 0 && !hash.equals(hash2)) + // if (hash.length > 0 && !hash.equals(hash2)) + if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; } @@ -226,8 +245,9 @@ function p2wsh(a, opts) { '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)) + const hash2 = (0, sha256_1.sha256)(a.redeem.output); + // if (hash.length > 0 && !hash.equals(hash2)) + if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; } @@ -236,7 +256,7 @@ function p2wsh(a, opts) { if ( a.witness && a.redeem.witness && - !(0, types_1.stacksEqual)(a.witness, a.redeem.witness) + !(0, types_js_1.stacksEqual)(a.witness, a.redeem.witness) ) throw new TypeError('Witness and redeem.witness mismatch'); if ( @@ -253,7 +273,12 @@ function p2wsh(a, opts) { } if (a.witness && a.witness.length > 0) { const wScript = a.witness[a.witness.length - 1]; - if (a.redeem && a.redeem.output && !a.redeem.output.equals(wScript)) + // if (a.redeem && a.redeem.output && !a.redeem.output.equals(wScript)) + if ( + a.redeem && + a.redeem.output && + tools.compare(a.redeem.output, wScript) !== 0 + ) throw new TypeError('Witness and redeem.output mismatch'); if ( a.witness.some(chunkHasUncompressedPubkey) || @@ -264,4 +289,3 @@ function p2wsh(a, opts) { } return Object.assign(o, a); } -exports.p2wsh = p2wsh; diff --git a/src/cjs/payments/p2wsh.d.ts b/src/cjs/payments/p2wsh.d.ts index 4169a30de..315f55f8c 100644 --- a/src/cjs/payments/p2wsh.d.ts +++ b/src/cjs/payments/p2wsh.d.ts @@ -1,4 +1,4 @@ -import { Payment, PaymentOpts } from './index'; +import { Payment, PaymentOpts } from './index.js'; /** * Creates a Pay-to-Witness-Script-Hash (P2WSH) payment object. * diff --git a/src/cjs/psbt.js b/src/cjs/psbt.cjs similarity index 85% rename from src/cjs/psbt.js rename to src/cjs/psbt.cjs index e82bf0522..65e60e192 100644 --- a/src/cjs/psbt.js +++ b/src/cjs/psbt.cjs @@ -47,16 +47,17 @@ Object.defineProperty(exports, '__esModule', { value: true }); exports.Psbt = void 0; const bip174_1 = require('bip174'); const varuint = __importStar(require('varuint-bitcoin')); -const utils_1 = require('bip174/src/lib/utils'); -const address_1 = require('./address'); -const bufferutils_1 = require('./bufferutils'); -const networks_1 = require('./networks'); -const payments = __importStar(require('./payments')); -const bip341_1 = require('./payments/bip341'); -const bscript = __importStar(require('./script')); -const transaction_1 = require('./transaction'); -const bip371_1 = require('./psbt/bip371'); -const psbtutils_1 = require('./psbt/psbtutils'); +const bip174_2 = require('bip174'); +const address_js_1 = require('./address.cjs'); +const bufferutils_js_1 = require('./bufferutils.cjs'); +const networks_js_1 = require('./networks.cjs'); +const payments = __importStar(require('./payments/index.cjs')); +const bip341_js_1 = require('./payments/bip341.cjs'); +const bscript = __importStar(require('./script.cjs')); +const transaction_js_1 = require('./transaction.cjs'); +const bip371_js_1 = require('./psbt/bip371.cjs'); +const psbtutils_js_1 = require('./psbt/psbtutils.cjs'); +const tools = __importStar(require('uint8array-tools')); /** * These are the default arguments for a Psbt instance. */ @@ -65,7 +66,7 @@ const DEFAULT_OPTS = { * A bitcoinjs Network object. This is only used if you pass an `address` * parameter to addOutput. Otherwise it is not needed and can be left default. */ - network: networks_1.bitcoin, + network: networks_js_1.bitcoin, /** * When extractTransaction is called, the fee rate is checked. * THIS IS NOT TO BE RELIED ON. @@ -113,11 +114,13 @@ const DEFAULT_OPTS = { class Psbt { data; static fromBase64(data, opts = {}) { - const buffer = Buffer.from(data, 'base64'); + // const buffer = Buffer.from(data, 'base64'); + const buffer = tools.fromBase64(data); return this.fromBuffer(buffer, opts); } static fromHex(data, opts = {}) { - const buffer = Buffer.from(data, 'hex'); + // const buffer = Buffer.from(data, 'hex'); + const buffer = tools.fromHex(data); return this.fromBuffer(buffer, opts); } static fromBuffer(buffer, opts = {}) { @@ -174,7 +177,7 @@ class Psbt { } get txInputs() { return this.__CACHE.__TX.ins.map(input => ({ - hash: (0, bufferutils_1.cloneBuffer)(input.hash), + hash: (0, bufferutils_js_1.cloneBuffer)(input.hash), index: input.index, sequence: input.sequence, })); @@ -183,13 +186,13 @@ class Psbt { return this.__CACHE.__TX.outs.map(output => { let address; try { - address = (0, address_1.fromOutputScript)( + address = (0, address_js_1.fromOutputScript)( output.script, this.opts.network, ); } catch (_) {} return { - script: (0, bufferutils_1.cloneBuffer)(output.script), + script: (0, bufferutils_js_1.cloneBuffer)(output.script), value: output.value, address, }; @@ -252,7 +255,7 @@ class Psbt { `Requires single object with at least [hash] and [index]`, ); } - (0, bip371_1.checkTaprootInputFields)(inputData, inputData, 'addInput'); + (0, bip371_js_1.checkTaprootInputFields)(inputData, inputData, 'addInput'); checkInputsForPartialSig(this.data.inputs, 'addInput'); if (inputData.witnessScript) checkInvalidP2WSH(inputData.witnessScript); const c = this.__CACHE; @@ -289,10 +292,14 @@ 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_js_1.toOutputScript)(address, network); outputData = Object.assign({}, outputData, { script }); } - (0, bip371_1.checkTaprootOutputFields)(outputData, outputData, 'addOutput'); + (0, bip371_js_1.checkTaprootOutputFields)( + outputData, + outputData, + 'addOutput', + ); const c = this.__CACHE; this.data.addOutput(outputData); c.__FEE = undefined; @@ -323,13 +330,13 @@ class Psbt { return getTxCacheValue('__FEE', 'fee', this.data.inputs, this.__CACHE); } finalizeAllInputs() { - (0, utils_1.checkForInput)(this.data.inputs, 0); // making sure we have at least one + (0, bip174_2.checkForInput)(this.data.inputs, 0); // making sure we have at least one range(this.data.inputs.length).forEach(idx => this.finalizeInput(idx)); return this; } finalizeInput(inputIndex, finalScriptsFunc) { - const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex); - if ((0, bip371_1.isTaprootInput)(input)) + const input = (0, bip174_2.checkForInput)(this.data.inputs, inputIndex); + if ((0, bip371_js_1.isTaprootInput)(input)) return this._finalizeTaprootInput( inputIndex, input, @@ -341,10 +348,10 @@ class Psbt { finalizeTaprootInput( inputIndex, tapLeafHashToFinalize, - finalScriptsFunc = bip371_1.tapScriptFinalizer, + finalScriptsFunc = bip371_js_1.tapScriptFinalizer, ) { - const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex); - if ((0, bip371_1.isTaprootInput)(input)) + const input = (0, bip174_2.checkForInput)(this.data.inputs, inputIndex); + if ((0, bip371_js_1.isTaprootInput)(input)) return this._finalizeTaprootInput( inputIndex, input, @@ -381,7 +388,7 @@ class Psbt { inputIndex, input, tapLeafHashToFinalize, - finalScriptsFunc = bip371_1.tapScriptFinalizer, + finalScriptsFunc = bip371_js_1.tapScriptFinalizer, ) { if (!input.witnessUtxo) throw new Error( @@ -393,9 +400,8 @@ class Psbt { output: input.witnessUtxo.script, signature: input.tapKeySig, }); - const finalScriptWitness = (0, psbtutils_1.witnessStackToScriptWitness)( - payment.witness, - ); + const finalScriptWitness = (0, + psbtutils_js_1.witnessStackToScriptWitness)(payment.witness); this.data.updateInput(inputIndex, { finalScriptWitness }); } else { const { finalScriptWitness } = finalScriptsFunc( @@ -409,7 +415,7 @@ class Psbt { return this; } getInputType(inputIndex) { - const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex); + const input = (0, bip174_2.checkForInput)(this.data.inputs, inputIndex); const script = getScriptFromUtxo(inputIndex, input, this.__CACHE); const result = getMeaningfulScript( script, @@ -424,29 +430,29 @@ class Psbt { return type + mainType; } inputHasPubkey(inputIndex, pubkey) { - const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex); + const input = (0, bip174_2.checkForInput)(this.data.inputs, inputIndex); return pubkeyInInput(pubkey, input, inputIndex, this.__CACHE); } inputHasHDKey(inputIndex, root) { - const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex); + const input = (0, bip174_2.checkForInput)(this.data.inputs, inputIndex); const derivationIsMine = bip32DerivationIsMine(root); return ( !!input.bip32Derivation && input.bip32Derivation.some(derivationIsMine) ); } outputHasPubkey(outputIndex, pubkey) { - const output = (0, utils_1.checkForOutput)(this.data.outputs, outputIndex); + const output = (0, bip174_2.checkForOutput)(this.data.outputs, outputIndex); return pubkeyInOutput(pubkey, output, outputIndex, this.__CACHE); } outputHasHDKey(outputIndex, root) { - const output = (0, utils_1.checkForOutput)(this.data.outputs, outputIndex); + const output = (0, bip174_2.checkForOutput)(this.data.outputs, outputIndex); const derivationIsMine = bip32DerivationIsMine(root); return ( !!output.bip32Derivation && output.bip32Derivation.some(derivationIsMine) ); } validateSignaturesOfAllInputs(validator) { - (0, utils_1.checkForInput)(this.data.inputs, 0); // making sure we have at least one + (0, bip174_2.checkForInput)(this.data.inputs, 0); // making sure we have at least one const results = range(this.data.inputs.length).map(idx => this.validateSignaturesOfInput(idx, validator), ); @@ -454,7 +460,7 @@ class Psbt { } validateSignaturesOfInput(inputIndex, validator, pubkey) { const input = this.data.inputs[inputIndex]; - if ((0, bip371_1.isTaprootInput)(input)) + if ((0, bip371_js_1.isTaprootInput)(input)) return this.validateSignaturesOfTaprootInput( inputIndex, validator, @@ -470,7 +476,7 @@ class Psbt { if (typeof validator !== 'function') throw new Error('Need validator function to validate signatures'); const mySigs = pubkey - ? partialSig.filter(sig => sig.pubkey.equals(pubkey)) + ? partialSig.filter(sig => tools.compare(sig.pubkey, pubkey) === 0) : partialSig; if (mySigs.length < 1) throw new Error('No signatures for this pubkey'); const results = []; @@ -504,7 +510,7 @@ class Psbt { 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); + pubkey = pubkey && (0, bip371_js_1.toXOnly)(pubkey); const allHashses = pubkey ? getTaprootHashesForSig( inputIndex, @@ -533,7 +539,10 @@ class Psbt { } if (tapScriptSig) { for (const tapSig of tapScriptSig) { - const tapSigHash = allHashses.find(h => tapSig.pubkey.equals(h.pubkey)); + // const tapSigHash = allHashses.find(h => tapSig.pubkey.equals(h.pubkey)); + const tapSigHash = allHashses.find( + h => tools.compare(h.pubkey, tapSig.pubkey) === 0, + ); if (tapSigHash) { const isValidTapScriptSig = validator( tapSig.pubkey, @@ -549,7 +558,7 @@ class Psbt { } signAllInputsHD( hdKeyPair, - sighashTypes = [transaction_1.Transaction.SIGHASH_ALL], + sighashTypes = [transaction_js_1.Transaction.SIGHASH_ALL], ) { if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) { throw new Error('Need HDSigner to sign input'); @@ -570,7 +579,7 @@ class Psbt { } signAllInputsHDAsync( hdKeyPair, - sighashTypes = [transaction_1.Transaction.SIGHASH_ALL], + sighashTypes = [transaction_js_1.Transaction.SIGHASH_ALL], ) { return new Promise((resolve, reject) => { if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) { @@ -601,7 +610,7 @@ class Psbt { signInputHD( inputIndex, hdKeyPair, - sighashTypes = [transaction_1.Transaction.SIGHASH_ALL], + sighashTypes = [transaction_js_1.Transaction.SIGHASH_ALL], ) { if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) { throw new Error('Need HDSigner to sign input'); @@ -613,7 +622,7 @@ class Psbt { signInputHDAsync( inputIndex, hdKeyPair, - sighashTypes = [transaction_1.Transaction.SIGHASH_ALL], + sighashTypes = [transaction_js_1.Transaction.SIGHASH_ALL], ) { return new Promise((resolve, reject) => { if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) { @@ -682,8 +691,8 @@ class Psbt { 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)) { + const input = (0, bip174_2.checkForInput)(this.data.inputs, inputIndex); + if ((0, bip371_js_1.isTaprootInput)(input)) { return this._signTaprootInput( inputIndex, input, @@ -697,8 +706,8 @@ class Psbt { 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)) + const input = (0, bip174_2.checkForInput)(this.data.inputs, inputIndex); + if ((0, bip371_js_1.isTaprootInput)(input)) return this._signTaprootInput( inputIndex, input, @@ -711,7 +720,7 @@ class Psbt { _signInput( inputIndex, keyPair, - sighashTypes = [transaction_1.Transaction.SIGHASH_ALL], + sighashTypes = [transaction_js_1.Transaction.SIGHASH_ALL], ) { const { hash, sighashType } = getHashAndSighashType( this.data.inputs, @@ -734,7 +743,7 @@ class Psbt { input, keyPair, tapLeafHashToSign, - allowedSighashTypes = [transaction_1.Transaction.SIGHASH_DEFAULT], + allowedSighashTypes = [transaction_js_1.Transaction.SIGHASH_DEFAULT], ) { const hashesForSig = this.checkTaprootHashesForSig( inputIndex, @@ -746,7 +755,7 @@ class Psbt { const tapKeySig = hashesForSig .filter(h => !h.leafHash) .map(h => - (0, bip371_1.serializeTaprootSignature)( + (0, bip371_js_1.serializeTaprootSignature)( keyPair.signSchnorr(h.hash), input.sighashType, ), @@ -754,8 +763,8 @@ class Psbt { const tapScriptSig = hashesForSig .filter(h => !!h.leafHash) .map(h => ({ - pubkey: (0, bip371_1.toXOnly)(keyPair.publicKey), - signature: (0, bip371_1.serializeTaprootSignature)( + pubkey: (0, bip371_js_1.toXOnly)(keyPair.publicKey), + signature: (0, bip371_js_1.serializeTaprootSignature)( keyPair.signSchnorr(h.hash), input.sighashType, ), @@ -773,8 +782,8 @@ class Psbt { 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)) + const input = (0, bip174_2.checkForInput)(this.data.inputs, inputIndex); + if ((0, bip371_js_1.isTaprootInput)(input)) return this._signTaprootInputAsync( inputIndex, input, @@ -789,8 +798,8 @@ class Psbt { 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)) + const input = (0, bip174_2.checkForInput)(this.data.inputs, inputIndex); + if ((0, bip371_js_1.isTaprootInput)(input)) return this._signTaprootInputAsync( inputIndex, input, @@ -804,7 +813,7 @@ class Psbt { _signInputAsync( inputIndex, keyPair, - sighashTypes = [transaction_1.Transaction.SIGHASH_ALL], + sighashTypes = [transaction_js_1.Transaction.SIGHASH_ALL], ) { const { hash, sighashType } = getHashAndSighashType( this.data.inputs, @@ -828,7 +837,7 @@ class Psbt { input, keyPair, tapLeafHash, - sighashTypes = [transaction_1.Transaction.SIGHASH_DEFAULT], + sighashTypes = [transaction_js_1.Transaction.SIGHASH_DEFAULT], ) { const hashesForSig = this.checkTaprootHashesForSig( inputIndex, @@ -844,7 +853,7 @@ class Psbt { keyPair.signSchnorr(tapKeyHash.hash), ).then(sig => { return { - tapKeySig: (0, bip371_1.serializeTaprootSignature)( + tapKeySig: (0, bip371_js_1.serializeTaprootSignature)( sig, input.sighashType, ), @@ -859,8 +868,8 @@ class Psbt { signature => { const tapScriptSig = [ { - pubkey: (0, bip371_1.toXOnly)(keyPair.publicKey), - signature: (0, bip371_1.serializeTaprootSignature)( + pubkey: (0, bip371_js_1.toXOnly)(keyPair.publicKey), + signature: (0, bip371_js_1.serializeTaprootSignature)( signature, input.sighashType, ), @@ -899,9 +908,7 @@ class Psbt { ); if (!hashesForSig || !hashesForSig.length) throw new Error( - `Can not sign for input #${inputIndex} with the key ${keyPair.publicKey.toString( - 'hex', - )}`, + `Can not sign for input #${inputIndex} with the key ${tools.toHex(keyPair.publicKey)}`, ); return hashesForSig; } @@ -923,7 +930,7 @@ class Psbt { } updateInput(inputIndex, updateData) { if (updateData.witnessScript) checkInvalidP2WSH(updateData.witnessScript); - (0, bip371_1.checkTaprootInputFields)( + (0, bip371_js_1.checkTaprootInputFields)( this.data.inputs[inputIndex], updateData, 'updateInput', @@ -940,7 +947,7 @@ class Psbt { } updateOutput(outputIndex, updateData) { const outputData = this.data.outputs[outputIndex]; - (0, bip371_1.checkTaprootOutputFields)( + (0, bip371_js_1.checkTaprootOutputFields)( outputData, updateData, 'updateOutput', @@ -978,8 +985,8 @@ const transactionFromBuffer = buffer => new PsbtTransaction(buffer); */ class PsbtTransaction { tx; - constructor(buffer = Buffer.from([2, 0, 0, 0, 0, 0, 0, 0, 0, 0])) { - this.tx = transaction_1.Transaction.fromBuffer(buffer); + constructor(buffer = Uint8Array.from([2, 0, 0, 0, 0, 0, 0, 0, 0, 0])) { + this.tx = transaction_js_1.Transaction.fromBuffer(buffer); checkTxEmpty(this.tx); Object.defineProperty(this, 'tx', { enumerable: false, @@ -996,14 +1003,15 @@ class PsbtTransaction { if ( input.hash === undefined || input.index === undefined || - (!Buffer.isBuffer(input.hash) && typeof input.hash !== 'string') || + (!(input.hash instanceof Uint8Array) && typeof input.hash !== 'string') || typeof input.index !== 'number' ) { throw new Error('Error adding input.'); } const hash = typeof input.hash === 'string' - ? (0, bufferutils_1.reverseBuffer)(Buffer.from(input.hash, 'hex')) + ? // ? reverseBuffer(Buffer.from(input.hash, 'hex')) + (0, bufferutils_js_1.reverseBuffer)(tools.fromHex(input.hash)) : input.hash; this.tx.addInput(hash, input.index, input.sequence); } @@ -1011,8 +1019,8 @@ class PsbtTransaction { if ( output.script === undefined || output.value === undefined || - !Buffer.isBuffer(output.script) || - typeof output.value !== 'number' + !(output.script instanceof Uint8Array) || + typeof output.value !== 'bigint' ) { throw new Error('Error adding output.'); } @@ -1047,7 +1055,9 @@ function hasSigs(neededSigs, partialSig, pubkeys) { sigs = pubkeys .map(pkey => { const pubkey = compressPubkey(pkey); - return partialSig.find(pSig => pSig.pubkey.equals(pubkey)); + return partialSig.find( + pSig => tools.compare(pSig.pubkey, pubkey) === 0, + ); }) .filter(v => !!v); } else { @@ -1061,8 +1071,11 @@ function isFinalized(input) { } function bip32DerivationIsMine(root) { return d => { - if (!d.masterFingerprint.equals(root.fingerprint)) return false; - if (!root.derivePath(d.path).publicKey.equals(d.pubkey)) return false; + // if (!d.masterFingerprint.equals(root.fingerprint)) return false; + if (tools.compare(root.fingerprint, d.masterFingerprint)) return false; + // if (!root.derivePath(d.path).publicKey.equals(d.pubkey)) return false; + if (tools.compare(root.derivePath(d.path).publicKey, d.pubkey)) + return false; return true; }; } @@ -1092,9 +1105,9 @@ function checkFees(psbt, cache, opts) { } function checkInputsForPartialSig(inputs, action) { inputs.forEach(input => { - const throws = (0, bip371_1.isTaprootInput)(input) - ? (0, bip371_1.checkTaprootInputForSigs)(input, action) - : (0, psbtutils_1.checkInputForSig)(input, action); + const throws = (0, bip371_js_1.isTaprootInput)(input) + ? (0, bip371_js_1.checkTaprootInputForSigs)(input, action) + : (0, psbtutils_js_1.checkInputForSig)(input, action); if (throws) throw new Error('Can not modify transaction, signatures exist.'); }); @@ -1110,9 +1123,9 @@ function checkPartialSigSighashes(input) { }); } function checkScriptForPubkey(pubkey, script, action) { - if (!(0, psbtutils_1.pubkeyInScript)(pubkey, script)) { + if (!(0, psbtutils_js_1.pubkeyInScript)(pubkey, script)) { throw new Error( - `Can not ${action} for this input with the key ${pubkey.toString('hex')}`, + `Can not ${action} for this input with the key ${tools.toHex(pubkey)}`, ); } } @@ -1135,7 +1148,9 @@ function checkTxForDupeIns(tx, cache) { } function checkTxInputCache(cache, input) { const key = - (0, bufferutils_1.reverseBuffer)(Buffer.from(input.hash)).toString('hex') + + tools.toHex( + (0, bufferutils_js_1.reverseBuffer)(Uint8Array.from(input.hash)), + ) + ':' + input.index; if (cache.__TX_IN_CACHE[key]) throw new Error('Duplicate input detected.'); @@ -1146,7 +1161,8 @@ function scriptCheckerFactory(payment, paymentScriptName) { const redeemScriptOutput = payment({ redeem: { output: redeemScript }, }).output; - if (!scriptPubKey.equals(redeemScriptOutput)) { + // if (!scriptPubKey.equals(redeemScriptOutput)) { + if (tools.compare(scriptPubKey, redeemScriptOutput)) { throw new Error( `${paymentScriptName} for ${ioType} #${inputIndex} doesn't match the scriptPubKey in the prevout`, ); @@ -1204,11 +1220,11 @@ function prepareFinalScripts( const p2sh = !isP2SH ? null : payments.p2sh({ redeem: p2wsh || payment }); if (isSegwit) { if (p2wsh) { - finalScriptWitness = (0, psbtutils_1.witnessStackToScriptWitness)( + finalScriptWitness = (0, psbtutils_js_1.witnessStackToScriptWitness)( p2wsh.witness, ); } else { - finalScriptWitness = (0, psbtutils_1.witnessStackToScriptWitness)( + finalScriptWitness = (0, psbtutils_js_1.witnessStackToScriptWitness)( payment.witness, ); } @@ -1234,7 +1250,7 @@ function getHashAndSighashType( cache, sighashTypes, ) { - const input = (0, utils_1.checkForInput)(inputs, inputIndex); + const input = (0, bip174_2.checkForInput)(inputs, inputIndex); const { hash, sighashType, script } = getHashForSig( inputIndex, input, @@ -1251,7 +1267,7 @@ function getHashAndSighashType( function getHashForSig(inputIndex, input, cache, forValidate, sighashTypes) { const unsignedTx = cache.__TX; const sighashType = - input.sighashType || transaction_1.Transaction.SIGHASH_ALL; + input.sighashType || transaction_js_1.Transaction.SIGHASH_ALL; checkSighashTypeAllowed(sighashType, sighashTypes); let hash; let prevout; @@ -1264,7 +1280,8 @@ function getHashForSig(inputIndex, input, cache, forValidate, sighashTypes) { const prevoutHash = unsignedTx.ins[inputIndex].hash; const utxoHash = nonWitnessUtxoTx.getHash(); // If a non-witness UTXO is provided, its hash must match the hash specified in the prevout - if (!prevoutHash.equals(utxoHash)) { + // if (!prevoutHash.equals(utxoHash)) { + if (tools.compare(prevoutHash, utxoHash) !== 0) { throw new Error( `Non-witness UTXO hash for input #${inputIndex} doesn't match the hash specified in the prevout`, ); @@ -1290,7 +1307,7 @@ function getHashForSig(inputIndex, input, cache, forValidate, sighashTypes) { prevout.value, sighashType, ); - } else if ((0, psbtutils_1.isP2WPKH)(meaningfulScript)) { + } else if ((0, psbtutils_js_1.isP2WPKH)(meaningfulScript)) { // P2WPKH uses the P2PKH template for prevoutScript when signing const signingScript = payments.p2pkh({ hash: meaningfulScript.slice(2), @@ -1309,7 +1326,7 @@ function getHashForSig(inputIndex, input, cache, forValidate, sighashTypes) { ) throw new Error( `Input #${inputIndex} has witnessUtxo but non-segwit script: ` + - `${meaningfulScript.toString('hex')}`, + `${tools.toHex(meaningfulScript)}`, ); if (!forValidate && cache.__UNSAFE_SIGN_NONSEGWIT !== false) console.warn( @@ -1345,14 +1362,14 @@ function getAllTaprootHashesForSig(inputIndex, input, inputs, cache) { const tapScriptPubkeys = input.tapScriptSig.map(tss => tss.pubkey); allPublicKeys.push(...tapScriptPubkeys); } - const allHashes = allPublicKeys.map(pubicKey => - getTaprootHashesForSig(inputIndex, input, inputs, pubicKey, cache), + const allHashes = allPublicKeys.map(publicKey => + getTaprootHashesForSig(inputIndex, input, inputs, publicKey, 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; + return (0, psbtutils_js_1.isP2TR)(script) ? script.subarray(2, 34) : null; } function trimTaprootSig(signature) { return signature.length === 64 ? signature : signature.subarray(0, 64); @@ -1368,7 +1385,7 @@ function getTaprootHashesForSig( ) { const unsignedTx = cache.__TX; const sighashType = - input.sighashType || transaction_1.Transaction.SIGHASH_DEFAULT; + input.sighashType || transaction_js_1.Transaction.SIGHASH_DEFAULT; checkSighashTypeAllowed(sighashType, allowedSighashTypes); const prevOuts = inputs.map((i, index) => getScriptAndAmountFromUtxo(index, i, cache), @@ -1378,8 +1395,9 @@ function getTaprootHashesForSig( const hashes = []; if (input.tapInternalKey && !tapLeafHashToSign) { const outputKey = - getPrevoutTaprootKey(inputIndex, input, cache) || Buffer.from([]); - if ((0, bip371_1.toXOnly)(pubkey).equals(outputKey)) { + getPrevoutTaprootKey(inputIndex, input, cache) || Uint8Array.from([]); + // if (toXOnly(pubkey).equals(outputKey)) { + if (tools.compare((0, bip371_js_1.toXOnly)(pubkey), outputKey) === 0) { const tapKeyHash = unsignedTx.hashForWitnessV1( inputIndex, signingScripts, @@ -1390,16 +1408,20 @@ function getTaprootHashesForSig( } } const tapLeafHashes = (input.tapLeafScript || []) - .filter(tapLeaf => (0, psbtutils_1.pubkeyInScript)(pubkey, tapLeaf.script)) + .filter(tapLeaf => + (0, psbtutils_js_1.pubkeyInScript)(pubkey, tapLeaf.script), + ) .map(tapLeaf => { - const hash = (0, bip341_1.tapleafHash)({ + const hash = (0, bip341_js_1.tapleafHash)({ output: tapLeaf.script, version: tapLeaf.leafVersion, }); return Object.assign({ hash }, tapLeaf); }) .filter( - tapLeaf => !tapLeafHashToSign || tapLeafHashToSign.equals(tapLeaf.hash), + tapLeaf => + !tapLeafHashToSign || + tools.compare(tapLeafHashToSign, tapLeaf.hash) === 0, ) .map(tapLeaf => { const tapScriptHash = unsignedTx.hashForWitnessV1( @@ -1486,19 +1508,20 @@ function getScriptFromInput(inputIndex, input, cache) { res.script = input.witnessUtxo.script; } } - if (input.witnessScript || (0, psbtutils_1.isP2WPKH)(res.script)) { + if (input.witnessScript || (0, psbtutils_js_1.isP2WPKH)(res.script)) { res.isSegwit = true; } return res; } function getSignersFromHD(inputIndex, inputs, hdKeyPair) { - const input = (0, utils_1.checkForInput)(inputs, inputIndex); + const input = (0, bip174_2.checkForInput)(inputs, inputIndex); if (!input.bip32Derivation || input.bip32Derivation.length === 0) { throw new Error('Need bip32Derivation to sign with HD'); } const myDerivations = input.bip32Derivation .map(bipDv => { - if (bipDv.masterFingerprint.equals(hdKeyPair.fingerprint)) { + // if (bipDv.masterFingerprint.equals(hdKeyPair.fingerprint)) { + if (tools.compare(bipDv.masterFingerprint, hdKeyPair.fingerprint) === 0) { return bipDv; } else { return; @@ -1512,7 +1535,8 @@ function getSignersFromHD(inputIndex, inputs, hdKeyPair) { } const signers = myDerivations.map(bipDv => { const node = hdKeyPair.derivePath(bipDv.path); - if (!bipDv.pubkey.equals(node.publicKey)) { + // if (!bipDv!.pubkey.equals(node.publicKey)) { + if (tools.compare(bipDv.pubkey, node.publicKey) !== 0) { throw new Error('pubkey did not match bip32Derivation'); } return node; @@ -1527,7 +1551,8 @@ function getSortedSigs(script, partialSig) { // filter partialSig array by pubkey being equal return ( partialSig.filter(ps => { - return ps.pubkey.equals(pk); + // return ps.pubkey.equals(pk); + return tools.compare(ps.pubkey, pk) === 0; })[0] || {} ).signature; // Any pubkey without a match will return undefined @@ -1559,18 +1584,18 @@ function scriptWitnessToWitnessStack(buffer) { } function sighashTypeToString(sighashType) { let text = - sighashType & transaction_1.Transaction.SIGHASH_ANYONECANPAY + sighashType & transaction_js_1.Transaction.SIGHASH_ANYONECANPAY ? 'SIGHASH_ANYONECANPAY | ' : ''; const sigMod = sighashType & 0x1f; switch (sigMod) { - case transaction_1.Transaction.SIGHASH_ALL: + case transaction_js_1.Transaction.SIGHASH_ALL: text += 'SIGHASH_ALL'; break; - case transaction_1.Transaction.SIGHASH_SINGLE: + case transaction_js_1.Transaction.SIGHASH_SINGLE: text += 'SIGHASH_SINGLE'; break; - case transaction_1.Transaction.SIGHASH_NONE: + case transaction_js_1.Transaction.SIGHASH_NONE: text += 'SIGHASH_NONE'; break; } @@ -1578,7 +1603,7 @@ function sighashTypeToString(sighashType) { } function addNonWitnessTxCache(cache, input, inputIndex) { cache.__NON_WITNESS_UTXO_BUF_CACHE[inputIndex] = input.nonWitnessUtxo; - const tx = transaction_1.Transaction.fromBuffer(input.nonWitnessUtxo); + const tx = transaction_js_1.Transaction.fromBuffer(input.nonWitnessUtxo); cache.__NON_WITNESS_UTXO_TX_CACHE[inputIndex] = tx; const self = cache; const selfIndex = inputIndex; @@ -1602,7 +1627,7 @@ function addNonWitnessTxCache(cache, input, inputIndex) { }); } function inputFinalizeGetAmts(inputs, tx, cache, mustFinalize) { - let inputAmount = 0; + let inputAmount = 0n; inputs.forEach((input, idx) => { if (mustFinalize && input.finalScriptSig) tx.ins[idx].script = input.finalScriptSig; @@ -1620,7 +1645,7 @@ function inputFinalizeGetAmts(inputs, tx, cache, mustFinalize) { inputAmount += out.value; } }); - const outputAmount = tx.outs.reduce((total, o) => total + o.value, 0); + const outputAmount = tx.outs.reduce((total, o) => total + o.value, 0n); const fee = inputAmount - outputAmount; if (fee < 0) { throw new Error('Outputs are spending more than Inputs'); @@ -1628,7 +1653,7 @@ function inputFinalizeGetAmts(inputs, tx, cache, mustFinalize) { const bytes = tx.virtualSize(); cache.__FEE = fee; cache.__EXTRACTED_TX = tx; - cache.__FEE_RATE = Math.floor(fee / bytes); + cache.__FEE_RATE = Math.floor(Number(fee / BigInt(bytes))); } function nonWitnessUtxoTxFromCache(cache, input, inputIndex) { const c = cache.__NON_WITNESS_UTXO_TX_CACHE; @@ -1668,7 +1693,7 @@ function pubkeyInInput(pubkey, input, inputIndex, cache) { input.redeemScript, input.witnessScript, ); - return (0, psbtutils_1.pubkeyInScript)(pubkey, meaningfulScript); + return (0, psbtutils_js_1.pubkeyInScript)(pubkey, meaningfulScript); } function pubkeyInOutput(pubkey, output, outputIndex, cache) { const script = cache.__TX.outs[outputIndex].script; @@ -1679,7 +1704,7 @@ function pubkeyInOutput(pubkey, output, outputIndex, cache) { output.redeemScript, output.witnessScript, ); - return (0, psbtutils_1.pubkeyInScript)(pubkey, meaningfulScript); + return (0, psbtutils_js_1.pubkeyInScript)(pubkey, meaningfulScript); } function redeemFromFinalScriptSig(finalScript) { if (!finalScript) return; @@ -1687,7 +1712,8 @@ function redeemFromFinalScriptSig(finalScript) { if (!decomp) return; const lastItem = decomp[decomp.length - 1]; if ( - !Buffer.isBuffer(lastItem) || + // !Buffer.isBuffer(lastItem) || + !(lastItem instanceof Uint8Array) || isPubkeyLike(lastItem) || isSigLike(lastItem) ) @@ -1727,10 +1753,10 @@ function getMeaningfulScript( redeemScript, witnessScript, ) { - const isP2SH = (0, psbtutils_1.isP2SHScript)(script); + const isP2SH = (0, psbtutils_js_1.isP2SHScript)(script); const isP2SHP2WSH = - isP2SH && redeemScript && (0, psbtutils_1.isP2WSHScript)(redeemScript); - const isP2WSH = (0, psbtutils_1.isP2WSHScript)(script); + isP2SH && redeemScript && (0, psbtutils_js_1.isP2WSHScript)(redeemScript); + const isP2WSH = (0, psbtutils_js_1.isP2WSHScript)(script); if (isP2SH && redeemScript === undefined) throw new Error('scriptPubkey is P2SH but redeemScript missing'); if ((isP2WSH || isP2SHP2WSH) && witnessScript === undefined) @@ -1758,25 +1784,25 @@ function getMeaningfulScript( type: isP2SHP2WSH ? 'p2sh-p2wsh' : isP2SH - ? 'p2sh' - : isP2WSH - ? 'p2wsh' - : 'raw', + ? 'p2sh' + : isP2WSH + ? 'p2wsh' + : 'raw', }; } function checkInvalidP2WSH(script) { if ( - (0, psbtutils_1.isP2WPKH)(script) || - (0, psbtutils_1.isP2SHScript)(script) + (0, psbtutils_js_1.isP2WPKH)(script) || + (0, psbtutils_js_1.isP2SHScript)(script) ) { throw new Error('P2WPKH or P2SH can not be contained within P2WSH'); } } function classifyScript(script) { - 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'; + if ((0, psbtutils_js_1.isP2WPKH)(script)) return 'witnesspubkeyhash'; + if ((0, psbtutils_js_1.isP2PKH)(script)) return 'pubkeyhash'; + if ((0, psbtutils_js_1.isP2MS)(script)) return 'multisig'; + if ((0, psbtutils_js_1.isP2PK)(script)) return 'pubkey'; return 'nonstandard'; } function range(n) { diff --git a/src/cjs/psbt.d.ts b/src/cjs/psbt.d.ts index d350ca12b..4e2da7f66 100644 --- a/src/cjs/psbt.d.ts +++ b/src/cjs/psbt.d.ts @@ -1,24 +1,23 @@ -/// 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 { KeyValue, PsbtGlobalUpdate, PsbtInput, PsbtInputUpdate, PsbtOutput, PsbtOutputUpdate } from 'bip174'; +import { Network } from './networks.js'; +import { Transaction } from './transaction.js'; export interface TransactionInput { - hash: string | Buffer; + hash: string | Uint8Array; index: number; sequence?: number; } export interface PsbtTxInput extends TransactionInput { - hash: Buffer; + hash: Uint8Array; } export interface TransactionOutput { - script: Buffer; - value: number; + script: Uint8Array; + value: bigint; } export interface PsbtTxOutput extends TransactionOutput { address: string | undefined; } -export type ValidateSigFunction = (pubkey: Buffer, msghash: Buffer, signature: Buffer) => boolean; +export type ValidateSigFunction = (pubkey: Uint8Array, msghash: Uint8Array, signature: Uint8Array) => 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) @@ -60,7 +59,7 @@ export declare class Psbt { readonly data: PsbtBase; static fromBase64(data: string, opts?: PsbtOptsOptional): Psbt; static fromHex(data: string, opts?: PsbtOptsOptional): Psbt; - static fromBuffer(buffer: Buffer, opts?: PsbtOptsOptional): Psbt; + static fromBuffer(buffer: Uint8Array, opts?: PsbtOptsOptional): Psbt; private __CACHE; private opts; constructor(opts?: PsbtOptsOptional, data?: PsbtBase); @@ -83,19 +82,19 @@ export declare class Psbt { addOutput(outputData: PsbtOutputExtended): this; extractTransaction(disableFeeCheck?: boolean): Transaction; getFeeRate(): number; - getFee(): number; + getFee(): bigint; finalizeAllInputs(): this; finalizeInput(inputIndex: number, finalScriptsFunc?: FinalScriptsFunc | FinalTaprootScriptsFunc): this; - finalizeTaprootInput(inputIndex: number, tapLeafHashToFinalize?: Buffer, finalScriptsFunc?: FinalTaprootScriptsFunc): this; + finalizeTaprootInput(inputIndex: number, tapLeafHashToFinalize?: Uint8Array, finalScriptsFunc?: FinalTaprootScriptsFunc): this; private _finalizeInput; private _finalizeTaprootInput; getInputType(inputIndex: number): AllScriptType; - inputHasPubkey(inputIndex: number, pubkey: Buffer): boolean; + inputHasPubkey(inputIndex: number, pubkey: Uint8Array): boolean; inputHasHDKey(inputIndex: number, root: HDSigner): boolean; - outputHasPubkey(outputIndex: number, pubkey: Buffer): boolean; + outputHasPubkey(outputIndex: number, pubkey: Uint8Array): boolean; outputHasHDKey(outputIndex: number, root: HDSigner): boolean; validateSignaturesOfAllInputs(validator: ValidateSigFunction): boolean; - validateSignaturesOfInput(inputIndex: number, validator: ValidateSigFunction, pubkey?: Buffer): boolean; + validateSignaturesOfInput(inputIndex: number, validator: ValidateSigFunction, pubkey?: Uint8Array): boolean; private _validateSignaturesOfInput; private validateSignaturesOfTaprootInput; signAllInputsHD(hdKeyPair: HDSigner, sighashTypes?: number[]): this; @@ -105,15 +104,15 @@ 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; + signTaprootInput(inputIndex: number, keyPair: Signer, tapLeafHashToSign?: Uint8Array, 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; + signTaprootInputAsync(inputIndex: number, keyPair: Signer | SignerAsync, tapLeafHash?: Uint8Array, sighashTypes?: number[]): Promise; private _signInputAsync; private _signTaprootInputAsync; private checkTaprootHashesForSig; - toBuffer(): Buffer; + toBuffer(): Uint8Array; toHex(): string; toBase64(): string; updateGlobal(updateData: PsbtGlobalUpdate): this; @@ -133,21 +132,21 @@ interface PsbtInputExtended extends PsbtInput, TransactionInput { type PsbtOutputExtended = PsbtOutputExtendedAddress | PsbtOutputExtendedScript; interface PsbtOutputExtendedAddress extends PsbtOutput { address: string; - value: number; + value: bigint; } interface PsbtOutputExtendedScript extends PsbtOutput { - script: Buffer; - value: number; + script: Uint8Array; + value: bigint; } interface HDSignerBase { /** * DER format compressed publicKey buffer */ - publicKey: Buffer; + publicKey: Uint8Array; /** * The first 4 bytes of the sha256-ripemd160 of the publicKey */ - fingerprint: Buffer; + fingerprint: Uint8Array; } export interface HDSigner extends HDSignerBase { /** @@ -159,28 +158,28 @@ export interface HDSigner extends HDSignerBase { * Input hash (the "message digest") for the signature algorithm * Return a 64 byte signature (32 byte r and 32 byte s in that order) */ - sign(hash: Buffer): Buffer; + sign(hash: Uint8Array): Uint8Array; } /** * Same as above but with async sign method */ export interface HDSignerAsync extends HDSignerBase { derivePath(path: string): HDSignerAsync; - sign(hash: Buffer): Promise; + sign(hash: Uint8Array): Promise; } export interface Signer { - publicKey: Buffer; + publicKey: Uint8Array; network?: any; - sign(hash: Buffer, lowR?: boolean): Buffer; - signSchnorr?(hash: Buffer): Buffer; - getPublicKey?(): Buffer; + sign(hash: Uint8Array, lowR?: boolean): Uint8Array; + signSchnorr?(hash: Uint8Array): Uint8Array; + getPublicKey?(): Uint8Array; } export interface SignerAsync { - publicKey: Buffer; + publicKey: Uint8Array; network?: any; - sign(hash: Buffer, lowR?: boolean): Promise; - signSchnorr?(hash: Buffer): Promise; - getPublicKey?(): Buffer; + sign(hash: Uint8Array, lowR?: boolean): Promise; + signSchnorr?(hash: Uint8Array): Promise; + getPublicKey?(): Uint8Array; } /** * This function must do two things: @@ -190,17 +189,17 @@ export interface SignerAsync { */ 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.) +script: Uint8Array, // The "meaningful" locking script Buffer (redeemScript for P2SH etc.) isSegwit: boolean, // Is it segwit? isP2SH: boolean, // Is it P2SH? isP2WSH: boolean) => { - finalScriptSig: Buffer | undefined; - finalScriptWitness: Buffer | undefined; + finalScriptSig: Uint8Array | undefined; + finalScriptWitness: Uint8Array | undefined; }; type FinalTaprootScriptsFunc = (inputIndex: number, // Which input is it? input: PsbtInput, // The PSBT input contents -tapLeafHashToFinalize?: Buffer) => { - finalScriptWitness: Buffer | undefined; +tapLeafHashToFinalize?: Uint8Array) => { + finalScriptWitness: Uint8Array | undefined; }; 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/cjs/psbt/bip371.js b/src/cjs/psbt/bip371.cjs similarity index 80% rename from src/cjs/psbt/bip371.js rename to src/cjs/psbt/bip371.cjs index 0fe92721e..ced52581f 100644 --- a/src/cjs/psbt/bip371.js +++ b/src/cjs/psbt/bip371.cjs @@ -1,23 +1,67 @@ 'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if ( + !desc || + ('get' in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, 'default', { enumerable: true, value: v }); + } + : function (o, v) { + o['default'] = v; + }); +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k in mod) + if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; + }; 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; -const types_1 = require('../types'); -const transaction_1 = require('../transaction'); -const psbtutils_1 = require('./psbtutils'); -const bip341_1 = require('../payments/bip341'); -const payments_1 = require('../payments'); -const psbtutils_2 = require('./psbtutils'); +exports.toXOnly = void 0; +exports.tapScriptFinalizer = tapScriptFinalizer; +exports.serializeTaprootSignature = serializeTaprootSignature; +exports.isTaprootInput = isTaprootInput; +exports.isTaprootOutput = isTaprootOutput; +exports.checkTaprootInputFields = checkTaprootInputFields; +exports.checkTaprootOutputFields = checkTaprootOutputFields; +exports.tweakInternalPubKey = tweakInternalPubKey; +exports.tapTreeToList = tapTreeToList; +exports.tapTreeFromList = tapTreeFromList; +exports.checkTaprootInputForSigs = checkTaprootInputForSigs; +const types_js_1 = require('../types.cjs'); +const transaction_js_1 = require('../transaction.cjs'); +const psbtutils_js_1 = require('./psbtutils.cjs'); +const bip341_js_1 = require('../payments/bip341.cjs'); +const index_js_1 = require('../payments/index.cjs'); +const tools = __importStar(require('uint8array-tools')); +const psbtutils_js_2 = require('./psbtutils.cjs'); /** * Converts a public key to an X-only public key. * @param pubKey The public key to convert. @@ -44,13 +88,14 @@ function tapScriptFinalizer(inputIndex, input, tapLeafHashToFinalize) { const sigs = sortSignatures(input, tapLeaf); const witness = sigs.concat(tapLeaf.script).concat(tapLeaf.controlBlock); return { - finalScriptWitness: (0, psbtutils_1.witnessStackToScriptWitness)(witness), + finalScriptWitness: (0, psbtutils_js_1.witnessStackToScriptWitness)( + witness, + ), }; } catch (err) { throw new Error(`Can not finalize taproot input #${inputIndex}: ${err}`); } } -exports.tapScriptFinalizer = tapScriptFinalizer; /** * Serializes a taproot signature. * @param sig The signature to serialize. @@ -59,11 +104,10 @@ exports.tapScriptFinalizer = tapScriptFinalizer; */ function serializeTaprootSignature(sig, sighashType) { const sighashTypeByte = sighashType - ? Buffer.from([sighashType]) - : Buffer.from([]); - return Buffer.concat([sig, sighashTypeByte]); + ? Uint8Array.from([sighashType]) + : Uint8Array.from([]); + return tools.concat([sig, sighashTypeByte]); } -exports.serializeTaprootSignature = serializeTaprootSignature; /** * Checks if a PSBT input is a taproot input. * @param input The PSBT input to check. @@ -77,11 +121,11 @@ function isTaprootInput(input) { input.tapMerkleRoot || (input.tapLeafScript && input.tapLeafScript.length) || (input.tapBip32Derivation && input.tapBip32Derivation.length) || - (input.witnessUtxo && (0, psbtutils_1.isP2TR)(input.witnessUtxo.script)) + (input.witnessUtxo && + (0, psbtutils_js_1.isP2TR)(input.witnessUtxo.script)) ) ); } -exports.isTaprootInput = isTaprootInput; /** * Checks if a PSBT output is a taproot output. * @param output The PSBT output to check. @@ -95,11 +139,10 @@ function isTaprootOutput(output, script) { output.tapInternalKey || output.tapTree || (output.tapBip32Derivation && output.tapBip32Derivation.length) || - (script && (0, psbtutils_1.isP2TR)(script)) + (script && (0, psbtutils_js_1.isP2TR)(script)) ) ); } -exports.isTaprootOutput = isTaprootOutput; /** * Checks the taproot input fields for consistency. * @param inputData The original input data. @@ -111,7 +154,6 @@ function checkTaprootInputFields(inputData, newInputData, action) { checkMixedTaprootAndNonTaprootInputFields(inputData, newInputData, action); checkIfTapLeafInTree(inputData, newInputData, action); } -exports.checkTaprootInputFields = checkTaprootInputFields; /** * Checks the taproot output fields for consistency. * @param outputData The original output data. @@ -123,7 +165,6 @@ function checkTaprootOutputFields(outputData, newOutputData, action) { checkMixedTaprootAndNonTaprootOutputFields(outputData, newOutputData, action); checkTaprootScriptPubkey(outputData, newOutputData); } -exports.checkTaprootOutputFields = checkTaprootOutputFields; function checkTaprootScriptPubkey(outputData, newOutputData) { if (!newOutputData.tapTree && !newOutputData.tapInternalKey) return; const tapInternalKey = @@ -132,7 +173,8 @@ function checkTaprootScriptPubkey(outputData, newOutputData) { if (tapInternalKey) { const { script: scriptPubkey } = outputData; const script = getTaprootScripPubkey(tapInternalKey, tapTree); - if (scriptPubkey && !scriptPubkey.equals(script)) + // if (scriptPubkey && !scriptPubkey.equals(script)) + if (scriptPubkey && tools.compare(script, scriptPubkey) !== 0) throw new Error('Error adding output. Script or address mismatch.'); } } @@ -145,7 +187,7 @@ function checkTaprootScriptPubkey(outputData, newOutputData) { */ function getTaprootScripPubkey(tapInternalKey, tapTree) { const scriptTree = tapTree && tapTreeFromList(tapTree.leaves); - const { output } = (0, payments_1.p2tr)({ + const { output } = (0, index_js_1.p2tr)({ internalPubkey: tapInternalKey, scriptTree, }); @@ -162,16 +204,16 @@ function tweakInternalPubKey(inputIndex, input) { const tapInternalKey = input.tapInternalKey; const outputKey = tapInternalKey && - (0, bip341_1.tweakKey)(tapInternalKey, input.tapMerkleRoot); + (0, bip341_js_1.tweakKey)(tapInternalKey, input.tapMerkleRoot); if (!outputKey) throw new Error( `Cannot tweak tap internal key for input #${inputIndex}. Public key: ${ - tapInternalKey && tapInternalKey.toString('hex') + // tapInternalKey && tapInternalKey.toString('hex') + tapInternalKey && tools.toHex(tapInternalKey) }`, ); 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, @@ -181,13 +223,12 @@ exports.tweakInternalPubKey = tweakInternalPubKey; * @returns a list of BIP 371 tapleaves */ function tapTreeToList(tree) { - if (!(0, types_1.isTaptree)(tree)) + if (!(0, types_js_1.isTaptree)(tree)) throw new Error( 'Cannot convert taptree to tapleaf list. Expecting a tapree structure.', ); 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): @@ -204,7 +245,6 @@ function tapTreeFromList(leaves = []) { }; return instertLeavesInTree(leaves); } -exports.tapTreeFromList = tapTreeFromList; /** * Checks the taproot input for signatures. * @param input The PSBT input to check. @@ -214,10 +254,13 @@ exports.tapTreeFromList = tapTreeFromList; function checkTaprootInputForSigs(input, action) { const sigs = extractTaprootSigs(input); return sigs.some(sig => - (0, psbtutils_2.signatureBlocksAction)(sig, decodeSchnorrSignature, action), + (0, psbtutils_js_2.signatureBlocksAction)( + sig, + decodeSchnorrSignature, + action, + ), ); } -exports.checkTaprootInputForSigs = checkTaprootInputForSigs; /** * Decodes a Schnorr signature. * @param signature The signature to decode. @@ -227,7 +270,7 @@ function decodeSchnorrSignature(signature) { return { signature: signature.slice(0, 64), hashType: - signature.slice(64)[0] || transaction_1.Transaction.SIGHASH_DEFAULT, + signature.slice(64)[0] || transaction_js_1.Transaction.SIGHASH_DEFAULT, }; } /** @@ -266,13 +309,13 @@ function getTapKeySigFromWithness(finalScriptWitness) { * @throws Throws an error if the taptree cannot be converted to a tapleaf list. */ function _tapTreeToList(tree, leaves = [], depth = 0) { - if (depth > bip341_1.MAX_TAPTREE_DEPTH) + if (depth > bip341_js_1.MAX_TAPTREE_DEPTH) throw new Error('Max taptree depth exceeded.'); if (!tree) return []; - if ((0, types_1.isTapleaf)(tree)) { + if ((0, types_js_1.isTapleaf)(tree)) { leaves.push({ depth, - leafVersion: tree.version || bip341_1.LEAF_VERSION_TAPSCRIPT, + leafVersion: tree.version || bip341_js_1.LEAF_VERSION_TAPSCRIPT, script: tree.output, }); return leaves; @@ -303,7 +346,7 @@ function instertLeavesInTree(leaves) { * @returns The updated taproot tree. */ function instertLeafInTree(leaf, tree, depth = 0) { - if (depth > bip341_1.MAX_TAPTREE_DEPTH) + if (depth > bip341_js_1.MAX_TAPTREE_DEPTH) throw new Error('Max taptree depth exceeded.'); if (leaf.depth === depth) { if (!tree) @@ -313,7 +356,7 @@ function instertLeafInTree(leaf, tree, depth = 0) { }; return; } - if ((0, types_1.isTapleaf)(tree)) return; + if ((0, types_js_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); @@ -409,15 +452,16 @@ function checkIfTapLeafInTree(inputData, newInputData, action) { */ function isTapLeafInTree(tapLeaf, merkleRoot) { if (!merkleRoot) return true; - const leafHash = (0, bip341_1.tapleafHash)({ + const leafHash = (0, bip341_js_1.tapleafHash)({ output: tapLeaf.script, version: tapLeaf.leafVersion, }); - const rootHash = (0, bip341_1.rootHashFromPath)( + const rootHash = (0, bip341_js_1.rootHashFromPath)( tapLeaf.controlBlock, leafHash, ); - return rootHash.equals(merkleRoot); + // return rootHash.equals(merkleRoot); + return tools.compare(rootHash, merkleRoot) === 0; } /** * Sorts the signatures in the input's tapScriptSig array based on their position in the tapLeaf script. @@ -427,15 +471,18 @@ function isTapLeafInTree(tapLeaf, merkleRoot) { * @returns An array of sorted signatures as Buffers. */ function sortSignatures(input, tapLeaf) { - const leafHash = (0, bip341_1.tapleafHash)({ + const leafHash = (0, bip341_js_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); + return ( + (input.tapScriptSig || []) + // .filter(tss => tss.leafHash.equals(leafHash)) + .filter(tss => tools.compare(tss.leafHash, leafHash) === 0) + .map(tss => addPubkeyPositionInScript(tapLeaf.script, tss)) + .sort((t1, t2) => t2.positionInScript - t1.positionInScript) + .map(t => t.signature) + ); } /** * Adds the position of a public key in a script to a TapScriptSig object. @@ -446,7 +493,7 @@ function sortSignatures(input, tapLeaf) { function addPubkeyPositionInScript(script, tss) { return Object.assign( { - positionInScript: (0, psbtutils_1.pubkeyPositionInScript)( + positionInScript: (0, psbtutils_js_1.pubkeyPositionInScript)( tss.pubkey, script, ), @@ -482,14 +529,17 @@ function findTapLeafToFinalize(input, inputIndex, leafHashToFinalize) { * @returns A boolean indicating whether the TapLeafScript can be finalized. */ function canFinalizeLeaf(leaf, tapScriptSig, hash) { - const leafHash = (0, bip341_1.tapleafHash)({ + const leafHash = (0, bip341_js_1.tapleafHash)({ output: leaf.script, version: leaf.leafVersion, }); - const whiteListedHash = !hash || hash.equals(leafHash); + // const whiteListedHash = !hash || hash.equals(leafHash); + const whiteListedHash = !hash || tools.compare(leafHash, hash) === 0; return ( whiteListedHash && - tapScriptSig.find(tss => tss.leafHash.equals(leafHash)) !== undefined + // tapScriptSig!.find(tss => tss.leafHash.equals(leafHash)) !== undefined + tapScriptSig.find(tss => tools.compare(tss.leafHash, leafHash) === 0) !== + undefined ); } /** diff --git a/src/cjs/psbt/bip371.d.ts b/src/cjs/psbt/bip371.d.ts index c8755dbd0..52e16c854 100644 --- a/src/cjs/psbt/bip371.d.ts +++ b/src/cjs/psbt/bip371.d.ts @@ -1,12 +1,11 @@ -/// -import { Taptree } from '../types'; -import { PsbtInput, PsbtOutput, TapLeaf } from 'bip174/src/lib/interfaces'; +import { Taptree } from '../types.js'; +import { PsbtInput, PsbtOutput, TapLeaf } from 'bip174'; /** * Converts a public key to an X-only public key. * @param pubKey The public key to convert. * @returns The X-only public key. */ -export declare const toXOnly: (pubKey: Buffer) => Buffer; +export declare const toXOnly: (pubKey: Uint8Array) => Uint8Array; /** * 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. @@ -16,8 +15,8 @@ export declare const toXOnly: (pubKey: Buffer) => Buffer; * 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 tapScriptFinalizer(inputIndex: number, input: PsbtInput, tapLeafHashToFinalize?: Uint8Array): { + finalScriptWitness: Uint8Array | undefined; }; /** * Serializes a taproot signature. @@ -25,7 +24,7 @@ export declare function tapScriptFinalizer(inputIndex: number, input: PsbtInput, * @param sighashType The sighash type. Optional. * @returns The serialized taproot signature. */ -export declare function serializeTaprootSignature(sig: Buffer, sighashType?: number): Buffer; +export declare function serializeTaprootSignature(sig: Uint8Array, sighashType?: number): Uint8Array; /** * Checks if a PSBT input is a taproot input. * @param input The PSBT input to check. @@ -38,7 +37,7 @@ export declare function isTaprootInput(input: PsbtInput): boolean; * @param script The script to check. Optional. * @returns True if the output is a taproot output, false otherwise. */ -export declare function isTaprootOutput(output: PsbtOutput, script?: Buffer): boolean; +export declare function isTaprootOutput(output: PsbtOutput, script?: Uint8Array): boolean; /** * Checks the taproot input fields for consistency. * @param inputData The original input data. @@ -62,7 +61,7 @@ export declare function checkTaprootOutputFields(outputData: PsbtOutput, newOutp * @returns The tweaked internal public key. * @throws Error if the tap internal key cannot be tweaked. */ -export declare function tweakInternalPubKey(inputIndex: number, input: PsbtInput): Buffer; +export declare function tweakInternalPubKey(inputIndex: number, input: PsbtInput): Uint8Array; /** * 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, diff --git a/src/cjs/psbt/psbtutils.js b/src/cjs/psbt/psbtutils.cjs similarity index 85% rename from src/cjs/psbt/psbtutils.js rename to src/cjs/psbt/psbtutils.cjs index 0d5cd1688..dbebd1407 100644 --- a/src/cjs/psbt/psbtutils.js +++ b/src/cjs/psbt/psbtutils.cjs @@ -44,12 +44,7 @@ var __importStar = return result; }; Object.defineProperty(exports, '__esModule', { value: true }); -exports.signatureBlocksAction = - exports.checkInputForSig = - exports.pubkeyInScript = - exports.pubkeyPositionInScript = - exports.witnessStackToScriptWitness = - exports.isP2TR = +exports.isP2TR = exports.isP2SHScript = exports.isP2WSHScript = exports.isP2WPKH = @@ -57,11 +52,17 @@ exports.signatureBlocksAction = exports.isP2PK = exports.isP2MS = void 0; +exports.witnessStackToScriptWitness = witnessStackToScriptWitness; +exports.pubkeyPositionInScript = pubkeyPositionInScript; +exports.pubkeyInScript = pubkeyInScript; +exports.checkInputForSig = checkInputForSig; +exports.signatureBlocksAction = signatureBlocksAction; const varuint = __importStar(require('varuint-bitcoin')); -const bscript = __importStar(require('../script')); -const transaction_1 = require('../transaction'); -const crypto_1 = require('../crypto'); -const payments = __importStar(require('../payments')); +const bscript = __importStar(require('../script.cjs')); +const transaction_js_1 = require('../transaction.cjs'); +const crypto_js_1 = require('../crypto.cjs'); +const payments = __importStar(require('../payments/index.cjs')); +const tools = __importStar(require('uint8array-tools')); /** * Checks if a given payment factory can generate a payment script from a given script. * @param payment The payment factory to check. @@ -90,14 +91,16 @@ exports.isP2TR = isPaymentFactory(payments.p2tr); * @returns The script witness as a Buffer. */ function witnessStackToScriptWitness(witness) { - let buffer = Buffer.allocUnsafe(0); + let buffer = new Uint8Array(0); function writeSlice(slice) { - buffer = Buffer.concat([buffer, Buffer.from(slice)]); + // buffer = Buffer.concat([buffer, Buffer.from(slice)]); + buffer = tools.concat([buffer, slice]); } function writeVarInt(i) { const currentLen = buffer.length; const varintLen = varuint.encodingLength(i); - buffer = Buffer.concat([buffer, Buffer.allocUnsafe(varintLen)]); + // buffer = Buffer.concat([buffer, Buffer.allocUnsafe(varintLen)]); + buffer = tools.concat([buffer, new Uint8Array(varintLen)]); varuint.encode(i, buffer, currentLen); } function writeVarSlice(slice) { @@ -111,7 +114,6 @@ function witnessStackToScriptWitness(witness) { writeVector(witness); return buffer; } -exports.witnessStackToScriptWitness = witnessStackToScriptWitness; /** * Finds the position of a public key in a script. * @param pubkey The public key to search for. @@ -120,20 +122,22 @@ exports.witnessStackToScriptWitness = witnessStackToScriptWitness; * @throws {Error} If there is an unknown script error. */ function pubkeyPositionInScript(pubkey, script) { - const pubkeyHash = (0, crypto_1.hash160)(pubkey); + const pubkeyHash = (0, crypto_js_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) + // element.equals(pubkey) || + // element.equals(pubkeyHash) || + // element.equals(pubkeyXOnly) + tools.compare(pubkey, element) === 0 || + tools.compare(pubkeyHash, element) === 0 || + tools.compare(pubkeyXOnly, element) === 0 ); }); } -exports.pubkeyPositionInScript = pubkeyPositionInScript; /** * Checks if a public key is present in a script. * @param pubkey The public key to check. @@ -143,7 +147,6 @@ exports.pubkeyPositionInScript = pubkeyPositionInScript; function pubkeyInScript(pubkey, script) { return pubkeyPositionInScript(pubkey, script) !== -1; } -exports.pubkeyInScript = pubkeyInScript; /** * Checks if an input contains a signature for a specific action. * @param input - The input to check. @@ -156,7 +159,6 @@ function checkInputForSig(input, action) { signatureBlocksAction(pSig, bscript.signature.decode, action), ); } -exports.checkInputForSig = checkInputForSig; /** * Determines if a given action is allowed for a signature block. * @param signature - The signature block. @@ -168,14 +170,14 @@ function signatureBlocksAction(signature, signatureDecodeFn, action) { const { hashType } = signatureDecodeFn(signature); const whitelist = []; const isAnyoneCanPay = - hashType & transaction_1.Transaction.SIGHASH_ANYONECANPAY; + hashType & transaction_js_1.Transaction.SIGHASH_ANYONECANPAY; if (isAnyoneCanPay) whitelist.push('addInput'); const hashMod = hashType & 0x1f; switch (hashMod) { - case transaction_1.Transaction.SIGHASH_ALL: + case transaction_js_1.Transaction.SIGHASH_ALL: break; - case transaction_1.Transaction.SIGHASH_SINGLE: - case transaction_1.Transaction.SIGHASH_NONE: + case transaction_js_1.Transaction.SIGHASH_SINGLE: + case transaction_js_1.Transaction.SIGHASH_NONE: whitelist.push('addOutput'); whitelist.push('setInputSequence'); break; @@ -185,7 +187,6 @@ function signatureBlocksAction(signature, signatureDecodeFn, action) { } return false; } -exports.signatureBlocksAction = signatureBlocksAction; /** * Extracts the signatures from a PsbtInput object. * If the input has partial signatures, it returns an array of the signatures. @@ -224,7 +225,9 @@ function getPsigsFromInputFinalScripts(input) { return scriptItems .concat(witnessItems) .filter(item => { - return Buffer.isBuffer(item) && bscript.isCanonicalScriptSignature(item); + return ( + item instanceof Uint8Array && bscript.isCanonicalScriptSignature(item) + ); }) .map(sig => ({ signature: sig })); } diff --git a/src/cjs/psbt/psbtutils.d.ts b/src/cjs/psbt/psbtutils.d.ts index b6351cf55..64955e0f5 100644 --- a/src/cjs/psbt/psbtutils.d.ts +++ b/src/cjs/psbt/psbtutils.d.ts @@ -1,18 +1,17 @@ -/// -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; -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; +import { PsbtInput } from 'bip174'; +export declare const isP2MS: (script: Uint8Array) => boolean; +export declare const isP2PK: (script: Uint8Array) => boolean; +export declare const isP2PKH: (script: Uint8Array) => boolean; +export declare const isP2WPKH: (script: Uint8Array) => boolean; +export declare const isP2WSHScript: (script: Uint8Array) => boolean; +export declare const isP2SHScript: (script: Uint8Array) => boolean; +export declare const isP2TR: (script: Uint8Array) => boolean; /** * Converts a witness stack to a script witness. * @param witness The witness stack to convert. * @returns The script witness as a Buffer. */ -export declare function witnessStackToScriptWitness(witness: Buffer[]): Buffer; +export declare function witnessStackToScriptWitness(witness: Uint8Array[]): Uint8Array; /** * Finds the position of a public key in a script. * @param pubkey The public key to search for. @@ -20,14 +19,14 @@ export declare function witnessStackToScriptWitness(witness: Buffer[]): Buffer; * @returns The index of the public key in the script, or -1 if not found. * @throws {Error} If there is an unknown script error. */ -export declare function pubkeyPositionInScript(pubkey: Buffer, script: Buffer): number; +export declare function pubkeyPositionInScript(pubkey: Uint8Array, script: Uint8Array): number; /** * Checks if a public key is present in a script. * @param pubkey The public key to check. * @param script The script to search in. * @returns A boolean indicating whether the public key is present in the script. */ -export declare function pubkeyInScript(pubkey: Buffer, script: Buffer): boolean; +export declare function pubkeyInScript(pubkey: Uint8Array, script: Uint8Array): boolean; /** * Checks if an input contains a signature for a specific action. * @param input - The input to check. @@ -35,8 +34,8 @@ export declare function pubkeyInScript(pubkey: Buffer, script: Buffer): boolean; * @returns A boolean indicating whether the input contains a signature for the specified action. */ export declare function checkInputForSig(input: PsbtInput, action: string): boolean; -type SignatureDecodeFunc = (buffer: Buffer) => { - signature: Buffer; +type SignatureDecodeFunc = (buffer: Uint8Array) => { + signature: Uint8Array; hashType: number; }; /** @@ -46,5 +45,5 @@ type SignatureDecodeFunc = (buffer: Buffer) => { * @param action - The action to be checked. * @returns True if the action is allowed, false otherwise. */ -export declare function signatureBlocksAction(signature: Buffer, signatureDecodeFn: SignatureDecodeFunc, action: string): boolean; +export declare function signatureBlocksAction(signature: Uint8Array, signatureDecodeFn: SignatureDecodeFunc, action: string): boolean; export {}; diff --git a/src/cjs/push_data.cjs b/src/cjs/push_data.cjs new file mode 100644 index 000000000..18d8f1f3d --- /dev/null +++ b/src/cjs/push_data.cjs @@ -0,0 +1,144 @@ +'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if ( + !desc || + ('get' in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, 'default', { enumerable: true, value: v }); + } + : function (o, v) { + o['default'] = v; + }); +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k in mod) + if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; + }; +Object.defineProperty(exports, '__esModule', { value: true }); +exports.encodingLength = encodingLength; +exports.encode = encode; +exports.decode = decode; +const ops_js_1 = require('./ops.cjs'); +const tools = __importStar(require('uint8array-tools')); +/** + * Calculates the encoding length of a number used for push data in Bitcoin transactions. + * @param i The number to calculate the encoding length for. + * @returns The encoding length of the number. + */ +function encodingLength(i) { + return i < ops_js_1.OPS.OP_PUSHDATA1 + ? 1 + : i <= 0xff + ? 2 + : i <= 0xffff + ? 3 + : 5; +} +/** + * Encodes a number into a buffer using a variable-length encoding scheme. + * The encoded buffer is written starting at the specified offset. + * Returns the size of the encoded buffer. + * + * @param buffer - The buffer to write the encoded data into. + * @param num - The number to encode. + * @param offset - The offset at which to start writing the encoded buffer. + * @returns The size of the encoded buffer. + */ +function encode(buffer, num, offset) { + const size = encodingLength(num); + // ~6 bit + if (size === 1) { + // buffer.writeUInt8(num, offset); + tools.writeUInt8(buffer, offset, num); + // 8 bit + } else if (size === 2) { + // buffer.writeUInt8(OPS.OP_PUSHDATA1, offset); + tools.writeUInt8(buffer, offset, ops_js_1.OPS.OP_PUSHDATA1); + // buffer.writeUInt8(num, offset + 1); + tools.writeUInt8(buffer, offset + 1, num); + // 16 bit + } else if (size === 3) { + // buffer.writeUInt8(OPS.OP_PUSHDATA2, offset); + tools.writeUInt8(buffer, offset, ops_js_1.OPS.OP_PUSHDATA2); + // buffer.writeUInt16LE(num, offset + 1); + tools.writeUInt16(buffer, offset + 1, num, 'LE'); + // 32 bit + } else { + // buffer.writeUInt8(OPS.OP_PUSHDATA4, offset); + tools.writeUInt8(buffer, offset, ops_js_1.OPS.OP_PUSHDATA4); + // buffer.writeUInt32LE(num, offset + 1); + tools.writeUInt32(buffer, offset + 1, num, 'LE'); + } + return size; +} +/** + * Decodes a buffer and returns information about the opcode, number, and size. + * @param buffer - The buffer to decode. + * @param offset - The offset within the buffer to start decoding. + * @returns An object containing the opcode, number, and size, or null if decoding fails. + */ +function decode(buffer, offset) { + // const opcode = buffer.readUInt8(offset); + const opcode = tools.readUInt8(buffer, offset); + let num; + let size; + // ~6 bit + if (opcode < ops_js_1.OPS.OP_PUSHDATA1) { + num = opcode; + size = 1; + // 8 bit + } else if (opcode === ops_js_1.OPS.OP_PUSHDATA1) { + if (offset + 2 > buffer.length) return null; + // num = buffer.readUInt8(offset + 1); + num = tools.readUInt8(buffer, offset + 1); + size = 2; + // 16 bit + } else if (opcode === ops_js_1.OPS.OP_PUSHDATA2) { + if (offset + 3 > buffer.length) return null; + // num = buffer.readUInt16LE(offset + 1); + num = tools.readUInt16(buffer, offset + 1, 'LE'); + size = 3; + // 32 bit + } else { + if (offset + 5 > buffer.length) return null; + if (opcode !== ops_js_1.OPS.OP_PUSHDATA4) + throw new Error('Unexpected opcode'); + // num = buffer.readUInt32LE(offset + 1); + num = tools.readUInt32(buffer, offset + 1, 'LE'); + size = 5; + } + return { + opcode, + number: num, + size, + }; +} diff --git a/src/cjs/push_data.d.ts b/src/cjs/push_data.d.ts index 068456148..2ce910991 100644 --- a/src/cjs/push_data.d.ts +++ b/src/cjs/push_data.d.ts @@ -1,4 +1,3 @@ -/// /** * Calculates the encoding length of a number used for push data in Bitcoin transactions. * @param i The number to calculate the encoding length for. @@ -15,14 +14,14 @@ export declare function encodingLength(i: number): number; * @param offset - The offset at which to start writing the encoded buffer. * @returns The size of the encoded buffer. */ -export declare function encode(buffer: Buffer, num: number, offset: number): number; +export declare function encode(buffer: Uint8Array, num: number, offset: number): number; /** * Decodes a buffer and returns information about the opcode, number, and size. * @param buffer - The buffer to decode. * @param offset - The offset within the buffer to start decoding. * @returns An object containing the opcode, number, and size, or null if decoding fails. */ -export declare function decode(buffer: Buffer, offset: number): { +export declare function decode(buffer: Uint8Array, offset: number): { opcode: number; number: number; size: number; diff --git a/src/cjs/push_data.js b/src/cjs/push_data.js deleted file mode 100644 index 2d3683769..000000000 --- a/src/cjs/push_data.js +++ /dev/null @@ -1,82 +0,0 @@ -'use strict'; -Object.defineProperty(exports, '__esModule', { value: true }); -exports.decode = exports.encode = exports.encodingLength = void 0; -const ops_1 = require('./ops'); -/** - * Calculates the encoding length of a number used for push data in Bitcoin transactions. - * @param i The number to calculate the encoding length for. - * @returns The encoding length of the number. - */ -function encodingLength(i) { - return i < ops_1.OPS.OP_PUSHDATA1 ? 1 : i <= 0xff ? 2 : i <= 0xffff ? 3 : 5; -} -exports.encodingLength = encodingLength; -/** - * Encodes a number into a buffer using a variable-length encoding scheme. - * The encoded buffer is written starting at the specified offset. - * Returns the size of the encoded buffer. - * - * @param buffer - The buffer to write the encoded data into. - * @param num - The number to encode. - * @param offset - The offset at which to start writing the encoded buffer. - * @returns The size of the encoded buffer. - */ -function encode(buffer, num, offset) { - const size = encodingLength(num); - // ~6 bit - if (size === 1) { - buffer.writeUInt8(num, offset); - // 8 bit - } else if (size === 2) { - buffer.writeUInt8(ops_1.OPS.OP_PUSHDATA1, offset); - buffer.writeUInt8(num, offset + 1); - // 16 bit - } else if (size === 3) { - buffer.writeUInt8(ops_1.OPS.OP_PUSHDATA2, offset); - buffer.writeUInt16LE(num, offset + 1); - // 32 bit - } else { - buffer.writeUInt8(ops_1.OPS.OP_PUSHDATA4, offset); - buffer.writeUInt32LE(num, offset + 1); - } - return size; -} -exports.encode = encode; -/** - * Decodes a buffer and returns information about the opcode, number, and size. - * @param buffer - The buffer to decode. - * @param offset - The offset within the buffer to start decoding. - * @returns An object containing the opcode, number, and size, or null if decoding fails. - */ -function decode(buffer, offset) { - const opcode = buffer.readUInt8(offset); - let num; - let size; - // ~6 bit - if (opcode < ops_1.OPS.OP_PUSHDATA1) { - num = opcode; - size = 1; - // 8 bit - } else if (opcode === ops_1.OPS.OP_PUSHDATA1) { - if (offset + 2 > buffer.length) return null; - num = buffer.readUInt8(offset + 1); - size = 2; - // 16 bit - } else if (opcode === ops_1.OPS.OP_PUSHDATA2) { - if (offset + 3 > buffer.length) return null; - num = buffer.readUInt16LE(offset + 1); - size = 3; - // 32 bit - } else { - if (offset + 5 > buffer.length) return null; - if (opcode !== ops_1.OPS.OP_PUSHDATA4) throw new Error('Unexpected opcode'); - num = buffer.readUInt32LE(offset + 1); - size = 5; - } - return { - opcode, - number: num, - size, - }; -} -exports.decode = decode; diff --git a/src/cjs/script.js b/src/cjs/script.cjs similarity index 72% rename from src/cjs/script.js rename to src/cjs/script.cjs index 8f0546f4e..4e2b95921 100644 --- a/src/cjs/script.js +++ b/src/cjs/script.cjs @@ -44,71 +44,71 @@ var __importStar = return result; }; 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.countNonPushOnlyOPs = - exports.isPushOnly = - exports.OPS = - void 0; +exports.signature = exports.number = exports.OPS = void 0; +exports.isPushOnly = isPushOnly; +exports.countNonPushOnlyOPs = countNonPushOnlyOPs; +exports.compile = compile; +exports.decompile = decompile; +exports.toASM = toASM; +exports.fromASM = fromASM; +exports.toStack = toStack; +exports.isCanonicalPubKey = isCanonicalPubKey; +exports.isDefinedHashType = isDefinedHashType; +exports.isCanonicalScriptSignature = isCanonicalScriptSignature; /** * Script tools, including decompile, compile, toASM, fromASM, toStack, isCanonicalPubKey, isCanonicalScriptSignature * @packageDocumentation */ -const bip66 = __importStar(require('./bip66')); -const ops_1 = require('./ops'); +const bip66 = __importStar(require('./bip66.cjs')); +const ops_js_1 = require('./ops.cjs'); Object.defineProperty(exports, 'OPS', { enumerable: true, get: function () { - return ops_1.OPS; + return ops_js_1.OPS; }, }); -const pushdata = __importStar(require('./push_data')); -const scriptNumber = __importStar(require('./script_number')); -const scriptSignature = __importStar(require('./script_signature')); -const types = __importStar(require('./types')); -const { typeforce } = types; -const OP_INT_BASE = ops_1.OPS.OP_RESERVED; // OP_1 - 1 +const pushdata = __importStar(require('./push_data.cjs')); +const scriptNumber = __importStar(require('./script_number.cjs')); +const scriptSignature = __importStar(require('./script_signature.cjs')); +const types = __importStar(require('./types.cjs')); +const tools = __importStar(require('uint8array-tools')); +const v = __importStar(require('valibot')); +const OP_INT_BASE = ops_js_1.OPS.OP_RESERVED; // OP_1 - 1 +const StackSchema = v.array(v.union([v.instance(Uint8Array), v.number()])); function isOPInt(value) { return ( - types.Number(value) && - (value === ops_1.OPS.OP_0 || - (value >= ops_1.OPS.OP_1 && value <= ops_1.OPS.OP_16) || - value === ops_1.OPS.OP_1NEGATE) + v.is(v.number(), value) && + (value === ops_js_1.OPS.OP_0 || + (value >= ops_js_1.OPS.OP_1 && value <= ops_js_1.OPS.OP_16) || + value === ops_js_1.OPS.OP_1NEGATE) ); } function isPushOnlyChunk(value) { - return types.Buffer(value) || isOPInt(value); + return v.is(types.BufferSchema, value) || isOPInt(value); } function isPushOnly(value) { - return types.Array(value) && value.every(isPushOnlyChunk); + // return types.Array(value) && value.every(isPushOnlyChunk); + return v.is(v.pipe(v.any(), v.everyItem(isPushOnlyChunk)), value); } -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 === 0) return ops_js_1.OPS.OP_0; if (buffer.length !== 1) return; if (buffer[0] >= 1 && buffer[0] <= 16) return OP_INT_BASE + buffer[0]; - if (buffer[0] === 0x81) return ops_1.OPS.OP_1NEGATE; + if (buffer[0] === 0x81) return ops_js_1.OPS.OP_1NEGATE; } function chunksIsBuffer(buf) { - return Buffer.isBuffer(buf); + // return Buffer.isBuffer(buf); + return buf instanceof Uint8Array; } function chunksIsArray(buf) { - return types.Array(buf); + // return types.Array(buf); + return v.is(StackSchema, buf); } function singleChunkIsBuffer(buf) { - return Buffer.isBuffer(buf); + return buf instanceof Uint8Array; } /** * Compiles an array of chunks into a Buffer. @@ -120,7 +120,8 @@ function singleChunkIsBuffer(buf) { function compile(chunks) { // TODO: remove me if (chunksIsBuffer(chunks)) return chunks; - typeforce(types.Array, chunks); + // typeforce(types.Array, chunks); + v.parse(StackSchema, chunks); const bufferSize = chunks.reduce((accum, chunk) => { // data chunk if (singleChunkIsBuffer(chunk)) { @@ -133,7 +134,7 @@ function compile(chunks) { // opcode return accum + 1; }, 0.0); - const buffer = Buffer.allocUnsafe(bufferSize); + const buffer = new Uint8Array(bufferSize); let offset = 0; chunks.forEach(chunk => { // data chunk @@ -141,33 +142,36 @@ function compile(chunks) { // adhere to BIP62.3, minimal push policy const opcode = asMinimalOP(chunk); if (opcode !== undefined) { - buffer.writeUInt8(opcode, offset); + // buffer.writeUInt8(opcode, offset); + tools.writeUInt8(buffer, offset, opcode); offset += 1; return; } offset += pushdata.encode(buffer, chunk.length, offset); - chunk.copy(buffer, offset); + // chunk.copy(buffer, offset); + buffer.set(chunk, offset); offset += chunk.length; // opcode } else { - buffer.writeUInt8(chunk, offset); + // buffer.writeUInt8(chunk, offset); + tools.writeUInt8(buffer, offset, chunk); offset += 1; } }); if (offset !== buffer.length) throw new Error('Could not decode chunks'); return buffer; } -exports.compile = compile; function decompile(buffer) { // TODO: remove me if (chunksIsArray(buffer)) return buffer; - typeforce(types.Buffer, buffer); + // typeforce(types.Buffer, buffer); + v.parse(types.BufferSchema, buffer); const chunks = []; let i = 0; while (i < buffer.length) { const opcode = buffer[i]; // data chunk - if (opcode > ops_1.OPS.OP_0 && opcode <= ops_1.OPS.OP_PUSHDATA4) { + if (opcode > ops_js_1.OPS.OP_0 && opcode <= ops_js_1.OPS.OP_PUSHDATA4) { const d = pushdata.decode(buffer, i); // did reading a pushDataInt fail? if (d === null) return null; @@ -191,7 +195,6 @@ function decompile(buffer) { } return chunks; } -exports.decompile = decompile; /** * Converts the given chunks into an ASM (Assembly) string representation. * If the chunks parameter is a Buffer, it will be decompiled into a Stack before conversion. @@ -210,33 +213,34 @@ function toASM(chunks) { // data? if (singleChunkIsBuffer(chunk)) { const op = asMinimalOP(chunk); - if (op === undefined) return chunk.toString('hex'); + if (op === undefined) return tools.toHex(chunk); chunk = op; } // opcode! - return ops_1.REVERSE_OPS[chunk]; + return ops_js_1.REVERSE_OPS[chunk]; }) .join(' '); } -exports.toASM = toASM; /** * Converts an ASM string to a Buffer. * @param asm The ASM string to convert. * @returns The converted Buffer. */ function fromASM(asm) { - typeforce(types.String, asm); + // typeforce(types.String, asm); + v.parse(v.string(), asm); return compile( asm.split(' ').map(chunkStr => { // opcode? - if (ops_1.OPS[chunkStr] !== undefined) return ops_1.OPS[chunkStr]; - typeforce(types.Hex, chunkStr); + if (ops_js_1.OPS[chunkStr] !== undefined) return ops_js_1.OPS[chunkStr]; + // typeforce(types.Hex, chunkStr); + v.parse(types.HexSchema, chunkStr); // data! - return Buffer.from(chunkStr, 'hex'); + // return Buffer.from(chunkStr, 'hex'); + return tools.fromHex(chunkStr); }), ); } -exports.fromASM = fromASM; /** * Converts the given chunks into a stack of buffers. * @@ -245,29 +249,26 @@ exports.fromASM = fromASM; */ function toStack(chunks) { chunks = decompile(chunks); - typeforce(isPushOnly, chunks); + // typeforce(isPushOnly, chunks); + v.parse(v.custom(isPushOnly), chunks); return chunks.map(op => { if (singleChunkIsBuffer(op)) return op; - if (op === ops_1.OPS.OP_0) return Buffer.allocUnsafe(0); + if (op === ops_js_1.OPS.OP_0) return new Uint8Array(0); return scriptNumber.encode(op - OP_INT_BASE); }); } -exports.toStack = toStack; function isCanonicalPubKey(buffer) { return types.isPoint(buffer); } -exports.isCanonicalPubKey = isCanonicalPubKey; function isDefinedHashType(hashType) { const hashTypeMod = hashType & ~0x80; // return hashTypeMod > SIGHASH_ALL && hashTypeMod < SIGHASH_SINGLE return hashTypeMod > 0x00 && hashTypeMod < 0x04; } -exports.isDefinedHashType = isDefinedHashType; function isCanonicalScriptSignature(buffer) { - if (!Buffer.isBuffer(buffer)) return false; + if (!(buffer instanceof Uint8Array)) return false; if (!isDefinedHashType(buffer[buffer.length - 1])) return false; return bip66.check(buffer.slice(0, -1)); } -exports.isCanonicalScriptSignature = isCanonicalScriptSignature; exports.number = scriptNumber; exports.signature = scriptSignature; diff --git a/src/cjs/script.d.ts b/src/cjs/script.d.ts index ffc8c89bb..9d31f50a1 100644 --- a/src/cjs/script.d.ts +++ b/src/cjs/script.d.ts @@ -1,8 +1,7 @@ -/// -import { OPS } from './ops'; -import { Stack } from './payments'; -import * as scriptNumber from './script_number'; -import * as scriptSignature from './script_signature'; +import { OPS } from './ops.js'; +import { Stack } from './payments/index.js'; +import * as scriptNumber from './script_number.js'; +import * as scriptSignature from './script_signature.js'; export { OPS }; export declare function isPushOnly(value: Stack): boolean; export declare function countNonPushOnlyOPs(value: Stack): number; @@ -13,30 +12,30 @@ export declare function countNonPushOnlyOPs(value: Stack): number; * @returns The compiled Buffer. * @throws Error if the compilation fails. */ -export declare function compile(chunks: Buffer | Stack): Buffer; -export declare function decompile(buffer: Buffer | Array): Array | null; +export declare function compile(chunks: Uint8Array | Stack): Uint8Array; +export declare function decompile(buffer: Uint8Array | Array): Array | null; /** * Converts the given chunks into an ASM (Assembly) string representation. * If the chunks parameter is a Buffer, it will be decompiled into a Stack before conversion. * @param chunks - The chunks to convert into ASM. * @returns The ASM string representation of the chunks. */ -export declare function toASM(chunks: Buffer | Array): string; +export declare function toASM(chunks: Uint8Array | Array): string; /** * Converts an ASM string to a Buffer. * @param asm The ASM string to convert. * @returns The converted Buffer. */ -export declare function fromASM(asm: string): Buffer; +export declare function fromASM(asm: string): Uint8Array; /** * Converts the given chunks into a stack of buffers. * * @param chunks - The chunks to convert. * @returns The stack of buffers. */ -export declare function toStack(chunks: Buffer | Array): Buffer[]; -export declare function isCanonicalPubKey(buffer: Buffer): boolean; +export declare function toStack(chunks: Uint8Array | Array): Uint8Array[]; +export declare function isCanonicalPubKey(buffer: Uint8Array): boolean; export declare function isDefinedHashType(hashType: number): boolean; -export declare function isCanonicalScriptSignature(buffer: Buffer): boolean; +export declare function isCanonicalScriptSignature(buffer: Uint8Array): boolean; export declare const number: typeof scriptNumber; export declare const signature: typeof scriptSignature; diff --git a/src/cjs/script_number.cjs b/src/cjs/script_number.cjs new file mode 100644 index 000000000..088b8f26f --- /dev/null +++ b/src/cjs/script_number.cjs @@ -0,0 +1,126 @@ +'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if ( + !desc || + ('get' in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, 'default', { enumerable: true, value: v }); + } + : function (o, v) { + o['default'] = v; + }); +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k in mod) + if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; + }; +Object.defineProperty(exports, '__esModule', { value: true }); +exports.decode = decode; +exports.encode = encode; +const tools = __importStar(require('uint8array-tools')); +/** + * Decodes a script number from a buffer. + * + * @param buffer - The buffer containing the script number. + * @param maxLength - The maximum length of the script number. Defaults to 4. + * @param minimal - Whether the script number should be minimal. Defaults to true. + * @returns The decoded script number. + * @throws {TypeError} If the script number overflows the maximum length. + * @throws {Error} If the script number is not minimally encoded when minimal is true. + */ +function decode(buffer, maxLength, minimal) { + maxLength = maxLength || 4; + minimal = minimal === undefined ? true : minimal; + const length = buffer.length; + if (length === 0) return 0; + if (length > maxLength) throw new TypeError('Script number overflow'); + if (minimal) { + if ((buffer[length - 1] & 0x7f) === 0) { + if (length <= 1 || (buffer[length - 2] & 0x80) === 0) + throw new Error('Non-minimally encoded script number'); + } + } + // 40-bit + if (length === 5) { + // const a = buffer.readUInt32LE(0); + // const b = buffer.readUInt8(4); + const a = tools.readUInt32(buffer, 0, 'LE'); + const b = tools.readUInt8(buffer, 4); + if (b & 0x80) return -((b & ~0x80) * 0x100000000 + a); + return b * 0x100000000 + a; + } + // 32-bit / 24-bit / 16-bit / 8-bit + let result = 0; + for (let i = 0; i < length; ++i) { + result |= buffer[i] << (8 * i); + } + if (buffer[length - 1] & 0x80) + return -(result & ~(0x80 << (8 * (length - 1)))); + return result; +} +function scriptNumSize(i) { + return i > 0x7fffffff + ? 5 + : i > 0x7fffff + ? 4 + : i > 0x7fff + ? 3 + : i > 0x7f + ? 2 + : i > 0x00 + ? 1 + : 0; +} +/** + * Encodes a number into a Uint8Array using a specific format. + * + * @param _number - The number to encode. + * @returns The encoded number as a Uint8Array. + */ +function encode(_number) { + let value = Math.abs(_number); + const size = scriptNumSize(value); + const buffer = new Uint8Array(size); + const negative = _number < 0; + for (let i = 0; i < size; ++i) { + // buffer.writeUInt8(value & 0xff, i); + tools.writeUInt8(buffer, i, value & 0xff); + value >>= 8; + } + if (buffer[size - 1] & 0x80) { + // buffer.writeUInt8(negative ? 0x80 : 0x00, size - 1); + tools.writeUInt8(buffer, size - 1, negative ? 0x80 : 0x00); + } else if (negative) { + buffer[size - 1] |= 0x80; + } + return buffer; +} diff --git a/src/cjs/script_number.d.ts b/src/cjs/script_number.d.ts index 90f09c55a..26a2ea089 100644 --- a/src/cjs/script_number.d.ts +++ b/src/cjs/script_number.d.ts @@ -1,4 +1,3 @@ -/// /** * Decodes a script number from a buffer. * @@ -9,11 +8,11 @@ * @throws {TypeError} If the script number overflows the maximum length. * @throws {Error} If the script number is not minimally encoded when minimal is true. */ -export declare function decode(buffer: Buffer, maxLength?: number, minimal?: boolean): number; +export declare function decode(buffer: Uint8Array, maxLength?: number, minimal?: boolean): number; /** - * Encodes a number into a Buffer using a specific format. + * Encodes a number into a Uint8Array using a specific format. * * @param _number - The number to encode. - * @returns The encoded number as a Buffer. + * @returns The encoded number as a Uint8Array. */ -export declare function encode(_number: number): Buffer; +export declare function encode(_number: number): Uint8Array; diff --git a/src/cjs/script_number.js b/src/cjs/script_number.js deleted file mode 100644 index 2691b41e6..000000000 --- a/src/cjs/script_number.js +++ /dev/null @@ -1,78 +0,0 @@ -'use strict'; -Object.defineProperty(exports, '__esModule', { value: true }); -exports.encode = exports.decode = void 0; -/** - * Decodes a script number from a buffer. - * - * @param buffer - The buffer containing the script number. - * @param maxLength - The maximum length of the script number. Defaults to 4. - * @param minimal - Whether the script number should be minimal. Defaults to true. - * @returns The decoded script number. - * @throws {TypeError} If the script number overflows the maximum length. - * @throws {Error} If the script number is not minimally encoded when minimal is true. - */ -function decode(buffer, maxLength, minimal) { - maxLength = maxLength || 4; - minimal = minimal === undefined ? true : minimal; - const length = buffer.length; - if (length === 0) return 0; - if (length > maxLength) throw new TypeError('Script number overflow'); - if (minimal) { - if ((buffer[length - 1] & 0x7f) === 0) { - if (length <= 1 || (buffer[length - 2] & 0x80) === 0) - throw new Error('Non-minimally encoded script number'); - } - } - // 40-bit - if (length === 5) { - const a = buffer.readUInt32LE(0); - const b = buffer.readUInt8(4); - if (b & 0x80) return -((b & ~0x80) * 0x100000000 + a); - return b * 0x100000000 + a; - } - // 32-bit / 24-bit / 16-bit / 8-bit - let result = 0; - for (let i = 0; i < length; ++i) { - result |= buffer[i] << (8 * i); - } - if (buffer[length - 1] & 0x80) - return -(result & ~(0x80 << (8 * (length - 1)))); - return result; -} -exports.decode = decode; -function scriptNumSize(i) { - return i > 0x7fffffff - ? 5 - : i > 0x7fffff - ? 4 - : i > 0x7fff - ? 3 - : i > 0x7f - ? 2 - : i > 0x00 - ? 1 - : 0; -} -/** - * Encodes a number into a Buffer using a specific format. - * - * @param _number - The number to encode. - * @returns The encoded number as a Buffer. - */ -function encode(_number) { - let value = Math.abs(_number); - const size = scriptNumSize(value); - const buffer = Buffer.allocUnsafe(size); - const negative = _number < 0; - for (let i = 0; i < size; ++i) { - buffer.writeUInt8(value & 0xff, i); - value >>= 8; - } - if (buffer[size - 1] & 0x80) { - buffer.writeUInt8(negative ? 0x80 : 0x00, size - 1); - } else if (negative) { - buffer[size - 1] |= 0x80; - } - return buffer; -} -exports.encode = encode; diff --git a/src/cjs/script_signature.js b/src/cjs/script_signature.cjs similarity index 68% rename from src/cjs/script_signature.js rename to src/cjs/script_signature.cjs index 74f4dce85..adb3a64eb 100644 --- a/src/cjs/script_signature.js +++ b/src/cjs/script_signature.cjs @@ -44,12 +44,14 @@ var __importStar = return result; }; Object.defineProperty(exports, '__esModule', { value: true }); -exports.encode = exports.decode = void 0; -const bip66 = __importStar(require('./bip66')); -const script_1 = require('./script'); -const types = __importStar(require('./types')); -const { typeforce } = types; -const ZERO = Buffer.alloc(1, 0); +exports.decode = decode; +exports.encode = encode; +const bip66 = __importStar(require('./bip66.cjs')); +const script_js_1 = require('./script.cjs'); +const v = __importStar(require('valibot')); +const tools = __importStar(require('uint8array-tools')); +const types_js_1 = require('./types.cjs'); +const ZERO = new Uint8Array(1); /** * Converts a buffer to a DER-encoded buffer. * @param x - The buffer to be converted. @@ -60,7 +62,7 @@ function toDER(x) { while (x[i] === 0) ++i; if (i === x.length) return ZERO; x = x.slice(i); - if (x[0] & 0x80) return Buffer.concat([ZERO, x], 1 + x.length); + if (x[0] & 0x80) return tools.concat([ZERO, x]); return x; } /** @@ -72,9 +74,10 @@ function toDER(x) { */ function fromDER(x) { if (x[0] === 0x00) x = x.slice(1); - const buffer = Buffer.alloc(32, 0); + const buffer = new Uint8Array(32); const bstart = Math.max(0, 32 - x.length); - x.copy(buffer, bstart); + // x.copy(buffer, bstart); + buffer.set(x, bstart); return buffer; } // BIP62: 1 byte hashType flag (only 0x01, 0x02, 0x03, 0x81, 0x82 and 0x83 are allowed) @@ -85,17 +88,17 @@ function fromDER(x) { * @throws Error if the hashType is invalid. */ function decode(buffer) { - const hashType = buffer.readUInt8(buffer.length - 1); - if (!(0, script_1.isDefinedHashType)(hashType)) { + // const hashType = buffer.readUInt8(buffer.length - 1); + const hashType = tools.readUInt8(buffer, buffer.length - 1); + if (!(0, script_js_1.isDefinedHashType)(hashType)) { throw new Error('Invalid hashType ' + hashType); } - const decoded = bip66.decode(buffer.slice(0, -1)); + const decoded = bip66.decode(buffer.subarray(0, -1)); const r = fromDER(decoded.r); const s = fromDER(decoded.s); - const signature = Buffer.concat([r, s], 64); + const signature = tools.concat([r, s]); return { signature, hashType }; } -exports.decode = decode; /** * Encodes a signature and hash type into a buffer. * @param signature - The signature to encode. @@ -104,20 +107,29 @@ exports.decode = decode; * @throws Error if the hashType is invalid. */ function encode(signature, hashType) { - typeforce( - { - signature: types.BufferN(64), - hashType: types.UInt8, - }, + // typeforce( + // { + // signature: types.BufferN(64), + // hashType: types.UInt8, + // }, + // { signature, hashType }, + // ); + v.parse( + v.object({ + signature: (0, types_js_1.NBufferSchemaFactory)(64), + hashType: types_js_1.UInt8Schema, + }), { signature, hashType }, ); - if (!(0, script_1.isDefinedHashType)(hashType)) { + if (!(0, script_js_1.isDefinedHashType)(hashType)) { throw new Error('Invalid hashType ' + hashType); } - const hashTypeBuffer = Buffer.allocUnsafe(1); - hashTypeBuffer.writeUInt8(hashType, 0); + // const hashTypeBuffer = Buffer.allocUnsafe(1); + const hashTypeBuffer = new Uint8Array(1); + // hashTypeBuffer.writeUInt8(hashType, 0); + tools.writeUInt8(hashTypeBuffer, 0, hashType); const r = toDER(signature.slice(0, 32)); const s = toDER(signature.slice(32, 64)); - return Buffer.concat([bip66.encode(r, s), hashTypeBuffer]); + // return Buffer.concat([bip66.encode(r, s), hashTypeBuffer]); + return tools.concat([bip66.encode(r, s), hashTypeBuffer]); } -exports.encode = encode; diff --git a/src/cjs/script_signature.d.ts b/src/cjs/script_signature.d.ts index b9034a816..16f645869 100644 --- a/src/cjs/script_signature.d.ts +++ b/src/cjs/script_signature.d.ts @@ -1,6 +1,5 @@ -/// interface ScriptSignature { - signature: Buffer; + signature: Uint8Array; hashType: number; } /** @@ -9,7 +8,7 @@ interface ScriptSignature { * @returns The decoded ScriptSignature object. * @throws Error if the hashType is invalid. */ -export declare function decode(buffer: Buffer): ScriptSignature; +export declare function decode(buffer: Uint8Array): ScriptSignature; /** * Encodes a signature and hash type into a buffer. * @param signature - The signature to encode. @@ -17,5 +16,5 @@ export declare function decode(buffer: Buffer): ScriptSignature; * @returns The encoded buffer. * @throws Error if the hashType is invalid. */ -export declare function encode(signature: Buffer, hashType: number): Buffer; +export declare function encode(signature: Uint8Array, hashType: number): Uint8Array; export {}; diff --git a/src/cjs/transaction.js b/src/cjs/transaction.cjs similarity index 73% rename from src/cjs/transaction.js rename to src/cjs/transaction.cjs index 0361e93fc..c730ab54c 100644 --- a/src/cjs/transaction.js +++ b/src/cjs/transaction.cjs @@ -45,36 +45,45 @@ var __importStar = }; Object.defineProperty(exports, '__esModule', { value: true }); exports.Transaction = void 0; -const bufferutils_1 = require('./bufferutils'); -const bcrypto = __importStar(require('./crypto')); -const bscript = __importStar(require('./script')); -const script_1 = require('./script'); -const types = __importStar(require('./types')); -const { typeforce } = types; +const bufferutils_js_1 = require('./bufferutils.cjs'); +const bcrypto = __importStar(require('./crypto.cjs')); +const sha256_1 = require('@noble/hashes/sha256'); +const bscript = __importStar(require('./script.cjs')); +const script_js_1 = require('./script.cjs'); +const types = __importStar(require('./types.cjs')); +const tools = __importStar(require('uint8array-tools')); +const v = __importStar(require('valibot')); function varSliceSize(someScript) { const length = someScript.length; - return bufferutils_1.varuint.encodingLength(length) + length; + return bufferutils_js_1.varuint.encodingLength(length) + length; } function vectorSize(someVector) { const length = someVector.length; return ( - bufferutils_1.varuint.encodingLength(length) + + bufferutils_js_1.varuint.encodingLength(length) + someVector.reduce((sum, witness) => { return sum + varSliceSize(witness); }, 0) ); } -const EMPTY_BUFFER = Buffer.allocUnsafe(0); +const EMPTY_BUFFER = new Uint8Array(0); const EMPTY_WITNESS = []; -const ZERO = Buffer.from( +// const ZERO: Buffer = Buffer.from( +// '0000000000000000000000000000000000000000000000000000000000000000', +// 'hex', +// ); +const ZERO = tools.fromHex( '0000000000000000000000000000000000000000000000000000000000000000', - 'hex', ); -const ONE = Buffer.from( +// const ONE: Buffer = Buffer.from( +// '0000000000000000000000000000000000000000000000000000000000000001', +// 'hex', +// ); +const ONE = tools.fromHex( '0000000000000000000000000000000000000000000000000000000000000001', - 'hex', ); -const VALUE_UINT64_MAX = Buffer.from('ffffffffffffffff', 'hex'); +// const VALUE_UINT64_MAX: Buffer = Buffer.from('ffffffffffffffff', 'hex'); +const VALUE_UINT64_MAX = tools.fromHex('ffffffffffffffff'); const BLANK_OUTPUT = { script: EMPTY_BUFFER, valueBuffer: VALUE_UINT64_MAX, @@ -97,7 +106,7 @@ class Transaction { static ADVANCED_TRANSACTION_MARKER = 0x00; static ADVANCED_TRANSACTION_FLAG = 0x01; static fromBuffer(buffer, _NO_STRICT) { - const bufferReader = new bufferutils_1.BufferReader(buffer); + const bufferReader = new bufferutils_js_1.BufferReader(buffer); const tx = new Transaction(); tx.version = bufferReader.readInt32(); const marker = bufferReader.readUInt8(); @@ -143,10 +152,11 @@ class Transaction { return tx; } static fromHex(hex) { - return Transaction.fromBuffer(Buffer.from(hex, 'hex'), false); + return Transaction.fromBuffer(tools.fromHex(hex), false); } static isCoinbaseHash(buffer) { - typeforce(types.Hash256bit, buffer); + // typeforce(types.Hash256bit, buffer); + v.parse(types.Hash256bitSchema, buffer); for (let i = 0; i < 32; ++i) { if (buffer[i] !== 0) return false; } @@ -162,16 +172,25 @@ class Transaction { ); } addInput(hash, index, sequence, scriptSig) { - typeforce( - types.tuple( - types.Hash256bit, - types.UInt32, - types.maybe(types.UInt32), - types.maybe(types.Buffer), - ), - arguments, + // typeforce( + // types.tuple( + // types.Hash256bit, + // types.UInt32, + // types.maybe(types.UInt32), + // types.maybe(types.Buffer), + // ), + // arguments, + // ); + v.parse( + v.tuple([ + types.Hash256bitSchema, + types.UInt32Schema, + v.nullable(v.optional(types.UInt32Schema)), + v.nullable(v.optional(types.BufferSchema)), + ]), + [hash, index, sequence, scriptSig], ); - if (types.Null(sequence)) { + if (sequence === undefined || sequence === null) { sequence = Transaction.DEFAULT_SEQUENCE; } // Add the input and return the input's index @@ -186,7 +205,11 @@ class Transaction { ); } addOutput(scriptPubKey, value) { - typeforce(types.tuple(types.Buffer, types.Satoshi), arguments); + // typeforce(types.tuple(types.Buffer, types.Satoshi), arguments); + v.parse(v.tuple([types.BufferSchema, types.SatoshiSchema]), [ + scriptPubKey, + value, + ]); // Add the output and return the output's index return ( this.outs.push({ @@ -212,8 +235,8 @@ class Transaction { const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses(); return ( (hasWitnesses ? 10 : 8) + - bufferutils_1.varuint.encodingLength(this.ins.length) + - bufferutils_1.varuint.encodingLength(this.outs.length) + + bufferutils_js_1.varuint.encodingLength(this.ins.length) + + bufferutils_js_1.varuint.encodingLength(this.outs.length) + this.ins.reduce((sum, input) => { return sum + 40 + varSliceSize(input.script); }, 0) + @@ -257,16 +280,21 @@ class Transaction { * This hash can then be used to sign the provided transaction input. */ hashForSignature(inIndex, prevOutScript, hashType) { - typeforce( - types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), - arguments, - ); + // typeforce( + // types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), + // arguments, + // ); + v.parse(v.tuple([types.UInt32Schema, types.BufferSchema, v.number()]), [ + inIndex, + prevOutScript, + hashType, + ]); // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L29 if (inIndex >= this.ins.length) return ONE; // ignore OP_CODESEPARATOR const ourScript = bscript.compile( bscript.decompile(prevOutScript).filter(x => { - return x !== script_1.OPS.OP_CODESEPARATOR; + return x !== script_js_1.OPS.OP_CODESEPARATOR; }), ); const txTmp = this.clone(); @@ -307,21 +335,31 @@ class Transaction { txTmp.ins[inIndex].script = ourScript; } // serialize and hash - const buffer = Buffer.allocUnsafe(txTmp.byteLength(false) + 4); - buffer.writeInt32LE(hashType, buffer.length - 4); + const buffer = new Uint8Array(txTmp.byteLength(false) + 4); + // buffer.writeInt32LE(hashType, buffer.length - 4); + tools.writeInt32(buffer, hashType, buffer.length - 4, 'LE'); txTmp.__toBuffer(buffer, 0, false); return bcrypto.hash256(buffer); } hashForWitnessV1(inIndex, prevOutScripts, values, hashType, leafHash, annex) { // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#common-signature-message - typeforce( - types.tuple( - types.UInt32, - typeforce.arrayOf(types.Buffer), - typeforce.arrayOf(types.Satoshi), - types.UInt32, - ), - arguments, + // typeforce( + // types.tuple( + // types.UInt32, + // typeforce.arrayOf(types.Buffer), + // typeforce.arrayOf(types.Satoshi), + // types.UInt32, + // ), + // arguments, + // ); + v.parse( + v.tuple([ + types.UInt32Schema, + v.array(types.BufferSchema), + v.array(types.SatoshiSchema), + types.UInt32Schema, + ]), + [inIndex, prevOutScripts, values, hashType], ); if ( values.length !== this.ins.length || @@ -343,31 +381,31 @@ class Transaction { let hashSequences = EMPTY_BUFFER; let hashOutputs = EMPTY_BUFFER; if (!isAnyoneCanPay) { - let bufferWriter = bufferutils_1.BufferWriter.withCapacity( + let bufferWriter = bufferutils_js_1.BufferWriter.withCapacity( 36 * this.ins.length, ); this.ins.forEach(txIn => { bufferWriter.writeSlice(txIn.hash); bufferWriter.writeUInt32(txIn.index); }); - hashPrevouts = bcrypto.sha256(bufferWriter.end()); - bufferWriter = bufferutils_1.BufferWriter.withCapacity( + hashPrevouts = (0, sha256_1.sha256)(bufferWriter.end()); + bufferWriter = bufferutils_js_1.BufferWriter.withCapacity( 8 * this.ins.length, ); values.forEach(value => bufferWriter.writeUInt64(value)); - hashAmounts = bcrypto.sha256(bufferWriter.end()); - bufferWriter = bufferutils_1.BufferWriter.withCapacity( + hashAmounts = (0, sha256_1.sha256)(bufferWriter.end()); + bufferWriter = bufferutils_js_1.BufferWriter.withCapacity( prevOutScripts.map(varSliceSize).reduce((a, b) => a + b), ); prevOutScripts.forEach(prevOutScript => bufferWriter.writeVarSlice(prevOutScript), ); - hashScriptPubKeys = bcrypto.sha256(bufferWriter.end()); - bufferWriter = bufferutils_1.BufferWriter.withCapacity( + hashScriptPubKeys = (0, sha256_1.sha256)(bufferWriter.end()); + bufferWriter = bufferutils_js_1.BufferWriter.withCapacity( 4 * this.ins.length, ); this.ins.forEach(txIn => bufferWriter.writeUInt32(txIn.sequence)); - hashSequences = bcrypto.sha256(bufferWriter.end()); + hashSequences = (0, sha256_1.sha256)(bufferWriter.end()); } if (!(isNone || isSingle)) { if (!this.outs.length) @@ -375,20 +413,22 @@ class Transaction { const txOutsSize = this.outs .map(output => 8 + varSliceSize(output.script)) .reduce((a, b) => a + b); - const bufferWriter = bufferutils_1.BufferWriter.withCapacity(txOutsSize); + const bufferWriter = + bufferutils_js_1.BufferWriter.withCapacity(txOutsSize); this.outs.forEach(out => { - bufferWriter.writeUInt64(out.value); + // bufferWriter.writeUInt64(out.value); + bufferWriter.writeInt64(out.value); bufferWriter.writeVarSlice(out.script); }); - hashOutputs = bcrypto.sha256(bufferWriter.end()); + hashOutputs = (0, sha256_1.sha256)(bufferWriter.end()); } else if (isSingle && inIndex < this.outs.length) { const output = this.outs[inIndex]; - const bufferWriter = bufferutils_1.BufferWriter.withCapacity( + const bufferWriter = bufferutils_js_1.BufferWriter.withCapacity( 8 + varSliceSize(output.script), ); bufferWriter.writeUInt64(output.value); bufferWriter.writeVarSlice(output.script); - hashOutputs = bcrypto.sha256(bufferWriter.end()); + hashOutputs = (0, sha256_1.sha256)(bufferWriter.end()); } const spendType = (leafHash ? 2 : 0) + (annex ? 1 : 0); // Length calculation from: @@ -401,7 +441,7 @@ class Transaction { (isNone ? 32 : 0) + (annex ? 32 : 0) + (leafHash ? 37 : 0); - const sigMsgWriter = bufferutils_1.BufferWriter.withCapacity(sigMsgSize); + const sigMsgWriter = bufferutils_js_1.BufferWriter.withCapacity(sigMsgSize); sigMsgWriter.writeUInt8(hashType); // Transaction sigMsgWriter.writeInt32(this.version); @@ -426,11 +466,11 @@ class Transaction { sigMsgWriter.writeUInt32(inIndex); } if (annex) { - const bufferWriter = bufferutils_1.BufferWriter.withCapacity( + const bufferWriter = bufferutils_js_1.BufferWriter.withCapacity( varSliceSize(annex), ); bufferWriter.writeVarSlice(annex); - sigMsgWriter.writeSlice(bcrypto.sha256(bufferWriter.end())); + sigMsgWriter.writeSlice((0, sha256_1.sha256)(bufferWriter.end())); } // Output if (isSingle) { @@ -446,22 +486,31 @@ class Transaction { // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-19 return bcrypto.taggedHash( 'TapSighash', - Buffer.concat([Buffer.from([0x00]), sigMsgWriter.end()]), + tools.concat([Uint8Array.from([0x00]), sigMsgWriter.end()]), ); } hashForWitnessV0(inIndex, prevOutScript, value, hashType) { - typeforce( - types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), - arguments, + // typeforce( + // types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), + // arguments, + // ); + v.parse( + v.tuple([ + types.UInt32Schema, + types.BufferSchema, + types.SatoshiSchema, + types.UInt32Schema, + ]), + [inIndex, prevOutScript, value, hashType], ); - let tbuffer = Buffer.from([]); + let tbuffer = Uint8Array.from([]); let bufferWriter; let hashOutputs = ZERO; let hashPrevouts = ZERO; let hashSequence = ZERO; if (!(hashType & Transaction.SIGHASH_ANYONECANPAY)) { - tbuffer = Buffer.allocUnsafe(36 * this.ins.length); - bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); + tbuffer = new Uint8Array(36 * this.ins.length); + bufferWriter = new bufferutils_js_1.BufferWriter(tbuffer, 0); this.ins.forEach(txIn => { bufferWriter.writeSlice(txIn.hash); bufferWriter.writeUInt32(txIn.index); @@ -473,8 +522,8 @@ class Transaction { (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && (hashType & 0x1f) !== Transaction.SIGHASH_NONE ) { - tbuffer = Buffer.allocUnsafe(4 * this.ins.length); - bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); + tbuffer = new Uint8Array(4 * this.ins.length); + bufferWriter = new bufferutils_js_1.BufferWriter(tbuffer, 0); this.ins.forEach(txIn => { bufferWriter.writeUInt32(txIn.sequence); }); @@ -487,8 +536,8 @@ class Transaction { const txOutsSize = this.outs.reduce((sum, output) => { return sum + 8 + varSliceSize(output.script); }, 0); - tbuffer = Buffer.allocUnsafe(txOutsSize); - bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); + tbuffer = new Uint8Array(txOutsSize); + bufferWriter = new bufferutils_js_1.BufferWriter(tbuffer, 0); this.outs.forEach(out => { bufferWriter.writeUInt64(out.value); bufferWriter.writeVarSlice(out.script); @@ -499,14 +548,14 @@ class Transaction { inIndex < this.outs.length ) { const output = this.outs[inIndex]; - tbuffer = Buffer.allocUnsafe(8 + varSliceSize(output.script)); - bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); + tbuffer = new Uint8Array(8 + varSliceSize(output.script)); + bufferWriter = new bufferutils_js_1.BufferWriter(tbuffer, 0); bufferWriter.writeUInt64(output.value); bufferWriter.writeVarSlice(output.script); hashOutputs = bcrypto.hash256(tbuffer); } - tbuffer = Buffer.allocUnsafe(156 + varSliceSize(prevOutScript)); - bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0); + tbuffer = new Uint8Array(156 + varSliceSize(prevOutScript)); + bufferWriter = new bufferutils_js_1.BufferWriter(tbuffer, 0); const input = this.ins[inIndex]; bufferWriter.writeInt32(this.version); bufferWriter.writeSlice(hashPrevouts); @@ -523,32 +572,37 @@ class Transaction { } getHash(forWitness) { // wtxid for coinbase is always 32 bytes of 0x00 - if (forWitness && this.isCoinbase()) return Buffer.alloc(32, 0); + if (forWitness && this.isCoinbase()) return new Uint8Array(32); return bcrypto.hash256(this.__toBuffer(undefined, undefined, forWitness)); } getId() { // transaction hash's are displayed in reverse order - return (0, bufferutils_1.reverseBuffer)(this.getHash(false)).toString( - 'hex', + return tools.toHex( + (0, bufferutils_js_1.reverseBuffer)(this.getHash(false)), ); } toBuffer(buffer, initialOffset) { return this.__toBuffer(buffer, initialOffset, true); } toHex() { - return this.toBuffer(undefined, undefined).toString('hex'); + return tools.toHex(this.toBuffer(undefined, undefined)); } setInputScript(index, scriptSig) { - typeforce(types.tuple(types.Number, types.Buffer), arguments); + // typeforce(types.tuple(types.Number, types.Buffer), arguments); + v.parse(v.tuple([v.number(), types.BufferSchema]), [index, scriptSig]); this.ins[index].script = scriptSig; } setWitness(index, witness) { - typeforce(types.tuple(types.Number, [types.Buffer]), arguments); + // typeforce(types.tuple(types.Number, [types.Buffer]), arguments); + v.parse(v.tuple([v.number(), v.array(types.BufferSchema)]), [ + index, + witness, + ]); this.ins[index].witness = witness; } __toBuffer(buffer, initialOffset, _ALLOW_WITNESS = false) { - if (!buffer) buffer = Buffer.allocUnsafe(this.byteLength(_ALLOW_WITNESS)); - const bufferWriter = new bufferutils_1.BufferWriter( + if (!buffer) buffer = new Uint8Array(this.byteLength(_ALLOW_WITNESS)); + const bufferWriter = new bufferutils_js_1.BufferWriter( buffer, initialOffset || 0, ); diff --git a/src/cjs/transaction.d.ts b/src/cjs/transaction.d.ts index 118fa57f1..6f9d61534 100644 --- a/src/cjs/transaction.d.ts +++ b/src/cjs/transaction.d.ts @@ -1,14 +1,13 @@ -/// export interface Output { - script: Buffer; - value: number; + script: Uint8Array; + value: bigint; } export interface Input { - hash: Buffer; + hash: Uint8Array; index: number; - script: Buffer; + script: Uint8Array; sequence: number; - witness: Buffer[]; + witness: Uint8Array[]; } /** * Represents a Bitcoin transaction. @@ -24,16 +23,16 @@ export declare class Transaction { static readonly SIGHASH_INPUT_MASK = 128; static readonly ADVANCED_TRANSACTION_MARKER = 0; static readonly ADVANCED_TRANSACTION_FLAG = 1; - static fromBuffer(buffer: Buffer, _NO_STRICT?: boolean): Transaction; + static fromBuffer(buffer: Uint8Array, _NO_STRICT?: boolean): Transaction; static fromHex(hex: string): Transaction; - static isCoinbaseHash(buffer: Buffer): boolean; + static isCoinbaseHash(buffer: Uint8Array): boolean; version: number; locktime: number; ins: Input[]; outs: Output[]; isCoinbase(): boolean; - addInput(hash: Buffer, index: number, sequence?: number, scriptSig?: Buffer): number; - addOutput(scriptPubKey: Buffer, value: number): number; + addInput(hash: Uint8Array, index: number, sequence?: number, scriptSig?: Uint8Array): number; + addOutput(scriptPubKey: Uint8Array, value: bigint): number; hasWitnesses(): boolean; weight(): number; virtualSize(): number; @@ -47,14 +46,14 @@ export declare class Transaction { * hashType, and then hashes the result. * This hash can then be used to sign the provided transaction input. */ - hashForSignature(inIndex: number, prevOutScript: Buffer, hashType: number): Buffer; - hashForWitnessV1(inIndex: number, prevOutScripts: Buffer[], values: number[], hashType: number, leafHash?: Buffer, annex?: Buffer): Buffer; - hashForWitnessV0(inIndex: number, prevOutScript: Buffer, value: number, hashType: number): Buffer; - getHash(forWitness?: boolean): Buffer; + hashForSignature(inIndex: number, prevOutScript: Uint8Array, hashType: number): Uint8Array; + hashForWitnessV1(inIndex: number, prevOutScripts: Uint8Array[], values: bigint[], hashType: number, leafHash?: Uint8Array, annex?: Uint8Array): Uint8Array; + hashForWitnessV0(inIndex: number, prevOutScript: Uint8Array, value: bigint, hashType: number): Uint8Array; + getHash(forWitness?: boolean): Uint8Array; getId(): string; - toBuffer(buffer?: Buffer, initialOffset?: number): Buffer; + toBuffer(buffer?: Uint8Array, initialOffset?: number): Uint8Array; toHex(): string; - setInputScript(index: number, scriptSig: Buffer): void; - setWitness(index: number, witness: Buffer[]): void; + setInputScript(index: number, scriptSig: Uint8Array): void; + setWitness(index: number, witness: Uint8Array[]): void; private __toBuffer; } diff --git a/src/cjs/types.cjs b/src/cjs/types.cjs new file mode 100644 index 000000000..d83bcaddc --- /dev/null +++ b/src/cjs/types.cjs @@ -0,0 +1,157 @@ +'use strict'; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if ( + !desc || + ('get' in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, 'default', { enumerable: true, value: v }); + } + : function (o, v) { + o['default'] = v; + }); +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k in mod) + if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; + }; +Object.defineProperty(exports, '__esModule', { value: true }); +exports.NullablePartial = + exports.SatoshiSchema = + exports.UInt32Schema = + exports.UInt8Schema = + exports.HexSchema = + exports.BufferSchema = + exports.Hash256bitSchema = + exports.Hash160bitSchema = + exports.Buffer256bitSchema = + exports.TAPLEAF_VERSION_MASK = + exports.NBufferSchemaFactory = + void 0; +exports.stacksEqual = stacksEqual; +exports.isPoint = isPoint; +exports.isTapleaf = isTapleaf; +exports.isTaptree = isTaptree; +const tools = __importStar(require('uint8array-tools')); +const v = __importStar(require('valibot')); +// export const typeforce = require('typeforce'); +const ZERO32 = new Uint8Array(32); +const EC_P = tools.fromHex( + 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', +); +const NBufferSchemaFactory = size => + v.pipe(v.instance(Uint8Array), v.length(size)); +exports.NBufferSchemaFactory = NBufferSchemaFactory; +/** + * Checks if two arrays of Buffers are equal. + * @param a - The first array of Buffers. + * @param b - The second array of Buffers. + * @returns True if the arrays are equal, false otherwise. + */ +function stacksEqual(a, b) { + if (a.length !== b.length) return false; + return a.every((x, i) => { + // return x.equals(b[i]); + return tools.compare(x, b[i]) === 0; + }); +} +/** + * Checks if the given value is a valid elliptic curve point. + * @param p - The value to check. + * @returns True if the value is a valid elliptic curve point, false otherwise. + */ +function isPoint(p) { + if (!(p instanceof Uint8Array)) return false; + if (p.length < 33) return false; + const t = p[0]; + const x = p.slice(1, 33); + // if (x.compare(ZERO32) === 0) return false; + if (tools.compare(ZERO32, x) === 0) return false; + // if (x.compare(EC_P) >= 0) return false; + if (tools.compare(x, 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 (tools.compare(ZERO32, y) === 0) return false; + // if (y.compare(EC_P) >= 0) return false; + if (tools.compare(y, EC_P) >= 0) return false; + if (t === 0x04 && p.length === 65) return true; + return false; +} +exports.TAPLEAF_VERSION_MASK = 0xfe; +function isTapleaf(o) { + if (!o || !('output' in o)) return false; + if (!(o.output instanceof Uint8Array)) return false; + if (o.version !== undefined) + return (o.version & exports.TAPLEAF_VERSION_MASK) === o.version; + return true; +} +function isTaptree(scriptTree) { + if (!Array.isArray(scriptTree)) return isTapleaf(scriptTree); + if (scriptTree.length !== 2) return false; + return scriptTree.every(t => isTaptree(t)); +} +exports.Buffer256bitSchema = (0, exports.NBufferSchemaFactory)(32); +exports.Hash160bitSchema = (0, exports.NBufferSchemaFactory)(20); +exports.Hash256bitSchema = (0, exports.NBufferSchemaFactory)(32); +// export const Number = typeforce.Number; +// export const Array = typeforce.Array; +// export const Boolean = typeforce.Boolean; +// export const String = typeforce.String; +exports.BufferSchema = v.instance(Uint8Array); +exports.HexSchema = v.pipe(v.string(), v.regex(/^([0-9a-f]{2})+$/i)); +exports.UInt8Schema = v.pipe( + v.number(), + v.integer(), + v.minValue(0), + v.maxValue(0xff), +); +exports.UInt32Schema = v.pipe( + v.number(), + v.integer(), + v.minValue(0), + v.maxValue(0xffffffff), +); +exports.SatoshiSchema = v.pipe( + v.bigint(), + v.minValue(0n), + v.maxValue(0x7fffffffffffffffn), +); +const NullablePartial = a => + v.object( + Object.entries(a).reduce( + (acc, next) => ({ ...acc, [next[0]]: v.nullish(next[1]) }), + {}, + ), + ); +exports.NullablePartial = NullablePartial; diff --git a/src/cjs/types.d.ts b/src/cjs/types.d.ts index 31e906a1a..7abcd67bb 100644 --- a/src/cjs/types.d.ts +++ b/src/cjs/types.d.ts @@ -1,25 +1,24 @@ -/// -export declare const typeforce: any; +import * as v from 'valibot'; +export declare const NBufferSchemaFactory: (size: number) => v.SchemaWithPipe<[v.InstanceSchema, v.LengthAction]>; /** * Checks if two arrays of Buffers are equal. * @param a - The first array of Buffers. * @param b - The second array of Buffers. * @returns True if the arrays are equal, false otherwise. */ -export declare function stacksEqual(a: Buffer[], b: Buffer[]): boolean; +export declare function stacksEqual(a: Uint8Array[], b: Uint8Array[]): boolean; /** * Checks if the given value is a valid elliptic curve point. * @param p - The value to check. * @returns True if the value is a valid elliptic curve point, false otherwise. */ -export declare function isPoint(p: Buffer | number | undefined | null): boolean; -export declare function Satoshi(value: number): boolean; +export declare function isPoint(p: Uint8Array | number | undefined | null): boolean; export interface XOnlyPointAddTweakResult { parity: 1 | 0; xOnlyPubkey: Uint8Array; } export interface Tapleaf { - output: Buffer; + output: Uint8Array; version?: number; } export declare const TAPLEAF_VERSION_MASK = 254; @@ -35,20 +34,12 @@ 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; -export declare const Number: any; -export declare const Array: any; -export declare const Boolean: any; -export declare const String: any; -export declare const Buffer: any; -export declare const Hex: any; -export declare const maybe: any; -export declare const tuple: any; -export declare const UInt8: any; -export declare const UInt32: any; -export declare const Function: any; -export declare const BufferN: any; -export declare const Null: any; -export declare const oneOf: any; +export declare const Buffer256bitSchema: v.SchemaWithPipe<[v.InstanceSchema, v.LengthAction]>; +export declare const Hash160bitSchema: v.SchemaWithPipe<[v.InstanceSchema, v.LengthAction]>; +export declare const Hash256bitSchema: v.SchemaWithPipe<[v.InstanceSchema, v.LengthAction]>; +export declare const BufferSchema: v.InstanceSchema; +export declare const HexSchema: v.SchemaWithPipe<[v.StringSchema, v.RegexAction]>; +export declare const UInt8Schema: v.SchemaWithPipe<[v.NumberSchema, v.IntegerAction, v.MinValueAction, v.MaxValueAction]>; +export declare const UInt32Schema: v.SchemaWithPipe<[v.NumberSchema, v.IntegerAction, v.MinValueAction, v.MaxValueAction]>; +export declare const SatoshiSchema: v.SchemaWithPipe<[v.BigintSchema, v.MinValueAction, v.MaxValueAction]>; +export declare const NullablePartial: (a: Record) => v.ObjectSchema<{}, undefined>; diff --git a/src/cjs/types.js b/src/cjs/types.js deleted file mode 100644 index bcebef356..000000000 --- a/src/cjs/types.js +++ /dev/null @@ -1,106 +0,0 @@ -'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.Satoshi = - exports.isPoint = - exports.stacksEqual = - exports.typeforce = - void 0; -const buffer_1 = require('buffer'); -exports.typeforce = require('typeforce'); -const ZERO32 = buffer_1.Buffer.alloc(32, 0); -const EC_P = buffer_1.Buffer.from( - 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', - 'hex', -); -/** - * Checks if two arrays of Buffers are equal. - * @param a - The first array of Buffers. - * @param b - The second array of Buffers. - * @returns True if the arrays are equal, false otherwise. - */ -function stacksEqual(a, b) { - if (a.length !== b.length) return false; - return a.every((x, i) => { - return x.equals(b[i]); - }); -} -exports.stacksEqual = stacksEqual; -/** - * Checks if the given value is a valid elliptic curve point. - * @param p - The value to check. - * @returns True if the value is a valid elliptic curve point, false otherwise. - */ -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(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(ZERO32) === 0) return false; - if (y.compare(EC_P) >= 0) return false; - if (t === 0x04 && p.length === 65) return true; - return false; -} -exports.isPoint = isPoint; -const SATOSHI_MAX = 21 * 1e14; -function Satoshi(value) { - return exports.typeforce.UInt53(value) && value <= SATOSHI_MAX; -} -exports.Satoshi = Satoshi; -exports.TAPLEAF_VERSION_MASK = 0xfe; -function isTapleaf(o) { - 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; - 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); -exports.Number = exports.typeforce.Number; -exports.Array = exports.typeforce.Array; -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; -exports.tuple = exports.typeforce.tuple; -exports.UInt8 = exports.typeforce.UInt8; -exports.UInt32 = exports.typeforce.UInt32; -exports.Function = exports.typeforce.Function; -exports.BufferN = exports.typeforce.BufferN; -exports.Null = exports.typeforce.Null; -exports.oneOf = exports.typeforce.oneOf; diff --git a/src/esm/address.js b/src/esm/address.js index 7faecedcd..029656ce9 100644 --- a/src/esm/address.js +++ b/src/esm/address.js @@ -1,9 +1,11 @@ -import * as networks from './networks'; -import * as payments from './payments'; -import * as bscript from './script'; -import { typeforce, tuple, Hash160bit, UInt8 } from './types'; +import * as networks from './networks.js'; +import * as payments from './payments/index.js'; +import * as bscript from './script.js'; +import { Hash160bitSchema, UInt8Schema } from './types.js'; import { bech32, bech32m } from 'bech32'; -import * as bs58check from 'bs58check'; +import bs58check from 'bs58check'; +import * as tools from 'uint8array-tools'; +import * as v from 'valibot'; const FUTURE_SEGWIT_MAX_SIZE = 40; const FUTURE_SEGWIT_MIN_SIZE = 2; const FUTURE_SEGWIT_MAX_VERSION = 16; @@ -36,11 +38,12 @@ function _toFutureSegwitAddress(output, network) { * decode address with base58 specification, return address version and address hash if valid */ export function fromBase58Check(address) { - const payload = Buffer.from(bs58check.decode(address)); + const payload = 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 version = tools.readUInt8(payload, 0); const hash = payload.slice(1); return { version, hash }; } @@ -65,17 +68,19 @@ export function fromBech32(address) { return { version, prefix: result.prefix, - data: Buffer.from(data), + data: Uint8Array.from(data), }; } /** * encode address hash to base58 address with version */ export function toBase58Check(hash, version) { - typeforce(tuple(Hash160bit, UInt8), arguments); - const payload = Buffer.allocUnsafe(21); - payload.writeUInt8(version, 0); - hash.copy(payload, 1); + v.parse(v.tuple([Hash160bitSchema, UInt8Schema]), [hash, version]); + const payload = new Uint8Array(21); + // payload.writeUInt8(version, 0); + tools.writeUInt8(payload, 0, version); + // hash.copy(payload, 1); + payload.set(hash, 1); return bs58check.encode(payload); } /** diff --git a/src/esm/bip66.js b/src/esm/bip66.js index c7a3a2269..6ef5246d5 100644 --- a/src/esm/bip66.js +++ b/src/esm/bip66.js @@ -82,15 +82,17 @@ export function encode(r, s) { throw new Error('R value excessively padded'); if (lenS > 1 && s[0] === 0x00 && !(s[1] & 0x80)) throw new Error('S value excessively padded'); - const signature = Buffer.allocUnsafe(6 + lenR + lenS); + const signature = new Uint8Array(6 + lenR + lenS); // 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] signature[0] = 0x30; signature[1] = signature.length - 2; signature[2] = 0x02; signature[3] = r.length; - r.copy(signature, 4); + // r.copy(signature, 4); + signature.set(r, 4); signature[4 + lenR] = 0x02; signature[5 + lenR] = s.length; - s.copy(signature, 6 + lenR); + // s.copy(signature, 6 + lenR); + signature.set(s, 6 + lenR); return signature; } diff --git a/src/esm/block.js b/src/esm/block.js index fe01cdf22..54c8f7c85 100644 --- a/src/esm/block.js +++ b/src/esm/block.js @@ -3,12 +3,13 @@ import { BufferWriter, reverseBuffer, varuint, -} from './bufferutils'; -import * as bcrypto from './crypto'; -import { fastMerkleRoot } from './merkle'; -import { Transaction } from './transaction'; -import * as types from './types'; -const { typeforce } = types; +} from './bufferutils.js'; +import * as bcrypto from './crypto.js'; +import { fastMerkleRoot } from './merkle.js'; +import { Transaction } from './transaction.js'; +import * as v from 'valibot'; +import * as tools from 'uint8array-tools'; +// const { typeforce } = types; const errorMerkleNoTxes = new TypeError( 'Cannot compute merkle root for zero transactions', ); @@ -47,17 +48,22 @@ export class Block { return block; } static fromHex(hex) { - return Block.fromBuffer(Buffer.from(hex, 'hex')); + // return Block.fromBuffer(Buffer.from(hex, 'hex')); + return Block.fromBuffer(tools.fromHex(hex)); } static calculateTarget(bits) { const exponent = ((bits & 0xff000000) >> 24) - 3; const mantissa = bits & 0x007fffff; - const target = Buffer.alloc(32, 0); - target.writeUIntBE(mantissa, 29 - exponent, 3); + const target = new Uint8Array(32); + // target.writeUIntBE(mantissa, 29 - exponent, 3); + target[29 - exponent] = (mantissa >> 16) & 0xff; + target[30 - exponent] = (mantissa >> 8) & 0xff; + target[31 - exponent] = mantissa & 0xff; return target; } static calculateMerkleRoot(transactions, forWitness) { - typeforce([{ getHash: types.Function }], transactions); + // typeforce([{ getHash: types.Function }], transactions); + v.parse(v.array(v.object({ getHash: v.function() })), transactions); if (transactions.length === 0) throw errorMerkleNoTxes; if (forWitness && !txesHaveWitnessCommit(transactions)) throw errorWitnessNotSegwit; @@ -67,7 +73,7 @@ export class Block { const rootHash = fastMerkleRoot(hashes, bcrypto.hash256); return forWitness ? bcrypto.hash256( - Buffer.concat([rootHash, transactions[0].ins[0].witness[0]]), + tools.concat([rootHash, transactions[0].ins[0].witness[0]]), ) : rootHash; } @@ -86,19 +92,24 @@ export class Block { // The root is prepended with 0xaa21a9ed so check for 0x6a24aa21a9ed // If multiple commits are found, the output with highest index is assumed. const witnessCommits = this.transactions[0].outs - .filter(out => - out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex')), + .filter( + out => + // out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex')), + tools.compare( + out.script.slice(0, 6), + Uint8Array.from([0x6a, 0x24, 0xaa, 0x21, 0xa9, 0xed]), + ) === 0, ) .map(out => out.script.slice(6, 38)); if (witnessCommits.length === 0) return null; // Use the commit with the highest output (should only be one though) const result = witnessCommits[witnessCommits.length - 1]; - if (!(result instanceof Buffer && result.length === 32)) return null; + if (!(result instanceof Uint8Array && result.length === 32)) return null; return result; } hasWitnessCommit() { if ( - this.witnessCommit instanceof Buffer && + this.witnessCommit instanceof Uint8Array && this.witnessCommit.length === 32 ) return true; @@ -125,7 +136,7 @@ export class Block { return bcrypto.hash256(this.toBuffer(true)); } getId() { - return reverseBuffer(this.getHash()).toString('hex'); + return tools.toHex(reverseBuffer(this.getHash())); } getUTCDate() { const date = new Date(0); // epoch @@ -134,7 +145,7 @@ export class Block { } // TODO: buffer, offset compatibility toBuffer(headersOnly) { - const buffer = Buffer.allocUnsafe(this.byteLength(headersOnly)); + const buffer = new Uint8Array(this.byteLength(headersOnly)); const bufferWriter = new BufferWriter(buffer); bufferWriter.writeInt32(this.version); bufferWriter.writeSlice(this.prevHash); @@ -157,7 +168,7 @@ export class Block { return buffer; } toHex(headersOnly) { - return this.toBuffer(headersOnly).toString('hex'); + return tools.toHex(this.toBuffer(headersOnly)); } checkTxRoots() { // If the Block has segwit transactions but no witness commit, @@ -172,12 +183,14 @@ export class Block { checkProofOfWork() { const hash = reverseBuffer(this.getHash()); const target = Block.calculateTarget(this.bits); - return hash.compare(target) <= 0; + // return hash.compare(target) <= 0; + return tools.compare(hash, target) <= 0; } __checkMerkleRoot() { if (!this.transactions) throw errorMerkleNoTxes; const actualMerkleRoot = Block.calculateMerkleRoot(this.transactions); - return this.merkleRoot.compare(actualMerkleRoot) === 0; + // return this.merkleRoot!.compare(actualMerkleRoot) === 0; + return tools.compare(this.merkleRoot, actualMerkleRoot) === 0; } __checkWitnessCommit() { if (!this.transactions) throw errorMerkleNoTxes; @@ -186,7 +199,8 @@ export class Block { this.transactions, true, ); - return this.witnessCommit.compare(actualWitnessCommit) === 0; + // return this.witnessCommit!.compare(actualWitnessCommit) === 0; + return tools.compare(this.witnessCommit, actualWitnessCommit) === 0; } } function txesHaveWitnessCommit(transactions) { diff --git a/src/esm/bufferutils.js b/src/esm/bufferutils.js index ea23cc490..ff90e8647 100644 --- a/src/esm/bufferutils.js +++ b/src/esm/bufferutils.js @@ -1,7 +1,8 @@ -import * as types from './types'; -const { typeforce } = types; +import * as types from './types.js'; import * as varuint from 'varuint-bitcoin'; +import * as v from 'valibot'; export { varuint }; +import * as tools from 'uint8array-tools'; const MAX_JS_NUMBER = 0x001fffffffffffff; // https://github.com/feross/buffer/blob/master/index.js#L1127 function verifuint(value, max) { @@ -14,13 +15,13 @@ function verifuint(value, max) { if (Math.floor(Number(value)) !== Number(value)) throw new Error('value has a fractional component'); } -export function readUInt64LE(buffer, offset) { - const a = buffer.readUInt32LE(offset); - let b = buffer.readUInt32LE(offset + 4); - b *= 0x100000000; - verifuint(b + a, MAX_JS_NUMBER); - return b + a; -} +// export function readUInt64LE(buffer: Buffer, offset: number): number { +// const a = buffer.readUInt32LE(offset); +// let b = buffer.readUInt32LE(offset + 4); +// b *= 0x100000000; +// verifuint(b + a, MAX_JS_NUMBER); +// return b + a; +// } /** * Writes a 64-bit unsigned integer in little-endian format to the specified buffer at the given offset. * @@ -29,12 +30,39 @@ export function readUInt64LE(buffer, offset) { * @param offset - The offset in the buffer where the value should be written. * @returns The new offset after writing the value. */ -export function writeUInt64LE(buffer, value, offset) { - verifuint(value, MAX_JS_NUMBER); - buffer.writeInt32LE(value & -1, offset); - buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4); - return offset + 8; -} +// export function writeUInt64LE( +// buffer: Buffer, +// value: number, +// offset: number, +// ): number { +// verifuint(value, MAX_JS_NUMBER); +// buffer.writeInt32LE(value & -1, offset); +// buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4); +// return offset + 8; +// } +/** + * Reads a 64-bit signed integer from a Uint8Array in little-endian format. + * + * @param {Uint8Array} buffer - The buffer to read the value from. + * @param {number} offset - The offset in the buffer where the value starts. + * @return {number} The 64-bit signed integer value. + */ +// export function readInt64LE( +// buffer: Uint8Array, +// offset: number +// ): number { +// if((buffer[offset + 7] & 0x7f) > 0) throw new Error("RangeError: value out of range, greater than int64"); +// return ( +// buffer[offset] | +// (buffer[offset + 1] << 8) | +// (buffer[offset + 2] << 16) | +// (buffer[offset + 3] << 24) | +// (buffer[offset + 4] << 32) | +// (buffer[offset + 5] << 40) | +// (buffer[offset + 6] << 48) | +// (buffer[offset + 7] << 56) +// ); +// } /** * Reverses the order of bytes in a buffer. * @param buffer - The buffer to reverse. @@ -53,8 +81,8 @@ export function reverseBuffer(buffer) { return buffer; } export function cloneBuffer(buffer) { - const clone = Buffer.allocUnsafe(buffer.length); - buffer.copy(clone); + const clone = new Uint8Array(buffer.length); + clone.set(buffer); return clone; } /** @@ -64,24 +92,35 @@ export class BufferWriter { buffer; offset; static withCapacity(size) { - return new BufferWriter(Buffer.alloc(size)); + return new BufferWriter(new Uint8Array(size)); } constructor(buffer, offset = 0) { this.buffer = buffer; this.offset = offset; - typeforce(types.tuple(types.Buffer, types.UInt32), [buffer, offset]); + // typeforce(types.tuple(types.Buffer, types.UInt32), [buffer, offset]); + v.parse(v.tuple([types.BufferSchema, types.UInt32Schema]), [ + buffer, + offset, + ]); } writeUInt8(i) { - this.offset = this.buffer.writeUInt8(i, this.offset); + // this.offset = this.buffer.writeUInt8(i, this.offset); + this.offset = tools.writeUInt8(this.buffer, this.offset, i); } writeInt32(i) { - this.offset = this.buffer.writeInt32LE(i, this.offset); + // this.offset = this.buffer.writeInt32LE(i, this.offset); + this.offset = tools.writeInt32(this.buffer, i, this.offset, 'LE'); + } + writeInt64(i) { + this.offset = tools.writeInt64(this.buffer, BigInt(i), this.offset, 'LE'); } writeUInt32(i) { - this.offset = this.buffer.writeUInt32LE(i, this.offset); + // this.offset = this.buffer.writeUInt32LE(i, this.offset); + this.offset = tools.writeUInt32(this.buffer, this.offset, i, 'LE'); } writeUInt64(i) { - this.offset = writeUInt64LE(this.buffer, i, this.offset); + // this.offset = writeUInt64LE(this.buffer, i, this.offset); + this.offset = tools.writeUInt64(this.buffer, this.offset, BigInt(i), 'LE'); } writeVarInt(i) { const { bytes } = varuint.encode(i, this.buffer, this.offset); @@ -91,7 +130,9 @@ export class BufferWriter { if (this.buffer.length < this.offset + slice.length) { throw new Error('Cannot write slice out of bounds'); } - this.offset += slice.copy(this.buffer, this.offset); + // this.offset += slice.copy(this.buffer, this.offset); + this.buffer.set(slice, this.offset); + this.offset += slice.length; } writeVarSlice(slice) { this.writeVarInt(slice.length); @@ -117,25 +158,33 @@ export class BufferReader { constructor(buffer, offset = 0) { this.buffer = buffer; this.offset = offset; - typeforce(types.tuple(types.Buffer, types.UInt32), [buffer, offset]); + // typeforce(types.tuple(types.Buffer, types.UInt32), [buffer, offset]); + v.parse(v.tuple([types.BufferSchema, types.UInt32Schema]), [ + buffer, + offset, + ]); } readUInt8() { - const result = this.buffer.readUInt8(this.offset); + // const result = this.buffer.readUInt8(this.offset); + const result = tools.readUInt8(this.buffer, this.offset); this.offset++; return result; } readInt32() { - const result = this.buffer.readInt32LE(this.offset); + // const result = readInt32LE(this.buffer, this.offset); + const result = tools.readInt32(this.buffer, this.offset, 'LE'); this.offset += 4; return result; } readUInt32() { - const result = this.buffer.readUInt32LE(this.offset); + // const result = this.buffer.readUInt32LE(this.offset); + const result = tools.readUInt32(this.buffer, this.offset, 'LE'); this.offset += 4; return result; } readUInt64() { - const result = readUInt64LE(this.buffer, this.offset); + // const result = readUInt64LE(this.buffer, this.offset); + const result = tools.readUInt64(this.buffer, this.offset, 'LE'); this.offset += 8; return result; } diff --git a/src/esm/crypto.js b/src/esm/crypto.js index 211891cef..88705eb63 100644 --- a/src/esm/crypto.js +++ b/src/esm/crypto.js @@ -4,23 +4,14 @@ * * @packageDocumentation */ -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) { - return Buffer.from(_ripemd160(Uint8Array.from(buffer))); -} -export function sha1(buffer) { - return Buffer.from(_sha1(Uint8Array.from(buffer))); -} -export function sha256(buffer) { - return Buffer.from(_sha256(Uint8Array.from(buffer))); -} +import { ripemd160 } from '@noble/hashes/ripemd160'; +import { sha256 } from '@noble/hashes/sha256'; +import * as tools from 'uint8array-tools'; export function hash160(buffer) { - return Buffer.from(_ripemd160(_sha256(Uint8Array.from(buffer)))); + return ripemd160(sha256(buffer)); } export function hash256(buffer) { - return Buffer.from(_sha256(_sha256(Uint8Array.from(buffer)))); + return sha256(sha256(buffer)); } export const TAGS = [ 'BIP0340/challenge', @@ -38,55 +29,55 @@ export const TAGS = [ * Defines the tagged hash prefixes used in the crypto module. */ export const TAGGED_HASH_PREFIXES = { - 'BIP0340/challenge': Buffer.from([ + 'BIP0340/challenge': Uint8Array.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([ + 'BIP0340/aux': Uint8Array.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([ + 'BIP0340/nonce': Uint8Array.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([ + TapLeaf: Uint8Array.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([ + TapBranch: Uint8Array.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([ + TapSighash: Uint8Array.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([ + TapTweak: Uint8Array.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([ + 'KeyAgg list': Uint8Array.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([ + 'KeyAgg coefficient': Uint8Array.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, @@ -94,5 +85,5 @@ export const TAGGED_HASH_PREFIXES = { ]), }; export function taggedHash(prefix, data) { - return sha256(Buffer.concat([TAGGED_HASH_PREFIXES[prefix], data])); + return sha256(tools.concat([TAGGED_HASH_PREFIXES[prefix], data])); } diff --git a/src/esm/ecc_lib.js b/src/esm/ecc_lib.js index b02701594..0f965604c 100644 --- a/src/esm/ecc_lib.js +++ b/src/esm/ecc_lib.js @@ -1,3 +1,4 @@ +import * as tools from 'uint8array-tools'; const _ECCLIB_CACHE = {}; /** * Initializes the ECC library with the provided instance. @@ -30,7 +31,7 @@ export function getEccLib() { ); return _ECCLIB_CACHE.eccLib; } -const h = hex => Buffer.from(hex, 'hex'); +const h = hex => tools.fromHex(hex); /** * Verifies the ECC functionality. * @@ -76,7 +77,7 @@ function verifyEcc(ecc) { } else { assert(r !== null); assert(r.parity === t.parity); - assert(Buffer.from(r.xOnlyPubkey).equals(h(t.result))); + assert(tools.compare(r.xOnlyPubkey, h(t.result)) === 0); } }); } diff --git a/src/esm/index.js b/src/esm/index.js index 44660a3aa..fccfcb1d1 100644 --- a/src/esm/index.js +++ b/src/esm/index.js @@ -1,12 +1,12 @@ -import * as address from './address'; -import * as crypto from './crypto'; -import * as networks from './networks'; -import * as payments from './payments'; -import * as script from './script'; +import * as address from './address.js'; +import * as crypto from './crypto.js'; +import * as networks from './networks.js'; +import * as payments from './payments/index.js'; +import * as script from './script.js'; export { address, crypto, networks, payments, script }; -export { Block } from './block'; -export { Psbt } from './psbt'; +export { Block } from './block.js'; +export { Psbt } from './psbt.js'; /** @hidden */ -export { OPS as opcodes } from './ops'; -export { Transaction } from './transaction'; -export { initEccLib } from './ecc_lib'; +export { OPS as opcodes } from './ops.js'; +export { Transaction } from './transaction.js'; +export { initEccLib } from './ecc_lib.js'; diff --git a/src/esm/merkle.js b/src/esm/merkle.js index 701a28acd..0a67870c0 100644 --- a/src/esm/merkle.js +++ b/src/esm/merkle.js @@ -1,3 +1,4 @@ +import * as tools from 'uint8array-tools'; /** * Calculates the Merkle root of an array of buffers using a specified digest function. * @@ -17,7 +18,7 @@ export function fastMerkleRoot(values, digestFn) { for (let i = 0; i < length; i += 2, ++j) { const left = results[i]; const right = i + 1 === length ? left : results[i + 1]; - const data = Buffer.concat([left, right]); + const data = tools.concat([left, right]); results[j] = digestFn(data); } length = j; diff --git a/src/esm/payments/bip341.js b/src/esm/payments/bip341.js index 489b7c3eb..810b494d2 100644 --- a/src/esm/payments/bip341.js +++ b/src/esm/payments/bip341.js @@ -1,8 +1,9 @@ -import { Buffer as NBuffer } from 'buffer'; -import { getEccLib } from '../ecc_lib'; -import * as bcrypto from '../crypto'; -import { varuint } from '../bufferutils'; -import { isTapleaf } from '../types'; +// import { Buffer as NBuffer } from 'buffer'; +import { getEccLib } from '../ecc_lib.js'; +import * as bcrypto from '../crypto.js'; +import { varuint } from '../bufferutils.js'; +import { isTapleaf } from '../types.js'; +import * as tools from 'uint8array-tools'; export const LEAF_VERSION_TAPSCRIPT = 0xc0; export const MAX_TAPTREE_DEPTH = 128; const isHashBranch = ht => 'left' in ht && 'right' in ht; @@ -22,7 +23,8 @@ export function rootHashFromPath(controlBlock, leafHash) { 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) { + // if (kj.compare(ej) < 0) { + if (tools.compare(kj, ej) < 0) { kj = tapBranchHash(kj, ej); } else { kj = tapBranchHash(ej, kj); @@ -37,7 +39,8 @@ export function rootHashFromPath(controlBlock, leafHash) { export function toHashTree(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)); + // hashes.sort((a, b) => a.hash.compare(b.hash)); + hashes.sort((a, b) => tools.compare(a.hash, b.hash)); const [left, right] = hashes; return { hash: tapBranchHash(left.hash, right.hash), @@ -59,7 +62,8 @@ export function findScriptPath(node, 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)) { + // } else if (node.hash.equals(hash)) { + } else if (tools.compare(node.hash, hash) === 0) { return []; } return undefined; @@ -68,17 +72,17 @@ export function tapleafHash(leaf) { const version = leaf.version || LEAF_VERSION_TAPSCRIPT; return bcrypto.taggedHash( 'TapLeaf', - NBuffer.concat([NBuffer.from([version]), serializeScript(leaf.output)]), + tools.concat([Uint8Array.from([version]), serializeScript(leaf.output)]), ); } export function tapTweakHash(pubKey, h) { return bcrypto.taggedHash( 'TapTweak', - NBuffer.concat(h ? [pubKey, h] : [pubKey]), + tools.concat(h ? [pubKey, h] : [pubKey]), ); } export function tweakKey(pubKey, h) { - if (!NBuffer.isBuffer(pubKey)) return null; + if (!(pubKey instanceof Uint8Array)) return null; if (pubKey.length !== 32) return null; if (h && h.length !== 32) return null; const tweakHash = tapTweakHash(pubKey, h); @@ -86,16 +90,17 @@ export function tweakKey(pubKey, h) { if (!res || res.xOnlyPubkey === null) return null; return { parity: res.parity, - x: NBuffer.from(res.xOnlyPubkey), + x: Uint8Array.from(res.xOnlyPubkey), }; } function tapBranchHash(a, b) { - return bcrypto.taggedHash('TapBranch', NBuffer.concat([a, b])); + return bcrypto.taggedHash('TapBranch', tools.concat([a, b])); } function serializeScript(s) { /* global BigInt */ const varintLen = varuint.encodingLength(s.length); - const buffer = NBuffer.allocUnsafe(varintLen); // better + // const buffer = NBuffer.allocUnsafe(varintLen); // better + const buffer = new Uint8Array(varintLen); varuint.encode(s.length, buffer); - return NBuffer.concat([buffer, s]); + return tools.concat([buffer, s]); } diff --git a/src/esm/payments/embed.js b/src/esm/payments/embed.js index 00084fa1e..e8c581c8d 100644 --- a/src/esm/payments/embed.js +++ b/src/esm/payments/embed.js @@ -1,7 +1,8 @@ -import { bitcoin as BITCOIN_NETWORK } from '../networks'; -import * as bscript from '../script'; -import { typeforce as typef, stacksEqual } from '../types'; -import * as lazy from './lazy'; +import { bitcoin as BITCOIN_NETWORK } from '../networks.js'; +import * as bscript from '../script.js'; +import { stacksEqual, BufferSchema } from '../types.js'; +import * as lazy from './lazy.js'; +import * as v from 'valibot'; const OPS = bscript.OPS; // output: OP_RETURN ... /** @@ -14,12 +15,22 @@ const OPS = bscript.OPS; export function p2data(a, opts) { if (!a.data && !a.output) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - typef( - { - network: typef.maybe(typef.Object), - output: typef.maybe(typef.Buffer), - data: typef.maybe(typef.arrayOf(typef.Buffer)), - }, + // typef( + // { + // network: typef.maybe(typef.Object), + // output: typef.maybe(typef.Buffer), + // data: typef.maybe(typef.arrayOf(typef.Buffer)), + // }, + // a, + // ); + v.parse( + v.partial( + v.object({ + network: v.object({}), + output: BufferSchema, + data: v.array(BufferSchema), + }), + ), a, ); const network = a.network || BITCOIN_NETWORK; @@ -37,7 +48,7 @@ export function p2data(a, opts) { if (a.output) { const chunks = bscript.decompile(a.output); if (chunks[0] !== OPS.OP_RETURN) throw new TypeError('Output is invalid'); - if (!chunks.slice(1).every(typef.Buffer)) + if (!chunks.slice(1).every(chunk => v.is(BufferSchema, chunk))) throw new TypeError('Output is invalid'); if (a.data && !stacksEqual(a.data, o.data)) throw new TypeError('Data mismatch'); diff --git a/src/esm/payments/index.js b/src/esm/payments/index.js index e2436ce68..3c2fd1e5e 100644 --- a/src/esm/payments/index.js +++ b/src/esm/payments/index.js @@ -1,11 +1,11 @@ -import { p2data as embed } from './embed'; -import { p2ms } from './p2ms'; -import { p2pk } from './p2pk'; -import { p2pkh } from './p2pkh'; -import { p2sh } from './p2sh'; -import { p2wpkh } from './p2wpkh'; -import { p2wsh } from './p2wsh'; -import { p2tr } from './p2tr'; +import { p2data as embed } from './embed.js'; +import { p2ms } from './p2ms.js'; +import { p2pk } from './p2pk.js'; +import { p2pkh } from './p2pkh.js'; +import { p2sh } from './p2sh.js'; +import { p2wpkh } from './p2wpkh.js'; +import { p2wsh } from './p2wsh.js'; +import { p2tr } from './p2tr.js'; export { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh, p2tr }; // TODO // witness commitment diff --git a/src/esm/payments/p2ms.js b/src/esm/payments/p2ms.js index c64386738..1f494c24f 100644 --- a/src/esm/payments/p2ms.js +++ b/src/esm/payments/p2ms.js @@ -1,7 +1,8 @@ -import { bitcoin as BITCOIN_NETWORK } from '../networks'; -import * as bscript from '../script'; -import { isPoint, typeforce as typef, stacksEqual } from '../types'; -import * as lazy from './lazy'; +import { bitcoin as BITCOIN_NETWORK } from '../networks.js'; +import * as bscript from '../script.js'; +import { BufferSchema, isPoint, stacksEqual } from '../types.js'; +import * as lazy from './lazy.js'; +import * as v from 'valibot'; const OPS = bscript.OPS; const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1 // input: OP_0 [signatures ...] @@ -28,16 +29,33 @@ export function p2ms(a, opts) { (opts.allowIncomplete && x === OPS.OP_0) !== undefined ); } - typef( - { - network: typef.maybe(typef.Object), - m: typef.maybe(typef.Number), - n: typef.maybe(typef.Number), - output: typef.maybe(typef.Buffer), - pubkeys: typef.maybe(typef.arrayOf(isPoint)), - signatures: typef.maybe(typef.arrayOf(isAcceptableSignature)), - input: typef.maybe(typef.Buffer), - }, + // typef( + // { + // network: typef.maybe(typef.Object), + // m: typef.maybe(typef.Number), + // n: typef.maybe(typef.Number), + // output: typef.maybe(typef.Buffer), + // pubkeys: typef.maybe(typef.arrayOf(isPoint)), + // signatures: typef.maybe(typef.arrayOf(isAcceptableSignature)), + // input: typef.maybe(typef.Buffer), + // }, + // a, + // ); + v.parse( + v.partial( + v.object({ + network: v.object({}), + m: v.number(), + n: v.number(), + output: BufferSchema, + pubkeys: v.array(v.custom(isPoint), 'Received invalid pubkey'), + signatures: v.array( + v.custom(isAcceptableSignature), + 'Expected signature to be of type isAcceptableSignature', + ), + input: BufferSchema, + }), + ), a, ); const network = a.network || BITCOIN_NETWORK; @@ -99,9 +117,13 @@ export function p2ms(a, opts) { if (opts.validate) { if (a.output) { decode(a.output); - if (!typef.Number(chunks[0])) throw new TypeError('Output is invalid'); - if (!typef.Number(chunks[chunks.length - 2])) - throw new TypeError('Output is invalid'); + // if (!typef.Number(chunks[0])) throw new TypeError('Output is invalid'); + v.parse(v.number(), chunks[0], { message: 'Output is invalid' }); + // if (!typef.Number(chunks[chunks.length - 2])) + // throw new TypeError('Output is invalid'); + v.parse(v.number(), chunks[chunks.length - 2], { + message: 'Output is invalid', + }); if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG) throw new TypeError('Output is invalid'); if (o.m <= 0 || o.n > 16 || o.m > o.n || o.n !== chunks.length - 3) diff --git a/src/esm/payments/p2pk.js b/src/esm/payments/p2pk.js index 1560f1cfa..29d95023a 100644 --- a/src/esm/payments/p2pk.js +++ b/src/esm/payments/p2pk.js @@ -1,7 +1,9 @@ -import { bitcoin as BITCOIN_NETWORK } from '../networks'; -import * as bscript from '../script'; -import { isPoint, typeforce as typef } from '../types'; -import * as lazy from './lazy'; +import { bitcoin as BITCOIN_NETWORK } from '../networks.js'; +import * as bscript from '../script.js'; +import { BufferSchema, isPoint } from '../types.js'; +import * as lazy from './lazy.js'; +import * as tools from 'uint8array-tools'; +import * as v from 'valibot'; const OPS = bscript.OPS; // input: {signature} // output: {pubKey} OP_CHECKSIG @@ -17,14 +19,29 @@ export function p2pk(a, opts) { if (!a.input && !a.output && !a.pubkey && !a.input && !a.signature) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - typef( - { - network: typef.maybe(typef.Object), - output: typef.maybe(typef.Buffer), - pubkey: typef.maybe(isPoint), - signature: typef.maybe(bscript.isCanonicalScriptSignature), - input: typef.maybe(typef.Buffer), - }, + // typef( + // { + // network: typef.maybe(typef.Object), + // output: typef.maybe(typef.Buffer), + // pubkey: typef.maybe(isPoint), + // signature: typef.maybe(bscript.isCanonicalScriptSignature), + // input: typef.maybe(typef.Buffer), + // }, + // a, + // ); + v.parse( + v.partial( + v.object({ + network: v.object({}), + output: BufferSchema, + pubkey: v.custom(isPoint, 'invalid pubkey'), + signature: v.custom( + bscript.isCanonicalScriptSignature, + 'Expected signature to be of type isCanonicalScriptSignature', + ), + input: BufferSchema, + }), + ), a, ); const _chunks = lazy.value(() => { @@ -58,11 +75,13 @@ export function p2pk(a, opts) { if (a.output[a.output.length - 1] !== OPS.OP_CHECKSIG) throw new TypeError('Output is invalid'); if (!isPoint(o.pubkey)) throw new TypeError('Output pubkey is invalid'); - if (a.pubkey && !a.pubkey.equals(o.pubkey)) + // if (a.pubkey && !a.pubkey.equals(o.pubkey!)) + if (a.pubkey && tools.compare(a.pubkey, o.pubkey) !== 0) throw new TypeError('Pubkey mismatch'); } if (a.signature) { - if (a.input && !a.input.equals(o.input)) + // if (a.input && !a.input.equals(o.input!)) + if (a.input && tools.compare(a.input, o.input) !== 0) throw new TypeError('Signature mismatch'); } if (a.input) { diff --git a/src/esm/payments/p2pkh.js b/src/esm/payments/p2pkh.js index 9e79dc5ab..ed3b0dd29 100644 --- a/src/esm/payments/p2pkh.js +++ b/src/esm/payments/p2pkh.js @@ -1,9 +1,16 @@ -import * as bcrypto from '../crypto'; -import { bitcoin as BITCOIN_NETWORK } from '../networks'; -import * as bscript from '../script'; -import { isPoint, typeforce as typef } from '../types'; -import * as lazy from './lazy'; -import * as bs58check from 'bs58check'; +import * as bcrypto from '../crypto.js'; +import { bitcoin as BITCOIN_NETWORK } from '../networks.js'; +import * as bscript from '../script.js'; +import { + isPoint, + Hash160bitSchema, + NBufferSchemaFactory, + BufferSchema, +} from '../types.js'; +import * as lazy from './lazy.js'; +import bs58check from 'bs58check'; +import * as tools from 'uint8array-tools'; +import * as v from 'valibot'; const OPS = bscript.OPS; // input: {signature} {pubkey} // output: OP_DUP OP_HASH160 {hash160(pubkey)} OP_EQUALVERIFY OP_CHECKSIG @@ -19,21 +26,36 @@ export function p2pkh(a, opts) { if (!a.address && !a.hash && !a.output && !a.pubkey && !a.input) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - typef( - { - network: typef.maybe(typef.Object), - address: typef.maybe(typef.String), - hash: typef.maybe(typef.BufferN(20)), - output: typef.maybe(typef.BufferN(25)), - pubkey: typef.maybe(isPoint), - signature: typef.maybe(bscript.isCanonicalScriptSignature), - input: typef.maybe(typef.Buffer), - }, + // typef( + // { + // network: typef.maybe(typef.Object), + // address: typef.maybe(typef.String), + // hash: typef.maybe(typef.BufferN(20)), + // output: typef.maybe(typef.BufferN(25)), + // pubkey: typef.maybe(isPoint), + // signature: typef.maybe(bscript.isCanonicalScriptSignature), + // input: typef.maybe(typef.Buffer), + // }, + // a, + // ); + v.parse( + v.partial( + v.object({ + network: v.object({}), + address: v.string(), + hash: Hash160bitSchema, + output: NBufferSchemaFactory(25), + pubkey: v.custom(isPoint), + signature: v.custom(bscript.isCanonicalScriptSignature), + input: BufferSchema, + }), + ), a, ); const _address = lazy.value(() => { - const payload = Buffer.from(bs58check.decode(a.address)); - const version = payload.readUInt8(0); + const payload = bs58check.decode(a.address); + // const version = payload.readUInt8(0); + const version = tools.readUInt8(payload, 0); const hash = payload.slice(1); return { version, hash }; }); @@ -44,9 +66,11 @@ export function p2pkh(a, opts) { const o = { name: 'p2pkh', network }; lazy.prop(o, 'address', () => { if (!o.hash) return; - const payload = Buffer.allocUnsafe(21); - payload.writeUInt8(network.pubKeyHash, 0); - o.hash.copy(payload, 1); + const payload = new Uint8Array(21); + // payload.writeUInt8(network.pubKeyHash, 0); + tools.writeUInt8(payload, 0, network.pubKeyHash); + // o.hash.copy(payload, 1); + payload.set(o.hash, 1); return bs58check.encode(payload); }); lazy.prop(o, 'hash', () => { @@ -83,7 +107,7 @@ export function p2pkh(a, opts) { }); // extended validation if (opts.validate) { - let hash = Buffer.from([]); + let hash = Uint8Array.from([]); if (a.address) { if (_address().version !== network.pubKeyHash) throw new TypeError('Invalid version or Network mismatch'); @@ -91,7 +115,8 @@ export function p2pkh(a, opts) { hash = _address().hash; } if (a.hash) { - if (hash.length > 0 && !hash.equals(a.hash)) + // if (hash.length > 0 && !hash.equals(a.hash)) + if (hash.length > 0 && tools.compare(hash, a.hash) !== 0) throw new TypeError('Hash mismatch'); else hash = a.hash; } @@ -106,13 +131,15 @@ export function p2pkh(a, opts) { ) throw new TypeError('Output is invalid'); const hash2 = a.output.slice(3, 23); - if (hash.length > 0 && !hash.equals(hash2)) + // if (hash.length > 0 && !hash.equals(hash2)) + if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; } if (a.pubkey) { const pkh = bcrypto.hash160(a.pubkey); - if (hash.length > 0 && !hash.equals(pkh)) + // if (hash.length > 0 && !hash.equals(pkh)) + if (hash.length > 0 && tools.compare(hash, pkh) !== 0) throw new TypeError('Hash mismatch'); else hash = pkh; } @@ -122,12 +149,15 @@ export function p2pkh(a, opts) { if (!bscript.isCanonicalScriptSignature(chunks[0])) throw new TypeError('Input has invalid signature'); if (!isPoint(chunks[1])) throw new TypeError('Input has invalid pubkey'); - if (a.signature && !a.signature.equals(chunks[0])) + // if (a.signature && !a.signature.equals(chunks[0])) + if (a.signature && tools.compare(a.signature, chunks[0]) !== 0) throw new TypeError('Signature mismatch'); - if (a.pubkey && !a.pubkey.equals(chunks[1])) + // if (a.pubkey && !a.pubkey.equals(chunks[1] as Buffer)) + if (a.pubkey && tools.compare(a.pubkey, chunks[1]) !== 0) throw new TypeError('Pubkey mismatch'); const pkh = bcrypto.hash160(chunks[1]); - if (hash.length > 0 && !hash.equals(pkh)) + // if (hash.length > 0 && !hash.equals(pkh)) + if (hash.length > 0 && tools.compare(hash, pkh) !== 0) throw new TypeError('Hash mismatch'); } } diff --git a/src/esm/payments/p2sh.js b/src/esm/payments/p2sh.js index f652ab7cb..77b05247f 100644 --- a/src/esm/payments/p2sh.js +++ b/src/esm/payments/p2sh.js @@ -1,9 +1,11 @@ -import * as bcrypto from '../crypto'; -import { bitcoin as BITCOIN_NETWORK } from '../networks'; -import * as bscript from '../script'; -import { typeforce as typef, stacksEqual } from '../types'; -import * as lazy from './lazy'; -import * as bs58check from 'bs58check'; +import * as bcrypto from '../crypto.js'; +import { bitcoin as BITCOIN_NETWORK } from '../networks.js'; +import * as bscript from '../script.js'; +import { BufferSchema, NBufferSchemaFactory, stacksEqual } from '../types.js'; +import * as lazy from './lazy.js'; +import bs58check from 'bs58check'; +import * as tools from 'uint8array-tools'; +import * as v from 'valibot'; const OPS = bscript.OPS; // input: [redeemScriptSig ...] {redeemScript} // witness: @@ -20,21 +22,42 @@ export function p2sh(a, opts) { if (!a.address && !a.hash && !a.output && !a.redeem && !a.input) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - typef( - { - network: typef.maybe(typef.Object), - address: typef.maybe(typef.String), - hash: typef.maybe(typef.BufferN(20)), - output: typef.maybe(typef.BufferN(23)), - redeem: typef.maybe({ - network: typef.maybe(typef.Object), - output: typef.maybe(typef.Buffer), - input: typef.maybe(typef.Buffer), - witness: typef.maybe(typef.arrayOf(typef.Buffer)), + // typef( + // { + // network: typef.maybe(typef.Object), + // address: typef.maybe(typef.String), + // hash: typef.maybe(typef.BufferN(20)), + // output: typef.maybe(typef.BufferN(23)), + // redeem: typef.maybe({ + // network: typef.maybe(typef.Object), + // output: typef.maybe(typef.Buffer), + // input: typef.maybe(typef.Buffer), + // witness: typef.maybe(typef.arrayOf(typef.Buffer)), + // }), + // input: typef.maybe(typef.Buffer), + // witness: typef.maybe(typef.arrayOf(typef.Buffer)), + // }, + // a, + // ); + v.parse( + v.partial( + v.object({ + network: v.object({}), + address: v.string(), + hash: NBufferSchemaFactory(20), + output: NBufferSchemaFactory(23), + redeem: v.partial( + v.object({ + network: v.object({}), + output: BufferSchema, + input: BufferSchema, + witness: v.array(BufferSchema), + }), + ), + input: BufferSchema, + witness: v.array(BufferSchema), }), - input: typef.maybe(typef.Buffer), - witness: typef.maybe(typef.arrayOf(typef.Buffer)), - }, + ), a, ); let network = a.network; @@ -43,8 +66,9 @@ export function p2sh(a, opts) { } const o = { network }; const _address = lazy.value(() => { - const payload = Buffer.from(bs58check.decode(a.address)); - const version = payload.readUInt8(0); + const payload = bs58check.decode(a.address); + // const version = payload.readUInt8(0); + const version = tools.readUInt8(payload, 0); const hash = payload.slice(1); return { version, hash }; }); @@ -56,7 +80,7 @@ export function p2sh(a, opts) { const lastChunk = chunks[chunks.length - 1]; return { network, - output: lastChunk === OPS.OP_FALSE ? Buffer.from([]) : lastChunk, + output: lastChunk === OPS.OP_FALSE ? Uint8Array.from([]) : lastChunk, input: bscript.compile(chunks.slice(0, -1)), witness: a.witness || [], }; @@ -64,9 +88,11 @@ export function p2sh(a, opts) { // output dependents lazy.prop(o, 'address', () => { if (!o.hash) return; - const payload = Buffer.allocUnsafe(21); - payload.writeUInt8(o.network.scriptHash, 0); - o.hash.copy(payload, 1); + const payload = new Uint8Array(21); + // payload.writeUInt8(o.network!.scriptHash, 0); + tools.writeUInt8(payload, 0, o.network.scriptHash); + // o.hash.copy(payload, 1); + payload.set(o.hash, 1); return bs58check.encode(payload); }); lazy.prop(o, 'hash', () => { @@ -101,7 +127,7 @@ export function p2sh(a, opts) { return nameParts.join('-'); }); if (opts.validate) { - let hash = Buffer.from([]); + let hash = Uint8Array.from([]); if (a.address) { if (_address().version !== network.scriptHash) throw new TypeError('Invalid version or Network mismatch'); @@ -109,7 +135,8 @@ export function p2sh(a, opts) { hash = _address().hash; } if (a.hash) { - if (hash.length > 0 && !hash.equals(a.hash)) + // if (hash.length > 0 && !hash.equals(a.hash)) + if (hash.length > 0 && tools.compare(hash, a.hash) !== 0) throw new TypeError('Hash mismatch'); else hash = a.hash; } @@ -122,7 +149,8 @@ export function p2sh(a, opts) { ) throw new TypeError('Output is invalid'); const hash2 = a.output.slice(2, 22); - if (hash.length > 0 && !hash.equals(hash2)) + // if (hash.length > 0 && !hash.equals(hash2)) + if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; } @@ -143,7 +171,8 @@ export function p2sh(a, opts) { ); // match hash against other sources const hash2 = bcrypto.hash160(redeem.output); - if (hash.length > 0 && !hash.equals(hash2)) + // if (hash.length > 0 && !hash.equals(hash2)) + if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; } @@ -163,7 +192,7 @@ export function p2sh(a, opts) { if (a.input) { const chunks = _chunks(); if (!chunks || chunks.length < 1) throw new TypeError('Input too short'); - if (!Buffer.isBuffer(_redeem().output)) + if (!(_redeem().output instanceof Uint8Array)) throw new TypeError('Input is invalid'); checkRedeem(_redeem()); } @@ -172,9 +201,14 @@ export function p2sh(a, opts) { throw new TypeError('Network mismatch'); if (a.input) { const redeem = _redeem(); - if (a.redeem.output && !a.redeem.output.equals(redeem.output)) + // if (a.redeem.output && !a.redeem.output.equals(redeem.output!)) + if ( + a.redeem.output && + tools.compare(a.redeem.output, redeem.output) !== 0 + ) throw new TypeError('Redeem.output mismatch'); - if (a.redeem.input && !a.redeem.input.equals(redeem.input)) + // if (a.redeem.input && !a.redeem.input.equals(redeem.input!)) + if (a.redeem.input && tools.compare(a.redeem.input, redeem.input) !== 0) throw new TypeError('Redeem.input mismatch'); } checkRedeem(a.redeem); diff --git a/src/esm/payments/p2tr.js b/src/esm/payments/p2tr.js index eaa09c562..e647b1725 100644 --- a/src/esm/payments/p2tr.js +++ b/src/esm/payments/p2tr.js @@ -1,13 +1,14 @@ -import { Buffer as NBuffer } from 'buffer'; -import { bitcoin as BITCOIN_NETWORK } from '../networks'; -import * as bscript from '../script'; +// import { Buffer as NBuffer } from 'buffer'; +import { bitcoin as BITCOIN_NETWORK } from '../networks.js'; +import * as bscript from '../script.js'; import { - typeforce as typef, isTaptree, TAPLEAF_VERSION_MASK, stacksEqual, -} from '../types'; -import { getEccLib } from '../ecc_lib'; + NBufferSchemaFactory, + BufferSchema, +} from '../types.js'; +import { getEccLib } from '../ecc_lib.js'; import { toHashTree, rootHashFromPath, @@ -15,10 +16,12 @@ import { tapleafHash, tweakKey, LEAF_VERSION_TAPSCRIPT, -} from './bip341'; -import * as lazy from './lazy'; +} from './bip341.js'; +import * as lazy from './lazy.js'; import { bech32m } from 'bech32'; -import { fromBech32 } from '../address'; +import { fromBech32 } from '../address.js'; +import * as tools from 'uint8array-tools'; +import * as v from 'valibot'; const OPS = bscript.OPS; const TAPROOT_WITNESS_VERSION = 0x01; const ANNEX_PREFIX = 0x50; @@ -40,25 +43,53 @@ export function p2tr(a, opts) { ) 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(typef.anyOf(typef.BufferN(64), typef.BufferN(65))), - witness: typef.maybe(typef.arrayOf(typef.Buffer)), - scriptTree: typef.maybe(isTaptree), - redeem: typef.maybe({ - output: typef.maybe(typef.Buffer), - redeemVersion: typef.maybe(typef.Number), - witness: typef.maybe(typef.arrayOf(typef.Buffer)), + // 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)), // 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))), + // witness: typef.maybe(typef.arrayOf(typef.Buffer)), + // scriptTree: typef.maybe(isTaptree), + // redeem: typef.maybe({ + // 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), + // }, + // a, + // ); + v.parse( + v.partial( + v.object({ + address: v.string(), + input: NBufferSchemaFactory(0), + network: v.object({}), + output: NBufferSchemaFactory(34), + internalPubkey: NBufferSchemaFactory(32), + hash: NBufferSchemaFactory(32), // merkle root hash, the tweak + pubkey: NBufferSchemaFactory(32), // tweaked with `hash` from `internalPubkey` + signature: v.union([ + NBufferSchemaFactory(64), + NBufferSchemaFactory(65), + ]), + witness: v.array(BufferSchema), + scriptTree: v.custom(isTaptree, 'Taptree is not of type isTaptree'), + redeem: v.partial( + v.object({ + output: BufferSchema, // tapleaf script + redeemVersion: v.number(), // tapleaf version + witness: v.array(BufferSchema), + }), + ), + redeemVersion: v.number(), }), - redeemVersion: typef.maybe(typef.Number), - }, + ), a, ); const _address = lazy.value(() => { @@ -158,9 +189,9 @@ export function p2tr(a, opts) { if (!path) return; const outputKey = tweakKey(a.internalPubkey, hashTree.hash); if (!outputKey) return; - const controlBock = NBuffer.concat( + const controlBock = tools.concat( [ - NBuffer.from([o.redeemVersion | outputKey.parity]), + Uint8Array.from([o.redeemVersion | outputKey.parity]), a.internalPubkey, ].concat(path), ); @@ -170,7 +201,7 @@ export function p2tr(a, opts) { }); // extended validation if (opts.validate) { - let pubkey = NBuffer.from([]); + let pubkey = Uint8Array.from([]); if (a.address) { if (network && network.bech32 !== _address().prefix) throw new TypeError('Invalid prefix or Network mismatch'); @@ -181,7 +212,8 @@ export function p2tr(a, opts) { pubkey = _address().data; } if (a.pubkey) { - if (pubkey.length > 0 && !pubkey.equals(a.pubkey)) + // if (pubkey.length > 0 && !pubkey.equals(a.pubkey)) + if (pubkey.length > 0 && tools.compare(pubkey, a.pubkey) !== 0) throw new TypeError('Pubkey mismatch'); else pubkey = a.pubkey; } @@ -192,13 +224,15 @@ export function p2tr(a, opts) { a.output[1] !== 0x20 ) throw new TypeError('Output is invalid'); - if (pubkey.length > 0 && !pubkey.equals(a.output.slice(2))) + // if (pubkey.length > 0 && !pubkey.equals(a.output.slice(2))) + if (pubkey.length > 0 && tools.compare(pubkey, a.output.slice(2)) !== 0) 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)) + // if (pubkey.length > 0 && !pubkey.equals(tweakedKey!.x)) + if (pubkey.length > 0 && tools.compare(pubkey, tweakedKey.x) !== 0) throw new TypeError('Pubkey mismatch'); else pubkey = tweakedKey.x; } @@ -208,7 +242,9 @@ export function p2tr(a, opts) { } const hashTree = _hashTree(); if (a.hash && hashTree) { - if (!a.hash.equals(hashTree.hash)) throw new TypeError('Hash mismatch'); + // if (!a.hash.equals(hashTree.hash)) throw new TypeError('Hash mismatch'); + if (tools.compare(a.hash, hashTree.hash) !== 0) + throw new TypeError('Hash mismatch'); } if (a.redeem && a.redeem.output && hashTree) { const leafHash = tapleafHash({ @@ -229,7 +265,11 @@ export function p2tr(a, opts) { 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)) + // if (o.redeem.output && !a.redeem.output.equals(o.redeem.output)) + if ( + o.redeem.output && + tools.compare(a.redeem.output, o.redeem.output) !== 0 + ) throw new TypeError('Redeem.output and witness mismatch'); } if (a.redeem.witness) { @@ -243,7 +283,8 @@ export function p2tr(a, opts) { if (witness && witness.length) { if (witness.length === 1) { // key spending - if (a.signature && !a.signature.equals(witness[0])) + // if (a.signature && !a.signature.equals(witness[0])) + if (a.signature && tools.compare(a.signature, witness[0]) !== 0) throw new TypeError('Signature mismatch'); } else { // script path spending @@ -262,7 +303,11 @@ export function p2tr(a, opts) { `The script path is too long. Got ${m}, expected max 128.`, ); const internalPubkey = controlBlock.slice(1, 33); - if (a.internalPubkey && !a.internalPubkey.equals(internalPubkey)) + // if (a.internalPubkey && !a.internalPubkey.equals(internalPubkey)) + if ( + a.internalPubkey && + tools.compare(a.internalPubkey, internalPubkey) !== 0 + ) throw new TypeError('Internal pubkey mismatch'); if (!getEccLib().isXOnlyPoint(internalPubkey)) throw new TypeError('Invalid internalPubkey for p2tr witness'); @@ -274,7 +319,8 @@ export function p2tr(a, opts) { if (!outputKey) // todo: needs test data throw new TypeError('Invalid outputKey for p2tr witness'); - if (pubkey.length && !pubkey.equals(outputKey.x)) + // if (pubkey.length && !pubkey.equals(outputKey.x)) + if (pubkey.length && tools.compare(pubkey, outputKey.x) !== 0) throw new TypeError('Pubkey mismatch for p2tr witness'); if (outputKey.parity !== (controlBlock[0] & 1)) throw new Error('Incorrect parity'); diff --git a/src/esm/payments/p2wpkh.js b/src/esm/payments/p2wpkh.js index 4c6a85309..24800e2c6 100644 --- a/src/esm/payments/p2wpkh.js +++ b/src/esm/payments/p2wpkh.js @@ -1,11 +1,13 @@ -import * as bcrypto from '../crypto'; -import { bitcoin as BITCOIN_NETWORK } from '../networks'; -import * as bscript from '../script'; -import { isPoint, typeforce as typef } from '../types'; -import * as lazy from './lazy'; +import * as bcrypto from '../crypto.js'; +import { bitcoin as BITCOIN_NETWORK } from '../networks.js'; +import * as bscript from '../script.js'; +import { BufferSchema, isPoint, NBufferSchemaFactory } from '../types.js'; +import * as lazy from './lazy.js'; import { bech32 } from 'bech32'; +import * as tools from 'uint8array-tools'; +import * as v from 'valibot'; const OPS = bscript.OPS; -const EMPTY_BUFFER = Buffer.alloc(0); +const EMPTY_BUFFER = new Uint8Array(0); // witness: {signature} {pubKey} // input: <> // output: OP_0 {pubKeyHash} @@ -21,17 +23,32 @@ export function p2wpkh(a, opts) { if (!a.address && !a.hash && !a.output && !a.pubkey && !a.witness) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - typef( - { - 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(22)), - pubkey: typef.maybe(isPoint), - signature: typef.maybe(bscript.isCanonicalScriptSignature), - witness: typef.maybe(typef.arrayOf(typef.Buffer)), - }, + // typef( + // { + // 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(22)), + // pubkey: typef.maybe(isPoint), + // signature: typef.maybe(bscript.isCanonicalScriptSignature), + // witness: typef.maybe(typef.arrayOf(typef.Buffer)), + // }, + // a, + // ); + v.parse( + v.partial( + v.object({ + address: v.string(), + hash: NBufferSchemaFactory(20), + input: NBufferSchemaFactory(0), + network: v.object({}), + output: NBufferSchemaFactory(22), + pubkey: v.custom(isPoint, 'Not a valid pubkey'), + signature: v.custom(bscript.isCanonicalScriptSignature), + witness: v.array(BufferSchema), + }), + ), a, ); const _address = lazy.value(() => { @@ -41,7 +58,7 @@ export function p2wpkh(a, opts) { return { version, prefix: result.prefix, - data: Buffer.from(data), + data: Uint8Array.from(data), }; }); const network = a.network || BITCOIN_NETWORK; @@ -81,7 +98,7 @@ export function p2wpkh(a, opts) { }); // extended validation if (opts.validate) { - let hash = Buffer.from([]); + let hash = Uint8Array.from([]); if (a.address) { if (network && network.bech32 !== _address().prefix) throw new TypeError('Invalid prefix or Network mismatch'); @@ -92,7 +109,8 @@ export function p2wpkh(a, opts) { hash = _address().data; } if (a.hash) { - if (hash.length > 0 && !hash.equals(a.hash)) + // if (hash.length > 0 && !hash.equals(a.hash)) + if (hash.length > 0 && tools.compare(hash, a.hash) !== 0) throw new TypeError('Hash mismatch'); else hash = a.hash; } @@ -103,13 +121,15 @@ export function p2wpkh(a, opts) { a.output[1] !== 0x14 ) throw new TypeError('Output is invalid'); - if (hash.length > 0 && !hash.equals(a.output.slice(2))) + // if (hash.length > 0 && !hash.equals(a.output.slice(2))) + if (hash.length > 0 && tools.compare(hash, a.output.slice(2)) !== 0) throw new TypeError('Hash mismatch'); else hash = a.output.slice(2); } if (a.pubkey) { const pkh = bcrypto.hash160(a.pubkey); - if (hash.length > 0 && !hash.equals(pkh)) + // if (hash.length > 0 && !hash.equals(pkh)) + if (hash.length > 0 && tools.compare(hash, pkh) !== 0) throw new TypeError('Hash mismatch'); else hash = pkh; if (!isPoint(a.pubkey) || a.pubkey.length !== 33) @@ -121,12 +141,15 @@ export function p2wpkh(a, opts) { throw new TypeError('Witness has invalid signature'); if (!isPoint(a.witness[1]) || a.witness[1].length !== 33) throw new TypeError('Witness has invalid pubkey'); - if (a.signature && !a.signature.equals(a.witness[0])) + // if (a.signature && !a.signature.equals(a.witness[0])) + if (a.signature && tools.compare(a.signature, a.witness[0]) !== 0) throw new TypeError('Signature mismatch'); - if (a.pubkey && !a.pubkey.equals(a.witness[1])) + // if (a.pubkey && !a.pubkey.equals(a.witness[1])) + if (a.pubkey && tools.compare(a.pubkey, a.witness[1]) !== 0) throw new TypeError('Pubkey mismatch'); const pkh = bcrypto.hash160(a.witness[1]); - if (hash.length > 0 && !hash.equals(pkh)) + // if (hash.length > 0 && !hash.equals(pkh)) + if (hash.length > 0 && tools.compare(hash, pkh) !== 0) throw new TypeError('Hash mismatch'); } } diff --git a/src/esm/payments/p2wsh.js b/src/esm/payments/p2wsh.js index f8b71706c..a3c2b71cc 100644 --- a/src/esm/payments/p2wsh.js +++ b/src/esm/payments/p2wsh.js @@ -1,14 +1,24 @@ -import * as bcrypto from '../crypto'; -import { bitcoin as BITCOIN_NETWORK } from '../networks'; -import * as bscript from '../script'; -import { isPoint, typeforce as typef, stacksEqual } from '../types'; -import * as lazy from './lazy'; +import { sha256 } from '@noble/hashes/sha256'; +import { bitcoin as BITCOIN_NETWORK } from '../networks.js'; +import * as bscript from '../script.js'; +import { + Buffer256bitSchema, + BufferSchema, + isPoint, + NBufferSchemaFactory, + stacksEqual, + NullablePartial, +} from '../types.js'; +import * as lazy from './lazy.js'; import { bech32 } from 'bech32'; +import * as tools from 'uint8array-tools'; +import * as v from 'valibot'; const OPS = bscript.OPS; -const EMPTY_BUFFER = Buffer.alloc(0); +const EMPTY_BUFFER = new Uint8Array(0); function chunkHasUncompressedPubkey(chunk) { if ( - Buffer.isBuffer(chunk) && + // Buffer.isBuffer(chunk) && + chunk instanceof Uint8Array && chunk.length === 65 && chunk[0] === 0x04 && isPoint(chunk) @@ -33,21 +43,38 @@ export function p2wsh(a, opts) { if (!a.address && !a.hash && !a.output && !a.redeem && !a.witness) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - typef( - { - network: typef.maybe(typef.Object), - address: typef.maybe(typef.String), - hash: typef.maybe(typef.BufferN(32)), - output: typef.maybe(typef.BufferN(34)), - redeem: typef.maybe({ - input: typef.maybe(typef.Buffer), - network: typef.maybe(typef.Object), - output: typef.maybe(typef.Buffer), - witness: typef.maybe(typef.arrayOf(typef.Buffer)), + // typef( + // { + // network: typef.maybe(typef.Object), + // address: typef.maybe(typef.String), + // hash: typef.maybe(typef.BufferN(32)), + // output: typef.maybe(typef.BufferN(34)), + // redeem: typef.maybe({ + // input: typef.maybe(typef.Buffer), + // network: typef.maybe(typef.Object), + // output: typef.maybe(typef.Buffer), + // witness: typef.maybe(typef.arrayOf(typef.Buffer)), + // }), + // input: typef.maybe(typef.BufferN(0)), + // witness: typef.maybe(typef.arrayOf(typef.Buffer)), + // }, + // a, + // ); + v.parse( + NullablePartial({ + network: v.object({}), + address: v.string(), + hash: Buffer256bitSchema, + output: NBufferSchemaFactory(34), + redeem: NullablePartial({ + input: BufferSchema, + network: v.object({}), + output: BufferSchema, + witness: v.array(BufferSchema), }), - input: typef.maybe(typef.BufferN(0)), - witness: typef.maybe(typef.arrayOf(typef.Buffer)), - }, + input: NBufferSchemaFactory(0), + witness: v.array(BufferSchema), + }), a, ); const _address = lazy.value(() => { @@ -57,7 +84,7 @@ export function p2wsh(a, opts) { return { version, prefix: result.prefix, - data: Buffer.from(data), + data: Uint8Array.from(data), }; }); const _rchunks = lazy.value(() => { @@ -77,7 +104,7 @@ export function p2wsh(a, opts) { lazy.prop(o, 'hash', () => { if (a.output) return a.output.slice(2); if (a.address) return _address().data; - if (o.redeem && o.redeem.output) return bcrypto.sha256(o.redeem.output); + if (o.redeem && o.redeem.output) return sha256(o.redeem.output); }); lazy.prop(o, 'output', () => { if (!o.hash) return; @@ -123,7 +150,7 @@ export function p2wsh(a, opts) { }); // extended validation if (opts.validate) { - let hash = Buffer.from([]); + let hash = Uint8Array.from([]); if (a.address) { if (_address().prefix !== network.bech32) throw new TypeError('Invalid prefix or Network mismatch'); @@ -134,7 +161,8 @@ export function p2wsh(a, opts) { hash = _address().data; } if (a.hash) { - if (hash.length > 0 && !hash.equals(a.hash)) + // if (hash.length > 0 && !hash.equals(a.hash)) + if (hash.length > 0 && tools.compare(hash, a.hash) !== 0) throw new TypeError('Hash mismatch'); else hash = a.hash; } @@ -146,7 +174,8 @@ export function p2wsh(a, opts) { ) throw new TypeError('Output is invalid'); const hash2 = a.output.slice(2); - if (hash.length > 0 && !hash.equals(hash2)) + // if (hash.length > 0 && !hash.equals(hash2)) + if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; } @@ -175,8 +204,9 @@ export function p2wsh(a, opts) { '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)) + const hash2 = sha256(a.redeem.output); + // if (hash.length > 0 && !hash.equals(hash2)) + if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; } @@ -202,7 +232,12 @@ export function p2wsh(a, opts) { } if (a.witness && a.witness.length > 0) { const wScript = a.witness[a.witness.length - 1]; - if (a.redeem && a.redeem.output && !a.redeem.output.equals(wScript)) + // if (a.redeem && a.redeem.output && !a.redeem.output.equals(wScript)) + if ( + a.redeem && + a.redeem.output && + tools.compare(a.redeem.output, wScript) !== 0 + ) throw new TypeError('Witness and redeem.output mismatch'); if ( a.witness.some(chunkHasUncompressedPubkey) || diff --git a/src/esm/psbt.js b/src/esm/psbt.js index 1167257b9..e82a0139e 100644 --- a/src/esm/psbt.js +++ b/src/esm/psbt.js @@ -1,13 +1,13 @@ import { Psbt as PsbtBase } from 'bip174'; import * as varuint from 'varuint-bitcoin'; -import { checkForInput, checkForOutput } from 'bip174/src/lib/utils'; -import { fromOutputScript, toOutputScript } from './address'; -import { cloneBuffer, reverseBuffer } from './bufferutils'; -import { bitcoin as btcNetwork } from './networks'; -import * as payments from './payments'; -import { tapleafHash } from './payments/bip341'; -import * as bscript from './script'; -import { Transaction } from './transaction'; +import { checkForInput, checkForOutput } from 'bip174'; +import { fromOutputScript, toOutputScript } from './address.js'; +import { cloneBuffer, reverseBuffer } from './bufferutils.js'; +import { bitcoin as btcNetwork } from './networks.js'; +import * as payments from './payments/index.js'; +import { tapleafHash } from './payments/bip341.js'; +import * as bscript from './script.js'; +import { Transaction } from './transaction.js'; import { toXOnly, tapScriptFinalizer, @@ -16,7 +16,7 @@ import { checkTaprootInputFields, checkTaprootOutputFields, checkTaprootInputForSigs, -} from './psbt/bip371'; +} from './psbt/bip371.js'; import { witnessStackToScriptWitness, checkInputForSig, @@ -28,7 +28,8 @@ import { isP2WSHScript, isP2SHScript, isP2TR, -} from './psbt/psbtutils'; +} from './psbt/psbtutils.js'; +import * as tools from 'uint8array-tools'; /** * These are the default arguments for a Psbt instance. */ @@ -85,11 +86,13 @@ const DEFAULT_OPTS = { export class Psbt { data; static fromBase64(data, opts = {}) { - const buffer = Buffer.from(data, 'base64'); + // const buffer = Buffer.from(data, 'base64'); + const buffer = tools.fromBase64(data); return this.fromBuffer(buffer, opts); } static fromHex(data, opts = {}) { - const buffer = Buffer.from(data, 'hex'); + // const buffer = Buffer.from(data, 'hex'); + const buffer = tools.fromHex(data); return this.fromBuffer(buffer, opts); } static fromBuffer(buffer, opts = {}) { @@ -437,7 +440,7 @@ export class Psbt { if (typeof validator !== 'function') throw new Error('Need validator function to validate signatures'); const mySigs = pubkey - ? partialSig.filter(sig => sig.pubkey.equals(pubkey)) + ? partialSig.filter(sig => tools.compare(sig.pubkey, pubkey) === 0) : partialSig; if (mySigs.length < 1) throw new Error('No signatures for this pubkey'); const results = []; @@ -500,7 +503,10 @@ export class Psbt { } if (tapScriptSig) { for (const tapSig of tapScriptSig) { - const tapSigHash = allHashses.find(h => tapSig.pubkey.equals(h.pubkey)); + // const tapSigHash = allHashses.find(h => tapSig.pubkey.equals(h.pubkey)); + const tapSigHash = allHashses.find( + h => tools.compare(h.pubkey, tapSig.pubkey) === 0, + ); if (tapSigHash) { const isValidTapScriptSig = validator( tapSig.pubkey, @@ -689,6 +695,7 @@ export class Psbt { tapLeafHashToSign, allowedSighashTypes = [Transaction.SIGHASH_DEFAULT], ) { + console.log("inside sign taproot input"); const hashesForSig = this.checkTaprootHashesForSig( inputIndex, input, @@ -696,6 +703,7 @@ export class Psbt { tapLeafHashToSign, allowedSighashTypes, ); + console.log("hash: ", tools.toHex(hashesForSig[0].hash)); const tapKeySig = hashesForSig .filter(h => !h.leafHash) .map(h => @@ -714,6 +722,7 @@ export class Psbt { ), leafHash: h.leafHash, })); + console.log("signature", tools.toHex(tapKeySig)); if (tapKeySig) { this.data.updateInput(inputIndex, { tapKeySig }); } @@ -847,9 +856,7 @@ export class Psbt { ); if (!hashesForSig || !hashesForSig.length) throw new Error( - `Can not sign for input #${inputIndex} with the key ${keyPair.publicKey.toString( - 'hex', - )}`, + `Can not sign for input #${inputIndex} with the key ${tools.toHex(keyPair.publicKey)}`, ); return hashesForSig; } @@ -921,7 +928,7 @@ const transactionFromBuffer = buffer => new PsbtTransaction(buffer); */ class PsbtTransaction { tx; - constructor(buffer = Buffer.from([2, 0, 0, 0, 0, 0, 0, 0, 0, 0])) { + constructor(buffer = Uint8Array.from([2, 0, 0, 0, 0, 0, 0, 0, 0, 0])) { this.tx = Transaction.fromBuffer(buffer); checkTxEmpty(this.tx); Object.defineProperty(this, 'tx', { @@ -939,14 +946,15 @@ class PsbtTransaction { if ( input.hash === undefined || input.index === undefined || - (!Buffer.isBuffer(input.hash) && typeof input.hash !== 'string') || + (!(input.hash instanceof Uint8Array) && typeof input.hash !== 'string') || typeof input.index !== 'number' ) { throw new Error('Error adding input.'); } const hash = typeof input.hash === 'string' - ? reverseBuffer(Buffer.from(input.hash, 'hex')) + ? // ? reverseBuffer(Buffer.from(input.hash, 'hex')) + reverseBuffer(tools.fromHex(input.hash)) : input.hash; this.tx.addInput(hash, input.index, input.sequence); } @@ -954,8 +962,8 @@ class PsbtTransaction { if ( output.script === undefined || output.value === undefined || - !Buffer.isBuffer(output.script) || - typeof output.value !== 'number' + !(output.script instanceof Uint8Array) || + typeof output.value !== 'bigint' ) { throw new Error('Error adding output.'); } @@ -990,7 +998,9 @@ function hasSigs(neededSigs, partialSig, pubkeys) { sigs = pubkeys .map(pkey => { const pubkey = compressPubkey(pkey); - return partialSig.find(pSig => pSig.pubkey.equals(pubkey)); + return partialSig.find( + pSig => tools.compare(pSig.pubkey, pubkey) === 0, + ); }) .filter(v => !!v); } else { @@ -1004,8 +1014,11 @@ function isFinalized(input) { } function bip32DerivationIsMine(root) { return d => { - if (!d.masterFingerprint.equals(root.fingerprint)) return false; - if (!root.derivePath(d.path).publicKey.equals(d.pubkey)) return false; + // if (!d.masterFingerprint.equals(root.fingerprint)) return false; + if (tools.compare(root.fingerprint, d.masterFingerprint)) return false; + // if (!root.derivePath(d.path).publicKey.equals(d.pubkey)) return false; + if (tools.compare(root.derivePath(d.path).publicKey, d.pubkey)) + return false; return true; }; } @@ -1055,7 +1068,7 @@ function checkPartialSigSighashes(input) { function checkScriptForPubkey(pubkey, script, action) { if (!pubkeyInScript(pubkey, script)) { throw new Error( - `Can not ${action} for this input with the key ${pubkey.toString('hex')}`, + `Can not ${action} for this input with the key ${tools.toHex(pubkey)}`, ); } } @@ -1078,7 +1091,7 @@ function checkTxForDupeIns(tx, cache) { } function checkTxInputCache(cache, input) { const key = - reverseBuffer(Buffer.from(input.hash)).toString('hex') + ':' + input.index; + tools.toHex(reverseBuffer(Uint8Array.from(input.hash))) + ':' + input.index; if (cache.__TX_IN_CACHE[key]) throw new Error('Duplicate input detected.'); cache.__TX_IN_CACHE[key] = 1; } @@ -1087,7 +1100,8 @@ function scriptCheckerFactory(payment, paymentScriptName) { const redeemScriptOutput = payment({ redeem: { output: redeemScript }, }).output; - if (!scriptPubKey.equals(redeemScriptOutput)) { + // if (!scriptPubKey.equals(redeemScriptOutput)) { + if (tools.compare(scriptPubKey, redeemScriptOutput)) { throw new Error( `${paymentScriptName} for ${ioType} #${inputIndex} doesn't match the scriptPubKey in the prevout`, ); @@ -1200,7 +1214,8 @@ function getHashForSig(inputIndex, input, cache, forValidate, sighashTypes) { const prevoutHash = unsignedTx.ins[inputIndex].hash; const utxoHash = nonWitnessUtxoTx.getHash(); // If a non-witness UTXO is provided, its hash must match the hash specified in the prevout - if (!prevoutHash.equals(utxoHash)) { + // if (!prevoutHash.equals(utxoHash)) { + if (tools.compare(prevoutHash, utxoHash) !== 0) { throw new Error( `Non-witness UTXO hash for input #${inputIndex} doesn't match the hash specified in the prevout`, ); @@ -1245,7 +1260,7 @@ function getHashForSig(inputIndex, input, cache, forValidate, sighashTypes) { ) throw new Error( `Input #${inputIndex} has witnessUtxo but non-segwit script: ` + - `${meaningfulScript.toString('hex')}`, + `${tools.toHex(meaningfulScript)}`, ); if (!forValidate && cache.__UNSAFE_SIGN_NONSEGWIT !== false) console.warn( @@ -1281,8 +1296,8 @@ function getAllTaprootHashesForSig(inputIndex, input, inputs, cache) { const tapScriptPubkeys = input.tapScriptSig.map(tss => tss.pubkey); allPublicKeys.push(...tapScriptPubkeys); } - const allHashes = allPublicKeys.map(pubicKey => - getTaprootHashesForSig(inputIndex, input, inputs, pubicKey, cache), + const allHashes = allPublicKeys.map(publicKey => + getTaprootHashesForSig(inputIndex, input, inputs, publicKey, cache), ); return allHashes.flat(); } @@ -1313,8 +1328,9 @@ function getTaprootHashesForSig( const hashes = []; if (input.tapInternalKey && !tapLeafHashToSign) { const outputKey = - getPrevoutTaprootKey(inputIndex, input, cache) || Buffer.from([]); - if (toXOnly(pubkey).equals(outputKey)) { + getPrevoutTaprootKey(inputIndex, input, cache) || Uint8Array.from([]); + // if (toXOnly(pubkey).equals(outputKey)) { + if (tools.compare(toXOnly(pubkey), outputKey) === 0) { const tapKeyHash = unsignedTx.hashForWitnessV1( inputIndex, signingScripts, @@ -1334,7 +1350,9 @@ function getTaprootHashesForSig( return Object.assign({ hash }, tapLeaf); }) .filter( - tapLeaf => !tapLeafHashToSign || tapLeafHashToSign.equals(tapLeaf.hash), + tapLeaf => + !tapLeafHashToSign || + tools.compare(tapLeafHashToSign, tapLeaf.hash) === 0, ) .map(tapLeaf => { const tapScriptHash = unsignedTx.hashForWitnessV1( @@ -1433,7 +1451,8 @@ function getSignersFromHD(inputIndex, inputs, hdKeyPair) { } const myDerivations = input.bip32Derivation .map(bipDv => { - if (bipDv.masterFingerprint.equals(hdKeyPair.fingerprint)) { + // if (bipDv.masterFingerprint.equals(hdKeyPair.fingerprint)) { + if (tools.compare(bipDv.masterFingerprint, hdKeyPair.fingerprint) === 0) { return bipDv; } else { return; @@ -1447,7 +1466,8 @@ function getSignersFromHD(inputIndex, inputs, hdKeyPair) { } const signers = myDerivations.map(bipDv => { const node = hdKeyPair.derivePath(bipDv.path); - if (!bipDv.pubkey.equals(node.publicKey)) { + // if (!bipDv!.pubkey.equals(node.publicKey)) { + if (tools.compare(bipDv.pubkey, node.publicKey) !== 0) { throw new Error('pubkey did not match bip32Derivation'); } return node; @@ -1462,7 +1482,8 @@ function getSortedSigs(script, partialSig) { // filter partialSig array by pubkey being equal return ( partialSig.filter(ps => { - return ps.pubkey.equals(pk); + // return ps.pubkey.equals(pk); + return tools.compare(ps.pubkey, pk) === 0; })[0] || {} ).signature; // Any pubkey without a match will return undefined @@ -1537,7 +1558,7 @@ function addNonWitnessTxCache(cache, input, inputIndex) { }); } function inputFinalizeGetAmts(inputs, tx, cache, mustFinalize) { - let inputAmount = 0; + let inputAmount = 0n; inputs.forEach((input, idx) => { if (mustFinalize && input.finalScriptSig) tx.ins[idx].script = input.finalScriptSig; @@ -1555,7 +1576,7 @@ function inputFinalizeGetAmts(inputs, tx, cache, mustFinalize) { inputAmount += out.value; } }); - const outputAmount = tx.outs.reduce((total, o) => total + o.value, 0); + const outputAmount = tx.outs.reduce((total, o) => total + o.value, 0n); const fee = inputAmount - outputAmount; if (fee < 0) { throw new Error('Outputs are spending more than Inputs'); @@ -1563,7 +1584,7 @@ function inputFinalizeGetAmts(inputs, tx, cache, mustFinalize) { const bytes = tx.virtualSize(); cache.__FEE = fee; cache.__EXTRACTED_TX = tx; - cache.__FEE_RATE = Math.floor(fee / bytes); + cache.__FEE_RATE = Math.floor(Number(fee / BigInt(bytes))); } function nonWitnessUtxoTxFromCache(cache, input, inputIndex) { const c = cache.__NON_WITNESS_UTXO_TX_CACHE; @@ -1622,7 +1643,8 @@ function redeemFromFinalScriptSig(finalScript) { if (!decomp) return; const lastItem = decomp[decomp.length - 1]; if ( - !Buffer.isBuffer(lastItem) || + // !Buffer.isBuffer(lastItem) || + !(lastItem instanceof Uint8Array) || isPubkeyLike(lastItem) || isSigLike(lastItem) ) @@ -1692,10 +1714,10 @@ function getMeaningfulScript( type: isP2SHP2WSH ? 'p2sh-p2wsh' : isP2SH - ? 'p2sh' - : isP2WSH - ? 'p2wsh' - : 'raw', + ? 'p2sh' + : isP2WSH + ? 'p2wsh' + : 'raw', }; } function checkInvalidP2WSH(script) { diff --git a/src/esm/psbt/bip371.js b/src/esm/psbt/bip371.js index 1e32299d6..34852d388 100644 --- a/src/esm/psbt/bip371.js +++ b/src/esm/psbt/bip371.js @@ -1,19 +1,20 @@ -import { isTapleaf, isTaptree } from '../types'; -import { Transaction } from '../transaction'; +import { isTapleaf, isTaptree } from '../types.js'; +import { Transaction } from '../transaction.js'; import { witnessStackToScriptWitness, pubkeyPositionInScript, isP2TR, -} from './psbtutils'; +} from './psbtutils.js'; import { tweakKey, tapleafHash, rootHashFromPath, LEAF_VERSION_TAPSCRIPT, MAX_TAPTREE_DEPTH, -} from '../payments/bip341'; -import { p2tr } from '../payments'; -import { signatureBlocksAction } from './psbtutils'; +} from '../payments/bip341.js'; +import { p2tr } from '../payments/index.js'; +import * as tools from 'uint8array-tools'; +import { signatureBlocksAction } from './psbtutils.js'; /** * Converts a public key to an X-only public key. * @param pubKey The public key to convert. @@ -52,9 +53,9 @@ export function tapScriptFinalizer(inputIndex, input, tapLeafHashToFinalize) { */ export function serializeTaprootSignature(sig, sighashType) { const sighashTypeByte = sighashType - ? Buffer.from([sighashType]) - : Buffer.from([]); - return Buffer.concat([sig, sighashTypeByte]); + ? Uint8Array.from([sighashType]) + : Uint8Array.from([]); + return tools.concat([sig, sighashTypeByte]); } /** * Checks if a PSBT input is a taproot input. @@ -120,7 +121,8 @@ function checkTaprootScriptPubkey(outputData, newOutputData) { if (tapInternalKey) { const { script: scriptPubkey } = outputData; const script = getTaprootScripPubkey(tapInternalKey, tapTree); - if (scriptPubkey && !scriptPubkey.equals(script)) + // if (scriptPubkey && !scriptPubkey.equals(script)) + if (scriptPubkey && tools.compare(script, scriptPubkey) !== 0) throw new Error('Error adding output. Script or address mismatch.'); } } @@ -153,7 +155,8 @@ export function tweakInternalPubKey(inputIndex, input) { if (!outputKey) throw new Error( `Cannot tweak tap internal key for input #${inputIndex}. Public key: ${ - tapInternalKey && tapInternalKey.toString('hex') + // tapInternalKey && tapInternalKey.toString('hex') + tapInternalKey && tools.toHex(tapInternalKey) }`, ); return outputKey.x; @@ -394,7 +397,8 @@ function isTapLeafInTree(tapLeaf, merkleRoot) { version: tapLeaf.leafVersion, }); const rootHash = rootHashFromPath(tapLeaf.controlBlock, leafHash); - return rootHash.equals(merkleRoot); + // return rootHash.equals(merkleRoot); + return tools.compare(rootHash, merkleRoot) === 0; } /** * Sorts the signatures in the input's tapScriptSig array based on their position in the tapLeaf script. @@ -408,11 +412,14 @@ function sortSignatures(input, tapLeaf) { 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); + return ( + (input.tapScriptSig || []) + // .filter(tss => tss.leafHash.equals(leafHash)) + .filter(tss => tools.compare(tss.leafHash, leafHash) === 0) + .map(tss => addPubkeyPositionInScript(tapLeaf.script, tss)) + .sort((t1, t2) => t2.positionInScript - t1.positionInScript) + .map(t => t.signature) + ); } /** * Adds the position of a public key in a script to a TapScriptSig object. @@ -460,10 +467,13 @@ function canFinalizeLeaf(leaf, tapScriptSig, hash) { output: leaf.script, version: leaf.leafVersion, }); - const whiteListedHash = !hash || hash.equals(leafHash); + // const whiteListedHash = !hash || hash.equals(leafHash); + const whiteListedHash = !hash || tools.compare(leafHash, hash) === 0; return ( whiteListedHash && - tapScriptSig.find(tss => tss.leafHash.equals(leafHash)) !== undefined + // tapScriptSig!.find(tss => tss.leafHash.equals(leafHash)) !== undefined + tapScriptSig.find(tss => tools.compare(tss.leafHash, leafHash) === 0) !== + undefined ); } /** diff --git a/src/esm/psbt/psbtutils.js b/src/esm/psbt/psbtutils.js index 31fb62a8c..a03257ec9 100644 --- a/src/esm/psbt/psbtutils.js +++ b/src/esm/psbt/psbtutils.js @@ -1,8 +1,9 @@ import * as varuint from 'varuint-bitcoin'; -import * as bscript from '../script'; -import { Transaction } from '../transaction'; -import { hash160 } from '../crypto'; -import * as payments from '../payments'; +import * as bscript from '../script.js'; +import { Transaction } from '../transaction.js'; +import { hash160 } from '../crypto.js'; +import * as payments from '../payments/index.js'; +import * as tools from 'uint8array-tools'; /** * Checks if a given payment factory can generate a payment script from a given script. * @param payment The payment factory to check. @@ -31,14 +32,16 @@ export const isP2TR = isPaymentFactory(payments.p2tr); * @returns The script witness as a Buffer. */ export function witnessStackToScriptWitness(witness) { - let buffer = Buffer.allocUnsafe(0); + let buffer = new Uint8Array(0); function writeSlice(slice) { - buffer = Buffer.concat([buffer, Buffer.from(slice)]); + // buffer = Buffer.concat([buffer, Buffer.from(slice)]); + buffer = tools.concat([buffer, slice]); } function writeVarInt(i) { const currentLen = buffer.length; const varintLen = varuint.encodingLength(i); - buffer = Buffer.concat([buffer, Buffer.allocUnsafe(varintLen)]); + // buffer = Buffer.concat([buffer, Buffer.allocUnsafe(varintLen)]); + buffer = tools.concat([buffer, new Uint8Array(varintLen)]); varuint.encode(i, buffer, currentLen); } function writeVarSlice(slice) { @@ -67,9 +70,12 @@ export function pubkeyPositionInScript(pubkey, script) { return decompiled.findIndex(element => { if (typeof element === 'number') return false; return ( - element.equals(pubkey) || - element.equals(pubkeyHash) || - element.equals(pubkeyXOnly) + // element.equals(pubkey) || + // element.equals(pubkeyHash) || + // element.equals(pubkeyXOnly) + tools.compare(pubkey, element) === 0 || + tools.compare(pubkeyHash, element) === 0 || + tools.compare(pubkeyXOnly, element) === 0 ); }); } @@ -159,7 +165,9 @@ function getPsigsFromInputFinalScripts(input) { return scriptItems .concat(witnessItems) .filter(item => { - return Buffer.isBuffer(item) && bscript.isCanonicalScriptSignature(item); + return ( + item instanceof Uint8Array && bscript.isCanonicalScriptSignature(item) + ); }) .map(sig => ({ signature: sig })); } diff --git a/src/esm/push_data.js b/src/esm/push_data.js index 14aee8926..62fabb7d6 100644 --- a/src/esm/push_data.js +++ b/src/esm/push_data.js @@ -1,4 +1,5 @@ -import { OPS } from './ops'; +import { OPS } from './ops.js'; +import * as tools from 'uint8array-tools'; /** * Calculates the encoding length of a number used for push data in Bitcoin transactions. * @param i The number to calculate the encoding length for. @@ -21,19 +22,26 @@ export function encode(buffer, num, offset) { const size = encodingLength(num); // ~6 bit if (size === 1) { - buffer.writeUInt8(num, offset); + // buffer.writeUInt8(num, offset); + tools.writeUInt8(buffer, offset, num); // 8 bit } else if (size === 2) { - buffer.writeUInt8(OPS.OP_PUSHDATA1, offset); - buffer.writeUInt8(num, offset + 1); + // buffer.writeUInt8(OPS.OP_PUSHDATA1, offset); + tools.writeUInt8(buffer, offset, OPS.OP_PUSHDATA1); + // buffer.writeUInt8(num, offset + 1); + tools.writeUInt8(buffer, offset + 1, num); // 16 bit } else if (size === 3) { - buffer.writeUInt8(OPS.OP_PUSHDATA2, offset); - buffer.writeUInt16LE(num, offset + 1); + // buffer.writeUInt8(OPS.OP_PUSHDATA2, offset); + tools.writeUInt8(buffer, offset, OPS.OP_PUSHDATA2); + // buffer.writeUInt16LE(num, offset + 1); + tools.writeUInt16(buffer, offset + 1, num, 'LE'); // 32 bit } else { - buffer.writeUInt8(OPS.OP_PUSHDATA4, offset); - buffer.writeUInt32LE(num, offset + 1); + // buffer.writeUInt8(OPS.OP_PUSHDATA4, offset); + tools.writeUInt8(buffer, offset, OPS.OP_PUSHDATA4); + // buffer.writeUInt32LE(num, offset + 1); + tools.writeUInt32(buffer, offset + 1, num, 'LE'); } return size; } @@ -44,7 +52,8 @@ export function encode(buffer, num, offset) { * @returns An object containing the opcode, number, and size, or null if decoding fails. */ export function decode(buffer, offset) { - const opcode = buffer.readUInt8(offset); + // const opcode = buffer.readUInt8(offset); + const opcode = tools.readUInt8(buffer, offset); let num; let size; // ~6 bit @@ -54,18 +63,21 @@ export function decode(buffer, offset) { // 8 bit } else if (opcode === OPS.OP_PUSHDATA1) { if (offset + 2 > buffer.length) return null; - num = buffer.readUInt8(offset + 1); + // num = buffer.readUInt8(offset + 1); + num = tools.readUInt8(buffer, offset + 1); size = 2; // 16 bit } else if (opcode === OPS.OP_PUSHDATA2) { if (offset + 3 > buffer.length) return null; - num = buffer.readUInt16LE(offset + 1); + // num = buffer.readUInt16LE(offset + 1); + num = tools.readUInt16(buffer, offset + 1, 'LE'); size = 3; // 32 bit } else { if (offset + 5 > buffer.length) return null; if (opcode !== OPS.OP_PUSHDATA4) throw new Error('Unexpected opcode'); - num = buffer.readUInt32LE(offset + 1); + // num = buffer.readUInt32LE(offset + 1); + num = tools.readUInt32(buffer, offset + 1, 'LE'); size = 5; } return { diff --git a/src/esm/script.js b/src/esm/script.js index 7992da950..52b6acdba 100644 --- a/src/esm/script.js +++ b/src/esm/script.js @@ -2,28 +2,31 @@ * Script tools, including decompile, compile, toASM, fromASM, toStack, isCanonicalPubKey, isCanonicalScriptSignature * @packageDocumentation */ -import * as bip66 from './bip66'; -import { OPS, REVERSE_OPS } from './ops'; -import * as pushdata from './push_data'; -import * as scriptNumber from './script_number'; -import * as scriptSignature from './script_signature'; -import * as types from './types'; -const { typeforce } = types; +import * as bip66 from './bip66.js'; +import { OPS, REVERSE_OPS } from './ops.js'; +import * as pushdata from './push_data.js'; +import * as scriptNumber from './script_number.js'; +import * as scriptSignature from './script_signature.js'; +import * as types from './types.js'; +import * as tools from 'uint8array-tools'; +import * as v from 'valibot'; const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1 export { OPS }; +const StackSchema = v.array(v.union([v.instance(Uint8Array), v.number()])); function isOPInt(value) { return ( - types.Number(value) && + v.is(v.number(), value) && (value === OPS.OP_0 || (value >= OPS.OP_1 && value <= OPS.OP_16) || value === OPS.OP_1NEGATE) ); } function isPushOnlyChunk(value) { - return types.Buffer(value) || isOPInt(value); + return v.is(types.BufferSchema, value) || isOPInt(value); } export function isPushOnly(value) { - return types.Array(value) && value.every(isPushOnlyChunk); + // return types.Array(value) && value.every(isPushOnlyChunk); + return v.is(v.pipe(v.any(), v.everyItem(isPushOnlyChunk)), value); } export function countNonPushOnlyOPs(value) { return value.length - value.filter(isPushOnlyChunk).length; @@ -35,13 +38,15 @@ function asMinimalOP(buffer) { if (buffer[0] === 0x81) return OPS.OP_1NEGATE; } function chunksIsBuffer(buf) { - return Buffer.isBuffer(buf); + // return Buffer.isBuffer(buf); + return buf instanceof Uint8Array; } function chunksIsArray(buf) { - return types.Array(buf); + // return types.Array(buf); + return v.is(StackSchema, buf); } function singleChunkIsBuffer(buf) { - return Buffer.isBuffer(buf); + return buf instanceof Uint8Array; } /** * Compiles an array of chunks into a Buffer. @@ -53,7 +58,8 @@ function singleChunkIsBuffer(buf) { export function compile(chunks) { // TODO: remove me if (chunksIsBuffer(chunks)) return chunks; - typeforce(types.Array, chunks); + // typeforce(types.Array, chunks); + v.parse(StackSchema, chunks); const bufferSize = chunks.reduce((accum, chunk) => { // data chunk if (singleChunkIsBuffer(chunk)) { @@ -66,7 +72,7 @@ export function compile(chunks) { // opcode return accum + 1; }, 0.0); - const buffer = Buffer.allocUnsafe(bufferSize); + const buffer = new Uint8Array(bufferSize); let offset = 0; chunks.forEach(chunk => { // data chunk @@ -74,16 +80,19 @@ export function compile(chunks) { // adhere to BIP62.3, minimal push policy const opcode = asMinimalOP(chunk); if (opcode !== undefined) { - buffer.writeUInt8(opcode, offset); + // buffer.writeUInt8(opcode, offset); + tools.writeUInt8(buffer, offset, opcode); offset += 1; return; } offset += pushdata.encode(buffer, chunk.length, offset); - chunk.copy(buffer, offset); + // chunk.copy(buffer, offset); + buffer.set(chunk, offset); offset += chunk.length; // opcode } else { - buffer.writeUInt8(chunk, offset); + // buffer.writeUInt8(chunk, offset); + tools.writeUInt8(buffer, offset, chunk); offset += 1; } }); @@ -93,7 +102,8 @@ export function compile(chunks) { export function decompile(buffer) { // TODO: remove me if (chunksIsArray(buffer)) return buffer; - typeforce(types.Buffer, buffer); + // typeforce(types.Buffer, buffer); + v.parse(types.BufferSchema, buffer); const chunks = []; let i = 0; while (i < buffer.length) { @@ -141,7 +151,7 @@ export function toASM(chunks) { // data? if (singleChunkIsBuffer(chunk)) { const op = asMinimalOP(chunk); - if (op === undefined) return chunk.toString('hex'); + if (op === undefined) return tools.toHex(chunk); chunk = op; } // opcode! @@ -155,14 +165,17 @@ export function toASM(chunks) { * @returns The converted Buffer. */ export function fromASM(asm) { - typeforce(types.String, asm); + // typeforce(types.String, asm); + v.parse(v.string(), asm); return compile( asm.split(' ').map(chunkStr => { // opcode? if (OPS[chunkStr] !== undefined) return OPS[chunkStr]; - typeforce(types.Hex, chunkStr); + // typeforce(types.Hex, chunkStr); + v.parse(types.HexSchema, chunkStr); // data! - return Buffer.from(chunkStr, 'hex'); + // return Buffer.from(chunkStr, 'hex'); + return tools.fromHex(chunkStr); }), ); } @@ -174,10 +187,11 @@ export function fromASM(asm) { */ export function toStack(chunks) { chunks = decompile(chunks); - typeforce(isPushOnly, chunks); + // typeforce(isPushOnly, chunks); + v.parse(v.custom(isPushOnly), chunks); return chunks.map(op => { if (singleChunkIsBuffer(op)) return op; - if (op === OPS.OP_0) return Buffer.allocUnsafe(0); + if (op === OPS.OP_0) return new Uint8Array(0); return scriptNumber.encode(op - OP_INT_BASE); }); } @@ -190,7 +204,7 @@ export function isDefinedHashType(hashType) { return hashTypeMod > 0x00 && hashTypeMod < 0x04; } export function isCanonicalScriptSignature(buffer) { - if (!Buffer.isBuffer(buffer)) return false; + if (!(buffer instanceof Uint8Array)) return false; if (!isDefinedHashType(buffer[buffer.length - 1])) return false; return bip66.check(buffer.slice(0, -1)); } diff --git a/src/esm/script_number.js b/src/esm/script_number.js index 1d8cd34d5..9c89ba4af 100644 --- a/src/esm/script_number.js +++ b/src/esm/script_number.js @@ -1,3 +1,4 @@ +import * as tools from 'uint8array-tools'; /** * Decodes a script number from a buffer. * @@ -22,8 +23,10 @@ export function decode(buffer, maxLength, minimal) { } // 40-bit if (length === 5) { - const a = buffer.readUInt32LE(0); - const b = buffer.readUInt8(4); + // const a = buffer.readUInt32LE(0); + // const b = buffer.readUInt8(4); + const a = tools.readUInt32(buffer, 0, 'LE'); + const b = tools.readUInt8(buffer, 4); if (b & 0x80) return -((b & ~0x80) * 0x100000000 + a); return b * 0x100000000 + a; } @@ -40,32 +43,34 @@ function scriptNumSize(i) { return i > 0x7fffffff ? 5 : i > 0x7fffff - ? 4 - : i > 0x7fff - ? 3 - : i > 0x7f - ? 2 - : i > 0x00 - ? 1 - : 0; + ? 4 + : i > 0x7fff + ? 3 + : i > 0x7f + ? 2 + : i > 0x00 + ? 1 + : 0; } /** - * Encodes a number into a Buffer using a specific format. + * Encodes a number into a Uint8Array using a specific format. * * @param _number - The number to encode. - * @returns The encoded number as a Buffer. + * @returns The encoded number as a Uint8Array. */ export function encode(_number) { let value = Math.abs(_number); const size = scriptNumSize(value); - const buffer = Buffer.allocUnsafe(size); + const buffer = new Uint8Array(size); const negative = _number < 0; for (let i = 0; i < size; ++i) { - buffer.writeUInt8(value & 0xff, i); + // buffer.writeUInt8(value & 0xff, i); + tools.writeUInt8(buffer, i, value & 0xff); value >>= 8; } if (buffer[size - 1] & 0x80) { - buffer.writeUInt8(negative ? 0x80 : 0x00, size - 1); + // buffer.writeUInt8(negative ? 0x80 : 0x00, size - 1); + tools.writeUInt8(buffer, size - 1, negative ? 0x80 : 0x00); } else if (negative) { buffer[size - 1] |= 0x80; } diff --git a/src/esm/script_signature.js b/src/esm/script_signature.js index 8db94dc5a..afc414e13 100644 --- a/src/esm/script_signature.js +++ b/src/esm/script_signature.js @@ -1,8 +1,9 @@ -import * as bip66 from './bip66'; -import { isDefinedHashType } from './script'; -import * as types from './types'; -const { typeforce } = types; -const ZERO = Buffer.alloc(1, 0); +import * as bip66 from './bip66.js'; +import { isDefinedHashType } from './script.js'; +import * as v from 'valibot'; +import * as tools from 'uint8array-tools'; +import { NBufferSchemaFactory, UInt8Schema } from './types.js'; +const ZERO = new Uint8Array(1); /** * Converts a buffer to a DER-encoded buffer. * @param x - The buffer to be converted. @@ -13,7 +14,7 @@ function toDER(x) { while (x[i] === 0) ++i; if (i === x.length) return ZERO; x = x.slice(i); - if (x[0] & 0x80) return Buffer.concat([ZERO, x], 1 + x.length); + if (x[0] & 0x80) return tools.concat([ZERO, x]); return x; } /** @@ -25,9 +26,10 @@ function toDER(x) { */ function fromDER(x) { if (x[0] === 0x00) x = x.slice(1); - const buffer = Buffer.alloc(32, 0); + const buffer = new Uint8Array(32); const bstart = Math.max(0, 32 - x.length); - x.copy(buffer, bstart); + // x.copy(buffer, bstart); + buffer.set(x, bstart); return buffer; } // BIP62: 1 byte hashType flag (only 0x01, 0x02, 0x03, 0x81, 0x82 and 0x83 are allowed) @@ -38,14 +40,15 @@ function fromDER(x) { * @throws Error if the hashType is invalid. */ export function decode(buffer) { - const hashType = buffer.readUInt8(buffer.length - 1); + // const hashType = buffer.readUInt8(buffer.length - 1); + const hashType = tools.readUInt8(buffer, buffer.length - 1); if (!isDefinedHashType(hashType)) { throw new Error('Invalid hashType ' + hashType); } - const decoded = bip66.decode(buffer.slice(0, -1)); + const decoded = bip66.decode(buffer.subarray(0, -1)); const r = fromDER(decoded.r); const s = fromDER(decoded.s); - const signature = Buffer.concat([r, s], 64); + const signature = tools.concat([r, s]); return { signature, hashType }; } /** @@ -56,19 +59,29 @@ export function decode(buffer) { * @throws Error if the hashType is invalid. */ export function encode(signature, hashType) { - typeforce( - { - signature: types.BufferN(64), - hashType: types.UInt8, - }, + // typeforce( + // { + // signature: types.BufferN(64), + // hashType: types.UInt8, + // }, + // { signature, hashType }, + // ); + v.parse( + v.object({ + signature: NBufferSchemaFactory(64), + hashType: UInt8Schema, + }), { signature, hashType }, ); if (!isDefinedHashType(hashType)) { throw new Error('Invalid hashType ' + hashType); } - const hashTypeBuffer = Buffer.allocUnsafe(1); - hashTypeBuffer.writeUInt8(hashType, 0); + // const hashTypeBuffer = Buffer.allocUnsafe(1); + const hashTypeBuffer = new Uint8Array(1); + // hashTypeBuffer.writeUInt8(hashType, 0); + tools.writeUInt8(hashTypeBuffer, 0, hashType); const r = toDER(signature.slice(0, 32)); const s = toDER(signature.slice(32, 64)); - return Buffer.concat([bip66.encode(r, s), hashTypeBuffer]); + // return Buffer.concat([bip66.encode(r, s), hashTypeBuffer]); + return tools.concat([bip66.encode(r, s), hashTypeBuffer]); } diff --git a/src/esm/transaction.js b/src/esm/transaction.js index ade02be31..835a5726a 100644 --- a/src/esm/transaction.js +++ b/src/esm/transaction.js @@ -3,12 +3,14 @@ import { BufferWriter, reverseBuffer, varuint, -} from './bufferutils'; -import * as bcrypto from './crypto'; -import * as bscript from './script'; -import { OPS as opcodes } from './script'; -import * as types from './types'; -const { typeforce } = types; +} from './bufferutils.js'; +import * as bcrypto from './crypto.js'; +import { sha256 } from '@noble/hashes/sha256'; +import * as bscript from './script.js'; +import { OPS as opcodes } from './script.js'; +import * as types from './types.js'; +import * as tools from 'uint8array-tools'; +import * as v from 'valibot'; function varSliceSize(someScript) { const length = someScript.length; return varuint.encodingLength(length) + length; @@ -22,17 +24,24 @@ function vectorSize(someVector) { }, 0) ); } -const EMPTY_BUFFER = Buffer.allocUnsafe(0); +const EMPTY_BUFFER = new Uint8Array(0); const EMPTY_WITNESS = []; -const ZERO = Buffer.from( +// const ZERO: Buffer = Buffer.from( +// '0000000000000000000000000000000000000000000000000000000000000000', +// 'hex', +// ); +const ZERO = tools.fromHex( '0000000000000000000000000000000000000000000000000000000000000000', - 'hex', ); -const ONE = Buffer.from( +// const ONE: Buffer = Buffer.from( +// '0000000000000000000000000000000000000000000000000000000000000001', +// 'hex', +// ); +const ONE = tools.fromHex( '0000000000000000000000000000000000000000000000000000000000000001', - 'hex', ); -const VALUE_UINT64_MAX = Buffer.from('ffffffffffffffff', 'hex'); +// const VALUE_UINT64_MAX: Buffer = Buffer.from('ffffffffffffffff', 'hex'); +const VALUE_UINT64_MAX = tools.fromHex('ffffffffffffffff'); const BLANK_OUTPUT = { script: EMPTY_BUFFER, valueBuffer: VALUE_UINT64_MAX, @@ -101,10 +110,11 @@ export class Transaction { return tx; } static fromHex(hex) { - return Transaction.fromBuffer(Buffer.from(hex, 'hex'), false); + return Transaction.fromBuffer(tools.fromHex(hex), false); } static isCoinbaseHash(buffer) { - typeforce(types.Hash256bit, buffer); + // typeforce(types.Hash256bit, buffer); + v.parse(types.Hash256bitSchema, buffer); for (let i = 0; i < 32; ++i) { if (buffer[i] !== 0) return false; } @@ -120,16 +130,25 @@ export class Transaction { ); } addInput(hash, index, sequence, scriptSig) { - typeforce( - types.tuple( - types.Hash256bit, - types.UInt32, - types.maybe(types.UInt32), - types.maybe(types.Buffer), - ), - arguments, + // typeforce( + // types.tuple( + // types.Hash256bit, + // types.UInt32, + // types.maybe(types.UInt32), + // types.maybe(types.Buffer), + // ), + // arguments, + // ); + v.parse( + v.tuple([ + types.Hash256bitSchema, + types.UInt32Schema, + v.nullable(v.optional(types.UInt32Schema)), + v.nullable(v.optional(types.BufferSchema)), + ]), + [hash, index, sequence, scriptSig], ); - if (types.Null(sequence)) { + if (sequence === undefined || sequence === null) { sequence = Transaction.DEFAULT_SEQUENCE; } // Add the input and return the input's index @@ -144,7 +163,11 @@ export class Transaction { ); } addOutput(scriptPubKey, value) { - typeforce(types.tuple(types.Buffer, types.Satoshi), arguments); + // typeforce(types.tuple(types.Buffer, types.Satoshi), arguments); + v.parse(v.tuple([types.BufferSchema, types.SatoshiSchema]), [ + scriptPubKey, + value, + ]); // Add the output and return the output's index return ( this.outs.push({ @@ -215,10 +238,15 @@ export class Transaction { * This hash can then be used to sign the provided transaction input. */ hashForSignature(inIndex, prevOutScript, hashType) { - typeforce( - types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), - arguments, - ); + // typeforce( + // types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), + // arguments, + // ); + v.parse(v.tuple([types.UInt32Schema, types.BufferSchema, v.number()]), [ + inIndex, + prevOutScript, + hashType, + ]); // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L29 if (inIndex >= this.ins.length) return ONE; // ignore OP_CODESEPARATOR @@ -265,21 +293,31 @@ export class Transaction { txTmp.ins[inIndex].script = ourScript; } // serialize and hash - const buffer = Buffer.allocUnsafe(txTmp.byteLength(false) + 4); - buffer.writeInt32LE(hashType, buffer.length - 4); + const buffer = new Uint8Array(txTmp.byteLength(false) + 4); + // buffer.writeInt32LE(hashType, buffer.length - 4); + tools.writeInt32(buffer, hashType, buffer.length - 4, 'LE'); txTmp.__toBuffer(buffer, 0, false); return bcrypto.hash256(buffer); } hashForWitnessV1(inIndex, prevOutScripts, values, hashType, leafHash, annex) { // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#common-signature-message - typeforce( - types.tuple( - types.UInt32, - typeforce.arrayOf(types.Buffer), - typeforce.arrayOf(types.Satoshi), - types.UInt32, - ), - arguments, + // typeforce( + // types.tuple( + // types.UInt32, + // typeforce.arrayOf(types.Buffer), + // typeforce.arrayOf(types.Satoshi), + // types.UInt32, + // ), + // arguments, + // ); + v.parse( + v.tuple([ + types.UInt32Schema, + v.array(types.BufferSchema), + v.array(types.SatoshiSchema), + types.UInt32Schema, + ]), + [inIndex, prevOutScripts, values, hashType], ); if ( values.length !== this.ins.length || @@ -306,20 +344,20 @@ export class Transaction { bufferWriter.writeSlice(txIn.hash); bufferWriter.writeUInt32(txIn.index); }); - hashPrevouts = bcrypto.sha256(bufferWriter.end()); + hashPrevouts = sha256(bufferWriter.end()); bufferWriter = BufferWriter.withCapacity(8 * this.ins.length); values.forEach(value => bufferWriter.writeUInt64(value)); - hashAmounts = bcrypto.sha256(bufferWriter.end()); + hashAmounts = sha256(bufferWriter.end()); bufferWriter = BufferWriter.withCapacity( prevOutScripts.map(varSliceSize).reduce((a, b) => a + b), ); prevOutScripts.forEach(prevOutScript => bufferWriter.writeVarSlice(prevOutScript), ); - hashScriptPubKeys = bcrypto.sha256(bufferWriter.end()); + hashScriptPubKeys = sha256(bufferWriter.end()); bufferWriter = BufferWriter.withCapacity(4 * this.ins.length); this.ins.forEach(txIn => bufferWriter.writeUInt32(txIn.sequence)); - hashSequences = bcrypto.sha256(bufferWriter.end()); + hashSequences = sha256(bufferWriter.end()); } if (!(isNone || isSingle)) { if (!this.outs.length) @@ -329,10 +367,11 @@ export class Transaction { .reduce((a, b) => a + b); const bufferWriter = BufferWriter.withCapacity(txOutsSize); this.outs.forEach(out => { - bufferWriter.writeUInt64(out.value); + // bufferWriter.writeUInt64(out.value); + bufferWriter.writeInt64(out.value); bufferWriter.writeVarSlice(out.script); }); - hashOutputs = bcrypto.sha256(bufferWriter.end()); + hashOutputs = sha256(bufferWriter.end()); } else if (isSingle && inIndex < this.outs.length) { const output = this.outs[inIndex]; const bufferWriter = BufferWriter.withCapacity( @@ -340,7 +379,7 @@ export class Transaction { ); bufferWriter.writeUInt64(output.value); bufferWriter.writeVarSlice(output.script); - hashOutputs = bcrypto.sha256(bufferWriter.end()); + hashOutputs = sha256(bufferWriter.end()); } const spendType = (leafHash ? 2 : 0) + (annex ? 1 : 0); // Length calculation from: @@ -380,7 +419,7 @@ export class Transaction { if (annex) { const bufferWriter = BufferWriter.withCapacity(varSliceSize(annex)); bufferWriter.writeVarSlice(annex); - sigMsgWriter.writeSlice(bcrypto.sha256(bufferWriter.end())); + sigMsgWriter.writeSlice(sha256(bufferWriter.end())); } // Output if (isSingle) { @@ -396,21 +435,30 @@ export class Transaction { // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-19 return bcrypto.taggedHash( 'TapSighash', - Buffer.concat([Buffer.from([0x00]), sigMsgWriter.end()]), + tools.concat([Uint8Array.from([0x00]), sigMsgWriter.end()]), ); } hashForWitnessV0(inIndex, prevOutScript, value, hashType) { - typeforce( - types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), - arguments, + // typeforce( + // types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), + // arguments, + // ); + v.parse( + v.tuple([ + types.UInt32Schema, + types.BufferSchema, + types.SatoshiSchema, + types.UInt32Schema, + ]), + [inIndex, prevOutScript, value, hashType], ); - let tbuffer = Buffer.from([]); + let tbuffer = Uint8Array.from([]); let bufferWriter; let hashOutputs = ZERO; let hashPrevouts = ZERO; let hashSequence = ZERO; if (!(hashType & Transaction.SIGHASH_ANYONECANPAY)) { - tbuffer = Buffer.allocUnsafe(36 * this.ins.length); + tbuffer = new Uint8Array(36 * this.ins.length); bufferWriter = new BufferWriter(tbuffer, 0); this.ins.forEach(txIn => { bufferWriter.writeSlice(txIn.hash); @@ -423,7 +471,7 @@ export class Transaction { (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && (hashType & 0x1f) !== Transaction.SIGHASH_NONE ) { - tbuffer = Buffer.allocUnsafe(4 * this.ins.length); + tbuffer = new Uint8Array(4 * this.ins.length); bufferWriter = new BufferWriter(tbuffer, 0); this.ins.forEach(txIn => { bufferWriter.writeUInt32(txIn.sequence); @@ -437,7 +485,7 @@ export class Transaction { const txOutsSize = this.outs.reduce((sum, output) => { return sum + 8 + varSliceSize(output.script); }, 0); - tbuffer = Buffer.allocUnsafe(txOutsSize); + tbuffer = new Uint8Array(txOutsSize); bufferWriter = new BufferWriter(tbuffer, 0); this.outs.forEach(out => { bufferWriter.writeUInt64(out.value); @@ -449,13 +497,13 @@ export class Transaction { inIndex < this.outs.length ) { const output = this.outs[inIndex]; - tbuffer = Buffer.allocUnsafe(8 + varSliceSize(output.script)); + tbuffer = new Uint8Array(8 + varSliceSize(output.script)); bufferWriter = new BufferWriter(tbuffer, 0); bufferWriter.writeUInt64(output.value); bufferWriter.writeVarSlice(output.script); hashOutputs = bcrypto.hash256(tbuffer); } - tbuffer = Buffer.allocUnsafe(156 + varSliceSize(prevOutScript)); + tbuffer = new Uint8Array(156 + varSliceSize(prevOutScript)); bufferWriter = new BufferWriter(tbuffer, 0); const input = this.ins[inIndex]; bufferWriter.writeInt32(this.version); @@ -473,29 +521,34 @@ export class Transaction { } getHash(forWitness) { // wtxid for coinbase is always 32 bytes of 0x00 - if (forWitness && this.isCoinbase()) return Buffer.alloc(32, 0); + if (forWitness && this.isCoinbase()) return new Uint8Array(32); return bcrypto.hash256(this.__toBuffer(undefined, undefined, forWitness)); } getId() { // transaction hash's are displayed in reverse order - return reverseBuffer(this.getHash(false)).toString('hex'); + return tools.toHex(reverseBuffer(this.getHash(false))); } toBuffer(buffer, initialOffset) { return this.__toBuffer(buffer, initialOffset, true); } toHex() { - return this.toBuffer(undefined, undefined).toString('hex'); + return tools.toHex(this.toBuffer(undefined, undefined)); } setInputScript(index, scriptSig) { - typeforce(types.tuple(types.Number, types.Buffer), arguments); + // typeforce(types.tuple(types.Number, types.Buffer), arguments); + v.parse(v.tuple([v.number(), types.BufferSchema]), [index, scriptSig]); this.ins[index].script = scriptSig; } setWitness(index, witness) { - typeforce(types.tuple(types.Number, [types.Buffer]), arguments); + // typeforce(types.tuple(types.Number, [types.Buffer]), arguments); + v.parse(v.tuple([v.number(), v.array(types.BufferSchema)]), [ + index, + witness, + ]); this.ins[index].witness = witness; } __toBuffer(buffer, initialOffset, _ALLOW_WITNESS = false) { - if (!buffer) buffer = Buffer.allocUnsafe(this.byteLength(_ALLOW_WITNESS)); + if (!buffer) buffer = new Uint8Array(this.byteLength(_ALLOW_WITNESS)); const bufferWriter = new BufferWriter(buffer, initialOffset || 0); bufferWriter.writeInt32(this.version); const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses(); diff --git a/src/esm/types.js b/src/esm/types.js index d896a1f5c..2d82f70f5 100644 --- a/src/esm/types.js +++ b/src/esm/types.js @@ -1,10 +1,12 @@ -import { Buffer as NBuffer } from 'buffer'; -export const typeforce = require('typeforce'); -const ZERO32 = NBuffer.alloc(32, 0); -const EC_P = NBuffer.from( +import * as tools from 'uint8array-tools'; +import * as v from 'valibot'; +// export const typeforce = require('typeforce'); +const ZERO32 = new Uint8Array(32); +const EC_P = tools.fromHex( 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', - 'hex', ); +export const NBufferSchemaFactory = size => + v.pipe(v.instance(Uint8Array), v.length(size)); /** * Checks if two arrays of Buffers are equal. * @param a - The first array of Buffers. @@ -14,7 +16,8 @@ const EC_P = NBuffer.from( export function stacksEqual(a, b) { if (a.length !== b.length) return false; return a.every((x, i) => { - return x.equals(b[i]); + // return x.equals(b[i]); + return tools.compare(x, b[i]) === 0; }); } /** @@ -23,52 +26,68 @@ export function stacksEqual(a, b) { * @returns True if the value is a valid elliptic curve point, false otherwise. */ export function isPoint(p) { - if (!NBuffer.isBuffer(p)) return false; + if (!(p instanceof Uint8Array)) return false; 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(ZERO32) === 0) return false; + if (tools.compare(ZERO32, x) === 0) return false; + // if (x.compare(EC_P) >= 0) return false; + if (tools.compare(x, 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(ZERO32) === 0) return false; + if (tools.compare(ZERO32, y) === 0) return false; + // if (y.compare(EC_P) >= 0) return false; + if (tools.compare(y, EC_P) >= 0) return false; if (t === 0x04 && p.length === 65) return true; return false; } -const SATOSHI_MAX = 21 * 1e14; -export function Satoshi(value) { - return typeforce.UInt53(value) && value <= SATOSHI_MAX; -} export const TAPLEAF_VERSION_MASK = 0xfe; export function isTapleaf(o) { if (!o || !('output' in o)) return false; - if (!NBuffer.isBuffer(o.output)) return false; + if (!(o.output instanceof Uint8Array)) return false; if (o.version !== undefined) return (o.version & TAPLEAF_VERSION_MASK) === o.version; return true; } export function isTaptree(scriptTree) { - if (!Array(scriptTree)) return isTapleaf(scriptTree); + if (!Array.isArray(scriptTree)) return isTapleaf(scriptTree); if (scriptTree.length !== 2) return false; return scriptTree.every(t => isTaptree(t)); } -export const Buffer256bit = typeforce.BufferN(32); -export const Hash160bit = typeforce.BufferN(20); -export const Hash256bit = typeforce.BufferN(32); -export const Number = typeforce.Number; -export const Array = typeforce.Array; -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; -export const tuple = typeforce.tuple; -export const UInt8 = typeforce.UInt8; -export const UInt32 = typeforce.UInt32; -export const Function = typeforce.Function; -export const BufferN = typeforce.BufferN; -export const Null = typeforce.Null; -export const oneOf = typeforce.oneOf; +export const Buffer256bitSchema = NBufferSchemaFactory(32); +export const Hash160bitSchema = NBufferSchemaFactory(20); +export const Hash256bitSchema = NBufferSchemaFactory(32); +// export const Number = typeforce.Number; +// export const Array = typeforce.Array; +// export const Boolean = typeforce.Boolean; +// export const String = typeforce.String; +export const BufferSchema = v.instance(Uint8Array); +export const HexSchema = v.pipe(v.string(), v.regex(/^([0-9a-f]{2})+$/i)); +export const UInt8Schema = v.pipe( + v.number(), + v.integer(), + v.minValue(0), + v.maxValue(0xff), +); +export const UInt32Schema = v.pipe( + v.number(), + v.integer(), + v.minValue(0), + v.maxValue(0xffffffff), +); +export const SatoshiSchema = v.pipe( + v.bigint(), + v.minValue(0n), + v.maxValue(0x7fffffffffffffffn), +); +export const NullablePartial = a => + v.object( + Object.entries(a).reduce( + (acc, next) => ({ ...acc, [next[0]]: v.nullish(next[1]) }), + {}, + ), + ); diff --git a/test/address.spec.ts b/test/address.spec.ts index 23c18b9f6..e88aaa9c6 100644 --- a/test/address.spec.ts +++ b/test/address.spec.ts @@ -1,27 +1,28 @@ 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'; - -import { initEccLib } from '../src'; - -const NETWORKS = Object.assign( - { - litecoin: { - messagePrefix: '\x19Litecoin Signed Message:\n', - bip32: { - public: 0x019da462, - private: 0x019d9cfe, - }, - pubKeyHash: 0x30, - scriptHash: 0x32, - wif: 0xb0, +import * as baddress from '../src/esm/address.js'; +import * as bscript from '../src/esm/script.js'; +import fixtures from './fixtures/address.json'; +import * as tools from 'uint8array-tools'; +import { networks } from '..'; + +import { initEccLib } from '../src/esm/ecc_lib.js'; + +const NETWORKS = { + ...networks, + litecoin: { + messagePrefix: '\x19Litecoin Signed Message:\n', + bech32: 'ltc', + bip32: { + public: 0x019da462, + private: 0x019d9cfe, }, - }, - require('../src/networks'), -); + pubKeyHash: 0x30, + scriptHash: 0x32, + wif: 0xb0, + } as typeof networks.bitcoin, +}; describe('address', () => { describe('fromBase58Check', () => { @@ -32,15 +33,18 @@ describe('address', () => { const decode = baddress.fromBase58Check(f.base58check); assert.strictEqual(decode.version, f.version); - assert.strictEqual(decode.hash.toString('hex'), f.hash); + assert.strictEqual(tools.toHex(decode.hash), f.hash); }); }); fixtures.invalid.fromBase58Check.forEach(f => { it('throws on ' + f.exception, () => { - assert.throws(() => { - baddress.fromBase58Check(f.address); - }, new RegExp(f.address + ' ' + f.exception)); + assert.throws( + () => { + baddress.fromBase58Check(f.address); + }, + new RegExp(f.address + ' ' + f.exception), + ); }); }); }); @@ -54,7 +58,7 @@ describe('address', () => { assert.strictEqual(actual.version, f.version); assert.strictEqual(actual.prefix, NETWORKS[f.network].bech32); - assert.strictEqual(actual.data.toString('hex'), f.data); + assert.strictEqual(tools.toHex(actual.data), f.data); }); }); diff --git a/test/bitcoin.core.spec.ts b/test/bitcoin.core.spec.ts index 9040416bb..c51654064 100644 --- a/test/bitcoin.core.spec.ts +++ b/test/bitcoin.core.spec.ts @@ -10,6 +10,8 @@ import * as sigCanonical from './fixtures/core/sig_canonical.json'; import * as sigNoncanonical from './fixtures/core/sig_noncanonical.json'; import * as sigHash from './fixtures/core/sighash.json'; import * as txValid from './fixtures/core/tx_valid.json'; +import * as tools from 'uint8array-tools'; +import { bigint } from 'valibot'; describe('Bitcoin-core', () => { // base58EncodeDecode @@ -119,7 +121,7 @@ describe('Bitcoin-core', () => { const prevOutHash = Buffer.from(input[0] as string, 'hex').reverse(); const prevOutIndex = input[1]; - assert.deepStrictEqual(txIn.hash, prevOutHash); + assert.deepStrictEqual(Buffer.from(txIn.hash), prevOutHash); // we read UInt32, not Int32 assert.strictEqual(txIn.index & 0xffffffff, prevOutIndex); @@ -140,7 +142,7 @@ describe('Bitcoin-core', () => { const hashType = f[3] as number; const expectedHash = f[4]; - const hashTypes = []; + const hashTypes: string[] = []; if ((hashType & 0x1f) === bitcoin.Transaction.SIGHASH_NONE) hashTypes.push('SIGHASH_NONE'); else if ((hashType & 0x1f) === bitcoin.Transaction.SIGHASH_SINGLE) @@ -160,7 +162,7 @@ describe('Bitcoin-core', () => { const script = Buffer.from(scriptHex, 'hex'); const scriptChunks = bitcoin.script.decompile(script); assert.strictEqual( - bitcoin.script.compile(scriptChunks!).toString('hex'), + tools.toHex(bitcoin.script.compile(scriptChunks!)), scriptHex, ); @@ -168,7 +170,7 @@ describe('Bitcoin-core', () => { // reverse because test data is reversed assert.strictEqual( - (hash.reverse() as Buffer).toString('hex'), + tools.toHex(hash.reverse() as Buffer), expectedHash, ); @@ -176,7 +178,7 @@ describe('Bitcoin-core', () => { transaction.hashForWitnessV0( inIndex, script, - 0, + BigInt(0), // convert to UInt32 hashType < 0 ? 0x100000000 + hashType : hashType, ), @@ -197,7 +199,7 @@ describe('Bitcoin-core', () => { parsed.hashType, ); - assert.strictEqual(actual.toString('hex'), hex); + assert.strictEqual(tools.toHex(actual), hex); }); }); diff --git a/test/block.spec.ts b/test/block.spec.ts index e93420c2e..358e38d49 100644 --- a/test/block.spec.ts +++ b/test/block.spec.ts @@ -1,6 +1,7 @@ import * as assert from 'assert'; import { beforeEach, describe, it } from 'mocha'; -import { Block } from '..'; +import { Block } from '../src/esm/block.js'; +import * as tools from 'uint8array-tools'; import * as fixtures from './fixtures/block.json'; @@ -23,7 +24,7 @@ describe('Block', () => { const bits = parseInt(f.bits, 16); assert.strictEqual( - Block.calculateTarget(bits).toString('hex'), + tools.toHex(Block.calculateTarget(bits)), f.expected, ); }); @@ -36,13 +37,10 @@ describe('Block', () => { const block = Block.fromHex(f.hex); assert.strictEqual(block.version, f.version); - assert.strictEqual(block.prevHash!.toString('hex'), f.prevHash); - assert.strictEqual(block.merkleRoot!.toString('hex'), f.merkleRoot); + assert.strictEqual(tools.toHex(block.prevHash!), f.prevHash); + assert.strictEqual(tools.toHex(block.merkleRoot!), f.merkleRoot); if (block.witnessCommit) { - assert.strictEqual( - block.witnessCommit.toString('hex'), - f.witnessCommit, - ); + assert.strictEqual(tools.toHex(block.witnessCommit), f.witnessCommit); } assert.strictEqual(block.timestamp, f.timestamp); assert.strictEqual(block.bits, f.bits); @@ -89,7 +87,7 @@ describe('Block', () => { }); it('returns ' + f.id + ' for ' + f.description, () => { - assert.strictEqual(block.getHash().toString('hex'), f.hash); + assert.strictEqual(tools.toHex(block.getHash()), f.hash); assert.strictEqual(block.getId(), f.id); }); }); @@ -129,7 +127,7 @@ describe('Block', () => { it('returns ' + f.merkleRoot + ' for ' + f.id, () => { assert.strictEqual( - Block.calculateMerkleRoot(block.transactions!).toString('hex'), + tools.toHex(Block.calculateMerkleRoot(block.transactions!)), f.merkleRoot, ); }); @@ -137,9 +135,7 @@ describe('Block', () => { if (f.witnessCommit) { it('returns witness commit ' + f.witnessCommit + ' for ' + f.id, () => { assert.strictEqual( - Block.calculateMerkleRoot(block.transactions!, true).toString( - 'hex', - ), + tools.toHex(Block.calculateMerkleRoot(block.transactions!, true)), f.witnessCommit, ); }); diff --git a/test/bufferutils.spec.ts b/test/bufferutils.spec.ts index 21a97ad4b..1150f57fa 100644 --- a/test/bufferutils.spec.ts +++ b/test/bufferutils.spec.ts @@ -1,57 +1,58 @@ import * as assert from 'assert'; import { describe, it } from 'mocha'; -import * as bufferutils from '../src/bufferutils'; -import { BufferReader, BufferWriter } from '../src/bufferutils'; +import * as bufferutils from '../src/esm/bufferutils'; +import { BufferReader, BufferWriter } from '../src/esm/bufferutils'; import * as fixtures from './fixtures/bufferutils.json'; -import varuint = require('varuint-bitcoin'); +// import varuint = require('varuint-bitcoin'); +import * as varuint from 'varuint-bitcoin'; describe('bufferutils', () => { function concatToBuffer(values: number[][]): Buffer { return Buffer.concat(values.map(data => Buffer.from(data))); } - describe('readUInt64LE', () => { - fixtures.valid.forEach(f => { - it('decodes ' + f.hex, () => { - const buffer = Buffer.from(f.hex, 'hex'); - const num = bufferutils.readUInt64LE(buffer, 0); - - assert.strictEqual(num, f.dec); - }); - }); - - fixtures.invalid.readUInt64LE.forEach(f => { - it('throws on ' + f.description, () => { - const buffer = Buffer.from(f.hex, 'hex'); - - assert.throws(() => { - bufferutils.readUInt64LE(buffer, 0); - }, new RegExp(f.exception)); - }); - }); - }); - - describe('writeUInt64LE', () => { - fixtures.valid.forEach(f => { - it('encodes ' + f.dec, () => { - const buffer = Buffer.alloc(8, 0); - - bufferutils.writeUInt64LE(buffer, f.dec, 0); - assert.strictEqual(buffer.toString('hex'), f.hex); - }); - }); - - fixtures.invalid.writeUInt64LE.forEach(f => { - it('throws on ' + f.description, () => { - const buffer = Buffer.alloc(8, 0); - - assert.throws(() => { - bufferutils.writeUInt64LE(buffer, f.dec, 0); - }, new RegExp(f.exception)); - }); - }); - }); + // describe('readUInt64LE', () => { + // fixtures.valid.forEach(f => { + // it('decodes ' + f.hex, () => { + // const buffer = Buffer.from(f.hex, 'hex'); + // const num = bufferutils.readUInt64LE(buffer, 0); + + // assert.strictEqual(num, f.dec); + // }); + // }); + + // fixtures.invalid.readUInt64LE.forEach(f => { + // it('throws on ' + f.description, () => { + // const buffer = Buffer.from(f.hex, 'hex'); + + // assert.throws(() => { + // bufferutils.readUInt64LE(buffer, 0); + // }, new RegExp(f.exception)); + // }); + // }); + // }); + + // describe('writeUInt64LE', () => { + // fixtures.valid.forEach(f => { + // it('encodes ' + f.dec, () => { + // const buffer = Buffer.alloc(8, 0); + + // bufferutils.writeUInt64LE(buffer, f.dec, 0); + // assert.strictEqual(buffer.toString('hex'), f.hex); + // }); + // }); + + // fixtures.invalid.writeUInt64LE.forEach(f => { + // it('throws on ' + f.description, () => { + // const buffer = Buffer.alloc(8, 0); + + // assert.throws(() => { + // bufferutils.writeUInt64LE(buffer, f.dec, 0); + // }, new RegExp(f.exception)); + // }); + // }); + // }); describe('BufferWriter', () => { function testBuffer( @@ -61,8 +62,8 @@ describe('bufferutils', () => { ): void { assert.strictEqual(bufferWriter.offset, expectedOffset); assert.deepStrictEqual( - bufferWriter.buffer.slice(0, expectedOffset), - expectedBuffer.slice(0, expectedOffset), + Buffer.from(bufferWriter.buffer.slice(0, expectedOffset)), + Buffer.from(expectedBuffer.slice(0, expectedOffset)), ); } @@ -299,8 +300,8 @@ describe('bufferutils', () => { describe('BufferReader', () => { function testValue( bufferReader: BufferReader, - value: Buffer | number, - expectedValue: Buffer | number, + value: Buffer | bigint | number, + expectedValue: Buffer | bigint | number, expectedOffset: number = Buffer.isBuffer(expectedValue) ? expectedValue.length : 0, @@ -308,11 +309,11 @@ describe('bufferutils', () => { assert.strictEqual(bufferReader.offset, expectedOffset); if (Buffer.isBuffer(expectedValue)) { assert.deepStrictEqual( - (value as Buffer).slice(0, expectedOffset), - expectedValue.slice(0, expectedOffset), + Buffer.from(value as Buffer).slice(0, expectedOffset), + Buffer.from(expectedValue).slice(0, expectedOffset), ); } else { - assert.strictEqual(value as number, expectedValue); + assert.strictEqual(value, expectedValue); } } @@ -371,19 +372,21 @@ describe('bufferutils', () => { it('readUInt64', () => { const values = [ - 0, - 1, - Math.pow(2, 32), - Number.MAX_SAFE_INTEGER /* 2^53 - 1 */, + 0n, + 1n, + BigInt(Math.pow(2, 32)), + BigInt(Number.MAX_SAFE_INTEGER) /* 2^53 - 1 */, + (BigInt(1) << 64n) - 1n, ]; const buffer = concatToBuffer([ [0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0], [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00], + [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], ]); const bufferReader = new BufferReader(buffer); - values.forEach((value: number) => { + values.forEach((value: bigint) => { const expectedOffset = bufferReader.offset + 8; const val = bufferReader.readUInt64(); testValue(bufferReader, val, value, expectedOffset); diff --git a/test/crypto.spec.ts b/test/crypto.spec.ts index b7273568f..502dd6b57 100644 --- a/test/crypto.spec.ts +++ b/test/crypto.spec.ts @@ -1,11 +1,14 @@ 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, TAGS, TAGGED_HASH_PREFIXES } from '../src/crypto'; +import * as bcrypto from '../src/esm/crypto.js'; +import type { TaggedHashPrefix } from '..'; +import fixtures from './fixtures/crypto.json'; +import * as tools from 'uint8array-tools'; +import { TAGS, TAGGED_HASH_PREFIXES } from '../src/esm/crypto.js'; +import { sha256 } from '@noble/hashes/sha256'; describe('crypto', () => { - ['hash160', 'hash256', 'ripemd160', 'sha1', 'sha256'].forEach(algorithm => { + ['hash160', 'hash256'].forEach(algorithm => { describe(algorithm, () => { fixtures.hashes.forEach(f => { const fn = (bcrypto as any)[algorithm]; @@ -13,9 +16,9 @@ describe('crypto', () => { it('returns ' + expected + ' for ' + f.hex, () => { const data = Buffer.from(f.hex, 'hex'); - const actual = fn(data).toString('hex'); + const actual = fn(data); - assert.strictEqual(actual, expected); + assert.strictEqual(tools.toHex(actual), expected); }); }); }); @@ -24,10 +27,10 @@ describe('crypto', () => { describe('taggedHash', () => { fixtures.taggedHash.forEach(f => { const bytes = Buffer.from(f.hex, 'hex'); - const expected = Buffer.from(f.result, 'hex'); + const expected = f.result; it(`returns ${f.result} for taggedHash "${f.tag}" of ${f.hex}`, () => { const actual = bcrypto.taggedHash(f.tag as TaggedHashPrefix, bytes); - assert.strictEqual(actual.toString('hex'), expected.toString('hex')); + assert.strictEqual(tools.toHex(actual), expected); }); }); }); @@ -36,7 +39,7 @@ describe('crypto', () => { const taggedHashPrefixes = Object.fromEntries( TAGS.map((tag: TaggedHashPrefix) => { const tagHash = sha256(Buffer.from(tag)); - return [tag, Buffer.concat([tagHash, tagHash])]; + return [tag, tools.concat([tagHash, tagHash])]; }), ); it('stored the result of operation', () => { diff --git a/test/fixtures/crypto.json b/test/fixtures/crypto.json index 1d1976b5e..20a51a36c 100644 --- a/test/fixtures/crypto.json +++ b/test/fixtures/crypto.json @@ -3,34 +3,22 @@ { "hex": "0000000000000001", "hash160": "cdb00698f02afd929ffabea308340fa99ac2afa8", - "hash256": "3ae5c198d17634e79059c2cd735491553d22c4e09d1d9fea3ecf214565df2284", - "ripemd160": "8d1a05d1bc08870968eb8a81ad4393fd3aac6633", - "sha1": "cb473678976f425d6ec1339838f11011007ad27d", - "sha256": "cd2662154e6d76b2b2b92e70c0cac3ccf534f9b74eb5b89819ec509083d00a50" + "hash256": "3ae5c198d17634e79059c2cd735491553d22c4e09d1d9fea3ecf214565df2284" }, { "hex": "0101010101010101", "hash160": "abaf1119f83e384210fe8e222eac76e2f0da39dc", - "hash256": "728338d99f356175c4945ef5cccfa61b7b56143cbbf426ddd0e0fc7cfe8c3c23", - "ripemd160": "5825701b4b9767fd35063b286dca3582853e0630", - "sha1": "c0357a32ed1f6a03be92dd094476f7f1a2e214ec", - "sha256": "04abc8821a06e5a30937967d11ad10221cb5ac3b5273e434f1284ee87129a061" + "hash256": "728338d99f356175c4945ef5cccfa61b7b56143cbbf426ddd0e0fc7cfe8c3c23" }, { "hex": "ffffffffffffffff", "hash160": "f86221f5a1fca059a865c0b7d374dfa9d5f3aeb4", - "hash256": "752adad0a7b9ceca853768aebb6965eca126a62965f698a0c1bc43d83db632ad", - "ripemd160": "cb760221600ed34337ca3ab70016b5f58c838120", - "sha1": "be673e8a56eaa9d8c1d35064866701c11ef8e089", - "sha256": "12a3ae445661ce5dee78d0650d33362dec29c4f82af05e7e57fb595bbbacf0ca" + "hash256": "752adad0a7b9ceca853768aebb6965eca126a62965f698a0c1bc43d83db632ad" }, { "hex": "4c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e73656374657475722061646970697363696e6720656c69742e20446f6e65632061742066617563696275732073617069656e2c2076656c20666163696c6973697320617263752e20536564207574206d61737361206e6962682e205574206d6f6c6c69732070756c76696e6172206d617373612e20557420756c6c616d636f7270657220646f6c6f7220656e696d2c20696e206d6f6c657374696520656e696d20636f6e64696d656e74756d2061632e20416c697175616d206572617420766f6c75747061742e204e756c6c6120736f64616c657320617420647569206e656320", "hash160": "9763e6b367c363bd6b88a7b361c98e6beee243a5", - "hash256": "033588797115feb3545052670cac2a46584ab3cb460de63756ee0275e66b5799", - "ripemd160": "cad8593dcdef12ee334c97bab9787f07b3f3a1a5", - "sha1": "10d96fb43aca84e342206887bbeed3065d4e4344", - "sha256": "a7fb8276035057ed6479c5f2305a96da100ac43f0ac10f277e5ab8c5457429da" + "hash256": "033588797115feb3545052670cac2a46584ab3cb460de63756ee0275e66b5799" } ], "taggedHash": [ diff --git a/test/fixtures/p2pk.json b/test/fixtures/p2pk.json index f3982d327..f93ca87a1 100644 --- a/test/fixtures/p2pk.json +++ b/test/fixtures/p2pk.json @@ -74,7 +74,7 @@ }, { "description": "Non-canonical signature", - "exception": "Expected property \"signature\" of type \\?isCanonicalScriptSignature, got Buffer", + "exception": "ValiError: Expected signature to be of type isCanonicalScriptSignature", "arguments": { "pubkey": "030000000000000000000000000000000000000000000000000000000000000001", "signature": "3044" diff --git a/test/fixtures/p2pkh.json b/test/fixtures/p2pkh.json index 4efbb5990..d372a9e44 100644 --- a/test/fixtures/p2pkh.json +++ b/test/fixtures/p2pkh.json @@ -124,7 +124,7 @@ }, { "description": "Non-minimally encoded (non BIP62 compliant)", - "exception": "Expected property \"output\" of type Buffer\\(Length: 25\\), got Buffer\\(Length: 26\\)", + "exception": "ValiError: Invalid length: Expected 25 but received 26", "arguments": { "outputHex": "76a94c14aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac" } diff --git a/test/fixtures/p2sh.json b/test/fixtures/p2sh.json index 32f108c91..0ded4ab08 100644 --- a/test/fixtures/p2sh.json +++ b/test/fixtures/p2sh.json @@ -204,7 +204,7 @@ }, { "description": "Non-minimally encoded (non BIP62 compliant)", - "exception": "Expected property \"output\" of type Buffer\\(Length: 23\\), got Buffer\\(Length: 24\\)", + "exception": "ValiError: Invalid length: Expected 23 but received 24", "arguments": { "outputHex": "a94c14c286a1af0947f58d1ad787385b1c2c4a976f9e7187" } diff --git a/test/fixtures/p2tr.json b/test/fixtures/p2tr.json index aaa82fbb4..4ba31cc57 100644 --- a/test/fixtures/p2tr.json +++ b/test/fixtures/p2tr.json @@ -1051,7 +1051,7 @@ }, { "description": "Script Tree is not a binary tree (has tree leafs)", - "exception": "property \"scriptTree\" of type \\?isTaptree, got Array", + "exception": "ValiError: Taptree is not of type isTaptree", "options": {}, "arguments": { "internalPubkey": "9fa5ffb68821cf559001caa0577eeea4978b29416def328a707b15e91701a2f7", @@ -1080,7 +1080,7 @@ }, { "description": "Script Tree is not a TapTree tree (leaf has no script)", - "exception": "property \"scriptTree\" of type \\?isTaptree, got Array", + "exception": "ValiError: Taptree is not of type isTaptree", "options": {}, "arguments": { "internalPubkey": "9fa5ffb68821cf559001caa0577eeea4978b29416def328a707b15e91701a2f7", diff --git a/test/fixtures/psbt.json b/test/fixtures/psbt.json index 33c599fec..6cb152f1d 100644 --- a/test/fixtures/psbt.json +++ b/test/fixtures/psbt.json @@ -196,7 +196,7 @@ { "witnessUtxo": { "script": "Buffer.from('a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e887', 'hex')", - "value": 200000000 + "value": "200000000" }, "redeemScript": "Buffer.from('00208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903', 'hex')", "witnessScript": "Buffer.from('522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae', 'hex')", diff --git a/test/fixtures/script.json b/test/fixtures/script.json index 545c8f3bb..d435cea91 100644 --- a/test/fixtures/script.json +++ b/test/fixtures/script.json @@ -457,7 +457,7 @@ ], "fromASM": [ { - "description": "Expected Hex, got String \"0xff\"", + "description": "ValiError: Invalid format: Expected \\\/\\^\\(\\[0-9a-f\\]\\{2\\}\\)\\+\\$\\\/i but received \"0xff\"", "script": "0xff OP_CHECKSIG" } ] diff --git a/test/fixtures/transaction.json b/test/fixtures/transaction.json index 979549ab7..a04f7be02 100644 --- a/test/fixtures/transaction.json +++ b/test/fixtures/transaction.json @@ -892,12 +892,12 @@ "invalid": { "addInput": [ { - "exception": "Expected property \"0\" of type Buffer\\(Length: 32\\), got Buffer\\(Length: 30\\)", + "exception": "ValiError: Invalid length: Expected 32 but received 30", "hash": "0aed1366a73b6057ee7800d737bff1bdf8c448e98d86bc0998f2b009816d", "index": 0 }, { - "exception": "Expected property \"0\" of type Buffer\\(Length: 32\\), got Buffer\\(Length: 34\\)", + "exception": "ValiError: Invalid length: Expected 32 but received 34", "hash": "0aed1366a73b6057ee7800d737bff1bdf8c448e98d86bc0998f2b009816da9b0ffff", "index": 0 } diff --git a/test/integration/bip32.spec.ts b/test/integration/bip32.spec.ts index 2ecf308c4..418e74272 100644 --- a/test/integration/bip32.spec.ts +++ b/test/integration/bip32.spec.ts @@ -123,7 +123,7 @@ describe('bitcoinjs-lib (BIP32)', () => { // var mnemonic = bip39.generateMnemonic() const mnemonic = 'praise you muffin lion enable neck grocery crumble super myself license ghost'; - assert(bip39.validateMnemonic(mnemonic)); + assert.strictEqual(bip39.validateMnemonic(mnemonic), true); const seed = bip39.mnemonicToSeedSync(mnemonic); const root = bip32.fromSeed(seed); diff --git a/test/integration/cltv.spec.ts b/test/integration/cltv.spec.ts index d81442057..7a816b216 100644 --- a/test/integration/cltv.spec.ts +++ b/test/integration/cltv.spec.ts @@ -4,17 +4,19 @@ import * as ecc from 'tiny-secp256k1'; import { before, describe, it } from 'mocha'; import * as bitcoin from '../..'; import { regtestUtils } from './_regtest'; +import { reverseBuffer } from '../../src/esm/bufferutils'; +import * as tools from 'uint8array-tools'; const ECPair = ECPairFactory(ecc); const regtest = regtestUtils.network; const bip65 = require('bip65'); -function toOutputScript(address: string): Buffer { +function toOutputScript(address: string): Uint8Array { return bitcoin.address.toOutputScript(address, regtest); } function idToHash(txid: string): Buffer { - return Buffer.from(txid, 'hex').reverse(); + return reverseBuffer(tools.fromHex(txid)); } const alice = ECPair.fromWIF( @@ -35,24 +37,24 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', () => { const hashType = bitcoin.Transaction.SIGHASH_ALL; interface KeyPair { - publicKey: Buffer; + publicKey: Uint8Array; } function cltvCheckSigOutput( aQ: KeyPair, bQ: KeyPair, lockTime: number, - ): Buffer { + ): Uint8Array { return bitcoin.script.fromASM( ` OP_IF - ${bitcoin.script.number.encode(lockTime).toString('hex')} + ${tools.toHex(bitcoin.script.number.encode(lockTime))} OP_CHECKLOCKTIMEVERIFY OP_DROP OP_ELSE - ${bQ.publicKey.toString('hex')} + ${tools.toHex(bQ.publicKey)} OP_CHECKSIGVERIFY OP_ENDIF - ${aQ.publicKey.toString('hex')} + ${tools.toHex(aQ.publicKey)} OP_CHECKSIG ` .trim() @@ -83,7 +85,7 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', () => { tx.locktime = lockTime; // Note: nSequence MUST be <= 0xfffffffe otherwise OP_CHECKLOCKTIMEVERIFY will fail. tx.addInput(idToHash(unspent.txId), unspent.vout, 0xfffffffe); - tx.addOutput(toOutputScript(regtestUtils.RANDOM_ADDRESS), 7e4); + tx.addOutput(toOutputScript(regtestUtils.RANDOM_ADDRESS), BigInt(7e4)); // {Alice's signature} OP_TRUE const signatureHash = tx.hashForSignature(0, redeemScript, hashType); @@ -110,7 +112,7 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', () => { value: 7e4, }); }, - ); + ).timeout(4000); // expiry will pass, {Alice's signature} OP_TRUE it( @@ -132,7 +134,7 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', () => { tx.locktime = lockTime; // Note: nSequence MUST be <= 0xfffffffe otherwise OP_CHECKLOCKTIMEVERIFY will fail. tx.addInput(idToHash(unspent.txId), unspent.vout, 0xfffffffe); - tx.addOutput(toOutputScript(regtestUtils.RANDOM_ADDRESS), 7e4); + tx.addOutput(toOutputScript(regtestUtils.RANDOM_ADDRESS), BigInt(7e4)); // {Alice's signature} OP_TRUE const signatureHash = tx.hashForSignature(0, redeemScript, hashType); @@ -162,7 +164,7 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', () => { value: 7e4, }); }, - ); + ).timeout(6000); // expiry ignored, {Bob's signature} {Alice's signature} OP_FALSE it( @@ -183,7 +185,7 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', () => { tx.locktime = lockTime; // Note: nSequence MUST be <= 0xfffffffe otherwise OP_CHECKLOCKTIMEVERIFY will fail. tx.addInput(idToHash(unspent.txId), unspent.vout, 0xfffffffe); - tx.addOutput(toOutputScript(regtestUtils.RANDOM_ADDRESS), 8e4); + tx.addOutput(toOutputScript(regtestUtils.RANDOM_ADDRESS), BigInt(8e4)); // {Alice's signature} {Bob's signature} OP_FALSE const signatureHash = tx.hashForSignature(0, redeemScript, hashType); @@ -210,7 +212,7 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', () => { value: 8e4, }); }, - ); + ).timeout(4000); // expiry in the future, {Alice's signature} OP_TRUE it( @@ -231,7 +233,7 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', () => { tx.locktime = lockTime; // Note: nSequence MUST be <= 0xfffffffe otherwise OP_CHECKLOCKTIMEVERIFY will fail. tx.addInput(idToHash(unspent.txId), unspent.vout, 0xfffffffe); - tx.addOutput(toOutputScript(regtestUtils.RANDOM_ADDRESS), 1e4); + tx.addOutput(toOutputScript(regtestUtils.RANDOM_ADDRESS), BigInt(1e4)); // {Alice's signature} OP_TRUE const signatureHash = tx.hashForSignature(0, redeemScript, hashType); @@ -256,5 +258,5 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', () => { }, /Error: non-final/); }); }, - ); + ).timeout(4000); }); diff --git a/test/integration/csv.spec.ts b/test/integration/csv.spec.ts index 2da433877..86c49c4b2 100644 --- a/test/integration/csv.spec.ts +++ b/test/integration/csv.spec.ts @@ -1,22 +1,24 @@ import * as assert from 'assert'; -import { PsbtInput } from 'bip174/src/lib/interfaces'; +import { PsbtInput } from 'bip174'; import ECPairFactory from 'ecpair'; import * as ecc from 'tiny-secp256k1'; import { before, describe, it } from 'mocha'; import * as bitcoin from '../..'; import { regtestUtils } from './_regtest'; +import { reverseBuffer } from '../../src/esm/bufferutils'; +import * as tools from 'uint8array-tools'; const ECPair = ECPairFactory(ecc); const regtest = regtestUtils.network; const bip68 = require('bip68'); const varuint = require('varuint-bitcoin'); -function toOutputScript(address: string): Buffer { +function toOutputScript(address: string): Uint8Array { return bitcoin.address.toOutputScript(address, regtest); } -function idToHash(txid: string): Buffer { - return Buffer.from(txid, 'hex').reverse(); +function idToHash(txid: string): Uint8Array { + return reverseBuffer(tools.fromHex(txid)); } const alice = ECPair.fromWIF( @@ -45,25 +47,25 @@ describe('bitcoinjs-lib (transactions w/ CSV)', () => { const hashType = bitcoin.Transaction.SIGHASH_ALL; interface KeyPair { - publicKey: Buffer; + publicKey: Uint8Array; } // IF MTP (from when confirmed) > seconds, _alice can redeem function csvCheckSigOutput( _alice: KeyPair, _bob: KeyPair, sequence: number, - ): Buffer { + ): Uint8Array { return bitcoin.script.fromASM( ` OP_IF - ${bitcoin.script.number.encode(sequence).toString('hex')} + ${tools.toHex(bitcoin.script.number.encode(sequence))} OP_CHECKSEQUENCEVERIFY OP_DROP OP_ELSE - ${_bob.publicKey.toString('hex')} + ${tools.toHex(_bob.publicKey)} OP_CHECKSIGVERIFY OP_ENDIF - ${_alice.publicKey.toString('hex')} + ${tools.toHex(_alice.publicKey)} OP_CHECKSIG ` .trim() @@ -86,30 +88,30 @@ describe('bitcoinjs-lib (transactions w/ CSV)', () => { _dave: KeyPair, sequence1: number, sequence2: number, - ): Buffer { + ): Uint8Array { return bitcoin.script.fromASM( ` OP_IF OP_IF OP_2 OP_ELSE - ${bitcoin.script.number.encode(sequence1).toString('hex')} + ${tools.toHex(bitcoin.script.number.encode(sequence1))} OP_CHECKSEQUENCEVERIFY OP_DROP - ${_alice.publicKey.toString('hex')} + ${tools.toHex(_alice.publicKey)} OP_CHECKSIGVERIFY OP_1 OP_ENDIF - ${_bob.publicKey.toString('hex')} - ${_charles.publicKey.toString('hex')} - ${_dave.publicKey.toString('hex')} + ${tools.toHex(_bob.publicKey)} + ${tools.toHex(_charles.publicKey)} + ${tools.toHex(_dave.publicKey)} OP_3 OP_CHECKMULTISIG OP_ELSE - ${bitcoin.script.number.encode(sequence2).toString('hex')} + ${tools.toHex(bitcoin.script.number.encode(sequence2))} OP_CHECKSEQUENCEVERIFY OP_DROP - ${_alice.publicKey.toString('hex')} + ${tools.toHex(_alice.publicKey)} OP_CHECKSIG OP_ENDIF ` @@ -151,7 +153,7 @@ describe('bitcoinjs-lib (transactions w/ CSV)', () => { }) .addOutput({ address: regtestUtils.RANDOM_ADDRESS, - value: 7e4, + value: BigInt(7e4), }) .signInput(0, alice) .finalizeInput(0, csvGetFinalScripts) // See csvGetFinalScripts below @@ -171,7 +173,7 @@ describe('bitcoinjs-lib (transactions w/ CSV)', () => { value: 7e4, }); }, - ); + ).timeout(8000); // expiry in the future, {Alice's signature} OP_TRUE it( @@ -193,7 +195,7 @@ describe('bitcoinjs-lib (transactions w/ CSV)', () => { const tx = new bitcoin.Transaction(); tx.version = 2; tx.addInput(idToHash(unspent.txId), unspent.vout, sequence); - tx.addOutput(toOutputScript(regtestUtils.RANDOM_ADDRESS), 1e4); + tx.addOutput(toOutputScript(regtestUtils.RANDOM_ADDRESS), BigInt(1e4)); // {Alice's signature} OP_TRUE const signatureHash = tx.hashForSignature( @@ -224,7 +226,7 @@ describe('bitcoinjs-lib (transactions w/ CSV)', () => { }, /Error: non-BIP68-final/); }); }, - ); + ).timeout(8000); // Check first combination of complex CSV, 2 of 3 it( @@ -255,7 +257,7 @@ describe('bitcoinjs-lib (transactions w/ CSV)', () => { const tx = new bitcoin.Transaction(); tx.version = 2; tx.addInput(idToHash(unspent.txId), unspent.vout); - tx.addOutput(toOutputScript(regtestUtils.RANDOM_ADDRESS), 7e4); + tx.addOutput(toOutputScript(regtestUtils.RANDOM_ADDRESS), BigInt(7e4)); // OP_0 {Bob sig} {Charles sig} OP_TRUE OP_TRUE const signatureHash = tx.hashForSignature( @@ -291,7 +293,7 @@ describe('bitcoinjs-lib (transactions w/ CSV)', () => { value: 7e4, }); }, - ); + ).timeout(8000); // Check first combination of complex CSV, mediator + 1 of 3 after 2 blocks it( @@ -322,7 +324,7 @@ describe('bitcoinjs-lib (transactions w/ CSV)', () => { const tx = new bitcoin.Transaction(); tx.version = 2; tx.addInput(idToHash(unspent.txId), unspent.vout, sequence1); // Set sequence1 for input - tx.addOutput(toOutputScript(regtestUtils.RANDOM_ADDRESS), 7e4); + tx.addOutput(toOutputScript(regtestUtils.RANDOM_ADDRESS), BigInt(7e4)); // OP_0 {Bob sig} {Alice mediator sig} OP_FALSE OP_TRUE const signatureHash = tx.hashForSignature( @@ -361,7 +363,7 @@ describe('bitcoinjs-lib (transactions w/ CSV)', () => { value: 7e4, }); }, - ); + ).timeout(8000); // Check first combination of complex CSV, mediator after 5 blocks it( @@ -392,7 +394,7 @@ describe('bitcoinjs-lib (transactions w/ CSV)', () => { const tx = new bitcoin.Transaction(); tx.version = 2; tx.addInput(idToHash(unspent.txId), unspent.vout, sequence2); // Set sequence2 for input - tx.addOutput(toOutputScript(regtestUtils.RANDOM_ADDRESS), 7e4); + tx.addOutput(toOutputScript(regtestUtils.RANDOM_ADDRESS), BigInt(7e4)); // {Alice mediator sig} OP_FALSE const signatureHash = tx.hashForSignature( @@ -428,7 +430,7 @@ describe('bitcoinjs-lib (transactions w/ CSV)', () => { value: 7e4, }); }, - ); + ).timeout(8000); }); // This function is used to finalize a CSV transaction using PSBT. @@ -436,13 +438,13 @@ describe('bitcoinjs-lib (transactions w/ CSV)', () => { function csvGetFinalScripts( inputIndex: number, input: PsbtInput, - script: Buffer, + script: Uint8Array, isSegwit: boolean, isP2SH: boolean, isP2WSH: boolean, ): { - finalScriptSig: Buffer | undefined; - finalScriptWitness: Buffer | undefined; + finalScriptSig: Uint8Array | undefined; + finalScriptWitness: Uint8Array | undefined; } { // Step 1: Check to make sure the meaningful script matches what you expect. const decompiled = bitcoin.script.decompile(script); @@ -477,11 +479,11 @@ function csvGetFinalScripts( redeem: payment, }); - function witnessStackToScriptWitness(witness: Buffer[]): Buffer { - let buffer = Buffer.allocUnsafe(0); + function witnessStackToScriptWitness(witness: Uint8Array[]): Uint8Array { + let buffer = new Uint8Array(0); - function writeSlice(slice: Buffer): void { - buffer = Buffer.concat([buffer, Buffer.from(slice)]); + function writeSlice(slice: Uint8Array): void { + buffer = Buffer.concat([buffer, slice]); } function writeVarInt(i: number): void { @@ -492,12 +494,12 @@ function csvGetFinalScripts( varuint.encode(i, buffer, currentLen); } - function writeVarSlice(slice: Buffer): void { + function writeVarSlice(slice: Uint8Array): void { writeVarInt(slice.length); writeSlice(slice); } - function writeVector(vector: Buffer[]): void { + function writeVector(vector: Uint8Array[]): void { writeVarInt(vector.length); vector.forEach(writeVarSlice); } diff --git a/test/integration/payments.spec.ts b/test/integration/payments.spec.ts index 4bf01f49f..673b180cd 100644 --- a/test/integration/payments.spec.ts +++ b/test/integration/payments.spec.ts @@ -30,7 +30,7 @@ async function buildAndSign( }) .addOutput({ address: regtestUtils.RANDOM_ADDRESS, - value: 2e4, + value: BigInt(2e4), }); if (depends.signatures) { @@ -41,12 +41,13 @@ async function buildAndSign( psbt.signInput(0, keyPairs[0]); } + console.log(psbt.finalizeAllInputs().extractTransaction().toHex()); return regtestUtils.broadcast( psbt.finalizeAllInputs().extractTransaction().toHex(), ); } -['p2ms', 'p2pk', 'p2pkh', 'p2wpkh'].forEach(k => { +['p2ms'].forEach(k => { const fixtures = require('../fixtures/' + k); const { depends } = fixtures.dynamic; const fn: any = (bitcoin.payments as any)[k]; diff --git a/test/integration/taproot.spec.ts b/test/integration/taproot.spec.ts index 12448623e..dde9f3559 100644 --- a/test/integration/taproot.spec.ts +++ b/test/integration/taproot.spec.ts @@ -1,15 +1,24 @@ import * as assert from 'assert'; -import BIP32Factory from 'bip32'; +import BIP32Factory, { BIP32Interface } from 'bip32'; import * as bip39 from 'bip39'; import * as ecc from 'tiny-secp256k1'; import { describe, it } from 'mocha'; -import { PsbtInput, TapLeaf, TapLeafScript } from 'bip174/src/lib/interfaces'; +import { PsbtInput, TapLeaf, TapLeafScript } from 'bip174'; import { regtestUtils } from './_regtest'; -import * as bitcoin from '../..'; -import { Taptree } from '../../src/types'; -import { LEAF_VERSION_TAPSCRIPT, tapleafHash } from '../../src/payments/bip341'; -import { toXOnly, tapTreeToList, tapTreeFromList } from '../../src/psbt/bip371'; -import { witnessStackToScriptWitness } from '../../src/psbt/psbtutils'; +import * as bitcoin from '../../'; +import { Taptree } from '../../src/cjs/types'; +import { + LEAF_VERSION_TAPSCRIPT, + tapleafHash, +} from '../../src/esm/payments/bip341.js'; +import { + toXOnly, + tapTreeToList, + tapTreeFromList, +} from '../../src/esm/psbt/bip371.js'; +import { witnessStackToScriptWitness } from '../../src/esm/psbt/psbtutils.js'; +import * as tools from 'uint8array-tools'; +import { sha256 } from '@noble/hashes/sha256'; const rng = require('randombytes'); const regtest = regtestUtils.network; @@ -46,7 +55,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { const { address, output } = bitcoin.payments.p2tr({ internalPubkey, }); - assert(output); + assert.ok(!!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. @@ -60,7 +69,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { 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, + Buffer.from(output), amount, ); // Sent 420000 sats to taproot address @@ -69,11 +78,11 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { .addInput({ hash, index, - witnessUtxo: { value: amount, script: output }, + witnessUtxo: { value: BigInt(amount), script: output }, tapInternalKey: childNodeXOnlyPubkey, }) .addOutput({ - value: sendAmount, + value: BigInt(sendAmount), address: regtestUtils.RANDOM_ADDRESS, }) .signInput(0, tweakedChildNode) @@ -108,10 +117,16 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { // amount to send const sendAmount = amount - 1e4; // get faucet - const unspent = await regtestUtils.faucetComplex(output!, amount); + const unspent = await regtestUtils.faucetComplex( + Buffer.from(output!), + amount, + ); // non segwit utxo - const p2pkhUnspent = await regtestUtils.faucetComplex(p2pkhOutput!, amount); + const p2pkhUnspent = await regtestUtils.faucetComplex( + Buffer.from(p2pkhOutput!), + amount, + ); const utx = await regtestUtils.fetch(p2pkhUnspent.txId); const nonWitnessUtxo = Buffer.from(utx.txHex, 'hex'); @@ -119,7 +134,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { psbt.addInput({ hash: unspent.txId, index: 0, - witnessUtxo: { value: amount, script: output! }, + witnessUtxo: { value: BigInt(amount), script: output! }, tapInternalKey: toXOnly(internalKey.publicKey), }); psbt.addInput({ index: 0, hash: p2pkhUnspent.txId, nonWitnessUtxo }); @@ -132,7 +147,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { }); psbt.addOutput({ - value: sendAmount, + value: BigInt(sendAmount), address: sendAddress!, tapInternalKey: sendPubKey, }); @@ -147,7 +162,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { const tx = psbt.extractTransaction(); const rawTx = tx.toBuffer(); - const hex = rawTx.toString('hex'); + const hex = tools.toHex(rawTx); await regtestUtils.broadcast(hex); await regtestUtils.verify({ @@ -162,8 +177,8 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { const internalKey = bip32.fromSeed(rng(64), regtest); const leafKey = bip32.fromSeed(rng(64), regtest); - const leafScriptAsm = `${toXOnly(leafKey.publicKey).toString( - 'hex', + const leafScriptAsm = `${tools.toHex( + toXOnly(leafKey.publicKey), )} OP_CHECKSIG`; const leafScript = bitcoin.script.fromASM(leafScriptAsm); @@ -182,17 +197,20 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { // amount to send const sendAmount = amount - 1e4; // get faucet - const unspent = await regtestUtils.faucetComplex(output!, amount); + const unspent = await regtestUtils.faucetComplex( + Buffer.from(output!), + amount, + ); const psbt = new bitcoin.Psbt({ network: regtest }); psbt.addInput({ hash: unspent.txId, index: 0, - witnessUtxo: { value: amount, script: output! }, + witnessUtxo: { value: BigInt(amount), script: output! }, tapInternalKey: toXOnly(internalKey.publicKey), tapMerkleRoot: hash, }); - psbt.addOutput({ value: sendAmount, address: address! }); + psbt.addOutput({ value: BigInt(sendAmount), address: address! }); const tweakedSigner = internalKey.tweak( bitcoin.crypto.taggedHash( @@ -206,7 +224,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { const tx = psbt.extractTransaction(); const rawTx = tx.toBuffer(); - const hex = rawTx.toString('hex'); + const hex = tools.toHex(rawTx); await regtestUtils.broadcast(hex); await regtestUtils.verify({ @@ -221,8 +239,8 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { const internalKey = bip32.fromSeed(rng(64), regtest); const leafKey = bip32.fromSeed(rng(64), regtest); - const leafScriptAsm = `${toXOnly(leafKey.publicKey).toString( - 'hex', + const leafScriptAsm = `${tools.toHex( + toXOnly(leafKey.publicKey), )} OP_CHECKSIG`; const leafScript = bitcoin.script.fromASM(leafScriptAsm); @@ -288,13 +306,16 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { // amount to send const sendAmount = amount - 1e4; // get faucet - const unspent = await regtestUtils.faucetComplex(output!, amount); + const unspent = await regtestUtils.faucetComplex( + Buffer.from(output!), + amount, + ); const psbt = new bitcoin.Psbt({ network: regtest }); psbt.addInput({ hash: unspent.txId, index: 0, - witnessUtxo: { value: amount, script: output! }, + witnessUtxo: { value: BigInt(amount), script: output! }, }); psbt.updateInput(0, { tapLeafScript: [ @@ -315,7 +336,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { }); psbt.addOutput({ - value: sendAmount, + value: BigInt(sendAmount), address: sendAddress!, tapInternalKey: sendPubKey, tapTree: { leaves: tapTreeToList(scriptTree) }, @@ -325,7 +346,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { psbt.finalizeInput(0); const tx = psbt.extractTransaction(); const rawTx = tx.toBuffer(); - const hex = rawTx.toString('hex'); + const hex = tools.toHex(rawTx); await regtestUtils.broadcast(hex); await regtestUtils.verify({ @@ -339,7 +360,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { 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 leafPubkey = tools.toHex(toXOnly(leafKey.publicKey)); const leafScriptAsm = `OP_10 OP_CHECKSEQUENCEVERIFY OP_DROP ${leafPubkey} OP_CHECKSIG`; const leafScript = bitcoin.script.fromASM(leafScriptAsm); @@ -378,14 +399,17 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { // amount to send const sendAmount = amount - 1e4; // get faucet - const unspent = await regtestUtils.faucetComplex(output!, amount); + const unspent = await regtestUtils.faucetComplex( + Buffer.from(output!), + amount, + ); const psbt = new bitcoin.Psbt({ network: regtest }); psbt.addInput({ hash: unspent.txId, index: 0, sequence: 10, - witnessUtxo: { value: amount, script: output! }, + witnessUtxo: { value: BigInt(amount), script: output! }, }); psbt.updateInput(0, { tapLeafScript: [ @@ -405,7 +429,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { network: regtest, }); - psbt.addOutput({ value: sendAmount, address: sendAddress! }); + psbt.addOutput({ value: BigInt(sendAmount), address: sendAddress! }); // just to test that updateOutput works as expected psbt.updateOutput(0, { tapInternalKey: sendPubKey, @@ -417,7 +441,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { psbt.finalizeInput(0); const tx = psbt.extractTransaction(); const rawTx = tx.toBuffer(); - const hex = rawTx.toString('hex'); + const hex = tools.toHex(rawTx); try { // broadcast before the confirmation period has expired @@ -443,12 +467,12 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { 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 = []; + const leafKeys: BIP32Interface[] = []; + const leafPubkeys: string[] = []; for (let i = 0; i < 3; i++) { const leafKey = bip32.fromSeed(rng(64), regtest); leafKeys.push(leafKey); - leafPubkeys.push(toXOnly(leafKey.publicKey).toString('hex')); + leafPubkeys.push(tools.toHex(toXOnly(leafKey.publicKey))); } const leafScriptAsm = `${leafPubkeys[2]} OP_CHECKSIG ${leafPubkeys[1]} OP_CHECKSIGADD ${leafPubkeys[0]} OP_CHECKSIGADD OP_3 OP_NUMEQUAL`; @@ -489,13 +513,16 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { // amount to send const sendAmount = amount - 1e4; // get faucet - const unspent = await regtestUtils.faucetComplex(output!, amount); + const unspent = await regtestUtils.faucetComplex( + Buffer.from(output!), + amount, + ); const psbt = new bitcoin.Psbt({ network: regtest }); psbt.addInput({ hash: unspent.txId, index: 0, - witnessUtxo: { value: amount, script: output! }, + witnessUtxo: { value: BigInt(amount), script: output! }, }); psbt.updateInput(0, { tapLeafScript: [ @@ -507,7 +534,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { ], }); - psbt.addOutput({ value: sendAmount, address: address! }); + psbt.addOutput({ value: BigInt(sendAmount), address: address! }); // random order for signers psbt.signInput(0, leafKeys[1]); @@ -517,7 +544,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { psbt.finalizeInput(0); const tx = psbt.extractTransaction(); const rawTx = tx.toBuffer(); - const hex = rawTx.toString('hex'); + const hex = tools.toHex(rawTx); await regtestUtils.broadcast(hex); await regtestUtils.verify({ @@ -529,8 +556,8 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { }); it('can create (and broadcast via 3PBP) a taproot script-path spend Transaction - OP_CHECKSIGADD (2-of-3) and verify unspendable internalKey', async () => { - const leafKeys = []; - const leafPubkeys: Buffer[] = []; + const leafKeys: BIP32Interface[] = []; + const leafPubkeys: Uint8Array[] = []; for (let i = 0; i < 3; i++) { const leafKey = bip32.fromSeed(rng(64), regtest); leafKeys.push(leafKey); @@ -553,16 +580,19 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { // amount to send const sendAmount = amount - 1e4; // get faucet - const unspent = await regtestUtils.faucetComplex(wallet.output, amount); + const unspent = await regtestUtils.faucetComplex( + Buffer.from(wallet.output), + amount, + ); const psbt = new bitcoin.Psbt({ network: regtest }); // Adding an input is a bit special in this case, // So we contain it in the wallet class // Any wallet can do this, wallet2 or wallet3 could be used. - wallet.addInput(psbt, unspent.txId, unspent.vout, unspent.value); + wallet.addInput(psbt, unspent.txId, unspent.vout, BigInt(unspent.value)); - psbt.addOutput({ value: sendAmount, address: wallet.address }); + psbt.addOutput({ value: BigInt(sendAmount), address: wallet.address }); // Sign with at least 2 of the 3 wallets. // Verify that there is a matching leaf script @@ -580,7 +610,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { psbt.finalizeAllInputs(); const tx = psbt.extractTransaction(); const rawTx = tx.toBuffer(); - const hex = rawTx.toString('hex'); + const hex = tools.toHex(rawTx); await regtestUtils.broadcast(hex); await regtestUtils.verify({ @@ -600,7 +630,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { depth: 3, leafVersion: LEAF_VERSION_TAPSCRIPT, script: bitcoin.script.fromASM(`OP_ADD OP_${index * 2} OP_EQUAL`), - } as TapLeaf), + }) as TapLeaf, ); const scriptTree = tapTreeFromList(leaves); @@ -623,13 +653,16 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { // amount to send const sendAmount = amount - 1e4; // get faucet - const unspent = await regtestUtils.faucetComplex(output!, amount); + const unspent = await regtestUtils.faucetComplex( + Buffer.from(output!), + amount, + ); const psbt = new bitcoin.Psbt({ network: regtest }); psbt.addInput({ hash: unspent.txId, index: 0, - witnessUtxo: { value: amount, script: output! }, + witnessUtxo: { value: BigInt(amount), script: output! }, }); const tapLeafScript: TapLeafScript = { @@ -642,7 +675,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { const sendAddress = 'bcrt1pqknex3jwpsaatu5e5dcjw70nac3fr5k5y3hcxr4hgg6rljzp59nqs6a0vh'; psbt.addOutput({ - value: sendAmount, + value: BigInt(sendAmount), address: sendAddress, }); @@ -653,7 +686,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { psbt.finalizeInput(0, leafIndexFinalizerFn); const tx = psbt.extractTransaction(); const rawTx = tx.toBuffer(); - const hex = rawTx.toString('hex'); + const hex = tools.toHex(rawTx); await regtestUtils.broadcast(hex); await regtestUtils.verify({ @@ -667,9 +700,9 @@ 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, + pubkey: Uint8Array, + msghash: Uint8Array, + signature: Uint8Array, ) => { return ecc.verifySchnorr(msghash, pubkey, signature); }; @@ -690,7 +723,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { const psbt = bitcoin.Psbt.fromBase64(psbtBase64); - assert( + assert.ok( !psbt.validateSignaturesOfAllInputs(schnorrValidator), 'Should fail validation', ); @@ -698,9 +731,9 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { it('should succeed validating valid signatures for taproot (See issue #1934)', () => { const schnorrValidator = ( - pubkey: Buffer, - msghash: Buffer, - signature: Buffer, + pubkey: Uint8Array, + msghash: Uint8Array, + signature: Uint8Array, ) => { return ecc.verifySchnorr(msghash, pubkey, signature); }; @@ -719,7 +752,7 @@ describe('bitcoinjs-lib (transaction with taproot)', () => { const psbt = bitcoin.Psbt.fromBase64(psbtBase64); - assert( + assert.ok( psbt.validateSignaturesOfAllInputs(schnorrValidator), 'Should succeed validation', ); @@ -732,21 +765,21 @@ function buildLeafIndexFinalizer( ): ( inputIndex: number, _input: PsbtInput, - _tapLeafHashToFinalize?: Buffer, + _tapLeafHashToFinalize?: Uint8Array, ) => { - finalScriptWitness: Buffer | undefined; + finalScriptWitness: Uint8Array | undefined; } { return ( inputIndex: number, _input: PsbtInput, - _tapLeafHashToFinalize?: Buffer, + _tapLeafHashToFinalize?: Uint8Array, ): { - finalScriptWitness: Buffer | undefined; + finalScriptWitness: Uint8Array | undefined; } => { try { const scriptSolution = [ - Buffer.from([leafIndex]), - Buffer.from([leafIndex]), + Uint8Array.from([leafIndex]), + Uint8Array.from([leafIndex]), ]; const witness = scriptSolution .concat(tapLeafScript.script) @@ -758,7 +791,7 @@ function buildLeafIndexFinalizer( }; } -function makeUnspendableInternalKey(provableNonce?: Buffer): Buffer { +function makeUnspendableInternalKey(provableNonce?: Uint8Array): Uint8Array { // This is the generator point of secp256k1. Private key is known (equal to 1) const G = Buffer.from( '0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8', @@ -768,11 +801,11 @@ function makeUnspendableInternalKey(provableNonce?: Buffer): Buffer { // It is also a valid X value on the curve, but we don't know what the private key is. // Since we know this X value (a fake "public key") is made from a hash of a well known value, // We can prove that the internalKey is unspendable. - const Hx = bitcoin.crypto.sha256(G); + const Hx = sha256(G); // This "Nothing Up My Sleeve" value is mentioned in BIP341 so we verify it here: assert.strictEqual( - Hx.toString('hex'), + tools.toHex(Hx), '50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0', ); @@ -803,17 +836,17 @@ function makeUnspendableInternalKey(provableNonce?: Buffer): Buffer { } class TaprootMultisigWallet { - private leafScriptCache: Buffer | null = null; - private internalPubkeyCache: Buffer | null = null; + private leafScriptCache: Uint8Array | null = null; + private internalPubkeyCache: Uint8Array | null = null; private paymentCache: bitcoin.Payment | null = null; - private readonly publicKeyCache: Buffer; + private readonly publicKeyCache: Uint8Array; network: bitcoin.Network; constructor( /** * A list of all the (x-only) pubkeys in the multisig */ - private readonly pubkeys: Buffer[], + private readonly pubkeys: Uint8Array[], /** * The number of required signatures */ @@ -821,7 +854,7 @@ class TaprootMultisigWallet { /** * The private key you hold. */ - private readonly privateKey: Buffer, + private readonly privateKey: Uint8Array, /** * leaf version (0xc0 currently) */ @@ -831,42 +864,42 @@ class TaprootMultisigWallet { * the fact that key-spend is unspendable should not be public, * BUT each signer must verify that it is unspendable to be safe. */ - private readonly sharedNonce?: Buffer, + private readonly sharedNonce?: Uint8Array, ) { this.network = bitcoin.networks.bitcoin; - assert(pubkeys.length > 0, 'Need pubkeys'); - assert( + assert.ok(pubkeys.length > 0, 'Need pubkeys'); + assert.ok( pubkeys.every(p => p.length === 32), 'Pubkeys must be 32 bytes (x-only)', ); - assert( + assert.ok( requiredSigs > 0 && requiredSigs <= pubkeys.length, 'Invalid requiredSigs', ); - assert( + assert.ok( leafVersion <= 0xff && (leafVersion & 1) === 0, 'Invalid leafVersion', ); if (sharedNonce) { - assert( + assert.ok( sharedNonce.length === 32 && ecc.isPrivate(sharedNonce), 'Invalid sharedNonce', ); } const pubkey = ecc.pointFromScalar(privateKey); - assert(pubkey, 'Invalid pubkey'); + assert.ok(pubkey, 'Invalid pubkey'); this.publicKeyCache = Buffer.from(pubkey); - assert( - pubkeys.some(p => p.equals(toXOnly(this.publicKeyCache))), + assert.ok( + pubkeys.some(p => tools.compare(p, toXOnly(this.publicKeyCache))), 'At least one pubkey must match your private key', ); // IMPORTANT: Make sure the pubkeys are sorted (To prevent ordering issues between wallet signers) - this.pubkeys.sort((a, b) => a.compare(b)); + this.pubkeys.sort((a, b) => tools.compare(a, b)); } setNetwork(network: bitcoin.Network): this { @@ -876,7 +909,7 @@ class TaprootMultisigWallet { // Required for Signer interface. // Prevent setting by using a getter. - get publicKey(): Buffer { + get publicKey(): Uint8Array { return this.publicKeyCache; } @@ -884,11 +917,11 @@ class TaprootMultisigWallet { * Lazily build the leafScript. A 2 of 3 would look like: * key1 OP_CHECKSIG key2 OP_CHECKSIGADD key3 OP_CHECKSIGADD OP_2 OP_GREATERTHANOREQUAL */ - get leafScript(): Buffer { + get leafScript(): Uint8Array { if (this.leafScriptCache) { return this.leafScriptCache; } - const ops = []; + const ops: bitcoin.Stack = []; this.pubkeys.forEach(pubkey => { if (ops.length === 0) { ops.push(pubkey); @@ -909,7 +942,7 @@ class TaprootMultisigWallet { return this.leafScriptCache; } - get internalPubkey(): Buffer { + get internalPubkey(): Uint8Array { if (this.internalPubkeyCache) { return this.internalPubkeyCache; } @@ -928,7 +961,7 @@ class TaprootMultisigWallet { } get redeem(): { - output: Buffer; + output: Uint8Array; redeemVersion: number; } { return { @@ -950,7 +983,7 @@ class TaprootMultisigWallet { return this.paymentCache; } - get output(): Buffer { + get output(): Uint8Array { return this.payment.output!; } @@ -958,7 +991,7 @@ class TaprootMultisigWallet { return this.payment.address!; } - get controlBlock(): Buffer { + get controlBlock(): Uint8Array { const witness = this.payment.witness!; return witness[witness.length - 1]; } @@ -971,8 +1004,9 @@ class TaprootMultisigWallet { const hasMatch = input.tapLeafScript.length === 1 && input.tapLeafScript[0].leafVersion === this.leafVersion && - input.tapLeafScript[0].script.equals(this.leafScript) && - input.tapLeafScript[0].controlBlock.equals(this.controlBlock); + tools.compare(input.tapLeafScript[0].script, this.leafScript) === 0 && + tools.compare(input.tapLeafScript[0].controlBlock, this.controlBlock) === + 0; if (!hasMatch) throw new Error( 'No matching leafScript, or extra leaf script. Refusing to sign.', @@ -983,7 +1017,7 @@ class TaprootMultisigWallet { psbt: bitcoin.Psbt, hash: string | Buffer, index: number, - value: number, + value: bigint, ) { psbt.addInput({ hash, @@ -1009,10 +1043,11 @@ class TaprootMultisigWallet { for (const input of psbt.data.inputs) { if (!input.tapScriptSig) continue; const signedPubkeys = input.tapScriptSig - .filter(ts => ts.leafHash.equals(leafHash)) + .filter(ts => tools.compare(ts.leafHash, leafHash) === 0) .map(ts => ts.pubkey); for (const pubkey of this.pubkeys) { - if (signedPubkeys.some(sPub => sPub.equals(pubkey))) continue; + if (signedPubkeys.some(sPub => tools.compare(sPub, pubkey) === 0)) + continue; // Before finalizing, every key that did not sign must have an empty signature // in place where their signature would be. // In order to do this currently we need to construct a dummy signature manually. @@ -1029,12 +1064,12 @@ class TaprootMultisigWallet { } // required for Signer interface - sign(hash: Buffer, _lowR?: boolean): Buffer { - return Buffer.from(ecc.sign(hash, this.privateKey)); + sign(hash: Uint8Array, _lowR?: boolean): Uint8Array { + return ecc.sign(hash, this.privateKey); } // required for Signer interface - signSchnorr(hash: Buffer): Buffer { - return Buffer.from(ecc.signSchnorr(hash, this.privateKey)); + signSchnorr(hash: Uint8Array): Uint8Array { + return ecc.signSchnorr(hash, this.privateKey); } } diff --git a/test/integration/transactions.spec.ts b/test/integration/transactions.spec.ts index 2754ee226..af73f5e3f 100644 --- a/test/integration/transactions.spec.ts +++ b/test/integration/transactions.spec.ts @@ -5,6 +5,7 @@ import ECPairFactory from 'ecpair'; import { describe, it } from 'mocha'; import * as bitcoin from '../..'; import { regtestUtils } from './_regtest'; +import * as tools from 'uint8array-tools'; const ECPair = ECPairFactory(ecc); const rng = require('randombytes'); @@ -12,9 +13,9 @@ const regtest = regtestUtils.network; const bip32 = BIP32Factory(ecc); const validator = ( - pubkey: Buffer, - msghash: Buffer, - signature: Buffer, + pubkey: Uint8Array, + msghash: Uint8Array, + signature: Uint8Array, ): boolean => ECPair.fromPublicKey(pubkey).verify(msghash, signature); // See bottom of file for some helper functions used to make the payment objects needed. @@ -67,7 +68,7 @@ describe('bitcoinjs-lib (transactions with psbt)', () => { }); psbt.addOutput({ address: '1KRMKfeZcmosxALVYESdPNez1AP1mEtywp', - value: 80000, + value: 80000n, }); psbt.signInput(0, alice); psbt.validateSignaturesOfInput(0, validator); @@ -117,11 +118,11 @@ describe('bitcoinjs-lib (transactions with psbt)', () => { .addInput(inputData2) // alice2 unspent .addOutput({ address: 'mwCwTceJvYV27KXBc3NJZys6CjsgsoeHmf', - value: 8e4, + value: BigInt(8e4), }) // the actual "spend" .addOutput({ address: alice2.payment.address, // OR script, which is a Buffer. - value: 1e4, + value: BigInt(1e4), }); // Alice's change // (in)(5e4 + 7e4) - (out)(8e4 + 1e4) = (fee)3e4 = 30000, this is the miner fee @@ -186,11 +187,11 @@ describe('bitcoinjs-lib (transactions with psbt)', () => { .addInput(inputData1) .addOutput({ script: embed.output!, - value: 1000, + value: 1000n, }) .addOutput({ address: regtestUtils.RANDOM_ADDRESS, - value: 1e5, + value: BigInt(1e5), }) .signInput(0, alice1.keys[0]); @@ -221,7 +222,7 @@ describe('bitcoinjs-lib (transactions with psbt)', () => { .addInput(inputData1) .addOutput({ address: regtestUtils.RANDOM_ADDRESS, - value: 1e4, + value: BigInt(1e4), }) .signInput(0, multisig.keys[0]) .signInput(0, multisig.keys[2]); @@ -268,11 +269,11 @@ describe('bitcoinjs-lib (transactions with psbt)', () => { const keyPair = p2sh.keys[0]; const outputData = { script: p2sh.payment.output, // sending to myself for fun - value: 2e4, + value: BigInt(2e4), }; const outputData2 = { script: p2sh.payment.output, // sending to myself for fun - value: 7e4, + value: BigInt(7e4), }; const tx = new bitcoin.Psbt() @@ -302,11 +303,11 @@ describe('bitcoinjs-lib (transactions with psbt)', () => { const keyPair = p2sh.keys[0]; const outputData = { script: p2sh.payment.output, - value: 2e4, + value: BigInt(2e4), }; const outputData2 = { script: p2sh.payment.output, - value: 7e4, + value: BigInt(7e4), }; const tx = new bitcoin.Psbt() .addInputs([inputData, inputData2]) @@ -337,7 +338,7 @@ describe('bitcoinjs-lib (transactions with psbt)', () => { .addInput(inputData) .addOutput({ address: regtestUtils.RANDOM_ADDRESS, - value: 2e4, + value: BigInt(2e4), }) .signInput(0, p2wpkh.keys[0]); @@ -371,7 +372,7 @@ describe('bitcoinjs-lib (transactions with psbt)', () => { .addInput(inputData) .addOutput({ address: regtestUtils.RANDOM_ADDRESS, - value: 2e4, + value: BigInt(2e4), }) .signInput(0, p2wpkh.keys[0]); psbt.finalizeAllInputs(); @@ -405,7 +406,7 @@ describe('bitcoinjs-lib (transactions with psbt)', () => { .addInput(inputData) .addOutput({ address: regtestUtils.RANDOM_ADDRESS, - value: 2e4, + value: BigInt(2e4), }) .signInput(0, p2wsh.keys[0]); @@ -434,7 +435,7 @@ describe('bitcoinjs-lib (transactions with psbt)', () => { .addInput(inputData) .addOutput({ address: regtestUtils.RANDOM_ADDRESS, - value: 2e4, + value: BigInt(2e4), }) .signInput(0, p2wsh.keys[0]); psbt.finalizeAllInputs(); @@ -472,7 +473,7 @@ describe('bitcoinjs-lib (transactions with psbt)', () => { .addInput(inputData) .addOutput({ address: regtestUtils.RANDOM_ADDRESS, - value: 2e4, + value: BigInt(2e4), }) .signInput(0, p2sh.keys[0]) .signInput(0, p2sh.keys[2]) @@ -519,7 +520,7 @@ describe('bitcoinjs-lib (transactions with psbt)', () => { .addInput(inputData) .addOutput({ address: regtestUtils.RANDOM_ADDRESS, - value: 2e4, + value: BigInt(2e4), }) .signInput(0, p2sh.keys[0]) .signInput(0, p2sh.keys[2]) @@ -551,7 +552,7 @@ describe('bitcoinjs-lib (transactions with psbt)', () => { .addInput(inputData) .addOutput({ address: regtestUtils.RANDOM_ADDRESS, - value: 2e4, + value: BigInt(2e4), }) .signInput(0, p2sh.keys[0]); psbt.finalizeAllInputs(); @@ -605,7 +606,7 @@ describe('bitcoinjs-lib (transactions with psbt)', () => { // .updateInput(0, updateData) // if you didn't merge the bip32Derivation with inputData .addOutput({ address: regtestUtils.RANDOM_ADDRESS, - value: 2e4, + value: BigInt(2e4), }) .signInputHD(0, hdRoot); // must sign with root!!! @@ -655,7 +656,9 @@ function createPayment(_type: string, myKeys?: any[], network?: any): any { if (type.slice(0, 4) === 'p2ms') { payment = bitcoin.payments.p2ms({ m, - pubkeys: keys.map(key => key.publicKey).sort((a, b) => a.compare(b)), + pubkeys: keys + .map(key => key.publicKey) + .sort((a, b) => tools.compare(a, b)), network, }); } else if (['p2sh', 'p2wsh'].indexOf(type) > -1) { @@ -679,7 +682,8 @@ function createPayment(_type: string, myKeys?: any[], network?: any): any { function getWitnessUtxo(out: any): any { delete out.address; - out.script = Buffer.from(out.script, 'hex'); + out.script = tools.fromHex(out.script); + out.value = BigInt(out.value); return out; } @@ -689,7 +693,10 @@ async function getInputData( isSegwit: boolean, redeemType: string, ): Promise { - const unspent = await regtestUtils.faucetComplex(payment.output, amount); + const unspent = await regtestUtils.faucetComplex( + Buffer.from(payment.output), + amount, + ); const utx = await regtestUtils.fetch(unspent.txId); // for non segwit inputs, you must pass the full transaction buffer const nonWitnessUtxo = Buffer.from(utx.txHex, 'hex'); diff --git a/test/payments.spec.ts b/test/payments.spec.ts index 07b1442f9..45d993213 100644 --- a/test/payments.spec.ts +++ b/test/payments.spec.ts @@ -1,124 +1,172 @@ import * as assert from 'assert'; import * as ecc from 'tiny-secp256k1'; -import { describe, it } from 'mocha'; -import { PaymentCreator } from '../src/payments'; +import { describe, it, before, beforeEach } from 'mocha'; +import { PaymentCreator } from '..'; import * as u from './payments.utils'; -import { initEccLib } from '../src'; +import { initEccLib } from '../src/esm/ecc_lib'; +import { p2data } from '../src/esm/payments/embed.js'; +import { p2ms } from '../src/esm/payments/p2ms.js'; +import { p2pk } from '../src/esm/payments/p2pk.js'; +import { p2pkh } from '../src/esm/payments/p2pkh.js'; +import { p2sh } from '../src/esm/payments/p2sh.js'; +import { p2wpkh } from '../src/esm/payments/p2wpkh.js'; +import { p2wsh } from '../src/esm/payments/p2wsh.js'; +import { p2tr } from '../src/esm/payments/p2tr.js'; -['embed', 'p2ms', 'p2pk', 'p2pkh', 'p2sh', 'p2wpkh', 'p2wsh', 'p2tr'].forEach( - p => { - describe(p, () => { - beforeEach(() => { - initEccLib(p === 'p2tr' ? ecc : undefined); - }); - let fn: PaymentCreator; - const payment = require('../src/payments/' + p); - if (p === 'embed') { - fn = payment.p2data; - } else { - fn = payment[p]; - } - - const fixtures = require('./fixtures/' + p); +import embedFixtures from './fixtures/embed.json'; +import p2msFixtures from './fixtures/p2ms.json'; +import p2pkFixtures from './fixtures/p2pk.json'; +import p2pkhFixtures from './fixtures/p2pkh.json'; +import p2shFixtures from './fixtures/p2sh.json'; +import p2wpkhFixtures from './fixtures/p2wpkh.json'; +import p2wshFixtures from './fixtures/p2wsh.json'; +import p2trFixtures from './fixtures/p2tr.json'; - fixtures.valid.forEach((f: any) => { - it(f.description + ' as expected', () => { - const args = u.preform(f.arguments); - const actual = fn(args, f.options); +let testSuite: { + paymentName: string; + fixtures: { valid: any[]; invalid: any[]; dynamic?: any }; + payment: PaymentCreator; +}[] = [ + { + paymentName: 'embed', + fixtures: embedFixtures, + payment: p2data, + }, + { + paymentName: 'p2ms', + fixtures: p2msFixtures, + payment: p2ms, + }, + { + paymentName: 'p2pk', + fixtures: p2pkFixtures, + payment: p2pk, + }, + { + paymentName: 'p2pkh', + fixtures: p2pkhFixtures, + payment: p2pkh, + }, + { + paymentName: 'p2sh', + fixtures: p2shFixtures, + payment: p2sh, + }, + { + paymentName: 'p2wpkh', + fixtures: p2wpkhFixtures, + payment: p2wpkh, + }, + { + paymentName: 'p2wsh', + fixtures: p2wshFixtures, + payment: p2wsh, + }, + { + paymentName: 'p2tr', + fixtures: p2trFixtures, + payment: p2tr, + }, +]; - u.equate(actual, f.expected, f.arguments); - }); +testSuite.forEach(p => { + describe(p.paymentName, () => { + beforeEach(async () => { + initEccLib(p.paymentName === 'p2tr' ? ecc : undefined); + }); - it(f.description + ' as expected (no validation)', () => { - const args = u.preform(f.arguments); - const actual = fn( - args, - Object.assign({}, f.options, { - validate: false, - }), - ); + p.fixtures.valid.forEach((f: any) => { + it(f.description + ' as expected', () => { + const args = u.preform(f.arguments); + const actual = p.payment(args, f.options); - 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); - - assert.throws(() => { - fn(args, f.options); - }, new RegExp(f.exception)); - }, + it(f.description + ' as expected (no validation)', () => { + const args = u.preform(f.arguments); + const actual = p.payment( + args, + Object.assign({}, f.options, { + validate: false, + }), ); + + u.equate(actual, f.expected, f.arguments); }); + }); + + p.fixtures.invalid.forEach((f: any) => { + it( + 'throws ' + f.exception + (f.description ? 'for ' + f.description : ''), + () => { + const args = u.preform(f.arguments); + assert.throws(() => { + p.payment(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.paymentName === 'p2sh') { + it('properly assembles nested p2wsh with names', () => { + const actual = p.payment({ + 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'); + }), }); - } - - // cross-verify dynamically too - if (!fixtures.dynamic) return; - const { depends, details } = fixtures.dynamic; + 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'); + }); + } - details.forEach((f: any) => { - const detail = u.preform(f); - const disabled: any = {}; - if (f.disabled) - f.disabled.forEach((k: string) => { - disabled[k] = true; - }); + // cross-verify dynamically too + if (!p.fixtures!.dynamic) return; + const { depends, details } = p.fixtures.dynamic; - for (const key in depends) { - if (key in disabled) continue; - const dependencies = depends[key]; + details.forEach((f: any) => { + const detail = u.preform(f); + const disabled: any = {}; + if (f.disabled) + f.disabled.forEach((k: string) => { + disabled[k] = true; + }); - dependencies.forEach((dependency: any) => { - if (!Array.isArray(dependency)) dependency = [dependency]; + for (const key in depends) { + if (key in disabled) continue; + const dependencies = depends[key]; - const args = {}; - dependency.forEach((d: any) => { - u.from(d, detail, args); - }); - const expected = u.from(key, detail); + dependencies.forEach((dependency: any) => { + if (!Array.isArray(dependency)) dependency = [dependency]; - it( - f.description + - ', ' + - key + - ' derives from ' + - JSON.stringify(dependency), - () => { - u.equate(fn(args), expected); - }, - ); + 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(p.payment(args), expected); + }, + ); + }); + } }); - }, -); + }); +}); diff --git a/test/payments.utils.ts b/test/payments.utils.ts index e2599204c..7b07cc9ae 100644 --- a/test/payments.utils.ts +++ b/test/payments.utils.ts @@ -1,23 +1,25 @@ import * as t from 'assert'; -import * as BNETWORKS from '../src/networks'; -import * as bscript from '../src/script'; +import * as BNETWORKS from '../src/esm/networks'; +import * as bscript from '../src/esm/script'; +import * as tools from 'uint8array-tools'; +import { isTaptree } from '../src/esm/types'; -function tryHex(x: Buffer | Buffer[]): string | string[] { - if (Buffer.isBuffer(x)) return x.toString('hex'); +function tryHex(x: Uint8Array | Uint8Array[]): string | string[] { + if (x instanceof Uint8Array) return tools.toHex(x); if (Array.isArray(x)) return x.map(tryHex) as string[]; return x; } -function fromHex(x: string | string[]): Buffer | Buffer[] { - if (typeof x === 'string') return Buffer.from(x, 'hex'); - if (Array.isArray(x)) return x.map(fromHex) as Buffer[]; +function fromHex(x: string | string[]): Uint8Array | Uint8Array[] { + if (typeof x === 'string') return tools.fromHex(x); + if (Array.isArray(x)) return x.map(fromHex) as Uint8Array[]; return x; } -function tryASM(x: Buffer): string { - if (Buffer.isBuffer(x)) return bscript.toASM(x); +function tryASM(x: Uint8Array): string { + if (x instanceof Uint8Array) return bscript.toASM(x); return x; } -function asmToBuffer(x: string): Buffer { +function asmToBuffer(x: string): Uint8Array { if (x === '') return Buffer.alloc(0); return bscript.fromASM(x); } diff --git a/test/psbt.spec.ts b/test/psbt.spec.ts index c61ec1732..3c7b9cb63 100644 --- a/test/psbt.spec.ts +++ b/test/psbt.spec.ts @@ -1,20 +1,24 @@ import * as assert from 'assert'; -import BIP32Factory from 'bip32'; +import * as BIP32Factory from 'bip32'; import * as ecc from 'tiny-secp256k1'; 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/bip341'; -import { tapTreeToList, tapTreeFromList } from '../src/psbt/bip371'; -import { Taptree } from '../src/types'; -import { initEccLib } from '../src'; +import { LEAF_VERSION_TAPSCRIPT } from '../src/esm/payments/bip341'; +import { tapTreeToList, tapTreeFromList } from '../src/esm/psbt/bip371'; +import type { Taptree } from '../src/cjs/types.js'; +import { initEccLib } from '../src/esm/ecc_lib.js'; +import * as tools from 'uint8array-tools'; -const bip32 = BIP32Factory(ecc); +const bip32 = BIP32Factory.BIP32Factory(ecc); const ECPair = ECPairFactory(ecc); -import { networks as NETWORKS, payments, Psbt, Signer, SignerAsync } from '..'; +import { Psbt } from '../src/esm/psbt.js'; +import { networks as NETWORKS } from '../src/esm/index.js'; +import { payments } from '../src/esm/index.js'; +import type { Signer, SignerAsync } from '..'; import * as preFixtures from './fixtures/psbt.json'; import * as taprootFixtures from './fixtures/p2tr.json'; @@ -25,6 +29,27 @@ const validator = ( signature: Buffer, ): boolean => ECPair.fromPublicKey(pubkey).verify(msghash, signature); +function toBip174Format(data: unknown) { + if (typeof data !== 'object' || data === null) { + return data; + } + + if (Array.isArray(data)) { + return data.map(toBip174Format); + } + + if (Buffer.isBuffer(data)) { + return Uint8Array.from(data); + } + + return Object.fromEntries( + Object.entries(data).map(([key, value]) => [ + key, + key === 'value' ? BigInt(value) : toBip174Format(value), + ]), + ); +} + const schnorrValidator = ( pubkey: Buffer, msghash: Buffer, @@ -51,7 +76,10 @@ const upperCaseFirstLetter = (str: string): string => const toAsyncSigner = (signer: Signer): SignerAsync => { const ret: SignerAsync = { publicKey: signer.publicKey, - sign: (hash: Buffer, lowerR: boolean | undefined): Promise => { + sign: ( + hash: Uint8Array, + lowerR: boolean | undefined, + ): Promise => { return new Promise((resolve, rejects): void => { setTimeout(() => { try { @@ -66,10 +94,10 @@ const toAsyncSigner = (signer: Signer): SignerAsync => { }; return ret; }; -const failedAsyncSigner = (publicKey: Buffer): SignerAsync => { +const failedAsyncSigner = (publicKey: Uint8Array): SignerAsync => { return { publicKey, - sign: (__: Buffer): Promise => { + sign: (__: Uint8Array): Promise => { return new Promise((_, reject): void => { setTimeout(() => { reject(new Error('sign failed')); @@ -120,7 +148,7 @@ describe(`Psbt`, () => { } for (const output of f.outputs) { const script = Buffer.from(output.script, 'hex'); - psbt.addOutput({ ...output, script }); + psbt.addOutput({ value: BigInt(output.value), script }); } assert.strictEqual(psbt.toBase64(), f.result); }); @@ -128,7 +156,9 @@ describe(`Psbt`, () => { fixtures.bip174.updater.forEach(f => { it('Updates PSBT to the expected result', () => { - if (f.isTaproot) initEccLib(ecc); + if (f.isTaproot) { + initEccLib(ecc); + } const psbt = Psbt.fromBase64(f.psbt); for (const inputOrOutput of ['input', 'output']) { @@ -136,7 +166,7 @@ describe(`Psbt`, () => { if (fixtureData) { for (const [i, data] of fixtureData.entries()) { const txt = upperCaseFirstLetter(inputOrOutput); - (psbt as any)[`update${txt}`](i, data); + (psbt as any)[`update${txt}`](i, toBip174Format(data)); } } } @@ -146,14 +176,16 @@ describe(`Psbt`, () => { }); fixtures.bip174.signer.forEach(f => { - it('Signs PSBT to the expected result', () => { + it.only('Signs PSBT to the expected result', () => { 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 }) => { + console.log("new keypair"); const keyPair = ECPair.fromWIF(WIF, NETWORKS.testnet); + console.log(tools.toHex(keyPair.privateKey!)); if (tapLeafHashToSign) psbt.signTaprootInput( inputToSign, @@ -560,11 +592,8 @@ describe(`Psbt`, () => { }, new RegExp('No script found for input #0')); psbt.updateInput(0, { witnessUtxo: { - script: Buffer.from( - '0014d85c2b71d0060b09c9886aeb815e50991dda124d', - 'hex', - ), - value: 2e5, + script: tools.fromHex('0014d85c2b71d0060b09c9886aeb815e50991dda124d'), + value: BigInt(2e5), }, }); assert.throws(() => { @@ -629,13 +658,13 @@ describe(`Psbt`, () => { }, new RegExp(f.exception)); } else { assert.doesNotThrow(() => { - psbt.addOutput(f.outputData as any); + psbt.addOutput(toBip174Format(f.outputData)); }); if (f.result) { assert.strictEqual(psbt.toBase64(), f.result); } assert.doesNotThrow(() => { - psbt.addOutputs([f.outputData as any]); + psbt.addOutputs([toBip174Format(f.outputData)]); }); } }); @@ -692,24 +721,25 @@ describe(`Psbt`, () => { describe('getInputType', () => { const key = ECPair.makeRandom(); const { publicKey } = key; - const p2wpkhPub = (pubkey: Buffer): Buffer => + const p2wpkhPub = (pubkey: Uint8Array): Uint8Array => payments.p2wpkh({ pubkey, }).output!; - const p2pkhPub = (pubkey: Buffer): Buffer => + const p2pkhPub = (pubkey: Uint8Array): Uint8Array => payments.p2pkh({ pubkey, }).output!; - const p2shOut = (output: Buffer): Buffer => + const p2shOut = (output: Uint8Array): Uint8Array => payments.p2sh({ redeem: { output }, }).output!; - const p2wshOut = (output: Buffer): Buffer => + const p2wshOut = (output: Uint8Array): Uint8Array => payments.p2wsh({ redeem: { output }, }).output!; - const p2shp2wshOut = (output: Buffer): Buffer => p2shOut(p2wshOut(output)); - const noOuter = (output: Buffer): Buffer => output; + const p2shp2wshOut = (output: Uint8Array): Uint8Array => + p2shOut(p2wshOut(output)); + const noOuter = (output: Uint8Array): Uint8Array => output; function getInputTypeTest({ innerScript, @@ -726,14 +756,14 @@ describe(`Psbt`, () => { index: 0, witnessUtxo: { script: outerScript(innerScript(publicKey)), - value: 2e3, + value: BigInt(2e3), }, ...(redeemGetter ? { redeemScript: redeemGetter(publicKey) } : {}), ...(witnessGetter ? { witnessScript: witnessGetter(publicKey) } : {}), }) .addOutput({ script: Buffer.from('0014d85c2b71d0060b09c9886aeb815e50991dda124d'), - value: 1800, + value: BigInt(1800), }); if (finalize) psbt.signInput(0, key).finalizeInput(0); const type = psbt.getInputType(0); @@ -823,7 +853,7 @@ describe(`Psbt`, () => { psbt.updateInput(0, { witnessUtxo: { - value: 1337, + value: 1337n, script: payments.p2sh({ redeem: { output: Buffer.from([0x51]) }, }).output!, @@ -838,7 +868,7 @@ describe(`Psbt`, () => { psbt.updateInput(0, { witnessUtxo: { - value: 1337, + value: 1337n, script: payments.p2wsh({ redeem: { output: Buffer.from([0x51]) }, }).output!, @@ -853,7 +883,7 @@ describe(`Psbt`, () => { psbt.updateInput(0, { witnessUtxo: { - value: 1337, + value: 1337n, script: payments.p2sh({ redeem: payments.p2wsh({ redeem: { output: Buffer.from([0x51]) }, @@ -895,7 +925,7 @@ describe(`Psbt`, () => { '0014000102030405060708090a0b0c0d0e0f00010203', 'hex', ), - value: 2000, + value: 2000n, bip32Derivation: [ { masterFingerprint: root.fingerprint, @@ -921,7 +951,7 @@ describe(`Psbt`, () => { script: payments.p2sh({ redeem: { output: Buffer.from([0x51]) }, }).output!, - value: 1337, + value: 1337n, }); assert.throws(() => { @@ -1200,7 +1230,7 @@ describe(`Psbt`, () => { }); psbt.addOutput({ address: '1KRMKfeZcmosxALVYESdPNez1AP1mEtywp', - value: 80000, + value: 80000n, }); psbt.signInput(0, alice); assert.throws(() => { @@ -1274,7 +1304,12 @@ describe(`Psbt`, () => { // Cache is rebuilt from internal transaction object when cleared psbt.data.inputs[index].nonWitnessUtxo = Buffer.from([1, 2, 3]); (psbt as any).__CACHE.__NON_WITNESS_UTXO_BUF_CACHE[index] = undefined; - assert.ok((psbt as any).data.inputs[index].nonWitnessUtxo.equals(value)); + assert.ok( + tools.compare( + (psbt as any).data.inputs[index].nonWitnessUtxo, + value!, + ) === 0, + ); }); }); @@ -1310,7 +1345,7 @@ describe(`Psbt`, () => { const input = psbt.txInputs[0]; const internalInput = (psbt as any).__CACHE.__TX.ins[0]; - assert.ok(input.hash.equals(internalInput.hash)); + assert.ok(tools.compare(input.hash, internalInput.hash) === 0); assert.strictEqual(input.index, internalInput.index); assert.strictEqual(input.sequence, internalInput.sequence); @@ -1318,7 +1353,7 @@ describe(`Psbt`, () => { input.index = 123; input.sequence = 123; - assert.ok(!input.hash.equals(internalInput.hash)); + assert.ok(tools.compare(input.hash, internalInput.hash) !== 0); assert.notEqual(input.index, internalInput.index); assert.notEqual(input.sequence, internalInput.sequence); }); @@ -1326,7 +1361,7 @@ describe(`Psbt`, () => { it('.txOutputs is exposed as a readonly clone', () => { const psbt = new Psbt(); const address = '1LukeQU5jwebXbMLDVydeH4vFSobRV9rkj'; - const value = 100000; + const value = 100000n; psbt.addOutput({ address, value }); const output = psbt.txOutputs[0]; @@ -1334,13 +1369,13 @@ describe(`Psbt`, () => { assert.strictEqual(output.address, address); - assert.ok(output.script.equals(internalInput.script)); + assert.ok(tools.compare(output.script, internalInput.script) === 0); assert.strictEqual(output.value, internalInput.value); output.script[0] = 123; - output.value = 123; + output.value = 123n; - assert.ok(!output.script.equals(internalInput.script)); + assert.ok(tools.compare(output.script, internalInput.script) !== 0); assert.notEqual(output.value, internalInput.value); }); }); diff --git a/test/script.spec.ts b/test/script.spec.ts index d593ab17d..9ed628616 100644 --- a/test/script.spec.ts +++ b/test/script.spec.ts @@ -1,8 +1,9 @@ import * as assert from 'assert'; import { describe, it } from 'mocha'; -import * as bscript from '../src/script'; +import { script as bscript } from '..'; import * as fixtures from './fixtures/script.json'; const minimalData = require('minimaldata'); +import * as tools from 'uint8array-tools'; describe('script', () => { // TODO @@ -62,7 +63,7 @@ describe('script', () => { it('encodes/decodes ' + ih, () => { const script = bscript.fromASM(f.input); - assert.strictEqual(script.toString('hex'), f.inputHex); + assert.strictEqual(tools.toHex(script), f.inputHex); assert.strictEqual(bscript.toASM(script), f.input); }); } @@ -70,7 +71,7 @@ describe('script', () => { if (f.outputHex) { it('encodes/decodes ' + f.output, () => { const script = bscript.fromASM(f.output); - assert.strictEqual(script.toString('hex'), f.outputHex); + assert.strictEqual(tools.toHex(script), f.outputHex); assert.strictEqual(bscript.toASM(script), f.output); }); } @@ -89,7 +90,7 @@ describe('script', () => { }); describe('toStack', () => { - fixtures.valid.forEach(f => { + fixtures.valid.forEach((f, i) => { it('returns ' + !!f.stack + ' for ' + f.asm, () => { if (!f.stack || !f.asm) return; @@ -98,7 +99,7 @@ describe('script', () => { const stack = bscript.toStack(script); assert.deepStrictEqual( stack.map(x => { - return x.toString('hex'); + return tools.toHex(x); }), f.stack, ); @@ -117,12 +118,12 @@ describe('script', () => { it('compiles ' + f.asm, () => { const scriptSig = bscript.fromASM(f.asm); - assert.strictEqual(scriptSig.toString('hex'), f.script); + assert.strictEqual(tools.toHex(scriptSig), f.script); if (f.nonstandard) { const scriptSigNS = bscript.fromASM(f.nonstandard.scriptSig); - assert.strictEqual(scriptSigNS.toString('hex'), f.script); + assert.strictEqual(tools.toHex(scriptSigNS), f.script); } }); }); @@ -133,7 +134,7 @@ describe('script', () => { it('decompiles ' + f.asm, () => { const chunks = bscript.decompile(Buffer.from(f.script, 'hex')); - assert.strictEqual(bscript.compile(chunks!).toString('hex'), f.script); + assert.strictEqual(tools.toHex(bscript.compile(chunks!)), f.script); assert.strictEqual(bscript.toASM(chunks!), f.asm); if (f.nonstandard) { @@ -141,10 +142,7 @@ describe('script', () => { Buffer.from(f.nonstandard.scriptSigHex, 'hex'), ); - assert.strictEqual( - bscript.compile(chunksNS!).toString('hex'), - f.script, - ); + assert.strictEqual(tools.toHex(bscript.compile(chunksNS!)), f.script); // toASM converts verbatim, only `compile` transforms the script to a minimalpush compliant script assert.strictEqual(bscript.toASM(chunksNS!), f.nonstandard.scriptSig); @@ -169,7 +167,7 @@ describe('script', () => { it('compliant for scriptSig ' + f.asm, () => { const script = Buffer.from(f.script, 'hex'); - assert(minimalData(script)); + assert.equal(minimalData(script), true); }); }); @@ -178,9 +176,10 @@ describe('script', () => { const buffer = Buffer.alloc(num); const script = bscript.compile([buffer]); - assert( - minimalData(script), - 'Failed for ' + num + ' length script: ' + script.toString('hex'), + assert.equal( + minimalData(Buffer.from(script)), + true, + 'Failed for ' + num + ' length script: ' + tools.toHex(script), ); }); } diff --git a/test/script_number.spec.ts b/test/script_number.spec.ts index 3b05082fb..bd01badc7 100644 --- a/test/script_number.spec.ts +++ b/test/script_number.spec.ts @@ -1,7 +1,8 @@ import * as assert from 'assert'; import { describe, it } from 'mocha'; -import * as scriptNumber from '../src/script_number'; -import * as fixtures from './fixtures/script_number.json'; +import * as scriptNumber from '../src/esm/script_number.js'; +import fixtures from './fixtures/script_number.json'; +import * as tools from 'uint8array-tools'; describe('script-number', () => { describe('decode', () => { @@ -19,7 +20,7 @@ describe('script-number', () => { it(f.number + ' returns ' + f.hex, () => { const actual = scriptNumber.encode(f.number); - assert.strictEqual(actual.toString('hex'), f.hex); + assert.strictEqual(tools.toHex(actual), f.hex); }); }); }); diff --git a/test/script_signature.spec.ts b/test/script_signature.spec.ts index f70caa475..561327d72 100644 --- a/test/script_signature.spec.ts +++ b/test/script_signature.spec.ts @@ -1,23 +1,25 @@ import * as assert from 'assert'; import { describe, it } from 'mocha'; -import { signature as bscriptSig } from '../src/script'; -import * as fixtures from './fixtures/signature.json'; +import { script } from '..'; +const bscriptSig = script.signature; +import fixtures from './fixtures/signature.json'; +import * as tools from 'uint8array-tools'; describe('Script Signatures', () => { - function fromRaw(signature: { r: string; s: string }): Buffer { - return Buffer.concat( - [Buffer.from(signature.r, 'hex'), Buffer.from(signature.s, 'hex')], - 64, - ); + function fromRaw(signature: { r: string; s: string }): Uint8Array { + return tools.concat([ + tools.fromHex(signature.r), + tools.fromHex(signature.s), + ]); } - function toRaw(signature: Buffer): { + function toRaw(signature: Uint8Array): { r: string; s: string; } { return { - r: signature.slice(0, 32).toString('hex'), - s: signature.slice(32, 64).toString('hex'), + r: tools.toHex(signature.subarray(0, 32)), + s: tools.toHex(signature.subarray(32, 64)), }; } @@ -26,7 +28,7 @@ describe('Script Signatures', () => { it('encodes ' + f.hex, () => { const buffer = bscriptSig.encode(fromRaw(f.raw), f.hashType); - assert.strictEqual(buffer.toString('hex'), f.hex); + assert.strictEqual(tools.toHex(buffer), f.hex); }); }); diff --git a/test/transaction.spec.ts b/test/transaction.spec.ts index 991557ba3..298f5ead2 100644 --- a/test/transaction.spec.ts +++ b/test/transaction.spec.ts @@ -1,8 +1,9 @@ import * as assert from 'assert'; import { beforeEach, describe, it } from 'mocha'; import { Transaction } from '..'; -import * as bscript from '../src/script'; +import { script as bscript } from '../src/esm/index.js'; import * as fixtures from './fixtures/transaction.json'; +import * as tools from 'uint8array-tools'; describe('Transaction', () => { function fromRaw(raw: any, noWitness?: boolean): Transaction { @@ -32,7 +33,7 @@ describe('Transaction', () => { }); raw.outs.forEach((txOut: any) => { - let script: Buffer; + let script: Uint8Array; if (txOut.data) { script = Buffer.from(txOut.data, 'hex'); @@ -40,7 +41,7 @@ describe('Transaction', () => { script = bscript.fromASM(txOut.script); } - tx.addOutput(script!, txOut.value); + tx.addOutput(script!, BigInt(txOut.value)); }); return tx; @@ -112,8 +113,8 @@ describe('Transaction', () => { assert.strictEqual(a.length, byteLength); assert.strictEqual(b.length, byteLength); - assert.strictEqual(a.toString('hex'), f.hex); - assert.strictEqual(b.toString('hex'), f.hex); + assert.strictEqual(tools.toHex(a), f.hex); + assert.strictEqual(tools.toHex(b), f.hex); assert.deepStrictEqual(a, b); assert.deepStrictEqual(a, target.slice(0, byteLength)); assert.deepStrictEqual(b, target.slice(byteLength)); @@ -192,8 +193,8 @@ describe('Transaction', () => { describe('addOutput', () => { it('returns an index', () => { const tx = new Transaction(); - assert.strictEqual(tx.addOutput(Buffer.alloc(0), 0), 0); - assert.strictEqual(tx.addOutput(Buffer.alloc(0), 0), 1); + assert.strictEqual(tx.addOutput(Buffer.alloc(0), 0n), 0); + assert.strictEqual(tx.addOutput(Buffer.alloc(0), 0n), 1); }); }); @@ -222,7 +223,7 @@ describe('Transaction', () => { it('should return the id for ' + f.id + '(' + f.description + ')', () => { const tx = Transaction.fromHex(f.whex || f.hex); - assert.strictEqual(tx.getHash().toString('hex'), f.hash); + assert.strictEqual(tools.toHex(tx.getHash()), f.hash); assert.strictEqual(tx.getId(), f.id); }); } @@ -263,7 +264,7 @@ describe('Transaction', () => { ), 0, ); - tx.addOutput(randScript, 5000000000); + tx.addOutput(randScript, 5000000000n); const original = (tx as any).__toBuffer; (tx as any).__toBuffer = function ( @@ -298,7 +299,7 @@ describe('Transaction', () => { const script = bscript.fromASM(f.script); assert.strictEqual( - tx.hashForSignature(f.inIndex, script, f.type).toString('hex'), + tools.toHex(tx.hashForSignature(f.inIndex, script, f.type)), f.hash, ); }, @@ -318,9 +319,9 @@ describe('Transaction', () => { const script = bscript.fromASM(f.script); assert.strictEqual( - tx - .hashForWitnessV0(f.inIndex, script, f.value, f.type) - .toString('hex'), + tools.toHex( + tx.hashForWitnessV0(f.inIndex, script, BigInt(f.value), f.type), + ), f.hash, ); }, @@ -334,16 +335,16 @@ describe('Transaction', () => { const prevOutScripts = f.utxos.map(({ scriptHex }) => Buffer.from(scriptHex, 'hex'), ); - const values = f.utxos.map(({ value }) => value); + const values = f.utxos.map(({ value }) => BigInt(value)); f.cases.forEach(c => { - let hash: Buffer; + let hash: Uint8Array; it(`should hash to ${c.hash} for ${f.description}:${c.vin}`, () => { const hashType = Buffer.from(c.typeHex, 'hex').readUInt8(0); hash = tx.hashForWitnessV1(c.vin, prevOutScripts, values, hashType); - assert.strictEqual(hash.toString('hex'), c.hash); + assert.strictEqual(tools.toHex(hash), c.hash); }); }); }); @@ -353,7 +354,7 @@ describe('Transaction', () => { it('only accepts a witness stack (Array of Buffers)', () => { assert.throws(() => { (new Transaction().setWitness as any)(0, 'foobar'); - }, /Expected property "1" of type \[Buffer], got String "foobar"/); + }, /ValiError: Invalid type: Expected Array but received "foobar"/); }); }); }); diff --git a/test/ts-node-register.js b/test/ts-node-register.js deleted file mode 100644 index fef284dc2..000000000 --- a/test/ts-node-register.js +++ /dev/null @@ -1,5 +0,0 @@ -// This file is required to run mocha tests on the TS files directly - -require("ts-node").register({ - project: "test/tsconfig.json", -}); diff --git a/test/tsconfig.json b/test/tsconfig.json deleted file mode 100644 index 6752ec5f3..000000000 --- a/test/tsconfig.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "module": "commonjs", - "outDir": "../", - "declaration": false, - "rootDir": "../", - "rootDirs": [ - "../src", - "../types" - ], - "types": [ - "node", - "mocha" - ], - "allowJs": false, - "resolveJsonModule": true, - "strict": true, - "noImplicitAny": true, - "strictNullChecks": true, - "strictFunctionTypes": true, - "strictBindCallApply": true, - "strictPropertyInitialization": true, - "noImplicitThis": true, - "alwaysStrict": true, - "esModuleInterop": false, - "noUnusedLocals": true, - "noUnusedParameters": true, - "baseUrl": ".", - "paths": { - "../src/*": ["../ts_src/*"] - } - }, - "include": [ - "./**/*.ts" - ], - "exclude": [ - "../ts_src/**/*.ts" - ] -} diff --git a/test/types.spec.ts b/test/types.spec.ts index 363b83c19..210b0d6cb 100644 --- a/test/types.spec.ts +++ b/test/types.spec.ts @@ -1,7 +1,7 @@ import * as assert from 'assert'; import { describe, it } from 'mocha'; -import * as types from '../src/types'; -const typeforce = require('typeforce'); +import * as types from '../src/esm/types'; +import * as v from 'valibot'; describe('types', () => { describe('Buffer Hash160/Hash256', () => { @@ -9,21 +9,21 @@ describe('types', () => { const buffer32byte = Buffer.alloc(32); it('return true for valid size', () => { - assert(types.Hash160bit(buffer20byte)); - assert(types.Hash256bit(buffer32byte)); + assert.equal(v.is(types.Hash160bitSchema, buffer20byte), true); + assert.equal(v.is(types.Hash256bitSchema, buffer32byte), true); }); it('return true for oneOf', () => { assert.doesNotThrow(() => { - typeforce( - types.oneOf(types.Hash160bit, types.Hash256bit), + v.parse( + v.union([types.Hash160bitSchema, types.Hash256bitSchema]), buffer32byte, ); }); assert.doesNotThrow(() => { - typeforce( - types.oneOf(types.Hash256bit, types.Hash160bit), + v.parse( + v.union([types.Hash256bitSchema, types.Hash160bitSchema]), buffer32byte, ); }); @@ -31,26 +31,28 @@ describe('types', () => { it('throws for invalid size', () => { assert.throws(() => { - types.Hash160bit(buffer32byte); - }, /Expected Buffer\(Length: 20\), got Buffer\(Length: 32\)/); + v.parse(types.Hash160bitSchema, buffer32byte); + }, /ValiError: Invalid length: Expected 20 but received 32/); assert.throws(() => { - types.Hash256bit(buffer20byte); - }, /Expected Buffer\(Length: 32\), got Buffer\(Length: 20\)/); + v.parse(types.Hash256bitSchema, buffer20byte); + }, /ValiError: Invalid length: Expected 32 but received 20/); }); }); describe('Satoshi', () => { [ - { value: -1, result: false }, - { value: 0, result: true }, - { value: 1, result: true }, - { value: 20999999 * 1e8, result: true }, - { value: 21000000 * 1e8, result: true }, - { value: 21000001 * 1e8, result: false }, + { value: BigInt(-1), result: false }, + { value: BigInt(0), result: true }, + { value: BigInt(1), result: true }, + { value: BigInt(20999999 * 1e8), result: true }, + { value: BigInt(21000000 * 1e8), result: true }, + { value: BigInt(21000001 * 1e8), result: true }, + { value: BigInt((1n << 63n) - 1n), result: true }, + { value: BigInt(1n << 63n), result: false }, ].forEach(f => { it('returns ' + f.result + ' for valid for ' + f.value, () => { - assert.strictEqual(types.Satoshi(f.value), f.result); + assert.strictEqual(v.is(types.SatoshiSchema, f.value), f.result); }); }); }); diff --git a/ts_src/address.ts b/ts_src/address.ts index 957e9b868..29b9f631c 100644 --- a/ts_src/address.ts +++ b/ts_src/address.ts @@ -11,10 +11,11 @@ import { Network } from './networks.js'; import * as networks from './networks.js'; import * as payments from './payments/index.js'; import * as bscript from './script.js'; -import { typeforce, tuple, Hash160bit, UInt8 } from './types.js'; +import { Hash160bitSchema, UInt8Schema } from './types.js'; import { bech32, bech32m } from 'bech32'; import bs58check from 'bs58check'; -import * as tools from "uint8array-tools"; +import * as tools from 'uint8array-tools'; +import * as v from 'valibot'; /** base58check decode result */ export interface Base58CheckResult { @@ -31,7 +32,7 @@ export interface Bech32Result { /** address prefix: bc for P2WPKH、P2WSH、P2TR */ prefix: string; /** address data:20 bytes for P2WPKH, 32 bytes for P2WSH、P2TR */ - data: Buffer; + data: Uint8Array; } const FUTURE_SEGWIT_MAX_SIZE: number = 40; @@ -111,19 +112,21 @@ export function fromBech32(address: string): Bech32Result { return { version, prefix: result.prefix, - data: Buffer.from(data), + data: Uint8Array.from(data), }; } /** * encode address hash to base58 address with version */ -export function toBase58Check(hash: Buffer, version: number): string { - typeforce(tuple(Hash160bit, UInt8), arguments); +export function toBase58Check(hash: Uint8Array, version: number): string { + v.parse(v.tuple([Hash160bitSchema, UInt8Schema]), [hash, version]); - const payload = Buffer.allocUnsafe(21); - payload.writeUInt8(version, 0); - hash.copy(payload, 1); + const payload = new Uint8Array(21); + // payload.writeUInt8(version, 0); + tools.writeUInt8(payload, 0, version); + // hash.copy(payload, 1); + payload.set(hash, 1); return bs58check.encode(payload); } @@ -147,7 +150,10 @@ export function toBech32( /** * decode address from output script with network, return address if matched */ -export function fromOutputScript(output: Uint8Array, network?: Network): string { +export function fromOutputScript( + output: Uint8Array, + network?: Network, +): string { // TODO: Network network = network || networks.bitcoin; @@ -176,7 +182,7 @@ export function fromOutputScript(output: Uint8Array, network?: Network): string /** * encodes address to output script with network, return output script if address matched */ -export function toOutputScript(address: string, network?: Network): Buffer { +export function toOutputScript(address: string, network?: Network): Uint8Array { network = network || networks.bitcoin; let decodeBase58: Base58CheckResult | undefined; @@ -187,9 +193,9 @@ export function toOutputScript(address: string, network?: Network): Buffer { if (decodeBase58) { if (decodeBase58.version === network.pubKeyHash) - return payments.p2pkh({ hash: decodeBase58.hash }).output as Buffer; + return payments.p2pkh({ hash: decodeBase58.hash }).output as Uint8Array; if (decodeBase58.version === network.scriptHash) - return payments.p2sh({ hash: decodeBase58.hash }).output as Buffer; + return payments.p2sh({ hash: decodeBase58.hash }).output as Uint8Array; } else { try { decodeBech32 = fromBech32(address); @@ -200,12 +206,15 @@ export function toOutputScript(address: string, network?: Network): Buffer { throw new Error(address + ' has an invalid prefix'); if (decodeBech32.version === 0) { if (decodeBech32.data.length === 20) - return payments.p2wpkh({ hash: decodeBech32.data }).output as Buffer; + return payments.p2wpkh({ hash: decodeBech32.data }) + .output as Uint8Array; if (decodeBech32.data.length === 32) - return payments.p2wsh({ hash: decodeBech32.data }).output as Buffer; + return payments.p2wsh({ hash: decodeBech32.data }) + .output as Uint8Array; } else if (decodeBech32.version === 1) { if (decodeBech32.data.length === 32) - return payments.p2tr({ pubkey: decodeBech32.data }).output as Buffer; + return payments.p2tr({ pubkey: decodeBech32.data }) + .output as Uint8Array; } else if ( decodeBech32.version >= FUTURE_SEGWIT_MIN_VERSION && decodeBech32.version <= FUTURE_SEGWIT_MAX_VERSION && diff --git a/ts_src/bip66.ts b/ts_src/bip66.ts index 47d9f7552..17ce826cc 100644 --- a/ts_src/bip66.ts +++ b/ts_src/bip66.ts @@ -2,7 +2,7 @@ // Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] // NOTE: SIGHASH byte ignored AND restricted, truncate before use -export function check(buffer: Buffer): boolean { +export function check(buffer: Uint8Array): boolean { if (buffer.length < 8) return false; if (buffer.length > 72) return false; if (buffer[0] !== 0x30) return false; @@ -81,7 +81,7 @@ export function decode(buffer: Uint8Array): { r: Uint8Array; s: Uint8Array } { * 62300 => 0x00f35c * -62300 => 0xff0ca4 */ -export function encode(r: Uint8Array, s: Uint8Array): Buffer { +export function encode(r: Uint8Array, s: Uint8Array): Uint8Array { const lenR = r.length; const lenS = s.length; if (lenR === 0) throw new Error('R length is zero'); @@ -95,7 +95,7 @@ export function encode(r: Uint8Array, s: Uint8Array): Buffer { if (lenS > 1 && s[0] === 0x00 && !(s[1] & 0x80)) throw new Error('S value excessively padded'); - const signature = Buffer.allocUnsafe(6 + lenR + lenS); + const signature = new Uint8Array(6 + lenR + lenS); // 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] signature[0] = 0x30; diff --git a/ts_src/block.ts b/ts_src/block.ts index f851c2d11..36115cae7 100644 --- a/ts_src/block.ts +++ b/ts_src/block.ts @@ -3,12 +3,14 @@ import { BufferWriter, reverseBuffer, varuint, -} from './bufferutils'; -import * as bcrypto from './crypto'; -import { fastMerkleRoot } from './merkle'; -import { Transaction } from './transaction'; -import * as types from './types'; -const { typeforce } = types; +} from './bufferutils.js'; +import * as bcrypto from './crypto.js'; +import { fastMerkleRoot } from './merkle.js'; +import { Transaction } from './transaction.js'; +import * as v from 'valibot'; +import * as tools from 'uint8array-tools'; + +// const { typeforce } = types; const errorMerkleNoTxes = new TypeError( 'Cannot compute merkle root for zero transactions', @@ -18,7 +20,7 @@ const errorWitnessNotSegwit = new TypeError( ); export class Block { - static fromBuffer(buffer: Buffer): Block { + static fromBuffer(buffer: Uint8Array): Block { if (buffer.length < 80) throw new Error('Buffer too small (< 80 bytes)'); const bufferReader = new BufferReader(buffer); @@ -58,22 +60,27 @@ export class Block { } static fromHex(hex: string): Block { - return Block.fromBuffer(Buffer.from(hex, 'hex')); + // return Block.fromBuffer(Buffer.from(hex, 'hex')); + return Block.fromBuffer(tools.fromHex(hex)); } - static calculateTarget(bits: number): Buffer { + static calculateTarget(bits: number): Uint8Array { const exponent = ((bits & 0xff000000) >> 24) - 3; const mantissa = bits & 0x007fffff; - const target = Buffer.alloc(32, 0); - target.writeUIntBE(mantissa, 29 - exponent, 3); + const target = new Uint8Array(32); + // target.writeUIntBE(mantissa, 29 - exponent, 3); + target[29 - exponent] = (mantissa >> 16) & 0xff; + target[30 - exponent] = (mantissa >> 8) & 0xff; + target[31 - exponent] = mantissa & 0xff; return target; } static calculateMerkleRoot( transactions: Transaction[], forWitness?: boolean, - ): Buffer { - typeforce([{ getHash: types.Function }], transactions); + ): Uint8Array { + // typeforce([{ getHash: types.Function }], transactions); + v.parse(v.array(v.object({ getHash: v.function() })), transactions); if (transactions.length === 0) throw errorMerkleNoTxes; if (forWitness && !txesHaveWitnessCommit(transactions)) throw errorWitnessNotSegwit; @@ -86,41 +93,46 @@ export class Block { return forWitness ? bcrypto.hash256( - Buffer.concat([rootHash, transactions[0].ins[0].witness[0]]), + tools.concat([rootHash, transactions[0].ins[0].witness[0]]), ) : rootHash; } version: number = 1; - prevHash?: Buffer = undefined; - merkleRoot?: Buffer = undefined; + prevHash?: Uint8Array = undefined; + merkleRoot?: Uint8Array = undefined; timestamp: number = 0; - witnessCommit?: Buffer = undefined; + witnessCommit?: Uint8Array = undefined; bits: number = 0; nonce: number = 0; transactions?: Transaction[] = undefined; - getWitnessCommit(): Buffer | null { + getWitnessCommit(): Uint8Array | null { if (!txesHaveWitnessCommit(this.transactions!)) return null; // The merkle root for the witness data is in an OP_RETURN output. // There is no rule for the index of the output, so use filter to find it. // The root is prepended with 0xaa21a9ed so check for 0x6a24aa21a9ed // If multiple commits are found, the output with highest index is assumed. - const witnessCommits = this.transactions![0].outs.filter(out => - out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex')), + const witnessCommits = this.transactions![0].outs.filter( + out => + // out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex')), + tools.compare( + out.script.slice(0, 6), + Uint8Array.from([0x6a, 0x24, 0xaa, 0x21, 0xa9, 0xed]), + ) === 0, ).map(out => out.script.slice(6, 38)); if (witnessCommits.length === 0) return null; // Use the commit with the highest output (should only be one though) const result = witnessCommits[witnessCommits.length - 1]; - if (!(result instanceof Buffer && result.length === 32)) return null; + if (!(result instanceof Uint8Array && result.length === 32)) return null; return result; } hasWitnessCommit(): boolean { if ( - this.witnessCommit instanceof Buffer && + this.witnessCommit instanceof Uint8Array && this.witnessCommit.length === 32 ) return true; @@ -148,12 +160,12 @@ export class Block { ); } - getHash(): Buffer { + getHash(): Uint8Array { return bcrypto.hash256(this.toBuffer(true)); } getId(): string { - return reverseBuffer(this.getHash()).toString('hex'); + return tools.toHex(reverseBuffer(this.getHash())); } getUTCDate(): Date { @@ -164,8 +176,8 @@ export class Block { } // TODO: buffer, offset compatibility - toBuffer(headersOnly?: boolean): Buffer { - const buffer: Buffer = Buffer.allocUnsafe(this.byteLength(headersOnly)); + toBuffer(headersOnly?: boolean): Uint8Array { + const buffer = new Uint8Array(this.byteLength(headersOnly)); const bufferWriter = new BufferWriter(buffer); @@ -195,7 +207,7 @@ export class Block { } toHex(headersOnly?: boolean): string { - return this.toBuffer(headersOnly).toString('hex'); + return tools.toHex(this.toBuffer(headersOnly)); } checkTxRoots(): boolean { @@ -210,17 +222,19 @@ export class Block { } checkProofOfWork(): boolean { - const hash: Buffer = reverseBuffer(this.getHash()); + const hash = reverseBuffer(this.getHash()); const target = Block.calculateTarget(this.bits); - return hash.compare(target) <= 0; + // return hash.compare(target) <= 0; + return tools.compare(hash, target) <= 0; } private __checkMerkleRoot(): boolean { if (!this.transactions) throw errorMerkleNoTxes; const actualMerkleRoot = Block.calculateMerkleRoot(this.transactions); - return this.merkleRoot!.compare(actualMerkleRoot) === 0; + // return this.merkleRoot!.compare(actualMerkleRoot) === 0; + return tools.compare(this.merkleRoot!, actualMerkleRoot) === 0; } private __checkWitnessCommit(): boolean { @@ -231,7 +245,8 @@ export class Block { this.transactions, true, ); - return this.witnessCommit!.compare(actualWitnessCommit) === 0; + // return this.witnessCommit!.compare(actualWitnessCommit) === 0; + return tools.compare(this.witnessCommit!, actualWitnessCommit) === 0; } } diff --git a/ts_src/bufferutils.ts b/ts_src/bufferutils.ts index 3d7725e08..4102ae34c 100644 --- a/ts_src/bufferutils.ts +++ b/ts_src/bufferutils.ts @@ -1,8 +1,8 @@ import * as types from './types.js'; -const { typeforce } = types; import * as varuint from 'varuint-bitcoin'; +import * as v from 'valibot'; export { varuint }; -import * as tools from "uint8array-tools"; +import * as tools from 'uint8array-tools'; const MAX_JS_NUMBER = 0x001fffffffffffff; @@ -35,17 +35,17 @@ function verifuint(value: number | bigint, max: number): void { * @param offset - The offset in the buffer where the value should be written. * @returns The new offset after writing the value. */ -export function writeUInt64LE( - buffer: Buffer, - value: number, - offset: number, -): number { - verifuint(value, MAX_JS_NUMBER); - - buffer.writeInt32LE(value & -1, offset); - buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4); - return offset + 8; -} +// export function writeUInt64LE( +// buffer: Buffer, +// value: number, +// offset: number, +// ): number { +// verifuint(value, MAX_JS_NUMBER); + +// buffer.writeInt32LE(value & -1, offset); +// buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4); +// return offset + 8; +// } /** * Reads a 64-bit signed integer from a Uint8Array in little-endian format. @@ -54,23 +54,23 @@ export function writeUInt64LE( * @param {number} offset - The offset in the buffer where the value starts. * @return {number} The 64-bit signed integer value. */ -export function readInt64LE( - buffer: Uint8Array, - offset: number -): number { - if((buffer[offset + 7] & 0x7f) > 0) throw new Error("RangeError: value out of range, greater than int64"); - - return ( - buffer[offset] | - (buffer[offset + 1] << 8) | - (buffer[offset + 2] << 16) | - (buffer[offset + 3] << 24) | - (buffer[offset + 4] << 32) | - (buffer[offset + 5] << 40) | - (buffer[offset + 6] << 48) | - (buffer[offset + 7] << 56) - ); -} +// export function readInt64LE( +// buffer: Uint8Array, +// offset: number +// ): number { +// if((buffer[offset + 7] & 0x7f) > 0) throw new Error("RangeError: value out of range, greater than int64"); + +// return ( +// buffer[offset] | +// (buffer[offset + 1] << 8) | +// (buffer[offset + 2] << 16) | +// (buffer[offset + 3] << 24) | +// (buffer[offset + 4] << 32) | +// (buffer[offset + 5] << 40) | +// (buffer[offset + 6] << 48) | +// (buffer[offset + 7] << 56) +// ); +// } /** * Reverses the order of bytes in a buffer. @@ -104,32 +104,39 @@ export class BufferWriter { return new BufferWriter(new Uint8Array(size)); } - constructor(public buffer: Uint8Array, public offset: number = 0) { - typeforce(types.tuple(types.Buffer, types.UInt32), [buffer, offset]); + constructor( + public buffer: Uint8Array, + public offset: number = 0, + ) { + // typeforce(types.tuple(types.Buffer, types.UInt32), [buffer, offset]); + v.parse(v.tuple([types.BufferSchema, types.UInt32Schema]), [ + buffer, + offset, + ]); } writeUInt8(i: number): void { // this.offset = this.buffer.writeUInt8(i, this.offset); - this.offset = tools.writeUInt8(this.buffer, i, this.offset); + this.offset = tools.writeUInt8(this.buffer, this.offset, i); } writeInt32(i: number): void { // this.offset = this.buffer.writeInt32LE(i, this.offset); - this.offset = tools.writeInt32(this.buffer, i, this.offset, "LE"); + this.offset = tools.writeInt32(this.buffer, i, this.offset, 'LE'); } writeInt64(i: number | bigint): void { - this.offset = tools.writeInt64(this.buffer, BigInt(i), this.offset, "LE"); + this.offset = tools.writeInt64(this.buffer, BigInt(i), this.offset, 'LE'); } writeUInt32(i: number): void { // this.offset = this.buffer.writeUInt32LE(i, this.offset); - this.offset = tools.writeUInt32(this.buffer, i, this.offset, "LE"); + this.offset = tools.writeUInt32(this.buffer, this.offset, i, 'LE'); } writeUInt64(i: number | bigint): void { // this.offset = writeUInt64LE(this.buffer, i, this.offset); - this.offset = tools.writeUInt64(this.buffer, this.offset, BigInt(i), "LE"); + this.offset = tools.writeUInt64(this.buffer, this.offset, BigInt(i), 'LE'); } writeVarInt(i: number): void { @@ -168,8 +175,15 @@ export class BufferWriter { * Helper class for reading of bitcoin data types from a buffer. */ export class BufferReader { - constructor(public buffer: Uint8Array, public offset: number = 0) { - typeforce(types.tuple(types.Buffer, types.UInt32), [buffer, offset]); + constructor( + public buffer: Uint8Array, + public offset: number = 0, + ) { + // typeforce(types.tuple(types.Buffer, types.UInt32), [buffer, offset]); + v.parse(v.tuple([types.BufferSchema, types.UInt32Schema]), [ + buffer, + offset, + ]); } readUInt8(): number { @@ -181,21 +195,21 @@ export class BufferReader { readInt32(): number { // const result = readInt32LE(this.buffer, this.offset); - const result = tools.readInt32(this.buffer, this.offset, "LE"); + const result = tools.readInt32(this.buffer, this.offset, 'LE'); this.offset += 4; return result; } readUInt32(): number { // const result = this.buffer.readUInt32LE(this.offset); - const result = tools.readUInt32(this.buffer, this.offset, "LE"); + const result = tools.readUInt32(this.buffer, this.offset, 'LE'); this.offset += 4; return result; } readUInt64(): bigint { // const result = readUInt64LE(this.buffer, this.offset); - const result = tools.readUInt64(this.buffer, this.offset, "LE"); + const result = tools.readUInt64(this.buffer, this.offset, 'LE'); this.offset += 8; return result; } diff --git a/ts_src/crypto.ts b/ts_src/crypto.ts index 2e534664c..3f94b2c3b 100644 --- a/ts_src/crypto.ts +++ b/ts_src/crypto.ts @@ -6,7 +6,7 @@ */ import { ripemd160 } from '@noble/hashes/ripemd160'; import { sha256 } from '@noble/hashes/sha256'; -import * as tools from "uint8array-tools"; +import * as tools from 'uint8array-tools'; export function hash160(buffer: Uint8Array): Uint8Array { return ripemd160(sha256(buffer)); @@ -27,64 +27,64 @@ export const TAGS = [ 'KeyAgg list', 'KeyAgg coefficient', ] as const; -export type TaggedHashPrefix = typeof TAGS[number]; +export type TaggedHashPrefix = (typeof TAGS)[number]; type TaggedHashPrefixes = { - [key in TaggedHashPrefix]: Buffer; + [key in TaggedHashPrefix]: Uint8Array; }; /** An object mapping tags to their tagged hash prefix of [SHA256(tag) | SHA256(tag)] */ /** * Defines the tagged hash prefixes used in the crypto module. */ export const TAGGED_HASH_PREFIXES: TaggedHashPrefixes = { - 'BIP0340/challenge': Buffer.from([ + 'BIP0340/challenge': Uint8Array.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([ + 'BIP0340/aux': Uint8Array.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([ + 'BIP0340/nonce': Uint8Array.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([ + TapLeaf: Uint8Array.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([ + TapBranch: Uint8Array.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([ + TapSighash: Uint8Array.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([ + TapTweak: Uint8Array.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([ + 'KeyAgg list': Uint8Array.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([ + 'KeyAgg coefficient': Uint8Array.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, @@ -92,6 +92,9 @@ export const TAGGED_HASH_PREFIXES: TaggedHashPrefixes = { ]), }; -export function taggedHash(prefix: TaggedHashPrefix, data: Uint8Array): Uint8Array { +export function taggedHash( + prefix: TaggedHashPrefix, + data: Uint8Array, +): Uint8Array { return sha256(tools.concat([TAGGED_HASH_PREFIXES[prefix], data])); } diff --git a/ts_src/ecc_lib.ts b/ts_src/ecc_lib.ts index fbd1fcdb8..f78bf3bbf 100644 --- a/ts_src/ecc_lib.ts +++ b/ts_src/ecc_lib.ts @@ -1,4 +1,5 @@ -import { TinySecp256k1Interface } from './types'; +import { TinySecp256k1Interface } from './types.js'; +import * as tools from 'uint8array-tools'; const _ECCLIB_CACHE: { eccLib?: TinySecp256k1Interface } = {}; @@ -35,7 +36,7 @@ export function getEccLib(): TinySecp256k1Interface { return _ECCLIB_CACHE.eccLib; } -const h = (hex: string): Buffer => Buffer.from(hex, 'hex'); +const h = (hex: string): Uint8Array => tools.fromHex(hex); /** * Verifies the ECC functionality. @@ -83,7 +84,7 @@ function verifyEcc(ecc: TinySecp256k1Interface): void { } else { assert(r !== null); assert(r!.parity === t.parity); - assert(Buffer.from(r!.xOnlyPubkey).equals(h(t.result))); + assert(tools.compare(r!.xOnlyPubkey, h(t.result)) === 0); } }); } diff --git a/ts_src/index.ts b/ts_src/index.ts index 4b4041152..27404e834 100644 --- a/ts_src/index.ts +++ b/ts_src/index.ts @@ -1,14 +1,14 @@ -import * as address from './address'; -import * as crypto from './crypto'; -import * as networks from './networks'; -import * as payments from './payments'; -import * as script from './script'; +import * as address from './address.js'; +import * as crypto from './crypto.js'; +import * as networks from './networks.js'; +import * as payments from './payments/index.js'; +import * as script from './script.js'; export { address, crypto, networks, payments, script }; -export { Block } from './block'; +export { Block } from './block.js'; /** @hidden */ -export { TaggedHashPrefix } from './crypto'; +export { TaggedHashPrefix } from './crypto.js'; export { Psbt, PsbtTxInput, @@ -17,12 +17,12 @@ export { SignerAsync, HDSigner, HDSignerAsync, -} from './psbt'; +} from './psbt.js'; /** @hidden */ -export { OPS as opcodes } from './ops'; -export { Transaction } from './transaction'; +export { OPS as opcodes } from './ops.js'; +export { Transaction } from './transaction.js'; /** @hidden */ -export { Network } from './networks'; +export { Network } from './networks.js'; /** @hidden */ export { Payment, @@ -30,6 +30,6 @@ export { PaymentOpts, Stack, StackElement, -} from './payments'; -export { Input as TxInput, Output as TxOutput } from './transaction'; -export { initEccLib } from './ecc_lib'; +} from './payments/index.js'; +export { Input as TxInput, Output as TxOutput } from './transaction.js'; +export { initEccLib } from './ecc_lib.js'; diff --git a/ts_src/merkle.ts b/ts_src/merkle.ts index 206f8fcd0..316155ae0 100644 --- a/ts_src/merkle.ts +++ b/ts_src/merkle.ts @@ -1,3 +1,5 @@ +import * as tools from 'uint8array-tools'; + /** * Calculates the Merkle root of an array of buffers using a specified digest function. * @@ -7,9 +9,9 @@ * @throws {TypeError} If the values parameter is not an array or the digestFn parameter is not a function. */ export function fastMerkleRoot( - values: Buffer[], - digestFn: (b: Buffer) => Buffer, -): Buffer { + values: Uint8Array[], + digestFn: (b: Uint8Array) => Uint8Array, +): Uint8Array { if (!Array.isArray(values)) throw TypeError('Expected values Array'); if (typeof digestFn !== 'function') throw TypeError('Expected digest Function'); @@ -23,7 +25,7 @@ export function fastMerkleRoot( for (let i = 0; i < length; i += 2, ++j) { const left = results[i]; const right = i + 1 === length ? left : results[i + 1]; - const data = Buffer.concat([left, right]); + const data = tools.concat([left, right]); results[j] = digestFn(data); } diff --git a/ts_src/payments/bip341.ts b/ts_src/payments/bip341.ts index 8c7a36108..cee7b7ad4 100644 --- a/ts_src/payments/bip341.ts +++ b/ts_src/payments/bip341.ts @@ -1,26 +1,27 @@ -import { Buffer as NBuffer } from 'buffer'; -import { getEccLib } from '../ecc_lib'; -import * as bcrypto from '../crypto'; +// import { Buffer as NBuffer } from 'buffer'; +import { getEccLib } from '../ecc_lib.js'; +import * as bcrypto from '../crypto.js'; -import { varuint } from '../bufferutils'; -import { Tapleaf, Taptree, isTapleaf } from '../types'; +import { varuint } from '../bufferutils.js'; +import { Tapleaf, Taptree, isTapleaf } from '../types.js'; +import * as tools from 'uint8array-tools'; export const LEAF_VERSION_TAPSCRIPT = 0xc0; export const MAX_TAPTREE_DEPTH = 128; interface HashLeaf { - hash: Buffer; + hash: Uint8Array; } interface HashBranch { - hash: Buffer; + hash: Uint8Array; left: HashTree; right: HashTree; } interface TweakedPublicKey { parity: number; - x: Buffer; + x: Uint8Array; } const isHashBranch = (ht: HashTree): ht is HashBranch => @@ -42,9 +43,9 @@ export type HashTree = HashLeaf | HashBranch; * @throws {TypeError} If the control block length is less than 33. */ export function rootHashFromPath( - controlBlock: Buffer, - leafHash: Buffer, -): Buffer { + controlBlock: Uint8Array, + leafHash: Uint8Array, +): Uint8Array { if (controlBlock.length < 33) throw new TypeError( `The control-block length is too small. Got ${controlBlock.length}, expected min 33.`, @@ -54,7 +55,8 @@ export function rootHashFromPath( 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) { + // if (kj.compare(ej) < 0) { + if (tools.compare(kj, ej) < 0) { kj = tapBranchHash(kj, ej); } else { kj = tapBranchHash(ej, kj); @@ -72,7 +74,8 @@ export function toHashTree(scriptTree: Taptree): HashTree { if (isTapleaf(scriptTree)) return { hash: tapleafHash(scriptTree) }; const hashes = [toHashTree(scriptTree[0]), toHashTree(scriptTree[1])]; - hashes.sort((a, b) => a.hash.compare(b.hash)); + // hashes.sort((a, b) => a.hash.compare(b.hash)); + hashes.sort((a, b) => tools.compare(a.hash, b.hash)); const [left, right] = hashes; return { @@ -92,41 +95,45 @@ export function toHashTree(scriptTree: Taptree): HashTree { */ export function findScriptPath( node: HashTree, - hash: Buffer, -): Buffer[] | undefined { + hash: Uint8Array, +): Uint8Array[] | 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)) { + // } else if (node.hash.equals(hash)) { + } else if (tools.compare(node.hash, hash) === 0) { return []; } return undefined; } -export function tapleafHash(leaf: Tapleaf): Buffer { +export function tapleafHash(leaf: Tapleaf): Uint8Array { const version = leaf.version || LEAF_VERSION_TAPSCRIPT; return bcrypto.taggedHash( 'TapLeaf', - NBuffer.concat([NBuffer.from([version]), serializeScript(leaf.output)]), + tools.concat([Uint8Array.from([version]), serializeScript(leaf.output)]), ); } -export function tapTweakHash(pubKey: Buffer, h: Buffer | undefined): Buffer { +export function tapTweakHash( + pubKey: Uint8Array, + h: Uint8Array | undefined, +): Uint8Array { return bcrypto.taggedHash( 'TapTweak', - NBuffer.concat(h ? [pubKey, h] : [pubKey]), + tools.concat(h ? [pubKey, h] : [pubKey]), ); } export function tweakKey( - pubKey: Buffer, - h: Buffer | undefined, + pubKey: Uint8Array, + h: Uint8Array | undefined, ): TweakedPublicKey | null { - if (!NBuffer.isBuffer(pubKey)) return null; + if (!(pubKey instanceof Uint8Array)) return null; if (pubKey.length !== 32) return null; if (h && h.length !== 32) return null; @@ -137,18 +144,19 @@ export function tweakKey( return { parity: res.parity, - x: NBuffer.from(res.xOnlyPubkey), + x: Uint8Array.from(res.xOnlyPubkey), }; } -function tapBranchHash(a: Buffer, b: Buffer): Buffer { - return bcrypto.taggedHash('TapBranch', NBuffer.concat([a, b])); +function tapBranchHash(a: Uint8Array, b: Uint8Array): Uint8Array { + return bcrypto.taggedHash('TapBranch', tools.concat([a, b])); } -function serializeScript(s: Buffer): Buffer { +function serializeScript(s: Uint8Array): Uint8Array { /* global BigInt */ const varintLen = varuint.encodingLength(s.length); - const buffer = NBuffer.allocUnsafe(varintLen); // better + // const buffer = NBuffer.allocUnsafe(varintLen); // better + const buffer = new Uint8Array(varintLen); varuint.encode(s.length, buffer); - return NBuffer.concat([buffer, s]); + return tools.concat([buffer, s]); } diff --git a/ts_src/payments/embed.ts b/ts_src/payments/embed.ts index aef14e1b7..0064d275c 100644 --- a/ts_src/payments/embed.ts +++ b/ts_src/payments/embed.ts @@ -1,8 +1,9 @@ -import { bitcoin as BITCOIN_NETWORK } from '../networks'; -import * as bscript from '../script'; -import { typeforce as typef, stacksEqual } from '../types'; -import { Payment, PaymentOpts, Stack } from './index'; -import * as lazy from './lazy'; +import { bitcoin as BITCOIN_NETWORK } from '../networks.js'; +import * as bscript from '../script.js'; +import { stacksEqual, BufferSchema } from '../types.js'; +import { Payment, PaymentOpts, Stack } from './index.js'; +import * as lazy from './lazy.js'; +import * as v from 'valibot'; const OPS = bscript.OPS; @@ -18,12 +19,23 @@ export function p2data(a: Payment, opts?: PaymentOpts): Payment { if (!a.data && !a.output) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - typef( - { - network: typef.maybe(typef.Object), - output: typef.maybe(typef.Buffer), - data: typef.maybe(typef.arrayOf(typef.Buffer)), - }, + // typef( + // { + // network: typef.maybe(typef.Object), + // output: typef.maybe(typef.Buffer), + // data: typef.maybe(typef.arrayOf(typef.Buffer)), + // }, + // a, + // ); + + v.parse( + v.partial( + v.object({ + network: v.object({}), + output: BufferSchema, + data: v.array(BufferSchema), + }), + ), a, ); @@ -45,10 +57,9 @@ export function p2data(a: Payment, opts?: PaymentOpts): Payment { const chunks = bscript.decompile(a.output); if (chunks![0] !== OPS.OP_RETURN) throw new TypeError('Output is invalid'); - if (!chunks!.slice(1).every(typef.Buffer)) + if (!chunks!.slice(1).every(chunk => v.is(BufferSchema, chunk))) throw new TypeError('Output is invalid'); - - if (a.data && !stacksEqual(a.data, o.data as Buffer[])) + if (a.data && !stacksEqual(a.data, o.data as Uint8Array[])) throw new TypeError('Data mismatch'); } } diff --git a/ts_src/payments/index.ts b/ts_src/payments/index.ts index 3e6d6b9b1..2fe2bb54a 100644 --- a/ts_src/payments/index.ts +++ b/ts_src/payments/index.ts @@ -19,22 +19,22 @@ import { p2tr } from './p2tr.js'; export interface Payment { name?: string; network?: Network; - output?: Buffer; - data?: Buffer[]; + output?: Uint8Array; + data?: Uint8Array[]; m?: number; n?: number; - pubkeys?: Buffer[]; - input?: Buffer; - signatures?: Buffer[]; - internalPubkey?: Buffer; - pubkey?: Buffer; - signature?: Buffer; + pubkeys?: Uint8Array[]; + input?: Uint8Array; + signatures?: Uint8Array[]; + internalPubkey?: Uint8Array; + pubkey?: Uint8Array; + signature?: Uint8Array; address?: string; - hash?: Buffer; + hash?: Uint8Array; redeem?: Payment; redeemVersion?: number; scriptTree?: Taptree; - witness?: Buffer[]; + witness?: Uint8Array[]; } export type PaymentCreator = (a: Payment, opts?: PaymentOpts) => Payment; diff --git a/ts_src/payments/lazy.ts b/ts_src/payments/lazy.ts index 1df181fd9..22906d9ec 100644 --- a/ts_src/payments/lazy.ts +++ b/ts_src/payments/lazy.ts @@ -1,4 +1,4 @@ -export function prop(object: {}, name: string, f: () => any): void { +export function prop(object: object, name: string, f: () => any): void { Object.defineProperty(object, name, { configurable: true, enumerable: true, diff --git a/ts_src/payments/p2ms.ts b/ts_src/payments/p2ms.ts index ffbf0155b..c557aaf7a 100644 --- a/ts_src/payments/p2ms.ts +++ b/ts_src/payments/p2ms.ts @@ -1,8 +1,9 @@ -import { bitcoin as BITCOIN_NETWORK } from '../networks'; -import * as bscript from '../script'; -import { isPoint, typeforce as typef, stacksEqual } from '../types'; -import { Payment, PaymentOpts, Stack } from './index'; -import * as lazy from './lazy'; +import { bitcoin as BITCOIN_NETWORK } from '../networks.js'; +import * as bscript from '../script.js'; +import { BufferSchema, isPoint, stacksEqual } from '../types.js'; +import { Payment, PaymentOpts, Stack } from './index.js'; +import * as lazy from './lazy.js'; +import * as v from 'valibot'; const OPS = bscript.OPS; const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1 @@ -26,24 +27,46 @@ export function p2ms(a: Payment, opts?: PaymentOpts): Payment { throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - function isAcceptableSignature(x: Buffer | number): boolean { + function isAcceptableSignature(x: Uint8Array | number): boolean { return ( - bscript.isCanonicalScriptSignature(x as Buffer) || + bscript.isCanonicalScriptSignature(x as Uint8Array) || (opts!.allowIncomplete && (x as number) === OPS.OP_0) !== undefined ); } - typef( - { - network: typef.maybe(typef.Object), - m: typef.maybe(typef.Number), - n: typef.maybe(typef.Number), - output: typef.maybe(typef.Buffer), - pubkeys: typef.maybe(typef.arrayOf(isPoint)), - - signatures: typef.maybe(typef.arrayOf(isAcceptableSignature)), - input: typef.maybe(typef.Buffer), - }, + // typef( + // { + // network: typef.maybe(typef.Object), + // m: typef.maybe(typef.Number), + // n: typef.maybe(typef.Number), + // output: typef.maybe(typef.Buffer), + // pubkeys: typef.maybe(typef.arrayOf(isPoint)), + + // signatures: typef.maybe(typef.arrayOf(isAcceptableSignature)), + // input: typef.maybe(typef.Buffer), + // }, + // a, + // ); + + v.parse( + v.partial( + v.object({ + network: v.object({}), + m: v.number(), + n: v.number(), + output: BufferSchema, + pubkeys: v.array( + v.custom(isPoint as (input: unknown) => boolean), + 'Received invalid pubkey', + ), + + signatures: v.array( + v.custom(isAcceptableSignature as (input: unknown) => boolean), + 'Expected signature to be of type isAcceptableSignature', + ), + input: BufferSchema, + }), + ), a, ); @@ -52,13 +75,13 @@ export function p2ms(a: Payment, opts?: PaymentOpts): Payment { let chunks: Stack = []; let decoded = false; - function decode(output: Buffer | Stack): void { + function decode(output: Uint8Array | Stack): void { if (decoded) return; decoded = true; chunks = bscript.decompile(output) as Stack; o.m = (chunks[0] as number) - OP_INT_BASE; o.n = (chunks[chunks.length - 2] as number) - OP_INT_BASE; - o.pubkeys = chunks.slice(1, -2) as Buffer[]; + o.pubkeys = chunks.slice(1, -2) as Uint8Array[]; } lazy.prop(o, 'output', () => { @@ -109,9 +132,13 @@ export function p2ms(a: Payment, opts?: PaymentOpts): Payment { if (opts.validate) { if (a.output) { decode(a.output); - if (!typef.Number(chunks[0])) throw new TypeError('Output is invalid'); - if (!typef.Number(chunks[chunks.length - 2])) - throw new TypeError('Output is invalid'); + // if (!typef.Number(chunks[0])) throw new TypeError('Output is invalid'); + v.parse(v.number(), chunks[0], { message: 'Output is invalid' }); + // if (!typef.Number(chunks[chunks.length - 2])) + // throw new TypeError('Output is invalid'); + v.parse(v.number(), chunks[chunks.length - 2], { + message: 'Output is invalid', + }); if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG) throw new TypeError('Output is invalid'); diff --git a/ts_src/payments/p2pk.ts b/ts_src/payments/p2pk.ts index c6c83b35d..898238710 100644 --- a/ts_src/payments/p2pk.ts +++ b/ts_src/payments/p2pk.ts @@ -1,8 +1,10 @@ -import { bitcoin as BITCOIN_NETWORK } from '../networks'; -import * as bscript from '../script'; -import { isPoint, typeforce as typef } from '../types'; -import { Payment, PaymentOpts, StackFunction } from './index'; -import * as lazy from './lazy'; +import { bitcoin as BITCOIN_NETWORK } from '../networks.js'; +import * as bscript from '../script.js'; +import { BufferSchema, isPoint } from '../types.js'; +import { Payment, PaymentOpts, StackFunction } from './index.js'; +import * as lazy from './lazy.js'; +import * as tools from 'uint8array-tools'; +import * as v from 'valibot'; const OPS = bscript.OPS; // input: {signature} @@ -20,15 +22,35 @@ export function p2pk(a: Payment, opts?: PaymentOpts): Payment { throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - typef( - { - network: typef.maybe(typef.Object), - output: typef.maybe(typef.Buffer), - pubkey: typef.maybe(isPoint), + // typef( + // { + // network: typef.maybe(typef.Object), + // output: typef.maybe(typef.Buffer), + // pubkey: typef.maybe(isPoint), - signature: typef.maybe(bscript.isCanonicalScriptSignature), - input: typef.maybe(typef.Buffer), - }, + // signature: typef.maybe(bscript.isCanonicalScriptSignature), + // input: typef.maybe(typef.Buffer), + // }, + // a, + // ); + + v.parse( + v.partial( + v.object({ + network: v.object({}), + output: BufferSchema, + pubkey: v.custom( + isPoint as (input: unknown) => boolean, + 'invalid pubkey', + ), + + signature: v.custom( + bscript.isCanonicalScriptSignature as (input: unknown) => boolean, + 'Expected signature to be of type isCanonicalScriptSignature', + ), + input: BufferSchema, + }), + ), a, ); @@ -49,7 +71,7 @@ export function p2pk(a: Payment, opts?: PaymentOpts): Payment { }); lazy.prop(o, 'signature', () => { if (!a.input) return; - return _chunks()[0] as Buffer; + return _chunks()[0] as Uint8Array; }); lazy.prop(o, 'input', () => { if (!a.signature) return; @@ -66,12 +88,14 @@ export function p2pk(a: Payment, opts?: PaymentOpts): Payment { if (a.output[a.output.length - 1] !== OPS.OP_CHECKSIG) throw new TypeError('Output is invalid'); if (!isPoint(o.pubkey)) throw new TypeError('Output pubkey is invalid'); - if (a.pubkey && !a.pubkey.equals(o.pubkey!)) + // if (a.pubkey && !a.pubkey.equals(o.pubkey!)) + if (a.pubkey && tools.compare(a.pubkey, o.pubkey!) !== 0) throw new TypeError('Pubkey mismatch'); } if (a.signature) { - if (a.input && !a.input.equals(o.input!)) + // if (a.input && !a.input.equals(o.input!)) + if (a.input && tools.compare(a.input, o.input!) !== 0) throw new TypeError('Signature mismatch'); } diff --git a/ts_src/payments/p2pkh.ts b/ts_src/payments/p2pkh.ts index 2873a6ebe..bcf3b7124 100644 --- a/ts_src/payments/p2pkh.ts +++ b/ts_src/payments/p2pkh.ts @@ -1,10 +1,18 @@ -import * as bcrypto from '../crypto'; -import { bitcoin as BITCOIN_NETWORK } from '../networks'; -import * as bscript from '../script'; -import { isPoint, typeforce as typef } from '../types'; -import { Payment, PaymentOpts, StackFunction } from './index'; -import * as lazy from './lazy'; -import * as bs58check from 'bs58check'; +import * as bcrypto from '../crypto.js'; +import { bitcoin as BITCOIN_NETWORK } from '../networks.js'; +import * as bscript from '../script.js'; +import { + isPoint, + Hash160bitSchema, + NBufferSchemaFactory, + BufferSchema, +} from '../types.js'; +import { Payment, PaymentOpts, StackFunction } from './index.js'; +import * as lazy from './lazy.js'; +import bs58check from 'bs58check'; +import * as tools from 'uint8array-tools'; +import * as v from 'valibot'; + const OPS = bscript.OPS; // input: {signature} {pubkey} @@ -22,23 +30,42 @@ export function p2pkh(a: Payment, opts?: PaymentOpts): Payment { throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - typef( - { - network: typef.maybe(typef.Object), - address: typef.maybe(typef.String), - hash: typef.maybe(typef.BufferN(20)), - output: typef.maybe(typef.BufferN(25)), - - pubkey: typef.maybe(isPoint), - signature: typef.maybe(bscript.isCanonicalScriptSignature), - input: typef.maybe(typef.Buffer), - }, + // typef( + // { + // network: typef.maybe(typef.Object), + // address: typef.maybe(typef.String), + // hash: typef.maybe(typef.BufferN(20)), + // output: typef.maybe(typef.BufferN(25)), + + // pubkey: typef.maybe(isPoint), + // signature: typef.maybe(bscript.isCanonicalScriptSignature), + // input: typef.maybe(typef.Buffer), + // }, + // a, + // ); + + v.parse( + v.partial( + v.object({ + network: v.object({}), + address: v.string(), + hash: Hash160bitSchema, + output: NBufferSchemaFactory(25), + + pubkey: v.custom(isPoint as (input: unknown) => boolean), + signature: v.custom( + bscript.isCanonicalScriptSignature as (input: unknown) => boolean, + ), + input: BufferSchema, + }), + ), a, ); const _address = lazy.value(() => { - const payload = Buffer.from(bs58check.decode(a.address!)); - const version = payload.readUInt8(0); + const payload = bs58check.decode(a.address!); + // const version = payload.readUInt8(0); + const version = tools.readUInt8(payload, 0); const hash = payload.slice(1); return { version, hash }; }); @@ -52,9 +79,11 @@ export function p2pkh(a: Payment, opts?: PaymentOpts): Payment { lazy.prop(o, 'address', () => { if (!o.hash) return; - const payload = Buffer.allocUnsafe(21); - payload.writeUInt8(network.pubKeyHash, 0); - o.hash.copy(payload, 1); + const payload = new Uint8Array(21); + // payload.writeUInt8(network.pubKeyHash, 0); + tools.writeUInt8(payload, 0, network.pubKeyHash); + // o.hash.copy(payload, 1); + payload.set(o.hash, 1); return bs58check.encode(payload); }); lazy.prop(o, 'hash', () => { @@ -74,11 +103,11 @@ export function p2pkh(a: Payment, opts?: PaymentOpts): Payment { }); lazy.prop(o, 'pubkey', () => { if (!a.input) return; - return _chunks()[1] as Buffer; + return _chunks()[1] as Uint8Array; }); lazy.prop(o, 'signature', () => { if (!a.input) return; - return _chunks()[0] as Buffer; + return _chunks()[0] as Uint8Array; }); lazy.prop(o, 'input', () => { if (!a.pubkey) return; @@ -92,7 +121,7 @@ export function p2pkh(a: Payment, opts?: PaymentOpts): Payment { // extended validation if (opts.validate) { - let hash: Buffer = Buffer.from([]); + let hash: Uint8Array = Uint8Array.from([]); if (a.address) { if (_address().version !== network.pubKeyHash) throw new TypeError('Invalid version or Network mismatch'); @@ -101,7 +130,8 @@ export function p2pkh(a: Payment, opts?: PaymentOpts): Payment { } if (a.hash) { - if (hash.length > 0 && !hash.equals(a.hash)) + // if (hash.length > 0 && !hash.equals(a.hash)) + if (hash.length > 0 && tools.compare(hash, a.hash) !== 0) throw new TypeError('Hash mismatch'); else hash = a.hash; } @@ -118,14 +148,16 @@ export function p2pkh(a: Payment, opts?: PaymentOpts): Payment { throw new TypeError('Output is invalid'); const hash2 = a.output.slice(3, 23); - if (hash.length > 0 && !hash.equals(hash2)) + // if (hash.length > 0 && !hash.equals(hash2)) + if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; } if (a.pubkey) { const pkh = bcrypto.hash160(a.pubkey); - if (hash.length > 0 && !hash.equals(pkh)) + // if (hash.length > 0 && !hash.equals(pkh)) + if (hash.length > 0 && tools.compare(hash, pkh) !== 0) throw new TypeError('Hash mismatch'); else hash = pkh; } @@ -133,17 +165,23 @@ export function p2pkh(a: Payment, opts?: PaymentOpts): Payment { if (a.input) { const chunks = _chunks(); if (chunks.length !== 2) throw new TypeError('Input is invalid'); - if (!bscript.isCanonicalScriptSignature(chunks[0] as Buffer)) + if (!bscript.isCanonicalScriptSignature(chunks[0] as Uint8Array)) throw new TypeError('Input has invalid signature'); if (!isPoint(chunks[1])) throw new TypeError('Input has invalid pubkey'); - if (a.signature && !a.signature.equals(chunks[0] as Buffer)) + // if (a.signature && !a.signature.equals(chunks[0])) + if ( + a.signature && + tools.compare(a.signature, chunks[0] as Uint8Array) !== 0 + ) throw new TypeError('Signature mismatch'); - if (a.pubkey && !a.pubkey.equals(chunks[1] as Buffer)) + // if (a.pubkey && !a.pubkey.equals(chunks[1] as Buffer)) + if (a.pubkey && tools.compare(a.pubkey, chunks[1] as Uint8Array) !== 0) throw new TypeError('Pubkey mismatch'); - const pkh = bcrypto.hash160(chunks[1] as Buffer); - if (hash.length > 0 && !hash.equals(pkh)) + const pkh = bcrypto.hash160(chunks[1] as Uint8Array); + // if (hash.length > 0 && !hash.equals(pkh)) + if (hash.length > 0 && tools.compare(hash, pkh) !== 0) throw new TypeError('Hash mismatch'); } } diff --git a/ts_src/payments/p2sh.ts b/ts_src/payments/p2sh.ts index 2f5f936c6..0873a8d34 100644 --- a/ts_src/payments/p2sh.ts +++ b/ts_src/payments/p2sh.ts @@ -1,16 +1,18 @@ -import * as bcrypto from '../crypto'; -import { bitcoin as BITCOIN_NETWORK } from '../networks'; -import * as bscript from '../script'; -import { typeforce as typef, stacksEqual } from '../types'; +import * as bcrypto from '../crypto.js'; +import { bitcoin as BITCOIN_NETWORK } from '../networks.js'; +import * as bscript from '../script.js'; +import { BufferSchema, NBufferSchemaFactory, stacksEqual } from '../types.js'; import { Payment, PaymentFunction, PaymentOpts, Stack, StackFunction, -} from './index'; -import * as lazy from './lazy'; -import * as bs58check from 'bs58check'; +} from './index.js'; +import * as lazy from './lazy.js'; +import bs58check from 'bs58check'; +import * as tools from 'uint8array-tools'; +import * as v from 'valibot'; const OPS = bscript.OPS; // input: [redeemScriptSig ...] {redeemScript} @@ -29,23 +31,47 @@ export function p2sh(a: Payment, opts?: PaymentOpts): Payment { throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - typef( - { - network: typef.maybe(typef.Object), + // typef( + // { + // network: typef.maybe(typef.Object), - address: typef.maybe(typef.String), - hash: typef.maybe(typef.BufferN(20)), - output: typef.maybe(typef.BufferN(23)), + // address: typef.maybe(typef.String), + // hash: typef.maybe(typef.BufferN(20)), + // output: typef.maybe(typef.BufferN(23)), - redeem: typef.maybe({ - network: typef.maybe(typef.Object), - output: typef.maybe(typef.Buffer), - input: typef.maybe(typef.Buffer), - witness: typef.maybe(typef.arrayOf(typef.Buffer)), + // redeem: typef.maybe({ + // network: typef.maybe(typef.Object), + // output: typef.maybe(typef.Buffer), + // input: typef.maybe(typef.Buffer), + // witness: typef.maybe(typef.arrayOf(typef.Buffer)), + // }), + // input: typef.maybe(typef.Buffer), + // witness: typef.maybe(typef.arrayOf(typef.Buffer)), + // }, + // a, + // ); + + v.parse( + v.partial( + v.object({ + network: v.object({}), + + address: v.string(), + hash: NBufferSchemaFactory(20), + output: NBufferSchemaFactory(23), + + redeem: v.partial( + v.object({ + network: v.object({}), + output: BufferSchema, + input: BufferSchema, + witness: v.array(BufferSchema), + }), + ), + input: BufferSchema, + witness: v.array(BufferSchema), }), - input: typef.maybe(typef.Buffer), - witness: typef.maybe(typef.arrayOf(typef.Buffer)), - }, + ), a, ); @@ -57,8 +83,9 @@ export function p2sh(a: Payment, opts?: PaymentOpts): Payment { const o: Payment = { network }; const _address = lazy.value(() => { - const payload = Buffer.from(bs58check.decode(a.address!)); - const version = payload.readUInt8(0); + const payload = bs58check.decode(a.address!); + // const version = payload.readUInt8(0); + const version = tools.readUInt8(payload, 0); const hash = payload.slice(1); return { version, hash }; }); @@ -71,7 +98,9 @@ export function p2sh(a: Payment, opts?: PaymentOpts): Payment { return { network, output: - lastChunk === OPS.OP_FALSE ? Buffer.from([]) : (lastChunk as Buffer), + lastChunk === OPS.OP_FALSE + ? Uint8Array.from([]) + : (lastChunk as Uint8Array), input: bscript.compile(chunks.slice(0, -1)), witness: a.witness || [], }; @@ -81,9 +110,11 @@ export function p2sh(a: Payment, opts?: PaymentOpts): Payment { lazy.prop(o, 'address', () => { if (!o.hash) return; - const payload = Buffer.allocUnsafe(21); - payload.writeUInt8(o.network!.scriptHash, 0); - o.hash.copy(payload, 1); + const payload = new Uint8Array(21); + // payload.writeUInt8(o.network!.scriptHash, 0); + tools.writeUInt8(payload, 0, o.network!.scriptHash); + // o.hash.copy(payload, 1); + payload.set(o.hash, 1); return bs58check.encode(payload); }); lazy.prop(o, 'hash', () => { @@ -123,7 +154,7 @@ export function p2sh(a: Payment, opts?: PaymentOpts): Payment { }); if (opts.validate) { - let hash: Buffer = Buffer.from([]); + let hash = Uint8Array.from([]); if (a.address) { if (_address().version !== network.scriptHash) throw new TypeError('Invalid version or Network mismatch'); @@ -132,7 +163,8 @@ export function p2sh(a: Payment, opts?: PaymentOpts): Payment { } if (a.hash) { - if (hash.length > 0 && !hash.equals(a.hash)) + // if (hash.length > 0 && !hash.equals(a.hash)) + if (hash.length > 0 && tools.compare(hash, a.hash) !== 0) throw new TypeError('Hash mismatch'); else hash = a.hash; } @@ -147,7 +179,8 @@ export function p2sh(a: Payment, opts?: PaymentOpts): Payment { throw new TypeError('Output is invalid'); const hash2 = a.output.slice(2, 22); - if (hash.length > 0 && !hash.equals(hash2)) + // if (hash.length > 0 && !hash.equals(hash2)) + if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; } @@ -170,7 +203,8 @@ export function p2sh(a: Payment, opts?: PaymentOpts): Payment { // match hash against other sources const hash2 = bcrypto.hash160(redeem.output); - if (hash.length > 0 && !hash.equals(hash2)) + // if (hash.length > 0 && !hash.equals(hash2)) + if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; } @@ -192,7 +226,7 @@ export function p2sh(a: Payment, opts?: PaymentOpts): Payment { if (a.input) { const chunks = _chunks(); if (!chunks || chunks.length < 1) throw new TypeError('Input too short'); - if (!Buffer.isBuffer(_redeem().output)) + if (!(_redeem().output instanceof Uint8Array)) throw new TypeError('Input is invalid'); checkRedeem(_redeem()); @@ -203,9 +237,17 @@ export function p2sh(a: Payment, opts?: PaymentOpts): Payment { throw new TypeError('Network mismatch'); if (a.input) { const redeem = _redeem(); - if (a.redeem.output && !a.redeem.output.equals(redeem.output!)) + // if (a.redeem.output && !a.redeem.output.equals(redeem.output!)) + if ( + a.redeem.output && + tools.compare(a.redeem.output, redeem.output!) !== 0 + ) throw new TypeError('Redeem.output mismatch'); - if (a.redeem.input && !a.redeem.input.equals(redeem.input!)) + // if (a.redeem.input && !a.redeem.input.equals(redeem.input!)) + if ( + a.redeem.input && + tools.compare(a.redeem.input, redeem.input!) !== 0 + ) throw new TypeError('Redeem.input mismatch'); } diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts index c1140b715..048e195ac 100644 --- a/ts_src/payments/p2tr.ts +++ b/ts_src/payments/p2tr.ts @@ -1,13 +1,14 @@ -import { Buffer as NBuffer } from 'buffer'; -import { bitcoin as BITCOIN_NETWORK } from '../networks'; -import * as bscript from '../script'; +// import { Buffer as NBuffer } from 'buffer'; +import { bitcoin as BITCOIN_NETWORK } from '../networks.js'; +import * as bscript from '../script.js'; import { - typeforce as typef, isTaptree, TAPLEAF_VERSION_MASK, stacksEqual, -} from '../types'; -import { getEccLib } from '../ecc_lib'; + NBufferSchemaFactory, + BufferSchema, +} from '../types.js'; +import { getEccLib } from '../ecc_lib.js'; import { toHashTree, rootHashFromPath, @@ -15,11 +16,13 @@ import { tapleafHash, tweakKey, LEAF_VERSION_TAPSCRIPT, -} from './bip341'; -import { Payment, PaymentOpts } from './index'; -import * as lazy from './lazy'; +} from './bip341.js'; +import { Payment, PaymentOpts } from './index.js'; +import * as lazy from './lazy.js'; import { bech32m } from 'bech32'; -import { fromBech32 } from '../address'; +import { fromBech32 } from '../address.js'; +import * as tools from 'uint8array-tools'; +import * as v from 'valibot'; const OPS = bscript.OPS; const TAPROOT_WITNESS_VERSION = 0x01; @@ -45,25 +48,54 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment { 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)), // 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))), - witness: typef.maybe(typef.arrayOf(typef.Buffer)), - scriptTree: typef.maybe(isTaptree), - redeem: typef.maybe({ - output: typef.maybe(typef.Buffer), // tapleaf script - redeemVersion: typef.maybe(typef.Number), // tapleaf version - witness: typef.maybe(typef.arrayOf(typef.Buffer)), + // 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)), // 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))), + // witness: typef.maybe(typef.arrayOf(typef.Buffer)), + // scriptTree: typef.maybe(isTaptree), + // redeem: typef.maybe({ + // 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), + // }, + // a, + // ); + + v.parse( + v.partial( + v.object({ + address: v.string(), + input: NBufferSchemaFactory(0), + network: v.object({}), + output: NBufferSchemaFactory(34), + internalPubkey: NBufferSchemaFactory(32), + hash: NBufferSchemaFactory(32), // merkle root hash, the tweak + pubkey: NBufferSchemaFactory(32), // tweaked with `hash` from `internalPubkey` + signature: v.union([ + NBufferSchemaFactory(64), + NBufferSchemaFactory(65), + ]), + witness: v.array(BufferSchema), + scriptTree: v.custom(isTaptree, 'Taptree is not of type isTaptree'), + redeem: v.partial( + v.object({ + output: BufferSchema, // tapleaf script + redeemVersion: v.number(), // tapleaf version + witness: v.array(BufferSchema), + }), + ), + redeemVersion: v.number(), }), - redeemVersion: typef.maybe(typef.Number), - }, + ), a, ); @@ -173,9 +205,9 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment { if (!path) return; const outputKey = tweakKey(a.internalPubkey, hashTree.hash); if (!outputKey) return; - const controlBock = NBuffer.concat( + const controlBock = tools.concat( [ - NBuffer.from([o.redeemVersion! | outputKey.parity]), + Uint8Array.from([o.redeemVersion! | outputKey.parity]), a.internalPubkey, ].concat(path), ); @@ -186,7 +218,7 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment { // extended validation if (opts.validate) { - let pubkey: Buffer = NBuffer.from([]); + let pubkey: Uint8Array = Uint8Array.from([]); if (a.address) { if (network && network.bech32 !== _address().prefix) throw new TypeError('Invalid prefix or Network mismatch'); @@ -198,7 +230,8 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment { } if (a.pubkey) { - if (pubkey.length > 0 && !pubkey.equals(a.pubkey)) + // if (pubkey.length > 0 && !pubkey.equals(a.pubkey)) + if (pubkey.length > 0 && tools.compare(pubkey, a.pubkey) !== 0) throw new TypeError('Pubkey mismatch'); else pubkey = a.pubkey; } @@ -210,14 +243,16 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment { a.output[1] !== 0x20 ) throw new TypeError('Output is invalid'); - if (pubkey.length > 0 && !pubkey.equals(a.output.slice(2))) + // if (pubkey.length > 0 && !pubkey.equals(a.output.slice(2))) + if (pubkey.length > 0 && tools.compare(pubkey, a.output.slice(2)) !== 0) 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)) + // if (pubkey.length > 0 && !pubkey.equals(tweakedKey!.x)) + if (pubkey.length > 0 && tools.compare(pubkey, tweakedKey!.x) !== 0) throw new TypeError('Pubkey mismatch'); else pubkey = tweakedKey!.x; } @@ -230,7 +265,9 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment { const hashTree = _hashTree(); if (a.hash && hashTree) { - if (!a.hash.equals(hashTree.hash)) throw new TypeError('Hash mismatch'); + // if (!a.hash.equals(hashTree.hash)) throw new TypeError('Hash mismatch'); + if (tools.compare(a.hash, hashTree.hash) !== 0) + throw new TypeError('Hash mismatch'); } if (a.redeem && a.redeem.output && hashTree) { @@ -256,7 +293,11 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment { 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)) + // if (o.redeem.output && !a.redeem.output.equals(o.redeem.output)) + if ( + o.redeem.output && + tools.compare(a.redeem.output, o.redeem.output) !== 0 + ) throw new TypeError('Redeem.output and witness mismatch'); } if (a.redeem.witness) { @@ -271,7 +312,8 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment { if (witness && witness.length) { if (witness.length === 1) { // key spending - if (a.signature && !a.signature.equals(witness[0])) + // if (a.signature && !a.signature.equals(witness[0])) + if (a.signature && tools.compare(a.signature, witness[0]) !== 0) throw new TypeError('Signature mismatch'); } else { // script path spending @@ -293,7 +335,11 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment { ); const internalPubkey = controlBlock.slice(1, 33); - if (a.internalPubkey && !a.internalPubkey.equals(internalPubkey)) + // if (a.internalPubkey && !a.internalPubkey.equals(internalPubkey)) + if ( + a.internalPubkey && + tools.compare(a.internalPubkey, internalPubkey) !== 0 + ) throw new TypeError('Internal pubkey mismatch'); if (!getEccLib().isXOnlyPoint(internalPubkey)) @@ -310,7 +356,8 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment { // todo: needs test data throw new TypeError('Invalid outputKey for p2tr witness'); - if (pubkey.length && !pubkey.equals(outputKey.x)) + // if (pubkey.length && !pubkey.equals(outputKey.x)) + if (pubkey.length && tools.compare(pubkey, outputKey.x) !== 0) throw new TypeError('Pubkey mismatch for p2tr witness'); if (outputKey.parity !== (controlBlock[0] & 1)) diff --git a/ts_src/payments/p2wpkh.ts b/ts_src/payments/p2wpkh.ts index 997cb6292..c04b577c4 100644 --- a/ts_src/payments/p2wpkh.ts +++ b/ts_src/payments/p2wpkh.ts @@ -1,13 +1,16 @@ -import * as bcrypto from '../crypto'; -import { bitcoin as BITCOIN_NETWORK } from '../networks'; -import * as bscript from '../script'; -import { isPoint, typeforce as typef } from '../types'; -import { Payment, PaymentOpts } from './index'; -import * as lazy from './lazy'; +import * as bcrypto from '../crypto.js'; +import { bitcoin as BITCOIN_NETWORK } from '../networks.js'; +import * as bscript from '../script.js'; +import { BufferSchema, isPoint, NBufferSchemaFactory } from '../types.js'; +import { Payment, PaymentOpts } from './index.js'; +import * as lazy from './lazy.js'; import { bech32 } from 'bech32'; +import * as tools from 'uint8array-tools'; +import * as v from 'valibot'; + const OPS = bscript.OPS; -const EMPTY_BUFFER = Buffer.alloc(0); +const EMPTY_BUFFER = new Uint8Array(0); // witness: {signature} {pubKey} // input: <> @@ -25,17 +28,38 @@ export function p2wpkh(a: Payment, opts?: PaymentOpts): Payment { throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - typef( - { - 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(22)), - pubkey: typef.maybe(isPoint), - signature: typef.maybe(bscript.isCanonicalScriptSignature), - witness: typef.maybe(typef.arrayOf(typef.Buffer)), - }, + // typef( + // { + // 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(22)), + // pubkey: typef.maybe(isPoint), + // signature: typef.maybe(bscript.isCanonicalScriptSignature), + // witness: typef.maybe(typef.arrayOf(typef.Buffer)), + // }, + // a, + // ); + + v.parse( + v.partial( + v.object({ + address: v.string(), + hash: NBufferSchemaFactory(20), + input: NBufferSchemaFactory(0), + network: v.object({}), + output: NBufferSchemaFactory(22), + pubkey: v.custom( + isPoint as (input: unknown) => boolean, + 'Not a valid pubkey', + ), + signature: v.custom( + bscript.isCanonicalScriptSignature as (input: unknown) => boolean, + ), + witness: v.array(BufferSchema), + }), + ), a, ); @@ -46,7 +70,7 @@ export function p2wpkh(a: Payment, opts?: PaymentOpts): Payment { return { version, prefix: result.prefix, - data: Buffer.from(data), + data: Uint8Array.from(data), }; }); @@ -90,7 +114,7 @@ export function p2wpkh(a: Payment, opts?: PaymentOpts): Payment { // extended validation if (opts.validate) { - let hash: Buffer = Buffer.from([]); + let hash: Uint8Array = Uint8Array.from([]); if (a.address) { if (network && network.bech32 !== _address().prefix) throw new TypeError('Invalid prefix or Network mismatch'); @@ -102,7 +126,8 @@ export function p2wpkh(a: Payment, opts?: PaymentOpts): Payment { } if (a.hash) { - if (hash.length > 0 && !hash.equals(a.hash)) + // if (hash.length > 0 && !hash.equals(a.hash)) + if (hash.length > 0 && tools.compare(hash, a.hash) !== 0) throw new TypeError('Hash mismatch'); else hash = a.hash; } @@ -114,14 +139,16 @@ export function p2wpkh(a: Payment, opts?: PaymentOpts): Payment { a.output[1] !== 0x14 ) throw new TypeError('Output is invalid'); - if (hash.length > 0 && !hash.equals(a.output.slice(2))) + // if (hash.length > 0 && !hash.equals(a.output.slice(2))) + if (hash.length > 0 && tools.compare(hash, a.output.slice(2)) !== 0) throw new TypeError('Hash mismatch'); else hash = a.output.slice(2); } if (a.pubkey) { const pkh = bcrypto.hash160(a.pubkey); - if (hash.length > 0 && !hash.equals(pkh)) + // if (hash.length > 0 && !hash.equals(pkh)) + if (hash.length > 0 && tools.compare(hash, pkh) !== 0) throw new TypeError('Hash mismatch'); else hash = pkh; if (!isPoint(a.pubkey) || a.pubkey.length !== 33) @@ -135,13 +162,16 @@ export function p2wpkh(a: Payment, opts?: PaymentOpts): Payment { if (!isPoint(a.witness[1]) || a.witness[1].length !== 33) throw new TypeError('Witness has invalid pubkey'); - if (a.signature && !a.signature.equals(a.witness[0])) + // if (a.signature && !a.signature.equals(a.witness[0])) + if (a.signature && tools.compare(a.signature, a.witness[0]) !== 0) throw new TypeError('Signature mismatch'); - if (a.pubkey && !a.pubkey.equals(a.witness[1])) + // if (a.pubkey && !a.pubkey.equals(a.witness[1])) + if (a.pubkey && tools.compare(a.pubkey, a.witness[1]) !== 0) throw new TypeError('Pubkey mismatch'); const pkh = bcrypto.hash160(a.witness[1]); - if (hash.length > 0 && !hash.equals(pkh)) + // if (hash.length > 0 && !hash.equals(pkh)) + if (hash.length > 0 && tools.compare(hash, pkh) !== 0) throw new TypeError('Hash mismatch'); } } diff --git a/ts_src/payments/p2wsh.ts b/ts_src/payments/p2wsh.ts index bd9339277..963f760da 100644 --- a/ts_src/payments/p2wsh.ts +++ b/ts_src/payments/p2wsh.ts @@ -1,17 +1,28 @@ -import * as bcrypto from '../crypto'; -import { bitcoin as BITCOIN_NETWORK } from '../networks'; -import * as bscript from '../script'; -import { isPoint, typeforce as typef, stacksEqual } from '../types'; -import { Payment, PaymentOpts, StackElement, StackFunction } from './index'; -import * as lazy from './lazy'; +import { sha256 } from '@noble/hashes/sha256'; +import { bitcoin as BITCOIN_NETWORK } from '../networks.js'; +import * as bscript from '../script.js'; +import { + Buffer256bitSchema, + BufferSchema, + isPoint, + NBufferSchemaFactory, + stacksEqual, + NullablePartial, +} from '../types.js'; +import { Payment, PaymentOpts, StackElement, StackFunction } from './index.js'; +import * as lazy from './lazy.js'; import { bech32 } from 'bech32'; +import * as tools from 'uint8array-tools'; +import * as v from 'valibot'; + const OPS = bscript.OPS; -const EMPTY_BUFFER = Buffer.alloc(0); +const EMPTY_BUFFER = new Uint8Array(0); function chunkHasUncompressedPubkey(chunk: StackElement): boolean { if ( - Buffer.isBuffer(chunk) && + // Buffer.isBuffer(chunk) && + chunk instanceof Uint8Array && chunk.length === 65 && chunk[0] === 0x04 && isPoint(chunk) @@ -38,23 +49,43 @@ export function p2wsh(a: Payment, opts?: PaymentOpts): Payment { throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - typef( - { - network: typef.maybe(typef.Object), + // typef( + // { + // network: typef.maybe(typef.Object), + + // address: typef.maybe(typef.String), + // hash: typef.maybe(typef.BufferN(32)), + // output: typef.maybe(typef.BufferN(34)), + + // redeem: typef.maybe({ + // input: typef.maybe(typef.Buffer), + // network: typef.maybe(typef.Object), + // output: typef.maybe(typef.Buffer), + // witness: typef.maybe(typef.arrayOf(typef.Buffer)), + // }), + // input: typef.maybe(typef.BufferN(0)), + // witness: typef.maybe(typef.arrayOf(typef.Buffer)), + // }, + // a, + // ); - address: typef.maybe(typef.String), - hash: typef.maybe(typef.BufferN(32)), - output: typef.maybe(typef.BufferN(34)), + v.parse( + NullablePartial({ + network: v.object({}), - redeem: typef.maybe({ - input: typef.maybe(typef.Buffer), - network: typef.maybe(typef.Object), - output: typef.maybe(typef.Buffer), - witness: typef.maybe(typef.arrayOf(typef.Buffer)), + address: v.string(), + hash: Buffer256bitSchema, + output: NBufferSchemaFactory(34), + + redeem: NullablePartial({ + input: BufferSchema, + network: v.object({}), + output: BufferSchema, + witness: v.array(BufferSchema), }), - input: typef.maybe(typef.BufferN(0)), - witness: typef.maybe(typef.arrayOf(typef.Buffer)), - }, + input: NBufferSchemaFactory(0), + witness: v.array(BufferSchema), + }), a, ); @@ -65,7 +96,7 @@ export function p2wsh(a: Payment, opts?: PaymentOpts): Payment { return { version, prefix: result.prefix, - data: Buffer.from(data), + data: Uint8Array.from(data), }; }); const _rchunks = lazy.value(() => { @@ -88,7 +119,7 @@ export function p2wsh(a: Payment, opts?: PaymentOpts): Payment { lazy.prop(o, 'hash', () => { if (a.output) return a.output.slice(2); if (a.address) return _address().data; - if (o.redeem && o.redeem.output) return bcrypto.sha256(o.redeem.output); + if (o.redeem && o.redeem.output) return sha256(o.redeem.output); }); lazy.prop(o, 'output', () => { if (!o.hash) return; @@ -120,13 +151,13 @@ export function p2wsh(a: Payment, opts?: PaymentOpts): Payment { // assign, and blank the existing input o.redeem = Object.assign({ witness: stack }, a.redeem); o.redeem.input = EMPTY_BUFFER; - return ([] as Buffer[]).concat(stack, a.redeem.output); + return ([] as Uint8Array[]).concat(stack, a.redeem.output); } if (!a.redeem) return; if (!a.redeem.output) return; if (!a.redeem.witness) return; - return ([] as Buffer[]).concat(a.redeem.witness, a.redeem.output); + return ([] as Uint8Array[]).concat(a.redeem.witness, a.redeem.output); }); lazy.prop(o, 'name', () => { const nameParts = ['p2wsh']; @@ -137,7 +168,7 @@ export function p2wsh(a: Payment, opts?: PaymentOpts): Payment { // extended validation if (opts.validate) { - let hash: Buffer = Buffer.from([]); + let hash = Uint8Array.from([]); if (a.address) { if (_address().prefix !== network.bech32) throw new TypeError('Invalid prefix or Network mismatch'); @@ -149,7 +180,8 @@ export function p2wsh(a: Payment, opts?: PaymentOpts): Payment { } if (a.hash) { - if (hash.length > 0 && !hash.equals(a.hash)) + // if (hash.length > 0 && !hash.equals(a.hash)) + if (hash.length > 0 && tools.compare(hash, a.hash) !== 0) throw new TypeError('Hash mismatch'); else hash = a.hash; } @@ -162,7 +194,8 @@ export function p2wsh(a: Payment, opts?: PaymentOpts): Payment { ) throw new TypeError('Output is invalid'); const hash2 = a.output.slice(2); - if (hash.length > 0 && !hash.equals(hash2)) + // if (hash.length > 0 && !hash.equals(hash2)) + if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; } @@ -195,8 +228,9 @@ export function p2wsh(a: Payment, opts?: PaymentOpts): Payment { ); // match hash against other sources - const hash2 = bcrypto.sha256(a.redeem.output); - if (hash.length > 0 && !hash.equals(hash2)) + const hash2 = sha256(a.redeem.output); + // if (hash.length > 0 && !hash.equals(hash2)) + if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; } @@ -224,7 +258,12 @@ export function p2wsh(a: Payment, opts?: PaymentOpts): Payment { if (a.witness && a.witness.length > 0) { const wScript = a.witness[a.witness.length - 1]; - if (a.redeem && a.redeem.output && !a.redeem.output.equals(wScript)) + // if (a.redeem && a.redeem.output && !a.redeem.output.equals(wScript)) + if ( + a.redeem && + a.redeem.output && + tools.compare(a.redeem.output, wScript) !== 0 + ) throw new TypeError('Witness and redeem.output mismatch'); if ( a.witness.some(chunkHasUncompressedPubkey) || diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts index 6433b1831..3ff0a37df 100644 --- a/ts_src/psbt.ts +++ b/ts_src/psbt.ts @@ -13,8 +13,9 @@ import { TransactionFromBuffer, TapKeySig, TapScriptSig, -} from 'bip174/lib/interfaces'; -import { checkForInput, checkForOutput } from 'bip174/lib/utils'; + TapLeafScript, +} from 'bip174'; +import { checkForInput, checkForOutput } from 'bip174'; import { fromOutputScript, toOutputScript } from './address.js'; import { cloneBuffer, reverseBuffer } from './bufferutils.js'; import { bitcoin as btcNetwork, Network } from './networks.js'; @@ -43,7 +44,7 @@ import { isP2SHScript, isP2TR, } from './psbt/psbtutils.js'; -import * as tools from "uint8array-tools"; +import * as tools from 'uint8array-tools'; export interface TransactionInput { hash: string | Uint8Array; @@ -127,12 +128,14 @@ const DEFAULT_OPTS: PsbtOpts = { */ export class Psbt { static fromBase64(data: string, opts: PsbtOptsOptional = {}): Psbt { - const buffer = Buffer.from(data, 'base64'); + // const buffer = Buffer.from(data, 'base64'); + const buffer = tools.fromBase64(data); return this.fromBuffer(buffer, opts); } static fromHex(data: string, opts: PsbtOptsOptional = {}): Psbt { - const buffer = Buffer.from(data, 'hex'); + // const buffer = Buffer.from(data, 'hex'); + const buffer = tools.fromHex(data); return this.fromBuffer(buffer, opts); } @@ -362,11 +365,16 @@ export class Psbt { 'fee rate', this.data.inputs, this.__CACHE, - )!; + )! as number; } - getFee(): number { - return getTxCacheValue('__FEE', 'fee', this.data.inputs, this.__CACHE)!; + getFee(): bigint { + return getTxCacheValue( + '__FEE', + 'fee', + this.data.inputs, + this.__CACHE, + )! as bigint; } finalizeAllInputs(): this { @@ -396,7 +404,7 @@ export class Psbt { finalizeTaprootInput( inputIndex: number, - tapLeafHashToFinalize?: Buffer, + tapLeafHashToFinalize?: Uint8Array, finalScriptsFunc: FinalTaprootScriptsFunc = tapScriptFinalizer, ): this { const input = checkForInput(this.data.inputs, inputIndex); @@ -446,7 +454,7 @@ export class Psbt { private _finalizeTaprootInput( inputIndex: number, input: PsbtInput, - tapLeafHashToFinalize?: Buffer, + tapLeafHashToFinalize?: Uint8Array, finalScriptsFunc = tapScriptFinalizer, ): this { if (!input.witnessUtxo) @@ -492,7 +500,7 @@ export class Psbt { return (type + mainType) as AllScriptType; } - inputHasPubkey(inputIndex: number, pubkey: Buffer): boolean { + inputHasPubkey(inputIndex: number, pubkey: Uint8Array): boolean { const input = checkForInput(this.data.inputs, inputIndex); return pubkeyInInput(pubkey, input, inputIndex, this.__CACHE); } @@ -505,7 +513,7 @@ export class Psbt { ); } - outputHasPubkey(outputIndex: number, pubkey: Buffer): boolean { + outputHasPubkey(outputIndex: number, pubkey: Uint8Array): boolean { const output = checkForOutput(this.data.outputs, outputIndex); return pubkeyInOutput(pubkey, output, outputIndex, this.__CACHE); } @@ -529,7 +537,7 @@ export class Psbt { validateSignaturesOfInput( inputIndex: number, validator: ValidateSigFunction, - pubkey?: Buffer, + pubkey?: Uint8Array, ): boolean { const input = this.data.inputs[inputIndex]; if (isTaprootInput(input)) @@ -558,8 +566,8 @@ export class Psbt { : partialSig; if (mySigs.length < 1) throw new Error('No signatures for this pubkey'); const results: boolean[] = []; - let hashCache: Buffer; - let scriptCache: Buffer; + let hashCache: Uint8Array; + let scriptCache: Uint8Array; let sighashCache: number; for (const pSig of mySigs) { const sig = bscript.signature.decode(pSig.signature); @@ -584,7 +592,7 @@ export class Psbt { private validateSignaturesOfTaprootInput( inputIndex: number, validator: ValidateSigFunction, - pubkey?: Buffer, + pubkey?: Uint8Array, ): boolean { const input = this.data.inputs[inputIndex]; const tapKeySig = (input || {}).tapKeySig; @@ -626,7 +634,10 @@ export class Psbt { if (tapScriptSig) { for (const tapSig of tapScriptSig) { - const tapSigHash = allHashses.find(h => tapSig.pubkey.equals(h.pubkey)); + // const tapSigHash = allHashses.find(h => tapSig.pubkey.equals(h.pubkey)); + const tapSigHash = allHashses.find( + h => tools.compare(h.pubkey, tapSig.pubkey) === 0, + ); if (tapSigHash) { const isValidTapScriptSig = validator( tapSig.pubkey, @@ -816,7 +827,7 @@ export class Psbt { signTaprootInput( inputIndex: number, keyPair: Signer, - tapLeafHashToSign?: Buffer, + tapLeafHashToSign?: Uint8Array, sighashTypes?: number[], ): this { if (!keyPair || !keyPair.publicKey) @@ -862,7 +873,7 @@ export class Psbt { inputIndex: number, input: PsbtInput, keyPair: Signer, - tapLeafHashToSign?: Buffer, + tapLeafHashToSign?: Uint8Array, allowedSighashTypes: number[] = [Transaction.SIGHASH_DEFAULT], ): this { const hashesForSig = this.checkTaprootHashesForSig( @@ -893,7 +904,7 @@ export class Psbt { input.sighashType, ), leafHash: h.leafHash, - } as TapScriptSig), + }) as TapScriptSig, ); if (tapKeySig) { @@ -933,7 +944,7 @@ export class Psbt { signTaprootInputAsync( inputIndex: number, keyPair: Signer | SignerAsync, - tapLeafHash?: Buffer, + tapLeafHash?: Uint8Array, sighashTypes?: number[], ): Promise { return Promise.resolve().then(() => { @@ -983,7 +994,7 @@ export class Psbt { inputIndex: number, input: PsbtInput, keyPair: Signer | SignerAsync, - tapLeafHash?: Buffer, + tapLeafHash?: Uint8Array, sighashTypes: number[] = [Transaction.SIGHASH_DEFAULT], ): Promise { const hashesForSig = this.checkTaprootHashesForSig( @@ -995,7 +1006,7 @@ export class Psbt { ); const signaturePromises: Promise< - { tapKeySig: Buffer } | { tapScriptSig: TapScriptSig[] } + { tapKeySig: Uint8Array } | { tapScriptSig: TapScriptSig[] } >[] = []; const tapKeyHash = hashesForSig.filter(h => !h.leafHash)[0]; if (tapKeyHash) { @@ -1038,9 +1049,9 @@ export class Psbt { inputIndex: number, input: PsbtInput, keyPair: Signer | SignerAsync, - tapLeafHashToSign?: Buffer, + tapLeafHashToSign?: Uint8Array, allowedSighashTypes?: number[], - ): { hash: Buffer; leafHash?: Buffer }[] { + ): { hash: Uint8Array; leafHash?: Uint8Array }[] { if (typeof keyPair.signSchnorr !== 'function') throw new Error( `Need Schnorr Signer to sign taproot input #${inputIndex}.`, @@ -1058,8 +1069,8 @@ export class Psbt { if (!hashesForSig || !hashesForSig.length) throw new Error( - `Can not sign for input #${inputIndex} with the key ${keyPair.publicKey.toString( - 'hex', + `Can not sign for input #${inputIndex} with the key ${tools.toHex( + keyPair.publicKey, )}`, ); @@ -1135,11 +1146,11 @@ export class Psbt { interface PsbtCache { __NON_WITNESS_UTXO_TX_CACHE: Transaction[]; - __NON_WITNESS_UTXO_BUF_CACHE: Buffer[]; + __NON_WITNESS_UTXO_BUF_CACHE: Uint8Array[]; __TX_IN_CACHE: { [index: string]: number }; __TX: Transaction; __FEE_RATE?: number; - __FEE?: number; + __FEE?: bigint; __EXTRACTED_TX?: Transaction; __UNSAFE_SIGN_NONSEGWIT: boolean; } @@ -1160,23 +1171,23 @@ type PsbtOutputExtended = PsbtOutputExtendedAddress | PsbtOutputExtendedScript; interface PsbtOutputExtendedAddress extends PsbtOutput { address: string; - value: number; + value: bigint; } interface PsbtOutputExtendedScript extends PsbtOutput { - script: Buffer; - value: number; + script: Uint8Array; + value: bigint; } interface HDSignerBase { /** * DER format compressed publicKey buffer */ - publicKey: Buffer; + publicKey: Uint8Array; /** * The first 4 bytes of the sha256-ripemd160 of the publicKey */ - fingerprint: Buffer; + fingerprint: Uint8Array; } export interface HDSigner extends HDSignerBase { @@ -1189,7 +1200,7 @@ export interface HDSigner extends HDSignerBase { * Input hash (the "message digest") for the signature algorithm * Return a 64 byte signature (32 byte r and 32 byte s in that order) */ - sign(hash: Buffer): Buffer; + sign(hash: Uint8Array): Uint8Array; } /** @@ -1197,23 +1208,23 @@ export interface HDSigner extends HDSignerBase { */ export interface HDSignerAsync extends HDSignerBase { derivePath(path: string): HDSignerAsync; - sign(hash: Buffer): Promise; + sign(hash: Uint8Array): Promise; } export interface Signer { - publicKey: Buffer; + publicKey: Uint8Array; network?: any; - sign(hash: Buffer, lowR?: boolean): Buffer; - signSchnorr?(hash: Buffer): Buffer; - getPublicKey?(): Buffer; + sign(hash: Uint8Array, lowR?: boolean): Uint8Array; + signSchnorr?(hash: Uint8Array): Uint8Array; + getPublicKey?(): Uint8Array; } export interface SignerAsync { - publicKey: Buffer; + publicKey: Uint8Array; network?: any; - sign(hash: Buffer, lowR?: boolean): Promise; - signSchnorr?(hash: Buffer): Promise; - getPublicKey?(): Buffer; + sign(hash: Uint8Array, lowR?: boolean): Promise; + signSchnorr?(hash: Uint8Array): Promise; + getPublicKey?(): Uint8Array; } /** @@ -1231,7 +1242,9 @@ const transactionFromBuffer: TransactionFromBuffer = ( */ class PsbtTransaction implements ITransaction { tx: Transaction; - constructor(buffer: Uint8Array = Uint8Array.from([2, 0, 0, 0, 0, 0, 0, 0, 0, 0])) { + constructor( + buffer: Uint8Array = Uint8Array.from([2, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + ) { this.tx = Transaction.fromBuffer(buffer); checkTxEmpty(this.tx); Object.defineProperty(this, 'tx', { @@ -1254,7 +1267,7 @@ class PsbtTransaction implements ITransaction { if ( (input as any).hash === undefined || (input as any).index === undefined || - (!Buffer.isBuffer((input as any).hash) && + (!((input as any).hash instanceof Uint8Array) && typeof (input as any).hash !== 'string') || typeof (input as any).index !== 'number' ) { @@ -1262,7 +1275,8 @@ class PsbtTransaction implements ITransaction { } const hash = typeof input.hash === 'string' - ? reverseBuffer(Buffer.from(input.hash, 'hex')) + ? // ? reverseBuffer(Buffer.from(input.hash, 'hex')) + reverseBuffer(tools.fromHex(input.hash)) : input.hash; this.tx.addInput(hash, input.index, input.sequence); } @@ -1271,8 +1285,8 @@ class PsbtTransaction implements ITransaction { if ( (output as any).script === undefined || (output as any).value === undefined || - !Buffer.isBuffer((output as any).script) || - typeof (output as any).value !== 'number' + !((output as any).script instanceof Uint8Array) || + typeof (output as any).value !== 'bigint' ) { throw new Error('Error adding output.'); } @@ -1286,7 +1300,7 @@ class PsbtTransaction implements ITransaction { function canFinalize( input: PsbtInput, - script: Buffer, + script: Uint8Array, scriptType: string, ): boolean { switch (scriptType) { @@ -1311,7 +1325,7 @@ function checkCache(cache: PsbtCache): void { function hasSigs( neededSigs: number, partialSig?: any[], - pubkeys?: Buffer[], + pubkeys?: Uint8Array[], ): boolean { if (!partialSig) return false; let sigs: any; @@ -1319,7 +1333,9 @@ function hasSigs( sigs = pubkeys .map(pkey => { const pubkey = compressPubkey(pkey); - return partialSig.find(pSig => pSig.pubkey.equals(pubkey)); + return partialSig.find( + pSig => tools.compare(pSig.pubkey, pubkey) === 0, + ); }) .filter(v => !!v); } else { @@ -1338,8 +1354,10 @@ function bip32DerivationIsMine( ): (d: Bip32Derivation) => boolean { return (d: Bip32Derivation): boolean => { // if (!d.masterFingerprint.equals(root.fingerprint)) return false; - if(tools.compare(root.fingerprint, d.masterFingerprint)) return false; - if (!root.derivePath(d.path).publicKey.equals(d.pubkey)) return false; + if (tools.compare(root.fingerprint, d.masterFingerprint)) return false; + // if (!root.derivePath(d.path).publicKey.equals(d.pubkey)) return false; + if (tools.compare(root.derivePath(d.path).publicKey, d.pubkey)) + return false; return true; }; } @@ -1383,7 +1401,7 @@ function checkInputsForPartialSig(inputs: PsbtInput[], action: string): void { function checkPartialSigSighashes(input: PsbtInput): void { if (!input.sighashType || !input.partialSig) return; const { partialSig, sighashType } = input; - partialSig.forEach(pSig => { + partialSig.forEach((pSig: PartialSig) => { const { hashType } = bscript.signature.decode(pSig.signature); if (sighashType !== hashType) { throw new Error('Signature sighash does not match input sighash type'); @@ -1427,7 +1445,7 @@ function checkTxInputCache( input: { hash: Uint8Array; index: number }, ): void { const key = - tools.toHex(reverseBuffer(input.hash)) + ':' + input.index; + tools.toHex(reverseBuffer(Uint8Array.from(input.hash))) + ':' + input.index; if (cache.__TX_IN_CACHE[key]) throw new Error('Duplicate input detected.'); cache.__TX_IN_CACHE[key] = 1; } @@ -1435,7 +1453,12 @@ function checkTxInputCache( function scriptCheckerFactory( payment: any, paymentScriptName: string, -): (idx: number, spk: Uint8Array, rs: Buffer, ioType: 'input' | 'output') => void { +): ( + idx: number, + spk: Uint8Array, + rs: Uint8Array, + ioType: 'input' | 'output', +) => void { return ( inputIndex: number, scriptPubKey: Uint8Array, @@ -1444,7 +1467,7 @@ function scriptCheckerFactory( ): void => { const redeemScriptOutput = payment({ redeem: { output: redeemScript }, - }).output as Buffer; + }).output as Uint8Array; // if (!scriptPubKey.equals(redeemScriptOutput)) { if (tools.compare(scriptPubKey, redeemScriptOutput)) { @@ -1461,12 +1484,12 @@ const checkWitnessScript = scriptCheckerFactory( ); type TxCacheNumberKey = '__FEE_RATE' | '__FEE'; -function getTxCacheValue( - key: TxCacheNumberKey, +function getTxCacheValue( + key: T, name: string, inputs: PsbtInput[], c: PsbtCache, -): number | undefined { +): bigint | number | undefined { if (!inputs.every(isFinalized)) throw new Error(`PSBT must be finalized to calculate ${name}`); if (key === '__FEE_RATE' && c.__FEE_RATE) return c.__FEE_RATE; @@ -1493,32 +1516,32 @@ function getTxCacheValue( 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.) + script: Uint8Array, // The "meaningful" locking script Buffer (redeemScript for P2SH etc.) isSegwit: boolean, // Is it segwit? isP2SH: boolean, // Is it P2SH? isP2WSH: boolean, // Is it P2WSH? ) => { - finalScriptSig: Buffer | undefined; - finalScriptWitness: Buffer | undefined; + finalScriptSig: Uint8Array | undefined; + finalScriptWitness: Uint8Array | undefined; }; type FinalTaprootScriptsFunc = ( inputIndex: number, // Which input is it? input: PsbtInput, // The PSBT input contents - tapLeafHashToFinalize?: Buffer, // Only finalize this specific leaf + tapLeafHashToFinalize?: Uint8Array, // Only finalize this specific leaf ) => { - finalScriptWitness: Buffer | undefined; + finalScriptWitness: Uint8Array | undefined; }; function getFinalScripts( inputIndex: number, input: PsbtInput, - script: Buffer, + script: Uint8Array, isSegwit: boolean, isP2SH: boolean, isP2WSH: boolean, ): { - finalScriptSig: Buffer | undefined; - finalScriptWitness: Buffer | undefined; + finalScriptSig: Uint8Array | undefined; + finalScriptWitness: Uint8Array | undefined; } { const scriptType = classifyScript(script); if (!canFinalize(input, script, scriptType)) @@ -1534,18 +1557,18 @@ function getFinalScripts( } function prepareFinalScripts( - script: Buffer, + script: Uint8Array, scriptType: string, partialSig: PartialSig[], isSegwit: boolean, isP2SH: boolean, isP2WSH: boolean, ): { - finalScriptSig: Buffer | undefined; - finalScriptWitness: Buffer | undefined; + finalScriptSig: Uint8Array | undefined; + finalScriptWitness: Uint8Array | undefined; } { - let finalScriptSig: Buffer | undefined; - let finalScriptWitness: Buffer | undefined; + let finalScriptSig: Uint8Array | undefined; + let finalScriptWitness: Uint8Array | undefined; // Wow, the payments API is very handy const payment: payments.Payment = getPayment(script, scriptType, partialSig); @@ -1577,11 +1600,11 @@ function prepareFinalScripts( function getHashAndSighashType( inputs: PsbtInput[], inputIndex: number, - pubkey: Buffer, + pubkey: Uint8Array, cache: PsbtCache, sighashTypes: number[], ): { - hash: Buffer; + hash: Uint8Array; sighashType: number; } { const input = checkForInput(inputs, inputIndex); @@ -1606,15 +1629,15 @@ function getHashForSig( forValidate: boolean, sighashTypes?: number[], ): { - script: Buffer; - hash: Buffer; + script: Uint8Array; + hash: Uint8Array; sighashType: number; } { const unsignedTx = cache.__TX; const sighashType = input.sighashType || Transaction.SIGHASH_ALL; checkSighashTypeAllowed(sighashType, sighashTypes); - let hash: Buffer; + let hash: Uint8Array; let prevout: Output; if (input.nonWitnessUtxo) { @@ -1629,7 +1652,7 @@ function getHashForSig( // If a non-witness UTXO is provided, its hash must match the hash specified in the prevout // if (!prevoutHash.equals(utxoHash)) { - if (tools.compare(prevoutHash, utxoHash) !== 0) { + if (tools.compare(prevoutHash, utxoHash) !== 0) { throw new Error( `Non-witness UTXO hash for input #${inputIndex} doesn't match the hash specified in the prevout`, ); @@ -1660,8 +1683,9 @@ function getHashForSig( ); } else if (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, @@ -1676,7 +1700,7 @@ function getHashForSig( ) throw new Error( `Input #${inputIndex} has witnessUtxo but non-segwit script: ` + - `${meaningfulScript.toString('hex')}`, + `${tools.toHex(meaningfulScript)}`, ); if (!forValidate && cache.__UNSAFE_SIGN_NONSEGWIT !== false) console.warn( @@ -1707,7 +1731,7 @@ function getAllTaprootHashesForSig( input: PsbtInput, inputs: PsbtInput[], cache: PsbtCache, -): { pubkey: Buffer; hash: Buffer; leafHash?: Buffer }[] { +): { pubkey: Uint8Array; hash: Uint8Array; leafHash?: Uint8Array }[] { const allPublicKeys = []; if (input.tapInternalKey) { const key = getPrevoutTaprootKey(inputIndex, input, cache); @@ -1717,12 +1741,14 @@ function getAllTaprootHashesForSig( } if (input.tapScriptSig) { - const tapScriptPubkeys = input.tapScriptSig.map(tss => tss.pubkey); + const tapScriptPubkeys = input.tapScriptSig.map( + (tss: TapScriptSig) => tss.pubkey, + ); allPublicKeys.push(...tapScriptPubkeys); } - const allHashes = allPublicKeys.map(pubicKey => - getTaprootHashesForSig(inputIndex, input, inputs, pubicKey, cache), + const allHashes = allPublicKeys.map(publicKey => + getTaprootHashesForSig(inputIndex, input, inputs, publicKey, cache), ); return allHashes.flat(); @@ -1732,12 +1758,12 @@ function getPrevoutTaprootKey( inputIndex: number, input: PsbtInput, cache: PsbtCache, -): Buffer | null { +): Uint8Array | null { const { script } = getScriptAndAmountFromUtxo(inputIndex, input, cache); return isP2TR(script) ? script.subarray(2, 34) : null; } -function trimTaprootSig(signature: Buffer): Buffer { +function trimTaprootSig(signature: Uint8Array): Uint8Array { return signature.length === 64 ? signature : signature.subarray(0, 64); } @@ -1745,11 +1771,11 @@ function getTaprootHashesForSig( inputIndex: number, input: PsbtInput, inputs: PsbtInput[], - pubkey: Buffer, + pubkey: Uint8Array, cache: PsbtCache, - tapLeafHashToSign?: Buffer, + tapLeafHashToSign?: Uint8Array, allowedSighashTypes?: number[], -): { pubkey: Buffer; hash: Buffer; leafHash?: Buffer }[] { +): { pubkey: Uint8Array; hash: Uint8Array; leafHash?: Uint8Array }[] { const unsignedTx = cache.__TX; const sighashType = input.sighashType || Transaction.SIGHASH_DEFAULT; @@ -1764,8 +1790,9 @@ function getTaprootHashesForSig( const hashes = []; if (input.tapInternalKey && !tapLeafHashToSign) { const outputKey = - getPrevoutTaprootKey(inputIndex, input, cache) || Buffer.from([]); - if (toXOnly(pubkey).equals(outputKey)) { + getPrevoutTaprootKey(inputIndex, input, cache) || Uint8Array.from([]); + // if (toXOnly(pubkey).equals(outputKey)) { + if (tools.compare(toXOnly(pubkey), outputKey) === 0) { const tapKeyHash = unsignedTx.hashForWitnessV1( inputIndex, signingScripts, @@ -1777,8 +1804,8 @@ function getTaprootHashesForSig( } const tapLeafHashes = (input.tapLeafScript || []) - .filter(tapLeaf => pubkeyInScript(pubkey, tapLeaf.script)) - .map(tapLeaf => { + .filter((tapLeaf: TapLeafScript) => pubkeyInScript(pubkey, tapLeaf.script)) + .map((tapLeaf: TapLeafScript) => { const hash = tapleafHash({ output: tapLeaf.script, version: tapLeaf.leafVersion, @@ -1786,7 +1813,9 @@ function getTaprootHashesForSig( return Object.assign({ hash }, tapLeaf); }) .filter( - tapLeaf => !tapLeafHashToSign || tapLeafHashToSign.equals(tapLeaf.hash), + tapLeaf => + !tapLeafHashToSign || + tools.compare(tapLeafHashToSign, tapLeaf.hash) === 0, ) .map(tapLeaf => { const tapScriptHash = unsignedTx.hashForWitnessV1( @@ -1821,7 +1850,7 @@ function checkSighashTypeAllowed( } function getPayment( - script: Buffer, + script: Uint8Array, scriptType: string, partialSig: PartialSig[], ): payments.Payment { @@ -1859,7 +1888,7 @@ function getPayment( } interface GetScriptReturn { - script: Buffer | null; + script: Uint8Array | null; isSegwit: boolean; isP2SH: boolean; isP2WSH: boolean; @@ -1911,14 +1940,15 @@ function getSignersFromHD( throw new Error('Need bip32Derivation to sign with HD'); } const myDerivations = input.bip32Derivation - .map(bipDv => { - if (bipDv.masterFingerprint.equals(hdKeyPair.fingerprint)) { + .map((bipDv: Bip32Derivation) => { + // if (bipDv.masterFingerprint.equals(hdKeyPair.fingerprint)) { + if (tools.compare(bipDv.masterFingerprint, hdKeyPair.fingerprint) === 0) { return bipDv; } else { return; } }) - .filter(v => !!v); + .filter((v: Bip32Derivation | undefined) => !!v) as Bip32Derivation[]; if (myDerivations.length === 0) { throw new Error( 'Need one bip32Derivation masterFingerprint to match the HDSigner fingerprint', @@ -1926,7 +1956,8 @@ function getSignersFromHD( } const signers: Array = myDerivations.map(bipDv => { const node = hdKeyPair.derivePath(bipDv!.path); - if (!bipDv!.pubkey.equals(node.publicKey)) { + // if (!bipDv!.pubkey.equals(node.publicKey)) { + if (tools.compare(bipDv!.pubkey, node.publicKey) !== 0) { throw new Error('pubkey did not match bip32Derivation'); } return node; @@ -1934,7 +1965,10 @@ function getSignersFromHD( return signers; } -function getSortedSigs(script: Buffer, partialSig: PartialSig[]): Buffer[] { +function getSortedSigs( + script: Uint8Array, + partialSig: PartialSig[], +): Uint8Array[] { const p2ms = payments.p2ms({ output: script }); // for each pubkey in order of p2ms script return p2ms @@ -1942,7 +1976,8 @@ function getSortedSigs(script: Buffer, partialSig: PartialSig[]): Buffer[] { // filter partialSig array by pubkey being equal return ( partialSig.filter(ps => { - return ps.pubkey.equals(pk); + // return ps.pubkey.equals(pk); + return tools.compare(ps.pubkey, pk) === 0; })[0] || {} ).signature; // Any pubkey without a match will return undefined @@ -1951,10 +1986,10 @@ function getSortedSigs(script: Buffer, partialSig: PartialSig[]): Buffer[] { .filter(v => !!v); } -function scriptWitnessToWitnessStack(buffer: Buffer): Buffer[] { +function scriptWitnessToWitnessStack(buffer: Uint8Array): Uint8Array[] { let offset = 0; - function readSlice(n: number): Buffer { + function readSlice(n: number): Uint8Array { offset += n; return buffer.slice(offset - n, offset); } @@ -1965,13 +2000,13 @@ function scriptWitnessToWitnessStack(buffer: Buffer): Buffer[] { return vi.numberValue!; } - function readVarSlice(): Buffer { + function readVarSlice(): Uint8Array { return readSlice(readVarInt()); } - function readVector(): Buffer[] { + function readVector(): Uint8Array[] { const count = readVarInt(); - const vector: Buffer[] = []; + const vector: Uint8Array[] = []; for (let i = 0; i < count; i++) vector.push(readVarSlice()); return vector; } @@ -2014,7 +2049,7 @@ function addNonWitnessTxCache( delete input.nonWitnessUtxo; Object.defineProperty(input, 'nonWitnessUtxo', { enumerable: true, - get(): Buffer { + get(): Uint8Array { const buf = self.__NON_WITNESS_UTXO_BUF_CACHE[selfIndex]; const txCache = self.__NON_WITNESS_UTXO_TX_CACHE[selfIndex]; if (buf !== undefined) { @@ -2025,7 +2060,7 @@ function addNonWitnessTxCache( return newBuf; } }, - set(data: Buffer): void { + set(data: Uint8Array): void { self.__NON_WITNESS_UTXO_BUF_CACHE[selfIndex] = data; }, }); @@ -2037,7 +2072,7 @@ function inputFinalizeGetAmts( cache: PsbtCache, mustFinalize: boolean, ): void { - let inputAmount = 0; + let inputAmount = 0n; inputs.forEach((input, idx) => { if (mustFinalize && input.finalScriptSig) tx.ins[idx].script = input.finalScriptSig; @@ -2057,7 +2092,7 @@ function inputFinalizeGetAmts( }); const outputAmount = (tx.outs as Output[]).reduce( (total, o) => total + o.value, - 0, + 0n, ); const fee = inputAmount - outputAmount; if (fee < 0) { @@ -2066,7 +2101,7 @@ function inputFinalizeGetAmts( const bytes = tx.virtualSize(); cache.__FEE = fee; cache.__EXTRACTED_TX = tx; - cache.__FEE_RATE = Math.floor(fee / bytes); + cache.__FEE_RATE = Math.floor(Number(fee / BigInt(bytes))); } function nonWitnessUtxoTxFromCache( @@ -2085,7 +2120,7 @@ function getScriptFromUtxo( inputIndex: number, input: PsbtInput, cache: PsbtCache, -): Buffer { +): Uint8Array { const { script } = getScriptAndAmountFromUtxo(inputIndex, input, cache); return script; } @@ -2094,7 +2129,7 @@ function getScriptAndAmountFromUtxo( inputIndex: number, input: PsbtInput, cache: PsbtCache, -): { script: Buffer; value: number } { +): { script: Uint8Array; value: bigint } { if (input.witnessUtxo !== undefined) { return { script: input.witnessUtxo.script, @@ -2114,7 +2149,7 @@ function getScriptAndAmountFromUtxo( } function pubkeyInInput( - pubkey: Buffer, + pubkey: Uint8Array, input: PsbtInput, inputIndex: number, cache: PsbtCache, @@ -2131,7 +2166,7 @@ function pubkeyInInput( } function pubkeyInOutput( - pubkey: Buffer, + pubkey: Uint8Array, output: PsbtOutput, outputIndex: number, cache: PsbtCache, @@ -2148,14 +2183,15 @@ function pubkeyInOutput( } function redeemFromFinalScriptSig( - finalScript: Buffer | undefined, -): Buffer | undefined { + finalScript: Uint8Array | undefined, +): Uint8Array | undefined { if (!finalScript) return; const decomp = bscript.decompile(finalScript); if (!decomp) return; const lastItem = decomp[decomp.length - 1]; if ( - !Buffer.isBuffer(lastItem) || + // !Buffer.isBuffer(lastItem) || + !(lastItem instanceof Uint8Array) || isPubkeyLike(lastItem) || isSigLike(lastItem) ) @@ -2166,8 +2202,8 @@ function redeemFromFinalScriptSig( } function redeemFromFinalWitnessScript( - finalScript: Buffer | undefined, -): Buffer | undefined { + finalScript: Uint8Array | undefined, +): Uint8Array | undefined { if (!finalScript) return; const decomp = scriptWitnessToWitnessStack(finalScript); const lastItem = decomp[decomp.length - 1]; @@ -2177,7 +2213,7 @@ function redeemFromFinalWitnessScript( return lastItem; } -function compressPubkey(pubkey: Buffer): Buffer { +function compressPubkey(pubkey: Uint8Array): Uint8Array { if (pubkey.length === 65) { const parity = pubkey[64] & 1; const newKey = pubkey.slice(0, 33); @@ -2187,11 +2223,11 @@ function compressPubkey(pubkey: Buffer): Buffer { return pubkey.slice(); } -function isPubkeyLike(buf: Buffer): boolean { +function isPubkeyLike(buf: Uint8Array): boolean { return buf.length === 33 && bscript.isCanonicalPubKey(buf); } -function isSigLike(buf: Buffer): boolean { +function isSigLike(buf: Uint8Array): boolean { return bscript.isCanonicalScriptSignature(buf); } @@ -2202,7 +2238,7 @@ function getMeaningfulScript( redeemScript?: Uint8Array, witnessScript?: Uint8Array, ): { - meaningfulScript: Buffer; + meaningfulScript: Uint8Array; type: 'p2sh' | 'p2wsh' | 'p2sh-p2wsh' | 'raw'; } { const isP2SH = isP2SHScript(script); @@ -2238,10 +2274,10 @@ function getMeaningfulScript( type: isP2SHP2WSH ? 'p2sh-p2wsh' : isP2SH - ? 'p2sh' - : isP2WSH - ? 'p2wsh' - : 'raw', + ? 'p2sh' + : isP2WSH + ? 'p2wsh' + : 'raw', }; } @@ -2276,7 +2312,7 @@ type ScriptType = | 'multisig' | 'pubkey' | 'nonstandard'; -function classifyScript(script: Buffer): ScriptType { +function classifyScript(script: Uint8Array): ScriptType { if (isP2WPKH(script)) return 'witnesspubkeyhash'; if (isP2PKH(script)) return 'pubkeyhash'; if (isP2MS(script)) return 'multisig'; diff --git a/ts_src/psbt/bip371.ts b/ts_src/psbt/bip371.ts index 573264ab9..bc9fe255d 100644 --- a/ts_src/psbt/bip371.ts +++ b/ts_src/psbt/bip371.ts @@ -1,4 +1,4 @@ -import { Taptree, Tapleaf, isTapleaf, isTaptree } from '../types'; +import { Taptree, Tapleaf, isTapleaf, isTaptree } from '../types.js'; import { PsbtInput, PsbtOutput, @@ -7,32 +7,32 @@ import { TapLeaf, TapTree, TapInternalKey, -} from 'bip174/src/lib/interfaces'; +} from 'bip174'; -import { Transaction } from '../transaction'; +import { Transaction } from '../transaction.js'; import { witnessStackToScriptWitness, pubkeyPositionInScript, isP2TR, -} from './psbtutils'; +} from './psbtutils.js'; import { tweakKey, tapleafHash, rootHashFromPath, LEAF_VERSION_TAPSCRIPT, MAX_TAPTREE_DEPTH, -} from '../payments/bip341'; -import { p2tr } from '../payments'; - -import { signatureBlocksAction } from './psbtutils'; +} from '../payments/bip341.js'; +import { p2tr } from '../payments/index.js'; +import * as tools from 'uint8array-tools'; +import { signatureBlocksAction } from './psbtutils.js'; /** * Converts a public key to an X-only public key. * @param pubKey The public key to convert. * @returns The X-only public key. */ -export const toXOnly = (pubKey: Buffer) => +export const toXOnly = (pubKey: Uint8Array) => pubKey.length === 32 ? pubKey : pubKey.slice(1, 33); /** @@ -47,9 +47,9 @@ export const toXOnly = (pubKey: Buffer) => export function tapScriptFinalizer( inputIndex: number, input: PsbtInput, - tapLeafHashToFinalize?: Buffer, + tapLeafHashToFinalize?: Uint8Array, ): { - finalScriptWitness: Buffer | undefined; + finalScriptWitness: Uint8Array | undefined; } { const tapLeaf = findTapLeafToFinalize( input, @@ -73,14 +73,14 @@ export function tapScriptFinalizer( * @returns The serialized taproot signature. */ export function serializeTaprootSignature( - sig: Buffer, + sig: Uint8Array, sighashType?: number, -): Buffer { +): Uint8Array { const sighashTypeByte = sighashType - ? Buffer.from([sighashType!]) - : Buffer.from([]); + ? Uint8Array.from([sighashType!]) + : Uint8Array.from([]); - return Buffer.concat([sig, sighashTypeByte]); + return tools.concat([sig, sighashTypeByte]); } /** @@ -107,7 +107,10 @@ export function isTaprootInput(input: PsbtInput): boolean { * @param script The script to check. Optional. * @returns True if the output is a taproot output, false otherwise. */ -export function isTaprootOutput(output: PsbtOutput, script?: Buffer): boolean { +export function isTaprootOutput( + output: PsbtOutput, + script?: Uint8Array, +): boolean { return ( output && !!( @@ -164,7 +167,8 @@ function checkTaprootScriptPubkey( if (tapInternalKey) { const { script: scriptPubkey } = outputData as any; const script = getTaprootScripPubkey(tapInternalKey, tapTree); - if (scriptPubkey && !scriptPubkey.equals(script)) + // if (scriptPubkey && !scriptPubkey.equals(script)) + if (scriptPubkey && tools.compare(script, scriptPubkey) !== 0) throw new Error('Error adding output. Script or address mismatch.'); } } @@ -179,7 +183,7 @@ function checkTaprootScriptPubkey( function getTaprootScripPubkey( tapInternalKey: TapInternalKey, tapTree?: TapTree, -): Buffer { +): Uint8Array { const scriptTree = tapTree && tapTreeFromList(tapTree.leaves); const { output } = p2tr({ internalPubkey: tapInternalKey, @@ -198,7 +202,7 @@ function getTaprootScripPubkey( export function tweakInternalPubKey( inputIndex: number, input: PsbtInput, -): Buffer { +): Uint8Array { const tapInternalKey = input.tapInternalKey; const outputKey = tapInternalKey && tweakKey(tapInternalKey, input.tapMerkleRoot); @@ -206,7 +210,8 @@ export function tweakInternalPubKey( if (!outputKey) throw new Error( `Cannot tweak tap internal key for input #${inputIndex}. Public key: ${ - tapInternalKey && tapInternalKey.toString('hex') + // tapInternalKey && tapInternalKey.toString('hex') + tapInternalKey && tools.toHex(tapInternalKey) }`, ); return outputKey.x; @@ -267,8 +272,8 @@ export function checkTaprootInputForSigs( * @param signature The signature to decode. * @returns The decoded Schnorr signature. */ -function decodeSchnorrSignature(signature: Buffer): { - signature: Buffer; +function decodeSchnorrSignature(signature: Uint8Array): { + signature: Uint8Array; hashType: number; } { return { @@ -282,8 +287,8 @@ function decodeSchnorrSignature(signature: Buffer): { * @param input The PSBT input to extract signatures from. * @returns An array of taproot signatures. */ -function extractTaprootSigs(input: PsbtInput): Buffer[] { - const sigs: Buffer[] = []; +function extractTaprootSigs(input: PsbtInput): Uint8Array[] { + const sigs: Uint8Array[] = []; if (input.tapKeySig) sigs.push(input.tapKeySig); if (input.tapScriptSig) sigs.push(...input.tapScriptSig.map(s => s.signature)); @@ -301,8 +306,8 @@ function extractTaprootSigs(input: PsbtInput): Buffer[] { * @returns The taproot signature, or undefined if not found. */ function getTapKeySigFromWithness( - finalScriptWitness?: Buffer, -): Buffer | undefined { + finalScriptWitness?: Uint8Array, +): Uint8Array | undefined { if (!finalScriptWitness) return; const witness = finalScriptWitness.slice(2); // todo: add schnorr signature validation @@ -486,7 +491,10 @@ function checkIfTapLeafInTree( * @param merkleRoot The Merkle root of the tree. If not provided, the function assumes the TapLeafScript is present. * @returns A boolean indicating whether the TapLeafScript is present in the tree. */ -function isTapLeafInTree(tapLeaf: TapLeafScript, merkleRoot?: Buffer): boolean { +function isTapLeafInTree( + tapLeaf: TapLeafScript, + merkleRoot?: Uint8Array, +): boolean { if (!merkleRoot) return true; const leafHash = tapleafHash({ @@ -495,7 +503,8 @@ function isTapLeafInTree(tapLeaf: TapLeafScript, merkleRoot?: Buffer): boolean { }); const rootHash = rootHashFromPath(tapLeaf.controlBlock, leafHash); - return rootHash.equals(merkleRoot); + // return rootHash.equals(merkleRoot); + return tools.compare(rootHash, merkleRoot) === 0; } /** @@ -505,17 +514,23 @@ function isTapLeafInTree(tapLeaf: TapLeafScript, merkleRoot?: Buffer): boolean { * @param tapLeaf - The TapLeafScript object. * @returns An array of sorted signatures as Buffers. */ -function sortSignatures(input: PsbtInput, tapLeaf: TapLeafScript): Buffer[] { +function sortSignatures( + input: PsbtInput, + tapLeaf: TapLeafScript, +): Uint8Array[] { 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[]; + return ( + (input.tapScriptSig || []) + // .filter(tss => tss.leafHash.equals(leafHash)) + .filter(tss => tools.compare(tss.leafHash, leafHash) === 0) + .map(tss => addPubkeyPositionInScript(tapLeaf.script, tss)) + .sort((t1, t2) => t2.positionInScript - t1.positionInScript) + .map(t => t.signature) as Uint8Array[] + ); } /** @@ -525,7 +540,7 @@ function sortSignatures(input: PsbtInput, tapLeaf: TapLeafScript): Buffer[] { * @returns A TapScriptSigWitPosition object with the added position. */ function addPubkeyPositionInScript( - script: Buffer, + script: Uint8Array, tss: TapScriptSig, ): TapScriptSigWitPosition { return Object.assign( @@ -542,7 +557,7 @@ function addPubkeyPositionInScript( function findTapLeafToFinalize( input: PsbtInput, inputIndex: number, - leafHashToFinalize?: Buffer, + leafHashToFinalize?: Uint8Array, ): TapLeafScript { if (!input.tapScriptSig || !input.tapScriptSig.length) throw new Error( @@ -573,16 +588,19 @@ function findTapLeafToFinalize( function canFinalizeLeaf( leaf: TapLeafScript, tapScriptSig: TapScriptSig[], - hash?: Buffer, + hash?: Uint8Array, ): boolean { const leafHash = tapleafHash({ output: leaf.script, version: leaf.leafVersion, }); - const whiteListedHash = !hash || hash.equals(leafHash); + // const whiteListedHash = !hash || hash.equals(leafHash); + const whiteListedHash = !hash || tools.compare(leafHash, hash) === 0; return ( whiteListedHash && - tapScriptSig!.find(tss => tss.leafHash.equals(leafHash)) !== undefined + // tapScriptSig!.find(tss => tss.leafHash.equals(leafHash)) !== undefined + tapScriptSig!.find(tss => tools.compare(tss.leafHash, leafHash) === 0) !== + undefined ); } diff --git a/ts_src/psbt/psbtutils.ts b/ts_src/psbt/psbtutils.ts index 4bfeff164..9ef3b65c1 100644 --- a/ts_src/psbt/psbtutils.ts +++ b/ts_src/psbt/psbtutils.ts @@ -1,10 +1,10 @@ import * as varuint from 'varuint-bitcoin'; -import { PartialSig, PsbtInput } from 'bip174/lib/interfaces'; +import { PartialSig, PsbtInput } from 'bip174'; import * as bscript from '../script.js'; import { Transaction } from '../transaction.js'; import { hash160 } from '../crypto.js'; import * as payments from '../payments/index.js'; -import * as tools from "uint8array-tools"; +import * as tools from 'uint8array-tools'; /** * Checks if a given payment factory can generate a payment script from a given script. @@ -35,27 +35,29 @@ export const isP2TR = isPaymentFactory(payments.p2tr); * @param witness The witness stack to convert. * @returns The script witness as a Buffer. */ -export function witnessStackToScriptWitness(witness: Buffer[]): Buffer { - let buffer = Buffer.allocUnsafe(0); +export function witnessStackToScriptWitness(witness: Uint8Array[]): Uint8Array { + let buffer = new Uint8Array(0); - function writeSlice(slice: Buffer): void { - buffer = Buffer.concat([buffer, Buffer.from(slice)]); + function writeSlice(slice: Uint8Array): void { + // buffer = Buffer.concat([buffer, Buffer.from(slice)]); + buffer = tools.concat([buffer, slice]); } function writeVarInt(i: number): void { const currentLen = buffer.length; const varintLen = varuint.encodingLength(i); - buffer = Buffer.concat([buffer, Buffer.allocUnsafe(varintLen)]); + // buffer = Buffer.concat([buffer, Buffer.allocUnsafe(varintLen)]); + buffer = tools.concat([buffer, new Uint8Array(varintLen)]); varuint.encode(i, buffer, currentLen); } - function writeVarSlice(slice: Buffer): void { + function writeVarSlice(slice: Uint8Array): void { writeVarInt(slice.length); writeSlice(slice); } - function writeVector(vector: Buffer[]): void { + function writeVector(vector: Uint8Array[]): void { writeVarInt(vector.length); vector.forEach(writeVarSlice); } @@ -72,7 +74,10 @@ export function witnessStackToScriptWitness(witness: Buffer[]): Buffer { * @returns The index of the public key in the script, or -1 if not found. * @throws {Error} If there is an unknown script error. */ -export function pubkeyPositionInScript(pubkey: Uint8Array, script: Uint8Array): number { +export function pubkeyPositionInScript( + pubkey: Uint8Array, + script: Uint8Array, +): number { const pubkeyHash = hash160(pubkey); const pubkeyXOnly = pubkey.slice(1, 33); // slice before calling? @@ -85,8 +90,8 @@ export function pubkeyPositionInScript(pubkey: Uint8Array, script: Uint8Array): // element.equals(pubkey) || // element.equals(pubkeyHash) || // element.equals(pubkeyXOnly) - tools.compare(pubkey, element) === 0 || - tools.compare(pubkeyHash, element) === 0 || + tools.compare(pubkey, element) === 0 || + tools.compare(pubkeyHash, element) === 0 || tools.compare(pubkeyXOnly, element) === 0 ); }); @@ -98,7 +103,10 @@ export function pubkeyPositionInScript(pubkey: Uint8Array, script: Uint8Array): * @param script The script to search in. * @returns A boolean indicating whether the public key is present in the script. */ -export function pubkeyInScript(pubkey: Uint8Array, script: Uint8Array): boolean { +export function pubkeyInScript( + pubkey: Uint8Array, + script: Uint8Array, +): boolean { return pubkeyPositionInScript(pubkey, script) !== -1; } @@ -191,7 +199,9 @@ function getPsigsFromInputFinalScripts(input: PsbtInput): PartialSig[] { return scriptItems .concat(witnessItems) .filter(item => { - return Buffer.isBuffer(item) && bscript.isCanonicalScriptSignature(item); + return ( + item instanceof Uint8Array && bscript.isCanonicalScriptSignature(item) + ); }) .map(sig => ({ signature: sig })) as PartialSig[]; } diff --git a/ts_src/push_data.ts b/ts_src/push_data.ts index d78a31beb..61e576c88 100644 --- a/ts_src/push_data.ts +++ b/ts_src/push_data.ts @@ -1,5 +1,5 @@ import { OPS } from './ops.js'; -import * as tools from "uint8array-tools"; +import * as tools from 'uint8array-tools'; /** * Calculates the encoding length of a number used for push data in Bitcoin transactions. @@ -20,32 +20,36 @@ export function encodingLength(i: number): number { * @param offset - The offset at which to start writing the encoded buffer. * @returns The size of the encoded buffer. */ -export function encode(buffer: Uint8Array, num: number, offset: number): number { +export function encode( + buffer: Uint8Array, + num: number, + offset: number, +): number { const size = encodingLength(num); // ~6 bit if (size === 1) { // buffer.writeUInt8(num, offset); - tools.writeUInt8(buffer, num, offset); + tools.writeUInt8(buffer, offset, num); // 8 bit } else if (size === 2) { // buffer.writeUInt8(OPS.OP_PUSHDATA1, offset); - tools.writeUInt8(buffer, OPS.OP_PUSHDATA1, offset); + tools.writeUInt8(buffer, offset, OPS.OP_PUSHDATA1); // buffer.writeUInt8(num, offset + 1); - tools.writeUInt8(buffer, num, offset + 1); + tools.writeUInt8(buffer, offset + 1, num); // 16 bit } else if (size === 3) { // buffer.writeUInt8(OPS.OP_PUSHDATA2, offset); - tools.writeUInt8(buffer, OPS.OP_PUSHDATA2, offset); + tools.writeUInt8(buffer, offset, OPS.OP_PUSHDATA2); // buffer.writeUInt16LE(num, offset + 1); - tools.writeUInt16(buffer, num, offset + 1, "LE"); + tools.writeUInt16(buffer, offset + 1, num, 'LE'); // 32 bit } else { // buffer.writeUInt8(OPS.OP_PUSHDATA4, offset); - tools.writeUInt8(buffer, OPS.OP_PUSHDATA4, offset); + tools.writeUInt8(buffer, offset, OPS.OP_PUSHDATA4); // buffer.writeUInt32LE(num, offset + 1); - tools.writeUInt32(buffer, num, offset + 1, "LE"); + tools.writeUInt32(buffer, offset + 1, num, 'LE'); } return size; @@ -86,7 +90,7 @@ export function decode( } else if (opcode === OPS.OP_PUSHDATA2) { if (offset + 3 > buffer.length) return null; // num = buffer.readUInt16LE(offset + 1); - num = tools.readUInt16(buffer, offset + 1, "LE"); + num = tools.readUInt16(buffer, offset + 1, 'LE'); size = 3; // 32 bit @@ -95,7 +99,7 @@ export function decode( if (opcode !== OPS.OP_PUSHDATA4) throw new Error('Unexpected opcode'); // num = buffer.readUInt32LE(offset + 1); - num = tools.readUInt32(buffer, offset + 1, "LE"); + num = tools.readUInt32(buffer, offset + 1, 'LE'); size = 5; } diff --git a/ts_src/script.ts b/ts_src/script.ts index 0f81a5912..c2a9c344b 100644 --- a/ts_src/script.ts +++ b/ts_src/script.ts @@ -9,15 +9,17 @@ import * as pushdata from './push_data.js'; import * as scriptNumber from './script_number.js'; import * as scriptSignature from './script_signature.js'; import * as types from './types.js'; -const { typeforce } = types; -import * as tools from "uint8array-tools"; +import * as tools from 'uint8array-tools'; +import * as v from 'valibot'; const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1 export { OPS }; +const StackSchema = v.array(v.union([v.instance(Uint8Array), v.number()])); + function isOPInt(value: number): boolean { return ( - types.Number(value) && + v.is(v.number(), value) && (value === OPS.OP_0 || (value >= OPS.OP_1 && value <= OPS.OP_16) || value === OPS.OP_1NEGATE) @@ -25,11 +27,15 @@ function isOPInt(value: number): boolean { } function isPushOnlyChunk(value: number | Uint8Array): boolean { - return types.Buffer(value) || isOPInt(value as number); + return v.is(types.BufferSchema, value) || isOPInt(value as number); } export function isPushOnly(value: Stack): boolean { - return types.Array(value) && value.every(isPushOnlyChunk); + // return types.Array(value) && value.every(isPushOnlyChunk); + return v.is( + v.pipe(v.any(), v.everyItem(isPushOnlyChunk as (x: any) => boolean)), + value, + ); } export function countNonPushOnlyOPs(value: Stack): number { @@ -43,13 +49,14 @@ function asMinimalOP(buffer: Uint8Array): number | void { if (buffer[0] === 0x81) return OPS.OP_1NEGATE; } -function chunksIsBuffer(buf: Uint8Array | Stack): buf is Buffer { +function chunksIsBuffer(buf: Uint8Array | Stack): buf is Uint8Array { // return Buffer.isBuffer(buf); - return buf instanceof Buffer; + return buf instanceof Uint8Array; } function chunksIsArray(buf: Uint8Array | Stack): buf is Stack { - return types.Array(buf); + // return types.Array(buf); + return v.is(StackSchema, buf); } function singleChunkIsBuffer(buf: number | Uint8Array): buf is Uint8Array { @@ -63,11 +70,12 @@ function singleChunkIsBuffer(buf: number | Uint8Array): buf is Uint8Array { * @returns The compiled Buffer. * @throws Error if the compilation fails. */ -export function compile(chunks: Buffer | Stack): Buffer { +export function compile(chunks: Uint8Array | Stack): Uint8Array { // TODO: remove me if (chunksIsBuffer(chunks)) return chunks; - typeforce(types.Array, chunks); + // typeforce(types.Array, chunks); + v.parse(StackSchema, chunks); const bufferSize = chunks.reduce((accum: number, chunk) => { // data chunk @@ -84,7 +92,7 @@ export function compile(chunks: Buffer | Stack): Buffer { return accum + 1; }, 0.0); - const buffer = Buffer.allocUnsafe(bufferSize); + const buffer = new Uint8Array(bufferSize); let offset = 0; chunks.forEach(chunk => { @@ -93,7 +101,8 @@ export function compile(chunks: Buffer | Stack): Buffer { // adhere to BIP62.3, minimal push policy const opcode = asMinimalOP(chunk); if (opcode !== undefined) { - buffer.writeUInt8(opcode, offset); + // buffer.writeUInt8(opcode, offset); + tools.writeUInt8(buffer, offset, opcode); offset += 1; return; } @@ -105,7 +114,8 @@ export function compile(chunks: Buffer | Stack): Buffer { // opcode } else { - buffer.writeUInt8(chunk, offset); + // buffer.writeUInt8(chunk, offset); + tools.writeUInt8(buffer, offset, chunk); offset += 1; } }); @@ -120,7 +130,8 @@ export function decompile( // TODO: remove me if (chunksIsArray(buffer)) return buffer; - typeforce(types.Buffer, buffer); + // typeforce(types.Buffer, buffer); + v.parse(types.BufferSchema, buffer); const chunks: Array = []; let i = 0; @@ -194,17 +205,20 @@ export function toASM(chunks: Uint8Array | Array): string { * @param asm The ASM string to convert. * @returns The converted Buffer. */ -export function fromASM(asm: string): Buffer { - typeforce(types.String, asm); +export function fromASM(asm: string): Uint8Array { + // typeforce(types.String, asm); + v.parse(v.string(), asm); return compile( asm.split(' ').map(chunkStr => { // opcode? if (OPS[chunkStr] !== undefined) return OPS[chunkStr]; - typeforce(types.Hex, chunkStr); + // typeforce(types.Hex, chunkStr); + v.parse(types.HexSchema, chunkStr); // data! - return Buffer.from(chunkStr, 'hex'); + // return Buffer.from(chunkStr, 'hex'); + return tools.fromHex(chunkStr); }), ); } @@ -215,19 +229,22 @@ export function fromASM(asm: string): Buffer { * @param chunks - The chunks to convert. * @returns The stack of buffers. */ -export function toStack(chunks: Uint8Array | Array): Uint8Array[] { +export function toStack( + chunks: Uint8Array | Array, +): Uint8Array[] { chunks = decompile(chunks) as Stack; - typeforce(isPushOnly, chunks); + // typeforce(isPushOnly, chunks); + v.parse(v.custom(isPushOnly as (x: any) => boolean), chunks); return chunks.map(op => { if (singleChunkIsBuffer(op)) return op; - if (op === OPS.OP_0) return Buffer.allocUnsafe(0); + if (op === OPS.OP_0) return new Uint8Array(0); return scriptNumber.encode(op - OP_INT_BASE); }); } -export function isCanonicalPubKey(buffer: Buffer): boolean { +export function isCanonicalPubKey(buffer: Uint8Array): boolean { return types.isPoint(buffer); } @@ -238,8 +255,8 @@ export function isDefinedHashType(hashType: number): boolean { return hashTypeMod > 0x00 && hashTypeMod < 0x04; } -export function isCanonicalScriptSignature(buffer: Buffer): boolean { - if (!Buffer.isBuffer(buffer)) return false; +export function isCanonicalScriptSignature(buffer: Uint8Array): boolean { + if (!(buffer instanceof Uint8Array)) return false; if (!isDefinedHashType(buffer[buffer.length - 1])) return false; return bip66.check(buffer.slice(0, -1)); diff --git a/ts_src/script_number.ts b/ts_src/script_number.ts index 1ad20e2ff..1c574e335 100644 --- a/ts_src/script_number.ts +++ b/ts_src/script_number.ts @@ -1,3 +1,5 @@ +import * as tools from 'uint8array-tools'; + /** * Decodes a script number from a buffer. * @@ -9,7 +11,7 @@ * @throws {Error} If the script number is not minimally encoded when minimal is true. */ export function decode( - buffer: Buffer, + buffer: Uint8Array, maxLength?: number, minimal?: boolean, ): number { @@ -28,8 +30,10 @@ export function decode( // 40-bit if (length === 5) { - const a = buffer.readUInt32LE(0); - const b = buffer.readUInt8(4); + // const a = buffer.readUInt32LE(0); + // const b = buffer.readUInt8(4); + const a = tools.readUInt32(buffer, 0, 'LE'); + const b = tools.readUInt8(buffer, 4); if (b & 0x80) return -((b & ~0x80) * 0x100000000 + a); return b * 0x100000000 + a; @@ -50,35 +54,37 @@ function scriptNumSize(i: number): number { return i > 0x7fffffff ? 5 : i > 0x7fffff - ? 4 - : i > 0x7fff - ? 3 - : i > 0x7f - ? 2 - : i > 0x00 - ? 1 - : 0; + ? 4 + : i > 0x7fff + ? 3 + : i > 0x7f + ? 2 + : i > 0x00 + ? 1 + : 0; } /** - * Encodes a number into a Buffer using a specific format. + * Encodes a number into a Uint8Array using a specific format. * * @param _number - The number to encode. - * @returns The encoded number as a Buffer. + * @returns The encoded number as a Uint8Array. */ -export function encode(_number: number): Buffer { +export function encode(_number: number): Uint8Array { let value = Math.abs(_number); const size = scriptNumSize(value); - const buffer = Buffer.allocUnsafe(size); + const buffer = new Uint8Array(size); const negative = _number < 0; for (let i = 0; i < size; ++i) { - buffer.writeUInt8(value & 0xff, i); + // buffer.writeUInt8(value & 0xff, i); + tools.writeUInt8(buffer, i, value & 0xff); value >>= 8; } if (buffer[size - 1] & 0x80) { - buffer.writeUInt8(negative ? 0x80 : 0x00, size - 1); + // buffer.writeUInt8(negative ? 0x80 : 0x00, size - 1); + tools.writeUInt8(buffer, size - 1, negative ? 0x80 : 0x00); } else if (negative) { buffer[size - 1] |= 0x80; } diff --git a/ts_src/script_signature.ts b/ts_src/script_signature.ts index dc0981189..c21b45c26 100644 --- a/ts_src/script_signature.ts +++ b/ts_src/script_signature.ts @@ -1,10 +1,10 @@ import * as bip66 from './bip66.js'; import { isDefinedHashType } from './script.js'; -import * as types from './types.js'; -import * as tools from "uint8array-tools"; -const { typeforce } = types; +import * as v from 'valibot'; +import * as tools from 'uint8array-tools'; +import { NBufferSchemaFactory, UInt8Schema } from './types.js'; -const ZERO = Buffer.alloc(1, 0); +const ZERO = new Uint8Array(1); /** * Converts a buffer to a DER-encoded buffer. * @param x - The buffer to be converted. @@ -57,7 +57,7 @@ export function decode(buffer: Uint8Array): ScriptSignature { const decoded = bip66.decode(buffer.subarray(0, -1)); const r = fromDER(decoded.r); const s = fromDER(decoded.s); - const signature = Buffer.concat([r, s], 64); + const signature = tools.concat([r, s]); return { signature, hashType }; } @@ -70,11 +70,18 @@ export function decode(buffer: Uint8Array): ScriptSignature { * @throws Error if the hashType is invalid. */ export function encode(signature: Uint8Array, hashType: number): Uint8Array { - typeforce( - { - signature: types.BufferN(64), - hashType: types.UInt8, - }, + // typeforce( + // { + // signature: types.BufferN(64), + // hashType: types.UInt8, + // }, + // { signature, hashType }, + // ); + v.parse( + v.object({ + signature: NBufferSchemaFactory(64), + hashType: UInt8Schema, + }), { signature, hashType }, ); @@ -85,7 +92,7 @@ export function encode(signature: Uint8Array, hashType: number): Uint8Array { // const hashTypeBuffer = Buffer.allocUnsafe(1); const hashTypeBuffer = new Uint8Array(1); // hashTypeBuffer.writeUInt8(hashType, 0); - tools.writeUInt8(hashTypeBuffer, hashType, 0); + tools.writeUInt8(hashTypeBuffer, 0, hashType); const r = toDER(signature.slice(0, 32)); const s = toDER(signature.slice(32, 64)); diff --git a/ts_src/transaction.ts b/ts_src/transaction.ts index 2ef8db45a..7dcd045ef 100644 --- a/ts_src/transaction.ts +++ b/ts_src/transaction.ts @@ -9,8 +9,8 @@ import { sha256 } from '@noble/hashes/sha256'; import * as bscript from './script.js'; import { OPS as opcodes } from './script.js'; import * as types from './types.js'; -import * as tools from "uint8array-tools"; -const { typeforce } = types; +import * as tools from 'uint8array-tools'; +import * as v from 'valibot'; function varSliceSize(someScript: Uint8Array): number { const length = someScript.length; @@ -35,13 +35,18 @@ const EMPTY_WITNESS: Uint8Array[] = []; // '0000000000000000000000000000000000000000000000000000000000000000', // 'hex', // ); -const ZERO = tools.fromHex('0000000000000000000000000000000000000000000000000000000000000000'); +const ZERO = tools.fromHex( + '0000000000000000000000000000000000000000000000000000000000000000', +); // const ONE: Buffer = Buffer.from( // '0000000000000000000000000000000000000000000000000000000000000001', // 'hex', // ); -const ONE = tools.fromHex('0000000000000000000000000000000000000000000000000000000000000001'); -const VALUE_UINT64_MAX: Buffer = Buffer.from('ffffffffffffffff', 'hex'); +const ONE = tools.fromHex( + '0000000000000000000000000000000000000000000000000000000000000001', +); +// const VALUE_UINT64_MAX: Buffer = Buffer.from('ffffffffffffffff', 'hex'); +const VALUE_UINT64_MAX = tools.fromHex('ffffffffffffffff'); const BLANK_OUTPUT = { script: EMPTY_BUFFER, valueBuffer: VALUE_UINT64_MAX, @@ -137,11 +142,12 @@ export class Transaction { } static fromHex(hex: string): Transaction { - return Transaction.fromBuffer(Buffer.from(hex, 'hex'), false); + return Transaction.fromBuffer(tools.fromHex(hex), false); } static isCoinbaseHash(buffer: Uint8Array): boolean { - typeforce(types.Hash256bit, buffer); + // typeforce(types.Hash256bit, buffer); + v.parse(types.Hash256bitSchema, buffer); for (let i = 0; i < 32; ++i) { if (buffer[i] !== 0) return false; } @@ -160,22 +166,32 @@ export class Transaction { } addInput( - hash: Buffer, + hash: Uint8Array, index: number, sequence?: number, - scriptSig?: Buffer, + scriptSig?: Uint8Array, ): number { - typeforce( - types.tuple( - types.Hash256bit, - types.UInt32, - types.maybe(types.UInt32), - types.maybe(types.Buffer), - ), - arguments, + // typeforce( + // types.tuple( + // types.Hash256bit, + // types.UInt32, + // types.maybe(types.UInt32), + // types.maybe(types.Buffer), + // ), + // arguments, + // ); + + v.parse( + v.tuple([ + types.Hash256bitSchema, + types.UInt32Schema, + v.nullable(v.optional(types.UInt32Schema)), + v.nullable(v.optional(types.BufferSchema)), + ]), + [hash, index, sequence, scriptSig], ); - if (types.Null(sequence)) { + if (sequence === undefined || sequence === null) { sequence = Transaction.DEFAULT_SEQUENCE; } @@ -191,14 +207,18 @@ export class Transaction { ); } - addOutput(scriptPubKey: Buffer, value: number | bigint): number { - typeforce(types.tuple(types.Buffer, types.Satoshi), arguments); + addOutput(scriptPubKey: Uint8Array, value: bigint): number { + // typeforce(types.tuple(types.Buffer, types.Satoshi), arguments); + v.parse(v.tuple([types.BufferSchema, types.SatoshiSchema]), [ + scriptPubKey, + value, + ]); // Add the output and return the output's index return ( this.outs.push({ script: scriptPubKey, - value: BigInt(value), + value, }) - 1 ); } @@ -278,10 +298,16 @@ export class Transaction { prevOutScript: Uint8Array, hashType: number, ): Uint8Array { - typeforce( - types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), - arguments, - ); + // typeforce( + // types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), + // arguments, + // ); + + v.parse(v.tuple([types.UInt32Schema, types.BufferSchema, v.number()]), [ + inIndex, + prevOutScript, + hashType, + ]); // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L29 if (inIndex >= this.ins.length) return ONE; @@ -342,8 +368,9 @@ export class Transaction { } // serialize and hash - const buffer: Buffer = Buffer.allocUnsafe(txTmp.byteLength(false) + 4); - buffer.writeInt32LE(hashType, buffer.length - 4); + const buffer = new Uint8Array(txTmp.byteLength(false) + 4); + // buffer.writeInt32LE(hashType, buffer.length - 4); + tools.writeInt32(buffer, hashType, buffer.length - 4, 'LE'); txTmp.__toBuffer(buffer, 0, false); return bcrypto.hash256(buffer); @@ -352,20 +379,30 @@ export class Transaction { hashForWitnessV1( inIndex: number, prevOutScripts: Uint8Array[], - values: number[], + values: bigint[], hashType: number, leafHash?: Uint8Array, annex?: Uint8Array, ): Uint8Array { // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#common-signature-message - typeforce( - types.tuple( - types.UInt32, - typeforce.arrayOf(types.Buffer), - typeforce.arrayOf(types.Satoshi), - types.UInt32, - ), - arguments, + // typeforce( + // types.tuple( + // types.UInt32, + // typeforce.arrayOf(types.Buffer), + // typeforce.arrayOf(types.Satoshi), + // types.UInt32, + // ), + // arguments, + // ); + + v.parse( + v.tuple([ + types.UInt32Schema, + v.array(types.BufferSchema), + v.array(types.SatoshiSchema), + types.UInt32Schema, + ]), + [inIndex, prevOutScripts, values, hashType], ); if ( @@ -427,7 +464,7 @@ export class Transaction { this.outs.forEach(out => { // bufferWriter.writeUInt64(out.value); - bufferWriter.writeInt64(out.value) + bufferWriter.writeInt64(out.value); bufferWriter.writeVarSlice(out.script); }); @@ -500,7 +537,7 @@ export class Transaction { // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-19 return bcrypto.taggedHash( 'TapSighash', - Buffer.concat([Buffer.from([0x00]), sigMsgWriter.end()]), + tools.concat([Uint8Array.from([0x00]), sigMsgWriter.end()]), ); } @@ -510,9 +547,19 @@ export class Transaction { value: bigint, hashType: number, ): Uint8Array { - typeforce( - types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), - arguments, + // typeforce( + // types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), + // arguments, + // ); + + v.parse( + v.tuple([ + types.UInt32Schema, + types.BufferSchema, + types.SatoshiSchema, + types.UInt32Schema, + ]), + [inIndex, prevOutScript, value, hashType], ); let tbuffer: Uint8Array = Uint8Array.from([]); @@ -523,7 +570,7 @@ export class Transaction { let hashSequence = ZERO; if (!(hashType & Transaction.SIGHASH_ANYONECANPAY)) { - tbuffer = Buffer.allocUnsafe(36 * this.ins.length); + tbuffer = new Uint8Array(36 * this.ins.length); bufferWriter = new BufferWriter(tbuffer, 0); this.ins.forEach(txIn => { @@ -539,7 +586,7 @@ export class Transaction { (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && (hashType & 0x1f) !== Transaction.SIGHASH_NONE ) { - tbuffer = Buffer.allocUnsafe(4 * this.ins.length); + tbuffer = new Uint8Array(4 * this.ins.length); bufferWriter = new BufferWriter(tbuffer, 0); this.ins.forEach(txIn => { @@ -557,7 +604,7 @@ export class Transaction { return sum + 8 + varSliceSize(output.script); }, 0); - tbuffer = Buffer.allocUnsafe(txOutsSize); + tbuffer = new Uint8Array(txOutsSize); bufferWriter = new BufferWriter(tbuffer, 0); this.outs.forEach(out => { @@ -572,7 +619,7 @@ export class Transaction { ) { const output = this.outs[inIndex]; - tbuffer = Buffer.allocUnsafe(8 + varSliceSize(output.script)); + tbuffer = new Uint8Array(8 + varSliceSize(output.script)); bufferWriter = new BufferWriter(tbuffer, 0); bufferWriter.writeUInt64(output.value); bufferWriter.writeVarSlice(output.script); @@ -580,7 +627,7 @@ export class Transaction { hashOutputs = bcrypto.hash256(tbuffer); } - tbuffer = Buffer.allocUnsafe(156 + varSliceSize(prevOutScript)); + tbuffer = new Uint8Array(156 + varSliceSize(prevOutScript)); bufferWriter = new BufferWriter(tbuffer, 0); const input = this.ins[inIndex]; @@ -617,14 +664,19 @@ export class Transaction { return tools.toHex(this.toBuffer(undefined, undefined)); } - setInputScript(index: number, scriptSig: Buffer): void { - typeforce(types.tuple(types.Number, types.Buffer), arguments); + setInputScript(index: number, scriptSig: Uint8Array): void { + // typeforce(types.tuple(types.Number, types.Buffer), arguments); + v.parse(v.tuple([v.number(), types.BufferSchema]), [index, scriptSig]); this.ins[index].script = scriptSig; } - setWitness(index: number, witness: Buffer[]): void { - typeforce(types.tuple(types.Number, [types.Buffer]), arguments); + setWitness(index: number, witness: Uint8Array[]): void { + // typeforce(types.tuple(types.Number, [types.Buffer]), arguments); + v.parse(v.tuple([v.number(), v.array(types.BufferSchema)]), [ + index, + witness, + ]); this.ins[index].witness = witness; } @@ -635,7 +687,7 @@ export class Transaction { _ALLOW_WITNESS: boolean = false, ): Uint8Array { if (!buffer) - buffer = new Uint8Array(this.byteLength(_ALLOW_WITNESS)) as Buffer; + buffer = new Uint8Array(this.byteLength(_ALLOW_WITNESS)) as Uint8Array; const bufferWriter = new BufferWriter(buffer, initialOffset || 0); diff --git a/ts_src/types.ts b/ts_src/types.ts index f4ce4875d..cfea43c27 100644 --- a/ts_src/types.ts +++ b/ts_src/types.ts @@ -1,24 +1,28 @@ -import { Buffer as NBuffer } from 'buffer'; +import * as tools from 'uint8array-tools'; +import * as v from 'valibot'; -export const typeforce = require('typeforce'); +// export const typeforce = require('typeforce'); -const ZERO32 = NBuffer.alloc(32, 0); -const EC_P = NBuffer.from( +const ZERO32 = new Uint8Array(32); +const EC_P = tools.fromHex( 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', - 'hex', ); +export const NBufferSchemaFactory = (size: number) => + v.pipe(v.instance(Uint8Array), v.length(size)); + /** * Checks if two arrays of Buffers are equal. * @param a - The first array of Buffers. * @param b - The second array of Buffers. * @returns True if the arrays are equal, false otherwise. */ -export function stacksEqual(a: Buffer[], b: Buffer[]): boolean { +export function stacksEqual(a: Uint8Array[], b: Uint8Array[]): boolean { if (a.length !== b.length) return false; return a.every((x, i) => { - return x.equals(b[i]); + // return x.equals(b[i]); + return tools.compare(x, b[i]) === 0; }); } @@ -27,44 +31,43 @@ export function stacksEqual(a: Buffer[], b: Buffer[]): boolean { * @param p - The value to check. * @returns True if the value is a valid elliptic curve point, false otherwise. */ -export function isPoint(p: Buffer | number | undefined | null): boolean { - if (!NBuffer.isBuffer(p)) return false; +export function isPoint(p: Uint8Array | number | undefined | null): boolean { + if (!(p instanceof Uint8Array)) return false; 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(ZERO32) === 0) return false; + if (tools.compare(ZERO32, x) === 0) return false; + // if (x.compare(EC_P) >= 0) return false; + if (tools.compare(x, 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(ZERO32) === 0) return false; + if (tools.compare(ZERO32, y) === 0) return false; + // if (y.compare(EC_P) >= 0) return false; + if (tools.compare(y, EC_P) >= 0) return false; if (t === 0x04 && p.length === 65) return true; return false; } -const SATOSHI_MAX: number = 21 * 1e14; -export function Satoshi(value: number): boolean { - return typeforce.UInt53(value) && value <= SATOSHI_MAX; -} - export interface XOnlyPointAddTweakResult { parity: 1 | 0; xOnlyPubkey: Uint8Array; } export interface Tapleaf { - output: Buffer; + output: Uint8Array; version?: number; } export const TAPLEAF_VERSION_MASK = 0xfe; export function isTapleaf(o: any): o is Tapleaf { if (!o || !('output' in o)) return false; - if (!NBuffer.isBuffer(o.output)) return false; + if (!(o.output instanceof Uint8Array)) return false; if (o.version !== undefined) return (o.version & TAPLEAF_VERSION_MASK) === o.version; return true; @@ -78,7 +81,7 @@ export function isTapleaf(o: any): o is Tapleaf { export type Taptree = [Taptree | Tapleaf, Taptree | Tapleaf] | Tapleaf; export function isTaptree(scriptTree: any): scriptTree is Taptree { - if (!Array(scriptTree)) return isTapleaf(scriptTree); + if (!Array.isArray(scriptTree)) return isTapleaf(scriptTree); if (scriptTree.length !== 2) return false; return scriptTree.every((t: any) => isTaptree(t)); } @@ -91,20 +94,37 @@ export interface TinySecp256k1Interface { ): XOnlyPointAddTweakResult | null; } -export const Buffer256bit = typeforce.BufferN(32); -export const Hash160bit = typeforce.BufferN(20); -export const Hash256bit = typeforce.BufferN(32); -export const Number = typeforce.Number; -export const Array = typeforce.Array; -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; -export const tuple = typeforce.tuple; -export const UInt8 = typeforce.UInt8; -export const UInt32 = typeforce.UInt32; -export const Function = typeforce.Function; -export const BufferN = typeforce.BufferN; -export const Null = typeforce.Null; -export const oneOf = typeforce.oneOf; +export const Buffer256bitSchema = NBufferSchemaFactory(32); +export const Hash160bitSchema = NBufferSchemaFactory(20); +export const Hash256bitSchema = NBufferSchemaFactory(32); +// export const Number = typeforce.Number; +// export const Array = typeforce.Array; +// export const Boolean = typeforce.Boolean; +// export const String = typeforce.String; +export const BufferSchema = v.instance(Uint8Array); +export const HexSchema = v.pipe(v.string(), v.regex(/^([0-9a-f]{2})+$/i)); +export const UInt8Schema = v.pipe( + v.number(), + v.integer(), + v.minValue(0), + v.maxValue(0xff), +); +export const UInt32Schema = v.pipe( + v.number(), + v.integer(), + v.minValue(0), + v.maxValue(0xffffffff), +); +export const SatoshiSchema = v.pipe( + v.bigint(), + v.minValue(0n), + v.maxValue(0x7fff_ffff_ffff_ffffn), +); + +export const NullablePartial = (a: Record) => + v.object( + Object.entries(a).reduce( + (acc, next) => ({ ...acc, [next[0]]: v.nullish(next[1]) }), + {}, + ), + ); diff --git a/tsconfig.base.json b/tsconfig.base.json index 38997b07f..61b3af5a0 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -14,9 +14,9 @@ "strictPropertyInitialization": true, "noImplicitThis": true, "alwaysStrict": true, - "esModuleInterop": true, "noUnusedLocals": true, - "noUnusedParameters": true + "noUnusedParameters": true, + "moduleResolution": "Node" }, "include": ["ts_src/**/*.ts"], "exclude": ["node_modules/**/*"] diff --git a/tsconfig.cjs.json b/tsconfig.cjs.json index 705d59dea..e7c9acf6d 100644 --- a/tsconfig.cjs.json +++ b/tsconfig.cjs.json @@ -3,7 +3,8 @@ "compilerOptions": { "declaration": true, "outDir": "src/cjs", - "module": "commonjs", + "module": "CommonJS", + "esModuleInterop": true, } } \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 25e32d29b..0d15b0248 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,6 @@ "compilerOptions": { "outDir": "src/esm", "resolveJsonModule": true, - "module": "NodeNext", - "moduleResolution": "NodeNext" + "module": "ESNext", }, } From 579538fd10303d82fde86ad4435a46dec21f7ca8 Mon Sep 17 00:00:00 2001 From: ayman Date: Tue, 3 Sep 2024 19:35:12 +0530 Subject: [PATCH 4/6] feat: updated tests --- package-lock.json | 272 +++++++++----------------- package.json | 9 +- src/cjs/address.cjs | 3 - src/cjs/bip66.cjs | 2 - src/cjs/block.cjs | 8 - src/cjs/bufferutils.cjs | 67 +------ src/cjs/bufferutils.d.ts | 17 +- src/cjs/payments/bip341.cjs | 4 - src/cjs/payments/embed.cjs | 8 - src/cjs/payments/p2ms.cjs | 15 -- src/cjs/payments/p2pk.cjs | 12 -- src/cjs/payments/p2pkh.cjs | 21 -- src/cjs/payments/p2sh.cjs | 25 --- src/cjs/payments/p2tr.cjs | 30 --- src/cjs/payments/p2wpkh.cjs | 18 -- src/cjs/payments/p2wsh.cjs | 22 --- src/cjs/psbt.cjs | 15 +- src/cjs/psbt/bip371.cjs | 4 - src/cjs/psbt/psbtutils.cjs | 5 - src/cjs/push_data.cjs | 11 -- src/cjs/script.cjs | 13 -- src/cjs/script_number.cjs | 4 - src/cjs/script_signature.cjs | 12 -- src/cjs/transaction.cjs | 59 +----- src/cjs/types.cjs | 10 - src/esm/address.js | 3 - src/esm/bip66.js | 2 - src/esm/block.js | 8 - src/esm/bufferutils.js | 67 +------ src/esm/payments/bip341.js | 4 - src/esm/payments/embed.js | 8 - src/esm/payments/p2ms.js | 15 -- src/esm/payments/p2pk.js | 12 -- src/esm/payments/p2pkh.js | 21 -- src/esm/payments/p2sh.js | 25 --- src/esm/payments/p2tr.js | 30 --- src/esm/payments/p2wpkh.js | 18 -- src/esm/payments/p2wsh.js | 22 --- src/esm/psbt.js | 18 +- src/esm/psbt/bip371.js | 4 - src/esm/psbt/psbtutils.js | 5 - src/esm/push_data.js | 11 -- src/esm/script.js | 13 -- src/esm/script_number.js | 4 - src/esm/script_signature.js | 12 -- src/esm/transaction.js | 59 +----- src/esm/types.js | 10 - test/address.spec.ts | 12 +- test/bitcoin.core.spec.ts | 21 +- test/block.spec.ts | 4 +- test/bufferutils.spec.ts | 63 +----- test/crypto.spec.ts | 6 +- test/fixtures/psbt.json | 14 +- test/integration/addresses.spec.ts | 4 +- test/integration/bip32.spec.ts | 2 +- test/integration/blocks.spec.ts | 2 +- test/integration/cltv.spec.ts | 18 +- test/integration/csv.spec.ts | 10 +- test/integration/payments.spec.ts | 60 ++++-- test/integration/taproot.spec.ts | 15 +- test/integration/transactions.spec.ts | 8 +- test/payments.spec.ts | 25 +-- test/payments.utils.ts | 6 +- test/psbt.spec.ts | 47 ++--- test/script.spec.ts | 8 +- test/script_number.spec.ts | 2 +- test/script_signature.spec.ts | 2 +- test/transaction.spec.ts | 5 +- test/tsconfig.json | 109 +++++++++++ test/types.spec.ts | 2 +- ts_src/address.ts | 3 - ts_src/bip66.ts | 2 - ts_src/block.ts | 9 - ts_src/bufferutils.ts | 73 +------ ts_src/payments/bip341.ts | 4 - ts_src/payments/embed.ts | 9 - ts_src/payments/p2ms.ts | 17 -- ts_src/payments/p2pk.ts | 14 -- ts_src/payments/p2pkh.ts | 23 --- ts_src/payments/p2sh.ts | 28 --- ts_src/payments/p2tr.ts | 31 --- ts_src/payments/p2wpkh.ts | 19 -- ts_src/payments/p2wsh.ts | 25 --- ts_src/psbt.ts | 15 +- ts_src/psbt/bip371.ts | 4 - ts_src/psbt/psbtutils.ts | 5 - ts_src/push_data.ts | 11 -- ts_src/script.ts | 13 -- ts_src/script_number.ts | 4 - ts_src/script_signature.ts | 12 -- ts_src/transaction.ts | 63 +----- ts_src/types.ts | 11 -- 92 files changed, 418 insertions(+), 1459 deletions(-) create mode 100644 test/tsconfig.json diff --git a/package-lock.json b/package-lock.json index dddd21d9f..139019263 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,9 +11,8 @@ "dependencies": { "@noble/hashes": "^1.2.0", "bech32": "^2.0.0", - "bip174": "../bip174", + "bip174": "git://github.com/bitcoinjs/bip174.git#a475ce6bc50879448b054c3fe6a0d30ae1151b67", "bs58check": "^4.0.0", - "typeforce": "^1.11.3", "uint8array-tools": "../uint8array-tools", "valibot": "^0.38.0", "varuint-bitcoin": "../varuint-bitcoin" @@ -34,6 +33,7 @@ "bip39": "^3.1.0", "bip65": "^1.0.1", "bip68": "^1.0.3", + "bitcoinjs-lib": ".", "bs58": "^4.0.0", "c8": "^10.1.2", "dhttp": "^3.0.0", @@ -60,28 +60,6 @@ "node": ">=18.0.0" } }, - "../bip174": { - "version": "2.1.1", - "license": "MIT", - "dependencies": { - "uint8array-tools": "../uint8array-tools", - "varuint-bitcoin": "../varuint-bitcoin" - }, - "devDependencies": { - "@types/node": "12.0.8", - "@types/tape": "4.2.33", - "bitcoinjs-lib": "^5.0.5", - "c8": "^10.1.2", - "prettier": "^1.18.2", - "rimraf": "^2.6.3", - "tape": "^5.3.0", - "tslint": "5.17.0", - "typescript": "3.5.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "../bip32": { "version": "4.0.0", "dev": true, @@ -120,25 +98,12 @@ "@types/create-hash": "^1.2.2", "@types/mocha": "^5.2.7", "@types/node": "^20.14.2", - "@types/proxyquire": "^1.3.28", - "@types/randombytes": "^2.0.0", "@types/wif": "^2.0.2", - "bip39": "^3.0.2", - "bip65": "^1.0.1", - "bip68": "^1.0.3", - "bn.js": "^4.11.8", - "bs58": "^4.0.0", "c8": "^10.1.2", - "create-hash": "^1.2.0", - "dhttp": "^3.0.0", - "ecpair": ".", - "minimaldata": "^1.0.2", - "mocha": "^10.0.4", - "npm-audit-whitelister": "^1.0.2", + "mocha": "^10.7.3", "prettier": "^3.3.3", - "proxyquire": "^2.0.1", "rimraf": "^2.6.3", - "tiny-secp256k1": "^2.2.1", + "tiny-secp256k1": "^2.2.3", "tslint": "^6.1.3", "tsx": "^4.16.5", "typescript": "^5.0.4" @@ -148,7 +113,7 @@ } }, "../uint8array-tools": { - "version": "0.0.8", + "version": "0.0.9", "license": "MIT", "devDependencies": { "@types/jest": "27.0.2", @@ -820,11 +785,11 @@ } }, "node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz", + "integrity": "sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==", "engines": { - "node": ">= 16" + "node": "^14.21.3 || >=16" }, "funding": { "url": "https://paulmillr.com/funding/" @@ -888,14 +853,21 @@ } }, "node_modules/@shikijs/core": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.14.1.tgz", - "integrity": "sha512-KyHIIpKNaT20FtFPFjCQB5WVSTpLR/n+jQXhWHWVUMm9MaOaG9BGOG0MSyt7yA4+Lm+4c9rTc03tt3nYzeYSfw==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.16.1.tgz", + "integrity": "sha512-aI0hBtw+a6KsJp2jcD4YuQqKpeCbURMZbhHVozDknJpm+KJqeMRkEnfBC8BaKE/5XC+uofPgCLsa/TkTk0Ba0w==", "dev": true, "dependencies": { + "@shikijs/vscode-textmate": "^9.2.0", "@types/hast": "^3.0.4" } }, + "node_modules/@shikijs/vscode-textmate": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-9.2.0.tgz", + "integrity": "sha512-5FinaOp6Vdh/dl4/yaOTh0ZeKch+rYS8DUb38V3GMKYVkdqzxw53lViRKUYkVILRiVQT7dcPC7VvAKOR73zVtQ==", + "dev": true + }, "node_modules/@types/bs58": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/bs58/-/bs58-4.0.4.tgz", @@ -937,9 +909,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.19.46", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.46.tgz", - "integrity": "sha512-vnRgMS7W6cKa1/0G3/DTtQYpVrZ8c0Xm6UkLaVFrb9jtcVC3okokW09Ki1Qdrj9ISokszD69nY4WDLRlvHlhAA==", + "version": "18.19.48", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.48.tgz", + "integrity": "sha512-7WevbG4ekUcRQSZzOwxWgi5dZmTak7FaxXDoW7xVxPBmKx1rTzfmRLkeCgJzcbBnOV2dkhAPc8cCeT6agocpjg==", "dev": true, "dependencies": { "undici-types": "~5.26.4" @@ -967,16 +939,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.2.0.tgz", - "integrity": "sha512-02tJIs655em7fvt9gps/+4k4OsKULYGtLBPJfOsmOq1+3cdClYiF0+d6mHu6qDnTcg88wJBkcPLpQhq7FyDz0A==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.4.0.tgz", + "integrity": "sha512-rg8LGdv7ri3oAlenMACk9e+AR4wUV0yrrG+XKsGKOK0EVgeEDqurkXMPILG2836fW4ibokTB5v4b6Z9+GYQDEw==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.2.0", - "@typescript-eslint/type-utils": "8.2.0", - "@typescript-eslint/utils": "8.2.0", - "@typescript-eslint/visitor-keys": "8.2.0", + "@typescript-eslint/scope-manager": "8.4.0", + "@typescript-eslint/type-utils": "8.4.0", + "@typescript-eslint/utils": "8.4.0", + "@typescript-eslint/visitor-keys": "8.4.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -1000,15 +972,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.2.0.tgz", - "integrity": "sha512-j3Di+o0lHgPrb7FxL3fdEy6LJ/j2NE8u+AP/5cQ9SKb+JLH6V6UHDqJ+e0hXBkHP1wn1YDFjYCS9LBQsZDlDEg==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.4.0.tgz", + "integrity": "sha512-NHgWmKSgJk5K9N16GIhQ4jSobBoJwrmURaLErad0qlLjrpP5bECYg+wxVTGlGZmJbU03jj/dfnb6V9bw+5icsA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.2.0", - "@typescript-eslint/types": "8.2.0", - "@typescript-eslint/typescript-estree": "8.2.0", - "@typescript-eslint/visitor-keys": "8.2.0", + "@typescript-eslint/scope-manager": "8.4.0", + "@typescript-eslint/types": "8.4.0", + "@typescript-eslint/typescript-estree": "8.4.0", + "@typescript-eslint/visitor-keys": "8.4.0", "debug": "^4.3.4" }, "engines": { @@ -1028,13 +1000,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.2.0.tgz", - "integrity": "sha512-OFn80B38yD6WwpoHU2Tz/fTz7CgFqInllBoC3WP+/jLbTb4gGPTy9HBSTsbDWkMdN55XlVU0mMDYAtgvlUspGw==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.4.0.tgz", + "integrity": "sha512-n2jFxLeY0JmKfUqy3P70rs6vdoPjHK8P/w+zJcV3fk0b0BwRXC/zxRTEnAsgYT7MwdQDt/ZEbtdzdVC+hcpF0A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.2.0", - "@typescript-eslint/visitor-keys": "8.2.0" + "@typescript-eslint/types": "8.4.0", + "@typescript-eslint/visitor-keys": "8.4.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1045,13 +1017,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.2.0.tgz", - "integrity": "sha512-g1CfXGFMQdT5S+0PSO0fvGXUaiSkl73U1n9LTK5aRAFnPlJ8dLKkXr4AaLFvPedW8lVDoMgLLE3JN98ZZfsj0w==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.4.0.tgz", + "integrity": "sha512-pu2PAmNrl9KX6TtirVOrbLPLwDmASpZhK/XU7WvoKoCUkdtq9zF7qQ7gna0GBZFN0hci0vHaSusiL2WpsQk37A==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "8.2.0", - "@typescript-eslint/utils": "8.2.0", + "@typescript-eslint/typescript-estree": "8.4.0", + "@typescript-eslint/utils": "8.4.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -1069,9 +1041,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.2.0.tgz", - "integrity": "sha512-6a9QSK396YqmiBKPkJtxsgZZZVjYQ6wQ/TlI0C65z7vInaETuC6HAHD98AGLC8DyIPqHytvNuS8bBVvNLKyqvQ==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.4.0.tgz", + "integrity": "sha512-T1RB3KQdskh9t3v/qv7niK6P8yvn7ja1mS7QK7XfRVL6wtZ8/mFs/FHf4fKvTA0rKnqnYxl/uHFNbnEt0phgbw==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1082,15 +1054,15 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.2.0.tgz", - "integrity": "sha512-kiG4EDUT4dImplOsbh47B1QnNmXSoUqOjWDvCJw/o8LgfD0yr7k2uy54D5Wm0j4t71Ge1NkynGhpWdS0dEIAUA==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.4.0.tgz", + "integrity": "sha512-kJ2OIP4dQw5gdI4uXsaxUZHRwWAGpREJ9Zq6D5L0BweyOrWsL6Sz0YcAZGWhvKnH7fm1J5YFE1JrQL0c9dd53A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.2.0", - "@typescript-eslint/visitor-keys": "8.2.0", + "@typescript-eslint/types": "8.4.0", + "@typescript-eslint/visitor-keys": "8.4.0", "debug": "^4.3.4", - "globby": "^11.1.0", + "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", @@ -1134,15 +1106,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.2.0.tgz", - "integrity": "sha512-O46eaYKDlV3TvAVDNcoDzd5N550ckSe8G4phko++OCSC1dYIb9LTc3HDGYdWqWIAT5qDUKphO6sd9RrpIJJPfg==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.4.0.tgz", + "integrity": "sha512-swULW8n1IKLjRAgciCkTCafyTHHfwVQFt8DovmaF69sKbOxTSFMmIZaSHjqO9i/RV0wIblaawhzvtva8Nmm7lQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.2.0", - "@typescript-eslint/types": "8.2.0", - "@typescript-eslint/typescript-estree": "8.2.0" + "@typescript-eslint/scope-manager": "8.4.0", + "@typescript-eslint/types": "8.4.0", + "@typescript-eslint/typescript-estree": "8.4.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1156,12 +1128,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.2.0.tgz", - "integrity": "sha512-sbgsPMW9yLvS7IhCi8IpuK1oBmtbWUNP+hBdwl/I9nzqVsszGnNGti5r9dUtF5RLivHUFFIdRvLiTsPhzSyJ3Q==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.4.0.tgz", + "integrity": "sha512-zTQD6WLNTre1hj5wp09nBIDiOc2U5r/qmzo7wxPn4ZgAjHql09EofqhF9WF+fZHzL5aCyaIpPcT2hyxl73kr9A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.2.0", + "@typescript-eslint/types": "8.4.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -1267,15 +1239,6 @@ "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", @@ -1306,9 +1269,9 @@ "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" }, "node_modules/better-npm-audit": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/better-npm-audit/-/better-npm-audit-3.8.3.tgz", - "integrity": "sha512-DY1VwwxUF/Bc5Rgh1kP0S8Jg63YyBICG+6/KGYjo9cqZ50jzF+bMSqez3yQ6Bvvf4vd9TRs/nw/GT/ZZEaLbvg==", + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/better-npm-audit/-/better-npm-audit-3.10.0.tgz", + "integrity": "sha512-fzvUFurO4LFr+8TkxWyeOstUAfK5i8Ke0U0Y51N/r2NdEfiSI4YHbWi7YXt+QBJ4jX+dx/cP8ujZ/T5Tl2r4Iw==", "dev": true, "dependencies": { "commander": "^8.0.0", @@ -1337,8 +1300,17 @@ } }, "node_modules/bip174": { - "resolved": "../bip174", - "link": true + "version": "2.1.1", + "resolved": "git+ssh://git@github.com/bitcoinjs/bip174.git#a475ce6bc50879448b054c3fe6a0d30ae1151b67", + "integrity": "sha512-nJq4YcTyTakoFrWJnDfn1+d8TodI9CTl39BHKncErdaQDmMemA1tsfv6k7lCj23SjfGxHe+9/+OBhPnH7apPVA==", + "license": "MIT", + "dependencies": { + "uint8array-tools": "^0.0.9", + "varuint-bitcoin": "^2.0.0" + }, + "engines": { + "node": ">=18.0.0" + } }, "node_modules/bip32": { "resolved": "../bip32", @@ -1377,6 +1349,10 @@ "integrity": "sha512-pef6gxZFztEhaE9RY9HmWVmiIHqCb2OyS4HPKkpc6CIiiOa3Qmuoylxc5P2EkU3w+5eTSifI9SEZC88idAIGow==", "dev": true }, + "node_modules/bitcoinjs-lib": { + "resolved": "", + "link": true + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1698,18 +1674,6 @@ "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/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -1778,9 +1742,9 @@ } }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, "engines": { "node": ">=6" @@ -2213,9 +2177,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.7.6", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.6.tgz", - "integrity": "sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA==", + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.0.tgz", + "integrity": "sha512-Pgba6TExTZ0FJAn1qkJAjIeKoDJ3CsI2ChuLohJnZl/tTU8MVrq3b+2t5UOPfRa4RMsorClBjJALkJUMjG1PAw==", "dev": true, "dependencies": { "resolve-pkg-maps": "^1.0.0" @@ -2289,26 +2253,6 @@ "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/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -3088,15 +3032,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "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/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -3466,12 +3401,13 @@ } }, "node_modules/shiki": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.14.1.tgz", - "integrity": "sha512-FujAN40NEejeXdzPt+3sZ3F2dx1U24BY2XTY01+MG8mbxCiA2XukXdcbyMyLAHJ/1AUUnQd1tZlvIjefWWEJeA==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.16.1.tgz", + "integrity": "sha512-tCJIMaxDVB1mEIJ5TvfZU7kCPB5eo9fli5+21Olc/bmyv+w8kye3JOp+LZRmGkAyT71hrkefQhTiY+o9mBikRQ==", "dev": true, "dependencies": { - "@shikijs/core": "1.14.1", + "@shikijs/core": "1.16.1", + "@shikijs/vscode-textmate": "^9.2.0", "@types/hast": "^3.0.4" } }, @@ -3487,15 +3423,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "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", @@ -3844,9 +3771,9 @@ "dev": true }, "node_modules/tsx": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.18.0.tgz", - "integrity": "sha512-a1jaKBSVQkd6yEc1/NI7G6yHFfefIcuf3QJST7ZEyn4oQnxLYrZR5uZAM8UrwUa3Ge8suiZHcNS1gNrEvmobqg==", + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.0.tgz", + "integrity": "sha512-bV30kM7bsLZKZIOCHeMNVMJ32/LuJzLVajkQI/qf92J2Qr08ueLQvW00PUZGiuLPP760UINwupgUj8qrSCPUKg==", "dev": true, "dependencies": { "esbuild": "~0.23.0", @@ -3920,11 +3847,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "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": "5.5.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", diff --git a/package.json b/package.json index 44f4fbbcd..36594ccae 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,11 @@ "require": "./src/cjs/index.cjs", "import": "./src/esm/index.js", "types": "./src/cjs/index.d.ts" + }, + "./src/*": { + "require": "./src/cjs/*.cjs", + "types": "./src/cjs/*.d.ts", + "import": "./src/esm/*.js" } }, "engines": { @@ -60,14 +65,14 @@ "dependencies": { "@noble/hashes": "^1.2.0", "bech32": "^2.0.0", - "bip174": "../bip174", + "bip174": "git://github.com/bitcoinjs/bip174.git#a475ce6bc50879448b054c3fe6a0d30ae1151b67", "bs58check": "^4.0.0", - "typeforce": "^1.11.3", "uint8array-tools": "../uint8array-tools", "valibot": "^0.38.0", "varuint-bitcoin": "../varuint-bitcoin" }, "devDependencies": { + "bitcoinjs-lib": ".", "@eslint/eslintrc": "^3.1.0", "@eslint/js": "^9.9.1", "@types/bs58": "^4.0.0", diff --git a/src/cjs/address.cjs b/src/cjs/address.cjs index 57eee4e24..390994ae3 100644 --- a/src/cjs/address.cjs +++ b/src/cjs/address.cjs @@ -99,7 +99,6 @@ 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 = tools.readUInt8(payload, 0); const hash = payload.slice(1); return { version, hash }; @@ -137,9 +136,7 @@ function toBase58Check(hash, version) { version, ]); const payload = new Uint8Array(21); - // payload.writeUInt8(version, 0); tools.writeUInt8(payload, 0, version); - // hash.copy(payload, 1); payload.set(hash, 1); return bs58check_1.default.encode(payload); } diff --git a/src/cjs/bip66.cjs b/src/cjs/bip66.cjs index 1e0f47984..1fb691cd8 100644 --- a/src/cjs/bip66.cjs +++ b/src/cjs/bip66.cjs @@ -93,11 +93,9 @@ function encode(r, s) { signature[1] = signature.length - 2; signature[2] = 0x02; signature[3] = r.length; - // r.copy(signature, 4); signature.set(r, 4); signature[4 + lenR] = 0x02; signature[5 + lenR] = s.length; - // s.copy(signature, 6 + lenR); signature.set(s, 6 + lenR); return signature; } diff --git a/src/cjs/block.cjs b/src/cjs/block.cjs index 158b37ef3..bc4db559c 100644 --- a/src/cjs/block.cjs +++ b/src/cjs/block.cjs @@ -51,7 +51,6 @@ const merkle_js_1 = require('./merkle.cjs'); const transaction_js_1 = require('./transaction.cjs'); const v = __importStar(require('valibot')); const tools = __importStar(require('uint8array-tools')); -// const { typeforce } = types; const errorMerkleNoTxes = new TypeError( 'Cannot compute merkle root for zero transactions', ); @@ -90,21 +89,18 @@ class Block { return block; } static fromHex(hex) { - // return Block.fromBuffer(Buffer.from(hex, 'hex')); return Block.fromBuffer(tools.fromHex(hex)); } static calculateTarget(bits) { const exponent = ((bits & 0xff000000) >> 24) - 3; const mantissa = bits & 0x007fffff; const target = new Uint8Array(32); - // target.writeUIntBE(mantissa, 29 - exponent, 3); target[29 - exponent] = (mantissa >> 16) & 0xff; target[30 - exponent] = (mantissa >> 8) & 0xff; target[31 - exponent] = mantissa & 0xff; return target; } static calculateMerkleRoot(transactions, forWitness) { - // typeforce([{ getHash: types.Function }], transactions); v.parse(v.array(v.object({ getHash: v.function() })), transactions); if (transactions.length === 0) throw errorMerkleNoTxes; if (forWitness && !txesHaveWitnessCommit(transactions)) @@ -136,7 +132,6 @@ class Block { const witnessCommits = this.transactions[0].outs .filter( out => - // out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex')), tools.compare( out.script.slice(0, 6), Uint8Array.from([0x6a, 0x24, 0xaa, 0x21, 0xa9, 0xed]), @@ -225,13 +220,11 @@ class Block { checkProofOfWork() { const hash = (0, bufferutils_js_1.reverseBuffer)(this.getHash()); const target = Block.calculateTarget(this.bits); - // return hash.compare(target) <= 0; return tools.compare(hash, target) <= 0; } __checkMerkleRoot() { if (!this.transactions) throw errorMerkleNoTxes; const actualMerkleRoot = Block.calculateMerkleRoot(this.transactions); - // return this.merkleRoot!.compare(actualMerkleRoot) === 0; return tools.compare(this.merkleRoot, actualMerkleRoot) === 0; } __checkWitnessCommit() { @@ -241,7 +234,6 @@ class Block { this.transactions, true, ); - // return this.witnessCommit!.compare(actualWitnessCommit) === 0; return tools.compare(this.witnessCommit, actualWitnessCommit) === 0; } } diff --git a/src/cjs/bufferutils.cjs b/src/cjs/bufferutils.cjs index 9023d1ef0..c52453264 100644 --- a/src/cjs/bufferutils.cjs +++ b/src/cjs/bufferutils.cjs @@ -64,54 +64,6 @@ function verifuint(value, max) { if (Math.floor(Number(value)) !== Number(value)) throw new Error('value has a fractional component'); } -// export function readUInt64LE(buffer: Buffer, offset: number): number { -// const a = buffer.readUInt32LE(offset); -// let b = buffer.readUInt32LE(offset + 4); -// b *= 0x100000000; -// verifuint(b + a, MAX_JS_NUMBER); -// return b + a; -// } -/** - * Writes a 64-bit unsigned integer in little-endian format to the specified buffer at the given offset. - * - * @param buffer - The buffer to write the value to. - * @param value - The 64-bit unsigned integer value to write. - * @param offset - The offset in the buffer where the value should be written. - * @returns The new offset after writing the value. - */ -// export function writeUInt64LE( -// buffer: Buffer, -// value: number, -// offset: number, -// ): number { -// verifuint(value, MAX_JS_NUMBER); -// buffer.writeInt32LE(value & -1, offset); -// buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4); -// return offset + 8; -// } -/** - * Reads a 64-bit signed integer from a Uint8Array in little-endian format. - * - * @param {Uint8Array} buffer - The buffer to read the value from. - * @param {number} offset - The offset in the buffer where the value starts. - * @return {number} The 64-bit signed integer value. - */ -// export function readInt64LE( -// buffer: Uint8Array, -// offset: number -// ): number { -// if((buffer[offset + 7] & 0x7f) > 0) throw new Error("RangeError: value out of range, greater than int64"); -// return ( -// buffer[offset] | -// (buffer[offset + 1] << 8) | -// (buffer[offset + 2] << 16) | -// (buffer[offset + 3] << 24) | -// (buffer[offset + 4] << 32) | -// (buffer[offset + 5] << 40) | -// (buffer[offset + 6] << 48) | -// (buffer[offset + 7] << 56) -// ); -// } /** * Reverses the order of bytes in a buffer. * @param buffer - The buffer to reverse. @@ -146,29 +98,24 @@ class BufferWriter { constructor(buffer, offset = 0) { this.buffer = buffer; this.offset = offset; - // typeforce(types.tuple(types.Buffer, types.UInt32), [buffer, offset]); v.parse(v.tuple([types.BufferSchema, types.UInt32Schema]), [ buffer, offset, ]); } writeUInt8(i) { - // this.offset = this.buffer.writeUInt8(i, this.offset); this.offset = tools.writeUInt8(this.buffer, this.offset, i); } writeInt32(i) { - // this.offset = this.buffer.writeInt32LE(i, this.offset); - this.offset = tools.writeInt32(this.buffer, i, this.offset, 'LE'); + this.offset = tools.writeInt32(this.buffer, this.offset, i, 'LE'); } writeInt64(i) { - this.offset = tools.writeInt64(this.buffer, BigInt(i), this.offset, 'LE'); + this.offset = tools.writeInt64(this.buffer, this.offset, BigInt(i), 'LE'); } writeUInt32(i) { - // this.offset = this.buffer.writeUInt32LE(i, this.offset); this.offset = tools.writeUInt32(this.buffer, this.offset, i, 'LE'); } writeUInt64(i) { - // this.offset = writeUInt64LE(this.buffer, i, this.offset); this.offset = tools.writeUInt64(this.buffer, this.offset, BigInt(i), 'LE'); } writeVarInt(i) { @@ -179,7 +126,6 @@ class BufferWriter { if (this.buffer.length < this.offset + slice.length) { throw new Error('Cannot write slice out of bounds'); } - // this.offset += slice.copy(this.buffer, this.offset); this.buffer.set(slice, this.offset); this.offset += slice.length; } @@ -208,33 +154,28 @@ class BufferReader { constructor(buffer, offset = 0) { this.buffer = buffer; this.offset = offset; - // typeforce(types.tuple(types.Buffer, types.UInt32), [buffer, offset]); v.parse(v.tuple([types.BufferSchema, types.UInt32Schema]), [ buffer, offset, ]); } readUInt8() { - // const result = this.buffer.readUInt8(this.offset); const result = tools.readUInt8(this.buffer, this.offset); this.offset++; return result; } readInt32() { - // const result = readInt32LE(this.buffer, this.offset); const result = tools.readInt32(this.buffer, this.offset, 'LE'); this.offset += 4; return result; } readUInt32() { - // const result = this.buffer.readUInt32LE(this.offset); const result = tools.readUInt32(this.buffer, this.offset, 'LE'); this.offset += 4; return result; } - readUInt64() { - // const result = readUInt64LE(this.buffer, this.offset); - const result = tools.readUInt64(this.buffer, this.offset, 'LE'); + readInt64() { + const result = tools.readInt64(this.buffer, this.offset, 'LE'); this.offset += 8; return result; } diff --git a/src/cjs/bufferutils.d.ts b/src/cjs/bufferutils.d.ts index ecfd943d2..0998bfa56 100644 --- a/src/cjs/bufferutils.d.ts +++ b/src/cjs/bufferutils.d.ts @@ -1,20 +1,5 @@ import * as varuint from 'varuint-bitcoin'; export { varuint }; -/** - * Writes a 64-bit unsigned integer in little-endian format to the specified buffer at the given offset. - * - * @param buffer - The buffer to write the value to. - * @param value - The 64-bit unsigned integer value to write. - * @param offset - The offset in the buffer where the value should be written. - * @returns The new offset after writing the value. - */ -/** - * Reads a 64-bit signed integer from a Uint8Array in little-endian format. - * - * @param {Uint8Array} buffer - The buffer to read the value from. - * @param {number} offset - The offset in the buffer where the value starts. - * @return {number} The 64-bit signed integer value. - */ /** * Reverses the order of bytes in a buffer. * @param buffer - The buffer to reverse. @@ -51,7 +36,7 @@ export declare class BufferReader { readUInt8(): number; readInt32(): number; readUInt32(): number; - readUInt64(): bigint; + readInt64(): bigint; readVarInt(): bigint; readSlice(n: number | bigint): Uint8Array; readVarSlice(): Uint8Array; diff --git a/src/cjs/payments/bip341.cjs b/src/cjs/payments/bip341.cjs index 791bfe6b9..480bcfeed 100644 --- a/src/cjs/payments/bip341.cjs +++ b/src/cjs/payments/bip341.cjs @@ -51,7 +51,6 @@ exports.findScriptPath = findScriptPath; exports.tapleafHash = tapleafHash; exports.tapTweakHash = tapTweakHash; exports.tweakKey = tweakKey; -// import { Buffer as NBuffer } from 'buffer'; const ecc_lib_js_1 = require('../ecc_lib.cjs'); const bcrypto = __importStar(require('../crypto.cjs')); const bufferutils_js_1 = require('../bufferutils.cjs'); @@ -76,7 +75,6 @@ function rootHashFromPath(controlBlock, leafHash) { 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) { if (tools.compare(kj, ej) < 0) { kj = tapBranchHash(kj, ej); } else { @@ -116,7 +114,6 @@ function findScriptPath(node, 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)) { } else if (tools.compare(node.hash, hash) === 0) { return []; } @@ -156,7 +153,6 @@ function tapBranchHash(a, b) { function serializeScript(s) { /* global BigInt */ const varintLen = bufferutils_js_1.varuint.encodingLength(s.length); - // const buffer = NBuffer.allocUnsafe(varintLen); // better const buffer = new Uint8Array(varintLen); bufferutils_js_1.varuint.encode(s.length, buffer); return tools.concat([buffer, s]); diff --git a/src/cjs/payments/embed.cjs b/src/cjs/payments/embed.cjs index eddcafff2..42034a92c 100644 --- a/src/cjs/payments/embed.cjs +++ b/src/cjs/payments/embed.cjs @@ -62,14 +62,6 @@ const OPS = bscript.OPS; function p2data(a, opts) { if (!a.data && !a.output) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - // typef( - // { - // network: typef.maybe(typef.Object), - // output: typef.maybe(typef.Buffer), - // data: typef.maybe(typef.arrayOf(typef.Buffer)), - // }, - // a, - // ); v.parse( v.partial( v.object({ diff --git a/src/cjs/payments/p2ms.cjs b/src/cjs/payments/p2ms.cjs index d7efe41af..b84158af3 100644 --- a/src/cjs/payments/p2ms.cjs +++ b/src/cjs/payments/p2ms.cjs @@ -76,18 +76,6 @@ function p2ms(a, opts) { (opts.allowIncomplete && x === OPS.OP_0) !== undefined ); } - // typef( - // { - // network: typef.maybe(typef.Object), - // m: typef.maybe(typef.Number), - // n: typef.maybe(typef.Number), - // output: typef.maybe(typef.Buffer), - // pubkeys: typef.maybe(typef.arrayOf(isPoint)), - // signatures: typef.maybe(typef.arrayOf(isAcceptableSignature)), - // input: typef.maybe(typef.Buffer), - // }, - // a, - // ); v.parse( v.partial( v.object({ @@ -167,10 +155,7 @@ function p2ms(a, opts) { if (opts.validate) { if (a.output) { decode(a.output); - // if (!typef.Number(chunks[0])) throw new TypeError('Output is invalid'); v.parse(v.number(), chunks[0], { message: 'Output is invalid' }); - // if (!typef.Number(chunks[chunks.length - 2])) - // throw new TypeError('Output is invalid'); v.parse(v.number(), chunks[chunks.length - 2], { message: 'Output is invalid', }); diff --git a/src/cjs/payments/p2pk.cjs b/src/cjs/payments/p2pk.cjs index 61fb41ef4..65310dbc3 100644 --- a/src/cjs/payments/p2pk.cjs +++ b/src/cjs/payments/p2pk.cjs @@ -66,16 +66,6 @@ function p2pk(a, opts) { if (!a.input && !a.output && !a.pubkey && !a.input && !a.signature) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - // typef( - // { - // network: typef.maybe(typef.Object), - // output: typef.maybe(typef.Buffer), - // pubkey: typef.maybe(isPoint), - // signature: typef.maybe(bscript.isCanonicalScriptSignature), - // input: typef.maybe(typef.Buffer), - // }, - // a, - // ); v.parse( v.partial( v.object({ @@ -123,12 +113,10 @@ function p2pk(a, opts) { throw new TypeError('Output is invalid'); if (!(0, types_js_1.isPoint)(o.pubkey)) throw new TypeError('Output pubkey is invalid'); - // if (a.pubkey && !a.pubkey.equals(o.pubkey!)) if (a.pubkey && tools.compare(a.pubkey, o.pubkey) !== 0) throw new TypeError('Pubkey mismatch'); } if (a.signature) { - // if (a.input && !a.input.equals(o.input!)) if (a.input && tools.compare(a.input, o.input) !== 0) throw new TypeError('Signature mismatch'); } diff --git a/src/cjs/payments/p2pkh.cjs b/src/cjs/payments/p2pkh.cjs index ce8bc75e5..2ec52c192 100644 --- a/src/cjs/payments/p2pkh.cjs +++ b/src/cjs/payments/p2pkh.cjs @@ -73,18 +73,6 @@ function p2pkh(a, opts) { if (!a.address && !a.hash && !a.output && !a.pubkey && !a.input) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - // typef( - // { - // network: typef.maybe(typef.Object), - // address: typef.maybe(typef.String), - // hash: typef.maybe(typef.BufferN(20)), - // output: typef.maybe(typef.BufferN(25)), - // pubkey: typef.maybe(isPoint), - // signature: typef.maybe(bscript.isCanonicalScriptSignature), - // input: typef.maybe(typef.Buffer), - // }, - // a, - // ); v.parse( v.partial( v.object({ @@ -101,7 +89,6 @@ function p2pkh(a, opts) { ); const _address = lazy.value(() => { const payload = bs58check_1.default.decode(a.address); - // const version = payload.readUInt8(0); const version = tools.readUInt8(payload, 0); const hash = payload.slice(1); return { version, hash }; @@ -114,9 +101,7 @@ function p2pkh(a, opts) { lazy.prop(o, 'address', () => { if (!o.hash) return; const payload = new Uint8Array(21); - // payload.writeUInt8(network.pubKeyHash, 0); tools.writeUInt8(payload, 0, network.pubKeyHash); - // o.hash.copy(payload, 1); payload.set(o.hash, 1); return bs58check_1.default.encode(payload); }); @@ -162,7 +147,6 @@ function p2pkh(a, opts) { hash = _address().hash; } if (a.hash) { - // if (hash.length > 0 && !hash.equals(a.hash)) if (hash.length > 0 && tools.compare(hash, a.hash) !== 0) throw new TypeError('Hash mismatch'); else hash = a.hash; @@ -178,14 +162,12 @@ function p2pkh(a, opts) { ) throw new TypeError('Output is invalid'); const hash2 = a.output.slice(3, 23); - // if (hash.length > 0 && !hash.equals(hash2)) if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; } if (a.pubkey) { const pkh = bcrypto.hash160(a.pubkey); - // if (hash.length > 0 && !hash.equals(pkh)) if (hash.length > 0 && tools.compare(hash, pkh) !== 0) throw new TypeError('Hash mismatch'); else hash = pkh; @@ -197,14 +179,11 @@ function p2pkh(a, opts) { throw new TypeError('Input has invalid signature'); if (!(0, types_js_1.isPoint)(chunks[1])) throw new TypeError('Input has invalid pubkey'); - // if (a.signature && !a.signature.equals(chunks[0])) if (a.signature && tools.compare(a.signature, chunks[0]) !== 0) throw new TypeError('Signature mismatch'); - // if (a.pubkey && !a.pubkey.equals(chunks[1] as Buffer)) if (a.pubkey && tools.compare(a.pubkey, chunks[1]) !== 0) throw new TypeError('Pubkey mismatch'); const pkh = bcrypto.hash160(chunks[1]); - // if (hash.length > 0 && !hash.equals(pkh)) if (hash.length > 0 && tools.compare(hash, pkh) !== 0) throw new TypeError('Hash mismatch'); } diff --git a/src/cjs/payments/p2sh.cjs b/src/cjs/payments/p2sh.cjs index 650fe86de..979396158 100644 --- a/src/cjs/payments/p2sh.cjs +++ b/src/cjs/payments/p2sh.cjs @@ -74,23 +74,6 @@ function p2sh(a, opts) { if (!a.address && !a.hash && !a.output && !a.redeem && !a.input) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - // typef( - // { - // network: typef.maybe(typef.Object), - // address: typef.maybe(typef.String), - // hash: typef.maybe(typef.BufferN(20)), - // output: typef.maybe(typef.BufferN(23)), - // redeem: typef.maybe({ - // network: typef.maybe(typef.Object), - // output: typef.maybe(typef.Buffer), - // input: typef.maybe(typef.Buffer), - // witness: typef.maybe(typef.arrayOf(typef.Buffer)), - // }), - // input: typef.maybe(typef.Buffer), - // witness: typef.maybe(typef.arrayOf(typef.Buffer)), - // }, - // a, - // ); v.parse( v.partial( v.object({ @@ -119,7 +102,6 @@ function p2sh(a, opts) { const o = { network }; const _address = lazy.value(() => { const payload = bs58check_1.default.decode(a.address); - // const version = payload.readUInt8(0); const version = tools.readUInt8(payload, 0); const hash = payload.slice(1); return { version, hash }; @@ -141,9 +123,7 @@ function p2sh(a, opts) { lazy.prop(o, 'address', () => { if (!o.hash) return; const payload = new Uint8Array(21); - // payload.writeUInt8(o.network!.scriptHash, 0); tools.writeUInt8(payload, 0, o.network.scriptHash); - // o.hash.copy(payload, 1); payload.set(o.hash, 1); return bs58check_1.default.encode(payload); }); @@ -187,7 +167,6 @@ function p2sh(a, opts) { hash = _address().hash; } if (a.hash) { - // if (hash.length > 0 && !hash.equals(a.hash)) if (hash.length > 0 && tools.compare(hash, a.hash) !== 0) throw new TypeError('Hash mismatch'); else hash = a.hash; @@ -201,7 +180,6 @@ function p2sh(a, opts) { ) throw new TypeError('Output is invalid'); const hash2 = a.output.slice(2, 22); - // if (hash.length > 0 && !hash.equals(hash2)) if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; @@ -223,7 +201,6 @@ function p2sh(a, opts) { ); // match hash against other sources const hash2 = bcrypto.hash160(redeem.output); - // if (hash.length > 0 && !hash.equals(hash2)) if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; @@ -253,13 +230,11 @@ function p2sh(a, opts) { throw new TypeError('Network mismatch'); if (a.input) { const redeem = _redeem(); - // if (a.redeem.output && !a.redeem.output.equals(redeem.output!)) if ( a.redeem.output && tools.compare(a.redeem.output, redeem.output) !== 0 ) throw new TypeError('Redeem.output mismatch'); - // if (a.redeem.input && !a.redeem.input.equals(redeem.input!)) if (a.redeem.input && tools.compare(a.redeem.input, redeem.input) !== 0) throw new TypeError('Redeem.input mismatch'); } diff --git a/src/cjs/payments/p2tr.cjs b/src/cjs/payments/p2tr.cjs index 728893b19..c2c1c74bc 100644 --- a/src/cjs/payments/p2tr.cjs +++ b/src/cjs/payments/p2tr.cjs @@ -45,7 +45,6 @@ var __importStar = }; Object.defineProperty(exports, '__esModule', { value: true }); exports.p2tr = p2tr; -// import { Buffer as NBuffer } from 'buffer'; const networks_js_1 = require('../networks.cjs'); const bscript = __importStar(require('../script.cjs')); const types_js_1 = require('../types.cjs'); @@ -77,27 +76,6 @@ function p2tr(a, opts) { ) 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)), // 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))), - // witness: typef.maybe(typef.arrayOf(typef.Buffer)), - // scriptTree: typef.maybe(isTaptree), - // redeem: typef.maybe({ - // 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), - // }, - // a, - // ); v.parse( v.partial( v.object({ @@ -256,7 +234,6 @@ function p2tr(a, opts) { pubkey = _address().data; } if (a.pubkey) { - // if (pubkey.length > 0 && !pubkey.equals(a.pubkey)) if (pubkey.length > 0 && tools.compare(pubkey, a.pubkey) !== 0) throw new TypeError('Pubkey mismatch'); else pubkey = a.pubkey; @@ -268,14 +245,12 @@ function p2tr(a, opts) { a.output[1] !== 0x20 ) throw new TypeError('Output is invalid'); - // if (pubkey.length > 0 && !pubkey.equals(a.output.slice(2))) if (pubkey.length > 0 && tools.compare(pubkey, a.output.slice(2)) !== 0) throw new TypeError('Pubkey mismatch'); else pubkey = a.output.slice(2); } if (a.internalPubkey) { const tweakedKey = (0, bip341_js_1.tweakKey)(a.internalPubkey, o.hash); - // if (pubkey.length > 0 && !pubkey.equals(tweakedKey!.x)) if (pubkey.length > 0 && tools.compare(pubkey, tweakedKey.x) !== 0) throw new TypeError('Pubkey mismatch'); else pubkey = tweakedKey.x; @@ -286,7 +261,6 @@ function p2tr(a, opts) { } const hashTree = _hashTree(); if (a.hash && hashTree) { - // if (!a.hash.equals(hashTree.hash)) throw new TypeError('Hash mismatch'); if (tools.compare(a.hash, hashTree.hash) !== 0) throw new TypeError('Hash mismatch'); } @@ -309,7 +283,6 @@ function p2tr(a, opts) { 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)) if ( o.redeem.output && tools.compare(a.redeem.output, o.redeem.output) !== 0 @@ -327,7 +300,6 @@ function p2tr(a, opts) { if (witness && witness.length) { if (witness.length === 1) { // key spending - // if (a.signature && !a.signature.equals(witness[0])) if (a.signature && tools.compare(a.signature, witness[0]) !== 0) throw new TypeError('Signature mismatch'); } else { @@ -347,7 +319,6 @@ function p2tr(a, opts) { `The script path is too long. Got ${m}, expected max 128.`, ); const internalPubkey = controlBlock.slice(1, 33); - // if (a.internalPubkey && !a.internalPubkey.equals(internalPubkey)) if ( a.internalPubkey && tools.compare(a.internalPubkey, internalPubkey) !== 0 @@ -366,7 +337,6 @@ function p2tr(a, opts) { if (!outputKey) // todo: needs test data throw new TypeError('Invalid outputKey for p2tr witness'); - // if (pubkey.length && !pubkey.equals(outputKey.x)) if (pubkey.length && tools.compare(pubkey, outputKey.x) !== 0) throw new TypeError('Pubkey mismatch for p2tr witness'); if (outputKey.parity !== (controlBlock[0] & 1)) diff --git a/src/cjs/payments/p2wpkh.cjs b/src/cjs/payments/p2wpkh.cjs index 9905ac6d0..4ad3cdb22 100644 --- a/src/cjs/payments/p2wpkh.cjs +++ b/src/cjs/payments/p2wpkh.cjs @@ -70,19 +70,6 @@ function p2wpkh(a, opts) { if (!a.address && !a.hash && !a.output && !a.pubkey && !a.witness) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - // typef( - // { - // 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(22)), - // pubkey: typef.maybe(isPoint), - // signature: typef.maybe(bscript.isCanonicalScriptSignature), - // witness: typef.maybe(typef.arrayOf(typef.Buffer)), - // }, - // a, - // ); v.parse( v.partial( v.object({ @@ -156,7 +143,6 @@ function p2wpkh(a, opts) { hash = _address().data; } if (a.hash) { - // if (hash.length > 0 && !hash.equals(a.hash)) if (hash.length > 0 && tools.compare(hash, a.hash) !== 0) throw new TypeError('Hash mismatch'); else hash = a.hash; @@ -168,14 +154,12 @@ function p2wpkh(a, opts) { a.output[1] !== 0x14 ) throw new TypeError('Output is invalid'); - // if (hash.length > 0 && !hash.equals(a.output.slice(2))) if (hash.length > 0 && tools.compare(hash, a.output.slice(2)) !== 0) throw new TypeError('Hash mismatch'); else hash = a.output.slice(2); } if (a.pubkey) { const pkh = bcrypto.hash160(a.pubkey); - // if (hash.length > 0 && !hash.equals(pkh)) if (hash.length > 0 && tools.compare(hash, pkh) !== 0) throw new TypeError('Hash mismatch'); else hash = pkh; @@ -188,14 +172,12 @@ function p2wpkh(a, opts) { throw new TypeError('Witness has invalid signature'); if (!(0, types_js_1.isPoint)(a.witness[1]) || a.witness[1].length !== 33) throw new TypeError('Witness has invalid pubkey'); - // if (a.signature && !a.signature.equals(a.witness[0])) if (a.signature && tools.compare(a.signature, a.witness[0]) !== 0) throw new TypeError('Signature mismatch'); // if (a.pubkey && !a.pubkey.equals(a.witness[1])) if (a.pubkey && tools.compare(a.pubkey, a.witness[1]) !== 0) throw new TypeError('Pubkey mismatch'); const pkh = bcrypto.hash160(a.witness[1]); - // if (hash.length > 0 && !hash.equals(pkh)) if (hash.length > 0 && tools.compare(hash, pkh) !== 0) throw new TypeError('Hash mismatch'); } diff --git a/src/cjs/payments/p2wsh.cjs b/src/cjs/payments/p2wsh.cjs index 3633d32bf..97c63d473 100644 --- a/src/cjs/payments/p2wsh.cjs +++ b/src/cjs/payments/p2wsh.cjs @@ -57,7 +57,6 @@ const OPS = bscript.OPS; const EMPTY_BUFFER = new Uint8Array(0); function chunkHasUncompressedPubkey(chunk) { if ( - // Buffer.isBuffer(chunk) && chunk instanceof Uint8Array && chunk.length === 65 && chunk[0] === 0x04 && @@ -83,23 +82,6 @@ function p2wsh(a, opts) { if (!a.address && !a.hash && !a.output && !a.redeem && !a.witness) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - // typef( - // { - // network: typef.maybe(typef.Object), - // address: typef.maybe(typef.String), - // hash: typef.maybe(typef.BufferN(32)), - // output: typef.maybe(typef.BufferN(34)), - // redeem: typef.maybe({ - // input: typef.maybe(typef.Buffer), - // network: typef.maybe(typef.Object), - // output: typef.maybe(typef.Buffer), - // witness: typef.maybe(typef.arrayOf(typef.Buffer)), - // }), - // input: typef.maybe(typef.BufferN(0)), - // witness: typef.maybe(typef.arrayOf(typef.Buffer)), - // }, - // a, - // ); v.parse( (0, types_js_1.NullablePartial)({ network: v.object({}), @@ -202,7 +184,6 @@ function p2wsh(a, opts) { hash = _address().data; } if (a.hash) { - // if (hash.length > 0 && !hash.equals(a.hash)) if (hash.length > 0 && tools.compare(hash, a.hash) !== 0) throw new TypeError('Hash mismatch'); else hash = a.hash; @@ -215,7 +196,6 @@ function p2wsh(a, opts) { ) throw new TypeError('Output is invalid'); const hash2 = a.output.slice(2); - // if (hash.length > 0 && !hash.equals(hash2)) if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; @@ -246,7 +226,6 @@ function p2wsh(a, opts) { ); // match hash against other sources const hash2 = (0, sha256_1.sha256)(a.redeem.output); - // if (hash.length > 0 && !hash.equals(hash2)) if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; @@ -273,7 +252,6 @@ function p2wsh(a, opts) { } if (a.witness && a.witness.length > 0) { const wScript = a.witness[a.witness.length - 1]; - // if (a.redeem && a.redeem.output && !a.redeem.output.equals(wScript)) if ( a.redeem && a.redeem.output && diff --git a/src/cjs/psbt.cjs b/src/cjs/psbt.cjs index 65e60e192..b6b28e643 100644 --- a/src/cjs/psbt.cjs +++ b/src/cjs/psbt.cjs @@ -114,12 +114,10 @@ const DEFAULT_OPTS = { class Psbt { data; static fromBase64(data, opts = {}) { - // const buffer = Buffer.from(data, 'base64'); const buffer = tools.fromBase64(data); return this.fromBuffer(buffer, opts); } static fromHex(data, opts = {}) { - // const buffer = Buffer.from(data, 'hex'); const buffer = tools.fromHex(data); return this.fromBuffer(buffer, opts); } @@ -539,7 +537,6 @@ class Psbt { } if (tapScriptSig) { for (const tapSig of tapScriptSig) { - // const tapSigHash = allHashses.find(h => tapSig.pubkey.equals(h.pubkey)); const tapSigHash = allHashses.find( h => tools.compare(h.pubkey, tapSig.pubkey) === 0, ); @@ -1010,8 +1007,7 @@ class PsbtTransaction { } const hash = typeof input.hash === 'string' - ? // ? reverseBuffer(Buffer.from(input.hash, 'hex')) - (0, bufferutils_js_1.reverseBuffer)(tools.fromHex(input.hash)) + ? (0, bufferutils_js_1.reverseBuffer)(tools.fromHex(input.hash)) : input.hash; this.tx.addInput(hash, input.index, input.sequence); } @@ -1071,9 +1067,7 @@ function isFinalized(input) { } function bip32DerivationIsMine(root) { return d => { - // if (!d.masterFingerprint.equals(root.fingerprint)) return false; if (tools.compare(root.fingerprint, d.masterFingerprint)) return false; - // if (!root.derivePath(d.path).publicKey.equals(d.pubkey)) return false; if (tools.compare(root.derivePath(d.path).publicKey, d.pubkey)) return false; return true; @@ -1161,7 +1155,6 @@ function scriptCheckerFactory(payment, paymentScriptName) { const redeemScriptOutput = payment({ redeem: { output: redeemScript }, }).output; - // if (!scriptPubKey.equals(redeemScriptOutput)) { if (tools.compare(scriptPubKey, redeemScriptOutput)) { throw new Error( `${paymentScriptName} for ${ioType} #${inputIndex} doesn't match the scriptPubKey in the prevout`, @@ -1280,7 +1273,6 @@ function getHashForSig(inputIndex, input, cache, forValidate, sighashTypes) { const prevoutHash = unsignedTx.ins[inputIndex].hash; const utxoHash = nonWitnessUtxoTx.getHash(); // If a non-witness UTXO is provided, its hash must match the hash specified in the prevout - // if (!prevoutHash.equals(utxoHash)) { if (tools.compare(prevoutHash, utxoHash) !== 0) { throw new Error( `Non-witness UTXO hash for input #${inputIndex} doesn't match the hash specified in the prevout`, @@ -1396,7 +1388,6 @@ function getTaprootHashesForSig( if (input.tapInternalKey && !tapLeafHashToSign) { const outputKey = getPrevoutTaprootKey(inputIndex, input, cache) || Uint8Array.from([]); - // if (toXOnly(pubkey).equals(outputKey)) { if (tools.compare((0, bip371_js_1.toXOnly)(pubkey), outputKey) === 0) { const tapKeyHash = unsignedTx.hashForWitnessV1( inputIndex, @@ -1520,7 +1511,6 @@ function getSignersFromHD(inputIndex, inputs, hdKeyPair) { } const myDerivations = input.bip32Derivation .map(bipDv => { - // if (bipDv.masterFingerprint.equals(hdKeyPair.fingerprint)) { if (tools.compare(bipDv.masterFingerprint, hdKeyPair.fingerprint) === 0) { return bipDv; } else { @@ -1535,7 +1525,6 @@ function getSignersFromHD(inputIndex, inputs, hdKeyPair) { } const signers = myDerivations.map(bipDv => { const node = hdKeyPair.derivePath(bipDv.path); - // if (!bipDv!.pubkey.equals(node.publicKey)) { if (tools.compare(bipDv.pubkey, node.publicKey) !== 0) { throw new Error('pubkey did not match bip32Derivation'); } @@ -1551,7 +1540,6 @@ function getSortedSigs(script, partialSig) { // filter partialSig array by pubkey being equal return ( partialSig.filter(ps => { - // return ps.pubkey.equals(pk); return tools.compare(ps.pubkey, pk) === 0; })[0] || {} ).signature; @@ -1712,7 +1700,6 @@ function redeemFromFinalScriptSig(finalScript) { if (!decomp) return; const lastItem = decomp[decomp.length - 1]; if ( - // !Buffer.isBuffer(lastItem) || !(lastItem instanceof Uint8Array) || isPubkeyLike(lastItem) || isSigLike(lastItem) diff --git a/src/cjs/psbt/bip371.cjs b/src/cjs/psbt/bip371.cjs index ced52581f..e7657ddf9 100644 --- a/src/cjs/psbt/bip371.cjs +++ b/src/cjs/psbt/bip371.cjs @@ -173,7 +173,6 @@ function checkTaprootScriptPubkey(outputData, newOutputData) { if (tapInternalKey) { const { script: scriptPubkey } = outputData; const script = getTaprootScripPubkey(tapInternalKey, tapTree); - // if (scriptPubkey && !scriptPubkey.equals(script)) if (scriptPubkey && tools.compare(script, scriptPubkey) !== 0) throw new Error('Error adding output. Script or address mismatch.'); } @@ -460,7 +459,6 @@ function isTapLeafInTree(tapLeaf, merkleRoot) { tapLeaf.controlBlock, leafHash, ); - // return rootHash.equals(merkleRoot); return tools.compare(rootHash, merkleRoot) === 0; } /** @@ -533,11 +531,9 @@ function canFinalizeLeaf(leaf, tapScriptSig, hash) { output: leaf.script, version: leaf.leafVersion, }); - // const whiteListedHash = !hash || hash.equals(leafHash); const whiteListedHash = !hash || tools.compare(leafHash, hash) === 0; return ( whiteListedHash && - // tapScriptSig!.find(tss => tss.leafHash.equals(leafHash)) !== undefined tapScriptSig.find(tss => tools.compare(tss.leafHash, leafHash) === 0) !== undefined ); diff --git a/src/cjs/psbt/psbtutils.cjs b/src/cjs/psbt/psbtutils.cjs index dbebd1407..6918f0226 100644 --- a/src/cjs/psbt/psbtutils.cjs +++ b/src/cjs/psbt/psbtutils.cjs @@ -93,13 +93,11 @@ exports.isP2TR = isPaymentFactory(payments.p2tr); function witnessStackToScriptWitness(witness) { let buffer = new Uint8Array(0); function writeSlice(slice) { - // buffer = Buffer.concat([buffer, Buffer.from(slice)]); buffer = tools.concat([buffer, slice]); } function writeVarInt(i) { const currentLen = buffer.length; const varintLen = varuint.encodingLength(i); - // buffer = Buffer.concat([buffer, Buffer.allocUnsafe(varintLen)]); buffer = tools.concat([buffer, new Uint8Array(varintLen)]); varuint.encode(i, buffer, currentLen); } @@ -129,9 +127,6 @@ function pubkeyPositionInScript(pubkey, script) { return decompiled.findIndex(element => { if (typeof element === 'number') return false; return ( - // element.equals(pubkey) || - // element.equals(pubkeyHash) || - // element.equals(pubkeyXOnly) tools.compare(pubkey, element) === 0 || tools.compare(pubkeyHash, element) === 0 || tools.compare(pubkeyXOnly, element) === 0 diff --git a/src/cjs/push_data.cjs b/src/cjs/push_data.cjs index 18d8f1f3d..dd2888887 100644 --- a/src/cjs/push_data.cjs +++ b/src/cjs/push_data.cjs @@ -77,25 +77,18 @@ function encode(buffer, num, offset) { const size = encodingLength(num); // ~6 bit if (size === 1) { - // buffer.writeUInt8(num, offset); tools.writeUInt8(buffer, offset, num); // 8 bit } else if (size === 2) { - // buffer.writeUInt8(OPS.OP_PUSHDATA1, offset); tools.writeUInt8(buffer, offset, ops_js_1.OPS.OP_PUSHDATA1); - // buffer.writeUInt8(num, offset + 1); tools.writeUInt8(buffer, offset + 1, num); // 16 bit } else if (size === 3) { - // buffer.writeUInt8(OPS.OP_PUSHDATA2, offset); tools.writeUInt8(buffer, offset, ops_js_1.OPS.OP_PUSHDATA2); - // buffer.writeUInt16LE(num, offset + 1); tools.writeUInt16(buffer, offset + 1, num, 'LE'); // 32 bit } else { - // buffer.writeUInt8(OPS.OP_PUSHDATA4, offset); tools.writeUInt8(buffer, offset, ops_js_1.OPS.OP_PUSHDATA4); - // buffer.writeUInt32LE(num, offset + 1); tools.writeUInt32(buffer, offset + 1, num, 'LE'); } return size; @@ -107,7 +100,6 @@ function encode(buffer, num, offset) { * @returns An object containing the opcode, number, and size, or null if decoding fails. */ function decode(buffer, offset) { - // const opcode = buffer.readUInt8(offset); const opcode = tools.readUInt8(buffer, offset); let num; let size; @@ -118,13 +110,11 @@ function decode(buffer, offset) { // 8 bit } else if (opcode === ops_js_1.OPS.OP_PUSHDATA1) { if (offset + 2 > buffer.length) return null; - // num = buffer.readUInt8(offset + 1); num = tools.readUInt8(buffer, offset + 1); size = 2; // 16 bit } else if (opcode === ops_js_1.OPS.OP_PUSHDATA2) { if (offset + 3 > buffer.length) return null; - // num = buffer.readUInt16LE(offset + 1); num = tools.readUInt16(buffer, offset + 1, 'LE'); size = 3; // 32 bit @@ -132,7 +122,6 @@ function decode(buffer, offset) { if (offset + 5 > buffer.length) return null; if (opcode !== ops_js_1.OPS.OP_PUSHDATA4) throw new Error('Unexpected opcode'); - // num = buffer.readUInt32LE(offset + 1); num = tools.readUInt32(buffer, offset + 1, 'LE'); size = 5; } diff --git a/src/cjs/script.cjs b/src/cjs/script.cjs index 4e2b95921..0af216ddf 100644 --- a/src/cjs/script.cjs +++ b/src/cjs/script.cjs @@ -87,7 +87,6 @@ function isPushOnlyChunk(value) { return v.is(types.BufferSchema, value) || isOPInt(value); } function isPushOnly(value) { - // return types.Array(value) && value.every(isPushOnlyChunk); return v.is(v.pipe(v.any(), v.everyItem(isPushOnlyChunk)), value); } function countNonPushOnlyOPs(value) { @@ -100,11 +99,9 @@ function asMinimalOP(buffer) { if (buffer[0] === 0x81) return ops_js_1.OPS.OP_1NEGATE; } function chunksIsBuffer(buf) { - // return Buffer.isBuffer(buf); return buf instanceof Uint8Array; } function chunksIsArray(buf) { - // return types.Array(buf); return v.is(StackSchema, buf); } function singleChunkIsBuffer(buf) { @@ -120,7 +117,6 @@ function singleChunkIsBuffer(buf) { function compile(chunks) { // TODO: remove me if (chunksIsBuffer(chunks)) return chunks; - // typeforce(types.Array, chunks); v.parse(StackSchema, chunks); const bufferSize = chunks.reduce((accum, chunk) => { // data chunk @@ -142,18 +138,15 @@ function compile(chunks) { // adhere to BIP62.3, minimal push policy const opcode = asMinimalOP(chunk); if (opcode !== undefined) { - // buffer.writeUInt8(opcode, offset); tools.writeUInt8(buffer, offset, opcode); offset += 1; return; } offset += pushdata.encode(buffer, chunk.length, offset); - // chunk.copy(buffer, offset); buffer.set(chunk, offset); offset += chunk.length; // opcode } else { - // buffer.writeUInt8(chunk, offset); tools.writeUInt8(buffer, offset, chunk); offset += 1; } @@ -164,7 +157,6 @@ function compile(chunks) { function decompile(buffer) { // TODO: remove me if (chunksIsArray(buffer)) return buffer; - // typeforce(types.Buffer, buffer); v.parse(types.BufferSchema, buffer); const chunks = []; let i = 0; @@ -227,16 +219,13 @@ function toASM(chunks) { * @returns The converted Buffer. */ function fromASM(asm) { - // typeforce(types.String, asm); v.parse(v.string(), asm); return compile( asm.split(' ').map(chunkStr => { // opcode? if (ops_js_1.OPS[chunkStr] !== undefined) return ops_js_1.OPS[chunkStr]; - // typeforce(types.Hex, chunkStr); v.parse(types.HexSchema, chunkStr); // data! - // return Buffer.from(chunkStr, 'hex'); return tools.fromHex(chunkStr); }), ); @@ -249,7 +238,6 @@ function fromASM(asm) { */ function toStack(chunks) { chunks = decompile(chunks); - // typeforce(isPushOnly, chunks); v.parse(v.custom(isPushOnly), chunks); return chunks.map(op => { if (singleChunkIsBuffer(op)) return op; @@ -262,7 +250,6 @@ function isCanonicalPubKey(buffer) { } function isDefinedHashType(hashType) { const hashTypeMod = hashType & ~0x80; - // return hashTypeMod > SIGHASH_ALL && hashTypeMod < SIGHASH_SINGLE return hashTypeMod > 0x00 && hashTypeMod < 0x04; } function isCanonicalScriptSignature(buffer) { diff --git a/src/cjs/script_number.cjs b/src/cjs/script_number.cjs index 088b8f26f..1ef0334f5 100644 --- a/src/cjs/script_number.cjs +++ b/src/cjs/script_number.cjs @@ -71,8 +71,6 @@ function decode(buffer, maxLength, minimal) { } // 40-bit if (length === 5) { - // const a = buffer.readUInt32LE(0); - // const b = buffer.readUInt8(4); const a = tools.readUInt32(buffer, 0, 'LE'); const b = tools.readUInt8(buffer, 4); if (b & 0x80) return -((b & ~0x80) * 0x100000000 + a); @@ -112,12 +110,10 @@ function encode(_number) { const buffer = new Uint8Array(size); const negative = _number < 0; for (let i = 0; i < size; ++i) { - // buffer.writeUInt8(value & 0xff, i); tools.writeUInt8(buffer, i, value & 0xff); value >>= 8; } if (buffer[size - 1] & 0x80) { - // buffer.writeUInt8(negative ? 0x80 : 0x00, size - 1); tools.writeUInt8(buffer, size - 1, negative ? 0x80 : 0x00); } else if (negative) { buffer[size - 1] |= 0x80; diff --git a/src/cjs/script_signature.cjs b/src/cjs/script_signature.cjs index adb3a64eb..0ef4ee806 100644 --- a/src/cjs/script_signature.cjs +++ b/src/cjs/script_signature.cjs @@ -76,7 +76,6 @@ function fromDER(x) { if (x[0] === 0x00) x = x.slice(1); const buffer = new Uint8Array(32); const bstart = Math.max(0, 32 - x.length); - // x.copy(buffer, bstart); buffer.set(x, bstart); return buffer; } @@ -88,7 +87,6 @@ function fromDER(x) { * @throws Error if the hashType is invalid. */ function decode(buffer) { - // const hashType = buffer.readUInt8(buffer.length - 1); const hashType = tools.readUInt8(buffer, buffer.length - 1); if (!(0, script_js_1.isDefinedHashType)(hashType)) { throw new Error('Invalid hashType ' + hashType); @@ -107,13 +105,6 @@ function decode(buffer) { * @throws Error if the hashType is invalid. */ function encode(signature, hashType) { - // typeforce( - // { - // signature: types.BufferN(64), - // hashType: types.UInt8, - // }, - // { signature, hashType }, - // ); v.parse( v.object({ signature: (0, types_js_1.NBufferSchemaFactory)(64), @@ -124,12 +115,9 @@ function encode(signature, hashType) { if (!(0, script_js_1.isDefinedHashType)(hashType)) { throw new Error('Invalid hashType ' + hashType); } - // const hashTypeBuffer = Buffer.allocUnsafe(1); const hashTypeBuffer = new Uint8Array(1); - // hashTypeBuffer.writeUInt8(hashType, 0); tools.writeUInt8(hashTypeBuffer, 0, hashType); const r = toDER(signature.slice(0, 32)); const s = toDER(signature.slice(32, 64)); - // return Buffer.concat([bip66.encode(r, s), hashTypeBuffer]); return tools.concat([bip66.encode(r, s), hashTypeBuffer]); } diff --git a/src/cjs/transaction.cjs b/src/cjs/transaction.cjs index c730ab54c..f05cf7f02 100644 --- a/src/cjs/transaction.cjs +++ b/src/cjs/transaction.cjs @@ -68,21 +68,12 @@ function vectorSize(someVector) { } const EMPTY_BUFFER = new Uint8Array(0); const EMPTY_WITNESS = []; -// const ZERO: Buffer = Buffer.from( -// '0000000000000000000000000000000000000000000000000000000000000000', -// 'hex', -// ); const ZERO = tools.fromHex( '0000000000000000000000000000000000000000000000000000000000000000', ); -// const ONE: Buffer = Buffer.from( -// '0000000000000000000000000000000000000000000000000000000000000001', -// 'hex', -// ); const ONE = tools.fromHex( '0000000000000000000000000000000000000000000000000000000000000001', ); -// const VALUE_UINT64_MAX: Buffer = Buffer.from('ffffffffffffffff', 'hex'); const VALUE_UINT64_MAX = tools.fromHex('ffffffffffffffff'); const BLANK_OUTPUT = { script: EMPTY_BUFFER, @@ -133,7 +124,7 @@ class Transaction { const voutLen = bufferReader.readVarInt(); for (let i = 0; i < voutLen; ++i) { tx.outs.push({ - value: bufferReader.readUInt64(), + value: bufferReader.readInt64(), script: bufferReader.readVarSlice(), }); } @@ -155,7 +146,6 @@ class Transaction { return Transaction.fromBuffer(tools.fromHex(hex), false); } static isCoinbaseHash(buffer) { - // typeforce(types.Hash256bit, buffer); v.parse(types.Hash256bitSchema, buffer); for (let i = 0; i < 32; ++i) { if (buffer[i] !== 0) return false; @@ -172,15 +162,6 @@ class Transaction { ); } addInput(hash, index, sequence, scriptSig) { - // typeforce( - // types.tuple( - // types.Hash256bit, - // types.UInt32, - // types.maybe(types.UInt32), - // types.maybe(types.Buffer), - // ), - // arguments, - // ); v.parse( v.tuple([ types.Hash256bitSchema, @@ -205,7 +186,6 @@ class Transaction { ); } addOutput(scriptPubKey, value) { - // typeforce(types.tuple(types.Buffer, types.Satoshi), arguments); v.parse(v.tuple([types.BufferSchema, types.SatoshiSchema]), [ scriptPubKey, value, @@ -280,10 +260,6 @@ class Transaction { * This hash can then be used to sign the provided transaction input. */ hashForSignature(inIndex, prevOutScript, hashType) { - // typeforce( - // types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), - // arguments, - // ); v.parse(v.tuple([types.UInt32Schema, types.BufferSchema, v.number()]), [ inIndex, prevOutScript, @@ -336,22 +312,12 @@ class Transaction { } // serialize and hash const buffer = new Uint8Array(txTmp.byteLength(false) + 4); - // buffer.writeInt32LE(hashType, buffer.length - 4); - tools.writeInt32(buffer, hashType, buffer.length - 4, 'LE'); + tools.writeInt32(buffer, buffer.length - 4, hashType, 'LE'); txTmp.__toBuffer(buffer, 0, false); return bcrypto.hash256(buffer); } hashForWitnessV1(inIndex, prevOutScripts, values, hashType, leafHash, annex) { // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#common-signature-message - // typeforce( - // types.tuple( - // types.UInt32, - // typeforce.arrayOf(types.Buffer), - // typeforce.arrayOf(types.Satoshi), - // types.UInt32, - // ), - // arguments, - // ); v.parse( v.tuple([ types.UInt32Schema, @@ -392,7 +358,7 @@ class Transaction { bufferWriter = bufferutils_js_1.BufferWriter.withCapacity( 8 * this.ins.length, ); - values.forEach(value => bufferWriter.writeUInt64(value)); + values.forEach(value => bufferWriter.writeInt64(value)); hashAmounts = (0, sha256_1.sha256)(bufferWriter.end()); bufferWriter = bufferutils_js_1.BufferWriter.withCapacity( prevOutScripts.map(varSliceSize).reduce((a, b) => a + b), @@ -416,7 +382,6 @@ class Transaction { const bufferWriter = bufferutils_js_1.BufferWriter.withCapacity(txOutsSize); this.outs.forEach(out => { - // bufferWriter.writeUInt64(out.value); bufferWriter.writeInt64(out.value); bufferWriter.writeVarSlice(out.script); }); @@ -426,7 +391,7 @@ class Transaction { const bufferWriter = bufferutils_js_1.BufferWriter.withCapacity( 8 + varSliceSize(output.script), ); - bufferWriter.writeUInt64(output.value); + bufferWriter.writeInt64(output.value); bufferWriter.writeVarSlice(output.script); hashOutputs = (0, sha256_1.sha256)(bufferWriter.end()); } @@ -459,7 +424,7 @@ class Transaction { const input = this.ins[inIndex]; sigMsgWriter.writeSlice(input.hash); sigMsgWriter.writeUInt32(input.index); - sigMsgWriter.writeUInt64(values[inIndex]); + sigMsgWriter.writeInt64(values[inIndex]); sigMsgWriter.writeVarSlice(prevOutScripts[inIndex]); sigMsgWriter.writeUInt32(input.sequence); } else { @@ -490,10 +455,6 @@ class Transaction { ); } hashForWitnessV0(inIndex, prevOutScript, value, hashType) { - // typeforce( - // types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), - // arguments, - // ); v.parse( v.tuple([ types.UInt32Schema, @@ -539,7 +500,7 @@ class Transaction { tbuffer = new Uint8Array(txOutsSize); bufferWriter = new bufferutils_js_1.BufferWriter(tbuffer, 0); this.outs.forEach(out => { - bufferWriter.writeUInt64(out.value); + bufferWriter.writeInt64(out.value); bufferWriter.writeVarSlice(out.script); }); hashOutputs = bcrypto.hash256(tbuffer); @@ -550,7 +511,7 @@ class Transaction { const output = this.outs[inIndex]; tbuffer = new Uint8Array(8 + varSliceSize(output.script)); bufferWriter = new bufferutils_js_1.BufferWriter(tbuffer, 0); - bufferWriter.writeUInt64(output.value); + bufferWriter.writeInt64(output.value); bufferWriter.writeVarSlice(output.script); hashOutputs = bcrypto.hash256(tbuffer); } @@ -563,7 +524,7 @@ class Transaction { bufferWriter.writeSlice(input.hash); bufferWriter.writeUInt32(input.index); bufferWriter.writeVarSlice(prevOutScript); - bufferWriter.writeUInt64(value); + bufferWriter.writeInt64(value); bufferWriter.writeUInt32(input.sequence); bufferWriter.writeSlice(hashOutputs); bufferWriter.writeUInt32(this.locktime); @@ -588,12 +549,10 @@ class Transaction { return tools.toHex(this.toBuffer(undefined, undefined)); } setInputScript(index, scriptSig) { - // typeforce(types.tuple(types.Number, types.Buffer), arguments); v.parse(v.tuple([v.number(), types.BufferSchema]), [index, scriptSig]); this.ins[index].script = scriptSig; } setWitness(index, witness) { - // typeforce(types.tuple(types.Number, [types.Buffer]), arguments); v.parse(v.tuple([v.number(), v.array(types.BufferSchema)]), [ index, witness, @@ -622,7 +581,7 @@ class Transaction { bufferWriter.writeVarInt(this.outs.length); this.outs.forEach(txOut => { if (isOutput(txOut)) { - bufferWriter.writeUInt64(txOut.value); + bufferWriter.writeInt64(txOut.value); } else { bufferWriter.writeSlice(txOut.valueBuffer); } diff --git a/src/cjs/types.cjs b/src/cjs/types.cjs index d83bcaddc..0d5794818 100644 --- a/src/cjs/types.cjs +++ b/src/cjs/types.cjs @@ -62,7 +62,6 @@ exports.isTapleaf = isTapleaf; exports.isTaptree = isTaptree; const tools = __importStar(require('uint8array-tools')); const v = __importStar(require('valibot')); -// export const typeforce = require('typeforce'); const ZERO32 = new Uint8Array(32); const EC_P = tools.fromHex( 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', @@ -79,7 +78,6 @@ exports.NBufferSchemaFactory = NBufferSchemaFactory; function stacksEqual(a, b) { if (a.length !== b.length) return false; return a.every((x, i) => { - // return x.equals(b[i]); return tools.compare(x, b[i]) === 0; }); } @@ -93,17 +91,13 @@ 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 (tools.compare(ZERO32, x) === 0) return false; - // if (x.compare(EC_P) >= 0) return false; if (tools.compare(x, 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 (tools.compare(ZERO32, y) === 0) return false; - // if (y.compare(EC_P) >= 0) return false; if (tools.compare(y, EC_P) >= 0) return false; if (t === 0x04 && p.length === 65) return true; return false; @@ -124,10 +118,6 @@ function isTaptree(scriptTree) { exports.Buffer256bitSchema = (0, exports.NBufferSchemaFactory)(32); exports.Hash160bitSchema = (0, exports.NBufferSchemaFactory)(20); exports.Hash256bitSchema = (0, exports.NBufferSchemaFactory)(32); -// export const Number = typeforce.Number; -// export const Array = typeforce.Array; -// export const Boolean = typeforce.Boolean; -// export const String = typeforce.String; exports.BufferSchema = v.instance(Uint8Array); exports.HexSchema = v.pipe(v.string(), v.regex(/^([0-9a-f]{2})+$/i)); exports.UInt8Schema = v.pipe( diff --git a/src/esm/address.js b/src/esm/address.js index 029656ce9..7ac1c1f7c 100644 --- a/src/esm/address.js +++ b/src/esm/address.js @@ -42,7 +42,6 @@ export 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 = tools.readUInt8(payload, 0); const hash = payload.slice(1); return { version, hash }; @@ -77,9 +76,7 @@ export function fromBech32(address) { export function toBase58Check(hash, version) { v.parse(v.tuple([Hash160bitSchema, UInt8Schema]), [hash, version]); const payload = new Uint8Array(21); - // payload.writeUInt8(version, 0); tools.writeUInt8(payload, 0, version); - // hash.copy(payload, 1); payload.set(hash, 1); return bs58check.encode(payload); } diff --git a/src/esm/bip66.js b/src/esm/bip66.js index 6ef5246d5..656d84dfa 100644 --- a/src/esm/bip66.js +++ b/src/esm/bip66.js @@ -88,11 +88,9 @@ export function encode(r, s) { signature[1] = signature.length - 2; signature[2] = 0x02; signature[3] = r.length; - // r.copy(signature, 4); signature.set(r, 4); signature[4 + lenR] = 0x02; signature[5 + lenR] = s.length; - // s.copy(signature, 6 + lenR); signature.set(s, 6 + lenR); return signature; } diff --git a/src/esm/block.js b/src/esm/block.js index 54c8f7c85..c717d3d7a 100644 --- a/src/esm/block.js +++ b/src/esm/block.js @@ -9,7 +9,6 @@ import { fastMerkleRoot } from './merkle.js'; import { Transaction } from './transaction.js'; import * as v from 'valibot'; import * as tools from 'uint8array-tools'; -// const { typeforce } = types; const errorMerkleNoTxes = new TypeError( 'Cannot compute merkle root for zero transactions', ); @@ -48,21 +47,18 @@ export class Block { return block; } static fromHex(hex) { - // return Block.fromBuffer(Buffer.from(hex, 'hex')); return Block.fromBuffer(tools.fromHex(hex)); } static calculateTarget(bits) { const exponent = ((bits & 0xff000000) >> 24) - 3; const mantissa = bits & 0x007fffff; const target = new Uint8Array(32); - // target.writeUIntBE(mantissa, 29 - exponent, 3); target[29 - exponent] = (mantissa >> 16) & 0xff; target[30 - exponent] = (mantissa >> 8) & 0xff; target[31 - exponent] = mantissa & 0xff; return target; } static calculateMerkleRoot(transactions, forWitness) { - // typeforce([{ getHash: types.Function }], transactions); v.parse(v.array(v.object({ getHash: v.function() })), transactions); if (transactions.length === 0) throw errorMerkleNoTxes; if (forWitness && !txesHaveWitnessCommit(transactions)) @@ -94,7 +90,6 @@ export class Block { const witnessCommits = this.transactions[0].outs .filter( out => - // out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex')), tools.compare( out.script.slice(0, 6), Uint8Array.from([0x6a, 0x24, 0xaa, 0x21, 0xa9, 0xed]), @@ -183,13 +178,11 @@ export class Block { checkProofOfWork() { const hash = reverseBuffer(this.getHash()); const target = Block.calculateTarget(this.bits); - // return hash.compare(target) <= 0; return tools.compare(hash, target) <= 0; } __checkMerkleRoot() { if (!this.transactions) throw errorMerkleNoTxes; const actualMerkleRoot = Block.calculateMerkleRoot(this.transactions); - // return this.merkleRoot!.compare(actualMerkleRoot) === 0; return tools.compare(this.merkleRoot, actualMerkleRoot) === 0; } __checkWitnessCommit() { @@ -199,7 +192,6 @@ export class Block { this.transactions, true, ); - // return this.witnessCommit!.compare(actualWitnessCommit) === 0; return tools.compare(this.witnessCommit, actualWitnessCommit) === 0; } } diff --git a/src/esm/bufferutils.js b/src/esm/bufferutils.js index ff90e8647..fb819fbb8 100644 --- a/src/esm/bufferutils.js +++ b/src/esm/bufferutils.js @@ -15,54 +15,6 @@ function verifuint(value, max) { if (Math.floor(Number(value)) !== Number(value)) throw new Error('value has a fractional component'); } -// export function readUInt64LE(buffer: Buffer, offset: number): number { -// const a = buffer.readUInt32LE(offset); -// let b = buffer.readUInt32LE(offset + 4); -// b *= 0x100000000; -// verifuint(b + a, MAX_JS_NUMBER); -// return b + a; -// } -/** - * Writes a 64-bit unsigned integer in little-endian format to the specified buffer at the given offset. - * - * @param buffer - The buffer to write the value to. - * @param value - The 64-bit unsigned integer value to write. - * @param offset - The offset in the buffer where the value should be written. - * @returns The new offset after writing the value. - */ -// export function writeUInt64LE( -// buffer: Buffer, -// value: number, -// offset: number, -// ): number { -// verifuint(value, MAX_JS_NUMBER); -// buffer.writeInt32LE(value & -1, offset); -// buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4); -// return offset + 8; -// } -/** - * Reads a 64-bit signed integer from a Uint8Array in little-endian format. - * - * @param {Uint8Array} buffer - The buffer to read the value from. - * @param {number} offset - The offset in the buffer where the value starts. - * @return {number} The 64-bit signed integer value. - */ -// export function readInt64LE( -// buffer: Uint8Array, -// offset: number -// ): number { -// if((buffer[offset + 7] & 0x7f) > 0) throw new Error("RangeError: value out of range, greater than int64"); -// return ( -// buffer[offset] | -// (buffer[offset + 1] << 8) | -// (buffer[offset + 2] << 16) | -// (buffer[offset + 3] << 24) | -// (buffer[offset + 4] << 32) | -// (buffer[offset + 5] << 40) | -// (buffer[offset + 6] << 48) | -// (buffer[offset + 7] << 56) -// ); -// } /** * Reverses the order of bytes in a buffer. * @param buffer - The buffer to reverse. @@ -97,29 +49,24 @@ export class BufferWriter { constructor(buffer, offset = 0) { this.buffer = buffer; this.offset = offset; - // typeforce(types.tuple(types.Buffer, types.UInt32), [buffer, offset]); v.parse(v.tuple([types.BufferSchema, types.UInt32Schema]), [ buffer, offset, ]); } writeUInt8(i) { - // this.offset = this.buffer.writeUInt8(i, this.offset); this.offset = tools.writeUInt8(this.buffer, this.offset, i); } writeInt32(i) { - // this.offset = this.buffer.writeInt32LE(i, this.offset); - this.offset = tools.writeInt32(this.buffer, i, this.offset, 'LE'); + this.offset = tools.writeInt32(this.buffer, this.offset, i, 'LE'); } writeInt64(i) { - this.offset = tools.writeInt64(this.buffer, BigInt(i), this.offset, 'LE'); + this.offset = tools.writeInt64(this.buffer, this.offset, BigInt(i), 'LE'); } writeUInt32(i) { - // this.offset = this.buffer.writeUInt32LE(i, this.offset); this.offset = tools.writeUInt32(this.buffer, this.offset, i, 'LE'); } writeUInt64(i) { - // this.offset = writeUInt64LE(this.buffer, i, this.offset); this.offset = tools.writeUInt64(this.buffer, this.offset, BigInt(i), 'LE'); } writeVarInt(i) { @@ -130,7 +77,6 @@ export class BufferWriter { if (this.buffer.length < this.offset + slice.length) { throw new Error('Cannot write slice out of bounds'); } - // this.offset += slice.copy(this.buffer, this.offset); this.buffer.set(slice, this.offset); this.offset += slice.length; } @@ -158,33 +104,28 @@ export class BufferReader { constructor(buffer, offset = 0) { this.buffer = buffer; this.offset = offset; - // typeforce(types.tuple(types.Buffer, types.UInt32), [buffer, offset]); v.parse(v.tuple([types.BufferSchema, types.UInt32Schema]), [ buffer, offset, ]); } readUInt8() { - // const result = this.buffer.readUInt8(this.offset); const result = tools.readUInt8(this.buffer, this.offset); this.offset++; return result; } readInt32() { - // const result = readInt32LE(this.buffer, this.offset); const result = tools.readInt32(this.buffer, this.offset, 'LE'); this.offset += 4; return result; } readUInt32() { - // const result = this.buffer.readUInt32LE(this.offset); const result = tools.readUInt32(this.buffer, this.offset, 'LE'); this.offset += 4; return result; } - readUInt64() { - // const result = readUInt64LE(this.buffer, this.offset); - const result = tools.readUInt64(this.buffer, this.offset, 'LE'); + readInt64() { + const result = tools.readInt64(this.buffer, this.offset, 'LE'); this.offset += 8; return result; } diff --git a/src/esm/payments/bip341.js b/src/esm/payments/bip341.js index 810b494d2..5fe80db6b 100644 --- a/src/esm/payments/bip341.js +++ b/src/esm/payments/bip341.js @@ -1,4 +1,3 @@ -// import { Buffer as NBuffer } from 'buffer'; import { getEccLib } from '../ecc_lib.js'; import * as bcrypto from '../crypto.js'; import { varuint } from '../bufferutils.js'; @@ -23,7 +22,6 @@ export function rootHashFromPath(controlBlock, leafHash) { 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) { if (tools.compare(kj, ej) < 0) { kj = tapBranchHash(kj, ej); } else { @@ -62,7 +60,6 @@ export function findScriptPath(node, 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)) { } else if (tools.compare(node.hash, hash) === 0) { return []; } @@ -99,7 +96,6 @@ function tapBranchHash(a, b) { function serializeScript(s) { /* global BigInt */ const varintLen = varuint.encodingLength(s.length); - // const buffer = NBuffer.allocUnsafe(varintLen); // better const buffer = new Uint8Array(varintLen); varuint.encode(s.length, buffer); return tools.concat([buffer, s]); diff --git a/src/esm/payments/embed.js b/src/esm/payments/embed.js index e8c581c8d..d16db9c93 100644 --- a/src/esm/payments/embed.js +++ b/src/esm/payments/embed.js @@ -15,14 +15,6 @@ const OPS = bscript.OPS; export function p2data(a, opts) { if (!a.data && !a.output) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - // typef( - // { - // network: typef.maybe(typef.Object), - // output: typef.maybe(typef.Buffer), - // data: typef.maybe(typef.arrayOf(typef.Buffer)), - // }, - // a, - // ); v.parse( v.partial( v.object({ diff --git a/src/esm/payments/p2ms.js b/src/esm/payments/p2ms.js index 1f494c24f..200ee1bca 100644 --- a/src/esm/payments/p2ms.js +++ b/src/esm/payments/p2ms.js @@ -29,18 +29,6 @@ export function p2ms(a, opts) { (opts.allowIncomplete && x === OPS.OP_0) !== undefined ); } - // typef( - // { - // network: typef.maybe(typef.Object), - // m: typef.maybe(typef.Number), - // n: typef.maybe(typef.Number), - // output: typef.maybe(typef.Buffer), - // pubkeys: typef.maybe(typef.arrayOf(isPoint)), - // signatures: typef.maybe(typef.arrayOf(isAcceptableSignature)), - // input: typef.maybe(typef.Buffer), - // }, - // a, - // ); v.parse( v.partial( v.object({ @@ -117,10 +105,7 @@ export function p2ms(a, opts) { if (opts.validate) { if (a.output) { decode(a.output); - // if (!typef.Number(chunks[0])) throw new TypeError('Output is invalid'); v.parse(v.number(), chunks[0], { message: 'Output is invalid' }); - // if (!typef.Number(chunks[chunks.length - 2])) - // throw new TypeError('Output is invalid'); v.parse(v.number(), chunks[chunks.length - 2], { message: 'Output is invalid', }); diff --git a/src/esm/payments/p2pk.js b/src/esm/payments/p2pk.js index 29d95023a..8dba5e1ae 100644 --- a/src/esm/payments/p2pk.js +++ b/src/esm/payments/p2pk.js @@ -19,16 +19,6 @@ export function p2pk(a, opts) { if (!a.input && !a.output && !a.pubkey && !a.input && !a.signature) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - // typef( - // { - // network: typef.maybe(typef.Object), - // output: typef.maybe(typef.Buffer), - // pubkey: typef.maybe(isPoint), - // signature: typef.maybe(bscript.isCanonicalScriptSignature), - // input: typef.maybe(typef.Buffer), - // }, - // a, - // ); v.parse( v.partial( v.object({ @@ -75,12 +65,10 @@ export function p2pk(a, opts) { if (a.output[a.output.length - 1] !== OPS.OP_CHECKSIG) throw new TypeError('Output is invalid'); if (!isPoint(o.pubkey)) throw new TypeError('Output pubkey is invalid'); - // if (a.pubkey && !a.pubkey.equals(o.pubkey!)) if (a.pubkey && tools.compare(a.pubkey, o.pubkey) !== 0) throw new TypeError('Pubkey mismatch'); } if (a.signature) { - // if (a.input && !a.input.equals(o.input!)) if (a.input && tools.compare(a.input, o.input) !== 0) throw new TypeError('Signature mismatch'); } diff --git a/src/esm/payments/p2pkh.js b/src/esm/payments/p2pkh.js index ed3b0dd29..41101eb03 100644 --- a/src/esm/payments/p2pkh.js +++ b/src/esm/payments/p2pkh.js @@ -26,18 +26,6 @@ export function p2pkh(a, opts) { if (!a.address && !a.hash && !a.output && !a.pubkey && !a.input) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - // typef( - // { - // network: typef.maybe(typef.Object), - // address: typef.maybe(typef.String), - // hash: typef.maybe(typef.BufferN(20)), - // output: typef.maybe(typef.BufferN(25)), - // pubkey: typef.maybe(isPoint), - // signature: typef.maybe(bscript.isCanonicalScriptSignature), - // input: typef.maybe(typef.Buffer), - // }, - // a, - // ); v.parse( v.partial( v.object({ @@ -54,7 +42,6 @@ export function p2pkh(a, opts) { ); const _address = lazy.value(() => { const payload = bs58check.decode(a.address); - // const version = payload.readUInt8(0); const version = tools.readUInt8(payload, 0); const hash = payload.slice(1); return { version, hash }; @@ -67,9 +54,7 @@ export function p2pkh(a, opts) { lazy.prop(o, 'address', () => { if (!o.hash) return; const payload = new Uint8Array(21); - // payload.writeUInt8(network.pubKeyHash, 0); tools.writeUInt8(payload, 0, network.pubKeyHash); - // o.hash.copy(payload, 1); payload.set(o.hash, 1); return bs58check.encode(payload); }); @@ -115,7 +100,6 @@ export function p2pkh(a, opts) { hash = _address().hash; } if (a.hash) { - // if (hash.length > 0 && !hash.equals(a.hash)) if (hash.length > 0 && tools.compare(hash, a.hash) !== 0) throw new TypeError('Hash mismatch'); else hash = a.hash; @@ -131,14 +115,12 @@ export function p2pkh(a, opts) { ) throw new TypeError('Output is invalid'); const hash2 = a.output.slice(3, 23); - // if (hash.length > 0 && !hash.equals(hash2)) if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; } if (a.pubkey) { const pkh = bcrypto.hash160(a.pubkey); - // if (hash.length > 0 && !hash.equals(pkh)) if (hash.length > 0 && tools.compare(hash, pkh) !== 0) throw new TypeError('Hash mismatch'); else hash = pkh; @@ -149,14 +131,11 @@ export function p2pkh(a, opts) { if (!bscript.isCanonicalScriptSignature(chunks[0])) throw new TypeError('Input has invalid signature'); if (!isPoint(chunks[1])) throw new TypeError('Input has invalid pubkey'); - // if (a.signature && !a.signature.equals(chunks[0])) if (a.signature && tools.compare(a.signature, chunks[0]) !== 0) throw new TypeError('Signature mismatch'); - // if (a.pubkey && !a.pubkey.equals(chunks[1] as Buffer)) if (a.pubkey && tools.compare(a.pubkey, chunks[1]) !== 0) throw new TypeError('Pubkey mismatch'); const pkh = bcrypto.hash160(chunks[1]); - // if (hash.length > 0 && !hash.equals(pkh)) if (hash.length > 0 && tools.compare(hash, pkh) !== 0) throw new TypeError('Hash mismatch'); } diff --git a/src/esm/payments/p2sh.js b/src/esm/payments/p2sh.js index 77b05247f..ed2d28c68 100644 --- a/src/esm/payments/p2sh.js +++ b/src/esm/payments/p2sh.js @@ -22,23 +22,6 @@ export function p2sh(a, opts) { if (!a.address && !a.hash && !a.output && !a.redeem && !a.input) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - // typef( - // { - // network: typef.maybe(typef.Object), - // address: typef.maybe(typef.String), - // hash: typef.maybe(typef.BufferN(20)), - // output: typef.maybe(typef.BufferN(23)), - // redeem: typef.maybe({ - // network: typef.maybe(typef.Object), - // output: typef.maybe(typef.Buffer), - // input: typef.maybe(typef.Buffer), - // witness: typef.maybe(typef.arrayOf(typef.Buffer)), - // }), - // input: typef.maybe(typef.Buffer), - // witness: typef.maybe(typef.arrayOf(typef.Buffer)), - // }, - // a, - // ); v.parse( v.partial( v.object({ @@ -67,7 +50,6 @@ export function p2sh(a, opts) { const o = { network }; const _address = lazy.value(() => { const payload = bs58check.decode(a.address); - // const version = payload.readUInt8(0); const version = tools.readUInt8(payload, 0); const hash = payload.slice(1); return { version, hash }; @@ -89,9 +71,7 @@ export function p2sh(a, opts) { lazy.prop(o, 'address', () => { if (!o.hash) return; const payload = new Uint8Array(21); - // payload.writeUInt8(o.network!.scriptHash, 0); tools.writeUInt8(payload, 0, o.network.scriptHash); - // o.hash.copy(payload, 1); payload.set(o.hash, 1); return bs58check.encode(payload); }); @@ -135,7 +115,6 @@ export function p2sh(a, opts) { hash = _address().hash; } if (a.hash) { - // if (hash.length > 0 && !hash.equals(a.hash)) if (hash.length > 0 && tools.compare(hash, a.hash) !== 0) throw new TypeError('Hash mismatch'); else hash = a.hash; @@ -149,7 +128,6 @@ export function p2sh(a, opts) { ) throw new TypeError('Output is invalid'); const hash2 = a.output.slice(2, 22); - // if (hash.length > 0 && !hash.equals(hash2)) if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; @@ -171,7 +149,6 @@ export function p2sh(a, opts) { ); // match hash against other sources const hash2 = bcrypto.hash160(redeem.output); - // if (hash.length > 0 && !hash.equals(hash2)) if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; @@ -201,13 +178,11 @@ export function p2sh(a, opts) { throw new TypeError('Network mismatch'); if (a.input) { const redeem = _redeem(); - // if (a.redeem.output && !a.redeem.output.equals(redeem.output!)) if ( a.redeem.output && tools.compare(a.redeem.output, redeem.output) !== 0 ) throw new TypeError('Redeem.output mismatch'); - // if (a.redeem.input && !a.redeem.input.equals(redeem.input!)) if (a.redeem.input && tools.compare(a.redeem.input, redeem.input) !== 0) throw new TypeError('Redeem.input mismatch'); } diff --git a/src/esm/payments/p2tr.js b/src/esm/payments/p2tr.js index e647b1725..d12fabdbc 100644 --- a/src/esm/payments/p2tr.js +++ b/src/esm/payments/p2tr.js @@ -1,4 +1,3 @@ -// import { Buffer as NBuffer } from 'buffer'; import { bitcoin as BITCOIN_NETWORK } from '../networks.js'; import * as bscript from '../script.js'; import { @@ -43,27 +42,6 @@ export function p2tr(a, opts) { ) 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)), // 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))), - // witness: typef.maybe(typef.arrayOf(typef.Buffer)), - // scriptTree: typef.maybe(isTaptree), - // redeem: typef.maybe({ - // 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), - // }, - // a, - // ); v.parse( v.partial( v.object({ @@ -212,7 +190,6 @@ export function p2tr(a, opts) { pubkey = _address().data; } if (a.pubkey) { - // if (pubkey.length > 0 && !pubkey.equals(a.pubkey)) if (pubkey.length > 0 && tools.compare(pubkey, a.pubkey) !== 0) throw new TypeError('Pubkey mismatch'); else pubkey = a.pubkey; @@ -224,14 +201,12 @@ export function p2tr(a, opts) { a.output[1] !== 0x20 ) throw new TypeError('Output is invalid'); - // if (pubkey.length > 0 && !pubkey.equals(a.output.slice(2))) if (pubkey.length > 0 && tools.compare(pubkey, a.output.slice(2)) !== 0) 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)) if (pubkey.length > 0 && tools.compare(pubkey, tweakedKey.x) !== 0) throw new TypeError('Pubkey mismatch'); else pubkey = tweakedKey.x; @@ -242,7 +217,6 @@ export function p2tr(a, opts) { } const hashTree = _hashTree(); if (a.hash && hashTree) { - // if (!a.hash.equals(hashTree.hash)) throw new TypeError('Hash mismatch'); if (tools.compare(a.hash, hashTree.hash) !== 0) throw new TypeError('Hash mismatch'); } @@ -265,7 +239,6 @@ export function p2tr(a, opts) { 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)) if ( o.redeem.output && tools.compare(a.redeem.output, o.redeem.output) !== 0 @@ -283,7 +256,6 @@ export function p2tr(a, opts) { if (witness && witness.length) { if (witness.length === 1) { // key spending - // if (a.signature && !a.signature.equals(witness[0])) if (a.signature && tools.compare(a.signature, witness[0]) !== 0) throw new TypeError('Signature mismatch'); } else { @@ -303,7 +275,6 @@ export function p2tr(a, opts) { `The script path is too long. Got ${m}, expected max 128.`, ); const internalPubkey = controlBlock.slice(1, 33); - // if (a.internalPubkey && !a.internalPubkey.equals(internalPubkey)) if ( a.internalPubkey && tools.compare(a.internalPubkey, internalPubkey) !== 0 @@ -319,7 +290,6 @@ export function p2tr(a, opts) { if (!outputKey) // todo: needs test data throw new TypeError('Invalid outputKey for p2tr witness'); - // if (pubkey.length && !pubkey.equals(outputKey.x)) if (pubkey.length && tools.compare(pubkey, outputKey.x) !== 0) throw new TypeError('Pubkey mismatch for p2tr witness'); if (outputKey.parity !== (controlBlock[0] & 1)) diff --git a/src/esm/payments/p2wpkh.js b/src/esm/payments/p2wpkh.js index 24800e2c6..7b550736c 100644 --- a/src/esm/payments/p2wpkh.js +++ b/src/esm/payments/p2wpkh.js @@ -23,19 +23,6 @@ export function p2wpkh(a, opts) { if (!a.address && !a.hash && !a.output && !a.pubkey && !a.witness) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - // typef( - // { - // 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(22)), - // pubkey: typef.maybe(isPoint), - // signature: typef.maybe(bscript.isCanonicalScriptSignature), - // witness: typef.maybe(typef.arrayOf(typef.Buffer)), - // }, - // a, - // ); v.parse( v.partial( v.object({ @@ -109,7 +96,6 @@ export function p2wpkh(a, opts) { hash = _address().data; } if (a.hash) { - // if (hash.length > 0 && !hash.equals(a.hash)) if (hash.length > 0 && tools.compare(hash, a.hash) !== 0) throw new TypeError('Hash mismatch'); else hash = a.hash; @@ -121,14 +107,12 @@ export function p2wpkh(a, opts) { a.output[1] !== 0x14 ) throw new TypeError('Output is invalid'); - // if (hash.length > 0 && !hash.equals(a.output.slice(2))) if (hash.length > 0 && tools.compare(hash, a.output.slice(2)) !== 0) throw new TypeError('Hash mismatch'); else hash = a.output.slice(2); } if (a.pubkey) { const pkh = bcrypto.hash160(a.pubkey); - // if (hash.length > 0 && !hash.equals(pkh)) if (hash.length > 0 && tools.compare(hash, pkh) !== 0) throw new TypeError('Hash mismatch'); else hash = pkh; @@ -141,14 +125,12 @@ export function p2wpkh(a, opts) { throw new TypeError('Witness has invalid signature'); if (!isPoint(a.witness[1]) || a.witness[1].length !== 33) throw new TypeError('Witness has invalid pubkey'); - // if (a.signature && !a.signature.equals(a.witness[0])) if (a.signature && tools.compare(a.signature, a.witness[0]) !== 0) throw new TypeError('Signature mismatch'); // if (a.pubkey && !a.pubkey.equals(a.witness[1])) if (a.pubkey && tools.compare(a.pubkey, a.witness[1]) !== 0) throw new TypeError('Pubkey mismatch'); const pkh = bcrypto.hash160(a.witness[1]); - // if (hash.length > 0 && !hash.equals(pkh)) if (hash.length > 0 && tools.compare(hash, pkh) !== 0) throw new TypeError('Hash mismatch'); } diff --git a/src/esm/payments/p2wsh.js b/src/esm/payments/p2wsh.js index a3c2b71cc..0ca099bb6 100644 --- a/src/esm/payments/p2wsh.js +++ b/src/esm/payments/p2wsh.js @@ -17,7 +17,6 @@ const OPS = bscript.OPS; const EMPTY_BUFFER = new Uint8Array(0); function chunkHasUncompressedPubkey(chunk) { if ( - // Buffer.isBuffer(chunk) && chunk instanceof Uint8Array && chunk.length === 65 && chunk[0] === 0x04 && @@ -43,23 +42,6 @@ export function p2wsh(a, opts) { if (!a.address && !a.hash && !a.output && !a.redeem && !a.witness) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - // typef( - // { - // network: typef.maybe(typef.Object), - // address: typef.maybe(typef.String), - // hash: typef.maybe(typef.BufferN(32)), - // output: typef.maybe(typef.BufferN(34)), - // redeem: typef.maybe({ - // input: typef.maybe(typef.Buffer), - // network: typef.maybe(typef.Object), - // output: typef.maybe(typef.Buffer), - // witness: typef.maybe(typef.arrayOf(typef.Buffer)), - // }), - // input: typef.maybe(typef.BufferN(0)), - // witness: typef.maybe(typef.arrayOf(typef.Buffer)), - // }, - // a, - // ); v.parse( NullablePartial({ network: v.object({}), @@ -161,7 +143,6 @@ export function p2wsh(a, opts) { hash = _address().data; } if (a.hash) { - // if (hash.length > 0 && !hash.equals(a.hash)) if (hash.length > 0 && tools.compare(hash, a.hash) !== 0) throw new TypeError('Hash mismatch'); else hash = a.hash; @@ -174,7 +155,6 @@ export function p2wsh(a, opts) { ) throw new TypeError('Output is invalid'); const hash2 = a.output.slice(2); - // if (hash.length > 0 && !hash.equals(hash2)) if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; @@ -205,7 +185,6 @@ export function p2wsh(a, opts) { ); // match hash against other sources const hash2 = sha256(a.redeem.output); - // if (hash.length > 0 && !hash.equals(hash2)) if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; @@ -232,7 +211,6 @@ export function p2wsh(a, opts) { } if (a.witness && a.witness.length > 0) { const wScript = a.witness[a.witness.length - 1]; - // if (a.redeem && a.redeem.output && !a.redeem.output.equals(wScript)) if ( a.redeem && a.redeem.output && diff --git a/src/esm/psbt.js b/src/esm/psbt.js index e82a0139e..7af7cd79b 100644 --- a/src/esm/psbt.js +++ b/src/esm/psbt.js @@ -86,12 +86,10 @@ const DEFAULT_OPTS = { export class Psbt { data; static fromBase64(data, opts = {}) { - // const buffer = Buffer.from(data, 'base64'); const buffer = tools.fromBase64(data); return this.fromBuffer(buffer, opts); } static fromHex(data, opts = {}) { - // const buffer = Buffer.from(data, 'hex'); const buffer = tools.fromHex(data); return this.fromBuffer(buffer, opts); } @@ -503,7 +501,6 @@ export class Psbt { } if (tapScriptSig) { for (const tapSig of tapScriptSig) { - // const tapSigHash = allHashses.find(h => tapSig.pubkey.equals(h.pubkey)); const tapSigHash = allHashses.find( h => tools.compare(h.pubkey, tapSig.pubkey) === 0, ); @@ -695,7 +692,6 @@ export class Psbt { tapLeafHashToSign, allowedSighashTypes = [Transaction.SIGHASH_DEFAULT], ) { - console.log("inside sign taproot input"); const hashesForSig = this.checkTaprootHashesForSig( inputIndex, input, @@ -703,7 +699,6 @@ export class Psbt { tapLeafHashToSign, allowedSighashTypes, ); - console.log("hash: ", tools.toHex(hashesForSig[0].hash)); const tapKeySig = hashesForSig .filter(h => !h.leafHash) .map(h => @@ -722,7 +717,6 @@ export class Psbt { ), leafHash: h.leafHash, })); - console.log("signature", tools.toHex(tapKeySig)); if (tapKeySig) { this.data.updateInput(inputIndex, { tapKeySig }); } @@ -953,8 +947,7 @@ class PsbtTransaction { } const hash = typeof input.hash === 'string' - ? // ? reverseBuffer(Buffer.from(input.hash, 'hex')) - reverseBuffer(tools.fromHex(input.hash)) + ? reverseBuffer(tools.fromHex(input.hash)) : input.hash; this.tx.addInput(hash, input.index, input.sequence); } @@ -1014,9 +1007,7 @@ function isFinalized(input) { } function bip32DerivationIsMine(root) { return d => { - // if (!d.masterFingerprint.equals(root.fingerprint)) return false; if (tools.compare(root.fingerprint, d.masterFingerprint)) return false; - // if (!root.derivePath(d.path).publicKey.equals(d.pubkey)) return false; if (tools.compare(root.derivePath(d.path).publicKey, d.pubkey)) return false; return true; @@ -1100,7 +1091,6 @@ function scriptCheckerFactory(payment, paymentScriptName) { const redeemScriptOutput = payment({ redeem: { output: redeemScript }, }).output; - // if (!scriptPubKey.equals(redeemScriptOutput)) { if (tools.compare(scriptPubKey, redeemScriptOutput)) { throw new Error( `${paymentScriptName} for ${ioType} #${inputIndex} doesn't match the scriptPubKey in the prevout`, @@ -1214,7 +1204,6 @@ function getHashForSig(inputIndex, input, cache, forValidate, sighashTypes) { const prevoutHash = unsignedTx.ins[inputIndex].hash; const utxoHash = nonWitnessUtxoTx.getHash(); // If a non-witness UTXO is provided, its hash must match the hash specified in the prevout - // if (!prevoutHash.equals(utxoHash)) { if (tools.compare(prevoutHash, utxoHash) !== 0) { throw new Error( `Non-witness UTXO hash for input #${inputIndex} doesn't match the hash specified in the prevout`, @@ -1329,7 +1318,6 @@ function getTaprootHashesForSig( if (input.tapInternalKey && !tapLeafHashToSign) { const outputKey = getPrevoutTaprootKey(inputIndex, input, cache) || Uint8Array.from([]); - // if (toXOnly(pubkey).equals(outputKey)) { if (tools.compare(toXOnly(pubkey), outputKey) === 0) { const tapKeyHash = unsignedTx.hashForWitnessV1( inputIndex, @@ -1451,7 +1439,6 @@ function getSignersFromHD(inputIndex, inputs, hdKeyPair) { } const myDerivations = input.bip32Derivation .map(bipDv => { - // if (bipDv.masterFingerprint.equals(hdKeyPair.fingerprint)) { if (tools.compare(bipDv.masterFingerprint, hdKeyPair.fingerprint) === 0) { return bipDv; } else { @@ -1466,7 +1453,6 @@ function getSignersFromHD(inputIndex, inputs, hdKeyPair) { } const signers = myDerivations.map(bipDv => { const node = hdKeyPair.derivePath(bipDv.path); - // if (!bipDv!.pubkey.equals(node.publicKey)) { if (tools.compare(bipDv.pubkey, node.publicKey) !== 0) { throw new Error('pubkey did not match bip32Derivation'); } @@ -1482,7 +1468,6 @@ function getSortedSigs(script, partialSig) { // filter partialSig array by pubkey being equal return ( partialSig.filter(ps => { - // return ps.pubkey.equals(pk); return tools.compare(ps.pubkey, pk) === 0; })[0] || {} ).signature; @@ -1643,7 +1628,6 @@ function redeemFromFinalScriptSig(finalScript) { if (!decomp) return; const lastItem = decomp[decomp.length - 1]; if ( - // !Buffer.isBuffer(lastItem) || !(lastItem instanceof Uint8Array) || isPubkeyLike(lastItem) || isSigLike(lastItem) diff --git a/src/esm/psbt/bip371.js b/src/esm/psbt/bip371.js index 34852d388..7f318aa04 100644 --- a/src/esm/psbt/bip371.js +++ b/src/esm/psbt/bip371.js @@ -121,7 +121,6 @@ function checkTaprootScriptPubkey(outputData, newOutputData) { if (tapInternalKey) { const { script: scriptPubkey } = outputData; const script = getTaprootScripPubkey(tapInternalKey, tapTree); - // if (scriptPubkey && !scriptPubkey.equals(script)) if (scriptPubkey && tools.compare(script, scriptPubkey) !== 0) throw new Error('Error adding output. Script or address mismatch.'); } @@ -397,7 +396,6 @@ function isTapLeafInTree(tapLeaf, merkleRoot) { version: tapLeaf.leafVersion, }); const rootHash = rootHashFromPath(tapLeaf.controlBlock, leafHash); - // return rootHash.equals(merkleRoot); return tools.compare(rootHash, merkleRoot) === 0; } /** @@ -467,11 +465,9 @@ function canFinalizeLeaf(leaf, tapScriptSig, hash) { output: leaf.script, version: leaf.leafVersion, }); - // const whiteListedHash = !hash || hash.equals(leafHash); const whiteListedHash = !hash || tools.compare(leafHash, hash) === 0; return ( whiteListedHash && - // tapScriptSig!.find(tss => tss.leafHash.equals(leafHash)) !== undefined tapScriptSig.find(tss => tools.compare(tss.leafHash, leafHash) === 0) !== undefined ); diff --git a/src/esm/psbt/psbtutils.js b/src/esm/psbt/psbtutils.js index a03257ec9..fa4bc2758 100644 --- a/src/esm/psbt/psbtutils.js +++ b/src/esm/psbt/psbtutils.js @@ -34,13 +34,11 @@ export const isP2TR = isPaymentFactory(payments.p2tr); export function witnessStackToScriptWitness(witness) { let buffer = new Uint8Array(0); function writeSlice(slice) { - // buffer = Buffer.concat([buffer, Buffer.from(slice)]); buffer = tools.concat([buffer, slice]); } function writeVarInt(i) { const currentLen = buffer.length; const varintLen = varuint.encodingLength(i); - // buffer = Buffer.concat([buffer, Buffer.allocUnsafe(varintLen)]); buffer = tools.concat([buffer, new Uint8Array(varintLen)]); varuint.encode(i, buffer, currentLen); } @@ -70,9 +68,6 @@ export function pubkeyPositionInScript(pubkey, script) { return decompiled.findIndex(element => { if (typeof element === 'number') return false; return ( - // element.equals(pubkey) || - // element.equals(pubkeyHash) || - // element.equals(pubkeyXOnly) tools.compare(pubkey, element) === 0 || tools.compare(pubkeyHash, element) === 0 || tools.compare(pubkeyXOnly, element) === 0 diff --git a/src/esm/push_data.js b/src/esm/push_data.js index 62fabb7d6..12b233a27 100644 --- a/src/esm/push_data.js +++ b/src/esm/push_data.js @@ -22,25 +22,18 @@ export function encode(buffer, num, offset) { const size = encodingLength(num); // ~6 bit if (size === 1) { - // buffer.writeUInt8(num, offset); tools.writeUInt8(buffer, offset, num); // 8 bit } else if (size === 2) { - // buffer.writeUInt8(OPS.OP_PUSHDATA1, offset); tools.writeUInt8(buffer, offset, OPS.OP_PUSHDATA1); - // buffer.writeUInt8(num, offset + 1); tools.writeUInt8(buffer, offset + 1, num); // 16 bit } else if (size === 3) { - // buffer.writeUInt8(OPS.OP_PUSHDATA2, offset); tools.writeUInt8(buffer, offset, OPS.OP_PUSHDATA2); - // buffer.writeUInt16LE(num, offset + 1); tools.writeUInt16(buffer, offset + 1, num, 'LE'); // 32 bit } else { - // buffer.writeUInt8(OPS.OP_PUSHDATA4, offset); tools.writeUInt8(buffer, offset, OPS.OP_PUSHDATA4); - // buffer.writeUInt32LE(num, offset + 1); tools.writeUInt32(buffer, offset + 1, num, 'LE'); } return size; @@ -52,7 +45,6 @@ export function encode(buffer, num, offset) { * @returns An object containing the opcode, number, and size, or null if decoding fails. */ export function decode(buffer, offset) { - // const opcode = buffer.readUInt8(offset); const opcode = tools.readUInt8(buffer, offset); let num; let size; @@ -63,20 +55,17 @@ export function decode(buffer, offset) { // 8 bit } else if (opcode === OPS.OP_PUSHDATA1) { if (offset + 2 > buffer.length) return null; - // num = buffer.readUInt8(offset + 1); num = tools.readUInt8(buffer, offset + 1); size = 2; // 16 bit } else if (opcode === OPS.OP_PUSHDATA2) { if (offset + 3 > buffer.length) return null; - // num = buffer.readUInt16LE(offset + 1); num = tools.readUInt16(buffer, offset + 1, 'LE'); size = 3; // 32 bit } else { if (offset + 5 > buffer.length) return null; if (opcode !== OPS.OP_PUSHDATA4) throw new Error('Unexpected opcode'); - // num = buffer.readUInt32LE(offset + 1); num = tools.readUInt32(buffer, offset + 1, 'LE'); size = 5; } diff --git a/src/esm/script.js b/src/esm/script.js index 52b6acdba..985d016b5 100644 --- a/src/esm/script.js +++ b/src/esm/script.js @@ -25,7 +25,6 @@ function isPushOnlyChunk(value) { return v.is(types.BufferSchema, value) || isOPInt(value); } export function isPushOnly(value) { - // return types.Array(value) && value.every(isPushOnlyChunk); return v.is(v.pipe(v.any(), v.everyItem(isPushOnlyChunk)), value); } export function countNonPushOnlyOPs(value) { @@ -38,11 +37,9 @@ function asMinimalOP(buffer) { if (buffer[0] === 0x81) return OPS.OP_1NEGATE; } function chunksIsBuffer(buf) { - // return Buffer.isBuffer(buf); return buf instanceof Uint8Array; } function chunksIsArray(buf) { - // return types.Array(buf); return v.is(StackSchema, buf); } function singleChunkIsBuffer(buf) { @@ -58,7 +55,6 @@ function singleChunkIsBuffer(buf) { export function compile(chunks) { // TODO: remove me if (chunksIsBuffer(chunks)) return chunks; - // typeforce(types.Array, chunks); v.parse(StackSchema, chunks); const bufferSize = chunks.reduce((accum, chunk) => { // data chunk @@ -80,18 +76,15 @@ export function compile(chunks) { // adhere to BIP62.3, minimal push policy const opcode = asMinimalOP(chunk); if (opcode !== undefined) { - // buffer.writeUInt8(opcode, offset); tools.writeUInt8(buffer, offset, opcode); offset += 1; return; } offset += pushdata.encode(buffer, chunk.length, offset); - // chunk.copy(buffer, offset); buffer.set(chunk, offset); offset += chunk.length; // opcode } else { - // buffer.writeUInt8(chunk, offset); tools.writeUInt8(buffer, offset, chunk); offset += 1; } @@ -102,7 +95,6 @@ export function compile(chunks) { export function decompile(buffer) { // TODO: remove me if (chunksIsArray(buffer)) return buffer; - // typeforce(types.Buffer, buffer); v.parse(types.BufferSchema, buffer); const chunks = []; let i = 0; @@ -165,16 +157,13 @@ export function toASM(chunks) { * @returns The converted Buffer. */ export function fromASM(asm) { - // typeforce(types.String, asm); v.parse(v.string(), asm); return compile( asm.split(' ').map(chunkStr => { // opcode? if (OPS[chunkStr] !== undefined) return OPS[chunkStr]; - // typeforce(types.Hex, chunkStr); v.parse(types.HexSchema, chunkStr); // data! - // return Buffer.from(chunkStr, 'hex'); return tools.fromHex(chunkStr); }), ); @@ -187,7 +176,6 @@ export function fromASM(asm) { */ export function toStack(chunks) { chunks = decompile(chunks); - // typeforce(isPushOnly, chunks); v.parse(v.custom(isPushOnly), chunks); return chunks.map(op => { if (singleChunkIsBuffer(op)) return op; @@ -200,7 +188,6 @@ export function isCanonicalPubKey(buffer) { } export function isDefinedHashType(hashType) { const hashTypeMod = hashType & ~0x80; - // return hashTypeMod > SIGHASH_ALL && hashTypeMod < SIGHASH_SINGLE return hashTypeMod > 0x00 && hashTypeMod < 0x04; } export function isCanonicalScriptSignature(buffer) { diff --git a/src/esm/script_number.js b/src/esm/script_number.js index 9c89ba4af..b96c8696a 100644 --- a/src/esm/script_number.js +++ b/src/esm/script_number.js @@ -23,8 +23,6 @@ export function decode(buffer, maxLength, minimal) { } // 40-bit if (length === 5) { - // const a = buffer.readUInt32LE(0); - // const b = buffer.readUInt8(4); const a = tools.readUInt32(buffer, 0, 'LE'); const b = tools.readUInt8(buffer, 4); if (b & 0x80) return -((b & ~0x80) * 0x100000000 + a); @@ -64,12 +62,10 @@ export function encode(_number) { const buffer = new Uint8Array(size); const negative = _number < 0; for (let i = 0; i < size; ++i) { - // buffer.writeUInt8(value & 0xff, i); tools.writeUInt8(buffer, i, value & 0xff); value >>= 8; } if (buffer[size - 1] & 0x80) { - // buffer.writeUInt8(negative ? 0x80 : 0x00, size - 1); tools.writeUInt8(buffer, size - 1, negative ? 0x80 : 0x00); } else if (negative) { buffer[size - 1] |= 0x80; diff --git a/src/esm/script_signature.js b/src/esm/script_signature.js index afc414e13..fbf3f95d9 100644 --- a/src/esm/script_signature.js +++ b/src/esm/script_signature.js @@ -28,7 +28,6 @@ function fromDER(x) { if (x[0] === 0x00) x = x.slice(1); const buffer = new Uint8Array(32); const bstart = Math.max(0, 32 - x.length); - // x.copy(buffer, bstart); buffer.set(x, bstart); return buffer; } @@ -40,7 +39,6 @@ function fromDER(x) { * @throws Error if the hashType is invalid. */ export function decode(buffer) { - // const hashType = buffer.readUInt8(buffer.length - 1); const hashType = tools.readUInt8(buffer, buffer.length - 1); if (!isDefinedHashType(hashType)) { throw new Error('Invalid hashType ' + hashType); @@ -59,13 +57,6 @@ export function decode(buffer) { * @throws Error if the hashType is invalid. */ export function encode(signature, hashType) { - // typeforce( - // { - // signature: types.BufferN(64), - // hashType: types.UInt8, - // }, - // { signature, hashType }, - // ); v.parse( v.object({ signature: NBufferSchemaFactory(64), @@ -76,12 +67,9 @@ export function encode(signature, hashType) { if (!isDefinedHashType(hashType)) { throw new Error('Invalid hashType ' + hashType); } - // const hashTypeBuffer = Buffer.allocUnsafe(1); const hashTypeBuffer = new Uint8Array(1); - // hashTypeBuffer.writeUInt8(hashType, 0); tools.writeUInt8(hashTypeBuffer, 0, hashType); const r = toDER(signature.slice(0, 32)); const s = toDER(signature.slice(32, 64)); - // return Buffer.concat([bip66.encode(r, s), hashTypeBuffer]); return tools.concat([bip66.encode(r, s), hashTypeBuffer]); } diff --git a/src/esm/transaction.js b/src/esm/transaction.js index 835a5726a..3379e0cf0 100644 --- a/src/esm/transaction.js +++ b/src/esm/transaction.js @@ -26,21 +26,12 @@ function vectorSize(someVector) { } const EMPTY_BUFFER = new Uint8Array(0); const EMPTY_WITNESS = []; -// const ZERO: Buffer = Buffer.from( -// '0000000000000000000000000000000000000000000000000000000000000000', -// 'hex', -// ); const ZERO = tools.fromHex( '0000000000000000000000000000000000000000000000000000000000000000', ); -// const ONE: Buffer = Buffer.from( -// '0000000000000000000000000000000000000000000000000000000000000001', -// 'hex', -// ); const ONE = tools.fromHex( '0000000000000000000000000000000000000000000000000000000000000001', ); -// const VALUE_UINT64_MAX: Buffer = Buffer.from('ffffffffffffffff', 'hex'); const VALUE_UINT64_MAX = tools.fromHex('ffffffffffffffff'); const BLANK_OUTPUT = { script: EMPTY_BUFFER, @@ -91,7 +82,7 @@ export class Transaction { const voutLen = bufferReader.readVarInt(); for (let i = 0; i < voutLen; ++i) { tx.outs.push({ - value: bufferReader.readUInt64(), + value: bufferReader.readInt64(), script: bufferReader.readVarSlice(), }); } @@ -113,7 +104,6 @@ export class Transaction { return Transaction.fromBuffer(tools.fromHex(hex), false); } static isCoinbaseHash(buffer) { - // typeforce(types.Hash256bit, buffer); v.parse(types.Hash256bitSchema, buffer); for (let i = 0; i < 32; ++i) { if (buffer[i] !== 0) return false; @@ -130,15 +120,6 @@ export class Transaction { ); } addInput(hash, index, sequence, scriptSig) { - // typeforce( - // types.tuple( - // types.Hash256bit, - // types.UInt32, - // types.maybe(types.UInt32), - // types.maybe(types.Buffer), - // ), - // arguments, - // ); v.parse( v.tuple([ types.Hash256bitSchema, @@ -163,7 +144,6 @@ export class Transaction { ); } addOutput(scriptPubKey, value) { - // typeforce(types.tuple(types.Buffer, types.Satoshi), arguments); v.parse(v.tuple([types.BufferSchema, types.SatoshiSchema]), [ scriptPubKey, value, @@ -238,10 +218,6 @@ export class Transaction { * This hash can then be used to sign the provided transaction input. */ hashForSignature(inIndex, prevOutScript, hashType) { - // typeforce( - // types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), - // arguments, - // ); v.parse(v.tuple([types.UInt32Schema, types.BufferSchema, v.number()]), [ inIndex, prevOutScript, @@ -294,22 +270,12 @@ export class Transaction { } // serialize and hash const buffer = new Uint8Array(txTmp.byteLength(false) + 4); - // buffer.writeInt32LE(hashType, buffer.length - 4); - tools.writeInt32(buffer, hashType, buffer.length - 4, 'LE'); + tools.writeInt32(buffer, buffer.length - 4, hashType, 'LE'); txTmp.__toBuffer(buffer, 0, false); return bcrypto.hash256(buffer); } hashForWitnessV1(inIndex, prevOutScripts, values, hashType, leafHash, annex) { // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#common-signature-message - // typeforce( - // types.tuple( - // types.UInt32, - // typeforce.arrayOf(types.Buffer), - // typeforce.arrayOf(types.Satoshi), - // types.UInt32, - // ), - // arguments, - // ); v.parse( v.tuple([ types.UInt32Schema, @@ -346,7 +312,7 @@ export class Transaction { }); hashPrevouts = sha256(bufferWriter.end()); bufferWriter = BufferWriter.withCapacity(8 * this.ins.length); - values.forEach(value => bufferWriter.writeUInt64(value)); + values.forEach(value => bufferWriter.writeInt64(value)); hashAmounts = sha256(bufferWriter.end()); bufferWriter = BufferWriter.withCapacity( prevOutScripts.map(varSliceSize).reduce((a, b) => a + b), @@ -367,7 +333,6 @@ export class Transaction { .reduce((a, b) => a + b); const bufferWriter = BufferWriter.withCapacity(txOutsSize); this.outs.forEach(out => { - // bufferWriter.writeUInt64(out.value); bufferWriter.writeInt64(out.value); bufferWriter.writeVarSlice(out.script); }); @@ -377,7 +342,7 @@ export class Transaction { const bufferWriter = BufferWriter.withCapacity( 8 + varSliceSize(output.script), ); - bufferWriter.writeUInt64(output.value); + bufferWriter.writeInt64(output.value); bufferWriter.writeVarSlice(output.script); hashOutputs = sha256(bufferWriter.end()); } @@ -410,7 +375,7 @@ export class Transaction { const input = this.ins[inIndex]; sigMsgWriter.writeSlice(input.hash); sigMsgWriter.writeUInt32(input.index); - sigMsgWriter.writeUInt64(values[inIndex]); + sigMsgWriter.writeInt64(values[inIndex]); sigMsgWriter.writeVarSlice(prevOutScripts[inIndex]); sigMsgWriter.writeUInt32(input.sequence); } else { @@ -439,10 +404,6 @@ export class Transaction { ); } hashForWitnessV0(inIndex, prevOutScript, value, hashType) { - // typeforce( - // types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), - // arguments, - // ); v.parse( v.tuple([ types.UInt32Schema, @@ -488,7 +449,7 @@ export class Transaction { tbuffer = new Uint8Array(txOutsSize); bufferWriter = new BufferWriter(tbuffer, 0); this.outs.forEach(out => { - bufferWriter.writeUInt64(out.value); + bufferWriter.writeInt64(out.value); bufferWriter.writeVarSlice(out.script); }); hashOutputs = bcrypto.hash256(tbuffer); @@ -499,7 +460,7 @@ export class Transaction { const output = this.outs[inIndex]; tbuffer = new Uint8Array(8 + varSliceSize(output.script)); bufferWriter = new BufferWriter(tbuffer, 0); - bufferWriter.writeUInt64(output.value); + bufferWriter.writeInt64(output.value); bufferWriter.writeVarSlice(output.script); hashOutputs = bcrypto.hash256(tbuffer); } @@ -512,7 +473,7 @@ export class Transaction { bufferWriter.writeSlice(input.hash); bufferWriter.writeUInt32(input.index); bufferWriter.writeVarSlice(prevOutScript); - bufferWriter.writeUInt64(value); + bufferWriter.writeInt64(value); bufferWriter.writeUInt32(input.sequence); bufferWriter.writeSlice(hashOutputs); bufferWriter.writeUInt32(this.locktime); @@ -535,12 +496,10 @@ export class Transaction { return tools.toHex(this.toBuffer(undefined, undefined)); } setInputScript(index, scriptSig) { - // typeforce(types.tuple(types.Number, types.Buffer), arguments); v.parse(v.tuple([v.number(), types.BufferSchema]), [index, scriptSig]); this.ins[index].script = scriptSig; } setWitness(index, witness) { - // typeforce(types.tuple(types.Number, [types.Buffer]), arguments); v.parse(v.tuple([v.number(), v.array(types.BufferSchema)]), [ index, witness, @@ -566,7 +525,7 @@ export class Transaction { bufferWriter.writeVarInt(this.outs.length); this.outs.forEach(txOut => { if (isOutput(txOut)) { - bufferWriter.writeUInt64(txOut.value); + bufferWriter.writeInt64(txOut.value); } else { bufferWriter.writeSlice(txOut.valueBuffer); } diff --git a/src/esm/types.js b/src/esm/types.js index 2d82f70f5..8e406a338 100644 --- a/src/esm/types.js +++ b/src/esm/types.js @@ -1,6 +1,5 @@ import * as tools from 'uint8array-tools'; import * as v from 'valibot'; -// export const typeforce = require('typeforce'); const ZERO32 = new Uint8Array(32); const EC_P = tools.fromHex( 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', @@ -16,7 +15,6 @@ export const NBufferSchemaFactory = size => export function stacksEqual(a, b) { if (a.length !== b.length) return false; return a.every((x, i) => { - // return x.equals(b[i]); return tools.compare(x, b[i]) === 0; }); } @@ -30,17 +28,13 @@ export 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 (tools.compare(ZERO32, x) === 0) return false; - // if (x.compare(EC_P) >= 0) return false; if (tools.compare(x, 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 (tools.compare(ZERO32, y) === 0) return false; - // if (y.compare(EC_P) >= 0) return false; if (tools.compare(y, EC_P) >= 0) return false; if (t === 0x04 && p.length === 65) return true; return false; @@ -61,10 +55,6 @@ export function isTaptree(scriptTree) { export const Buffer256bitSchema = NBufferSchemaFactory(32); export const Hash160bitSchema = NBufferSchemaFactory(20); export const Hash256bitSchema = NBufferSchemaFactory(32); -// export const Number = typeforce.Number; -// export const Array = typeforce.Array; -// export const Boolean = typeforce.Boolean; -// export const String = typeforce.String; export const BufferSchema = v.instance(Uint8Array); export const HexSchema = v.pipe(v.string(), v.regex(/^([0-9a-f]{2})+$/i)); export const UInt8Schema = v.pipe( diff --git a/test/address.spec.ts b/test/address.spec.ts index e88aaa9c6..8ef401791 100644 --- a/test/address.spec.ts +++ b/test/address.spec.ts @@ -1,15 +1,15 @@ import * as assert from 'assert'; import { describe, it } from 'mocha'; import * as ecc from 'tiny-secp256k1'; -import * as baddress from '../src/esm/address.js'; -import * as bscript from '../src/esm/script.js'; +import { address as baddress } from 'bitcoinjs-lib'; +import { script as bscript } from 'bitcoinjs-lib'; import fixtures from './fixtures/address.json'; import * as tools from 'uint8array-tools'; -import { networks } from '..'; +import { networks } from 'bitcoinjs-lib'; -import { initEccLib } from '../src/esm/ecc_lib.js'; +import { initEccLib } from 'bitcoinjs-lib'; -const NETWORKS = { +const NETWORKS: Record = { ...networks, litecoin: { messagePrefix: '\x19Litecoin Signed Message:\n', @@ -21,7 +21,7 @@ const NETWORKS = { pubKeyHash: 0x30, scriptHash: 0x32, wif: 0xb0, - } as typeof networks.bitcoin, + } as networks.Network, }; describe('address', () => { diff --git a/test/bitcoin.core.spec.ts b/test/bitcoin.core.spec.ts index c51654064..1a8b7d659 100644 --- a/test/bitcoin.core.spec.ts +++ b/test/bitcoin.core.spec.ts @@ -1,17 +1,16 @@ import * as assert from 'assert'; -import * as base58 from 'bs58'; +import base58 from 'bs58'; import { describe, it } from 'mocha'; -import * as bitcoin from '..'; -import * as base58EncodeDecode from './fixtures/core/base58_encode_decode.json'; -import * as base58KeysInvalid from './fixtures/core/base58_keys_invalid.json'; -import * as base58KeysValid from './fixtures/core/base58_keys_valid.json'; -import * as blocksValid from './fixtures/core/blocks.json'; -import * as sigCanonical from './fixtures/core/sig_canonical.json'; -import * as sigNoncanonical from './fixtures/core/sig_noncanonical.json'; -import * as sigHash from './fixtures/core/sighash.json'; -import * as txValid from './fixtures/core/tx_valid.json'; +import * as bitcoin from 'bitcoinjs-lib'; +import base58EncodeDecode from './fixtures/core/base58_encode_decode.json'; +import base58KeysInvalid from './fixtures/core/base58_keys_invalid.json'; +import base58KeysValid from './fixtures/core/base58_keys_valid.json'; +import blocksValid from './fixtures/core/blocks.json'; +import sigCanonical from './fixtures/core/sig_canonical.json'; +import sigNoncanonical from './fixtures/core/sig_noncanonical.json'; +import sigHash from './fixtures/core/sighash.json'; +import txValid from './fixtures/core/tx_valid.json'; import * as tools from 'uint8array-tools'; -import { bigint } from 'valibot'; describe('Bitcoin-core', () => { // base58EncodeDecode diff --git a/test/block.spec.ts b/test/block.spec.ts index 358e38d49..7cd123193 100644 --- a/test/block.spec.ts +++ b/test/block.spec.ts @@ -1,9 +1,9 @@ import * as assert from 'assert'; import { beforeEach, describe, it } from 'mocha'; -import { Block } from '../src/esm/block.js'; +import { Block } from 'bitcoinjs-lib'; import * as tools from 'uint8array-tools'; -import * as fixtures from './fixtures/block.json'; +import fixtures from './fixtures/block.json'; describe('Block', () => { describe('version', () => { diff --git a/test/bufferutils.spec.ts b/test/bufferutils.spec.ts index 1150f57fa..e3e17f1a1 100644 --- a/test/bufferutils.spec.ts +++ b/test/bufferutils.spec.ts @@ -1,10 +1,7 @@ import * as assert from 'assert'; import { describe, it } from 'mocha'; -import * as bufferutils from '../src/esm/bufferutils'; -import { BufferReader, BufferWriter } from '../src/esm/bufferutils'; +import { BufferReader, BufferWriter } from 'bitcoinjs-lib/src/bufferutils'; -import * as fixtures from './fixtures/bufferutils.json'; -// import varuint = require('varuint-bitcoin'); import * as varuint from 'varuint-bitcoin'; describe('bufferutils', () => { @@ -12,52 +9,10 @@ describe('bufferutils', () => { return Buffer.concat(values.map(data => Buffer.from(data))); } - // describe('readUInt64LE', () => { - // fixtures.valid.forEach(f => { - // it('decodes ' + f.hex, () => { - // const buffer = Buffer.from(f.hex, 'hex'); - // const num = bufferutils.readUInt64LE(buffer, 0); - - // assert.strictEqual(num, f.dec); - // }); - // }); - - // fixtures.invalid.readUInt64LE.forEach(f => { - // it('throws on ' + f.description, () => { - // const buffer = Buffer.from(f.hex, 'hex'); - - // assert.throws(() => { - // bufferutils.readUInt64LE(buffer, 0); - // }, new RegExp(f.exception)); - // }); - // }); - // }); - - // describe('writeUInt64LE', () => { - // fixtures.valid.forEach(f => { - // it('encodes ' + f.dec, () => { - // const buffer = Buffer.alloc(8, 0); - - // bufferutils.writeUInt64LE(buffer, f.dec, 0); - // assert.strictEqual(buffer.toString('hex'), f.hex); - // }); - // }); - - // fixtures.invalid.writeUInt64LE.forEach(f => { - // it('throws on ' + f.description, () => { - // const buffer = Buffer.alloc(8, 0); - - // assert.throws(() => { - // bufferutils.writeUInt64LE(buffer, f.dec, 0); - // }, new RegExp(f.exception)); - // }); - // }); - // }); - describe('BufferWriter', () => { function testBuffer( bufferWriter: BufferWriter, - expectedBuffer: Buffer, + expectedBuffer: Uint8Array, expectedOffset: number = expectedBuffer.length, ): void { assert.strictEqual(bufferWriter.offset, expectedOffset); @@ -300,14 +255,14 @@ describe('bufferutils', () => { describe('BufferReader', () => { function testValue( bufferReader: BufferReader, - value: Buffer | bigint | number, - expectedValue: Buffer | bigint | number, + value: Uint8Array | bigint | number, + expectedValue: Uint8Array | bigint | number, expectedOffset: number = Buffer.isBuffer(expectedValue) ? expectedValue.length : 0, ): void { assert.strictEqual(bufferReader.offset, expectedOffset); - if (Buffer.isBuffer(expectedValue)) { + if (expectedValue instanceof Buffer) { assert.deepStrictEqual( Buffer.from(value as Buffer).slice(0, expectedOffset), Buffer.from(expectedValue).slice(0, expectedOffset), @@ -370,25 +325,25 @@ describe('bufferutils', () => { }); }); - it('readUInt64', () => { + it('readInt64', () => { const values = [ 0n, 1n, BigInt(Math.pow(2, 32)), BigInt(Number.MAX_SAFE_INTEGER) /* 2^53 - 1 */, - (BigInt(1) << 64n) - 1n, + (BigInt(1) << 63n) - 1n, ]; const buffer = concatToBuffer([ [0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0], [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00], - [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], + [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f], ]); const bufferReader = new BufferReader(buffer); values.forEach((value: bigint) => { const expectedOffset = bufferReader.offset + 8; - const val = bufferReader.readUInt64(); + const val = bufferReader.readInt64(); testValue(bufferReader, val, value, expectedOffset); }); }); diff --git a/test/crypto.spec.ts b/test/crypto.spec.ts index 502dd6b57..de59bf55a 100644 --- a/test/crypto.spec.ts +++ b/test/crypto.spec.ts @@ -1,10 +1,10 @@ import * as assert from 'assert'; import { describe, it } from 'mocha'; -import * as bcrypto from '../src/esm/crypto.js'; -import type { TaggedHashPrefix } from '..'; +import { crypto as bcrypto } from 'bitcoinjs-lib'; +import type { TaggedHashPrefix } from 'bitcoinjs-lib'; import fixtures from './fixtures/crypto.json'; import * as tools from 'uint8array-tools'; -import { TAGS, TAGGED_HASH_PREFIXES } from '../src/esm/crypto.js'; +import { TAGS, TAGGED_HASH_PREFIXES } from 'bitcoinjs-lib/src/crypto'; import { sha256 } from '@noble/hashes/sha256'; describe('crypto', () => { diff --git a/test/fixtures/psbt.json b/test/fixtures/psbt.json index 6cb152f1d..7e971ac54 100644 --- a/test/fixtures/psbt.json +++ b/test/fixtures/psbt.json @@ -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/ivq2cBAAEBK7gFAQAAAAAAIlEgT+9cUWO+ppqT50pZZyu+sIGDcHfLlM+m5IGlzwDYqxgBE0B0eYK4chVhtLT9WMi14T8ZknZSdTe1pMdIvaq6tIfwqY2xQ9YlcTTy0jWU9utItw/rHQ2c1FplbF9bRvZ6RLQSARcglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+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+m5IGlzwDYqxgBE0BhU0RJZPtgS8Nfo3rQIalmkhtIYCuTSrpp9lGYuxRkdD8ulwzPJKz+hkQU5C1u068lN3uVHKs1XOTm6t0Dl/18ARcglCHnNLD50sRn6n3Rl8Yay0RnzcvJ9MsMVx+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]", @@ -346,7 +346,7 @@ "WIF": "cTrPNrN2EQo4ppBHcFNxyLBFq2WLjZoNKY5nQbPwAGdhQqqsRKSu" } ], - "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=" + "result": "cHNidP8BAF4CAAAAAQU2GLj/HTOEN804Hc6JRNTLM7EmDlIBdjG2G1aUw266AAAAAAD/////AYAaBgAAAAAAIlEg35sLGepBXUbR93XfxDJcYBCHqNVjw/jogOgPVdic1UgAAAAAAAEBK6BoBgAAAAAAIlEgVZx4+tHeORcb0jDJnOytrOnNOGL1uS0MdMUg1GQeS15BFDlfgSndY7SlwvEhJOqgW3p+0w9w5R+5MwXe7MVC5/nrrqI0FdZdKILLLZgRVK8L9Bn2ijU6IcoqqyImKIWt3MtA0Qs3hMTM9htXOJ9ma+GJHzDabXGSm0YQjLuov1fgN+2897h6AdMVJHFbOfPN0hKeh2+jlH6oOD4jMxm4bfp1cUEUj4kary4texRheMVKh+Ku3dnR1oZpIleSjmfPCBdP83WuojQV1l0ogsstmBFUrwv0GfaKNTohyiqrIiYoha3cy0B0zkdTBdMYKfT/G05vAI/nHDvsu+7TxwXN1WNA4hDaR1wIcNi/qNGN3EMBrPoM0aU+U9s1VPgHgGJH/VFIBz88QRSoqze8FgnYNMOROzU42tHITX+baoNf/BdXd5FaN641cq6iNBXWXSiCyy2YEVSvC/QZ9oo1OiHKKqsiJiiFrdzLQMhiSbnEKdnqXOdAYgqjmFY1Y9F5+y/cHmjbd9NvFOxHaNOJakOajrCWkqa19CwWKZJ3lgxKqSFLT1zbt8sbrRFiFcFmuQP4s1ds7KJtMOh4fTw1QCgxkWUA3FUAuUzKHzjDvhpSnJ+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)", @@ -358,7 +358,7 @@ "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==" + "result": "cHNidP8BAF4CAAAAATNOP+fCPDCsZrgGIptDVbwY/yrkM2xaFfLe05BSLulZAAAAAAD/////AZBBBgAAAAAAIlEgo6glLro4LvJCjIXCj+2xYC8NQ5BB/tvaXLukmWNHDaQAAAAAAAEBK6BoBgAAAAAAIlEgo6glLro4LvJCjIXCj+2xYC8NQ5BB/tvaXLukmWNHDaRBFP1IuUG/pcYMyG7KOHraqMXMKKOJb5eIpnjGt7LrvcsWIjJncH2zqZGpUloPoJZipi/NkKmjWthVrvnedXPOOOdAWh/SY0SIN0yP6TggtuXbx2KEGSKx4ywGaj9Irldz2JzKphk7uFUo49THWtJ0OinN6Wk0pA9CTynHjFEkOivhSEEU/Ui5Qb+lxgzIbso4etqoxcwoo4lvl4imeMa3suu9yxZZ4RArokXwS/gTxiDbmC8PNuLMoA7qbokPTzaAWOxY1UBRckOaOAdI93odstKtTZKwDVMinPkXg85GnzL3BQWfuttr86geYaEJmnTWeyzKhGTu5MYPGPX0BuE6ThCBR7pQYhXA14I7V9HPPG3inemPM0WGwDWVxHPHQ4ZbqfL90gol9GwaUpyfs81+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)", @@ -371,7 +371,7 @@ "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=" + "result": "cHNidP8BAF4CAAAAAdXMkUOLeYvgm981k3T7Pmdf5Dr31jOxvpFHiXiU9D2gAAAAAAD/////AZBBBgAAAAAAIlEgD31MIAvwCaanOsAzyBoQ4o/WozgFiqVQTEqGJE18XqwAAAAAAAEBK6BoBgAAAAAAIlEgD31MIAvwCaanOsAzyBoQ4o/WozgFiqVQTEqGJE18XqxBFCo/Wsfk0hSOCy21lUyn+vXnc1SG1lNVWHlnXCh3xegq8tn9mi+A4Oer6siBOY/DcZj0blyALsAMlRUqpvcD5x5AobIOM9VQGlOm3DOObInhbKG6m528jHocxgMLE+6KDdfcB/YPZ6qkdSt8Zhl3Jg9vsvNsGYqZJiRy7as7IGD03WIVwAjUk5QzdUBMEkLbwcjUHnMpA13k3j9ziDszUJiFladaGlKcn7PNfndtYbYiW2xhDokG+4+qbFmsXD6VtfgtKdaTipNtL9o84yJyfhx52eesqJWF2CBZtnGxCFpdeDn8S2kgKj9ax+TSFI4LLbWVTKf69edzVIbWU1VYeWdcKHfF6CqsIJy6ZeYeVOa94xIEs49J9vofeVpf3u1m0XiCqbHNX6BsuiBcF5S+4nRv+Yw5rfnf3GLPT81/1FAJYZldegI1wVRh17pTnMBCFcAI1JOUM3VATBJC28HI1B5zKQNd5N4/c4g7M1CYhZWnWl8Vv/I1WWJt8byg3fk43iQn6QFlDgumFTPXr7uOK24+IyAqP1rH5NIUjgsttZVMp/r153NUhtZTVVh5Z1wod8XoKqzAAAA=" } ], "combiner": [ @@ -777,7 +777,7 @@ ], "inputToCheck": 0, "WIF": "KypUz2y1jdgzM8HGDUx9DYLmyzd8EWhruvLX2J5iSL7MiAcc7dBG", - "result": "cHNidP8BAF4CAAAAAf17fGksrz9eKGx1nSU3RX4vcwr7bfNdQzPZ9dSEkWBcAAAAAAD/////AZBBBgAAAAAAIlEgPLBe/d3922lmXjTIt52b9NG1HFDC9jzPCTn111AG8TQAAAAAAAEBK6BoBgAAAAAAIlEgPLBe/d3922lmXjTIt52b9NG1HFDC9jzPCTn111AG8TQBAwSDAAAAARNBqgjqjSQVTf41zgZ1H9Lq3CKQt0nq1APST8FpwGifNjyUHMS0MbFnIxA70SXTEOoSJePyOXTW+u59fzLpxekL2oMBFyBbMLiqcPfsndZoMRtk9GKEFd0jSA3rwEa60nKQNwdHrAEYIOUOtfVyfPBm+ZzIsEfwzo2JL2WTslXAznzBllU7Oa4zAAA=" + "result": "cHNidP8BAF4CAAAAAf17fGksrz9eKGx1nSU3RX4vcwr7bfNdQzPZ9dSEkWBcAAAAAAD/////AZBBBgAAAAAAIlEgPLBe/d3922lmXjTIt52b9NG1HFDC9jzPCTn111AG8TQAAAAAAAEBK6BoBgAAAAAAIlEgPLBe/d3922lmXjTIt52b9NG1HFDC9jzPCTn111AG8TQBAwSDAAAAARNB00Q0N1Uq9JJ5oXGHRK31Juc5o1kKiWLla9ygRWjqItHETXP4frDFThlXShPu/3ltLKVRHXd20zJVr3r/1BgcF4MBFyBbMLiqcPfsndZoMRtk9GKEFd0jSA3rwEa60nKQNwdHrAEYIOUOtfVyfPBm+ZzIsEfwzo2JL2WTslXAznzBllU7Oa4zAAA=" } }, { @@ -787,7 +787,7 @@ "psbt": "cHNidP8BAF4CAAAAAf17fGksrz9eKGx1nSU3RX4vcwr7bfNdQzPZ9dSEkWBcAAAAAAD/////AZBBBgAAAAAAIlEgPLBe/d3922lmXjTIt52b9NG1HFDC9jzPCTn111AG8TQAAAAAAAEBK6BoBgAAAAAAIlEgPLBe/d3922lmXjTIt52b9NG1HFDC9jzPCTn111AG8TQBFyBbMLiqcPfsndZoMRtk9GKEFd0jSA3rwEa60nKQNwdHrAEYIOUOtfVyfPBm+ZzIsEfwzo2JL2WTslXAznzBllU7Oa4zAAA=", "inputToCheck": 0, "WIF": "KypUz2y1jdgzM8HGDUx9DYLmyzd8EWhruvLX2J5iSL7MiAcc7dBG", - "result": "cHNidP8BAF4CAAAAAf17fGksrz9eKGx1nSU3RX4vcwr7bfNdQzPZ9dSEkWBcAAAAAAD/////AZBBBgAAAAAAIlEgPLBe/d3922lmXjTIt52b9NG1HFDC9jzPCTn111AG8TQAAAAAAAEBK6BoBgAAAAAAIlEgPLBe/d3922lmXjTIt52b9NG1HFDC9jzPCTn111AG8TQBE0AAqkKg+dq3eThMoqzjh214urhgUoGTgwHlNyyMQ2RwhfeRIhAp+m9mZwQoXOxK7p2ILjf2G5j28F9KMhMzH7bXARcgWzC4qnD37J3WaDEbZPRihBXdI0gN68BGutJykDcHR6wBGCDlDrX1cnzwZvmcyLBH8M6NiS9lk7JVwM58wZZVOzmuMwAA" + "result": "cHNidP8BAF4CAAAAAf17fGksrz9eKGx1nSU3RX4vcwr7bfNdQzPZ9dSEkWBcAAAAAAD/////AZBBBgAAAAAAIlEgPLBe/d3922lmXjTIt52b9NG1HFDC9jzPCTn111AG8TQAAAAAAAEBK6BoBgAAAAAAIlEgPLBe/d3922lmXjTIt52b9NG1HFDC9jzPCTn111AG8TQBE0CgvdrzBha8PBO1WyIR8VempGnHK9tlU7ehwQimbpUzjK+cqOsSl1wnszN9KXsM0pF7WbojsVM/WJdmTMllB7fQARcgWzC4qnD37J3WaDEbZPRihBXdI0gN68BGutJykDcHR6wBGCDlDrX1cnzwZvmcyLBH8M6NiS9lk7JVwM58wZZVOzmuMwAA" } }, { @@ -797,7 +797,7 @@ "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" + "result": "cHNidP8BAF4CAAAAAUYAJ/rjwsScVTFXg1in8cNdaBDtwLAsQ6l1O8sWijmlAAAAAAD/////AZBBBgAAAAAAIlEgFlrANpbJgyRLzVMhozrVHKr6rGrz7e2bQ+3TyITRhB4AAAAAAAEBK6BoBgAAAAAAIlEgFlrANpbJgyRLzVMhozrVHKr6rGrz7e2bQ+3TyITRhB5BFKtbJ8WUX1l4vAjIxUmqGxt3pW1lni/UKn5cmkLU2BBtT3q/MbhvStFL2jaKZM6N8TeYvCUfSVytPrzfjkXWQbdA7g4pNghfGa8m3iusZD4LGZWuvoc9ysHg8RrQuuaFUQvHGpzgmFUJ7LwDYhtbul/i4m6iGU3ArEqLGO5JxcLrgUEU2ztZ8a4DUNntmiu9oLvsTiuf8jaFtW2iDEekSfEpncMaUpyfs81+d21htiJbbGEOiQb7j6psWaxcPpW1+C0p1kBuMHFYqh1YufKo8/XywsCOFNz85e0dW2T4Btz97xKhMjFo45GWao56BsIoBTIvj40V0CWC1xTIdQLFZrEnfKTEYhXA6mYGYszjiuf7PC2+XVzJZiF4wJVi5fZqCp6Ic6+ytcgaUpyfs81+d21htiJbbGEOiQb7j6psWaxcPpW1+C0p1hpSnJ+zzX53bWG2IltsYQ6JBvuPqmxZrFw+lbX4LSnWaSCrWyfFlF9ZeLwIyMVJqhsbd6VtZZ4v1Cp+XJpC1NgQbawg2ztZ8a4DUNntmiu9oLvsTiuf8jaFtW2iDEekSfEpncO6IHxnyxVRJtCnSryZCIPmflygytHNAABKc702ymAiT2lnulOcwAAA" } } ] diff --git a/test/integration/addresses.spec.ts b/test/integration/addresses.spec.ts index d6e758b9d..0051fd2b0 100644 --- a/test/integration/addresses.spec.ts +++ b/test/integration/addresses.spec.ts @@ -2,8 +2,8 @@ import * as assert from 'assert'; 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 'bitcoinjs-lib'; +import { regtestUtils } from './_regtest.js'; const ECPair = ECPairFactory(ecc); const dhttp = regtestUtils.dhttp; diff --git a/test/integration/bip32.spec.ts b/test/integration/bip32.spec.ts index 418e74272..ac1088b7e 100644 --- a/test/integration/bip32.spec.ts +++ b/test/integration/bip32.spec.ts @@ -3,7 +3,7 @@ import BIP32Factory from 'bip32'; import * as ecc from 'tiny-secp256k1'; import * as bip39 from 'bip39'; import { describe, it } from 'mocha'; -import * as bitcoin from '../..'; +import * as bitcoin from 'bitcoinjs-lib'; const bip32 = BIP32Factory(ecc); diff --git a/test/integration/blocks.spec.ts b/test/integration/blocks.spec.ts index a98c5eb79..e1533f955 100644 --- a/test/integration/blocks.spec.ts +++ b/test/integration/blocks.spec.ts @@ -1,6 +1,6 @@ import * as assert from 'assert'; import { describe, it } from 'mocha'; -import * as bitcoin from '../..'; +import * as bitcoin from 'bitcoinjs-lib'; describe('bitcoinjs-lib (blocks)', () => { it('can extract a height from a CoinBase transaction', () => { diff --git a/test/integration/cltv.spec.ts b/test/integration/cltv.spec.ts index 7a816b216..0e532fc5b 100644 --- a/test/integration/cltv.spec.ts +++ b/test/integration/cltv.spec.ts @@ -2,20 +2,20 @@ import * as assert from 'assert'; import ECPairFactory from 'ecpair'; import * as ecc from 'tiny-secp256k1'; import { before, describe, it } from 'mocha'; -import * as bitcoin from '../..'; -import { regtestUtils } from './_regtest'; -import { reverseBuffer } from '../../src/esm/bufferutils'; +import * as bitcoin from 'bitcoinjs-lib'; +import { regtestUtils } from './_regtest.js'; +import { reverseBuffer } from 'bitcoinjs-lib/src/bufferutils'; import * as tools from 'uint8array-tools'; const ECPair = ECPairFactory(ecc); const regtest = regtestUtils.network; -const bip65 = require('bip65'); +import bip65 from 'bip65'; function toOutputScript(address: string): Uint8Array { return bitcoin.address.toOutputScript(address, regtest); } -function idToHash(txid: string): Buffer { +function idToHash(txid: string): Uint8Array { return reverseBuffer(tools.fromHex(txid)); } @@ -112,7 +112,7 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', () => { value: 7e4, }); }, - ).timeout(4000); + ); // expiry will pass, {Alice's signature} OP_TRUE it( @@ -164,7 +164,7 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', () => { value: 7e4, }); }, - ).timeout(6000); + ); // expiry ignored, {Bob's signature} {Alice's signature} OP_FALSE it( @@ -212,7 +212,7 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', () => { value: 8e4, }); }, - ).timeout(4000); + ); // expiry in the future, {Alice's signature} OP_TRUE it( @@ -258,5 +258,5 @@ describe('bitcoinjs-lib (transactions w/ CLTV)', () => { }, /Error: non-final/); }); }, - ).timeout(4000); + ); }); diff --git a/test/integration/csv.spec.ts b/test/integration/csv.spec.ts index 86c49c4b2..6e8754e3a 100644 --- a/test/integration/csv.spec.ts +++ b/test/integration/csv.spec.ts @@ -3,15 +3,15 @@ import { PsbtInput } from 'bip174'; import ECPairFactory from 'ecpair'; import * as ecc from 'tiny-secp256k1'; import { before, describe, it } from 'mocha'; -import * as bitcoin from '../..'; -import { regtestUtils } from './_regtest'; -import { reverseBuffer } from '../../src/esm/bufferutils'; +import * as bitcoin from 'bitcoinjs-lib'; +import { regtestUtils } from './_regtest.js'; +import { reverseBuffer } from 'bitcoinjs-lib/src/bufferutils'; import * as tools from 'uint8array-tools'; const ECPair = ECPairFactory(ecc); const regtest = regtestUtils.network; -const bip68 = require('bip68'); -const varuint = require('varuint-bitcoin'); +import bip68 from 'bip68'; +import * as varuint from 'varuint-bitcoin'; function toOutputScript(address: string): Uint8Array { return bitcoin.address.toOutputScript(address, regtest); diff --git a/test/integration/payments.spec.ts b/test/integration/payments.spec.ts index 673b180cd..fd09dbc27 100644 --- a/test/integration/payments.spec.ts +++ b/test/integration/payments.spec.ts @@ -1,8 +1,32 @@ 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 'bitcoinjs-lib'; +import { regtestUtils } from './_regtest.js'; + +import p2msFixtures from '../fixtures/p2ms.json'; +import p2pkFixtures from '../fixtures/p2pk.json'; +import p2pkhFixtures from '../fixtures/p2pkh.json'; +import p2wpkhFixtures from '../fixtures/p2wpkh.json'; + +const testSuite = [ + { + paymentName: 'p2ms', + fixtures: p2msFixtures, + }, + { + paymentName: 'p2pk', + fixtures: p2pkFixtures, + }, + { + paymentName: 'p2pkh', + fixtures: p2pkhFixtures, + }, + { + paymentName: 'p2wpkh', + fixtures: p2wpkhFixtures, + }, +]; const ECPair = ECPairFactory(ecc); const NETWORK = regtestUtils.network; @@ -17,7 +41,10 @@ async function buildAndSign( redeemScript: any, witnessScript: any, ): Promise { - const unspent = await regtestUtils.faucetComplex(prevOutput, 5e4); + const unspent = await regtestUtils.faucetComplex( + Buffer.from(prevOutput), + 5e4, + ); const utx = await regtestUtils.fetch(unspent.txId); const psbt = new bitcoin.Psbt({ network: NETWORK }) @@ -41,16 +68,15 @@ async function buildAndSign( psbt.signInput(0, keyPairs[0]); } - console.log(psbt.finalizeAllInputs().extractTransaction().toHex()); return regtestUtils.broadcast( psbt.finalizeAllInputs().extractTransaction().toHex(), ); } -['p2ms'].forEach(k => { - const fixtures = require('../fixtures/' + k); +testSuite.forEach(t => { + const fixtures = t.fixtures; const { depends } = fixtures.dynamic; - const fn: any = (bitcoin.payments as any)[k]; + const fn: any = (bitcoin.payments as any)[t.paymentName]; const base: any = {}; if (depends.pubkey) base.pubkey = keyPairs[0].publicKey; @@ -60,22 +86,22 @@ async function buildAndSign( const { output } = fn(base); if (!output) throw new TypeError('Missing output'); - describe('bitcoinjs-lib (payments - ' + k + ')', () => { + describe('bitcoinjs-lib (payments - ' + t.paymentName + ')', () => { it('can broadcast as an output, and be spent as an input', async () => { - Object.assign(depends, { prevOutScriptType: k }); + Object.assign(depends, { prevOutScriptType: t.paymentName }); await buildAndSign(depends, output, undefined, undefined); }); it( 'can (as P2SH(' + - k + + t.paymentName + ')) broadcast as an output, and be spent as an input', async () => { const p2sh = bitcoin.payments.p2sh({ redeem: { output }, network: NETWORK, }); - Object.assign(depends, { prevOutScriptType: 'p2sh-' + k }); + Object.assign(depends, { prevOutScriptType: 'p2sh-' + t.paymentName }); await buildAndSign( depends, p2sh.output, @@ -86,18 +112,18 @@ async function buildAndSign( ); // NOTE: P2WPKH cannot be wrapped in P2WSH, consensus fail - if (k === 'p2wpkh') return; + if (t.paymentName === 'p2wpkh') return; it( 'can (as P2WSH(' + - k + + t.paymentName + ')) broadcast as an output, and be spent as an input', async () => { const p2wsh = bitcoin.payments.p2wsh({ redeem: { output }, network: NETWORK, }); - Object.assign(depends, { prevOutScriptType: 'p2wsh-' + k }); + Object.assign(depends, { prevOutScriptType: 'p2wsh-' + t.paymentName }); await buildAndSign( depends, p2wsh.output, @@ -109,7 +135,7 @@ async function buildAndSign( it( 'can (as P2SH(P2WSH(' + - k + + t.paymentName + '))) broadcast as an output, and be spent as an input', async () => { const p2wsh = bitcoin.payments.p2wsh({ @@ -121,7 +147,9 @@ async function buildAndSign( network: NETWORK, }); - Object.assign(depends, { prevOutScriptType: 'p2sh-p2wsh-' + k }); + Object.assign(depends, { + prevOutScriptType: 'p2sh-p2wsh-' + t.paymentName, + }); await buildAndSign( depends, p2sh.output, diff --git a/test/integration/taproot.spec.ts b/test/integration/taproot.spec.ts index dde9f3559..ec8e4071e 100644 --- a/test/integration/taproot.spec.ts +++ b/test/integration/taproot.spec.ts @@ -4,26 +4,27 @@ import * as bip39 from 'bip39'; import * as ecc from 'tiny-secp256k1'; import { describe, it } from 'mocha'; import { PsbtInput, TapLeaf, TapLeafScript } from 'bip174'; -import { regtestUtils } from './_regtest'; -import * as bitcoin from '../../'; -import { Taptree } from '../../src/cjs/types'; +import { regtestUtils } from './_regtest.js'; +import * as bitcoin from 'bitcoinjs-lib'; +import { Taptree } from 'bitcoinjs-lib/src/types'; import { LEAF_VERSION_TAPSCRIPT, tapleafHash, -} from '../../src/esm/payments/bip341.js'; +} from 'bitcoinjs-lib/src/payments/bip341'; import { toXOnly, tapTreeToList, tapTreeFromList, -} from '../../src/esm/psbt/bip371.js'; -import { witnessStackToScriptWitness } from '../../src/esm/psbt/psbtutils.js'; +} from 'bitcoinjs-lib/src/psbt/bip371'; +import { witnessStackToScriptWitness } from 'bitcoinjs-lib/src/psbt/psbtutils'; import * as tools from 'uint8array-tools'; import { sha256 } from '@noble/hashes/sha256'; +import { randomBytes } from 'crypto'; -const rng = require('randombytes'); const regtest = regtestUtils.network; bitcoin.initEccLib(ecc); const bip32 = BIP32Factory(ecc); +const rng = (size: number) => randomBytes(size); describe('bitcoinjs-lib (transaction with taproot)', () => { it('can verify the BIP86 HD wallet vectors for taproot single sig (& sending example)', async () => { diff --git a/test/integration/transactions.spec.ts b/test/integration/transactions.spec.ts index af73f5e3f..0f5580784 100644 --- a/test/integration/transactions.spec.ts +++ b/test/integration/transactions.spec.ts @@ -3,12 +3,14 @@ import BIP32Factory from 'bip32'; import * as ecc from 'tiny-secp256k1'; import ECPairFactory from 'ecpair'; import { describe, it } from 'mocha'; -import * as bitcoin from '../..'; -import { regtestUtils } from './_regtest'; +import * as bitcoin from 'bitcoinjs-lib'; +import { regtestUtils } from './_regtest.js'; import * as tools from 'uint8array-tools'; +import { randomBytes } from 'crypto'; const ECPair = ECPairFactory(ecc); -const rng = require('randombytes'); +// const rng = require('randombytes'); +const rng = (size: number) => randomBytes(size); const regtest = regtestUtils.network; const bip32 = BIP32Factory(ecc); diff --git a/test/payments.spec.ts b/test/payments.spec.ts index 45d993213..d7128c0ab 100644 --- a/test/payments.spec.ts +++ b/test/payments.spec.ts @@ -1,17 +1,20 @@ import * as assert from 'assert'; import * as ecc from 'tiny-secp256k1'; import { describe, it, before, beforeEach } from 'mocha'; -import { PaymentCreator } from '..'; -import * as u from './payments.utils'; -import { initEccLib } from '../src/esm/ecc_lib'; -import { p2data } from '../src/esm/payments/embed.js'; -import { p2ms } from '../src/esm/payments/p2ms.js'; -import { p2pk } from '../src/esm/payments/p2pk.js'; -import { p2pkh } from '../src/esm/payments/p2pkh.js'; -import { p2sh } from '../src/esm/payments/p2sh.js'; -import { p2wpkh } from '../src/esm/payments/p2wpkh.js'; -import { p2wsh } from '../src/esm/payments/p2wsh.js'; -import { p2tr } from '../src/esm/payments/p2tr.js'; +import { PaymentCreator } from 'bitcoinjs-lib'; +import * as u from './payments.utils.js'; +import { initEccLib } from 'bitcoinjs-lib'; +import { payments } from 'bitcoinjs-lib'; +const { + embed: p2data, + p2ms, + p2pk, + p2pkh, + p2sh, + p2wpkh, + p2wsh, + p2tr, +} = payments; import embedFixtures from './fixtures/embed.json'; import p2msFixtures from './fixtures/p2ms.json'; diff --git a/test/payments.utils.ts b/test/payments.utils.ts index 7b07cc9ae..a2bde3848 100644 --- a/test/payments.utils.ts +++ b/test/payments.utils.ts @@ -1,8 +1,8 @@ import * as t from 'assert'; -import * as BNETWORKS from '../src/esm/networks'; -import * as bscript from '../src/esm/script'; +import * as BNETWORKS from 'bitcoinjs-lib/src/networks'; +import * as bscript from 'bitcoinjs-lib/src/script'; import * as tools from 'uint8array-tools'; -import { isTaptree } from '../src/esm/types'; +import { isTaptree } from 'bitcoinjs-lib/src/types'; function tryHex(x: Uint8Array | Uint8Array[]): string | string[] { if (x instanceof Uint8Array) return tools.toHex(x); diff --git a/test/psbt.spec.ts b/test/psbt.spec.ts index 3c7b9cb63..eddcd44b0 100644 --- a/test/psbt.spec.ts +++ b/test/psbt.spec.ts @@ -5,31 +5,34 @@ 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/esm/payments/bip341'; -import { tapTreeToList, tapTreeFromList } from '../src/esm/psbt/bip371'; -import type { Taptree } from '../src/cjs/types.js'; -import { initEccLib } from '../src/esm/ecc_lib.js'; +import { convertScriptTree } from './payments.utils.js'; +import { LEAF_VERSION_TAPSCRIPT } from 'bitcoinjs-lib/src/payments/bip341'; +import { tapTreeToList, tapTreeFromList } from 'bitcoinjs-lib/src/psbt/bip371'; +import type { Taptree } from 'bitcoinjs-lib/src/types'; +import { initEccLib } from 'bitcoinjs-lib'; import * as tools from 'uint8array-tools'; const bip32 = BIP32Factory.BIP32Factory(ecc); const ECPair = ECPairFactory(ecc); -import { Psbt } from '../src/esm/psbt.js'; -import { networks as NETWORKS } from '../src/esm/index.js'; -import { payments } from '../src/esm/index.js'; -import type { Signer, SignerAsync } from '..'; +import { + Psbt, + networks as NETWORKS, + payments, + Signer, + SignerAsync, +} from 'bitcoinjs-lib'; -import * as preFixtures from './fixtures/psbt.json'; -import * as taprootFixtures from './fixtures/p2tr.json'; +import preFixtures from './fixtures/psbt.json'; +import taprootFixtures from './fixtures/p2tr.json'; const validator = ( - pubkey: Buffer, - msghash: Buffer, - signature: Buffer, + pubkey: Uint8Array, + msghash: Uint8Array, + signature: Uint8Array, ): boolean => ECPair.fromPublicKey(pubkey).verify(msghash, signature); -function toBip174Format(data: unknown) { +function toBip174Format(data: unknown): any { if (typeof data !== 'object' || data === null) { return data; } @@ -51,9 +54,9 @@ function toBip174Format(data: unknown) { } const schnorrValidator = ( - pubkey: Buffer, - msghash: Buffer, - signature: Buffer, + pubkey: Uint8Array, + msghash: Uint8Array, + signature: Uint8Array, ): boolean => ecc.verifySchnorr(msghash, pubkey, signature); const initBuffers = (object: any): typeof preFixtures => @@ -176,16 +179,14 @@ describe(`Psbt`, () => { }); fixtures.bip174.signer.forEach(f => { - it.only('Signs PSBT to the expected result', () => { + it('Signs PSBT to the expected result', () => { 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 }) => { - console.log("new keypair"); const keyPair = ECPair.fromWIF(WIF, NETWORKS.testnet); - console.log(tools.toHex(keyPair.privateKey!)); if (tapLeafHashToSign) psbt.signTaprootInput( inputToSign, @@ -810,7 +811,7 @@ describe(`Psbt`, () => { { innerScript: p2pkhPub, outerScript: p2shp2wshOut, - redeemGetter: (pk: Buffer): Buffer => p2wshOut(p2pkhPub(pk)), + redeemGetter: (pk: Uint8Array): Uint8Array => p2wshOut(p2pkhPub(pk)), witnessGetter: p2pkhPub, expectedType: 'p2sh-p2wsh-pubkeyhash', }, @@ -1187,7 +1188,7 @@ describe(`Psbt`, () => { })); assert.throws(() => { - tapTreeToList(tree as Taptree); + tapTreeToList(tree as unknown as Taptree); }, new RegExp('Cannot convert taptree to tapleaf list. Expecting a tapree structure.')); }); }); diff --git a/test/script.spec.ts b/test/script.spec.ts index 9ed628616..eba1a15c5 100644 --- a/test/script.spec.ts +++ b/test/script.spec.ts @@ -1,10 +1,10 @@ import * as assert from 'assert'; import { describe, it } from 'mocha'; -import { script as bscript } from '..'; -import * as fixtures from './fixtures/script.json'; -const minimalData = require('minimaldata'); -import * as tools from 'uint8array-tools'; +import { script as bscript } from 'bitcoinjs-lib'; +import fixtures from './fixtures/script.json'; +import minimalData from 'minimaldata'; +import * as tools from 'uint8array-tools'; describe('script', () => { // TODO describe('isCanonicalPubKey', () => { diff --git a/test/script_number.spec.ts b/test/script_number.spec.ts index bd01badc7..e0082f1fd 100644 --- a/test/script_number.spec.ts +++ b/test/script_number.spec.ts @@ -1,6 +1,6 @@ import * as assert from 'assert'; import { describe, it } from 'mocha'; -import * as scriptNumber from '../src/esm/script_number.js'; +import * as scriptNumber from 'bitcoinjs-lib/src/script_number'; import fixtures from './fixtures/script_number.json'; import * as tools from 'uint8array-tools'; diff --git a/test/script_signature.spec.ts b/test/script_signature.spec.ts index 561327d72..c798a053e 100644 --- a/test/script_signature.spec.ts +++ b/test/script_signature.spec.ts @@ -1,6 +1,6 @@ import * as assert from 'assert'; import { describe, it } from 'mocha'; -import { script } from '..'; +import { script } from 'bitcoinjs-lib'; const bscriptSig = script.signature; import fixtures from './fixtures/signature.json'; import * as tools from 'uint8array-tools'; diff --git a/test/transaction.spec.ts b/test/transaction.spec.ts index 298f5ead2..e4c58cedf 100644 --- a/test/transaction.spec.ts +++ b/test/transaction.spec.ts @@ -1,8 +1,7 @@ import * as assert from 'assert'; import { beforeEach, describe, it } from 'mocha'; -import { Transaction } from '..'; -import { script as bscript } from '../src/esm/index.js'; -import * as fixtures from './fixtures/transaction.json'; +import { Transaction, script as bscript } from 'bitcoinjs-lib'; +import fixtures from './fixtures/transaction.json'; import * as tools from 'uint8array-tools'; describe('Transaction', () => { diff --git a/test/tsconfig.json b/test/tsconfig.json new file mode 100644 index 000000000..f416a161d --- /dev/null +++ b/test/tsconfig.json @@ -0,0 +1,109 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "ESNext", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "NodeNext", /* Specify what module code is generated. */ + "rootDir": "./", /* Specify the root folder within your source files. */ + "moduleResolution": "NodeNext", /* Specify how TypeScript looks up a file from a given module specifier. */ + "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + }, + "include": ["**/*.ts",] +} diff --git a/test/types.spec.ts b/test/types.spec.ts index 210b0d6cb..e258fa271 100644 --- a/test/types.spec.ts +++ b/test/types.spec.ts @@ -1,6 +1,6 @@ import * as assert from 'assert'; import { describe, it } from 'mocha'; -import * as types from '../src/esm/types'; +import * as types from 'bitcoinjs-lib/src/types'; import * as v from 'valibot'; describe('types', () => { diff --git a/ts_src/address.ts b/ts_src/address.ts index 29b9f631c..3baaec94e 100644 --- a/ts_src/address.ts +++ b/ts_src/address.ts @@ -81,7 +81,6 @@ 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 = tools.readUInt8(payload, 0); const hash = payload.slice(1); @@ -123,9 +122,7 @@ export function toBase58Check(hash: Uint8Array, version: number): string { v.parse(v.tuple([Hash160bitSchema, UInt8Schema]), [hash, version]); const payload = new Uint8Array(21); - // payload.writeUInt8(version, 0); tools.writeUInt8(payload, 0, version); - // hash.copy(payload, 1); payload.set(hash, 1); return bs58check.encode(payload); diff --git a/ts_src/bip66.ts b/ts_src/bip66.ts index 17ce826cc..39a40683a 100644 --- a/ts_src/bip66.ts +++ b/ts_src/bip66.ts @@ -102,11 +102,9 @@ export function encode(r: Uint8Array, s: Uint8Array): Uint8Array { signature[1] = signature.length - 2; signature[2] = 0x02; signature[3] = r.length; - // r.copy(signature, 4); signature.set(r, 4); signature[4 + lenR] = 0x02; signature[5 + lenR] = s.length; - // s.copy(signature, 6 + lenR); signature.set(s, 6 + lenR); return signature; diff --git a/ts_src/block.ts b/ts_src/block.ts index 36115cae7..5d065a19f 100644 --- a/ts_src/block.ts +++ b/ts_src/block.ts @@ -10,8 +10,6 @@ import { Transaction } from './transaction.js'; import * as v from 'valibot'; import * as tools from 'uint8array-tools'; -// const { typeforce } = types; - const errorMerkleNoTxes = new TypeError( 'Cannot compute merkle root for zero transactions', ); @@ -60,7 +58,6 @@ export class Block { } static fromHex(hex: string): Block { - // return Block.fromBuffer(Buffer.from(hex, 'hex')); return Block.fromBuffer(tools.fromHex(hex)); } @@ -68,7 +65,6 @@ export class Block { const exponent = ((bits & 0xff000000) >> 24) - 3; const mantissa = bits & 0x007fffff; const target = new Uint8Array(32); - // target.writeUIntBE(mantissa, 29 - exponent, 3); target[29 - exponent] = (mantissa >> 16) & 0xff; target[30 - exponent] = (mantissa >> 8) & 0xff; target[31 - exponent] = mantissa & 0xff; @@ -79,7 +75,6 @@ export class Block { transactions: Transaction[], forWitness?: boolean, ): Uint8Array { - // typeforce([{ getHash: types.Function }], transactions); v.parse(v.array(v.object({ getHash: v.function() })), transactions); if (transactions.length === 0) throw errorMerkleNoTxes; if (forWitness && !txesHaveWitnessCommit(transactions)) @@ -116,7 +111,6 @@ export class Block { // If multiple commits are found, the output with highest index is assumed. const witnessCommits = this.transactions![0].outs.filter( out => - // out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex')), tools.compare( out.script.slice(0, 6), Uint8Array.from([0x6a, 0x24, 0xaa, 0x21, 0xa9, 0xed]), @@ -225,7 +219,6 @@ export class Block { const hash = reverseBuffer(this.getHash()); const target = Block.calculateTarget(this.bits); - // return hash.compare(target) <= 0; return tools.compare(hash, target) <= 0; } @@ -233,7 +226,6 @@ export class Block { if (!this.transactions) throw errorMerkleNoTxes; const actualMerkleRoot = Block.calculateMerkleRoot(this.transactions); - // return this.merkleRoot!.compare(actualMerkleRoot) === 0; return tools.compare(this.merkleRoot!, actualMerkleRoot) === 0; } @@ -245,7 +237,6 @@ export class Block { this.transactions, true, ); - // return this.witnessCommit!.compare(actualWitnessCommit) === 0; return tools.compare(this.witnessCommit!, actualWitnessCommit) === 0; } } diff --git a/ts_src/bufferutils.ts b/ts_src/bufferutils.ts index 4102ae34c..d8b7dfb0e 100644 --- a/ts_src/bufferutils.ts +++ b/ts_src/bufferutils.ts @@ -18,60 +18,6 @@ function verifuint(value: number | bigint, max: number): void { throw new Error('value has a fractional component'); } -// export function readUInt64LE(buffer: Buffer, offset: number): number { -// const a = buffer.readUInt32LE(offset); -// let b = buffer.readUInt32LE(offset + 4); -// b *= 0x100000000; - -// verifuint(b + a, MAX_JS_NUMBER); -// return b + a; -// } - -/** - * Writes a 64-bit unsigned integer in little-endian format to the specified buffer at the given offset. - * - * @param buffer - The buffer to write the value to. - * @param value - The 64-bit unsigned integer value to write. - * @param offset - The offset in the buffer where the value should be written. - * @returns The new offset after writing the value. - */ -// export function writeUInt64LE( -// buffer: Buffer, -// value: number, -// offset: number, -// ): number { -// verifuint(value, MAX_JS_NUMBER); - -// buffer.writeInt32LE(value & -1, offset); -// buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4); -// return offset + 8; -// } - -/** - * Reads a 64-bit signed integer from a Uint8Array in little-endian format. - * - * @param {Uint8Array} buffer - The buffer to read the value from. - * @param {number} offset - The offset in the buffer where the value starts. - * @return {number} The 64-bit signed integer value. - */ -// export function readInt64LE( -// buffer: Uint8Array, -// offset: number -// ): number { -// if((buffer[offset + 7] & 0x7f) > 0) throw new Error("RangeError: value out of range, greater than int64"); - -// return ( -// buffer[offset] | -// (buffer[offset + 1] << 8) | -// (buffer[offset + 2] << 16) | -// (buffer[offset + 3] << 24) | -// (buffer[offset + 4] << 32) | -// (buffer[offset + 5] << 40) | -// (buffer[offset + 6] << 48) | -// (buffer[offset + 7] << 56) -// ); -// } - /** * Reverses the order of bytes in a buffer. * @param buffer - The buffer to reverse. @@ -108,7 +54,6 @@ export class BufferWriter { public buffer: Uint8Array, public offset: number = 0, ) { - // typeforce(types.tuple(types.Buffer, types.UInt32), [buffer, offset]); v.parse(v.tuple([types.BufferSchema, types.UInt32Schema]), [ buffer, offset, @@ -116,26 +61,22 @@ export class BufferWriter { } writeUInt8(i: number): void { - // this.offset = this.buffer.writeUInt8(i, this.offset); this.offset = tools.writeUInt8(this.buffer, this.offset, i); } writeInt32(i: number): void { - // this.offset = this.buffer.writeInt32LE(i, this.offset); - this.offset = tools.writeInt32(this.buffer, i, this.offset, 'LE'); + this.offset = tools.writeInt32(this.buffer, this.offset, i, 'LE'); } writeInt64(i: number | bigint): void { - this.offset = tools.writeInt64(this.buffer, BigInt(i), this.offset, 'LE'); + this.offset = tools.writeInt64(this.buffer, this.offset, BigInt(i), 'LE'); } writeUInt32(i: number): void { - // this.offset = this.buffer.writeUInt32LE(i, this.offset); this.offset = tools.writeUInt32(this.buffer, this.offset, i, 'LE'); } writeUInt64(i: number | bigint): void { - // this.offset = writeUInt64LE(this.buffer, i, this.offset); this.offset = tools.writeUInt64(this.buffer, this.offset, BigInt(i), 'LE'); } @@ -148,7 +89,6 @@ export class BufferWriter { if (this.buffer.length < this.offset + slice.length) { throw new Error('Cannot write slice out of bounds'); } - // this.offset += slice.copy(this.buffer, this.offset); this.buffer.set(slice, this.offset); this.offset += slice.length; } @@ -179,7 +119,6 @@ export class BufferReader { public buffer: Uint8Array, public offset: number = 0, ) { - // typeforce(types.tuple(types.Buffer, types.UInt32), [buffer, offset]); v.parse(v.tuple([types.BufferSchema, types.UInt32Schema]), [ buffer, offset, @@ -187,29 +126,25 @@ export class BufferReader { } readUInt8(): number { - // const result = this.buffer.readUInt8(this.offset); const result = tools.readUInt8(this.buffer, this.offset); this.offset++; return result; } readInt32(): number { - // const result = readInt32LE(this.buffer, this.offset); const result = tools.readInt32(this.buffer, this.offset, 'LE'); this.offset += 4; return result; } readUInt32(): number { - // const result = this.buffer.readUInt32LE(this.offset); const result = tools.readUInt32(this.buffer, this.offset, 'LE'); this.offset += 4; return result; } - readUInt64(): bigint { - // const result = readUInt64LE(this.buffer, this.offset); - const result = tools.readUInt64(this.buffer, this.offset, 'LE'); + readInt64(): bigint { + const result = tools.readInt64(this.buffer, this.offset, 'LE'); this.offset += 8; return result; } diff --git a/ts_src/payments/bip341.ts b/ts_src/payments/bip341.ts index cee7b7ad4..33bfb714b 100644 --- a/ts_src/payments/bip341.ts +++ b/ts_src/payments/bip341.ts @@ -1,4 +1,3 @@ -// import { Buffer as NBuffer } from 'buffer'; import { getEccLib } from '../ecc_lib.js'; import * as bcrypto from '../crypto.js'; @@ -55,7 +54,6 @@ export function rootHashFromPath( 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) { if (tools.compare(kj, ej) < 0) { kj = tapBranchHash(kj, ej); } else { @@ -103,7 +101,6 @@ export function findScriptPath( const rightPath = findScriptPath(node.right, hash); if (rightPath !== undefined) return [...rightPath, node.left.hash]; - // } else if (node.hash.equals(hash)) { } else if (tools.compare(node.hash, hash) === 0) { return []; } @@ -155,7 +152,6 @@ function tapBranchHash(a: Uint8Array, b: Uint8Array): Uint8Array { function serializeScript(s: Uint8Array): Uint8Array { /* global BigInt */ const varintLen = varuint.encodingLength(s.length); - // const buffer = NBuffer.allocUnsafe(varintLen); // better const buffer = new Uint8Array(varintLen); varuint.encode(s.length, buffer); return tools.concat([buffer, s]); diff --git a/ts_src/payments/embed.ts b/ts_src/payments/embed.ts index 0064d275c..dccbc5777 100644 --- a/ts_src/payments/embed.ts +++ b/ts_src/payments/embed.ts @@ -19,15 +19,6 @@ export function p2data(a: Payment, opts?: PaymentOpts): Payment { if (!a.data && !a.output) throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - // typef( - // { - // network: typef.maybe(typef.Object), - // output: typef.maybe(typef.Buffer), - // data: typef.maybe(typef.arrayOf(typef.Buffer)), - // }, - // a, - // ); - v.parse( v.partial( v.object({ diff --git a/ts_src/payments/p2ms.ts b/ts_src/payments/p2ms.ts index c557aaf7a..a40d7c35b 100644 --- a/ts_src/payments/p2ms.ts +++ b/ts_src/payments/p2ms.ts @@ -34,20 +34,6 @@ export function p2ms(a: Payment, opts?: PaymentOpts): Payment { ); } - // typef( - // { - // network: typef.maybe(typef.Object), - // m: typef.maybe(typef.Number), - // n: typef.maybe(typef.Number), - // output: typef.maybe(typef.Buffer), - // pubkeys: typef.maybe(typef.arrayOf(isPoint)), - - // signatures: typef.maybe(typef.arrayOf(isAcceptableSignature)), - // input: typef.maybe(typef.Buffer), - // }, - // a, - // ); - v.parse( v.partial( v.object({ @@ -132,10 +118,7 @@ export function p2ms(a: Payment, opts?: PaymentOpts): Payment { if (opts.validate) { if (a.output) { decode(a.output); - // if (!typef.Number(chunks[0])) throw new TypeError('Output is invalid'); v.parse(v.number(), chunks[0], { message: 'Output is invalid' }); - // if (!typef.Number(chunks[chunks.length - 2])) - // throw new TypeError('Output is invalid'); v.parse(v.number(), chunks[chunks.length - 2], { message: 'Output is invalid', }); diff --git a/ts_src/payments/p2pk.ts b/ts_src/payments/p2pk.ts index 898238710..5726e2052 100644 --- a/ts_src/payments/p2pk.ts +++ b/ts_src/payments/p2pk.ts @@ -22,18 +22,6 @@ export function p2pk(a: Payment, opts?: PaymentOpts): Payment { throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - // typef( - // { - // network: typef.maybe(typef.Object), - // output: typef.maybe(typef.Buffer), - // pubkey: typef.maybe(isPoint), - - // signature: typef.maybe(bscript.isCanonicalScriptSignature), - // input: typef.maybe(typef.Buffer), - // }, - // a, - // ); - v.parse( v.partial( v.object({ @@ -88,13 +76,11 @@ export function p2pk(a: Payment, opts?: PaymentOpts): Payment { if (a.output[a.output.length - 1] !== OPS.OP_CHECKSIG) throw new TypeError('Output is invalid'); if (!isPoint(o.pubkey)) throw new TypeError('Output pubkey is invalid'); - // if (a.pubkey && !a.pubkey.equals(o.pubkey!)) if (a.pubkey && tools.compare(a.pubkey, o.pubkey!) !== 0) throw new TypeError('Pubkey mismatch'); } if (a.signature) { - // if (a.input && !a.input.equals(o.input!)) if (a.input && tools.compare(a.input, o.input!) !== 0) throw new TypeError('Signature mismatch'); } diff --git a/ts_src/payments/p2pkh.ts b/ts_src/payments/p2pkh.ts index bcf3b7124..696e09714 100644 --- a/ts_src/payments/p2pkh.ts +++ b/ts_src/payments/p2pkh.ts @@ -30,20 +30,6 @@ export function p2pkh(a: Payment, opts?: PaymentOpts): Payment { throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - // typef( - // { - // network: typef.maybe(typef.Object), - // address: typef.maybe(typef.String), - // hash: typef.maybe(typef.BufferN(20)), - // output: typef.maybe(typef.BufferN(25)), - - // pubkey: typef.maybe(isPoint), - // signature: typef.maybe(bscript.isCanonicalScriptSignature), - // input: typef.maybe(typef.Buffer), - // }, - // a, - // ); - v.parse( v.partial( v.object({ @@ -64,7 +50,6 @@ export function p2pkh(a: Payment, opts?: PaymentOpts): Payment { const _address = lazy.value(() => { const payload = bs58check.decode(a.address!); - // const version = payload.readUInt8(0); const version = tools.readUInt8(payload, 0); const hash = payload.slice(1); return { version, hash }; @@ -80,9 +65,7 @@ export function p2pkh(a: Payment, opts?: PaymentOpts): Payment { if (!o.hash) return; const payload = new Uint8Array(21); - // payload.writeUInt8(network.pubKeyHash, 0); tools.writeUInt8(payload, 0, network.pubKeyHash); - // o.hash.copy(payload, 1); payload.set(o.hash, 1); return bs58check.encode(payload); }); @@ -130,7 +113,6 @@ export function p2pkh(a: Payment, opts?: PaymentOpts): Payment { } if (a.hash) { - // if (hash.length > 0 && !hash.equals(a.hash)) if (hash.length > 0 && tools.compare(hash, a.hash) !== 0) throw new TypeError('Hash mismatch'); else hash = a.hash; @@ -148,7 +130,6 @@ export function p2pkh(a: Payment, opts?: PaymentOpts): Payment { throw new TypeError('Output is invalid'); const hash2 = a.output.slice(3, 23); - // if (hash.length > 0 && !hash.equals(hash2)) if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; @@ -156,7 +137,6 @@ export function p2pkh(a: Payment, opts?: PaymentOpts): Payment { if (a.pubkey) { const pkh = bcrypto.hash160(a.pubkey); - // if (hash.length > 0 && !hash.equals(pkh)) if (hash.length > 0 && tools.compare(hash, pkh) !== 0) throw new TypeError('Hash mismatch'); else hash = pkh; @@ -169,18 +149,15 @@ export function p2pkh(a: Payment, opts?: PaymentOpts): Payment { throw new TypeError('Input has invalid signature'); if (!isPoint(chunks[1])) throw new TypeError('Input has invalid pubkey'); - // if (a.signature && !a.signature.equals(chunks[0])) if ( a.signature && tools.compare(a.signature, chunks[0] as Uint8Array) !== 0 ) throw new TypeError('Signature mismatch'); - // if (a.pubkey && !a.pubkey.equals(chunks[1] as Buffer)) if (a.pubkey && tools.compare(a.pubkey, chunks[1] as Uint8Array) !== 0) throw new TypeError('Pubkey mismatch'); const pkh = bcrypto.hash160(chunks[1] as Uint8Array); - // if (hash.length > 0 && !hash.equals(pkh)) if (hash.length > 0 && tools.compare(hash, pkh) !== 0) throw new TypeError('Hash mismatch'); } diff --git a/ts_src/payments/p2sh.ts b/ts_src/payments/p2sh.ts index 0873a8d34..cd9dd77eb 100644 --- a/ts_src/payments/p2sh.ts +++ b/ts_src/payments/p2sh.ts @@ -31,26 +31,6 @@ export function p2sh(a: Payment, opts?: PaymentOpts): Payment { throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - // typef( - // { - // network: typef.maybe(typef.Object), - - // address: typef.maybe(typef.String), - // hash: typef.maybe(typef.BufferN(20)), - // output: typef.maybe(typef.BufferN(23)), - - // redeem: typef.maybe({ - // network: typef.maybe(typef.Object), - // output: typef.maybe(typef.Buffer), - // input: typef.maybe(typef.Buffer), - // witness: typef.maybe(typef.arrayOf(typef.Buffer)), - // }), - // input: typef.maybe(typef.Buffer), - // witness: typef.maybe(typef.arrayOf(typef.Buffer)), - // }, - // a, - // ); - v.parse( v.partial( v.object({ @@ -84,7 +64,6 @@ export function p2sh(a: Payment, opts?: PaymentOpts): Payment { const _address = lazy.value(() => { const payload = bs58check.decode(a.address!); - // const version = payload.readUInt8(0); const version = tools.readUInt8(payload, 0); const hash = payload.slice(1); return { version, hash }; @@ -111,9 +90,7 @@ export function p2sh(a: Payment, opts?: PaymentOpts): Payment { if (!o.hash) return; const payload = new Uint8Array(21); - // payload.writeUInt8(o.network!.scriptHash, 0); tools.writeUInt8(payload, 0, o.network!.scriptHash); - // o.hash.copy(payload, 1); payload.set(o.hash, 1); return bs58check.encode(payload); }); @@ -163,7 +140,6 @@ export function p2sh(a: Payment, opts?: PaymentOpts): Payment { } if (a.hash) { - // if (hash.length > 0 && !hash.equals(a.hash)) if (hash.length > 0 && tools.compare(hash, a.hash) !== 0) throw new TypeError('Hash mismatch'); else hash = a.hash; @@ -179,7 +155,6 @@ export function p2sh(a: Payment, opts?: PaymentOpts): Payment { throw new TypeError('Output is invalid'); const hash2 = a.output.slice(2, 22); - // if (hash.length > 0 && !hash.equals(hash2)) if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; @@ -203,7 +178,6 @@ export function p2sh(a: Payment, opts?: PaymentOpts): Payment { // match hash against other sources const hash2 = bcrypto.hash160(redeem.output); - // if (hash.length > 0 && !hash.equals(hash2)) if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; @@ -237,13 +211,11 @@ export function p2sh(a: Payment, opts?: PaymentOpts): Payment { throw new TypeError('Network mismatch'); if (a.input) { const redeem = _redeem(); - // if (a.redeem.output && !a.redeem.output.equals(redeem.output!)) if ( a.redeem.output && tools.compare(a.redeem.output, redeem.output!) !== 0 ) throw new TypeError('Redeem.output mismatch'); - // if (a.redeem.input && !a.redeem.input.equals(redeem.input!)) if ( a.redeem.input && tools.compare(a.redeem.input, redeem.input!) !== 0 diff --git a/ts_src/payments/p2tr.ts b/ts_src/payments/p2tr.ts index 048e195ac..922064bc0 100644 --- a/ts_src/payments/p2tr.ts +++ b/ts_src/payments/p2tr.ts @@ -1,4 +1,3 @@ -// import { Buffer as NBuffer } from 'buffer'; import { bitcoin as BITCOIN_NETWORK } from '../networks.js'; import * as bscript from '../script.js'; import { @@ -48,28 +47,6 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment { 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)), // 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))), - // witness: typef.maybe(typef.arrayOf(typef.Buffer)), - // scriptTree: typef.maybe(isTaptree), - // redeem: typef.maybe({ - // 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), - // }, - // a, - // ); - v.parse( v.partial( v.object({ @@ -230,7 +207,6 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment { } if (a.pubkey) { - // if (pubkey.length > 0 && !pubkey.equals(a.pubkey)) if (pubkey.length > 0 && tools.compare(pubkey, a.pubkey) !== 0) throw new TypeError('Pubkey mismatch'); else pubkey = a.pubkey; @@ -243,7 +219,6 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment { a.output[1] !== 0x20 ) throw new TypeError('Output is invalid'); - // if (pubkey.length > 0 && !pubkey.equals(a.output.slice(2))) if (pubkey.length > 0 && tools.compare(pubkey, a.output.slice(2)) !== 0) throw new TypeError('Pubkey mismatch'); else pubkey = a.output.slice(2); @@ -251,7 +226,6 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment { if (a.internalPubkey) { const tweakedKey = tweakKey(a.internalPubkey, o.hash); - // if (pubkey.length > 0 && !pubkey.equals(tweakedKey!.x)) if (pubkey.length > 0 && tools.compare(pubkey, tweakedKey!.x) !== 0) throw new TypeError('Pubkey mismatch'); else pubkey = tweakedKey!.x; @@ -265,7 +239,6 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment { const hashTree = _hashTree(); if (a.hash && hashTree) { - // if (!a.hash.equals(hashTree.hash)) throw new TypeError('Hash mismatch'); if (tools.compare(a.hash, hashTree.hash) !== 0) throw new TypeError('Hash mismatch'); } @@ -293,7 +266,6 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment { 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)) if ( o.redeem.output && tools.compare(a.redeem.output, o.redeem.output) !== 0 @@ -312,7 +284,6 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment { if (witness && witness.length) { if (witness.length === 1) { // key spending - // if (a.signature && !a.signature.equals(witness[0])) if (a.signature && tools.compare(a.signature, witness[0]) !== 0) throw new TypeError('Signature mismatch'); } else { @@ -335,7 +306,6 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment { ); const internalPubkey = controlBlock.slice(1, 33); - // if (a.internalPubkey && !a.internalPubkey.equals(internalPubkey)) if ( a.internalPubkey && tools.compare(a.internalPubkey, internalPubkey) !== 0 @@ -356,7 +326,6 @@ export function p2tr(a: Payment, opts?: PaymentOpts): Payment { // todo: needs test data throw new TypeError('Invalid outputKey for p2tr witness'); - // if (pubkey.length && !pubkey.equals(outputKey.x)) if (pubkey.length && tools.compare(pubkey, outputKey.x) !== 0) throw new TypeError('Pubkey mismatch for p2tr witness'); diff --git a/ts_src/payments/p2wpkh.ts b/ts_src/payments/p2wpkh.ts index c04b577c4..326181ec4 100644 --- a/ts_src/payments/p2wpkh.ts +++ b/ts_src/payments/p2wpkh.ts @@ -28,20 +28,6 @@ export function p2wpkh(a: Payment, opts?: PaymentOpts): Payment { throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - // typef( - // { - // 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(22)), - // pubkey: typef.maybe(isPoint), - // signature: typef.maybe(bscript.isCanonicalScriptSignature), - // witness: typef.maybe(typef.arrayOf(typef.Buffer)), - // }, - // a, - // ); - v.parse( v.partial( v.object({ @@ -126,7 +112,6 @@ export function p2wpkh(a: Payment, opts?: PaymentOpts): Payment { } if (a.hash) { - // if (hash.length > 0 && !hash.equals(a.hash)) if (hash.length > 0 && tools.compare(hash, a.hash) !== 0) throw new TypeError('Hash mismatch'); else hash = a.hash; @@ -139,7 +124,6 @@ export function p2wpkh(a: Payment, opts?: PaymentOpts): Payment { a.output[1] !== 0x14 ) throw new TypeError('Output is invalid'); - // if (hash.length > 0 && !hash.equals(a.output.slice(2))) if (hash.length > 0 && tools.compare(hash, a.output.slice(2)) !== 0) throw new TypeError('Hash mismatch'); else hash = a.output.slice(2); @@ -147,7 +131,6 @@ export function p2wpkh(a: Payment, opts?: PaymentOpts): Payment { if (a.pubkey) { const pkh = bcrypto.hash160(a.pubkey); - // if (hash.length > 0 && !hash.equals(pkh)) if (hash.length > 0 && tools.compare(hash, pkh) !== 0) throw new TypeError('Hash mismatch'); else hash = pkh; @@ -162,7 +145,6 @@ export function p2wpkh(a: Payment, opts?: PaymentOpts): Payment { if (!isPoint(a.witness[1]) || a.witness[1].length !== 33) throw new TypeError('Witness has invalid pubkey'); - // if (a.signature && !a.signature.equals(a.witness[0])) if (a.signature && tools.compare(a.signature, a.witness[0]) !== 0) throw new TypeError('Signature mismatch'); // if (a.pubkey && !a.pubkey.equals(a.witness[1])) @@ -170,7 +152,6 @@ export function p2wpkh(a: Payment, opts?: PaymentOpts): Payment { throw new TypeError('Pubkey mismatch'); const pkh = bcrypto.hash160(a.witness[1]); - // if (hash.length > 0 && !hash.equals(pkh)) if (hash.length > 0 && tools.compare(hash, pkh) !== 0) throw new TypeError('Hash mismatch'); } diff --git a/ts_src/payments/p2wsh.ts b/ts_src/payments/p2wsh.ts index 963f760da..ae8c8b12e 100644 --- a/ts_src/payments/p2wsh.ts +++ b/ts_src/payments/p2wsh.ts @@ -21,7 +21,6 @@ const EMPTY_BUFFER = new Uint8Array(0); function chunkHasUncompressedPubkey(chunk: StackElement): boolean { if ( - // Buffer.isBuffer(chunk) && chunk instanceof Uint8Array && chunk.length === 65 && chunk[0] === 0x04 && @@ -49,26 +48,6 @@ export function p2wsh(a: Payment, opts?: PaymentOpts): Payment { throw new TypeError('Not enough data'); opts = Object.assign({ validate: true }, opts || {}); - // typef( - // { - // network: typef.maybe(typef.Object), - - // address: typef.maybe(typef.String), - // hash: typef.maybe(typef.BufferN(32)), - // output: typef.maybe(typef.BufferN(34)), - - // redeem: typef.maybe({ - // input: typef.maybe(typef.Buffer), - // network: typef.maybe(typef.Object), - // output: typef.maybe(typef.Buffer), - // witness: typef.maybe(typef.arrayOf(typef.Buffer)), - // }), - // input: typef.maybe(typef.BufferN(0)), - // witness: typef.maybe(typef.arrayOf(typef.Buffer)), - // }, - // a, - // ); - v.parse( NullablePartial({ network: v.object({}), @@ -180,7 +159,6 @@ export function p2wsh(a: Payment, opts?: PaymentOpts): Payment { } if (a.hash) { - // if (hash.length > 0 && !hash.equals(a.hash)) if (hash.length > 0 && tools.compare(hash, a.hash) !== 0) throw new TypeError('Hash mismatch'); else hash = a.hash; @@ -194,7 +172,6 @@ export function p2wsh(a: Payment, opts?: PaymentOpts): Payment { ) throw new TypeError('Output is invalid'); const hash2 = a.output.slice(2); - // if (hash.length > 0 && !hash.equals(hash2)) if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; @@ -229,7 +206,6 @@ export function p2wsh(a: Payment, opts?: PaymentOpts): Payment { // match hash against other sources const hash2 = sha256(a.redeem.output); - // if (hash.length > 0 && !hash.equals(hash2)) if (hash.length > 0 && tools.compare(hash, hash2) !== 0) throw new TypeError('Hash mismatch'); else hash = hash2; @@ -258,7 +234,6 @@ export function p2wsh(a: Payment, opts?: PaymentOpts): Payment { if (a.witness && a.witness.length > 0) { const wScript = a.witness[a.witness.length - 1]; - // if (a.redeem && a.redeem.output && !a.redeem.output.equals(wScript)) if ( a.redeem && a.redeem.output && diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts index 3ff0a37df..70f2a1e89 100644 --- a/ts_src/psbt.ts +++ b/ts_src/psbt.ts @@ -128,13 +128,11 @@ const DEFAULT_OPTS: PsbtOpts = { */ export class Psbt { static fromBase64(data: string, opts: PsbtOptsOptional = {}): Psbt { - // const buffer = Buffer.from(data, 'base64'); const buffer = tools.fromBase64(data); return this.fromBuffer(buffer, opts); } static fromHex(data: string, opts: PsbtOptsOptional = {}): Psbt { - // const buffer = Buffer.from(data, 'hex'); const buffer = tools.fromHex(data); return this.fromBuffer(buffer, opts); } @@ -634,7 +632,6 @@ export class Psbt { if (tapScriptSig) { for (const tapSig of tapScriptSig) { - // const tapSigHash = allHashses.find(h => tapSig.pubkey.equals(h.pubkey)); const tapSigHash = allHashses.find( h => tools.compare(h.pubkey, tapSig.pubkey) === 0, ); @@ -1275,8 +1272,7 @@ class PsbtTransaction implements ITransaction { } const hash = typeof input.hash === 'string' - ? // ? reverseBuffer(Buffer.from(input.hash, 'hex')) - reverseBuffer(tools.fromHex(input.hash)) + ? reverseBuffer(tools.fromHex(input.hash)) : input.hash; this.tx.addInput(hash, input.index, input.sequence); } @@ -1353,9 +1349,7 @@ function bip32DerivationIsMine( root: HDSigner, ): (d: Bip32Derivation) => boolean { return (d: Bip32Derivation): boolean => { - // if (!d.masterFingerprint.equals(root.fingerprint)) return false; if (tools.compare(root.fingerprint, d.masterFingerprint)) return false; - // if (!root.derivePath(d.path).publicKey.equals(d.pubkey)) return false; if (tools.compare(root.derivePath(d.path).publicKey, d.pubkey)) return false; return true; @@ -1469,7 +1463,6 @@ function scriptCheckerFactory( redeem: { output: redeemScript }, }).output as Uint8Array; - // if (!scriptPubKey.equals(redeemScriptOutput)) { if (tools.compare(scriptPubKey, redeemScriptOutput)) { throw new Error( `${paymentScriptName} for ${ioType} #${inputIndex} doesn't match the scriptPubKey in the prevout`, @@ -1651,7 +1644,6 @@ function getHashForSig( const utxoHash = nonWitnessUtxoTx.getHash(); // If a non-witness UTXO is provided, its hash must match the hash specified in the prevout - // if (!prevoutHash.equals(utxoHash)) { if (tools.compare(prevoutHash, utxoHash) !== 0) { throw new Error( `Non-witness UTXO hash for input #${inputIndex} doesn't match the hash specified in the prevout`, @@ -1791,7 +1783,6 @@ function getTaprootHashesForSig( if (input.tapInternalKey && !tapLeafHashToSign) { const outputKey = getPrevoutTaprootKey(inputIndex, input, cache) || Uint8Array.from([]); - // if (toXOnly(pubkey).equals(outputKey)) { if (tools.compare(toXOnly(pubkey), outputKey) === 0) { const tapKeyHash = unsignedTx.hashForWitnessV1( inputIndex, @@ -1941,7 +1932,6 @@ function getSignersFromHD( } const myDerivations = input.bip32Derivation .map((bipDv: Bip32Derivation) => { - // if (bipDv.masterFingerprint.equals(hdKeyPair.fingerprint)) { if (tools.compare(bipDv.masterFingerprint, hdKeyPair.fingerprint) === 0) { return bipDv; } else { @@ -1956,7 +1946,6 @@ function getSignersFromHD( } const signers: Array = myDerivations.map(bipDv => { const node = hdKeyPair.derivePath(bipDv!.path); - // if (!bipDv!.pubkey.equals(node.publicKey)) { if (tools.compare(bipDv!.pubkey, node.publicKey) !== 0) { throw new Error('pubkey did not match bip32Derivation'); } @@ -1976,7 +1965,6 @@ function getSortedSigs( // filter partialSig array by pubkey being equal return ( partialSig.filter(ps => { - // return ps.pubkey.equals(pk); return tools.compare(ps.pubkey, pk) === 0; })[0] || {} ).signature; @@ -2190,7 +2178,6 @@ function redeemFromFinalScriptSig( if (!decomp) return; const lastItem = decomp[decomp.length - 1]; if ( - // !Buffer.isBuffer(lastItem) || !(lastItem instanceof Uint8Array) || isPubkeyLike(lastItem) || isSigLike(lastItem) diff --git a/ts_src/psbt/bip371.ts b/ts_src/psbt/bip371.ts index bc9fe255d..f1c2c71de 100644 --- a/ts_src/psbt/bip371.ts +++ b/ts_src/psbt/bip371.ts @@ -167,7 +167,6 @@ function checkTaprootScriptPubkey( if (tapInternalKey) { const { script: scriptPubkey } = outputData as any; const script = getTaprootScripPubkey(tapInternalKey, tapTree); - // if (scriptPubkey && !scriptPubkey.equals(script)) if (scriptPubkey && tools.compare(script, scriptPubkey) !== 0) throw new Error('Error adding output. Script or address mismatch.'); } @@ -503,7 +502,6 @@ function isTapLeafInTree( }); const rootHash = rootHashFromPath(tapLeaf.controlBlock, leafHash); - // return rootHash.equals(merkleRoot); return tools.compare(rootHash, merkleRoot) === 0; } @@ -594,11 +592,9 @@ function canFinalizeLeaf( output: leaf.script, version: leaf.leafVersion, }); - // const whiteListedHash = !hash || hash.equals(leafHash); const whiteListedHash = !hash || tools.compare(leafHash, hash) === 0; return ( whiteListedHash && - // tapScriptSig!.find(tss => tss.leafHash.equals(leafHash)) !== undefined tapScriptSig!.find(tss => tools.compare(tss.leafHash, leafHash) === 0) !== undefined ); diff --git a/ts_src/psbt/psbtutils.ts b/ts_src/psbt/psbtutils.ts index 9ef3b65c1..298f4769c 100644 --- a/ts_src/psbt/psbtutils.ts +++ b/ts_src/psbt/psbtutils.ts @@ -39,7 +39,6 @@ export function witnessStackToScriptWitness(witness: Uint8Array[]): Uint8Array { let buffer = new Uint8Array(0); function writeSlice(slice: Uint8Array): void { - // buffer = Buffer.concat([buffer, Buffer.from(slice)]); buffer = tools.concat([buffer, slice]); } @@ -47,7 +46,6 @@ export function witnessStackToScriptWitness(witness: Uint8Array[]): Uint8Array { const currentLen = buffer.length; const varintLen = varuint.encodingLength(i); - // buffer = Buffer.concat([buffer, Buffer.allocUnsafe(varintLen)]); buffer = tools.concat([buffer, new Uint8Array(varintLen)]); varuint.encode(i, buffer, currentLen); } @@ -87,9 +85,6 @@ export function pubkeyPositionInScript( return decompiled.findIndex(element => { if (typeof element === 'number') return false; return ( - // element.equals(pubkey) || - // element.equals(pubkeyHash) || - // element.equals(pubkeyXOnly) tools.compare(pubkey, element) === 0 || tools.compare(pubkeyHash, element) === 0 || tools.compare(pubkeyXOnly, element) === 0 diff --git a/ts_src/push_data.ts b/ts_src/push_data.ts index 61e576c88..4c05d2038 100644 --- a/ts_src/push_data.ts +++ b/ts_src/push_data.ts @@ -29,26 +29,19 @@ export function encode( // ~6 bit if (size === 1) { - // buffer.writeUInt8(num, offset); tools.writeUInt8(buffer, offset, num); // 8 bit } else if (size === 2) { - // buffer.writeUInt8(OPS.OP_PUSHDATA1, offset); tools.writeUInt8(buffer, offset, OPS.OP_PUSHDATA1); - // buffer.writeUInt8(num, offset + 1); tools.writeUInt8(buffer, offset + 1, num); // 16 bit } else if (size === 3) { - // buffer.writeUInt8(OPS.OP_PUSHDATA2, offset); tools.writeUInt8(buffer, offset, OPS.OP_PUSHDATA2); - // buffer.writeUInt16LE(num, offset + 1); tools.writeUInt16(buffer, offset + 1, num, 'LE'); // 32 bit } else { - // buffer.writeUInt8(OPS.OP_PUSHDATA4, offset); tools.writeUInt8(buffer, offset, OPS.OP_PUSHDATA4); - // buffer.writeUInt32LE(num, offset + 1); tools.writeUInt32(buffer, offset + 1, num, 'LE'); } @@ -69,7 +62,6 @@ export function decode( number: number; size: number; } | null { - // const opcode = buffer.readUInt8(offset); const opcode = tools.readUInt8(buffer, offset); let num: number; let size: number; @@ -82,14 +74,12 @@ export function decode( // 8 bit } else if (opcode === OPS.OP_PUSHDATA1) { if (offset + 2 > buffer.length) return null; - // num = buffer.readUInt8(offset + 1); num = tools.readUInt8(buffer, offset + 1); size = 2; // 16 bit } else if (opcode === OPS.OP_PUSHDATA2) { if (offset + 3 > buffer.length) return null; - // num = buffer.readUInt16LE(offset + 1); num = tools.readUInt16(buffer, offset + 1, 'LE'); size = 3; @@ -98,7 +88,6 @@ export function decode( if (offset + 5 > buffer.length) return null; if (opcode !== OPS.OP_PUSHDATA4) throw new Error('Unexpected opcode'); - // num = buffer.readUInt32LE(offset + 1); num = tools.readUInt32(buffer, offset + 1, 'LE'); size = 5; } diff --git a/ts_src/script.ts b/ts_src/script.ts index c2a9c344b..a5e12b805 100644 --- a/ts_src/script.ts +++ b/ts_src/script.ts @@ -31,7 +31,6 @@ function isPushOnlyChunk(value: number | Uint8Array): boolean { } export function isPushOnly(value: Stack): boolean { - // return types.Array(value) && value.every(isPushOnlyChunk); return v.is( v.pipe(v.any(), v.everyItem(isPushOnlyChunk as (x: any) => boolean)), value, @@ -50,12 +49,10 @@ function asMinimalOP(buffer: Uint8Array): number | void { } function chunksIsBuffer(buf: Uint8Array | Stack): buf is Uint8Array { - // return Buffer.isBuffer(buf); return buf instanceof Uint8Array; } function chunksIsArray(buf: Uint8Array | Stack): buf is Stack { - // return types.Array(buf); return v.is(StackSchema, buf); } @@ -74,7 +71,6 @@ export function compile(chunks: Uint8Array | Stack): Uint8Array { // TODO: remove me if (chunksIsBuffer(chunks)) return chunks; - // typeforce(types.Array, chunks); v.parse(StackSchema, chunks); const bufferSize = chunks.reduce((accum: number, chunk) => { @@ -101,20 +97,17 @@ export function compile(chunks: Uint8Array | Stack): Uint8Array { // adhere to BIP62.3, minimal push policy const opcode = asMinimalOP(chunk); if (opcode !== undefined) { - // buffer.writeUInt8(opcode, offset); tools.writeUInt8(buffer, offset, opcode); offset += 1; return; } offset += pushdata.encode(buffer, chunk.length, offset); - // chunk.copy(buffer, offset); buffer.set(chunk, offset); offset += chunk.length; // opcode } else { - // buffer.writeUInt8(chunk, offset); tools.writeUInt8(buffer, offset, chunk); offset += 1; } @@ -130,7 +123,6 @@ export function decompile( // TODO: remove me if (chunksIsArray(buffer)) return buffer; - // typeforce(types.Buffer, buffer); v.parse(types.BufferSchema, buffer); const chunks: Array = []; @@ -206,18 +198,15 @@ export function toASM(chunks: Uint8Array | Array): string { * @returns The converted Buffer. */ export function fromASM(asm: string): Uint8Array { - // typeforce(types.String, asm); v.parse(v.string(), asm); return compile( asm.split(' ').map(chunkStr => { // opcode? if (OPS[chunkStr] !== undefined) return OPS[chunkStr]; - // typeforce(types.Hex, chunkStr); v.parse(types.HexSchema, chunkStr); // data! - // return Buffer.from(chunkStr, 'hex'); return tools.fromHex(chunkStr); }), ); @@ -233,7 +222,6 @@ export function toStack( chunks: Uint8Array | Array, ): Uint8Array[] { chunks = decompile(chunks) as Stack; - // typeforce(isPushOnly, chunks); v.parse(v.custom(isPushOnly as (x: any) => boolean), chunks); return chunks.map(op => { @@ -251,7 +239,6 @@ export function isCanonicalPubKey(buffer: Uint8Array): boolean { export function isDefinedHashType(hashType: number): boolean { const hashTypeMod = hashType & ~0x80; - // return hashTypeMod > SIGHASH_ALL && hashTypeMod < SIGHASH_SINGLE return hashTypeMod > 0x00 && hashTypeMod < 0x04; } diff --git a/ts_src/script_number.ts b/ts_src/script_number.ts index 1c574e335..7e4c8bbcb 100644 --- a/ts_src/script_number.ts +++ b/ts_src/script_number.ts @@ -30,8 +30,6 @@ export function decode( // 40-bit if (length === 5) { - // const a = buffer.readUInt32LE(0); - // const b = buffer.readUInt8(4); const a = tools.readUInt32(buffer, 0, 'LE'); const b = tools.readUInt8(buffer, 4); @@ -77,13 +75,11 @@ export function encode(_number: number): Uint8Array { const negative = _number < 0; for (let i = 0; i < size; ++i) { - // buffer.writeUInt8(value & 0xff, i); tools.writeUInt8(buffer, i, value & 0xff); value >>= 8; } if (buffer[size - 1] & 0x80) { - // buffer.writeUInt8(negative ? 0x80 : 0x00, size - 1); tools.writeUInt8(buffer, size - 1, negative ? 0x80 : 0x00); } else if (negative) { buffer[size - 1] |= 0x80; diff --git a/ts_src/script_signature.ts b/ts_src/script_signature.ts index c21b45c26..ba536b532 100644 --- a/ts_src/script_signature.ts +++ b/ts_src/script_signature.ts @@ -30,7 +30,6 @@ function fromDER(x: Uint8Array): Uint8Array { if (x[0] === 0x00) x = x.slice(1); const buffer = new Uint8Array(32); const bstart = Math.max(0, 32 - x.length); - // x.copy(buffer, bstart); buffer.set(x, bstart); return buffer; } @@ -48,7 +47,6 @@ interface ScriptSignature { * @throws Error if the hashType is invalid. */ export function decode(buffer: Uint8Array): ScriptSignature { - // const hashType = buffer.readUInt8(buffer.length - 1); const hashType = tools.readUInt8(buffer, buffer.length - 1); if (!isDefinedHashType(hashType)) { throw new Error('Invalid hashType ' + hashType); @@ -70,13 +68,6 @@ export function decode(buffer: Uint8Array): ScriptSignature { * @throws Error if the hashType is invalid. */ export function encode(signature: Uint8Array, hashType: number): Uint8Array { - // typeforce( - // { - // signature: types.BufferN(64), - // hashType: types.UInt8, - // }, - // { signature, hashType }, - // ); v.parse( v.object({ signature: NBufferSchemaFactory(64), @@ -89,14 +80,11 @@ export function encode(signature: Uint8Array, hashType: number): Uint8Array { throw new Error('Invalid hashType ' + hashType); } - // const hashTypeBuffer = Buffer.allocUnsafe(1); const hashTypeBuffer = new Uint8Array(1); - // hashTypeBuffer.writeUInt8(hashType, 0); tools.writeUInt8(hashTypeBuffer, 0, hashType); const r = toDER(signature.slice(0, 32)); const s = toDER(signature.slice(32, 64)); - // return Buffer.concat([bip66.encode(r, s), hashTypeBuffer]); return tools.concat([bip66.encode(r, s), hashTypeBuffer]); } diff --git a/ts_src/transaction.ts b/ts_src/transaction.ts index 7dcd045ef..d6e80955d 100644 --- a/ts_src/transaction.ts +++ b/ts_src/transaction.ts @@ -31,21 +31,12 @@ function vectorSize(someVector: Uint8Array[]): number { const EMPTY_BUFFER = new Uint8Array(0); const EMPTY_WITNESS: Uint8Array[] = []; -// const ZERO: Buffer = Buffer.from( -// '0000000000000000000000000000000000000000000000000000000000000000', -// 'hex', -// ); const ZERO = tools.fromHex( '0000000000000000000000000000000000000000000000000000000000000000', ); -// const ONE: Buffer = Buffer.from( -// '0000000000000000000000000000000000000000000000000000000000000001', -// 'hex', -// ); const ONE = tools.fromHex( '0000000000000000000000000000000000000000000000000000000000000001', ); -// const VALUE_UINT64_MAX: Buffer = Buffer.from('ffffffffffffffff', 'hex'); const VALUE_UINT64_MAX = tools.fromHex('ffffffffffffffff'); const BLANK_OUTPUT = { script: EMPTY_BUFFER, @@ -117,7 +108,7 @@ export class Transaction { const voutLen = bufferReader.readVarInt(); for (let i = 0; i < voutLen; ++i) { tx.outs.push({ - value: bufferReader.readUInt64(), + value: bufferReader.readInt64(), script: bufferReader.readVarSlice(), }); } @@ -146,7 +137,6 @@ export class Transaction { } static isCoinbaseHash(buffer: Uint8Array): boolean { - // typeforce(types.Hash256bit, buffer); v.parse(types.Hash256bitSchema, buffer); for (let i = 0; i < 32; ++i) { if (buffer[i] !== 0) return false; @@ -171,16 +161,6 @@ export class Transaction { sequence?: number, scriptSig?: Uint8Array, ): number { - // typeforce( - // types.tuple( - // types.Hash256bit, - // types.UInt32, - // types.maybe(types.UInt32), - // types.maybe(types.Buffer), - // ), - // arguments, - // ); - v.parse( v.tuple([ types.Hash256bitSchema, @@ -208,7 +188,6 @@ export class Transaction { } addOutput(scriptPubKey: Uint8Array, value: bigint): number { - // typeforce(types.tuple(types.Buffer, types.Satoshi), arguments); v.parse(v.tuple([types.BufferSchema, types.SatoshiSchema]), [ scriptPubKey, value, @@ -298,11 +277,6 @@ export class Transaction { prevOutScript: Uint8Array, hashType: number, ): Uint8Array { - // typeforce( - // types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), - // arguments, - // ); - v.parse(v.tuple([types.UInt32Schema, types.BufferSchema, v.number()]), [ inIndex, prevOutScript, @@ -369,8 +343,7 @@ export class Transaction { // serialize and hash const buffer = new Uint8Array(txTmp.byteLength(false) + 4); - // buffer.writeInt32LE(hashType, buffer.length - 4); - tools.writeInt32(buffer, hashType, buffer.length - 4, 'LE'); + tools.writeInt32(buffer, buffer.length - 4, hashType, 'LE'); txTmp.__toBuffer(buffer, 0, false); return bcrypto.hash256(buffer); @@ -385,16 +358,6 @@ export class Transaction { annex?: Uint8Array, ): Uint8Array { // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#common-signature-message - // typeforce( - // types.tuple( - // types.UInt32, - // typeforce.arrayOf(types.Buffer), - // typeforce.arrayOf(types.Satoshi), - // types.UInt32, - // ), - // arguments, - // ); - v.parse( v.tuple([ types.UInt32Schema, @@ -438,7 +401,7 @@ export class Transaction { hashPrevouts = sha256(bufferWriter.end()); bufferWriter = BufferWriter.withCapacity(8 * this.ins.length); - values.forEach(value => bufferWriter.writeUInt64(value)); + values.forEach(value => bufferWriter.writeInt64(value)); hashAmounts = sha256(bufferWriter.end()); bufferWriter = BufferWriter.withCapacity( @@ -463,7 +426,6 @@ export class Transaction { const bufferWriter = BufferWriter.withCapacity(txOutsSize); this.outs.forEach(out => { - // bufferWriter.writeUInt64(out.value); bufferWriter.writeInt64(out.value); bufferWriter.writeVarSlice(out.script); }); @@ -475,7 +437,7 @@ export class Transaction { const bufferWriter = BufferWriter.withCapacity( 8 + varSliceSize(output.script), ); - bufferWriter.writeUInt64(output.value); + bufferWriter.writeInt64(output.value); bufferWriter.writeVarSlice(output.script); hashOutputs = sha256(bufferWriter.end()); } @@ -511,7 +473,7 @@ export class Transaction { const input = this.ins[inIndex]; sigMsgWriter.writeSlice(input.hash); sigMsgWriter.writeUInt32(input.index); - sigMsgWriter.writeUInt64(values[inIndex]); + sigMsgWriter.writeInt64(values[inIndex]); sigMsgWriter.writeVarSlice(prevOutScripts[inIndex]); sigMsgWriter.writeUInt32(input.sequence); } else { @@ -547,11 +509,6 @@ export class Transaction { value: bigint, hashType: number, ): Uint8Array { - // typeforce( - // types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), - // arguments, - // ); - v.parse( v.tuple([ types.UInt32Schema, @@ -608,7 +565,7 @@ export class Transaction { bufferWriter = new BufferWriter(tbuffer, 0); this.outs.forEach(out => { - bufferWriter.writeUInt64(out.value); + bufferWriter.writeInt64(out.value); bufferWriter.writeVarSlice(out.script); }); @@ -621,7 +578,7 @@ export class Transaction { tbuffer = new Uint8Array(8 + varSliceSize(output.script)); bufferWriter = new BufferWriter(tbuffer, 0); - bufferWriter.writeUInt64(output.value); + bufferWriter.writeInt64(output.value); bufferWriter.writeVarSlice(output.script); hashOutputs = bcrypto.hash256(tbuffer); @@ -637,7 +594,7 @@ export class Transaction { bufferWriter.writeSlice(input.hash); bufferWriter.writeUInt32(input.index); bufferWriter.writeVarSlice(prevOutScript); - bufferWriter.writeUInt64(value); + bufferWriter.writeInt64(value); bufferWriter.writeUInt32(input.sequence); bufferWriter.writeSlice(hashOutputs); bufferWriter.writeUInt32(this.locktime); @@ -665,14 +622,12 @@ export class Transaction { } setInputScript(index: number, scriptSig: Uint8Array): void { - // typeforce(types.tuple(types.Number, types.Buffer), arguments); v.parse(v.tuple([v.number(), types.BufferSchema]), [index, scriptSig]); this.ins[index].script = scriptSig; } setWitness(index: number, witness: Uint8Array[]): void { - // typeforce(types.tuple(types.Number, [types.Buffer]), arguments); v.parse(v.tuple([v.number(), v.array(types.BufferSchema)]), [ index, witness, @@ -712,7 +667,7 @@ export class Transaction { bufferWriter.writeVarInt(this.outs.length); this.outs.forEach(txOut => { if (isOutput(txOut)) { - bufferWriter.writeUInt64(txOut.value); + bufferWriter.writeInt64(txOut.value); } else { bufferWriter.writeSlice((txOut as any).valueBuffer); } diff --git a/ts_src/types.ts b/ts_src/types.ts index cfea43c27..975f408c8 100644 --- a/ts_src/types.ts +++ b/ts_src/types.ts @@ -1,8 +1,6 @@ import * as tools from 'uint8array-tools'; import * as v from 'valibot'; -// export const typeforce = require('typeforce'); - const ZERO32 = new Uint8Array(32); const EC_P = tools.fromHex( 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', @@ -21,7 +19,6 @@ export function stacksEqual(a: Uint8Array[], b: Uint8Array[]): boolean { if (a.length !== b.length) return false; return a.every((x, i) => { - // return x.equals(b[i]); return tools.compare(x, b[i]) === 0; }); } @@ -37,18 +34,14 @@ export function isPoint(p: Uint8Array | number | undefined | null): boolean { const t = p[0]; const x = p.slice(1, 33); - // if (x.compare(ZERO32) === 0) return false; if (tools.compare(ZERO32, x) === 0) return false; - // if (x.compare(EC_P) >= 0) return false; if (tools.compare(x, 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 (tools.compare(ZERO32, y) === 0) return false; - // if (y.compare(EC_P) >= 0) return false; if (tools.compare(y, EC_P) >= 0) return false; if (t === 0x04 && p.length === 65) return true; return false; @@ -97,10 +90,6 @@ export interface TinySecp256k1Interface { export const Buffer256bitSchema = NBufferSchemaFactory(32); export const Hash160bitSchema = NBufferSchemaFactory(20); export const Hash256bitSchema = NBufferSchemaFactory(32); -// export const Number = typeforce.Number; -// export const Array = typeforce.Array; -// export const Boolean = typeforce.Boolean; -// export const String = typeforce.String; export const BufferSchema = v.instance(Uint8Array); export const HexSchema = v.pipe(v.string(), v.regex(/^([0-9a-f]{2})+$/i)); export const UInt8Schema = v.pipe( From fc415aa3e8132574d1fa7c37397a4ce44abfe91c Mon Sep 17 00:00:00 2001 From: ayman Date: Wed, 4 Sep 2024 19:44:36 +0530 Subject: [PATCH 5/6] chore: link packages through git --- package-lock.json | 346 ++++++++++++++++---------------------- package.json | 11 +- test/bitcoin.core.spec.ts | 2 +- ts_src/address.ts | 2 +- 4 files changed, 148 insertions(+), 213 deletions(-) diff --git a/package-lock.json b/package-lock.json index 139019263..1a43dc934 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,9 +13,9 @@ "bech32": "^2.0.0", "bip174": "git://github.com/bitcoinjs/bip174.git#a475ce6bc50879448b054c3fe6a0d30ae1151b67", "bs58check": "^4.0.0", - "uint8array-tools": "../uint8array-tools", + "uint8array-tools": "^0.0.9", "valibot": "^0.38.0", - "varuint-bitcoin": "../varuint-bitcoin" + "varuint-bitcoin": "^2.0.0" }, "devDependencies": { "@eslint/eslintrc": "^3.1.0", @@ -29,15 +29,15 @@ "@typescript-eslint/eslint-plugin": "^8.2.0", "@typescript-eslint/parser": "^8.2.0", "better-npm-audit": "^3.7.3", - "bip32": "../bip32", + "bip32": "git://github.com/bitcoinjs/bip32.git#d220114b237aefc1965b53ae305cca063a46d3b9", "bip39": "^3.1.0", "bip65": "^1.0.1", "bip68": "^1.0.3", "bitcoinjs-lib": ".", - "bs58": "^4.0.0", + "bs58": "^6.0.0", "c8": "^10.1.2", "dhttp": "^3.0.0", - "ecpair": "../ecpair", + "ecpair": "git://github.com/bitcoinjs/ecpair.git#0c8666fba4b1d626aa5a0ff81f88005ea1dee3b2", "eslint": "^9.9.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.2.1", @@ -51,7 +51,6 @@ "regtest-client": "0.2.0", "rimraf": "^2.6.3", "tiny-secp256k1": "^2.2.0", - "ts-node": "^8.3.0", "tsx": "^4.17.0", "typedoc": "^0.26.6", "typescript": "^5.0.4" @@ -60,93 +59,6 @@ "node": ">=18.0.0" } }, - "../bip32": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "^1.2.0", - "@scure/base": "^1.1.1", - "uint8array-tools": "^0.0.8", - "valibot": "^0.37.0", - "wif": "^5.0.0" - }, - "devDependencies": { - "@types/node": "18.x", - "@types/tape": "^5.6.4", - "c8": "^10.1.2", - "prettier": "1.16.4", - "tape": "^5.3.0", - "tiny-secp256k1": "^2.2.1", - "tslint": "^6.1.0", - "typescript": "^5.0.4" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "../ecpair": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "uint8array-tools": "^0.0.8", - "valibot": "^0.37.0", - "wif": "^5.0.0" - }, - "devDependencies": { - "@types/create-hash": "^1.2.2", - "@types/mocha": "^5.2.7", - "@types/node": "^20.14.2", - "@types/wif": "^2.0.2", - "c8": "^10.1.2", - "mocha": "^10.7.3", - "prettier": "^3.3.3", - "rimraf": "^2.6.3", - "tiny-secp256k1": "^2.2.3", - "tslint": "^6.1.3", - "tsx": "^4.16.5", - "typescript": "^5.0.4" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "../uint8array-tools": { - "version": "0.0.9", - "license": "MIT", - "devDependencies": { - "@types/jest": "27.0.2", - "@types/node": "16.11.1", - "@typescript-eslint/eslint-plugin": "5.0.0", - "@typescript-eslint/parser": "5.0.0", - "eslint": "8.0.1", - "eslint-config-prettier": "8.3.0", - "eslint-plugin-prettier": "4.0.0", - "jest": "27.2.5", - "prettier": "2.4.1", - "ts-jest": "27.0.7", - "typescript": "4.4.4" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "../varuint-bitcoin": { - "version": "2.0.0", - "license": "MIT", - "dependencies": { - "uint8array-tools": "^0.0.8" - }, - "devDependencies": { - "@types/node": "^20.14.8", - "c8": "^10.1.2", - "rimraf": "^5.0.7", - "tape": "^5.3.0", - "ts-standard": "^12.0.2", - "typescript": "^5.1.6" - } - }, "node_modules/@bcoe/v8-coverage": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", @@ -852,6 +764,15 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/@scure/base": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.8.tgz", + "integrity": "sha512-6CyAclxj3Nb0XT7GHK6K4zK6k2xJm6E4Ft0Ohjt4WgegiFUHEtFb2CGzmPmGBwoIhrLsqNLYfLr04Y1GePrzZg==", + "dev": true, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@shikijs/core": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.16.1.tgz", @@ -909,9 +830,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.19.48", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.48.tgz", - "integrity": "sha512-7WevbG4ekUcRQSZzOwxWgi5dZmTak7FaxXDoW7xVxPBmKx1rTzfmRLkeCgJzcbBnOV2dkhAPc8cCeT6agocpjg==", + "version": "18.19.49", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.49.tgz", + "integrity": "sha512-ALCeIR6n0nQ7j0FUF1ycOhrp6+XutJWqEu/vtdEqXFUQwkBfgUA5cEg3ZNmjWGF/ZYA/FcF9QMkL55Ar0O6UrA==", "dev": true, "dependencies": { "undici-types": "~5.26.4" @@ -1227,12 +1148,6 @@ "node": ">= 8" } }, - "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", @@ -1313,8 +1228,44 @@ } }, "node_modules/bip32": { - "resolved": "../bip32", - "link": true + "version": "4.0.0", + "resolved": "git+ssh://git@github.com/bitcoinjs/bip32.git#d220114b237aefc1965b53ae305cca063a46d3b9", + "integrity": "sha512-NTSJbOpWrAPAeUuCm0Wd6BKBQAH/gEcVzP+jUMbjKXYTE5S43TvujJuXglLi5wYbGnCgl9aw1sAqWg0FMDDtdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.2.0", + "@scure/base": "^1.1.1", + "uint8array-tools": "^0.0.8", + "valibot": "^0.37.0", + "wif": "^5.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/bip32/node_modules/uint8array-tools": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.8.tgz", + "integrity": "sha512-xS6+s8e0Xbx++5/0L+yyexukU7pz//Yg6IHg3BKhXotg1JcYtgxVcUctQ0HxLByiJzpAkNFawz1Nz5Xadzo82g==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/bip32/node_modules/valibot": { + "version": "0.37.0", + "resolved": "https://registry.npmjs.org/valibot/-/valibot-0.37.0.tgz", + "integrity": "sha512-FQz52I8RXgFgOHym3XHYSREbNtkgSjF9prvMFH1nBsRyfL6SfCzoT1GuSDTlbsuPubM7/6Kbw0ZMQb8A+V+VsQ==", + "dev": true, + "peerDependencies": { + "typescript": ">=5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } }, "node_modules/bip39": { "version": "3.1.0", @@ -1382,14 +1333,18 @@ "dev": true }, "node_modules/bs58": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", - "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", - "dev": true, + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-6.0.0.tgz", + "integrity": "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==", "dependencies": { - "base-x": "^3.0.2" + "base-x": "^5.0.0" } }, + "node_modules/bs58/node_modules/base-x": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.0.tgz", + "integrity": "sha512-sMW3VGSX1QWVFA6l8U62MLKz29rRfpTlYdCqLdpLo1/Yd4zZwSbnUaDfciIAowAqvq7YFnWq9hrhdg1KYgc1lQ==" + }, "node_modules/bs58check": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-4.0.0.tgz", @@ -1399,25 +1354,6 @@ "bs58": "^6.0.0" } }, - "node_modules/bs58check/node_modules/base-x": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.0.tgz", - "integrity": "sha512-sMW3VGSX1QWVFA6l8U62MLKz29rRfpTlYdCqLdpLo1/Yd4zZwSbnUaDfciIAowAqvq7YFnWq9hrhdg1KYgc1lQ==" - }, - "node_modules/bs58check/node_modules/bs58": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-6.0.0.tgz", - "integrity": "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==", - "dependencies": { - "base-x": "^5.0.0" - } - }, - "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/c8": { "version": "10.1.2", "resolved": "https://registry.npmjs.org/c8/-/c8-10.1.2.tgz", @@ -1681,8 +1617,42 @@ "dev": true }, "node_modules/ecpair": { - "resolved": "../ecpair", - "link": true + "version": "2.1.0", + "resolved": "git+ssh://git@github.com/bitcoinjs/ecpair.git#0c8666fba4b1d626aa5a0ff81f88005ea1dee3b2", + "integrity": "sha512-csseCIpfrjlZhlAI1yDbOJ0abMTyIj2FZWVrQY1J78nksqxmUPFLaXeaeeRQ5UzKpP6QuAb5w+Nzlenp5V3o7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "uint8array-tools": "^0.0.8", + "valibot": "^0.37.0", + "wif": "^5.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/ecpair/node_modules/uint8array-tools": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.8.tgz", + "integrity": "sha512-xS6+s8e0Xbx++5/0L+yyexukU7pz//Yg6IHg3BKhXotg1JcYtgxVcUctQ0HxLByiJzpAkNFawz1Nz5Xadzo82g==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/ecpair/node_modules/valibot": { + "version": "0.37.0", + "resolved": "https://registry.npmjs.org/valibot/-/valibot-0.37.0.tgz", + "integrity": "sha512-FQz52I8RXgFgOHym3XHYSREbNtkgSjF9prvMFH1nBsRyfL6SfCzoT1GuSDTlbsuPubM7/6Kbw0ZMQb8A+V+VsQ==", + "dev": true, + "peerDependencies": { + "typescript": ">=5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -2665,12 +2635,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "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/markdown-it": { "version": "14.1.0", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", @@ -3184,6 +3148,15 @@ "randombytes": "^2.1.0" } }, + "node_modules/regtest-client/node_modules/bs58": { + "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" + } + }, "node_modules/regtest-client/node_modules/bs58check": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", @@ -3440,25 +3413,6 @@ "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/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -3730,40 +3684,6 @@ "typescript": ">=4.2.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": "2.7.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", @@ -3867,8 +3787,12 @@ "dev": true }, "node_modules/uint8array-tools": { - "resolved": "../uint8array-tools", - "link": true + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.9.tgz", + "integrity": "sha512-9vqDWmoSXOoi+K14zNaf6LBV51Q8MayF0/IiQs3GlygIKUYtog603e6virExkjjFosfJUBI4LhbQK1iq8IG11A==", + "engines": { + "node": ">=14.0.0" + } }, "node_modules/undici-types": { "version": "5.26.5", @@ -3919,8 +3843,20 @@ } }, "node_modules/varuint-bitcoin": { - "resolved": "../varuint-bitcoin", - "link": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/varuint-bitcoin/-/varuint-bitcoin-2.0.0.tgz", + "integrity": "sha512-6QZbU/rHO2ZQYpWFDALCDSRsXbAs1VOEmXAxtbtjLtKuMJ/FQ8YbhfxlaiKv5nklci0M6lZtlZyxo9Q+qNnyog==", + "dependencies": { + "uint8array-tools": "^0.0.8" + } + }, + "node_modules/varuint-bitcoin/node_modules/uint8array-tools": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.8.tgz", + "integrity": "sha512-xS6+s8e0Xbx++5/0L+yyexukU7pz//Yg6IHg3BKhXotg1JcYtgxVcUctQ0HxLByiJzpAkNFawz1Nz5Xadzo82g==", + "engines": { + "node": ">=14.0.0" + } }, "node_modules/which": { "version": "2.0.2", @@ -3937,6 +3873,15 @@ "node": ">= 8" } }, + "node_modules/wif": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/wif/-/wif-5.0.0.tgz", + "integrity": "sha512-iFzrC/9ne740qFbNjTZ2FciSRJlHIXoxqk/Y5EnE08QOXu1WjJyCCswwDTYbohAOEnlCtLaAAQBhyaLRFh2hMA==", + "dev": true, + "dependencies": { + "bs58check": "^4.0.0" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -4003,9 +3948,9 @@ } }, "node_modules/yaml": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz", - "integrity": "sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz", + "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==", "dev": true, "bin": { "yaml": "bin.mjs" @@ -4056,15 +4001,6 @@ "node": ">=10" } }, - "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", diff --git a/package.json b/package.json index 36594ccae..9497182d5 100644 --- a/package.json +++ b/package.json @@ -67,9 +67,9 @@ "bech32": "^2.0.0", "bip174": "git://github.com/bitcoinjs/bip174.git#a475ce6bc50879448b054c3fe6a0d30ae1151b67", "bs58check": "^4.0.0", - "uint8array-tools": "../uint8array-tools", + "uint8array-tools": "^0.0.9", "valibot": "^0.38.0", - "varuint-bitcoin": "../varuint-bitcoin" + "varuint-bitcoin": "^2.0.0" }, "devDependencies": { "bitcoinjs-lib": ".", @@ -84,13 +84,13 @@ "@typescript-eslint/eslint-plugin": "^8.2.0", "@typescript-eslint/parser": "^8.2.0", "better-npm-audit": "^3.7.3", - "bip32": "../bip32", + "bip32": "git://github.com/bitcoinjs/bip32.git#d220114b237aefc1965b53ae305cca063a46d3b9", "bip39": "^3.1.0", "bip65": "^1.0.1", "bip68": "^1.0.3", - "bs58": "^4.0.0", + "bs58": "^6.0.0", "dhttp": "^3.0.0", - "ecpair": "../ecpair", + "ecpair": "git://github.com/bitcoinjs/ecpair.git#0c8666fba4b1d626aa5a0ff81f88005ea1dee3b2", "eslint": "^9.9.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.2.1", @@ -105,7 +105,6 @@ "regtest-client": "0.2.0", "rimraf": "^2.6.3", "tiny-secp256k1": "^2.2.0", - "ts-node": "^8.3.0", "tsx": "^4.17.0", "typedoc": "^0.26.6", "typescript": "^5.0.4" diff --git a/test/bitcoin.core.spec.ts b/test/bitcoin.core.spec.ts index 1a8b7d659..1c1b50787 100644 --- a/test/bitcoin.core.spec.ts +++ b/test/bitcoin.core.spec.ts @@ -21,7 +21,7 @@ describe('Bitcoin-core', () => { it('can decode ' + fb58, () => { const buffer = base58.decode(fb58); - const actual = buffer.toString('hex'); + const actual = tools.toHex(buffer); assert.strictEqual(actual, fhex); }); diff --git a/ts_src/address.ts b/ts_src/address.ts index 51acdaba6..907574953 100644 --- a/ts_src/address.ts +++ b/ts_src/address.ts @@ -46,7 +46,7 @@ const FUTURE_SEGWIT_VERSION_WARNING: string = 'with caution. Wallets should verify the segwit version from the output of fromBech32, ' + 'then decide when it is safe to use which version of segwit.'; - /** +/** * Converts an output buffer to a future segwit address. * @param output - The output buffer. * @param network - The network object. From 240be2f0da6dfb9f3884a73eedc7cafad22aba21 Mon Sep 17 00:00:00 2001 From: ayman Date: Wed, 4 Sep 2024 21:23:10 +0530 Subject: [PATCH 6/6] fix: tests for nodev18 --- package-lock.json | 6 +++--- test/integration/addresses.spec.ts | 9 ++++++--- test/integration/payments.spec.ts | 7 +++++-- test/integration/transactions.spec.ts | 6 +++--- test/psbt.spec.ts | 6 ++++-- 5 files changed, 21 insertions(+), 13 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1a43dc934..500747e31 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1217,7 +1217,7 @@ "node_modules/bip174": { "version": "2.1.1", "resolved": "git+ssh://git@github.com/bitcoinjs/bip174.git#a475ce6bc50879448b054c3fe6a0d30ae1151b67", - "integrity": "sha512-nJq4YcTyTakoFrWJnDfn1+d8TodI9CTl39BHKncErdaQDmMemA1tsfv6k7lCj23SjfGxHe+9/+OBhPnH7apPVA==", + "integrity": "sha512-C7LLdoGN2Vc7548LBiFvz5LfBaRhj9ySMKQ3SsZPGC+Y1dGRRWMYvRBoEYUu4C4voEwtSxIp+cjG0ZkfAm4PyQ==", "license": "MIT", "dependencies": { "uint8array-tools": "^0.0.9", @@ -1230,7 +1230,7 @@ "node_modules/bip32": { "version": "4.0.0", "resolved": "git+ssh://git@github.com/bitcoinjs/bip32.git#d220114b237aefc1965b53ae305cca063a46d3b9", - "integrity": "sha512-NTSJbOpWrAPAeUuCm0Wd6BKBQAH/gEcVzP+jUMbjKXYTE5S43TvujJuXglLi5wYbGnCgl9aw1sAqWg0FMDDtdQ==", + "integrity": "sha512-Z8bzD4skSv2KfyjM/4K3yDDGsBP0v/mVkcTtE9o4gFaQCGIphBvpXbyyZnN8ByA+12aBjvZHO+I+4xVZ2g1TLQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1619,7 +1619,7 @@ "node_modules/ecpair": { "version": "2.1.0", "resolved": "git+ssh://git@github.com/bitcoinjs/ecpair.git#0c8666fba4b1d626aa5a0ff81f88005ea1dee3b2", - "integrity": "sha512-csseCIpfrjlZhlAI1yDbOJ0abMTyIj2FZWVrQY1J78nksqxmUPFLaXeaeeRQ5UzKpP6QuAb5w+Nzlenp5V3o7w==", + "integrity": "sha512-aBwXHe8kjGjgniLVg8f3WBrBK/uBLmSMIR/nDKpQ4lv5cbm8ix2dta6rQeyXh/wKwFl/im/74eHLJaIA53AqJg==", "dev": true, "license": "MIT", "dependencies": { diff --git a/test/integration/addresses.spec.ts b/test/integration/addresses.spec.ts index 0051fd2b0..0b234c473 100644 --- a/test/integration/addresses.spec.ts +++ b/test/integration/addresses.spec.ts @@ -4,17 +4,20 @@ import * as ecc from 'tiny-secp256k1'; import { describe, it } from 'mocha'; import * as bitcoin from 'bitcoinjs-lib'; import { regtestUtils } from './_regtest.js'; +import { randomBytes } from 'crypto'; const ECPair = ECPairFactory(ecc); const dhttp = regtestUtils.dhttp; const TESTNET = bitcoin.networks.testnet; +const rng = (size: number) => randomBytes(size); + describe('bitcoinjs-lib (addresses)', () => { it( 'can generate a random address [and support the retrieval of ' + 'transactions for that address (via 3PBP)]', async () => { - const keyPair = ECPair.makeRandom(); + const keyPair = ECPair.makeRandom({ rng }); const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey }); // bitcoin P2PKH addresses start with a '1' @@ -107,7 +110,7 @@ describe('bitcoinjs-lib (addresses)', () => { // examples using other network information it('can generate a Testnet address', () => { - const keyPair = ECPair.makeRandom({ network: TESTNET }); + const keyPair = ECPair.makeRandom({ network: TESTNET, rng }); const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey, network: TESTNET, @@ -134,7 +137,7 @@ describe('bitcoinjs-lib (addresses)', () => { wif: 0xb0, }; - const keyPair = ECPair.makeRandom({ network: LITECOIN }); + const keyPair = ECPair.makeRandom({ network: LITECOIN, rng }); const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey, network: LITECOIN, diff --git a/test/integration/payments.spec.ts b/test/integration/payments.spec.ts index fd09dbc27..c0b2f4a24 100644 --- a/test/integration/payments.spec.ts +++ b/test/integration/payments.spec.ts @@ -3,12 +3,15 @@ import * as ecc from 'tiny-secp256k1'; import { describe, it } from 'mocha'; import * as bitcoin from 'bitcoinjs-lib'; import { regtestUtils } from './_regtest.js'; +import { randomBytes } from 'crypto'; import p2msFixtures from '../fixtures/p2ms.json'; import p2pkFixtures from '../fixtures/p2pk.json'; import p2pkhFixtures from '../fixtures/p2pkh.json'; import p2wpkhFixtures from '../fixtures/p2wpkh.json'; +const rng = (size: number) => randomBytes(size); + const testSuite = [ { paymentName: 'p2ms', @@ -31,8 +34,8 @@ const testSuite = [ const ECPair = ECPairFactory(ecc); const NETWORK = regtestUtils.network; const keyPairs = [ - ECPair.makeRandom({ network: NETWORK }), - ECPair.makeRandom({ network: NETWORK }), + ECPair.makeRandom({ network: NETWORK, rng }), + ECPair.makeRandom({ network: NETWORK, rng }), ]; async function buildAndSign( diff --git a/test/integration/transactions.spec.ts b/test/integration/transactions.spec.ts index 0f5580784..994af186b 100644 --- a/test/integration/transactions.spec.ts +++ b/test/integration/transactions.spec.ts @@ -543,7 +543,7 @@ describe('bitcoinjs-lib (transactions with psbt)', () => { 'can create (and broadcast via 3PBP) a Transaction, w/ a ' + 'P2SH(P2MS(2 of 2)) input with nonWitnessUtxo', async () => { - const myKey = ECPair.makeRandom({ network: regtest }); + const myKey = ECPair.makeRandom({ network: regtest, rng }); const myKeys = [ myKey, ECPair.fromPrivateKey(myKey.privateKey!, { network: regtest }), @@ -647,11 +647,11 @@ function createPayment(_type: string, myKeys?: any[], network?: any): any { throw new Error('Need n keys for multisig'); } while (!myKeys && n > 1) { - keys.push(ECPair.makeRandom({ network })); + keys.push(ECPair.makeRandom({ network, rng })); n--; } } - if (!myKeys) keys.push(ECPair.makeRandom({ network })); + if (!myKeys) keys.push(ECPair.makeRandom({ network, rng })); let payment: any; splitType.forEach(type => { diff --git a/test/psbt.spec.ts b/test/psbt.spec.ts index eddcd44b0..410c3ed7d 100644 --- a/test/psbt.spec.ts +++ b/test/psbt.spec.ts @@ -12,6 +12,8 @@ import type { Taptree } from 'bitcoinjs-lib/src/types'; import { initEccLib } from 'bitcoinjs-lib'; import * as tools from 'uint8array-tools'; +const rng = (size: number) => crypto.randomBytes(size); + const bip32 = BIP32Factory.BIP32Factory(ecc); const ECPair = ECPairFactory(ecc); @@ -134,7 +136,7 @@ describe(`Psbt`, () => { }); fixtures.bip174.failSignChecks.forEach(f => { - const keyPair = ECPair.makeRandom(); + const keyPair = ECPair.makeRandom({ rng }); it(`Fails Signer checks: ${f.description}`, () => { const psbt = Psbt.fromBase64(f.psbt); assert.throws(() => { @@ -720,7 +722,7 @@ describe(`Psbt`, () => { }); describe('getInputType', () => { - const key = ECPair.makeRandom(); + const key = ECPair.makeRandom({ rng }); const { publicKey } = key; const p2wpkhPub = (pubkey: Uint8Array): Uint8Array => payments.p2wpkh({