@bitcoinerlab/descriptors 1.0.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/ledger.js CHANGED
@@ -1,31 +1,31 @@
1
1
  "use strict";
2
2
  // Copyright (c) 2023 Jose-Luis Landabaso - https://bitcoinerlab.com
3
3
  // Distributed under the MIT software license
4
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
5
- if (k2 === undefined) k2 = k;
6
- var desc = Object.getOwnPropertyDescriptor(m, k);
7
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
8
- desc = { enumerable: true, get: function() { return m[k]; } };
9
- }
10
- Object.defineProperty(o, k2, desc);
11
- }) : (function(o, m, k, k2) {
12
- if (k2 === undefined) k2 = k;
13
- o[k2] = m[k];
14
- }));
15
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
16
- Object.defineProperty(o, "default", { enumerable: true, value: v });
17
- }) : function(o, v) {
18
- o["default"] = v;
19
- });
20
- var __importStar = (this && this.__importStar) || function (mod) {
21
- if (mod && mod.__esModule) return mod;
22
- var result = {};
23
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
24
- __setModuleDefault(result, mod);
25
- return result;
26
- };
27
4
  Object.defineProperty(exports, "__esModule", { value: true });
28
- exports.ledgerPolicyFromState = exports.comparePolicies = exports.ledgerPolicyFromStandard = exports.registerLedgerWallet = exports.descriptorToLedgerFormat = exports.getLedgerXpub = exports.getLedgerMasterFingerPrint = exports.assertLedgerApp = exports.importAndValidateLedgerBitcoin = void 0;
5
+ exports.ledgerPolicyFromState = exports.comparePolicies = exports.ledgerPolicyFromStandard = exports.registerLedgerWallet = exports.ledgerPolicyFromOutput = exports.ledgerPolicyFromPsbtInput = exports.getLedgerXpub = exports.getLedgerMasterFingerPrint = exports.assertLedgerApp = exports.importAndValidateLedgerBitcoin = void 0;
6
+ /*
7
+ * Notes on Ledger implementation:
8
+ *
9
+ * Ledger assumes as external all keyRoots that do not have origin information.
10
+ *
11
+ * Some known Ledger Limitations (based on my tests as of Febr 2023):
12
+ *
13
+ * 1) All keyExpressions must be expanded into @i. In other words,
14
+ * this template is not valid:
15
+ * wsh(and_v(v:pk(03ed0b41d808b012b3a77dd7f6a30c4180dfbcab604133d90ce7593ec7f3e4037b),and_v(v:sha256(6c60f404f8167a38fc70eaf8aa17ac351023bef86bcb9d1086a19afe95bd5333),and_v(and_v(v:pk(@0/**),v:pk(@1/**)),older(5)))))
16
+ * (note the fixed 03ed0b41d808b012b3a77dd7f6a30c4180dfbcab604133d90ce7593ec7f3e4037b pubkey)
17
+ *
18
+ * 2) All elements in the keyRoot vector must be xpub-type (no xprv-type, no pubkey-type, ...)
19
+ *
20
+ * 3) All originPaths of the expressions in the keyRoot vector must be the same.
21
+ * On the other hand, an empty originPath is permitted for external keys.
22
+ *
23
+ * 4) Since all originPaths must be the same and originPaths for the Ledger are
24
+ * necessary, a Ledger device can only sign at most 1 key per policy and input.
25
+ *
26
+ * All the conditions above are checked in function ledgerPolicyFromOutput.
27
+ */
28
+ const descriptors_1 = require("./descriptors");
29
29
  const bitcoinjs_lib_1 = require("bitcoinjs-lib");
30
30
  const re_1 = require("./re");
31
31
  /**
@@ -49,7 +49,18 @@ const re_1 = require("./re");
49
49
  async function importAndValidateLedgerBitcoin(ledgerClient) {
50
50
  let ledgerBitcoinModule;
51
51
  try {
52
- ledgerBitcoinModule = await Promise.resolve().then(() => __importStar(require('ledger-bitcoin')));
52
+ // Originally, the code used dynamic imports:
53
+ // ledgerBitcoinModule = await import('ledger-bitcoin');
54
+ // However, in React Native with the Metro bundler, there's an issue with
55
+ // recognizing dynamic imports inside try-catch blocks. For details, refer to:
56
+ // https://github.com/react-native-community/discussions-and-proposals/issues/120
57
+ // The dynamic import gets transpiled to:
58
+ // ledgerBitcoinModule = Promise.resolve().then(() => __importStar(require('ledger-bitcoin')));
59
+ // Metro bundler fails to recognize the above as conditional. Hence, it tries
60
+ // to require 'ledger-bitcoin' unconditionally, leading to potential errors if
61
+ // 'ledger-bitcoin' is not installed (given it's an optional peerDependency).
62
+ // To bypass this, we directly use require:
63
+ ledgerBitcoinModule = require('ledger-bitcoin');
53
64
  }
54
65
  catch (error) {
55
66
  throw new Error('Could not import "ledger-bitcoin". This is a peer dependency and needs to be installed explicitly. Please run "npm install ledger-bitcoin" to use Ledger Hardware Wallet functionality.');
@@ -74,6 +85,15 @@ async function ledgerAppInfo(transport) {
74
85
  const flags = r.slice(i, (i += flagLength));
75
86
  return { name, version, flags, format };
76
87
  }
88
+ /**
89
+ * Verifies if the Ledger device is connected, if the required Bitcoin App is opened,
90
+ * and if the version of the app meets the minimum requirements.
91
+ *
92
+ * @throws Will throw an error if the Ledger device is not connected, the required
93
+ * Bitcoin App is not opened, or if the version is below the required number.
94
+ *
95
+ * @returns Promise<void> - A promise that resolves if all assertions pass, or throws otherwise.
96
+ */
77
97
  async function assertLedgerApp({ transport, name, minVersion }) {
78
98
  const { name: openName, version } = await ledgerAppInfo(transport);
79
99
  if (openName !== name) {
@@ -114,7 +134,14 @@ function isLedgerStandard({ ledgerTemplate, keyRoots, network = bitcoinjs_lib_1.
114
134
  return true;
115
135
  return false;
116
136
  }
117
- async function getLedgerMasterFingerPrint({ ledgerClient, ledgerState }) {
137
+ /** @hidden */
138
+ async function getLedgerMasterFingerPrint({ ledgerClient, ledgerState, ledgerManager }) {
139
+ if (ledgerManager && (ledgerClient || ledgerState))
140
+ throw new Error(`ledgerClient and ledgerState have been deprecated`);
141
+ if (ledgerManager)
142
+ ({ ledgerClient, ledgerState } = ledgerManager);
143
+ if (!ledgerClient || !ledgerState)
144
+ throw new Error(`Could not retrieve ledgerClient or ledgerState`);
118
145
  const { AppClient } = (await importAndValidateLedgerBitcoin(ledgerClient));
119
146
  if (!(ledgerClient instanceof AppClient))
120
147
  throw new Error(`Error: pass a valid ledgerClient`);
@@ -126,7 +153,14 @@ async function getLedgerMasterFingerPrint({ ledgerClient, ledgerState }) {
126
153
  return masterFingerprint;
127
154
  }
128
155
  exports.getLedgerMasterFingerPrint = getLedgerMasterFingerPrint;
129
- async function getLedgerXpub({ originPath, ledgerClient, ledgerState }) {
156
+ /** @hidden */
157
+ async function getLedgerXpub({ originPath, ledgerClient, ledgerState, ledgerManager }) {
158
+ if (ledgerManager && (ledgerClient || ledgerState))
159
+ throw new Error(`ledgerClient and ledgerState have been deprecated`);
160
+ if (ledgerManager)
161
+ ({ ledgerClient, ledgerState } = ledgerManager);
162
+ if (!ledgerClient || !ledgerState)
163
+ throw new Error(`Could not retrieve ledgerClient or ledgerState`);
130
164
  const { AppClient } = (await importAndValidateLedgerBitcoin(ledgerClient));
131
165
  if (!(ledgerClient instanceof AppClient))
132
166
  throw new Error(`Error: pass a valid ledgerClient`);
@@ -149,7 +183,151 @@ async function getLedgerXpub({ originPath, ledgerClient, ledgerState }) {
149
183
  }
150
184
  exports.getLedgerXpub = getLedgerXpub;
151
185
  /**
152
- * Takes a descriptor and gets its Ledger Wallet Policy, that is, its keyRoots and template.
186
+ * Checks whether there is a policy in ledgerState that the ledger
187
+ * could use to sign this psbt input.
188
+ *
189
+ * It found return the policy, otherwise, return undefined
190
+ *
191
+ * All considerations in the header of this file are applied
192
+ */
193
+ async function ledgerPolicyFromPsbtInput({ ledgerManager, psbt, index }) {
194
+ const { ledgerState, ledgerClient, ecc, network } = ledgerManager;
195
+ const { Output } = (0, descriptors_1.DescriptorsFactory)(ecc);
196
+ const input = psbt.data.inputs[index];
197
+ if (!input)
198
+ throw new Error(`Input numer ${index} not set.`);
199
+ let scriptPubKey;
200
+ if (input.nonWitnessUtxo) {
201
+ const vout = psbt.txInputs[index]?.index;
202
+ if (vout === undefined)
203
+ throw new Error(`Could not extract vout from nonWitnessUtxo for input ${index}.`);
204
+ scriptPubKey = bitcoinjs_lib_1.Transaction.fromBuffer(input.nonWitnessUtxo).outs[vout]
205
+ ?.script;
206
+ }
207
+ else if (input.witnessUtxo) {
208
+ scriptPubKey = input.witnessUtxo.script;
209
+ }
210
+ if (!scriptPubKey)
211
+ throw new Error(`Could not retrieve scriptPubKey for input ${index}.`);
212
+ const bip32Derivations = input.bip32Derivation;
213
+ if (!bip32Derivations || !bip32Derivations.length)
214
+ throw new Error(`Input ${index} does not contain bip32 derivations.`);
215
+ const ledgerMasterFingerprint = await getLedgerMasterFingerPrint({
216
+ ledgerManager
217
+ });
218
+ for (const bip32Derivation of bip32Derivations) {
219
+ //get the keyRoot and keyPath. If it matches one of our policies then
220
+ //we are still not sure this is the policy that must be used yet
221
+ //So we must use the template and the keyRoot of each policy and compute the
222
+ //scriptPubKey:
223
+ if (Buffer.compare(bip32Derivation.masterFingerprint, ledgerMasterFingerprint) === 0) {
224
+ // Match /m followed by n consecutive hardened levels and then 2 consecutive unhardened levels:
225
+ const match = bip32Derivation.path.match(/m((\/\d+['hH])*)(\/\d+\/\d+)?/);
226
+ const originPath = match ? match[1] : undefined; //n consecutive hardened levels
227
+ const keyPath = match ? match[3] : undefined; //2 unhardened levels or undefined
228
+ if (originPath && keyPath) {
229
+ const [, strChange, strIndex] = keyPath.split('/');
230
+ if (!strChange || !strIndex)
231
+ throw new Error(`keyPath ${keyPath} incorrectly extracted`);
232
+ const change = parseInt(strChange, 10);
233
+ const index = parseInt(strIndex, 10);
234
+ const coinType = network === bitcoinjs_lib_1.networks.bitcoin ? 0 : 1;
235
+ //standard policy candidate. This policy will be added to the pool
236
+ //of policies below and check if it produces the correct scriptPubKey
237
+ let standardPolicy;
238
+ if (change === 0 || change === 1) {
239
+ const standardTemplate = originPath.match(new RegExp(`^/44'/${coinType}'/(\\d+)'$`))
240
+ ? 'pkh(@0/**)'
241
+ : originPath.match(new RegExp(`^/84'/${coinType}'/(\\d+)'$`))
242
+ ? 'wpkh(@0/**)'
243
+ : originPath.match(new RegExp(`^/49'/${coinType}'/(\\d+)'$`))
244
+ ? 'sh(wpkh(@0/**))'
245
+ : originPath.match(new RegExp(`^/86'/${coinType}'/(\\d+)'$`))
246
+ ? 'tr(@0/**)'
247
+ : undefined;
248
+ if (standardTemplate) {
249
+ const xpub = await getLedgerXpub({
250
+ originPath,
251
+ ledgerClient,
252
+ ledgerState
253
+ });
254
+ standardPolicy = {
255
+ ledgerTemplate: standardTemplate,
256
+ keyRoots: [
257
+ `[${ledgerMasterFingerprint.toString('hex')}${originPath}]${xpub}`
258
+ ]
259
+ };
260
+ }
261
+ }
262
+ const policies = [...(ledgerState.policies || [])];
263
+ if (standardPolicy)
264
+ policies.push(standardPolicy);
265
+ for (const policy of policies) {
266
+ //Build the descriptor from the ledgerTemplate + keyRoots
267
+ //then get the scriptPubKey
268
+ let descriptor = policy.ledgerTemplate;
269
+ // Replace change (making sure the value in the change level for the
270
+ // template of the policy meets the change in bip32Derivation):
271
+ descriptor = descriptor.replace(/\/\*\*/g, `/<0;1>/*`);
272
+ const regExpMN = new RegExp(`/<(\\d+);(\\d+)>`, 'g');
273
+ let matchMN;
274
+ while (descriptor && (matchMN = regExpMN.exec(descriptor)) !== null) {
275
+ const [M, N] = [
276
+ parseInt(matchMN[1], 10),
277
+ parseInt(matchMN[2], 10)
278
+ ];
279
+ if (M === change || N === change)
280
+ descriptor = descriptor.replace(`/<${M};${N}>`, `/${change}`);
281
+ else
282
+ descriptor = undefined;
283
+ }
284
+ if (descriptor) {
285
+ // Replace index:
286
+ descriptor = descriptor.replace(/\/\*/g, `/${index}`);
287
+ // Replace origin in reverse order to prevent
288
+ // misreplacements, e.g., @10 being mistaken for @1 and leaving a 0.
289
+ for (let i = policy.keyRoots.length - 1; i >= 0; i--) {
290
+ const keyRoot = policy.keyRoots[i];
291
+ if (!keyRoot)
292
+ throw new Error(`keyRoot ${keyRoot} invalidly extracted.`);
293
+ const match = keyRoot.match(/\[([^]+)\]/);
294
+ const keyRootOrigin = match && match[1];
295
+ if (keyRootOrigin) {
296
+ const [, ...arrKeyRootOriginPath] = keyRootOrigin.split('/');
297
+ const keyRootOriginPath = '/' + arrKeyRootOriginPath.join('/');
298
+ //We check all origins to be the same even if they do not
299
+ //belong to the ledger (read the header in this file)
300
+ if (descriptor && keyRootOriginPath === originPath)
301
+ descriptor = descriptor.replace(new RegExp(`@${i}`, 'g'), keyRoot);
302
+ else
303
+ descriptor = undefined;
304
+ }
305
+ else
306
+ descriptor = undefined;
307
+ }
308
+ //verify the scriptPubKey from the input vs. the one obtained from
309
+ //the policy after having filled in the keyPath in the template
310
+ if (descriptor) {
311
+ const policyScriptPubKey = new Output({
312
+ descriptor,
313
+ network
314
+ }).getScriptPubKey();
315
+ if (Buffer.compare(policyScriptPubKey, scriptPubKey) === 0) {
316
+ return policy;
317
+ }
318
+ }
319
+ }
320
+ }
321
+ }
322
+ }
323
+ }
324
+ return;
325
+ }
326
+ exports.ledgerPolicyFromPsbtInput = ledgerPolicyFromPsbtInput;
327
+ /**
328
+ * Given an output, it extracts its descriptor and converts it to a Ledger
329
+ * Wallet Policy, that is, its keyRoots and template.
330
+ *
153
331
  * keyRoots and template follow Ledger's specifications:
154
332
  * https://github.com/LedgerHQ/app-bitcoin-new/blob/develop/doc/wallet.md
155
333
  *
@@ -173,11 +351,11 @@ exports.getLedgerXpub = getLedgerXpub;
173
351
  * This function takes into account all the considerations regarding Ledger
174
352
  * policy implementation details expressed in the header of this file.
175
353
  */
176
- async function descriptorToLedgerFormat({ descriptor, ledgerClient, ledgerState }) {
177
- const expandedExpression = descriptor.expand().expandedExpression;
178
- const expansionMap = descriptor.expand().expansionMap;
354
+ async function ledgerPolicyFromOutput({ output, ledgerClient, ledgerState }) {
355
+ const expandedExpression = output.expand().expandedExpression;
356
+ const expansionMap = output.expand().expansionMap;
179
357
  if (!expandedExpression || !expansionMap)
180
- throw new Error(`Error: invalid descriptor`);
358
+ throw new Error(`Error: invalid output`);
181
359
  const ledgerMasterFingerprint = await getLedgerMasterFingerPrint({
182
360
  ledgerClient,
183
361
  ledgerState
@@ -233,34 +411,57 @@ async function descriptorToLedgerFormat({ descriptor, ledgerClient, ledgerState
233
411
  });
234
412
  return { ledgerTemplate, keyRoots };
235
413
  }
236
- exports.descriptorToLedgerFormat = descriptorToLedgerFormat;
414
+ exports.ledgerPolicyFromOutput = ledgerPolicyFromOutput;
237
415
  /**
238
- * It registers a policy based on a descriptor. It stores it in ledgerState.
239
- *
240
- * If the policy was already registered, it does not register it.
241
- * If the policy is standard, it does not register it.
242
- *
416
+ * To be removed in v3.0 and replaced by a version that does not accept
417
+ * descriptors
418
+ * @hidden
243
419
  **/
244
- async function registerLedgerWallet({ descriptor, ledgerClient, ledgerState, policyName }) {
420
+ async function registerLedgerWallet({ descriptor, ledgerClient, ledgerState, ledgerManager, policyName }) {
421
+ if (typeof descriptor !== 'string' && ledgerManager)
422
+ throw new Error(`Invalid usage: descriptor must be a string`);
423
+ if (ledgerManager && (ledgerClient || ledgerState))
424
+ throw new Error(`Invalid usage: either ledgerManager or ledgerClient + ledgerState`);
425
+ if (ledgerManager)
426
+ ({ ledgerClient, ledgerState } = ledgerManager);
427
+ if (!ledgerClient)
428
+ throw new Error(`ledgerManager not provided`);
429
+ if (!ledgerState)
430
+ throw new Error(`ledgerManager not provided`);
245
431
  const { WalletPolicy, AppClient } = (await importAndValidateLedgerBitcoin(ledgerClient));
246
432
  if (!(ledgerClient instanceof AppClient))
247
433
  throw new Error(`Error: pass a valid ledgerClient`);
248
- const result = await descriptorToLedgerFormat({
249
- descriptor,
434
+ let output;
435
+ if (typeof descriptor === 'string') {
436
+ if (!ledgerManager)
437
+ throw new Error(`ledgerManager not provided`);
438
+ const { Output } = (0, descriptors_1.DescriptorsFactory)(ledgerManager.ecc);
439
+ output = new Output({
440
+ descriptor,
441
+ ...(descriptor.includes('*') ? { index: 0 } : {}),
442
+ network: ledgerManager.network
443
+ });
444
+ }
445
+ else
446
+ output = descriptor;
447
+ if (await ledgerPolicyFromStandard({ output, ledgerClient, ledgerState }))
448
+ return;
449
+ const result = await ledgerPolicyFromOutput({
450
+ output,
250
451
  ledgerClient,
251
452
  ledgerState
252
453
  });
253
- if (await ledgerPolicyFromStandard({ descriptor, ledgerClient, ledgerState }))
454
+ if (await ledgerPolicyFromStandard({ output, ledgerClient, ledgerState }))
254
455
  return;
255
456
  if (!result)
256
- throw new Error(`Error: descriptor does not have a ledger input`);
457
+ throw new Error(`Error: output does not have a ledger input`);
257
458
  const { ledgerTemplate, keyRoots } = result;
258
459
  if (!ledgerState.policies)
259
460
  ledgerState.policies = [];
260
461
  let walletPolicy, policyHmac;
261
462
  //Search in ledgerState first
262
463
  const policy = await ledgerPolicyFromState({
263
- descriptor,
464
+ output,
264
465
  ledgerClient,
265
466
  ledgerState
266
467
  });
@@ -287,9 +488,9 @@ exports.registerLedgerWallet = registerLedgerWallet;
287
488
  /**
288
489
  * Retrieve a standard ledger policy or null if it does correspond.
289
490
  **/
290
- async function ledgerPolicyFromStandard({ descriptor, ledgerClient, ledgerState }) {
291
- const result = await descriptorToLedgerFormat({
292
- descriptor,
491
+ async function ledgerPolicyFromStandard({ output, ledgerClient, ledgerState }) {
492
+ const result = await ledgerPolicyFromOutput({
493
+ output,
293
494
  ledgerClient,
294
495
  ledgerState
295
496
  });
@@ -299,7 +500,7 @@ async function ledgerPolicyFromStandard({ descriptor, ledgerClient, ledgerState
299
500
  if (isLedgerStandard({
300
501
  ledgerTemplate,
301
502
  keyRoots,
302
- network: descriptor.getNetwork()
503
+ network: output.getNetwork()
303
504
  }))
304
505
  return { ledgerTemplate, keyRoots };
305
506
  return null;
@@ -324,14 +525,14 @@ exports.comparePolicies = comparePolicies;
324
525
  /**
325
526
  * Retrieve a ledger policy from ledgerState or null if it does not exist yet.
326
527
  **/
327
- async function ledgerPolicyFromState({ descriptor, ledgerClient, ledgerState }) {
328
- const result = await descriptorToLedgerFormat({
329
- descriptor,
528
+ async function ledgerPolicyFromState({ output, ledgerClient, ledgerState }) {
529
+ const result = await ledgerPolicyFromOutput({
530
+ output,
330
531
  ledgerClient,
331
532
  ledgerState
332
533
  });
333
534
  if (!result)
334
- throw new Error(`Error: descriptor does not have a ledger input`);
535
+ throw new Error(`Error: output does not have a ledger input`);
335
536
  const { ledgerTemplate, keyRoots } = result;
336
537
  if (!ledgerState.policies)
337
538
  ledgerState.policies = [];
@@ -1,57 +1,102 @@
1
1
  import { Network } from 'bitcoinjs-lib';
2
- import type { LedgerState } from './ledger';
2
+ import type { LedgerState, LedgerManager } from './ledger';
3
3
  import type { BIP32Interface } from 'bip32';
4
4
  export declare const pkhBIP32: ({ masterNode, network, keyPath, account, change, index, isPublic }: {
5
5
  masterNode: BIP32Interface;
6
+ /** @default networks.bitcoin */
6
7
  network?: Network;
7
8
  account: number;
8
9
  change?: number | undefined;
9
10
  index?: number | undefined | '*';
10
11
  keyPath?: string;
12
+ /**
13
+ * Compute an xpub or xprv
14
+ * @default true
15
+ */
11
16
  isPublic?: boolean;
12
17
  }) => string;
13
18
  export declare const shWpkhBIP32: ({ masterNode, network, keyPath, account, change, index, isPublic }: {
14
19
  masterNode: BIP32Interface;
20
+ /** @default networks.bitcoin */
15
21
  network?: Network;
16
22
  account: number;
17
23
  change?: number | undefined;
18
24
  index?: number | undefined | '*';
19
25
  keyPath?: string;
26
+ /**
27
+ * Compute an xpub or xprv
28
+ * @default true
29
+ */
20
30
  isPublic?: boolean;
21
31
  }) => string;
22
32
  export declare const wpkhBIP32: ({ masterNode, network, keyPath, account, change, index, isPublic }: {
23
33
  masterNode: BIP32Interface;
34
+ /** @default networks.bitcoin */
24
35
  network?: Network;
25
36
  account: number;
26
37
  change?: number | undefined;
27
38
  index?: number | undefined | '*';
28
39
  keyPath?: string;
40
+ /**
41
+ * Compute an xpub or xprv
42
+ * @default true
43
+ */
29
44
  isPublic?: boolean;
30
45
  }) => string;
31
- export declare const pkhLedger: ({ ledgerClient, ledgerState, network, account, keyPath, change, index }: {
32
- ledgerClient: unknown;
33
- ledgerState: LedgerState;
34
- network?: Network;
35
- account: number;
36
- keyPath?: string;
37
- change?: number | undefined;
38
- index?: number | undefined | '*';
39
- }) => Promise<string>;
40
- export declare const shWpkhLedger: ({ ledgerClient, ledgerState, network, account, keyPath, change, index }: {
41
- ledgerClient: unknown;
42
- ledgerState: LedgerState;
43
- network?: Network;
44
- account: number;
45
- keyPath?: string;
46
- change?: number | undefined;
47
- index?: number | undefined | '*';
48
- }) => Promise<string>;
49
- export declare const wpkhLedger: ({ ledgerClient, ledgerState, network, account, keyPath, change, index }: {
50
- ledgerClient: unknown;
51
- ledgerState: LedgerState;
52
- network?: Network;
53
- account: number;
54
- keyPath?: string;
55
- change?: number | undefined;
56
- index?: number | undefined | '*';
57
- }) => Promise<string>;
46
+ export declare const pkhLedger: {
47
+ ({ ledgerManager, account, keyPath, change, index }: {
48
+ ledgerManager: LedgerManager;
49
+ account: number;
50
+ keyPath?: string;
51
+ change?: number | undefined;
52
+ index?: number | undefined | '*';
53
+ }): Promise<string>;
54
+ ({ ledgerClient, ledgerState, network, account, keyPath, change, index }: {
55
+ ledgerClient: unknown;
56
+ ledgerState: LedgerState;
57
+ /** @default networks.bitcoin */
58
+ network?: Network;
59
+ account: number;
60
+ keyPath?: string;
61
+ change?: number | undefined;
62
+ index?: number | undefined | '*';
63
+ }): Promise<string>;
64
+ };
65
+ export declare const shWpkhLedger: {
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
+ };
84
+ export declare const wpkhLedger: {
85
+ ({ ledgerManager, account, keyPath, change, index }: {
86
+ ledgerManager: LedgerManager;
87
+ account: number;
88
+ keyPath?: string;
89
+ change?: number | undefined;
90
+ index?: number | undefined | '*';
91
+ }): Promise<string>;
92
+ ({ ledgerClient, ledgerState, network, account, keyPath, change, index }: {
93
+ ledgerClient: unknown;
94
+ ledgerState: LedgerState;
95
+ /** @default networks.bitcoin */
96
+ network?: Network;
97
+ account: number;
98
+ keyPath?: string;
99
+ change?: number | undefined;
100
+ index?: number | undefined | '*';
101
+ }): Promise<string>;
102
+ };
@@ -11,7 +11,20 @@ function assertStandardKeyPath(keyPath) {
11
11
  }
12
12
  }
13
13
  function standardExpressionsBIP32Maker(purpose, scriptTemplate) {
14
- function standardKeyExpressionBIP32({ masterNode, network = bitcoinjs_lib_1.networks.bitcoin, keyPath, account, change, index, isPublic = true }) {
14
+ /**
15
+ * Computes the standard descriptor based on given parameters.
16
+ *
17
+ * You can define the output location either by:
18
+ * - Providing the full `keyPath` (e.g., "/0/2").
19
+ * OR
20
+ * - Specifying the `change` and `index` values separately (e.g., `{change:0, index:2}`).
21
+ *
22
+ * For ranged indexing, the `index` can be set as a wildcard '*'. For example:
23
+ * - `keyPath="/0/*"`
24
+ * OR
25
+ * - `{change:0, index:'*'}`.
26
+ */
27
+ function standardScriptExpressionBIP32({ masterNode, network = bitcoinjs_lib_1.networks.bitcoin, keyPath, account, change, index, isPublic = true }) {
15
28
  const originPath = `/${purpose}'/${network === bitcoinjs_lib_1.networks.bitcoin ? 0 : 1}'/${account}'`;
16
29
  if (keyPath !== undefined)
17
30
  assertStandardKeyPath(keyPath);
@@ -25,13 +38,22 @@ function standardExpressionsBIP32Maker(purpose, scriptTemplate) {
25
38
  });
26
39
  return scriptTemplate.replace('KEYEXPRESSION', keyExpression);
27
40
  }
28
- return standardKeyExpressionBIP32;
41
+ return standardScriptExpressionBIP32;
29
42
  }
30
43
  exports.pkhBIP32 = standardExpressionsBIP32Maker(44, 'pkh(KEYEXPRESSION)');
31
44
  exports.shWpkhBIP32 = standardExpressionsBIP32Maker(49, 'sh(wpkh(KEYEXPRESSION))');
32
45
  exports.wpkhBIP32 = standardExpressionsBIP32Maker(84, 'wpkh(KEYEXPRESSION)');
33
46
  function standardExpressionsLedgerMaker(purpose, scriptTemplate) {
34
- async function standardKeyExpressionLedger({ ledgerClient, ledgerState, network = bitcoinjs_lib_1.networks.bitcoin, account, keyPath, change, index }) {
47
+ /** @hidden */
48
+ async function standardScriptExpressionLedger({ ledgerClient, ledgerState, ledgerManager, network = bitcoinjs_lib_1.networks.bitcoin, account, keyPath, change, index }) {
49
+ if (ledgerManager && (ledgerClient || ledgerState))
50
+ throw new Error(`ledgerClient and ledgerState have been deprecated`);
51
+ if (ledgerManager && network)
52
+ throw new Error(`ledgerManager already includes the network object`);
53
+ if (ledgerManager)
54
+ ({ ledgerClient, ledgerState, network } = ledgerManager);
55
+ if (!ledgerClient || !ledgerState)
56
+ throw new Error(`Could not retrieve ledgerClient or ledgerState`);
35
57
  const originPath = `/${purpose}'/${network === bitcoinjs_lib_1.networks.bitcoin ? 0 : 1}'/${account}'`;
36
58
  if (keyPath !== undefined)
37
59
  assertStandardKeyPath(keyPath);
@@ -45,7 +67,7 @@ function standardExpressionsLedgerMaker(purpose, scriptTemplate) {
45
67
  });
46
68
  return scriptTemplate.replace('KEYEXPRESSION', keyExpression);
47
69
  }
48
- return standardKeyExpressionLedger;
70
+ return standardScriptExpressionLedger;
49
71
  }
50
72
  exports.pkhLedger = standardExpressionsLedgerMaker(44, 'pkh(KEYEXPRESSION)');
51
73
  exports.shWpkhLedger = standardExpressionsLedgerMaker(49, 'sh(wpkh(KEYEXPRESSION))');
package/dist/signers.d.ts CHANGED
@@ -1,8 +1,8 @@
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 { DescriptorInterface } from './types';
5
- import { LedgerState } from './ledger';
4
+ import type { DescriptorInstance } from './descriptors';
5
+ import { LedgerState, LedgerManager } from './ledger';
6
6
  export declare function signInputECPair({ psbt, index, ecpair }: {
7
7
  psbt: Psbt;
8
8
  index: number;
@@ -21,16 +21,49 @@ export declare function signBIP32({ psbt, masterNode }: {
21
21
  psbt: Psbt;
22
22
  masterNode: BIP32Interface;
23
23
  }): void;
24
+ /**
25
+ * Signs an input of the `psbt` where the keys are controlled by a Ledger
26
+ * device.
27
+ *
28
+ * The function will throw an error if it's unable to sign the input.
29
+ */
30
+ export declare function signInputLedger({ psbt, index, ledgerManager }: {
31
+ psbt: Psbt;
32
+ index: number;
33
+ ledgerManager: LedgerManager;
34
+ }): Promise<void>;
35
+ /**
36
+ * @deprecated
37
+ * @hidden
38
+ */
24
39
  export declare function signInputLedger({ psbt, index, descriptor, ledgerClient, ledgerState }: {
25
40
  psbt: Psbt;
26
41
  index: number;
27
- descriptor: DescriptorInterface;
42
+ descriptor: DescriptorInstance;
28
43
  ledgerClient: unknown;
29
44
  ledgerState: LedgerState;
30
45
  }): Promise<void>;
46
+ /**
47
+ * Signs the inputs of the `psbt` where the keys are controlled by a Ledger
48
+ * device.
49
+ *
50
+ * `signLedger` can sign multiple inputs of the same wallet policy in a single
51
+ * pass by grouping inputs by their wallet policy type before the signing
52
+ * process.
53
+ *
54
+ * The function will throw an error if it's unable to sign any input.
55
+ */
56
+ export declare function signLedger({ psbt, ledgerManager }: {
57
+ psbt: Psbt;
58
+ ledgerManager: LedgerManager;
59
+ }): Promise<void>;
60
+ /**
61
+ * @deprecated
62
+ * @hidden
63
+ */
31
64
  export declare function signLedger({ psbt, descriptors, ledgerClient, ledgerState }: {
32
65
  psbt: Psbt;
33
- descriptors: DescriptorInterface[];
66
+ descriptors: DescriptorInstance[];
34
67
  ledgerClient: unknown;
35
68
  ledgerState: LedgerState;
36
69
  }): Promise<void>;