@exodus/hw-ledger 2.6.0 → 2.8.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,23 @@
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.8.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/hw-ledger@2.7.0...@exodus/hw-ledger@2.8.0) (2024-07-10)
7
+
8
+ ### Features
9
+
10
+ - **ledger:** add redux module ([#7734](https://github.com/ExodusMovement/exodus-hydra/issues/7734)) ([a26cb0a](https://github.com/ExodusMovement/exodus-hydra/commit/a26cb0ae76730d20ad6bbbb931f7c0f28094dbf4))
11
+
12
+ ### Bug Fixes
13
+
14
+ - **ledger:** add missing atom ([#7731](https://github.com/ExodusMovement/exodus-hydra/issues/7731)) ([34b77d5](https://github.com/ExodusMovement/exodus-hydra/commit/34b77d5f3a7a1aca97646137e94b42758e5aaa85))
15
+
16
+ ## [2.7.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/hw-ledger@2.6.0...@exodus/hw-ledger@2.7.0) (2024-07-04)
17
+
18
+ ### Features
19
+
20
+ - **ledger:** add `bluetoothScanningAtom` atom to indicate if scanning ([#7645](https://github.com/ExodusMovement/exodus-hydra/issues/7645)) ([bc377ea](https://github.com/ExodusMovement/exodus-hydra/commit/bc377ea7c4b1dd3a33b892791b80ea53e8ec2b58))
21
+ - **ledger:** support retrieving BLE status ([#7631](https://github.com/ExodusMovement/exodus-hydra/issues/7631)) ([22eebc1](https://github.com/ExodusMovement/exodus-hydra/commit/22eebc1a059c502644f515897aefd1b4ef268cad))
22
+
6
23
  ## [2.6.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/hw-ledger@2.5.1...@exodus/hw-ledger@2.6.0) (2024-07-03)
7
24
 
8
25
  ### Features
@@ -0,0 +1,12 @@
1
+ export declare const bluetoothEnabledAtomDefinition: {
2
+ readonly id: "bluetoothEnabledAtom";
3
+ readonly type: "atom";
4
+ readonly factory: () => import("@exodus/atoms").Atom<boolean>;
5
+ readonly dependencies: readonly [];
6
+ };
7
+ export declare const bluetoothScanningAtomDefinition: {
8
+ readonly id: "bluetoothScanningAtom";
9
+ readonly type: "atom";
10
+ readonly factory: () => import("@exodus/atoms").Atom<boolean>;
11
+ readonly dependencies: readonly [];
12
+ };
@@ -0,0 +1,13 @@
1
+ import { createInMemoryAtom } from '@exodus/atoms';
2
+ export const bluetoothEnabledAtomDefinition = {
3
+ id: 'bluetoothEnabledAtom',
4
+ type: 'atom',
5
+ factory: () => createInMemoryAtom({ defaultValue: false }),
6
+ dependencies: [],
7
+ };
8
+ export const bluetoothScanningAtomDefinition = {
9
+ id: 'bluetoothScanningAtom',
10
+ type: 'atom',
11
+ factory: () => createInMemoryAtom({ defaultValue: false }),
12
+ dependencies: [],
13
+ };
package/lib/index.d.ts CHANGED
@@ -1,16 +1,47 @@
1
1
  import type { HwLedgerConfig } from './module/types';
2
2
  declare const hardwareWalletLedger: ({ bluetoothScannerTimeout, }?: Partial<HwLedgerConfig>) => {
3
- id: string;
4
- definitions: {
5
- definition: {
3
+ readonly id: "hardwareWalletLedger";
4
+ readonly definitions: readonly [{
5
+ readonly definition: {
6
+ readonly id: "bluetoothEnabledAtom";
7
+ readonly type: "atom";
8
+ readonly factory: () => import("libraries/atoms/lib").Atom<boolean>;
9
+ readonly dependencies: readonly [];
10
+ };
11
+ }, {
12
+ readonly definition: {
13
+ readonly id: "bluetoothScanningAtom";
14
+ readonly type: "atom";
15
+ readonly factory: () => import("libraries/atoms/lib").Atom<boolean>;
16
+ readonly dependencies: readonly [];
17
+ };
18
+ }, {
19
+ readonly definition: {
20
+ readonly id: "hardwareWalletLedgerPlugin";
21
+ readonly type: "plugin";
22
+ readonly factory: ({ logger, transportsFactories, bluetoothEnabledAtom, bluetoothScanningAtom, port, }: {
23
+ logger: import("./shared/types").Logger;
24
+ transportsFactories: import("./module/types").TransportFactories;
25
+ bluetoothEnabledAtom: import("libraries/atoms/lib").Atom<boolean>;
26
+ bluetoothScanningAtom: import("libraries/atoms/lib").Atom<boolean>;
27
+ port: import("./shared/types").Port;
28
+ }) => {
29
+ onUnlock: () => void;
30
+ onLoad: () => void;
31
+ onStop: () => void;
32
+ };
33
+ readonly dependencies: readonly ["logger", "transportsFactories", "bluetoothEnabledAtom", "bluetoothScanningAtom", "port"];
34
+ };
35
+ }, {
36
+ readonly definition: {
6
37
  readonly id: "ledgerDiscovery";
7
38
  readonly type: "module";
8
39
  readonly factory: (deps: import("./module").Dependencies) => import("./module").LedgerDiscovery;
9
- readonly dependencies: readonly ["config", "logger", "transportsFactories"];
40
+ readonly dependencies: readonly ["config", "logger", "transportsFactories", "bluetoothScanningAtom"];
10
41
  };
11
- config: {
12
- bluetoothScannerTimeout: number;
42
+ readonly config: {
43
+ readonly bluetoothScannerTimeout: number;
13
44
  };
14
- }[];
45
+ }];
15
46
  };
16
47
  export default hardwareWalletLedger;
package/lib/index.js CHANGED
@@ -1,8 +1,19 @@
1
+ import { bluetoothEnabledAtomDefinition, bluetoothScanningAtomDefinition } from './atoms';
1
2
  import ledgerDiscoveryDefinition from './module';
3
+ import hardwareWalletLedgerPluginDefinition from './plugin';
2
4
  const hardwareWalletLedger = ({ bluetoothScannerTimeout = 10000, } = {}) => {
3
5
  return {
4
6
  id: 'hardwareWalletLedger',
5
7
  definitions: [
8
+ {
9
+ definition: bluetoothEnabledAtomDefinition,
10
+ },
11
+ {
12
+ definition: bluetoothScanningAtomDefinition,
13
+ },
14
+ {
15
+ definition: hardwareWalletLedgerPluginDefinition,
16
+ },
6
17
  {
7
18
  definition: ledgerDiscoveryDefinition,
8
19
  config: { bluetoothScannerTimeout },
@@ -1,19 +1,16 @@
1
- import ExodusModule from '@exodus/module';
2
1
  import { Logger } from '../shared/types';
2
+ import type { Atom } from '@exodus/atoms';
3
3
  import type { HardwareWalletDescriptor, HardwareWalletDiscovery } from '@exodus/hw-common';
4
- import type { TransportFactory, HwLedgerConfig } from './types';
4
+ import type { HwLedgerConfig, TransportFactories } from './types';
5
5
  export type Dependencies = {
6
6
  config: HwLedgerConfig;
7
7
  logger: Logger;
8
- transportsFactories: {
9
- usb: TransportFactory;
10
- bluetooth: TransportFactory;
11
- tcp: TransportFactory;
12
- };
8
+ transportsFactories: TransportFactories;
9
+ bluetoothScanningAtom: Atom<boolean>;
13
10
  };
14
- export declare class LedgerDiscovery extends ExodusModule implements HardwareWalletDiscovery {
11
+ export declare class LedgerDiscovery implements HardwareWalletDiscovery {
15
12
  #private;
16
- constructor({ config, logger, transportsFactories }: Dependencies);
13
+ constructor({ config, logger, transportsFactories, bluetoothScanningAtom }: Dependencies);
17
14
  scan: () => Promise<void>;
18
15
  stopScan: (clearDevices?: boolean) => void;
19
16
  list: () => Promise<HardwareWalletDescriptor[]>;
@@ -23,6 +20,6 @@ declare const _default: {
23
20
  readonly id: "ledgerDiscovery";
24
21
  readonly type: "module";
25
22
  readonly factory: (deps: Dependencies) => LedgerDiscovery;
26
- readonly dependencies: readonly ["config", "logger", "transportsFactories"];
23
+ readonly dependencies: readonly ["config", "logger", "transportsFactories", "bluetoothScanningAtom"];
27
24
  };
28
25
  export default _default;
@@ -1,16 +1,18 @@
1
- import ExodusModule from '@exodus/module';
2
1
  import { getInfosForServiceUuid, identifyUSBProductId } from '@exodus/ledgerhq-devices';
3
2
  import { APDU_PORT } from './constants';
4
3
  import { LedgerDevice } from './device';
5
4
  import { NoDeviceFoundError, UnknownTransportError } from './errors';
6
5
  const MODULE_ID = 'ledgerDiscovery';
7
- export class LedgerDiscovery extends ExodusModule {
6
+ export class LedgerDiscovery {
7
+ #logger;
8
8
  #transportsFactories;
9
9
  #scannerTimeout;
10
10
  #scannerBluetooth;
11
+ #bluetoothScanningAtom;
11
12
  #discoveredBluetoothDevices = Object.create(null);
12
- constructor({ config, logger, transportsFactories }) {
13
- super({ name: MODULE_ID, logger });
13
+ constructor({ config, logger, transportsFactories, bluetoothScanningAtom }) {
14
+ this.#logger = logger;
15
+ this.#bluetoothScanningAtom = bluetoothScanningAtom;
14
16
  if (!(typeof transportsFactories === 'object' &&
15
17
  Object.keys(transportsFactories).length > 0 &&
16
18
  Object.entries(transportsFactories).every(([transportName, transportFactory]) => ['usb', 'bluetooth', 'tcp'].includes(transportName) &&
@@ -36,19 +38,20 @@ export class LedgerDiscovery extends ExodusModule {
36
38
  }
37
39
  },
38
40
  error: (error) => {
39
- this._logger.error(`an error occured while scanning for bluetooth devices "${error.message}"`);
41
+ this.#logger.error(`an error occured while scanning for bluetooth devices "${error.message}"`);
40
42
  this.stopScan();
41
43
  reject(error);
42
44
  },
43
45
  complete: () => { },
44
46
  });
47
+ this.#bluetoothScanningAtom.set(true);
45
48
  setTimeout(() => {
46
49
  this.stopScan();
47
50
  resolve();
48
51
  }, this.#scannerTimeout);
49
52
  }
50
53
  else {
51
- this._logger.error(`Attempted to perform scan without having bluetooth transport factory`);
54
+ this.#logger.error(`Attempted to perform scan without having bluetooth transport factory`);
52
55
  reject(new Error(`Attempted to perform scan without having bluetooth transport factory`));
53
56
  }
54
57
  });
@@ -58,6 +61,7 @@ export class LedgerDiscovery extends ExodusModule {
58
61
  this.#discoveredBluetoothDevices = Object.create(null);
59
62
  }
60
63
  if (this.#scannerBluetooth) {
64
+ this.#bluetoothScanningAtom.set(false);
61
65
  this.#scannerBluetooth.unsubscribe();
62
66
  this.#scannerBluetooth = undefined;
63
67
  }
@@ -125,5 +129,5 @@ export default {
125
129
  id: MODULE_ID,
126
130
  type: 'module',
127
131
  factory: createLedgerDiscovery,
128
- dependencies: ['config', 'logger', 'transportsFactories'],
132
+ dependencies: ['config', 'logger', 'transportsFactories', 'bluetoothScanningAtom'],
129
133
  };
@@ -1,5 +1,21 @@
1
1
  import type Transport from '@ledgerhq/hw-transport';
2
+ import type { TransportTypes } from '@exodus/hw-common';
3
+ import type { Subscription } from '@ledgerhq/hw-transport';
2
4
  export type TransportFactory = typeof Transport;
5
+ export type TransportFactories = Partial<Record<TransportTypes, TransportFactory>> & {
6
+ bluetooth?: TransportFactory & {
7
+ observeAvailability?: (observer: {
8
+ next: (available: boolean) => void;
9
+ error: (err: Error) => void;
10
+ }) => Subscription;
11
+ observeState?: (observer: {
12
+ next: (evt: {
13
+ available: boolean;
14
+ }) => void;
15
+ error: (err: Error) => void;
16
+ }) => Subscription;
17
+ };
18
+ };
3
19
  export type HwLedgerConfig = {
4
20
  bluetoothScannerTimeout: number;
5
21
  };
@@ -0,0 +1,20 @@
1
+ import type { Atom } from '@exodus/atoms';
2
+ import type { TransportFactories } from '../module/types';
3
+ import type { Logger, Port } from '../shared/types';
4
+ declare const hardwareWalletLedgerPluginDefinition: {
5
+ readonly id: "hardwareWalletLedgerPlugin";
6
+ readonly type: "plugin";
7
+ readonly factory: ({ logger, transportsFactories, bluetoothEnabledAtom, bluetoothScanningAtom, port, }: {
8
+ logger: Logger;
9
+ transportsFactories: TransportFactories;
10
+ bluetoothEnabledAtom: Atom<boolean>;
11
+ bluetoothScanningAtom: Atom<boolean>;
12
+ port: Port;
13
+ }) => {
14
+ onUnlock: () => void;
15
+ onLoad: () => void;
16
+ onStop: () => void;
17
+ };
18
+ readonly dependencies: readonly ["logger", "transportsFactories", "bluetoothEnabledAtom", "bluetoothScanningAtom", "port"];
19
+ };
20
+ export default hardwareWalletLedgerPluginDefinition;
@@ -0,0 +1,59 @@
1
+ import { createAtomObserver } from '@exodus/atoms';
2
+ const createHardwareWalletLedgerPlugin = ({ logger, transportsFactories, bluetoothEnabledAtom, bluetoothScanningAtom, port, }) => {
3
+ let subscription;
4
+ const observers = [
5
+ createAtomObserver({ atom: bluetoothEnabledAtom, port, event: 'bluetoothEnabled' }),
6
+ createAtomObserver({ atom: bluetoothScanningAtom, port, event: 'bluetoothScanning' }),
7
+ ];
8
+ observers.forEach((observer) => observer.register());
9
+ const start = () => {
10
+ if (!transportsFactories.bluetooth)
11
+ return;
12
+ if (subscription)
13
+ return;
14
+ if (transportsFactories.bluetooth.observeState) {
15
+ subscription = transportsFactories.bluetooth.observeState({
16
+ next: (e) => {
17
+ bluetoothEnabledAtom.set(!!e.available);
18
+ },
19
+ error: (error) => logger.error(error),
20
+ });
21
+ }
22
+ else if (transportsFactories.bluetooth.observeAvailability) {
23
+ subscription = transportsFactories.bluetooth.observeAvailability({
24
+ next: (available) => {
25
+ bluetoothEnabledAtom.set(available);
26
+ },
27
+ error: (error) => logger.error(error),
28
+ });
29
+ }
30
+ observers.forEach((observer) => observer.start());
31
+ };
32
+ const stop = () => {
33
+ observers.forEach((observer) => observer.unregister());
34
+ subscription?.unsubscribe();
35
+ };
36
+ const onUnlock = () => {
37
+ start();
38
+ };
39
+ const onLoad = () => {
40
+ start();
41
+ };
42
+ const onStop = () => {
43
+ stop();
44
+ };
45
+ return { onUnlock, onLoad, onStop };
46
+ };
47
+ const hardwareWalletLedgerPluginDefinition = {
48
+ id: 'hardwareWalletLedgerPlugin',
49
+ type: 'plugin',
50
+ factory: createHardwareWalletLedgerPlugin,
51
+ dependencies: [
52
+ 'logger',
53
+ 'transportsFactories',
54
+ 'bluetoothEnabledAtom',
55
+ 'bluetoothScanningAtom',
56
+ 'port',
57
+ ],
58
+ };
59
+ export default hardwareWalletLedgerPluginDefinition;
@@ -0,0 +1,2 @@
1
+ declare const id = "hardwareWalletLedger";
2
+ export default id;
@@ -0,0 +1,2 @@
1
+ const id = 'hardwareWalletLedger';
2
+ export default id;
@@ -0,0 +1,30 @@
1
+ import { type LedgerHardwareWalletState } from './initial-state';
2
+ declare const exchangeReduxDefinition: {
3
+ readonly id: "hardwareWalletLedger";
4
+ readonly type: "redux-module";
5
+ readonly initialState: LedgerHardwareWalletState;
6
+ readonly eventReducers: {
7
+ readonly bluetoothEnabled: (state: LedgerHardwareWalletState, payload: boolean) => {
8
+ bluetoothEnabled: boolean;
9
+ bluetoothScanning: boolean;
10
+ };
11
+ readonly bluetoothScanning: (state: LedgerHardwareWalletState, payload: boolean) => {
12
+ bluetoothScanning: boolean;
13
+ bluetoothEnabled: boolean;
14
+ };
15
+ };
16
+ readonly selectorDefinitions: ({
17
+ readonly id: "bluetoothEnabled";
18
+ readonly resultFunction: (bluetoothEnabled: LedgerHardwareWalletState) => LedgerHardwareWalletState;
19
+ readonly dependencies: readonly [{
20
+ readonly selector: "bluetoothEnabled";
21
+ }];
22
+ } | {
23
+ readonly id: "bluetoothScanning";
24
+ readonly resultFunction: (bluetoothScanning: LedgerHardwareWalletState) => LedgerHardwareWalletState;
25
+ readonly dependencies: readonly [{
26
+ readonly selector: "bluetoothScanning";
27
+ }];
28
+ })[];
29
+ };
30
+ export default exchangeReduxDefinition;
@@ -0,0 +1,20 @@
1
+ import id from './id';
2
+ import initialState from './initial-state';
3
+ import selectorDefinitions from './selectors';
4
+ const exchangeReduxDefinition = {
5
+ id,
6
+ type: 'redux-module',
7
+ initialState,
8
+ eventReducers: {
9
+ bluetoothEnabled: (state, payload) => ({
10
+ ...state,
11
+ bluetoothEnabled: payload,
12
+ }),
13
+ bluetoothScanning: (state, payload) => ({
14
+ ...state,
15
+ bluetoothScanning: payload,
16
+ }),
17
+ },
18
+ selectorDefinitions,
19
+ };
20
+ export default exchangeReduxDefinition;
@@ -0,0 +1,6 @@
1
+ export type LedgerHardwareWalletState = {
2
+ bluetoothEnabled: boolean;
3
+ bluetoothScanning: boolean;
4
+ };
5
+ declare const initialState: LedgerHardwareWalletState;
6
+ export default initialState;
@@ -0,0 +1,5 @@
1
+ const initialState = {
2
+ bluetoothEnabled: false,
3
+ bluetoothScanning: false,
4
+ };
5
+ export default initialState;
@@ -0,0 +1,9 @@
1
+ import type { LedgerHardwareWalletState } from '../initial-state';
2
+ declare const bluetoothEnabledSelectorDefinition: {
3
+ readonly id: "bluetoothEnabled";
4
+ readonly resultFunction: (bluetoothEnabled: LedgerHardwareWalletState) => LedgerHardwareWalletState;
5
+ readonly dependencies: readonly [{
6
+ readonly selector: "bluetoothEnabled";
7
+ }];
8
+ };
9
+ export default bluetoothEnabledSelectorDefinition;
@@ -0,0 +1,7 @@
1
+ const resultFunction = (bluetoothEnabled) => bluetoothEnabled;
2
+ const bluetoothEnabledSelectorDefinition = {
3
+ id: 'bluetoothEnabled',
4
+ resultFunction,
5
+ dependencies: [{ selector: 'bluetoothEnabled' }],
6
+ };
7
+ export default bluetoothEnabledSelectorDefinition;
@@ -0,0 +1,9 @@
1
+ import type { LedgerHardwareWalletState } from '../initial-state';
2
+ declare const bluetoothScanningSelectorDefinition: {
3
+ readonly id: "bluetoothScanning";
4
+ readonly resultFunction: (bluetoothScanning: LedgerHardwareWalletState) => LedgerHardwareWalletState;
5
+ readonly dependencies: readonly [{
6
+ readonly selector: "bluetoothScanning";
7
+ }];
8
+ };
9
+ export default bluetoothScanningSelectorDefinition;
@@ -0,0 +1,7 @@
1
+ const resultFunction = (bluetoothScanning) => bluetoothScanning;
2
+ const bluetoothScanningSelectorDefinition = {
3
+ id: 'bluetoothScanning',
4
+ resultFunction,
5
+ dependencies: [{ selector: 'bluetoothScanning' }],
6
+ };
7
+ export default bluetoothScanningSelectorDefinition;
@@ -0,0 +1,14 @@
1
+ declare const ledgerSelectors: ({
2
+ readonly id: "bluetoothEnabled";
3
+ readonly resultFunction: (bluetoothEnabled: import("../initial-state").LedgerHardwareWalletState) => import("../initial-state").LedgerHardwareWalletState;
4
+ readonly dependencies: readonly [{
5
+ readonly selector: "bluetoothEnabled";
6
+ }];
7
+ } | {
8
+ readonly id: "bluetoothScanning";
9
+ readonly resultFunction: (bluetoothScanning: import("../initial-state").LedgerHardwareWalletState) => import("../initial-state").LedgerHardwareWalletState;
10
+ readonly dependencies: readonly [{
11
+ readonly selector: "bluetoothScanning";
12
+ }];
13
+ })[];
14
+ export default ledgerSelectors;
@@ -0,0 +1,4 @@
1
+ import bluetoothEnabledSelectorDefinition from './bluetoothEnabled';
2
+ import bluetoothScanningSelectorDefinition from './bluetoothScanning';
3
+ const ledgerSelectors = [bluetoothEnabledSelectorDefinition, bluetoothScanningSelectorDefinition];
4
+ export default ledgerSelectors;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/hw-ledger",
3
- "version": "2.6.0",
3
+ "version": "2.8.0",
4
4
  "description": "The ledger module",
5
5
  "author": "Exodus Movement, Inc.",
6
6
  "repository": {
@@ -30,6 +30,7 @@
30
30
  "prepublishOnly": "yarn run -T build --scope @exodus/hw-ledger"
31
31
  },
32
32
  "dependencies": {
33
+ "@exodus/atoms": "^7.5.1",
33
34
  "@exodus/bip322-js": "^1.1.0-exodus.4",
34
35
  "@exodus/bitcoinjs-lib": "^6.1.5-exodus.0",
35
36
  "@exodus/ethersproject-transactions": "^5.4.2-exodus.0",
@@ -69,5 +70,5 @@
69
70
  "ts-jest": "^29.0.3",
70
71
  "typescript": "^4.7.3"
71
72
  },
72
- "gitHead": "2ac1721860b9d11c2ebbf365f7a8ecd123e9ed40"
73
+ "gitHead": "7c0905f9185d9c00a8f3d4897991f596e226867a"
73
74
  }