@bitcoinerlab/descriptors 2.3.6 → 3.0.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.
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ // Copyright (c) 2026 Jose-Luis Landabaso
3
+ // Distributed under the MIT software license
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.MAX_STANDARD_P2WSH_SCRIPT_SIZE = exports.MAX_SCRIPT_ELEMENT_SIZE = void 0;
6
+ exports.assertScriptNonPushOnlyOpsLimit = assertScriptNonPushOnlyOpsLimit;
7
+ exports.assertConsensusStackResourceLimits = assertConsensusStackResourceLimits;
8
+ exports.assertWitnessV0SatisfactionResourceLimits = assertWitnessV0SatisfactionResourceLimits;
9
+ exports.assertTaprootScriptPathSatisfactionResourceLimits = assertTaprootScriptPathSatisfactionResourceLimits;
10
+ exports.assertP2shScriptSigStandardSize = assertP2shScriptSigStandardSize;
11
+ const bitcoinjs_lib_1 = require("bitcoinjs-lib");
12
+ const { p2sh } = bitcoinjs_lib_1.payments;
13
+ // See Sipa's Miniscript "Resource limitations":
14
+ // https://bitcoin.sipa.be/miniscript/
15
+ // and Bitcoin Core policy/consensus constants.
16
+ //https://github.com/bitcoin/bitcoin/blob/master/src/policy/policy.h
17
+ // Consensus: max number of elements in initial stack (and stack+altstack after
18
+ // each opcode execution).
19
+ const MAX_STACK_SIZE = 1000;
20
+ // Consensus: max size for any stack element is 520 bytes.
21
+ // This is a per-element limit, not a full script-size limit.
22
+ // In legacy P2SH, redeemScript is pushed as a stack element,
23
+ // ( this is why we typically say that the redeemScript cannot be larger than 520 ).
24
+ // But the same per-element rule applies to other stack items as well.
25
+ exports.MAX_SCRIPT_ELEMENT_SIZE = 520;
26
+ // Standardness policy limits.
27
+ // See Sipa's Miniscript "Resource limitations":
28
+ // https://bitcoin.sipa.be/miniscript/
29
+ // and Bitcoin Core policy/consensus constants.
30
+ //https://github.com/bitcoin/bitcoin/blob/master/src/policy/policy.h
31
+ exports.MAX_STANDARD_P2WSH_SCRIPT_SIZE = 3600;
32
+ const MAX_STANDARD_P2WSH_STACK_ITEMS = 100;
33
+ const MAX_OPS_PER_SCRIPT = 201;
34
+ const MAX_STANDARD_SCRIPTSIG_SIZE = 1650;
35
+ const MAX_STANDARD_P2WSH_STACK_ITEM_SIZE = 80;
36
+ const MAX_STANDARD_TAPSCRIPT_STACK_ITEM_SIZE = 80;
37
+ function countNonPushOnlyOPs(script) {
38
+ const chunks = bitcoinjs_lib_1.script.decompile(script);
39
+ if (!chunks)
40
+ throw new Error(`Error: could not decompile ${script}`);
41
+ return bitcoinjs_lib_1.script.countNonPushOnlyOPs(chunks);
42
+ }
43
+ function assertScriptNonPushOnlyOpsLimit({ script }) {
44
+ const nonPushOnlyOps = countNonPushOnlyOPs(script);
45
+ if (nonPushOnlyOps > MAX_OPS_PER_SCRIPT)
46
+ throw new Error(`Error: too many non-push ops, ${nonPushOnlyOps} non-push ops is larger than ${MAX_OPS_PER_SCRIPT}`);
47
+ }
48
+ /**
49
+ * Enforces consensus stack resource limits.
50
+ */
51
+ function assertConsensusStackResourceLimits({ stackItems, stackLabel = 'stack', stackItemLabel = 'stack item' }) {
52
+ if (stackItems.length > MAX_STACK_SIZE)
53
+ throw new Error(`Error: ${stackLabel} has too many items, ${stackItems.length} is larger than ${MAX_STACK_SIZE}`);
54
+ for (const stackItem of stackItems) {
55
+ if (stackItem.length > exports.MAX_SCRIPT_ELEMENT_SIZE)
56
+ throw new Error(`Error: ${stackItemLabel} is too large, ${stackItem.length} bytes is larger than ${exports.MAX_SCRIPT_ELEMENT_SIZE} bytes`);
57
+ }
58
+ }
59
+ function assertWitnessV0SatisfactionResourceLimits({ stackItems }) {
60
+ assertConsensusStackResourceLimits({ stackItems });
61
+ if (stackItems.length > MAX_STANDARD_P2WSH_STACK_ITEMS)
62
+ throw new Error(`Error: witness stack has too many items, ${stackItems.length} is larger than ${MAX_STANDARD_P2WSH_STACK_ITEMS}`);
63
+ for (const stackItem of stackItems) {
64
+ if (stackItem.length > MAX_STANDARD_P2WSH_STACK_ITEM_SIZE)
65
+ throw new Error(`Error: witness stack item exceeds standard policy, ${stackItem.length} bytes is larger than ${MAX_STANDARD_P2WSH_STACK_ITEM_SIZE} bytes`);
66
+ }
67
+ }
68
+ function assertTaprootScriptPathSatisfactionResourceLimits({ stackItems }) {
69
+ assertConsensusStackResourceLimits({
70
+ stackItems,
71
+ stackLabel: 'taproot script-path stack',
72
+ stackItemLabel: 'taproot script-path stack item'
73
+ });
74
+ // Standardness policy for tapscript (leaf version 0xc0): <= 80 bytes.
75
+ for (const stackItem of stackItems) {
76
+ if (stackItem.length > MAX_STANDARD_TAPSCRIPT_STACK_ITEM_SIZE)
77
+ throw new Error(`Error: taproot script-path stack item exceeds standard policy, ${stackItem.length} bytes is larger than ${MAX_STANDARD_TAPSCRIPT_STACK_ITEM_SIZE} bytes`);
78
+ }
79
+ }
80
+ function assertP2shScriptSigStandardSize({ scriptSatisfaction, redeemScript, network }) {
81
+ const scriptSig = p2sh({
82
+ redeem: { input: scriptSatisfaction, output: redeemScript, network },
83
+ network
84
+ }).input;
85
+ if (!scriptSig)
86
+ throw new Error(`Error: could not build scriptSig from satisfaction`);
87
+ if (scriptSig.length > MAX_STANDARD_SCRIPTSIG_SIZE)
88
+ throw new Error(`Error: scriptSig is too large, ${scriptSig.length} bytes is larger than ${MAX_STANDARD_SCRIPTSIG_SIZE} bytes`);
89
+ }
@@ -1,5 +1,5 @@
1
1
  import { Network } from 'bitcoinjs-lib';
2
- import type { LedgerState, LedgerManager } from './ledger';
2
+ import type { LedgerManager } from './ledger';
3
3
  import type { BIP32Interface } from 'bip32';
4
4
  /** @function */
5
5
  export declare const pkhBIP32: ({ masterNode, network, keyPath, account, change, index, isPublic }: {
@@ -62,82 +62,34 @@ export declare const trBIP32: ({ masterNode, network, keyPath, account, change,
62
62
  isPublic?: boolean;
63
63
  }) => string;
64
64
  /** @function */
65
- export declare const pkhLedger: {
66
- ({ ledgerManager, account, keyPath, change, index }: {
67
- ledgerManager: LedgerManager;
68
- account: number;
69
- keyPath?: string;
70
- change?: number | undefined;
71
- index?: number | undefined | "*";
72
- }): Promise<string>;
73
- ({ ledgerClient, ledgerState, network, account, keyPath, change, index }: {
74
- ledgerClient: unknown;
75
- ledgerState: LedgerState;
76
- /** @default networks.bitcoin */
77
- network?: Network;
78
- account: number;
79
- keyPath?: string;
80
- change?: number | undefined;
81
- index?: number | undefined | "*";
82
- }): Promise<string>;
83
- };
65
+ export declare const pkhLedger: ({ ledgerManager, account, keyPath, change, index }: {
66
+ ledgerManager: LedgerManager;
67
+ account: number;
68
+ keyPath?: string;
69
+ change?: number | undefined;
70
+ index?: number | undefined | "*";
71
+ }) => Promise<string>;
84
72
  /** @function */
85
- export declare const shWpkhLedger: {
86
- ({ ledgerManager, account, keyPath, change, index }: {
87
- ledgerManager: LedgerManager;
88
- account: number;
89
- keyPath?: string;
90
- change?: number | undefined;
91
- index?: number | undefined | "*";
92
- }): Promise<string>;
93
- ({ ledgerClient, ledgerState, network, account, keyPath, change, index }: {
94
- ledgerClient: unknown;
95
- ledgerState: LedgerState;
96
- /** @default networks.bitcoin */
97
- network?: Network;
98
- account: number;
99
- keyPath?: string;
100
- change?: number | undefined;
101
- index?: number | undefined | "*";
102
- }): Promise<string>;
103
- };
73
+ export declare const shWpkhLedger: ({ ledgerManager, account, keyPath, change, index }: {
74
+ ledgerManager: LedgerManager;
75
+ account: number;
76
+ keyPath?: string;
77
+ change?: number | undefined;
78
+ index?: number | undefined | "*";
79
+ }) => Promise<string>;
104
80
  /** @function */
105
- export declare const wpkhLedger: {
106
- ({ ledgerManager, account, keyPath, change, index }: {
107
- ledgerManager: LedgerManager;
108
- account: number;
109
- keyPath?: string;
110
- change?: number | undefined;
111
- index?: number | undefined | "*";
112
- }): Promise<string>;
113
- ({ ledgerClient, ledgerState, network, account, keyPath, change, index }: {
114
- ledgerClient: unknown;
115
- ledgerState: LedgerState;
116
- /** @default networks.bitcoin */
117
- network?: Network;
118
- account: number;
119
- keyPath?: string;
120
- change?: number | undefined;
121
- index?: number | undefined | "*";
122
- }): Promise<string>;
123
- };
81
+ export declare const wpkhLedger: ({ ledgerManager, account, keyPath, change, index }: {
82
+ ledgerManager: LedgerManager;
83
+ account: number;
84
+ keyPath?: string;
85
+ change?: number | undefined;
86
+ index?: number | undefined | "*";
87
+ }) => Promise<string>;
124
88
  /** @function */
125
- export declare const trLedger: {
126
- ({ ledgerManager, account, keyPath, change, index }: {
127
- ledgerManager: LedgerManager;
128
- account: number;
129
- keyPath?: string;
130
- change?: number | undefined;
131
- index?: number | undefined | "*";
132
- }): Promise<string>;
133
- ({ ledgerClient, ledgerState, network, account, keyPath, change, index }: {
134
- ledgerClient: unknown;
135
- ledgerState: LedgerState;
136
- /** @default networks.bitcoin */
137
- network?: Network;
138
- account: number;
139
- keyPath?: string;
140
- change?: number | undefined;
141
- index?: number | undefined | "*";
142
- }): Promise<string>;
143
- };
89
+ export declare const trLedger: ({ ledgerManager, account, keyPath, change, index }: {
90
+ ledgerManager: LedgerManager;
91
+ account: number;
92
+ keyPath?: string;
93
+ change?: number | undefined;
94
+ index?: number | undefined | "*";
95
+ }) => Promise<string>;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.trLedger = exports.wpkhLedger = exports.shWpkhLedger = exports.pkhLedger = exports.trBIP32 = exports.wpkhBIP32 = exports.shWpkhBIP32 = exports.pkhBIP32 = void 0;
4
4
  const bitcoinjs_lib_1 = require("bitcoinjs-lib");
5
5
  const keyExpressions_1 = require("./keyExpressions");
6
+ const networkUtils_1 = require("./networkUtils");
6
7
  function assertStandardKeyPath(keyPath) {
7
8
  // Regular expression to match "/change/index" or "/change/*" format
8
9
  const regex = /^\/[01]\/(\d+|\*)$/;
@@ -25,7 +26,7 @@ function standardExpressionsBIP32Maker(purpose, scriptTemplate) {
25
26
  * - `{change:0, index:'*'}`.
26
27
  */
27
28
  function standardScriptExpressionBIP32({ masterNode, network = bitcoinjs_lib_1.networks.bitcoin, keyPath, account, change, index, isPublic = true }) {
28
- const originPath = `/${purpose}'/${network === bitcoinjs_lib_1.networks.bitcoin ? 0 : 1}'/${account}'`;
29
+ const originPath = `/${purpose}'/${(0, networkUtils_1.coinTypeFromNetwork)(network)}'/${account}'`;
29
30
  if (keyPath !== undefined)
30
31
  assertStandardKeyPath(keyPath);
31
32
  const keyExpression = (0, keyExpressions_1.keyExpressionBIP32)({
@@ -49,24 +50,26 @@ exports.wpkhBIP32 = standardExpressionsBIP32Maker(84, 'wpkh(KEYEXPRESSION)');
49
50
  /** @function */
50
51
  exports.trBIP32 = standardExpressionsBIP32Maker(86, 'tr(KEYEXPRESSION)');
51
52
  function standardExpressionsLedgerMaker(purpose, scriptTemplate) {
52
- /** @overload */
53
- async function standardScriptExpressionLedger({ ledgerClient, ledgerState, ledgerManager, network, account, keyPath, change, index }) {
54
- if (ledgerManager && (ledgerClient || ledgerState))
55
- throw new Error(`ledgerClient and ledgerState have been deprecated`);
56
- if (ledgerManager && network)
57
- throw new Error(`ledgerManager already includes the network object`);
58
- if (!ledgerManager && !network)
59
- network = bitcoinjs_lib_1.networks.bitcoin;
60
- if (ledgerManager)
61
- ({ ledgerClient, ledgerState, network } = ledgerManager);
62
- if (!ledgerClient || !ledgerState)
63
- throw new Error(`Could not retrieve ledgerClient or ledgerState`);
64
- const originPath = `/${purpose}'/${network === bitcoinjs_lib_1.networks.bitcoin ? 0 : 1}'/${account}'`;
53
+ /**
54
+ * Computes the standard descriptor based on given parameters.
55
+ *
56
+ * You can define the output location either by:
57
+ * - Providing the full `keyPath` (e.g., "/0/2").
58
+ * OR
59
+ * - Specifying the `change` and `index` values separately (e.g., `{change:0, index:2}`).
60
+ *
61
+ * For ranged indexing, the `index` can be set as a wildcard '*'. For example:
62
+ * - `keyPath="/0/*"`
63
+ * OR
64
+ * - `{change:0, index:'*'}`.
65
+ */
66
+ async function standardScriptExpressionLedger({ ledgerManager, account, keyPath, change, index }) {
67
+ const { network } = ledgerManager;
68
+ const originPath = `/${purpose}'/${(0, networkUtils_1.coinTypeFromNetwork)(network)}'/${account}'`;
65
69
  if (keyPath !== undefined)
66
70
  assertStandardKeyPath(keyPath);
67
71
  const keyExpression = await (0, keyExpressions_1.keyExpressionLedger)({
68
- ledgerClient,
69
- ledgerState,
72
+ ledgerManager,
70
73
  originPath,
71
74
  keyPath,
72
75
  change,
package/dist/signers.d.ts CHANGED
@@ -1,8 +1,7 @@
1
1
  import type { Psbt } from 'bitcoinjs-lib';
2
2
  import type { ECPairInterface } from 'ecpair';
3
3
  import type { BIP32Interface } from 'bip32';
4
- import type { DescriptorInstance } from './descriptors';
5
- import { LedgerState, LedgerManager } from './ledger';
4
+ import { LedgerManager } from './ledger';
6
5
  /**
7
6
  * Signs a specific input of a PSBT with an ECPair.
8
7
  *
@@ -69,16 +68,6 @@ export declare function signInputLedger({ psbt, index, ledgerManager }: {
69
68
  index: number;
70
69
  ledgerManager: LedgerManager;
71
70
  }): Promise<void>;
72
- /**
73
- * @hidden
74
- */
75
- export declare function signInputLedger({ psbt, index, descriptor, ledgerClient, ledgerState }: {
76
- psbt: Psbt;
77
- index: number;
78
- descriptor: DescriptorInstance;
79
- ledgerClient: unknown;
80
- ledgerState: LedgerState;
81
- }): Promise<void>;
82
71
  /**
83
72
  * Signs the inputs of the `psbt` where the keys are controlled by a Ledger
84
73
  * device.
@@ -93,12 +82,3 @@ export declare function signLedger({ psbt, ledgerManager }: {
93
82
  psbt: Psbt;
94
83
  ledgerManager: LedgerManager;
95
84
  }): Promise<void>;
96
- /**
97
- * @hidden
98
- */
99
- export declare function signLedger({ psbt, descriptors, ledgerClient, ledgerState }: {
100
- psbt: Psbt;
101
- descriptors: DescriptorInstance[];
102
- ledgerClient: unknown;
103
- ledgerState: LedgerState;
104
- }): Promise<void>;
package/dist/signers.js CHANGED
@@ -8,8 +8,7 @@ exports.signInputBIP32 = signInputBIP32;
8
8
  exports.signBIP32 = signBIP32;
9
9
  exports.signInputLedger = signInputLedger;
10
10
  exports.signLedger = signLedger;
11
- const bip371_1 = require("bitcoinjs-lib/src/psbt/bip371");
12
- const bip341_1 = require("bitcoinjs-lib/src/payments/bip341");
11
+ const bitcoinjs_lib_internals_1 = require("./bitcoinjs-lib-internals");
13
12
  const ledger_1 = require("./ledger");
14
13
  const applyPR2137_1 = require("./applyPR2137");
15
14
  function range(n) {
@@ -39,12 +38,12 @@ function signInputECPair({ psbt, index, ecpair }) {
39
38
  const input = psbt.data.inputs[index];
40
39
  if (!input)
41
40
  throw new Error('Invalid index');
42
- if ((0, bip371_1.isTaprootInput)(input)) {
41
+ if ((0, bitcoinjs_lib_internals_1.isTaprootInput)(input)) {
43
42
  // If script-path (tapLeafScript present) -> DO NOT TWEAK
44
43
  if (input.tapLeafScript && input.tapLeafScript.length > 0)
45
44
  psbt.signInput(index, ecpair);
46
45
  else {
47
- const hash = (0, bip341_1.tapTweakHash)(Buffer.from(ecpair.publicKey.slice(1, 33)), undefined);
46
+ const hash = (0, bitcoinjs_lib_internals_1.tapTweakHash)(ecpair.publicKey.slice(1, 33), undefined);
48
47
  const tweakedEcpair = ecpair.tweak(hash);
49
48
  psbt.signInput(index, tweakedEcpair);
50
49
  }
@@ -101,136 +100,91 @@ function signBIP32({ psbt, masterNode }) {
101
100
  }
102
101
  const ledgerSignaturesForInputIndex = (index, ledgerSignatures) => ledgerSignatures
103
102
  .filter(([i]) => i === index)
104
- .map(([_i, partialSignature]) => ({
105
- pubkey: partialSignature.pubkey,
106
- signature: partialSignature.signature
107
- }));
108
- /**
109
- * To be removed in v3.0 and replaced by a version that does not accept
110
- * descriptor
111
- * @overload
112
- */
113
- async function signInputLedger({ psbt, index, descriptor, ledgerClient, ledgerState, ledgerManager }) {
114
- if (!descriptor && !ledgerManager)
115
- throw new Error(`ledgerManager not provided`);
116
- if (descriptor && ledgerManager)
117
- throw new Error(`Invalid usage: don't pass descriptor`);
118
- if (ledgerManager && (ledgerClient || ledgerState))
119
- throw new Error(`Invalid usage: either ledgerManager or ledgerClient + ledgerState`);
120
- const output = descriptor;
121
- if (ledgerManager)
122
- ({ ledgerClient, ledgerState } = ledgerManager);
123
- if (!ledgerClient)
124
- throw new Error(`ledgerManager not provided`);
125
- if (!ledgerState)
126
- throw new Error(`ledgerManager not provided`);
127
- const { PsbtV2, DefaultWalletPolicy, WalletPolicy, AppClient } = (await (0, ledger_1.importAndValidateLedgerBitcoin)(ledgerClient));
128
- if (!(ledgerClient instanceof AppClient))
129
- throw new Error(`Error: pass a valid ledgerClient`);
130
- let ledgerSignatures;
131
- if (ledgerManager) {
132
- if (psbt.data.inputs[index]?.tapInternalKey)
133
- throw new Error('Taproot inputs not yet supported for the Ledger device');
134
- const policy = await (0, ledger_1.ledgerPolicyFromPsbtInput)({
135
- psbt,
136
- index,
137
- ledgerManager
138
- });
139
- if (!policy)
140
- throw new Error(`Error: the ledger cannot sign this pstb input`);
141
- if (policy.policyName && policy.policyHmac && policy.policyId) {
142
- //non-standard policy
143
- const walletPolicy = new WalletPolicy(policy.policyName, policy.ledgerTemplate, policy.keyRoots);
144
- ledgerSignatures = await ledgerClient.signPsbt(new PsbtV2().fromBitcoinJS(psbt), walletPolicy, policy.policyHmac);
103
+ .map(([_i, partialSignature]) => partialSignature);
104
+ function addLedgerSignaturesToInput({ psbt, index, ledgerSignatures }) {
105
+ const input = psbt.data.inputs[index];
106
+ if (!input)
107
+ throw new Error(`Error: input ${index} not available`);
108
+ const signatures = ledgerSignaturesForInputIndex(index, ledgerSignatures);
109
+ if (signatures.length === 0)
110
+ throw new Error(`Error: no ledger signatures found for input ${index}`);
111
+ if ((0, bitcoinjs_lib_internals_1.isTaprootInput)(input)) {
112
+ // Ledger returns per-input signatures as [pubkey, signature, tapleafHash?].
113
+ // For taproot we must map them to PSBT taproot fields (not partialSig):
114
+ // - signatures with tapleafHash -> tapScriptSig[] (script-path)
115
+ // - signature without tapleafHash -> tapKeySig (key-path)
116
+ // A taproot input may contain script-path signatures, key-path signature,
117
+ // or both in edge cases; each must be written to its corresponding field.
118
+ const tapScriptSig = signatures
119
+ .filter((sig) => sig.tapleafHash)
120
+ .map((sig) => ({
121
+ pubkey: sig.pubkey,
122
+ signature: sig.signature,
123
+ leafHash: sig.tapleafHash
124
+ }));
125
+ const tapKeySigs = signatures.filter((sig) => !sig.tapleafHash);
126
+ if (tapScriptSig.length > 0) {
127
+ psbt.updateInput(index, { tapScriptSig });
145
128
  }
146
- else {
147
- //standard policy
148
- ledgerSignatures = await ledgerClient.signPsbt(new PsbtV2().fromBitcoinJS(psbt), new DefaultWalletPolicy(policy.ledgerTemplate, policy.keyRoots[0]), null);
129
+ if (tapKeySigs.length > 1)
130
+ throw new Error(`Error: expected at most one tapKeySig for input ${index}`);
131
+ const tapKeySig = tapKeySigs[0]?.signature;
132
+ if (tapKeySig) {
133
+ psbt.updateInput(index, { tapKeySig });
149
134
  }
135
+ if (tapScriptSig.length === 0 && !tapKeySig)
136
+ throw new Error(`Error: no valid taproot ledger signatures found for input ${index}`);
150
137
  }
151
138
  else {
152
- if (!output)
153
- throw new Error(`outputs not provided`);
154
- const result = await (0, ledger_1.ledgerPolicyFromOutput)({
155
- output,
156
- ledgerClient,
157
- ledgerState
158
- });
159
- if (!result)
160
- throw new Error(`Error: output does not have a ledger input`);
161
- const { ledgerTemplate, keyRoots } = result;
162
- const standardPolicy = await (0, ledger_1.ledgerPolicyFromStandard)({
163
- output,
164
- ledgerClient,
165
- ledgerState
166
- });
167
- if (standardPolicy) {
168
- ledgerSignatures = await ledgerClient.signPsbt(new PsbtV2().fromBitcoinJS(psbt), new DefaultWalletPolicy(ledgerTemplate, keyRoots[0]), null);
169
- }
170
- else {
171
- const policy = await (0, ledger_1.ledgerPolicyFromState)({
172
- output,
173
- ledgerClient,
174
- ledgerState
175
- });
176
- if (!policy || !policy.policyName || !policy.policyHmac)
177
- throw new Error(`Error: the descriptor's policy is not registered`);
178
- const walletPolicy = new WalletPolicy(policy.policyName, ledgerTemplate, keyRoots);
179
- ledgerSignatures = await ledgerClient.signPsbt(new PsbtV2().fromBitcoinJS(psbt), walletPolicy, policy.policyHmac);
180
- }
139
+ const partialSig = signatures.map((sig) => ({
140
+ pubkey: sig.pubkey,
141
+ signature: sig.signature
142
+ }));
143
+ psbt.updateInput(index, { partialSig });
181
144
  }
182
- //Add the signatures to the Psbt object using PartialSig format:
183
- psbt.updateInput(index, {
184
- partialSig: ledgerSignaturesForInputIndex(index, ledgerSignatures)
145
+ }
146
+ async function signInputLedger({ psbt, index, ledgerManager }) {
147
+ const { ledgerClient } = ledgerManager;
148
+ const { DefaultWalletPolicy, WalletPolicy, AppClient } = (await (0, ledger_1.importAndValidateLedgerBitcoin)(ledgerClient));
149
+ if (!(ledgerClient instanceof AppClient))
150
+ throw new Error(`Error: pass a valid ledgerClient`);
151
+ const policy = await (0, ledger_1.ledgerPolicyFromPsbtInput)({
152
+ psbt,
153
+ index,
154
+ ledgerManager
185
155
  });
156
+ if (!policy)
157
+ throw new Error(`Error: the ledger cannot sign this pstb input`);
158
+ let ledgerSignatures;
159
+ if (policy.policyName && policy.policyHmac && policy.policyId) {
160
+ //non-standard policy
161
+ const walletPolicy = new WalletPolicy(policy.policyName, policy.ledgerTemplate, policy.keyRoots);
162
+ const walletHmac = policy.policyHmac;
163
+ ledgerSignatures = await ledgerClient.signPsbt(psbt.toBase64(), walletPolicy, walletHmac);
164
+ }
165
+ else {
166
+ //standard policy
167
+ ledgerSignatures = await ledgerClient.signPsbt(psbt.toBase64(), new DefaultWalletPolicy(policy.ledgerTemplate, policy.keyRoots[0]), null);
168
+ }
169
+ addLedgerSignaturesToInput({ psbt, index, ledgerSignatures });
186
170
  }
187
- /**
188
- * To be removed in v3.0 and replaced by a version that does not accept
189
- * descriptors
190
- * @overload
191
- */
192
- async function signLedger({ psbt, descriptors, ledgerClient, ledgerState, ledgerManager }) {
193
- if (!descriptors && !ledgerManager)
194
- throw new Error(`ledgerManager not provided`);
195
- if (descriptors && ledgerManager)
196
- throw new Error(`Invalid usage: don't pass descriptors`);
197
- if (ledgerManager && (ledgerClient || ledgerState))
198
- throw new Error(`Invalid usage: either ledgerManager or ledgerClient + ledgerState`);
199
- const outputs = descriptors;
200
- if (ledgerManager)
201
- ({ ledgerClient, ledgerState } = ledgerManager);
202
- if (!ledgerClient)
203
- throw new Error(`ledgerManager not provided`);
204
- if (!ledgerState)
205
- throw new Error(`ledgerManager not provided`);
206
- const { PsbtV2, DefaultWalletPolicy, WalletPolicy, AppClient } = (await (0, ledger_1.importAndValidateLedgerBitcoin)(ledgerClient));
171
+ async function signLedger({ psbt, ledgerManager }) {
172
+ const { ledgerClient } = ledgerManager;
173
+ const { DefaultWalletPolicy, WalletPolicy, AppClient } = (await (0, ledger_1.importAndValidateLedgerBitcoin)(ledgerClient));
207
174
  if (!(ledgerClient instanceof AppClient))
208
175
  throw new Error(`Error: pass a valid ledgerClient`);
209
176
  const ledgerPolicies = [];
210
- if (ledgerManager)
211
- for (let index = 0; index < psbt.data.inputs.length; index++) {
212
- if (psbt.data.inputs[index]?.tapInternalKey)
213
- throw new Error('Taproot inputs not yet supported for the Ledger device');
214
- const policy = await (0, ledger_1.ledgerPolicyFromPsbtInput)({
215
- psbt,
216
- index,
217
- ledgerManager
218
- });
219
- if (policy)
220
- ledgerPolicies.push(policy);
221
- }
222
- else {
223
- if (!outputs)
224
- throw new Error(`outputs not provided`);
225
- for (const output of outputs) {
226
- const policy = (await (0, ledger_1.ledgerPolicyFromState)({ output, ledgerClient, ledgerState })) ||
227
- (await (0, ledger_1.ledgerPolicyFromStandard)({ output, ledgerClient, ledgerState }));
228
- if (policy)
229
- ledgerPolicies.push(policy);
230
- }
231
- if (ledgerPolicies.length === 0)
232
- throw new Error(`Error: there are no inputs which could be signed`);
177
+ for (let index = 0; index < psbt.data.inputs.length; index++) {
178
+ const policy = await (0, ledger_1.ledgerPolicyFromPsbtInput)({
179
+ psbt,
180
+ index,
181
+ ledgerManager
182
+ });
183
+ if (policy)
184
+ ledgerPolicies.push(policy);
233
185
  }
186
+ if (ledgerPolicies.length === 0)
187
+ throw new Error(`Error: there are no inputs which could be signed`);
234
188
  //cluster unique LedgerPolicies
235
189
  const uniquePolicies = [];
236
190
  for (const policy of ledgerPolicies) {
@@ -244,16 +198,18 @@ async function signLedger({ psbt, descriptors, ledgerClient, ledgerState, ledger
244
198
  uniquePolicy.policyId) {
245
199
  //non-standard policy
246
200
  const walletPolicy = new WalletPolicy(uniquePolicy.policyName, uniquePolicy.ledgerTemplate, uniquePolicy.keyRoots);
247
- ledgerSignatures = await ledgerClient.signPsbt(new PsbtV2().fromBitcoinJS(psbt), walletPolicy, uniquePolicy.policyHmac);
201
+ const walletHmac = uniquePolicy.policyHmac;
202
+ ledgerSignatures = await ledgerClient.signPsbt(psbt.toBase64(), walletPolicy, walletHmac);
248
203
  }
249
204
  else {
250
205
  //standard policy
251
- ledgerSignatures = await ledgerClient.signPsbt(new PsbtV2().fromBitcoinJS(psbt), new DefaultWalletPolicy(uniquePolicy.ledgerTemplate, uniquePolicy.keyRoots[0]), null);
206
+ ledgerSignatures = await ledgerClient.signPsbt(psbt.toBase64(), new DefaultWalletPolicy(uniquePolicy.ledgerTemplate, uniquePolicy.keyRoots[0]), null);
252
207
  }
253
- for (const [index, ,] of ledgerSignatures) {
254
- psbt.updateInput(index, {
255
- partialSig: ledgerSignaturesForInputIndex(index, ledgerSignatures)
256
- });
208
+ const signedIndexes = [
209
+ ...new Set(ledgerSignatures.map(([index]) => index))
210
+ ];
211
+ for (const index of signedIndexes) {
212
+ addLedgerSignaturesToInput({ psbt, index, ledgerSignatures });
257
213
  }
258
214
  }
259
215
  }