@caravan/psbt 1.6.0 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -28,6 +28,12 @@ declare enum PsbtGlobalTxModifiableBits {
28
28
  OUTPUTS = "OUTPUTS",// 0b00000010
29
29
  SIGHASH_SINGLE = "SIGHASH_SINGLE"
30
30
  }
31
+ declare enum SighashType {
32
+ SIGHASH_ALL = 1,
33
+ SIGHASH_NONE = 2,
34
+ SIGHASH_SINGLE = 3,
35
+ SIGHASH_ANYONECANPAY = 128
36
+ }
31
37
  type InputOutputIndexType = number;
32
38
  type MapSelectorType = "global" | ["inputs", InputOutputIndexType] | ["outputs", InputOutputIndexType];
33
39
 
@@ -52,7 +58,7 @@ declare abstract class PsbtV2Maps {
52
58
  */
53
59
  serialize(format?: "base64" | "hex"): string;
54
60
  /**
55
- * Copies the maps in this PsbtV2 object to another PsbtV2 object.
61
+ * Copies the maps in this PsbtV2Maps object to another PsbtV2Maps object.
56
62
  *
57
63
  * NOTE: This copy method is made available to achieve parity with the PSBT
58
64
  * api required by `ledger-bitcoin` for creating merklized PSBTs. HOWEVER, it
@@ -60,7 +66,7 @@ declare abstract class PsbtV2Maps {
60
66
  * validation defined in the constructor, so it could create a psbtv2 in an
61
67
  * invalid psbt state. PsbtV2.serialize is preferable whenever possible.
62
68
  */
63
- copy(to: PsbtV2): void;
69
+ copy(to: PsbtV2Maps): void;
64
70
  private copyMaps;
65
71
  private copyMap;
66
72
  }
@@ -281,7 +287,7 @@ declare class PsbtV2 extends PsbtV2Maps {
281
287
  */
282
288
  dangerouslySetGlobalTxVersion1(): void;
283
289
  addGlobalXpub(xpub: Buffer, fingerprint: Buffer, path: string): void;
284
- addInput({ previousTxId, outputIndex, sequence, nonWitnessUtxo, witnessUtxo, redeemScript, witnessScript, bip32Derivation, }: {
290
+ addInput({ previousTxId, outputIndex, sequence, nonWitnessUtxo, witnessUtxo, redeemScript, witnessScript, bip32Derivation, sighashType, }: {
285
291
  previousTxId: Buffer | string;
286
292
  outputIndex: number;
287
293
  sequence?: number;
@@ -297,6 +303,7 @@ declare class PsbtV2 extends PsbtV2Maps {
297
303
  masterFingerprint: Buffer;
298
304
  path: string;
299
305
  }[];
306
+ sighashType?: SighashType;
300
307
  }): void;
301
308
  addOutput({ amount, script, redeemScript, witnessScript, bip32Derivation, }: {
302
309
  amount: number;
@@ -378,10 +385,16 @@ declare class PsbtV2 extends PsbtV2Maps {
378
385
  * Attempts to return a PsbtV2 by converting from a PsbtV0 string or Buffer.
379
386
  *
380
387
  * This method first starts with a fresh PsbtV2 having just been created. It
381
- * then takes the PsbtV2 through its operator saga through the Signer role. In
382
- * this sense validation for each operator role will be performed.
388
+ * then takes the PsbtV2 through its operator saga and through the Input
389
+ * Finalizer role. In this sense, validation for each operator role will be
390
+ * performed as the Psbt saga is replayed.
383
391
  */
384
392
  static FromV0(psbt: string | Buffer, allowTxnVersion1?: boolean): PsbtV2;
393
+ /**
394
+ * Outputs a serialized PSBTv0 from a best-attempt conversion of the fields in
395
+ * this PSBTv2. Accepts optional desired format as a string (default base64).
396
+ */
397
+ toV0(format?: "base64" | "hex"): string;
385
398
  }
386
399
 
387
400
  interface PsbtInput {
package/dist/index.js CHANGED
@@ -57,6 +57,54 @@ var PSBT_MAGIC_HEX = "70736274ff";
57
57
  var PSBT_MAGIC_B64 = "cHNidP8";
58
58
  var PSBT_MAGIC_BYTES = import_buffer.Buffer.from([112, 115, 98, 116, 255]);
59
59
 
60
+ // src/psbtv2/types.ts
61
+ var KeyType = /* @__PURE__ */ ((KeyType2) => {
62
+ KeyType2["PSBT_GLOBAL_XPUB"] = "01";
63
+ KeyType2["PSBT_GLOBAL_TX_VERSION"] = "02";
64
+ KeyType2["PSBT_GLOBAL_FALLBACK_LOCKTIME"] = "03";
65
+ KeyType2["PSBT_GLOBAL_INPUT_COUNT"] = "04";
66
+ KeyType2["PSBT_GLOBAL_OUTPUT_COUNT"] = "05";
67
+ KeyType2["PSBT_GLOBAL_TX_MODIFIABLE"] = "06";
68
+ KeyType2["PSBT_GLOBAL_VERSION"] = "fb";
69
+ KeyType2["PSBT_GLOBAL_PROPRIETARY"] = "fc";
70
+ KeyType2["PSBT_IN_NON_WITNESS_UTXO"] = "00";
71
+ KeyType2["PSBT_IN_WITNESS_UTXO"] = "01";
72
+ KeyType2["PSBT_IN_PARTIAL_SIG"] = "02";
73
+ KeyType2["PSBT_IN_SIGHASH_TYPE"] = "03";
74
+ KeyType2["PSBT_IN_REDEEM_SCRIPT"] = "04";
75
+ KeyType2["PSBT_IN_WITNESS_SCRIPT"] = "05";
76
+ KeyType2["PSBT_IN_BIP32_DERIVATION"] = "06";
77
+ KeyType2["PSBT_IN_FINAL_SCRIPTSIG"] = "07";
78
+ KeyType2["PSBT_IN_FINAL_SCRIPTWITNESS"] = "08";
79
+ KeyType2["PSBT_IN_POR_COMMITMENT"] = "09";
80
+ KeyType2["PSBT_IN_RIPEMD160"] = "0a";
81
+ KeyType2["PSBT_IN_SHA256"] = "0b";
82
+ KeyType2["PSBT_IN_HASH160"] = "0c";
83
+ KeyType2["PSBT_IN_HASH256"] = "0d";
84
+ KeyType2["PSBT_IN_PREVIOUS_TXID"] = "0e";
85
+ KeyType2["PSBT_IN_OUTPUT_INDEX"] = "0f";
86
+ KeyType2["PSBT_IN_SEQUENCE"] = "10";
87
+ KeyType2["PSBT_IN_REQUIRED_TIME_LOCKTIME"] = "11";
88
+ KeyType2["PSBT_IN_REQUIRED_HEIGHT_LOCKTIME"] = "12";
89
+ KeyType2["PSBT_IN_TAP_KEY_SIG"] = "13";
90
+ KeyType2["PSBT_IN_TAP_SCRIPT_SIG"] = "14";
91
+ KeyType2["PSBT_IN_TAP_LEAF_SCRIPT"] = "15";
92
+ KeyType2["PSBT_IN_TAP_BIP32_DERIVATION"] = "16";
93
+ KeyType2["PSBT_IN_TAP_INTERNAL_KEY"] = "17";
94
+ KeyType2["PSBT_IN_TAP_MERKLE_ROOT"] = "18";
95
+ KeyType2["PSBT_IN_PROPRIETARY"] = "fc";
96
+ KeyType2["PSBT_OUT_REDEEM_SCRIPT"] = "00";
97
+ KeyType2["PSBT_OUT_WITNESS_SCRIPT"] = "01";
98
+ KeyType2["PSBT_OUT_BIP32_DERIVATION"] = "02";
99
+ KeyType2["PSBT_OUT_AMOUNT"] = "03";
100
+ KeyType2["PSBT_OUT_SCRIPT"] = "04";
101
+ KeyType2["PSBT_OUT_TAP_INTERNAL_KEY"] = "05";
102
+ KeyType2["PSBT_OUT_TAP_TREE"] = "06";
103
+ KeyType2["PSBT_OUT_TAP_BIP32_DERIVATION"] = "07";
104
+ KeyType2["PSBT_OUT_PROPRIETARY"] = "fc";
105
+ return KeyType2;
106
+ })(KeyType || {});
107
+
60
108
  // src/psbtv2/values.ts
61
109
  var PSBT_MAP_SEPARATOR = import_buffer.Buffer.from([0]);
62
110
  var BIP_32_NODE_REGEX = /(\/[0-9]+'?)/gi;
@@ -152,10 +200,11 @@ function getPsbtVersionNumber(psbt) {
152
200
 
153
201
  // src/psbtv2/psbtv2.ts
154
202
  var import_bufio3 = require("bufio");
155
- var import_bitcoinjs_lib_v6 = require("bitcoinjs-lib-v6");
203
+ var import_bitcoinjs_lib_v62 = require("bitcoinjs-lib-v6");
156
204
 
157
205
  // src/psbtv2/psbtv2maps.ts
158
206
  var import_bufio2 = require("bufio");
207
+ var import_bitcoinjs_lib_v6 = require("bitcoinjs-lib-v6");
159
208
  var PsbtV2Maps = class {
160
209
  // These maps directly correspond to the maps defined in BIP0174 and extended
161
210
  // in BIP0370
@@ -207,7 +256,7 @@ var PsbtV2Maps = class {
207
256
  return bw.render().toString(format2);
208
257
  }
209
258
  /**
210
- * Copies the maps in this PsbtV2 object to another PsbtV2 object.
259
+ * Copies the maps in this PsbtV2Maps object to another PsbtV2Maps object.
211
260
  *
212
261
  * NOTE: This copy method is made available to achieve parity with the PSBT
213
262
  * api required by `ledger-bitcoin` for creating merklized PSBTs. HOWEVER, it
@@ -231,6 +280,86 @@ var PsbtV2Maps = class {
231
280
  from.forEach((v5, k4) => to.set(k4, import_buffer.Buffer.from(v5)));
232
281
  }
233
282
  };
283
+ var PsbtConversionMaps = class extends PsbtV2Maps {
284
+ /**
285
+ * Builds the unsigned transaction that is required on global map key 0x00 for
286
+ * a PSBTv0. Relies on bitcoinjs-lib to construct the transaction.
287
+ */
288
+ buildUnsignedTx() {
289
+ const tx = new import_bitcoinjs_lib_v6.Transaction();
290
+ tx.version = this.globalMap.get("02" /* PSBT_GLOBAL_TX_VERSION */)?.readUInt8() || 0;
291
+ tx.locktime = this.globalMap.get("03" /* PSBT_GLOBAL_FALLBACK_LOCKTIME */)?.readUInt32LE() || 0;
292
+ const numInputs = this.globalMap.get("04" /* PSBT_GLOBAL_INPUT_COUNT */)?.readUInt8() || 0;
293
+ const numOutputs = this.globalMap.get("05" /* PSBT_GLOBAL_OUTPUT_COUNT */)?.readUInt8() || 0;
294
+ for (let i6 = 0; i6 < numInputs; i6++) {
295
+ if (!this.inputMaps[i6].has("0e" /* PSBT_IN_PREVIOUS_TXID */)) {
296
+ console.warn(`Input ${i6} is missing previous txid. Skipping.`);
297
+ continue;
298
+ }
299
+ tx.addInput(
300
+ this.inputMaps[i6].get("0e" /* PSBT_IN_PREVIOUS_TXID */),
301
+ this.inputMaps[i6].get("0f" /* PSBT_IN_OUTPUT_INDEX */)?.readUint32LE() || 0,
302
+ this.inputMaps[i6].get("10" /* PSBT_IN_SEQUENCE */)?.readUint32LE()
303
+ );
304
+ }
305
+ for (let i6 = 0; i6 < numOutputs; i6++) {
306
+ if (!this.outputMaps[i6].has("04" /* PSBT_OUT_SCRIPT */) || !this.outputMaps[i6].has("03" /* PSBT_OUT_AMOUNT */)) {
307
+ console.warn(
308
+ `Output ${i6} is missing previous out script or amount. Skipping.`
309
+ );
310
+ continue;
311
+ }
312
+ const bigintAmount = this.outputMaps[i6].get("03" /* PSBT_OUT_AMOUNT */).readBigInt64LE();
313
+ const numberAmount = parseInt(bigintAmount.toString());
314
+ tx.addOutput(
315
+ this.outputMaps[i6].get("04" /* PSBT_OUT_SCRIPT */),
316
+ numberAmount
317
+ );
318
+ }
319
+ return tx.toBuffer();
320
+ }
321
+ /**
322
+ * Warns and then deletes map values. Intended for use when converting to a
323
+ * PsbtV0.
324
+ */
325
+ v0delete(map, key) {
326
+ if (map.has(key)) {
327
+ const keyName = Object.keys(KeyType)[Object.values(KeyType).indexOf(key)];
328
+ console.warn(
329
+ `Key ${keyName} key is not supported on PSBTv0 and will be omitted.`
330
+ );
331
+ }
332
+ map.delete(key);
333
+ }
334
+ /**
335
+ * Constructs an unsigned txn to be added to the PSBT_GLOBAL_UNSIGNED_TX key
336
+ * which is required on PsbtV0. Then removes all the fields which a PsbtV0 is
337
+ * incompatible with.
338
+ */
339
+ convertToV0 = () => {
340
+ this.globalMap.set(
341
+ "00" /* PSBT_GLOBAL_UNSIGNED_TX */,
342
+ this.buildUnsignedTx()
343
+ );
344
+ this.v0delete(this.globalMap, "02" /* PSBT_GLOBAL_TX_VERSION */);
345
+ this.v0delete(this.globalMap, "03" /* PSBT_GLOBAL_FALLBACK_LOCKTIME */);
346
+ this.v0delete(this.globalMap, "04" /* PSBT_GLOBAL_INPUT_COUNT */);
347
+ this.v0delete(this.globalMap, "05" /* PSBT_GLOBAL_OUTPUT_COUNT */);
348
+ this.v0delete(this.globalMap, "06" /* PSBT_GLOBAL_TX_MODIFIABLE */);
349
+ this.v0delete(this.globalMap, "fb" /* PSBT_GLOBAL_VERSION */);
350
+ for (const inputMap of this.inputMaps) {
351
+ this.v0delete(inputMap, "0e" /* PSBT_IN_PREVIOUS_TXID */);
352
+ this.v0delete(inputMap, "0f" /* PSBT_IN_OUTPUT_INDEX */);
353
+ this.v0delete(inputMap, "10" /* PSBT_IN_SEQUENCE */);
354
+ this.v0delete(inputMap, "11" /* PSBT_IN_REQUIRED_TIME_LOCKTIME */);
355
+ this.v0delete(inputMap, "12" /* PSBT_IN_REQUIRED_HEIGHT_LOCKTIME */);
356
+ }
357
+ for (const outputMap of this.outputMaps) {
358
+ this.v0delete(outputMap, "03" /* PSBT_OUT_AMOUNT */);
359
+ this.v0delete(outputMap, "04" /* PSBT_OUT_SCRIPT */);
360
+ }
361
+ };
362
+ };
234
363
 
235
364
  // src/psbtv2/psbtv2.ts
236
365
  var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
@@ -907,7 +1036,8 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
907
1036
  witnessUtxo,
908
1037
  redeemScript,
909
1038
  witnessScript,
910
- bip32Derivation
1039
+ bip32Derivation,
1040
+ sighashType
911
1041
  }) {
912
1042
  if (!this.isReadyForConstructor) {
913
1043
  throw Error(
@@ -958,6 +1088,10 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
958
1088
  map.set(key, bw.render());
959
1089
  }
960
1090
  }
1091
+ if (sighashType !== void 0) {
1092
+ bw.writeU32(sighashType);
1093
+ map.set("03" /* PSBT_IN_SIGHASH_TYPE */, bw.render());
1094
+ }
961
1095
  this.PSBT_GLOBAL_INPUT_COUNT = this.inputMaps.push(map);
962
1096
  }
963
1097
  addOutput({
@@ -1209,12 +1343,13 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
1209
1343
  * Attempts to return a PsbtV2 by converting from a PsbtV0 string or Buffer.
1210
1344
  *
1211
1345
  * This method first starts with a fresh PsbtV2 having just been created. It
1212
- * then takes the PsbtV2 through its operator saga through the Signer role. In
1213
- * this sense validation for each operator role will be performed.
1346
+ * then takes the PsbtV2 through its operator saga and through the Input
1347
+ * Finalizer role. In this sense, validation for each operator role will be
1348
+ * performed as the Psbt saga is replayed.
1214
1349
  */
1215
1350
  static FromV0(psbt, allowTxnVersion1 = false) {
1216
1351
  const psbtv0Buf = bufferize(psbt);
1217
- const psbtv0 = import_bitcoinjs_lib_v6.Psbt.fromBuffer(psbtv0Buf);
1352
+ const psbtv0 = import_bitcoinjs_lib_v62.Psbt.fromBuffer(psbtv0Buf);
1218
1353
  const psbtv0GlobalMap = psbtv0.data.globalMap;
1219
1354
  const psbtv2 = new _PsbtV2();
1220
1355
  const txVersion = psbtv0.data.getTransaction().readInt32LE(0);
@@ -1223,6 +1358,7 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
1223
1358
  } else {
1224
1359
  psbtv2.PSBT_GLOBAL_TX_VERSION = psbtv0.data.getTransaction().readInt32LE(0);
1225
1360
  }
1361
+ psbtv2.PSBT_GLOBAL_FALLBACK_LOCKTIME = psbtv0.locktime;
1226
1362
  for (const globalXpub of psbtv0GlobalMap.globalXpub ?? []) {
1227
1363
  psbtv2.addGlobalXpub(
1228
1364
  globalXpub.extendedPubkey,
@@ -1247,7 +1383,8 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
1247
1383
  },
1248
1384
  redeemScript: input.redeemScript,
1249
1385
  witnessScript: input.witnessScript,
1250
- bip32Derivation: input.bip32Derivation
1386
+ bip32Derivation: input.bip32Derivation,
1387
+ sighashType: input.sighashType
1251
1388
  });
1252
1389
  }
1253
1390
  const txOutputs = [];
@@ -1269,13 +1406,37 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
1269
1406
  psbtv2.addPartialSig(index, sig.pubkey, sig.signature);
1270
1407
  }
1271
1408
  }
1409
+ for (const [index, input] of psbtv0.data.inputs.entries()) {
1410
+ if (input.finalScriptSig) {
1411
+ psbtv2.inputMaps[index].set(
1412
+ "07" /* PSBT_IN_FINAL_SCRIPTSIG */,
1413
+ input.finalScriptSig
1414
+ );
1415
+ }
1416
+ if (input.finalScriptWitness) {
1417
+ psbtv2.inputMaps[index].set(
1418
+ "08" /* PSBT_IN_FINAL_SCRIPTWITNESS */,
1419
+ input.finalScriptWitness
1420
+ );
1421
+ }
1422
+ }
1272
1423
  return psbtv2;
1273
1424
  }
1425
+ /**
1426
+ * Outputs a serialized PSBTv0 from a best-attempt conversion of the fields in
1427
+ * this PSBTv2. Accepts optional desired format as a string (default base64).
1428
+ */
1429
+ toV0(format2) {
1430
+ const converterMap = new PsbtConversionMaps();
1431
+ this.copy(converterMap);
1432
+ converterMap.convertToV0();
1433
+ return converterMap.serialize(format2);
1434
+ }
1274
1435
  };
1275
1436
 
1276
1437
  // src/psbtv0/psbt.ts
1277
1438
  var import_bitcoin4 = require("@caravan/bitcoin");
1278
- var import_bitcoinjs_lib_v63 = require("bitcoinjs-lib-v6");
1439
+ var import_bitcoinjs_lib_v64 = require("bitcoinjs-lib-v6");
1279
1440
  var import_address = require("bitcoinjs-lib-v6/src/address.js");
1280
1441
 
1281
1442
  // vendor/tiny-secp256k1-asmjs/lib/index.js
@@ -93806,7 +93967,7 @@ var braidDetailsToWalletConfig = (braidDetails) => {
93806
93967
 
93807
93968
  // src/psbtv0/utils.ts
93808
93969
  var import_bignumber = __toESM(require("bignumber.js"));
93809
- var import_bitcoinjs_lib_v62 = require("bitcoinjs-lib-v6");
93970
+ var import_bitcoinjs_lib_v63 = require("bitcoinjs-lib-v6");
93810
93971
  var import_bufio4 = require("bufio");
93811
93972
  var idToHash = (txid) => {
93812
93973
  return import_buffer.Buffer.from(txid, "hex").reverse();
@@ -93883,7 +94044,7 @@ function autoLoadPSBT(psbtFromFile, options) {
93883
94044
  } catch (e8) {
93884
94045
  return null;
93885
94046
  }
93886
- return import_bitcoinjs_lib_v62.Psbt.fromBuffer(psbtBuff, options);
94047
+ return import_bitcoinjs_lib_v63.Psbt.fromBuffer(psbtBuff, options);
93887
94048
  }
93888
94049
 
93889
94050
  // src/psbtv0/psbt.ts
@@ -93894,7 +94055,7 @@ var getUnsignedMultisigPsbtV0 = ({
93894
94055
  outputs,
93895
94056
  includeGlobalXpubs = false
93896
94057
  }) => {
93897
- const psbt = new import_bitcoinjs_lib_v63.Psbt({ network: (0, import_bitcoin4.networkData)(network) });
94058
+ const psbt = new import_bitcoinjs_lib_v64.Psbt({ network: (0, import_bitcoin4.networkData)(network) });
93898
94059
  psbt.setVersion(1);
93899
94060
  for (const input of inputs) {
93900
94061
  const inputData = psbtInputFormatter(
@@ -93913,7 +94074,7 @@ var getUnsignedMultisigPsbtV0 = ({
93913
94074
  return psbt;
93914
94075
  };
93915
94076
  var psbtInputFormatter = (input, addressType) => {
93916
- const tx = import_bitcoinjs_lib_v63.Transaction.fromHex(input.transactionHex);
94077
+ const tx = import_bitcoinjs_lib_v64.Transaction.fromHex(input.transactionHex);
93917
94078
  const inputData = { ...input };
93918
94079
  const nonWitnessUtxo = tx.toBuffer();
93919
94080
  if (addressType === import_bitcoin4.P2SH) {
@@ -93988,7 +94149,7 @@ var formatGlobalXpub = (extendedPublicKey) => {
93988
94149
  return global2;
93989
94150
  };
93990
94151
  var validateMultisigPsbtSignature = (raw, inputIndex, inputSignature, inputAmount) => {
93991
- const psbt = import_bitcoinjs_lib_v63.Psbt.fromBuffer(bufferize(raw));
94152
+ const psbt = import_bitcoinjs_lib_v64.Psbt.fromBuffer(bufferize(raw));
93992
94153
  if (psbt.inputCount === 0 || psbt.inputCount < inputIndex + 1) {
93993
94154
  throw new Error("Input index is out of range.");
93994
94155
  }
@@ -94004,8 +94165,8 @@ var validateMultisigPsbtSignature = (raw, inputIndex, inputSignature, inputAmoun
94004
94165
  }
94005
94166
  return false;
94006
94167
  };
94007
- var getHashForSignature = (psbt, inputIndex, inputAmount, sigHashFlag = import_bitcoinjs_lib_v63.Transaction.SIGHASH_ALL) => {
94008
- const tx = import_bitcoinjs_lib_v63.Transaction.fromBuffer(psbt.data.globalMap.unsignedTx.toBuffer());
94168
+ var getHashForSignature = (psbt, inputIndex, inputAmount, sigHashFlag = import_bitcoinjs_lib_v64.Transaction.SIGHASH_ALL) => {
94169
+ const tx = import_bitcoinjs_lib_v64.Transaction.fromBuffer(psbt.data.globalMap.unsignedTx.toBuffer());
94009
94170
  const input = psbt.data.inputs[inputIndex];
94010
94171
  if (!input.witnessScript && input.redeemScript) {
94011
94172
  return tx.hashForSignature(inputIndex, input.redeemScript, sigHashFlag);
@@ -94052,7 +94213,7 @@ function getUnchainedInputsFromPSBT(network, addressType, psbt) {
94052
94213
  inputs to protect against large fee attack`);
94053
94214
  }
94054
94215
  const fundingTxHex = dataInput.nonWitnessUtxo.toString("hex");
94055
- const fundingTx = import_bitcoinjs_lib_v63.Transaction.fromHex(fundingTxHex);
94216
+ const fundingTx = import_bitcoinjs_lib_v64.Transaction.fromHex(fundingTxHex);
94056
94217
  const multisig = (0, import_bitcoin4.generateMultisigFromHex)(
94057
94218
  network,
94058
94219
  addressType,
package/dist/index.mjs CHANGED
@@ -16,6 +16,54 @@ var PSBT_MAGIC_HEX = "70736274ff";
16
16
  var PSBT_MAGIC_B64 = "cHNidP8";
17
17
  var PSBT_MAGIC_BYTES = Buffer2.from([112, 115, 98, 116, 255]);
18
18
 
19
+ // src/psbtv2/types.ts
20
+ var KeyType = /* @__PURE__ */ ((KeyType2) => {
21
+ KeyType2["PSBT_GLOBAL_XPUB"] = "01";
22
+ KeyType2["PSBT_GLOBAL_TX_VERSION"] = "02";
23
+ KeyType2["PSBT_GLOBAL_FALLBACK_LOCKTIME"] = "03";
24
+ KeyType2["PSBT_GLOBAL_INPUT_COUNT"] = "04";
25
+ KeyType2["PSBT_GLOBAL_OUTPUT_COUNT"] = "05";
26
+ KeyType2["PSBT_GLOBAL_TX_MODIFIABLE"] = "06";
27
+ KeyType2["PSBT_GLOBAL_VERSION"] = "fb";
28
+ KeyType2["PSBT_GLOBAL_PROPRIETARY"] = "fc";
29
+ KeyType2["PSBT_IN_NON_WITNESS_UTXO"] = "00";
30
+ KeyType2["PSBT_IN_WITNESS_UTXO"] = "01";
31
+ KeyType2["PSBT_IN_PARTIAL_SIG"] = "02";
32
+ KeyType2["PSBT_IN_SIGHASH_TYPE"] = "03";
33
+ KeyType2["PSBT_IN_REDEEM_SCRIPT"] = "04";
34
+ KeyType2["PSBT_IN_WITNESS_SCRIPT"] = "05";
35
+ KeyType2["PSBT_IN_BIP32_DERIVATION"] = "06";
36
+ KeyType2["PSBT_IN_FINAL_SCRIPTSIG"] = "07";
37
+ KeyType2["PSBT_IN_FINAL_SCRIPTWITNESS"] = "08";
38
+ KeyType2["PSBT_IN_POR_COMMITMENT"] = "09";
39
+ KeyType2["PSBT_IN_RIPEMD160"] = "0a";
40
+ KeyType2["PSBT_IN_SHA256"] = "0b";
41
+ KeyType2["PSBT_IN_HASH160"] = "0c";
42
+ KeyType2["PSBT_IN_HASH256"] = "0d";
43
+ KeyType2["PSBT_IN_PREVIOUS_TXID"] = "0e";
44
+ KeyType2["PSBT_IN_OUTPUT_INDEX"] = "0f";
45
+ KeyType2["PSBT_IN_SEQUENCE"] = "10";
46
+ KeyType2["PSBT_IN_REQUIRED_TIME_LOCKTIME"] = "11";
47
+ KeyType2["PSBT_IN_REQUIRED_HEIGHT_LOCKTIME"] = "12";
48
+ KeyType2["PSBT_IN_TAP_KEY_SIG"] = "13";
49
+ KeyType2["PSBT_IN_TAP_SCRIPT_SIG"] = "14";
50
+ KeyType2["PSBT_IN_TAP_LEAF_SCRIPT"] = "15";
51
+ KeyType2["PSBT_IN_TAP_BIP32_DERIVATION"] = "16";
52
+ KeyType2["PSBT_IN_TAP_INTERNAL_KEY"] = "17";
53
+ KeyType2["PSBT_IN_TAP_MERKLE_ROOT"] = "18";
54
+ KeyType2["PSBT_IN_PROPRIETARY"] = "fc";
55
+ KeyType2["PSBT_OUT_REDEEM_SCRIPT"] = "00";
56
+ KeyType2["PSBT_OUT_WITNESS_SCRIPT"] = "01";
57
+ KeyType2["PSBT_OUT_BIP32_DERIVATION"] = "02";
58
+ KeyType2["PSBT_OUT_AMOUNT"] = "03";
59
+ KeyType2["PSBT_OUT_SCRIPT"] = "04";
60
+ KeyType2["PSBT_OUT_TAP_INTERNAL_KEY"] = "05";
61
+ KeyType2["PSBT_OUT_TAP_TREE"] = "06";
62
+ KeyType2["PSBT_OUT_TAP_BIP32_DERIVATION"] = "07";
63
+ KeyType2["PSBT_OUT_PROPRIETARY"] = "fc";
64
+ return KeyType2;
65
+ })(KeyType || {});
66
+
19
67
  // src/psbtv2/values.ts
20
68
  var PSBT_MAP_SEPARATOR = Buffer2.from([0]);
21
69
  var BIP_32_NODE_REGEX = /(\/[0-9]+'?)/gi;
@@ -115,6 +163,7 @@ import { Psbt } from "bitcoinjs-lib-v6";
115
163
 
116
164
  // src/psbtv2/psbtv2maps.ts
117
165
  import { BufferReader as BufferReader2, BufferWriter as BufferWriter2 } from "bufio";
166
+ import { Transaction } from "bitcoinjs-lib-v6";
118
167
  var PsbtV2Maps = class {
119
168
  // These maps directly correspond to the maps defined in BIP0174 and extended
120
169
  // in BIP0370
@@ -166,7 +215,7 @@ var PsbtV2Maps = class {
166
215
  return bw.render().toString(format2);
167
216
  }
168
217
  /**
169
- * Copies the maps in this PsbtV2 object to another PsbtV2 object.
218
+ * Copies the maps in this PsbtV2Maps object to another PsbtV2Maps object.
170
219
  *
171
220
  * NOTE: This copy method is made available to achieve parity with the PSBT
172
221
  * api required by `ledger-bitcoin` for creating merklized PSBTs. HOWEVER, it
@@ -190,6 +239,86 @@ var PsbtV2Maps = class {
190
239
  from.forEach((v5, k4) => to.set(k4, Buffer2.from(v5)));
191
240
  }
192
241
  };
242
+ var PsbtConversionMaps = class extends PsbtV2Maps {
243
+ /**
244
+ * Builds the unsigned transaction that is required on global map key 0x00 for
245
+ * a PSBTv0. Relies on bitcoinjs-lib to construct the transaction.
246
+ */
247
+ buildUnsignedTx() {
248
+ const tx = new Transaction();
249
+ tx.version = this.globalMap.get("02" /* PSBT_GLOBAL_TX_VERSION */)?.readUInt8() || 0;
250
+ tx.locktime = this.globalMap.get("03" /* PSBT_GLOBAL_FALLBACK_LOCKTIME */)?.readUInt32LE() || 0;
251
+ const numInputs = this.globalMap.get("04" /* PSBT_GLOBAL_INPUT_COUNT */)?.readUInt8() || 0;
252
+ const numOutputs = this.globalMap.get("05" /* PSBT_GLOBAL_OUTPUT_COUNT */)?.readUInt8() || 0;
253
+ for (let i6 = 0; i6 < numInputs; i6++) {
254
+ if (!this.inputMaps[i6].has("0e" /* PSBT_IN_PREVIOUS_TXID */)) {
255
+ console.warn(`Input ${i6} is missing previous txid. Skipping.`);
256
+ continue;
257
+ }
258
+ tx.addInput(
259
+ this.inputMaps[i6].get("0e" /* PSBT_IN_PREVIOUS_TXID */),
260
+ this.inputMaps[i6].get("0f" /* PSBT_IN_OUTPUT_INDEX */)?.readUint32LE() || 0,
261
+ this.inputMaps[i6].get("10" /* PSBT_IN_SEQUENCE */)?.readUint32LE()
262
+ );
263
+ }
264
+ for (let i6 = 0; i6 < numOutputs; i6++) {
265
+ if (!this.outputMaps[i6].has("04" /* PSBT_OUT_SCRIPT */) || !this.outputMaps[i6].has("03" /* PSBT_OUT_AMOUNT */)) {
266
+ console.warn(
267
+ `Output ${i6} is missing previous out script or amount. Skipping.`
268
+ );
269
+ continue;
270
+ }
271
+ const bigintAmount = this.outputMaps[i6].get("03" /* PSBT_OUT_AMOUNT */).readBigInt64LE();
272
+ const numberAmount = parseInt(bigintAmount.toString());
273
+ tx.addOutput(
274
+ this.outputMaps[i6].get("04" /* PSBT_OUT_SCRIPT */),
275
+ numberAmount
276
+ );
277
+ }
278
+ return tx.toBuffer();
279
+ }
280
+ /**
281
+ * Warns and then deletes map values. Intended for use when converting to a
282
+ * PsbtV0.
283
+ */
284
+ v0delete(map, key) {
285
+ if (map.has(key)) {
286
+ const keyName = Object.keys(KeyType)[Object.values(KeyType).indexOf(key)];
287
+ console.warn(
288
+ `Key ${keyName} key is not supported on PSBTv0 and will be omitted.`
289
+ );
290
+ }
291
+ map.delete(key);
292
+ }
293
+ /**
294
+ * Constructs an unsigned txn to be added to the PSBT_GLOBAL_UNSIGNED_TX key
295
+ * which is required on PsbtV0. Then removes all the fields which a PsbtV0 is
296
+ * incompatible with.
297
+ */
298
+ convertToV0 = () => {
299
+ this.globalMap.set(
300
+ "00" /* PSBT_GLOBAL_UNSIGNED_TX */,
301
+ this.buildUnsignedTx()
302
+ );
303
+ this.v0delete(this.globalMap, "02" /* PSBT_GLOBAL_TX_VERSION */);
304
+ this.v0delete(this.globalMap, "03" /* PSBT_GLOBAL_FALLBACK_LOCKTIME */);
305
+ this.v0delete(this.globalMap, "04" /* PSBT_GLOBAL_INPUT_COUNT */);
306
+ this.v0delete(this.globalMap, "05" /* PSBT_GLOBAL_OUTPUT_COUNT */);
307
+ this.v0delete(this.globalMap, "06" /* PSBT_GLOBAL_TX_MODIFIABLE */);
308
+ this.v0delete(this.globalMap, "fb" /* PSBT_GLOBAL_VERSION */);
309
+ for (const inputMap of this.inputMaps) {
310
+ this.v0delete(inputMap, "0e" /* PSBT_IN_PREVIOUS_TXID */);
311
+ this.v0delete(inputMap, "0f" /* PSBT_IN_OUTPUT_INDEX */);
312
+ this.v0delete(inputMap, "10" /* PSBT_IN_SEQUENCE */);
313
+ this.v0delete(inputMap, "11" /* PSBT_IN_REQUIRED_TIME_LOCKTIME */);
314
+ this.v0delete(inputMap, "12" /* PSBT_IN_REQUIRED_HEIGHT_LOCKTIME */);
315
+ }
316
+ for (const outputMap of this.outputMaps) {
317
+ this.v0delete(outputMap, "03" /* PSBT_OUT_AMOUNT */);
318
+ this.v0delete(outputMap, "04" /* PSBT_OUT_SCRIPT */);
319
+ }
320
+ };
321
+ };
193
322
 
194
323
  // src/psbtv2/psbtv2.ts
195
324
  var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
@@ -866,7 +995,8 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
866
995
  witnessUtxo,
867
996
  redeemScript,
868
997
  witnessScript,
869
- bip32Derivation
998
+ bip32Derivation,
999
+ sighashType
870
1000
  }) {
871
1001
  if (!this.isReadyForConstructor) {
872
1002
  throw Error(
@@ -917,6 +1047,10 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
917
1047
  map.set(key, bw.render());
918
1048
  }
919
1049
  }
1050
+ if (sighashType !== void 0) {
1051
+ bw.writeU32(sighashType);
1052
+ map.set("03" /* PSBT_IN_SIGHASH_TYPE */, bw.render());
1053
+ }
920
1054
  this.PSBT_GLOBAL_INPUT_COUNT = this.inputMaps.push(map);
921
1055
  }
922
1056
  addOutput({
@@ -1168,8 +1302,9 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
1168
1302
  * Attempts to return a PsbtV2 by converting from a PsbtV0 string or Buffer.
1169
1303
  *
1170
1304
  * This method first starts with a fresh PsbtV2 having just been created. It
1171
- * then takes the PsbtV2 through its operator saga through the Signer role. In
1172
- * this sense validation for each operator role will be performed.
1305
+ * then takes the PsbtV2 through its operator saga and through the Input
1306
+ * Finalizer role. In this sense, validation for each operator role will be
1307
+ * performed as the Psbt saga is replayed.
1173
1308
  */
1174
1309
  static FromV0(psbt, allowTxnVersion1 = false) {
1175
1310
  const psbtv0Buf = bufferize(psbt);
@@ -1182,6 +1317,7 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
1182
1317
  } else {
1183
1318
  psbtv2.PSBT_GLOBAL_TX_VERSION = psbtv0.data.getTransaction().readInt32LE(0);
1184
1319
  }
1320
+ psbtv2.PSBT_GLOBAL_FALLBACK_LOCKTIME = psbtv0.locktime;
1185
1321
  for (const globalXpub of psbtv0GlobalMap.globalXpub ?? []) {
1186
1322
  psbtv2.addGlobalXpub(
1187
1323
  globalXpub.extendedPubkey,
@@ -1206,7 +1342,8 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
1206
1342
  },
1207
1343
  redeemScript: input.redeemScript,
1208
1344
  witnessScript: input.witnessScript,
1209
- bip32Derivation: input.bip32Derivation
1345
+ bip32Derivation: input.bip32Derivation,
1346
+ sighashType: input.sighashType
1210
1347
  });
1211
1348
  }
1212
1349
  const txOutputs = [];
@@ -1228,8 +1365,32 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
1228
1365
  psbtv2.addPartialSig(index, sig.pubkey, sig.signature);
1229
1366
  }
1230
1367
  }
1368
+ for (const [index, input] of psbtv0.data.inputs.entries()) {
1369
+ if (input.finalScriptSig) {
1370
+ psbtv2.inputMaps[index].set(
1371
+ "07" /* PSBT_IN_FINAL_SCRIPTSIG */,
1372
+ input.finalScriptSig
1373
+ );
1374
+ }
1375
+ if (input.finalScriptWitness) {
1376
+ psbtv2.inputMaps[index].set(
1377
+ "08" /* PSBT_IN_FINAL_SCRIPTWITNESS */,
1378
+ input.finalScriptWitness
1379
+ );
1380
+ }
1381
+ }
1231
1382
  return psbtv2;
1232
1383
  }
1384
+ /**
1385
+ * Outputs a serialized PSBTv0 from a best-attempt conversion of the fields in
1386
+ * this PSBTv2. Accepts optional desired format as a string (default base64).
1387
+ */
1388
+ toV0(format2) {
1389
+ const converterMap = new PsbtConversionMaps();
1390
+ this.copy(converterMap);
1391
+ converterMap.convertToV0();
1392
+ return converterMap.serialize(format2);
1393
+ }
1233
1394
  };
1234
1395
 
1235
1396
  // src/psbtv0/psbt.ts
@@ -1244,7 +1405,7 @@ import {
1244
1405
  P2WSH as P2WSH2,
1245
1406
  signatureNoSighashType
1246
1407
  } from "@caravan/bitcoin";
1247
- import { Psbt as Psbt3, Transaction } from "bitcoinjs-lib-v6";
1408
+ import { Psbt as Psbt3, Transaction as Transaction2 } from "bitcoinjs-lib-v6";
1248
1409
  import { toOutputScript } from "bitcoinjs-lib-v6/src/address.js";
1249
1410
 
1250
1411
  // vendor/tiny-secp256k1-asmjs/lib/index.js
@@ -93892,7 +94053,7 @@ var getUnsignedMultisigPsbtV0 = ({
93892
94053
  return psbt;
93893
94054
  };
93894
94055
  var psbtInputFormatter = (input, addressType) => {
93895
- const tx = Transaction.fromHex(input.transactionHex);
94056
+ const tx = Transaction2.fromHex(input.transactionHex);
93896
94057
  const inputData = { ...input };
93897
94058
  const nonWitnessUtxo = tx.toBuffer();
93898
94059
  if (addressType === P2SH2) {
@@ -93983,8 +94144,8 @@ var validateMultisigPsbtSignature = (raw, inputIndex, inputSignature, inputAmoun
93983
94144
  }
93984
94145
  return false;
93985
94146
  };
93986
- var getHashForSignature = (psbt, inputIndex, inputAmount, sigHashFlag = Transaction.SIGHASH_ALL) => {
93987
- const tx = Transaction.fromBuffer(psbt.data.globalMap.unsignedTx.toBuffer());
94147
+ var getHashForSignature = (psbt, inputIndex, inputAmount, sigHashFlag = Transaction2.SIGHASH_ALL) => {
94148
+ const tx = Transaction2.fromBuffer(psbt.data.globalMap.unsignedTx.toBuffer());
93988
94149
  const input = psbt.data.inputs[inputIndex];
93989
94150
  if (!input.witnessScript && input.redeemScript) {
93990
94151
  return tx.hashForSignature(inputIndex, input.redeemScript, sigHashFlag);
@@ -94031,7 +94192,7 @@ function getUnchainedInputsFromPSBT(network, addressType, psbt) {
94031
94192
  inputs to protect against large fee attack`);
94032
94193
  }
94033
94194
  const fundingTxHex = dataInput.nonWitnessUtxo.toString("hex");
94034
- const fundingTx = Transaction.fromHex(fundingTxHex);
94195
+ const fundingTx = Transaction2.fromHex(fundingTxHex);
94035
94196
  const multisig = generateMultisigFromHex(
94036
94197
  network,
94037
94198
  addressType,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@caravan/psbt",
3
- "version": "1.6.0",
3
+ "version": "1.7.1",
4
4
  "description": "typescript library for working with PSBTs",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -39,7 +39,7 @@
39
39
  "psbt"
40
40
  ],
41
41
  "dependencies": {
42
- "@caravan/bitcoin": "*",
42
+ "@caravan/bitcoin": "0.3.1",
43
43
  "bignumber.js": "^8.1.1",
44
44
  "bip174": "^2.1.1",
45
45
  "bitcoinjs-lib-v6": "npm:bitcoinjs-lib@^6.1.5",