@exodus/hw-ledger 2.9.4 → 2.10.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 +13 -0
- package/lib/atoms/index.d.ts +17 -1
- package/lib/atoms/index.js +18 -2
- package/lib/index.d.ts +16 -7
- package/lib/index.js +4 -1
- package/lib/module/assets/bitcoin.d.ts +2 -1
- package/lib/module/assets/bitcoin.js +39 -8
- package/lib/module/assets/ethereum.js +1 -1
- package/lib/module/assets/index.d.ts +2 -1
- package/lib/module/assets/index.js +1 -0
- package/lib/module/assets/utils/psbt.d.ts +7 -3
- package/lib/module/assets/utils/psbt.js +42 -7
- package/lib/module/assets/utils/xpub.js +1 -1
- package/lib/module/device.d.ts +3 -1
- package/lib/module/device.js +5 -3
- package/lib/module/discovery.d.ts +8 -3
- package/lib/module/discovery.js +47 -4
- package/lib/plugin/index.d.ts +6 -7
- package/lib/plugin/index.js +3 -26
- package/lib/redux/index.d.ts +2 -2
- package/lib/redux/initial-state.d.ts +1 -4
- package/lib/redux/selectors/bluetoothStatus.d.ts +1 -1
- package/lib/redux/selectors/index.d.ts +1 -1
- package/package.json +5 -4
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,19 @@
|
|
|
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.10.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/hw-ledger@2.9.5...@exodus/hw-ledger@2.10.0) (2024-09-16)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
- add bitcoin multisig support to ledger ([#9218](https://github.com/ExodusMovement/exodus-hydra/issues/9218)) ([1b63e8a](https://github.com/ExodusMovement/exodus-hydra/commit/1b63e8a6ac7bab9cd580f602f2fd0cbff48ed01c))
|
|
11
|
+
|
|
12
|
+
## [2.9.5](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/hw-ledger@2.9.4...@exodus/hw-ledger@2.9.5) (2024-08-16)
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
- bluetooth on scan ([#8457](https://github.com/ExodusMovement/exodus-hydra/issues/8457)) ([c6cef7a](https://github.com/ExodusMovement/exodus-hydra/commit/c6cef7a19dad315bdbe8e01ea353f108348d48e3))
|
|
17
|
+
- use safe alloc ([#8467](https://github.com/ExodusMovement/exodus-hydra/issues/8467)) ([926ef36](https://github.com/ExodusMovement/exodus-hydra/commit/926ef36d1478e8fea290b56eabab5c807e7e6695))
|
|
18
|
+
|
|
6
19
|
## [2.9.4](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/hw-ledger@2.9.3...@exodus/hw-ledger@2.9.4) (2024-08-14)
|
|
7
20
|
|
|
8
21
|
### Bug Fixes
|
package/lib/atoms/index.d.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
+
import type { Storage } from 'adapters/storage-interface';
|
|
2
|
+
export type BluetoothStatus = {
|
|
3
|
+
type: 'Unknown' | 'Resetting' | 'Unsupported' | 'Unauthorized' | 'PoweredOff' | 'PoweredOn';
|
|
4
|
+
available: boolean;
|
|
5
|
+
};
|
|
1
6
|
export declare const bluetoothStatusAtomDefinition: {
|
|
2
7
|
readonly id: "bluetoothStatusAtom";
|
|
3
8
|
readonly type: "atom";
|
|
4
|
-
readonly factory: () => import("@exodus/atoms").Atom<
|
|
9
|
+
readonly factory: () => import("@exodus/atoms").Atom<BluetoothStatus>;
|
|
5
10
|
readonly dependencies: readonly [];
|
|
6
11
|
readonly public: true;
|
|
7
12
|
};
|
|
@@ -12,3 +17,14 @@ export declare const bluetoothScanningAtomDefinition: {
|
|
|
12
17
|
readonly dependencies: readonly [];
|
|
13
18
|
readonly public: true;
|
|
14
19
|
};
|
|
20
|
+
type Params = {
|
|
21
|
+
storage: Storage<Record<string, Buffer>>;
|
|
22
|
+
};
|
|
23
|
+
export declare const walletPolicyAtomDefinition: {
|
|
24
|
+
readonly id: "walletPolicyAtom";
|
|
25
|
+
readonly type: "atom";
|
|
26
|
+
readonly factory: ({ storage }: Params) => import("@exodus/atoms").Atom<Record<string, Buffer> | {}>;
|
|
27
|
+
readonly dependencies: readonly ["storage"];
|
|
28
|
+
readonly public: true;
|
|
29
|
+
};
|
|
30
|
+
export {};
|
package/lib/atoms/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { createInMemoryAtom } from '@exodus/atoms';
|
|
1
|
+
import { createInMemoryAtom, createStorageAtomFactory } from '@exodus/atoms';
|
|
2
2
|
export const bluetoothStatusAtomDefinition = {
|
|
3
3
|
id: 'bluetoothStatusAtom',
|
|
4
4
|
type: 'atom',
|
|
5
|
-
factory: () => createInMemoryAtom({
|
|
5
|
+
factory: () => createInMemoryAtom({
|
|
6
|
+
defaultValue: { type: 'Unknown', available: false },
|
|
7
|
+
}),
|
|
6
8
|
dependencies: [],
|
|
7
9
|
public: true,
|
|
8
10
|
};
|
|
@@ -13,3 +15,17 @@ export const bluetoothScanningAtomDefinition = {
|
|
|
13
15
|
dependencies: [],
|
|
14
16
|
public: true,
|
|
15
17
|
};
|
|
18
|
+
export const walletPolicyAtomDefinition = {
|
|
19
|
+
id: 'walletPolicyAtom',
|
|
20
|
+
type: 'atom',
|
|
21
|
+
factory: ({ storage }) => {
|
|
22
|
+
const createStorageAtom = createStorageAtomFactory({ storage });
|
|
23
|
+
return createStorageAtom({
|
|
24
|
+
key: 'walletPolicy',
|
|
25
|
+
defaultValue: {},
|
|
26
|
+
isSoleWriter: true,
|
|
27
|
+
});
|
|
28
|
+
},
|
|
29
|
+
dependencies: ['storage'],
|
|
30
|
+
public: true,
|
|
31
|
+
};
|
package/lib/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ declare const hardwareWalletLedger: ({ bluetoothScannerTimeout, }?: Partial<HwLe
|
|
|
5
5
|
readonly definition: {
|
|
6
6
|
readonly id: "bluetoothStatusAtom";
|
|
7
7
|
readonly type: "atom";
|
|
8
|
-
readonly factory: () => import("libraries/atoms/lib").Atom<
|
|
8
|
+
readonly factory: () => import("libraries/atoms/lib").Atom<import("./atoms").BluetoothStatus>;
|
|
9
9
|
readonly dependencies: readonly [];
|
|
10
10
|
readonly public: true;
|
|
11
11
|
};
|
|
@@ -17,22 +17,31 @@ declare const hardwareWalletLedger: ({ bluetoothScannerTimeout, }?: Partial<HwLe
|
|
|
17
17
|
readonly dependencies: readonly [];
|
|
18
18
|
readonly public: true;
|
|
19
19
|
};
|
|
20
|
+
}, {
|
|
21
|
+
readonly definition: {
|
|
22
|
+
readonly id: "walletPolicyAtom";
|
|
23
|
+
readonly type: "atom";
|
|
24
|
+
readonly factory: ({ storage }: {
|
|
25
|
+
storage: import("adapters/storage-interface").Storage<Record<string, Buffer>>;
|
|
26
|
+
}) => import("libraries/atoms/lib").Atom<Record<string, Buffer> | {}>;
|
|
27
|
+
readonly dependencies: readonly ["storage"];
|
|
28
|
+
readonly public: true;
|
|
29
|
+
};
|
|
20
30
|
}, {
|
|
21
31
|
readonly definition: {
|
|
22
32
|
readonly id: "hardwareWalletLedgerPlugin";
|
|
23
33
|
readonly type: "plugin";
|
|
24
|
-
readonly factory: ({
|
|
25
|
-
|
|
26
|
-
transportsFactories: import("./module/types").TransportFactories;
|
|
27
|
-
bluetoothStatusAtom: import("libraries/atoms/lib").Atom<import("./redux/initial-state").BluetoothStatus>;
|
|
34
|
+
readonly factory: ({ bluetoothStatusAtom, bluetoothScanningAtom, ledgerDiscovery, port, }: {
|
|
35
|
+
bluetoothStatusAtom: import("libraries/atoms/lib").Atom<import("./atoms").BluetoothStatus>;
|
|
28
36
|
bluetoothScanningAtom: import("libraries/atoms/lib").Atom<boolean>;
|
|
37
|
+
ledgerDiscovery: import("./module").LedgerDiscovery;
|
|
29
38
|
port: import("./shared/types").Port;
|
|
30
39
|
}) => {
|
|
31
40
|
onUnlock: () => void;
|
|
32
41
|
onLoad: () => void;
|
|
33
42
|
onStop: () => void;
|
|
34
43
|
};
|
|
35
|
-
readonly dependencies: readonly ["
|
|
44
|
+
readonly dependencies: readonly ["bluetoothStatusAtom", "bluetoothScanningAtom", "ledgerDiscovery", "port"];
|
|
36
45
|
readonly public: true;
|
|
37
46
|
};
|
|
38
47
|
}, {
|
|
@@ -40,7 +49,7 @@ declare const hardwareWalletLedger: ({ bluetoothScannerTimeout, }?: Partial<HwLe
|
|
|
40
49
|
readonly id: "ledgerDiscovery";
|
|
41
50
|
readonly type: "module";
|
|
42
51
|
readonly factory: (deps: import("./module").Dependencies) => import("./module").LedgerDiscovery;
|
|
43
|
-
readonly dependencies: readonly ["config", "logger", "transportsFactories", "bluetoothScanningAtom"];
|
|
52
|
+
readonly dependencies: readonly ["config", "logger", "transportsFactories", "bluetoothStatusAtom", "bluetoothScanningAtom", "walletPolicyAtom"];
|
|
44
53
|
readonly public: true;
|
|
45
54
|
};
|
|
46
55
|
readonly config: {
|
package/lib/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { bluetoothStatusAtomDefinition, bluetoothScanningAtomDefinition } from './atoms';
|
|
1
|
+
import { bluetoothStatusAtomDefinition, bluetoothScanningAtomDefinition, walletPolicyAtomDefinition, } from './atoms';
|
|
2
2
|
import ledgerDiscoveryDefinition from './module';
|
|
3
3
|
import hardwareWalletLedgerPluginDefinition from './plugin';
|
|
4
4
|
const hardwareWalletLedger = ({ bluetoothScannerTimeout = 10_000, } = {}) => {
|
|
@@ -11,6 +11,9 @@ const hardwareWalletLedger = ({ bluetoothScannerTimeout = 10_000, } = {}) => {
|
|
|
11
11
|
{
|
|
12
12
|
definition: bluetoothScanningAtomDefinition,
|
|
13
13
|
},
|
|
14
|
+
{
|
|
15
|
+
definition: walletPolicyAtomDefinition,
|
|
16
|
+
},
|
|
14
17
|
{
|
|
15
18
|
definition: hardwareWalletLedgerPluginDefinition,
|
|
16
19
|
},
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type Transport from '@ledgerhq/hw-transport';
|
|
2
|
+
import type { Atom } from '@exodus/atoms';
|
|
2
3
|
import type { Bytes, HardwareWalletAssetHandler } from '@exodus/hw-common';
|
|
3
4
|
export interface BitcoinMessage {
|
|
4
5
|
rawMessage?: Bytes;
|
|
@@ -7,7 +8,7 @@ export interface BitcoinMessage {
|
|
|
7
8
|
message: Bytes;
|
|
8
9
|
};
|
|
9
10
|
}
|
|
10
|
-
declare function createHandler(transport: Transport): Promise<HardwareWalletAssetHandler<BitcoinMessage>>;
|
|
11
|
+
declare function createHandler(transport: Transport, walletPolicyAtom?: Atom<Record<string, Buffer>>): Promise<HardwareWalletAssetHandler<BitcoinMessage>>;
|
|
11
12
|
declare const metadata: {
|
|
12
13
|
applications: {
|
|
13
14
|
applicationName: string;
|
|
@@ -3,17 +3,25 @@ import { AppClient, PsbtV2 } from '@exodus/ledger-bitcoin';
|
|
|
3
3
|
import { BIP322 } from '@exodus/bip322-js';
|
|
4
4
|
import { splitBip44DerivationPath } from './utils';
|
|
5
5
|
import assert from 'minimalistic-assert';
|
|
6
|
-
import { assertPsbtOnlyHasAllowedDerivationPaths, tagPsbtWithDerivationPaths, getWalletPolicy, derivationPathsToWalletPolicy, addDummyInputs, } from './utils/psbt';
|
|
6
|
+
import { assertPsbtOnlyHasAllowedDerivationPaths, tagPsbtWithDerivationPaths, getWalletPolicy, getMultisigWalletPolicy, derivationPathsToWalletPolicy, addDummyInputs, } from './utils/psbt';
|
|
7
7
|
import { buildBip322PSBT } from './utils/bip322';
|
|
8
8
|
import applications from './applications';
|
|
9
|
-
async function createHandler(transport) {
|
|
9
|
+
async function createHandler(transport, walletPolicyAtom) {
|
|
10
10
|
const app = new AppClient(transport);
|
|
11
11
|
const getAddress = async (params) => {
|
|
12
12
|
const [purpose, coin, account, change, address] = splitBip44DerivationPath(params.derivationPath);
|
|
13
13
|
const fpr = await app.getMasterFingerprint();
|
|
14
14
|
const xpub = await app.getExtendedPubkey(`m/${purpose}/${coin}/${account}`);
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
let walletPolicy;
|
|
16
|
+
let hmac = null;
|
|
17
|
+
if (params.multisigData) {
|
|
18
|
+
walletPolicy = getMultisigWalletPolicy(fpr, xpub, purpose, coin, account, params.multisigData);
|
|
19
|
+
hmac = await registerWalletPolicy(walletPolicy);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
walletPolicy = getWalletPolicy(fpr, xpub, purpose, coin, account);
|
|
23
|
+
}
|
|
24
|
+
return app.getWalletAddress(walletPolicy, hmac, Number(change), Number(address), params.displayOnDevice ?? false);
|
|
17
25
|
};
|
|
18
26
|
const getXPub = async (params) => {
|
|
19
27
|
return app.getExtendedPubkey(params.derivationPath);
|
|
@@ -28,19 +36,30 @@ async function createHandler(transport) {
|
|
|
28
36
|
psbt.deserialize(psbtBuffer);
|
|
29
37
|
const fpr = await app.getMasterFingerprint();
|
|
30
38
|
const derivationPathToPublicKeyMap = Object.create(null);
|
|
39
|
+
const addressToDerivationPathMap = Object.create(null);
|
|
31
40
|
for (const derivationPath of params.derivationPaths) {
|
|
32
|
-
|
|
41
|
+
if (params.multisigData) {
|
|
42
|
+
const address = await getAddress({
|
|
43
|
+
assetName: 'bitcoin',
|
|
44
|
+
derivationPath,
|
|
45
|
+
multisigData: params.multisigData,
|
|
46
|
+
});
|
|
47
|
+
addressToDerivationPathMap[address] = derivationPath;
|
|
48
|
+
}
|
|
49
|
+
const publicKey = await getPublicKey({
|
|
33
50
|
assetName: 'bitcoin',
|
|
34
51
|
derivationPath,
|
|
35
52
|
});
|
|
53
|
+
derivationPathToPublicKeyMap[derivationPath] = publicKey;
|
|
36
54
|
}
|
|
37
|
-
tagPsbtWithDerivationPaths(psbt, fpr, derivationPathToPublicKeyMap);
|
|
55
|
+
tagPsbtWithDerivationPaths(psbt, fpr, derivationPathToPublicKeyMap, addressToDerivationPathMap);
|
|
38
56
|
addDummyInputs(psbt);
|
|
39
57
|
assertPsbtOnlyHasAllowedDerivationPaths(psbt, fpr, params.derivationPaths);
|
|
40
58
|
const signatures = [];
|
|
41
|
-
const walletPolicies = await derivationPathsToWalletPolicy(fpr, app, params.derivationPaths);
|
|
59
|
+
const walletPolicies = await derivationPathsToWalletPolicy(fpr, app, params.derivationPaths, params.multisigData);
|
|
42
60
|
for (const walletPolicy of walletPolicies) {
|
|
43
|
-
const
|
|
61
|
+
const hmac = params.multisigData ? await registerWalletPolicy(walletPolicy) : null;
|
|
62
|
+
const _signatures = await app.signPsbt(psbt.serialize(), walletPolicy, hmac);
|
|
44
63
|
signatures.push(..._signatures);
|
|
45
64
|
}
|
|
46
65
|
const result = signatures.map(([inputIndex, partialSignature]) => ({
|
|
@@ -95,6 +114,18 @@ async function createHandler(transport) {
|
|
|
95
114
|
}
|
|
96
115
|
throw new Error('rawMessage or bip322Message must be defined');
|
|
97
116
|
};
|
|
117
|
+
const registerWalletPolicy = async (walletPolicy) => {
|
|
118
|
+
const walletPolicies = (await walletPolicyAtom?.get()) ?? {};
|
|
119
|
+
const id = walletPolicy.getId().toString('hex');
|
|
120
|
+
let hmac = walletPolicies[id];
|
|
121
|
+
if (!hmac) {
|
|
122
|
+
const [, h] = await app.registerWallet(walletPolicy);
|
|
123
|
+
hmac = h;
|
|
124
|
+
const updatedPolicies = { ...walletPolicies, [id]: hmac };
|
|
125
|
+
await walletPolicyAtom?.set(updatedPolicies);
|
|
126
|
+
}
|
|
127
|
+
return hmac;
|
|
128
|
+
};
|
|
98
129
|
return {
|
|
99
130
|
getAddress,
|
|
100
131
|
getPublicKey,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import secp256k1 from '@exodus/secp256k1';
|
|
2
2
|
import * as ethers from '@exodus/ethersproject-transactions';
|
|
3
3
|
import AppEth, { ledgerService } from '@exodus/ledgerhq-hw-app-eth';
|
|
4
|
-
import { TypedDataUtils, SignTypedDataVersion
|
|
4
|
+
import { TypedDataUtils, SignTypedDataVersion } from '@metamask/eth-sig-util';
|
|
5
5
|
import assert from 'minimalistic-assert';
|
|
6
6
|
import { buildFauxXPUB } from './utils';
|
|
7
7
|
import { RequiresBlindSigningError } from '../errors';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type Transport from '@ledgerhq/hw-transport';
|
|
2
2
|
import type { HardwareWalletAssetHandler } from '@exodus/hw-common';
|
|
3
|
-
type
|
|
3
|
+
import type { Atom } from '@exodus/atoms';
|
|
4
|
+
type HandlerFactory = (transport: Transport, walletPolicyAtom?: Atom<Record<string, Buffer>>) => Promise<HardwareWalletAssetHandler>;
|
|
4
5
|
type AssetMetadata = {
|
|
5
6
|
applications: {
|
|
6
7
|
applicationName: string;
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { PsbtV2 } from '@exodus/ledger-bitcoin';
|
|
2
|
+
import { DefaultWalletPolicy, WalletPolicy } from '@exodus/ledger-bitcoin';
|
|
3
|
+
import type { MultisigData } from 'libraries/hw-common/lib';
|
|
2
4
|
export declare function assertPsbtOnlyHasAllowedDerivationPaths(psbt: PsbtV2, masterFingerprint: string, derivationPaths: string[]): void;
|
|
3
|
-
export declare function tagPsbtWithDerivationPaths(psbt: PsbtV2, masterFingerprint: string, derivationPathToPublicKeyMap: Record<string, Buffer>): void;
|
|
5
|
+
export declare function tagPsbtWithDerivationPaths(psbt: PsbtV2, masterFingerprint: string, derivationPathToPublicKeyMap: Record<string, Buffer>, addressToDerivationPathMap?: Record<string, string>): void;
|
|
4
6
|
export declare const getWalletPolicy: (fpr: string, xpub: string, purpose: string, coin: string, account: string) => DefaultWalletPolicy;
|
|
5
|
-
export declare
|
|
7
|
+
export declare const DUMMY_TAPROOT_XPUB = "xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6QgnecKFpJFPpdzxKrwoaZoV44qAJewsc4kX9vGaCaBExuvJH57";
|
|
8
|
+
export declare const getMultisigWalletPolicy: (fpr: string, xpub: string, purpose: string, coin: string, account: string, multisigData: MultisigData) => WalletPolicy;
|
|
9
|
+
export declare function derivationPathsToWalletPolicy(fpr: string, app: any, derivationPaths: string[], multisigData?: MultisigData): Promise<WalletPolicy[]>;
|
|
6
10
|
export declare function addDummyInputs(psbt: PsbtV2): void;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import assert from 'minimalistic-assert';
|
|
2
|
-
import { DefaultWalletPolicy, } from '@exodus/ledger-bitcoin';
|
|
3
|
-
import { payments } from '@exodus/bitcoinjs-lib';
|
|
2
|
+
import { DefaultWalletPolicy, WalletPolicy } from '@exodus/ledger-bitcoin';
|
|
3
|
+
import { payments, address as baddress } from '@exodus/bitcoinjs-lib';
|
|
4
4
|
import { buildBip44PathFromNumber, assertBip44PathNumber, splitBip44PathToNumber, splitBip44DerivationPath, } from './derivation-paths';
|
|
5
5
|
export function assertPsbtOnlyHasAllowedDerivationPaths(psbt, masterFingerprint, derivationPaths) {
|
|
6
6
|
for (let i = 0; i < psbt.getGlobalInputCount(); i++) {
|
|
@@ -31,14 +31,21 @@ function assertAllowedDerivation(bip32Derivation, masterFingerprint, derivationP
|
|
|
31
31
|
assert(derivationPaths.includes(derivationPath), `found unsupported derivation path: ${derivationPath}`);
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
-
export function tagPsbtWithDerivationPaths(psbt, masterFingerprint, derivationPathToPublicKeyMap) {
|
|
34
|
+
export function tagPsbtWithDerivationPaths(psbt, masterFingerprint, derivationPathToPublicKeyMap, addressToDerivationPathMap) {
|
|
35
35
|
const masterFingerprintBuffer = Buffer.from(masterFingerprint, 'hex');
|
|
36
36
|
const scriptPubKeyToDerivationPathMap = computeScriptPubKeyToDerivationPathMap(derivationPathToPublicKeyMap);
|
|
37
37
|
for (let inputIndex = 0; inputIndex < psbt.getGlobalInputCount(); inputIndex++) {
|
|
38
38
|
const witnessUtxo = psbt.getInputWitnessUtxo(inputIndex);
|
|
39
39
|
assert(witnessUtxo, `witnessUtxo is currently the only supported type`);
|
|
40
40
|
const scriptPubKey = witnessUtxo.scriptPubKey.toString('hex');
|
|
41
|
-
|
|
41
|
+
let derivationPath = scriptPubKeyToDerivationPathMap[scriptPubKey];
|
|
42
|
+
if (addressToDerivationPathMap && !derivationPath) {
|
|
43
|
+
try {
|
|
44
|
+
const address = baddress.fromOutputScript(witnessUtxo.scriptPubKey);
|
|
45
|
+
derivationPath = addressToDerivationPathMap[address];
|
|
46
|
+
}
|
|
47
|
+
catch { }
|
|
48
|
+
}
|
|
42
49
|
if (derivationPath) {
|
|
43
50
|
const publicKey = derivationPathToPublicKeyMap[derivationPath];
|
|
44
51
|
assert(Buffer.isBuffer(publicKey), `no public key found for derivation path`);
|
|
@@ -53,7 +60,14 @@ export function tagPsbtWithDerivationPaths(psbt, masterFingerprint, derivationPa
|
|
|
53
60
|
}
|
|
54
61
|
for (let outputIndex = 0; outputIndex < psbt.getGlobalOutputCount(); outputIndex++) {
|
|
55
62
|
const scriptPubKey = psbt.getOutputScript(outputIndex);
|
|
56
|
-
|
|
63
|
+
let derivationPath = scriptPubKeyToDerivationPathMap[scriptPubKey.toString('hex')];
|
|
64
|
+
if (addressToDerivationPathMap && !derivationPath) {
|
|
65
|
+
try {
|
|
66
|
+
const address = baddress.fromOutputScript(scriptPubKey);
|
|
67
|
+
derivationPath = addressToDerivationPathMap[address];
|
|
68
|
+
}
|
|
69
|
+
catch { }
|
|
70
|
+
}
|
|
57
71
|
if (derivationPath) {
|
|
58
72
|
const publicKey = derivationPathToPublicKeyMap[derivationPath];
|
|
59
73
|
assert(Buffer.isBuffer(publicKey), `no public key found for derivation path`);
|
|
@@ -104,7 +118,23 @@ export const getWalletPolicy = (fpr, xpub, purpose, coin, account) => {
|
|
|
104
118
|
}[purpose];
|
|
105
119
|
return new DefaultWalletPolicy(desc, `[${fpr}/${purpose}/${coin}/${account}]${xpub}`);
|
|
106
120
|
};
|
|
107
|
-
export
|
|
121
|
+
export const DUMMY_TAPROOT_XPUB = 'xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6QgnecKFpJFPpdzxKrwoaZoV44qAJewsc4kX9vGaCaBExuvJH57';
|
|
122
|
+
export const getMultisigWalletPolicy = (fpr, xpub, purpose, coin, account, multisigData) => {
|
|
123
|
+
let template = `tr(@0/**,sortedmulti_a(${multisigData.threshold}`;
|
|
124
|
+
const keys = [DUMMY_TAPROOT_XPUB];
|
|
125
|
+
multisigData.xpubs.forEach((xpub2, i) => {
|
|
126
|
+
if (xpub === xpub2) {
|
|
127
|
+
keys.push(`[${fpr}/${purpose}/${coin}/${account}]${xpub}`);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
keys.push(xpub2);
|
|
131
|
+
}
|
|
132
|
+
template += `,@${i + 1}/**`;
|
|
133
|
+
});
|
|
134
|
+
template += '))';
|
|
135
|
+
return new WalletPolicy('Multisig', template, keys);
|
|
136
|
+
};
|
|
137
|
+
export async function derivationPathsToWalletPolicy(fpr, app, derivationPaths, multisigData) {
|
|
108
138
|
const splittedDerivationPaths = derivationPaths.map(splitBip44DerivationPath);
|
|
109
139
|
const dedupedPaths = Object.values(splittedDerivationPaths.reduce((prev, splittedDerivationPath) => {
|
|
110
140
|
const [purpose, coin, account] = splittedDerivationPath;
|
|
@@ -115,7 +145,12 @@ export async function derivationPathsToWalletPolicy(fpr, app, derivationPaths) {
|
|
|
115
145
|
for (const dedupedPath of dedupedPaths) {
|
|
116
146
|
const [purpose, coin, account] = dedupedPath;
|
|
117
147
|
const xpub = await app.getExtendedPubkey(`m/${purpose}/${coin}/${account}`);
|
|
118
|
-
|
|
148
|
+
if (multisigData) {
|
|
149
|
+
walletPolicies.push(getMultisigWalletPolicy(fpr, xpub, purpose, coin, account, multisigData));
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
walletPolicies.push(getWalletPolicy(fpr, xpub, purpose, coin, account));
|
|
153
|
+
}
|
|
119
154
|
}
|
|
120
155
|
return walletPolicies;
|
|
121
156
|
}
|
|
@@ -2,7 +2,7 @@ import bs58check from 'bs58check';
|
|
|
2
2
|
export function buildFauxXPUB(publicKey, chainCode) {
|
|
3
3
|
const LEN = 78;
|
|
4
4
|
const XPUB_PREFIX = 0x04_88_b2_1e;
|
|
5
|
-
const buffer = Buffer.
|
|
5
|
+
const buffer = Buffer.alloc(LEN);
|
|
6
6
|
const fingerprint = 0x00_00_00_00;
|
|
7
7
|
const depth = 0;
|
|
8
8
|
const index = 0;
|
package/lib/module/device.d.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import type { GetAddressParams, GetPublicKeyParams, GetXPubParams, HardwareWalletDevice, SignMessageParams, SignTransactionParams } from '@exodus/hw-common';
|
|
2
2
|
import type { TransportFactory } from './types';
|
|
3
|
+
import type { Atom } from '@exodus/atoms';
|
|
3
4
|
export type Descriptor = unknown;
|
|
4
5
|
export type Dependencies = {
|
|
5
6
|
transportFactory: TransportFactory;
|
|
6
7
|
descriptor: Descriptor;
|
|
8
|
+
walletPolicyAtom: Atom<Record<string, Buffer>>;
|
|
7
9
|
};
|
|
8
10
|
export declare class LedgerDevice implements HardwareWalletDevice {
|
|
9
11
|
#private;
|
|
10
|
-
constructor({ transportFactory, descriptor }: Dependencies);
|
|
12
|
+
constructor({ transportFactory, descriptor, walletPolicyAtom }: Dependencies);
|
|
11
13
|
ensureApplicationIsOpened: (baseAssetName: string) => Promise<void>;
|
|
12
14
|
listSupportedAssetNames: () => Promise<string[]>;
|
|
13
15
|
listInstalledAssetNames: () => Promise<string[]>;
|
package/lib/module/device.js
CHANGED
|
@@ -6,9 +6,11 @@ import { UnsupportedVersionError, ApplicationNotFoundError } from './errors';
|
|
|
6
6
|
export class LedgerDevice {
|
|
7
7
|
#transportFactory;
|
|
8
8
|
#descriptor;
|
|
9
|
-
|
|
9
|
+
#walletPolicyAtom;
|
|
10
|
+
constructor({ transportFactory, descriptor, walletPolicyAtom }) {
|
|
10
11
|
this.#transportFactory = transportFactory;
|
|
11
12
|
this.#descriptor = descriptor;
|
|
13
|
+
this.#walletPolicyAtom = walletPolicyAtom;
|
|
12
14
|
}
|
|
13
15
|
#runInSession = async (operation, expectErrorWhenClosing = false) => {
|
|
14
16
|
const transport = await this.#transportFactory.open(this.#descriptor);
|
|
@@ -119,7 +121,7 @@ export class LedgerDevice {
|
|
|
119
121
|
getAddress = async (params) => {
|
|
120
122
|
await this.ensureApplicationIsOpened(params.assetName);
|
|
121
123
|
return this.#runInSession(async (transport) => {
|
|
122
|
-
const handler = await this.#getAssetApplication(params.assetName).handler(transport);
|
|
124
|
+
const handler = await this.#getAssetApplication(params.assetName).handler(transport, this.#walletPolicyAtom);
|
|
123
125
|
return handler.getAddress(params);
|
|
124
126
|
});
|
|
125
127
|
};
|
|
@@ -140,7 +142,7 @@ export class LedgerDevice {
|
|
|
140
142
|
signTransaction = async (params) => {
|
|
141
143
|
await this.ensureApplicationIsOpened(params.assetName);
|
|
142
144
|
return this.#runInSession(async (transport) => {
|
|
143
|
-
const handler = await this.#getAssetApplication(params.assetName).handler(transport);
|
|
145
|
+
const handler = await this.#getAssetApplication(params.assetName).handler(transport, this.#walletPolicyAtom);
|
|
144
146
|
return handler.signTransaction(params);
|
|
145
147
|
});
|
|
146
148
|
};
|
|
@@ -1,26 +1,31 @@
|
|
|
1
|
-
import { Logger } from '../shared/types';
|
|
1
|
+
import type { Logger } from '../shared/types';
|
|
2
2
|
import type { Atom } from '@exodus/atoms';
|
|
3
3
|
import type { HardwareWalletDescriptor, HardwareWalletDiscovery } from '@exodus/hw-common';
|
|
4
4
|
import type { HwLedgerConfig, TransportFactories } from './types';
|
|
5
|
+
import type { BluetoothStatus } from '../atoms';
|
|
5
6
|
export type Dependencies = {
|
|
6
7
|
config: HwLedgerConfig;
|
|
7
8
|
logger: Logger;
|
|
8
9
|
transportsFactories: TransportFactories;
|
|
10
|
+
bluetoothStatusAtom: Atom<BluetoothStatus>;
|
|
9
11
|
bluetoothScanningAtom: Atom<boolean>;
|
|
12
|
+
walletPolicyAtom: Atom<Record<string, Buffer>>;
|
|
10
13
|
};
|
|
11
14
|
export declare class LedgerDiscovery implements HardwareWalletDiscovery {
|
|
12
15
|
#private;
|
|
13
|
-
constructor({ config, logger, transportsFactories, bluetoothScanningAtom }: Dependencies);
|
|
16
|
+
constructor({ config, logger, transportsFactories, bluetoothStatusAtom, bluetoothScanningAtom, walletPolicyAtom, }: Dependencies);
|
|
17
|
+
start: () => void;
|
|
14
18
|
scan: () => Promise<void>;
|
|
15
19
|
stopScan: (clearDevices?: boolean) => void;
|
|
16
20
|
list: () => Promise<HardwareWalletDescriptor[]>;
|
|
17
21
|
getFirstDevice: () => Promise<import("@exodus/hw-common").HardwareWalletDevice<import("@exodus/hw-common").Message>>;
|
|
22
|
+
stop: () => Promise<void>;
|
|
18
23
|
}
|
|
19
24
|
declare const _default: {
|
|
20
25
|
readonly id: "ledgerDiscovery";
|
|
21
26
|
readonly type: "module";
|
|
22
27
|
readonly factory: (deps: Dependencies) => LedgerDiscovery;
|
|
23
|
-
readonly dependencies: readonly ["config", "logger", "transportsFactories", "bluetoothScanningAtom"];
|
|
28
|
+
readonly dependencies: readonly ["config", "logger", "transportsFactories", "bluetoothStatusAtom", "bluetoothScanningAtom", "walletPolicyAtom"];
|
|
24
29
|
readonly public: true;
|
|
25
30
|
};
|
|
26
31
|
export default _default;
|
package/lib/module/discovery.js
CHANGED
|
@@ -7,12 +7,17 @@ export class LedgerDiscovery {
|
|
|
7
7
|
#logger;
|
|
8
8
|
#transportsFactories;
|
|
9
9
|
#scannerTimeout;
|
|
10
|
+
#statusBluetooth;
|
|
11
|
+
#bluetoothStatusAtom;
|
|
10
12
|
#scannerBluetooth;
|
|
11
13
|
#bluetoothScanningAtom;
|
|
14
|
+
#walletPolicyAtom;
|
|
12
15
|
#discoveredBluetoothDevices = Object.create(null);
|
|
13
|
-
constructor({ config, logger, transportsFactories, bluetoothScanningAtom }) {
|
|
16
|
+
constructor({ config, logger, transportsFactories, bluetoothStatusAtom, bluetoothScanningAtom, walletPolicyAtom, }) {
|
|
14
17
|
this.#logger = logger;
|
|
18
|
+
this.#bluetoothStatusAtom = bluetoothStatusAtom;
|
|
15
19
|
this.#bluetoothScanningAtom = bluetoothScanningAtom;
|
|
20
|
+
this.#walletPolicyAtom = walletPolicyAtom;
|
|
16
21
|
if (!(typeof transportsFactories === 'object' &&
|
|
17
22
|
Object.keys(transportsFactories).length > 0 &&
|
|
18
23
|
Object.entries(transportsFactories).every(([transportName, transportFactory]) => ['usb', 'bluetooth', 'tcp'].includes(transportName) &&
|
|
@@ -26,7 +31,26 @@ export class LedgerDiscovery {
|
|
|
26
31
|
this.#transportsFactories = transportsFactories;
|
|
27
32
|
this.#scannerTimeout = config.bluetoothScannerTimeout;
|
|
28
33
|
}
|
|
34
|
+
start = () => {
|
|
35
|
+
if (!this.#transportsFactories.bluetooth)
|
|
36
|
+
return;
|
|
37
|
+
if (this.#statusBluetooth)
|
|
38
|
+
return;
|
|
39
|
+
if (this.#transportsFactories.bluetooth.observeState) {
|
|
40
|
+
this.#statusBluetooth = this.#transportsFactories.bluetooth.observeState({
|
|
41
|
+
next: ({ type, available }) => this.#bluetoothStatusAtom.set({ type, available }),
|
|
42
|
+
error: (error) => this.#logger.error(error),
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
else if (this.#transportsFactories.bluetooth.observeAvailability) {
|
|
46
|
+
this.#statusBluetooth = this.#transportsFactories.bluetooth.observeAvailability({
|
|
47
|
+
next: (available) => this.#bluetoothStatusAtom.set({ type: 'Unknown', available }),
|
|
48
|
+
error: (error) => this.#logger.error(error),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
};
|
|
29
52
|
scan = async () => {
|
|
53
|
+
this.start();
|
|
30
54
|
return new Promise((resolve, reject) => {
|
|
31
55
|
if (this.#transportsFactories.bluetooth) {
|
|
32
56
|
this.stopScan(true);
|
|
@@ -79,7 +103,11 @@ export class LedgerDiscovery {
|
|
|
79
103
|
manufacturer: 'ledger',
|
|
80
104
|
transport: 'usb',
|
|
81
105
|
model: deviceModel?.id ?? 'unknown',
|
|
82
|
-
get: async () => new LedgerDevice({
|
|
106
|
+
get: async () => new LedgerDevice({
|
|
107
|
+
transportFactory,
|
|
108
|
+
descriptor: hidDevice,
|
|
109
|
+
walletPolicyAtom: this.#walletPolicyAtom,
|
|
110
|
+
}),
|
|
83
111
|
};
|
|
84
112
|
});
|
|
85
113
|
descriptors.push(...usbDeviceList);
|
|
@@ -93,7 +121,11 @@ export class LedgerDiscovery {
|
|
|
93
121
|
manufacturer: 'ledger',
|
|
94
122
|
transport: 'bluetooth',
|
|
95
123
|
model: deviceModel?.id ?? 'unknown',
|
|
96
|
-
get: async () => new LedgerDevice({
|
|
124
|
+
get: async () => new LedgerDevice({
|
|
125
|
+
transportFactory,
|
|
126
|
+
descriptor: bluetoothDevice,
|
|
127
|
+
walletPolicyAtom: this.#walletPolicyAtom,
|
|
128
|
+
}),
|
|
97
129
|
};
|
|
98
130
|
});
|
|
99
131
|
descriptors.push(...bluetoothDeviceList);
|
|
@@ -107,6 +139,7 @@ export class LedgerDiscovery {
|
|
|
107
139
|
get: async () => new LedgerDevice({
|
|
108
140
|
transportFactory,
|
|
109
141
|
descriptor: { apduPort: APDU_PORT },
|
|
142
|
+
walletPolicyAtom: this.#walletPolicyAtom,
|
|
110
143
|
}),
|
|
111
144
|
});
|
|
112
145
|
break;
|
|
@@ -123,12 +156,22 @@ export class LedgerDiscovery {
|
|
|
123
156
|
}
|
|
124
157
|
throw new NoDeviceFoundError();
|
|
125
158
|
};
|
|
159
|
+
stop = async () => {
|
|
160
|
+
this.#statusBluetooth?.unsubscribe();
|
|
161
|
+
};
|
|
126
162
|
}
|
|
127
163
|
const createLedgerDiscovery = (deps) => new LedgerDiscovery({ ...deps });
|
|
128
164
|
export default {
|
|
129
165
|
id: MODULE_ID,
|
|
130
166
|
type: 'module',
|
|
131
167
|
factory: createLedgerDiscovery,
|
|
132
|
-
dependencies: [
|
|
168
|
+
dependencies: [
|
|
169
|
+
'config',
|
|
170
|
+
'logger',
|
|
171
|
+
'transportsFactories',
|
|
172
|
+
'bluetoothStatusAtom',
|
|
173
|
+
'bluetoothScanningAtom',
|
|
174
|
+
'walletPolicyAtom',
|
|
175
|
+
],
|
|
133
176
|
public: true,
|
|
134
177
|
};
|
package/lib/plugin/index.d.ts
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
import type { Atom } from '@exodus/atoms';
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
4
|
-
import {
|
|
2
|
+
import type { Port } from '../shared/types';
|
|
3
|
+
import type { BluetoothStatus } from '../atoms';
|
|
4
|
+
import type { LedgerDiscovery } from '../module';
|
|
5
5
|
declare const hardwareWalletLedgerPluginDefinition: {
|
|
6
6
|
readonly id: "hardwareWalletLedgerPlugin";
|
|
7
7
|
readonly type: "plugin";
|
|
8
|
-
readonly factory: ({
|
|
9
|
-
logger: Logger;
|
|
10
|
-
transportsFactories: TransportFactories;
|
|
8
|
+
readonly factory: ({ bluetoothStatusAtom, bluetoothScanningAtom, ledgerDiscovery, port, }: {
|
|
11
9
|
bluetoothStatusAtom: Atom<BluetoothStatus>;
|
|
12
10
|
bluetoothScanningAtom: Atom<boolean>;
|
|
11
|
+
ledgerDiscovery: LedgerDiscovery;
|
|
13
12
|
port: Port;
|
|
14
13
|
}) => {
|
|
15
14
|
onUnlock: () => void;
|
|
16
15
|
onLoad: () => void;
|
|
17
16
|
onStop: () => void;
|
|
18
17
|
};
|
|
19
|
-
readonly dependencies: readonly ["
|
|
18
|
+
readonly dependencies: readonly ["bluetoothStatusAtom", "bluetoothScanningAtom", "ledgerDiscovery", "port"];
|
|
20
19
|
readonly public: true;
|
|
21
20
|
};
|
|
22
21
|
export default hardwareWalletLedgerPluginDefinition;
|
package/lib/plugin/index.js
CHANGED
|
@@ -1,33 +1,16 @@
|
|
|
1
1
|
import { createAtomObserver } from '@exodus/atoms';
|
|
2
|
-
const createHardwareWalletLedgerPlugin = ({
|
|
3
|
-
let subscription;
|
|
2
|
+
const createHardwareWalletLedgerPlugin = ({ bluetoothStatusAtom, bluetoothScanningAtom, ledgerDiscovery, port, }) => {
|
|
4
3
|
const observers = [
|
|
5
4
|
createAtomObserver({ atom: bluetoothStatusAtom, port, event: 'bluetoothStatus' }),
|
|
6
5
|
createAtomObserver({ atom: bluetoothScanningAtom, port, event: 'bluetoothScanning' }),
|
|
7
6
|
];
|
|
8
7
|
observers.forEach((observer) => observer.register());
|
|
9
8
|
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: ({ type, available }) => bluetoothStatusAtom.set({ type, available }),
|
|
17
|
-
error: (error) => logger.error(error),
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
else if (transportsFactories.bluetooth.observeAvailability) {
|
|
21
|
-
subscription = transportsFactories.bluetooth.observeAvailability({
|
|
22
|
-
next: (available) => bluetoothStatusAtom.set({ type: 'Unknown', available }),
|
|
23
|
-
error: (error) => logger.error(error),
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
9
|
observers.forEach((observer) => observer.start());
|
|
27
10
|
};
|
|
28
11
|
const stop = () => {
|
|
29
12
|
observers.forEach((observer) => observer.unregister());
|
|
30
|
-
|
|
13
|
+
ledgerDiscovery.stop();
|
|
31
14
|
};
|
|
32
15
|
const onUnlock = () => {
|
|
33
16
|
start();
|
|
@@ -44,13 +27,7 @@ const hardwareWalletLedgerPluginDefinition = {
|
|
|
44
27
|
id: 'hardwareWalletLedgerPlugin',
|
|
45
28
|
type: 'plugin',
|
|
46
29
|
factory: createHardwareWalletLedgerPlugin,
|
|
47
|
-
dependencies: [
|
|
48
|
-
'logger',
|
|
49
|
-
'transportsFactories',
|
|
50
|
-
'bluetoothStatusAtom',
|
|
51
|
-
'bluetoothScanningAtom',
|
|
52
|
-
'port',
|
|
53
|
-
],
|
|
30
|
+
dependencies: ['bluetoothStatusAtom', 'bluetoothScanningAtom', 'ledgerDiscovery', 'port'],
|
|
54
31
|
public: true,
|
|
55
32
|
};
|
|
56
33
|
export default hardwareWalletLedgerPluginDefinition;
|
package/lib/redux/index.d.ts
CHANGED
|
@@ -10,12 +10,12 @@ declare const exchangeReduxDefinition: {
|
|
|
10
10
|
};
|
|
11
11
|
readonly bluetoothScanning: (state: LedgerHardwareWalletState, payload: boolean) => {
|
|
12
12
|
bluetoothScanning: boolean;
|
|
13
|
-
bluetoothStatus: import("
|
|
13
|
+
bluetoothStatus: import("../atoms").BluetoothStatus;
|
|
14
14
|
};
|
|
15
15
|
};
|
|
16
16
|
readonly selectorDefinitions: ({
|
|
17
17
|
readonly id: "bluetoothStatus";
|
|
18
|
-
readonly resultFunction: (state: LedgerHardwareWalletState) => import("
|
|
18
|
+
readonly resultFunction: (state: LedgerHardwareWalletState) => import("../atoms").BluetoothStatus;
|
|
19
19
|
readonly dependencies: readonly [{
|
|
20
20
|
readonly selector: string;
|
|
21
21
|
}];
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
type: 'Unknown' | 'Resetting' | 'Unsupported' | 'Unauthorized' | 'PoweredOff' | 'PoweredOn';
|
|
3
|
-
available: boolean;
|
|
4
|
-
};
|
|
1
|
+
import type { BluetoothStatus } from '../atoms';
|
|
5
2
|
export type LedgerHardwareWalletState = {
|
|
6
3
|
bluetoothStatus: BluetoothStatus;
|
|
7
4
|
bluetoothScanning: boolean;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { LedgerHardwareWalletState } from '../initial-state';
|
|
2
2
|
declare const bluetoothStatusSelectorDefinition: {
|
|
3
3
|
readonly id: "bluetoothStatus";
|
|
4
|
-
readonly resultFunction: (state: LedgerHardwareWalletState) => import("
|
|
4
|
+
readonly resultFunction: (state: LedgerHardwareWalletState) => import("../../atoms").BluetoothStatus;
|
|
5
5
|
readonly dependencies: readonly [{
|
|
6
6
|
readonly selector: string;
|
|
7
7
|
}];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
declare const ledgerSelectors: ({
|
|
2
2
|
readonly id: "bluetoothStatus";
|
|
3
|
-
readonly resultFunction: (state: import("../initial-state").LedgerHardwareWalletState) => import("
|
|
3
|
+
readonly resultFunction: (state: import("../initial-state").LedgerHardwareWalletState) => import("../../atoms").BluetoothStatus;
|
|
4
4
|
readonly dependencies: readonly [{
|
|
5
5
|
readonly selector: string;
|
|
6
6
|
}];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/hw-ledger",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.10.0",
|
|
4
4
|
"description": "The ledger module",
|
|
5
5
|
"author": "Exodus Movement, Inc.",
|
|
6
6
|
"repository": {
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"test": "run -T jest --testMatch='**/*.unit.test.js' --coverageDirectory coverage/unit",
|
|
26
26
|
"zemu:install": "docker pull zondax/builder-zemu:speculos-745fe46f81cfc18114b94a37beaefb58a09c0fcd",
|
|
27
27
|
"test:integration": "yarn zemu:install && run -T jest --runInBand",
|
|
28
|
-
"lint": "run -T eslint .
|
|
28
|
+
"lint": "run -T eslint .",
|
|
29
29
|
"lint:fix": "yarn lint --fix",
|
|
30
30
|
"prepublishOnly": "yarn run -T build --scope @exodus/hw-ledger"
|
|
31
31
|
},
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"@exodus/bip322-js": "^1.1.0-exodus.4",
|
|
35
35
|
"@exodus/bitcoinjs-lib": "^6.1.5-exodus.0",
|
|
36
36
|
"@exodus/ethersproject-transactions": "^5.4.2-exodus.0",
|
|
37
|
-
"@exodus/hw-common": "^2.
|
|
37
|
+
"@exodus/hw-common": "^2.4.0",
|
|
38
38
|
"@exodus/ledger-bitcoin": "^0.2.3-exodus.3",
|
|
39
39
|
"@exodus/ledgerhq-devices": "^8.1.0-exodus.3",
|
|
40
40
|
"@exodus/ledgerhq-hw-app-eth": "^6.33.7-exodus.8",
|
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
"@types/jest-when": "^3.5.2",
|
|
62
62
|
"@types/minimalistic-assert": "^1.0.1",
|
|
63
63
|
"@types/secp256k1": "^4.0.3",
|
|
64
|
+
"@types/semver": "^7.3.5",
|
|
64
65
|
"@zondax/zemu": "^0.43.1",
|
|
65
66
|
"bitcoinjs-lib": "^6.1.3",
|
|
66
67
|
"concurrently": "^7.6.0",
|
|
@@ -71,5 +72,5 @@
|
|
|
71
72
|
"tiny-secp256k1": "^2.2.3",
|
|
72
73
|
"ts-jest": "^29.0.3"
|
|
73
74
|
},
|
|
74
|
-
"gitHead": "
|
|
75
|
+
"gitHead": "d035797666e173e9cec145ddce8e137fe84dfb83"
|
|
75
76
|
}
|