@btc-vision/bitcoin 7.0.0-alpha.9 → 7.0.0-beta.0

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 (202) hide show
  1. package/README.md +22 -0
  2. package/benchmark-compare/BENCHMARK.md +144 -0
  3. package/benchmark-compare/compare.bench.ts +1024 -0
  4. package/benchmark-compare/harness.ts +220 -0
  5. package/benchmark-compare/package.json +18 -0
  6. package/browser/address.d.ts.map +1 -1
  7. package/browser/block.d.ts.map +1 -1
  8. package/browser/chunks/{psbt-parallel-BBFlkmiv.js → psbt-parallel-B-dfm5GZ.js} +2430 -2523
  9. package/browser/crypto-hashes.d.ts +4 -0
  10. package/browser/crypto-hashes.d.ts.map +1 -0
  11. package/browser/crypto-hashes.native.d.ts +4 -0
  12. package/browser/crypto-hashes.native.d.ts.map +1 -0
  13. package/browser/crypto.d.ts.map +1 -1
  14. package/browser/index.d.ts +2 -2
  15. package/browser/index.d.ts.map +1 -1
  16. package/browser/index.js +571 -547
  17. package/browser/io/base58check.d.ts +26 -0
  18. package/browser/io/base58check.d.ts.map +1 -0
  19. package/browser/io/base64.d.ts +8 -0
  20. package/browser/io/base64.d.ts.map +1 -1
  21. package/browser/io/index.d.ts +2 -1
  22. package/browser/io/index.d.ts.map +1 -1
  23. package/browser/io/utils.d.ts.map +1 -1
  24. package/browser/payments/bip341.d.ts.map +1 -1
  25. package/browser/payments/p2op.d.ts.map +1 -1
  26. package/browser/payments/p2pkh.d.ts.map +1 -1
  27. package/browser/payments/p2sh.d.ts.map +1 -1
  28. package/browser/payments/p2tr.d.ts.map +1 -1
  29. package/browser/payments/p2wpkh.d.ts.map +1 -1
  30. package/browser/psbt/PsbtCache.d.ts.map +1 -1
  31. package/browser/psbt/PsbtSigner.d.ts.map +1 -1
  32. package/browser/psbt/PsbtTransaction.d.ts +2 -2
  33. package/browser/psbt/PsbtTransaction.d.ts.map +1 -1
  34. package/browser/psbt/bip371.d.ts.map +1 -1
  35. package/browser/psbt.d.ts +1 -1
  36. package/browser/psbt.d.ts.map +1 -1
  37. package/browser/react-native-quick-crypto.d.ts +11 -0
  38. package/browser/script.d.ts.map +1 -1
  39. package/browser/transaction.d.ts.map +1 -1
  40. package/browser/workers/WorkerSigningPool.node.d.ts.map +1 -1
  41. package/browser/workers/WorkerSigningPool.sequential.d.ts.map +1 -1
  42. package/browser/workers/index.js +5 -5
  43. package/build/address.d.ts.map +1 -1
  44. package/build/address.js +19 -12
  45. package/build/address.js.map +1 -1
  46. package/build/bip66.js +4 -4
  47. package/build/bip66.js.map +1 -1
  48. package/build/block.d.ts.map +1 -1
  49. package/build/block.js +9 -2
  50. package/build/block.js.map +1 -1
  51. package/build/crypto-hashes.d.ts +4 -0
  52. package/build/crypto-hashes.d.ts.map +1 -0
  53. package/build/crypto-hashes.js +4 -0
  54. package/build/crypto-hashes.js.map +1 -0
  55. package/build/crypto-hashes.native.d.ts +4 -0
  56. package/build/crypto-hashes.native.d.ts.map +1 -0
  57. package/build/crypto-hashes.native.js +15 -0
  58. package/build/crypto-hashes.native.js.map +1 -0
  59. package/build/crypto.d.ts.map +1 -1
  60. package/build/crypto.js +1 -2
  61. package/build/crypto.js.map +1 -1
  62. package/build/env.js.map +1 -1
  63. package/build/index.d.ts +2 -2
  64. package/build/index.d.ts.map +1 -1
  65. package/build/index.js +1 -1
  66. package/build/index.js.map +1 -1
  67. package/build/io/BinaryReader.js +1 -1
  68. package/build/io/BinaryReader.js.map +1 -1
  69. package/build/io/base58check.d.ts +26 -0
  70. package/build/io/base58check.d.ts.map +1 -0
  71. package/build/io/base58check.js +32 -0
  72. package/build/io/base58check.js.map +1 -0
  73. package/build/io/base64.d.ts +8 -0
  74. package/build/io/base64.d.ts.map +1 -1
  75. package/build/io/base64.js +14 -0
  76. package/build/io/base64.js.map +1 -1
  77. package/build/io/hex.js +1 -1
  78. package/build/io/hex.js.map +1 -1
  79. package/build/io/index.d.ts +2 -1
  80. package/build/io/index.d.ts.map +1 -1
  81. package/build/io/index.js +4 -2
  82. package/build/io/index.js.map +1 -1
  83. package/build/io/utils.d.ts.map +1 -1
  84. package/build/io/utils.js +3 -4
  85. package/build/io/utils.js.map +1 -1
  86. package/build/merkle.js.map +1 -1
  87. package/build/payments/bip341.d.ts.map +1 -1
  88. package/build/payments/bip341.js +4 -3
  89. package/build/payments/bip341.js.map +1 -1
  90. package/build/payments/p2op.d.ts.map +1 -1
  91. package/build/payments/p2op.js +6 -4
  92. package/build/payments/p2op.js.map +1 -1
  93. package/build/payments/p2pkh.d.ts.map +1 -1
  94. package/build/payments/p2pkh.js +3 -4
  95. package/build/payments/p2pkh.js.map +1 -1
  96. package/build/payments/p2sh.d.ts.map +1 -1
  97. package/build/payments/p2sh.js +3 -4
  98. package/build/payments/p2sh.js.map +1 -1
  99. package/build/payments/p2tr.d.ts.map +1 -1
  100. package/build/payments/p2tr.js +13 -6
  101. package/build/payments/p2tr.js.map +1 -1
  102. package/build/payments/p2wpkh.d.ts.map +1 -1
  103. package/build/payments/p2wpkh.js +7 -5
  104. package/build/payments/p2wpkh.js.map +1 -1
  105. package/build/payments/p2wsh.js.map +1 -1
  106. package/build/psbt/PsbtCache.d.ts.map +1 -1
  107. package/build/psbt/PsbtCache.js +8 -4
  108. package/build/psbt/PsbtCache.js.map +1 -1
  109. package/build/psbt/PsbtFinalizer.js +14 -8
  110. package/build/psbt/PsbtFinalizer.js.map +1 -1
  111. package/build/psbt/PsbtSigner.d.ts.map +1 -1
  112. package/build/psbt/PsbtSigner.js +3 -2
  113. package/build/psbt/PsbtSigner.js.map +1 -1
  114. package/build/psbt/PsbtTransaction.d.ts +2 -2
  115. package/build/psbt/PsbtTransaction.d.ts.map +1 -1
  116. package/build/psbt/PsbtTransaction.js.map +1 -1
  117. package/build/psbt/bip371.d.ts.map +1 -1
  118. package/build/psbt/bip371.js +4 -3
  119. package/build/psbt/bip371.js.map +1 -1
  120. package/build/psbt/utils.js.map +1 -1
  121. package/build/psbt.d.ts +1 -1
  122. package/build/psbt.d.ts.map +1 -1
  123. package/build/psbt.js.map +1 -1
  124. package/build/push_data.js +1 -1
  125. package/build/push_data.js.map +1 -1
  126. package/build/script.d.ts.map +1 -1
  127. package/build/script.js +4 -3
  128. package/build/script.js.map +1 -1
  129. package/build/script_number.js +1 -1
  130. package/build/script_number.js.map +1 -1
  131. package/build/script_signature.js.map +1 -1
  132. package/build/transaction.d.ts.map +1 -1
  133. package/build/transaction.js +2 -1
  134. package/build/transaction.js.map +1 -1
  135. package/build/tsconfig.build.tsbuildinfo +1 -1
  136. package/build/types.js.map +1 -1
  137. package/build/workers/WorkerSigningPool.js.map +1 -1
  138. package/build/workers/WorkerSigningPool.node.d.ts.map +1 -1
  139. package/build/workers/WorkerSigningPool.node.js +25 -3
  140. package/build/workers/WorkerSigningPool.node.js.map +1 -1
  141. package/build/workers/WorkerSigningPool.sequential.d.ts.map +1 -1
  142. package/build/workers/WorkerSigningPool.sequential.js +2 -0
  143. package/build/workers/WorkerSigningPool.sequential.js.map +1 -1
  144. package/build/workers/psbt-parallel.js.map +1 -1
  145. package/package.json +7 -5
  146. package/src/address.ts +18 -13
  147. package/src/bip66.ts +18 -18
  148. package/src/block.ts +7 -2
  149. package/src/crypto-hashes.native.ts +18 -0
  150. package/src/crypto-hashes.ts +3 -0
  151. package/src/crypto.ts +1 -2
  152. package/src/env.ts +6 -6
  153. package/src/index.ts +3 -0
  154. package/src/io/BinaryReader.ts +1 -1
  155. package/src/io/base58check.ts +35 -0
  156. package/src/io/base64.ts +15 -0
  157. package/src/io/hex.ts +1 -1
  158. package/src/io/index.ts +5 -2
  159. package/src/io/utils.ts +6 -7
  160. package/src/merkle.ts +3 -3
  161. package/src/payments/bip341.ts +5 -4
  162. package/src/payments/p2op.ts +6 -4
  163. package/src/payments/p2pkh.ts +4 -5
  164. package/src/payments/p2sh.ts +4 -5
  165. package/src/payments/p2tr.ts +18 -11
  166. package/src/payments/p2wpkh.ts +7 -5
  167. package/src/payments/p2wsh.ts +1 -1
  168. package/src/psbt/PsbtCache.ts +14 -11
  169. package/src/psbt/PsbtFinalizer.ts +14 -8
  170. package/src/psbt/PsbtSigner.ts +4 -3
  171. package/src/psbt/PsbtTransaction.ts +2 -2
  172. package/src/psbt/bip371.ts +4 -3
  173. package/src/psbt/utils.ts +1 -1
  174. package/src/psbt.ts +10 -8
  175. package/src/push_data.ts +5 -5
  176. package/src/react-native-quick-crypto.d.ts +11 -0
  177. package/src/script.ts +5 -4
  178. package/src/script_number.ts +6 -6
  179. package/src/script_signature.ts +2 -2
  180. package/src/transaction.ts +14 -13
  181. package/src/types.ts +1 -1
  182. package/src/workers/WorkerSigningPool.node.ts +28 -4
  183. package/src/workers/WorkerSigningPool.sequential.ts +2 -1
  184. package/src/workers/WorkerSigningPool.ts +3 -3
  185. package/src/workers/psbt-parallel.ts +2 -2
  186. package/test/address.spec.ts +1 -0
  187. package/test/bitcoin.core.spec.ts +9 -2
  188. package/test/browser/psbt.spec.ts +54 -29
  189. package/test/browser/workers-signing.spec.ts +8 -8
  190. package/test/crypto.spec.ts +1 -1
  191. package/test/env.spec.ts +2 -2
  192. package/test/integration/_regtest.ts +2 -2
  193. package/test/integration/blocks.spec.ts +1 -1
  194. package/test/integration/csv.spec.ts +1 -1
  195. package/test/integration/payments.spec.ts +2 -2
  196. package/test/integration/taproot.spec.ts +3 -3
  197. package/test/integration/transactions.spec.ts +6 -5
  198. package/test/psbt.spec.ts +49 -25
  199. package/test/transaction.spec.ts +6 -3
  200. package/test/workers-pool.spec.ts +5 -5
  201. package/test/workers-signing.spec.ts +8 -8
  202. package/test/workers.spec.ts +3 -3
@@ -144,7 +144,7 @@ export class Transaction {
144
144
 
145
145
  if (hasWitnesses) {
146
146
  for (let i = 0; i < vinLen; ++i) {
147
- tx.ins[i]!.witness = bufferReader.readVector();
147
+ (tx.ins[i] as Transaction['ins'][0]).witness = bufferReader.readVector();
148
148
  }
149
149
 
150
150
  // was this pointless?
@@ -187,7 +187,8 @@ export class Transaction {
187
187
  }
188
188
 
189
189
  isCoinbase(): boolean {
190
- return this.ins.length === 1 && Transaction.isCoinbaseHash(this.ins[0]!.hash);
190
+ const firstIn = this.ins[0];
191
+ return this.ins.length === 1 && firstIn !== undefined && Transaction.isCoinbaseHash(firstIn.hash);
191
192
  }
192
193
 
193
194
  /**
@@ -391,8 +392,8 @@ export class Transaction {
391
392
 
392
393
  // SIGHASH_ANYONECANPAY: ignore inputs entirely?
393
394
  if (hashType & Transaction.SIGHASH_ANYONECANPAY) {
394
- txTmp.ins = [txTmp.ins[inIndex]!];
395
- txTmp.ins[0]!.script = ourScript;
395
+ txTmp.ins = [txTmp.ins[inIndex] as Transaction['ins'][0]];
396
+ (txTmp.ins[0] as Transaction['ins'][0]).script = ourScript;
396
397
 
397
398
  // SIGHASH_ALL: only ignore input scripts
398
399
  } else {
@@ -400,7 +401,7 @@ export class Transaction {
400
401
  txTmp.ins.forEach((input) => {
401
402
  input.script = EMPTY_BYTES;
402
403
  });
403
- txTmp.ins[inIndex]!.script = ourScript;
404
+ (txTmp.ins[inIndex] as Transaction['ins'][0]).script = ourScript;
404
405
  }
405
406
 
406
407
  // serialize and hash
@@ -522,7 +523,7 @@ export class Transaction {
522
523
  hashOutputs = bcrypto.sha256(bufferWriter.finish());
523
524
  }
524
525
  } else if (isSingle && inIndex < this.outs.length) {
525
- const output = this.outs[inIndex]!;
526
+ const output = this.outs[inIndex] as Transaction['outs'][0];
526
527
 
527
528
  const bufferWriter = new BinaryWriter(8 + varSliceSize(output.script));
528
529
  bufferWriter.writeUInt64LE(output.value);
@@ -558,11 +559,11 @@ export class Transaction {
558
559
  // Input
559
560
  sigMsgWriter.writeUInt8(spendType);
560
561
  if (isAnyoneCanPay) {
561
- const input = this.ins[inIndex]!;
562
+ const input = this.ins[inIndex] as Transaction['ins'][0];
562
563
  sigMsgWriter.writeBytes(input.hash);
563
564
  sigMsgWriter.writeUInt32LE(input.index);
564
- sigMsgWriter.writeUInt64LE(values[inIndex]!);
565
- sigMsgWriter.writeVarBytes(prevOutScripts[inIndex]!);
565
+ sigMsgWriter.writeUInt64LE(values[inIndex] as Satoshi);
566
+ sigMsgWriter.writeVarBytes(prevOutScripts[inIndex] as Uint8Array);
566
567
  sigMsgWriter.writeUInt32LE(input.sequence);
567
568
  } else {
568
569
  sigMsgWriter.writeUInt32LE(inIndex);
@@ -733,7 +734,7 @@ export class Transaction {
733
734
 
734
735
  hashOutputs = bcrypto.hash256(tbuffer);
735
736
  } else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE && inIndex < this.outs.length) {
736
- const output = this.outs[inIndex]!;
737
+ const output = this.outs[inIndex] as Transaction['outs'][0];
737
738
 
738
739
  tbuffer = alloc(8 + varSliceSize(output.script));
739
740
  bufferWriter = new BinaryWriter(tbuffer, 0);
@@ -746,7 +747,7 @@ export class Transaction {
746
747
  tbuffer = alloc(156 + varSliceSize(prevOutScript));
747
748
  bufferWriter = new BinaryWriter(tbuffer, 0);
748
749
 
749
- const input = this.ins[inIndex]!;
750
+ const input = this.ins[inIndex] as Transaction['ins'][0];
750
751
  bufferWriter.writeInt32LE(this.version);
751
752
  bufferWriter.writeBytes(hashPrevouts);
752
753
  bufferWriter.writeBytes(hashSequence);
@@ -817,7 +818,7 @@ export class Transaction {
817
818
  throw new TypeError('Expected Uint8Array for scriptSig');
818
819
  }
819
820
 
820
- this.ins[index]!.script = scriptSig;
821
+ (this.ins[index] as Transaction['ins'][0]).script = scriptSig;
821
822
  }
822
823
 
823
824
  /**
@@ -834,7 +835,7 @@ export class Transaction {
834
835
  throw new TypeError('Expected array of Uint8Array for witness');
835
836
  }
836
837
 
837
- this.ins[index]!.witness = witness;
838
+ (this.ins[index] as Transaction['ins'][0]).witness = witness;
838
839
  }
839
840
 
840
841
  /**
package/src/types.ts CHANGED
@@ -177,7 +177,7 @@ export type StackFunction = () => Stack;
177
177
 
178
178
  export function stacksEqual(a: Uint8Array[], b: Uint8Array[]): boolean {
179
179
  if (a.length !== b.length) return false;
180
- return a.every((x, i) => equals(x, b[i]!));
180
+ return a.every((x, i) => equals(x, b[i] as Uint8Array));
181
181
  }
182
182
 
183
183
  export function toBytes32(value: Uint8Array): Bytes32 {
@@ -289,7 +289,7 @@ export class NodeWorkerSigningPool {
289
289
  const taskBatches: SigningTask[][] = Array.from({ length: workerCount }, () => []);
290
290
 
291
291
  for (let i = 0; i < tasks.length; i++) {
292
- taskBatches[i % workerCount]!.push(tasks[i]!);
292
+ (taskBatches[i % workerCount] as SigningTask[]).push(tasks[i] as SigningTask);
293
293
  }
294
294
 
295
295
  // Get private key once
@@ -784,16 +784,40 @@ function handleSignBatch(msg) {
784
784
  leafHash: task.leafHash,
785
785
  }));
786
786
 
787
+ // Copy private key for this worker (original shared across workers)
788
+ const workerPrivateKey = new Uint8Array(privateKey);
789
+
787
790
  // Create batch message
788
791
  const message: BatchSigningMessage = {
789
792
  type: 'signBatch',
790
793
  batchId,
791
794
  tasks: batchTasks,
792
- privateKey,
795
+ privateKey: workerPrivateKey,
793
796
  };
794
797
 
795
- // Send to worker
796
- worker.worker.postMessage(message);
798
+ // Collect ArrayBuffers for zero-copy transfer.
799
+ // Only transfer buffers unique to this worker batch — NOT publicKey
800
+ // (shared across all worker batches, would detach for other workers).
801
+ const keyBuf = workerPrivateKey.buffer;
802
+ const transferList: ArrayBuffer[] = [keyBuf];
803
+ const seen = new Set<ArrayBuffer>([keyBuf]);
804
+ for (const task of batchTasks) {
805
+ const hashBuf = task.hash.buffer as ArrayBuffer;
806
+ if (!seen.has(hashBuf)) {
807
+ seen.add(hashBuf);
808
+ transferList.push(hashBuf);
809
+ }
810
+ if (task.leafHash) {
811
+ const leafBuf = task.leafHash.buffer as ArrayBuffer;
812
+ if (!seen.has(leafBuf)) {
813
+ seen.add(leafBuf);
814
+ transferList.push(leafBuf);
815
+ }
816
+ }
817
+ }
818
+
819
+ // Send to worker with transfer list (zero-copy)
820
+ worker.worker.postMessage(message, transferList);
797
821
  });
798
822
  }
799
823
 
@@ -142,7 +142,8 @@ export class SequentialSigningPool {
142
142
  const key = privateKey as PrivateKey;
143
143
 
144
144
  if (task.signatureType === SignatureType.Schnorr) {
145
- signature = ecc.signSchnorr!(hash, key);
145
+ if (!ecc.signSchnorr) throw new Error('Schnorr signing not supported');
146
+ signature = ecc.signSchnorr(hash, key);
146
147
  } else {
147
148
  signature = ecc.sign(hash, key);
148
149
  }
@@ -319,7 +319,7 @@ export class WorkerSigningPool {
319
319
  const taskBatches: SigningTask[][] = Array.from({ length: workerCount }, () => []);
320
320
 
321
321
  for (let i = 0; i < tasks.length; i++) {
322
- taskBatches[i % workerCount]!.push(tasks[i]!);
322
+ (taskBatches[i % workerCount] as SigningTask[]).push(tasks[i] as SigningTask);
323
323
  }
324
324
 
325
325
  // Get private key once
@@ -338,7 +338,7 @@ export class WorkerSigningPool {
338
338
  const errors = new Map<number, string>();
339
339
 
340
340
  for (let i = 0; i < batchResults.length; i++) {
341
- const result = batchResults[i]!;
341
+ const result = batchResults[i] as PromiseSettledResult<BatchSigningResultMessage>;
342
342
  if (result.status === 'fulfilled') {
343
343
  const batchResult = result.value;
344
344
 
@@ -365,7 +365,7 @@ export class WorkerSigningPool {
365
365
  const errorMsg = reason?.message ?? 'Batch signing failed';
366
366
 
367
367
  // Add error for each task in the failed batch
368
- const failedBatch = taskBatches[i]!;
368
+ const failedBatch = taskBatches[i] as SigningTask[];
369
369
  for (const task of failedBatch) {
370
370
  errors.set(task.inputIndex, errorMsg);
371
371
  }
@@ -177,7 +177,7 @@ export function prepareSigningTasks(
177
177
  const pubkey = keyPair.publicKey;
178
178
 
179
179
  for (let i = 0; i < inputs.length; i++) {
180
- const input = inputs[i]!;
180
+ const input = inputs[i] as PsbtInput;
181
181
 
182
182
  // Check if this input can be signed with this key
183
183
  if (!psbt.inputHasPubkey(i, pubkey as PublicKey)) {
@@ -285,7 +285,7 @@ export function applySignaturesToPsbt(
285
285
  const pubkey = keyPair.publicKey;
286
286
 
287
287
  for (const [inputIndex, sigResult] of result.signatures) {
288
- const input = psbt.data.inputs[inputIndex]!;
288
+ const input = psbt.data.inputs[inputIndex] as PsbtInput;
289
289
 
290
290
  if (sigResult.signatureType === SignatureType.Schnorr) {
291
291
  // Taproot signature
@@ -66,6 +66,7 @@ describe('address', () => {
66
66
  assert.strictEqual(actual.version, f.version);
67
67
  // Support both bech32 and bech32Opnet prefixes
68
68
  const network = NETWORKS[f.network];
69
+ assert.ok(network, `Unknown network: ${f.network}`);
69
70
  const validPrefixes = [network.bech32, network.bech32Opnet].filter(Boolean);
70
71
  assert.ok(
71
72
  validPrefixes.includes(actual.prefix),
@@ -21,6 +21,7 @@ describe('Bitcoin-core', () => {
21
21
  const fb58 = f[1];
22
22
 
23
23
  it('can decode ' + fb58, () => {
24
+ assert(fb58 !== undefined);
24
25
  const buffer = base58.decode(fb58);
25
26
  const actual = toHex(new Uint8Array(buffer));
26
27
 
@@ -28,6 +29,7 @@ describe('Bitcoin-core', () => {
28
29
  });
29
30
 
30
31
  it('can encode ' + fhex, () => {
32
+ assert(fhex !== undefined);
31
33
  const buffer = fromHex(fhex);
32
34
  const actual = base58.encode(buffer);
33
35
 
@@ -78,6 +80,7 @@ describe('Bitcoin-core', () => {
78
80
  const strng = f[0];
79
81
 
80
82
  it('throws on ' + strng, () => {
83
+ assert(strng !== undefined);
81
84
  assert.throws(() => {
82
85
  const address = bitcoin.address.fromBase58Check(strng);
83
86
 
@@ -113,10 +116,12 @@ describe('Bitcoin-core', () => {
113
116
  // const verifyFlags = f[2] // TODO: do we need to test this?
114
117
 
115
118
  it('can decode ' + fhex, () => {
119
+ assert(inputs !== undefined);
116
120
  const transaction = bitcoin.Transaction.fromHex(fhex as string);
117
121
 
118
122
  transaction.ins.forEach((txIn, i) => {
119
- const input = inputs[i];
123
+ const input = (inputs as unknown[][])[i];
124
+ assert(input !== undefined);
120
125
 
121
126
  // reverse because test data is reversed
122
127
  const prevOutHash = reverseCopy(fromHex(input[0] as string));
@@ -196,7 +201,9 @@ describe('Bitcoin-core', () => {
196
201
  if (i === 0) return;
197
202
  if (i % 2 !== 0) return;
198
203
 
199
- const description = sigNoncanonical[i - 1].slice(0, -1);
204
+ const prev = sigNoncanonical[i - 1];
205
+ assert(prev !== undefined);
206
+ const description = prev.slice(0, -1);
200
207
  const buffer = fromHex(hex);
201
208
 
202
209
  it('throws on ' + description, () => {
@@ -11,7 +11,7 @@ import { randomBytes } from './setup.js';
11
11
  import { convertScriptTree } from '../payments.utils.js';
12
12
  import { LEAF_VERSION_TAPSCRIPT } from '../../src/payments/bip341.js';
13
13
  import { tapTreeFromList, tapTreeToList } from '../../src/psbt/bip371.js';
14
- import type { Bytes32, EccLib, MessageHash, PrivateKey, PublicKey, Satoshi, Script, Signature, Taptree, } from '../../src/types.js';
14
+ import type { Bytes32, EccLib, PrivateKey, PublicKey, Satoshi, Script, Signature, Taptree, } from '../../src/types.js';
15
15
  import type { HDSigner, Signer, SignerAsync, ValidateSigFunction } from '../../src/index.js';
16
16
  import { initEccLib, networks, payments, Psbt } from '../../src/index.js';
17
17
  import { equals } from '../../src/io/index.js';
@@ -19,6 +19,7 @@ import { equals } from '../../src/io/index.js';
19
19
  import preFixtures from '../fixtures/psbt.json' with { type: 'json' };
20
20
  import taprootFixtures from '../fixtures/p2tr.json' with { type: 'json' };
21
21
  import { ECPairSigner, createNobleBackend } from '@btc-vision/ecpair';
22
+ import type { MessageHash } from '@btc-vision/ecpair';
22
23
  import type { Network } from '../../src/networks.js';
23
24
 
24
25
  const bip32 = BIP32Factory(ecc);
@@ -46,8 +47,8 @@ const initBuffers = (object: any): typeof preFixtures =>
46
47
  const result = regex.exec(value);
47
48
  if (!result) return value;
48
49
 
49
- const data = result[1];
50
- const encoding = result[2];
50
+ const data = result[1]!;
51
+ const encoding = result[2]!;
51
52
 
52
53
  return Buffer.from(data, encoding as BufferEncoding);
53
54
  });
@@ -59,7 +60,7 @@ const upperCaseFirstLetter = (str: string): string => str.replace(/^./, (s) => s
59
60
  const toAsyncSigner = (signer: Signer): SignerAsync => {
60
61
  return {
61
62
  publicKey: signer.publicKey,
62
- sign: (hash: Bytes32, lowerR: boolean | undefined): Promise<Signature> => {
63
+ sign: (hash: MessageHash, lowerR: boolean | undefined): Promise<Signature> => {
63
64
  return new Promise((resolve, rejects): void => {
64
65
  setTimeout(() => {
65
66
  try {
@@ -71,12 +72,12 @@ const toAsyncSigner = (signer: Signer): SignerAsync => {
71
72
  }, 10);
72
73
  });
73
74
  },
74
- };
75
+ } as unknown as SignerAsync;
75
76
  };
76
- const failedAsyncSigner = (publicKey: Buffer): SignerAsync => {
77
- return <SignerAsync>{
77
+ const failedAsyncSigner = (publicKey: Uint8Array): SignerAsync => {
78
+ return {
78
79
  publicKey: publicKey as unknown as PublicKey,
79
- sign: (__: Bytes32): Promise<Signature> => {
80
+ sign: (__: MessageHash): Promise<Signature> => {
80
81
  return new Promise((_, reject): void => {
81
82
  setTimeout(() => {
82
83
  reject(new Error('sign failed'));
@@ -181,10 +182,13 @@ describe(`Psbt`, () => {
181
182
  fixtures.bip174.combiner.forEach((f) => {
182
183
  it('Combines two PSBTs to the expected result', () => {
183
184
  const psbts = f.psbts.map((psbt) => Psbt.fromBase64(psbt));
185
+ const psbt0 = psbts[0];
186
+ const psbt1 = psbts[1];
187
+ assert(psbt0 && psbt1);
184
188
 
185
- psbts[0].combine(psbts[1]);
189
+ psbt0.combine(psbt1);
186
190
 
187
- assert.strictEqual(psbts[0].toHex(), Psbt.fromBase64(f.result).toHex());
191
+ assert.strictEqual(psbt0.toHex(), Psbt.fromBase64(f.result).toHex());
188
192
  });
189
193
  });
190
194
 
@@ -211,8 +215,10 @@ describe(`Psbt`, () => {
211
215
  assert.strictEqual(transaction1, f.transaction);
212
216
 
213
217
  const psbt3 = Psbt.fromBase64(f.psbt);
214
- delete psbt3.data.inputs[0].finalScriptSig;
215
- delete psbt3.data.inputs[0].finalScriptWitness;
218
+ const psbt3Input0 = psbt3.data.inputs[0];
219
+ assert(psbt3Input0);
220
+ delete psbt3Input0.finalScriptSig;
221
+ delete psbt3Input0.finalScriptWitness;
216
222
  assert.throws(() => {
217
223
  psbt3.extractTransaction();
218
224
  }, new RegExp('Not finalized'));
@@ -264,7 +270,7 @@ describe(`Psbt`, () => {
264
270
  await assert.rejects(async () => {
265
271
  await psbtThatShouldsign.signInputAsync(
266
272
  f.shouldSign.inputToCheck,
267
- failedAsyncSigner(ECPair.fromWIF(f.shouldSign.WIF).publicKey),
273
+ failedAsyncSigner(ECPair.fromWIF(f.shouldSign.WIF).publicKey as unknown as Buffer),
268
274
  f.shouldSign.sighashTypes || undefined,
269
275
  );
270
276
  }, failMessage);
@@ -688,9 +694,13 @@ describe(`Psbt`, () => {
688
694
  });
689
695
 
690
696
  assert.strictEqual(psbt.inputCount, 1);
691
- assert.strictEqual(psbt.txInputs[0].sequence, 0xffffffff);
697
+ const txIn0 = psbt.txInputs[0];
698
+ assert(txIn0);
699
+ assert.strictEqual(txIn0.sequence, 0xffffffff);
692
700
  psbt.setInputSequence(0, 0);
693
- assert.strictEqual(psbt.txInputs[0].sequence, 0);
701
+ const txIn0After = psbt.txInputs[0];
702
+ assert(txIn0After);
703
+ assert.strictEqual(txIn0After.sequence, 0);
694
704
  });
695
705
 
696
706
  it('throws if input index is too high', () => {
@@ -844,6 +854,9 @@ describe(`Psbt`, () => {
844
854
  index: 0,
845
855
  });
846
856
 
857
+ const input0 = psbt.data.inputs[0];
858
+ assert(input0);
859
+
847
860
  assert.throws(() => {
848
861
  psbt.inputHasPubkey(0, testPubkey);
849
862
  }, new RegExp("Can't find pubkey in input without Utxo data"));
@@ -853,7 +866,7 @@ describe(`Psbt`, () => {
853
866
  value: 1337n as Satoshi,
854
867
  script: payments.p2sh({
855
868
  redeem: { output: Buffer.from([0x51]) as unknown as Script },
856
- }).output!,
869
+ }).output as Script,
857
870
  },
858
871
  });
859
872
 
@@ -861,14 +874,14 @@ describe(`Psbt`, () => {
861
874
  psbt.inputHasPubkey(0, testPubkey);
862
875
  }, new RegExp('scriptPubkey is P2SH but redeemScript missing'));
863
876
 
864
- delete psbt.data.inputs[0].witnessUtxo;
877
+ delete input0.witnessUtxo;
865
878
 
866
879
  psbt.updateInput(0, {
867
880
  witnessUtxo: {
868
881
  value: 1337n as Satoshi,
869
882
  script: payments.p2wsh({
870
883
  redeem: { output: Buffer.from([0x51]) as unknown as Script },
871
- }).output!,
884
+ }).output as Script,
872
885
  },
873
886
  });
874
887
 
@@ -876,7 +889,7 @@ describe(`Psbt`, () => {
876
889
  psbt.inputHasPubkey(0, testPubkey);
877
890
  }, new RegExp('scriptPubkey or redeemScript is P2WSH but witnessScript missing'));
878
891
 
879
- delete psbt.data.inputs[0].witnessUtxo;
892
+ delete input0.witnessUtxo;
880
893
 
881
894
  // Create a script that contains the test pubkey
882
895
  const scriptWithPubkey = Buffer.concat([
@@ -1008,7 +1021,9 @@ describe(`Psbt`, () => {
1008
1021
  psbt3.outputHasPubkey(0, testPubkey);
1009
1022
  }, new RegExp('scriptPubkey or redeemScript is P2WSH but witnessScript missing'));
1010
1023
 
1011
- delete psbt3.data.outputs[0].redeemScript;
1024
+ const psbt3Output0 = psbt3.data.outputs[0];
1025
+ assert(psbt3Output0);
1026
+ delete psbt3Output0.redeemScript;
1012
1027
 
1013
1028
  psbt.updateOutput(0, {
1014
1029
  witnessScript: scriptWithPubkey,
@@ -1043,7 +1058,9 @@ describe(`Psbt`, () => {
1043
1058
  assert.strictEqual(clone.toBase64(), notAClone.toBase64());
1044
1059
  assert.strictEqual(psbt.toBase64(), notAClone.toBase64());
1045
1060
  // Mutate data layer to prove clone is independent
1046
- psbt.data.inputs[0].partialSig = [];
1061
+ const cloneInput0 = psbt.data.inputs[0];
1062
+ assert(cloneInput0);
1063
+ cloneInput0.partialSig = [];
1047
1064
  assert.notStrictEqual(clone.toBase64(), psbt.toBase64());
1048
1065
  assert.notStrictEqual(clone.toBase64(), notAClone.toBase64());
1049
1066
  assert.strictEqual(psbt.toBase64(), notAClone.toBase64());
@@ -1410,17 +1427,20 @@ describe(`Psbt`, () => {
1410
1427
  const psbt = Psbt.fromBase64(f.psbt);
1411
1428
  const index = f.inputIndex;
1412
1429
 
1430
+ const cacheInput = psbt.data.inputs[index];
1431
+ assert(cacheInput);
1432
+
1413
1433
  // nonWitnessUtxo is not set before updateInput
1414
- assert.strictEqual(psbt.data.inputs[index].nonWitnessUtxo, undefined);
1434
+ assert.strictEqual(cacheInput.nonWitnessUtxo, undefined);
1415
1435
 
1416
1436
  // After updateInput, the nonWitnessUtxo is stored on the input
1417
1437
  psbt.updateInput(index, {
1418
1438
  nonWitnessUtxo: f.nonWitnessUtxo as any,
1419
1439
  });
1420
- assert.ok(psbt.data.inputs[index].nonWitnessUtxo);
1440
+ assert.ok(cacheInput.nonWitnessUtxo);
1421
1441
  assert.ok(
1422
1442
  equals(
1423
- psbt.data.inputs[index].nonWitnessUtxo!,
1443
+ cacheInput.nonWitnessUtxo as Uint8Array,
1424
1444
  f.nonWitnessUtxo as any,
1425
1445
  ),
1426
1446
  );
@@ -1436,10 +1456,11 @@ describe(`Psbt`, () => {
1436
1456
  });
1437
1457
 
1438
1458
  const input = psbt.data.inputs[index];
1459
+ assert(input);
1439
1460
  const desc = Object.getOwnPropertyDescriptor(input, 'nonWitnessUtxo');
1440
1461
  assert.ok(desc, 'property should exist');
1441
- assert.strictEqual(desc!.get, undefined, 'should not have a getter');
1442
- assert.strictEqual(desc!.set, undefined, 'should not have a setter');
1462
+ assert.strictEqual(desc.get, undefined, 'should not have a getter');
1463
+ assert.strictEqual(desc.set, undefined, 'should not have a setter');
1443
1464
  });
1444
1465
  });
1445
1466
 
@@ -1469,17 +1490,19 @@ describe(`Psbt`, () => {
1469
1490
  psbt.addInput({ hash, index });
1470
1491
 
1471
1492
  const input = psbt.txInputs[0];
1493
+ assert(input);
1472
1494
  const originalHash = new Uint8Array(input.hash);
1473
1495
  const originalIndex = input.index;
1474
1496
  const originalSequence = input.sequence;
1475
1497
 
1476
1498
  // Mutate the returned clone
1477
1499
  input.hash[0] = 123;
1478
- input.index = 123;
1479
- input.sequence = 123;
1500
+ (input as { index: number }).index = 123;
1501
+ (input as { sequence: number }).sequence = 123;
1480
1502
 
1481
1503
  // Internal state should be unchanged
1482
1504
  const fresh = psbt.txInputs[0];
1505
+ assert(fresh);
1483
1506
  assert.ok(equals(fresh.hash, originalHash));
1484
1507
  assert.strictEqual(fresh.index, originalIndex);
1485
1508
  assert.strictEqual(fresh.sequence, originalSequence);
@@ -1492,6 +1515,7 @@ describe(`Psbt`, () => {
1492
1515
  psbt.addOutput({ address, value });
1493
1516
 
1494
1517
  const output = psbt.txOutputs[0];
1518
+ assert(output);
1495
1519
  assert.strictEqual(output.address, address);
1496
1520
 
1497
1521
  const originalScript = new Uint8Array(output.script);
@@ -1499,10 +1523,11 @@ describe(`Psbt`, () => {
1499
1523
 
1500
1524
  // Mutate the returned clone
1501
1525
  output.script[0] = 123;
1502
- output.value = 123n;
1526
+ (output as { value: bigint }).value = 123n;
1503
1527
 
1504
1528
  // Internal state should be unchanged
1505
1529
  const fresh = psbt.txOutputs[0];
1530
+ assert(fresh);
1506
1531
  assert.ok(equals(fresh.script, originalScript));
1507
1532
  assert.strictEqual(fresh.value, originalValue);
1508
1533
  });
@@ -83,7 +83,7 @@ describe('Worker Signing - Signature Verification', () => {
83
83
  const signature = ecc.sign(hash, keyPair.privateKey!);
84
84
 
85
85
  const modifiedHash = Buffer.from(hash);
86
- modifiedHash[0] ^= 0xff;
86
+ modifiedHash[0]! ^= 0xff;
87
87
 
88
88
  const isValid = ecc.verify(modifiedHash, keyPair.publicKey, signature);
89
89
  expect(isValid).toBe(false);
@@ -95,7 +95,7 @@ describe('Worker Signing - Signature Verification', () => {
95
95
 
96
96
  const signature = Buffer.from(ecc.sign(hash, keyPair.privateKey!));
97
97
 
98
- signature[0] ^= 0xff;
98
+ signature[0]! ^= 0xff;
99
99
 
100
100
  const isValid = ecc.verify(hash, keyPair.publicKey, signature);
101
101
  expect(isValid).toBe(false);
@@ -150,7 +150,7 @@ describe('Worker Signing - Signature Verification', () => {
150
150
  const signature = ecc.signSchnorr(hash, keyPair.privateKey!);
151
151
 
152
152
  const modifiedHash = Buffer.from(hash);
153
- modifiedHash[0] ^= 0xff;
153
+ modifiedHash[0]! ^= 0xff;
154
154
 
155
155
  const xOnlyPubkey = toXOnly(keyPair.publicKey);
156
156
  const isValid = ecc.verifySchnorr(modifiedHash, xOnlyPubkey, signature);
@@ -162,7 +162,7 @@ describe('Worker Signing - Signature Verification', () => {
162
162
  const hash = randomBytes(32);
163
163
 
164
164
  const signature = Buffer.from(ecc.signSchnorr(hash, keyPair.privateKey!));
165
- signature[0] ^= 0xff;
165
+ signature[0]! ^= 0xff;
166
166
 
167
167
  const xOnlyPubkey = toXOnly(keyPair.publicKey);
168
168
  const isValid = ecc.verifySchnorr(hash, xOnlyPubkey, signature);
@@ -173,7 +173,7 @@ describe('Worker Signing - Signature Verification', () => {
173
173
  describe('WorkerEccLib Interface Compatibility', () => {
174
174
  it('should create WorkerEccLib compatible wrapper', () => {
175
175
  const eccLib: WorkerEccLib = {
176
- sign: (hash: Uint8Array, privateKey: Uint8Array, lowR?: boolean): Uint8Array => {
176
+ sign: (hash: Uint8Array, privateKey: Uint8Array, _lowR?: boolean): Uint8Array => {
177
177
  return ecc.sign(hash, privateKey, undefined);
178
178
  },
179
179
  signSchnorr: (hash: Uint8Array, privateKey: Uint8Array): Uint8Array => {
@@ -256,7 +256,7 @@ describe('Worker Signing - Signature Verification', () => {
256
256
  const signatures = hashes.map((hash) => ecc.sign(hash, keyPair.privateKey!));
257
257
 
258
258
  for (let i = 0; i < hashes.length; i++) {
259
- expect(ecc.verify(hashes[i], keyPair.publicKey, signatures[i])).toBe(true);
259
+ expect(ecc.verify(hashes[i]!, keyPair.publicKey, signatures[i]!)).toBe(true);
260
260
  }
261
261
  });
262
262
 
@@ -325,7 +325,7 @@ describe('Worker Signing - Signature Verification', () => {
325
325
  }
326
326
  });
327
327
 
328
- const duration = Date.now() - startTime;
328
+ void (Date.now() - startTime);
329
329
 
330
330
  let validCount = 0;
331
331
  for (const result of results) {
@@ -406,7 +406,7 @@ describe('Worker Signing - Signature Verification', () => {
406
406
  let signature: Uint8Array;
407
407
 
408
408
  try {
409
- if (signatureType === SignatureType.Schnorr) {
409
+ if ((signatureType as SignatureType) === SignatureType.Schnorr) {
410
410
  if (!eccLib.signSchnorr) {
411
411
  throw new Error('ECC library does not support Schnorr');
412
412
  }
@@ -49,7 +49,7 @@ describe('crypto', () => {
49
49
 
50
50
  for (const key of storedKeys) {
51
51
  assert.ok(
52
- equals(TAGGED_HASH_PREFIXES[key as TaggedHashPrefix], taggedHashPrefixes[key]),
52
+ equals(TAGGED_HASH_PREFIXES[key as TaggedHashPrefix], taggedHashPrefixes[key] as Uint8Array),
53
53
  `Mismatch for tag ${key}`,
54
54
  );
55
55
  }
package/test/env.spec.ts CHANGED
@@ -30,7 +30,7 @@ describe('Runtime capability check — hard requirements', () => {
30
30
 
31
31
  it('should throw when DataView.getBigInt64 is missing', async () => {
32
32
  const orig = DataView.prototype.getBigInt64;
33
- (DataView.prototype as Record<string, unknown>)['getBigInt64'] = undefined;
33
+ (DataView.prototype as unknown as Record<string, unknown>)['getBigInt64'] = undefined;
34
34
 
35
35
  try {
36
36
  await import('../src/env.js');
@@ -261,7 +261,7 @@ describe('Polyfill — Promise.allSettled', () => {
261
261
 
262
262
  it('should polyfill Promise.allSettled when missing', async () => {
263
263
  const orig = Promise.allSettled;
264
- (Promise as Record<string, unknown>)['allSettled'] = undefined;
264
+ (Promise as unknown as Record<string, unknown>)['allSettled'] = undefined;
265
265
 
266
266
  try {
267
267
  await import('../src/env.js');
@@ -1,7 +1,7 @@
1
1
  import { RegtestUtils } from 'regtest-client';
2
2
 
3
- const APIPASS = process.env.APIPASS || 'satoshi';
4
- const APIURL = process.env.APIURL || 'https://regtest.bitbank.cc/1';
3
+ const APIPASS = process.env['APIPASS'] || 'satoshi';
4
+ const APIURL = process.env['APIURL'] || 'https://regtest.bitbank.cc/1';
5
5
 
6
6
  export const regtestUtils = new RegtestUtils({ APIPASS, APIURL });
7
7
 
@@ -17,7 +17,7 @@ describe('bitcoinjs-lib (blocks)', () => {
17
17
  const tx = bitcoin.Transaction.fromHex(txHex);
18
18
 
19
19
  assert.strictEqual(tx.ins.length, 1);
20
- const script = tx.ins[0].script;
20
+ const script = tx.ins[0]!.script;
21
21
  // bitcoin.script.decompile(script) // returns [] :(
22
22
 
23
23
  assert.strictEqual(script[0], 0x03);
@@ -403,7 +403,7 @@ function csvGetFinalScripts(
403
403
  output: script,
404
404
  // This logic should be more strict and make sure the pubkeys in the
405
405
  // meaningful script are the ones signing in the PSBT etc.
406
- input: bitcoin.script.compile([input.partialSig![0].signature, bitcoin.opcodes.OP_TRUE]),
406
+ input: bitcoin.script.compile([input.partialSig![0]!.signature, bitcoin.opcodes.OP_TRUE]),
407
407
  };
408
408
  if (isP2WSH && isSegwit)
409
409
  payment = bitcoin.payments.p2wsh({