@exodus/hardware-wallets 3.5.0 → 3.6.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/CHANGELOG.md CHANGED
@@ -3,6 +3,18 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [3.6.1](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/hardware-wallets@3.6.0...@exodus/hardware-wallets@3.6.1) (2026-02-09)
7
+
8
+ ### Bug Fixes
9
+
10
+ - fix(hardware-wallets): connect ledger evm from fresh wallets (#15201)
11
+
12
+ ## [3.6.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/hardware-wallets@3.5.0...@exodus/hardware-wallets@3.6.0) (2026-01-21)
13
+
14
+ ### Features
15
+
16
+ - feat: trezor passphrase support (#14965)
17
+
6
18
  ## [3.5.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/hardware-wallets@3.4.0...@exodus/hardware-wallets@3.5.0) (2025-12-11)
7
19
 
8
20
  ### Features
@@ -16,7 +16,6 @@ declare const hardwareWalletsApiDefinition: {
16
16
  listUseableAssetNames: () => Promise<string[]>;
17
17
  scanForDevices: (deviceType?: import("libraries/hw-common/lib/types.js").HardwareWalletManufacturer) => Promise<void>;
18
18
  canAccessAsset: ({ assetName }: import("../module/interfaces.js").CanAccessAssetParams) => Promise<boolean>;
19
- ensureApplicationIsOpened: ({ assetName }: import("../module/interfaces.js").EnsureApplicationIsOpenedParams) => Promise<void>;
20
19
  scan: ({ assetName, accountIndexes, addressLimit, addressOffset, }: import("../module/interfaces.js").ScanParams) => Promise<import("../module/interfaces.js").ScanResult>;
21
20
  sync: ({ accountIndex: index, isMultisig }?: import("../module/interfaces.js").SyncParams) => Promise<import("../module/interfaces.js").SyncedKeysId>;
22
21
  addPublicKeysToWalletAccount: ({ walletAccount, syncedKeysId }: import("../module/interfaces.js").StoreSyncedKeysParams) => Promise<void>;
@@ -25,6 +24,7 @@ declare const hardwareWalletsApiDefinition: {
25
24
  cancelSigningRequest: (id: string, fromUI: boolean) => Promise<void>;
26
25
  submitPairingCode: ({ code }: import("../module/interfaces.js").ProcessPairingCodeParams) => Promise<any>;
27
26
  clearPairingRequest: () => () => Promise<void>;
27
+ setPassphraseMode: ({ enabled }: import("../module/interfaces.js").SetPassphraseModeParams) => Promise<void>;
28
28
  };
29
29
  };
30
30
  readonly dependencies: readonly ["hardwareWallets", "txLogMonitors", "restoreProgressTracker"];
package/lib/api/index.js CHANGED
@@ -23,7 +23,6 @@ const createHardwareWalletsApi = ({ hardwareWallets, restoreProgressTracker, txL
23
23
  listUseableAssetNames: hardwareWallets.listUseableAssetNames,
24
24
  scanForDevices: hardwareWallets.scanForDevices,
25
25
  canAccessAsset: hardwareWallets.canAccessAsset,
26
- ensureApplicationIsOpened: hardwareWallets.ensureApplicationIsOpened,
27
26
  scan: hardwareWallets.scan,
28
27
  sync: hardwareWallets.sync,
29
28
  addPublicKeysToWalletAccount: hardwareWallets.addPublicKeysToWalletAccount,
@@ -32,6 +31,7 @@ const createHardwareWalletsApi = ({ hardwareWallets, restoreProgressTracker, txL
32
31
  cancelSigningRequest: hardwareWallets.cancelSigningRequest,
33
32
  submitPairingCode: hardwareWallets.submitPairingCode,
34
33
  clearPairingRequest: () => hardwareWallets.clearPairingRequest,
34
+ setPassphraseMode: hardwareWallets.setPassphraseMode,
35
35
  },
36
36
  };
37
37
  };
package/lib/index.d.ts CHANGED
@@ -19,7 +19,6 @@ declare const hardwareWallets: () => {
19
19
  listUseableAssetNames: () => Promise<string[]>;
20
20
  scanForDevices: (deviceType?: import("libraries/hw-common/lib/types.js").HardwareWalletManufacturer) => Promise<void>;
21
21
  canAccessAsset: ({ assetName }: import("./module/interfaces.js").CanAccessAssetParams) => Promise<boolean>;
22
- ensureApplicationIsOpened: ({ assetName }: import("./module/interfaces.js").EnsureApplicationIsOpenedParams) => Promise<void>;
23
22
  scan: ({ assetName, accountIndexes, addressLimit, addressOffset, }: import("./module/interfaces.js").ScanParams) => Promise<import("./module/interfaces.js").ScanResult>;
24
23
  sync: ({ accountIndex: index, isMultisig }?: import("./module/interfaces.js").SyncParams) => Promise<import("./module/interfaces.js").SyncedKeysId>;
25
24
  addPublicKeysToWalletAccount: ({ walletAccount, syncedKeysId }: import("./module/interfaces.js").StoreSyncedKeysParams) => Promise<void>;
@@ -28,6 +27,7 @@ declare const hardwareWallets: () => {
28
27
  cancelSigningRequest: (id: string, fromUI: boolean) => Promise<void>;
29
28
  submitPairingCode: ({ code }: import("./module/interfaces.js").ProcessPairingCodeParams) => Promise<any>;
30
29
  clearPairingRequest: () => () => Promise<void>;
30
+ setPassphraseMode: ({ enabled }: import("./module/interfaces.js").SetPassphraseModeParams) => Promise<void>;
31
31
  };
32
32
  };
33
33
  readonly dependencies: readonly ["hardwareWallets", "txLogMonitors", "restoreProgressTracker"];
@@ -37,7 +37,7 @@ declare const hardwareWallets: () => {
37
37
  readonly id: "hardwareWallets";
38
38
  readonly type: "module";
39
39
  readonly factory: (opts: import("./module/hardware-wallets.js").Dependencies) => import("./module/hardware-wallets.js").HardwareWallets;
40
- readonly dependencies: readonly ["assetsModule", "logger", "ledgerDiscovery", "trezorDiscovery", "publicKeyStore", "hardwareWalletSigningRequestsAtom", "wallet", "walletAccountsAtom", "walletAccounts"];
40
+ readonly dependencies: readonly ["assetsModule", "logger", "ledgerDiscovery", "trezorDiscovery", "publicKeyStore", "hardwareWalletSigningRequestsAtom", "wallet", "walletAccountsAtom", "walletAccounts", "enabledAssets", "availableAssetNamesAtom"];
41
41
  readonly public: true;
42
42
  };
43
43
  }, {
@@ -1,6 +1,6 @@
1
1
  import { WalletAccount } from '@exodus/models';
2
2
  import Emitter from '@exodus/wild-emitter';
3
- import type { HardwareSignerProvider, CanAccessAssetParams, CreateParams, StoreSyncedKeysParams, ScanParams, SyncParams, EnsureApplicationIsOpenedParams, SignTransactionParams, ScanResult, SyncedKeysId, GetAddressParams, RequireDeviceForParams, ProcessPairingCodeParams, SigningRequestState } from './interfaces.js';
3
+ import type { HardwareSignerProvider, CanAccessAssetParams, CreateParams, StoreSyncedKeysParams, ScanParams, SyncParams, SignTransactionParams, ScanResult, SyncedKeysId, GetAddressParams, RequireDeviceForParams, ProcessPairingCodeParams, SigningRequestState, SetPassphraseModeParams } from './interfaces.js';
4
4
  import type { HardwareWalletDiscovery, HardwareWalletManufacturer, SignMessageParams } from '@exodus/hw-common';
5
5
  import type { Atom } from '@exodus/atoms';
6
6
  import type { IPublicKeyStore } from '@exodus/public-key-provider/lib/module/store/types';
@@ -21,11 +21,13 @@ export type Dependencies = {
21
21
  walletAccounts: any;
22
22
  txLogMonitors: any;
23
23
  restoreProgressTracker: any;
24
+ enabledAssets: any;
25
+ availableAssetNamesAtom: Atom<string[]>;
24
26
  };
25
27
  export declare class HardwareWallets implements HardwareSignerProvider {
26
28
  #private;
27
29
  readonly events: Emitter<string, any>;
28
- constructor({ assetsModule, ledgerDiscovery, trezorDiscovery, logger, hardwareWalletSigningRequestsAtom, publicKeyStore, wallet, walletAccountsAtom, walletAccounts, }: Dependencies);
30
+ constructor({ assetsModule, ledgerDiscovery, trezorDiscovery, logger, hardwareWalletSigningRequestsAtom, publicKeyStore, wallet, walletAccountsAtom, walletAccounts, enabledAssets, availableAssetNamesAtom, }: Dependencies);
29
31
  retrySigningRequest: (id: string) => Promise<void>;
30
32
  cancelSigningRequest: (id: string, fromUI: boolean) => Promise<void>;
31
33
  signTransaction: ({ baseAssetName, unsignedTx, walletAccount, multisigData, }: SignTransactionParams) => Promise<any>;
@@ -38,7 +40,6 @@ export declare class HardwareWallets implements HardwareSignerProvider {
38
40
  }[]>;
39
41
  canAccessAsset: ({ assetName }: CanAccessAssetParams) => Promise<boolean>;
40
42
  listUseableAssetNames: () => Promise<string[]>;
41
- ensureApplicationIsOpened: ({ assetName }: EnsureApplicationIsOpenedParams) => Promise<void>;
42
43
  getAddress: ({ assetName, accountIndex, addressIndex, multisigData, displayOnDevice, }: GetAddressParams) => Promise<string>;
43
44
  scan: ({ assetName, accountIndexes, addressLimit, addressOffset, }: ScanParams) => Promise<ScanResult>;
44
45
  sync: ({ accountIndex: index, isMultisig }?: SyncParams) => Promise<SyncedKeysId>;
@@ -46,6 +47,7 @@ export declare class HardwareWallets implements HardwareSignerProvider {
46
47
  create: ({ syncedKeysId, isMultisig }: CreateParams) => Promise<WalletAccount>;
47
48
  clearPairingRequest: () => Promise<void>;
48
49
  submitPairingCode: ({ code }: ProcessPairingCodeParams) => Promise<any>;
50
+ setPassphraseMode: ({ enabled }: SetPassphraseModeParams) => Promise<void>;
49
51
  requireDeviceFor: ({ walletAccount }: RequireDeviceForParams) => Promise<{
50
52
  signTransaction: ({ baseAssetName, unsignedTx, walletAccount, multisigData, }: SignTransactionParams) => Promise<any>;
51
53
  signMessage: ({ assetName, derivationPath, message }: SignMessageParams) => Promise<any>;
@@ -55,7 +57,7 @@ declare const hardwareWalletsModuleDefinition: {
55
57
  readonly id: "hardwareWallets";
56
58
  readonly type: "module";
57
59
  readonly factory: (opts: Dependencies) => HardwareWallets;
58
- readonly dependencies: readonly ["assetsModule", "logger", "ledgerDiscovery", "trezorDiscovery", "publicKeyStore", "hardwareWalletSigningRequestsAtom", "wallet", "walletAccountsAtom", "walletAccounts"];
60
+ readonly dependencies: readonly ["assetsModule", "logger", "ledgerDiscovery", "trezorDiscovery", "publicKeyStore", "hardwareWalletSigningRequestsAtom", "wallet", "walletAccountsAtom", "walletAccounts", "enabledAssets", "availableAssetNamesAtom"];
59
61
  readonly public: true;
60
62
  };
61
63
  export default hardwareWalletsModuleDefinition;
@@ -3,7 +3,7 @@ import { WalletAccount } from '@exodus/models';
3
3
  import Emitter from '@exodus/wild-emitter';
4
4
  import { randomBytes } from '@exodus/crypto/randomBytes';
5
5
  import delay from 'delay';
6
- import { DeviceUninitializedError, NoDeviceFoundError, UserRefusedError } from '@exodus/hw-common';
6
+ import { DeviceUninitializedError, NoDeviceFoundError, HardwareWalletManufacturerMismatchError, UserRefusedError, } from '@exodus/hw-common';
7
7
  import restrictConcurrency from 'make-concurrent';
8
8
  import pDefer from 'p-defer';
9
9
  export class HardwareWallets {
@@ -16,11 +16,22 @@ export class HardwareWallets {
16
16
  #wallet;
17
17
  #walletAccountsAtom;
18
18
  #walletAccounts;
19
+ #enabledAssets;
20
+ #availableAssetNamesAtom;
19
21
  #syncedKeysMap = new Map();
20
22
  #signingRequest;
21
23
  #isRetrying = false;
22
24
  events = new Emitter();
23
- constructor({ assetsModule, ledgerDiscovery, trezorDiscovery, logger, hardwareWalletSigningRequestsAtom, publicKeyStore, wallet, walletAccountsAtom, walletAccounts, }) {
25
+ #requireTrezorDevice = (device) => {
26
+ if (device.descriptor.manufacturer !== WalletAccount.TREZOR_SRC) {
27
+ throw new HardwareWalletManufacturerMismatchError({
28
+ expected: WalletAccount.TREZOR_SRC,
29
+ actual: String(device.descriptor.manufacturer),
30
+ });
31
+ }
32
+ return device;
33
+ };
34
+ constructor({ assetsModule, ledgerDiscovery, trezorDiscovery, logger, hardwareWalletSigningRequestsAtom, publicKeyStore, wallet, walletAccountsAtom, walletAccounts, enabledAssets, availableAssetNamesAtom, }) {
24
35
  this.#assetsModule = assetsModule;
25
36
  this.#ledgerDiscovery = ledgerDiscovery;
26
37
  this.#trezorDiscovery = trezorDiscovery;
@@ -30,6 +41,8 @@ export class HardwareWallets {
30
41
  this.#wallet = wallet;
31
42
  this.#walletAccountsAtom = walletAccountsAtom;
32
43
  this.#walletAccounts = walletAccounts;
44
+ this.#enabledAssets = enabledAssets;
45
+ this.#availableAssetNamesAtom = availableAssetNamesAtom;
33
46
  }
34
47
  #listTrezorDevicesOrEmpty = async () => {
35
48
  try {
@@ -168,7 +181,7 @@ export class HardwareWallets {
168
181
  baseAssetName,
169
182
  scenario,
170
183
  });
171
- await device.ensureApplicationIsOpened(baseAssetName);
184
+ await device.ensureDeviceReady({ baseAssetName, walletAccount });
172
185
  return sign({ device });
173
186
  },
174
187
  resolve: deferred.resolve,
@@ -256,23 +269,6 @@ export class HardwareWallets {
256
269
  const { device } = await this.#getSelectedDevice();
257
270
  return device.listUseableAssetNames();
258
271
  };
259
- ensureApplicationIsOpened = async ({ assetName }) => {
260
- const asset = this.#assetsModule.getAsset(assetName);
261
- let i = 0;
262
- while (i < 3) {
263
- try {
264
- const { device } = await this.#getSelectedDevice();
265
- await device.ensureApplicationIsOpened(asset.baseAsset.name);
266
- }
267
- catch (error) {
268
- this.#logger.log(error);
269
- }
270
- finally {
271
- await delay(1000);
272
- i++;
273
- }
274
- }
275
- };
276
272
  getAddress = async ({ assetName, accountIndex, addressIndex, multisigData, displayOnDevice, }) => {
277
273
  const asset = this.#assetsModule.getAsset(assetName);
278
274
  const { device } = await this.#getSelectedDevice();
@@ -389,6 +385,7 @@ export class HardwareWallets {
389
385
  const { device } = await this.#getSelectedDevice();
390
386
  const source = device.descriptor.manufacturer;
391
387
  const accountIndex = index ?? this.#walletAccounts.getNextIndex({ source });
388
+ const walletId = (await device.getWalletId?.()) ?? randomBytes(32).toString('hex');
392
389
  const useableAssetNames = new Set(await device.listUseableAssetNames());
393
390
  for (const assetName of useableAssetNames) {
394
391
  const asset = this.#assetsModule.getAsset(assetName);
@@ -413,6 +410,7 @@ export class HardwareWallets {
413
410
  model: device.descriptor.model,
414
411
  assetNames: useableAssetNames,
415
412
  keysToSync,
413
+ walletId,
416
414
  });
417
415
  return id;
418
416
  };
@@ -423,6 +421,9 @@ export class HardwareWallets {
423
421
  const { xpub, publicKey } = keys;
424
422
  await this.#publicKeyStore.add({ walletAccount, keyIdentifier, xpub, publicKey });
425
423
  }
424
+ const availableAssetNames = await this.#availableAssetNamesAtom.get();
425
+ const assetNamesToEnable = [...assetNames].filter((assetName) => availableAssetNames.includes(assetName));
426
+ await this.#enabledAssets.enable(assetNamesToEnable);
426
427
  this.events.emit('syncAssets', { assetNames });
427
428
  };
428
429
  create = async ({ syncedKeysId, isMultisig }) => {
@@ -430,18 +431,14 @@ export class HardwareWallets {
430
431
  const { device } = await this.#getSelectedDevice();
431
432
  const source = device.descriptor.manufacturer;
432
433
  const label = source === WalletAccount.LEDGER_SRC ? 'Ledger' : 'Trezor';
433
- const id = source === WalletAccount.TREZOR_SRC
434
- ? device.descriptor.internalDescriptor
435
- :
436
- randomBytes(32).toString('hex');
437
- const { accountIndex, model } = this.#syncedKeysMap.get(syncedKeysId);
434
+ const { accountIndex, model, walletId } = this.#syncedKeysMap.get(syncedKeysId);
438
435
  const walletAccount = new WalletAccount({
439
436
  label: `${label}${accountIndex === 0 ? '' : '_' + accountIndex}`,
440
437
  icon: source,
441
438
  source,
442
439
  model,
443
440
  index: accountIndex,
444
- id,
441
+ id: walletId,
445
442
  isMultisig: !!isMultisig,
446
443
  });
447
444
  const walletAccountName = walletAccount.toString();
@@ -456,6 +453,11 @@ export class HardwareWallets {
456
453
  submitPairingCode = async ({ code }) => {
457
454
  return this.#trezorDiscovery.submitPairingCode(code);
458
455
  };
456
+ setPassphraseMode = async ({ enabled }) => {
457
+ const { device } = await this.#getSelectedDevice();
458
+ const trezorDevice = this.#requireTrezorDevice(device);
459
+ trezorDevice.setPassphraseMode(enabled ? 'hidden' : 'standard');
460
+ };
459
461
  requireDeviceFor = async ({ walletAccount }) => {
460
462
  return {
461
463
  signTransaction: this.signTransaction,
@@ -478,6 +480,8 @@ const hardwareWalletsModuleDefinition = {
478
480
  'wallet',
479
481
  'walletAccountsAtom',
480
482
  'walletAccounts',
483
+ 'enabledAssets',
484
+ 'availableAssetNamesAtom',
481
485
  ],
482
486
  public: true,
483
487
  };
@@ -6,7 +6,6 @@ export interface HardwareSignerProvider {
6
6
  scanForDevices: (deviceType: HardwareWalletManufacturer) => Promise<void>;
7
7
  canAccessAsset: ({ assetName }: CanAccessAssetParams) => Promise<boolean>;
8
8
  listUseableAssetNames: () => Promise<string[]>;
9
- ensureApplicationIsOpened: ({ assetName }: EnsureApplicationIsOpenedParams) => Promise<void>;
10
9
  scan: ({ assetName, accountIndexes, addressOffset }: ScanParams) => Promise<ScanResult>;
11
10
  sync: ({ accountIndex }: SyncParams) => Promise<SyncedKeysId>;
12
11
  addPublicKeysToWalletAccount: ({ walletAccount, syncedKeysId, }: StoreSyncedKeysParams) => Promise<void>;
@@ -14,6 +13,7 @@ export interface HardwareSignerProvider {
14
13
  signTransaction: ({ baseAssetName, unsignedTx, walletAccount, }: SignTransactionParams) => Promise<any>;
15
14
  signMessage: ({ assetName, derivationPath, message }: SignMessageParams) => Promise<any>;
16
15
  submitPairingCode: ({ code }: ProcessPairingCodeParams) => Promise<any>;
16
+ setPassphraseMode: ({ enabled }: SetPassphraseModeParams) => Promise<void>;
17
17
  }
18
18
  type Asset = {
19
19
  name: string;
@@ -64,6 +64,7 @@ export interface SyncedKeysData {
64
64
  model: HardwareWalletDeviceModels;
65
65
  assetNames: Set<string>;
66
66
  keysToSync: KeyToSyncData[];
67
+ walletId: string;
67
68
  }
68
69
  export type KeyToSyncData = [KeyIdentifier, {
69
70
  xpub?: string;
@@ -148,4 +149,7 @@ export interface RequireDeviceForParams {
148
149
  export interface ProcessPairingCodeParams {
149
150
  code: string;
150
151
  }
152
+ export interface SetPassphraseModeParams {
153
+ enabled: boolean;
154
+ }
151
155
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/hardware-wallets",
3
- "version": "3.5.0",
3
+ "version": "3.6.1",
4
4
  "description": "An Exodus SDK feature that provides a high level abstraction for interacting with hardware wallet devices",
5
5
  "author": "Exodus Movement, Inc.",
6
6
  "repository": {
@@ -32,7 +32,7 @@
32
32
  "@exodus/basic-utils": "^3.2.0",
33
33
  "@exodus/bip32": "^4.0.2",
34
34
  "@exodus/crypto": "^1.0.0-rc.14",
35
- "@exodus/hw-common": "^3.3.0",
35
+ "@exodus/hw-common": "^3.4.0",
36
36
  "@exodus/models": "^12.18.0",
37
37
  "@exodus/redux-dependency-injection": "^4.0.0",
38
38
  "@exodus/wild-emitter": "^1.1.0",
@@ -53,5 +53,5 @@
53
53
  "access": "public",
54
54
  "provenance": false
55
55
  },
56
- "gitHead": "91c5651b997e904755c35158697523f816611d71"
56
+ "gitHead": "e0cdf475edecde771229c25e2e0b1eb61ad52030"
57
57
  }