@caravan/psbt 1.0.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.
package/dist/index.js ADDED
@@ -0,0 +1,949 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ PsbtV2: () => PsbtV2,
34
+ getPsbtVersionNumber: () => getPsbtVersionNumber
35
+ });
36
+ module.exports = __toCommonJS(src_exports);
37
+
38
+ // ../../node_modules/esbuild-plugin-polyfill-node/polyfills/buffer.js
39
+ var import_buffer = require("buffer");
40
+
41
+ // src/psbtv2.ts
42
+ var import_bufio = require("bufio");
43
+ var import_bitcoinjs_lib2 = require("bitcoinjs-lib");
44
+ var import_bitcoin3 = require("@caravan/bitcoin");
45
+
46
+ // src/psbt.ts
47
+ var import_bitcoinjs_lib = require("bitcoinjs-lib");
48
+ var import_bufferutils = require("bitcoinjs-lib/src/bufferutils.js");
49
+ var import_bitcoin = require("@caravan/bitcoin");
50
+ var import_bitcoin2 = require("@caravan/bitcoin");
51
+ var import_bignumber = __toESM(require("bignumber.js"));
52
+ var PSBT_MAGIC_BYTES = import_buffer.Buffer.from([112, 115, 98, 116, 255]);
53
+
54
+ // src/psbtv2.ts
55
+ var PSBT_MAP_SEPARATOR = import_buffer.Buffer.from([0]);
56
+ var BIP_32_NODE_REGEX = /(\/[0-9]+'?)/gi;
57
+ var BIP_32_HARDENING_OFFSET = 2147483648;
58
+ function bufferize(psbt) {
59
+ if (import_buffer.Buffer.isBuffer(psbt)) {
60
+ return psbt;
61
+ }
62
+ if (typeof psbt === "string") {
63
+ if ((0, import_bitcoin3.validateHex)(psbt) === "") {
64
+ return import_buffer.Buffer.from(psbt, "hex");
65
+ }
66
+ if ((0, import_bitcoin3.validBase64)(psbt)) {
67
+ return import_buffer.Buffer.from(psbt, "base64");
68
+ }
69
+ }
70
+ throw Error("Input cannot be bufferized.");
71
+ }
72
+ function getNonUniqueKeyTypeValues(maps, keytype) {
73
+ if (Array.isArray(maps)) {
74
+ const values2 = maps.map(
75
+ (map2) => (
76
+ // TODO: Figure out a better way to type this
77
+ getNonUniqueKeyTypeValues(map2, keytype)
78
+ )
79
+ );
80
+ return values2;
81
+ }
82
+ const map = maps;
83
+ const values = [];
84
+ for (const [key, value] of map.entries()) {
85
+ if (key.startsWith(keytype)) {
86
+ values.push({ key, value: value?.toString("hex") || null });
87
+ }
88
+ }
89
+ return values;
90
+ }
91
+ function getOptionalMappedBytesAsHex(maps, keytype) {
92
+ return maps.map((map) => map.get(keytype)?.toString("hex") ?? null);
93
+ }
94
+ function getOptionalMappedBytesAsUInt(maps, keytype) {
95
+ return maps.map((map) => map.get(keytype)?.readUInt32LE(0) ?? null);
96
+ }
97
+ function parseDerivationPathNodesToBytes(path) {
98
+ const validationMessage = (0, import_bitcoin3.validateBIP32Path)(path);
99
+ if (validationMessage !== "") {
100
+ throw Error(validationMessage);
101
+ }
102
+ const bw = new import_bufio.BufferWriter();
103
+ for (const node of path.match(BIP_32_NODE_REGEX) ?? []) {
104
+ let num = parseInt(node.slice(1), 10);
105
+ if (node.indexOf("'") > -1) {
106
+ num += BIP_32_HARDENING_OFFSET;
107
+ }
108
+ bw.writeU32(num);
109
+ }
110
+ return bw.render();
111
+ }
112
+ function readAndSetKeyPairs(map, br) {
113
+ const nextByte = br.readBytes(1);
114
+ if (nextByte.equals(PSBT_MAP_SEPARATOR)) {
115
+ return;
116
+ }
117
+ const keyLen = nextByte.readUInt8(0);
118
+ const key = br.readBytes(keyLen);
119
+ const value = br.readVarBytes();
120
+ map.set(key.toString("hex"), value);
121
+ readAndSetKeyPairs(map, br);
122
+ }
123
+ function serializeMap(map, bw) {
124
+ map.forEach((value, key) => {
125
+ const keyBuf = import_buffer.Buffer.from(key, "hex");
126
+ const keyLen = keyBuf.length;
127
+ bw.writeVarint(keyLen);
128
+ bw.writeString(key, "hex");
129
+ bw.writeVarint(value.length);
130
+ bw.writeBytes(value);
131
+ });
132
+ bw.writeBytes(PSBT_MAP_SEPARATOR);
133
+ }
134
+ var PsbtV2Maps = class {
135
+ // These maps directly correspond to the maps defined in BIP0174
136
+ globalMap = /* @__PURE__ */ new Map();
137
+ inputMaps = [];
138
+ outputMaps = [];
139
+ constructor(psbt) {
140
+ if (!psbt) {
141
+ return;
142
+ }
143
+ const buf = bufferize(psbt);
144
+ const br = new import_bufio.BufferReader(buf);
145
+ if (!br.readBytes(PSBT_MAGIC_BYTES.length, true).equals(PSBT_MAGIC_BYTES)) {
146
+ throw Error("PsbtV2 magic bytes are incorrect.");
147
+ }
148
+ readAndSetKeyPairs(this.globalMap, br);
149
+ if (
150
+ // Assuming that psbt being passed in is a valid psbtv2
151
+ !this.globalMap.has("fb" /* PSBT_GLOBAL_VERSION */) || !this.globalMap.has("02" /* PSBT_GLOBAL_TX_VERSION */) || !this.globalMap.has("04" /* PSBT_GLOBAL_INPUT_COUNT */) || !this.globalMap.has("05" /* PSBT_GLOBAL_OUTPUT_COUNT */) || this.globalMap.has("00")
152
+ ) {
153
+ throw Error("Provided PsbtV2 not valid. Missing required global keys.");
154
+ }
155
+ const inputCount = this.globalMap.get("04" /* PSBT_GLOBAL_INPUT_COUNT */)?.readUInt8(0) ?? 0;
156
+ for (let i = 0; i < inputCount; i++) {
157
+ const map = /* @__PURE__ */ new Map();
158
+ readAndSetKeyPairs(map, br);
159
+ this.inputMaps.push(map);
160
+ }
161
+ const outputCount = this.globalMap.get("05" /* PSBT_GLOBAL_OUTPUT_COUNT */)?.readUInt8(0) ?? 0;
162
+ for (let i = 0; i < outputCount; i++) {
163
+ const map = /* @__PURE__ */ new Map();
164
+ readAndSetKeyPairs(map, br);
165
+ this.outputMaps.push(map);
166
+ }
167
+ }
168
+ // Return the current state of the psbt as a string in the specified format.
169
+ serialize(format = "base64") {
170
+ let bw = new import_bufio.BufferWriter();
171
+ bw.writeBytes(PSBT_MAGIC_BYTES);
172
+ serializeMap(this.globalMap, bw);
173
+ for (const map of this.inputMaps) {
174
+ serializeMap(map, bw);
175
+ }
176
+ for (const map of this.outputMaps) {
177
+ serializeMap(map, bw);
178
+ }
179
+ return bw.render().toString(format);
180
+ }
181
+ // NOTE: This set of copy methods is made available to
182
+ // achieve parity with the PSBT api required by ledger-bitcoin
183
+ // for creating merklized PSBTs. HOWEVER, it is not recommended
184
+ // to use this when avoidable as copying maps bypasses the validation
185
+ // defined in the constructor, so it could create a psbtv2 in an invalid psbt status.
186
+ // PsbtV2.serialize is preferable whenever possible.
187
+ copy(to) {
188
+ this.copyMap(this.globalMap, to.globalMap);
189
+ this.copyMaps(this.inputMaps, to.inputMaps);
190
+ this.copyMaps(this.outputMaps, to.outputMaps);
191
+ }
192
+ copyMaps(from, to) {
193
+ from.forEach((m, index) => {
194
+ const to_index = /* @__PURE__ */ new Map();
195
+ this.copyMap(m, to_index);
196
+ to[index] = to_index;
197
+ });
198
+ }
199
+ // eslint-disable-next-line class-methods-use-this
200
+ copyMap(from, to) {
201
+ from.forEach((v, k) => to.set(k, import_buffer.Buffer.from(v)));
202
+ }
203
+ };
204
+ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
205
+ constructor(psbt) {
206
+ super(psbt);
207
+ if (!psbt) {
208
+ this.create();
209
+ }
210
+ this.validate();
211
+ }
212
+ /**
213
+ * Globals Getters/Setters
214
+ */
215
+ get PSBT_GLOBAL_XPUB() {
216
+ return getNonUniqueKeyTypeValues(this.globalMap, "01" /* PSBT_GLOBAL_XPUB */);
217
+ }
218
+ get PSBT_GLOBAL_TX_VERSION() {
219
+ const val = this.globalMap.get("02" /* PSBT_GLOBAL_TX_VERSION */);
220
+ if (val === void 0) {
221
+ throw Error("PSBT_GLOBAL_TX_VERSION not set");
222
+ }
223
+ return val.readInt32LE(0);
224
+ }
225
+ set PSBT_GLOBAL_TX_VERSION(version) {
226
+ if (version < 2) {
227
+ throw Error(
228
+ `PsbtV2 cannot have a global tx version less than 2. Version ${version} specified.`
229
+ );
230
+ }
231
+ const bw = new import_bufio.BufferWriter();
232
+ bw.writeI32(version);
233
+ this.globalMap.set("02" /* PSBT_GLOBAL_TX_VERSION */, bw.render());
234
+ }
235
+ get PSBT_GLOBAL_FALLBACK_LOCKTIME() {
236
+ return this.globalMap.get("03" /* PSBT_GLOBAL_FALLBACK_LOCKTIME */)?.readUInt32LE(0) ?? null;
237
+ }
238
+ set PSBT_GLOBAL_FALLBACK_LOCKTIME(locktime) {
239
+ if (locktime === null) {
240
+ this.globalMap.delete("03" /* PSBT_GLOBAL_FALLBACK_LOCKTIME */);
241
+ } else {
242
+ const bw = new import_bufio.BufferWriter();
243
+ bw.writeI32(locktime);
244
+ this.globalMap.set("03" /* PSBT_GLOBAL_FALLBACK_LOCKTIME */, bw.render());
245
+ }
246
+ }
247
+ get PSBT_GLOBAL_INPUT_COUNT() {
248
+ const val = this.globalMap.get("04" /* PSBT_GLOBAL_INPUT_COUNT */);
249
+ if (val === void 0) {
250
+ throw Error("PSBT_GLOBAL_INPUT_COUNT not set");
251
+ }
252
+ return val.readUInt8(0);
253
+ }
254
+ set PSBT_GLOBAL_INPUT_COUNT(count) {
255
+ const bw = new import_bufio.BufferWriter();
256
+ bw.writeU8(count);
257
+ this.globalMap.set("04" /* PSBT_GLOBAL_INPUT_COUNT */, bw.render());
258
+ }
259
+ get PSBT_GLOBAL_OUTPUT_COUNT() {
260
+ const val = this.globalMap.get("05" /* PSBT_GLOBAL_OUTPUT_COUNT */);
261
+ if (val === void 0) {
262
+ throw Error("PSBT_GLOBAL_OUTPUT_COUNT not set");
263
+ }
264
+ return val.readUInt8(0);
265
+ }
266
+ set PSBT_GLOBAL_OUTPUT_COUNT(count) {
267
+ const bw = new import_bufio.BufferWriter();
268
+ bw.writeU8(count);
269
+ this.globalMap.set("05" /* PSBT_GLOBAL_OUTPUT_COUNT */, bw.render());
270
+ }
271
+ get PSBT_GLOBAL_TX_MODIFIABLE() {
272
+ const val = this.globalMap.get("06" /* PSBT_GLOBAL_TX_MODIFIABLE */)?.readUInt8(0) || 0;
273
+ let modifiable = [];
274
+ if (val & 1) {
275
+ modifiable.push("INPUTS" /* INPUTS */);
276
+ }
277
+ if (val & 2) {
278
+ modifiable.push("OUTPUTS" /* OUTPUTS */);
279
+ }
280
+ if (val & 4) {
281
+ modifiable.push("SIGHASH_SINGLE" /* SIGHASH_SINGLE */);
282
+ }
283
+ return modifiable;
284
+ }
285
+ set PSBT_GLOBAL_TX_MODIFIABLE(modifiable) {
286
+ let val = 0;
287
+ if (modifiable.includes("INPUTS" /* INPUTS */)) {
288
+ val |= 1;
289
+ }
290
+ if (modifiable.includes("OUTPUTS" /* OUTPUTS */)) {
291
+ val |= 2;
292
+ }
293
+ if (modifiable.includes("SIGHASH_SINGLE" /* SIGHASH_SINGLE */)) {
294
+ val |= 4;
295
+ }
296
+ const br = new import_bufio.BufferWriter();
297
+ br.writeU8(val);
298
+ this.globalMap.set("06" /* PSBT_GLOBAL_TX_MODIFIABLE */, br.render());
299
+ }
300
+ get PSBT_GLOBAL_VERSION() {
301
+ const version = this.globalMap.get("fb" /* PSBT_GLOBAL_VERSION */)?.readUInt32LE(0);
302
+ if (version === void 0) {
303
+ console.warn("PSBT_GLOBAL_VERSION key is missing! Setting to version 2.");
304
+ this.PSBT_GLOBAL_VERSION = 2;
305
+ }
306
+ return version ?? 2;
307
+ }
308
+ set PSBT_GLOBAL_VERSION(version) {
309
+ let workingVersion = version;
310
+ if (workingVersion < 2) {
311
+ console.warn(
312
+ `PsbtV2 cannot have a global version less than 2. Version ${workingVersion} specified. Setting to version 2.`
313
+ );
314
+ workingVersion = 2;
315
+ }
316
+ const bw = new import_bufio.BufferWriter();
317
+ bw.writeU32(workingVersion);
318
+ this.globalMap.set("fb" /* PSBT_GLOBAL_VERSION */, bw.render());
319
+ }
320
+ get PSBT_GLOBAL_PROPRIETARY() {
321
+ return getNonUniqueKeyTypeValues(
322
+ this.globalMap,
323
+ "fc" /* PSBT_GLOBAL_PROPRIETARY */
324
+ );
325
+ }
326
+ /**
327
+ * Input Getters/Setters
328
+ */
329
+ get PSBT_IN_NON_WITNESS_UTXO() {
330
+ return getOptionalMappedBytesAsHex(
331
+ this.inputMaps,
332
+ "00" /* PSBT_IN_NON_WITNESS_UTXO */
333
+ );
334
+ }
335
+ get PSBT_IN_WITNESS_UTXO() {
336
+ return getOptionalMappedBytesAsHex(
337
+ this.inputMaps,
338
+ "01" /* PSBT_IN_WITNESS_UTXO */
339
+ );
340
+ }
341
+ get PSBT_IN_PARTIAL_SIG() {
342
+ return getNonUniqueKeyTypeValues(
343
+ this.inputMaps,
344
+ "02" /* PSBT_IN_PARTIAL_SIG */
345
+ );
346
+ }
347
+ get PSBT_IN_SIGHASH_TYPE() {
348
+ return getOptionalMappedBytesAsUInt(
349
+ this.inputMaps,
350
+ "03" /* PSBT_IN_SIGHASH_TYPE */
351
+ );
352
+ }
353
+ get PSBT_IN_REDEEM_SCRIPT() {
354
+ return getOptionalMappedBytesAsHex(
355
+ this.inputMaps,
356
+ "04" /* PSBT_IN_REDEEM_SCRIPT */
357
+ );
358
+ }
359
+ get PSBT_IN_WITNESS_SCRIPT() {
360
+ return getOptionalMappedBytesAsHex(
361
+ this.inputMaps,
362
+ "05" /* PSBT_IN_WITNESS_SCRIPT */
363
+ );
364
+ }
365
+ get PSBT_IN_BIP32_DERIVATION() {
366
+ return getNonUniqueKeyTypeValues(
367
+ this.inputMaps,
368
+ "06" /* PSBT_IN_BIP32_DERIVATION */
369
+ );
370
+ }
371
+ get PSBT_IN_FINAL_SCRIPTSIG() {
372
+ return getOptionalMappedBytesAsHex(
373
+ this.inputMaps,
374
+ "07" /* PSBT_IN_FINAL_SCRIPTSIG */
375
+ );
376
+ }
377
+ get PSBT_IN_FINAL_SCRIPTWITNESS() {
378
+ return getOptionalMappedBytesAsHex(
379
+ this.inputMaps,
380
+ "08" /* PSBT_IN_FINAL_SCRIPTWITNESS */
381
+ );
382
+ }
383
+ get PSBT_IN_POR_COMMITMENT() {
384
+ return getOptionalMappedBytesAsHex(
385
+ this.inputMaps,
386
+ "09" /* PSBT_IN_POR_COMMITMENT */
387
+ );
388
+ }
389
+ get PSBT_IN_RIPEMD160() {
390
+ return getNonUniqueKeyTypeValues(this.inputMaps, "0a" /* PSBT_IN_RIPEMD160 */);
391
+ }
392
+ get PSBT_IN_SHA256() {
393
+ return getNonUniqueKeyTypeValues(this.inputMaps, "0b" /* PSBT_IN_SHA256 */);
394
+ }
395
+ get PSBT_IN_HASH160() {
396
+ return getNonUniqueKeyTypeValues(this.inputMaps, "0c" /* PSBT_IN_HASH160 */);
397
+ }
398
+ get PSBT_IN_HASH256() {
399
+ return getNonUniqueKeyTypeValues(this.inputMaps, "0d" /* PSBT_IN_HASH256 */);
400
+ }
401
+ get PSBT_IN_PREVIOUS_TXID() {
402
+ const indices = [];
403
+ for (const map of this.inputMaps) {
404
+ const value = map.get("0e" /* PSBT_IN_PREVIOUS_TXID */);
405
+ if (!value) {
406
+ throw Error("PSBT_IN_PREVIOUS_TXID not set for an input");
407
+ }
408
+ indices.push(value.toString("hex"));
409
+ }
410
+ return indices;
411
+ }
412
+ get PSBT_IN_OUTPUT_INDEX() {
413
+ const indices = [];
414
+ for (const map of this.inputMaps) {
415
+ const value = map.get("0f" /* PSBT_IN_OUTPUT_INDEX */);
416
+ if (!value) {
417
+ throw Error("PSBT_IN_OUTPUT_INDEX not set for an input");
418
+ }
419
+ indices.push(value.readUInt32LE(0));
420
+ }
421
+ return indices;
422
+ }
423
+ get PSBT_IN_SEQUENCE() {
424
+ return getOptionalMappedBytesAsUInt(
425
+ this.inputMaps,
426
+ "10" /* PSBT_IN_SEQUENCE */
427
+ );
428
+ }
429
+ get PSBT_IN_REQUIRED_TIME_LOCKTIME() {
430
+ return getOptionalMappedBytesAsUInt(
431
+ this.inputMaps,
432
+ "11" /* PSBT_IN_REQUIRED_TIME_LOCKTIME */
433
+ );
434
+ }
435
+ get PSBT_IN_REQUIRED_HEIGHT_LOCKTIME() {
436
+ return getOptionalMappedBytesAsUInt(
437
+ this.inputMaps,
438
+ "12" /* PSBT_IN_REQUIRED_HEIGHT_LOCKTIME */
439
+ );
440
+ }
441
+ get PSBT_IN_TAP_KEY_SIG() {
442
+ return getOptionalMappedBytesAsHex(
443
+ this.inputMaps,
444
+ "13" /* PSBT_IN_TAP_KEY_SIG */
445
+ );
446
+ }
447
+ get PSBT_IN_TAP_SCRIPT_SIG() {
448
+ return getNonUniqueKeyTypeValues(
449
+ this.inputMaps,
450
+ "14" /* PSBT_IN_TAP_SCRIPT_SIG */
451
+ );
452
+ }
453
+ get PSBT_IN_TAP_LEAF_SCRIPT() {
454
+ return getNonUniqueKeyTypeValues(
455
+ this.inputMaps,
456
+ "15" /* PSBT_IN_TAP_LEAF_SCRIPT */
457
+ );
458
+ }
459
+ get PSBT_IN_TAP_BIP32_DERIVATION() {
460
+ return getNonUniqueKeyTypeValues(
461
+ this.inputMaps,
462
+ "16" /* PSBT_IN_TAP_BIP32_DERIVATION */
463
+ );
464
+ }
465
+ get PSBT_IN_TAP_INTERNAL_KEY() {
466
+ return getOptionalMappedBytesAsHex(
467
+ this.inputMaps,
468
+ "17" /* PSBT_IN_TAP_INTERNAL_KEY */
469
+ );
470
+ }
471
+ get PSBT_IN_TAP_MERKLE_ROOT() {
472
+ return getOptionalMappedBytesAsHex(
473
+ this.inputMaps,
474
+ "18" /* PSBT_IN_TAP_MERKLE_ROOT */
475
+ );
476
+ }
477
+ get PSBT_IN_PROPRIETARY() {
478
+ return getNonUniqueKeyTypeValues(
479
+ this.inputMaps,
480
+ "fc" /* PSBT_IN_PROPRIETARY */
481
+ );
482
+ }
483
+ /**
484
+ * Output Getters/Setters
485
+ */
486
+ get PSBT_OUT_REDEEM_SCRIPT() {
487
+ return getOptionalMappedBytesAsHex(
488
+ this.outputMaps,
489
+ "00" /* PSBT_OUT_REDEEM_SCRIPT */
490
+ );
491
+ }
492
+ get PSBT_OUT_WITNESS_SCRIPT() {
493
+ return getOptionalMappedBytesAsHex(
494
+ this.outputMaps,
495
+ "01" /* PSBT_OUT_WITNESS_SCRIPT */
496
+ );
497
+ }
498
+ get PSBT_OUT_BIP32_DERIVATION() {
499
+ return getNonUniqueKeyTypeValues(
500
+ this.outputMaps,
501
+ "02" /* PSBT_OUT_BIP32_DERIVATION */
502
+ );
503
+ }
504
+ get PSBT_OUT_AMOUNT() {
505
+ const indices = [];
506
+ for (const map of this.outputMaps) {
507
+ const value = map.get("03" /* PSBT_OUT_AMOUNT */);
508
+ if (!value) {
509
+ throw Error("PSBT_OUT_AMOUNT not set for an output");
510
+ }
511
+ const br = new import_bufio.BufferReader(value);
512
+ indices.push(br.readBigI64(value));
513
+ }
514
+ return indices;
515
+ }
516
+ get PSBT_OUT_SCRIPT() {
517
+ const indices = [];
518
+ for (const map of this.outputMaps) {
519
+ const value = map.get("04" /* PSBT_OUT_SCRIPT */);
520
+ if (!value) {
521
+ throw Error("PSBT_OUT_SCRIPT not set for an output");
522
+ }
523
+ indices.push(value.toString("hex"));
524
+ }
525
+ return indices;
526
+ }
527
+ get PSBT_OUT_TAP_INTERNAL_KEY() {
528
+ return getOptionalMappedBytesAsHex(
529
+ this.outputMaps,
530
+ "05" /* PSBT_OUT_TAP_INTERNAL_KEY */
531
+ );
532
+ }
533
+ get PSBT_OUT_TAP_TREE() {
534
+ return getOptionalMappedBytesAsHex(
535
+ this.outputMaps,
536
+ "06" /* PSBT_OUT_TAP_TREE */
537
+ );
538
+ }
539
+ get PSBT_OUT_TAP_BIP32_DERIVATION() {
540
+ return getNonUniqueKeyTypeValues(
541
+ this.outputMaps,
542
+ "07" /* PSBT_OUT_TAP_BIP32_DERIVATION */
543
+ );
544
+ }
545
+ get PSBT_OUT_PROPRIETARY() {
546
+ return getNonUniqueKeyTypeValues(
547
+ this.outputMaps,
548
+ "fc" /* PSBT_OUT_PROPRIETARY */
549
+ );
550
+ }
551
+ /**
552
+ * Other Getters/Setters
553
+ */
554
+ get nLockTime() {
555
+ const inputCount = this.PSBT_GLOBAL_INPUT_COUNT;
556
+ const heightLocks = this.PSBT_IN_REQUIRED_HEIGHT_LOCKTIME;
557
+ const timeLocks = this.PSBT_IN_REQUIRED_TIME_LOCKTIME;
558
+ let heights = [];
559
+ let times = [];
560
+ for (let i = 0; i < this.PSBT_GLOBAL_INPUT_COUNT; i++) {
561
+ if (heightLocks[i] !== null) {
562
+ heights.push(heightLocks[i]);
563
+ }
564
+ if (timeLocks[i] !== null) {
565
+ times.push(timeLocks[i]);
566
+ }
567
+ }
568
+ if (heights.length === 0 && times.length === 0) {
569
+ return this.PSBT_GLOBAL_FALLBACK_LOCKTIME || 0;
570
+ }
571
+ if (heights.length === inputCount || heights.length > times.length) {
572
+ return Math.max(...heights);
573
+ }
574
+ if (times.length > heights.length) {
575
+ return Math.max(...times);
576
+ }
577
+ return null;
578
+ }
579
+ /**
580
+ * Creator/Constructor Methods
581
+ */
582
+ // This method ensures that global fields have initial values required by a
583
+ // PsbtV2 Creator. It is called by the constructor if constructed without a
584
+ // psbt.
585
+ create() {
586
+ this.PSBT_GLOBAL_VERSION = 2;
587
+ this.PSBT_GLOBAL_TX_VERSION = 2;
588
+ this.PSBT_GLOBAL_INPUT_COUNT = 0;
589
+ this.PSBT_GLOBAL_OUTPUT_COUNT = 0;
590
+ this.PSBT_GLOBAL_FALLBACK_LOCKTIME = 0;
591
+ }
592
+ // This method should check initial construction of any valid PsbtV2. It is
593
+ // called when a psbt is passed to the constructor or when a new psbt is being
594
+ // created. If constructed with a psbt, this method acts outside of the
595
+ // Creator role to validate the current state of the psbt.
596
+ validate() {
597
+ if (this.PSBT_GLOBAL_VERSION < 2) {
598
+ throw Error("PsbtV2 has a version field set less than 2");
599
+ }
600
+ if (this.PSBT_GLOBAL_TX_VERSION < 2) {
601
+ throw Error("PsbtV2 has a tx version field set less than 2");
602
+ }
603
+ for (const prevInTxid of this.PSBT_IN_PREVIOUS_TXID) {
604
+ if (!prevInTxid) {
605
+ throw Error("PsbtV2 input is missing PSBT_IN_PREVIOUS_TXID");
606
+ }
607
+ }
608
+ for (const prevInVOut of this.PSBT_IN_OUTPUT_INDEX) {
609
+ if (prevInVOut === void 0) {
610
+ throw Error("PsbtV2 input is missing PSBT_IN_OUTPUT_INDEX");
611
+ }
612
+ }
613
+ for (const amount of this.PSBT_OUT_AMOUNT) {
614
+ if (!amount) {
615
+ throw Error("PsbtV2 input is missing PSBT_OUT_AMOUNT");
616
+ }
617
+ }
618
+ for (const script of this.PSBT_OUT_SCRIPT) {
619
+ if (!script) {
620
+ throw Error("PsbtV2 input is missing PSBT_OUT_SCRIPT");
621
+ }
622
+ }
623
+ for (const locktime of this.PSBT_IN_REQUIRED_TIME_LOCKTIME) {
624
+ if (locktime && locktime < 5e8) {
625
+ throw Error("PsbtV2 input time locktime is less than 500000000.");
626
+ }
627
+ }
628
+ for (const locktime of this.PSBT_IN_REQUIRED_HEIGHT_LOCKTIME) {
629
+ if (locktime && locktime >= 5e8) {
630
+ throw Error("PsbtV2 input hight locktime is gte 500000000.");
631
+ }
632
+ }
633
+ }
634
+ // This method is provided for compatibility issues and probably shouldn't be
635
+ // used since a PsbtV2 with PSBT_GLOBAL_TX_VERSION = 1 is BIP0370
636
+ // non-compliant. No guarantees can be made here that a serialized PsbtV2
637
+ // which used this method will be compatible with outside consumers.
638
+ //
639
+ // One may wish to instance this class from a partially signed
640
+ // PSBTv0 with a txn version 1 by using the static PsbtV2.FromV0. This method
641
+ // provides a way to override validation logic for the txn version and roles
642
+ // lifecycle defined for PsbtV2.
643
+ dangerouslySetGlobalTxVersion1() {
644
+ console.warn("Dangerously setting PsbtV2.PSBT_GLOBAL_TX_VERSION to 1!");
645
+ const bw = new import_bufio.BufferWriter();
646
+ bw.writeI32(1);
647
+ this.globalMap.set("02" /* PSBT_GLOBAL_TX_VERSION */, bw.render());
648
+ }
649
+ // Is this a Creator/Constructor role action, or something else. BIPs don't
650
+ // define it well.
651
+ addGlobalXpub(xpub, fingerprint, path) {
652
+ const bw = new import_bufio.BufferWriter();
653
+ bw.writeBytes(import_buffer.Buffer.from("01" /* PSBT_GLOBAL_XPUB */, "hex"));
654
+ bw.writeBytes(xpub);
655
+ const key = bw.render().toString("hex");
656
+ bw.writeBytes(fingerprint);
657
+ const pathBytes = parseDerivationPathNodesToBytes(path);
658
+ bw.writeBytes(pathBytes);
659
+ const value = bw.render();
660
+ this.globalMap.set(key, value);
661
+ }
662
+ addInput({
663
+ previousTxId,
664
+ outputIndex,
665
+ sequence,
666
+ nonWitnessUtxo,
667
+ witnessUtxo,
668
+ redeemScript,
669
+ witnessScript,
670
+ bip32Derivation
671
+ }) {
672
+ if (!this.isModifiable(["INPUTS" /* INPUTS */])) {
673
+ throw Error(
674
+ "PsbtV2.PSBT_GLOBAL_TX_MODIFIABLE inputs cannot be modified."
675
+ );
676
+ }
677
+ const map = /* @__PURE__ */ new Map();
678
+ const bw = new import_bufio.BufferWriter();
679
+ const prevTxIdBuf = bufferize(previousTxId);
680
+ bw.writeBytes(prevTxIdBuf);
681
+ map.set("0e" /* PSBT_IN_PREVIOUS_TXID */, bw.render());
682
+ bw.writeI32(outputIndex);
683
+ map.set("0f" /* PSBT_IN_OUTPUT_INDEX */, bw.render());
684
+ if (sequence) {
685
+ bw.writeI32(sequence);
686
+ map.set("10" /* PSBT_IN_SEQUENCE */, bw.render());
687
+ }
688
+ if (nonWitnessUtxo) {
689
+ bw.writeBytes(nonWitnessUtxo);
690
+ map.set("00" /* PSBT_IN_NON_WITNESS_UTXO */, bw.render());
691
+ }
692
+ if (witnessUtxo) {
693
+ bw.writeI64(witnessUtxo.amount);
694
+ bw.writeU8(witnessUtxo.script.length);
695
+ bw.writeBytes(witnessUtxo.script);
696
+ map.set("01" /* PSBT_IN_WITNESS_UTXO */, bw.render());
697
+ }
698
+ if (redeemScript) {
699
+ bw.writeBytes(redeemScript);
700
+ map.set("04" /* PSBT_IN_REDEEM_SCRIPT */, bw.render());
701
+ }
702
+ if (witnessScript) {
703
+ bw.writeBytes(witnessScript);
704
+ map.set("05" /* PSBT_IN_WITNESS_SCRIPT */, bw.render());
705
+ }
706
+ if (bip32Derivation) {
707
+ for (const bip32 of bip32Derivation) {
708
+ bw.writeString("06" /* PSBT_IN_BIP32_DERIVATION */, "hex");
709
+ bw.writeBytes(bip32.pubkey);
710
+ const key = bw.render().toString("hex");
711
+ bw.writeBytes(bip32.masterFingerprint);
712
+ bw.writeBytes(parseDerivationPathNodesToBytes(bip32.path));
713
+ map.set(key, bw.render());
714
+ }
715
+ }
716
+ this.PSBT_GLOBAL_INPUT_COUNT = this.inputMaps.push(map);
717
+ }
718
+ addOutput({
719
+ amount,
720
+ script,
721
+ redeemScript,
722
+ witnessScript,
723
+ bip32Derivation
724
+ }) {
725
+ if (!this.isModifiable(["OUTPUTS" /* OUTPUTS */])) {
726
+ throw Error(
727
+ "PsbtV2.PSBT_GLOBAL_TX_MODIFIABLE outputs cannot be modified."
728
+ );
729
+ }
730
+ const map = /* @__PURE__ */ new Map();
731
+ const bw = new import_bufio.BufferWriter();
732
+ bw.writeI64(amount);
733
+ map.set("03" /* PSBT_OUT_AMOUNT */, bw.render());
734
+ bw.writeBytes(script);
735
+ map.set("04" /* PSBT_OUT_SCRIPT */, bw.render());
736
+ if (redeemScript) {
737
+ bw.writeBytes(redeemScript);
738
+ map.set("00" /* PSBT_OUT_REDEEM_SCRIPT */, bw.render());
739
+ }
740
+ if (witnessScript) {
741
+ bw.writeBytes(witnessScript);
742
+ map.set("01" /* PSBT_OUT_WITNESS_SCRIPT */, bw.render());
743
+ }
744
+ if (bip32Derivation) {
745
+ for (const bip32 of bip32Derivation) {
746
+ bw.writeString("02" /* PSBT_OUT_BIP32_DERIVATION */, "hex");
747
+ bw.writeBytes(bip32.pubkey);
748
+ const key = bw.render().toString("hex");
749
+ bw.writeBytes(bip32.masterFingerprint);
750
+ bw.writeBytes(parseDerivationPathNodesToBytes(bip32.path));
751
+ map.set(key, bw.render());
752
+ }
753
+ }
754
+ this.outputMaps.push(map);
755
+ this.PSBT_GLOBAL_OUTPUT_COUNT = this.outputMaps.length;
756
+ }
757
+ /**
758
+ * Updater/Signer Methods
759
+ */
760
+ // Removes an input-map from inputMaps
761
+ deleteInput(index) {
762
+ if (!this.isModifiable(["INPUTS" /* INPUTS */])) {
763
+ throw Error(
764
+ "PsbtV2.PSBT_GLOBAL_TX_MODIFIABLE inputs cannot be modified."
765
+ );
766
+ }
767
+ const newInputs = this.inputMaps.filter((_, i) => i !== index);
768
+ this.inputMaps = newInputs;
769
+ this.PSBT_GLOBAL_INPUT_COUNT = this.inputMaps.length;
770
+ }
771
+ // Removes an output-map from outputMaps
772
+ deleteOutput(index) {
773
+ if (!this.isModifiable(["OUTPUTS" /* OUTPUTS */])) {
774
+ throw Error(
775
+ "PsbtV2.PSBT_GLOBAL_TX_MODIFIABLE outputs cannot be modified."
776
+ );
777
+ }
778
+ const newOutputs = this.outputMaps.filter((_, i) => i !== index);
779
+ if (this.isModifiable(["SIGHASH_SINGLE" /* SIGHASH_SINGLE */])) {
780
+ this.removePartialSig(index);
781
+ }
782
+ this.outputMaps = newOutputs;
783
+ this.PSBT_GLOBAL_OUTPUT_COUNT = this.outputMaps.length;
784
+ }
785
+ // Checks that provided flags are present in PSBT_GLOBAL_TX_MODIFIABLE.
786
+ isModifiable(flags) {
787
+ for (const flag of flags) {
788
+ if (!this.PSBT_GLOBAL_TX_MODIFIABLE.includes(flag)) {
789
+ return false;
790
+ }
791
+ }
792
+ return true;
793
+ }
794
+ // The Signer, when it creates a signature, must add the partial sig keypair
795
+ // to the psbt for the input which it is signing. In the case that a
796
+ // particular signer does not, this method can be used to add a signature to
797
+ // the psbt. This method assumes the Signer did the validation outlined in
798
+ // BIP0174 before creating a signature.
799
+ // https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#signer
800
+ addPartialSig(inputIndex, pubkey, sig) {
801
+ if (!this.inputMaps[inputIndex]) {
802
+ throw Error(`PsbtV2 has no input at ${inputIndex}`);
803
+ }
804
+ if (!pubkey || !sig) {
805
+ throw Error(
806
+ `PsbtV2.addPartialSig() missing argument ${!pubkey && "pubkey" || !sig && "sig"}`
807
+ );
808
+ }
809
+ const key = `${"02" /* PSBT_IN_PARTIAL_SIG */}${pubkey.toString("hex")}`;
810
+ if (this.inputMaps[inputIndex].has(key)) {
811
+ throw Error(
812
+ "PsbtV2 already has a signature for this input with this pubkey"
813
+ );
814
+ }
815
+ const modBackup = this.PSBT_GLOBAL_TX_MODIFIABLE;
816
+ try {
817
+ this.inputMaps[inputIndex].set(key, sig);
818
+ this.handleSighashType(sig);
819
+ } catch (err) {
820
+ console.error(err);
821
+ this.inputMaps[inputIndex].delete(key);
822
+ this.PSBT_GLOBAL_TX_MODIFIABLE = modBackup;
823
+ }
824
+ }
825
+ // Removes all sigs for an input unless a pubkey is specified.
826
+ removePartialSig(inputIndex, pubkey) {
827
+ const input = this.inputMaps[inputIndex];
828
+ if (!input) {
829
+ throw Error(`PsbtV2 has no input at ${inputIndex}`);
830
+ }
831
+ if (pubkey) {
832
+ const key = `${"02" /* PSBT_IN_PARTIAL_SIG */}${pubkey.toString("hex")}`;
833
+ const sig = this.PSBT_IN_PARTIAL_SIG[inputIndex].find(
834
+ (el) => el.key === key
835
+ );
836
+ if (!sig) {
837
+ throw Error(
838
+ `PsbtV2 input has no signature from pubkey ${pubkey.toString("hex")}`
839
+ );
840
+ }
841
+ input.delete(key);
842
+ } else {
843
+ const sigs = this.PSBT_IN_PARTIAL_SIG[inputIndex];
844
+ for (const sig of sigs) {
845
+ input.delete(sig.key);
846
+ }
847
+ }
848
+ }
849
+ // Used to ensure the PSBT is in the proper state when adding a partial sig
850
+ // keypair.
851
+ // https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki#signer
852
+ handleSighashType(sig) {
853
+ const br = new import_bufio.BufferReader(sig.slice(-1));
854
+ let sighashVal = br.readU8();
855
+ let modifiable = this.PSBT_GLOBAL_TX_MODIFIABLE;
856
+ if (!(sighashVal & 128 /* SIGHASH_ANYONECANPAY */)) {
857
+ modifiable = modifiable.filter(
858
+ (val) => val !== "INPUTS" /* INPUTS */
859
+ );
860
+ } else {
861
+ sighashVal ^= 128 /* SIGHASH_ANYONECANPAY */;
862
+ }
863
+ if (sighashVal !== 2 /* SIGHASH_NONE */) {
864
+ modifiable = modifiable.filter(
865
+ (val) => val !== "OUTPUTS" /* OUTPUTS */
866
+ );
867
+ }
868
+ if (sighashVal === 3 /* SIGHASH_SINGLE */ && !modifiable.includes("SIGHASH_SINGLE" /* SIGHASH_SINGLE */)) {
869
+ modifiable.push("SIGHASH_SINGLE" /* SIGHASH_SINGLE */);
870
+ }
871
+ this.PSBT_GLOBAL_TX_MODIFIABLE = modifiable;
872
+ }
873
+ // Attempt to return a PsbtV2 by converting from a PsbtV0 string or Buffer
874
+ static FromV0(psbt, allowTxnVersion1 = false) {
875
+ const psbtv0Buf = bufferize(psbt);
876
+ const psbtv0 = import_bitcoinjs_lib2.Psbt.fromBuffer(psbtv0Buf);
877
+ const psbtv0GlobalMap = psbtv0.data.globalMap;
878
+ const psbtv2 = new _PsbtV2();
879
+ psbtv2.PSBT_GLOBAL_TX_MODIFIABLE = [
880
+ "INPUTS" /* INPUTS */,
881
+ "OUTPUTS" /* OUTPUTS */
882
+ ];
883
+ const txVersion = psbtv0.data.getTransaction().readInt32LE(0);
884
+ if (txVersion === 1 && allowTxnVersion1) {
885
+ psbtv2.dangerouslySetGlobalTxVersion1();
886
+ } else {
887
+ psbtv2.PSBT_GLOBAL_TX_VERSION = psbtv0.data.getTransaction().readInt32LE(0);
888
+ }
889
+ for (const globalXpub of psbtv0GlobalMap.globalXpub ?? []) {
890
+ psbtv2.addGlobalXpub(
891
+ globalXpub.extendedPubkey,
892
+ globalXpub.masterFingerprint,
893
+ globalXpub.path
894
+ );
895
+ }
896
+ let txInputs = [];
897
+ for (const [index, txInput] of psbtv0.txInputs.entries()) {
898
+ txInputs[index] = txInput;
899
+ }
900
+ for (const [index, input] of psbtv0.data.inputs.entries()) {
901
+ const txInput = txInputs[index];
902
+ psbtv2.addInput({
903
+ previousTxId: txInput.hash,
904
+ outputIndex: txInput.index,
905
+ sequence: txInput.sequence,
906
+ nonWitnessUtxo: input.nonWitnessUtxo,
907
+ witnessUtxo: input.witnessUtxo && {
908
+ amount: input.witnessUtxo.value,
909
+ script: input.witnessUtxo.script
910
+ },
911
+ redeemScript: input.redeemScript,
912
+ witnessScript: input.witnessScript,
913
+ bip32Derivation: input.bip32Derivation
914
+ });
915
+ }
916
+ let txOutputs = [];
917
+ for (const [index, txOutput] of psbtv0.txOutputs.entries()) {
918
+ txOutputs[index] = txOutput;
919
+ }
920
+ for (const [index, output] of psbtv0.data.outputs.entries()) {
921
+ const txOutput = txOutputs[index];
922
+ psbtv2.addOutput({
923
+ amount: txOutput.value,
924
+ script: txOutput.script,
925
+ redeemScript: output.redeemScript,
926
+ witnessScript: output.witnessScript,
927
+ bip32Derivation: output.bip32Derivation
928
+ });
929
+ }
930
+ for (const [index, input] of psbtv0.data.inputs.entries()) {
931
+ for (const sig of input.partialSig || []) {
932
+ psbtv2.addPartialSig(index, sig.pubkey, sig.signature);
933
+ }
934
+ }
935
+ return psbtv2;
936
+ }
937
+ };
938
+ function getPsbtVersionNumber(psbt) {
939
+ const map = /* @__PURE__ */ new Map();
940
+ const buf = bufferize(psbt);
941
+ const br = new import_bufio.BufferReader(buf.slice(PSBT_MAGIC_BYTES.length));
942
+ readAndSetKeyPairs(map, br);
943
+ return map.get("fb" /* PSBT_GLOBAL_VERSION */)?.readUInt32LE(0) || 0;
944
+ }
945
+ // Annotate the CommonJS export names for ESM import in node:
946
+ 0 && (module.exports = {
947
+ PsbtV2,
948
+ getPsbtVersionNumber
949
+ });