@exodus/hardware-wallets 3.5.0 → 3.6.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/CHANGELOG.md CHANGED
@@ -3,6 +3,12 @@
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.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/hardware-wallets@3.5.0...@exodus/hardware-wallets@3.6.0) (2026-01-21)
7
+
8
+ ### Features
9
+
10
+ - feat: trezor passphrase support (#14965)
11
+
6
12
  ## [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
13
 
8
14
  ### 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"];
@@ -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';
@@ -38,7 +38,6 @@ export declare class HardwareWallets implements HardwareSignerProvider {
38
38
  }[]>;
39
39
  canAccessAsset: ({ assetName }: CanAccessAssetParams) => Promise<boolean>;
40
40
  listUseableAssetNames: () => Promise<string[]>;
41
- ensureApplicationIsOpened: ({ assetName }: EnsureApplicationIsOpenedParams) => Promise<void>;
42
41
  getAddress: ({ assetName, accountIndex, addressIndex, multisigData, displayOnDevice, }: GetAddressParams) => Promise<string>;
43
42
  scan: ({ assetName, accountIndexes, addressLimit, addressOffset, }: ScanParams) => Promise<ScanResult>;
44
43
  sync: ({ accountIndex: index, isMultisig }?: SyncParams) => Promise<SyncedKeysId>;
@@ -46,6 +45,7 @@ export declare class HardwareWallets implements HardwareSignerProvider {
46
45
  create: ({ syncedKeysId, isMultisig }: CreateParams) => Promise<WalletAccount>;
47
46
  clearPairingRequest: () => Promise<void>;
48
47
  submitPairingCode: ({ code }: ProcessPairingCodeParams) => Promise<any>;
48
+ setPassphraseMode: ({ enabled }: SetPassphraseModeParams) => Promise<void>;
49
49
  requireDeviceFor: ({ walletAccount }: RequireDeviceForParams) => Promise<{
50
50
  signTransaction: ({ baseAssetName, unsignedTx, walletAccount, multisigData, }: SignTransactionParams) => Promise<any>;
51
51
  signMessage: ({ assetName, derivationPath, message }: SignMessageParams) => Promise<any>;
@@ -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 {
@@ -20,6 +20,15 @@ export class HardwareWallets {
20
20
  #signingRequest;
21
21
  #isRetrying = false;
22
22
  events = new Emitter();
23
+ #requireTrezorDevice = (device) => {
24
+ if (device.descriptor.manufacturer !== WalletAccount.TREZOR_SRC) {
25
+ throw new HardwareWalletManufacturerMismatchError({
26
+ expected: WalletAccount.TREZOR_SRC,
27
+ actual: String(device.descriptor.manufacturer),
28
+ });
29
+ }
30
+ return device;
31
+ };
23
32
  constructor({ assetsModule, ledgerDiscovery, trezorDiscovery, logger, hardwareWalletSigningRequestsAtom, publicKeyStore, wallet, walletAccountsAtom, walletAccounts, }) {
24
33
  this.#assetsModule = assetsModule;
25
34
  this.#ledgerDiscovery = ledgerDiscovery;
@@ -168,7 +177,7 @@ export class HardwareWallets {
168
177
  baseAssetName,
169
178
  scenario,
170
179
  });
171
- await device.ensureApplicationIsOpened(baseAssetName);
180
+ await device.ensureDeviceReady({ baseAssetName, walletAccount });
172
181
  return sign({ device });
173
182
  },
174
183
  resolve: deferred.resolve,
@@ -256,23 +265,6 @@ export class HardwareWallets {
256
265
  const { device } = await this.#getSelectedDevice();
257
266
  return device.listUseableAssetNames();
258
267
  };
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
268
  getAddress = async ({ assetName, accountIndex, addressIndex, multisigData, displayOnDevice, }) => {
277
269
  const asset = this.#assetsModule.getAsset(assetName);
278
270
  const { device } = await this.#getSelectedDevice();
@@ -389,6 +381,7 @@ export class HardwareWallets {
389
381
  const { device } = await this.#getSelectedDevice();
390
382
  const source = device.descriptor.manufacturer;
391
383
  const accountIndex = index ?? this.#walletAccounts.getNextIndex({ source });
384
+ const walletId = (await device.getWalletId?.()) ?? randomBytes(32).toString('hex');
392
385
  const useableAssetNames = new Set(await device.listUseableAssetNames());
393
386
  for (const assetName of useableAssetNames) {
394
387
  const asset = this.#assetsModule.getAsset(assetName);
@@ -413,6 +406,7 @@ export class HardwareWallets {
413
406
  model: device.descriptor.model,
414
407
  assetNames: useableAssetNames,
415
408
  keysToSync,
409
+ walletId,
416
410
  });
417
411
  return id;
418
412
  };
@@ -430,18 +424,14 @@ export class HardwareWallets {
430
424
  const { device } = await this.#getSelectedDevice();
431
425
  const source = device.descriptor.manufacturer;
432
426
  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);
427
+ const { accountIndex, model, walletId } = this.#syncedKeysMap.get(syncedKeysId);
438
428
  const walletAccount = new WalletAccount({
439
429
  label: `${label}${accountIndex === 0 ? '' : '_' + accountIndex}`,
440
430
  icon: source,
441
431
  source,
442
432
  model,
443
433
  index: accountIndex,
444
- id,
434
+ id: walletId,
445
435
  isMultisig: !!isMultisig,
446
436
  });
447
437
  const walletAccountName = walletAccount.toString();
@@ -456,6 +446,11 @@ export class HardwareWallets {
456
446
  submitPairingCode = async ({ code }) => {
457
447
  return this.#trezorDiscovery.submitPairingCode(code);
458
448
  };
449
+ setPassphraseMode = async ({ enabled }) => {
450
+ const { device } = await this.#getSelectedDevice();
451
+ const trezorDevice = this.#requireTrezorDevice(device);
452
+ trezorDevice.setPassphraseMode(enabled ? 'hidden' : 'standard');
453
+ };
459
454
  requireDeviceFor = async ({ walletAccount }) => {
460
455
  return {
461
456
  signTransaction: this.signTransaction,
@@ -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.0",
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": "43e7fa9467acd5e681d99473eb54d9e790130e04"
57
57
  }