@caravan/psbt 1.0.0 → 1.1.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/.turbo/turbo-build.log +19 -20
- package/.turbo/turbo-lint.log +54 -49
- package/.turbo/turbo-test.log +99 -196
- package/CHANGELOG.md +12 -0
- package/README.md +71 -16
- package/dist/index.d.mts +172 -25
- package/dist/index.d.ts +172 -25
- package/dist/index.js +268 -75
- package/dist/index.mjs +274 -76
- package/package.json +1 -1
- package/src/psbtv2/functions.ts +169 -0
- package/src/psbtv2/index.ts +3 -0
- package/src/{psbtv2.test.ts → psbtv2/psbtv2.test.ts} +175 -26
- package/src/{psbtv2.ts → psbtv2/psbtv2.ts} +289 -401
- package/src/psbtv2/psbtv2maps.ts +111 -0
- package/src/psbtv2/types.ts +85 -0
- package/src/psbtv2/values.ts +4 -0
- package/.turbo/turbo-ci.log +0 -258
- package/.turbo/turbo-test$colon$watch.log +0 -223
package/dist/index.js
CHANGED
|
@@ -38,9 +38,8 @@ module.exports = __toCommonJS(src_exports);
|
|
|
38
38
|
// ../../node_modules/esbuild-plugin-polyfill-node/polyfills/buffer.js
|
|
39
39
|
var import_buffer = require("buffer");
|
|
40
40
|
|
|
41
|
-
// src/psbtv2.ts
|
|
41
|
+
// src/psbtv2/functions.ts
|
|
42
42
|
var import_bufio = require("bufio");
|
|
43
|
-
var import_bitcoinjs_lib2 = require("bitcoinjs-lib");
|
|
44
43
|
var import_bitcoin3 = require("@caravan/bitcoin");
|
|
45
44
|
|
|
46
45
|
// src/psbt.ts
|
|
@@ -51,10 +50,12 @@ var import_bitcoin2 = require("@caravan/bitcoin");
|
|
|
51
50
|
var import_bignumber = __toESM(require("bignumber.js"));
|
|
52
51
|
var PSBT_MAGIC_BYTES = import_buffer.Buffer.from([112, 115, 98, 116, 255]);
|
|
53
52
|
|
|
54
|
-
// src/psbtv2.ts
|
|
53
|
+
// src/psbtv2/values.ts
|
|
55
54
|
var PSBT_MAP_SEPARATOR = import_buffer.Buffer.from([0]);
|
|
56
55
|
var BIP_32_NODE_REGEX = /(\/[0-9]+'?)/gi;
|
|
57
56
|
var BIP_32_HARDENING_OFFSET = 2147483648;
|
|
57
|
+
|
|
58
|
+
// src/psbtv2/functions.ts
|
|
58
59
|
function bufferize(psbt) {
|
|
59
60
|
if (import_buffer.Buffer.isBuffer(psbt)) {
|
|
60
61
|
return psbt;
|
|
@@ -131,8 +132,23 @@ function serializeMap(map, bw) {
|
|
|
131
132
|
});
|
|
132
133
|
bw.writeBytes(PSBT_MAP_SEPARATOR);
|
|
133
134
|
}
|
|
135
|
+
function getPsbtVersionNumber(psbt) {
|
|
136
|
+
const map = /* @__PURE__ */ new Map();
|
|
137
|
+
const buf = bufferize(psbt);
|
|
138
|
+
const br = new import_bufio.BufferReader(buf.slice(import_bitcoin3.PSBT_MAGIC_BYTES.length));
|
|
139
|
+
readAndSetKeyPairs(map, br);
|
|
140
|
+
return map.get("fb" /* PSBT_GLOBAL_VERSION */)?.readUInt32LE(0) || 0;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// src/psbtv2/psbtv2.ts
|
|
144
|
+
var import_bufio3 = require("bufio");
|
|
145
|
+
var import_bitcoinjs_lib2 = require("bitcoinjs-lib");
|
|
146
|
+
|
|
147
|
+
// src/psbtv2/psbtv2maps.ts
|
|
148
|
+
var import_bufio2 = require("bufio");
|
|
134
149
|
var PsbtV2Maps = class {
|
|
135
|
-
// These maps directly correspond to the maps defined in BIP0174
|
|
150
|
+
// These maps directly correspond to the maps defined in BIP0174 and extended
|
|
151
|
+
// in BIP0370
|
|
136
152
|
globalMap = /* @__PURE__ */ new Map();
|
|
137
153
|
inputMaps = [];
|
|
138
154
|
outputMaps = [];
|
|
@@ -141,7 +157,7 @@ var PsbtV2Maps = class {
|
|
|
141
157
|
return;
|
|
142
158
|
}
|
|
143
159
|
const buf = bufferize(psbt);
|
|
144
|
-
const br = new
|
|
160
|
+
const br = new import_bufio2.BufferReader(buf);
|
|
145
161
|
if (!br.readBytes(PSBT_MAGIC_BYTES.length, true).equals(PSBT_MAGIC_BYTES)) {
|
|
146
162
|
throw Error("PsbtV2 magic bytes are incorrect.");
|
|
147
163
|
}
|
|
@@ -165,9 +181,11 @@ var PsbtV2Maps = class {
|
|
|
165
181
|
this.outputMaps.push(map);
|
|
166
182
|
}
|
|
167
183
|
}
|
|
168
|
-
|
|
184
|
+
/**
|
|
185
|
+
* Return the current state of the psbt as a string in the specified format.
|
|
186
|
+
*/
|
|
169
187
|
serialize(format = "base64") {
|
|
170
|
-
|
|
188
|
+
const bw = new import_bufio2.BufferWriter();
|
|
171
189
|
bw.writeBytes(PSBT_MAGIC_BYTES);
|
|
172
190
|
serializeMap(this.globalMap, bw);
|
|
173
191
|
for (const map of this.inputMaps) {
|
|
@@ -178,12 +196,15 @@ var PsbtV2Maps = class {
|
|
|
178
196
|
}
|
|
179
197
|
return bw.render().toString(format);
|
|
180
198
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
199
|
+
/**
|
|
200
|
+
* Copies the maps in this PsbtV2 object to another PsbtV2 object.
|
|
201
|
+
*
|
|
202
|
+
* NOTE: This copy method is made available to achieve parity with the PSBT
|
|
203
|
+
* api required by `ledger-bitcoin` for creating merklized PSBTs. HOWEVER, it
|
|
204
|
+
* is not recommended to use this when avoidable as copying maps bypasses the
|
|
205
|
+
* validation defined in the constructor, so it could create a psbtv2 in an
|
|
206
|
+
* invalid psbt state. PsbtV2.serialize is preferable whenever possible.
|
|
207
|
+
*/
|
|
187
208
|
copy(to) {
|
|
188
209
|
this.copyMap(this.globalMap, to.globalMap);
|
|
189
210
|
this.copyMaps(this.inputMaps, to.inputMaps);
|
|
@@ -196,11 +217,12 @@ var PsbtV2Maps = class {
|
|
|
196
217
|
to[index] = to_index;
|
|
197
218
|
});
|
|
198
219
|
}
|
|
199
|
-
// eslint-disable-next-line class-methods-use-this
|
|
200
220
|
copyMap(from, to) {
|
|
201
221
|
from.forEach((v, k) => to.set(k, import_buffer.Buffer.from(v)));
|
|
202
222
|
}
|
|
203
223
|
};
|
|
224
|
+
|
|
225
|
+
// src/psbtv2/psbtv2.ts
|
|
204
226
|
var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
|
|
205
227
|
constructor(psbt) {
|
|
206
228
|
super(psbt);
|
|
@@ -213,7 +235,10 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
|
|
|
213
235
|
* Globals Getters/Setters
|
|
214
236
|
*/
|
|
215
237
|
get PSBT_GLOBAL_XPUB() {
|
|
216
|
-
return getNonUniqueKeyTypeValues(
|
|
238
|
+
return getNonUniqueKeyTypeValues(
|
|
239
|
+
this.globalMap,
|
|
240
|
+
"01" /* PSBT_GLOBAL_XPUB */
|
|
241
|
+
);
|
|
217
242
|
}
|
|
218
243
|
get PSBT_GLOBAL_TX_VERSION() {
|
|
219
244
|
const val = this.globalMap.get("02" /* PSBT_GLOBAL_TX_VERSION */);
|
|
@@ -228,7 +253,7 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
|
|
|
228
253
|
`PsbtV2 cannot have a global tx version less than 2. Version ${version} specified.`
|
|
229
254
|
);
|
|
230
255
|
}
|
|
231
|
-
const bw = new
|
|
256
|
+
const bw = new import_bufio3.BufferWriter();
|
|
232
257
|
bw.writeI32(version);
|
|
233
258
|
this.globalMap.set("02" /* PSBT_GLOBAL_TX_VERSION */, bw.render());
|
|
234
259
|
}
|
|
@@ -239,7 +264,7 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
|
|
|
239
264
|
if (locktime === null) {
|
|
240
265
|
this.globalMap.delete("03" /* PSBT_GLOBAL_FALLBACK_LOCKTIME */);
|
|
241
266
|
} else {
|
|
242
|
-
const bw = new
|
|
267
|
+
const bw = new import_bufio3.BufferWriter();
|
|
243
268
|
bw.writeI32(locktime);
|
|
244
269
|
this.globalMap.set("03" /* PSBT_GLOBAL_FALLBACK_LOCKTIME */, bw.render());
|
|
245
270
|
}
|
|
@@ -252,7 +277,7 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
|
|
|
252
277
|
return val.readUInt8(0);
|
|
253
278
|
}
|
|
254
279
|
set PSBT_GLOBAL_INPUT_COUNT(count) {
|
|
255
|
-
const bw = new
|
|
280
|
+
const bw = new import_bufio3.BufferWriter();
|
|
256
281
|
bw.writeU8(count);
|
|
257
282
|
this.globalMap.set("04" /* PSBT_GLOBAL_INPUT_COUNT */, bw.render());
|
|
258
283
|
}
|
|
@@ -264,7 +289,7 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
|
|
|
264
289
|
return val.readUInt8(0);
|
|
265
290
|
}
|
|
266
291
|
set PSBT_GLOBAL_OUTPUT_COUNT(count) {
|
|
267
|
-
const bw = new
|
|
292
|
+
const bw = new import_bufio3.BufferWriter();
|
|
268
293
|
bw.writeU8(count);
|
|
269
294
|
this.globalMap.set("05" /* PSBT_GLOBAL_OUTPUT_COUNT */, bw.render());
|
|
270
295
|
}
|
|
@@ -293,7 +318,7 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
|
|
|
293
318
|
if (modifiable.includes("SIGHASH_SINGLE" /* SIGHASH_SINGLE */)) {
|
|
294
319
|
val |= 4;
|
|
295
320
|
}
|
|
296
|
-
const br = new
|
|
321
|
+
const br = new import_bufio3.BufferWriter();
|
|
297
322
|
br.writeU8(val);
|
|
298
323
|
this.globalMap.set("06" /* PSBT_GLOBAL_TX_MODIFIABLE */, br.render());
|
|
299
324
|
}
|
|
@@ -313,7 +338,7 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
|
|
|
313
338
|
);
|
|
314
339
|
workingVersion = 2;
|
|
315
340
|
}
|
|
316
|
-
const bw = new
|
|
341
|
+
const bw = new import_bufio3.BufferWriter();
|
|
317
342
|
bw.writeU32(workingVersion);
|
|
318
343
|
this.globalMap.set("fb" /* PSBT_GLOBAL_VERSION */, bw.render());
|
|
319
344
|
}
|
|
@@ -387,16 +412,28 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
|
|
|
387
412
|
);
|
|
388
413
|
}
|
|
389
414
|
get PSBT_IN_RIPEMD160() {
|
|
390
|
-
return getNonUniqueKeyTypeValues(
|
|
415
|
+
return getNonUniqueKeyTypeValues(
|
|
416
|
+
this.inputMaps,
|
|
417
|
+
"0a" /* PSBT_IN_RIPEMD160 */
|
|
418
|
+
);
|
|
391
419
|
}
|
|
392
420
|
get PSBT_IN_SHA256() {
|
|
393
|
-
return getNonUniqueKeyTypeValues(
|
|
421
|
+
return getNonUniqueKeyTypeValues(
|
|
422
|
+
this.inputMaps,
|
|
423
|
+
"0b" /* PSBT_IN_SHA256 */
|
|
424
|
+
);
|
|
394
425
|
}
|
|
395
426
|
get PSBT_IN_HASH160() {
|
|
396
|
-
return getNonUniqueKeyTypeValues(
|
|
427
|
+
return getNonUniqueKeyTypeValues(
|
|
428
|
+
this.inputMaps,
|
|
429
|
+
"0c" /* PSBT_IN_HASH160 */
|
|
430
|
+
);
|
|
397
431
|
}
|
|
398
432
|
get PSBT_IN_HASH256() {
|
|
399
|
-
return getNonUniqueKeyTypeValues(
|
|
433
|
+
return getNonUniqueKeyTypeValues(
|
|
434
|
+
this.inputMaps,
|
|
435
|
+
"0d" /* PSBT_IN_HASH256 */
|
|
436
|
+
);
|
|
400
437
|
}
|
|
401
438
|
get PSBT_IN_PREVIOUS_TXID() {
|
|
402
439
|
const indices = [];
|
|
@@ -508,7 +545,7 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
|
|
|
508
545
|
if (!value) {
|
|
509
546
|
throw Error("PSBT_OUT_AMOUNT not set for an output");
|
|
510
547
|
}
|
|
511
|
-
const br = new
|
|
548
|
+
const br = new import_bufio3.BufferReader(value);
|
|
512
549
|
indices.push(br.readBigI64(value));
|
|
513
550
|
}
|
|
514
551
|
return indices;
|
|
@@ -548,9 +585,113 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
|
|
|
548
585
|
"fc" /* PSBT_OUT_PROPRIETARY */
|
|
549
586
|
);
|
|
550
587
|
}
|
|
588
|
+
/**
|
|
589
|
+
* Operator Role Validation Getters
|
|
590
|
+
*/
|
|
591
|
+
/**
|
|
592
|
+
* Returns true if the PsbtV2 is ready for an operator taking the Constructor
|
|
593
|
+
* role.
|
|
594
|
+
*
|
|
595
|
+
* This check assumes that the Creator used this class's constructor method to
|
|
596
|
+
* initialize the PsbtV2 without passing a psbt (constructor defaults were
|
|
597
|
+
* set).
|
|
598
|
+
*/
|
|
599
|
+
get isReadyForConstructor() {
|
|
600
|
+
if (this.PSBT_GLOBAL_FALLBACK_LOCKTIME === null) {
|
|
601
|
+
return false;
|
|
602
|
+
}
|
|
603
|
+
if (!this.isModifiable(["INPUTS" /* INPUTS */]) && !this.isModifiable(["OUTPUTS" /* OUTPUTS */])) {
|
|
604
|
+
return false;
|
|
605
|
+
}
|
|
606
|
+
return true;
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* Returns true if the PsbtV2 is ready for an operator taking the Updater
|
|
610
|
+
* role.
|
|
611
|
+
*
|
|
612
|
+
* Before signatures are added, but after an input is added, a PsbtV2 is
|
|
613
|
+
* likely to be ready for Constructor, ready for Updater, and ready for Signer
|
|
614
|
+
* simultaneously.
|
|
615
|
+
*
|
|
616
|
+
* According to BIP370, the Updater can modify the sequence number, but it is
|
|
617
|
+
* unclear if the Updater retains permissions provided in psbtv0 (BIP174). It
|
|
618
|
+
* is likely not the case that the Updater has the same permissions as
|
|
619
|
+
* previously because it seems to now be the realm of the Constructor to add
|
|
620
|
+
* inputs and outputs.
|
|
621
|
+
*/
|
|
622
|
+
get isReadyForUpdater() {
|
|
623
|
+
if (this.PSBT_GLOBAL_INPUT_COUNT === 0) {
|
|
624
|
+
return false;
|
|
625
|
+
}
|
|
626
|
+
if (!this.isModifiable(["INPUTS" /* INPUTS */])) {
|
|
627
|
+
return false;
|
|
628
|
+
}
|
|
629
|
+
return true;
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* Returns true if the PsbtV2 is ready for an operator taking the Signer role.
|
|
633
|
+
*/
|
|
634
|
+
get isReadyForSigner() {
|
|
635
|
+
if (this.PSBT_GLOBAL_INPUT_COUNT === 0) {
|
|
636
|
+
return false;
|
|
637
|
+
}
|
|
638
|
+
if (this.isReadyForTransactionExtractor) {
|
|
639
|
+
return false;
|
|
640
|
+
}
|
|
641
|
+
return true;
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Returns true if the PsbtV2 is ready for an operator taking the Combiner
|
|
645
|
+
* role.
|
|
646
|
+
*/
|
|
647
|
+
get isReadyForCombiner() {
|
|
648
|
+
return this.isReadyForConstructor || this.isReadyForUpdater || this.isReadyForSigner;
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* Unimplemented. Returns false.
|
|
652
|
+
*/
|
|
653
|
+
get isReadyForInputFinalizer() {
|
|
654
|
+
console.warn(
|
|
655
|
+
"PsbtV2.isReadyForInputFinalizer has been called, however, this getter is unimplemented and shouldn't be used."
|
|
656
|
+
);
|
|
657
|
+
return false;
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* Returns true if the PsbtV2 is ready for an operator taking the Transaction
|
|
661
|
+
* Extractor role.
|
|
662
|
+
*
|
|
663
|
+
* If all the inputs have been finalized, then the psbt is ready for the
|
|
664
|
+
* Transaction Extractor. According to BIP 174, it's the responsibility of the
|
|
665
|
+
* Input Finalizer to add scriptSigs or scriptWitnesses and then remove other
|
|
666
|
+
* details besides the UTXO. This getter checks that the Input Finalizer has
|
|
667
|
+
* finished its job.
|
|
668
|
+
*/
|
|
669
|
+
get isReadyForTransactionExtractor() {
|
|
670
|
+
for (let i = 0; i < this.PSBT_GLOBAL_INPUT_COUNT; i++) {
|
|
671
|
+
if (!this.PSBT_IN_FINAL_SCRIPTSIG[i] && !this.PSBT_IN_FINAL_SCRIPTWITNESS[i]) {
|
|
672
|
+
return false;
|
|
673
|
+
}
|
|
674
|
+
if (this.PSBT_IN_FINAL_SCRIPTSIG[i] && !this.PSBT_IN_NON_WITNESS_UTXO[i] || this.PSBT_IN_FINAL_SCRIPTWITNESS[i] && !this.PSBT_IN_WITNESS_UTXO[i]) {
|
|
675
|
+
return false;
|
|
676
|
+
}
|
|
677
|
+
if (
|
|
678
|
+
// Strings
|
|
679
|
+
this.PSBT_IN_REDEEM_SCRIPT[i] || this.PSBT_IN_WITNESS_SCRIPT[i] || this.PSBT_IN_POR_COMMITMENT[i] || this.PSBT_IN_TAP_KEY_SIG[i] || this.PSBT_IN_TAP_INTERNAL_KEY[i] || this.PSBT_IN_TAP_MERKLE_ROOT[i] || // Numbers
|
|
680
|
+
this.PSBT_IN_SIGHASH_TYPE[i] !== null || this.PSBT_IN_SEQUENCE[i] !== null || this.PSBT_IN_REQUIRED_TIME_LOCKTIME[i] !== null || this.PSBT_IN_REQUIRED_HEIGHT_LOCKTIME[i] !== null || // Arrays of non-unique keytype values
|
|
681
|
+
this.PSBT_IN_PARTIAL_SIG[i].filter((el) => el !== null).length > 0 || this.PSBT_IN_BIP32_DERIVATION[i].filter((el) => el !== null).length > 0 || this.PSBT_IN_RIPEMD160[i].filter((el) => el !== null).length > 0 || this.PSBT_IN_SHA256[i].filter((el) => el !== null).length > 0 || this.PSBT_IN_HASH160[i].filter((el) => el !== null).length > 0 || this.PSBT_IN_HASH256[i].filter((el) => el !== null).length > 0 || this.PSBT_IN_TAP_SCRIPT_SIG[i].filter((el) => el !== null).length > 0 || this.PSBT_IN_TAP_LEAF_SCRIPT[i].filter((el) => el !== null).length > 0 || this.PSBT_IN_TAP_BIP32_DERIVATION[i].filter((el) => el !== null).length > 0
|
|
682
|
+
) {
|
|
683
|
+
return false;
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
return true;
|
|
687
|
+
}
|
|
551
688
|
/**
|
|
552
689
|
* Other Getters/Setters
|
|
553
690
|
*/
|
|
691
|
+
/**
|
|
692
|
+
* Returns the `nLockTime` field for the psbt as if it were a bitcoin
|
|
693
|
+
* transaction.
|
|
694
|
+
*/
|
|
554
695
|
get nLockTime() {
|
|
555
696
|
const inputCount = this.PSBT_GLOBAL_INPUT_COUNT;
|
|
556
697
|
const heightLocks = this.PSBT_IN_REQUIRED_HEIGHT_LOCKTIME;
|
|
@@ -579,20 +720,27 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
|
|
|
579
720
|
/**
|
|
580
721
|
* Creator/Constructor Methods
|
|
581
722
|
*/
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
723
|
+
/**
|
|
724
|
+
* Ensures that global fields have initial values required by a PsbtV2
|
|
725
|
+
* Creator. It is called by the constructor if constructed without a psbt.
|
|
726
|
+
*/
|
|
585
727
|
create() {
|
|
586
728
|
this.PSBT_GLOBAL_VERSION = 2;
|
|
587
729
|
this.PSBT_GLOBAL_TX_VERSION = 2;
|
|
588
730
|
this.PSBT_GLOBAL_INPUT_COUNT = 0;
|
|
589
731
|
this.PSBT_GLOBAL_OUTPUT_COUNT = 0;
|
|
590
732
|
this.PSBT_GLOBAL_FALLBACK_LOCKTIME = 0;
|
|
733
|
+
this.PSBT_GLOBAL_TX_MODIFIABLE = [
|
|
734
|
+
"INPUTS" /* INPUTS */,
|
|
735
|
+
"OUTPUTS" /* OUTPUTS */
|
|
736
|
+
];
|
|
591
737
|
}
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
738
|
+
/**
|
|
739
|
+
* Checks initial construction of any valid PsbtV2. It is called when a psbt
|
|
740
|
+
* is passed to the constructor or when a new psbt is being created. If
|
|
741
|
+
* constructed with a psbt, this method acts outside of the Creator role to
|
|
742
|
+
* validate the current state of the psbt.
|
|
743
|
+
*/
|
|
596
744
|
validate() {
|
|
597
745
|
if (this.PSBT_GLOBAL_VERSION < 2) {
|
|
598
746
|
throw Error("PsbtV2 has a version field set less than 2");
|
|
@@ -631,25 +779,32 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
|
|
|
631
779
|
}
|
|
632
780
|
}
|
|
633
781
|
}
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
782
|
+
/**
|
|
783
|
+
* This method is provided for compatibility issues and probably shouldn't be
|
|
784
|
+
* used since a PsbtV2 with PSBT_GLOBAL_TX_VERSION = 1 is BIP0370
|
|
785
|
+
* non-compliant. No guarantees can be made here that a serialized PsbtV2
|
|
786
|
+
* which used this method will be compatible with outside consumers.
|
|
787
|
+
*
|
|
788
|
+
* One may wish to instance this class from a partially signed PSBTv0 with a
|
|
789
|
+
* txn version 1 by using the static PsbtV2.FromV0. This method provides a way
|
|
790
|
+
* to override validation logic for the txn version and roles lifecycle
|
|
791
|
+
* defined for PsbtV2.
|
|
792
|
+
*/
|
|
643
793
|
dangerouslySetGlobalTxVersion1() {
|
|
794
|
+
if (!this.isReadyForConstructor) {
|
|
795
|
+
throw Error(
|
|
796
|
+
"The PsbtV2 is not ready for a Constructor. The PSBT_GLOBAL_TX_VERSION should not be forced to version 1."
|
|
797
|
+
);
|
|
798
|
+
}
|
|
644
799
|
console.warn("Dangerously setting PsbtV2.PSBT_GLOBAL_TX_VERSION to 1!");
|
|
645
|
-
const bw = new
|
|
800
|
+
const bw = new import_bufio3.BufferWriter();
|
|
646
801
|
bw.writeI32(1);
|
|
647
802
|
this.globalMap.set("02" /* PSBT_GLOBAL_TX_VERSION */, bw.render());
|
|
648
803
|
}
|
|
649
|
-
// Is this a Creator/Constructor role action, or something else
|
|
804
|
+
// Is this a Creator/Constructor role action, or something else? BIPs don't
|
|
650
805
|
// define it well.
|
|
651
806
|
addGlobalXpub(xpub, fingerprint, path) {
|
|
652
|
-
const bw = new
|
|
807
|
+
const bw = new import_bufio3.BufferWriter();
|
|
653
808
|
bw.writeBytes(import_buffer.Buffer.from("01" /* PSBT_GLOBAL_XPUB */, "hex"));
|
|
654
809
|
bw.writeBytes(xpub);
|
|
655
810
|
const key = bw.render().toString("hex");
|
|
@@ -669,13 +824,18 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
|
|
|
669
824
|
witnessScript,
|
|
670
825
|
bip32Derivation
|
|
671
826
|
}) {
|
|
827
|
+
if (!this.isReadyForConstructor) {
|
|
828
|
+
throw Error(
|
|
829
|
+
"The PsbtV2 is not ready for a Constructor. Inputs cannot be added."
|
|
830
|
+
);
|
|
831
|
+
}
|
|
672
832
|
if (!this.isModifiable(["INPUTS" /* INPUTS */])) {
|
|
673
833
|
throw Error(
|
|
674
834
|
"PsbtV2.PSBT_GLOBAL_TX_MODIFIABLE inputs cannot be modified."
|
|
675
835
|
);
|
|
676
836
|
}
|
|
677
837
|
const map = /* @__PURE__ */ new Map();
|
|
678
|
-
const bw = new
|
|
838
|
+
const bw = new import_bufio3.BufferWriter();
|
|
679
839
|
const prevTxIdBuf = bufferize(previousTxId);
|
|
680
840
|
bw.writeBytes(prevTxIdBuf);
|
|
681
841
|
map.set("0e" /* PSBT_IN_PREVIOUS_TXID */, bw.render());
|
|
@@ -722,13 +882,18 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
|
|
|
722
882
|
witnessScript,
|
|
723
883
|
bip32Derivation
|
|
724
884
|
}) {
|
|
885
|
+
if (!this.isReadyForConstructor) {
|
|
886
|
+
throw Error(
|
|
887
|
+
"The PsbtV2 is not ready for a Constructor. Outputs cannot be added."
|
|
888
|
+
);
|
|
889
|
+
}
|
|
725
890
|
if (!this.isModifiable(["OUTPUTS" /* OUTPUTS */])) {
|
|
726
891
|
throw Error(
|
|
727
892
|
"PsbtV2.PSBT_GLOBAL_TX_MODIFIABLE outputs cannot be modified."
|
|
728
893
|
);
|
|
729
894
|
}
|
|
730
895
|
const map = /* @__PURE__ */ new Map();
|
|
731
|
-
const bw = new
|
|
896
|
+
const bw = new import_bufio3.BufferWriter();
|
|
732
897
|
bw.writeI64(amount);
|
|
733
898
|
map.set("03" /* PSBT_OUT_AMOUNT */, bw.render());
|
|
734
899
|
bw.writeBytes(script);
|
|
@@ -757,8 +922,15 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
|
|
|
757
922
|
/**
|
|
758
923
|
* Updater/Signer Methods
|
|
759
924
|
*/
|
|
760
|
-
|
|
925
|
+
/**
|
|
926
|
+
* Removes an input-map from inputMaps.
|
|
927
|
+
*/
|
|
761
928
|
deleteInput(index) {
|
|
929
|
+
if (!this.isReadyForConstructor) {
|
|
930
|
+
throw Error(
|
|
931
|
+
"The PsbtV2 is not ready for a Constructor. Inputs cannot be removed."
|
|
932
|
+
);
|
|
933
|
+
}
|
|
762
934
|
if (!this.isModifiable(["INPUTS" /* INPUTS */])) {
|
|
763
935
|
throw Error(
|
|
764
936
|
"PsbtV2.PSBT_GLOBAL_TX_MODIFIABLE inputs cannot be modified."
|
|
@@ -768,8 +940,15 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
|
|
|
768
940
|
this.inputMaps = newInputs;
|
|
769
941
|
this.PSBT_GLOBAL_INPUT_COUNT = this.inputMaps.length;
|
|
770
942
|
}
|
|
771
|
-
|
|
943
|
+
/**
|
|
944
|
+
* Removes an output-map from outputMaps.
|
|
945
|
+
*/
|
|
772
946
|
deleteOutput(index) {
|
|
947
|
+
if (!this.isReadyForConstructor) {
|
|
948
|
+
throw Error(
|
|
949
|
+
"The PsbtV2 is not ready for a Constructor. Outputs cannot be removed."
|
|
950
|
+
);
|
|
951
|
+
}
|
|
773
952
|
if (!this.isModifiable(["OUTPUTS" /* OUTPUTS */])) {
|
|
774
953
|
throw Error(
|
|
775
954
|
"PsbtV2.PSBT_GLOBAL_TX_MODIFIABLE outputs cannot be modified."
|
|
@@ -782,7 +961,9 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
|
|
|
782
961
|
this.outputMaps = newOutputs;
|
|
783
962
|
this.PSBT_GLOBAL_OUTPUT_COUNT = this.outputMaps.length;
|
|
784
963
|
}
|
|
785
|
-
|
|
964
|
+
/**
|
|
965
|
+
* Checks that all provided flags are present in PSBT_GLOBAL_TX_MODIFIABLE.
|
|
966
|
+
*/
|
|
786
967
|
isModifiable(flags) {
|
|
787
968
|
for (const flag of flags) {
|
|
788
969
|
if (!this.PSBT_GLOBAL_TX_MODIFIABLE.includes(flag)) {
|
|
@@ -791,13 +972,25 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
|
|
|
791
972
|
}
|
|
792
973
|
return true;
|
|
793
974
|
}
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
975
|
+
/**
|
|
976
|
+
* Adds a signature for an input. Validates that the input is mapped and does
|
|
977
|
+
* not already have a signature for the pubkey. Also validates for sighash.
|
|
978
|
+
* Other validation is incomplete. Also validates for required args in case
|
|
979
|
+
* typescript is not being used to call the method.
|
|
980
|
+
*
|
|
981
|
+
* The Signer, when it creates a signature, must add the partial sig keypair
|
|
982
|
+
* to the psbt for the input which it is signing. In the case that a
|
|
983
|
+
* particular signer does not, this method can be used to add a signature to
|
|
984
|
+
* the psbt. This method assumes the Signer did the validation outlined in
|
|
985
|
+
* BIP0174 before creating a signature.
|
|
986
|
+
* https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#signer
|
|
987
|
+
*/
|
|
800
988
|
addPartialSig(inputIndex, pubkey, sig) {
|
|
989
|
+
if (!this.isReadyForSigner) {
|
|
990
|
+
throw Error(
|
|
991
|
+
"The PsbtV2 is not ready for a Signer. Partial sigs cannot be added."
|
|
992
|
+
);
|
|
993
|
+
}
|
|
801
994
|
if (!this.inputMaps[inputIndex]) {
|
|
802
995
|
throw Error(`PsbtV2 has no input at ${inputIndex}`);
|
|
803
996
|
}
|
|
@@ -822,7 +1015,11 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
|
|
|
822
1015
|
this.PSBT_GLOBAL_TX_MODIFIABLE = modBackup;
|
|
823
1016
|
}
|
|
824
1017
|
}
|
|
825
|
-
|
|
1018
|
+
/**
|
|
1019
|
+
* Removes all sigs for an input unless a pubkey is specified. Validates that
|
|
1020
|
+
* the input exists. When providing a pubkey, this validates that a sig for
|
|
1021
|
+
* the pubkey exists.
|
|
1022
|
+
*/
|
|
826
1023
|
removePartialSig(inputIndex, pubkey) {
|
|
827
1024
|
const input = this.inputMaps[inputIndex];
|
|
828
1025
|
if (!input) {
|
|
@@ -846,11 +1043,12 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
|
|
|
846
1043
|
}
|
|
847
1044
|
}
|
|
848
1045
|
}
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
1046
|
+
/**
|
|
1047
|
+
* Ensures the PSBT is in the proper state when adding a partial sig keypair.
|
|
1048
|
+
* https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki#signer
|
|
1049
|
+
*/
|
|
852
1050
|
handleSighashType(sig) {
|
|
853
|
-
const br = new
|
|
1051
|
+
const br = new import_bufio3.BufferReader(sig.slice(-1));
|
|
854
1052
|
let sighashVal = br.readU8();
|
|
855
1053
|
let modifiable = this.PSBT_GLOBAL_TX_MODIFIABLE;
|
|
856
1054
|
if (!(sighashVal & 128 /* SIGHASH_ANYONECANPAY */)) {
|
|
@@ -870,16 +1068,18 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
|
|
|
870
1068
|
}
|
|
871
1069
|
this.PSBT_GLOBAL_TX_MODIFIABLE = modifiable;
|
|
872
1070
|
}
|
|
873
|
-
|
|
1071
|
+
/**
|
|
1072
|
+
* Attempts to return a PsbtV2 by converting from a PsbtV0 string or Buffer.
|
|
1073
|
+
*
|
|
1074
|
+
* This method first starts with a fresh PsbtV2 having just been created. It
|
|
1075
|
+
* then takes the PsbtV2 through its operator saga through the Signer role. In
|
|
1076
|
+
* this sense validation for each operator role will be performed.
|
|
1077
|
+
*/
|
|
874
1078
|
static FromV0(psbt, allowTxnVersion1 = false) {
|
|
875
1079
|
const psbtv0Buf = bufferize(psbt);
|
|
876
1080
|
const psbtv0 = import_bitcoinjs_lib2.Psbt.fromBuffer(psbtv0Buf);
|
|
877
1081
|
const psbtv0GlobalMap = psbtv0.data.globalMap;
|
|
878
1082
|
const psbtv2 = new _PsbtV2();
|
|
879
|
-
psbtv2.PSBT_GLOBAL_TX_MODIFIABLE = [
|
|
880
|
-
"INPUTS" /* INPUTS */,
|
|
881
|
-
"OUTPUTS" /* OUTPUTS */
|
|
882
|
-
];
|
|
883
1083
|
const txVersion = psbtv0.data.getTransaction().readInt32LE(0);
|
|
884
1084
|
if (txVersion === 1 && allowTxnVersion1) {
|
|
885
1085
|
psbtv2.dangerouslySetGlobalTxVersion1();
|
|
@@ -893,7 +1093,7 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
|
|
|
893
1093
|
globalXpub.path
|
|
894
1094
|
);
|
|
895
1095
|
}
|
|
896
|
-
|
|
1096
|
+
const txInputs = [];
|
|
897
1097
|
for (const [index, txInput] of psbtv0.txInputs.entries()) {
|
|
898
1098
|
txInputs[index] = txInput;
|
|
899
1099
|
}
|
|
@@ -913,7 +1113,7 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
|
|
|
913
1113
|
bip32Derivation: input.bip32Derivation
|
|
914
1114
|
});
|
|
915
1115
|
}
|
|
916
|
-
|
|
1116
|
+
const txOutputs = [];
|
|
917
1117
|
for (const [index, txOutput] of psbtv0.txOutputs.entries()) {
|
|
918
1118
|
txOutputs[index] = txOutput;
|
|
919
1119
|
}
|
|
@@ -935,13 +1135,6 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
|
|
|
935
1135
|
return psbtv2;
|
|
936
1136
|
}
|
|
937
1137
|
};
|
|
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
1138
|
// Annotate the CommonJS export names for ESM import in node:
|
|
946
1139
|
0 && (module.exports = {
|
|
947
1140
|
PsbtV2,
|