Skip to content

Commit d7a3969

Browse files
committed
feat: use dmk error in ledger
1 parent bddb574 commit d7a3969

10 files changed

Lines changed: 437 additions & 31 deletions

File tree

packages/hw-wallet-sdk/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Added
1111

1212
- Add `DMK_ERROR_TAG_MAPPINGS`, `DMK_MESSAGE_PATTERNS`, and `getDMKErrorFromTag` for parsing Ledger Device Management Kit (DMK) errors by their non-standard `_tag` property ([#597](https://github.com/MetaMask/accounts/pull/597))
13+
- Add `DMK_ERROR_MAPPINGS` providing full `ErrorMapping` details (severity, category, userMessage) for each DMK `_tag`
1314

1415
## [0.10.0]
1516

packages/hw-wallet-sdk/src/dmk-error-mappings.test.ts

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,74 @@
11
import {
2+
DMK_ERROR_MAPPINGS,
23
DMK_ERROR_TAG_MAPPINGS,
34
DMK_MESSAGE_PATTERNS,
45
getDMKErrorFromTag,
56
} from './dmk-error-mappings';
6-
import { ErrorCode } from './hardware-errors-enums';
7+
import type { ErrorMapping } from './hardware-error-mappings';
8+
import { Category, ErrorCode, Severity } from './hardware-errors-enums';
9+
10+
describe('DMK_ERROR_MAPPINGS', () => {
11+
it('maps DeviceSessionNotFound to DeviceDisconnected with full details', () => {
12+
expect(DMK_ERROR_MAPPINGS.DeviceSessionNotFound).toStrictEqual({
13+
code: ErrorCode.DeviceDisconnected,
14+
message: 'DMK device session not found',
15+
severity: Severity.Err,
16+
category: Category.Connection,
17+
userMessage:
18+
'Your Ledger device was disconnected. Please reconnect and try again.',
19+
});
20+
});
21+
22+
it('maps ConnectionOpeningError to BluetoothConnectionFailed', () => {
23+
expect(DMK_ERROR_MAPPINGS.ConnectionOpeningError?.code).toBe(
24+
ErrorCode.BluetoothConnectionFailed,
25+
);
26+
});
27+
28+
it('maps DeviceLockedError to AuthenticationDeviceLocked', () => {
29+
expect(DMK_ERROR_MAPPINGS.DeviceLockedError?.code).toBe(
30+
ErrorCode.AuthenticationDeviceLocked,
31+
);
32+
expect(DMK_ERROR_MAPPINGS.DeviceLockedError?.category).toBe(
33+
Category.Authentication,
34+
);
35+
});
36+
37+
it('maps SessionRefresherError to DeviceDisconnected', () => {
38+
expect(DMK_ERROR_MAPPINGS.SessionRefresherError?.code).toBe(
39+
ErrorCode.DeviceDisconnected,
40+
);
41+
});
42+
43+
it('has exactly 7 DMK error mappings', () => {
44+
expect(Object.keys(DMK_ERROR_MAPPINGS)).toHaveLength(7);
45+
});
46+
47+
it('every mapping has all required ErrorMapping fields', () => {
48+
Object.values(DMK_ERROR_MAPPINGS).forEach((mapping) => {
49+
expect(mapping).toHaveProperty('code');
50+
expect(mapping).toHaveProperty('message');
51+
expect(mapping).toHaveProperty('severity');
52+
expect(mapping).toHaveProperty('category');
53+
expect(mapping).toHaveProperty('userMessage');
54+
});
55+
});
56+
57+
it('every mapping code matches the code in DMK_ERROR_TAG_MAPPINGS', () => {
58+
Object.entries(DMK_ERROR_MAPPINGS).forEach(([tag, mapping]) => {
59+
expect(DMK_ERROR_TAG_MAPPINGS[tag]).toBe(mapping.code);
60+
});
61+
});
62+
63+
it('every mapping maps to a valid ErrorCode', () => {
64+
const validCodes = Object.values(ErrorCode).filter(
65+
(value): value is number => typeof value === 'number',
66+
);
67+
Object.values(DMK_ERROR_MAPPINGS).forEach((mapping: ErrorMapping) => {
68+
expect(validCodes).toContain(mapping.code);
69+
});
70+
});
71+
});
772

873
describe('DMK_ERROR_TAG_MAPPINGS', () => {
974
it('maps DeviceSessionNotFound to DeviceDisconnected', () => {

packages/hw-wallet-sdk/src/dmk-error-mappings.ts

Lines changed: 78 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,94 @@
1-
import { ErrorCode } from './hardware-errors-enums';
1+
import type { ErrorMapping } from './hardware-error-mappings';
2+
import { Category, ErrorCode, Severity } from './hardware-errors-enums';
23

34
/**
4-
* DMK (Device Management Kit) `_tag`-based error name mappings.
5+
* Full DMK (Device Management Kit) `_tag`-based error mappings.
56
*
67
* DMK is Ledger's newer SDK. Unlike legacy `@ledgerhq/errors`, which identify
78
* errors via the standard `error.name` property, DMK errors carry a
89
* non-standard `_tag` string (e.g. `'DeviceSessionNotFound'`,
910
* `'DeviceLockedError'`). Tag values are looked up in this mapping to resolve
10-
* the corresponding `ErrorCode`.
11+
* the full {@link ErrorMapping} (code, message, severity, category,
12+
* userMessage).
13+
*
14+
* This is the single source of truth for DMK tag → error details. The
15+
* code-only {@link DMK_ERROR_TAG_MAPPINGS} is derived from this object so
16+
* consumers that only need the `ErrorCode` (e.g. MetaMask Mobile) can use the
17+
* simpler mapping without duplicating data.
1118
*
1219
* These mappings are shared with legacy error names in consumers (e.g.
1320
* MetaMask Mobile) since both map to the same `ErrorCode` values.
1421
*/
15-
export const DMK_ERROR_TAG_MAPPINGS: Record<string, ErrorCode> = {
16-
DeviceSessionNotFound: ErrorCode.DeviceDisconnected,
17-
ConnectionOpeningError: ErrorCode.BluetoothConnectionFailed,
18-
DeviceDisconnectedWhileSendingError: ErrorCode.DeviceDisconnected,
19-
DeviceDisconnectedBeforeSendingApdu: ErrorCode.DeviceDisconnected,
20-
DeviceLockedError: ErrorCode.AuthenticationDeviceLocked,
21-
DeviceNotConnectedError: ErrorCode.DeviceDisconnected,
22-
SessionRefresherError: ErrorCode.DeviceDisconnected,
22+
export const DMK_ERROR_MAPPINGS: Record<string, ErrorMapping> = {
23+
DeviceSessionNotFound: {
24+
code: ErrorCode.DeviceDisconnected,
25+
message: 'DMK device session not found',
26+
severity: Severity.Err,
27+
category: Category.Connection,
28+
userMessage:
29+
'Your Ledger device was disconnected. Please reconnect and try again.',
30+
},
31+
ConnectionOpeningError: {
32+
code: ErrorCode.BluetoothConnectionFailed,
33+
message: 'DMK connection failed to open',
34+
severity: Severity.Err,
35+
category: Category.Connection,
36+
userMessage:
37+
'Failed to connect to your Ledger device. Please make sure it is nearby and try again.',
38+
},
39+
DeviceDisconnectedWhileSendingError: {
40+
code: ErrorCode.DeviceDisconnected,
41+
message: 'DMK device disconnected while sending',
42+
severity: Severity.Err,
43+
category: Category.Connection,
44+
userMessage:
45+
'Your Ledger device was disconnected. Please reconnect and try again.',
46+
},
47+
DeviceDisconnectedBeforeSendingApdu: {
48+
code: ErrorCode.DeviceDisconnected,
49+
message: 'DMK device disconnected before sending',
50+
severity: Severity.Err,
51+
category: Category.Connection,
52+
userMessage:
53+
'Your Ledger device was disconnected. Please reconnect and try again.',
54+
},
55+
DeviceLockedError: {
56+
code: ErrorCode.AuthenticationDeviceLocked,
57+
message: 'DMK device locked',
58+
severity: Severity.Err,
59+
category: Category.Authentication,
60+
userMessage: 'Please unlock your Ledger device to continue.',
61+
},
62+
DeviceNotConnectedError: {
63+
code: ErrorCode.DeviceDisconnected,
64+
message: 'DMK device not connected',
65+
severity: Severity.Err,
66+
category: Category.Connection,
67+
userMessage:
68+
'Your Ledger device is not connected. Please connect and try again.',
69+
},
70+
SessionRefresherError: {
71+
code: ErrorCode.DeviceDisconnected,
72+
message: 'DMK session refresh failed',
73+
severity: Severity.Err,
74+
category: Category.Connection,
75+
userMessage:
76+
'Your Ledger device session has expired. Please reconnect and try again.',
77+
},
2378
};
2479

80+
/**
81+
* DMK `_tag`-to-`ErrorCode` mappings.
82+
*
83+
* Derived from {@link DMK_ERROR_MAPPINGS} so there is a single source of truth
84+
* for tag → code resolution. Consumers that only need the numeric `ErrorCode`
85+
* (e.g. MetaMask Mobile) can use this lightweight mapping directly.
86+
*/
87+
export const DMK_ERROR_TAG_MAPPINGS: Record<string, ErrorCode> =
88+
Object.fromEntries(
89+
Object.entries(DMK_ERROR_MAPPINGS).map(([tag, { code }]) => [tag, code]),
90+
);
91+
2592
/**
2693
* DMK-specific message patterns for error parsing.
2794
*

packages/keyring-eth-ledger-bridge/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- Add `createDMKError` factory function for constructing `HardwareWalletError` instances from DMK `_tag` strings
13+
- `translateDmkError` now resolves DMK connection/session errors (e.g. `DeviceSessionNotFound`, `DeviceLockedError`) by their `_tag` before falling back to hex APDU status codes
14+
- `LedgerDmkBridge.#toError` also resolves DMK `_tag` errors so `sendCommand` failures are correctly classified
15+
- Bump `@metamask/hw-wallet-sdk` from `^0.10.0` to `^0.11.0` ([#597](https://github.com/MetaMask/accounts/pull/597))
16+
1017
## [12.3.0]
1118

1219
### Changed

0 commit comments

Comments
 (0)