diff --git a/apps/mobile/src/assets/locales/en/messages.json b/apps/mobile/src/assets/locales/en/messages.json index d3f045eac..5a9fc3967 100644 --- a/apps/mobile/src/assets/locales/en/messages.json +++ b/apps/mobile/src/assets/locales/en/messages.json @@ -1263,7 +1263,8 @@ "ethereum_app_not_installed_error": "Please install the Ethereum app on your Ledger device.", "ethereum_app_unconfirmed_error": "You have denied the request to open the Ethereum app.", "ethereum_app_open_error": "Please install/accept Ethereum app on your Ledger device.", - "running_app_close_error": "Failed to close the running app on your Ledger device." + "running_app_close_error": "Failed to close the running app on your Ledger device.", + "firmwareOrAppUpdateRequired": "Please update the firmware and Ethereum App on your Ledger" }, "openEthApp": { "title": "Connect Ledger", @@ -2108,6 +2109,12 @@ "message": "Rabby Wallet uses bluetooth access to connect Ledger", "open_settings": "OK", "cancel": "Don't Allow" + }, + "update_firmware_alert": { + "title": "Ledger Firmware Outdated", + "message": "Check out how to update Ledger firmware from Ledger support", + "update": "Update", + "cancel": "Cancel" } } } diff --git a/apps/mobile/src/components/ConnectLedger/ConnectLedger.tsx b/apps/mobile/src/components/ConnectLedger/ConnectLedger.tsx index 370baaf69..32c48490f 100644 --- a/apps/mobile/src/components/ConnectLedger/ConnectLedger.tsx +++ b/apps/mobile/src/components/ConnectLedger/ConnectLedger.tsx @@ -61,12 +61,18 @@ export const ConnectLedger: React.FC<{ }); } catch (err: any) { // maybe session is disconnect, just try to reconnect - if (loopCountRef.current < 3) { + if (!err.message && loopCountRef.current < 3) { loopCountRef.current++; console.log('checkEthApp isConnected error', err); return await checkEthApp(); } - toast.show(t('page.newAddress.ledger.error.lockedOrNoEthApp')); + + if (err.message !== LEDGER_ERROR_CODES.FIRMWARE_OR_APP_UPDATE_REQUIRED) { + toast.show( + err.message || t('page.newAddress.ledger.error.lockedOrNoEthApp'), + ); + } + setCurrentScreen('select'); console.error('checkEthApp', err); throw err; diff --git a/apps/mobile/src/core/apis/ledger.ts b/apps/mobile/src/core/apis/ledger.ts index 1c5f5af94..e37767a05 100644 --- a/apps/mobile/src/core/apis/ledger.ts +++ b/apps/mobile/src/core/apis/ledger.ts @@ -7,6 +7,8 @@ import TransportBLE from '@ledgerhq/react-native-hw-transport-ble'; import { LedgerHDPathType } from '@rabby-wallet/eth-keyring-ledger/dist/utils'; import PQueue from 'p-queue/dist/index'; import { t } from 'i18next'; +import { ledgerErrorHandler, LEDGER_ERROR_CODES } from '@/hooks/ledger/error'; +import { UpdateFirmwareAlert } from '@/utils/bluetoothPermissions'; let queue: PQueue; setTimeout(() => { @@ -151,6 +153,16 @@ export async function importFirstAddress({ export async function checkEthApp(cb: (result: boolean) => void) { const keyring = await getKeyring(KEYRING_TYPE.LedgerKeyring); + try { + await keyring.makeApp(); + } catch (e: any) { + const message = ledgerErrorHandler(e); + + if (message === LEDGER_ERROR_CODES.FIRMWARE_OR_APP_UPDATE_REQUIRED) { + UpdateFirmwareAlert(); + throw new Error(message); + } + } const { appName } = await keyring.getAppAndVersion(); if (appName === 'BOLOS') { diff --git a/apps/mobile/src/hooks/ledger/error.ts b/apps/mobile/src/hooks/ledger/error.ts index df1f82a14..9b00ebf6b 100644 --- a/apps/mobile/src/hooks/ledger/error.ts +++ b/apps/mobile/src/hooks/ledger/error.ts @@ -7,6 +7,7 @@ export enum LEDGER_ERROR_CODES { UNKNOWN = 'unknown', DISCONNECTED = 'disconnected', LOCKED_OR_NO_ETH_APP = 'locked_or_no_eth_app', + FIRMWARE_OR_APP_UPDATE_REQUIRED = 'firmware_or_app_update_required', } /** @@ -16,6 +17,9 @@ export const ledgerErrorHandler = (error: Error) => { if (!error.message) { return LEDGER_ERROR_CODES.UNKNOWN; } + if (error.message.includes('0x6b00') || error.message.includes('0x6e00')) { + return LEDGER_ERROR_CODES.FIRMWARE_OR_APP_UPDATE_REQUIRED; + } if (error.message.includes('0x650f')) { return LEDGER_ERROR_CODES.LOCKED_OR_NO_ETH_APP; } diff --git a/apps/mobile/src/utils/bluetoothPermissions.ts b/apps/mobile/src/utils/bluetoothPermissions.ts index 063013b36..0d088f7e0 100644 --- a/apps/mobile/src/utils/bluetoothPermissions.ts +++ b/apps/mobile/src/utils/bluetoothPermissions.ts @@ -59,6 +59,28 @@ export const showBluetoothPermissionsAlert = async () => { ); }; +export const UpdateFirmwareAlert = async () => { + Alert.alert( + i18n.t('bluetooth.update_firmware_alert.title'), + i18n.t('bluetooth.update_firmware_alert.message'), + [ + { + onPress: () => { + Linking.openURL( + 'https://support.ledger.com/hc/articles/360003117594-Ledger-device-firmware-update-FAQ', + ); + }, + text: i18n.t('bluetooth.update_firmware_alert.update'), + }, + { + onPress: () => null, + style: 'cancel', + text: i18n.t('bluetooth.update_firmware_alert.cancel'), + }, + ], + ); +}; + /** * Checks and requests bluetooth permissions for Android */ diff --git a/packages/eth-keyring-ledger/src/LedgerKeyring.ts b/packages/eth-keyring-ledger/src/LedgerKeyring.ts index f29cef4b0..d8aafac84 100644 --- a/packages/eth-keyring-ledger/src/LedgerKeyring.ts +++ b/packages/eth-keyring-ledger/src/LedgerKeyring.ts @@ -180,11 +180,7 @@ class LedgerKeyring { this.transport = await this.getTransport(this.deviceId!); this.app = new LedgerEth(this.transport); } catch (e: any) { - if ( - e.name === 'BleError' || - e.message?.includes('isConnected') || - e.message?.includes('DisconnectedDevice') - ) { + if (this.transportType === 'ble') { throw e; } else if (!e.message?.includes('The device is already open')) { console.error(e);