@exodus/hardware-wallets 1.2.0 → 1.3.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 -2
- package/lib/index.d.ts +4 -2
- package/lib/module/hardware-wallets.d.ts +6 -5
- package/lib/module/hardware-wallets.js +14 -6
- package/lib/module/interfaces.d.ts +8 -3
- package/package.json +7 -6
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
|
+
## [1.3.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/hardware-wallets@1.2.1...@exodus/hardware-wallets@1.3.0) (2024-09-19)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
- add multisig support to hardware-wallets ([#9312](https://github.com/ExodusMovement/exodus-hydra/issues/9312)) ([62afbf1](https://github.com/ExodusMovement/exodus-hydra/commit/62afbf1fa0295e3267b807c38a756a9169fdd816))
|
|
11
|
+
|
|
12
|
+
## [1.2.1](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/hardware-wallets@1.2.0...@exodus/hardware-wallets@1.2.1) (2024-09-13)
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
- dont await sign transaction/message modal ([#9268](https://github.com/ExodusMovement/exodus-hydra/issues/9268)) ([c2e1de9](https://github.com/ExodusMovement/exodus-hydra/commit/c2e1de987c31b2277bcc3cf65d13e11758bd2110))
|
|
17
|
+
|
|
6
18
|
## [1.2.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/hardware-wallets@1.1.2...@exodus/hardware-wallets@1.2.0) (2024-08-16)
|
|
7
19
|
|
|
8
20
|
### Features
|
package/lib/api/index.d.ts
CHANGED
|
@@ -18,9 +18,9 @@ declare const hardwareWalletsApiDefinition: {
|
|
|
18
18
|
canAccessAsset: ({ assetName }: import("../module/interfaces.js").CanAccessAssetParams) => Promise<boolean>;
|
|
19
19
|
ensureApplicationIsOpened: ({ assetName }: import("../module/interfaces.js").EnsureApplicationIsOpenedParams) => Promise<void>;
|
|
20
20
|
scan: ({ assetName, accountIndexes, addressLimit, addressOffset, }: import("../module/interfaces.js").ScanParams) => Promise<import("../module/interfaces.js").ScanResult>;
|
|
21
|
-
sync: ({ accountIndex }
|
|
21
|
+
sync: ({ accountIndex: index, isMultisig }?: import("../module/interfaces.js").SyncParams) => Promise<import("../module/interfaces.js").SyncedKeysId>;
|
|
22
22
|
addPublicKeysToWalletAccount: ({ walletAccountName, syncedKeysId, }: import("../module/interfaces.js").StoreSyncedKeysParams) => Promise<void>;
|
|
23
|
-
create: ({ syncedKeysId }: import("../module/interfaces.js").CreateParams) => Promise<
|
|
23
|
+
create: ({ syncedKeysId, isMultisig }: import("../module/interfaces.js").CreateParams) => Promise<import("@exodus/models").WalletAccount>;
|
|
24
24
|
};
|
|
25
25
|
};
|
|
26
26
|
readonly dependencies: readonly ["hardwareWallets", "txLogMonitors", "restoreProgressTracker"];
|
package/lib/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import hardwareWalletsApiDefinition from './api/index.js';
|
|
1
2
|
declare const hardwareWallets: () => {
|
|
2
3
|
readonly id: "hardwareWallets";
|
|
3
4
|
readonly definitions: readonly [{
|
|
@@ -20,9 +21,9 @@ declare const hardwareWallets: () => {
|
|
|
20
21
|
canAccessAsset: ({ assetName }: import("./module/interfaces.js").CanAccessAssetParams) => Promise<boolean>;
|
|
21
22
|
ensureApplicationIsOpened: ({ assetName }: import("./module/interfaces.js").EnsureApplicationIsOpenedParams) => Promise<void>;
|
|
22
23
|
scan: ({ assetName, accountIndexes, addressLimit, addressOffset, }: import("./module/interfaces.js").ScanParams) => Promise<import("./module/interfaces.js").ScanResult>;
|
|
23
|
-
sync: ({ accountIndex }
|
|
24
|
+
sync: ({ accountIndex: index, isMultisig }?: import("./module/interfaces.js").SyncParams) => Promise<import("./module/interfaces.js").SyncedKeysId>;
|
|
24
25
|
addPublicKeysToWalletAccount: ({ walletAccountName, syncedKeysId, }: import("./module/interfaces.js").StoreSyncedKeysParams) => Promise<void>;
|
|
25
|
-
create: ({ syncedKeysId }: import("./module/interfaces.js").CreateParams) => Promise<
|
|
26
|
+
create: ({ syncedKeysId, isMultisig }: import("./module/interfaces.js").CreateParams) => Promise<import("@exodus/models").WalletAccount>;
|
|
26
27
|
};
|
|
27
28
|
};
|
|
28
29
|
readonly dependencies: readonly ["hardwareWallets", "txLogMonitors", "restoreProgressTracker"];
|
|
@@ -36,4 +37,5 @@ declare const hardwareWallets: () => {
|
|
|
36
37
|
};
|
|
37
38
|
}];
|
|
38
39
|
};
|
|
40
|
+
export type HardwareWalletsApi = ReturnType<typeof hardwareWalletsApiDefinition.factory>;
|
|
39
41
|
export default hardwareWallets;
|
|
@@ -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, RequireDeviceForParams } from './interfaces.js';
|
|
3
|
+
import type { HardwareSignerProvider, CanAccessAssetParams, CreateParams, StoreSyncedKeysParams, ScanParams, SyncParams, EnsureApplicationIsOpenedParams, SignTransactionParams, ScanResult, SyncedKeysId, GetAddressParams, RequireDeviceForParams } 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-store';
|
|
@@ -21,7 +21,7 @@ export declare class HardwareWallets implements HardwareSignerProvider {
|
|
|
21
21
|
#private;
|
|
22
22
|
readonly events: Emitter<string, any>;
|
|
23
23
|
constructor({ assetsModule, ledgerDiscovery, logger, userInterface, publicKeyStore, wallet, walletAccountsAtom, walletAccounts, }: Dependencies);
|
|
24
|
-
signTransaction: ({ baseAssetName, unsignedTx, walletAccount }: SignTransactionParams) => Promise<any>;
|
|
24
|
+
signTransaction: ({ baseAssetName, unsignedTx, walletAccount, multisigData, }: SignTransactionParams) => Promise<any>;
|
|
25
25
|
signMessage: ({ assetName, derivationPath, message }: SignMessageParams) => Promise<any>;
|
|
26
26
|
isDeviceConnected: () => Promise<boolean>;
|
|
27
27
|
scanForDevices: () => Promise<void>;
|
|
@@ -32,12 +32,13 @@ export declare class HardwareWallets implements HardwareSignerProvider {
|
|
|
32
32
|
canAccessAsset: ({ assetName }: CanAccessAssetParams) => Promise<boolean>;
|
|
33
33
|
listUseableAssetNames: () => Promise<string[]>;
|
|
34
34
|
ensureApplicationIsOpened: ({ assetName }: EnsureApplicationIsOpenedParams) => Promise<void>;
|
|
35
|
+
getAddress: ({ assetName, accountIndex, addressIndex, multisigData, displayOnDevice, }: GetAddressParams) => Promise<string>;
|
|
35
36
|
scan: ({ assetName, accountIndexes, addressLimit, addressOffset, }: ScanParams) => Promise<ScanResult>;
|
|
36
|
-
sync: ({ accountIndex }
|
|
37
|
+
sync: ({ accountIndex: index, isMultisig }?: SyncParams) => Promise<SyncedKeysId>;
|
|
37
38
|
addPublicKeysToWalletAccount: ({ walletAccountName, syncedKeysId, }: StoreSyncedKeysParams) => Promise<void>;
|
|
38
|
-
create: ({ syncedKeysId }: CreateParams) => Promise<
|
|
39
|
+
create: ({ syncedKeysId, isMultisig }: CreateParams) => Promise<WalletAccount>;
|
|
39
40
|
requireDeviceFor: ({ walletAccount }: RequireDeviceForParams) => Promise<{
|
|
40
|
-
signTransaction: ({ baseAssetName, unsignedTx, walletAccount }: SignTransactionParams) => Promise<any>;
|
|
41
|
+
signTransaction: ({ baseAssetName, unsignedTx, walletAccount, multisigData, }: SignTransactionParams) => Promise<any>;
|
|
41
42
|
signMessage: ({ assetName, derivationPath, message }: SignMessageParams) => Promise<any>;
|
|
42
43
|
}>;
|
|
43
44
|
}
|
|
@@ -53,7 +53,7 @@ export class HardwareWallets {
|
|
|
53
53
|
break;
|
|
54
54
|
}
|
|
55
55
|
if (error.name === 'DisconnectedDeviceDuringOperation') {
|
|
56
|
-
|
|
56
|
+
this.#requestUserAction({
|
|
57
57
|
scenario,
|
|
58
58
|
baseAssetName,
|
|
59
59
|
});
|
|
@@ -82,7 +82,7 @@ export class HardwareWallets {
|
|
|
82
82
|
this.#requestUserAction({ scenario: 'completed' });
|
|
83
83
|
throw new UserCancelledError();
|
|
84
84
|
};
|
|
85
|
-
signTransaction = async ({ baseAssetName, unsignedTx, walletAccount }) => {
|
|
85
|
+
signTransaction = async ({ baseAssetName, unsignedTx, walletAccount, multisigData, }) => {
|
|
86
86
|
const baseAsset = this.#assetsModule.getAsset(baseAssetName);
|
|
87
87
|
const accountIndex = walletAccount.index;
|
|
88
88
|
const sign = async ({ hardwareDevice }) => {
|
|
@@ -90,6 +90,7 @@ export class HardwareWallets {
|
|
|
90
90
|
unsignedTx,
|
|
91
91
|
hardwareDevice,
|
|
92
92
|
accountIndex,
|
|
93
|
+
multisigData,
|
|
93
94
|
});
|
|
94
95
|
};
|
|
95
96
|
return this.#signGeneric({ baseAssetName, scenario: 'signTransaction', sign });
|
|
@@ -152,10 +153,11 @@ export class HardwareWallets {
|
|
|
152
153
|
}
|
|
153
154
|
}
|
|
154
155
|
};
|
|
155
|
-
|
|
156
|
+
getAddress = async ({ assetName, accountIndex, addressIndex, multisigData, displayOnDevice, }) => {
|
|
156
157
|
const asset = this.#assetsModule.getAsset(assetName);
|
|
157
158
|
const supportedPurposes = asset.baseAsset.api.getSupportedPurposes({
|
|
158
159
|
compatibilityMode: 'ledger',
|
|
160
|
+
isMultisig: !!multisigData,
|
|
159
161
|
});
|
|
160
162
|
const { derivationPath } = asset.baseAsset.api.getKeyIdentifier({
|
|
161
163
|
compatibilityMode: 'ledger',
|
|
@@ -168,6 +170,8 @@ export class HardwareWallets {
|
|
|
168
170
|
return device.getAddress({
|
|
169
171
|
assetName,
|
|
170
172
|
derivationPath,
|
|
173
|
+
multisigData,
|
|
174
|
+
displayOnDevice,
|
|
171
175
|
});
|
|
172
176
|
};
|
|
173
177
|
#getXPUB = async ({ device, baseAsset, purpose, accountIndex, }) => {
|
|
@@ -220,7 +224,7 @@ export class HardwareWallets {
|
|
|
220
224
|
const startIndex = offsetBy;
|
|
221
225
|
const addresses = [];
|
|
222
226
|
for (let idx = startIndex; idx < startIndex + n; idx++) {
|
|
223
|
-
addresses.push(await this
|
|
227
|
+
addresses.push(await this.getAddress({ assetName, accountIndex, addressIndex: idx }));
|
|
224
228
|
}
|
|
225
229
|
const fetchedBalances = await Promise.all(addresses.map(async (address) => ({
|
|
226
230
|
address,
|
|
@@ -253,9 +257,10 @@ export class HardwareWallets {
|
|
|
253
257
|
}
|
|
254
258
|
return accounts;
|
|
255
259
|
};
|
|
256
|
-
sync = async ({ accountIndex }) => {
|
|
260
|
+
sync = async ({ accountIndex: index, isMultisig } = {}) => {
|
|
257
261
|
const keysToSync = [];
|
|
258
262
|
const device = await this.#ledgerDiscovery.getFirstDevice();
|
|
263
|
+
const accountIndex = index ?? this.#walletAccounts.getNextIndex({ source: WalletAccount.LEDGER_SRC });
|
|
259
264
|
const useableAssetNames = new Set(await device.listUseableAssetNames());
|
|
260
265
|
for (const assetName of useableAssetNames) {
|
|
261
266
|
const asset = this.#assetsModule.getAsset(assetName);
|
|
@@ -263,6 +268,7 @@ export class HardwareWallets {
|
|
|
263
268
|
const baseAsset = asset.baseAsset;
|
|
264
269
|
const supportedPurposes = baseAsset.api.getSupportedPurposes({
|
|
265
270
|
compatibilityMode: 'ledger',
|
|
271
|
+
isMultisig,
|
|
266
272
|
});
|
|
267
273
|
for (const purpose of supportedPurposes) {
|
|
268
274
|
const { keyIdentifier, xpub, publicKey, } = (await this.#getXPUB({ device, baseAsset, purpose, accountIndex })) ||
|
|
@@ -287,7 +293,7 @@ export class HardwareWallets {
|
|
|
287
293
|
}
|
|
288
294
|
this.events.emit('syncAssets', { assetNames });
|
|
289
295
|
};
|
|
290
|
-
create = async ({ syncedKeysId }) => {
|
|
296
|
+
create = async ({ syncedKeysId, isMultisig }) => {
|
|
291
297
|
assert(this.#syncedKeysMap.has(syncedKeysId), `no synchronized keys found for id ${syncedKeysId}`);
|
|
292
298
|
const { accountIndex } = this.#syncedKeysMap.get(syncedKeysId);
|
|
293
299
|
const walletAccount = new WalletAccount({
|
|
@@ -296,11 +302,13 @@ export class HardwareWallets {
|
|
|
296
302
|
source: WalletAccount.LEDGER_SRC,
|
|
297
303
|
index: accountIndex,
|
|
298
304
|
id: randomBytes(32).toString('hex'),
|
|
305
|
+
isMultisig: !!isMultisig,
|
|
299
306
|
});
|
|
300
307
|
const walletAccountName = walletAccount.toString();
|
|
301
308
|
await this.#walletAccounts.create(walletAccount);
|
|
302
309
|
await this.#walletAccounts.setActive(walletAccountName);
|
|
303
310
|
await this.addPublicKeysToWalletAccount({ walletAccountName, syncedKeysId });
|
|
311
|
+
return walletAccount;
|
|
304
312
|
};
|
|
305
313
|
requireDeviceFor = async ({ walletAccount }) => {
|
|
306
314
|
return {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { WalletAccount } from '@exodus/models';
|
|
2
|
-
import type { HardwareWalletDevice, SignMessageParams } from '@exodus/hw-common';
|
|
2
|
+
import type { HardwareWalletDevice, MultisigData, SignMessageParams } from '@exodus/hw-common';
|
|
3
3
|
import type KeyIdentifier from '@exodus/key-identifier';
|
|
4
4
|
export interface HardwareSignerProvider {
|
|
5
5
|
isDeviceConnected: () => Promise<boolean>;
|
|
@@ -10,7 +10,7 @@ export interface HardwareSignerProvider {
|
|
|
10
10
|
scan: ({ assetName, accountIndexes, addressOffset }: ScanParams) => Promise<ScanResult>;
|
|
11
11
|
sync: ({ accountIndex }: SyncParams) => Promise<SyncedKeysId>;
|
|
12
12
|
addPublicKeysToWalletAccount: ({ walletAccountName, syncedKeysId, }: StoreSyncedKeysParams) => Promise<void>;
|
|
13
|
-
create: ({ syncedKeysId }: CreateParams) => Promise<
|
|
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
16
|
}
|
|
@@ -53,7 +53,8 @@ export type ScannedAccount = {
|
|
|
53
53
|
};
|
|
54
54
|
export type ScanResult = ScannedAccount[];
|
|
55
55
|
export interface SyncParams {
|
|
56
|
-
accountIndex
|
|
56
|
+
accountIndex?: number;
|
|
57
|
+
isMultisig?: boolean;
|
|
57
58
|
}
|
|
58
59
|
export type SyncedKeysId = string;
|
|
59
60
|
export interface SyncedKeysData {
|
|
@@ -71,6 +72,7 @@ export interface StoreSyncedKeysParams {
|
|
|
71
72
|
}
|
|
72
73
|
export interface CreateParams {
|
|
73
74
|
syncedKeysId: SyncedKeysId;
|
|
75
|
+
isMultisig?: boolean;
|
|
74
76
|
}
|
|
75
77
|
export type GenericSignCallback = ({ hardwareDevice, }: {
|
|
76
78
|
hardwareDevice: HardwareWalletDevice;
|
|
@@ -84,6 +86,7 @@ export interface SignTransactionParams {
|
|
|
84
86
|
baseAssetName: string;
|
|
85
87
|
unsignedTx: UnsignedTransaction;
|
|
86
88
|
walletAccount: WalletAccount;
|
|
89
|
+
multisigData?: MultisigData;
|
|
87
90
|
}
|
|
88
91
|
export interface UnsignedTransaction {
|
|
89
92
|
txData: any;
|
|
@@ -93,6 +96,8 @@ export interface GetAddressParams {
|
|
|
93
96
|
assetName: string;
|
|
94
97
|
accountIndex: number;
|
|
95
98
|
addressIndex: number;
|
|
99
|
+
multisigData?: MultisigData;
|
|
100
|
+
displayOnDevice?: boolean;
|
|
96
101
|
}
|
|
97
102
|
export interface GetXPUBParams {
|
|
98
103
|
device: HardwareWalletDevice;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/hardware-wallets",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.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": {
|
|
@@ -22,23 +22,24 @@
|
|
|
22
22
|
"scripts": {
|
|
23
23
|
"build": "run -T tsc --build tsconfig.build.json",
|
|
24
24
|
"clean": "run -T tsc --build --clean",
|
|
25
|
-
"lint": "run -T eslint .
|
|
25
|
+
"lint": "run -T eslint .",
|
|
26
26
|
"lint:fix": "yarn lint --fix",
|
|
27
27
|
"test": "run -T jest",
|
|
28
28
|
"prepublishOnly": "yarn run -T build --scope @exodus/hardware-wallets"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@exodus/models": "^
|
|
31
|
+
"@exodus/models": "^12.0.1",
|
|
32
32
|
"@exodus/wild-emitter": "^1.1.0",
|
|
33
33
|
"delay": "^5.0.0",
|
|
34
34
|
"minimalistic-assert": "^1.0.1",
|
|
35
35
|
"randombytes": "^2.1.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@exodus/atoms": "^8.
|
|
38
|
+
"@exodus/atoms": "^8.1.1",
|
|
39
39
|
"@exodus/hw-common": "^2.3.0",
|
|
40
40
|
"@exodus/logger": "^1.2.2",
|
|
41
|
-
"@exodus/public-key-store": "^1.2.2"
|
|
41
|
+
"@exodus/public-key-store": "^1.2.2",
|
|
42
|
+
"@types/randombytes": "^2.0.3"
|
|
42
43
|
},
|
|
43
|
-
"gitHead": "
|
|
44
|
+
"gitHead": "758ea1b22f91994c5982c19071ff1f80f63e48be"
|
|
44
45
|
}
|