diff --git a/packages/hw-wallet-sdk/CHANGELOG.md b/packages/hw-wallet-sdk/CHANGELOG.md index 0ce200440..ff3d1d0a3 100644 --- a/packages/hw-wallet-sdk/CHANGELOG.md +++ b/packages/hw-wallet-sdk/CHANGELOG.md @@ -10,5 +10,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Add hardware related error mappings and custom hardware error ([#421](https://github.com/MetaMask/accounts/pull/421)) +- Add BLE and mobile error mappings with new error codes for Bluetooth permissions, connection states, and mobile support ([#433](https://github.com/MetaMask/accounts/pull/433)) [Unreleased]: https://github.com/MetaMask/accounts/ diff --git a/packages/hw-wallet-sdk/src/hardware-error-mappings.test.ts b/packages/hw-wallet-sdk/src/hardware-error-mappings.test.ts index f90b85717..c39f3e2e6 100644 --- a/packages/hw-wallet-sdk/src/hardware-error-mappings.test.ts +++ b/packages/hw-wallet-sdk/src/hardware-error-mappings.test.ts @@ -1,4 +1,8 @@ -import { LEDGER_ERROR_MAPPINGS } from './hardware-error-mappings'; +import { + LEDGER_ERROR_MAPPINGS, + BLE_ERROR_MAPPINGS, + MOBILE_ERROR_MAPPINGS, +} from './hardware-error-mappings'; import { ErrorCode, Severity, Category } from './hardware-errors-enums'; describe('HARDWARE_ERROR_MAPPINGS', () => { @@ -102,4 +106,110 @@ describe('HARDWARE_ERROR_MAPPINGS', () => { }); }); }); + + describe('BLE mappings', () => { + const errorMappings = BLE_ERROR_MAPPINGS; + + it('has errorMappings object', () => { + expect(errorMappings).toBeDefined(); + expect(typeof errorMappings).toBe('object'); + }); + + describe('permission errors', () => { + it('maps BLUETOOTH_PERMISSION_DENIED correctly', () => { + const mapping = errorMappings.BLUETOOTH_PERMISSION_DENIED; + expect(mapping.code).toBe(ErrorCode.PermissionBluetoothDenied); + expect(mapping.severity).toBe(Severity.Err); + expect(mapping.category).toBe(Category.Configuration); + }); + + it('maps LOCATION_PERMISSION_DENIED correctly', () => { + const mapping = errorMappings.LOCATION_PERMISSION_DENIED; + expect(mapping.code).toBe(ErrorCode.PermissionLocationDenied); + expect(mapping.severity).toBe(Severity.Err); + expect(mapping.category).toBe(Category.Configuration); + expect(mapping.userMessage).toContain('Location'); + }); + + it('maps NEARBY_DEVICES_PERMISSION_DENIED correctly', () => { + const mapping = errorMappings.NEARBY_DEVICES_PERMISSION_DENIED; + expect(mapping.code).toBe(ErrorCode.PermissionNearbyDevicesDenied); + expect(mapping.severity).toBe(Severity.Err); + expect(mapping.category).toBe(Category.Configuration); + }); + }); + + describe('bluetooth state errors', () => { + it('maps BLUETOOTH_DISABLED correctly', () => { + const mapping = errorMappings.BLUETOOTH_DISABLED; + expect(mapping.code).toBe(ErrorCode.BluetoothDisabled); + expect(mapping.severity).toBe(Severity.Warning); + expect(mapping.category).toBe(Category.Connection); + }); + + it('maps BLUETOOTH_SCAN_FAILED correctly', () => { + const mapping = errorMappings.BLUETOOTH_SCAN_FAILED; + expect(mapping.code).toBe(ErrorCode.BluetoothScanFailed); + expect(mapping.severity).toBe(Severity.Err); + expect(mapping.category).toBe(Category.Connection); + }); + + it('maps BLUETOOTH_CONNECTION_FAILED correctly', () => { + const mapping = errorMappings.BLUETOOTH_CONNECTION_FAILED; + expect(mapping.code).toBe(ErrorCode.BluetoothConnectionFailed); + expect(mapping.severity).toBe(Severity.Err); + expect(mapping.category).toBe(Category.Connection); + }); + }); + + it('has valid structure for all mappings', () => { + Object.entries(errorMappings).forEach(([_, mapping]) => { + expect(mapping).toHaveProperty('code'); + expect(mapping).toHaveProperty('message'); + expect(mapping).toHaveProperty('severity'); + expect(mapping).toHaveProperty('category'); + + const numericErrorCodes = Object.values(ErrorCode).filter( + (value): value is number => typeof value === 'number', + ); + expect(numericErrorCodes).toContain(mapping.code); + expect(Object.values(Severity)).toContain(mapping.severity); + expect(Object.values(Category)).toContain(mapping.category); + expect(typeof mapping.message).toBe('string'); + }); + }); + }); + + describe('Mobile mappings', () => { + const errorMappings = MOBILE_ERROR_MAPPINGS; + + it('has errorMappings object', () => { + expect(errorMappings).toBeDefined(); + expect(typeof errorMappings).toBe('object'); + }); + + it('maps NOT_SUPPORTED correctly', () => { + const mapping = errorMappings.NOT_SUPPORTED; + expect(mapping.code).toBe(ErrorCode.MobileNotSupported); + expect(mapping.severity).toBe(Severity.Err); + expect(mapping.category).toBe(Category.DeviceState); + }); + + it('has valid structure for all mappings', () => { + Object.entries(errorMappings).forEach(([_, mapping]) => { + expect(mapping).toHaveProperty('code'); + expect(mapping).toHaveProperty('message'); + expect(mapping).toHaveProperty('severity'); + expect(mapping).toHaveProperty('category'); + + const numericErrorCodes = Object.values(ErrorCode).filter( + (value): value is number => typeof value === 'number', + ); + expect(numericErrorCodes).toContain(mapping.code); + expect(Object.values(Severity)).toContain(mapping.severity); + expect(Object.values(Category)).toContain(mapping.category); + expect(typeof mapping.message).toBe('string'); + }); + }); + }); }); diff --git a/packages/hw-wallet-sdk/src/hardware-error-mappings.ts b/packages/hw-wallet-sdk/src/hardware-error-mappings.ts index f786212fc..27bb5c44a 100644 --- a/packages/hw-wallet-sdk/src/hardware-error-mappings.ts +++ b/packages/hw-wallet-sdk/src/hardware-error-mappings.ts @@ -114,3 +114,63 @@ export const LEDGER_ERROR_MAPPINGS = { userMessage: 'Ethereum app is out of date. Please update it to continue.', }, }; + +export const BLE_ERROR_MAPPINGS = { + BLUETOOTH_PERMISSION_DENIED: { + code: ErrorCode.PermissionBluetoothDenied, + message: 'Bluetooth permission denied', + severity: Severity.Err, + category: Category.Configuration, + userMessage: + 'Bluetooth permission is required to connect to your hardware wallet. Please enable it in your device settings.', + }, + LOCATION_PERMISSION_DENIED: { + code: ErrorCode.PermissionLocationDenied, + message: 'Location permission denied', + severity: Severity.Err, + category: Category.Configuration, + userMessage: + 'Location permission is required for Bluetooth scanning on Android. Please enable it in your device settings.', + }, + NEARBY_DEVICES_PERMISSION_DENIED: { + code: ErrorCode.PermissionNearbyDevicesDenied, + message: 'Nearby devices permission denied', + severity: Severity.Err, + category: Category.Configuration, + userMessage: + 'Nearby devices permission is required to scan for your hardware wallet. Please enable it in your device settings.', + }, + BLUETOOTH_DISABLED: { + code: ErrorCode.BluetoothDisabled, + message: 'Bluetooth is turned off', + severity: Severity.Warning, + category: Category.Connection, + userMessage: + 'Bluetooth is turned off. Please enable Bluetooth to connect to your hardware wallet.', + }, + BLUETOOTH_SCAN_FAILED: { + code: ErrorCode.BluetoothScanFailed, + message: 'Bluetooth scanning failed', + severity: Severity.Err, + category: Category.Connection, + userMessage: 'Unable to scan for Bluetooth devices. Please try again.', + }, + BLUETOOTH_CONNECTION_FAILED: { + code: ErrorCode.BluetoothConnectionFailed, + message: 'Bluetooth connection failed', + severity: Severity.Err, + category: Category.Connection, + userMessage: + 'Failed to connect via Bluetooth. Please make sure your device is nearby and try again.', + }, +}; + +export const MOBILE_ERROR_MAPPINGS = { + NOT_SUPPORTED: { + code: ErrorCode.MobileNotSupported, + message: 'Operation not supported on mobile', + severity: Severity.Err, + category: Category.DeviceState, + userMessage: 'This operation is not supported on mobile devices.', + }, +}; diff --git a/packages/hw-wallet-sdk/src/hardware-errors-enums.ts b/packages/hw-wallet-sdk/src/hardware-errors-enums.ts index d40076eef..1faa29e2d 100644 --- a/packages/hw-wallet-sdk/src/hardware-errors-enums.ts +++ b/packages/hw-wallet-sdk/src/hardware-errors-enums.ts @@ -48,6 +48,15 @@ export enum ErrorCode { DeviceStateEthAppClosed = 6003, DeviceStateEthAppOutOfDate = 6004, + // Mobile/BLE Permission Errors + PermissionBluetoothDenied = 7000, + PermissionLocationDenied = 7001, + PermissionNearbyDevicesDenied = 7002, + BluetoothDisabled = 7100, + BluetoothScanFailed = 7101, + BluetoothConnectionFailed = 7102, + MobileNotSupported = 7300, + // Transaction TxInsufficientFunds = 10000, @@ -72,4 +81,5 @@ export enum Category { UserAction = 'UserAction', DeviceState = 'DeviceState', Unknown = 'Unknown', + Configuration = 'Configuration', }