From 4753d0e448b2e804b40547f22552f3df99c23b0f Mon Sep 17 00:00:00 2001 From: ByteZhang Date: Mon, 17 Aug 2026 22:53:44 +0800 Subject: [PATCH 1/3] fix: resolve third-party hardware wallet avatars per device model Ledger and Trezor wallets all shared one generic placeholder image regardless of physical model. Add a resolver that maps the device's persisted vendorModel (SDK code) / vendorModelName to a per-model avatar key, fix refillWalletInfo (which ran on every wallet read) to stop forcing avatars back to the generic vendor key, and wire the resolver through onboarding scan lists, BLE binding, and the Tray. --- development/spellCheckerSkipWords.txt | 1 + .../src/dbs/local/LocalDbBase.trezor.test.ts | 32 ----- packages/kit-bg/src/dbs/local/LocalDbBase.ts | 54 ++++---- .../Hardware/TrezorBleBindingDialog.tsx | 9 +- .../Hardware/trezorBleBindingUtils.ts | 2 + .../stories/ThirdPartyHardwareActions.tsx | 76 +++++++---- .../pages/ConnectionFlowLedger.tsx | 32 +++-- .../pages/ConnectionFlowTrezor.tsx | 32 +++-- .../Tray/components/PortfolioOverview.tsx | 11 +- .../src/assets/wallet/avatar/Ledger.png | Bin 3001 -> 0 bytes .../src/assets/wallet/avatar/LedgerFlex.png | Bin 0 -> 3957 bytes .../assets/wallet/avatar/LedgerNanoGen5.png | Bin 0 -> 3611 bytes .../src/assets/wallet/avatar/LedgerNanoS.png | Bin 0 -> 5089 bytes .../src/assets/wallet/avatar/LedgerNanoX.png | Bin 0 -> 4279 bytes .../src/assets/wallet/avatar/LedgerStax.png | Bin 0 -> 1454 bytes .../src/assets/wallet/avatar/Trezor.png | Bin 728 -> 0 bytes .../assets/wallet/avatar/TrezorModelOne.png | Bin 0 -> 2753 bytes .../src/assets/wallet/avatar/TrezorModelT.png | Bin 0 -> 4961 bytes .../src/assets/wallet/avatar/TrezorSafe3.png | Bin 0 -> 3052 bytes .../src/assets/wallet/avatar/TrezorSafe5.png | Bin 0 -> 4663 bytes .../src/assets/wallet/avatar/TrezorSafe7.png | Bin 0 -> 5594 bytes packages/shared/src/utils/avatarUtils.test.ts | 118 +++++++++++++++++- packages/shared/src/utils/avatarUtils.ts | 99 +++++++++++++-- .../shared/src/utils/thirdPartyDeviceUtils.ts | 10 +- packages/shared/types/device.ts | 3 + 25 files changed, 369 insertions(+), 110 deletions(-) delete mode 100644 packages/shared/src/assets/wallet/avatar/Ledger.png create mode 100644 packages/shared/src/assets/wallet/avatar/LedgerFlex.png create mode 100644 packages/shared/src/assets/wallet/avatar/LedgerNanoGen5.png create mode 100644 packages/shared/src/assets/wallet/avatar/LedgerNanoS.png create mode 100644 packages/shared/src/assets/wallet/avatar/LedgerNanoX.png create mode 100644 packages/shared/src/assets/wallet/avatar/LedgerStax.png delete mode 100644 packages/shared/src/assets/wallet/avatar/Trezor.png create mode 100644 packages/shared/src/assets/wallet/avatar/TrezorModelOne.png create mode 100644 packages/shared/src/assets/wallet/avatar/TrezorModelT.png create mode 100644 packages/shared/src/assets/wallet/avatar/TrezorSafe3.png create mode 100644 packages/shared/src/assets/wallet/avatar/TrezorSafe5.png create mode 100644 packages/shared/src/assets/wallet/avatar/TrezorSafe7.png 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..9c90efa90ada 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,18 @@ 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) { + // Third-party vendor: resolve the per-model avatar from persisted + // settings (device.settings is always populated by + // refillDeviceInfo, parseDeviceSettingsRaw is 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 +6131,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 +155,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 +180,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..81afa98ed75b 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,11 @@ export function PortfolioOverview({ wallet.avatarImg as IAllWalletAvatarImageNamesWithoutDividers ] : undefined; + // Mirrors WalletAvatarBase's hidden-wallet branch, which this direct + // AllWalletAvatarImages lookup bypasses. + const isHiddenWallet = accountUtils.isHwHiddenWallet({ + wallet: wallet as unknown as IDBWallet, + }); const hasAccountAvatar = Boolean( account.avatar?.address || account.avatar?.indexedAccount || @@ -85,6 +91,9 @@ export function PortfolioOverview({ /> ) : ( (() => { + if (isHiddenWallet) { + return ; + } if (avatarSource) { return ( ;3RN|L1=8`~L8|{+So;&WQ=j3G?vqh@q{_9k?3v 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 P00000NkvXXu0mjfKI{2* literal 0 HcmV?d00001 diff --git a/packages/shared/src/assets/wallet/avatar/LedgerNanoGen5.png b/packages/shared/src/assets/wallet/avatar/LedgerNanoGen5.png new file mode 100644 index 0000000000000000000000000000000000000000..9cc05e97b0540850533dad1a015630b5b4f25650 GIT binary patch literal 3611 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 literal 0 HcmV?d00001 diff --git a/packages/shared/src/assets/wallet/avatar/LedgerNanoS.png b/packages/shared/src/assets/wallet/avatar/LedgerNanoS.png new file mode 100644 index 0000000000000000000000000000000000000000..82fff19c3644bbbb93efa78ca48646e9f6ed1157 GIT binary patch literal 5089 zcmV<76CUh|P)Jw39rvOPULc6fG*jf#edhM%FITU=U$go3!axo2r-nVy)8kc^j`mVJPIVPRph zv9Y0|p;J>+pP-+Sm64*NqA@Wshm3}KeR+a~f;c!grm3d3x3)@3N=HXWo1L1Dj*dr1 zN1C0PIXOA8vawE3PKl3*q@<*^wzaadvRhkQw6?aeu&|@1qgz{BeSdsmVPQNxJUBQw zTU%RBPEM$(s2v?08yg!M8XBLao*Wz;Gcz-ootK@XoF5+_nxL7Sp_`tgos^lAo}`_U zmyuXlSXWn9o1vPVqMMbPl#`i~g@uKGgMgi)oRF1|eSm#?e|tDMIGLZAmYkK6l9GUh zfmK#jkCcvqgn)p6fPR5~j+2c#J3B2cEup8Oj*g9tk&A*M3vxtx_@TuuG;^6u;D z=;7Sh(ZRX6gZ%sU+}qpD%*DRFu9lXAeR30N!E^us5I#vnK~!ko?AKY03vnC=@O9t! zE$;jFAjB0%LXaSM@L)>U*_4Ei9&~g%?WQ~1YNxFpYq6t>9=mL-Xjy_%rOrCHrBtX} zTyZ75_|3FR!c*&b@!jt3<7dCW|G&S^7W~iu{LlaV<1}pDtb4a^-CGp=owV-OzyJKc z(`!#uDDfI>jezN^=aoNT!t5hl(Sbi2N*ZB=> z<9-j;?7!D!!~UBiI{X9!dyQ2g051d>uN3?ixW&i^l%jO!3ytlQvPp;U@X4a`BXFy( zU4vVdg*oaya+vk+fIH27f|r!IUwAwkNsXpWqbz*g&!CVj%#M1`mEQyRnEgy#a!dU2 zr0bKU=HkV&_F4E|VK!-4$u{1`HWuUy51#y53~-59CXsktE{|<^^KbCxG@7lPX}pPX z^M=O`TTxOXE`e`)kIUflcxqm>&BD8WfL|0|I|AE8iKsW76&$)Mm*xkL9=7}h)Ats% zUM+EX0Iu1PxnH#b*4S(pFPfGj2qztr8d0C9*mPmDLzNf2pzd3ds6>2Ad3^6 zJ33XpT-iqb>h2IhVfbQTF+qqFXAEp!v`@qOT?mqfZ5h~;fv*6Z^SY|*784~fXb};C z^CiS0LiF}i%;0jFTthlC@EN^61N%1|W!;4rj{{r*uqs!$)10~=MIyopb&02OkrNdI zj5_wj3?`SsV5`Hz5=my%+=b}?Y&u?9v9~H`xW}xz4uT!9$ob~w%SVJr1ceD=#X*+~ zVAqDx46Kx}jRDNU2TcdhI`&q}RpxrRt*iGm0@5>Avv?aS}ETrq(XR#$tfE1~fwb0`P6QQarB6ZcZ!MhP)ah+y6XilG?%z%Of<#<5F7JEdVx z2KH?Gupi(mPqo0YS-m+Vt(8OLNnU5fiQ_1tisNDw6T6`9oPuM5 z$#||ymtuGC8ZKmE&EqHB&GHkkS@=Rl$gF}V>s&@%Fo-6d6z#gr!e;R-D630*& zw4L^mfd{u@;67BA{sO)Y@NSTEgCT8c3WsAxofsZTrBb*S#c0e6jeWjg;FbRpR8}6U zJ_s-)XFrl_PT6idcJJN|m2-rf5A{ZzC`x(p2%ZYO2`IF7=o=&h0iVyhW%b=l(3pjh zJ-v>bmKGrkIS9bEotjhmz>xM-l*CDziePjgg}+S1gK)lN(B}*IES6VQ082`%tKp&N z-11%eo7&ZnxM%59Iw@4u^5fUS7+`%%)sZbaEgiw z5$1#eKA_o|9}MXojYM&p!bsZtD3N>_PmuxEEiN_|^Iydts!K0a0lcB=+nr|MeVU!@ ztq$b@4}wpqNW@OU-tf8=NyTNYj~O$tko)*IxN_5v@Oh>&TIbFP7FHMr9-A$-gzD2>OOEd#~w?#T+If}0YUz7iwUIHN=9LAkUm*F`Sf(kXmq=a!^H}rLbm4l zxl@OiE=3N>uW`?x=W@22%h<*Tn8s$6s%b$UX%+F3(Lgj9^#v?RU&12fD->b(4w+l% zcFXQBKg_@<-*OS@TMnn}7>9-T{SLTs=V+9U(m|`w=ezv0n3qfx3or9d3xzwvYlJ)Q zv+&+STyA=0v+&V<0%-^)tphlZ40HrxJHyN9GrrM&c^TKrHYQFB!+bvfbojZo%Cr<{ zP`|~tih;q+4~EpS2CTjy+-9p$mVBB>YQt+1%lN1Hyw!Z(`WqY4F!CK z4pHAnt1n=Lm8DQ9l9$7>(~sWq`D=EpS-qaOWc9KDW1WH^6zNZNU1` z$L>jsBKe3flkIr(PAlZ`R-azO)806~)MNr!twE5R<=wRswZy%tEAKg{w@=>p+y0z$`oW%r<-F_x%LmV?JgFD;4TZ@Rprpxvn&sOS>2HYjUuV%w`ctc-r_&7f63}Y znfU7M;P`Je+4s{Xx z^%*a-Zq8bWbSOu09EviN_kWY!8Xt8X?~kwE=>eE%10`0~MZA30?JJVf;76b=ilPNY zD2|^~BL4xtwmJ0z+jidh(RKa#XK%9_W$HUbKTn>*mW`<_X^wsl4f-{NFuZpRz!=TMFE+# zX471rDf)hcQvhCaGVB?cXe-IO&cZBFnq!Hyf)s=>;t<0jgdX!o32pdir%vuXzvNyx z?HRZOI1cHOM(MPrDKu;jgc-ncS1@LTV%?vX0UX!`j=cjD%^U{?SSKl(7DUV_2*l+% z#DQhyIV$y+3l0Z%T|F63cn5CSzcflPOco_73SyWN8b0%g=89><1sg7S$vscOL?hCI zHBG~kwlJn`%-9H-SMqiqYAv8gl|Q2npNFKq1j82591JGw8+8M zLV&Xs6WO*2ScT)BvXwu;Fic*9TZRNnu_yr}Y=cwm7MS5o+k&t~u2^CC{oBsOm$*qE z@)S(8)hM_}qJ;&-fmg&_G4q_w*fvL7w2Af`#0F1R(}shYtRaO%rArBOAP9OL(+-|F%2nd)|XVJt&$f9S9RC7@NqXMg;Pgd z@U@Dl_uvjNOqjziS3!?&L<)r?v5SS%2Tt?u)96M;Bn(McJoFw+G-Hq`+R(^K{>76> z-9qltffM^rM~}{@NG-(ik$3`JBxvh@rW#3-IYkCGTG?O?$Zi> zS(lT~Ke{D8?avG#%Aj$A`{=?q&g~8a!j-;EVfVH6?RHn5mH4x!?v^-fq=pk^P)k9C zbHvRBh12*lku$E;83dV3>^5naM<1)QpDv zn17PES?$ZKl0KY{(fnC;(eucmiieQ2uPIRu!C{8gOg}=Y#G5bQK7aoFDzfMJIX<}K z938#3y8ua_?oO0PJv2eH>?bRH72&r}zC4L!_KcUI{aPv&z)Vnvphc=#*Hj+e1$1(f*kk zhf&w?iLpevH1$$W*IAvFSXSnF^=vS>XxY0H2M)s!12@)otTeKjGkcC4*;Ah=o4U^4uxGs_!JdSL1%~HlbFr0&js0it9KLgA2vI)O8oP4U z%j2rd%Ivx1x#h<%=5j|48@_Bd`*8P^+C&*uXZq-svlkfeZqHkht^k{d4;#nR;d@tm zckWJNdP)l#;!_y+cDoj*^aifqy$YJ3T!;lb4f^l8>OE zpplf2x4O8Po0dR8K&-Ev zrk|dro}HtdQc+T+t)-8ZkEX7slbMn{JUp14mx+yuB_}1JsG*#qn}>^shl+ zlZ}&&golKdoRyQ9k)x`kiHwP%rlE_Gi%w2Xo1&YVpP5xwRg961qpPHxqnwhLkuEPT zmz|b_g@THWiiwYjS65e{sGy3Ei#IqoVPat^D=DY1sEdz@Q&dwdEGw6smW+~%qN<~V zhl5a1P$(%Umz|f5kBnGZSV~MvLPJ8Yv8arYjI*}0UtnKbU0bQKsjIA{A0QsZ%EYv^ ztEQ-+$j->Rz`3cZqJV>cdwhF!cXdWbM!?3vxw){ev#zbKrK6~#kd=^-l8&RKopEw; zV`gL<92>yFz?Ybnl$DfiZ*AV;-PYUH(A3bpytA2_nQ3ciFf%WvsHFh`0RR91tgWn` zpq@KEI}i{M2nYx{JUHv15dZ)H08n&NPE!Dof`|u<99d~E{(ch<>E@S-NJ9R)m3(?b z^yJ^p#kZ(vUQ_w+$u@^O_!C7mX_N30 z0(mvkqfi!TCoi%h_7XFNHcEsLHVbW05ZqQ7Yll>KnH4twBA>TO*WuV@NpJm9N^|<~ zJn!2uojP^uMCi(Uz04$9)xqtD$ggxncyx@Qsw;fc{gg%FGl+rTjLT-wxR*tSy)H(~t%oDtz} zC49ksKu71IwfFj`0h8;{HK zR=5dsds&w|3m>BH(G{f{$*n+>48^D|g^L*^c zaMyUPP^Ig&5ghO4=GP^7z)CgUm^d!4&bn~aV!bTggGFDrdieWJ5-BN+Y=Q}1!qsmW zrBG5SlmLdZ4*`xsrp~#p$++-0mIqqrlZB-cDLYpAMig` z%dfXdC=BBl{x@D|^ul=IrN&R;S3u{K+QFGfmY69)PAwD$Ibtda>%icj&Mqz2HHfcCc_DnXqiSbjvq#@PZ!2w%|1%NpufSXuG3zRV45g?YeJ#b zz)%oPBZ4u)H#g%U^6c4IX#fmL?|A14XQDcaQDiA<2mZ)1LI{2y-k2>E;*{?Wf!3pyg#+Zu!+tdlkSKdsgUu zeq8`=?3milajIE;$RQ3vgr*gLwb7|Ym_Wj=iOu;RzpwH|01uKEz;P+X$OP>^rZ@_X z5mHF794*^~D4sXtdY-WU6GBeFaO8>OCjd_S267NWbr59ht+sr>8F|Qcv1w`6kyQYX z0Qe6TlsLXKeI5)Cr2_9G$dSP?CUh|jR-&qBx+n~n7;*hB)EdA&onJ`6PXL^*)u2+UiuX8ETB6G0dm+ZzBZ& zZz&mFaMZmekw(W!oH2YHHE6aPO~$h{K@b?BP9Wn1+vmpMKig?XI`AGJGR9az*p)ji zGYB=Pmc`h7`Sbnlz|-l$ppy;;(;jx6na+yQ@GXYXV$XJcab$Q~Fbt5i;JuE69qf9p zsWn>BQUqL{5e$*f*9+7Z_uNHlcK^oIa1RXKx}FjYtHSp^7h@AUD-E^{DGNMrtD>R5 z`7qfBPk;PGEiS(LGMt%X&{0QVEY}S!L|)`sDYseZlczq;Q!kZ!vEwtn zj8lVQRhSl7Ha#W`YEfPUFfSSg%c?JC@An<=pQ6_2)$cJlBgdda7{DP+4O0vlKIj^} z!5S4-uU+Gw^}x_8>im?yFx(%RNvl(>3eUAHxJDW?u6Lu(xLpiXU9ai2`rN~TRs;BI zyqy4?S_d^V6hhBr7`xpJnoZki>nvN5q_=k8a-Z7=XOJ;ypJmO!lr#kau2Q#Qs74fU z5?A4*`p?Nh$G5L$Q!dac7*_p5L83v-yR3`hJO`Uj4Y09Ca38(D86a5H#K{8>%RZ zdb6X$QRgq@^GEO)^=WEo?$rcEEq>nu12-G+9*Y+Qo-x{n2s4X?YH?h?n9Jpg&nG9> z?ooFxKk0?scbo|rbQ1i+s0>zAQLnI-xLEmeF?Zq8iP&R>SG#7`@-z^I;R@mcD((xYxZsV5J6?!_-U%YqQai@j$V6i{)6{Arw#JY) zm831ySZ(d178S&zptvClDz2y~xcndAxc`8}D_=^#uUAjb%zNe>&ZKrSSIeF3!P8uU ztHRNQm=qCfudY2!{?ea3jto3$JxXEmWU;{w`5sUBDr3T2vMf2bUL8tae0w*UtlT@C z{0%;irH)3^!c5{gi?D@8ftV)iVuuCBF-C8mq*6}~C6g~^UQhmsI5P0KwI@#&ts$I6 zs>CFWt1>bbs3F<6o}6pleS!nzEsn3K!O&Dx;9{du;D2##nZFk_%FNm4K{bj{Wg^R-t`Q^^<4um1#xWicHkc!J4R zDdSUk%fVU;12OQtc3ac**Ohwm$<@s7h(R6`#?IAUl;)kVP6VN~030^6`fO>FC+>#tkCz!$?kjv72}4azWMGKOHt zN?=Q(q3htbN9_mAy{Xv1&{Wm+eOXmxN071B$R-IvBbD2)-`9VFFMjVbBL+`gO;qCh zRFL5!9Ke)5^$BA75IO22)wMbPIsydFK7`9*|kpT@e+0);g1NS#L9W{6c zc_a#>XtoFI^;(9~es196~f;^@}V)Gsg; zIe0uvd8~FIIEEkzlI=-a=q|YX!IPu$fuRMIDkkI0@Rv+&Q4+<0K0q={=z&r@!#$1( zJOSR46_*OWfrtY`k~IB$I(s+YT|&fHF78i5k%LhxRLa0!iW~%jXWIhE0}*kHBlJK3 zcg>sQ7Ty1^(n$OWmU3D z{UgUpX4v984~Ngv-@#bwIJC(1S-(n&$|wTIGp=e1`6~YRrJH+NmHmg)>CA>i9GVff zxdnyzip&v)xQwgN1|uWAZ{Mq548e!*ZBE3YS=NxS2$*HE$Y>VN!Dpml3vS)7 z><9Pol?91dGy&6FQs76&K=e%lJohkL0RO=$EH%h6fl(?N4XeoM$9R5-2Vi+(+1YBr z8s5GPFmz>pA|B1odjq0#riG2+GtlJl{)Nt38g^74Hc|8Z9+HY8xZQ@h2 zSUBCv-~Jkc4`(Wi5;18S247she==X-4-`3!gg9K0^zskSh2Tu)`iew6!T^fHbW^>< zVSruBW4PMS=T8>ZI{<^5c{e=~m!=j^;_556k2?@fv1{4z8Z0MVtXK9Q{rq|7hWOt4 zome`M&(%(rF68pLVyT=vP|MX0sL%FP_J8^C@!9f3Y#RF#7Y4X!%;R04V;3+=ujR6Z z%gb)E_?{j1#=8dl^?!oldD=>Xggnez|=0Sv>^TZyY@gaBN!F?Vj4#Ig)Lj>GaE; z^1eHtz)iKT?9V`B67gwvz1zKd?^wChY&Ofy=F{%c6qKo4y?^E6sW@L{pS*m^x-IEb zFYoLtcXq$KiWx3+{Os8$TeofBl!#knCr_TVYSqe>^XAQ4x^&5s#S=Eo7?=33|N5_g Zu5Vw@+k@>?sjdJ3002ovPDHLkV1gltEK~ph literal 0 HcmV?d00001 diff --git a/packages/shared/src/assets/wallet/avatar/LedgerStax.png b/packages/shared/src/assets/wallet/avatar/LedgerStax.png new file mode 100644 index 0000000000000000000000000000000000000000..372b286117e28dcdcf1547bdd96c21f489f1f256 GIT binary patch literal 1454 zcmV;f1yTBmP)FMcgZE4KR%4=+A;o;!q<>AT6$g;7o zMn*$vYG&i(;Vv#KSXfk3Q&O+5t%iq#ii(Hp>+8F_x}~M1Ute0Zw6a@USHi-=o}QlF z-QCsI)z8n*o12=Im6h4q*`cAK<>upLWMSy&=BcTvb8~V`Oi490GLDaqeSLkb5dL)l z000woQchC<4=^xxG-GuyF}hAgJq(TVZ6Nmqc9l2ara)Y zy#fVROKDiT7TZKjxb1>lzyD|2KwHuasx;KK_CHgLGmgK>V^Vp+(V;_!cGB7R@1J<@ zpVH}@ZQOQvb$|csk=;-0Py70%Hhelrteb^yv#u7q<=teBvMkHGIjJq5JHBI@PM(?P zm^_=6zngYZ_FewNL26l}le+M`%i-mpX^PVA-rcc_yY93**5s#{YUY_Z~2hGy<8MOqVBt!KBbZ}nGP9|ok|zIgK- zu%5w!Mvc;xRKQRd1rHfKO;a?@>r;B=mcr5aS{4I;UV>2{n|)Xclk~w810P@hT!7tC z_|P^=Vb#W}piwWuniqziR0;#n0AgXjyOe2C3BL@V*F8=-%;WHeX7IqcJW$s*x#hy#Sp7zZI;f^AIfkOo2QgcxEP zV7VBz05}X26UB%+*s+&J?IgNwIwo>_8)63`1Vq6+{&`)ovBmz48CoQ5XlwZA9IPp` zN}&0+Jx*(3sd@O_c5tWj;^1QjbN8t*Y_~$2S$n+Rb<6Y(%MaX{g996MuY-HPFWP$!HVfCD?QX%PD~u$6g~uNWdn1;US$Bxy5F zSqICLuYzHg!VXhW0k0JR@9ob@<1AGJ8xi;-LoPwt5tffF?b<*+Y<0v0=JIf#i=1{*rk-DY4gCRz#0 zELGOQ3>7@;h$`%=1kS*wU;regfGc;j*ikcbw=loaD*_DP!8tZfZ4!Wxtr-zt28%E> zfDa-UsIp-gsw@hQO*}|2hCz%6IB|oq&fXHhGl&lfgl>eO4|OQ)IK?5Rc5DZfVCs*h z7&##vM1bdeI%H(z6X@&E7krL2jg42*$;7hPZz>PCkt&OaSp`$Jo7IM3sSM~DaP z-VFTN`>CyiXT%sK!73n3y4rJ+%pVSP4heM1iXos7SbS)T$kZNR}Ib&%F#@ zVR?pXs5vSaJ|@*LOKk)`H>%;qF$>+*+rXqLSltk{*t55y;9ifzhM}qzFTZV#PHMwL z_CWRWbJWJ8BI(Gwe_Ini4N*8)==z$ysv5AyW^Z)<=07*qo IM6N<$f=BGaM*si- literal 0 HcmV?d00001 diff --git a/packages/shared/src/assets/wallet/avatar/Trezor.png b/packages/shared/src/assets/wallet/avatar/Trezor.png deleted file mode 100644 index 1874c679fbc54f0d7bc1dc9800ca3077a3e89ba6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 728 zcmV;}0w?{6P)pF z%F4>Z!osDcrJbFfnVFeeTU%38Q#Lj>^78W3)YQer#l5|~uCA`2prDM5jC*@~Y;0^# zPftfjM>8`sBqSstARxxZ#%XD3V`F0`CMMWGKH2~P00DGTPE!Ct=GbNc00GQNL_t(& z-tF0GPr^VD24Hqq%dy*9df0L!AR?&T;`#somPi;&VQYjA7?OEEwbNvtq}?XlX(p3l zM-2f45J12g0+!J>%|}DRIW8b=$MyL#e%T2WI#9WL;T!qvS-3zj;9GHvm_Xg0^`~{& zyTSsB@wy31i-02nSH^c90T>#w*Z{Owrw<1J?_w3cj)?d*ZZz#@9^$@8+*esF)q8=x@#?=Zi1jo- z%FeDdl581S3k6329KM^ySgEnAx!@cCRBF0T<))_S+G;NVB7+70LrO#I;LljufyI&( z(Kl00TZ$irU)nougrQ(|>T_+pMhj_f+L{zJ?Q;g=X!)V%Zmp(X1$p{zbq7)VuzQUE z2htALV>DYaWB_tI7ord2UR(guslw4&{=*@FF#-r6fH4A24}1ahK0!PBoiK|40000< KMNUMnLSTZ4tVhxS diff --git a/packages/shared/src/assets/wallet/avatar/TrezorModelOne.png b/packages/shared/src/assets/wallet/avatar/TrezorModelOne.png new file mode 100644 index 0000000000000000000000000000000000000000..d898d0201d56fe1366f2d703b966a921fa4059f3 GIT binary patch literal 2753 zcmXX|c|6nqA0Klw$8v@_=NyLG9CMT-k*t|3bLCu)MsrloxhhvBQqn=1sF6(4H#U;w zD%vDR&U8>ig=+Tu=<$0$9`D!t^?JUaulM`;e1HD=oWmYI01?|Q1_FT~2VER-z?!l% zMZiFmY=1EW0`Zk#58<7F(#FOHh-zwT8X6if7)()7QTg9cQc{wYmDSVJ)6&w?*VmVq zm)F+ThQr|w4h|+JCI$uu3JMCiBRC%)AD|b3Ko}YtT3cHqkw`v1J|2(f?d|R7=jY|+ zWo~Yc#bVKDGzx{Xw6rucGXvUp?b_w&=!n5!08mg+5C9<%2*3fvY;A45>U#x+LStfL z2n2$&v$LCVS*r z=x8dH3g`!10AxTdkw_$y$$&^eVMa#A+S(d}!AMI>15N{O2kvTaZca){I(zo4n3x!F z0)S&Zus{o74R{$>SJ#gpKbDr3hKGj(WWY5Jhf7XQR#jDvjEwZgdwY6%QYaJvX=`iq z_xA^I7Z(>mJYW;hucM=5Yinz7Zx7J+?b`=P_3-e(Gzk!@>P4-uJXLSMA>3 zSYLiayHk158Q57*L+LrO$D8WZ-?WA6E{ zjj8_8Q3sc1O*?e$;XdaR|LtM5BPu-u!wzy_{X^|EwyTqNv9HQ#?`7QAG_S9ou+|&0 z;c`!>E!Cl6+VK2wR>^xR-^955Z@wN;7x|()CPN3XiLg3<73>d35oWwp)G5nzadkQa z9m0;Xk8Znz88X+9ti?};FNdrPYJM!9%6 z^Y!2V>{9nEFFo*o#`BXhT2lD!Pm&;gZjIId`-UFDQaUr+|LGi&x9FC%k9OH; z#PH?p*CoMJX8ogwc(KiP`gPkMTIOd+FKx?Y@7^g`FGKNOHyM5L7u$rdL&tk@jJ4CZ zq}sOBn$Eb!sSamsUb(|LLM>w3qHT-u93S$g?voSByvcOlkCzsoY(xwDDPL-1g2q3T zFD5*hNnl3lW@W4&L)#qZ4*~U>SGo^GMC0DEyIwvIKSg{m{aD>57*dTMnqyw6Nzc@2 zjnMgo`rY$KPr5vJ8J4tgA{A<~-mhqb!Md*Y2BI4@4vxrNI^Q>b*=gYOi%#j^)q1bI zjw*c1Q$H%X51FVVk~)+9Q^NasDON98<2ptNTjV0+16Kp{T&E1y}PrdR?6@16sI1trKQRMm) zr3Q*YBCRbNpKlgDbGK5UbT%CS1HV7X24#49?V33@H5SsHvLL=>+1MpKzdFkeq7z#i zW@c5+QZw;gyVZOV-QtzfooepEanZSD0U~-2t1N3;#6EHw;vP55c*Kka4Zhf)wFq&O zYof?hpB*u%IBq57E6Zn$e%S-P9|Zk&*Cl`?EPiG)${nmgMdtZY)KVDLW!;{=ekt?i zBPVH9bhJ2Cyca_0L6A;X+%u5!wK|_2$w{?^WRx_X9!g-fZ`h!HpB|BR=H*N}O$OgL zez51>o6Xm&LhKR3bZ^XZ9AV>;^>pG~OwW0A27Yt_tOobYgd6$2ZC=D$81?w4)Rusg zi2g#ftuipetr_uQ-_m%@G`!ER&j7ANFKuJkhasCDW7i4i6+$k|4vG#nz8Bae%<1&; zCLU!>w`3uU=gU*`W09M?5tc;ih+Q-OO)lJ_;=(P1a{_K=dvTSfS_NK-rl;n)Qzti` zOM0`igzq_Yy3Xl=Z(@=orA32(@TY6>KSGC%jbE=#d!5G5(e1yN^CkY2X_)P@+U3H< z8SRYq>0iYYL7%hS2B$k(8|Cb_zH4<3_3JV`MN?ik&?PUn=C+cPzRip~Mby{N74;f% z@OR9RFf)Taz2s9zx*NWxSB1Y&G$~op_xZ9+5TemXgyk0Bfl!H^2_z?EU%hm8vcUIi zWM4^9nrmsqEyIPyhd7U8Bo~4(O5U5O43nsx)$7vjQV<_DK9pDAj5BaI2e&8vk=P^% zywLiE7%*c#9quliNw1gA6ABp1?CstLaU4OYh{>-f!w+5=ruWr760lP&N_bmy>8j<^ z3lzw7+imkd=SW)>wX|jKS1ydl{oT|X&f|M_I=jY5phn^n|D9BQTWM8dMqAU!-)19NNx(&jP&2x zOITg-;wV>$)Yoq9#{^gAvsOaYS-+%^nu_$9aCP<~J$njgeKGX<;@m`uJ>Em`n0nu@I_=>Yvb<*e+xq_AB;VFp5k-cZ*@l^* z<;X@BY4ocIa?-f)M#yp#IoYb%8axrm=s#zH3E1O*{iN0caVEZ{Lt>#ac~*vb`RN01 zrha?=0H>}hh+`3GCsz6w0qqe!t|sG7>H@nx?!qnAOjfFl9z=9>4{o`xsf3{ob^CNI zyw(#(t}1L51s=*SrE6MzA1YwmQAYRrjRb_561=_rvLx| literal 0 HcmV?d00001 diff --git a/packages/shared/src/assets/wallet/avatar/TrezorModelT.png b/packages/shared/src/assets/wallet/avatar/TrezorModelT.png new file mode 100644 index 0000000000000000000000000000000000000000..755391b12982273bd94d75e8b21036298da033df GIT binary patch literal 4961 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 f&slFwMM7_w%` z*rl;#S0qaqeedV@*YCXUbDeXp`+UxMU!T9uV+%6_CdgF?6%`ee;cZgq~LN^){? zs;a7RI2_1GN=k}~iXspQMMXs!85uP-H7O}6C={xpp#g)zL_|ac1O$MIkdTnBt}YW3 zlc1m=FE1}AC+C$bS6EqDRa8`%S=fLB+1c3vp_i8z5YNxgot&Jwxw!!hX=&-ez(4~7 z114tH-Q8U)D=Su3wvv*Ph=>RPz}VPCMphPJ08UU=MxfE?!^6Xvm>2~G1wad6+)z;g zr~n24PgYh|8G!)G$;`}5OiTpwhQ=mTN}6$U;{Sj>goZFL?YGI)d50n z9c=(xTU(opi%VZ$A8-Sx3jkA7R|o1^SXdYw90aZaiqcTiprfM$Jk-?G1olfvNC0L6 zF7fg4F)%Oy9-fqGX#y_$hFY0fQ&A`v7r=M%-}wLAe@oE+{Q*L6-PH^F3r--#yid8P zqEN~yl&?+hSbKFqM)#I_j_O`dLD3s;d zW_mF0oQjJ6v!Sk*jo0GNj9vI$bV;nY)pRV&mBCJ>PUD)qMPEr4Sa8`WQKSHVfdpJru3_lyGv12HjYV;g!X?3bm zjhM5Tp8ryLbW~-)a!muU27B;lqN1jzh8Xbk8!;ph6?3w;L?)jd6NyBbw`axQeEl`B zd*tzzsWAE68iPL?qQ)_elw$`

H?X zfcMrTR*(M{;n7pzmOjk87Ou#JrFgp#vYg9a>oj7X<&lxRZdfh;m;C#5iv$nEXc8y z!fX|Xttx%)SQ7(<>-*G;?-#xPw`IGn1y(z`{Rew#ofR)lM!#7_Rk%&#dWyjC(rm;h zbL#T`Tx2aqMF7<}Q)i?&)U58M*kk8Mu)TLkm6(wo*`CSpC)mT$k)KnMFM`F{%=vL! z{N40YanPL|;pLLt8@%_9 zF^W!>bard-`(s}EP#TxNv_)5+@uEPoU(jsU=n_M7mX+U*c!{9*`nmXPJ-?u8f-79z zrd)V6lCKTD0aDw+Xj!`Zd+-;ZXD{p!?+qw#2)9C>R_I$B8Wpg$ZhI`F7XHo&CXu{- znvIS(=~j{1w8W_R{>%3A@`O*8A1i*J-pjjf0%flSDW`SF;g_*04fMTnciE&zB;p&- zR`xG09z6UI5E#0d&8JtfddBW*D)uAnQ%rS`0g+I_QOhZNc#{t@1tPqj^yLb4ZNI~i zE1DVrt0)xh&dKd$%*om^c?Hk(03Zd!Fg6$7bjekVlK^-Lz>GDX@H)uo>7e`(4_K8y254Ae{AM58QWp5f$|JC9j-E$D?7a<+X=;Gg*C^m}iwWfLt!;QNhQ zUW#jpjzTQu+kOb1-J|X_l&53y#9mi3#_0?FXul#_T7vySO-VV{6W= zW169yj>VRLG4%!`*wsOxen5%lap9BCc>a?Wks!KQmpn$?SJ&fi|5lA;PRR~FAL7y< z^xa)rn%EAZ{@d}~_go>5R;5yf?Kl<{xNgf%!QY6AWJ55go9~O5U=qmXfjp&YkFEe} z4ay`vnVoRO>4J}Hl-Pbfekk^OU0V?J+tZq4)U_pCAG|z0Xg&G6Sm!~h32e1YfMfUi zd8YGpTwmApyp8EQUeY-(?3Tc}bKj-rSlWj=D#fFoB~!1arluNZcRZ@Aa%AuR8@>x6 z^$OZ>yHvzKY;k)a=ci-I&!W`S(K=P;pI)O3V$*-#EfO8l9J66F#atldi+fCWDkcVn z{{1_`QY$el5Z#Ulcrc%;PAAy8UUZ<2D0F6@36u%sOPFb;0tF|a@uHDflW-=UtqVCg zdZ0d?{HDpSWHg=JDg4AuTr|fg?E(Ez;*HbK*w`f<1@~X6+I`7uK8>E2rIyJk zv#I)EQ7khv^O06`^q$ie=-MeusxoL!bu0=_f*p`~rvILHWh*9`R?h;7 zXlZgj&51p^G}_RZb-l?UrralaFu65jQ0LJ`7T?Jrk8-6)Tk|Ei$XKDeSUMxJN(4>u zAnYG_h=;It_y@30`I2SXAU)%Wc_m+D%Y18F0u=6#g%%( zaZs}iX6!FJBI7ATJ?z?x;)Rlz|70lWjmMeC7p?ywd*Aypq1?vpeFASA4mor`Q4X|^ z67H}qcD=-HnJDx5d6rZP3&ba)@Q}^9BihEZP4m6gRze$MU4wAowjsUgEv1%e_po?> zosjh9%s#+91(OBBD{+68GdNV*d+l8T^0%M1y6l+>Q@NQN{o<6`T(+vrpCR{Kw$hb+ z#silOBh~FDH&x|L>h%5ISB&HG+o$jw5s%VZ z-Tl3DBJ8DUKjoCrT!^>VqH(0)oey_*6HejuSI5RPj7(9{s@L!p>w~=B zPGmZpW?^7lf=)XfDtg_v=1WcIvQX^&rBpg#XiU)6uM6VW;HNe9KFya_%$=*!RJcf} zB+dto6^z76XM1Z2JK#vtUKabCw74|4&sI_ODLDNw4b^Ce2b5E{dWV9#D^KK}4qZ31 pI!IZ0qhu;kx-XW7C661?hB4cU(&^Z*Y^DnmUpUA#6b{(mjiqOAY` literal 0 HcmV?d00001 diff --git a/packages/shared/src/assets/wallet/avatar/TrezorSafe5.png b/packages/shared/src/assets/wallet/avatar/TrezorSafe5.png new file mode 100644 index 0000000000000000000000000000000000000000..2374f23cb14fe30149bc0db99e564bbffef7bc0a GIT binary patch literal 4663 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�k_6fn|Yi*;#hJt2{>r&xby>wB0-n)+m#2?%jSCqEV*U6$@J<`Ms{` zC1=TxCJR4BOl|Ex?q{N9NHxcTqoC@8DO2`U7d@8{cR6r)WuFQd{0m}vCIqY@i8bC0 z5sZOet=X=LHp`{Su8ehk`_sRN)irZU%b)FLOepKq3qPmM+^T+Y+OgEp*fI5SbVRAz ze#HiTLOX*>#D%&t{E_IPjB%F&j+i#wsaN;W5hSJ5{<>WVRgi0>tGPOf&BUol9xbu) zIp>=64FEQ)@{cj@PN4umoNi*3*wlL`Ll?|PZ2T9NKJj~VTv#qN2(mN<<88%3cHtEf z{~%l9*D$U{ujG4&iRWr^Q}kaKz)`PT<}^L{Lguk=Jv_-&$Jzy_ApIV}OrCmcbsYnZ zx<2aH+-v+xv`PC@9XnwJTd@TBlBJbRO4ZVO?;ZTZT3DkVXN;f^8#lE%`}{_+gU(W( zK+8m2A$t;*x)0bQ;b8M97nzMk>RNUef?%fu&M9ADIKSN$N$Ksg>#rC1(X=ugIu2h| z^D7q7ZW>#eognP@gN~Umd(d84)@8>w8^?>Ci6|#AY>Sd&X7Jb7XWitA$HCcFoqKN} zZf+cX1a>!WR^qmR_*AnwNNRf!lW>#bxA>53h5Jzu!n7<=9(RhKPXrcevDR zxL^X-kRsP_0S2UlVnUjD{l~dqV(WXwNd#GLq)}7rt9|~u&FbDnZ95h}R2YJX?n7P{ z_95Gb@R$2vA6O>^CU2>ev@$wU^S*6-wA3w`H{1KnO=gLI-fMbx_IjI5Ike1~{;l<| z15NhygOm{?`#EPh);R4dqIYxj%qO*3Qz!wM5}q%waursyHPh$-x!mIitn~D!$AuG) znG>N3cF541vN2kDF}=ROM0`H{9M=RULw1NFyStSdXDNzke0oSXF1spXt-_uS>rTw#TC72@e@s;QI%XFqR>14D@V^4GQWZXut$E}8oNMCK&5if^|T zpJ<9fL4H_aGx^c`tsR0dig?nn--BH1(+haWRKMjpv=lilTd;b%dag+5(aB_0@7h>+ z{v6fW!1XP!oRlaU6ZlXE%CuV%v9)YyA__HOeFF~OJ59%tDf|>L3O`@>NNufmCt?0U zWS_%yEnqG>&4bo^vlgr|;U%?NA-V>hn&8-jqrbhaI8;)gzNFUra{q6cS5U8QoYC$KNg!x&8rKP5?+Nf+B F{V#nBpSA!1 literal 0 HcmV?d00001 diff --git a/packages/shared/src/utils/avatarUtils.test.ts b/packages/shared/src/utils/avatarUtils.test.ts index cabd504e854a..1c3a230446c6 100644 --- a/packages/shared/src/utils/avatarUtils.test.ts +++ b/packages/shared/src/utils/avatarUtils.test.ts @@ -1,6 +1,11 @@ import { EDeviceType } from '@onekeyfe/hd-shared'; -import { HwWalletAvatarImages } from './avatarUtils'; +import { EHardwareVendor } from '../../types/device'; + +import { + HwWalletAvatarImages, + getThirdPartyDeviceAvatarImage, +} from './avatarUtils'; import { NEO_DEVICE_TYPE } from './hardwareDeviceTypes'; describe('HwWalletAvatarImages', () => { @@ -13,3 +18,114 @@ describe('HwWalletAvatarImages', () => { }, ); }); + +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..0c9da6c9bf7d 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,18 @@ export const OthersWalletAvatarImages = { }; export const ThirdPartyWalletAvatarImages = { - 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'), + ledger: require('../assets/wallet/avatar/LedgerNanoX.png'), + trezor: require('../assets/wallet/avatar/TrezorSafe7.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 +104,75 @@ 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'], +]); + +// Human-name fallback only, used when vendorModel (internal_model code) is +// unavailable. Normalized via thirdPartyDeviceUtils.normalizeThirdPartyModelName, +// with a leading "trezor " prefix stripped. Ledger never needs this: 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 code lookup first — SDK model codes are fixed identifiers, + // never normalize/lowercase this branch or 'T3W1' silently stops 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 { From e220d0e8ccb1b1096503d4333c1ebadb94b9c370 Mon Sep 17 00:00:00 2001 From: ByteZhang Date: Mon, 17 Aug 2026 23:28:19 +0800 Subject: [PATCH 2/3] chore: trim overlong comments in avatar resolver --- packages/kit-bg/src/dbs/local/LocalDbBase.ts | 4 +--- .../Components/stories/ThirdPartyHardwareActions.tsx | 3 +-- .../kit/src/views/Tray/components/PortfolioOverview.tsx | 3 +-- packages/shared/src/utils/avatarUtils.ts | 7 ++----- 4 files changed, 5 insertions(+), 12 deletions(-) diff --git a/packages/kit-bg/src/dbs/local/LocalDbBase.ts b/packages/kit-bg/src/dbs/local/LocalDbBase.ts index 9c90efa90ada..e4287aa4d664 100644 --- a/packages/kit-bg/src/dbs/local/LocalDbBase.ts +++ b/packages/kit-bg/src/dbs/local/LocalDbBase.ts @@ -3411,9 +3411,7 @@ export abstract class LocalDbBase extends LocalDbBaseContainer { if (shouldFixAvatar) { if (profile.isThirdParty) { - // Third-party vendor: resolve the per-model avatar from persisted - // settings (device.settings is always populated by - // refillDeviceInfo, parseDeviceSettingsRaw is defensive fallback). + // Resolve per-model avatar; parseDeviceSettingsRaw is a defensive fallback. const deviceSettings = device?.settings ?? parseDeviceSettingsRaw(device?.settingsRaw); const expectedImg = getThirdPartyDeviceAvatarImage({ diff --git a/packages/kit/src/views/Developer/pages/Gallery/Components/stories/ThirdPartyHardwareActions.tsx b/packages/kit/src/views/Developer/pages/Gallery/Components/stories/ThirdPartyHardwareActions.tsx index e8ad7c0aebb3..5c5ded4d46bf 100644 --- a/packages/kit/src/views/Developer/pages/Gallery/Components/stories/ThirdPartyHardwareActions.tsx +++ b/packages/kit/src/views/Developer/pages/Gallery/Components/stories/ThirdPartyHardwareActions.tsx @@ -42,8 +42,7 @@ const DEVICE_MOCKS: IDeviceMock[] = [ vendor: EHardwareVendor.trezor, vendorModel: 'T2T1', }, - // vendorModel unavailable, only the human-readable name → exercises the - // normalized name-alias fallback. + // vendorModel unavailable → exercises the normalized name-alias fallback. { label: 'Trezor Safe 3', vendor: EHardwareVendor.trezor, diff --git a/packages/kit/src/views/Tray/components/PortfolioOverview.tsx b/packages/kit/src/views/Tray/components/PortfolioOverview.tsx index 81afa98ed75b..fea592fb4003 100644 --- a/packages/kit/src/views/Tray/components/PortfolioOverview.tsx +++ b/packages/kit/src/views/Tray/components/PortfolioOverview.tsx @@ -43,8 +43,7 @@ export function PortfolioOverview({ wallet.avatarImg as IAllWalletAvatarImageNamesWithoutDividers ] : undefined; - // Mirrors WalletAvatarBase's hidden-wallet branch, which this direct - // AllWalletAvatarImages lookup bypasses. + // Mirrors WalletAvatarBase's hidden-wallet branch (bypassed by this direct lookup). const isHiddenWallet = accountUtils.isHwHiddenWallet({ wallet: wallet as unknown as IDBWallet, }); diff --git a/packages/shared/src/utils/avatarUtils.ts b/packages/shared/src/utils/avatarUtils.ts index 0c9da6c9bf7d..9a376c07c88c 100644 --- a/packages/shared/src/utils/avatarUtils.ts +++ b/packages/shared/src/utils/avatarUtils.ts @@ -117,9 +117,7 @@ const TREZOR_MODEL_CODE_TO_AVATAR_KEY = new Map< ['T3W1', 'TrezorSafe7'], ]); -// Human-name fallback only, used when vendorModel (internal_model code) is -// unavailable. Normalized via thirdPartyDeviceUtils.normalizeThirdPartyModelName, -// with a leading "trezor " prefix stripped. Ledger never needs this: its +// 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, @@ -156,8 +154,7 @@ export function getThirdPartyDeviceAvatarImage({ fallback: IThirdPartyWalletAvatarImageNames; }): IThirdPartyWalletAvatarImageNames { if (vendor === EHardwareVendor.trezor) { - // Exact-case code lookup first — SDK model codes are fixed identifiers, - // never normalize/lowercase this branch or 'T3W1' silently stops matching. + // 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; From 28599560a70510e171e8a1a12f78513dd0c4a225 Mon Sep 17 00:00:00 2001 From: ByteZhang Date: Tue, 18 Aug 2026 09:03:05 +0800 Subject: [PATCH 3/3] fix: keep neutral vendor fallback avatars for unrecognized devices The ledger/trezor fallback keys pointed at the new Nano X / Safe 7 artwork, so an unrecognized or metadata-less device would render as that specific model instead of a neutral placeholder. Restore the original generic placeholder art for the two fallback keys and add a regression test asserting they stay byte-distinct from any specific-model asset. --- .../src/assets/wallet/avatar/Ledger.png | Bin 0 -> 3001 bytes .../src/assets/wallet/avatar/Trezor.png | Bin 0 -> 728 bytes packages/shared/src/utils/avatarUtils.test.ts | 20 ++++++++++++++++++ packages/shared/src/utils/avatarUtils.ts | 7 ++++-- 4 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 packages/shared/src/assets/wallet/avatar/Ledger.png create mode 100644 packages/shared/src/assets/wallet/avatar/Trezor.png diff --git a/packages/shared/src/assets/wallet/avatar/Ledger.png b/packages/shared/src/assets/wallet/avatar/Ledger.png new file mode 100644 index 0000000000000000000000000000000000000000..cd9a6e6dbc45aa0cb2710624e594c96837139b35 GIT binary patch literal 3001 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 h{$Gdsk5SE^-ybO|+*wq+>CAQ3JZK9$b0W$!pF z%F4>Z!osDcrJbFfnVFeeTU%38Q#Lj>^78W3)YQer#l5|~uCA`2prDM5jC*@~Y;0^# zPftfjM>8`sBqSstARxxZ#%XD3V`F0`CMMWGKH2~P00DGTPE!Ct=GbNc00GQNL_t(& z-tF0GPr^VD24Hqq%dy*9df0L!AR?&T;`#somPi;&VQYjA7?OEEwbNvtq}?XlX(p3l zM-2f45J12g0+!J>%|}DRIW8b=$MyL#e%T2WI#9WL;T!qvS-3zj;9GHvm_Xg0^`~{& zyTSsB@wy31i-02nSH^c90T>#w*Z{Owrw<1J?_w3cj)?d*ZZz#@9^$@8+*esF)q8=x@#?=Zi1jo- z%FeDdl581S3k6329KM^ySgEnAx!@cCRBF0T<))_S+G;NVB7+70LrO#I;LljufyI&( z(Kl00TZ$irU)nougrQ(|>T_+pMhj_f+L{zJ?Q;g=X!)V%Zmp(X1$p{zbq7)VuzQUE z2htALV>DYaWB_tI7ord2UR(guslw4&{=*@FF#-r6fH4A24}1ahK0!PBoiK|40000< KMNUMnLSTZ4tVhxS literal 0 HcmV?d00001 diff --git a/packages/shared/src/utils/avatarUtils.test.ts b/packages/shared/src/utils/avatarUtils.test.ts index 1c3a230446c6..8802b6f148b6 100644 --- a/packages/shared/src/utils/avatarUtils.test.ts +++ b/packages/shared/src/utils/avatarUtils.test.ts @@ -1,3 +1,6 @@ +import { readFileSync } from 'fs'; +import { join } from 'path'; + import { EDeviceType } from '@onekeyfe/hd-shared'; import { EHardwareVendor } from '../../types/device'; @@ -19,6 +22,23 @@ 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'], diff --git a/packages/shared/src/utils/avatarUtils.ts b/packages/shared/src/utils/avatarUtils.ts index 9a376c07c88c..71d0d9698a35 100644 --- a/packages/shared/src/utils/avatarUtils.ts +++ b/packages/shared/src/utils/avatarUtils.ts @@ -54,8 +54,11 @@ export const OthersWalletAvatarImages = { }; export const ThirdPartyWalletAvatarImages = { - ledger: require('../assets/wallet/avatar/LedgerNanoX.png'), - trezor: require('../assets/wallet/avatar/TrezorSafe7.png'), + // 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'), TrezorModelOne: require('../assets/wallet/avatar/TrezorModelOne.png'), TrezorModelT: require('../assets/wallet/avatar/TrezorModelT.png'), TrezorSafe3: require('../assets/wallet/avatar/TrezorSafe3.png'),