@exodus/hw-ledger 3.9.2 → 4.0.1
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 +37 -0
- package/README.md +1 -1
- package/lib/atoms/index.d.ts +3 -3
- package/lib/atoms/index.js +7 -10
- package/lib/index.d.ts +5 -5
- package/lib/index.js +9 -14
- package/lib/module/assets/applications.js +1 -3
- package/lib/module/assets/basemainnet.d.ts +1 -1
- package/lib/module/assets/basemainnet.js +5 -10
- package/lib/module/assets/bitcoin.d.ts +1 -1
- package/lib/module/assets/bitcoin.js +31 -36
- package/lib/module/assets/ethereum.d.ts +1 -1
- package/lib/module/assets/ethereum.js +31 -64
- package/lib/module/assets/index.d.ts +1 -1
- package/lib/module/assets/index.js +22 -28
- package/lib/module/assets/matic.d.ts +1 -1
- package/lib/module/assets/matic.js +5 -10
- package/lib/module/assets/ripple.d.ts +1 -1
- package/lib/module/assets/ripple.js +13 -17
- package/lib/module/assets/solana.d.ts +1 -1
- package/lib/module/assets/solana.js +16 -19
- package/lib/module/assets/tronmainnet.d.ts +1 -1
- package/lib/module/assets/tronmainnet.js +14 -50
- package/lib/module/assets/utils/bip322.js +7 -43
- package/lib/module/assets/utils/derivation-paths.js +17 -28
- package/lib/module/assets/utils/index.js +3 -19
- package/lib/module/assets/utils/psbt.d.ts +3 -3
- package/lib/module/assets/utils/psbt.js +34 -46
- package/lib/module/assets/utils/xpub.js +3 -6
- package/lib/module/constants.js +1 -4
- package/lib/module/device.d.ts +1 -1
- package/lib/module/device.js +21 -28
- package/lib/module/discovery.js +14 -18
- package/lib/module/errors.js +5 -12
- package/lib/module/index.js +2 -23
- package/lib/module/management/application.d.ts +2 -2
- package/lib/module/management/application.js +1 -4
- package/lib/module/types.d.ts +3 -2
- package/lib/module/types.js +1 -2
- package/lib/plugin/index.js +4 -6
- package/lib/redux/id.js +1 -3
- package/lib/redux/index.js +7 -12
- package/lib/redux/initial-state.js +1 -3
- package/lib/redux/selectors/bluetoothScanning.js +3 -5
- package/lib/redux/selectors/bluetoothStatus.js +3 -5
- package/lib/redux/selectors/index.js +4 -9
- package/package.json +23 -15
- package/redux.js +0 -1
|
@@ -1,18 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
exports.getMultisigWalletPolicy = exports.getWalletPolicy = void 0;
|
|
7
|
-
exports.assertPsbtOnlyHasAllowedDerivationPaths = assertPsbtOnlyHasAllowedDerivationPaths;
|
|
8
|
-
exports.tagPsbtWithDerivationPaths = tagPsbtWithDerivationPaths;
|
|
9
|
-
exports.derivationPathsToWalletPolicy = derivationPathsToWalletPolicy;
|
|
10
|
-
exports.addDummyInputs = addDummyInputs;
|
|
11
|
-
const minimalistic_assert_1 = __importDefault(require("minimalistic-assert"));
|
|
12
|
-
const ledger_bitcoin_1 = require("@exodus/ledger-bitcoin");
|
|
13
|
-
const bitcoinjs_1 = require("@exodus/bitcoinjs");
|
|
14
|
-
const derivation_paths_js_1 = require("./derivation-paths.js");
|
|
15
|
-
function assertPsbtOnlyHasAllowedDerivationPaths(psbt, masterFingerprint, derivationPaths) {
|
|
1
|
+
import assert from 'minimalistic-assert';
|
|
2
|
+
import { DefaultWalletPolicy, WalletPolicy } from '@exodus/ledger-bitcoin';
|
|
3
|
+
import { payments, address as baddress, Transaction } from '@exodus/bitcoinjs';
|
|
4
|
+
import { buildBip44PathFromNumber, assertBip44PathNumber, splitBip44PathToNumber, splitBip44DerivationPath, } from './derivation-paths.js';
|
|
5
|
+
export function assertPsbtOnlyHasAllowedDerivationPaths(psbt, masterFingerprint, derivationPaths) {
|
|
16
6
|
for (let i = 0; i < psbt.getGlobalInputCount(); i++) {
|
|
17
7
|
const BIP32_DERIVATION = 6;
|
|
18
8
|
const TAP_BIP32_DERIVATION = 22;
|
|
@@ -36,12 +26,12 @@ function assertAllowedDerivation(bip32Derivation, masterFingerprint, derivationP
|
|
|
36
26
|
const masterFingerprintToCheck = bip32Derivation.masterFingerprint.toString('hex');
|
|
37
27
|
const isOurMasterFingerprint = masterFingerprintToCheck === masterFingerprint;
|
|
38
28
|
if (isOurMasterFingerprint) {
|
|
39
|
-
|
|
40
|
-
const derivationPath =
|
|
41
|
-
(
|
|
29
|
+
assertBip44PathNumber(bip32Derivation.path);
|
|
30
|
+
const derivationPath = buildBip44PathFromNumber(bip32Derivation.path);
|
|
31
|
+
assert(derivationPaths.includes(derivationPath), `found unsupported derivation path: ${derivationPath}`);
|
|
42
32
|
}
|
|
43
33
|
}
|
|
44
|
-
function tagPsbtWithDerivationPaths(psbt, masterFingerprint, derivationPathToPublicKeyMap, addressToDerivationPathMap) {
|
|
34
|
+
export function tagPsbtWithDerivationPaths(psbt, masterFingerprint, derivationPathToPublicKeyMap, addressToDerivationPathMap) {
|
|
45
35
|
const masterFingerprintBuffer = Buffer.from(masterFingerprint, 'hex');
|
|
46
36
|
const scriptPubKeyToDerivationPathMap = computeScriptPubKeyToDerivationPathMap(derivationPathToPublicKeyMap);
|
|
47
37
|
const derivationPathsToSignFor = [];
|
|
@@ -54,7 +44,7 @@ function tagPsbtWithDerivationPaths(psbt, masterFingerprint, derivationPathToPub
|
|
|
54
44
|
}
|
|
55
45
|
else if (nonWitnessUtxo) {
|
|
56
46
|
const prevOutputIndex = psbt.getInputOutputIndex(inputIndex);
|
|
57
|
-
const decodedTransaction =
|
|
47
|
+
const decodedTransaction = Transaction.fromBuffer(nonWitnessUtxo);
|
|
58
48
|
scriptPubKey = decodedTransaction.outs[prevOutputIndex].script;
|
|
59
49
|
}
|
|
60
50
|
else {
|
|
@@ -63,15 +53,15 @@ function tagPsbtWithDerivationPaths(psbt, masterFingerprint, derivationPathToPub
|
|
|
63
53
|
let derivationPath = scriptPubKeyToDerivationPathMap[scriptPubKey.toString('hex')];
|
|
64
54
|
if (addressToDerivationPathMap && !derivationPath) {
|
|
65
55
|
try {
|
|
66
|
-
const address =
|
|
56
|
+
const address = baddress.fromOutputScript(scriptPubKey);
|
|
67
57
|
derivationPath = addressToDerivationPathMap[address];
|
|
68
58
|
}
|
|
69
59
|
catch { }
|
|
70
60
|
}
|
|
71
61
|
if (derivationPath) {
|
|
72
62
|
const publicKey = derivationPathToPublicKeyMap[derivationPath];
|
|
73
|
-
(
|
|
74
|
-
const derivationPathNumerical =
|
|
63
|
+
assert(Buffer.isBuffer(publicKey), `no public key found for derivation path`);
|
|
64
|
+
const derivationPathNumerical = splitBip44PathToNumber(derivationPath);
|
|
75
65
|
if (isTaproot(scriptPubKey)) {
|
|
76
66
|
psbt.setInputTapBip32Derivation(inputIndex, publicKey.slice(1), [], masterFingerprintBuffer, derivationPathNumerical);
|
|
77
67
|
}
|
|
@@ -86,15 +76,15 @@ function tagPsbtWithDerivationPaths(psbt, masterFingerprint, derivationPathToPub
|
|
|
86
76
|
let derivationPath = scriptPubKeyToDerivationPathMap[scriptPubKey.toString('hex')];
|
|
87
77
|
if (addressToDerivationPathMap && !derivationPath) {
|
|
88
78
|
try {
|
|
89
|
-
const address =
|
|
79
|
+
const address = baddress.fromOutputScript(scriptPubKey);
|
|
90
80
|
derivationPath = addressToDerivationPathMap[address];
|
|
91
81
|
}
|
|
92
82
|
catch { }
|
|
93
83
|
}
|
|
94
84
|
if (derivationPath) {
|
|
95
85
|
const publicKey = derivationPathToPublicKeyMap[derivationPath];
|
|
96
|
-
(
|
|
97
|
-
const derivationPathNumerical =
|
|
86
|
+
assert(Buffer.isBuffer(publicKey), `no public key found for derivation path`);
|
|
87
|
+
const derivationPathNumerical = splitBip44PathToNumber(derivationPath);
|
|
98
88
|
if (isTaproot(scriptPubKey)) {
|
|
99
89
|
psbt.setOutputTapBip32Derivation(outputIndex, publicKey.slice(1), [], masterFingerprintBuffer, derivationPathNumerical);
|
|
100
90
|
}
|
|
@@ -108,37 +98,37 @@ function tagPsbtWithDerivationPaths(psbt, masterFingerprint, derivationPathToPub
|
|
|
108
98
|
function computeScriptPubKeyToDerivationPathMap(derivationPathToPublicKeyMap) {
|
|
109
99
|
return Object.entries(derivationPathToPublicKeyMap).reduce((acc, [derivationPath, publicKey]) => {
|
|
110
100
|
if (derivationPath.startsWith('m/44')) {
|
|
111
|
-
const p2pkh =
|
|
101
|
+
const p2pkh = payments.p2pkh({
|
|
112
102
|
pubkey: publicKey,
|
|
113
103
|
}).output;
|
|
114
|
-
(
|
|
104
|
+
assert(p2pkh, 'failed to compute p2pkh scriptPubKey');
|
|
115
105
|
Object.assign(acc, {
|
|
116
106
|
[p2pkh.toString('hex')]: derivationPath,
|
|
117
107
|
});
|
|
118
108
|
}
|
|
119
109
|
else if (derivationPath.startsWith('m/49')) {
|
|
120
|
-
const nestedSegwit =
|
|
121
|
-
redeem:
|
|
110
|
+
const nestedSegwit = payments.p2sh({
|
|
111
|
+
redeem: payments.p2wpkh({ pubkey: publicKey }),
|
|
122
112
|
}).output;
|
|
123
|
-
(
|
|
113
|
+
assert(nestedSegwit, 'failed to compute p2sh scriptPubKey');
|
|
124
114
|
Object.assign(acc, {
|
|
125
115
|
[nestedSegwit.toString('hex')]: derivationPath,
|
|
126
116
|
});
|
|
127
117
|
}
|
|
128
118
|
else if (derivationPath.startsWith('m/84')) {
|
|
129
|
-
const p2wpkh =
|
|
119
|
+
const p2wpkh = payments.p2wpkh({
|
|
130
120
|
pubkey: publicKey,
|
|
131
121
|
}).output;
|
|
132
|
-
(
|
|
122
|
+
assert(p2wpkh, 'failed to compute p2wpkh scriptPubKey');
|
|
133
123
|
Object.assign(acc, {
|
|
134
124
|
[p2wpkh.toString('hex')]: derivationPath,
|
|
135
125
|
});
|
|
136
126
|
}
|
|
137
127
|
else if (derivationPath.startsWith('m/86')) {
|
|
138
|
-
const p2tr =
|
|
128
|
+
const p2tr = payments.p2tr({
|
|
139
129
|
internalPubkey: publicKey.slice(1),
|
|
140
130
|
}).output;
|
|
141
|
-
(
|
|
131
|
+
assert(p2tr, 'failed to compute p2tr scriptPubKey');
|
|
142
132
|
Object.assign(acc, {
|
|
143
133
|
[p2tr.toString('hex')]: derivationPath,
|
|
144
134
|
});
|
|
@@ -149,17 +139,16 @@ function computeScriptPubKeyToDerivationPathMap(derivationPathToPublicKeyMap) {
|
|
|
149
139
|
function isTaproot(scriptPubKey) {
|
|
150
140
|
return scriptPubKey.length === 34 && scriptPubKey.at(0) === 0x51 && scriptPubKey.at(1) === 0x20;
|
|
151
141
|
}
|
|
152
|
-
const getWalletPolicy = (fpr, xpub, purpose, coin, account) => {
|
|
142
|
+
export const getWalletPolicy = (fpr, xpub, purpose, coin, account) => {
|
|
153
143
|
const desc = {
|
|
154
144
|
"44'": 'pkh(@0/**)',
|
|
155
145
|
"49'": 'sh(wpkh(@0/**))',
|
|
156
146
|
"84'": 'wpkh(@0/**)',
|
|
157
147
|
"86'": 'tr(@0/**)',
|
|
158
148
|
}[purpose];
|
|
159
|
-
return new
|
|
149
|
+
return new DefaultWalletPolicy(desc, `[${fpr}/${purpose}/${coin}/${account}]${xpub}`);
|
|
160
150
|
};
|
|
161
|
-
|
|
162
|
-
const getMultisigWalletPolicy = (fpr, xpub, purpose, coin, account, multisigData) => {
|
|
151
|
+
export const getMultisigWalletPolicy = (fpr, xpub, purpose, coin, account, multisigData) => {
|
|
163
152
|
let template = `tr(@0/**,sortedmulti_a(${multisigData.threshold}`;
|
|
164
153
|
const keys = [multisigData.internalXpub];
|
|
165
154
|
multisigData.xpubs.forEach((xpub2, i) => {
|
|
@@ -172,11 +161,10 @@ const getMultisigWalletPolicy = (fpr, xpub, purpose, coin, account, multisigData
|
|
|
172
161
|
template += `,@${i + 1}/**`;
|
|
173
162
|
});
|
|
174
163
|
template += '))';
|
|
175
|
-
return new
|
|
164
|
+
return new WalletPolicy('Multisig', template, keys);
|
|
176
165
|
};
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
const splittedDerivationPaths = derivationPaths.map(derivation_paths_js_1.splitBip44DerivationPath);
|
|
166
|
+
export async function derivationPathsToWalletPolicy(fpr, app, derivationPaths, multisigData) {
|
|
167
|
+
const splittedDerivationPaths = derivationPaths.map(splitBip44DerivationPath);
|
|
180
168
|
const dedupedPaths = Object.values(splittedDerivationPaths.reduce((prev, splittedDerivationPath) => {
|
|
181
169
|
const [purpose, coin, account] = splittedDerivationPath;
|
|
182
170
|
prev[[purpose, coin, account].toString()] = [purpose, coin, account];
|
|
@@ -187,10 +175,10 @@ async function derivationPathsToWalletPolicy(fpr, app, derivationPaths, multisig
|
|
|
187
175
|
const [purpose, coin, account] = dedupedPath;
|
|
188
176
|
const xpub = await app.getExtendedPubkey(`m/${purpose}/${coin}/${account}`);
|
|
189
177
|
if (multisigData) {
|
|
190
|
-
walletPolicies.push(
|
|
178
|
+
walletPolicies.push(getMultisigWalletPolicy(fpr, xpub, purpose, coin, account, multisigData));
|
|
191
179
|
}
|
|
192
180
|
else {
|
|
193
|
-
walletPolicies.push(
|
|
181
|
+
walletPolicies.push(getWalletPolicy(fpr, xpub, purpose, coin, account));
|
|
194
182
|
}
|
|
195
183
|
}
|
|
196
184
|
return walletPolicies;
|
|
@@ -206,7 +194,7 @@ function canModifyInputs(psbt) {
|
|
|
206
194
|
}
|
|
207
195
|
return true;
|
|
208
196
|
}
|
|
209
|
-
function addDummyInputs(psbt) {
|
|
197
|
+
export function addDummyInputs(psbt) {
|
|
210
198
|
const canAddDummy = canModifyInputs(psbt);
|
|
211
199
|
if (!canAddDummy) {
|
|
212
200
|
return;
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.buildFauxXPUB = buildFauxXPUB;
|
|
4
|
-
const base58check_js_1 = require("@exodus/bytes/base58check.js");
|
|
5
|
-
function buildFauxXPUB(publicKey, chainCode) {
|
|
1
|
+
import { toBase58checkSync } from '@exodus/bytes/base58check.js';
|
|
2
|
+
export function buildFauxXPUB(publicKey, chainCode) {
|
|
6
3
|
const LEN = 78;
|
|
7
4
|
const XPUB_PREFIX = 0x04_88_b2_1e;
|
|
8
5
|
const buffer = Buffer.alloc(LEN);
|
|
@@ -15,5 +12,5 @@ function buildFauxXPUB(publicKey, chainCode) {
|
|
|
15
12
|
buffer.writeUInt32BE(index, 9);
|
|
16
13
|
chainCode.copy(buffer, 13);
|
|
17
14
|
publicKey.copy(buffer, 45);
|
|
18
|
-
return
|
|
15
|
+
return toBase58checkSync(buffer);
|
|
19
16
|
}
|
package/lib/module/constants.js
CHANGED
package/lib/module/device.d.ts
CHANGED
|
@@ -19,6 +19,6 @@ export declare class LedgerDevice implements HardwareWalletDevice {
|
|
|
19
19
|
getAddress: (params: GetAddressParams) => Promise<string>;
|
|
20
20
|
getXPub: (params: GetXPubParams) => Promise<string>;
|
|
21
21
|
getPublicKey: (params: GetPublicKeyParams) => Promise<Readonly<Uint8Array<ArrayBufferLike>>>;
|
|
22
|
-
signTransaction: (params: SignTransactionParams) => Promise<import("@exodus/hw-common"
|
|
22
|
+
signTransaction: (params: SignTransactionParams) => Promise<import("@exodus/hw-common").Signatures>;
|
|
23
23
|
signMessage: (params: SignMessageParams) => Promise<Readonly<Uint8Array<ArrayBufferLike>>>;
|
|
24
24
|
}
|
package/lib/module/device.js
CHANGED
|
@@ -1,15 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const semver_1 = __importDefault(require("semver"));
|
|
8
|
-
const hw_common_1 = require("@exodus/hw-common");
|
|
9
|
-
const index_js_1 = require("./assets/index.js");
|
|
10
|
-
const application_js_1 = require("./management/application.js");
|
|
11
|
-
const errors_js_1 = require("./errors.js");
|
|
12
|
-
class LedgerDevice {
|
|
1
|
+
import semver from 'semver';
|
|
2
|
+
import { AssetUnsupportedError, DeviceLockedError, DeviceConnectionError, UserRefusedError, } from '@exodus/hw-common';
|
|
3
|
+
import { applicationNameToBaseAssetNames, assetApplications, supportedBaseAssetNames, } from './assets/index.js';
|
|
4
|
+
import { createApplicationManager as applicationFactory } from './management/application.js';
|
|
5
|
+
import { UnsupportedVersionError, ApplicationNotFoundError } from './errors.js';
|
|
6
|
+
export class LedgerDevice {
|
|
13
7
|
#transportFactory;
|
|
14
8
|
#descriptor;
|
|
15
9
|
#walletPolicyAtom;
|
|
@@ -44,32 +38,32 @@ class LedgerDevice {
|
|
|
44
38
|
}
|
|
45
39
|
};
|
|
46
40
|
#getAssetApplication = (assetName) => {
|
|
47
|
-
const handlerFactory =
|
|
41
|
+
const handlerFactory = assetApplications[assetName];
|
|
48
42
|
if (!handlerFactory)
|
|
49
|
-
throw new
|
|
43
|
+
throw new AssetUnsupportedError(assetName);
|
|
50
44
|
return handlerFactory;
|
|
51
45
|
};
|
|
52
46
|
#listApplications = async () => {
|
|
53
47
|
return this.#runInSession(async (transport) => {
|
|
54
|
-
const handler = await (
|
|
48
|
+
const handler = await applicationFactory(transport);
|
|
55
49
|
return handler.listApplications();
|
|
56
50
|
});
|
|
57
51
|
};
|
|
58
52
|
#getInformation = async () => {
|
|
59
53
|
return this.#runInSession(async (transport) => {
|
|
60
|
-
const handler = await (
|
|
54
|
+
const handler = await applicationFactory(transport);
|
|
61
55
|
return handler.getInformation();
|
|
62
56
|
});
|
|
63
57
|
};
|
|
64
58
|
#openApplication = async (applicationName) => {
|
|
65
59
|
return this.#runInSession(async (transport) => {
|
|
66
|
-
const handler = await (
|
|
60
|
+
const handler = await applicationFactory(transport);
|
|
67
61
|
return handler.openApplication(applicationName);
|
|
68
62
|
}, true);
|
|
69
63
|
};
|
|
70
64
|
#quitApplication = async () => {
|
|
71
65
|
return this.#runInSession(async (transport) => {
|
|
72
|
-
const handler = await (
|
|
66
|
+
const handler = await applicationFactory(transport);
|
|
73
67
|
return handler.quitApplication();
|
|
74
68
|
});
|
|
75
69
|
};
|
|
@@ -104,14 +98,14 @@ class LedgerDevice {
|
|
|
104
98
|
}
|
|
105
99
|
}
|
|
106
100
|
if (!applicationName) {
|
|
107
|
-
throw new
|
|
101
|
+
throw new ApplicationNotFoundError(supportedApplicationNames);
|
|
108
102
|
}
|
|
109
103
|
desiredApplicationInfo = await this.#getInformation();
|
|
110
104
|
}
|
|
111
105
|
const { supportedVersions } = applications.find(({ applicationName }) => applicationName === desiredApplicationInfo.name);
|
|
112
|
-
const isSupportedVersion =
|
|
106
|
+
const isSupportedVersion = semver.satisfies(desiredApplicationInfo.version, supportedVersions);
|
|
113
107
|
if (!isSupportedVersion) {
|
|
114
|
-
throw new
|
|
108
|
+
throw new UnsupportedVersionError(baseAssetName, desiredApplicationInfo.name, desiredApplicationInfo.version, supportedVersions);
|
|
115
109
|
}
|
|
116
110
|
};
|
|
117
111
|
ensureApplicationIsOpened = async (baseAssetName) => {
|
|
@@ -121,7 +115,7 @@ class LedgerDevice {
|
|
|
121
115
|
await this.#ensureApplicationIsOpened(baseAssetName);
|
|
122
116
|
};
|
|
123
117
|
listSupportedAssetNames = async () => {
|
|
124
|
-
return
|
|
118
|
+
return supportedBaseAssetNames;
|
|
125
119
|
};
|
|
126
120
|
listInstalledAssetNames = async () => {
|
|
127
121
|
const { name: applicationName } = await this.#getInformation();
|
|
@@ -130,7 +124,7 @@ class LedgerDevice {
|
|
|
130
124
|
const installedApplications = await this.#listApplications();
|
|
131
125
|
const installedAssets = [];
|
|
132
126
|
installedApplications.forEach(({ name: applicationName }) => {
|
|
133
|
-
const assetNames =
|
|
127
|
+
const assetNames = applicationNameToBaseAssetNames[applicationName];
|
|
134
128
|
if (assetNames)
|
|
135
129
|
installedAssets.push(...assetNames);
|
|
136
130
|
});
|
|
@@ -138,7 +132,7 @@ class LedgerDevice {
|
|
|
138
132
|
};
|
|
139
133
|
listUseableAssetNames = async () => {
|
|
140
134
|
const { name: applicationName } = await this.#getInformation();
|
|
141
|
-
const assetNames =
|
|
135
|
+
const assetNames = applicationNameToBaseAssetNames[applicationName];
|
|
142
136
|
return assetNames || [];
|
|
143
137
|
};
|
|
144
138
|
getAddress = async (params) => {
|
|
@@ -177,14 +171,13 @@ class LedgerDevice {
|
|
|
177
171
|
});
|
|
178
172
|
};
|
|
179
173
|
}
|
|
180
|
-
exports.LedgerDevice = LedgerDevice;
|
|
181
174
|
function transformToCommonError(_err) {
|
|
182
175
|
const err = _err;
|
|
183
176
|
if (err.name === 'LockedDeviceError') {
|
|
184
|
-
return new
|
|
177
|
+
return new DeviceLockedError();
|
|
185
178
|
}
|
|
186
179
|
if (err.name === 'UserRefusedOnDevice' || err.statusCode === 0x69_85) {
|
|
187
|
-
return new
|
|
180
|
+
return new UserRefusedError(true);
|
|
188
181
|
}
|
|
189
182
|
if ([
|
|
190
183
|
'HwTransportError',
|
|
@@ -194,7 +187,7 @@ function transformToCommonError(_err) {
|
|
|
194
187
|
'DisconnectedDevice',
|
|
195
188
|
'DisconnectedDeviceDuringOperation',
|
|
196
189
|
].includes(err.name)) {
|
|
197
|
-
return new
|
|
190
|
+
return new DeviceConnectionError(err);
|
|
198
191
|
}
|
|
199
192
|
return err;
|
|
200
193
|
}
|
package/lib/module/discovery.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const constants_js_1 = require("./constants.js");
|
|
6
|
-
const device_js_1 = require("./device.js");
|
|
7
|
-
const errors_js_1 = require("./errors.js");
|
|
1
|
+
import { getInfosForServiceUuid, identifyUSBProductId } from '@exodus/ledgerhq-devices';
|
|
2
|
+
import { APDU_PORT } from './constants.js';
|
|
3
|
+
import { LedgerDevice } from './device.js';
|
|
4
|
+
import { UnknownTransportError } from './errors.js';
|
|
8
5
|
const MODULE_ID = 'ledgerDiscovery';
|
|
9
|
-
class LedgerDiscovery {
|
|
6
|
+
export class LedgerDiscovery {
|
|
10
7
|
#logger;
|
|
11
8
|
#transportsFactories;
|
|
12
9
|
#scannerTimeout;
|
|
@@ -27,7 +24,7 @@ class LedgerDiscovery {
|
|
|
27
24
|
transportFactory !== undefined &&
|
|
28
25
|
typeof transportFactory.list === 'function' &&
|
|
29
26
|
typeof transportFactory.open === 'function'))) {
|
|
30
|
-
throw new
|
|
27
|
+
throw new UnknownTransportError();
|
|
31
28
|
}
|
|
32
29
|
if (!Number.isInteger(config.bluetoothScannerTimeout)) {
|
|
33
30
|
throw new TypeError(`Invalid bluetoothScannerTimeout passed through config`);
|
|
@@ -101,14 +98,14 @@ class LedgerDiscovery {
|
|
|
101
98
|
case 'usb':
|
|
102
99
|
const deviceList = (await transportFactory.list());
|
|
103
100
|
const usbDeviceList = deviceList.map((hidDevice) => {
|
|
104
|
-
const deviceModel =
|
|
101
|
+
const deviceModel = identifyUSBProductId(hidDevice.productId);
|
|
105
102
|
const descriptor = {
|
|
106
103
|
name: deviceModel?.productName ?? 'Ledger USB',
|
|
107
104
|
manufacturer: 'ledger',
|
|
108
105
|
transport: 'usb',
|
|
109
106
|
model: deviceModel?.id ?? 'unknown',
|
|
110
107
|
internalDescriptor: hidDevice,
|
|
111
|
-
get: async () => new
|
|
108
|
+
get: async () => new LedgerDevice({
|
|
112
109
|
transportFactory,
|
|
113
110
|
descriptor,
|
|
114
111
|
walletPolicyAtom: this.#walletPolicyAtom,
|
|
@@ -120,14 +117,14 @@ class LedgerDiscovery {
|
|
|
120
117
|
break;
|
|
121
118
|
case 'bluetooth':
|
|
122
119
|
const bluetoothDeviceList = Object.values(this.#discoveredBluetoothDevices).map((bluetoothDevice) => {
|
|
123
|
-
const deviceModel =
|
|
120
|
+
const deviceModel = getInfosForServiceUuid(bluetoothDevice.serviceUUIDs?.[0] ?? '')?.deviceModel;
|
|
124
121
|
const descriptor = {
|
|
125
122
|
name: bluetoothDevice.localName ?? deviceModel?.productName,
|
|
126
123
|
manufacturer: 'ledger',
|
|
127
124
|
transport: 'bluetooth',
|
|
128
125
|
model: deviceModel?.id ?? 'unknown',
|
|
129
126
|
internalDescriptor: bluetoothDevice,
|
|
130
|
-
get: async () => new
|
|
127
|
+
get: async () => new LedgerDevice({
|
|
131
128
|
transportFactory,
|
|
132
129
|
descriptor,
|
|
133
130
|
walletPolicyAtom: this.#walletPolicyAtom,
|
|
@@ -143,8 +140,8 @@ class LedgerDiscovery {
|
|
|
143
140
|
manufacturer: 'ledger',
|
|
144
141
|
transport: 'tcp',
|
|
145
142
|
model: 'unknown',
|
|
146
|
-
internalDescriptor: { apduPort:
|
|
147
|
-
get: async () => new
|
|
143
|
+
internalDescriptor: { apduPort: APDU_PORT },
|
|
144
|
+
get: async () => new LedgerDevice({
|
|
148
145
|
transportFactory,
|
|
149
146
|
descriptor,
|
|
150
147
|
walletPolicyAtom: this.#walletPolicyAtom,
|
|
@@ -153,7 +150,7 @@ class LedgerDiscovery {
|
|
|
153
150
|
descriptors.push(descriptor);
|
|
154
151
|
break;
|
|
155
152
|
default:
|
|
156
|
-
throw new
|
|
153
|
+
throw new UnknownTransportError(transportName);
|
|
157
154
|
}
|
|
158
155
|
}
|
|
159
156
|
return descriptors;
|
|
@@ -162,9 +159,8 @@ class LedgerDiscovery {
|
|
|
162
159
|
this.#statusBluetooth?.unsubscribe();
|
|
163
160
|
};
|
|
164
161
|
}
|
|
165
|
-
exports.LedgerDiscovery = LedgerDiscovery;
|
|
166
162
|
const createLedgerDiscovery = (deps) => new LedgerDiscovery({ ...deps });
|
|
167
|
-
|
|
163
|
+
export default {
|
|
168
164
|
id: MODULE_ID,
|
|
169
165
|
type: 'module',
|
|
170
166
|
factory: createLedgerDiscovery,
|
package/lib/module/errors.js
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.RequiresBlindSigningError = exports.UnsupportedVersionError = exports.ApplicationNotFoundError = exports.UnknownTransportError = void 0;
|
|
4
|
-
const hw_common_1 = require("@exodus/hw-common");
|
|
5
|
-
class UnknownTransportError extends hw_common_1.HardwareWalletError {
|
|
1
|
+
import { HardwareWalletError } from '@exodus/hw-common';
|
|
2
|
+
export class UnknownTransportError extends HardwareWalletError {
|
|
6
3
|
name = 'UnknownTransportError';
|
|
7
4
|
constructor(transportName) {
|
|
8
5
|
super(`unknown transport type ${transportName || ''}`);
|
|
9
6
|
}
|
|
10
7
|
}
|
|
11
|
-
|
|
12
|
-
class ApplicationNotFoundError extends hw_common_1.HardwareWalletError {
|
|
8
|
+
export class ApplicationNotFoundError extends HardwareWalletError {
|
|
13
9
|
name = 'ApplicationNotFoundError';
|
|
14
10
|
supportedApplications;
|
|
15
11
|
constructor(supportedApplications) {
|
|
@@ -17,8 +13,7 @@ class ApplicationNotFoundError extends hw_common_1.HardwareWalletError {
|
|
|
17
13
|
this.supportedApplications = supportedApplications;
|
|
18
14
|
}
|
|
19
15
|
}
|
|
20
|
-
|
|
21
|
-
class UnsupportedVersionError extends hw_common_1.HardwareWalletError {
|
|
16
|
+
export class UnsupportedVersionError extends HardwareWalletError {
|
|
22
17
|
name = 'UnsupportedVersionError';
|
|
23
18
|
baseAssetName;
|
|
24
19
|
applicationName;
|
|
@@ -32,11 +27,9 @@ class UnsupportedVersionError extends hw_common_1.HardwareWalletError {
|
|
|
32
27
|
this.actualVersion = actualVersion;
|
|
33
28
|
}
|
|
34
29
|
}
|
|
35
|
-
|
|
36
|
-
class RequiresBlindSigningError extends hw_common_1.HardwareWalletError {
|
|
30
|
+
export class RequiresBlindSigningError extends HardwareWalletError {
|
|
37
31
|
name = 'RequiresBlindSigningError';
|
|
38
32
|
constructor() {
|
|
39
33
|
super('signing operation requires that blind signing is enabled on the device');
|
|
40
34
|
}
|
|
41
35
|
}
|
|
42
|
-
exports.RequiresBlindSigningError = RequiresBlindSigningError;
|
package/lib/module/index.js
CHANGED
|
@@ -1,23 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
17
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
|
-
};
|
|
19
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
-
exports.default = void 0;
|
|
21
|
-
__exportStar(require("./discovery.js"), exports);
|
|
22
|
-
var discovery_js_1 = require("./discovery.js");
|
|
23
|
-
Object.defineProperty(exports, "default", { enumerable: true, get: function () { return __importDefault(discovery_js_1).default; } });
|
|
1
|
+
export * from './discovery.js';
|
|
2
|
+
export { default } from './discovery.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type Transport from '
|
|
1
|
+
import type { Transport } from '../types.js';
|
|
2
2
|
export type GetInformationResponse = {
|
|
3
3
|
name: string;
|
|
4
4
|
version: string;
|
|
@@ -11,7 +11,7 @@ export type ListAppResponse = {
|
|
|
11
11
|
blocks?: number;
|
|
12
12
|
flags?: number;
|
|
13
13
|
}[];
|
|
14
|
-
export declare function createApplicationManager(transport: Transport): Promise<{
|
|
14
|
+
export declare function createApplicationManager(transport: Pick<Transport, 'send'>): Promise<{
|
|
15
15
|
getInformation: () => Promise<GetInformationResponse>;
|
|
16
16
|
listApplications: () => Promise<ListAppResponse>;
|
|
17
17
|
openApplication: (name: string) => Promise<void>;
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createApplicationManager = createApplicationManager;
|
|
4
|
-
async function createApplicationManager(transport) {
|
|
1
|
+
export async function createApplicationManager(transport) {
|
|
5
2
|
return {
|
|
6
3
|
getInformation: async () => {
|
|
7
4
|
const r = await transport.send(0xb0, 0x01, 0x00, 0x00);
|
package/lib/module/types.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type LedgerTransport from '@ledgerhq/hw-transport';
|
|
2
2
|
import type { TransportTypes } from '@exodus/hw-common';
|
|
3
3
|
import type { Subscription } from '@ledgerhq/hw-transport';
|
|
4
|
-
export type TransportFactory = typeof
|
|
4
|
+
export type TransportFactory = (typeof LedgerTransport)['default'];
|
|
5
|
+
export type Transport = InstanceType<TransportFactory>;
|
|
5
6
|
export type TransportFactories = Partial<Record<TransportTypes, TransportFactory>> & {
|
|
6
7
|
bluetooth?: TransportFactory & {
|
|
7
8
|
observeAvailability?: (observer: {
|
package/lib/module/types.js
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1
|
+
export {};
|
package/lib/plugin/index.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const atoms_1 = require("@exodus/atoms");
|
|
1
|
+
import { createAtomObserver } from '@exodus/atoms';
|
|
4
2
|
const createHardwareWalletLedgerPlugin = ({ bluetoothStatusAtom, bluetoothScanningAtom, ledgerDiscovery, port, }) => {
|
|
5
3
|
const observers = [
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
createAtomObserver({ atom: bluetoothStatusAtom, port, event: 'bluetoothStatus' }),
|
|
5
|
+
createAtomObserver({ atom: bluetoothScanningAtom, port, event: 'bluetoothScanning' }),
|
|
8
6
|
];
|
|
9
7
|
observers.forEach((observer) => observer.register());
|
|
10
8
|
const start = () => {
|
|
@@ -32,4 +30,4 @@ const hardwareWalletLedgerPluginDefinition = {
|
|
|
32
30
|
dependencies: ['bluetoothStatusAtom', 'bluetoothScanningAtom', 'ledgerDiscovery', 'port'],
|
|
33
31
|
public: true,
|
|
34
32
|
};
|
|
35
|
-
|
|
33
|
+
export default hardwareWalletLedgerPluginDefinition;
|
package/lib/redux/id.js
CHANGED
package/lib/redux/index.js
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const id_js_1 = __importDefault(require("./id.js"));
|
|
7
|
-
const initial_state_js_1 = __importDefault(require("./initial-state.js"));
|
|
8
|
-
const index_js_1 = __importDefault(require("./selectors/index.js"));
|
|
1
|
+
import id from './id.js';
|
|
2
|
+
import initialState, {} from './initial-state.js';
|
|
3
|
+
import selectorDefinitions from './selectors/index.js';
|
|
9
4
|
const exchangeReduxDefinition = {
|
|
10
|
-
id
|
|
5
|
+
id,
|
|
11
6
|
type: 'redux-module',
|
|
12
|
-
initialState
|
|
7
|
+
initialState,
|
|
13
8
|
eventReducers: {
|
|
14
9
|
bluetoothStatus: (state, payload) => ({
|
|
15
10
|
...state,
|
|
@@ -20,6 +15,6 @@ const exchangeReduxDefinition = {
|
|
|
20
15
|
bluetoothScanning: payload,
|
|
21
16
|
}),
|
|
22
17
|
},
|
|
23
|
-
selectorDefinitions
|
|
18
|
+
selectorDefinitions,
|
|
24
19
|
};
|
|
25
|
-
|
|
20
|
+
export default exchangeReduxDefinition;
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const redux_dependency_injection_1 = require("@exodus/redux-dependency-injection");
|
|
1
|
+
import { MY_STATE } from '@exodus/redux-dependency-injection';
|
|
4
2
|
const resultFunction = (state) => state.bluetoothScanning;
|
|
5
3
|
const bluetoothScanningSelectorDefinition = {
|
|
6
4
|
id: 'bluetoothScanning',
|
|
7
5
|
resultFunction,
|
|
8
|
-
dependencies: [{ selector:
|
|
6
|
+
dependencies: [{ selector: MY_STATE }],
|
|
9
7
|
};
|
|
10
|
-
|
|
8
|
+
export default bluetoothScanningSelectorDefinition;
|