@exodus/hw-ledger 2.3.1 → 2.4.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
+ ## [2.4.1](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/hw-ledger@2.4.0...@exodus/hw-ledger@2.4.1) (2024-03-15)
7
+
8
+ ### Bug Fixes
9
+
10
+ - don't infinitely hang ([#6143](https://github.com/ExodusMovement/exodus-hydra/issues/6143)) ([3f97e86](https://github.com/ExodusMovement/exodus-hydra/commit/3f97e8603ad5e49a7be3841bb62b01e3d082c9ea))
11
+
12
+ ## [2.4.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/hw-ledger@2.3.1...@exodus/hw-ledger@2.4.0) (2024-03-06)
13
+
14
+ ### Features
15
+
16
+ - add bluetooth support ([#5998](https://github.com/ExodusMovement/exodus-hydra/issues/5998)) ([6160b9e](https://github.com/ExodusMovement/exodus-hydra/commit/6160b9eec796afe0109699b6e1c3291fbaeeede1))
17
+
6
18
  ## [2.3.1](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/hw-ledger@2.3.0...@exodus/hw-ledger@2.3.1) (2024-02-13)
7
19
 
8
20
  ### Bug Fixes
package/lib/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- declare const hardwareWalletLedger: () => {
1
+ import type { HwLedgerConfig } from './module/types';
2
+ declare const hardwareWalletLedger: ({ bluetoothScannerTimeout, }?: Partial<HwLedgerConfig>) => {
2
3
  id: string;
3
4
  definitions: {
4
5
  definition: {
@@ -7,6 +8,9 @@ declare const hardwareWalletLedger: () => {
7
8
  factory: (deps: import("./module").Dependencies) => import("./module").LedgerDiscovery;
8
9
  dependencies: string[];
9
10
  };
11
+ config: {
12
+ bluetoothScannerTimeout: number;
13
+ };
10
14
  }[];
11
15
  };
12
16
  export default hardwareWalletLedger;
package/lib/index.js CHANGED
@@ -1,10 +1,11 @@
1
1
  import ledgerDiscoveryDefinition from './module';
2
- const hardwareWalletLedger = () => {
2
+ const hardwareWalletLedger = ({ bluetoothScannerTimeout = 10000, } = {}) => {
3
3
  return {
4
4
  id: 'hardwareWalletLedger',
5
5
  definitions: [
6
6
  {
7
7
  definition: ledgerDiscoveryDefinition,
8
+ config: { bluetoothScannerTimeout },
8
9
  },
9
10
  ],
10
11
  };
@@ -1,8 +1,9 @@
1
1
  import ExodusModule from '@exodus/module';
2
2
  import { Logger } from '../shared/types';
3
3
  import type { HardwareWalletDescriptor, HardwareWalletDiscovery } from '@exodus/hw-common';
4
- import type { TransportFactory } from './types';
4
+ import type { TransportFactory, HwLedgerConfig } from './types';
5
5
  export type Dependencies = {
6
+ config: HwLedgerConfig;
6
7
  logger: Logger;
7
8
  transportsFactories: {
8
9
  usb: TransportFactory;
@@ -12,7 +13,9 @@ export type Dependencies = {
12
13
  };
13
14
  export declare class LedgerDiscovery extends ExodusModule implements HardwareWalletDiscovery {
14
15
  #private;
15
- constructor({ logger, transportsFactories }: Dependencies);
16
+ constructor({ config, logger, transportsFactories }: Dependencies);
17
+ scan: () => Promise<void>;
18
+ stopScan: (clearDevices?: boolean) => void;
16
19
  list: () => Promise<HardwareWalletDescriptor[]>;
17
20
  getFirstDevice: () => Promise<import("@exodus/hw-common").HardwareWalletDevice<import("@exodus/hw-common").Message>>;
18
21
  }
@@ -5,7 +5,10 @@ import { NoDeviceFoundError, UnknownTransportError } from './errors';
5
5
  const MODULE_ID = 'ledgerDiscovery';
6
6
  export class LedgerDiscovery extends ExodusModule {
7
7
  #transportsFactories;
8
- constructor({ logger, transportsFactories }) {
8
+ #scannerTimeout;
9
+ #scannerBluetooth;
10
+ #discoveredBluetoothDevices = Object.create(null);
11
+ constructor({ config, logger, transportsFactories }) {
9
12
  super({ name: MODULE_ID, logger });
10
13
  if (!(typeof transportsFactories === 'object' &&
11
14
  Object.keys(transportsFactories).length > 0 &&
@@ -14,14 +17,56 @@ export class LedgerDiscovery extends ExodusModule {
14
17
  typeof transportFactory.list === 'function' &&
15
18
  typeof transportFactory.open === 'function')))
16
19
  throw new UnknownTransportError();
20
+ if (!Number.isInteger(config.bluetoothScannerTimeout)) {
21
+ throw new TypeError(`Invalid bluetoothScannerTimeout passed through config`);
22
+ }
17
23
  this.#transportsFactories = transportsFactories;
24
+ this.#scannerTimeout = config.bluetoothScannerTimeout;
18
25
  }
26
+ scan = async () => {
27
+ return new Promise((resolve, reject) => {
28
+ if (this.#transportsFactories.bluetooth) {
29
+ this.stopScan(true);
30
+ this.#scannerBluetooth = this.#transportsFactories.bluetooth.listen({
31
+ next: (evnt) => {
32
+ if (evnt.type === 'add') {
33
+ const descriptor = evnt.descriptor;
34
+ this.#discoveredBluetoothDevices[descriptor.id] = descriptor;
35
+ }
36
+ },
37
+ error: (error) => {
38
+ this._logger.error(`an error occured while scanning for bluetooth devices "${error.message}"`);
39
+ this.stopScan();
40
+ reject(error);
41
+ },
42
+ complete: () => { },
43
+ });
44
+ setTimeout(() => {
45
+ this.stopScan();
46
+ resolve();
47
+ }, this.#scannerTimeout);
48
+ }
49
+ else {
50
+ this._logger.error(`Attempted to perform scan without having bluetooth transport factory`);
51
+ reject(new Error(`Attempted to perform scan without having bluetooth transport factory`));
52
+ }
53
+ });
54
+ };
55
+ stopScan = (clearDevices = false) => {
56
+ if (clearDevices) {
57
+ this.#discoveredBluetoothDevices = Object.create(null);
58
+ }
59
+ if (this.#scannerBluetooth) {
60
+ this.#scannerBluetooth.unsubscribe();
61
+ this.#scannerBluetooth = undefined;
62
+ }
63
+ };
19
64
  list = async () => {
20
65
  const descriptors = [];
21
66
  for (const [transportName, transportFactory] of Object.entries(this.#transportsFactories)) {
22
- const deviceList = await transportFactory.list();
23
67
  switch (transportName) {
24
68
  case 'usb':
69
+ const deviceList = await transportFactory.list();
25
70
  const usbDeviceList = deviceList.map((hidDevice) => ({
26
71
  manufacturer: 'ledger',
27
72
  transport: 'usb',
@@ -30,7 +75,12 @@ export class LedgerDiscovery extends ExodusModule {
30
75
  descriptors.push(...usbDeviceList);
31
76
  break;
32
77
  case 'bluetooth':
33
- this._logger.error('bluetooth is not supported yet!');
78
+ const bluetoothDeviceList = Object.values(this.#discoveredBluetoothDevices).map((bluetoothDevice) => ({
79
+ manufacturer: 'ledger',
80
+ transport: 'bluetooth',
81
+ get: async () => new LedgerDevice({ transportFactory, descriptor: bluetoothDevice }),
82
+ }));
83
+ descriptors.push(...bluetoothDeviceList);
34
84
  break;
35
85
  case 'tcp':
36
86
  descriptors.push({
@@ -61,5 +111,5 @@ export default {
61
111
  id: MODULE_ID,
62
112
  type: 'module',
63
113
  factory: createLedgerDiscovery,
64
- dependencies: ['logger', 'transportsFactories'],
114
+ dependencies: ['config', 'logger', 'transportsFactories'],
65
115
  };
@@ -1,2 +1,5 @@
1
1
  import type Transport from '@ledgerhq/hw-transport';
2
2
  export type TransportFactory = typeof Transport;
3
+ export type HwLedgerConfig = {
4
+ bluetoothScannerTimeout: number;
5
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/hw-ledger",
3
- "version": "2.3.1",
3
+ "version": "2.4.1",
4
4
  "description": "The ledger module",
5
5
  "author": "Exodus Movement Inc.",
6
6
  "repository": {
@@ -22,10 +22,10 @@
22
22
  "build": "tsc --build tsconfig.build.json",
23
23
  "build:watch": "tsc --build tsconfig.build.json && (concurrently 'tsc --build -w tsconfig.build.json')",
24
24
  "clean": "tsc --build --clean",
25
- "test": "jest --testMatch='**/*.unit.test.js' --coverageDirectory coverage/unit",
25
+ "test": "run -T jest --testMatch='**/*.unit.test.js' --coverageDirectory coverage/unit",
26
26
  "zemu:install": "docker pull zondax/builder-zemu:speculos-745fe46f81cfc18114b94a37beaefb58a09c0fcd",
27
27
  "test:integration": "yarn zemu:install && jest --runInBand",
28
- "lint": "eslint . --ignore-path ../../.gitignore",
28
+ "lint": "run -T eslint . --ignore-path ../../.gitignore",
29
29
  "lint:fix": "yarn lint --fix",
30
30
  "prepublishOnly": "yarn run -T build --scope @exodus/hw-ledger"
31
31
  },
@@ -60,13 +60,11 @@
60
60
  "@types/secp256k1": "^4.0.3",
61
61
  "@zondax/zemu": "^0.43.1",
62
62
  "concurrently": "^7.6.0",
63
- "eslint": "^8.44.0",
64
63
  "istanbul-combine": "^0.3.0",
65
- "jest": "^29.1.2",
66
64
  "jest-when": "^3.5.2",
67
65
  "tiny-secp256k1": "^2.2.3",
68
66
  "ts-jest": "^29.0.3",
69
67
  "typescript": "^4.7.3"
70
68
  },
71
- "gitHead": "fac836c7ae4dbf64c3df293db1fb34b632400a02"
69
+ "gitHead": "76208b526d07f6e7b2bd9c23b10f7ed2b9d38f0c"
72
70
  }