@btc-vision/bitcoin 7.0.0-beta.0 → 7.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/README.md +112 -13
  2. package/benchmark-compare/BENCHMARK.md +74 -59
  3. package/benchmark-compare/compare.bench.ts +249 -96
  4. package/benchmark-compare/harness.ts +23 -25
  5. package/benchmark-compare/package.json +1 -0
  6. package/browser/address.d.ts +4 -4
  7. package/browser/address.d.ts.map +1 -1
  8. package/browser/chunks/{psbt-parallel-B-dfm5GZ.js → psbt-parallel-jZ6QcCnM.js} +3128 -2731
  9. package/browser/index.d.ts +1 -1
  10. package/browser/index.d.ts.map +1 -1
  11. package/browser/index.js +603 -585
  12. package/browser/io/base58check.d.ts +1 -25
  13. package/browser/io/base58check.d.ts.map +1 -1
  14. package/browser/io/base64.d.ts.map +1 -1
  15. package/browser/networks.d.ts +1 -0
  16. package/browser/networks.d.ts.map +1 -1
  17. package/browser/payments/bip341.d.ts +17 -0
  18. package/browser/payments/bip341.d.ts.map +1 -1
  19. package/browser/payments/index.d.ts +3 -2
  20. package/browser/payments/index.d.ts.map +1 -1
  21. package/browser/payments/p2mr.d.ts +169 -0
  22. package/browser/payments/p2mr.d.ts.map +1 -0
  23. package/browser/payments/types.d.ts +11 -1
  24. package/browser/payments/types.d.ts.map +1 -1
  25. package/browser/psbt/bip371.d.ts +30 -0
  26. package/browser/psbt/bip371.d.ts.map +1 -1
  27. package/browser/psbt/psbtutils.d.ts +1 -0
  28. package/browser/psbt/psbtutils.d.ts.map +1 -1
  29. package/browser/psbt.d.ts.map +1 -1
  30. package/browser/workers/index.js +9 -9
  31. package/build/address.d.ts +4 -4
  32. package/build/address.d.ts.map +1 -1
  33. package/build/address.js +11 -1
  34. package/build/address.js.map +1 -1
  35. package/build/index.d.ts +1 -1
  36. package/build/index.d.ts.map +1 -1
  37. package/build/index.js.map +1 -1
  38. package/build/io/base58check.d.ts +1 -25
  39. package/build/io/base58check.d.ts.map +1 -1
  40. package/build/io/base58check.js +1 -31
  41. package/build/io/base58check.js.map +1 -1
  42. package/build/io/base64.d.ts.map +1 -1
  43. package/build/io/base64.js +3 -0
  44. package/build/io/base64.js.map +1 -1
  45. package/build/networks.d.ts +1 -0
  46. package/build/networks.d.ts.map +1 -1
  47. package/build/networks.js +12 -0
  48. package/build/networks.js.map +1 -1
  49. package/build/payments/bip341.d.ts +17 -0
  50. package/build/payments/bip341.d.ts.map +1 -1
  51. package/build/payments/bip341.js +32 -1
  52. package/build/payments/bip341.js.map +1 -1
  53. package/build/payments/index.d.ts +3 -2
  54. package/build/payments/index.d.ts.map +1 -1
  55. package/build/payments/index.js +2 -1
  56. package/build/payments/index.js.map +1 -1
  57. package/build/payments/p2mr.d.ts +178 -0
  58. package/build/payments/p2mr.d.ts.map +1 -0
  59. package/build/payments/p2mr.js +555 -0
  60. package/build/payments/p2mr.js.map +1 -0
  61. package/build/payments/types.d.ts +11 -1
  62. package/build/payments/types.d.ts.map +1 -1
  63. package/build/payments/types.js +1 -0
  64. package/build/payments/types.js.map +1 -1
  65. package/build/psbt/bip371.d.ts +30 -0
  66. package/build/psbt/bip371.d.ts.map +1 -1
  67. package/build/psbt/bip371.js +80 -15
  68. package/build/psbt/bip371.js.map +1 -1
  69. package/build/psbt/psbtutils.d.ts +1 -0
  70. package/build/psbt/psbtutils.d.ts.map +1 -1
  71. package/build/psbt/psbtutils.js +2 -0
  72. package/build/psbt/psbtutils.js.map +1 -1
  73. package/build/psbt.d.ts.map +1 -1
  74. package/build/psbt.js +3 -2
  75. package/build/psbt.js.map +1 -1
  76. package/build/pubkey.js +1 -1
  77. package/build/pubkey.js.map +1 -1
  78. package/build/tsconfig.build.tsbuildinfo +1 -1
  79. package/documentation/README.md +122 -0
  80. package/documentation/address.md +820 -0
  81. package/documentation/block.md +679 -0
  82. package/documentation/crypto.md +461 -0
  83. package/documentation/ecc.md +584 -0
  84. package/documentation/errors.md +656 -0
  85. package/documentation/io.md +942 -0
  86. package/documentation/networks.md +625 -0
  87. package/documentation/p2mr.md +380 -0
  88. package/documentation/payments.md +1485 -0
  89. package/documentation/psbt.md +1400 -0
  90. package/documentation/script.md +730 -0
  91. package/documentation/taproot.md +670 -0
  92. package/documentation/transaction.md +943 -0
  93. package/documentation/types.md +587 -0
  94. package/documentation/workers.md +1007 -0
  95. package/eslint.config.js +3 -0
  96. package/package.json +17 -14
  97. package/src/address.ts +22 -10
  98. package/src/index.ts +1 -0
  99. package/src/io/base58check.ts +1 -35
  100. package/src/io/base64.ts +5 -0
  101. package/src/networks.ts +13 -0
  102. package/src/payments/bip341.ts +36 -1
  103. package/src/payments/index.ts +4 -0
  104. package/src/payments/p2mr.ts +660 -0
  105. package/src/payments/types.ts +12 -0
  106. package/src/psbt/bip371.ts +84 -13
  107. package/src/psbt/psbtutils.ts +2 -0
  108. package/src/psbt.ts +4 -2
  109. package/src/pubkey.ts +1 -1
  110. package/test/bitcoin.core.spec.ts +1 -1
  111. package/test/fixtures/p2mr.json +270 -0
  112. package/test/integration/taproot.spec.ts +7 -3
  113. package/test/opnetTestnet.spec.ts +302 -0
  114. package/test/payments.spec.ts +3 -1
  115. package/test/psbt.spec.ts +297 -2
  116. package/test/tsconfig.json +2 -2
@@ -11,6 +11,7 @@ import {
11
11
  LEAF_VERSION_TAPSCRIPT,
12
12
  MAX_TAPTREE_DEPTH,
13
13
  rootHashFromPath,
14
+ rootHashFromPathP2MR,
14
15
  tapleafHash,
15
16
  tweakKey,
16
17
  } from '../payments/bip341.js';
@@ -20,6 +21,7 @@ import type { Bytes32, Tapleaf, Taptree, XOnlyPublicKey } from '../types.js';
20
21
  import { isTapleaf, isTaptree } from '../types.js';
21
22
  import { concat, equals } from '../io/index.js';
22
23
  import {
24
+ isP2MR,
23
25
  isP2TR,
24
26
  pubkeyPositionInScript,
25
27
  signatureBlocksAction,
@@ -55,16 +57,31 @@ export function tapScriptFinalizer(
55
57
  .concat(new Uint8Array(tapLeaf.controlBlock));
56
58
  return { finalScriptWitness: witnessStackToScriptWitness(witness) };
57
59
  } catch (err) {
58
- throw new Error(`Can not finalize taproot input #${inputIndex}: ${err}`);
60
+ throw new Error(`Can not finalize taproot input #${inputIndex}: ${err}`, { cause: err });
59
61
  }
60
62
  }
61
63
 
64
+ /**
65
+ * Serializes a taproot (Schnorr) signature, optionally appending the sighash type byte.
66
+ * If sighashType is SIGHASH_DEFAULT (0x00) or not provided, no byte is appended (per BIP 341).
67
+ * Used for both P2TR key-path/script-path and P2MR script-path signatures.
68
+ * @param sig - The 64-byte Schnorr signature.
69
+ * @param sighashType - Optional sighash type. Omit or pass 0 for SIGHASH_DEFAULT.
70
+ * @returns The serialized signature (64 or 65 bytes).
71
+ */
62
72
  export function serializeTaprootSignature(sig: Uint8Array, sighashType?: number): Uint8Array {
63
73
  const sighashTypeByte = sighashType ? new Uint8Array([sighashType]) : new Uint8Array(0);
64
74
 
65
75
  return concat([sig, sighashTypeByte]);
66
76
  }
67
77
 
78
+ /**
79
+ * Determines whether a PSBT input should be handled as a taproot-style input.
80
+ * Returns true for both P2TR (SegWit v1, BIP 341) and P2MR (SegWit v2, BIP 360) inputs.
81
+ * This is the gateway check that routes inputs to taproot signing and finalization logic.
82
+ * @param input - The PSBT input to check.
83
+ * @returns True if the input has taproot/P2MR fields or a P2TR/P2MR witnessUtxo script.
84
+ */
68
85
  export function isTaprootInput(input: PsbtInput): boolean {
69
86
  return (
70
87
  input &&
@@ -73,11 +90,31 @@ export function isTaprootInput(input: PsbtInput): boolean {
73
90
  input.tapMerkleRoot ||
74
91
  (input.tapLeafScript && input.tapLeafScript.length) ||
75
92
  (input.tapBip32Derivation && input.tapBip32Derivation.length) ||
76
- (input.witnessUtxo && isP2TR(new Uint8Array(input.witnessUtxo.script)))
93
+ (input.witnessUtxo &&
94
+ (isP2TR(new Uint8Array(input.witnessUtxo.script)) ||
95
+ isP2MR(new Uint8Array(input.witnessUtxo.script))))
77
96
  )
78
97
  );
79
98
  }
80
99
 
100
+ /**
101
+ * Checks if the input is spending a P2MR (Pay-to-Merkle-Root, BIP 360) output.
102
+ * Requires `witnessUtxo` to be set on the input; returns false otherwise.
103
+ * P2MR uses SegWit version 2 with scriptPubKey: `OP_2 <32-byte merkle_root>`.
104
+ * @param input - The PSBT input to check.
105
+ * @returns True if the witnessUtxo script is a valid P2MR output.
106
+ */
107
+ export function isP2MRInput(input: PsbtInput): boolean {
108
+ return !!(input.witnessUtxo && isP2MR(new Uint8Array(input.witnessUtxo.script)));
109
+ }
110
+
111
+ /**
112
+ * Determines whether a PSBT output should be handled as a taproot-style output.
113
+ * Returns true for both P2TR (BIP 341) and P2MR (BIP 360) outputs.
114
+ * @param output - The PSBT output to check.
115
+ * @param script - Optional output script to test against P2TR/P2MR patterns.
116
+ * @returns True if the output has taproot fields or a P2TR/P2MR script.
117
+ */
81
118
  export function isTaprootOutput(output: PsbtOutput, script?: Uint8Array): boolean {
82
119
  return (
83
120
  output &&
@@ -85,7 +122,7 @@ export function isTaprootOutput(output: PsbtOutput, script?: Uint8Array): boolea
85
122
  output.tapInternalKey ||
86
123
  output.tapTree ||
87
124
  (output.tapBip32Derivation && output.tapBip32Derivation.length) ||
88
- (script && isP2TR(script))
125
+ (script && (isP2TR(script) || isP2MR(script)))
89
126
  )
90
127
  );
91
128
  }
@@ -324,20 +361,21 @@ function checkMixedTaprootAndNonTaprootOutputFields(
324
361
  * @throws {Error} - If the tap leaf is not part of the tap tree.
325
362
  */
326
363
  function checkIfTapLeafInTree(inputData: PsbtInput, newInputData: PsbtInput, action: string): void {
364
+ const p2mrInput = isP2MRInput(inputData) || isP2MRInput(newInputData);
327
365
  if (newInputData.tapMerkleRoot) {
328
366
  const merkleRoot = new Uint8Array(newInputData.tapMerkleRoot);
329
367
  const newLeafsInTree = (newInputData.tapLeafScript || []).every((l) =>
330
- isTapLeafInTree(l, merkleRoot),
368
+ isTapLeafInTree(l, merkleRoot, p2mrInput),
331
369
  );
332
370
  const oldLeafsInTree = (inputData.tapLeafScript || []).every((l) =>
333
- isTapLeafInTree(l, merkleRoot),
371
+ isTapLeafInTree(l, merkleRoot, p2mrInput),
334
372
  );
335
373
  if (!newLeafsInTree || !oldLeafsInTree)
336
374
  throw new Error(`Invalid arguments for Psbt.${action}. Tapleaf not part of taptree.`);
337
375
  } else if (inputData.tapMerkleRoot) {
338
376
  const merkleRoot = new Uint8Array(inputData.tapMerkleRoot);
339
377
  const newLeafsInTree = (newInputData.tapLeafScript || []).every((l) =>
340
- isTapLeafInTree(l, merkleRoot),
378
+ isTapLeafInTree(l, merkleRoot, p2mrInput),
341
379
  );
342
380
  if (!newLeafsInTree)
343
381
  throw new Error(`Invalid arguments for Psbt.${action}. Tapleaf not part of taptree.`);
@@ -345,12 +383,24 @@ function checkIfTapLeafInTree(inputData: PsbtInput, newInputData: PsbtInput, act
345
383
  }
346
384
 
347
385
  /**
348
- * Checks if a TapLeafScript is present in a Merkle tree.
349
- * @param tapLeaf The TapLeafScript to check.
350
- * @param merkleRoot The Merkle root of the tree. If not provided, the function assumes the TapLeafScript is present.
351
- * @returns A boolean indicating whether the TapLeafScript is present in the tree.
386
+ * Checks if a TapLeafScript is present in a Merkle tree by recomputing the root
387
+ * from the control block's merkle path.
388
+ *
389
+ * Handles both P2TR and P2MR control block formats:
390
+ * - P2TR: 33 + 32*m bytes (1 control byte + 32-byte internal pubkey + merkle path)
391
+ * - P2MR: 1 + 32*m bytes (1 control byte + merkle path, no internal pubkey)
392
+ *
393
+ * When `p2mr` is explicitly true, only the P2MR format is tried. When false and
394
+ * the input type is unknown (witnessUtxo not yet set), both formats are tried as
395
+ * their lengths overlap at 33, 65, 97... bytes. The merkle root is used to
396
+ * disambiguate which interpretation is correct.
397
+ *
398
+ * @param tapLeaf - The TapLeafScript to check (includes script, leafVersion, controlBlock).
399
+ * @param merkleRoot - The expected Merkle root. If not provided, returns true (no validation).
400
+ * @param p2mr - If true, use P2MR control block format exclusively.
401
+ * @returns True if the leaf's control block produces the expected merkle root.
352
402
  */
353
- function isTapLeafInTree(tapLeaf: TapLeafScript, merkleRoot?: Uint8Array): boolean {
403
+ function isTapLeafInTree(tapLeaf: TapLeafScript, merkleRoot?: Uint8Array, p2mr = false): boolean {
354
404
  if (!merkleRoot) return true;
355
405
 
356
406
  const leafHash = tapleafHash({
@@ -358,8 +408,29 @@ function isTapLeafInTree(tapLeaf: TapLeafScript, merkleRoot?: Uint8Array): boole
358
408
  version: tapLeaf.leafVersion,
359
409
  });
360
410
 
361
- const rootHash = rootHashFromPath(new Uint8Array(tapLeaf.controlBlock), leafHash);
362
- return equals(rootHash, merkleRoot);
411
+ const controlBlock = new Uint8Array(tapLeaf.controlBlock);
412
+
413
+ if (p2mr) {
414
+ return equals(rootHashFromPathP2MR(controlBlock, leafHash), merkleRoot);
415
+ }
416
+
417
+ // When the input type isn't known yet (witnessUtxo not set), try P2TR first,
418
+ // then fall back to P2MR. Control block lengths overlap (33, 65, ...) between
419
+ // P2TR (33 + 32*m) and P2MR (1 + 32*m), so we verify against the merkle root.
420
+ const isValidP2TRLength = controlBlock.length >= 33 && (controlBlock.length - 33) % 32 === 0;
421
+ const isValidP2MRLength = controlBlock.length >= 1 && (controlBlock.length - 1) % 32 === 0;
422
+
423
+ if (isValidP2TRLength) {
424
+ const rootHash = rootHashFromPath(controlBlock, leafHash);
425
+ if (equals(rootHash, merkleRoot)) return true;
426
+ }
427
+
428
+ if (isValidP2MRLength) {
429
+ const rootHash = rootHashFromPathP2MR(controlBlock, leafHash);
430
+ if (equals(rootHash, merkleRoot)) return true;
431
+ }
432
+
433
+ return false;
363
434
  }
364
435
 
365
436
  /**
@@ -5,6 +5,7 @@ import { p2ms } from '../payments/p2ms.js';
5
5
  import { p2pk } from '../payments/p2pk.js';
6
6
  import { p2pkh } from '../payments/p2pkh.js';
7
7
  import { p2sh } from '../payments/p2sh.js';
8
+ import { p2mr } from '../payments/p2mr.js';
8
9
  import { p2tr } from '../payments/p2tr.js';
9
10
  import { p2wpkh } from '../payments/p2wpkh.js';
10
11
  import { p2wsh } from '../payments/p2wsh.js';
@@ -34,6 +35,7 @@ export const isP2WPKH = isPaymentFactory(p2wpkh);
34
35
  export const isP2WSHScript = isPaymentFactory(p2wsh);
35
36
  export const isP2SHScript = isPaymentFactory(p2sh);
36
37
  export const isP2TR = isPaymentFactory(p2tr);
38
+ export const isP2MR = isPaymentFactory(p2mr);
37
39
  export const isP2OP = isPaymentFactory(p2op);
38
40
  export const isP2A = (script: Uint8Array): boolean => {
39
41
  return (
package/src/psbt.ts CHANGED
@@ -17,6 +17,7 @@ import * as payments from './payments/index.js';
17
17
  import {
18
18
  checkTaprootInputFields,
19
19
  checkTaprootOutputFields,
20
+ isP2MRInput,
20
21
  isTaprootInput,
21
22
  serializeTaprootSignature,
22
23
  tapScriptFinalizer,
@@ -420,7 +421,7 @@ export class Psbt {
420
421
  if (hasAddress) {
421
422
  const { address } = outputData as PsbtOutputExtendedAddress;
422
423
  const { network } = this.#opts;
423
- const script = toOutputScript(address, network) as Script;
424
+ const script = toOutputScript(address, network);
424
425
  outputData = Object.assign({}, outputData, { script });
425
426
  }
426
427
  checkTaprootOutputFields(outputData, outputData, 'addOutput');
@@ -921,7 +922,8 @@ export class Psbt {
921
922
  if (!input.witnessUtxo)
922
923
  throw new Error(`Cannot finalize input #${inputIndex}. Missing witness utxo.`);
923
924
 
924
- if (input.tapKeySig) {
925
+ // P2MR has no key-path spend — always use script-path finalization
926
+ if (input.tapKeySig && !isP2MRInput(input)) {
925
927
  const payment = payments.p2tr({
926
928
  output: input.witnessUtxo.script as Script,
927
929
  signature: input.tapKeySig as SchnorrSignature,
package/src/pubkey.ts CHANGED
@@ -55,7 +55,7 @@ export function decompressPublicKey(realPubKey: PublicKey): UncompressedPublicKe
55
55
  try {
56
56
  point = Point.fromHex(toHex(realPubKey));
57
57
  } catch (err) {
58
- throw new Error('Invalid secp256k1 public key bytes. Cannot parse.');
58
+ throw new Error('Invalid secp256k1 public key bytes. Cannot parse.', { cause: err });
59
59
  }
60
60
 
61
61
  const xBuf = bigIntTo32Bytes(point.x);
@@ -1,5 +1,5 @@
1
1
  import assert from 'assert';
2
- import base58 from 'bs58';
2
+ import { base58 } from '@scure/base';
3
3
  import { describe, it } from 'vitest';
4
4
  import * as bitcoin from '../src/index.js';
5
5
  import type { Bytes20, Satoshi, Script } from '../src/types.js';
@@ -0,0 +1,270 @@
1
+ {
2
+ "valid": [
3
+ {
4
+ "description": "output and hash from address",
5
+ "arguments": {
6
+ "address": "bc1z4rf73uru6qdyrv9w3nq9f3dwqlqmec4sdwj03hexu7n7r7dkehjs592djq"
7
+ },
8
+ "options": {},
9
+ "expected": {
10
+ "name": "p2mr",
11
+ "hash": "a8d3e8f07cd01a41b0ae8cc054c5ae07c1bce2b06ba4f8df26e7a7e1f9b6cde5",
12
+ "output": "OP_2 a8d3e8f07cd01a41b0ae8cc054c5ae07c1bce2b06ba4f8df26e7a7e1f9b6cde5",
13
+ "input": null,
14
+ "witness": null
15
+ }
16
+ },
17
+ {
18
+ "description": "address and hash from output",
19
+ "arguments": {
20
+ "output": "OP_2 a8d3e8f07cd01a41b0ae8cc054c5ae07c1bce2b06ba4f8df26e7a7e1f9b6cde5"
21
+ },
22
+ "options": {},
23
+ "expected": {
24
+ "name": "p2mr",
25
+ "address": "bc1z4rf73uru6qdyrv9w3nq9f3dwqlqmec4sdwj03hexu7n7r7dkehjs592djq",
26
+ "hash": "a8d3e8f07cd01a41b0ae8cc054c5ae07c1bce2b06ba4f8df26e7a7e1f9b6cde5",
27
+ "input": null,
28
+ "witness": null
29
+ }
30
+ },
31
+ {
32
+ "description": "address and output from hash",
33
+ "arguments": {
34
+ "hash": "a8d3e8f07cd01a41b0ae8cc054c5ae07c1bce2b06ba4f8df26e7a7e1f9b6cde5"
35
+ },
36
+ "options": {},
37
+ "expected": {
38
+ "name": "p2mr",
39
+ "address": "bc1z4rf73uru6qdyrv9w3nq9f3dwqlqmec4sdwj03hexu7n7r7dkehjs592djq",
40
+ "output": "OP_2 a8d3e8f07cd01a41b0ae8cc054c5ae07c1bce2b06ba4f8df26e7a7e1f9b6cde5",
41
+ "input": null,
42
+ "witness": null
43
+ }
44
+ },
45
+ {
46
+ "description": "hash, output and address from single-leaf scriptTree",
47
+ "arguments": {
48
+ "scriptTree": {
49
+ "output": "OP_1"
50
+ }
51
+ },
52
+ "options": {},
53
+ "expected": {
54
+ "name": "p2mr",
55
+ "hash": "a85b2107f791b26a84e7586c28cec7cb61202ed3d01944d832500f363782d675",
56
+ "output": "OP_2 a85b2107f791b26a84e7586c28cec7cb61202ed3d01944d832500f363782d675",
57
+ "address": "bc1z4pdjzplhjxex4p88tpkz3nk8edsjqtkn6qv5fkpj2q8nvduz6e6sy82nl4",
58
+ "input": null,
59
+ "witness": null
60
+ }
61
+ },
62
+ {
63
+ "description": "hash, address, output and witness from single-leaf scriptTree with redeem",
64
+ "arguments": {
65
+ "scriptTree": {
66
+ "output": "OP_1"
67
+ },
68
+ "redeem": {
69
+ "output": "OP_1"
70
+ }
71
+ },
72
+ "options": {},
73
+ "expected": {
74
+ "name": "p2mr",
75
+ "hash": "a85b2107f791b26a84e7586c28cec7cb61202ed3d01944d832500f363782d675",
76
+ "output": "OP_2 a85b2107f791b26a84e7586c28cec7cb61202ed3d01944d832500f363782d675",
77
+ "address": "bc1z4pdjzplhjxex4p88tpkz3nk8edsjqtkn6qv5fkpj2q8nvduz6e6sy82nl4",
78
+ "input": null,
79
+ "witness": [
80
+ "51",
81
+ "c1"
82
+ ]
83
+ }
84
+ },
85
+ {
86
+ "description": "hash, address, output from two-leaf scriptTree",
87
+ "arguments": {
88
+ "scriptTree": [
89
+ {
90
+ "output": "OP_1"
91
+ },
92
+ {
93
+ "output": "OP_0 OP_1"
94
+ }
95
+ ]
96
+ },
97
+ "options": {},
98
+ "expected": {
99
+ "name": "p2mr",
100
+ "hash": "9bc8cefc93017c588ec645d256d21f16897a33e3d107402dcb50868d6e5701a6",
101
+ "output": "OP_2 9bc8cefc93017c588ec645d256d21f16897a33e3d107402dcb50868d6e5701a6",
102
+ "address": "bc1zn0yvalynq9793rkxghf9d5slz6yh5vlr6yr5qtwt2zrg6mjhqxnq2qq9vy",
103
+ "input": null,
104
+ "witness": null
105
+ }
106
+ },
107
+ {
108
+ "description": "witness from two-leaf scriptTree spending second leaf",
109
+ "arguments": {
110
+ "scriptTree": [
111
+ {
112
+ "output": "OP_1"
113
+ },
114
+ {
115
+ "output": "OP_0 OP_1"
116
+ }
117
+ ],
118
+ "redeem": {
119
+ "output": "OP_0 OP_1"
120
+ }
121
+ },
122
+ "options": {},
123
+ "expected": {
124
+ "name": "p2mr",
125
+ "hash": "9bc8cefc93017c588ec645d256d21f16897a33e3d107402dcb50868d6e5701a6",
126
+ "output": "OP_2 9bc8cefc93017c588ec645d256d21f16897a33e3d107402dcb50868d6e5701a6",
127
+ "address": "bc1zn0yvalynq9793rkxghf9d5slz6yh5vlr6yr5qtwt2zrg6mjhqxnq2qq9vy",
128
+ "input": null,
129
+ "witness": [
130
+ "0051",
131
+ "c1a85b2107f791b26a84e7586c28cec7cb61202ed3d01944d832500f363782d675"
132
+ ]
133
+ }
134
+ },
135
+ {
136
+ "description": "hash, output and address from witness (script-path spend)",
137
+ "arguments": {
138
+ "witness": [
139
+ "0051",
140
+ "c1a85b2107f791b26a84e7586c28cec7cb61202ed3d01944d832500f363782d675"
141
+ ]
142
+ },
143
+ "options": {},
144
+ "expected": {
145
+ "name": "p2mr",
146
+ "hash": "9bc8cefc93017c588ec645d256d21f16897a33e3d107402dcb50868d6e5701a6",
147
+ "output": "OP_2 9bc8cefc93017c588ec645d256d21f16897a33e3d107402dcb50868d6e5701a6",
148
+ "address": "bc1zn0yvalynq9793rkxghf9d5slz6yh5vlr6yr5qtwt2zrg6mjhqxnq2qq9vy",
149
+ "input": null
150
+ }
151
+ },
152
+ {
153
+ "description": "three-leaf tree spending leaf C",
154
+ "arguments": {
155
+ "scriptTree": [
156
+ [
157
+ {
158
+ "output": "OP_1"
159
+ },
160
+ {
161
+ "output": "OP_0 OP_1"
162
+ }
163
+ ],
164
+ {
165
+ "output": "OP_2 OP_ADD"
166
+ }
167
+ ],
168
+ "redeem": {
169
+ "output": "OP_2 OP_ADD"
170
+ }
171
+ },
172
+ "options": {},
173
+ "expected": {
174
+ "name": "p2mr",
175
+ "hash": "51308a6978377038d26b9a24a9fd36dca763006b667b7ac7d33a3de513ed19ac",
176
+ "output": "OP_2 51308a6978377038d26b9a24a9fd36dca763006b667b7ac7d33a3de513ed19ac",
177
+ "address": "bc1z2ycg56tcxacr35ntngj2nlfkmjnkxqrtveah437n8g772yldrxkq3620s4",
178
+ "input": null,
179
+ "witness": [
180
+ "5293",
181
+ "c19bc8cefc93017c588ec645d256d21f16897a33e3d107402dcb50868d6e5701a6"
182
+ ]
183
+ }
184
+ },
185
+ {
186
+ "description": "three-leaf tree spending leaf A (deeper path)",
187
+ "arguments": {
188
+ "scriptTree": [
189
+ [
190
+ {
191
+ "output": "OP_1"
192
+ },
193
+ {
194
+ "output": "OP_0 OP_1"
195
+ }
196
+ ],
197
+ {
198
+ "output": "OP_2 OP_ADD"
199
+ }
200
+ ],
201
+ "redeem": {
202
+ "output": "OP_1"
203
+ }
204
+ },
205
+ "options": {},
206
+ "expected": {
207
+ "name": "p2mr",
208
+ "hash": "51308a6978377038d26b9a24a9fd36dca763006b667b7ac7d33a3de513ed19ac",
209
+ "output": "OP_2 51308a6978377038d26b9a24a9fd36dca763006b667b7ac7d33a3de513ed19ac",
210
+ "address": "bc1z2ycg56tcxacr35ntngj2nlfkmjnkxqrtveah437n8g772yldrxkq3620s4",
211
+ "input": null,
212
+ "witness": [
213
+ "51",
214
+ "c16a44dcd1309c36cb52f2cd8797d947b9b06dddf666fb9b8c6e8d8fb0bc41cd1b3173603d1ef3328ba80b0ba7d35aba099b2f96674473d80cab75944befa3daec"
215
+ ]
216
+ }
217
+ },
218
+ {
219
+ "description": "single leaf with non-default version (0xfa)",
220
+ "arguments": {
221
+ "scriptTree": {
222
+ "output": "OP_1",
223
+ "version": 250
224
+ },
225
+ "redeem": {
226
+ "output": "OP_1"
227
+ },
228
+ "redeemVersion": 250
229
+ },
230
+ "options": {},
231
+ "expected": {
232
+ "name": "p2mr",
233
+ "hash": "eb0c727d7160a3e717c3ec0cb3e7a2da50e62926a04f2f369eadb91c0f7fd825",
234
+ "output": "OP_2 eb0c727d7160a3e717c3ec0cb3e7a2da50e62926a04f2f369eadb91c0f7fd825",
235
+ "address": "bc1zavx8ylt3vz37w97rasxt8eazmfgwv2fx5p8j7d574ku3crmlmqjsgtmlz6",
236
+ "input": null,
237
+ "redeemVersion": 250,
238
+ "witness": [
239
+ "51",
240
+ "fb"
241
+ ]
242
+ }
243
+ }
244
+ ],
245
+ "invalid": [],
246
+ "dynamic": {
247
+ "depends": {
248
+ "output": [
249
+ "hash",
250
+ "address"
251
+ ],
252
+ "address": [
253
+ "hash",
254
+ "output"
255
+ ],
256
+ "hash": [
257
+ "output",
258
+ "address"
259
+ ]
260
+ },
261
+ "details": [
262
+ {
263
+ "description": "p2mr round-trip",
264
+ "hash": "a8d3e8f07cd01a41b0ae8cc054c5ae07c1bce2b06ba4f8df26e7a7e1f9b6cde5",
265
+ "output": "OP_2 a8d3e8f07cd01a41b0ae8cc054c5ae07c1bce2b06ba4f8df26e7a7e1f9b6cde5",
266
+ "address": "bc1z4rf73uru6qdyrv9w3nq9f3dwqlqmec4sdwj03hexu7n7r7dkehjs592djq"
267
+ }
268
+ ]
269
+ }
270
+ }
@@ -423,10 +423,12 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
423
423
  await regtestUtils.broadcast(hex);
424
424
  throw new Error('Broadcast should fail.');
425
425
  } catch (err) {
426
- if ((err as any).message !== 'non-BIP68-final')
426
+ if ((err as Error).message !== 'non-BIP68-final') {
427
427
  throw new Error(
428
- 'Expected OP_CHECKSEQUENCEVERIFY validation to fail. But it faild with: ' + err,
428
+ `Expected OP_CHECKSEQUENCEVERIFY validation to fail. But it faild with: ${err}`,
429
+ { cause: err },
429
430
  );
431
+ }
430
432
  }
431
433
  await regtestUtils.mine(10);
432
434
  await regtestUtils.broadcast(hex);
@@ -672,7 +674,9 @@ function buildLeafIndexFinalizer(
672
674
  ];
673
675
  return { finalScriptWitness: witnessStackToScriptWitness(witness) };
674
676
  } catch (err) {
675
- throw new Error(`Can not finalize taproot input #${inputIndex}: ${err}`);
677
+ throw new Error(`Can not finalize taproot input #${inputIndex}: ${err}`, {
678
+ cause: err,
679
+ });
676
680
  }
677
681
  };
678
682
  }