@swapkit/wallet-hardware 4.9.11 → 4.9.13

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.
@@ -17,7 +17,7 @@ export declare const ledgerWallet: {
17
17
  connectLedger: {
18
18
  connectWallet: ({ addChain }: {
19
19
  addChain: import("@swapkit/helpers").AddChainType;
20
- }) => (chains: Chain[], derivationPath?: [44, 118, 0, 0, 0] | [44, 931, 0, 0, 0] | [number, number, number, number, number] | [44, 637, 0, 0, 0] | [44, 60, 0, 0, 0] | [44, 397, 0, 0, 0] | [0, 0, 0, 0, 0] | [44, 144, 0, 0, 0] | [44, 501, 0, 0, 0] | [44, 607, 0, 0, 0] | [44, 195, 0, 0, 0] | [44, 148, 0, 0, 0] | [44, 784, 0, 0, 0] | [1852, 1815, 0, 0, 0] | [44, 9004, 0, 0, 0] | [number, number, number, number, (number | undefined)?] | [44, 145, 0, 0, 0] | [84, 2, 0, 0, 0] | [44, 3, 0, 0, 0] | [44, 5, 0, 0, 0] | [44, 133, 0, 0, 0] | undefined, params_2?: ConnectLedgerOptions | undefined) => Promise<boolean>;
20
+ }) => (chains: Chain[], derivationPath?: [44, 118, 0, 0, 0] | [44, 931, 0, 0, 0] | [number, number, number, number, number] | [44, 637, 0, 0, 0] | [44, 60, 0, 0, 0] | [44, 397, 0, 0, 0] | [0, 0, 0, 0, 0] | [44, 144, 0, 0, 0] | [44, 501, 0, 0, 0] | [8797555, 1, 0, 0, 0] | [44, 607, 0, 0, 0] | [44, 195, 0, 0, 0] | [44, 148, 0, 0, 0] | [44, 784, 0, 0, 0] | [1852, 1815, 0, 0, 0] | [44, 9004, 0, 0, 0] | [number, number, number, number, (number | undefined)?] | [44, 145, 0, 0, 0] | [84, 2, 0, 0, 0] | [44, 3, 0, 0, 0] | [44, 5, 0, 0, 0] | [44, 133, 0, 0, 0] | undefined, params_2?: ConnectLedgerOptions | undefined) => Promise<boolean>;
21
21
  directSigningSupport: import("@swapkit/wallet-core").DirectSigningSupport;
22
22
  getExtendedPublicKey?: import("@swapkit/wallet-core").GetExtendedPublicKey;
23
23
  supportedChains: (Chain.Arbitrum | Chain.Aurora | Chain.Avalanche | Chain.Base | Chain.Berachain | Chain.BinanceSmartChain | Chain.Bitcoin | Chain.BitcoinCash | Chain.Cosmos | Chain.Dash | Chain.Dogecoin | Chain.Ethereum | Chain.Gnosis | Chain.Litecoin | Chain.Monad | Chain.Near | Chain.Optimism | Chain.Polygon | Chain.Ripple | Chain.Sui | Chain.THORChain | Chain.Tron | Chain.XLayer | Chain.Zcash)[];
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ledger/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAEL,KAAK,EACL,KAAK,mBAAmB,EAUzB,MAAM,kBAAkB,CAAC;AAe1B,OAAO,EAA0C,KAAK,6BAA6B,EAAE,MAAM,sBAAsB,CAAC;AAGlH;;;;;;;GAOG;AACH,MAAM,MAAM,oBAAoB,GAAG;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,SAAS,CAAA;CAAE,CAAC;AAE/E,eAAO,MAAM,YAAY;;;;;;;;;CAyEvB,CAAC;AAEH,eAAO,MAAM,uBAAuB,mYAAyC,CAAC;AAW9E,wBAAsB,0BAA0B,CAC9C,KAAK,EAAE,KAAK,EACZ,cAAc,CAAC,EAAE,mBAAmB,EACpC,EAAE,YAAY,EAAE,GAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/C,OAAO,CAAC,6BAA6B,GAAG,SAAS,CAAC,CAgBpD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ledger/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAEL,KAAK,EACL,KAAK,mBAAmB,EAUzB,MAAM,kBAAkB,CAAC;AAe1B,OAAO,EAA0C,KAAK,6BAA6B,EAAE,MAAM,sBAAsB,CAAC;AAGlH;;;;;;;GAOG;AACH,MAAM,MAAM,oBAAoB,GAAG;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,SAAS,CAAA;CAAE,CAAC;AAE/E,eAAO,MAAM,YAAY;;;;;;;;;CAyEvB,CAAC;AAEH,eAAO,MAAM,uBAAuB,mYAAyC,CAAC;AAW9E,wBAAsB,0BAA0B,CAC9C,KAAK,EAAE,KAAK,EACZ,cAAc,CAAC,EAAE,mBAAmB,EACpC,EAAE,YAAY,EAAE,GAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/C,OAAO,CAAC,6BAA6B,GAAG,SAAS,CAAC,CAmBpD"}
@@ -12,7 +12,7 @@ export declare const trezorWallet: {
12
12
  connectTrezor: {
13
13
  connectWallet: ({ addChain }: {
14
14
  addChain: import("@swapkit/helpers").AddChainType;
15
- }) => (chains: Chain[], derivationPath: [44, 118, 0, 0, 0] | [44, 931, 0, 0, 0] | [number, number, number, number, number] | [44, 637, 0, 0, 0] | [44, 60, 0, 0, 0] | [44, 397, 0, 0, 0] | [0, 0, 0, 0, 0] | [44, 144, 0, 0, 0] | [44, 501, 0, 0, 0] | [44, 607, 0, 0, 0] | [44, 195, 0, 0, 0] | [44, 148, 0, 0, 0] | [44, 784, 0, 0, 0] | [1852, 1815, 0, 0, 0] | [44, 9004, 0, 0, 0] | [number, number, number, number, (number | undefined)?] | [44, 145, 0, 0, 0] | [84, 2, 0, 0, 0] | [44, 3, 0, 0, 0] | [44, 5, 0, 0, 0] | [44, 133, 0, 0, 0], params_2?: ConnectTrezorOptions | undefined) => Promise<boolean>;
15
+ }) => (chains: Chain[], derivationPath: [44, 118, 0, 0, 0] | [44, 931, 0, 0, 0] | [number, number, number, number, number] | [44, 637, 0, 0, 0] | [44, 60, 0, 0, 0] | [44, 397, 0, 0, 0] | [0, 0, 0, 0, 0] | [44, 144, 0, 0, 0] | [44, 501, 0, 0, 0] | [8797555, 1, 0, 0, 0] | [44, 607, 0, 0, 0] | [44, 195, 0, 0, 0] | [44, 148, 0, 0, 0] | [44, 784, 0, 0, 0] | [1852, 1815, 0, 0, 0] | [44, 9004, 0, 0, 0] | [number, number, number, number, (number | undefined)?] | [44, 145, 0, 0, 0] | [84, 2, 0, 0, 0] | [44, 3, 0, 0, 0] | [44, 5, 0, 0, 0] | [44, 133, 0, 0, 0], params_2?: ConnectTrezorOptions | undefined) => Promise<boolean>;
16
16
  directSigningSupport: import("@swapkit/wallet-core").DirectSigningSupport;
17
17
  getExtendedPublicKey?: import("@swapkit/wallet-core").GetExtendedPublicKey;
18
18
  supportedChains: (Chain.Arbitrum | Chain.Aurora | Chain.Avalanche | Chain.Base | Chain.Berachain | Chain.BinanceSmartChain | Chain.Bitcoin | Chain.BitcoinCash | Chain.Dash | Chain.Dogecoin | Chain.Ethereum | Chain.Gnosis | Chain.Litecoin | Chain.Monad | Chain.Optimism | Chain.Polygon | Chain.XLayer | Chain.Zcash)[];
package/package.json CHANGED
@@ -22,10 +22,10 @@
22
22
  "@near-js/transactions": "~2.5.0",
23
23
  "@scure/base": "2.2.0",
24
24
  "@scure/bip32": "2.2.0",
25
- "@swapkit/helpers": "^4.13.9",
26
- "@swapkit/toolboxes": "^4.15.13",
25
+ "@swapkit/helpers": "^4.13.10",
26
+ "@swapkit/toolboxes": "^4.15.14",
27
27
  "@swapkit/utxo-signer": "^2.1.3",
28
- "@swapkit/wallet-core": "^4.3.0",
28
+ "@swapkit/wallet-core": "^4.3.1",
29
29
  "@trezor/connect-web": "~9.7.3",
30
30
  "cosmjs-types": "~0.10.1",
31
31
  "ethers": "^6.14.0",
@@ -109,5 +109,5 @@
109
109
  "type-check:go": "tsgo"
110
110
  },
111
111
  "type": "module",
112
- "version": "4.9.11"
112
+ "version": "4.9.13"
113
113
  }
@@ -17,11 +17,19 @@ import {
17
17
 
18
18
  import { getLedgerTransport } from "../helpers/getLedgerTransport";
19
19
 
20
+ function parseLedgerSignatureV(v: number | string) {
21
+ if (typeof v === "number") return v;
22
+
23
+ const hex = v.startsWith("0x") ? v.slice(2) : v;
24
+ return Number.parseInt(hex || "0", 16);
25
+ }
26
+
20
27
  class EVMLedgerInterface extends AbstractSigner {
21
28
  chainId: ChainId = ChainId.Ethereum;
22
29
  derivationPath = "";
23
30
  ledgerApp: InstanceType<typeof EthereumApp> | null = null;
24
31
  ledgerTimeout = 50000;
32
+ private transport?: Transport;
25
33
  private readonly injectedTransport?: Transport;
26
34
 
27
35
  constructor({
@@ -44,19 +52,20 @@ class EVMLedgerInterface extends AbstractSigner {
44
52
  chainId: this.chainId,
45
53
  derivationPath: this.derivationPath,
46
54
  provider,
47
- transport: this.injectedTransport,
55
+ transport: this.transport ?? this.injectedTransport,
48
56
  });
49
57
 
50
58
  checkOrCreateTransportAndLedger = async () => {
51
- if (this.ledgerApp) return;
52
59
  await this.createTransportAndLedger();
53
60
  };
54
61
 
55
62
  createTransportAndLedger = async () => {
56
- const transport = this.injectedTransport ?? (await getLedgerTransport());
63
+ if (this.ledgerApp) return;
64
+
65
+ this.transport ||= this.injectedTransport ?? (await getLedgerTransport());
57
66
  const EthereumApp = (await import("@ledgerhq/hw-app-eth")).default;
58
67
 
59
- this.ledgerApp = new EthereumApp(transport);
68
+ this.ledgerApp = new EthereumApp(this.transport);
60
69
  };
61
70
 
62
71
  getAddress = async () => {
@@ -141,7 +150,9 @@ class EVMLedgerInterface extends AbstractSigner {
141
150
  const { Transaction } = await import("ethers");
142
151
  await this.createTransportAndLedger();
143
152
 
144
- const transactionCount = await this.provider?.getTransactionCount(tx.from || (await this.getAddress()));
153
+ const nonce = tx.nonce ?? undefined;
154
+ const transactionCount =
155
+ nonce === undefined ? await this.provider?.getTransactionCount(tx.from || (await this.getAddress())) : undefined;
145
156
 
146
157
  const baseTx = {
147
158
  chainId: tx.chainId || this.chainId,
@@ -150,7 +161,7 @@ class EVMLedgerInterface extends AbstractSigner {
150
161
  ...(tx.gasPrice && { gasPrice: tx.gasPrice }),
151
162
  ...(!tx.gasPrice &&
152
163
  tx.maxFeePerGas && { maxFeePerGas: tx.maxFeePerGas, maxPriorityFeePerGas: tx.maxPriorityFeePerGas }),
153
- nonce: tx.nonce !== undefined ? Number((tx.nonce || transactionCount || 0).toString()) : transactionCount,
164
+ nonce: nonce !== undefined ? Number(nonce.toString()) : transactionCount,
154
165
  to: tx.to?.toString(),
155
166
  type: tx.type && !Number.isNaN(tx.type) ? tx.type : tx.maxFeePerGas ? 2 : 0,
156
167
  value: tx.value,
@@ -169,7 +180,8 @@ class EVMLedgerInterface extends AbstractSigner {
169
180
 
170
181
  const { r, s, v } = signature;
171
182
 
172
- return Transaction.from({ ...baseTx, signature: { r: `0x${r}`, s: `0x${s}`, v: Number(BigInt(v)) } }).serialized;
183
+ return Transaction.from({ ...baseTx, signature: { r: `0x${r}`, s: `0x${s}`, v: parseLedgerSignatureV(v) } })
184
+ .serialized;
173
185
  };
174
186
  }
175
187
 
@@ -106,24 +106,25 @@ const BaseLedgerUTXO = ({
106
106
  // Per-call state — each BitcoinLedger/LitecoinLedger/... invocation has its own
107
107
  // transport + btcApp so different consumers (e.g. concurrent MCP sessions) cannot
108
108
  // cross-contaminate each other's Ledger device handle.
109
- let btcApp: InstanceType<typeof BitcoinApp>;
109
+ let btcApp: InstanceType<typeof BitcoinApp> | undefined;
110
110
  let transport: any = null;
111
111
 
112
- async function checkBtcAppAndCreateTransportWebUSB(checkBtcApp = true) {
113
- if (checkBtcApp && !btcApp) {
114
- new SwapKitError("wallet_ledger_connection_error", {
115
- message: `Ledger connection failed:\n${JSON.stringify({ btcApp, checkBtcApp })}`,
116
- });
117
- }
118
-
112
+ async function createTransportWebUSB() {
119
113
  transport ||= injectedTransport ?? (await getLedgerTransport());
114
+ const BitcoinApp = (await import("@ledgerhq/hw-app-btc")).default;
115
+
116
+ btcApp ||= new BitcoinApp({ currency: chain, transport });
117
+ return btcApp;
120
118
  }
121
119
 
122
- async function createTransportWebUSB() {
123
- transport = injectedTransport ?? (await getLedgerTransport());
124
- const BitcoinApp = (await import("@ledgerhq/hw-app-btc")).default;
120
+ async function getBtcApp() {
121
+ return btcApp || (await createTransportWebUSB());
122
+ }
125
123
 
126
- btcApp = new BitcoinApp({ currency: chain, transport });
124
+ async function disconnect() {
125
+ if (!injectedTransport) await transport?.close?.();
126
+ btcApp = undefined;
127
+ transport = null;
127
128
  }
128
129
 
129
130
  const derivationPath =
@@ -135,17 +136,15 @@ const BaseLedgerUTXO = ({
135
136
 
136
137
  return {
137
138
  connect: async () => {
138
- await checkBtcAppAndCreateTransportWebUSB(false);
139
- const BitcoinApp = (await import("@ledgerhq/hw-app-btc")).default;
140
-
141
- btcApp = new BitcoinApp({ currency: chain, transport });
139
+ await getBtcApp();
142
140
  },
141
+ disconnect,
143
142
  getAddress: async () => {
144
143
  const { toCashAddress } = await import("@swapkit/toolboxes/utxo");
145
144
 
146
- await checkBtcAppAndCreateTransportWebUSB(false);
145
+ const app = await getBtcApp();
147
146
 
148
- const { bitcoinAddress: address } = await btcApp.getWalletPublicKey(derivationPath, { format });
147
+ const { bitcoinAddress: address } = await app.getWalletPublicKey(derivationPath, { format });
149
148
 
150
149
  if (!address) {
151
150
  throw new SwapKitError("wallet_ledger_get_address_error", {
@@ -158,9 +157,9 @@ const BaseLedgerUTXO = ({
158
157
  : address;
159
158
  },
160
159
  getExtendedPublicKey: async (path = "84'/0'/0'", xpubVersion = 76067358) => {
161
- await checkBtcAppAndCreateTransportWebUSB(false);
160
+ const app = await getBtcApp();
162
161
 
163
- return btcApp.getWalletXpub({ path, xpubVersion });
162
+ return app.getWalletXpub({ path, xpubVersion });
164
163
  },
165
164
 
166
165
  signPCZT: async (pczt: PCZT): Promise<PCZT> => {
@@ -170,7 +169,7 @@ const BaseLedgerUTXO = ({
170
169
  });
171
170
  }
172
171
 
173
- await createTransportWebUSB();
172
+ const app = await getBtcApp();
174
173
 
175
174
  const { ZcashTransaction, Script } = await import("@swapkit/utxo-signer");
176
175
 
@@ -212,7 +211,7 @@ const BaseLedgerUTXO = ({
212
211
  }
213
212
 
214
213
  const signedTxHex = await signUTXOTransaction(
215
- { btcApp, chain, derivationPath, inputUtxos, tx: unsignedTx as unknown as Transaction },
214
+ { btcApp: app, chain, derivationPath, inputUtxos, tx: unsignedTx as unknown as Transaction },
216
215
  {
217
216
  ...additionalSignParams,
218
217
  expiryHeight: (() => {
@@ -240,9 +239,9 @@ const BaseLedgerUTXO = ({
240
239
  return signedPczt;
241
240
  },
242
241
  signTransaction: async (tx: Transaction, inputUtxos: UTXOType[]) => {
243
- await createTransportWebUSB();
242
+ const app = await getBtcApp();
244
243
 
245
- return signUTXOTransaction({ btcApp, chain, derivationPath, inputUtxos, tx }, additionalSignParams);
244
+ return signUTXOTransaction({ btcApp: app, chain, derivationPath, inputUtxos, tx }, additionalSignParams);
246
245
  },
247
246
 
248
247
  /**
@@ -250,10 +249,10 @@ const BaseLedgerUTXO = ({
250
249
  * Each input can be signed with its own derivation path.
251
250
  */
252
251
  signTransactionWithMultiplePaths: async (tx: Transaction, inputUtxos: UTXOType[], derivationPaths: string[]) => {
253
- await createTransportWebUSB();
252
+ const app = await getBtcApp();
254
253
 
255
254
  return signUTXOTransactionWithMultiplePaths(
256
- { btcApp, chain, derivationPaths, inputUtxos, tx },
255
+ { btcApp: app, chain, derivationPaths, inputUtxos, tx },
257
256
  additionalSignParams,
258
257
  );
259
258
  },
@@ -143,9 +143,12 @@ export async function getLedgerExtendedPublicKey(
143
143
  const path = derivationPathToString(accountPath);
144
144
  const ledgerPath = chain === Chain.Bitcoin || chain === Chain.Litecoin ? path : path.replace(/^m\//, "");
145
145
  const xpubVersion = getNetworkForChain(utxoChain).bip32.public;
146
- const xpub = await signer.getExtendedPublicKey(ledgerPath, xpubVersion);
147
-
148
- return { accountIndex: getUTXOAccountIndexFromPath(accountPath), path, xpub };
146
+ try {
147
+ const xpub = await signer.getExtendedPublicKey(ledgerPath, xpubVersion);
148
+ return { accountIndex: getUTXOAccountIndexFromPath(accountPath), path, xpub };
149
+ } finally {
150
+ await (signer as { disconnect?: () => Promise<void> }).disconnect?.();
151
+ }
149
152
  }
150
153
 
151
154
  async function getWalletMethods({