@caravan/psbt 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,1307 +0,0 @@
1
- import { BufferReader, BufferWriter } from "bufio";
2
- import { Psbt } from "bitcoinjs-lib";
3
-
4
- import {
5
- Key,
6
- Value,
7
- NonUniqueKeyTypeValue,
8
- KeyType,
9
- PsbtGlobalTxModifiableBits,
10
- SighashType,
11
- MapSelectorType,
12
- } from "./types";
13
- import {
14
- bufferize,
15
- getNonUniqueKeyTypeValues,
16
- getOptionalMappedBytesAsHex,
17
- getOptionalMappedBytesAsUInt,
18
- parseDerivationPathNodesToBytes,
19
- } from "./functions";
20
- import { PsbtV2Maps } from "./psbtv2maps";
21
-
22
- /**
23
- * The PsbtV2 class is intended to represent an easily modifiable and
24
- * serializable psbt of version 2 conforming to BIP0174. Getters exist for all
25
- * BIP-defined keytypes. Very few setters and modifier methods exist. As they
26
- * are added, they should enforce implied and documented rules and limitations.
27
- *
28
- * Defining BIPs:
29
- * https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki
30
- * https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki
31
- */
32
- export class PsbtV2 extends PsbtV2Maps {
33
- constructor(psbt?: Buffer | string) {
34
- super(psbt);
35
-
36
- if (!psbt) {
37
- this.create();
38
- }
39
-
40
- this.validate();
41
- }
42
-
43
- /**
44
- * Globals Getters/Setters
45
- */
46
-
47
- get PSBT_GLOBAL_XPUB() {
48
- return getNonUniqueKeyTypeValues(
49
- this.globalMap,
50
- KeyType.PSBT_GLOBAL_XPUB,
51
- ) as NonUniqueKeyTypeValue[];
52
- }
53
-
54
- get PSBT_GLOBAL_TX_VERSION() {
55
- const val = this.globalMap.get(KeyType.PSBT_GLOBAL_TX_VERSION);
56
-
57
- if (val === undefined) {
58
- throw Error("PSBT_GLOBAL_TX_VERSION not set");
59
- }
60
-
61
- return val.readInt32LE(0);
62
- }
63
-
64
- set PSBT_GLOBAL_TX_VERSION(version: number) {
65
- if (version < 2) {
66
- // It's unfortunate this setter has to throw, but a PsbtV2 is invalid with
67
- // a txn version < 2. The Creator role is responsible for setting this
68
- // value and BIP0370 specifies that it cannot be less than 2.
69
- // https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki#cite_note-3
70
- throw Error(
71
- `PsbtV2 cannot have a global tx version less than 2. Version ${version} specified.`,
72
- );
73
- }
74
-
75
- const bw = new BufferWriter();
76
- bw.writeI32(version);
77
- this.globalMap.set(KeyType.PSBT_GLOBAL_TX_VERSION, bw.render());
78
- }
79
-
80
- get PSBT_GLOBAL_FALLBACK_LOCKTIME() {
81
- return (
82
- this.globalMap
83
- .get(KeyType.PSBT_GLOBAL_FALLBACK_LOCKTIME)
84
- ?.readUInt32LE(0) ?? null
85
- );
86
- }
87
-
88
- set PSBT_GLOBAL_FALLBACK_LOCKTIME(locktime: number | null) {
89
- if (locktime === null) {
90
- this.globalMap.delete(KeyType.PSBT_GLOBAL_FALLBACK_LOCKTIME);
91
- } else {
92
- const bw = new BufferWriter();
93
- bw.writeI32(locktime);
94
- this.globalMap.set(KeyType.PSBT_GLOBAL_FALLBACK_LOCKTIME, bw.render());
95
- }
96
- }
97
-
98
- get PSBT_GLOBAL_INPUT_COUNT() {
99
- const val = this.globalMap.get(KeyType.PSBT_GLOBAL_INPUT_COUNT);
100
-
101
- if (val === undefined) {
102
- throw Error("PSBT_GLOBAL_INPUT_COUNT not set");
103
- }
104
-
105
- return val.readUInt8(0);
106
- }
107
-
108
- set PSBT_GLOBAL_INPUT_COUNT(count: number) {
109
- const bw = new BufferWriter();
110
- bw.writeU8(count);
111
- this.globalMap.set(KeyType.PSBT_GLOBAL_INPUT_COUNT, bw.render());
112
- }
113
-
114
- get PSBT_GLOBAL_OUTPUT_COUNT() {
115
- const val = this.globalMap.get(KeyType.PSBT_GLOBAL_OUTPUT_COUNT);
116
-
117
- if (val === undefined) {
118
- throw Error("PSBT_GLOBAL_OUTPUT_COUNT not set");
119
- }
120
-
121
- return val.readUInt8(0);
122
- }
123
-
124
- set PSBT_GLOBAL_OUTPUT_COUNT(count: number) {
125
- const bw = new BufferWriter();
126
- bw.writeU8(count);
127
- this.globalMap.set(KeyType.PSBT_GLOBAL_OUTPUT_COUNT, bw.render());
128
- }
129
-
130
- get PSBT_GLOBAL_TX_MODIFIABLE() {
131
- const val =
132
- this.globalMap.get(KeyType.PSBT_GLOBAL_TX_MODIFIABLE)?.readUInt8(0) || 0;
133
- let modifiable: PsbtGlobalTxModifiableBits[] = [];
134
-
135
- if (val & 0b00000001) {
136
- modifiable.push(PsbtGlobalTxModifiableBits.INPUTS);
137
- }
138
- if (val & 0b00000010) {
139
- modifiable.push(PsbtGlobalTxModifiableBits.OUTPUTS);
140
- }
141
- if (val & 0b00000100) {
142
- modifiable.push(PsbtGlobalTxModifiableBits.SIGHASH_SINGLE);
143
- }
144
-
145
- return modifiable;
146
- }
147
-
148
- set PSBT_GLOBAL_TX_MODIFIABLE(modifiable: PsbtGlobalTxModifiableBits[]) {
149
- let val = 0b00000000;
150
-
151
- if (modifiable.includes(PsbtGlobalTxModifiableBits.INPUTS)) {
152
- val |= 0b00000001;
153
- }
154
- if (modifiable.includes(PsbtGlobalTxModifiableBits.OUTPUTS)) {
155
- val |= 0b00000010;
156
- }
157
- if (modifiable.includes(PsbtGlobalTxModifiableBits.SIGHASH_SINGLE)) {
158
- val |= 0b00000100;
159
- }
160
-
161
- const br = new BufferWriter();
162
- br.writeU8(val);
163
- this.globalMap.set(KeyType.PSBT_GLOBAL_TX_MODIFIABLE, br.render());
164
- }
165
-
166
- get PSBT_GLOBAL_VERSION() {
167
- const version = this.globalMap
168
- .get(KeyType.PSBT_GLOBAL_VERSION)
169
- ?.readUInt32LE(0);
170
- if (version === undefined) {
171
- // This should never happen.
172
- console.warn("PSBT_GLOBAL_VERSION key is missing! Setting to version 2.");
173
- this.PSBT_GLOBAL_VERSION = 2;
174
- }
175
- return version ?? 2;
176
- }
177
-
178
- set PSBT_GLOBAL_VERSION(version: number) {
179
- let workingVersion = version;
180
- if (workingVersion < 2) {
181
- console.warn(
182
- `PsbtV2 cannot have a global version less than 2. Version ${workingVersion} specified. Setting to version 2.`,
183
- );
184
- workingVersion = 2;
185
- }
186
-
187
- const bw = new BufferWriter();
188
- bw.writeU32(workingVersion);
189
- this.globalMap.set(KeyType.PSBT_GLOBAL_VERSION, bw.render());
190
- }
191
-
192
- get PSBT_GLOBAL_PROPRIETARY() {
193
- return getNonUniqueKeyTypeValues(
194
- this.globalMap,
195
- KeyType.PSBT_GLOBAL_PROPRIETARY,
196
- ) as NonUniqueKeyTypeValue[];
197
- }
198
-
199
- /**
200
- * Input Getters/Setters
201
- */
202
-
203
- get PSBT_IN_NON_WITNESS_UTXO() {
204
- return getOptionalMappedBytesAsHex(
205
- this.inputMaps,
206
- KeyType.PSBT_IN_NON_WITNESS_UTXO,
207
- );
208
- }
209
-
210
- get PSBT_IN_WITNESS_UTXO() {
211
- return getOptionalMappedBytesAsHex(
212
- this.inputMaps,
213
- KeyType.PSBT_IN_WITNESS_UTXO,
214
- );
215
- }
216
-
217
- get PSBT_IN_PARTIAL_SIG() {
218
- return getNonUniqueKeyTypeValues(
219
- this.inputMaps,
220
- KeyType.PSBT_IN_PARTIAL_SIG,
221
- ) as NonUniqueKeyTypeValue[][];
222
- }
223
-
224
- get PSBT_IN_SIGHASH_TYPE() {
225
- return getOptionalMappedBytesAsUInt(
226
- this.inputMaps,
227
- KeyType.PSBT_IN_SIGHASH_TYPE,
228
- );
229
- }
230
-
231
- get PSBT_IN_REDEEM_SCRIPT() {
232
- return getOptionalMappedBytesAsHex(
233
- this.inputMaps,
234
- KeyType.PSBT_IN_REDEEM_SCRIPT,
235
- );
236
- }
237
-
238
- get PSBT_IN_WITNESS_SCRIPT() {
239
- return getOptionalMappedBytesAsHex(
240
- this.inputMaps,
241
- KeyType.PSBT_IN_WITNESS_SCRIPT,
242
- );
243
- }
244
-
245
- get PSBT_IN_BIP32_DERIVATION() {
246
- return getNonUniqueKeyTypeValues(
247
- this.inputMaps,
248
- KeyType.PSBT_IN_BIP32_DERIVATION,
249
- ) as NonUniqueKeyTypeValue[][];
250
- }
251
-
252
- get PSBT_IN_FINAL_SCRIPTSIG() {
253
- return getOptionalMappedBytesAsHex(
254
- this.inputMaps,
255
- KeyType.PSBT_IN_FINAL_SCRIPTSIG,
256
- );
257
- }
258
-
259
- get PSBT_IN_FINAL_SCRIPTWITNESS() {
260
- return getOptionalMappedBytesAsHex(
261
- this.inputMaps,
262
- KeyType.PSBT_IN_FINAL_SCRIPTWITNESS,
263
- );
264
- }
265
-
266
- get PSBT_IN_POR_COMMITMENT() {
267
- return getOptionalMappedBytesAsHex(
268
- this.inputMaps,
269
- KeyType.PSBT_IN_POR_COMMITMENT,
270
- );
271
- }
272
-
273
- get PSBT_IN_RIPEMD160() {
274
- return getNonUniqueKeyTypeValues(
275
- this.inputMaps,
276
- KeyType.PSBT_IN_RIPEMD160,
277
- ) as NonUniqueKeyTypeValue[][];
278
- }
279
-
280
- get PSBT_IN_SHA256() {
281
- return getNonUniqueKeyTypeValues(
282
- this.inputMaps,
283
- KeyType.PSBT_IN_SHA256,
284
- ) as NonUniqueKeyTypeValue[][];
285
- }
286
-
287
- get PSBT_IN_HASH160() {
288
- return getNonUniqueKeyTypeValues(
289
- this.inputMaps,
290
- KeyType.PSBT_IN_HASH160,
291
- ) as NonUniqueKeyTypeValue[][];
292
- }
293
-
294
- get PSBT_IN_HASH256() {
295
- return getNonUniqueKeyTypeValues(
296
- this.inputMaps,
297
- KeyType.PSBT_IN_HASH256,
298
- ) as NonUniqueKeyTypeValue[][];
299
- }
300
-
301
- get PSBT_IN_PREVIOUS_TXID() {
302
- const indices: string[] = [];
303
- for (const map of this.inputMaps) {
304
- const value = map.get(KeyType.PSBT_IN_PREVIOUS_TXID);
305
- if (!value) {
306
- throw Error("PSBT_IN_PREVIOUS_TXID not set for an input");
307
- }
308
- indices.push(value.toString("hex"));
309
- }
310
- return indices;
311
- }
312
-
313
- get PSBT_IN_OUTPUT_INDEX() {
314
- const indices: number[] = [];
315
- for (const map of this.inputMaps) {
316
- const value = map.get(KeyType.PSBT_IN_OUTPUT_INDEX);
317
- if (!value) {
318
- throw Error("PSBT_IN_OUTPUT_INDEX not set for an input");
319
- }
320
- indices.push(value.readUInt32LE(0));
321
- }
322
- return indices;
323
- }
324
-
325
- get PSBT_IN_SEQUENCE() {
326
- return getOptionalMappedBytesAsUInt(
327
- this.inputMaps,
328
- KeyType.PSBT_IN_SEQUENCE,
329
- );
330
- }
331
-
332
- get PSBT_IN_REQUIRED_TIME_LOCKTIME() {
333
- return getOptionalMappedBytesAsUInt(
334
- this.inputMaps,
335
- KeyType.PSBT_IN_REQUIRED_TIME_LOCKTIME,
336
- );
337
- }
338
-
339
- get PSBT_IN_REQUIRED_HEIGHT_LOCKTIME() {
340
- return getOptionalMappedBytesAsUInt(
341
- this.inputMaps,
342
- KeyType.PSBT_IN_REQUIRED_HEIGHT_LOCKTIME,
343
- );
344
- }
345
-
346
- get PSBT_IN_TAP_KEY_SIG() {
347
- return getOptionalMappedBytesAsHex(
348
- this.inputMaps,
349
- KeyType.PSBT_IN_TAP_KEY_SIG,
350
- );
351
- }
352
-
353
- get PSBT_IN_TAP_SCRIPT_SIG() {
354
- return getNonUniqueKeyTypeValues(
355
- this.inputMaps,
356
- KeyType.PSBT_IN_TAP_SCRIPT_SIG,
357
- ) as NonUniqueKeyTypeValue[][];
358
- }
359
-
360
- get PSBT_IN_TAP_LEAF_SCRIPT() {
361
- return getNonUniqueKeyTypeValues(
362
- this.inputMaps,
363
- KeyType.PSBT_IN_TAP_LEAF_SCRIPT,
364
- ) as NonUniqueKeyTypeValue[][];
365
- }
366
-
367
- get PSBT_IN_TAP_BIP32_DERIVATION() {
368
- return getNonUniqueKeyTypeValues(
369
- this.inputMaps,
370
- KeyType.PSBT_IN_TAP_BIP32_DERIVATION,
371
- ) as NonUniqueKeyTypeValue[][];
372
- }
373
-
374
- get PSBT_IN_TAP_INTERNAL_KEY() {
375
- return getOptionalMappedBytesAsHex(
376
- this.inputMaps,
377
- KeyType.PSBT_IN_TAP_INTERNAL_KEY,
378
- );
379
- }
380
-
381
- get PSBT_IN_TAP_MERKLE_ROOT() {
382
- return getOptionalMappedBytesAsHex(
383
- this.inputMaps,
384
- KeyType.PSBT_IN_TAP_MERKLE_ROOT,
385
- );
386
- }
387
-
388
- get PSBT_IN_PROPRIETARY() {
389
- return getNonUniqueKeyTypeValues(
390
- this.inputMaps,
391
- KeyType.PSBT_IN_PROPRIETARY,
392
- );
393
- }
394
-
395
- /**
396
- * Output Getters/Setters
397
- */
398
-
399
- get PSBT_OUT_REDEEM_SCRIPT() {
400
- return getOptionalMappedBytesAsHex(
401
- this.outputMaps,
402
- KeyType.PSBT_OUT_REDEEM_SCRIPT,
403
- );
404
- }
405
-
406
- get PSBT_OUT_WITNESS_SCRIPT() {
407
- return getOptionalMappedBytesAsHex(
408
- this.outputMaps,
409
- KeyType.PSBT_OUT_WITNESS_SCRIPT,
410
- );
411
- }
412
-
413
- get PSBT_OUT_BIP32_DERIVATION() {
414
- return getNonUniqueKeyTypeValues(
415
- this.outputMaps,
416
- KeyType.PSBT_OUT_BIP32_DERIVATION,
417
- );
418
- }
419
-
420
- get PSBT_OUT_AMOUNT() {
421
- const indices: bigint[] = [];
422
- for (const map of this.outputMaps) {
423
- const value = map.get(KeyType.PSBT_OUT_AMOUNT);
424
- if (!value) {
425
- throw Error("PSBT_OUT_AMOUNT not set for an output");
426
- }
427
- const br = new BufferReader(value);
428
- indices.push(br.readBigI64(value));
429
- }
430
- return indices;
431
- }
432
-
433
- get PSBT_OUT_SCRIPT() {
434
- const indices: string[] = [];
435
- for (const map of this.outputMaps) {
436
- const value = map.get(KeyType.PSBT_OUT_SCRIPT);
437
- if (!value) {
438
- // This should never happen, but it can't be gracefully handled.
439
- throw Error("PSBT_OUT_SCRIPT not set for an output");
440
- }
441
- indices.push(value.toString("hex"));
442
- }
443
- return indices;
444
- }
445
-
446
- get PSBT_OUT_TAP_INTERNAL_KEY() {
447
- return getOptionalMappedBytesAsHex(
448
- this.outputMaps,
449
- KeyType.PSBT_OUT_TAP_INTERNAL_KEY,
450
- );
451
- }
452
-
453
- get PSBT_OUT_TAP_TREE() {
454
- return getOptionalMappedBytesAsHex(
455
- this.outputMaps,
456
- KeyType.PSBT_OUT_TAP_TREE,
457
- );
458
- }
459
-
460
- get PSBT_OUT_TAP_BIP32_DERIVATION() {
461
- return getNonUniqueKeyTypeValues(
462
- this.outputMaps,
463
- KeyType.PSBT_OUT_TAP_BIP32_DERIVATION,
464
- );
465
- }
466
-
467
- get PSBT_OUT_PROPRIETARY() {
468
- return getNonUniqueKeyTypeValues(
469
- this.outputMaps,
470
- KeyType.PSBT_OUT_PROPRIETARY,
471
- );
472
- }
473
-
474
- /**
475
- * Operator Role Validation Getters
476
- */
477
-
478
- /**
479
- * Returns true if the PsbtV2 is ready for an operator taking the Constructor
480
- * role.
481
- *
482
- * This check assumes that the Creator used this class's constructor method to
483
- * initialize the PsbtV2 without passing a psbt (constructor defaults were
484
- * set).
485
- */
486
- get isReadyForConstructor() {
487
- // The Creator role (likely via the class constructor) must ensure at least
488
- // the following value has been initialized. The psbt cannot be passed to
489
- // the Constructor until it is set.
490
- if (this.PSBT_GLOBAL_FALLBACK_LOCKTIME === null) {
491
- return false;
492
- }
493
-
494
- // At least inputs or outputs must still be modifiable.
495
- if (
496
- !this.isModifiable([PsbtGlobalTxModifiableBits.INPUTS]) &&
497
- !this.isModifiable([PsbtGlobalTxModifiableBits.OUTPUTS])
498
- ) {
499
- return false;
500
- }
501
-
502
- return true;
503
- }
504
-
505
- /**
506
- * Returns true if the PsbtV2 is ready for an operator taking the Updater
507
- * role.
508
- *
509
- * Before signatures are added, but after an input is added, a PsbtV2 is
510
- * likely to be ready for Constructor, ready for Updater, and ready for Signer
511
- * simultaneously.
512
- *
513
- * According to BIP370, the Updater can modify the sequence number, but it is
514
- * unclear if the Updater retains permissions provided in psbtv0 (BIP174). It
515
- * is likely not the case that the Updater has the same permissions as
516
- * previously because it seems to now be the realm of the Constructor to add
517
- * inputs and outputs.
518
- */
519
- get isReadyForUpdater() {
520
- // In psbtv2, the Updater can set the sequence number, but an input must
521
- // exist for this to be set.
522
- if (this.PSBT_GLOBAL_INPUT_COUNT === 0) {
523
- return false;
524
- }
525
-
526
- // Inputs must still be modifiable
527
- if (!this.isModifiable([PsbtGlobalTxModifiableBits.INPUTS])) {
528
- return false;
529
- }
530
-
531
- return true;
532
- }
533
-
534
- /**
535
- * Returns true if the PsbtV2 is ready for an operator taking the Signer role.
536
- */
537
- get isReadyForSigner() {
538
- // An input must exist before it can be signed.
539
- if (this.PSBT_GLOBAL_INPUT_COUNT === 0) {
540
- return false;
541
- }
542
-
543
- // TODO: Maybe it makes sense to more granularly check if the psbt is fully
544
- // signed or has minimum signatures. Until then, just check that sigs have
545
- // not been finalized.
546
- if (this.isReadyForTransactionExtractor) {
547
- return false;
548
- }
549
-
550
- return true;
551
- }
552
-
553
- /**
554
- * Returns true if the PsbtV2 is ready for an operator taking the Combiner
555
- * role.
556
- */
557
- get isReadyForCombiner() {
558
- // The combiner can potentially provide everything that's missing when
559
- // merging another psbt. If it's at least ready for updates from the
560
- // following roles, then it's ready for a Combiner.
561
- return (
562
- this.isReadyForConstructor ||
563
- this.isReadyForUpdater ||
564
- this.isReadyForSigner
565
- );
566
- }
567
-
568
- /**
569
- * Unimplemented. Returns false.
570
- */
571
- get isReadyForInputFinalizer() {
572
- // Checks to see if the psbt contains everything needed to finalize inputs.
573
- // This can become quite complicated considering multisig and taproot.
574
- console.warn(
575
- "PsbtV2.isReadyForInputFinalizer has been called, however, this getter is unimplemented and shouldn't be used.",
576
- );
577
- return false;
578
- }
579
-
580
- /**
581
- * Returns true if the PsbtV2 is ready for an operator taking the Transaction
582
- * Extractor role.
583
- *
584
- * If all the inputs have been finalized, then the psbt is ready for the
585
- * Transaction Extractor. According to BIP 174, it's the responsibility of the
586
- * Input Finalizer to add scriptSigs or scriptWitnesses and then remove other
587
- * details besides the UTXO. This getter checks that the Input Finalizer has
588
- * finished its job.
589
- */
590
- get isReadyForTransactionExtractor() {
591
- // Iterate over all inputs
592
-
593
- for (let i = 0; i < this.PSBT_GLOBAL_INPUT_COUNT; i++) {
594
- // Check for finalized script
595
- if (
596
- !this.PSBT_IN_FINAL_SCRIPTSIG[i] &&
597
- !this.PSBT_IN_FINAL_SCRIPTWITNESS[i]
598
- ) {
599
- return false;
600
- }
601
-
602
- // Check that the corresponding UTXO is still available
603
- if (
604
- (this.PSBT_IN_FINAL_SCRIPTSIG[i] &&
605
- !this.PSBT_IN_NON_WITNESS_UTXO[i]) ||
606
- (this.PSBT_IN_FINAL_SCRIPTWITNESS[i] && !this.PSBT_IN_WITNESS_UTXO[i])
607
- ) {
608
- return false;
609
- }
610
-
611
- // Check that Input Finalizer removed other values from the input.
612
- //
613
- // Test vectors from BIP 370 indicate that a missing PSBT_IN_OUTPUT_INDEX
614
- // or PSBT_IN_PREVIOUS_TXID should be an invalid psbt, so the getters for
615
- // these keys will throw unless the values are set. However, the BIP also
616
- // requires that the Input Finalizer removes all other values from the
617
- // input map except for the finalized scripts and UTXOs. Since removal of
618
- // the above mentioned keys will result in an invalid psbt, it's decided
619
- // here that it's safe to ignore the fact that those keys have not been
620
- // removed.
621
- if (
622
- // Strings
623
- this.PSBT_IN_REDEEM_SCRIPT[i] ||
624
- this.PSBT_IN_WITNESS_SCRIPT[i] ||
625
- this.PSBT_IN_POR_COMMITMENT[i] ||
626
- this.PSBT_IN_TAP_KEY_SIG[i] ||
627
- this.PSBT_IN_TAP_INTERNAL_KEY[i] ||
628
- this.PSBT_IN_TAP_MERKLE_ROOT[i] ||
629
- // Numbers
630
- this.PSBT_IN_SIGHASH_TYPE[i] !== null ||
631
- this.PSBT_IN_SEQUENCE[i] !== null ||
632
- this.PSBT_IN_REQUIRED_TIME_LOCKTIME[i] !== null ||
633
- this.PSBT_IN_REQUIRED_HEIGHT_LOCKTIME[i] !== null ||
634
- // Arrays of non-unique keytype values
635
- this.PSBT_IN_PARTIAL_SIG[i].filter((el) => el !== null).length > 0 ||
636
- this.PSBT_IN_BIP32_DERIVATION[i].filter((el) => el !== null).length >
637
- 0 ||
638
- this.PSBT_IN_RIPEMD160[i].filter((el) => el !== null).length > 0 ||
639
- this.PSBT_IN_SHA256[i].filter((el) => el !== null).length > 0 ||
640
- this.PSBT_IN_HASH160[i].filter((el) => el !== null).length > 0 ||
641
- this.PSBT_IN_HASH256[i].filter((el) => el !== null).length > 0 ||
642
- this.PSBT_IN_TAP_SCRIPT_SIG[i].filter((el) => el !== null).length > 0 ||
643
- this.PSBT_IN_TAP_LEAF_SCRIPT[i].filter((el) => el !== null).length >
644
- 0 ||
645
- this.PSBT_IN_TAP_BIP32_DERIVATION[i].filter((el) => el !== null)
646
- .length > 0
647
- ) {
648
- return false;
649
- }
650
-
651
- // This input has been finalized. Continue checking the next one.
652
- }
653
-
654
- // All inputs have been finalized, so this psbt is ready for transaction
655
- // extraction.
656
- return true;
657
- }
658
-
659
- /**
660
- * Other Getters/Setters
661
- */
662
-
663
- /**
664
- * Returns the `nLockTime` field for the psbt as if it were a bitcoin
665
- * transaction.
666
- */
667
- get nLockTime() {
668
- // From BIP0370: The nLockTime field of a transaction is determined by
669
- // inspecting the PSBT_GLOBAL_FALLBACK_LOCKTIME and each input's
670
- // PSBT_IN_REQUIRED_TIME_LOCKTIME and PSBT_IN_REQUIRED_HEIGHT_LOCKTIME
671
- // fields.
672
- //
673
- // First collect total locks
674
- const inputCount = this.PSBT_GLOBAL_INPUT_COUNT;
675
- const heightLocks = this.PSBT_IN_REQUIRED_HEIGHT_LOCKTIME;
676
- const timeLocks = this.PSBT_IN_REQUIRED_TIME_LOCKTIME;
677
- let heights: number[] = [];
678
- let times: number[] = [];
679
- for (let i = 0; i < this.PSBT_GLOBAL_INPUT_COUNT; i++) {
680
- if (heightLocks[i] !== null) {
681
- heights.push(heightLocks[i] as number);
682
- }
683
-
684
- if (timeLocks[i] !== null) {
685
- times.push(timeLocks[i] as number);
686
- }
687
- }
688
-
689
- // From BIP0370: If none of the inputs have a PSBT_IN_REQUIRED_TIME_LOCKTIME
690
- // and *(or) PSBT_IN_REQUIRED_HEIGHT_LOCKTIME, then
691
- // PSBT_GLOBAL_FALLBACK_LOCKTIME must be used. If
692
- // PSBT_GLOBAL_FALLBACK_LOCKTIME is not provided, then it is assumed to be
693
- // 0.
694
- if (heights.length === 0 && times.length === 0) {
695
- return this.PSBT_GLOBAL_FALLBACK_LOCKTIME || 0;
696
- }
697
-
698
- // From BIP0370: If one or more inputs have a PSBT_IN_REQUIRED_TIME_LOCKTIME
699
- // or PSBT_IN_REQUIRED_HEIGHT_LOCKTIME, then the field chosen is the one
700
- // which is supported by all of the inputs. This can be determined by
701
- // looking at all of the inputs which specify a locktime in either of those
702
- // fields, and choosing the field which is present in all of those inputs.
703
- // Inputs not specifying a lock time field can take both types of lock
704
- // times, as can those that specify both. The lock time chosen is then the
705
- // maximum value of the chosen type of lock time.
706
- //
707
- // If a PSBT has both types of locktimes possible because one or more inputs
708
- // specify both PSBT_IN_REQUIRED_TIME_LOCKTIME and
709
- // PSBT_IN_REQUIRED_HEIGHT_LOCKTIME, then locktime determined by looking at
710
- // the PSBT_IN_REQUIRED_HEIGHT_LOCKTIME fields of the inputs must be chosen.
711
- if (heights.length === inputCount || heights.length > times.length) {
712
- return Math.max(...heights);
713
- }
714
- if (times.length > heights.length) {
715
- return Math.max(...times);
716
- }
717
-
718
- return null;
719
- }
720
-
721
- /**
722
- * Creator/Constructor Methods
723
- */
724
-
725
- /**
726
- * Ensures that global fields have initial values required by a PsbtV2
727
- * Creator. It is called by the constructor if constructed without a psbt.
728
- */
729
- private create() {
730
- this.PSBT_GLOBAL_VERSION = 2;
731
- this.PSBT_GLOBAL_TX_VERSION = 2;
732
- this.PSBT_GLOBAL_INPUT_COUNT = 0;
733
- this.PSBT_GLOBAL_OUTPUT_COUNT = 0;
734
-
735
- // TODO: Right now these values are setting a default. How can it be made to
736
- // accept values on the constructor method? The Creator role should be
737
- // allowed to configure these.
738
- this.PSBT_GLOBAL_FALLBACK_LOCKTIME = 0;
739
- this.PSBT_GLOBAL_TX_MODIFIABLE = [
740
- PsbtGlobalTxModifiableBits.INPUTS,
741
- PsbtGlobalTxModifiableBits.OUTPUTS,
742
- ];
743
- }
744
-
745
- /**
746
- * Checks initial construction of any valid PsbtV2. It is called when a psbt
747
- * is passed to the constructor or when a new psbt is being created. If
748
- * constructed with a psbt, this method acts outside of the Creator role to
749
- * validate the current state of the psbt.
750
- */
751
- private validate() {
752
- if (this.PSBT_GLOBAL_VERSION < 2) {
753
- throw Error("PsbtV2 has a version field set less than 2");
754
- }
755
- if (this.PSBT_GLOBAL_TX_VERSION < 2) {
756
- throw Error("PsbtV2 has a tx version field set less than 2");
757
- }
758
-
759
- for (const prevInTxid of this.PSBT_IN_PREVIOUS_TXID) {
760
- if (!prevInTxid) {
761
- throw Error("PsbtV2 input is missing PSBT_IN_PREVIOUS_TXID");
762
- }
763
- }
764
- for (const prevInVOut of this.PSBT_IN_OUTPUT_INDEX) {
765
- if (prevInVOut === undefined) {
766
- throw Error("PsbtV2 input is missing PSBT_IN_OUTPUT_INDEX");
767
- }
768
- }
769
- for (const amount of this.PSBT_OUT_AMOUNT) {
770
- if (!amount) {
771
- throw Error("PsbtV2 input is missing PSBT_OUT_AMOUNT");
772
- }
773
- }
774
- for (const script of this.PSBT_OUT_SCRIPT) {
775
- if (!script) {
776
- throw Error("PsbtV2 input is missing PSBT_OUT_SCRIPT");
777
- }
778
- }
779
- for (const locktime of this.PSBT_IN_REQUIRED_TIME_LOCKTIME) {
780
- if (locktime && locktime < 500000000) {
781
- throw Error("PsbtV2 input time locktime is less than 500000000.");
782
- }
783
- }
784
- for (const locktime of this.PSBT_IN_REQUIRED_HEIGHT_LOCKTIME) {
785
- if (locktime && locktime >= 500000000) {
786
- throw Error("PsbtV2 input hight locktime is gte 500000000.");
787
- }
788
- }
789
- }
790
-
791
- /**
792
- * This method is provided for compatibility issues and probably shouldn't be
793
- * used since a PsbtV2 with PSBT_GLOBAL_TX_VERSION = 1 is BIP0370
794
- * non-compliant. No guarantees can be made here that a serialized PsbtV2
795
- * which used this method will be compatible with outside consumers.
796
- *
797
- * One may wish to instance this class from a partially signed PSBTv0 with a
798
- * txn version 1 by using the static PsbtV2.FromV0. This method provides a way
799
- * to override validation logic for the txn version and roles lifecycle
800
- * defined for PsbtV2.
801
- */
802
- public dangerouslySetGlobalTxVersion1() {
803
- if (!this.isReadyForConstructor) {
804
- throw Error(
805
- "The PsbtV2 is not ready for a Constructor. The PSBT_GLOBAL_TX_VERSION should not be forced to version 1.",
806
- );
807
- }
808
- console.warn("Dangerously setting PsbtV2.PSBT_GLOBAL_TX_VERSION to 1!");
809
- const bw = new BufferWriter();
810
- bw.writeI32(1);
811
- this.globalMap.set(KeyType.PSBT_GLOBAL_TX_VERSION, bw.render());
812
- }
813
-
814
- // Is this a Creator/Constructor role action, or something else? BIPs don't
815
- // define it well.
816
- public addGlobalXpub(xpub: Buffer, fingerprint: Buffer, path: string) {
817
- const bw = new BufferWriter();
818
- bw.writeBytes(Buffer.from(KeyType.PSBT_GLOBAL_XPUB, "hex"));
819
- bw.writeBytes(xpub);
820
- const key = bw.render().toString("hex");
821
- bw.writeBytes(fingerprint);
822
- const pathBytes = parseDerivationPathNodesToBytes(path);
823
- bw.writeBytes(pathBytes);
824
- const value = bw.render();
825
- this.globalMap.set(key, value);
826
- }
827
-
828
- public addInput({
829
- previousTxId,
830
- outputIndex,
831
- sequence,
832
- nonWitnessUtxo,
833
- witnessUtxo,
834
- redeemScript,
835
- witnessScript,
836
- bip32Derivation,
837
- }: {
838
- previousTxId: Buffer | string;
839
- outputIndex: number;
840
- sequence?: number;
841
- nonWitnessUtxo?: Buffer;
842
- witnessUtxo?: { amount: number; script: Buffer };
843
- redeemScript?: Buffer;
844
- witnessScript?: Buffer;
845
- bip32Derivation?: {
846
- pubkey: Buffer;
847
- masterFingerprint: Buffer;
848
- path: string;
849
- }[];
850
- }) {
851
- // TODO: This must accept and add appropriate locktime fields. There is
852
- // significant validation concerning this step detailed in the BIP0370
853
- // Constructor role:
854
- // https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki#constructor
855
- //
856
- // TODO: This method must properly handle the SIGHASH_SINGLE flag. If the
857
- // `PSBT_GLOBAL_TX_MODIFIABLE` flag `SIGHASH_SINGLE` is present and a
858
- // signature is present, then adding or removing inputs or outputs before a
859
- // signature with sighash_single must happen atomically in pairs.
860
-
861
- if (!this.isReadyForConstructor) {
862
- throw Error(
863
- "The PsbtV2 is not ready for a Constructor. Inputs cannot be added.",
864
- );
865
- }
866
- if (!this.isModifiable([PsbtGlobalTxModifiableBits.INPUTS])) {
867
- throw Error(
868
- "PsbtV2.PSBT_GLOBAL_TX_MODIFIABLE inputs cannot be modified.",
869
- );
870
- }
871
- const map = new Map<Key, Value>();
872
- const bw = new BufferWriter();
873
- const prevTxIdBuf = bufferize(previousTxId);
874
- bw.writeBytes(prevTxIdBuf);
875
-
876
- map.set(KeyType.PSBT_IN_PREVIOUS_TXID, bw.render());
877
- bw.writeI32(outputIndex);
878
- map.set(KeyType.PSBT_IN_OUTPUT_INDEX, bw.render());
879
- if (sequence) {
880
- bw.writeI32(sequence);
881
- map.set(KeyType.PSBT_IN_SEQUENCE, bw.render());
882
- }
883
- if (nonWitnessUtxo) {
884
- bw.writeBytes(nonWitnessUtxo);
885
- map.set(KeyType.PSBT_IN_NON_WITNESS_UTXO, bw.render());
886
- }
887
- if (witnessUtxo) {
888
- bw.writeI64(witnessUtxo.amount);
889
- bw.writeU8(witnessUtxo.script.length);
890
- bw.writeBytes(witnessUtxo.script);
891
- map.set(KeyType.PSBT_IN_WITNESS_UTXO, bw.render());
892
- }
893
- if (redeemScript) {
894
- bw.writeBytes(redeemScript);
895
- map.set(KeyType.PSBT_IN_REDEEM_SCRIPT, bw.render());
896
- }
897
- if (witnessScript) {
898
- bw.writeBytes(witnessScript);
899
- map.set(KeyType.PSBT_IN_WITNESS_SCRIPT, bw.render());
900
- }
901
- if (bip32Derivation) {
902
- for (const bip32 of bip32Derivation) {
903
- bw.writeString(KeyType.PSBT_IN_BIP32_DERIVATION, "hex");
904
- bw.writeBytes(bip32.pubkey);
905
- const key = bw.render().toString("hex");
906
- bw.writeBytes(bip32.masterFingerprint);
907
- bw.writeBytes(parseDerivationPathNodesToBytes(bip32.path));
908
- map.set(key, bw.render());
909
- }
910
- }
911
-
912
- this.PSBT_GLOBAL_INPUT_COUNT = this.inputMaps.push(map);
913
- }
914
-
915
- public addOutput({
916
- amount,
917
- script,
918
- redeemScript,
919
- witnessScript,
920
- bip32Derivation,
921
- }: {
922
- amount: number;
923
- script: Buffer;
924
- redeemScript?: Buffer;
925
- witnessScript?: Buffer;
926
- bip32Derivation?: {
927
- pubkey: Buffer;
928
- masterFingerprint: Buffer;
929
- path: string;
930
- }[];
931
- }) {
932
- if (!this.isReadyForConstructor) {
933
- throw Error(
934
- "The PsbtV2 is not ready for a Constructor. Outputs cannot be added.",
935
- );
936
- }
937
- if (!this.isModifiable([PsbtGlobalTxModifiableBits.OUTPUTS])) {
938
- throw Error(
939
- "PsbtV2.PSBT_GLOBAL_TX_MODIFIABLE outputs cannot be modified.",
940
- );
941
- }
942
- const map = new Map<Key, Value>();
943
- const bw = new BufferWriter();
944
- bw.writeI64(amount);
945
- map.set(KeyType.PSBT_OUT_AMOUNT, bw.render());
946
- bw.writeBytes(script);
947
- map.set(KeyType.PSBT_OUT_SCRIPT, bw.render());
948
-
949
- if (redeemScript) {
950
- bw.writeBytes(redeemScript);
951
- map.set(KeyType.PSBT_OUT_REDEEM_SCRIPT, bw.render());
952
- }
953
- if (witnessScript) {
954
- bw.writeBytes(witnessScript);
955
- map.set(KeyType.PSBT_OUT_WITNESS_SCRIPT, bw.render());
956
- }
957
- if (bip32Derivation) {
958
- for (const bip32 of bip32Derivation) {
959
- bw.writeString(KeyType.PSBT_OUT_BIP32_DERIVATION, "hex");
960
- bw.writeBytes(bip32.pubkey);
961
- const key = bw.render().toString("hex");
962
- bw.writeBytes(bip32.masterFingerprint);
963
- bw.writeBytes(parseDerivationPathNodesToBytes(bip32.path));
964
- map.set(key, bw.render());
965
- }
966
- }
967
-
968
- this.outputMaps.push(map);
969
- this.PSBT_GLOBAL_OUTPUT_COUNT = this.outputMaps.length;
970
- }
971
-
972
- /**
973
- * Updater/Signer Methods
974
- */
975
-
976
- /**
977
- * Removes an input-map from inputMaps.
978
- */
979
- public deleteInput(index: number) {
980
- if (!this.isReadyForConstructor) {
981
- throw Error(
982
- "The PsbtV2 is not ready for a Constructor. Inputs cannot be removed.",
983
- );
984
- }
985
- if (!this.isModifiable([PsbtGlobalTxModifiableBits.INPUTS])) {
986
- throw Error(
987
- "PsbtV2.PSBT_GLOBAL_TX_MODIFIABLE inputs cannot be modified.",
988
- );
989
- }
990
- const newInputs = this.inputMaps.filter((_, i) => i !== index);
991
- this.inputMaps = newInputs;
992
- this.PSBT_GLOBAL_INPUT_COUNT = this.inputMaps.length;
993
- }
994
-
995
- /**
996
- * Removes an output-map from outputMaps.
997
- */
998
- public deleteOutput(index: number) {
999
- if (!this.isReadyForConstructor) {
1000
- throw Error(
1001
- "The PsbtV2 is not ready for a Constructor. Outputs cannot be removed.",
1002
- );
1003
- }
1004
- if (!this.isModifiable([PsbtGlobalTxModifiableBits.OUTPUTS])) {
1005
- throw Error(
1006
- "PsbtV2.PSBT_GLOBAL_TX_MODIFIABLE outputs cannot be modified.",
1007
- );
1008
- // Alternatively, an output could be removed, but depending on the sighash
1009
- // flags for each signature, it might prompt removing all sigs.
1010
- }
1011
-
1012
- const newOutputs = this.outputMaps.filter((_, i) => i !== index);
1013
-
1014
- if (this.isModifiable([PsbtGlobalTxModifiableBits.SIGHASH_SINGLE])) {
1015
- // SIGHASH_SINGLE ties the input to the output, so remove input sig since
1016
- // it is no longer valid.
1017
- this.removePartialSig(index);
1018
- }
1019
-
1020
- this.outputMaps = newOutputs;
1021
- this.PSBT_GLOBAL_OUTPUT_COUNT = this.outputMaps.length;
1022
- }
1023
-
1024
- /**
1025
- * Checks that all provided flags are present in PSBT_GLOBAL_TX_MODIFIABLE.
1026
- */
1027
- private isModifiable(flags: PsbtGlobalTxModifiableBits[]) {
1028
- for (const flag of flags) {
1029
- if (!this.PSBT_GLOBAL_TX_MODIFIABLE.includes(flag)) {
1030
- return false;
1031
- }
1032
- }
1033
-
1034
- return true;
1035
- }
1036
-
1037
- /**
1038
- * Adds a signature for an input. Validates that the input is mapped and does
1039
- * not already have a signature for the pubkey. Also validates for sighash.
1040
- * Other validation is incomplete. Also validates for required args in case
1041
- * typescript is not being used to call the method.
1042
- *
1043
- * The Signer, when it creates a signature, must add the partial sig keypair
1044
- * to the psbt for the input which it is signing. In the case that a
1045
- * particular signer does not, this method can be used to add a signature to
1046
- * the psbt. This method assumes the Signer did the validation outlined in
1047
- * BIP0174 before creating a signature.
1048
- * https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#signer
1049
- */
1050
- public addPartialSig(inputIndex: number, pubkey: Buffer, sig: Buffer) {
1051
- if (!this.isReadyForSigner) {
1052
- throw Error(
1053
- "The PsbtV2 is not ready for a Signer. Partial sigs cannot be added.",
1054
- );
1055
- }
1056
- if (!this.inputMaps[inputIndex]) {
1057
- throw Error(`PsbtV2 has no input at ${inputIndex}`);
1058
- }
1059
-
1060
- if (!pubkey || !sig) {
1061
- throw Error(
1062
- `PsbtV2.addPartialSig() missing argument ${
1063
- (!pubkey && "pubkey") || (!sig && "sig")
1064
- }`,
1065
- );
1066
- }
1067
-
1068
- const key = `${KeyType.PSBT_IN_PARTIAL_SIG}${pubkey.toString("hex")}`;
1069
- if (this.inputMaps[inputIndex].has(key)) {
1070
- throw Error(
1071
- "PsbtV2 already has a signature for this input with this pubkey",
1072
- );
1073
- }
1074
-
1075
- const modBackup = this.PSBT_GLOBAL_TX_MODIFIABLE;
1076
- try {
1077
- this.inputMaps[inputIndex].set(key, sig);
1078
- this.handleSighashType(sig);
1079
- } catch (err) {
1080
- console.error(err);
1081
- // To remain atomic, attempt to reset everything to the way it was.
1082
- this.inputMaps[inputIndex].delete(key);
1083
- this.PSBT_GLOBAL_TX_MODIFIABLE = modBackup;
1084
- }
1085
- }
1086
-
1087
- /**
1088
- * Removes all sigs for an input unless a pubkey is specified. Validates that
1089
- * the input exists. When providing a pubkey, this validates that a sig for
1090
- * the pubkey exists.
1091
- */
1092
- public removePartialSig(inputIndex: number, pubkey?: Buffer) {
1093
- // TODO: What role is allowed to remove a partial sig? Perform that
1094
- // role-check validation here.
1095
- const input = this.inputMaps[inputIndex];
1096
-
1097
- if (!input) {
1098
- throw Error(`PsbtV2 has no input at ${inputIndex}`);
1099
- }
1100
-
1101
- if (pubkey) {
1102
- // Pubkey has been provided to remove a specific sig on the input.
1103
- const key = `${KeyType.PSBT_IN_PARTIAL_SIG}${pubkey.toString("hex")}`;
1104
- const sig = this.PSBT_IN_PARTIAL_SIG[inputIndex].find(
1105
- (el) => el.key === key,
1106
- );
1107
-
1108
- if (!sig) {
1109
- throw Error(
1110
- `PsbtV2 input has no signature from pubkey ${pubkey.toString("hex")}`,
1111
- );
1112
- }
1113
-
1114
- input.delete(key);
1115
- } else {
1116
- // Remove all sigs on an input.
1117
- const sigs = this.PSBT_IN_PARTIAL_SIG[inputIndex];
1118
- for (const sig of sigs) {
1119
- input.delete(sig.key);
1120
- }
1121
- }
1122
- }
1123
-
1124
- /**
1125
- * Sets values on the proprietary keytype for a global, input, or output map.
1126
- * BIP 174 allows for proprietary values to be set on all maps with the
1127
- * keytype `0xFC`. This method sets byte data to key values defined by the
1128
- * args.
1129
- *
1130
- * Args:
1131
- * - `mapSelector` selects which map to set the proprietary value. If this
1132
- * value is not `"global"`, then a tuple must be provided with `"inputs"` or
1133
- * `"outputs"` as the first element and the index `number` on the second
1134
- * element representing which input or output map to set the value to. An
1135
- * example looks like `["inputs", 0]`. If the map name doesn't match, the
1136
- * values will be set to the global map. If the index is missing on
1137
- * `"inputs"` or `"outputs"`, then it will throw.
1138
- * - `identifier` should be the bytes identifier for the set of proprietary
1139
- * keytypes.
1140
- * - `subkeyType` accepts bytes proprietary keytype.
1141
- * - `subkeyData` accepts bytes proprietary keydata.
1142
- * - `valueData` accepts bytes which will be written as the proprietary value.
1143
- *
1144
- * From the provided args, a key with the following format will be generated:
1145
- * `0xFC<compact uint identifier length><bytes identifier><bytes
1146
- * subtype><bytes subkeydata>`
1147
- */
1148
- public setProprietaryValue(
1149
- mapSelector: MapSelectorType,
1150
- identifier: Buffer,
1151
- subkeyType: Buffer,
1152
- subkeyData: Buffer,
1153
- valueData: Buffer,
1154
- ) {
1155
- if (
1156
- (mapSelector[0] === "inputs" || mapSelector[0] === "outputs") &&
1157
- typeof mapSelector[1] !== "number"
1158
- ) {
1159
- throw Error(
1160
- "Must specify an index when setting proprietary values to inputs or outputs.",
1161
- );
1162
- }
1163
-
1164
- let classMap: Map<string, Buffer> = this.globalMap,
1165
- keyType = KeyType.PSBT_GLOBAL_PROPRIETARY;
1166
- if (mapSelector[0] === "inputs") {
1167
- classMap = this.inputMaps[mapSelector[1]];
1168
- keyType = KeyType.PSBT_IN_PROPRIETARY;
1169
- } else if (mapSelector[0] === "outputs") {
1170
- classMap = this.outputMaps[mapSelector[1]];
1171
- keyType = KeyType.PSBT_OUT_PROPRIETARY;
1172
- }
1173
-
1174
- if (!classMap) {
1175
- throw Error("Map does not exist at that index.");
1176
- }
1177
-
1178
- const bw = new BufferWriter();
1179
- bw.writeBytes(Buffer.from(keyType, "hex"));
1180
- bw.writeU8(identifier.length);
1181
- bw.writeBytes(identifier);
1182
- bw.writeBytes(subkeyType);
1183
- bw.writeBytes(subkeyData);
1184
- const key = bw.render().toString("hex");
1185
- bw.writeBytes(valueData);
1186
- const value = bw.render();
1187
- classMap.set(key, value);
1188
- }
1189
-
1190
- /**
1191
- * Ensures the PSBT is in the proper state when adding a partial sig keypair.
1192
- * https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki#signer
1193
- */
1194
- private handleSighashType(sig: Buffer) {
1195
- const br = new BufferReader(sig.slice(-1));
1196
- let sighashVal = br.readU8();
1197
- let modifiable = this.PSBT_GLOBAL_TX_MODIFIABLE;
1198
-
1199
- if (!(sighashVal & SighashType.SIGHASH_ANYONECANPAY)) {
1200
- modifiable = modifiable.filter(
1201
- (val) => val !== PsbtGlobalTxModifiableBits.INPUTS,
1202
- );
1203
- } else {
1204
- // Unset SIGHASH_ANYONECANPAY bit for simpler comparisons
1205
- sighashVal ^= SighashType.SIGHASH_ANYONECANPAY;
1206
- }
1207
-
1208
- // Can't use bitwise the whole way because SIGHASH_SINGLE is a 3.
1209
- if (sighashVal !== SighashType.SIGHASH_NONE) {
1210
- modifiable = modifiable.filter(
1211
- (val) => val !== PsbtGlobalTxModifiableBits.OUTPUTS,
1212
- );
1213
- }
1214
- if (
1215
- sighashVal === SighashType.SIGHASH_SINGLE &&
1216
- !modifiable.includes(PsbtGlobalTxModifiableBits.SIGHASH_SINGLE)
1217
- ) {
1218
- modifiable.push(PsbtGlobalTxModifiableBits.SIGHASH_SINGLE);
1219
- }
1220
-
1221
- this.PSBT_GLOBAL_TX_MODIFIABLE = modifiable;
1222
- }
1223
-
1224
- /**
1225
- * Attempts to return a PsbtV2 by converting from a PsbtV0 string or Buffer.
1226
- *
1227
- * This method first starts with a fresh PsbtV2 having just been created. It
1228
- * then takes the PsbtV2 through its operator saga through the Signer role. In
1229
- * this sense validation for each operator role will be performed.
1230
- */
1231
- static FromV0(psbt: string | Buffer, allowTxnVersion1 = false): PsbtV2 {
1232
- const psbtv0Buf = bufferize(psbt);
1233
- const psbtv0 = Psbt.fromBuffer(psbtv0Buf);
1234
- const psbtv0GlobalMap = psbtv0.data.globalMap;
1235
-
1236
- // Creator Role
1237
- const psbtv2 = new PsbtV2();
1238
- const txVersion = psbtv0.data.getTransaction().readInt32LE(0);
1239
- if (txVersion === 1 && allowTxnVersion1) {
1240
- psbtv2.dangerouslySetGlobalTxVersion1();
1241
- } else {
1242
- psbtv2.PSBT_GLOBAL_TX_VERSION = psbtv0.data
1243
- .getTransaction()
1244
- .readInt32LE(0);
1245
- }
1246
-
1247
- // Constructor Role
1248
- for (const globalXpub of psbtv0GlobalMap.globalXpub ?? []) {
1249
- psbtv2.addGlobalXpub(
1250
- globalXpub.extendedPubkey,
1251
- globalXpub.masterFingerprint,
1252
- globalXpub.path,
1253
- );
1254
- }
1255
-
1256
- const txInputs: any = [];
1257
- for (const [index, txInput] of psbtv0.txInputs.entries()) {
1258
- txInputs[index] = txInput;
1259
- }
1260
-
1261
- for (const [index, input] of psbtv0.data.inputs.entries()) {
1262
- const txInput = txInputs[index];
1263
- psbtv2.addInput({
1264
- previousTxId: txInput.hash,
1265
- outputIndex: txInput.index,
1266
- sequence: txInput.sequence,
1267
- nonWitnessUtxo: input.nonWitnessUtxo,
1268
- witnessUtxo: input.witnessUtxo && {
1269
- amount: input.witnessUtxo.value,
1270
- script: input.witnessUtxo.script,
1271
- },
1272
- redeemScript: input.redeemScript,
1273
- witnessScript: input.witnessScript,
1274
- bip32Derivation: input.bip32Derivation,
1275
- });
1276
- }
1277
-
1278
- const txOutputs: any = [];
1279
- for (const [index, txOutput] of psbtv0.txOutputs.entries()) {
1280
- txOutputs[index] = txOutput;
1281
- }
1282
-
1283
- for (const [index, output] of psbtv0.data.outputs.entries()) {
1284
- const txOutput = txOutputs[index];
1285
- psbtv2.addOutput({
1286
- amount: txOutput.value,
1287
- script: txOutput.script,
1288
- redeemScript: output.redeemScript,
1289
- witnessScript: output.witnessScript,
1290
- bip32Derivation: output.bip32Derivation,
1291
- });
1292
- }
1293
-
1294
- // Signer Role
1295
-
1296
- // Finally, add partialSigs to inputs. This has to be performed last since
1297
- // it may change PSBT_GLOBAL_TX_MODIFIABLE preventing inputs or outputs from
1298
- // being added.
1299
- for (const [index, input] of psbtv0.data.inputs.entries()) {
1300
- for (const sig of input.partialSig || []) {
1301
- psbtv2.addPartialSig(index, sig.pubkey, sig.signature);
1302
- }
1303
- }
1304
-
1305
- return psbtv2;
1306
- }
1307
- }