@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
@@ -0,0 +1,1400 @@
1
+ # PSBT (Partially Signed Bitcoin Transaction) - BIP 174
2
+
3
+ PSBT is a standardized binary format for unsigned and partially signed Bitcoin transactions. It allows multiple participants (wallets, hardware signers, coordinators) to collaboratively construct, sign, and finalize a transaction without requiring direct access to each other's private keys. This library implements BIP 174 with extensions for BIP 371 (Taproot).
4
+
5
+ ## Overview
6
+
7
+ | Property | Value |
8
+ |----------|-------|
9
+ | BIP | 174 (base), 371 (Taproot extensions) |
10
+ | Format | Binary with base64/hex serialization |
11
+ | Module entry | `src/psbt.ts` |
12
+ | Internal modules | `PsbtCache`, `PsbtSigner`, `PsbtFinalizer`, `PsbtTransaction` |
13
+ | Supported script types | P2PKH, P2WPKH, P2SH, P2WSH, P2SH-P2WSH, P2TR, P2MR, P2MS, P2PK, P2OP, P2A |
14
+
15
+ ### BIP 174 Roles
16
+
17
+ The PSBT specification defines six roles that the `Psbt` class fulfills:
18
+
19
+ | Role | Description | Methods |
20
+ |------|-------------|---------|
21
+ | **Creator** | Creates a new empty PSBT | `new Psbt()` |
22
+ | **Updater** | Adds inputs, outputs, and metadata | `addInput()`, `addOutput()`, `updateInput()`, `updateOutput()`, `updateGlobal()` |
23
+ | **Signer** | Signs inputs with private keys | `signInput()`, `signAllInputs()`, `signInputAsync()`, `signAllInputsAsync()` |
24
+ | **Combiner** | Merges multiple PSBTs for the same transaction | `combine()` |
25
+ | **Input Finalizer** | Constructs final scriptSigs and witnesses | `finalizeInput()`, `finalizeAllInputs()` |
26
+ | **Transaction Extractor** | Produces the final signed transaction | `extractTransaction()` |
27
+
28
+ ---
29
+
30
+ ## Installation
31
+
32
+ ```typescript
33
+ import {
34
+ Psbt,
35
+ // Types
36
+ type PsbtOpts,
37
+ type PsbtOptsOptional,
38
+ type PsbtInputExtended,
39
+ type PsbtOutputExtended,
40
+ type Signer,
41
+ type SignerAsync,
42
+ type HDSigner,
43
+ type HDSignerAsync,
44
+ type ValidateSigFunction,
45
+ type FinalScriptsFunc,
46
+ type FinalTaprootScriptsFunc,
47
+ type AllScriptType,
48
+ type PsbtTxInput,
49
+ type PsbtTxOutput,
50
+ // Utilities
51
+ getFinalScripts,
52
+ prepareFinalScripts,
53
+ PsbtCache,
54
+ PsbtSigner,
55
+ PsbtFinalizer,
56
+ PsbtTransaction,
57
+ transactionFromBuffer,
58
+ } from '@btc-vision/bitcoin';
59
+ ```
60
+
61
+ ---
62
+
63
+ ## Class: Psbt
64
+
65
+ ### Constructor
66
+
67
+ ```typescript
68
+ class Psbt {
69
+ constructor(opts?: PsbtOptsOptional, data?: PsbtBaseExtended);
70
+ }
71
+ ```
72
+
73
+ **Parameters:**
74
+
75
+ | Parameter | Type | Default | Description |
76
+ |-----------|------|---------|-------------|
77
+ | `opts` | `PsbtOptsOptional` | `{}` | Configuration options (network, maximumFeeRate, version) |
78
+ | `data` | `PsbtBaseExtended` | `new PsbtBase(new PsbtTransaction())` | Pre-existing PSBT data (used internally by deserialization) |
79
+
80
+ If `opts.version` is `3`, the transaction version is set to TRUC (Topologically Restricted Until Confirmation). Otherwise, if no inputs exist, the version defaults to `2`.
81
+
82
+ ### Properties
83
+
84
+ | Property | Type | Description |
85
+ |----------|------|-------------|
86
+ | `inputCount` | `number` | Number of inputs in the PSBT |
87
+ | `version` | `number` | Transaction version (get/set) |
88
+ | `locktime` | `number` | Transaction locktime (get/set) |
89
+ | `txInputs` | `PsbtTxInput[]` | Read-only cloned array of transaction inputs |
90
+ | `txOutputs` | `PsbtTxOutput[]` | Read-only cloned array of transaction outputs with decoded addresses |
91
+ | `maximumFeeRate` | `number` | Current maximum fee rate in satoshis per byte |
92
+ | `data` | `PsbtBaseExtended` | The underlying BIP 174 data structure |
93
+
94
+ ### Static Deserialization Methods
95
+
96
+ ```typescript
97
+ // From base64 string
98
+ static fromBase64(data: string, opts?: PsbtOptsOptional): Psbt;
99
+
100
+ // From hex string
101
+ static fromHex(data: string, opts?: PsbtOptsOptional): Psbt;
102
+
103
+ // From binary buffer
104
+ static fromBuffer(buffer: Uint8Array, opts?: PsbtOptsOptional): Psbt;
105
+ ```
106
+
107
+ All deserialization methods check for duplicate inputs and detect existing signatures.
108
+
109
+ ---
110
+
111
+ ## Creating a PSBT
112
+
113
+ ### addInput
114
+
115
+ ```typescript
116
+ addInput(inputData: PsbtInputExtended, checkPartialSigs?: boolean): this;
117
+ addInputs(inputDatas: PsbtInputExtended[], checkPartialSigs?: boolean): this;
118
+ ```
119
+
120
+ Adds one or more inputs to the PSBT. Each input requires at minimum a `hash` (the TXID of the previous transaction) and an `index` (the output index being spent).
121
+
122
+ **Parameters:**
123
+
124
+ | Parameter | Type | Default | Description |
125
+ |-----------|------|---------|-------------|
126
+ | `inputData` | `PsbtInputExtended` | (required) | Input data with at least `hash` and `index` |
127
+ | `checkPartialSigs` | `boolean` | `true` | Whether to check if existing signatures prevent modification |
128
+
129
+ **PsbtInputExtended fields:**
130
+
131
+ | Field | Type | Required | Description |
132
+ |-------|------|----------|-------------|
133
+ | `hash` | `string \| Bytes32` | Yes | Previous transaction hash (TXID) |
134
+ | `index` | `number` | Yes | Output index in the previous transaction |
135
+ | `sequence` | `number` | No | Input sequence number |
136
+ | `witnessUtxo` | `{ script: Script; value: bigint }` | Conditional | UTXO data for segwit inputs |
137
+ | `nonWitnessUtxo` | `Uint8Array` | Conditional | Full previous transaction for non-segwit inputs |
138
+ | `redeemScript` | `Uint8Array` | No | Redeem script for P2SH inputs |
139
+ | `witnessScript` | `Uint8Array` | No | Witness script for P2WSH inputs |
140
+ | `bip32Derivation` | `Bip32Derivation[]` | No | BIP 32 derivation paths for HD signing |
141
+ | `tapInternalKey` | `Uint8Array` | No | Taproot internal key (32 bytes, x-only) |
142
+ | `tapMerkleRoot` | `Uint8Array` | No | Taproot Merkle root |
143
+ | `tapLeafScript` | `TapLeafScript[]` | No | Taproot leaf scripts with control blocks |
144
+ | `tapBip32Derivation` | `TapBip32Derivation[]` | No | Taproot BIP 32 derivation paths |
145
+ | `sighashType` | `number` | No | Sighash type for this input |
146
+ | `isPayToAnchor` | `boolean` | No | Whether this is a Pay-to-Anchor input |
147
+
148
+ **Example:**
149
+
150
+ ```typescript
151
+ const psbt = new Psbt();
152
+
153
+ // Add a segwit input
154
+ psbt.addInput({
155
+ hash: 'abc123...', // TXID as hex string
156
+ index: 0,
157
+ witnessUtxo: {
158
+ script: Buffer.from('0014...', 'hex'), // scriptPubKey
159
+ value: 100000n, // in satoshis (bigint)
160
+ },
161
+ });
162
+
163
+ // Add a non-segwit input
164
+ psbt.addInput({
165
+ hash: txidBuffer, // TXID as Uint8Array (reversed)
166
+ index: 1,
167
+ nonWitnessUtxo: fullPreviousTxBuffer,
168
+ });
169
+ ```
170
+
171
+ ### addOutput
172
+
173
+ ```typescript
174
+ addOutput(outputData: PsbtOutputExtended, checkPartialSigs?: boolean): this;
175
+ addOutputs(outputDatas: PsbtOutputExtended[], checkPartialSigs?: boolean): this;
176
+ ```
177
+
178
+ Adds one or more outputs. Each output requires a `value` and either an `address` or a `script`.
179
+
180
+ **PsbtOutputExtended** is a union of two forms:
181
+
182
+ ```typescript
183
+ // Address-based output
184
+ interface PsbtOutputExtendedAddress {
185
+ readonly address: string;
186
+ readonly value: Satoshi; // bigint
187
+ }
188
+
189
+ // Script-based output
190
+ interface PsbtOutputExtendedScript {
191
+ readonly script: Script; // Uint8Array
192
+ readonly value: Satoshi; // bigint
193
+ }
194
+ ```
195
+
196
+ **Example:**
197
+
198
+ ```typescript
199
+ // Output by address
200
+ psbt.addOutput({
201
+ address: 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4',
202
+ value: 50000n,
203
+ });
204
+
205
+ // Output by script
206
+ psbt.addOutput({
207
+ script: outputScript,
208
+ value: 50000n,
209
+ });
210
+ ```
211
+
212
+ ---
213
+
214
+ ## Signing
215
+
216
+ The PSBT class provides both synchronous and asynchronous signing methods. Async methods are useful for hardware wallets and remote signing services.
217
+
218
+ ### signInput / signInputAsync
219
+
220
+ ```typescript
221
+ signInput(inputIndex: number, keyPair: Signer | HDSigner, sighashTypes?: number[]): this;
222
+
223
+ signInputAsync(
224
+ inputIndex: number,
225
+ keyPair: Signer | SignerAsync | HDSigner | HDSignerAsync,
226
+ sighashTypes?: number[],
227
+ ): Promise<void>;
228
+ ```
229
+
230
+ Signs a specific input. The method automatically detects whether the input is a Taproot input and routes to the appropriate signing logic.
231
+
232
+ **Parameters:**
233
+
234
+ | Parameter | Type | Default | Description |
235
+ |-----------|------|---------|-------------|
236
+ | `inputIndex` | `number` | (required) | Index of the input to sign |
237
+ | `keyPair` | `Signer \| HDSigner` | (required) | Key pair with signing capability |
238
+ | `sighashTypes` | `number[]` | `[SIGHASH_ALL]` | Allowed sighash types |
239
+
240
+ ### signAllInputs / signAllInputsAsync
241
+
242
+ ```typescript
243
+ signAllInputs(keyPair: Signer | HDSigner, sighashTypes?: number[]): this;
244
+
245
+ signAllInputsAsync(
246
+ keyPair: Signer | SignerAsync | HDSigner | HDSignerAsync,
247
+ sighashTypes?: number[],
248
+ ): Promise<void>;
249
+ ```
250
+
251
+ Attempts to sign every input with the provided key pair. Silently skips inputs that do not match the key. Throws only if no inputs were signed at all.
252
+
253
+ ### signTaprootInput / signTaprootInputAsync
254
+
255
+ ```typescript
256
+ signTaprootInput(
257
+ inputIndex: number,
258
+ keyPair: Signer | HDSigner,
259
+ tapLeafHashToSign?: Uint8Array,
260
+ sighashTypes?: number[],
261
+ ): this;
262
+
263
+ signTaprootInputAsync(
264
+ inputIndex: number,
265
+ keyPair: Signer | SignerAsync | HDSigner | HDSignerAsync,
266
+ tapLeafHash?: Uint8Array,
267
+ sighashTypes?: number[],
268
+ ): Promise<void>;
269
+ ```
270
+
271
+ Explicitly signs a Taproot input. Throws if the input is not a Taproot input. The optional `tapLeafHashToSign` restricts signing to a specific tap leaf.
272
+
273
+ **Default sighash types:**
274
+ - Non-Taproot: `[Transaction.SIGHASH_ALL]`
275
+ - Taproot: `[Transaction.SIGHASH_DEFAULT]`
276
+
277
+ ### HD Signing
278
+
279
+ ```typescript
280
+ signInputHD(inputIndex: number, hdKeyPair: HDSigner, sighashTypes?: number[]): this;
281
+ signInputHDAsync(inputIndex: number, hdKeyPair: HDSigner | HDSignerAsync, sighashTypes?: number[]): Promise<void>;
282
+
283
+ signAllInputsHD(hdKeyPair: HDSigner, sighashTypes?: number[]): this;
284
+ signAllInputsHDAsync(hdKeyPair: HDSigner | HDSignerAsync, sighashTypes?: number[]): Promise<void>;
285
+ ```
286
+
287
+ Signs using an HD key pair. The method derives child keys from `bip32Derivation` data in each input and signs with the derived keys.
288
+
289
+ **Example:**
290
+
291
+ ```typescript
292
+ import { ECPairSigner, createNobleBackend } from '@btc-vision/ecpair';
293
+ import { networks } from '@btc-vision/bitcoin';
294
+
295
+ const backend = createNobleBackend();
296
+
297
+ // Synchronous signing
298
+ const keyPair = ECPairSigner.fromWIF(backend, 'L1...', networks.bitcoin);
299
+ psbt.signAllInputs(keyPair);
300
+
301
+ // Async signing (e.g., hardware wallet)
302
+ await psbt.signAllInputsAsync(hardwareWalletSigner);
303
+
304
+ // HD signing
305
+ const hdRoot = bip32.fromSeed(seed);
306
+ psbt.signAllInputsHD(hdRoot);
307
+ ```
308
+
309
+ ---
310
+
311
+ ## Finalizing
312
+
313
+ Finalization constructs the final `scriptSig` and/or `witness` for each input from the collected partial signatures. After finalization, PSBT metadata no longer needed is cleared.
314
+
315
+ ### finalizeAllInputs
316
+
317
+ ```typescript
318
+ finalizeAllInputs(): this;
319
+ ```
320
+
321
+ Finalizes every input. Throws if any input cannot be finalized.
322
+
323
+ ### finalizeInput
324
+
325
+ ```typescript
326
+ finalizeInput(
327
+ inputIndex: number,
328
+ finalScriptsFunc?: FinalScriptsFunc | FinalTaprootScriptsFunc,
329
+ canRunChecks?: boolean,
330
+ ): this;
331
+ ```
332
+
333
+ Finalizes a specific input. Automatically detects Taproot inputs and routes to the appropriate finalizer.
334
+
335
+ **Parameters:**
336
+
337
+ | Parameter | Type | Default | Description |
338
+ |-----------|------|---------|-------------|
339
+ | `inputIndex` | `number` | (required) | Input index to finalize |
340
+ | `finalScriptsFunc` | `FinalScriptsFunc \| FinalTaprootScriptsFunc` | `getFinalScripts` or `tapScriptFinalizer` | Custom finalization function |
341
+ | `canRunChecks` | `boolean` | `true` | Whether to verify signatures can produce a valid final script |
342
+
343
+ ### finalizeTaprootInput
344
+
345
+ ```typescript
346
+ finalizeTaprootInput(
347
+ inputIndex: number,
348
+ tapLeafHashToFinalize?: Bytes32,
349
+ finalScriptsFunc?: FinalTaprootScriptsFunc,
350
+ ): this;
351
+ ```
352
+
353
+ Explicitly finalizes a Taproot input. If a `tapKeySig` is present, it creates a key-path spend witness. Otherwise, it uses the `finalScriptsFunc` to construct a script-path spend.
354
+
355
+ **Example:**
356
+
357
+ ```typescript
358
+ // Finalize all inputs
359
+ psbt.finalizeAllInputs();
360
+
361
+ // Finalize a specific input with custom logic
362
+ psbt.finalizeInput(0, myCustomFinalizer);
363
+
364
+ // Finalize a Taproot input for a specific leaf
365
+ psbt.finalizeTaprootInput(0, leafHash);
366
+ ```
367
+
368
+ ---
369
+
370
+ ## getFinalScripts and prepareFinalScripts
371
+
372
+ These standalone functions handle the construction of final scripts during finalization.
373
+
374
+ ### getFinalScripts
375
+
376
+ ```typescript
377
+ function getFinalScripts(
378
+ inputIndex: number,
379
+ input: PsbtInput,
380
+ script: Script,
381
+ isSegwit: boolean,
382
+ isP2SH: boolean,
383
+ isP2WSH: boolean,
384
+ canRunChecks?: boolean,
385
+ solution?: Uint8Array[],
386
+ ): {
387
+ finalScriptSig: Script | undefined;
388
+ finalScriptWitness: Uint8Array | undefined;
389
+ };
390
+ ```
391
+
392
+ The default finalization function. It classifies the script, checks that enough signatures are present (via `canFinalize`), and delegates to `prepareFinalScripts`.
393
+
394
+ ### prepareFinalScripts
395
+
396
+ ```typescript
397
+ function prepareFinalScripts(
398
+ script: Uint8Array,
399
+ scriptType: string,
400
+ partialSig: PartialSig[],
401
+ isSegwit: boolean,
402
+ isP2SH: boolean,
403
+ isP2WSH: boolean,
404
+ solution?: Uint8Array[],
405
+ ): {
406
+ finalScriptSig: Script | undefined;
407
+ finalScriptWitness: Uint8Array | undefined;
408
+ };
409
+ ```
410
+
411
+ Constructs the final `scriptSig` and/or `witness` from partial signatures. Handles P2PKH, P2PK, P2WPKH, P2MS (multisig), and nonstandard scripts. Wraps the result in P2SH or P2WSH as needed.
412
+
413
+ ---
414
+
415
+ ## Extracting
416
+
417
+ ### extractTransaction
418
+
419
+ ```typescript
420
+ extractTransaction(disableFeeCheck?: boolean, disableOutputChecks?: boolean): Transaction;
421
+ ```
422
+
423
+ Extracts the final signed `Transaction` object from the PSBT.
424
+
425
+ **Parameters:**
426
+
427
+ | Parameter | Type | Default | Description |
428
+ |-----------|------|---------|-------------|
429
+ | `disableFeeCheck` | `boolean` | `false` | Skip fee rate validation |
430
+ | `disableOutputChecks` | `boolean` | `false` | Skip output amount validation; filters out inputs with partial sigs |
431
+
432
+ **Validation:**
433
+ - All inputs must be finalized (have `finalScriptSig` or `finalScriptWitness`)
434
+ - Unless `disableFeeCheck` is `true`, the fee rate must be below `maximumFeeRate`
435
+ - Unless `disableOutputChecks` is `true`, output amounts must not exceed input amounts
436
+
437
+ ```typescript
438
+ const tx = psbt.extractTransaction();
439
+ const txHex = tx.toHex(); // Ready to broadcast
440
+ ```
441
+
442
+ ### getFeeRate / getFee
443
+
444
+ ```typescript
445
+ getFeeRate(disableOutputChecks?: boolean): number; // satoshis per vbyte
446
+ getFee(disableOutputChecks?: boolean): number; // total fee in satoshis
447
+ ```
448
+
449
+ Compute the fee rate and total fee of the finalized PSBT. Both require all inputs to be finalized.
450
+
451
+ ---
452
+
453
+ ## Serialization
454
+
455
+ ### toBuffer / toHex / toBase64
456
+
457
+ ```typescript
458
+ toBuffer(): Uint8Array;
459
+ toHex(): string;
460
+ toBase64(): string;
461
+ ```
462
+
463
+ Serializes the PSBT to binary, hex, or base64 format. Throws if the cache is in an unsafe state (e.g., `unsafeSignNonSegwit` was used).
464
+
465
+ ### clone
466
+
467
+ ```typescript
468
+ clone(): Psbt;
469
+ ```
470
+
471
+ Creates a deep copy of the PSBT by serializing to buffer and deserializing.
472
+
473
+ ### combine
474
+
475
+ ```typescript
476
+ combine(...those: Psbt[]): this;
477
+ ```
478
+
479
+ Merges other PSBTs into this one. All PSBTs must share the same unsigned transaction. The calling PSBT takes precedence on conflicts.
480
+
481
+ **Example:**
482
+
483
+ ```typescript
484
+ // Serialize for transport
485
+ const base64 = psbt.toBase64();
486
+
487
+ // Deserialize
488
+ const restored = Psbt.fromBase64(base64);
489
+
490
+ // Clone
491
+ const copy = psbt.clone();
492
+
493
+ // Combine partial signatures from multiple signers
494
+ const combined = psbt1.combine(psbt2, psbt3);
495
+ ```
496
+
497
+ ---
498
+
499
+ ## Validation
500
+
501
+ ### validateSignaturesOfAllInputs
502
+
503
+ ```typescript
504
+ validateSignaturesOfAllInputs(validator: ValidateSigFunction): boolean;
505
+ ```
506
+
507
+ Validates signatures for every input. Returns `true` only if all inputs pass validation.
508
+
509
+ ### validateSignaturesOfInput
510
+
511
+ ```typescript
512
+ validateSignaturesOfInput(
513
+ inputIndex: number,
514
+ validator: ValidateSigFunction,
515
+ pubkey?: PublicKey,
516
+ ): boolean;
517
+ ```
518
+
519
+ Validates signatures for a specific input. Optionally filters to signatures for a specific pubkey. Automatically handles both standard and Taproot inputs.
520
+
521
+ **ValidateSigFunction:**
522
+
523
+ ```typescript
524
+ type ValidateSigFunction = (
525
+ pubkey: PublicKey,
526
+ msghash: MessageHash,
527
+ signature: Uint8Array,
528
+ ) => boolean;
529
+ ```
530
+
531
+ The `msghash` is a 32-byte hash of the signing preimage. The `signature` is a 64-byte compact signature (r, s, 32 bytes each).
532
+
533
+ **Example:**
534
+
535
+ ```typescript
536
+ import * as ecc from 'tiny-secp256k1';
537
+
538
+ const validator = (pubkey, msghash, signature) => {
539
+ return ecc.verify(msghash, pubkey, signature);
540
+ };
541
+
542
+ const isValid = psbt.validateSignaturesOfAllInputs(validator);
543
+ ```
544
+
545
+ ### inputHasPubkey / outputHasPubkey
546
+
547
+ ```typescript
548
+ inputHasPubkey(inputIndex: number, pubkey: PublicKey): boolean;
549
+ outputHasPubkey(outputIndex: number, pubkey: PublicKey): boolean;
550
+ ```
551
+
552
+ Checks if a public key is referenced in the script of a specific input or output.
553
+
554
+ ### inputHasHDKey / outputHasHDKey
555
+
556
+ ```typescript
557
+ inputHasHDKey(inputIndex: number, root: HDSigner): boolean;
558
+ outputHasHDKey(outputIndex: number, root: HDSigner): boolean;
559
+ ```
560
+
561
+ Checks if an HD key pair's derivation path is present in the BIP 32 derivation data of a specific input or output.
562
+
563
+ ### getInputType
564
+
565
+ ```typescript
566
+ getInputType(inputIndex: number): AllScriptType;
567
+ ```
568
+
569
+ Returns the script type of a specific input as a compound string such as `'witnesspubkeyhash'`, `'p2sh-witnesspubkeyhash'`, `'p2wsh-multisig'`, `'p2sh-p2wsh-pubkeyhash'`, etc.
570
+
571
+ ---
572
+
573
+ ## Updating
574
+
575
+ ### updateInput / updateOutput / updateGlobal
576
+
577
+ ```typescript
578
+ updateInput(inputIndex: number, updateData: PsbtInputUpdate): this;
579
+ updateOutput(outputIndex: number, updateData: PsbtOutputUpdate): this;
580
+ updateGlobal(updateData: PsbtGlobalUpdate): this;
581
+ ```
582
+
583
+ Updates metadata on existing inputs, outputs, or global fields. Validates Taproot fields to prevent mixing Taproot and non-Taproot data.
584
+
585
+ ### setVersion / setLocktime / setInputSequence
586
+
587
+ ```typescript
588
+ setVersion(version: number): this;
589
+ setVersionTRUC(): this; // Sets version to TRUC (v3)
590
+ setLocktime(locktime: number): this;
591
+ setInputSequence(inputIndex: number, sequence: number): this;
592
+ setMaximumFeeRate(satoshiPerByte: number): void;
593
+ ```
594
+
595
+ All setters validate that the value is a 32-bit unsigned integer and that existing signatures permit the modification (based on sighash flags).
596
+
597
+ ### addUnknownKeyVal
598
+
599
+ ```typescript
600
+ addUnknownKeyValToGlobal(keyVal: KeyValue): this;
601
+ addUnknownKeyValToInput(inputIndex: number, keyVal: KeyValue): this;
602
+ addUnknownKeyValToOutput(outputIndex: number, keyVal: KeyValue): this;
603
+ ```
604
+
605
+ Adds proprietary or unknown key-value pairs for custom extensions.
606
+
607
+ ### clearFinalizedInput
608
+
609
+ ```typescript
610
+ clearFinalizedInput(inputIndex: number): this;
611
+ ```
612
+
613
+ Clears finalization data from a specific input, allowing re-finalization.
614
+
615
+ ---
616
+
617
+ ## Signer Interfaces
618
+
619
+ All signer interfaces are re-exported from `@btc-vision/ecpair`.
620
+
621
+ ### Signer
622
+
623
+ ```typescript
624
+ interface Signer {
625
+ readonly publicKey: PublicKey; // SEC1-encoded (33 or 65 bytes)
626
+ readonly network?: Network | undefined;
627
+ sign(hash: MessageHash, lowR?: boolean): Signature;
628
+ signSchnorr?(hash: MessageHash): SchnorrSignature; // Required for Taproot
629
+ }
630
+ ```
631
+
632
+ ### SignerAsync
633
+
634
+ ```typescript
635
+ interface SignerAsync {
636
+ readonly publicKey: PublicKey;
637
+ readonly network?: Network | undefined;
638
+ sign(hash: MessageHash, lowR?: boolean): Promise<Signature>;
639
+ signSchnorr?(hash: MessageHash): Promise<SchnorrSignature>;
640
+ }
641
+ ```
642
+
643
+ ### HDSigner
644
+
645
+ ```typescript
646
+ interface HDSigner {
647
+ readonly publicKey: PublicKey;
648
+ readonly fingerprint: Uint8Array; // First 4 bytes of hash160(publicKey)
649
+ derivePath(path: string): HDSigner;
650
+ sign(hash: MessageHash): Uint8Array;
651
+ }
652
+ ```
653
+
654
+ ### HDSignerAsync
655
+
656
+ ```typescript
657
+ interface HDSignerAsync {
658
+ readonly publicKey: PublicKey;
659
+ readonly fingerprint: Uint8Array;
660
+ derivePath(path: string): HDSignerAsync;
661
+ sign(hash: MessageHash): Promise<Uint8Array>;
662
+ }
663
+ ```
664
+
665
+ ### TaprootHashCheckSigner
666
+
667
+ A minimal signer interface used by `checkTaprootHashesForSig`. It only requires `publicKey` and optionally `signSchnorr`.
668
+
669
+ ```typescript
670
+ interface TaprootHashCheckSigner {
671
+ readonly publicKey: Uint8Array;
672
+ signSchnorr?(hash: Uint8Array): Uint8Array | Promise<Uint8Array>;
673
+ }
674
+ ```
675
+
676
+ ---
677
+
678
+ ## Options and Configuration
679
+
680
+ ### PsbtOpts
681
+
682
+ ```typescript
683
+ interface PsbtOpts {
684
+ readonly network: Network;
685
+ maximumFeeRate: number; // Satoshis per byte; default 5000
686
+ }
687
+ ```
688
+
689
+ ### PsbtOptsOptional
690
+
691
+ ```typescript
692
+ interface PsbtOptsOptional {
693
+ readonly network?: Network | undefined;
694
+ readonly maximumFeeRate?: number | undefined;
695
+ readonly version?: 1 | 2 | 3 | undefined; // 3 = TRUC version
696
+ }
697
+ ```
698
+
699
+ **Default options:**
700
+
701
+ ```typescript
702
+ const DEFAULT_OPTS: PsbtOpts = {
703
+ network: bitcoin, // mainnet
704
+ maximumFeeRate: 5000, // 5000 sat/vB
705
+ };
706
+ ```
707
+
708
+ ---
709
+
710
+ ## Script Type Detection
711
+
712
+ The `psbtutils` module provides factory functions for detecting script types. Each returns a boolean.
713
+
714
+ ```typescript
715
+ import {
716
+ isP2MS, // Pay-to-Multisig
717
+ isP2PK, // Pay-to-PubKey
718
+ isP2PKH, // Pay-to-PubKeyHash
719
+ isP2WPKH, // Pay-to-Witness-PubKeyHash
720
+ isP2WSHScript,// Pay-to-Witness-ScriptHash
721
+ isP2SHScript, // Pay-to-ScriptHash
722
+ isP2TR, // Pay-to-Taproot (BIP 341)
723
+ isP2MR, // Pay-to-Merkle-Root (BIP 360)
724
+ isP2OP, // Pay-to-OP_NET
725
+ isP2A, // Pay-to-Anchor
726
+ } from '@btc-vision/bitcoin';
727
+ ```
728
+
729
+ ### isP2A (Pay-to-Anchor)
730
+
731
+ P2A is detected by a fixed 4-byte pattern:
732
+
733
+ ```
734
+ OP_1 (0x51) PUSH2 (0x02) 0x4e 0x73
735
+ ```
736
+
737
+ ### classifyScript
738
+
739
+ ```typescript
740
+ function classifyScript(script: Uint8Array): ScriptType;
741
+ ```
742
+
743
+ Returns one of: `'witnesspubkeyhash'`, `'pubkeyhash'`, `'multisig'`, `'pubkey'`, `'nonstandard'`.
744
+
745
+ ### AllScriptType
746
+
747
+ The complete union of compound script types returned by `getInputType()`:
748
+
749
+ ```typescript
750
+ type AllScriptType =
751
+ | 'witnesspubkeyhash'
752
+ | 'pubkeyhash'
753
+ | 'multisig'
754
+ | 'pubkey'
755
+ | 'nonstandard'
756
+ | 'p2sh-witnesspubkeyhash'
757
+ | 'p2sh-pubkeyhash'
758
+ | 'p2sh-multisig'
759
+ | 'p2sh-pubkey'
760
+ | 'p2sh-nonstandard'
761
+ | 'p2wsh-pubkeyhash'
762
+ | 'p2wsh-multisig'
763
+ | 'p2wsh-pubkey'
764
+ | 'p2wsh-nonstandard'
765
+ | 'p2sh-p2wsh-pubkeyhash'
766
+ | 'p2sh-p2wsh-multisig'
767
+ | 'p2sh-p2wsh-pubkey'
768
+ | 'p2sh-p2wsh-nonstandard';
769
+ ```
770
+
771
+ ---
772
+
773
+ ## BIP 371 Taproot Extensions
774
+
775
+ The `bip371` module provides Taproot-specific utilities for PSBT construction and finalization.
776
+
777
+ ### isTaprootInput
778
+
779
+ ```typescript
780
+ function isTaprootInput(input: PsbtInput): boolean;
781
+ ```
782
+
783
+ Returns `true` if the input has any Taproot-specific fields: `tapInternalKey`, `tapMerkleRoot`, `tapLeafScript`, `tapBip32Derivation`, or a P2TR or P2MR `witnessUtxo` script.
784
+
785
+ ### isTaprootOutput
786
+
787
+ ```typescript
788
+ function isTaprootOutput(output: PsbtOutput, script?: Uint8Array): boolean;
789
+ ```
790
+
791
+ Returns `true` if the output has Taproot-specific fields: `tapInternalKey`, `tapTree`, `tapBip32Derivation`, or a P2TR or P2MR script.
792
+
793
+ ### isP2MRInput
794
+
795
+ ```typescript
796
+ function isP2MRInput(input: PsbtInput): boolean;
797
+ ```
798
+
799
+ Returns `true` if the input specifically has a P2MR (Pay-to-Merkle-Root) `witnessUtxo` script. Unlike `isTaprootInput` which matches both P2TR and P2MR, this function only matches P2MR inputs.
800
+
801
+ ### checkTaprootInputForSigs
802
+
803
+ ```typescript
804
+ function checkTaprootInputForSigs(input: PsbtInput, action: string): boolean;
805
+ ```
806
+
807
+ Checks whether a Taproot input has existing signatures (from `tapKeySig`, `tapScriptSig`, or `finalScriptWitness`) that would block the given action. Extracts all Taproot signatures from the input and checks each against the action using Schnorr signature decoding.
808
+
809
+ ### checkTaprootHashesForSig (Psbt method)
810
+
811
+ ```typescript
812
+ checkTaprootHashesForSig(
813
+ inputIndex: number,
814
+ input: PsbtInput,
815
+ keyPair: Signer | SignerAsync | HDSigner | HDSignerAsync | TaprootHashCheckSigner,
816
+ tapLeafHashToSign?: Uint8Array,
817
+ allowedSighashTypes?: number[],
818
+ ): { hash: MessageHash; leafHash?: Bytes32 }[];
819
+ ```
820
+
821
+ A public method on the `Psbt` class. Validates that the key pair has a `signSchnorr` method and retrieves all Taproot hashes that need to be signed for the given input and key pair. Throws if no hashes are found for the provided key. Used internally by Taproot signing methods and can be called directly for advanced use cases.
822
+
823
+ ### checkTaprootInputFields
824
+
825
+ ```typescript
826
+ function checkTaprootInputFields(
827
+ inputData: PsbtInput,
828
+ newInputData: PsbtInput,
829
+ action: string,
830
+ ): void;
831
+ ```
832
+
833
+ Validates that Taproot and non-Taproot fields are not mixed in the same input. Also verifies that any `tapLeafScript` entries belong to the tap tree (if a `tapMerkleRoot` is provided). Throws on validation failure.
834
+
835
+ ### checkTaprootOutputFields
836
+
837
+ ```typescript
838
+ function checkTaprootOutputFields(
839
+ outputData: PsbtOutput,
840
+ newOutputData: PsbtOutput,
841
+ action: string,
842
+ ): void;
843
+ ```
844
+
845
+ Validates that Taproot and non-Taproot fields are not mixed in the same output. Also verifies that the `tapInternalKey` and `tapTree` produce a script pubkey matching the output script.
846
+
847
+ ### serializeTaprootSignature
848
+
849
+ ```typescript
850
+ function serializeTaprootSignature(sig: Uint8Array, sighashType?: number): Uint8Array;
851
+ ```
852
+
853
+ Serializes a Schnorr signature with an optional sighash type byte appended. If `sighashType` is `SIGHASH_DEFAULT` (0) or undefined, no extra byte is appended (the signature is 64 bytes). Otherwise the sighash byte is appended (65 bytes).
854
+
855
+ ### tapScriptFinalizer
856
+
857
+ ```typescript
858
+ function tapScriptFinalizer(
859
+ inputIndex: number,
860
+ input: PsbtInput,
861
+ tapLeafHashToFinalize?: Uint8Array,
862
+ ): { finalScriptWitness: Uint8Array | undefined };
863
+ ```
864
+
865
+ The default Taproot script-path finalizer. It:
866
+
867
+ 1. Searches for a tap leaf matching `tapLeafHashToFinalize` (if provided)
868
+ 2. Otherwise selects the signed tap leaf with the shortest control block (shortest Merkle proof path)
869
+ 3. Sorts signatures by their public key position in the leaf script (reverse order for OP_CHECKSIGADD compatibility)
870
+ 4. Constructs the witness: `[...signatures, script, controlBlock]`
871
+
872
+ ### tweakInternalPubKey
873
+
874
+ ```typescript
875
+ function tweakInternalPubKey(inputIndex: number, input: PsbtInput): Uint8Array;
876
+ ```
877
+
878
+ Tweaks the `tapInternalKey` with the `tapMerkleRoot` to produce the output key. Used internally during Taproot signing.
879
+
880
+ ### tapTreeToList / tapTreeFromList
881
+
882
+ ```typescript
883
+ function tapTreeToList(tree: Taptree): TapLeaf[];
884
+ function tapTreeFromList(leaves?: TapLeaf[]): Taptree;
885
+ ```
886
+
887
+ Converts between the binary `Taptree` structure and the flat `TapLeaf[]` list format (BIP 371). The list format uses depth-first search ordering for tree reconstruction.
888
+
889
+ ---
890
+
891
+ ## FinalScriptsFunc and FinalTaprootScriptsFunc
892
+
893
+ These function types allow custom finalization logic to be injected.
894
+
895
+ ### FinalScriptsFunc
896
+
897
+ ```typescript
898
+ type FinalScriptsFunc = (
899
+ inputIndex: number,
900
+ input: PsbtInput,
901
+ script: Script,
902
+ isSegwit: boolean,
903
+ isP2SH: boolean,
904
+ isP2WSH: boolean,
905
+ canRunChecks: boolean,
906
+ ) => {
907
+ finalScriptSig: Script | undefined;
908
+ finalScriptWitness: Uint8Array | undefined;
909
+ };
910
+ ```
911
+
912
+ Used for non-Taproot inputs. Receives the classified script and wrapping flags. Must return either `finalScriptSig`, `finalScriptWitness`, or both.
913
+
914
+ ### FinalTaprootScriptsFunc
915
+
916
+ ```typescript
917
+ type FinalTaprootScriptsFunc = (
918
+ inputIndex: number,
919
+ input: PsbtInput,
920
+ tapLeafHashToFinalize?: Bytes32,
921
+ ) => {
922
+ finalScriptWitness: Uint8Array | undefined;
923
+ };
924
+ ```
925
+
926
+ Used for Taproot inputs. Must construct and return the `finalScriptWitness`.
927
+
928
+ ---
929
+
930
+ ## witnessStackToScriptWitness
931
+
932
+ ```typescript
933
+ function witnessStackToScriptWitness(witness: Uint8Array[]): Uint8Array;
934
+ ```
935
+
936
+ Converts a witness stack (array of `Uint8Array` items) into the serialized script witness format used in `finalScriptWitness`. The format is:
937
+
938
+ ```
939
+ [varint:numItems] [varint:item1Len] [item1] [varint:item2Len] [item2] ...
940
+ ```
941
+
942
+ The inverse operation is `scriptWitnessToWitnessStack`:
943
+
944
+ ```typescript
945
+ function scriptWitnessToWitnessStack(buffer: Uint8Array): Uint8Array[];
946
+ ```
947
+
948
+ ---
949
+
950
+ ## Internal Architecture
951
+
952
+ ### PsbtCache
953
+
954
+ The `PsbtCache` class manages all computed and cached values for a PSBT instance.
955
+
956
+ ```typescript
957
+ class PsbtCache {
958
+ readonly nonWitnessUtxoTxCache: Transaction[]; // Cached decoded non-witness transactions
959
+ readonly nonWitnessUtxoBufCache: Uint8Array[]; // Cached raw non-witness transaction buffers
960
+ readonly txInCache: Record<string, number>; // Cached transaction input lookups
961
+ readonly tx: Transaction;
962
+ unsafeSignNonSegwit: boolean; // Flag for unsafe non-segwit signing
963
+ hasSignatures: boolean;
964
+ fee: number | undefined;
965
+ feeRate: number | undefined;
966
+ extractedTx: Transaction | undefined;
967
+ prevOuts: readonly PrevOut[] | undefined; // Cached for Taproot signing
968
+ signingScripts: readonly Script[] | undefined; // Cached for Taproot signing
969
+ values: readonly Satoshi[] | undefined; // Cached for Taproot signing
970
+ taprootHashCache: TaprootHashCache | undefined; // Cached intermediate hashes
971
+
972
+ constructor(tx: Transaction);
973
+ invalidate(scope: 'full' | 'outputs'): void;
974
+ addNonWitnessTxCache(input, inputIndex, txFromBuffer): void;
975
+ getNonWitnessUtxoTx(input, inputIndex, txFromBuffer): Transaction;
976
+ getScriptFromUtxo(inputIndex, input, txFromBuffer): Script;
977
+ getScriptAndAmountFromUtxo(inputIndex, input, txFromBuffer): { script, value };
978
+ computeFee(inputs, disableOutputChecks?, txFromBuffer?): number;
979
+ computeFeeRate(inputs, disableOutputChecks?, txFromBuffer?): number;
980
+ checkFees(opts): void;
981
+ pubkeyInInput(pubkey, input, inputIndex, txFromBuffer): boolean;
982
+ pubkeyInOutput(pubkey, output, outputIndex): boolean;
983
+ redeemFromFinalScriptSig(finalScript): Uint8Array | undefined;
984
+ redeemFromFinalWitnessScript(finalScript): Uint8Array | undefined;
985
+ finalizeAndComputeAmounts(inputs, tx, mustFinalize, disableOutputChecks?, txFromBuffer?): { fee, feeRate };
986
+ getScriptFromInput(inputIndex, input, txFromBuffer): GetScriptReturn;
987
+ getPrevoutTaprootKey(inputIndex, input, txFromBuffer): XOnlyPublicKey | null;
988
+ }
989
+ ```
990
+
991
+ **Cache invalidation scopes:**
992
+ - `'full'`: Clears everything including `prevOuts`, `signingScripts`, and `values` (used when inputs change)
993
+ - `'outputs'`: Clears `fee`, `feeRate`, `extractedTx`, and `taprootHashCache` (used when outputs or version/locktime change)
994
+
995
+ ### PsbtSigner
996
+
997
+ The `PsbtSigner` class wraps all signing-related logic.
998
+
999
+ ```typescript
1000
+ class PsbtSigner {
1001
+ getHashAndSighashType(inputs, inputIndex, pubkey, sighashTypes): { hash, sighashType };
1002
+ getHashForSig(inputIndex, input, forValidate, sighashTypes?): { script, hash, sighashType };
1003
+ getTaprootHashesForSig(inputIndex, input, inputs, pubkey, tapLeafHashToSign?, allowedSighashTypes?): HashForSig[];
1004
+ getAllTaprootHashesForSig(inputIndex, input, inputs): HashForSig[];
1005
+ trimTaprootSig(signature): Uint8Array; // Trims 65-byte sig to 64 bytes
1006
+ getSignersFromHD(inputIndex, inputs, hdKeyPair): HDSigner[];
1007
+ bip32DerivationIsMine(root): (d: Bip32Derivation) => boolean;
1008
+ }
1009
+ ```
1010
+
1011
+ ### PsbtFinalizer
1012
+
1013
+ The `PsbtFinalizer` class wraps finalization logic.
1014
+
1015
+ ```typescript
1016
+ class PsbtFinalizer {
1017
+ getFinalScripts(inputIndex, input, script, isSegwit, isP2SH, isP2WSH, canRunChecks?, solution?): FinalScriptsResult;
1018
+ getScriptFromInput(inputIndex, input): GetScriptReturn;
1019
+ }
1020
+ ```
1021
+
1022
+ ### PsbtTransaction
1023
+
1024
+ Implements the `ITransaction` interface required by the `bip174` library. Wraps a `Transaction` object.
1025
+
1026
+ ```typescript
1027
+ class PsbtTransaction {
1028
+ tx: Transaction;
1029
+ constructor(buffer?: Uint8Array);
1030
+ getInputOutputCounts(): { inputCount: number; outputCount: number };
1031
+ addInput(input: TransactionInput): void;
1032
+ addOutput(output: PsbtTxOutput): void;
1033
+ toBuffer(): Uint8Array;
1034
+ }
1035
+ ```
1036
+
1037
+ When no buffer is provided, a default empty version-2 transaction is used: `[02 00 00 00] [00] [00] [00 00 00 00]`.
1038
+
1039
+ ---
1040
+
1041
+ ## Validation Utilities
1042
+
1043
+ ### check32Bit
1044
+
1045
+ ```typescript
1046
+ function check32Bit(num: number): void;
1047
+ ```
1048
+
1049
+ Validates that a number is a non-negative 32-bit integer. Throws on invalid values.
1050
+
1051
+ ### isFinalized
1052
+
1053
+ ```typescript
1054
+ function isFinalized(input: PsbtInput): boolean;
1055
+ ```
1056
+
1057
+ Returns `true` if the input has either `finalScriptSig` or `finalScriptWitness`.
1058
+
1059
+ ### checkInputsForPartialSig
1060
+
1061
+ ```typescript
1062
+ function checkInputsForPartialSig(
1063
+ inputs: PsbtInput[],
1064
+ action: string,
1065
+ hasSignaturesCache?: boolean,
1066
+ ): void;
1067
+ ```
1068
+
1069
+ Checks if existing signatures would be invalidated by the specified action (e.g., `'addInput'`, `'addOutput'`, `'setVersion'`). Uses the `hasSignatures` cache flag for O(1) fast-path when no signatures exist.
1070
+
1071
+ Sighash-based logic:
1072
+ - `SIGHASH_ANYONECANPAY`: allows `addInput`
1073
+ - `SIGHASH_NONE` / `SIGHASH_SINGLE`: allows `addOutput` and `setInputSequence`
1074
+ - `SIGHASH_ALL`: does not allow any modification
1075
+
1076
+ ### checkScriptForPubkey
1077
+
1078
+ ```typescript
1079
+ function checkScriptForPubkey(pubkey: PublicKey, script: Script, action: string): void;
1080
+ ```
1081
+
1082
+ Throws if the public key is not found in the script. Used during signing to prevent signing with the wrong key.
1083
+
1084
+ ### checkPartialSigSighashes
1085
+
1086
+ ```typescript
1087
+ function checkPartialSigSighashes(input: PsbtInput): void;
1088
+ ```
1089
+
1090
+ Validates that all partial signatures in an input have sighash types matching the input's `sighashType` field.
1091
+
1092
+ ### checkTxForDupeIns
1093
+
1094
+ ```typescript
1095
+ function checkTxForDupeIns(tx: Transaction, cache: PsbtCache): void;
1096
+ ```
1097
+
1098
+ Checks all transaction inputs for duplicates (same TXID and output index).
1099
+
1100
+ ### checkRedeemScript / checkWitnessScript
1101
+
1102
+ ```typescript
1103
+ const checkRedeemScript: (idx, scriptPubKey, redeemScript, ioType) => void;
1104
+ const checkWitnessScript: (idx, scriptPubKey, witnessScript, ioType) => void;
1105
+ ```
1106
+
1107
+ Validate that a redeem or witness script produces the expected scriptPubKey when wrapped in P2SH or P2WSH.
1108
+
1109
+ ---
1110
+
1111
+ ## Utility Functions
1112
+
1113
+ ### pubkeyPositionInScript
1114
+
1115
+ ```typescript
1116
+ function pubkeyPositionInScript(pubkey: Uint8Array, script: Uint8Array): number;
1117
+ ```
1118
+
1119
+ Finds the position of a public key in a script. Checks against the raw pubkey, its x-only form, its hash160, uncompressed form, and hybrid form. Returns `-1` if not found.
1120
+
1121
+ ### pubkeyInScript
1122
+
1123
+ ```typescript
1124
+ function pubkeyInScript(pubkey: Uint8Array, script: Uint8Array): boolean;
1125
+ ```
1126
+
1127
+ Returns `true` if the public key is found in the script (delegates to `pubkeyPositionInScript`).
1128
+
1129
+ ### checkInputForSig
1130
+
1131
+ ```typescript
1132
+ function checkInputForSig(input: PsbtInput, action: string): boolean;
1133
+ ```
1134
+
1135
+ Checks whether an input already has a signature that would block the given action.
1136
+
1137
+ ### getMeaningfulScript
1138
+
1139
+ ```typescript
1140
+ function getMeaningfulScript(
1141
+ script: Uint8Array,
1142
+ index: number,
1143
+ ioType: 'input' | 'output',
1144
+ redeemScript?: Uint8Array,
1145
+ witnessScript?: Uint8Array,
1146
+ ): {
1147
+ meaningfulScript: Uint8Array;
1148
+ type: 'p2sh' | 'p2wsh' | 'p2sh-p2wsh' | 'raw';
1149
+ };
1150
+ ```
1151
+
1152
+ Unwraps P2SH, P2WSH, and P2SH-P2WSH scripts to reveal the underlying meaningful script. Validates that redeem and witness scripts match the scriptPubKey.
1153
+
1154
+ ### sighashTypeToString
1155
+
1156
+ ```typescript
1157
+ function sighashTypeToString(sighashType: number): string;
1158
+ ```
1159
+
1160
+ Converts a sighash type integer to a human-readable string like `'SIGHASH_ALL'`, `'SIGHASH_ANYONECANPAY | SIGHASH_SINGLE'`, etc.
1161
+
1162
+ ### compressPubkey
1163
+
1164
+ ```typescript
1165
+ function compressPubkey(pubkey: Uint8Array): Uint8Array;
1166
+ ```
1167
+
1168
+ Compresses a 65-byte uncompressed public key to 33 bytes. Returns a copy if already compressed.
1169
+
1170
+ ### range
1171
+
1172
+ ```typescript
1173
+ function range(n: number): number[];
1174
+ ```
1175
+
1176
+ Creates an array `[0, 1, 2, ..., n-1]`.
1177
+
1178
+ ---
1179
+
1180
+ ## Complete Workflow Examples
1181
+
1182
+ ### Standard P2WPKH Transaction
1183
+
1184
+ ```typescript
1185
+ import { Psbt, networks } from '@btc-vision/bitcoin';
1186
+ import { ECPairSigner, createNobleBackend } from '@btc-vision/ecpair';
1187
+
1188
+ const backend = createNobleBackend();
1189
+
1190
+ // 1. Create
1191
+ const psbt = new Psbt({ network: networks.bitcoin });
1192
+
1193
+ // 2. Add inputs
1194
+ psbt.addInput({
1195
+ hash: 'previousTxId...', // TXID hex string
1196
+ index: 0,
1197
+ witnessUtxo: {
1198
+ script: Buffer.from('0014ab68025513c3dbd2f7b92a94e0581f5d50f654e7', 'hex'),
1199
+ value: 100000n,
1200
+ },
1201
+ });
1202
+
1203
+ // 3. Add outputs
1204
+ psbt.addOutput({
1205
+ address: 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4',
1206
+ value: 90000n,
1207
+ });
1208
+
1209
+ // 4. Sign
1210
+ const keyPair = ECPairSigner.fromWIF(backend, 'L1...', networks.bitcoin);
1211
+ psbt.signAllInputs(keyPair);
1212
+
1213
+ // 5. Validate (recommended before finalizing)
1214
+ const validator = (pubkey, msghash, signature) => {
1215
+ return keyPair.verify(msghash, signature);
1216
+ };
1217
+ psbt.validateSignaturesOfAllInputs(validator);
1218
+
1219
+ // 6. Finalize
1220
+ psbt.finalizeAllInputs();
1221
+
1222
+ // 7. Extract
1223
+ const tx = psbt.extractTransaction();
1224
+ const rawTx = tx.toHex(); // Ready to broadcast
1225
+ ```
1226
+
1227
+ ### Taproot Key-Path Spend
1228
+
1229
+ ```typescript
1230
+ import { Psbt } from '@btc-vision/bitcoin';
1231
+
1232
+ const psbt = new Psbt();
1233
+
1234
+ psbt.addInput({
1235
+ hash: 'previousTxId...',
1236
+ index: 0,
1237
+ witnessUtxo: {
1238
+ script: taprootOutputScript, // OP_1 <32-byte x-only pubkey>
1239
+ value: 50000n,
1240
+ },
1241
+ tapInternalKey: internalPubkeyXOnly, // 32-byte x-only public key
1242
+ });
1243
+
1244
+ psbt.addOutput({
1245
+ address: 'bc1p...',
1246
+ value: 40000n,
1247
+ });
1248
+
1249
+ // Sign with Schnorr-capable signer
1250
+ psbt.signInput(0, taprootKeyPair); // Uses SIGHASH_DEFAULT by default
1251
+ psbt.finalizeInput(0);
1252
+
1253
+ const tx = psbt.extractTransaction();
1254
+ ```
1255
+
1256
+ ### Taproot Script-Path Spend
1257
+
1258
+ ```typescript
1259
+ import { Psbt } from '@btc-vision/bitcoin';
1260
+
1261
+ const psbt = new Psbt();
1262
+
1263
+ psbt.addInput({
1264
+ hash: 'previousTxId...',
1265
+ index: 0,
1266
+ witnessUtxo: {
1267
+ script: taprootOutputScript,
1268
+ value: 50000n,
1269
+ },
1270
+ tapInternalKey: internalPubkeyXOnly,
1271
+ tapMerkleRoot: merkleRoot,
1272
+ tapLeafScript: [
1273
+ {
1274
+ controlBlock: controlBlockBuffer,
1275
+ script: leafScriptBuffer,
1276
+ leafVersion: 0xc0, // LEAF_VERSION_TAPSCRIPT
1277
+ },
1278
+ ],
1279
+ });
1280
+
1281
+ psbt.addOutput({
1282
+ address: 'bc1q...',
1283
+ value: 40000n,
1284
+ });
1285
+
1286
+ // Sign the specific tap leaf
1287
+ psbt.signTaprootInput(0, taprootKeyPair, leafHash);
1288
+
1289
+ // Finalize using the default tap script finalizer
1290
+ psbt.finalizeTaprootInput(0);
1291
+
1292
+ const tx = psbt.extractTransaction();
1293
+ ```
1294
+
1295
+ ### Multi-Party Signing (PSBT Combiner Pattern)
1296
+
1297
+ ```typescript
1298
+ import { Psbt } from '@btc-vision/bitcoin';
1299
+
1300
+ // Coordinator creates the PSBT
1301
+ const psbt = new Psbt();
1302
+ psbt.addInput({ hash: '...', index: 0, witnessUtxo: { script: p2wshScript, value: 100000n } });
1303
+ psbt.addOutput({ address: 'bc1q...', value: 90000n });
1304
+
1305
+ // Serialize and send to signers
1306
+ const psbtBase64 = psbt.toBase64();
1307
+
1308
+ // Signer A
1309
+ const psbtA = Psbt.fromBase64(psbtBase64);
1310
+ psbtA.signInput(0, signerA);
1311
+
1312
+ // Signer B
1313
+ const psbtB = Psbt.fromBase64(psbtBase64);
1314
+ psbtB.signInput(0, signerB);
1315
+
1316
+ // Coordinator combines
1317
+ const combined = Psbt.fromBase64(psbtBase64);
1318
+ combined.combine(psbtA, psbtB);
1319
+
1320
+ // Finalize and extract
1321
+ combined.finalizeAllInputs();
1322
+ const tx = combined.extractTransaction();
1323
+ ```
1324
+
1325
+ ### Async Signing with Hardware Wallet
1326
+
1327
+ ```typescript
1328
+ import { Psbt } from '@btc-vision/bitcoin';
1329
+
1330
+ const psbt = new Psbt();
1331
+ // ... add inputs and outputs ...
1332
+
1333
+ // Hardware wallet implements SignerAsync
1334
+ const hardwareSigner: SignerAsync = {
1335
+ publicKey: hwPublicKey,
1336
+ async sign(hash) {
1337
+ // Communicate with hardware device
1338
+ return await hardwareDevice.signECDSA(hash);
1339
+ },
1340
+ async signSchnorr(hash) {
1341
+ return await hardwareDevice.signSchnorr(hash);
1342
+ },
1343
+ };
1344
+
1345
+ await psbt.signAllInputsAsync(hardwareSigner);
1346
+ psbt.finalizeAllInputs();
1347
+ const tx = psbt.extractTransaction();
1348
+ ```
1349
+
1350
+ ### Custom Finalization Function
1351
+
1352
+ ```typescript
1353
+ import { Psbt, type FinalScriptsFunc } from '@btc-vision/bitcoin';
1354
+
1355
+ const customFinalizer: FinalScriptsFunc = (
1356
+ inputIndex, input, script, isSegwit, isP2SH, isP2WSH, canRunChecks
1357
+ ) => {
1358
+ // Custom logic to construct final scripts
1359
+ const witness = [input.partialSig[0].signature, input.partialSig[0].pubkey];
1360
+ return {
1361
+ finalScriptSig: undefined,
1362
+ finalScriptWitness: witnessStackToScriptWitness(witness),
1363
+ };
1364
+ };
1365
+
1366
+ psbt.finalizeInput(0, customFinalizer);
1367
+ ```
1368
+
1369
+ ---
1370
+
1371
+ ## Error Handling
1372
+
1373
+ Common errors thrown by the PSBT module:
1374
+
1375
+ | Error | Cause |
1376
+ |-------|-------|
1377
+ | `"Invalid arguments for Psbt.addInput"` | Missing `hash` or `index` |
1378
+ | `"Invalid arguments for Psbt.addOutput"` | Missing `value` or both `address` and `script` |
1379
+ | `"Can not modify transaction, signatures exist."` | Attempting to add input/output after signing with `SIGHASH_ALL` |
1380
+ | `"Need Signer to sign input"` | Null or missing key pair |
1381
+ | `"Need Schnorr Signer to sign taproot input"` | Signer lacks `signSchnorr` method |
1382
+ | `"No inputs were signed"` | Key pair did not match any input |
1383
+ | `"Not finalized"` | Calling `extractTransaction` before finalizing |
1384
+ | `"Can not finalize input #N"` | Missing required signatures for the script type |
1385
+ | `"Duplicate input detected."` | Same TXID:vout added twice |
1386
+ | `"Warning: You are paying around X in fees..."` | Fee rate exceeds `maximumFeeRate` |
1387
+ | `"Not BIP174 compliant, can not export"` | Attempting to serialize after `unsafeSignNonSegwit` |
1388
+ | `"Cannot use both taproot and non-taproot fields."` | Mixing Taproot and legacy fields in the same input/output |
1389
+ | `"Sighash type is not allowed."` | Input sighash type not in the allowed list |
1390
+ | `"P2WPKH or P2SH can not be contained within P2WSH"` | Invalid witness script wrapping |
1391
+
1392
+ ---
1393
+
1394
+ ## Security Considerations
1395
+
1396
+ - **Always validate signatures** before finalizing with `validateSignaturesOfAllInputs()`. The finalizer constructs scripts from partial data and does not re-validate cryptographic correctness.
1397
+ - **Fee rate protection**: The default `maximumFeeRate` of 5000 sat/vB prevents accidental overpayment. Adjust with `setMaximumFeeRate()` if higher rates are intentional.
1398
+ - **Non-segwit signing risk**: Signing non-segwit inputs with only `witnessUtxo` (no `nonWitnessUtxo`) is unsafe because a malicious node could lie about the input amount. The library blocks this by default; the `unsafeSignNonSegwit` flag bypasses this check but prevents BIP 174 serialization.
1399
+ - **Sighash type whitelisting**: Pass explicit `sighashTypes` arrays to signing methods to prevent unintended sighash usage.
1400
+ - **Duplicate input detection**: The library automatically checks for duplicate inputs (same TXID and output index) to prevent double-spend construction errors.