@caravan/psbt 1.3.2 → 1.4.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 +21 -1
- package/dist/index.js +184 -97
- package/dist/index.mjs +184 -98
- package/package.json +3 -2
package/dist/index.d.ts
CHANGED
|
@@ -371,6 +371,22 @@ declare const addGlobalXpubs: (psbt: Psbt, inputs: PsbtInput[], network: Network
|
|
|
371
371
|
* to support a newer API and be more PSBT-native.
|
|
372
372
|
*/
|
|
373
373
|
declare const validateMultisigPsbtSignature: (raw: string | Buffer, inputIndex: number, inputSignature: Buffer, inputAmount?: string) => boolean | string;
|
|
374
|
+
/***
|
|
375
|
+
* These should be deprecated eventually once we have better typescript support
|
|
376
|
+
* and a more api for handling PSBT saga.
|
|
377
|
+
* They are ports over from the legacy psbt code in caravan/bitcoin
|
|
378
|
+
*/
|
|
379
|
+
/**
|
|
380
|
+
* Translates a PSBT into inputs/outputs consumable by supported non-PSBT devices in the
|
|
381
|
+
* `@caravan/wallets` library.
|
|
382
|
+
*
|
|
383
|
+
* FIXME - Have only confirmed this is working for P2SH addresses on Ledger on regtest
|
|
384
|
+
*/
|
|
385
|
+
declare function translatePSBT(network: any, addressType: any, psbt: string, signingKeyDetails: any): {
|
|
386
|
+
unchainedInputs: any;
|
|
387
|
+
unchainedOutputs: any;
|
|
388
|
+
bip32Derivations: any;
|
|
389
|
+
} | null;
|
|
374
390
|
|
|
375
391
|
/**
|
|
376
392
|
* @file This file primarily contains utility functions migrated from the
|
|
@@ -419,9 +435,13 @@ interface LegacyOutput {
|
|
|
419
435
|
}
|
|
420
436
|
declare const convertLegacyInput: (input: LegacyInput) => PsbtInput;
|
|
421
437
|
declare const convertLegacyOutput: (output: LegacyOutput) => PsbtOutput;
|
|
438
|
+
/**
|
|
439
|
+
* Given a string, try to create a Psbt object based on MAGIC (hex or Base64)
|
|
440
|
+
*/
|
|
441
|
+
declare function autoLoadPSBT(psbtFromFile: any, options?: any): Psbt | null;
|
|
422
442
|
|
|
423
443
|
declare const PSBT_MAGIC_HEX = "70736274ff";
|
|
424
444
|
declare const PSBT_MAGIC_B64 = "cHNidP8";
|
|
425
445
|
declare const PSBT_MAGIC_BYTES: Buffer;
|
|
426
446
|
|
|
427
|
-
export { LegacyInput, LegacyMultisig, LegacyOutput, PSBT_MAGIC_B64, PSBT_MAGIC_BYTES, PSBT_MAGIC_HEX, PsbtInput, PsbtOutput, PsbtV2, addGlobalXpubs, convertLegacyInput, convertLegacyOutput, getPsbtVersionNumber, getUnsignedMultisigPsbtV0, validateMultisigPsbtSignature };
|
|
447
|
+
export { LegacyInput, LegacyMultisig, LegacyOutput, PSBT_MAGIC_B64, PSBT_MAGIC_BYTES, PSBT_MAGIC_HEX, PsbtInput, PsbtOutput, PsbtV2, addGlobalXpubs, autoLoadPSBT, convertLegacyInput, convertLegacyOutput, getPsbtVersionNumber, getUnsignedMultisigPsbtV0, translatePSBT, validateMultisigPsbtSignature };
|
package/dist/index.js
CHANGED
|
@@ -35,10 +35,12 @@ __export(src_exports, {
|
|
|
35
35
|
PSBT_MAGIC_HEX: () => PSBT_MAGIC_HEX,
|
|
36
36
|
PsbtV2: () => PsbtV2,
|
|
37
37
|
addGlobalXpubs: () => addGlobalXpubs,
|
|
38
|
+
autoLoadPSBT: () => autoLoadPSBT,
|
|
38
39
|
convertLegacyInput: () => convertLegacyInput,
|
|
39
40
|
convertLegacyOutput: () => convertLegacyOutput,
|
|
40
41
|
getPsbtVersionNumber: () => getPsbtVersionNumber,
|
|
41
42
|
getUnsignedMultisigPsbtV0: () => getUnsignedMultisigPsbtV0,
|
|
43
|
+
translatePSBT: () => translatePSBT,
|
|
42
44
|
validateMultisigPsbtSignature: () => validateMultisigPsbtSignature
|
|
43
45
|
});
|
|
44
46
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -1197,9 +1199,9 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
|
|
|
1197
1199
|
};
|
|
1198
1200
|
|
|
1199
1201
|
// src/psbtv0/psbt.ts
|
|
1200
|
-
var
|
|
1201
|
-
var
|
|
1202
|
-
var import_address = require("bitcoinjs-lib-v6/src/address");
|
|
1202
|
+
var import_bitcoin4 = require("@caravan/bitcoin");
|
|
1203
|
+
var import_bitcoinjs_lib_v63 = require("bitcoinjs-lib-v6");
|
|
1204
|
+
var import_address = require("bitcoinjs-lib-v6/src/address.js");
|
|
1203
1205
|
|
|
1204
1206
|
// vendor/tiny-secp256k1-asmjs/lib/index.js
|
|
1205
1207
|
var lib_exports = {};
|
|
@@ -93703,7 +93705,114 @@ function verifySchnorr2(h6, Q3, signature) {
|
|
|
93703
93705
|
|
|
93704
93706
|
// src/psbtv0/psbt.ts
|
|
93705
93707
|
var bitcoin = __toESM(require("bitcoinjs-lib-v6"));
|
|
93708
|
+
var import_bignumber2 = __toESM(require("bignumber.js"));
|
|
93709
|
+
var import_bufferutils = require("bitcoinjs-lib-v6/src/bufferutils.js");
|
|
93710
|
+
|
|
93711
|
+
// src/psbtv0/utils.ts
|
|
93712
|
+
var import_bitcoin3 = require("@caravan/bitcoin");
|
|
93713
|
+
|
|
93714
|
+
// ../multisig/dist/index.mjs
|
|
93715
|
+
var braidDetailsToWalletConfig = (braidDetails) => {
|
|
93716
|
+
return {
|
|
93717
|
+
network: braidDetails.network,
|
|
93718
|
+
extendedPublicKeys: braidDetails.extendedPublicKeys.map((key) => ({
|
|
93719
|
+
xpub: key.base58String,
|
|
93720
|
+
bip32Path: key.path,
|
|
93721
|
+
xfp: key.rootFingerprint
|
|
93722
|
+
})),
|
|
93723
|
+
quorum: {
|
|
93724
|
+
requiredSigners: braidDetails.requiredSigners,
|
|
93725
|
+
totalSigners: braidDetails.extendedPublicKeys.length
|
|
93726
|
+
},
|
|
93727
|
+
name: `${braidDetails.requiredSigners}-of-${braidDetails.extendedPublicKeys.length} ${braidDetails.addressType} ${braidDetails.network} wallet`,
|
|
93728
|
+
addressType: braidDetails.addressType
|
|
93729
|
+
};
|
|
93730
|
+
};
|
|
93731
|
+
|
|
93732
|
+
// src/psbtv0/utils.ts
|
|
93706
93733
|
var import_bignumber = __toESM(require("bignumber.js"));
|
|
93734
|
+
var import_bitcoinjs_lib_v62 = require("bitcoinjs-lib-v6");
|
|
93735
|
+
var import_bufio4 = require("bufio");
|
|
93736
|
+
var idToHash = (txid) => {
|
|
93737
|
+
return import_buffer.Buffer.from(txid, "hex").reverse();
|
|
93738
|
+
};
|
|
93739
|
+
function psbtMultisigLock(multisig) {
|
|
93740
|
+
if (!multisig) {
|
|
93741
|
+
return {};
|
|
93742
|
+
}
|
|
93743
|
+
const multisigLock = {};
|
|
93744
|
+
switch ((0, import_bitcoin3.multisigAddressType)(multisig)) {
|
|
93745
|
+
case import_bitcoin3.P2SH:
|
|
93746
|
+
multisigLock.redeemScript = (0, import_bitcoin3.multisigRedeemScript)(multisig).output;
|
|
93747
|
+
break;
|
|
93748
|
+
case import_bitcoin3.P2WSH:
|
|
93749
|
+
multisigLock.witnessScript = (0, import_bitcoin3.multisigWitnessScript)(multisig).output;
|
|
93750
|
+
break;
|
|
93751
|
+
case import_bitcoin3.P2SH_P2WSH:
|
|
93752
|
+
multisigLock.witnessScript = (0, import_bitcoin3.multisigWitnessScript)(multisig).output;
|
|
93753
|
+
multisigLock.redeemScript = (0, import_bitcoin3.multisigRedeemScript)(multisig).output;
|
|
93754
|
+
break;
|
|
93755
|
+
}
|
|
93756
|
+
return multisigLock;
|
|
93757
|
+
}
|
|
93758
|
+
function getBip32Derivation(multisig, index = 0) {
|
|
93759
|
+
if (!multisig) {
|
|
93760
|
+
return;
|
|
93761
|
+
}
|
|
93762
|
+
if (multisig.bip32Derivation) {
|
|
93763
|
+
return multisig.bip32Derivation;
|
|
93764
|
+
}
|
|
93765
|
+
const config = JSON.parse((0, import_bitcoin3.multisigBraidDetails)(multisig));
|
|
93766
|
+
const braid = (0, import_bitcoin3.generateBraid)(
|
|
93767
|
+
config.network,
|
|
93768
|
+
config.addressType,
|
|
93769
|
+
config.extendedPublicKeys,
|
|
93770
|
+
config.requiredSigners,
|
|
93771
|
+
config.index
|
|
93772
|
+
);
|
|
93773
|
+
return (0, import_bitcoin3.generateBip32DerivationByIndex)(braid, index);
|
|
93774
|
+
}
|
|
93775
|
+
var convertLegacyInput = (input) => {
|
|
93776
|
+
return {
|
|
93777
|
+
hash: idToHash(input.txid),
|
|
93778
|
+
index: input.index,
|
|
93779
|
+
transactionHex: input.transactionHex,
|
|
93780
|
+
bip32Derivation: input.multisig.bip32Derivation || getBip32Derivation(input.multisig),
|
|
93781
|
+
...psbtMultisigLock(input.multisig),
|
|
93782
|
+
spendingWallet: getWalletConfigFromInput(input)
|
|
93783
|
+
};
|
|
93784
|
+
};
|
|
93785
|
+
var convertLegacyOutput = (output) => {
|
|
93786
|
+
return {
|
|
93787
|
+
address: output.address,
|
|
93788
|
+
value: new import_bignumber.default(output.amountSats).toNumber(),
|
|
93789
|
+
bip32Derivation: output.bip32Derivation || getBip32Derivation(output.multisig),
|
|
93790
|
+
witnessScript: output.witnessScript,
|
|
93791
|
+
redeemScript: output.redeemScript
|
|
93792
|
+
};
|
|
93793
|
+
};
|
|
93794
|
+
var getWalletConfigFromInput = (input) => {
|
|
93795
|
+
return braidDetailsToWalletConfig(JSON.parse(input.multisig.braidDetails));
|
|
93796
|
+
};
|
|
93797
|
+
function autoLoadPSBT(psbtFromFile, options) {
|
|
93798
|
+
let psbtBuff;
|
|
93799
|
+
try {
|
|
93800
|
+
psbtBuff = bufferize(psbtFromFile);
|
|
93801
|
+
} catch (e8) {
|
|
93802
|
+
return null;
|
|
93803
|
+
}
|
|
93804
|
+
try {
|
|
93805
|
+
const br = new import_bufio4.BufferReader(psbtBuff);
|
|
93806
|
+
if (!br.readBytes(PSBT_MAGIC_BYTES.length, true).equals(PSBT_MAGIC_BYTES)) {
|
|
93807
|
+
return null;
|
|
93808
|
+
}
|
|
93809
|
+
} catch (e8) {
|
|
93810
|
+
return null;
|
|
93811
|
+
}
|
|
93812
|
+
return import_bitcoinjs_lib_v62.Psbt.fromBuffer(psbtBuff, options);
|
|
93813
|
+
}
|
|
93814
|
+
|
|
93815
|
+
// src/psbtv0/psbt.ts
|
|
93707
93816
|
bitcoin.initEccLib(lib_exports);
|
|
93708
93817
|
var getUnsignedMultisigPsbtV0 = ({
|
|
93709
93818
|
network,
|
|
@@ -93711,7 +93820,7 @@ var getUnsignedMultisigPsbtV0 = ({
|
|
|
93711
93820
|
outputs,
|
|
93712
93821
|
includeGlobalXpubs = false
|
|
93713
93822
|
}) => {
|
|
93714
|
-
const psbt = new
|
|
93823
|
+
const psbt = new import_bitcoinjs_lib_v63.Psbt({ network: (0, import_bitcoin4.networkData)(network) });
|
|
93715
93824
|
psbt.setVersion(1);
|
|
93716
93825
|
for (const input of inputs) {
|
|
93717
93826
|
const inputData = psbtInputFormatter(
|
|
@@ -93730,9 +93839,9 @@ var getUnsignedMultisigPsbtV0 = ({
|
|
|
93730
93839
|
return psbt;
|
|
93731
93840
|
};
|
|
93732
93841
|
var psbtInputFormatter = (input, addressType) => {
|
|
93733
|
-
const tx =
|
|
93842
|
+
const tx = import_bitcoinjs_lib_v63.Transaction.fromHex(input.transactionHex);
|
|
93734
93843
|
const inputData = { ...input };
|
|
93735
|
-
if (addressType ===
|
|
93844
|
+
if (addressType === import_bitcoin4.P2SH) {
|
|
93736
93845
|
const nonWitnessUtxo = tx.toBuffer();
|
|
93737
93846
|
inputData.nonWitnessUtxo = nonWitnessUtxo;
|
|
93738
93847
|
} else {
|
|
@@ -93746,7 +93855,7 @@ var psbtInputFormatter = (input, addressType) => {
|
|
|
93746
93855
|
return inputData;
|
|
93747
93856
|
};
|
|
93748
93857
|
var psbtOutputFormatter = (output, network) => {
|
|
93749
|
-
const script = (0, import_address.toOutputScript)(output.address, (0,
|
|
93858
|
+
const script = (0, import_address.toOutputScript)(output.address, (0, import_bitcoin4.networkData)(network));
|
|
93750
93859
|
const outputData = {
|
|
93751
93860
|
...output,
|
|
93752
93861
|
script,
|
|
@@ -93767,7 +93876,7 @@ var addGlobalXpubs = (psbt, inputs, network) => {
|
|
|
93767
93876
|
if (!key.bip32Path) {
|
|
93768
93877
|
return;
|
|
93769
93878
|
}
|
|
93770
|
-
const extendedPublicKey =
|
|
93879
|
+
const extendedPublicKey = import_bitcoin4.ExtendedPublicKey.fromBase58(key.xpub);
|
|
93771
93880
|
extendedPublicKey.network = network;
|
|
93772
93881
|
extendedPublicKey.path = key.bip32Path;
|
|
93773
93882
|
extendedPublicKey.rootFingerprint = key.xfp;
|
|
@@ -93794,7 +93903,7 @@ var formatGlobalXpub = (extendedPublicKey) => {
|
|
|
93794
93903
|
);
|
|
93795
93904
|
} else if (extendedPublicKey.parentFingerprint) {
|
|
93796
93905
|
global2.masterFingerprint = import_buffer.Buffer.from(
|
|
93797
|
-
(0,
|
|
93906
|
+
(0, import_bitcoin4.fingerprintToFixedLengthHex)(extendedPublicKey.parentFingerprint),
|
|
93798
93907
|
"hex"
|
|
93799
93908
|
);
|
|
93800
93909
|
} else {
|
|
@@ -93804,24 +93913,24 @@ var formatGlobalXpub = (extendedPublicKey) => {
|
|
|
93804
93913
|
return global2;
|
|
93805
93914
|
};
|
|
93806
93915
|
var validateMultisigPsbtSignature = (raw, inputIndex, inputSignature, inputAmount) => {
|
|
93807
|
-
const psbt =
|
|
93916
|
+
const psbt = import_bitcoinjs_lib_v63.Psbt.fromBuffer(bufferize(raw));
|
|
93808
93917
|
if (psbt.inputCount === 0 || psbt.inputCount < inputIndex + 1) {
|
|
93809
93918
|
throw new Error("Input index is out of range.");
|
|
93810
93919
|
}
|
|
93811
|
-
const signatureBuffer = (0,
|
|
93812
|
-
(0,
|
|
93920
|
+
const signatureBuffer = (0, import_bitcoin4.multisigSignatureBuffer)(
|
|
93921
|
+
(0, import_bitcoin4.signatureNoSighashType)(inputSignature.toString("hex"))
|
|
93813
93922
|
);
|
|
93814
93923
|
const input = psbt.data.inputs[inputIndex];
|
|
93815
93924
|
const msgHash = getHashForSignature(psbt, inputIndex, inputAmount);
|
|
93816
93925
|
for (const { pubkey } of input.bip32Derivation ?? []) {
|
|
93817
|
-
if ((0,
|
|
93926
|
+
if ((0, import_bitcoin4.isValidSignature)(pubkey, msgHash, signatureBuffer)) {
|
|
93818
93927
|
return pubkey.toString("hex");
|
|
93819
93928
|
}
|
|
93820
93929
|
}
|
|
93821
93930
|
return false;
|
|
93822
93931
|
};
|
|
93823
|
-
var getHashForSignature = (psbt, inputIndex, inputAmount, sigHashFlag =
|
|
93824
|
-
const tx =
|
|
93932
|
+
var getHashForSignature = (psbt, inputIndex, inputAmount, sigHashFlag = import_bitcoinjs_lib_v63.Transaction.SIGHASH_ALL) => {
|
|
93933
|
+
const tx = import_bitcoinjs_lib_v63.Transaction.fromBuffer(psbt.data.globalMap.unsignedTx.toBuffer());
|
|
93825
93934
|
const input = psbt.data.inputs[inputIndex];
|
|
93826
93935
|
if (!input.witnessScript && input.redeemScript) {
|
|
93827
93936
|
return tx.hashForSignature(inputIndex, input.redeemScript, sigHashFlag);
|
|
@@ -93829,7 +93938,7 @@ var getHashForSignature = (psbt, inputIndex, inputAmount, sigHashFlag = import_b
|
|
|
93829
93938
|
if (!inputAmount) {
|
|
93830
93939
|
throw new Error("Input amount is required for segwit inputs.");
|
|
93831
93940
|
}
|
|
93832
|
-
const amountSats = new
|
|
93941
|
+
const amountSats = new import_bignumber2.default(inputAmount).toNumber();
|
|
93833
93942
|
return tx.hashForWitnessV0(
|
|
93834
93943
|
inputIndex,
|
|
93835
93944
|
input.witnessScript,
|
|
@@ -93839,91 +93948,67 @@ var getHashForSignature = (psbt, inputIndex, inputAmount, sigHashFlag = import_b
|
|
|
93839
93948
|
}
|
|
93840
93949
|
throw new Error("No redeem or witness script found for input.");
|
|
93841
93950
|
};
|
|
93842
|
-
|
|
93843
|
-
|
|
93844
|
-
|
|
93845
|
-
|
|
93846
|
-
|
|
93847
|
-
var braidDetailsToWalletConfig = (braidDetails) => {
|
|
93848
|
-
return {
|
|
93849
|
-
network: braidDetails.network,
|
|
93850
|
-
extendedPublicKeys: braidDetails.extendedPublicKeys.map((key) => ({
|
|
93851
|
-
xpub: key.base58String,
|
|
93852
|
-
bip32Path: key.path,
|
|
93853
|
-
xfp: key.rootFingerprint
|
|
93854
|
-
})),
|
|
93855
|
-
quorum: {
|
|
93856
|
-
requiredSigners: braidDetails.requiredSigners,
|
|
93857
|
-
totalSigners: braidDetails.extendedPublicKeys.length
|
|
93858
|
-
},
|
|
93859
|
-
name: `${braidDetails.requiredSigners}-of-${braidDetails.extendedPublicKeys.length} ${braidDetails.addressType} ${braidDetails.network} wallet`,
|
|
93860
|
-
addressType: braidDetails.addressType
|
|
93861
|
-
};
|
|
93862
|
-
};
|
|
93863
|
-
|
|
93864
|
-
// src/psbtv0/utils.ts
|
|
93865
|
-
var import_bignumber2 = __toESM(require("bignumber.js"));
|
|
93866
|
-
var idToHash = (txid) => {
|
|
93867
|
-
return import_buffer.Buffer.from(txid, "hex").reverse();
|
|
93868
|
-
};
|
|
93869
|
-
function psbtMultisigLock(multisig) {
|
|
93870
|
-
if (!multisig) {
|
|
93871
|
-
return {};
|
|
93872
|
-
}
|
|
93873
|
-
const multisigLock = {};
|
|
93874
|
-
switch ((0, import_bitcoin4.multisigAddressType)(multisig)) {
|
|
93875
|
-
case import_bitcoin4.P2SH:
|
|
93876
|
-
multisigLock.redeemScript = (0, import_bitcoin4.multisigRedeemScript)(multisig).output;
|
|
93877
|
-
break;
|
|
93878
|
-
case import_bitcoin4.P2WSH:
|
|
93879
|
-
multisigLock.witnessScript = (0, import_bitcoin4.multisigWitnessScript)(multisig).output;
|
|
93880
|
-
break;
|
|
93881
|
-
case import_bitcoin4.P2SH_P2WSH:
|
|
93882
|
-
multisigLock.witnessScript = (0, import_bitcoin4.multisigWitnessScript)(multisig).output;
|
|
93883
|
-
multisigLock.redeemScript = (0, import_bitcoin4.multisigRedeemScript)(multisig).output;
|
|
93884
|
-
break;
|
|
93885
|
-
}
|
|
93886
|
-
return multisigLock;
|
|
93887
|
-
}
|
|
93888
|
-
function getBip32Derivation(multisig, index = 0) {
|
|
93889
|
-
if (!multisig) {
|
|
93890
|
-
return;
|
|
93891
|
-
}
|
|
93892
|
-
if (multisig.bip32Derivation) {
|
|
93893
|
-
return multisig.bip32Derivation;
|
|
93951
|
+
function translatePSBT(network, addressType, psbt, signingKeyDetails) {
|
|
93952
|
+
if (addressType !== import_bitcoin4.P2SH) {
|
|
93953
|
+
throw new Error(
|
|
93954
|
+
"Unsupported addressType -- only P2SH is supported right now"
|
|
93955
|
+
);
|
|
93894
93956
|
}
|
|
93895
|
-
const
|
|
93896
|
-
|
|
93897
|
-
|
|
93898
|
-
|
|
93899
|
-
|
|
93900
|
-
|
|
93901
|
-
config.index
|
|
93957
|
+
const localPSBT = autoLoadPSBT(psbt, { network: (0, import_bitcoin4.networkData)(network) });
|
|
93958
|
+
if (localPSBT === null)
|
|
93959
|
+
return null;
|
|
93960
|
+
const bip32Derivations = filterRelevantBip32Derivations(
|
|
93961
|
+
localPSBT,
|
|
93962
|
+
signingKeyDetails
|
|
93902
93963
|
);
|
|
93903
|
-
|
|
93904
|
-
|
|
93905
|
-
|
|
93906
|
-
|
|
93907
|
-
|
|
93908
|
-
|
|
93909
|
-
transactionHex: input.transactionHex,
|
|
93910
|
-
bip32Derivation: input.multisig.bip32Derivation || getBip32Derivation(input.multisig),
|
|
93911
|
-
...psbtMultisigLock(input.multisig),
|
|
93912
|
-
spendingWallet: getWalletConfigFromInput(input)
|
|
93913
|
-
};
|
|
93914
|
-
};
|
|
93915
|
-
var convertLegacyOutput = (output) => {
|
|
93964
|
+
const unchainedInputs = getUnchainedInputsFromPSBT(
|
|
93965
|
+
network,
|
|
93966
|
+
addressType,
|
|
93967
|
+
localPSBT
|
|
93968
|
+
);
|
|
93969
|
+
const unchainedOutputs = getUnchainedOutputsFromPSBT(localPSBT);
|
|
93916
93970
|
return {
|
|
93971
|
+
unchainedInputs,
|
|
93972
|
+
unchainedOutputs,
|
|
93973
|
+
bip32Derivations
|
|
93974
|
+
};
|
|
93975
|
+
}
|
|
93976
|
+
function getUnchainedInputsFromPSBT(network, addressType, psbt) {
|
|
93977
|
+
return psbt.txInputs.map((input, index) => {
|
|
93978
|
+
const dataInput = psbt.data.inputs[index];
|
|
93979
|
+
const fundingTxHex = dataInput.nonWitnessUtxo.toString("hex");
|
|
93980
|
+
const fundingTx = import_bitcoinjs_lib_v63.Transaction.fromHex(fundingTxHex);
|
|
93981
|
+
const multisig = (0, import_bitcoin4.generateMultisigFromHex)(
|
|
93982
|
+
network,
|
|
93983
|
+
addressType,
|
|
93984
|
+
dataInput.redeemScript.toString("hex")
|
|
93985
|
+
);
|
|
93986
|
+
return {
|
|
93987
|
+
amountSats: fundingTx.outs[input.index].value,
|
|
93988
|
+
index: input.index,
|
|
93989
|
+
transactionHex: fundingTxHex,
|
|
93990
|
+
txid: (0, import_bufferutils.reverseBuffer)(input.hash).toString("hex"),
|
|
93991
|
+
multisig
|
|
93992
|
+
};
|
|
93993
|
+
});
|
|
93994
|
+
}
|
|
93995
|
+
function getUnchainedOutputsFromPSBT(psbt) {
|
|
93996
|
+
return psbt.txOutputs.map((output) => ({
|
|
93917
93997
|
address: output.address,
|
|
93918
|
-
|
|
93919
|
-
|
|
93920
|
-
|
|
93921
|
-
|
|
93922
|
-
|
|
93923
|
-
|
|
93924
|
-
|
|
93925
|
-
|
|
93926
|
-
|
|
93998
|
+
amountSats: output.value
|
|
93999
|
+
}));
|
|
94000
|
+
}
|
|
94001
|
+
function filterRelevantBip32Derivations(psbt, signingKeyDetails) {
|
|
94002
|
+
return psbt.data.inputs.map((input) => {
|
|
94003
|
+
const bip32Derivation = input.bip32Derivation.filter(
|
|
94004
|
+
(b32d) => b32d.path.startsWith(signingKeyDetails.path) && b32d.masterFingerprint.toString("hex") === signingKeyDetails.xfp
|
|
94005
|
+
);
|
|
94006
|
+
if (!bip32Derivation.length) {
|
|
94007
|
+
throw new Error("Signing key details not included in PSBT");
|
|
94008
|
+
}
|
|
94009
|
+
return bip32Derivation[0];
|
|
94010
|
+
});
|
|
94011
|
+
}
|
|
93927
94012
|
// Annotate the CommonJS export names for ESM import in node:
|
|
93928
94013
|
0 && (module.exports = {
|
|
93929
94014
|
PSBT_MAGIC_B64,
|
|
@@ -93931,10 +94016,12 @@ var getWalletConfigFromInput = (input) => {
|
|
|
93931
94016
|
PSBT_MAGIC_HEX,
|
|
93932
94017
|
PsbtV2,
|
|
93933
94018
|
addGlobalXpubs,
|
|
94019
|
+
autoLoadPSBT,
|
|
93934
94020
|
convertLegacyInput,
|
|
93935
94021
|
convertLegacyOutput,
|
|
93936
94022
|
getPsbtVersionNumber,
|
|
93937
94023
|
getUnsignedMultisigPsbtV0,
|
|
94024
|
+
translatePSBT,
|
|
93938
94025
|
validateMultisigPsbtSignature
|
|
93939
94026
|
});
|
|
93940
94027
|
/*! Bundled license information:
|
package/dist/index.mjs
CHANGED
|
@@ -1161,14 +1161,15 @@ var PsbtV2 = class _PsbtV2 extends PsbtV2Maps {
|
|
|
1161
1161
|
import {
|
|
1162
1162
|
ExtendedPublicKey,
|
|
1163
1163
|
fingerprintToFixedLengthHex,
|
|
1164
|
+
generateMultisigFromHex,
|
|
1164
1165
|
isValidSignature,
|
|
1165
1166
|
multisigSignatureBuffer,
|
|
1166
1167
|
networkData,
|
|
1167
|
-
P2SH,
|
|
1168
|
+
P2SH as P2SH2,
|
|
1168
1169
|
signatureNoSighashType
|
|
1169
1170
|
} from "@caravan/bitcoin";
|
|
1170
|
-
import { Psbt as
|
|
1171
|
-
import { toOutputScript } from "bitcoinjs-lib-v6/src/address";
|
|
1171
|
+
import { Psbt as Psbt3, Transaction } from "bitcoinjs-lib-v6";
|
|
1172
|
+
import { toOutputScript } from "bitcoinjs-lib-v6/src/address.js";
|
|
1172
1173
|
|
|
1173
1174
|
// vendor/tiny-secp256k1-asmjs/lib/index.js
|
|
1174
1175
|
var lib_exports = {};
|
|
@@ -93672,7 +93673,124 @@ function verifySchnorr2(h6, Q3, signature) {
|
|
|
93672
93673
|
|
|
93673
93674
|
// src/psbtv0/psbt.ts
|
|
93674
93675
|
import * as bitcoin from "bitcoinjs-lib-v6";
|
|
93676
|
+
import BigNumber2 from "bignumber.js";
|
|
93677
|
+
import { reverseBuffer } from "bitcoinjs-lib-v6/src/bufferutils.js";
|
|
93678
|
+
|
|
93679
|
+
// src/psbtv0/utils.ts
|
|
93680
|
+
import {
|
|
93681
|
+
generateBip32DerivationByIndex,
|
|
93682
|
+
generateBraid,
|
|
93683
|
+
multisigAddressType,
|
|
93684
|
+
multisigBraidDetails,
|
|
93685
|
+
multisigRedeemScript,
|
|
93686
|
+
multisigWitnessScript,
|
|
93687
|
+
P2SH,
|
|
93688
|
+
P2SH_P2WSH,
|
|
93689
|
+
P2WSH
|
|
93690
|
+
} from "@caravan/bitcoin";
|
|
93691
|
+
|
|
93692
|
+
// ../multisig/dist/index.mjs
|
|
93693
|
+
var braidDetailsToWalletConfig = (braidDetails) => {
|
|
93694
|
+
return {
|
|
93695
|
+
network: braidDetails.network,
|
|
93696
|
+
extendedPublicKeys: braidDetails.extendedPublicKeys.map((key) => ({
|
|
93697
|
+
xpub: key.base58String,
|
|
93698
|
+
bip32Path: key.path,
|
|
93699
|
+
xfp: key.rootFingerprint
|
|
93700
|
+
})),
|
|
93701
|
+
quorum: {
|
|
93702
|
+
requiredSigners: braidDetails.requiredSigners,
|
|
93703
|
+
totalSigners: braidDetails.extendedPublicKeys.length
|
|
93704
|
+
},
|
|
93705
|
+
name: `${braidDetails.requiredSigners}-of-${braidDetails.extendedPublicKeys.length} ${braidDetails.addressType} ${braidDetails.network} wallet`,
|
|
93706
|
+
addressType: braidDetails.addressType
|
|
93707
|
+
};
|
|
93708
|
+
};
|
|
93709
|
+
|
|
93710
|
+
// src/psbtv0/utils.ts
|
|
93675
93711
|
import BigNumber from "bignumber.js";
|
|
93712
|
+
import { Psbt as Psbt2 } from "bitcoinjs-lib-v6";
|
|
93713
|
+
import { BufferReader as BufferReader4 } from "bufio";
|
|
93714
|
+
var idToHash = (txid) => {
|
|
93715
|
+
return Buffer2.from(txid, "hex").reverse();
|
|
93716
|
+
};
|
|
93717
|
+
function psbtMultisigLock(multisig) {
|
|
93718
|
+
if (!multisig) {
|
|
93719
|
+
return {};
|
|
93720
|
+
}
|
|
93721
|
+
const multisigLock = {};
|
|
93722
|
+
switch (multisigAddressType(multisig)) {
|
|
93723
|
+
case P2SH:
|
|
93724
|
+
multisigLock.redeemScript = multisigRedeemScript(multisig).output;
|
|
93725
|
+
break;
|
|
93726
|
+
case P2WSH:
|
|
93727
|
+
multisigLock.witnessScript = multisigWitnessScript(multisig).output;
|
|
93728
|
+
break;
|
|
93729
|
+
case P2SH_P2WSH:
|
|
93730
|
+
multisigLock.witnessScript = multisigWitnessScript(multisig).output;
|
|
93731
|
+
multisigLock.redeemScript = multisigRedeemScript(multisig).output;
|
|
93732
|
+
break;
|
|
93733
|
+
}
|
|
93734
|
+
return multisigLock;
|
|
93735
|
+
}
|
|
93736
|
+
function getBip32Derivation(multisig, index = 0) {
|
|
93737
|
+
if (!multisig) {
|
|
93738
|
+
return;
|
|
93739
|
+
}
|
|
93740
|
+
if (multisig.bip32Derivation) {
|
|
93741
|
+
return multisig.bip32Derivation;
|
|
93742
|
+
}
|
|
93743
|
+
const config = JSON.parse(multisigBraidDetails(multisig));
|
|
93744
|
+
const braid = generateBraid(
|
|
93745
|
+
config.network,
|
|
93746
|
+
config.addressType,
|
|
93747
|
+
config.extendedPublicKeys,
|
|
93748
|
+
config.requiredSigners,
|
|
93749
|
+
config.index
|
|
93750
|
+
);
|
|
93751
|
+
return generateBip32DerivationByIndex(braid, index);
|
|
93752
|
+
}
|
|
93753
|
+
var convertLegacyInput = (input) => {
|
|
93754
|
+
return {
|
|
93755
|
+
hash: idToHash(input.txid),
|
|
93756
|
+
index: input.index,
|
|
93757
|
+
transactionHex: input.transactionHex,
|
|
93758
|
+
bip32Derivation: input.multisig.bip32Derivation || getBip32Derivation(input.multisig),
|
|
93759
|
+
...psbtMultisigLock(input.multisig),
|
|
93760
|
+
spendingWallet: getWalletConfigFromInput(input)
|
|
93761
|
+
};
|
|
93762
|
+
};
|
|
93763
|
+
var convertLegacyOutput = (output) => {
|
|
93764
|
+
return {
|
|
93765
|
+
address: output.address,
|
|
93766
|
+
value: new BigNumber(output.amountSats).toNumber(),
|
|
93767
|
+
bip32Derivation: output.bip32Derivation || getBip32Derivation(output.multisig),
|
|
93768
|
+
witnessScript: output.witnessScript,
|
|
93769
|
+
redeemScript: output.redeemScript
|
|
93770
|
+
};
|
|
93771
|
+
};
|
|
93772
|
+
var getWalletConfigFromInput = (input) => {
|
|
93773
|
+
return braidDetailsToWalletConfig(JSON.parse(input.multisig.braidDetails));
|
|
93774
|
+
};
|
|
93775
|
+
function autoLoadPSBT(psbtFromFile, options) {
|
|
93776
|
+
let psbtBuff;
|
|
93777
|
+
try {
|
|
93778
|
+
psbtBuff = bufferize(psbtFromFile);
|
|
93779
|
+
} catch (e8) {
|
|
93780
|
+
return null;
|
|
93781
|
+
}
|
|
93782
|
+
try {
|
|
93783
|
+
const br = new BufferReader4(psbtBuff);
|
|
93784
|
+
if (!br.readBytes(PSBT_MAGIC_BYTES.length, true).equals(PSBT_MAGIC_BYTES)) {
|
|
93785
|
+
return null;
|
|
93786
|
+
}
|
|
93787
|
+
} catch (e8) {
|
|
93788
|
+
return null;
|
|
93789
|
+
}
|
|
93790
|
+
return Psbt2.fromBuffer(psbtBuff, options);
|
|
93791
|
+
}
|
|
93792
|
+
|
|
93793
|
+
// src/psbtv0/psbt.ts
|
|
93676
93794
|
bitcoin.initEccLib(lib_exports);
|
|
93677
93795
|
var getUnsignedMultisigPsbtV0 = ({
|
|
93678
93796
|
network,
|
|
@@ -93680,7 +93798,7 @@ var getUnsignedMultisigPsbtV0 = ({
|
|
|
93680
93798
|
outputs,
|
|
93681
93799
|
includeGlobalXpubs = false
|
|
93682
93800
|
}) => {
|
|
93683
|
-
const psbt = new
|
|
93801
|
+
const psbt = new Psbt3({ network: networkData(network) });
|
|
93684
93802
|
psbt.setVersion(1);
|
|
93685
93803
|
for (const input of inputs) {
|
|
93686
93804
|
const inputData = psbtInputFormatter(
|
|
@@ -93701,7 +93819,7 @@ var getUnsignedMultisigPsbtV0 = ({
|
|
|
93701
93819
|
var psbtInputFormatter = (input, addressType) => {
|
|
93702
93820
|
const tx = Transaction.fromHex(input.transactionHex);
|
|
93703
93821
|
const inputData = { ...input };
|
|
93704
|
-
if (addressType ===
|
|
93822
|
+
if (addressType === P2SH2) {
|
|
93705
93823
|
const nonWitnessUtxo = tx.toBuffer();
|
|
93706
93824
|
inputData.nonWitnessUtxo = nonWitnessUtxo;
|
|
93707
93825
|
} else {
|
|
@@ -93773,7 +93891,7 @@ var formatGlobalXpub = (extendedPublicKey) => {
|
|
|
93773
93891
|
return global2;
|
|
93774
93892
|
};
|
|
93775
93893
|
var validateMultisigPsbtSignature = (raw, inputIndex, inputSignature, inputAmount) => {
|
|
93776
|
-
const psbt =
|
|
93894
|
+
const psbt = Psbt3.fromBuffer(bufferize(raw));
|
|
93777
93895
|
if (psbt.inputCount === 0 || psbt.inputCount < inputIndex + 1) {
|
|
93778
93896
|
throw new Error("Input index is out of range.");
|
|
93779
93897
|
}
|
|
@@ -93798,7 +93916,7 @@ var getHashForSignature = (psbt, inputIndex, inputAmount, sigHashFlag = Transact
|
|
|
93798
93916
|
if (!inputAmount) {
|
|
93799
93917
|
throw new Error("Input amount is required for segwit inputs.");
|
|
93800
93918
|
}
|
|
93801
|
-
const amountSats = new
|
|
93919
|
+
const amountSats = new BigNumber2(inputAmount).toNumber();
|
|
93802
93920
|
return tx.hashForWitnessV0(
|
|
93803
93921
|
inputIndex,
|
|
93804
93922
|
input.witnessScript,
|
|
@@ -93808,111 +93926,79 @@ var getHashForSignature = (psbt, inputIndex, inputAmount, sigHashFlag = Transact
|
|
|
93808
93926
|
}
|
|
93809
93927
|
throw new Error("No redeem or witness script found for input.");
|
|
93810
93928
|
};
|
|
93811
|
-
|
|
93812
|
-
|
|
93813
|
-
|
|
93814
|
-
|
|
93815
|
-
|
|
93816
|
-
multisigAddressType,
|
|
93817
|
-
multisigBraidDetails,
|
|
93818
|
-
multisigRedeemScript,
|
|
93819
|
-
multisigWitnessScript,
|
|
93820
|
-
P2SH as P2SH2,
|
|
93821
|
-
P2SH_P2WSH,
|
|
93822
|
-
P2WSH
|
|
93823
|
-
} from "@caravan/bitcoin";
|
|
93824
|
-
|
|
93825
|
-
// ../multisig/dist/index.mjs
|
|
93826
|
-
var braidDetailsToWalletConfig = (braidDetails) => {
|
|
93827
|
-
return {
|
|
93828
|
-
network: braidDetails.network,
|
|
93829
|
-
extendedPublicKeys: braidDetails.extendedPublicKeys.map((key) => ({
|
|
93830
|
-
xpub: key.base58String,
|
|
93831
|
-
bip32Path: key.path,
|
|
93832
|
-
xfp: key.rootFingerprint
|
|
93833
|
-
})),
|
|
93834
|
-
quorum: {
|
|
93835
|
-
requiredSigners: braidDetails.requiredSigners,
|
|
93836
|
-
totalSigners: braidDetails.extendedPublicKeys.length
|
|
93837
|
-
},
|
|
93838
|
-
name: `${braidDetails.requiredSigners}-of-${braidDetails.extendedPublicKeys.length} ${braidDetails.addressType} ${braidDetails.network} wallet`,
|
|
93839
|
-
addressType: braidDetails.addressType
|
|
93840
|
-
};
|
|
93841
|
-
};
|
|
93842
|
-
|
|
93843
|
-
// src/psbtv0/utils.ts
|
|
93844
|
-
import BigNumber2 from "bignumber.js";
|
|
93845
|
-
var idToHash = (txid) => {
|
|
93846
|
-
return Buffer2.from(txid, "hex").reverse();
|
|
93847
|
-
};
|
|
93848
|
-
function psbtMultisigLock(multisig) {
|
|
93849
|
-
if (!multisig) {
|
|
93850
|
-
return {};
|
|
93851
|
-
}
|
|
93852
|
-
const multisigLock = {};
|
|
93853
|
-
switch (multisigAddressType(multisig)) {
|
|
93854
|
-
case P2SH2:
|
|
93855
|
-
multisigLock.redeemScript = multisigRedeemScript(multisig).output;
|
|
93856
|
-
break;
|
|
93857
|
-
case P2WSH:
|
|
93858
|
-
multisigLock.witnessScript = multisigWitnessScript(multisig).output;
|
|
93859
|
-
break;
|
|
93860
|
-
case P2SH_P2WSH:
|
|
93861
|
-
multisigLock.witnessScript = multisigWitnessScript(multisig).output;
|
|
93862
|
-
multisigLock.redeemScript = multisigRedeemScript(multisig).output;
|
|
93863
|
-
break;
|
|
93864
|
-
}
|
|
93865
|
-
return multisigLock;
|
|
93866
|
-
}
|
|
93867
|
-
function getBip32Derivation(multisig, index = 0) {
|
|
93868
|
-
if (!multisig) {
|
|
93869
|
-
return;
|
|
93870
|
-
}
|
|
93871
|
-
if (multisig.bip32Derivation) {
|
|
93872
|
-
return multisig.bip32Derivation;
|
|
93929
|
+
function translatePSBT(network, addressType, psbt, signingKeyDetails) {
|
|
93930
|
+
if (addressType !== P2SH2) {
|
|
93931
|
+
throw new Error(
|
|
93932
|
+
"Unsupported addressType -- only P2SH is supported right now"
|
|
93933
|
+
);
|
|
93873
93934
|
}
|
|
93874
|
-
const
|
|
93875
|
-
|
|
93876
|
-
|
|
93877
|
-
|
|
93878
|
-
|
|
93879
|
-
|
|
93880
|
-
config.index
|
|
93935
|
+
const localPSBT = autoLoadPSBT(psbt, { network: networkData(network) });
|
|
93936
|
+
if (localPSBT === null)
|
|
93937
|
+
return null;
|
|
93938
|
+
const bip32Derivations = filterRelevantBip32Derivations(
|
|
93939
|
+
localPSBT,
|
|
93940
|
+
signingKeyDetails
|
|
93881
93941
|
);
|
|
93882
|
-
|
|
93883
|
-
|
|
93884
|
-
|
|
93885
|
-
|
|
93886
|
-
|
|
93887
|
-
|
|
93888
|
-
transactionHex: input.transactionHex,
|
|
93889
|
-
bip32Derivation: input.multisig.bip32Derivation || getBip32Derivation(input.multisig),
|
|
93890
|
-
...psbtMultisigLock(input.multisig),
|
|
93891
|
-
spendingWallet: getWalletConfigFromInput(input)
|
|
93892
|
-
};
|
|
93893
|
-
};
|
|
93894
|
-
var convertLegacyOutput = (output) => {
|
|
93942
|
+
const unchainedInputs = getUnchainedInputsFromPSBT(
|
|
93943
|
+
network,
|
|
93944
|
+
addressType,
|
|
93945
|
+
localPSBT
|
|
93946
|
+
);
|
|
93947
|
+
const unchainedOutputs = getUnchainedOutputsFromPSBT(localPSBT);
|
|
93895
93948
|
return {
|
|
93949
|
+
unchainedInputs,
|
|
93950
|
+
unchainedOutputs,
|
|
93951
|
+
bip32Derivations
|
|
93952
|
+
};
|
|
93953
|
+
}
|
|
93954
|
+
function getUnchainedInputsFromPSBT(network, addressType, psbt) {
|
|
93955
|
+
return psbt.txInputs.map((input, index) => {
|
|
93956
|
+
const dataInput = psbt.data.inputs[index];
|
|
93957
|
+
const fundingTxHex = dataInput.nonWitnessUtxo.toString("hex");
|
|
93958
|
+
const fundingTx = Transaction.fromHex(fundingTxHex);
|
|
93959
|
+
const multisig = generateMultisigFromHex(
|
|
93960
|
+
network,
|
|
93961
|
+
addressType,
|
|
93962
|
+
dataInput.redeemScript.toString("hex")
|
|
93963
|
+
);
|
|
93964
|
+
return {
|
|
93965
|
+
amountSats: fundingTx.outs[input.index].value,
|
|
93966
|
+
index: input.index,
|
|
93967
|
+
transactionHex: fundingTxHex,
|
|
93968
|
+
txid: reverseBuffer(input.hash).toString("hex"),
|
|
93969
|
+
multisig
|
|
93970
|
+
};
|
|
93971
|
+
});
|
|
93972
|
+
}
|
|
93973
|
+
function getUnchainedOutputsFromPSBT(psbt) {
|
|
93974
|
+
return psbt.txOutputs.map((output) => ({
|
|
93896
93975
|
address: output.address,
|
|
93897
|
-
|
|
93898
|
-
|
|
93899
|
-
|
|
93900
|
-
|
|
93901
|
-
|
|
93902
|
-
|
|
93903
|
-
|
|
93904
|
-
|
|
93905
|
-
|
|
93976
|
+
amountSats: output.value
|
|
93977
|
+
}));
|
|
93978
|
+
}
|
|
93979
|
+
function filterRelevantBip32Derivations(psbt, signingKeyDetails) {
|
|
93980
|
+
return psbt.data.inputs.map((input) => {
|
|
93981
|
+
const bip32Derivation = input.bip32Derivation.filter(
|
|
93982
|
+
(b32d) => b32d.path.startsWith(signingKeyDetails.path) && b32d.masterFingerprint.toString("hex") === signingKeyDetails.xfp
|
|
93983
|
+
);
|
|
93984
|
+
if (!bip32Derivation.length) {
|
|
93985
|
+
throw new Error("Signing key details not included in PSBT");
|
|
93986
|
+
}
|
|
93987
|
+
return bip32Derivation[0];
|
|
93988
|
+
});
|
|
93989
|
+
}
|
|
93906
93990
|
export {
|
|
93907
93991
|
PSBT_MAGIC_B64,
|
|
93908
93992
|
PSBT_MAGIC_BYTES,
|
|
93909
93993
|
PSBT_MAGIC_HEX,
|
|
93910
93994
|
PsbtV2,
|
|
93911
93995
|
addGlobalXpubs,
|
|
93996
|
+
autoLoadPSBT,
|
|
93912
93997
|
convertLegacyInput,
|
|
93913
93998
|
convertLegacyOutput,
|
|
93914
93999
|
getPsbtVersionNumber,
|
|
93915
94000
|
getUnsignedMultisigPsbtV0,
|
|
94001
|
+
translatePSBT,
|
|
93916
94002
|
validateMultisigPsbtSignature
|
|
93917
94003
|
};
|
|
93918
94004
|
/*! Bundled license information:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@caravan/psbt",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "typescript library for working with PSBTs",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
"author": "unchained capital",
|
|
52
52
|
"license": "ISC",
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@caravan/multisig": "*",
|
|
55
54
|
"@caravan/eslint-config": "*",
|
|
55
|
+
"@caravan/multisig": "*",
|
|
56
56
|
"@caravan/typescript-config": "*",
|
|
57
57
|
"@inrupt/jest-jsdom-polyfills": "^3.2.1",
|
|
58
58
|
"@jest/globals": "^29.7.0",
|
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
"jest": "^29.4.1",
|
|
62
62
|
"jsdom": "24.0.0",
|
|
63
63
|
"jsdom-global": "3.0.2",
|
|
64
|
+
"lodash": "^4.17.21",
|
|
64
65
|
"react-silence": "^1.0.4",
|
|
65
66
|
"ts-jest": "^29.1.2",
|
|
66
67
|
"ts-node": "^10.9.2",
|