@exodus/hardware-wallets 3.1.0 → 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 +6 -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 +47 -17
- package/lib/module/interfaces.d.ts +4 -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,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.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
|
+
|
|
6
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)
|
|
7
13
|
|
|
8
14
|
### Features
|
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
|
}
|
|
@@ -156,6 +164,9 @@ export class HardwareWallets {
|
|
|
156
164
|
return this.#signGeneric({ baseAssetName, scenario: 'signMessage', sign });
|
|
157
165
|
};
|
|
158
166
|
isDeviceConnected = async () => {
|
|
167
|
+
if (this.#trezorDiscovery.connected) {
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
159
170
|
try {
|
|
160
171
|
const devices = await this.#ledgerDiscovery.list();
|
|
161
172
|
return devices.length > 0;
|
|
@@ -165,12 +176,16 @@ export class HardwareWallets {
|
|
|
165
176
|
}
|
|
166
177
|
};
|
|
167
178
|
scanForDevices = async () => {
|
|
179
|
+
this.#trezorDiscovery.stopScan(true);
|
|
168
180
|
this.#ledgerDiscovery.stopScan(true);
|
|
169
|
-
|
|
181
|
+
await Promise.all([this.#ledgerDiscovery.scan(), this.#trezorDiscovery.scan()]);
|
|
170
182
|
};
|
|
171
183
|
getAvailableDevices = async () => {
|
|
172
|
-
const
|
|
173
|
-
|
|
184
|
+
const [ledgers, trezors] = await Promise.all([
|
|
185
|
+
this.#ledgerDiscovery.list().catch(() => []),
|
|
186
|
+
this.#trezorDiscovery.list().catch(() => []),
|
|
187
|
+
]);
|
|
188
|
+
return [...ledgers, ...trezors].map((device) => ({
|
|
174
189
|
model: device.model,
|
|
175
190
|
name: device.name,
|
|
176
191
|
}));
|
|
@@ -204,18 +219,18 @@ export class HardwareWallets {
|
|
|
204
219
|
};
|
|
205
220
|
getAddress = async ({ assetName, accountIndex, addressIndex, multisigData, displayOnDevice, }) => {
|
|
206
221
|
const asset = this.#assetsModule.getAsset(assetName);
|
|
222
|
+
const { device } = await this.#getSelectedDevice();
|
|
207
223
|
const supportedPurposes = asset.baseAsset.api.getSupportedPurposes({
|
|
208
|
-
compatibilityMode:
|
|
224
|
+
compatibilityMode: device.descriptor.manufacturer,
|
|
209
225
|
isMultisig: !!multisigData,
|
|
210
226
|
});
|
|
211
227
|
const { derivationPath } = asset.baseAsset.api.getKeyIdentifier({
|
|
212
|
-
compatibilityMode:
|
|
228
|
+
compatibilityMode: device.descriptor.manufacturer,
|
|
213
229
|
purpose: supportedPurposes[0],
|
|
214
230
|
accountIndex,
|
|
215
231
|
chainIndex: 0,
|
|
216
232
|
addressIndex,
|
|
217
233
|
});
|
|
218
|
-
const { device } = await this.#getSelectedDevice();
|
|
219
234
|
return device.getAddress({
|
|
220
235
|
assetName,
|
|
221
236
|
derivationPath,
|
|
@@ -226,7 +241,7 @@ export class HardwareWallets {
|
|
|
226
241
|
#getXPUB = async ({ device, baseAsset, purpose, accountIndex, }) => {
|
|
227
242
|
try {
|
|
228
243
|
const keyIdentifier = baseAsset.api.getKeyIdentifier({
|
|
229
|
-
compatibilityMode:
|
|
244
|
+
compatibilityMode: device.descriptor.manufacturer,
|
|
230
245
|
purpose,
|
|
231
246
|
accountIndex,
|
|
232
247
|
chainIndex: undefined,
|
|
@@ -244,7 +259,8 @@ export class HardwareWallets {
|
|
|
244
259
|
}
|
|
245
260
|
catch (error) {
|
|
246
261
|
if (error.name === 'XPubUnsupportedError' ||
|
|
247
|
-
error.message.includes(`XPUB derivation is not allowed`)
|
|
262
|
+
error.message.includes(`XPUB derivation is not allowed`) ||
|
|
263
|
+
error.message.includes('getXPub not supported')) {
|
|
248
264
|
this.#logger.warn(`Retrieving XPUBs for ${baseAsset.name} is not supported`, error);
|
|
249
265
|
return null;
|
|
250
266
|
}
|
|
@@ -253,7 +269,7 @@ export class HardwareWallets {
|
|
|
253
269
|
};
|
|
254
270
|
#getPublicKey = async ({ device, baseAsset, purpose, accountIndex, }) => {
|
|
255
271
|
const keyIdentifier = baseAsset.api.getKeyIdentifier({
|
|
256
|
-
compatibilityMode:
|
|
272
|
+
compatibilityMode: device.descriptor.manufacturer,
|
|
257
273
|
purpose,
|
|
258
274
|
accountIndex,
|
|
259
275
|
});
|
|
@@ -290,11 +306,13 @@ export class HardwareWallets {
|
|
|
290
306
|
return addressToBalanceMap;
|
|
291
307
|
};
|
|
292
308
|
scan = async ({ assetName, accountIndexes, addressLimit = 2, addressOffset = 0, }) => {
|
|
309
|
+
const { device } = await this.#getSelectedDevice();
|
|
310
|
+
const source = device.descriptor.manufacturer;
|
|
293
311
|
let usedAccountIndexes = [];
|
|
294
312
|
if (await this.#wallet.exists()) {
|
|
295
313
|
const walletAccounts = Object.values(await this.#walletAccountsAtom.get());
|
|
296
314
|
usedAccountIndexes = walletAccounts
|
|
297
|
-
.filter(({ source }) => source ===
|
|
315
|
+
.filter(({ source: s }) => source === s)
|
|
298
316
|
.map(({ index }) => index);
|
|
299
317
|
}
|
|
300
318
|
const accounts = accountIndexes.map((accountIndex) => ({ accountIndex }));
|
|
@@ -313,7 +331,8 @@ export class HardwareWallets {
|
|
|
313
331
|
sync = async ({ accountIndex: index, isMultisig } = {}) => {
|
|
314
332
|
const keysToSync = [];
|
|
315
333
|
const { device } = await this.#getSelectedDevice();
|
|
316
|
-
const
|
|
334
|
+
const source = device.descriptor.manufacturer;
|
|
335
|
+
const accountIndex = index ?? this.#walletAccounts.getNextIndex({ source });
|
|
317
336
|
const useableAssetNames = new Set(await device.listUseableAssetNames());
|
|
318
337
|
for (const assetName of useableAssetNames) {
|
|
319
338
|
const asset = this.#assetsModule.getAsset(assetName);
|
|
@@ -323,7 +342,7 @@ export class HardwareWallets {
|
|
|
323
342
|
}
|
|
324
343
|
const baseAsset = asset.baseAsset;
|
|
325
344
|
const supportedPurposes = baseAsset.api.getSupportedPurposes({
|
|
326
|
-
compatibilityMode:
|
|
345
|
+
compatibilityMode: source,
|
|
327
346
|
isMultisig,
|
|
328
347
|
});
|
|
329
348
|
for (const purpose of supportedPurposes) {
|
|
@@ -352,11 +371,14 @@ export class HardwareWallets {
|
|
|
352
371
|
};
|
|
353
372
|
create = async ({ syncedKeysId, isMultisig }) => {
|
|
354
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';
|
|
355
377
|
const { accountIndex, model } = this.#syncedKeysMap.get(syncedKeysId);
|
|
356
378
|
const walletAccount = new WalletAccount({
|
|
357
|
-
label:
|
|
358
|
-
icon:
|
|
359
|
-
source
|
|
379
|
+
label: `${label}${accountIndex === 0 ? '' : '_' + accountIndex}`,
|
|
380
|
+
icon: source,
|
|
381
|
+
source,
|
|
360
382
|
model,
|
|
361
383
|
index: accountIndex,
|
|
362
384
|
id: randomBytes(32).toString('hex'),
|
|
@@ -368,6 +390,12 @@ export class HardwareWallets {
|
|
|
368
390
|
await this.addPublicKeysToWalletAccount({ walletAccount, syncedKeysId });
|
|
369
391
|
return walletAccount;
|
|
370
392
|
};
|
|
393
|
+
clearPairingRequest = async () => {
|
|
394
|
+
await this.#pairingPromptAtom.set(false);
|
|
395
|
+
};
|
|
396
|
+
submitPairingCode = async ({ code }) => {
|
|
397
|
+
return this.#trezorDiscovery.submitPairingCode(code);
|
|
398
|
+
};
|
|
371
399
|
requireDeviceFor = async ({ walletAccount }) => {
|
|
372
400
|
return {
|
|
373
401
|
signTransaction: this.signTransaction,
|
|
@@ -384,8 +412,10 @@ const hardwareWalletsModuleDefinition = {
|
|
|
384
412
|
'assetsModule',
|
|
385
413
|
'logger',
|
|
386
414
|
'ledgerDiscovery',
|
|
415
|
+
'trezorDiscovery',
|
|
387
416
|
'publicKeyStore',
|
|
388
417
|
'hardwareWalletSigningRequestsAtom',
|
|
418
|
+
'hardwareWalletPairingPromptAtom',
|
|
389
419
|
'wallet',
|
|
390
420
|
'walletAccountsAtom',
|
|
391
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;
|
|
@@ -142,4 +143,7 @@ export type FetchBalanceResult = any | null;
|
|
|
142
143
|
export interface RequireDeviceForParams {
|
|
143
144
|
walletAccount: WalletAccount;
|
|
144
145
|
}
|
|
146
|
+
export interface ProcessPairingCodeParams {
|
|
147
|
+
code: string;
|
|
148
|
+
}
|
|
145
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.
|
|
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;
|