@btc-vision/bitcoin 7.0.0-alpha.1 → 7.0.0-alpha.10

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 (290) hide show
  1. package/README.md +455 -155
  2. package/browser/address.d.ts +5 -1
  3. package/browser/address.d.ts.map +1 -1
  4. package/browser/branded.d.ts +3 -14
  5. package/browser/branded.d.ts.map +1 -1
  6. package/browser/chunks/psbt-parallel-BBFlkmiv.js +10717 -0
  7. package/browser/ecc/context.d.ts +22 -21
  8. package/browser/ecc/context.d.ts.map +1 -1
  9. package/browser/ecc/index.d.ts +1 -1
  10. package/browser/ecc/index.d.ts.map +1 -1
  11. package/browser/ecc/types.d.ts +10 -123
  12. package/browser/ecc/types.d.ts.map +1 -1
  13. package/browser/env.d.ts +13 -0
  14. package/browser/env.d.ts.map +1 -0
  15. package/browser/index.d.ts +6 -6
  16. package/browser/index.d.ts.map +1 -1
  17. package/browser/index.js +2602 -11786
  18. package/browser/io/hex.d.ts.map +1 -1
  19. package/browser/io/index.d.ts +0 -1
  20. package/browser/io/index.d.ts.map +1 -1
  21. package/browser/opcodes.d.ts +11 -0
  22. package/browser/opcodes.d.ts.map +1 -1
  23. package/browser/payments/p2tr.d.ts.map +1 -1
  24. package/browser/psbt/PsbtCache.d.ts +54 -0
  25. package/browser/psbt/PsbtCache.d.ts.map +1 -0
  26. package/browser/psbt/PsbtFinalizer.d.ts +21 -0
  27. package/browser/psbt/PsbtFinalizer.d.ts.map +1 -0
  28. package/browser/psbt/PsbtSigner.d.ts +32 -0
  29. package/browser/psbt/PsbtSigner.d.ts.map +1 -0
  30. package/browser/psbt/PsbtTransaction.d.ts +25 -0
  31. package/browser/psbt/PsbtTransaction.d.ts.map +1 -0
  32. package/browser/psbt/types.d.ts +4 -70
  33. package/browser/psbt/types.d.ts.map +1 -1
  34. package/browser/psbt/validation.d.ts +1 -1
  35. package/browser/psbt/validation.d.ts.map +1 -1
  36. package/browser/psbt.d.ts +26 -40
  37. package/browser/psbt.d.ts.map +1 -1
  38. package/browser/script.d.ts.map +1 -1
  39. package/browser/transaction.d.ts +4 -4
  40. package/browser/transaction.d.ts.map +1 -1
  41. package/browser/types.d.ts +5 -3
  42. package/browser/types.d.ts.map +1 -1
  43. package/browser/workers/WorkerSigningPool.d.ts +7 -0
  44. package/browser/workers/WorkerSigningPool.d.ts.map +1 -1
  45. package/browser/workers/WorkerSigningPool.node.d.ts +7 -0
  46. package/browser/workers/WorkerSigningPool.node.d.ts.map +1 -1
  47. package/browser/workers/WorkerSigningPool.sequential.d.ts +67 -0
  48. package/browser/workers/WorkerSigningPool.sequential.d.ts.map +1 -0
  49. package/browser/workers/WorkerSigningPool.worklet.d.ts +64 -0
  50. package/browser/workers/WorkerSigningPool.worklet.d.ts.map +1 -0
  51. package/browser/workers/index.browser.d.ts +16 -0
  52. package/browser/workers/index.browser.d.ts.map +1 -0
  53. package/browser/workers/index.d.ts +4 -64
  54. package/browser/workers/index.d.ts.map +1 -1
  55. package/browser/workers/index.js +28 -0
  56. package/browser/workers/index.node.d.ts +17 -0
  57. package/browser/workers/index.node.d.ts.map +1 -0
  58. package/browser/workers/index.react-native.d.ts +28 -0
  59. package/browser/workers/index.react-native.d.ts.map +1 -0
  60. package/browser/workers/index.shared.d.ts +15 -0
  61. package/browser/workers/index.shared.d.ts.map +1 -0
  62. package/browser/workers/psbt-parallel.d.ts +2 -3
  63. package/browser/workers/psbt-parallel.d.ts.map +1 -1
  64. package/browser/workers/types.d.ts +17 -0
  65. package/browser/workers/types.d.ts.map +1 -1
  66. package/build/address.d.ts +5 -1
  67. package/build/address.d.ts.map +1 -1
  68. package/build/address.js +29 -17
  69. package/build/address.js.map +1 -1
  70. package/build/bech32utils.js.map +1 -1
  71. package/build/block.js.map +1 -1
  72. package/build/branded.d.ts +3 -14
  73. package/build/branded.d.ts.map +1 -1
  74. package/build/branded.js +0 -5
  75. package/build/branded.js.map +1 -1
  76. package/build/ecc/context.d.ts +22 -21
  77. package/build/ecc/context.d.ts.map +1 -1
  78. package/build/ecc/context.js +23 -95
  79. package/build/ecc/context.js.map +1 -1
  80. package/build/ecc/index.d.ts +1 -1
  81. package/build/ecc/index.d.ts.map +1 -1
  82. package/build/ecc/types.d.ts +7 -126
  83. package/build/ecc/types.d.ts.map +1 -1
  84. package/build/ecc/types.js +4 -1
  85. package/build/ecc/types.js.map +1 -1
  86. package/build/env.d.ts +13 -0
  87. package/build/env.d.ts.map +1 -0
  88. package/build/env.js +198 -0
  89. package/build/env.js.map +1 -0
  90. package/build/index.d.ts +7 -6
  91. package/build/index.d.ts.map +1 -1
  92. package/build/index.js +7 -5
  93. package/build/index.js.map +1 -1
  94. package/build/io/hex.d.ts.map +1 -1
  95. package/build/io/hex.js +2 -1
  96. package/build/io/hex.js.map +1 -1
  97. package/build/io/index.d.ts +0 -1
  98. package/build/io/index.d.ts.map +1 -1
  99. package/build/io/index.js +0 -2
  100. package/build/io/index.js.map +1 -1
  101. package/build/opcodes.d.ts +11 -0
  102. package/build/opcodes.d.ts.map +1 -1
  103. package/build/opcodes.js +19 -4
  104. package/build/opcodes.js.map +1 -1
  105. package/build/payments/bip341.js.map +1 -1
  106. package/build/payments/embed.js.map +1 -1
  107. package/build/payments/p2ms.js.map +1 -1
  108. package/build/payments/p2pk.js.map +1 -1
  109. package/build/payments/p2pkh.js.map +1 -1
  110. package/build/payments/p2sh.js.map +1 -1
  111. package/build/payments/p2tr.d.ts.map +1 -1
  112. package/build/payments/p2tr.js +2 -3
  113. package/build/payments/p2tr.js.map +1 -1
  114. package/build/payments/p2wpkh.js.map +1 -1
  115. package/build/payments/p2wsh.js.map +1 -1
  116. package/build/psbt/PsbtCache.d.ts +54 -0
  117. package/build/psbt/PsbtCache.d.ts.map +1 -0
  118. package/build/psbt/PsbtCache.js +249 -0
  119. package/build/psbt/PsbtCache.js.map +1 -0
  120. package/build/psbt/PsbtFinalizer.d.ts +21 -0
  121. package/build/psbt/PsbtFinalizer.d.ts.map +1 -0
  122. package/build/psbt/PsbtFinalizer.js +157 -0
  123. package/build/psbt/PsbtFinalizer.js.map +1 -0
  124. package/build/psbt/PsbtSigner.d.ts +32 -0
  125. package/build/psbt/PsbtSigner.d.ts.map +1 -0
  126. package/build/psbt/PsbtSigner.js +192 -0
  127. package/build/psbt/PsbtSigner.js.map +1 -0
  128. package/build/psbt/PsbtTransaction.d.ts +25 -0
  129. package/build/psbt/PsbtTransaction.d.ts.map +1 -0
  130. package/build/psbt/PsbtTransaction.js +61 -0
  131. package/build/psbt/PsbtTransaction.js.map +1 -0
  132. package/build/psbt/types.d.ts +4 -70
  133. package/build/psbt/types.d.ts.map +1 -1
  134. package/build/psbt/validation.d.ts +1 -1
  135. package/build/psbt/validation.d.ts.map +1 -1
  136. package/build/psbt.d.ts +26 -40
  137. package/build/psbt.d.ts.map +1 -1
  138. package/build/psbt.js +177 -799
  139. package/build/psbt.js.map +1 -1
  140. package/build/script.d.ts.map +1 -1
  141. package/build/script.js +2 -2
  142. package/build/script.js.map +1 -1
  143. package/build/transaction.d.ts +4 -4
  144. package/build/transaction.d.ts.map +1 -1
  145. package/build/transaction.js +5 -4
  146. package/build/transaction.js.map +1 -1
  147. package/build/tsconfig.build.tsbuildinfo +1 -1
  148. package/build/types.d.ts +5 -3
  149. package/build/types.d.ts.map +1 -1
  150. package/build/types.js +11 -16
  151. package/build/types.js.map +1 -1
  152. package/build/workers/WorkerSigningPool.d.ts +7 -0
  153. package/build/workers/WorkerSigningPool.d.ts.map +1 -1
  154. package/build/workers/WorkerSigningPool.js +12 -1
  155. package/build/workers/WorkerSigningPool.js.map +1 -1
  156. package/build/workers/WorkerSigningPool.node.d.ts +7 -0
  157. package/build/workers/WorkerSigningPool.node.d.ts.map +1 -1
  158. package/build/workers/WorkerSigningPool.node.js +37 -5
  159. package/build/workers/WorkerSigningPool.node.js.map +1 -1
  160. package/build/workers/WorkerSigningPool.sequential.d.ts +76 -0
  161. package/build/workers/WorkerSigningPool.sequential.d.ts.map +1 -0
  162. package/build/workers/WorkerSigningPool.sequential.js +160 -0
  163. package/build/workers/WorkerSigningPool.sequential.js.map +1 -0
  164. package/build/workers/WorkerSigningPool.worklet.d.ts +79 -0
  165. package/build/workers/WorkerSigningPool.worklet.d.ts.map +1 -0
  166. package/build/workers/WorkerSigningPool.worklet.js +390 -0
  167. package/build/workers/WorkerSigningPool.worklet.js.map +1 -0
  168. package/build/workers/index.browser.d.ts +24 -0
  169. package/build/workers/index.browser.d.ts.map +1 -0
  170. package/build/workers/index.browser.js +30 -0
  171. package/build/workers/index.browser.js.map +1 -0
  172. package/build/workers/index.d.ts +6 -18
  173. package/build/workers/index.d.ts.map +1 -1
  174. package/build/workers/index.js +12 -14
  175. package/build/workers/index.js.map +1 -1
  176. package/build/workers/index.node.d.ts +38 -0
  177. package/build/workers/index.node.d.ts.map +1 -0
  178. package/build/workers/index.node.js +45 -0
  179. package/build/workers/index.node.js.map +1 -0
  180. package/build/workers/index.react-native.d.ts +28 -0
  181. package/build/workers/index.react-native.d.ts.map +1 -0
  182. package/build/workers/index.react-native.js +67 -0
  183. package/build/workers/index.react-native.js.map +1 -0
  184. package/build/workers/index.shared.d.ts +15 -0
  185. package/build/workers/index.shared.d.ts.map +1 -0
  186. package/build/workers/index.shared.js +20 -0
  187. package/build/workers/index.shared.js.map +1 -0
  188. package/build/workers/psbt-parallel.d.ts +2 -3
  189. package/build/workers/psbt-parallel.d.ts.map +1 -1
  190. package/build/workers/psbt-parallel.js +4 -4
  191. package/build/workers/psbt-parallel.js.map +1 -1
  192. package/build/workers/types.d.ts +17 -0
  193. package/build/workers/types.d.ts.map +1 -1
  194. package/package.json +46 -8
  195. package/src/address.ts +41 -18
  196. package/src/bech32utils.ts +3 -3
  197. package/src/block.ts +2 -2
  198. package/src/branded.ts +15 -13
  199. package/src/ecc/context.ts +30 -133
  200. package/src/ecc/index.ts +2 -2
  201. package/src/ecc/types.ts +7 -138
  202. package/src/env.ts +239 -0
  203. package/src/index.ts +45 -9
  204. package/src/io/hex.ts +2 -1
  205. package/src/io/index.ts +0 -3
  206. package/src/opcodes.ts +21 -4
  207. package/src/payments/bip341.ts +3 -3
  208. package/src/payments/embed.ts +1 -1
  209. package/src/payments/p2ms.ts +2 -2
  210. package/src/payments/p2pk.ts +2 -2
  211. package/src/payments/p2pkh.ts +3 -3
  212. package/src/payments/p2sh.ts +4 -4
  213. package/src/payments/p2tr.ts +9 -9
  214. package/src/payments/p2wpkh.ts +5 -5
  215. package/src/payments/p2wsh.ts +2 -2
  216. package/src/psbt/PsbtCache.ts +325 -0
  217. package/src/psbt/PsbtFinalizer.ts +213 -0
  218. package/src/psbt/PsbtSigner.ts +302 -0
  219. package/src/psbt/PsbtTransaction.ts +82 -0
  220. package/src/psbt/types.ts +4 -86
  221. package/src/psbt/validation.ts +1 -1
  222. package/src/psbt.ts +349 -1198
  223. package/src/script.ts +2 -2
  224. package/src/transaction.ts +10 -9
  225. package/src/types.ts +18 -28
  226. package/src/workers/WorkerSigningPool.node.ts +41 -5
  227. package/src/workers/WorkerSigningPool.sequential.ts +191 -0
  228. package/src/workers/WorkerSigningPool.ts +14 -1
  229. package/src/workers/WorkerSigningPool.worklet.ts +522 -0
  230. package/src/workers/index.browser.ts +34 -0
  231. package/src/workers/index.node.ts +50 -0
  232. package/src/workers/index.react-native.ts +110 -0
  233. package/src/workers/index.shared.ts +58 -0
  234. package/src/workers/index.ts +14 -65
  235. package/src/workers/psbt-parallel.ts +7 -7
  236. package/src/workers/types.ts +21 -0
  237. package/test/address.spec.ts +2 -2
  238. package/test/bitcoin.core.spec.ts +5 -2
  239. package/test/browser/payments.spec.ts +151 -0
  240. package/test/browser/psbt.spec.ts +1510 -0
  241. package/test/browser/script.spec.ts +223 -0
  242. package/test/browser/setup.ts +13 -0
  243. package/test/browser/workers-signing.spec.ts +537 -0
  244. package/test/crypto.spec.ts +2 -2
  245. package/test/env.spec.ts +418 -0
  246. package/test/fixtures/core/base58_encode_decode.json +12 -48
  247. package/test/fixtures/core/base58_keys_invalid.json +50 -150
  248. package/test/fixtures/core/sighash.json +1 -3
  249. package/test/fixtures/core/tx_valid.json +133 -501
  250. package/test/fixtures/embed.json +3 -11
  251. package/test/fixtures/p2ms.json +21 -91
  252. package/test/fixtures/p2pk.json +5 -24
  253. package/test/fixtures/p2pkh.json +7 -36
  254. package/test/fixtures/p2sh.json +8 -54
  255. package/test/fixtures/p2tr.json +2 -6
  256. package/test/fixtures/p2wpkh.json +7 -36
  257. package/test/fixtures/p2wsh.json +14 -59
  258. package/test/fixtures/psbt.json +2 -6
  259. package/test/fixtures/script.json +12 -48
  260. package/test/integration/addresses.spec.ts +11 -5
  261. package/test/integration/bip32.spec.ts +1 -1
  262. package/test/integration/cltv.spec.ts +10 -6
  263. package/test/integration/csv.spec.ts +10 -9
  264. package/test/integration/payments.spec.ts +8 -4
  265. package/test/integration/taproot.spec.ts +26 -6
  266. package/test/integration/transactions.spec.ts +22 -8
  267. package/test/payments.spec.ts +1 -1
  268. package/test/payments.utils.ts +1 -1
  269. package/test/psbt.spec.ts +250 -64
  270. package/test/script_signature.spec.ts +1 -1
  271. package/test/transaction.spec.ts +18 -5
  272. package/test/tsconfig.json +6 -20
  273. package/test/workers-pool.spec.ts +65 -23
  274. package/test/workers-sequential.spec.ts +669 -0
  275. package/test/workers-signing.spec.ts +7 -3
  276. package/test/workers-worklet.spec.ts +500 -0
  277. package/test/workers.spec.ts +6 -7
  278. package/typedoc.json +11 -1
  279. package/vite.config.browser.ts +31 -6
  280. package/vitest.config.browser.ts +68 -0
  281. package/browser/ecpair.d.ts +0 -99
  282. package/browser/io/MemoryPool.d.ts +0 -220
  283. package/browser/io/MemoryPool.d.ts.map +0 -1
  284. package/build/io/MemoryPool.d.ts +0 -220
  285. package/build/io/MemoryPool.d.ts.map +0 -1
  286. package/build/io/MemoryPool.js +0 -309
  287. package/build/io/MemoryPool.js.map +0 -1
  288. package/src/ecpair.d.ts +0 -99
  289. package/src/io/MemoryPool.ts +0 -343
  290. package/test/taproot-cache.spec.ts +0 -694
package/test/psbt.spec.ts CHANGED
@@ -2,25 +2,36 @@ import assert from 'assert';
2
2
  import { BIP32Factory } from '@btc-vision/bip32';
3
3
  import * as ecc from 'tiny-secp256k1';
4
4
  import * as crypto from 'crypto';
5
- import { ECPairFactory } from 'ecpair';
6
5
  import { beforeEach, describe, it } from 'vitest';
7
6
 
8
7
  import { convertScriptTree } from './payments.utils.js';
9
8
  import { LEAF_VERSION_TAPSCRIPT } from '../src/payments/bip341.js';
10
9
  import { tapTreeFromList, tapTreeToList } from '../src/psbt/bip371.js';
11
- import type { Taptree, Bytes32, Script, Satoshi, PublicKey, Signature, EccLib } from '../src/types.js';
12
- import { initEccLib, networks as NETWORKS, payments, Psbt } from '../src/index.js';
13
- import type { Signer, SignerAsync, HDSigner, HDSignerAsync, ValidateSigFunction } from '../src/index.js';
10
+ import type { Bytes32, EccLib, MessageHash, PrivateKey, PublicKey, Satoshi, Script, Signature, Taptree, } from '../src/types.js';
11
+ import type { HDSigner, Signer, SignerAsync, ValidateSigFunction } from '../src/index.js';
12
+ import { initEccLib, networks, payments, Psbt } from '../src/index.js';
14
13
  import { equals } from '../src/io/index.js';
15
14
 
16
15
  import preFixtures from './fixtures/psbt.json' with { type: 'json' };
17
16
  import taprootFixtures from './fixtures/p2tr.json' with { type: 'json' };
17
+ import { ECPairSigner, createNobleBackend } from '@btc-vision/ecpair';
18
+ import type { Network } from '../src/networks.js';
18
19
 
19
20
  const bip32 = BIP32Factory(ecc);
20
- const ECPair = ECPairFactory(ecc);
21
+ const backend = createNobleBackend();
22
+ const ECPair = {
23
+ makeRandom: (opts?: { network?: Network }) =>
24
+ ECPairSigner.makeRandom(backend, opts?.network ?? networks.bitcoin),
25
+ fromWIF: (wif: string, network?: Network | Network[]) =>
26
+ ECPairSigner.fromWIF(backend, wif, network ?? networks.bitcoin),
27
+ fromPublicKey: (pubkey: Uint8Array, opts?: { network?: Network }) =>
28
+ ECPairSigner.fromPublicKey(backend, pubkey as PublicKey, opts?.network ?? networks.bitcoin),
29
+ fromPrivateKey: (key: Uint8Array, opts?: { network?: Network }) =>
30
+ ECPairSigner.fromPrivateKey(backend, key as PrivateKey, opts?.network ?? networks.bitcoin),
31
+ };
21
32
 
22
33
  const validator: ValidateSigFunction = (pubkey, msghash, signature): boolean =>
23
- ECPair.fromPublicKey(pubkey).verify(msghash, signature);
34
+ ECPair.fromPublicKey(pubkey).verify(msghash, signature as Signature);
24
35
 
25
36
  const schnorrValidator: ValidateSigFunction = (pubkey, msghash, signature): boolean =>
26
37
  ecc.verifySchnorr(msghash, pubkey, signature);
@@ -146,7 +157,7 @@ describe(`Psbt`, () => {
146
157
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
147
158
  // @ts-ignore // cannot find tapLeafHashToSign
148
159
  f.keys.forEach(({ inputToSign, tapLeafHashToSign, WIF }) => {
149
- const keyPair = ECPair.fromWIF(WIF, NETWORKS.testnet);
160
+ const keyPair = ECPair.fromWIF(WIF, networks.testnet);
150
161
  if (tapLeafHashToSign)
151
162
  psbt.signTaprootInput(
152
163
  inputToSign,
@@ -509,7 +520,10 @@ describe(`Psbt`, () => {
509
520
  const f = fixtures.finalizeInput.finalizeTapleafByHash;
510
521
  const psbt = Psbt.fromBase64(f.psbt);
511
522
 
512
- psbt.finalizeTaprootInput(f.index, Buffer.from(f.leafHash, 'hex') as unknown as Bytes32);
523
+ psbt.finalizeTaprootInput(
524
+ f.index,
525
+ Buffer.from(f.leafHash, 'hex') as unknown as Bytes32,
526
+ );
513
527
 
514
528
  assert.strictEqual(psbt.toBase64(), f.result);
515
529
  });
@@ -519,7 +533,10 @@ describe(`Psbt`, () => {
519
533
  const psbt = Psbt.fromBase64(f.psbt);
520
534
 
521
535
  assert.throws(() => {
522
- psbt.finalizeTaprootInput(f.index, Buffer.from(f.leafHash, 'hex').reverse() as unknown as Bytes32);
536
+ psbt.finalizeTaprootInput(
537
+ f.index,
538
+ Buffer.from(f.leafHash, 'hex').reverse() as unknown as Bytes32,
539
+ );
523
540
  }, new RegExp('Can not finalize taproot input #0. Signature for tapleaf script not found.'));
524
541
  });
525
542
 
@@ -557,7 +574,10 @@ describe(`Psbt`, () => {
557
574
  }, new RegExp('No script found for input #0'));
558
575
  psbt.updateInput(0, {
559
576
  witnessUtxo: {
560
- script: Buffer.from('0014d85c2b71d0060b09c9886aeb815e50991dda124d', 'hex') as unknown as Script,
577
+ script: Buffer.from(
578
+ '0014d85c2b71d0060b09c9886aeb815e50991dda124d',
579
+ 'hex',
580
+ ) as unknown as Script,
561
581
  value: 200000n as Satoshi,
562
582
  },
563
583
  });
@@ -730,7 +750,10 @@ describe(`Psbt`, () => {
730
750
  ...(redeemGetter ? { redeemScript: redeemGetter(publicKey) } : {}),
731
751
  ...(witnessGetter ? { witnessScript: witnessGetter(publicKey) } : {}),
732
752
  }).addOutput({
733
- script: Buffer.from('0014d85c2b71d0060b09c9886aeb815e50991dda124d', 'hex') as unknown as Script,
753
+ script: Buffer.from(
754
+ '0014d85c2b71d0060b09c9886aeb815e50991dda124d',
755
+ 'hex',
756
+ ) as unknown as Script,
734
757
  value: 1800n as Satoshi,
735
758
  });
736
759
  if (finalize) psbt.signInput(0, key).finalizeInput(0);
@@ -904,7 +927,10 @@ describe(`Psbt`, () => {
904
927
  hash: '0000000000000000000000000000000000000000000000000000000000000000',
905
928
  index: 0,
906
929
  }).addOutput({
907
- script: Buffer.from('0014000102030405060708090a0b0c0d0e0f00010203', 'hex') as unknown as Script,
930
+ script: Buffer.from(
931
+ '0014000102030405060708090a0b0c0d0e0f00010203',
932
+ 'hex',
933
+ ) as unknown as Script,
908
934
  value: 2000n as Satoshi,
909
935
  bip32Derivation: [
910
936
  {
@@ -936,7 +962,9 @@ describe(`Psbt`, () => {
936
962
  index: 0,
937
963
  }).addOutput({
938
964
  script: payments.p2sh({
939
- redeem: { output: Buffer.from([0x51]) as unknown as Script },
965
+ redeem: payments.p2wsh({
966
+ redeem: { output: scriptWithPubkey as unknown as Script },
967
+ }),
940
968
  }).output!,
941
969
  value: 1337n as Satoshi,
942
970
  });
@@ -945,31 +973,45 @@ describe(`Psbt`, () => {
945
973
  psbt.outputHasPubkey(0, testPubkey);
946
974
  }, new RegExp('scriptPubkey is P2SH but redeemScript missing'));
947
975
 
948
- (psbt as any).__CACHE.tx.outs[0].script = payments.p2wsh({
949
- redeem: { output: Buffer.from([0x51]) as unknown as Script },
950
- }).output!;
976
+ const psbt2 = new Psbt();
977
+ psbt2.addInput({
978
+ hash: '0000000000000000000000000000000000000000000000000000000000000000',
979
+ index: 0,
980
+ }).addOutput({
981
+ script: payments.p2wsh({
982
+ redeem: { output: Buffer.from([0x51]) as unknown as Script },
983
+ }).output!,
984
+ value: 1337n as Satoshi,
985
+ });
951
986
 
952
987
  assert.throws(() => {
953
- psbt.outputHasPubkey(0, testPubkey);
988
+ psbt2.outputHasPubkey(0, testPubkey);
954
989
  }, new RegExp('scriptPubkey or redeemScript is P2WSH but witnessScript missing'));
955
990
 
956
- (psbt as any).__CACHE.tx.outs[0].script = payments.p2sh({
957
- redeem: payments.p2wsh({
958
- redeem: { output: scriptWithPubkey as unknown as Script },
959
- }),
960
- }).output!;
991
+ const psbt3 = new Psbt();
992
+ psbt3.addInput({
993
+ hash: '0000000000000000000000000000000000000000000000000000000000000000',
994
+ index: 0,
995
+ }).addOutput({
996
+ script: payments.p2sh({
997
+ redeem: payments.p2wsh({
998
+ redeem: { output: scriptWithPubkey as unknown as Script },
999
+ }),
1000
+ }).output!,
1001
+ value: 1337n as Satoshi,
1002
+ });
961
1003
 
962
- psbt.updateOutput(0, {
1004
+ psbt3.updateOutput(0, {
963
1005
  redeemScript: payments.p2wsh({
964
1006
  redeem: { output: scriptWithPubkey as unknown as Script },
965
1007
  }).output!,
966
1008
  });
967
1009
 
968
1010
  assert.throws(() => {
969
- psbt.outputHasPubkey(0, testPubkey);
1011
+ psbt3.outputHasPubkey(0, testPubkey);
970
1012
  }, new RegExp('scriptPubkey or redeemScript is P2WSH but witnessScript missing'));
971
1013
 
972
- delete psbt.data.outputs[0].redeemScript;
1014
+ delete psbt3.data.outputs[0].redeemScript;
973
1015
 
974
1016
  psbt.updateOutput(0, {
975
1017
  witnessScript: scriptWithPubkey,
@@ -1003,7 +1045,8 @@ describe(`Psbt`, () => {
1003
1045
  assert.strictEqual(clone.toBase64(), psbt.toBase64());
1004
1046
  assert.strictEqual(clone.toBase64(), notAClone.toBase64());
1005
1047
  assert.strictEqual(psbt.toBase64(), notAClone.toBase64());
1006
- (psbt as any).__CACHE.tx.version |= 0xff0000;
1048
+ // Mutate data layer to prove clone is independent
1049
+ psbt.data.inputs[0].partialSig = [];
1007
1050
  assert.notStrictEqual(clone.toBase64(), psbt.toBase64());
1008
1051
  assert.notStrictEqual(clone.toBase64(), notAClone.toBase64());
1009
1052
  assert.strictEqual(psbt.toBase64(), notAClone.toBase64());
@@ -1014,9 +1057,9 @@ describe(`Psbt`, () => {
1014
1057
  it('Sets the maximumFeeRate value', () => {
1015
1058
  const psbt = new Psbt();
1016
1059
 
1017
- assert.strictEqual((psbt as any).opts.maximumFeeRate, 5000);
1060
+ assert.strictEqual(psbt.maximumFeeRate, 5000);
1018
1061
  psbt.setMaximumFeeRate(6000);
1019
- assert.strictEqual((psbt as any).opts.maximumFeeRate, 6000);
1062
+ assert.strictEqual(psbt.maximumFeeRate, 6000);
1020
1063
  });
1021
1064
  });
1022
1065
 
@@ -1154,11 +1197,149 @@ describe(`Psbt`, () => {
1154
1197
  psbt.finalizeAllInputs();
1155
1198
 
1156
1199
  assert.strictEqual(psbt.getFeeRate(), f.fee);
1157
- (psbt as any).__CACHE.feeRate = undefined;
1200
+ // Calling again returns the same cached value
1158
1201
  assert.strictEqual(psbt.getFeeRate(), f.fee);
1159
1202
  });
1160
1203
  });
1161
1204
 
1205
+ describe('getFee and getFeeRate return correct values', () => {
1206
+ it('computes fee as inputAmount - outputAmount for nonWitnessUtxo', () => {
1207
+ // nonWitnessUtxo output[0] = 90,000 sats; we send 80,000 sats => fee = 10,000 sats
1208
+ const alice = ECPair.fromWIF('L2uPYXe17xSTqbCjZvL2DsyXPCbXspvcu5mHLDYUgzdUbZGSKrSr');
1209
+ const psbt = new Psbt();
1210
+ const inputValue = 90_000n;
1211
+ const outputValue = 80_000n as Satoshi;
1212
+
1213
+ psbt.addInput({
1214
+ hash: '7d067b4a697a09d2c3cff7d4d9506c9955e93bff41bf82d439da7d030382bc3e',
1215
+ index: 0,
1216
+ nonWitnessUtxo: Buffer.from(
1217
+ '0200000001f9f34e95b9d5c8abcd20fc5bd4a825d1517be62f0f775e5f36da944d9' +
1218
+ '452e550000000006b483045022100c86e9a111afc90f64b4904bd609e9eaed80d48' +
1219
+ 'ca17c162b1aca0a788ac3526f002207bb79b60d4fc6526329bf18a77135dc566020' +
1220
+ '9e761da46e1c2f1152ec013215801210211755115eabf846720f5cb18f248666fec' +
1221
+ '631e5e1e66009ce3710ceea5b1ad13ffffffff01905f0100000000001976a9148bb' +
1222
+ 'c95d2709c71607c60ee3f097c1217482f518d88ac00000000',
1223
+ 'hex',
1224
+ ),
1225
+ sighashType: 1,
1226
+ });
1227
+ psbt.addOutput({
1228
+ address: '1KRMKfeZcmosxALVYESdPNez1AP1mEtywp',
1229
+ value: outputValue,
1230
+ });
1231
+ psbt.signInput(0, alice);
1232
+ psbt.finalizeAllInputs();
1233
+
1234
+ const expectedFee = Number(inputValue - outputValue); // 10,000
1235
+ const fee = psbt.getFee();
1236
+ assert.strictEqual(fee, expectedFee, `fee should be ${expectedFee}, got ${fee}`);
1237
+
1238
+ const tx = psbt.extractTransaction(true);
1239
+ const vsize = tx.virtualSize();
1240
+ const expectedFeeRate = Math.floor(expectedFee / vsize);
1241
+ const feeRate = psbt.getFeeRate();
1242
+ assert.strictEqual(
1243
+ feeRate,
1244
+ expectedFeeRate,
1245
+ `feeRate should be fee/vsize = ${expectedFee}/${vsize} = ${expectedFeeRate}, got ${feeRate}`,
1246
+ );
1247
+ });
1248
+
1249
+ it('computes fee as inputAmount - outputAmount for witnessUtxo', () => {
1250
+ const alice = ECPair.fromWIF('L2uPYXe17xSTqbCjZvL2DsyXPCbXspvcu5mHLDYUgzdUbZGSKrSr');
1251
+ const p2wpkh = payments.p2wpkh({ pubkey: alice.publicKey as PublicKey });
1252
+ const inputValue = 50_000n;
1253
+ const outputValue = 40_000n as Satoshi;
1254
+
1255
+ const psbt = new Psbt();
1256
+ psbt.addInput({
1257
+ hash: '0000000000000000000000000000000000000000000000000000000000000001',
1258
+ index: 0,
1259
+ witnessUtxo: {
1260
+ script: p2wpkh.output! as Script,
1261
+ value: inputValue as Satoshi,
1262
+ },
1263
+ });
1264
+ psbt.addOutput({
1265
+ address: '1KRMKfeZcmosxALVYESdPNez1AP1mEtywp',
1266
+ value: outputValue,
1267
+ });
1268
+ psbt.signInput(0, alice);
1269
+ psbt.finalizeAllInputs();
1270
+
1271
+ const expectedFee = Number(inputValue - outputValue); // 10,000
1272
+ const fee = psbt.getFee();
1273
+ assert.strictEqual(fee, expectedFee, `fee should be ${expectedFee}, got ${fee}`);
1274
+
1275
+ const tx = psbt.extractTransaction(true);
1276
+ const vsize = tx.virtualSize();
1277
+ const expectedFeeRate = Math.floor(expectedFee / vsize);
1278
+ const feeRate = psbt.getFeeRate();
1279
+ assert.strictEqual(
1280
+ feeRate,
1281
+ expectedFeeRate,
1282
+ `feeRate should be fee/vsize = ${expectedFee}/${vsize} = ${expectedFeeRate}, got ${feeRate}`,
1283
+ );
1284
+ assert.ok(feeRate > 0, 'feeRate must be positive');
1285
+ });
1286
+
1287
+ it('computes fee correctly with multiple inputs and outputs', () => {
1288
+ const alice = ECPair.fromWIF('L2uPYXe17xSTqbCjZvL2DsyXPCbXspvcu5mHLDYUgzdUbZGSKrSr');
1289
+ const p2wpkh = payments.p2wpkh({ pubkey: alice.publicKey as PublicKey });
1290
+
1291
+ const input1Value = 30_000n;
1292
+ const input2Value = 25_000n;
1293
+ const output1Value = 20_000n as Satoshi;
1294
+ const output2Value = 15_000n as Satoshi;
1295
+
1296
+ const psbt = new Psbt();
1297
+ psbt.addInput({
1298
+ hash: '0000000000000000000000000000000000000000000000000000000000000001',
1299
+ index: 0,
1300
+ witnessUtxo: {
1301
+ script: p2wpkh.output! as Script,
1302
+ value: input1Value as Satoshi,
1303
+ },
1304
+ });
1305
+ psbt.addInput({
1306
+ hash: '0000000000000000000000000000000000000000000000000000000000000002',
1307
+ index: 0,
1308
+ witnessUtxo: {
1309
+ script: p2wpkh.output! as Script,
1310
+ value: input2Value as Satoshi,
1311
+ },
1312
+ });
1313
+ psbt.addOutput({
1314
+ address: '1KRMKfeZcmosxALVYESdPNez1AP1mEtywp',
1315
+ value: output1Value,
1316
+ });
1317
+ psbt.addOutput({
1318
+ address: '1KRMKfeZcmosxALVYESdPNez1AP1mEtywp',
1319
+ value: output2Value,
1320
+ });
1321
+ psbt.signAllInputs(alice);
1322
+ psbt.finalizeAllInputs();
1323
+
1324
+ const totalIn = input1Value + input2Value; // 55,000
1325
+ const totalOut = output1Value + output2Value; // 35,000
1326
+ const expectedFee = Number(totalIn - totalOut); // 20,000
1327
+ const fee = psbt.getFee();
1328
+ assert.strictEqual(fee, expectedFee, `fee should be ${expectedFee}, got ${fee}`);
1329
+
1330
+ const tx = psbt.extractTransaction(true);
1331
+ const vsize = tx.virtualSize();
1332
+ const expectedFeeRate = Math.floor(expectedFee / vsize);
1333
+ const feeRate = psbt.getFeeRate();
1334
+ assert.strictEqual(
1335
+ feeRate,
1336
+ expectedFeeRate,
1337
+ `feeRate should be ${expectedFee}/${vsize} = ${expectedFeeRate}, got ${feeRate}`,
1338
+ );
1339
+ assert.ok(feeRate > 0, 'feeRate must be positive');
1340
+ });
1341
+ });
1342
+
1162
1343
  describe('create 1-to-1 transaction', () => {
1163
1344
  it('creates and signs a 1-to-1 transaction correctly', () => {
1164
1345
  const alice = ECPair.fromWIF('L2uPYXe17xSTqbCjZvL2DsyXPCbXspvcu5mHLDYUgzdUbZGSKrSr');
@@ -1213,49 +1394,56 @@ describe(`Psbt`, () => {
1213
1394
  ),
1214
1395
  );
1215
1396
  assert.strictEqual(psbt instanceof Psbt, true);
1216
- assert.ok((psbt as any).__CACHE.tx);
1397
+ assert.strictEqual(typeof psbt.version, 'number');
1217
1398
  });
1218
1399
  it('fromBase64 returns Psbt type (not base class)', () => {
1219
1400
  const psbt = Psbt.fromBase64('cHNidP8BAAoBAAAAAAAAAAAAAAAA');
1220
1401
  assert.strictEqual(psbt instanceof Psbt, true);
1221
- assert.ok((psbt as any).__CACHE.tx);
1402
+ assert.strictEqual(typeof psbt.version, 'number');
1222
1403
  });
1223
1404
  it('fromHex returns Psbt type (not base class)', () => {
1224
1405
  const psbt = Psbt.fromHex('70736274ff01000a01000000000000000000000000');
1225
1406
  assert.strictEqual(psbt instanceof Psbt, true);
1226
- assert.ok((psbt as any).__CACHE.tx);
1407
+ assert.strictEqual(typeof psbt.version, 'number');
1227
1408
  });
1228
1409
  });
1229
1410
 
1230
1411
  describe('Cache', () => {
1231
- it('non-witness UTXOs are cached', () => {
1412
+ it('non-witness UTXOs are stored after updateInput', () => {
1232
1413
  const f = fixtures.cache.nonWitnessUtxo;
1233
1414
  const psbt = Psbt.fromBase64(f.psbt);
1234
1415
  const index = f.inputIndex;
1235
1416
 
1236
- // Cache is empty
1237
- assert.strictEqual(
1238
- (psbt as any).__CACHE.nonWitnessUtxoBufCache[index],
1239
- undefined,
1240
- );
1417
+ // nonWitnessUtxo is not set before updateInput
1418
+ assert.strictEqual(psbt.data.inputs[index].nonWitnessUtxo, undefined);
1241
1419
 
1242
- // Cache is populated
1420
+ // After updateInput, the nonWitnessUtxo is stored on the input
1243
1421
  psbt.updateInput(index, {
1244
1422
  nonWitnessUtxo: f.nonWitnessUtxo as any,
1245
1423
  });
1246
- const value = psbt.data.inputs[index].nonWitnessUtxo;
1247
- assert.ok(equals((psbt as any).__CACHE.nonWitnessUtxoBufCache[index], value));
1424
+ assert.ok(psbt.data.inputs[index].nonWitnessUtxo);
1248
1425
  assert.ok(
1249
1426
  equals(
1250
- (psbt as any).__CACHE.nonWitnessUtxoBufCache[index],
1427
+ psbt.data.inputs[index].nonWitnessUtxo!,
1251
1428
  f.nonWitnessUtxo as any,
1252
1429
  ),
1253
1430
  );
1431
+ });
1432
+
1433
+ it('nonWitnessUtxo remains a plain data property (no defineProperty)', () => {
1434
+ const f = fixtures.cache.nonWitnessUtxo;
1435
+ const psbt = Psbt.fromBase64(f.psbt);
1436
+ const index = f.inputIndex;
1254
1437
 
1255
- // Cache is rebuilt from internal transaction object when cleared
1256
- psbt.data.inputs[index].nonWitnessUtxo = new Uint8Array([1, 2, 3]);
1257
- (psbt as any).__CACHE.nonWitnessUtxoBufCache[index] = undefined;
1258
- assert.ok(equals((psbt as any).data.inputs[index].nonWitnessUtxo!, value!));
1438
+ psbt.updateInput(index, {
1439
+ nonWitnessUtxo: f.nonWitnessUtxo as any,
1440
+ });
1441
+
1442
+ const input = psbt.data.inputs[index];
1443
+ const desc = Object.getOwnPropertyDescriptor(input, 'nonWitnessUtxo');
1444
+ assert.ok(desc, 'property should exist');
1445
+ assert.strictEqual(desc!.get, undefined, 'should not have a getter');
1446
+ assert.strictEqual(desc!.set, undefined, 'should not have a setter');
1259
1447
  });
1260
1448
  });
1261
1449
 
@@ -1264,22 +1452,18 @@ describe(`Psbt`, () => {
1264
1452
  const psbt = new Psbt();
1265
1453
 
1266
1454
  assert.strictEqual(psbt.version, 2);
1267
- assert.strictEqual(psbt.version, (psbt as any).__CACHE.tx.version);
1268
1455
 
1269
1456
  psbt.version = 1;
1270
1457
  assert.strictEqual(psbt.version, 1);
1271
- assert.strictEqual(psbt.version, (psbt as any).__CACHE.tx.version);
1272
1458
  });
1273
1459
 
1274
1460
  it('.locktime is exposed and is settable', () => {
1275
1461
  const psbt = new Psbt();
1276
1462
 
1277
1463
  assert.strictEqual(psbt.locktime, 0);
1278
- assert.strictEqual(psbt.locktime, (psbt as any).__CACHE.tx.locktime);
1279
1464
 
1280
1465
  psbt.locktime = 123;
1281
1466
  assert.strictEqual(psbt.locktime, 123);
1282
- assert.strictEqual(psbt.locktime, (psbt as any).__CACHE.tx.locktime);
1283
1467
  });
1284
1468
 
1285
1469
  it('.txInputs is exposed as a readonly clone', () => {
@@ -1289,19 +1473,20 @@ describe(`Psbt`, () => {
1289
1473
  psbt.addInput({ hash, index });
1290
1474
 
1291
1475
  const input = psbt.txInputs[0];
1292
- const internalInput = (psbt as any).__CACHE.tx.ins[0];
1293
-
1294
- assert.ok(equals(input.hash, internalInput.hash));
1295
- assert.strictEqual(input.index, internalInput.index);
1296
- assert.strictEqual(input.sequence, internalInput.sequence);
1476
+ const originalHash = new Uint8Array(input.hash);
1477
+ const originalIndex = input.index;
1478
+ const originalSequence = input.sequence;
1297
1479
 
1480
+ // Mutate the returned clone
1298
1481
  input.hash[0] = 123;
1299
1482
  input.index = 123;
1300
1483
  input.sequence = 123;
1301
1484
 
1302
- assert.ok(!equals(input.hash, internalInput.hash));
1303
- assert.notEqual(input.index, internalInput.index);
1304
- assert.notEqual(input.sequence, internalInput.sequence);
1485
+ // Internal state should be unchanged
1486
+ const fresh = psbt.txInputs[0];
1487
+ assert.ok(equals(fresh.hash, originalHash));
1488
+ assert.strictEqual(fresh.index, originalIndex);
1489
+ assert.strictEqual(fresh.sequence, originalSequence);
1305
1490
  });
1306
1491
 
1307
1492
  it('.txOutputs is exposed as a readonly clone', () => {
@@ -1311,18 +1496,19 @@ describe(`Psbt`, () => {
1311
1496
  psbt.addOutput({ address, value });
1312
1497
 
1313
1498
  const output = psbt.txOutputs[0];
1314
- const internalInput = (psbt as any).__CACHE.tx.outs[0];
1315
-
1316
1499
  assert.strictEqual(output.address, address);
1317
1500
 
1318
- assert.ok(equals(output.script, internalInput.script));
1319
- assert.strictEqual(output.value, internalInput.value);
1501
+ const originalScript = new Uint8Array(output.script);
1502
+ const originalValue = output.value;
1320
1503
 
1504
+ // Mutate the returned clone
1321
1505
  output.script[0] = 123;
1322
1506
  output.value = 123n;
1323
1507
 
1324
- assert.ok(!equals(output.script, internalInput.script));
1325
- assert.notEqual(output.value, internalInput.value);
1508
+ // Internal state should be unchanged
1509
+ const fresh = psbt.txOutputs[0];
1510
+ assert.ok(equals(fresh.script, originalScript));
1511
+ assert.strictEqual(fresh.value, originalValue);
1326
1512
  });
1327
1513
  });
1328
1514
  });
@@ -1,7 +1,7 @@
1
1
  import assert from 'assert';
2
2
  import { describe, it } from 'vitest';
3
3
  import { signature as bscriptSig } from '../src/script.js';
4
- import { toHex, fromHex, concat } from '../src/io/index.js';
4
+ import { concat, fromHex, toHex } from '../src/io/index.js';
5
5
  import fixtures from './fixtures/signature.json' with { type: 'json' };
6
6
 
7
7
  describe('Script Signatures', () => {
@@ -2,7 +2,7 @@ import assert from 'assert';
2
2
  import { beforeEach, describe, it } from 'vitest';
3
3
  import { Transaction } from '../src/index.js';
4
4
  import * as bscript from '../src/script.js';
5
- import type { Bytes32, Script, Satoshi } from '../src/types.js';
5
+ import type { Bytes32, Satoshi, Script } from '../src/types.js';
6
6
  import fixtures from './fixtures/transaction.json' with { type: 'json' };
7
7
 
8
8
  describe('Transaction', () => {
@@ -189,8 +189,14 @@ describe('Transaction', () => {
189
189
  describe('addOutput', () => {
190
190
  it('returns an index', () => {
191
191
  const tx = new Transaction();
192
- assert.strictEqual(tx.addOutput(Buffer.alloc(0) as unknown as Script, 0n as Satoshi), 0);
193
- assert.strictEqual(tx.addOutput(Buffer.alloc(0) as unknown as Script, 0n as Satoshi), 1);
192
+ assert.strictEqual(
193
+ tx.addOutput(Buffer.alloc(0) as unknown as Script, 0n as Satoshi),
194
+ 0,
195
+ );
196
+ assert.strictEqual(
197
+ tx.addOutput(Buffer.alloc(0) as unknown as Script, 0n as Satoshi),
198
+ 1,
199
+ );
194
200
  });
195
201
  });
196
202
 
@@ -293,7 +299,12 @@ describe('Transaction', () => {
293
299
  const tx = Transaction.fromHex(f.txHex);
294
300
  const script = bscript.fromASM(f.script);
295
301
 
296
- const hash = tx.hashForWitnessV0(f.inIndex, script, BigInt(f.value) as Satoshi, f.type);
302
+ const hash = tx.hashForWitnessV0(
303
+ f.inIndex,
304
+ script,
305
+ BigInt(f.value) as Satoshi,
306
+ f.type,
307
+ );
297
308
  assert.strictEqual(Buffer.from(hash).toString('hex'), f.hash);
298
309
  },
299
310
  );
@@ -303,7 +314,9 @@ describe('Transaction', () => {
303
314
  describe('taprootSigning', () => {
304
315
  fixtures.taprootSigning.forEach((f) => {
305
316
  const tx = Transaction.fromHex(f.txHex);
306
- const prevOutScripts = f.utxos.map(({ scriptHex }) => Buffer.from(scriptHex, 'hex')) as unknown as Script[];
317
+ const prevOutScripts = f.utxos.map(({ scriptHex }) =>
318
+ Buffer.from(scriptHex, 'hex'),
319
+ ) as unknown as Script[];
307
320
  const values = f.utxos.map(({ value }) => BigInt(value)) as Satoshi[];
308
321
 
309
322
  f.cases.forEach((c) => {
@@ -7,17 +7,9 @@
7
7
  "declaration": false,
8
8
  "allowSyntheticDefaultImports": true,
9
9
  "rootDir": "../",
10
- "rootDirs": [
11
- "../src",
12
- "../types"
13
- ],
14
- "types": [
15
- "node",
16
- "mocha"
17
- ],
18
- "lib": [
19
- "ES2021"
20
- ],
10
+ "rootDirs": ["../src", "../types"],
11
+ "types": ["node"],
12
+ "lib": ["ES2021"],
21
13
  "resolvePackageJsonImports": true,
22
14
  "allowJs": false,
23
15
  "resolveJsonModule": true,
@@ -34,15 +26,9 @@
34
26
  "noUnusedParameters": true,
35
27
  "baseUrl": ".",
36
28
  "paths": {
37
- "../src/*": [
38
- "../ts_src/*"
39
- ]
29
+ "../src/*": ["../ts_src/*"]
40
30
  }
41
31
  },
42
- "include": [
43
- "./**/*.ts"
44
- ],
45
- "exclude": [
46
- "../ts_src/**/*.ts"
47
- ]
32
+ "include": ["./**/*.ts"],
33
+ "exclude": ["../ts_src/**/*.ts"]
48
34
  }