@exodus/hardware-wallets 3.0.2 → 3.2.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 +12 -0
- package/lib/api/index.d.ts +2 -0
- package/lib/api/index.js +2 -0
- package/lib/atoms/hardwareWalletPairingPromptAtom.d.ts +6 -0
- package/lib/atoms/hardwareWalletPairingPromptAtom.js +9 -0
- package/lib/atoms/index.d.ts +1 -0
- package/lib/atoms/index.js +1 -0
- package/lib/index.d.ts +13 -3
- package/lib/index.js +4 -1
- package/lib/module/hardware-wallets.d.ts +10 -3
- package/lib/module/hardware-wallets.js +49 -17
- package/lib/module/interfaces.d.ts +5 -0
- package/lib/plugin/index.d.ts +3 -2
- package/lib/plugin/index.js +7 -1
- package/lib/redux/index.d.ts +9 -8
- package/lib/redux/index.js +4 -0
- package/lib/redux/initial-state.d.ts +1 -0
- package/lib/redux/initial-state.js +1 -0
- package/lib/redux/selectors/index.d.ts +2 -8
- package/lib/redux/selectors/index.js +1 -5
- package/package.json +5 -4
- package/lib/redux/selectors/getSigningRequests.d.ts +0 -9
- package/lib/redux/selectors/getSigningRequests.js +0 -8
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.2.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/hardware-wallets@3.1.0...@exodus/hardware-wallets@3.2.0) (2025-10-09)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
- feat: add trezor safe 7 support (#13965)
|
|
11
|
+
|
|
12
|
+
## [3.1.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/hardware-wallets@3.0.2...@exodus/hardware-wallets@3.1.0) (2025-10-01)
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
- feat(hardware-wallets): add baseAssetName to signRequest (#13962)
|
|
17
|
+
|
|
6
18
|
## [3.0.2](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/hardware-wallets@3.0.1...@exodus/hardware-wallets@3.0.2) (2025-08-08)
|
|
7
19
|
|
|
8
20
|
### Bug Fixes
|
package/lib/api/index.d.ts
CHANGED
|
@@ -23,6 +23,8 @@ declare const hardwareWalletsApiDefinition: {
|
|
|
23
23
|
create: ({ syncedKeysId, isMultisig }: import("../module/interfaces.js").CreateParams) => Promise<import("libraries/models/lib/index.js").WalletAccount>;
|
|
24
24
|
retrySigningRequest: (id: string) => Promise<void>;
|
|
25
25
|
cancelSigningRequest: (id: string, fromUI: boolean) => Promise<void>;
|
|
26
|
+
submitPairingCode: ({ code }: import("../module/interfaces.js").ProcessPairingCodeParams) => Promise<any>;
|
|
27
|
+
clearPairingRequest: () => () => Promise<void>;
|
|
26
28
|
};
|
|
27
29
|
};
|
|
28
30
|
readonly dependencies: readonly ["hardwareWallets", "txLogMonitors", "restoreProgressTracker"];
|
package/lib/api/index.js
CHANGED
|
@@ -30,6 +30,8 @@ const createHardwareWalletsApi = ({ hardwareWallets, restoreProgressTracker, txL
|
|
|
30
30
|
create: hardwareWallets.create,
|
|
31
31
|
retrySigningRequest: hardwareWallets.retrySigningRequest,
|
|
32
32
|
cancelSigningRequest: hardwareWallets.cancelSigningRequest,
|
|
33
|
+
submitPairingCode: hardwareWallets.submitPairingCode,
|
|
34
|
+
clearPairingRequest: () => hardwareWallets.clearPairingRequest,
|
|
33
35
|
},
|
|
34
36
|
};
|
|
35
37
|
};
|
package/lib/atoms/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { hardwareWalletSigningRequestsAtomDefinition } from './hardwareWalletSigningRequestsAtom.js';
|
|
2
|
+
export { hardwareWalletPairingPromptAtomDefinition } from './hardwareWalletPairingPromptAtom.js';
|
|
2
3
|
type WalletAccountName = string;
|
|
3
4
|
type AssetName = string;
|
|
4
5
|
export type WalletAccountNameToConnectedAssetNamesMap = Record<WalletAccountName, AssetName[]>;
|
package/lib/atoms/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import { combine, compute } from '@exodus/atoms';
|
|
|
2
2
|
import { memoize } from '@exodus/basic-utils';
|
|
3
3
|
import { HARDENED_OFFSET } from '@exodus/bip32';
|
|
4
4
|
export { hardwareWalletSigningRequestsAtomDefinition } from './hardwareWalletSigningRequestsAtom.js';
|
|
5
|
+
export { hardwareWalletPairingPromptAtomDefinition } from './hardwareWalletPairingPromptAtom.js';
|
|
5
6
|
export const createHardwareWalletConnectedAssetNamesAtom = ({ hardwareWalletPublicKeysAtom, assetsModule, walletAccountsAtom, availableAssetNamesAtom, }) => {
|
|
6
7
|
const selector = memoize(({ hardwareWalletPublicKeys, walletAccounts, availableAssetNames }) => {
|
|
7
8
|
const result = Object.create(null);
|
package/lib/index.d.ts
CHANGED
|
@@ -26,6 +26,8 @@ declare const hardwareWallets: () => {
|
|
|
26
26
|
create: ({ syncedKeysId, isMultisig }: import("./module/interfaces.js").CreateParams) => Promise<import("libraries/models/lib/index.js").WalletAccount>;
|
|
27
27
|
retrySigningRequest: (id: string) => Promise<void>;
|
|
28
28
|
cancelSigningRequest: (id: string, fromUI: boolean) => Promise<void>;
|
|
29
|
+
submitPairingCode: ({ code }: import("./module/interfaces.js").ProcessPairingCodeParams) => Promise<any>;
|
|
30
|
+
clearPairingRequest: () => () => Promise<void>;
|
|
29
31
|
};
|
|
30
32
|
};
|
|
31
33
|
readonly dependencies: readonly ["hardwareWallets", "txLogMonitors", "restoreProgressTracker"];
|
|
@@ -35,7 +37,7 @@ declare const hardwareWallets: () => {
|
|
|
35
37
|
readonly id: "hardwareWallets";
|
|
36
38
|
readonly type: "module";
|
|
37
39
|
readonly factory: (opts: import("./module/hardware-wallets.js").Dependencies) => import("./module/hardware-wallets.js").HardwareWallets;
|
|
38
|
-
readonly dependencies: readonly ["assetsModule", "logger", "ledgerDiscovery", "publicKeyStore", "hardwareWalletSigningRequestsAtom", "wallet", "walletAccountsAtom", "walletAccounts"];
|
|
40
|
+
readonly dependencies: readonly ["assetsModule", "logger", "ledgerDiscovery", "trezorDiscovery", "publicKeyStore", "hardwareWalletSigningRequestsAtom", "hardwareWalletPairingPromptAtom", "wallet", "walletAccountsAtom", "walletAccounts"];
|
|
39
41
|
readonly public: true;
|
|
40
42
|
};
|
|
41
43
|
}, {
|
|
@@ -53,20 +55,28 @@ declare const hardwareWallets: () => {
|
|
|
53
55
|
readonly dependencies: readonly [];
|
|
54
56
|
readonly public: false;
|
|
55
57
|
};
|
|
58
|
+
}, {
|
|
59
|
+
readonly definition: {
|
|
60
|
+
readonly id: "hardwareWalletPairingPromptAtom";
|
|
61
|
+
readonly type: "atom";
|
|
62
|
+
readonly factory: () => import("libraries/atoms/lib/index.js").Atom<boolean>;
|
|
63
|
+
readonly public: true;
|
|
64
|
+
};
|
|
56
65
|
}, {
|
|
57
66
|
readonly definition: {
|
|
58
67
|
readonly id: "hardwareWalletsPlugin";
|
|
59
68
|
readonly type: "plugin";
|
|
60
|
-
readonly factory: ({ hardwareWalletConnectedAssetNamesAtom, hardwareWalletSigningRequestsAtom, port, }: {
|
|
69
|
+
readonly factory: ({ hardwareWalletConnectedAssetNamesAtom, hardwareWalletSigningRequestsAtom, hardwareWalletPairingPromptAtom, port, }: {
|
|
61
70
|
hardwareWalletConnectedAssetNamesAtom: import("libraries/atoms/lib/index.js").Atom<import("./atoms/index.js").WalletAccountNameToConnectedAssetNamesMap>;
|
|
62
71
|
hardwareWalletSigningRequestsAtom: import("libraries/atoms/lib/index.js").Atom<import("./module/interfaces.js").SigningRequestState>;
|
|
72
|
+
hardwareWalletPairingPromptAtom: import("libraries/atoms/lib/index.js").Atom<boolean>;
|
|
63
73
|
port: import("./shared/types.js").Port;
|
|
64
74
|
}) => {
|
|
65
75
|
onUnlock: () => void;
|
|
66
76
|
onLoad: () => void;
|
|
67
77
|
onStop: () => void;
|
|
68
78
|
};
|
|
69
|
-
readonly dependencies: readonly ["hardwareWalletConnectedAssetNamesAtom", "hardwareWalletSigningRequestsAtom", "port"];
|
|
79
|
+
readonly dependencies: readonly ["hardwareWalletConnectedAssetNamesAtom", "hardwareWalletSigningRequestsAtom", "hardwareWalletPairingPromptAtom", "port"];
|
|
70
80
|
};
|
|
71
81
|
}];
|
|
72
82
|
};
|
package/lib/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import hardwareWalletsApiDefinition from './api/index.js';
|
|
2
2
|
import hardwareWalletsModuleDefinition from './module/hardware-wallets.js';
|
|
3
|
-
import { hardwareWalletConnectedAssetNamesAtomDefinition, hardwareWalletSigningRequestsAtomDefinition, } from './atoms/index.js';
|
|
3
|
+
import { hardwareWalletConnectedAssetNamesAtomDefinition, hardwareWalletSigningRequestsAtomDefinition, hardwareWalletPairingPromptAtomDefinition, } from './atoms/index.js';
|
|
4
4
|
import hardwareWalletsPluginDefinition from './plugin/index.js';
|
|
5
5
|
const hardwareWallets = () => {
|
|
6
6
|
return {
|
|
@@ -18,6 +18,9 @@ const hardwareWallets = () => {
|
|
|
18
18
|
{
|
|
19
19
|
definition: hardwareWalletSigningRequestsAtomDefinition,
|
|
20
20
|
},
|
|
21
|
+
{
|
|
22
|
+
definition: hardwareWalletPairingPromptAtomDefinition,
|
|
23
|
+
},
|
|
21
24
|
{
|
|
22
25
|
definition: hardwareWalletsPluginDefinition,
|
|
23
26
|
},
|
|
@@ -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, SigningRequestState } from './interfaces.js';
|
|
3
|
+
import type { HardwareSignerProvider, CanAccessAssetParams, CreateParams, StoreSyncedKeysParams, ScanParams, SyncParams, EnsureApplicationIsOpenedParams, SignTransactionParams, ScanResult, SyncedKeysId, GetAddressParams, RequireDeviceForParams, ProcessPairingCodeParams, SigningRequestState } from './interfaces.js';
|
|
4
4
|
import type { HardwareWalletDiscovery, 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';
|
|
@@ -8,8 +8,13 @@ import type { Logger } from '@exodus/logger';
|
|
|
8
8
|
export type Dependencies = {
|
|
9
9
|
assetsModule: any;
|
|
10
10
|
ledgerDiscovery: HardwareWalletDiscovery;
|
|
11
|
+
trezorDiscovery: HardwareWalletDiscovery & {
|
|
12
|
+
connected: boolean;
|
|
13
|
+
submitPairingCode: (code: string) => Promise<any>;
|
|
14
|
+
};
|
|
11
15
|
logger: Logger;
|
|
12
16
|
hardwareWalletSigningRequestsAtom: Atom<SigningRequestState>;
|
|
17
|
+
hardwareWalletPairingPromptAtom: Atom<boolean>;
|
|
13
18
|
publicKeyStore: IPublicKeyStore;
|
|
14
19
|
wallet: any;
|
|
15
20
|
walletAccountsAtom: Atom<WalletAccount>;
|
|
@@ -20,7 +25,7 @@ export type Dependencies = {
|
|
|
20
25
|
export declare class HardwareWallets implements HardwareSignerProvider {
|
|
21
26
|
#private;
|
|
22
27
|
readonly events: Emitter<string, any>;
|
|
23
|
-
constructor({ assetsModule, ledgerDiscovery, logger, hardwareWalletSigningRequestsAtom, publicKeyStore, wallet, walletAccountsAtom, walletAccounts, }: Dependencies);
|
|
28
|
+
constructor({ assetsModule, ledgerDiscovery, trezorDiscovery, logger, hardwareWalletSigningRequestsAtom, hardwareWalletPairingPromptAtom, publicKeyStore, wallet, walletAccountsAtom, walletAccounts, }: Dependencies);
|
|
24
29
|
retrySigningRequest: (id: string) => Promise<void>;
|
|
25
30
|
cancelSigningRequest: (id: string, fromUI: boolean) => Promise<void>;
|
|
26
31
|
signTransaction: ({ baseAssetName, unsignedTx, walletAccount, multisigData, }: SignTransactionParams) => Promise<any>;
|
|
@@ -39,6 +44,8 @@ export declare class HardwareWallets implements HardwareSignerProvider {
|
|
|
39
44
|
sync: ({ accountIndex: index, isMultisig }?: SyncParams) => Promise<SyncedKeysId>;
|
|
40
45
|
addPublicKeysToWalletAccount: ({ walletAccount, syncedKeysId }: StoreSyncedKeysParams) => Promise<void>;
|
|
41
46
|
create: ({ syncedKeysId, isMultisig }: CreateParams) => Promise<WalletAccount>;
|
|
47
|
+
clearPairingRequest: () => Promise<void>;
|
|
48
|
+
submitPairingCode: ({ code }: ProcessPairingCodeParams) => Promise<any>;
|
|
42
49
|
requireDeviceFor: ({ walletAccount }: RequireDeviceForParams) => Promise<{
|
|
43
50
|
signTransaction: ({ baseAssetName, unsignedTx, walletAccount, multisigData, }: SignTransactionParams) => Promise<any>;
|
|
44
51
|
signMessage: ({ assetName, derivationPath, message }: SignMessageParams) => Promise<any>;
|
|
@@ -48,7 +55,7 @@ declare const hardwareWalletsModuleDefinition: {
|
|
|
48
55
|
readonly id: "hardwareWallets";
|
|
49
56
|
readonly type: "module";
|
|
50
57
|
readonly factory: (opts: Dependencies) => HardwareWallets;
|
|
51
|
-
readonly dependencies: readonly ["assetsModule", "logger", "ledgerDiscovery", "publicKeyStore", "hardwareWalletSigningRequestsAtom", "wallet", "walletAccountsAtom", "walletAccounts"];
|
|
58
|
+
readonly dependencies: readonly ["assetsModule", "logger", "ledgerDiscovery", "trezorDiscovery", "publicKeyStore", "hardwareWalletSigningRequestsAtom", "hardwareWalletPairingPromptAtom", "wallet", "walletAccountsAtom", "walletAccounts"];
|
|
52
59
|
readonly public: true;
|
|
53
60
|
};
|
|
54
61
|
export default hardwareWalletsModuleDefinition;
|
|
@@ -9,27 +9,35 @@ import pDefer from 'p-defer';
|
|
|
9
9
|
export class HardwareWallets {
|
|
10
10
|
#assetsModule;
|
|
11
11
|
#ledgerDiscovery;
|
|
12
|
+
#trezorDiscovery;
|
|
12
13
|
#logger;
|
|
13
14
|
#publicKeyStore;
|
|
14
15
|
#signingRequestAtom;
|
|
16
|
+
#pairingPromptAtom;
|
|
15
17
|
#wallet;
|
|
16
18
|
#walletAccountsAtom;
|
|
17
19
|
#walletAccounts;
|
|
18
20
|
#syncedKeysMap = new Map();
|
|
19
21
|
#signingRequest;
|
|
20
22
|
events = new Emitter();
|
|
21
|
-
constructor({ assetsModule, ledgerDiscovery, logger, hardwareWalletSigningRequestsAtom, publicKeyStore, wallet, walletAccountsAtom, walletAccounts, }) {
|
|
23
|
+
constructor({ assetsModule, ledgerDiscovery, trezorDiscovery, logger, hardwareWalletSigningRequestsAtom, hardwareWalletPairingPromptAtom, publicKeyStore, wallet, walletAccountsAtom, walletAccounts, }) {
|
|
22
24
|
this.#assetsModule = assetsModule;
|
|
23
25
|
this.#ledgerDiscovery = ledgerDiscovery;
|
|
26
|
+
this.#trezorDiscovery = trezorDiscovery;
|
|
24
27
|
this.#logger = logger;
|
|
25
28
|
this.#publicKeyStore = publicKeyStore;
|
|
26
29
|
this.#signingRequestAtom = hardwareWalletSigningRequestsAtom;
|
|
30
|
+
this.#pairingPromptAtom = hardwareWalletPairingPromptAtom;
|
|
27
31
|
this.#wallet = wallet;
|
|
28
32
|
this.#walletAccountsAtom = walletAccountsAtom;
|
|
29
33
|
this.#walletAccounts = walletAccounts;
|
|
30
34
|
}
|
|
31
35
|
#getSelectedDevice = async () => {
|
|
32
|
-
const
|
|
36
|
+
const [trezors, ledgers] = await Promise.all([
|
|
37
|
+
this.#trezorDiscovery.list().catch(() => []),
|
|
38
|
+
this.#ledgerDiscovery.list().catch(() => []),
|
|
39
|
+
]);
|
|
40
|
+
const descriptors = [...trezors, ...ledgers];
|
|
33
41
|
if (descriptors[0]) {
|
|
34
42
|
return { device: await descriptors[0].get() };
|
|
35
43
|
}
|
|
@@ -84,6 +92,7 @@ export class HardwareWallets {
|
|
|
84
92
|
id,
|
|
85
93
|
scenario: 'error',
|
|
86
94
|
error: _error,
|
|
95
|
+
baseAssetName: this.#signingRequest.baseAssetName,
|
|
87
96
|
});
|
|
88
97
|
}
|
|
89
98
|
};
|
|
@@ -114,6 +123,7 @@ export class HardwareWallets {
|
|
|
114
123
|
const deferred = pDefer();
|
|
115
124
|
this.#signingRequest = {
|
|
116
125
|
id,
|
|
126
|
+
baseAssetName,
|
|
117
127
|
sign: async ({ device }) => {
|
|
118
128
|
await this.#updateSigningRequest({
|
|
119
129
|
id,
|
|
@@ -154,6 +164,9 @@ export class HardwareWallets {
|
|
|
154
164
|
return this.#signGeneric({ baseAssetName, scenario: 'signMessage', sign });
|
|
155
165
|
};
|
|
156
166
|
isDeviceConnected = async () => {
|
|
167
|
+
if (this.#trezorDiscovery.connected) {
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
157
170
|
try {
|
|
158
171
|
const devices = await this.#ledgerDiscovery.list();
|
|
159
172
|
return devices.length > 0;
|
|
@@ -163,12 +176,16 @@ export class HardwareWallets {
|
|
|
163
176
|
}
|
|
164
177
|
};
|
|
165
178
|
scanForDevices = async () => {
|
|
179
|
+
this.#trezorDiscovery.stopScan(true);
|
|
166
180
|
this.#ledgerDiscovery.stopScan(true);
|
|
167
|
-
|
|
181
|
+
await Promise.all([this.#ledgerDiscovery.scan(), this.#trezorDiscovery.scan()]);
|
|
168
182
|
};
|
|
169
183
|
getAvailableDevices = async () => {
|
|
170
|
-
const
|
|
171
|
-
|
|
184
|
+
const [ledgers, trezors] = await Promise.all([
|
|
185
|
+
this.#ledgerDiscovery.list().catch(() => []),
|
|
186
|
+
this.#trezorDiscovery.list().catch(() => []),
|
|
187
|
+
]);
|
|
188
|
+
return [...ledgers, ...trezors].map((device) => ({
|
|
172
189
|
model: device.model,
|
|
173
190
|
name: device.name,
|
|
174
191
|
}));
|
|
@@ -202,18 +219,18 @@ export class HardwareWallets {
|
|
|
202
219
|
};
|
|
203
220
|
getAddress = async ({ assetName, accountIndex, addressIndex, multisigData, displayOnDevice, }) => {
|
|
204
221
|
const asset = this.#assetsModule.getAsset(assetName);
|
|
222
|
+
const { device } = await this.#getSelectedDevice();
|
|
205
223
|
const supportedPurposes = asset.baseAsset.api.getSupportedPurposes({
|
|
206
|
-
compatibilityMode:
|
|
224
|
+
compatibilityMode: device.descriptor.manufacturer,
|
|
207
225
|
isMultisig: !!multisigData,
|
|
208
226
|
});
|
|
209
227
|
const { derivationPath } = asset.baseAsset.api.getKeyIdentifier({
|
|
210
|
-
compatibilityMode:
|
|
228
|
+
compatibilityMode: device.descriptor.manufacturer,
|
|
211
229
|
purpose: supportedPurposes[0],
|
|
212
230
|
accountIndex,
|
|
213
231
|
chainIndex: 0,
|
|
214
232
|
addressIndex,
|
|
215
233
|
});
|
|
216
|
-
const { device } = await this.#getSelectedDevice();
|
|
217
234
|
return device.getAddress({
|
|
218
235
|
assetName,
|
|
219
236
|
derivationPath,
|
|
@@ -224,7 +241,7 @@ export class HardwareWallets {
|
|
|
224
241
|
#getXPUB = async ({ device, baseAsset, purpose, accountIndex, }) => {
|
|
225
242
|
try {
|
|
226
243
|
const keyIdentifier = baseAsset.api.getKeyIdentifier({
|
|
227
|
-
compatibilityMode:
|
|
244
|
+
compatibilityMode: device.descriptor.manufacturer,
|
|
228
245
|
purpose,
|
|
229
246
|
accountIndex,
|
|
230
247
|
chainIndex: undefined,
|
|
@@ -242,7 +259,8 @@ export class HardwareWallets {
|
|
|
242
259
|
}
|
|
243
260
|
catch (error) {
|
|
244
261
|
if (error.name === 'XPubUnsupportedError' ||
|
|
245
|
-
error.message.includes(`XPUB derivation is not allowed`)
|
|
262
|
+
error.message.includes(`XPUB derivation is not allowed`) ||
|
|
263
|
+
error.message.includes('getXPub not supported')) {
|
|
246
264
|
this.#logger.warn(`Retrieving XPUBs for ${baseAsset.name} is not supported`, error);
|
|
247
265
|
return null;
|
|
248
266
|
}
|
|
@@ -251,7 +269,7 @@ export class HardwareWallets {
|
|
|
251
269
|
};
|
|
252
270
|
#getPublicKey = async ({ device, baseAsset, purpose, accountIndex, }) => {
|
|
253
271
|
const keyIdentifier = baseAsset.api.getKeyIdentifier({
|
|
254
|
-
compatibilityMode:
|
|
272
|
+
compatibilityMode: device.descriptor.manufacturer,
|
|
255
273
|
purpose,
|
|
256
274
|
accountIndex,
|
|
257
275
|
});
|
|
@@ -288,11 +306,13 @@ export class HardwareWallets {
|
|
|
288
306
|
return addressToBalanceMap;
|
|
289
307
|
};
|
|
290
308
|
scan = async ({ assetName, accountIndexes, addressLimit = 2, addressOffset = 0, }) => {
|
|
309
|
+
const { device } = await this.#getSelectedDevice();
|
|
310
|
+
const source = device.descriptor.manufacturer;
|
|
291
311
|
let usedAccountIndexes = [];
|
|
292
312
|
if (await this.#wallet.exists()) {
|
|
293
313
|
const walletAccounts = Object.values(await this.#walletAccountsAtom.get());
|
|
294
314
|
usedAccountIndexes = walletAccounts
|
|
295
|
-
.filter(({ source }) => source ===
|
|
315
|
+
.filter(({ source: s }) => source === s)
|
|
296
316
|
.map(({ index }) => index);
|
|
297
317
|
}
|
|
298
318
|
const accounts = accountIndexes.map((accountIndex) => ({ accountIndex }));
|
|
@@ -311,7 +331,8 @@ export class HardwareWallets {
|
|
|
311
331
|
sync = async ({ accountIndex: index, isMultisig } = {}) => {
|
|
312
332
|
const keysToSync = [];
|
|
313
333
|
const { device } = await this.#getSelectedDevice();
|
|
314
|
-
const
|
|
334
|
+
const source = device.descriptor.manufacturer;
|
|
335
|
+
const accountIndex = index ?? this.#walletAccounts.getNextIndex({ source });
|
|
315
336
|
const useableAssetNames = new Set(await device.listUseableAssetNames());
|
|
316
337
|
for (const assetName of useableAssetNames) {
|
|
317
338
|
const asset = this.#assetsModule.getAsset(assetName);
|
|
@@ -321,7 +342,7 @@ export class HardwareWallets {
|
|
|
321
342
|
}
|
|
322
343
|
const baseAsset = asset.baseAsset;
|
|
323
344
|
const supportedPurposes = baseAsset.api.getSupportedPurposes({
|
|
324
|
-
compatibilityMode:
|
|
345
|
+
compatibilityMode: source,
|
|
325
346
|
isMultisig,
|
|
326
347
|
});
|
|
327
348
|
for (const purpose of supportedPurposes) {
|
|
@@ -350,11 +371,14 @@ export class HardwareWallets {
|
|
|
350
371
|
};
|
|
351
372
|
create = async ({ syncedKeysId, isMultisig }) => {
|
|
352
373
|
assert(this.#syncedKeysMap.has(syncedKeysId), `no synchronized keys found for id ${syncedKeysId}`);
|
|
374
|
+
const { device } = await this.#getSelectedDevice();
|
|
375
|
+
const source = device.descriptor.manufacturer;
|
|
376
|
+
const label = source === WalletAccount.LEDGER_SRC ? 'Ledger' : 'Trezor';
|
|
353
377
|
const { accountIndex, model } = this.#syncedKeysMap.get(syncedKeysId);
|
|
354
378
|
const walletAccount = new WalletAccount({
|
|
355
|
-
label:
|
|
356
|
-
icon:
|
|
357
|
-
source
|
|
379
|
+
label: `${label}${accountIndex === 0 ? '' : '_' + accountIndex}`,
|
|
380
|
+
icon: source,
|
|
381
|
+
source,
|
|
358
382
|
model,
|
|
359
383
|
index: accountIndex,
|
|
360
384
|
id: randomBytes(32).toString('hex'),
|
|
@@ -366,6 +390,12 @@ export class HardwareWallets {
|
|
|
366
390
|
await this.addPublicKeysToWalletAccount({ walletAccount, syncedKeysId });
|
|
367
391
|
return walletAccount;
|
|
368
392
|
};
|
|
393
|
+
clearPairingRequest = async () => {
|
|
394
|
+
await this.#pairingPromptAtom.set(false);
|
|
395
|
+
};
|
|
396
|
+
submitPairingCode = async ({ code }) => {
|
|
397
|
+
return this.#trezorDiscovery.submitPairingCode(code);
|
|
398
|
+
};
|
|
369
399
|
requireDeviceFor = async ({ walletAccount }) => {
|
|
370
400
|
return {
|
|
371
401
|
signTransaction: this.signTransaction,
|
|
@@ -382,8 +412,10 @@ const hardwareWalletsModuleDefinition = {
|
|
|
382
412
|
'assetsModule',
|
|
383
413
|
'logger',
|
|
384
414
|
'ledgerDiscovery',
|
|
415
|
+
'trezorDiscovery',
|
|
385
416
|
'publicKeyStore',
|
|
386
417
|
'hardwareWalletSigningRequestsAtom',
|
|
418
|
+
'hardwareWalletPairingPromptAtom',
|
|
387
419
|
'wallet',
|
|
388
420
|
'walletAccountsAtom',
|
|
389
421
|
'walletAccounts',
|
|
@@ -13,6 +13,7 @@ export interface HardwareSignerProvider {
|
|
|
13
13
|
create: ({ syncedKeysId, isMultisig }: CreateParams) => Promise<WalletAccount>;
|
|
14
14
|
signTransaction: ({ baseAssetName, unsignedTx, walletAccount, }: SignTransactionParams) => Promise<any>;
|
|
15
15
|
signMessage: ({ assetName, derivationPath, message }: SignMessageParams) => Promise<any>;
|
|
16
|
+
submitPairingCode: ({ code }: ProcessPairingCodeParams) => Promise<any>;
|
|
16
17
|
}
|
|
17
18
|
type Asset = {
|
|
18
19
|
name: string;
|
|
@@ -92,6 +93,7 @@ export interface SigningRequestState {
|
|
|
92
93
|
}
|
|
93
94
|
export interface SigningRequest {
|
|
94
95
|
id: string;
|
|
96
|
+
baseAssetName?: string;
|
|
95
97
|
sign: GenericSignCallback;
|
|
96
98
|
resolve: (result: any) => void;
|
|
97
99
|
reject: (error: Error) => void;
|
|
@@ -141,4 +143,7 @@ export type FetchBalanceResult = any | null;
|
|
|
141
143
|
export interface RequireDeviceForParams {
|
|
142
144
|
walletAccount: WalletAccount;
|
|
143
145
|
}
|
|
146
|
+
export interface ProcessPairingCodeParams {
|
|
147
|
+
code: string;
|
|
148
|
+
}
|
|
144
149
|
export {};
|
package/lib/plugin/index.d.ts
CHANGED
|
@@ -5,15 +5,16 @@ import type { SigningRequestState } from '../module/interfaces.js';
|
|
|
5
5
|
declare const hardwareWalletsPluginDefinition: {
|
|
6
6
|
readonly id: "hardwareWalletsPlugin";
|
|
7
7
|
readonly type: "plugin";
|
|
8
|
-
readonly factory: ({ hardwareWalletConnectedAssetNamesAtom, hardwareWalletSigningRequestsAtom, port, }: {
|
|
8
|
+
readonly factory: ({ hardwareWalletConnectedAssetNamesAtom, hardwareWalletSigningRequestsAtom, hardwareWalletPairingPromptAtom, port, }: {
|
|
9
9
|
hardwareWalletConnectedAssetNamesAtom: Atom<WalletAccountNameToConnectedAssetNamesMap>;
|
|
10
10
|
hardwareWalletSigningRequestsAtom: Atom<SigningRequestState>;
|
|
11
|
+
hardwareWalletPairingPromptAtom: Atom<boolean>;
|
|
11
12
|
port: Port;
|
|
12
13
|
}) => {
|
|
13
14
|
onUnlock: () => void;
|
|
14
15
|
onLoad: () => void;
|
|
15
16
|
onStop: () => void;
|
|
16
17
|
};
|
|
17
|
-
readonly dependencies: readonly ["hardwareWalletConnectedAssetNamesAtom", "hardwareWalletSigningRequestsAtom", "port"];
|
|
18
|
+
readonly dependencies: readonly ["hardwareWalletConnectedAssetNamesAtom", "hardwareWalletSigningRequestsAtom", "hardwareWalletPairingPromptAtom", "port"];
|
|
18
19
|
};
|
|
19
20
|
export default hardwareWalletsPluginDefinition;
|
package/lib/plugin/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createAtomObserver } from '@exodus/atoms';
|
|
2
|
-
const createHardwareWalletsPlugin = ({ hardwareWalletConnectedAssetNamesAtom, hardwareWalletSigningRequestsAtom, port, }) => {
|
|
2
|
+
const createHardwareWalletsPlugin = ({ hardwareWalletConnectedAssetNamesAtom, hardwareWalletSigningRequestsAtom, hardwareWalletPairingPromptAtom, port, }) => {
|
|
3
3
|
const observers = [
|
|
4
4
|
createAtomObserver({
|
|
5
5
|
atom: hardwareWalletConnectedAssetNamesAtom,
|
|
@@ -11,6 +11,11 @@ const createHardwareWalletsPlugin = ({ hardwareWalletConnectedAssetNamesAtom, ha
|
|
|
11
11
|
port,
|
|
12
12
|
event: 'hardwareWalletSigningRequests',
|
|
13
13
|
}),
|
|
14
|
+
createAtomObserver({
|
|
15
|
+
atom: hardwareWalletPairingPromptAtom,
|
|
16
|
+
port,
|
|
17
|
+
event: 'hardwareWalletPairingPrompt',
|
|
18
|
+
}),
|
|
14
19
|
];
|
|
15
20
|
observers.forEach((observer) => observer.register());
|
|
16
21
|
const start = () => {
|
|
@@ -37,6 +42,7 @@ const hardwareWalletsPluginDefinition = {
|
|
|
37
42
|
dependencies: [
|
|
38
43
|
'hardwareWalletConnectedAssetNamesAtom',
|
|
39
44
|
'hardwareWalletSigningRequestsAtom',
|
|
45
|
+
'hardwareWalletPairingPromptAtom',
|
|
40
46
|
'port',
|
|
41
47
|
],
|
|
42
48
|
};
|
package/lib/redux/index.d.ts
CHANGED
|
@@ -8,24 +8,25 @@ declare const hardwareWalletsReduxDefinition: {
|
|
|
8
8
|
readonly hardwareWalletConnectedAssetNames: (state: HardwareWalletsState, payload: boolean) => {
|
|
9
9
|
walletAccountNameToConnectedAssetNamesMap: boolean;
|
|
10
10
|
signingRequests: SigningRequestState;
|
|
11
|
+
pairingPrompt: boolean;
|
|
11
12
|
};
|
|
12
13
|
readonly hardwareWalletSigningRequests: (state: HardwareWalletsState, payload: SigningRequestState) => {
|
|
13
14
|
signingRequests: SigningRequestState;
|
|
14
15
|
walletAccountNameToConnectedAssetNamesMap: import("../atoms/index.js").WalletAccountNameToConnectedAssetNamesMap;
|
|
16
|
+
pairingPrompt: boolean;
|
|
17
|
+
};
|
|
18
|
+
readonly hardwareWalletPairingPrompt: (state: HardwareWalletsState, payload: boolean) => {
|
|
19
|
+
pairingPrompt: boolean;
|
|
20
|
+
walletAccountNameToConnectedAssetNamesMap: import("../atoms/index.js").WalletAccountNameToConnectedAssetNamesMap;
|
|
21
|
+
signingRequests: SigningRequestState;
|
|
15
22
|
};
|
|
16
23
|
};
|
|
17
|
-
readonly selectorDefinitions:
|
|
24
|
+
readonly selectorDefinitions: {
|
|
18
25
|
readonly id: "isAssetNameConnectedForWalletAccount";
|
|
19
26
|
readonly selectorFactory: (selfSelector: any) => any;
|
|
20
27
|
readonly dependencies: readonly [{
|
|
21
28
|
readonly selector: string;
|
|
22
29
|
}];
|
|
23
|
-
}
|
|
24
|
-
readonly id: "getSigningRequests";
|
|
25
|
-
readonly resultFunction: (self: HardwareWalletsState) => SigningRequestState;
|
|
26
|
-
readonly dependencies: readonly [{
|
|
27
|
-
readonly selector: string;
|
|
28
|
-
}];
|
|
29
|
-
})[];
|
|
30
|
+
}[];
|
|
30
31
|
};
|
|
31
32
|
export default hardwareWalletsReduxDefinition;
|
package/lib/redux/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import type { SigningRequestState } from '../module/interfaces.js';
|
|
|
3
3
|
export type HardwareWalletsState = {
|
|
4
4
|
walletAccountNameToConnectedAssetNamesMap: WalletAccountNameToConnectedAssetNamesMap;
|
|
5
5
|
signingRequests: SigningRequestState;
|
|
6
|
+
pairingPrompt: boolean;
|
|
6
7
|
};
|
|
7
8
|
declare const initialState: HardwareWalletsState;
|
|
8
9
|
export default initialState;
|
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
declare const hardwareWalletsSelectors:
|
|
1
|
+
declare const hardwareWalletsSelectors: {
|
|
2
2
|
readonly id: "isAssetNameConnectedForWalletAccount";
|
|
3
3
|
readonly selectorFactory: (selfSelector: any) => any;
|
|
4
4
|
readonly dependencies: readonly [{
|
|
5
5
|
readonly selector: string;
|
|
6
6
|
}];
|
|
7
|
-
}
|
|
8
|
-
readonly id: "getSigningRequests";
|
|
9
|
-
readonly resultFunction: (self: import("../initial-state.js").HardwareWalletsState) => import("../../module/interfaces.js").SigningRequestState;
|
|
10
|
-
readonly dependencies: readonly [{
|
|
11
|
-
readonly selector: string;
|
|
12
|
-
}];
|
|
13
|
-
})[];
|
|
7
|
+
}[];
|
|
14
8
|
export default hardwareWalletsSelectors;
|
|
@@ -1,7 +1,3 @@
|
|
|
1
1
|
import isAssetNameConnectedForWalletAccountSelectorDefinition from './isAssetNameConnectedForWalletAccount.js';
|
|
2
|
-
|
|
3
|
-
const hardwareWalletsSelectors = [
|
|
4
|
-
isAssetNameConnectedForWalletAccountSelectorDefinition,
|
|
5
|
-
getSigningRequests,
|
|
6
|
-
];
|
|
2
|
+
const hardwareWalletsSelectors = [isAssetNameConnectedForWalletAccountSelectorDefinition];
|
|
7
3
|
export default hardwareWalletsSelectors;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/hardware-wallets",
|
|
3
|
-
"version": "3.0
|
|
3
|
+
"version": "3.2.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.
|
|
35
|
+
"@exodus/hw-common": "^3.2.0",
|
|
36
36
|
"@exodus/models": "^12.11.0",
|
|
37
37
|
"@exodus/redux-dependency-injection": "^4.0.0",
|
|
38
38
|
"@exodus/wild-emitter": "^1.1.0",
|
|
@@ -50,7 +50,8 @@
|
|
|
50
50
|
"redux": "^4.2.1"
|
|
51
51
|
},
|
|
52
52
|
"publishConfig": {
|
|
53
|
-
"access": "public"
|
|
53
|
+
"access": "public",
|
|
54
|
+
"provenance": false
|
|
54
55
|
},
|
|
55
|
-
"gitHead": "
|
|
56
|
+
"gitHead": "842023663c2b9fa3dce880a297e7f5a76446a684"
|
|
56
57
|
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { HardwareWalletsState } from '../initial-state.js';
|
|
2
|
-
declare const assetDataSelectorDefinition: {
|
|
3
|
-
readonly id: "getSigningRequests";
|
|
4
|
-
readonly resultFunction: (self: HardwareWalletsState) => import("../../module/interfaces.js").SigningRequestState;
|
|
5
|
-
readonly dependencies: readonly [{
|
|
6
|
-
readonly selector: string;
|
|
7
|
-
}];
|
|
8
|
-
};
|
|
9
|
-
export default assetDataSelectorDefinition;
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { MY_STATE } from '@exodus/redux-dependency-injection';
|
|
2
|
-
const resultFunction = (self) => self.signingRequests;
|
|
3
|
-
const assetDataSelectorDefinition = {
|
|
4
|
-
id: 'getSigningRequests',
|
|
5
|
-
resultFunction,
|
|
6
|
-
dependencies: [{ selector: MY_STATE }],
|
|
7
|
-
};
|
|
8
|
-
export default assetDataSelectorDefinition;
|