diff --git a/development/spellCheckerSkipWords.txt b/development/spellCheckerSkipWords.txt index aaa47da14eca..1dee2bf2a9d7 100644 --- a/development/spellCheckerSkipWords.txt +++ b/development/spellCheckerSkipWords.txt @@ -797,6 +797,7 @@ sompi Sompi Sparkline splitter +Stax sr25519 starcoin Starcoin diff --git a/packages/kit-bg/src/dbs/local/LocalDbBase.trezor.test.ts b/packages/kit-bg/src/dbs/local/LocalDbBase.trezor.test.ts index a261ac7b15f6..0a928d140730 100644 --- a/packages/kit-bg/src/dbs/local/LocalDbBase.trezor.test.ts +++ b/packages/kit-bg/src/dbs/local/LocalDbBase.trezor.test.ts @@ -1,4 +1,3 @@ -import { getVendorProfile } from '@onekeyhq/shared/src/hardware/vendorProfile'; import { EHardwareTransportType } from '@onekeyhq/shared/types'; import { EHardwareVendor } from '@onekeyhq/shared/types/device'; @@ -7,7 +6,6 @@ import { buildThirdPartyFeaturesInfoFromDevice, buildTrezorDesktopBleUsbConnectId, clearTrezorThpSettingsRaw, - getThirdPartyDeviceAvatarImage, getThirdPartyDeviceModelName, resolveBleConnectIdForCreate, } from './LocalDbBase'; @@ -220,36 +218,6 @@ describe('getThirdPartyDeviceModelName', () => { }); }); -describe('getThirdPartyDeviceAvatarImage', () => { - it.each([ - 'Safe 3', - 'Safe 5', - 'Safe 7', - 'Trezor Safe 7', - 'Model One', - 'Model T', - ])( - 'uses the Trezor vendorModelName avatar key when the %s asset is registered', - (modelName) => { - expect( - getThirdPartyDeviceAvatarImage({ - profile: getVendorProfile(EHardwareVendor.trezor), - modelName, - }), - ).toBe(modelName); - }, - ); - - it('falls back to the Trezor vendor avatar for unknown model assets', () => { - expect( - getThirdPartyDeviceAvatarImage({ - profile: getVendorProfile(EHardwareVendor.trezor), - modelName: 'Unknown Model', - }), - ).toBe('trezor'); - }); -}); - describe('buildTrezorDesktopBleUsbConnectId', () => { it('uses firmware device_id as usbConnectId only for Trezor Desktop BLE', () => { expect( diff --git a/packages/kit-bg/src/dbs/local/LocalDbBase.ts b/packages/kit-bg/src/dbs/local/LocalDbBase.ts index abb21751c8b4..e4287aa4d664 100644 --- a/packages/kit-bg/src/dbs/local/LocalDbBase.ts +++ b/packages/kit-bg/src/dbs/local/LocalDbBase.ts @@ -101,10 +101,10 @@ import platformEnv from '@onekeyhq/shared/src/platformEnv'; import accountUtils from '@onekeyhq/shared/src/utils/accountUtils'; import { checkIsDefined } from '@onekeyhq/shared/src/utils/assertUtils'; import { - AllWalletAvatarImages, getDeviceAvatarImage, + getThirdPartyDeviceAvatarImage, } from '@onekeyhq/shared/src/utils/avatarUtils'; -import type { IAllWalletAvatarImageNamesWithoutDividers } from '@onekeyhq/shared/src/utils/avatarUtils'; +import type { IThirdPartyWalletAvatarImageNames } from '@onekeyhq/shared/src/utils/avatarUtils'; import bufferUtils from '@onekeyhq/shared/src/utils/bufferUtils'; import perfUtils, { EPerformanceTimerLogNames, @@ -630,21 +630,20 @@ export function buildThirdPartyDeviceDisplayName({ return `${vendorName} Device`; } -export function getThirdPartyDeviceAvatarImage({ - profile, - modelName, +function getThirdPartyDeviceModelCode({ + device, + features, }: { - profile: ReturnType; - modelName?: string; -}): IAllWalletAvatarImageNamesWithoutDividers { - if ( - profile.vendor === EHardwareVendor.trezor && - modelName && - modelName in AllWalletAvatarImages - ) { - return modelName as IAllWalletAvatarImageNamesWithoutDividers; - } - return profile.avatarKey as IAllWalletAvatarImageNamesWithoutDividers; + device: IDBCreateHwWalletParams['device']; + features: IOneKeyDeviceFeatures; +}): string | undefined { + const featureRecord = features as IOneKeyDeviceFeatures & { + internal_model?: string; + }; + return ( + featureRecord.internal_model || + getExtraDeviceFieldString(device, 'vendorModel') + ); } function parseDeviceSettingsRaw(settingsRaw?: string): IDBDeviceSettings { @@ -3412,10 +3411,16 @@ export abstract class LocalDbBase extends LocalDbBaseContainer { if (shouldFixAvatar) { if (profile.isThirdParty) { - // Third-party vendor: fix avatar to match vendor key - const expectedImg = - profile.avatarKey as IAllWalletAvatarImageNamesWithoutDividers; - if (avatarInfo?.img && avatarInfo.img !== expectedImg) { + // Resolve per-model avatar; parseDeviceSettingsRaw is a defensive fallback. + const deviceSettings = + device?.settings ?? parseDeviceSettingsRaw(device?.settingsRaw); + const expectedImg = getThirdPartyDeviceAvatarImage({ + vendor: profile.vendor, + vendorModel: deviceSettings.vendorModel, + vendorModelName: deviceSettings.vendorModelName, + fallback: profile.avatarKey as IThirdPartyWalletAvatarImageNames, + }); + if (avatarInfo?.img !== expectedImg) { wallet.avatarInfo = { ...avatarInfo, img: expectedImg }; wallet.avatar = JSON.stringify(wallet.avatarInfo); } @@ -6124,7 +6129,12 @@ export abstract class LocalDbBase extends LocalDbBaseContainer { deviceType: EDeviceType.Unknown, firmwareType: thirdPartyDeviceUtils.getFirmwareType({ features }), avatar: { - img: getThirdPartyDeviceAvatarImage({ profile, modelName }), + img: getThirdPartyDeviceAvatarImage({ + vendor: profile.vendor, + vendorModel: getThirdPartyDeviceModelCode({ device, features }), + vendorModelName: modelName, + fallback: profile.avatarKey as IThirdPartyWalletAvatarImageNames, + }), }, deviceName: finalDeviceName, featuresInfo: buildThirdPartyFeaturesInfoFromDevice({ diff --git a/packages/kit/src/components/Hardware/TrezorBleBindingDialog.tsx b/packages/kit/src/components/Hardware/TrezorBleBindingDialog.tsx index f4979d788561..ea27c43d7f25 100644 --- a/packages/kit/src/components/Hardware/TrezorBleBindingDialog.tsx +++ b/packages/kit/src/components/Hardware/TrezorBleBindingDialog.tsx @@ -20,6 +20,7 @@ import { WalletAvatar } from '@onekeyhq/kit/src/components/WalletAvatar'; import { convertDeviceError } from '@onekeyhq/shared/src/errors/utils/deviceErrorUtils'; import { ETranslations } from '@onekeyhq/shared/src/locale'; import platformEnv from '@onekeyhq/shared/src/platformEnv'; +import { getThirdPartyDeviceAvatarImage } from '@onekeyhq/shared/src/utils/avatarUtils'; import deviceUtils from '@onekeyhq/shared/src/utils/deviceUtils'; import { EHardwareVendor } from '@onekeyhq/shared/types/device'; @@ -361,6 +362,12 @@ function TrezorBleBindingContent({ bindingId, rejectedConnectIds, }); + const avatarImg = getThirdPartyDeviceAvatarImage({ + vendor: EHardwareVendor.trezor, + vendorModel: device.vendorModel, + vendorModelName: device.vendorModelName, + fallback: 'trezor', + }); return ( - + = ThirdPartyWalletAvatarImages; - const profile = getVendorProfile(device.vendor); - const key = - device.vendor === EHardwareVendor.trezor && device.model in avatars - ? device.model - : profile.avatarKey; - return avatars[key] ?? avatars.trezor; -} - type IActionItem = { label: string; action: EThirdPartyHardwareUiAction; @@ -137,6 +154,12 @@ function ActionRows({ function ThirdPartyHardwareActionsTest() { const [device, setDevice] = useState(DEVICE_MOCKS[0]); + const avatarKey = getThirdPartyDeviceAvatarImage({ + vendor: device.vendor, + vendorModel: device.vendorModel, + vendorModelName: device.vendorModelName, + fallback: device.vendor === EHardwareVendor.ledger ? 'ledger' : 'trezor', + }); return ( @@ -156,15 +179,15 @@ function ThirdPartyHardwareActionsTest() { - {device.model} + {device.label} - {`vendor=${device.vendor}`} + {`vendor=${device.vendor} avatarKey=${avatarKey}`} diff --git a/packages/kit/src/views/Onboardingv2/pages/ConnectionFlowLedger.tsx b/packages/kit/src/views/Onboardingv2/pages/ConnectionFlowLedger.tsx index bd0d85e5f3f4..4e75790e3ebe 100644 --- a/packages/kit/src/views/Onboardingv2/pages/ConnectionFlowLedger.tsx +++ b/packages/kit/src/views/Onboardingv2/pages/ConnectionFlowLedger.tsx @@ -24,7 +24,10 @@ import { convertDeviceError } from '@onekeyhq/shared/src/errors/utils/deviceErro import { ETranslations } from '@onekeyhq/shared/src/locale'; import platformEnv from '@onekeyhq/shared/src/platformEnv'; import { EOnboardingPagesV2 } from '@onekeyhq/shared/src/routes/onboardingv2'; -import { ThirdPartyWalletAvatarImages } from '@onekeyhq/shared/src/utils/avatarUtils'; +import { + ThirdPartyWalletAvatarImages, + getThirdPartyDeviceAvatarImage, +} from '@onekeyhq/shared/src/utils/avatarUtils'; import deviceUtils from '@onekeyhq/shared/src/utils/deviceUtils'; import { EConnectDeviceChannel } from '@onekeyhq/shared/types/connectDevice'; import type { IConnectYourDeviceItem } from '@onekeyhq/shared/types/device'; @@ -223,11 +226,23 @@ export default function LedgerConnectionFlow() { // --- Device list data --- const devicesData = useMemo( () => - searchedDevices.map((item: SearchDevice) => ({ - title: item.name, - src: ThirdPartyWalletAvatarImages.ledger, - device: item, - })), + searchedDevices.map((item: SearchDevice) => { + const vendorFields = item as SearchDevice & { + vendorModel?: string; + vendorModelName?: string; + }; + return { + title: item.name, + src: ThirdPartyWalletAvatarImages.ledger, + device: item, + avatarImg: getThirdPartyDeviceAvatarImage({ + vendor: EHardwareVendor.ledger, + vendorModel: vendorFields.vendorModel, + vendorModelName: vendorFields.vendorModelName, + fallback: 'ledger', + }), + }; + }), [searchedDevices], ); @@ -397,7 +412,10 @@ export default function LedgerConnectionFlow() { }} userSelect="none" > - + ))} diff --git a/packages/kit/src/views/Onboardingv2/pages/ConnectionFlowTrezor.tsx b/packages/kit/src/views/Onboardingv2/pages/ConnectionFlowTrezor.tsx index cad65fdf41f8..f4acb6181db4 100644 --- a/packages/kit/src/views/Onboardingv2/pages/ConnectionFlowTrezor.tsx +++ b/packages/kit/src/views/Onboardingv2/pages/ConnectionFlowTrezor.tsx @@ -24,7 +24,10 @@ import { convertDeviceError } from '@onekeyhq/shared/src/errors/utils/deviceErro import { ETranslations } from '@onekeyhq/shared/src/locale'; import platformEnv from '@onekeyhq/shared/src/platformEnv'; import { EOnboardingPagesV2 } from '@onekeyhq/shared/src/routes/onboardingv2'; -import { ThirdPartyWalletAvatarImages } from '@onekeyhq/shared/src/utils/avatarUtils'; +import { + ThirdPartyWalletAvatarImages, + getThirdPartyDeviceAvatarImage, +} from '@onekeyhq/shared/src/utils/avatarUtils'; import deviceUtils from '@onekeyhq/shared/src/utils/deviceUtils'; import { EConnectDeviceChannel } from '@onekeyhq/shared/types/connectDevice'; import type { IConnectYourDeviceItem } from '@onekeyhq/shared/types/device'; @@ -281,11 +284,23 @@ export default function TrezorConnectionFlow() { // --- Device list data --- const devicesData = useMemo( () => - searchedDevices.map((item: SearchDevice) => ({ - title: item.name, - src: ThirdPartyWalletAvatarImages.trezor, - device: item, - })), + searchedDevices.map((item: SearchDevice) => { + const vendorFields = item as SearchDevice & { + vendorModel?: string; + vendorModelName?: string; + }; + return { + title: item.name, + src: ThirdPartyWalletAvatarImages.trezor, + device: item, + avatarImg: getThirdPartyDeviceAvatarImage({ + vendor: EHardwareVendor.trezor, + vendorModel: vendorFields.vendorModel, + vendorModelName: vendorFields.vendorModelName, + fallback: 'trezor', + }), + }; + }), [searchedDevices], ); @@ -518,7 +533,10 @@ export default function TrezorConnectionFlow() { }} userSelect="none" > - + ))} diff --git a/packages/kit/src/views/Tray/components/PortfolioOverview.tsx b/packages/kit/src/views/Tray/components/PortfolioOverview.tsx index 48eede9b412e..fea592fb4003 100644 --- a/packages/kit/src/views/Tray/components/PortfolioOverview.tsx +++ b/packages/kit/src/views/Tray/components/PortfolioOverview.tsx @@ -1,12 +1,13 @@ import BigNumber from 'bignumber.js'; -import { Image, SizableText, Stack } from '@onekeyhq/components'; +import { Icon, Image, SizableText, Stack } from '@onekeyhq/components'; import type { IDBAccount, IDBIndexedAccount, IDBWallet, } from '@onekeyhq/kit-bg/src/dbs/local/types'; import type { ITrayData } from '@onekeyhq/shared/src/types/desktop/tray'; +import accountUtils from '@onekeyhq/shared/src/utils/accountUtils'; import { AllWalletAvatarImages } from '@onekeyhq/shared/src/utils/avatarUtils'; import type { IAllWalletAvatarImageNamesWithoutDividers } from '@onekeyhq/shared/src/utils/avatarUtils'; import type { INetworkAccount } from '@onekeyhq/shared/types/account'; @@ -42,6 +43,10 @@ export function PortfolioOverview({ wallet.avatarImg as IAllWalletAvatarImageNamesWithoutDividers ] : undefined; + // Mirrors WalletAvatarBase's hidden-wallet branch (bypassed by this direct lookup). + const isHiddenWallet = accountUtils.isHwHiddenWallet({ + wallet: wallet as unknown as IDBWallet, + }); const hasAccountAvatar = Boolean( account.avatar?.address || account.avatar?.indexedAccount || @@ -85,6 +90,9 @@ export function PortfolioOverview({ /> ) : ( (() => { + if (isHiddenWallet) { + return ; + } if (avatarSource) { return ( { @@ -13,3 +21,131 @@ describe('HwWalletAvatarImages', () => { }, ); }); + +describe('ThirdPartyWalletAvatarImages neutral fallback', () => { + // require() resolves to a single mocked value under Jest, so compare the + // actual asset bytes on disk to prove the fallback keys are wired to their + // own neutral artwork, not aliased onto a specific-model asset. + const avatarDir = join(__dirname, '../assets/wallet/avatar'); + const readAvatar = (name: string) => readFileSync(join(avatarDir, name)); + + it('keeps the vendor fallback assets distinct from any specific-model asset', () => { + expect(readAvatar('Trezor.png').equals(readAvatar('TrezorSafe7.png'))).toBe( + false, + ); + expect(readAvatar('Ledger.png').equals(readAvatar('LedgerNanoX.png'))).toBe( + false, + ); + }); +}); + +describe('getThirdPartyDeviceAvatarImage', () => { + it.each([ + ['T1B1', 'TrezorModelOne'], + ['T2T1', 'TrezorModelT'], + ['T2B1', 'TrezorSafe3'], + ['T3B1', 'TrezorSafe3'], + ['T3T1', 'TrezorSafe5'], + ['T3W1', 'TrezorSafe7'], + ])('resolves Trezor model code %s to %s', (vendorModel, expected) => { + expect( + getThirdPartyDeviceAvatarImage({ + vendor: EHardwareVendor.trezor, + vendorModel, + fallback: 'trezor', + }), + ).toBe(expected); + }); + + it.each([ + ['Safe 3', 'TrezorSafe3'], + ['safe 5', 'TrezorSafe5'], + [' Safe 7 ', 'TrezorSafe7'], + ['Trezor Safe 7', 'TrezorSafe7'], + ['Model One', 'TrezorModelOne'], + ['Trezor Model T', 'TrezorModelT'], + ])( + 'resolves Trezor vendorModelName alias "%s" to %s when vendorModel is unavailable', + (vendorModelName, expected) => { + expect( + getThirdPartyDeviceAvatarImage({ + vendor: EHardwareVendor.trezor, + vendorModelName, + fallback: 'trezor', + }), + ).toBe(expected); + }, + ); + + it('prefers vendorModel code over vendorModelName alias', () => { + expect( + getThirdPartyDeviceAvatarImage({ + vendor: EHardwareVendor.trezor, + vendorModel: 'T1B1', + vendorModelName: 'Safe 7', + fallback: 'trezor', + }), + ).toBe('TrezorModelOne'); + }); + + it('does not match a Trezor code against the (lowercased) name-alias table', () => { + // 'safe 7' only exists in the normalized name-alias table; the code + // lookup must stay case-sensitive and must not fall through into it. + expect( + getThirdPartyDeviceAvatarImage({ + vendor: EHardwareVendor.trezor, + vendorModel: 'safe 7', + fallback: 'trezor', + }), + ).toBe('trezor'); + }); + + it('falls back to the Trezor generic avatar for unknown model/name', () => { + expect( + getThirdPartyDeviceAvatarImage({ + vendor: EHardwareVendor.trezor, + vendorModel: 'T9X9', + vendorModelName: 'Unknown Model', + fallback: 'trezor', + }), + ).toBe('trezor'); + }); + + it.each([ + ['nanoS', 'LedgerNanoS'], + ['nanoSP', 'LedgerNanoS'], + ['nanoX', 'LedgerNanoX'], + ['stax', 'LedgerStax'], + ['flex', 'LedgerFlex'], + ['apexp', 'LedgerNanoGen5'], + ])('resolves Ledger model code %s to %s', (vendorModel, expected) => { + expect( + getThirdPartyDeviceAvatarImage({ + vendor: EHardwareVendor.ledger, + vendorModel, + fallback: 'ledger', + }), + ).toBe(expected); + }); + + it('falls back to the Ledger generic avatar for an unknown model code', () => { + expect( + getThirdPartyDeviceAvatarImage({ + vendor: EHardwareVendor.ledger, + vendorModel: 'unknownModel', + fallback: 'ledger', + }), + ).toBe('ledger'); + }); + + it('always returns the fallback for a non-third-party vendor', () => { + expect( + getThirdPartyDeviceAvatarImage({ + vendor: EHardwareVendor.onekey, + vendorModel: 'T3W1', + vendorModelName: 'Safe 7', + fallback: 'trezor', + }), + ).toBe('trezor'); + }); +}); diff --git a/packages/shared/src/utils/avatarUtils.ts b/packages/shared/src/utils/avatarUtils.ts index 0a9a0afbb584..71d0d9698a35 100644 --- a/packages/shared/src/utils/avatarUtils.ts +++ b/packages/shared/src/utils/avatarUtils.ts @@ -1,6 +1,9 @@ import { EDeviceType } from '@onekeyfe/hd-shared'; +import { EHardwareVendor } from '../../types/device'; + import { NEO_DEVICE_TYPE } from './hardwareDeviceTypes'; +import thirdPartyDeviceUtils from './thirdPartyDeviceUtils'; import type { IDeviceType } from '@onekeyfe/hd-core'; import type { ImageSourcePropType } from 'react-native'; @@ -51,18 +54,21 @@ export const OthersWalletAvatarImages = { }; export const ThirdPartyWalletAvatarImages = { + // Neutral vendor fallback for unrecognized/metadata-less devices — kept + // distinct from any specific-model asset so an unknown device never + // presents as a particular physical model. ledger: require('../assets/wallet/avatar/Ledger.png'), trezor: require('../assets/wallet/avatar/Trezor.png'), - 'Safe 3': require('../assets/wallet/avatar/Trezor.png'), - 'Safe 5': require('../assets/wallet/avatar/Trezor.png'), - 'Safe 7': require('../assets/wallet/avatar/Trezor.png'), - 'Trezor Safe 3': require('../assets/wallet/avatar/Trezor.png'), - 'Trezor Safe 5': require('../assets/wallet/avatar/Trezor.png'), - 'Trezor Safe 7': require('../assets/wallet/avatar/Trezor.png'), - 'Model One': require('../assets/wallet/avatar/Trezor.png'), - 'Model T': require('../assets/wallet/avatar/Trezor.png'), - 'Trezor Model One': require('../assets/wallet/avatar/Trezor.png'), - 'Trezor Model T': require('../assets/wallet/avatar/Trezor.png'), + TrezorModelOne: require('../assets/wallet/avatar/TrezorModelOne.png'), + TrezorModelT: require('../assets/wallet/avatar/TrezorModelT.png'), + TrezorSafe3: require('../assets/wallet/avatar/TrezorSafe3.png'), + TrezorSafe5: require('../assets/wallet/avatar/TrezorSafe5.png'), + TrezorSafe7: require('../assets/wallet/avatar/TrezorSafe7.png'), + LedgerNanoS: require('../assets/wallet/avatar/LedgerNanoS.png'), + LedgerNanoX: require('../assets/wallet/avatar/LedgerNanoX.png'), + LedgerStax: require('../assets/wallet/avatar/LedgerStax.png'), + LedgerFlex: require('../assets/wallet/avatar/LedgerFlex.png'), + LedgerNanoGen5: require('../assets/wallet/avatar/LedgerNanoGen5.png'), }; export const AllWalletAvatarImages = { @@ -101,3 +107,72 @@ export function getDeviceAvatarImage( } return deviceType; } + +const TREZOR_MODEL_CODE_TO_AVATAR_KEY = new Map< + string, + IThirdPartyWalletAvatarImageNames +>([ + ['T1B1', 'TrezorModelOne'], + ['T2T1', 'TrezorModelT'], + ['T2B1', 'TrezorSafe3'], + ['T3B1', 'TrezorSafe3'], + ['T3T1', 'TrezorSafe5'], + ['T3W1', 'TrezorSafe7'], +]); + +// Fallback when vendorModel is unavailable; Ledger never needs this since its +// vendorModel is always the DMK code, never a human string. +const TREZOR_MODEL_NAME_ALIAS_TO_AVATAR_KEY = new Map< + string, + IThirdPartyWalletAvatarImageNames +>([ + ['model one', 'TrezorModelOne'], + ['model t', 'TrezorModelT'], + ['safe 3', 'TrezorSafe3'], + ['safe 5', 'TrezorSafe5'], + ['safe 7', 'TrezorSafe7'], +]); + +const LEDGER_MODEL_CODE_TO_AVATAR_KEY = new Map< + string, + IThirdPartyWalletAvatarImageNames +>([ + ['nanoS', 'LedgerNanoS'], + ['nanoSP', 'LedgerNanoS'], + ['nanoX', 'LedgerNanoX'], + ['stax', 'LedgerStax'], + ['flex', 'LedgerFlex'], + ['apexp', 'LedgerNanoGen5'], +]); + +export function getThirdPartyDeviceAvatarImage({ + vendor, + vendorModel, + vendorModelName, + fallback, +}: { + vendor: EHardwareVendor; + vendorModel?: string; + vendorModelName?: string; + fallback: IThirdPartyWalletAvatarImageNames; +}): IThirdPartyWalletAvatarImageNames { + if (vendor === EHardwareVendor.trezor) { + // Exact-case lookup — normalizing this branch stops 'T3W1' from matching. + const byCode = + vendorModel && TREZOR_MODEL_CODE_TO_AVATAR_KEY.get(vendorModel); + if (byCode) return byCode; + const normalizedName = thirdPartyDeviceUtils + .normalizeThirdPartyModelName(vendorModelName) + .replace(/^trezor /, ''); + const byName = TREZOR_MODEL_NAME_ALIAS_TO_AVATAR_KEY.get(normalizedName); + if (byName) return byName; + return fallback; + } + if (vendor === EHardwareVendor.ledger) { + const byCode = + vendorModel && LEDGER_MODEL_CODE_TO_AVATAR_KEY.get(vendorModel); + if (byCode) return byCode; + return fallback; + } + return fallback; +} diff --git a/packages/shared/src/utils/thirdPartyDeviceUtils.ts b/packages/shared/src/utils/thirdPartyDeviceUtils.ts index 8f60f48a08a8..e1d328276c30 100644 --- a/packages/shared/src/utils/thirdPartyDeviceUtils.ts +++ b/packages/shared/src/utils/thirdPartyDeviceUtils.ts @@ -66,9 +66,14 @@ const TREZOR_BLE_SUPPORTED_MODEL_NAMES = [ 'trezor safe 7', ] as const; +function normalizeThirdPartyModelName(model?: string): string { + if (!model) return ''; + return model.trim().replace(/\s+/g, ' ').toLowerCase(); +} + function isTrezorBleSupportedModel(model?: string): boolean { - if (!model) return false; - const normalizedModel = model.trim().replace(/\s+/g, ' ').toLowerCase(); + const normalizedModel = normalizeThirdPartyModelName(model); + if (!normalizedModel) return false; return (TREZOR_BLE_SUPPORTED_MODEL_NAMES as readonly string[]).includes( normalizedModel, ); @@ -359,4 +364,5 @@ export default { isTrezorBleBindingSupportedPlatform, isTrezorBleSupportedDevice, isTrezorBleSupportedModel, + normalizeThirdPartyModelName, }; diff --git a/packages/shared/types/device.ts b/packages/shared/types/device.ts index 34485a16a987..fa90826e9095 100644 --- a/packages/shared/types/device.ts +++ b/packages/shared/types/device.ts @@ -4,6 +4,7 @@ import type { } from '@onekeyhq/kit-bg/src/dbs/local/types'; import type { ILocaleSymbol } from '@onekeyhq/shared/src/locale'; +import type { IThirdPartyWalletAvatarImageNames } from '../src/utils/avatarUtils'; import type { BleReleaseInfoPayload, CommonParams, @@ -496,6 +497,8 @@ export interface IConnectYourDeviceItem { opacity?: number; device: SearchDevice | KnownDevice | undefined; vendor?: EHardwareVendor; + // Resolved per-model avatar key for third-party (Ledger/Trezor) scan rows. + avatarImg?: IThirdPartyWalletAvatarImageNames; } export interface IFirmwareVerifyResult {