@exodus/hw-ledger 2.1.0 → 2.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 +13 -0
- package/lib/module/assets/bitcoin.d.ts +4 -2
- package/lib/module/assets/bitcoin.js +6 -2
- package/lib/module/assets/ethereum.d.ts +4 -2
- package/lib/module/assets/ethereum.js +7 -3
- package/lib/module/assets/index.d.ts +4 -2
- package/lib/module/assets/index.js +1 -1
- package/lib/module/assets/matic.d.ts +4 -2
- package/lib/module/assets/matic.js +7 -2
- package/lib/module/assets/solana.d.ts +4 -2
- package/lib/module/assets/solana.js +6 -2
- package/lib/module/device.d.ts +1 -0
- package/lib/module/device.js +39 -13
- package/lib/module/errors.d.ts +7 -0
- package/lib/module/errors.js +12 -0
- package/package.json +3 -3
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.2.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/hw-ledger@2.1.1...@exodus/hw-ledger@2.2.0) (2024-01-11)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
- support signing matic transactions with ethereum app on ledger ([#5329](https://github.com/ExodusMovement/exodus-hydra/issues/5329)) ([55eda94](https://github.com/ExodusMovement/exodus-hydra/commit/55eda944b78e1714a2b7215731febf399167a85b))
|
|
11
|
+
|
|
12
|
+
## [2.1.1](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/hw-ledger@2.1.0...@exodus/hw-ledger@2.1.1) (2024-01-11)
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
- missing dependencies ([#5322](https://github.com/ExodusMovement/exodus-hydra/issues/5322)) ([01efedc](https://github.com/ExodusMovement/exodus-hydra/commit/01efedc7508fb14925277fdcd388afb721ac3dd1))
|
|
17
|
+
- skip ethereum parity v normalization ([#5330](https://github.com/ExodusMovement/exodus-hydra/issues/5330)) ([7408190](https://github.com/ExodusMovement/exodus-hydra/commit/740819013c486a67302298fa6e3e9c981f42014c))
|
|
18
|
+
|
|
6
19
|
## [2.1.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/hw-ledger@2.0.0...@exodus/hw-ledger@2.1.0) (2023-12-25)
|
|
7
20
|
|
|
8
21
|
### Features
|
|
@@ -9,8 +9,10 @@ export interface BitcoinMessage {
|
|
|
9
9
|
}
|
|
10
10
|
declare function createHandler(transport: Transport): Promise<HardwareWalletAssetHandler<BitcoinMessage>>;
|
|
11
11
|
declare const metadata: {
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
applications: {
|
|
13
|
+
applicationName: string;
|
|
14
|
+
supportedVersions: string;
|
|
15
|
+
}[];
|
|
14
16
|
handler: typeof createHandler;
|
|
15
17
|
};
|
|
16
18
|
export default metadata;
|
|
@@ -67,8 +67,12 @@ async function createHandler(transport) {
|
|
|
67
67
|
};
|
|
68
68
|
}
|
|
69
69
|
const metadata = {
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
applications: [
|
|
71
|
+
{
|
|
72
|
+
applicationName: 'Bitcoin',
|
|
73
|
+
supportedVersions: '^2.1.2',
|
|
74
|
+
},
|
|
75
|
+
],
|
|
72
76
|
handler: createHandler,
|
|
73
77
|
};
|
|
74
78
|
export default metadata;
|
|
@@ -2,8 +2,10 @@ import type Transport from '@ledgerhq/hw-transport';
|
|
|
2
2
|
import type { HardwareWalletAssetHandler } from '@exodus/hw-common';
|
|
3
3
|
declare function createHandler(transport: Transport): Promise<HardwareWalletAssetHandler>;
|
|
4
4
|
declare const metadata: {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
applications: {
|
|
6
|
+
applicationName: string;
|
|
7
|
+
supportedVersions: string;
|
|
8
|
+
}[];
|
|
7
9
|
handler: typeof createHandler;
|
|
8
10
|
};
|
|
9
11
|
export default metadata;
|
|
@@ -118,15 +118,19 @@ async function createHandler(transport) {
|
|
|
118
118
|
assert(false, 'rawMessage or EIP712Message must be specified');
|
|
119
119
|
}
|
|
120
120
|
const { r, s, v } = await signingPromise;
|
|
121
|
-
const vNorm =
|
|
121
|
+
const vNorm = v.toString(16);
|
|
122
122
|
const vHex = vNorm.length < 2 ? '0' + vNorm : vNorm;
|
|
123
123
|
return Buffer.from(`${r}${s}${vHex}`, 'hex');
|
|
124
124
|
},
|
|
125
125
|
};
|
|
126
126
|
}
|
|
127
127
|
const metadata = {
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
applications: [
|
|
129
|
+
{
|
|
130
|
+
applicationName: 'Ethereum',
|
|
131
|
+
supportedVersions: '^1.10.0',
|
|
132
|
+
},
|
|
133
|
+
],
|
|
130
134
|
handler: createHandler,
|
|
131
135
|
};
|
|
132
136
|
export default metadata;
|
|
@@ -2,8 +2,10 @@ import type Transport from '@ledgerhq/hw-transport';
|
|
|
2
2
|
import type { HardwareWalletAssetHandler } from '@exodus/hw-common';
|
|
3
3
|
type HandlerFactory = (transport: Transport) => Promise<HardwareWalletAssetHandler>;
|
|
4
4
|
type AssetMetadata = {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
applications: {
|
|
6
|
+
applicationName: string;
|
|
7
|
+
supportedVersions: string;
|
|
8
|
+
}[];
|
|
7
9
|
handler: HandlerFactory;
|
|
8
10
|
};
|
|
9
11
|
export declare const assetApplications: Record<string, AssetMetadata>;
|
|
@@ -10,6 +10,6 @@ export const assetApplications = {
|
|
|
10
10
|
};
|
|
11
11
|
export const supportedBaseAssetNames = Object.keys(assetApplications);
|
|
12
12
|
export const applicationNameToBaseAssetName = Object.entries(assetApplications).reduce((mapping, [assetName, metadata]) => {
|
|
13
|
-
mapping[metadata.applicationName] = assetName;
|
|
13
|
+
mapping[metadata.applications[0].applicationName] = assetName;
|
|
14
14
|
return mapping;
|
|
15
15
|
}, Object.create(null));
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
declare const metadata: {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
applications: {
|
|
3
|
+
applicationName: string;
|
|
4
|
+
supportedVersions: string;
|
|
5
|
+
}[];
|
|
4
6
|
handler: (transport: import("@ledgerhq/hw-transport").default) => Promise<import("libraries/hw-common/lib").HardwareWalletAssetHandler<import("libraries/hw-common/lib").Message>>;
|
|
5
7
|
};
|
|
6
8
|
export default metadata;
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import ethereum from './ethereum';
|
|
2
2
|
const metadata = {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
applications: [
|
|
4
|
+
{
|
|
5
|
+
applicationName: 'Polygon',
|
|
6
|
+
supportedVersions: '^1.10.0',
|
|
7
|
+
},
|
|
8
|
+
...ethereum.applications,
|
|
9
|
+
],
|
|
5
10
|
handler: ethereum.handler,
|
|
6
11
|
};
|
|
7
12
|
export default metadata;
|
|
@@ -2,8 +2,10 @@ import type Transport from '@ledgerhq/hw-transport';
|
|
|
2
2
|
import type { HardwareWalletAssetHandler } from '@exodus/hw-common';
|
|
3
3
|
declare function createHandler(transport: Transport): Promise<HardwareWalletAssetHandler>;
|
|
4
4
|
declare const metadata: {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
applications: {
|
|
6
|
+
applicationName: string;
|
|
7
|
+
supportedVersions: string;
|
|
8
|
+
}[];
|
|
7
9
|
handler: typeof createHandler;
|
|
8
10
|
};
|
|
9
11
|
export default metadata;
|
|
@@ -53,8 +53,12 @@ async function createHandler(transport) {
|
|
|
53
53
|
};
|
|
54
54
|
}
|
|
55
55
|
const metadata = {
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
applications: [
|
|
57
|
+
{
|
|
58
|
+
applicationName: 'Solana',
|
|
59
|
+
supportedVersions: '^1.4.0',
|
|
60
|
+
},
|
|
61
|
+
],
|
|
58
62
|
handler: createHandler,
|
|
59
63
|
};
|
|
60
64
|
export default metadata;
|
package/lib/module/device.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export type Dependencies = {
|
|
|
8
8
|
export declare class LedgerDevice implements HardwareWalletDevice {
|
|
9
9
|
#private;
|
|
10
10
|
constructor({ transportFactory, descriptor }: Dependencies);
|
|
11
|
+
ensureApplicationIsOpened: (baseAssetName: string) => Promise<void>;
|
|
11
12
|
listSupportedAssetNames: () => Promise<string[]>;
|
|
12
13
|
listInstalledAssetNames: () => Promise<string[]>;
|
|
13
14
|
listUseableAssetNames: () => Promise<string[]>;
|
package/lib/module/device.js
CHANGED
|
@@ -2,7 +2,7 @@ import semver from 'semver';
|
|
|
2
2
|
import { AssetUnsupportedError, DeviceLockedError, DeviceConnectionError, UserRefusedError, } from '@exodus/hw-common';
|
|
3
3
|
import { applicationNameToBaseAssetName, assetApplications, supportedBaseAssetNames, } from './assets';
|
|
4
4
|
import applicationFactory from './management/application';
|
|
5
|
-
import { UnsupportedVersionError } from './errors';
|
|
5
|
+
import { UnsupportedVersionError, ApplicationNotFoundError } from './errors';
|
|
6
6
|
export class LedgerDevice {
|
|
7
7
|
#transportFactory;
|
|
8
8
|
#descriptor;
|
|
@@ -10,7 +10,7 @@ export class LedgerDevice {
|
|
|
10
10
|
this.#transportFactory = transportFactory;
|
|
11
11
|
this.#descriptor = descriptor;
|
|
12
12
|
}
|
|
13
|
-
#runInSession = async (operation) => {
|
|
13
|
+
#runInSession = async (operation, expectErrorWhenClosing = false) => {
|
|
14
14
|
const transport = await this.#transportFactory.open(this.#descriptor);
|
|
15
15
|
try {
|
|
16
16
|
return await operation(transport);
|
|
@@ -19,7 +19,14 @@ export class LedgerDevice {
|
|
|
19
19
|
throw transformToCommonError(err);
|
|
20
20
|
}
|
|
21
21
|
finally {
|
|
22
|
-
|
|
22
|
+
if (expectErrorWhenClosing) {
|
|
23
|
+
await transport.close().catch((err) => {
|
|
24
|
+
console.warn(`caught error while closing ledger transport but was expected = `, err);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
await transport.close();
|
|
29
|
+
}
|
|
23
30
|
}
|
|
24
31
|
};
|
|
25
32
|
#getAssetApplication = (assetName) => {
|
|
@@ -44,7 +51,7 @@ export class LedgerDevice {
|
|
|
44
51
|
return this.#runInSession(async (transport) => {
|
|
45
52
|
const handler = await applicationFactory(transport);
|
|
46
53
|
return handler.openApplication(applicationName);
|
|
47
|
-
});
|
|
54
|
+
}, true);
|
|
48
55
|
};
|
|
49
56
|
#quitApplication = async () => {
|
|
50
57
|
return this.#runInSession(async (transport) => {
|
|
@@ -52,18 +59,37 @@ export class LedgerDevice {
|
|
|
52
59
|
return handler.quitApplication();
|
|
53
60
|
});
|
|
54
61
|
};
|
|
55
|
-
|
|
56
|
-
const {
|
|
62
|
+
ensureApplicationIsOpened = async (baseAssetName) => {
|
|
63
|
+
const { applications } = this.#getAssetApplication(baseAssetName);
|
|
64
|
+
const supportedApplicationNames = applications.map(({ applicationName }) => applicationName);
|
|
57
65
|
const currentApplicationInfo = await this.#getInformation();
|
|
58
66
|
let desiredApplicationInfo = null;
|
|
59
|
-
if (
|
|
67
|
+
if (supportedApplicationNames.includes(currentApplicationInfo.name)) {
|
|
60
68
|
desiredApplicationInfo = currentApplicationInfo;
|
|
61
69
|
}
|
|
62
70
|
else {
|
|
63
71
|
await this.#quitApplication();
|
|
64
|
-
|
|
72
|
+
let applicationName = null;
|
|
73
|
+
for (const applicationNameToOpen of supportedApplicationNames) {
|
|
74
|
+
try {
|
|
75
|
+
await this.#openApplication(applicationNameToOpen);
|
|
76
|
+
applicationName = applicationNameToOpen;
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
const APPLICATION_NOT_INSTALLED = 26631;
|
|
81
|
+
if (err.statusCode === APPLICATION_NOT_INSTALLED) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (!applicationName) {
|
|
87
|
+
throw new ApplicationNotFoundError(supportedApplicationNames);
|
|
88
|
+
}
|
|
65
89
|
desiredApplicationInfo = await this.#getInformation();
|
|
66
90
|
}
|
|
91
|
+
const currentApplicationName = desiredApplicationInfo.name;
|
|
92
|
+
const { supportedVersions } = applications.find(({ applicationName }) => applicationName === currentApplicationName);
|
|
67
93
|
const isSupportedVersion = semver.satisfies(desiredApplicationInfo.version, supportedVersions);
|
|
68
94
|
if (!isSupportedVersion) {
|
|
69
95
|
throw new UnsupportedVersionError(desiredApplicationInfo.version, supportedVersions);
|
|
@@ -91,35 +117,35 @@ export class LedgerDevice {
|
|
|
91
117
|
return assetName ? [assetName] : [];
|
|
92
118
|
};
|
|
93
119
|
getAddress = async (params) => {
|
|
94
|
-
await this
|
|
120
|
+
await this.ensureApplicationIsOpened(params.assetName);
|
|
95
121
|
return this.#runInSession(async (transport) => {
|
|
96
122
|
const handler = await this.#getAssetApplication(params.assetName).handler(transport);
|
|
97
123
|
return handler.getAddress(params);
|
|
98
124
|
});
|
|
99
125
|
};
|
|
100
126
|
getXPub = async (params) => {
|
|
101
|
-
await this
|
|
127
|
+
await this.ensureApplicationIsOpened(params.assetName);
|
|
102
128
|
return this.#runInSession(async (transport) => {
|
|
103
129
|
const handler = await this.#getAssetApplication(params.assetName).handler(transport);
|
|
104
130
|
return handler.getXPub(params);
|
|
105
131
|
});
|
|
106
132
|
};
|
|
107
133
|
getPublicKey = async (params) => {
|
|
108
|
-
await this
|
|
134
|
+
await this.ensureApplicationIsOpened(params.assetName);
|
|
109
135
|
return this.#runInSession(async (transport) => {
|
|
110
136
|
const handler = await this.#getAssetApplication(params.assetName).handler(transport);
|
|
111
137
|
return handler.getPublicKey(params);
|
|
112
138
|
});
|
|
113
139
|
};
|
|
114
140
|
signTransaction = async (params) => {
|
|
115
|
-
await this
|
|
141
|
+
await this.ensureApplicationIsOpened(params.assetName);
|
|
116
142
|
return this.#runInSession(async (transport) => {
|
|
117
143
|
const handler = await this.#getAssetApplication(params.assetName).handler(transport);
|
|
118
144
|
return handler.signTransaction(params);
|
|
119
145
|
});
|
|
120
146
|
};
|
|
121
147
|
signMessage = async (params) => {
|
|
122
|
-
await this
|
|
148
|
+
await this.ensureApplicationIsOpened(params.assetName);
|
|
123
149
|
return this.#runInSession(async (transport) => {
|
|
124
150
|
const handler = await this.#getAssetApplication(params.assetName).handler(transport);
|
|
125
151
|
return handler.signMessage(params);
|
package/lib/module/errors.d.ts
CHANGED
|
@@ -7,8 +7,15 @@ export declare class NoDeviceFoundError extends HardwareWalletError {
|
|
|
7
7
|
name: string;
|
|
8
8
|
constructor();
|
|
9
9
|
}
|
|
10
|
+
export declare class ApplicationNotFoundError extends HardwareWalletError {
|
|
11
|
+
name: string;
|
|
12
|
+
supportedApplications: string[];
|
|
13
|
+
constructor(supportedApplications: string[]);
|
|
14
|
+
}
|
|
10
15
|
export declare class UnsupportedVersionError extends HardwareWalletError {
|
|
11
16
|
name: string;
|
|
17
|
+
supportedVersions: string;
|
|
18
|
+
actualVersion: string;
|
|
12
19
|
constructor(actualVersion: string, supportedVersions: string);
|
|
13
20
|
}
|
|
14
21
|
export declare class RequiresBlindSigningError extends HardwareWalletError {
|
package/lib/module/errors.js
CHANGED
|
@@ -11,10 +11,22 @@ export class NoDeviceFoundError extends HardwareWalletError {
|
|
|
11
11
|
super(`unable to find a connected device`);
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
|
+
export class ApplicationNotFoundError extends HardwareWalletError {
|
|
15
|
+
name = 'ApplicationNotFoundError';
|
|
16
|
+
supportedApplications;
|
|
17
|
+
constructor(supportedApplications) {
|
|
18
|
+
super(`required application not installed, please install a supported application (${supportedApplications.join(', ')}).`);
|
|
19
|
+
this.supportedApplications = supportedApplications;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
14
22
|
export class UnsupportedVersionError extends HardwareWalletError {
|
|
15
23
|
name = 'UnsupportedVersionError';
|
|
24
|
+
supportedVersions;
|
|
25
|
+
actualVersion;
|
|
16
26
|
constructor(actualVersion, supportedVersions) {
|
|
17
27
|
super(`version does not meet version requirements: ${actualVersion} does not match ${supportedVersions}`);
|
|
28
|
+
this.supportedVersions = supportedVersions;
|
|
29
|
+
this.actualVersion = actualVersion;
|
|
18
30
|
}
|
|
19
31
|
}
|
|
20
32
|
export class RequiresBlindSigningError extends HardwareWalletError {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/hw-ledger",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "The ledger module",
|
|
5
5
|
"author": "Exodus Movement Inc.",
|
|
6
6
|
"repository": {
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"@exodus/hw-common": "^2.0.0",
|
|
37
37
|
"@exodus/ledger-bitcoin": "^0.2.3-exodus.0",
|
|
38
38
|
"@exodus/ledgerhq-hw-app-eth": "^6.33.7-exodus.3",
|
|
39
|
+
"@exodus/module": "^1.2.2",
|
|
39
40
|
"@exodus/secp256k1": "^4.0.2-exodus.0",
|
|
40
41
|
"@ledgerhq/hw-app-solana": "^7.0.10",
|
|
41
42
|
"@ledgerhq/hw-transport": "^6.28.5",
|
|
@@ -48,7 +49,6 @@
|
|
|
48
49
|
"devDependencies": {
|
|
49
50
|
"@exodus/bip32": "^2.0.0",
|
|
50
51
|
"@exodus/ledgerhq-devices": "^8.1.0-exodus.0",
|
|
51
|
-
"@exodus/module": "^1.2.2",
|
|
52
52
|
"@ledgerhq/hw-transport-node-hid": "^6.27.17",
|
|
53
53
|
"@ledgerhq/hw-transport-node-speculos": "^6.27.16",
|
|
54
54
|
"@types/bs58": "^4.0.1",
|
|
@@ -67,5 +67,5 @@
|
|
|
67
67
|
"ts-jest": "^29.0.3",
|
|
68
68
|
"typescript": "^4.7.3"
|
|
69
69
|
},
|
|
70
|
-
"gitHead": "
|
|
70
|
+
"gitHead": "d19b9139b125653c52a2d4e657d87d9ed40e5d4b"
|
|
71
71
|
}
|