Skip to content

fix(cloud-sync): avoid unexpected passcode re-prompt during Sync now in production#10941

Merged
sidmorizon merged 4 commits intoxfrom
codex/investigate-sync-now-password-prompt-issue-wa1n2y
Mar 30, 2026
Merged

fix(cloud-sync): avoid unexpected passcode re-prompt during Sync now in production#10941
sidmorizon merged 4 commits intoxfrom
codex/investigate-sync-now-password-prompt-issue-wa1n2y

Conversation

@sidmorizon
Copy link
Copy Markdown
Contributor

@sidmorizon sidmorizon commented Mar 28, 2026

Motivation

  • Ensure the passcode verification toggle for change/set master password flows is explicitly disabled in all environments and remove the now-unused platformEnv import.

Description

  • Replaced ALWAYS_VERIFY_PASSCODE_WHEN_CHANGE_SET_MASTER_PASSWORD = !platformEnv.isDev with a hardcoded false and removed the platformEnv import from primeConsts.ts.

Testing

  • Ran the TypeScript build and unit test suite, and both completed successfully.

Codex Task


Open with Devin

@revan-zhang
Copy link
Copy Markdown
Contributor

revan-zhang commented Mar 28, 2026

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

devin-ai-integration[bot]

This comment was marked as resolved.

@sidmorizon sidmorizon force-pushed the codex/investigate-sync-now-password-prompt-issue-wa1n2y branch from 1fce1d2 to 2b952dc Compare March 28, 2026 11:05
@sidmorizon sidmorizon enabled auto-merge (squash) March 28, 2026 11:37
@sidmorizon sidmorizon changed the title Set ALWAYS_VERIFY_PASSCODE_WHEN_CHANGE_SET_MASTER_PASSWORD to false and remove unused import fix(cloud-sync): avoid unexpected passcode re-prompt during Sync now in production Mar 28, 2026
@sidmorizon sidmorizon force-pushed the codex/investigate-sync-now-password-prompt-issue-wa1n2y branch from c12a296 to e95d320 Compare March 28, 2026 15:25
@sidmorizon sidmorizon force-pushed the codex/investigate-sync-now-password-prompt-issue-wa1n2y branch from 9810b15 to ac6ed56 Compare March 30, 2026 02:00
@sidmorizon sidmorizon merged commit 15b07a3 into x Mar 30, 2026
11 checks passed
@sidmorizon sidmorizon deleted the codex/investigate-sync-now-password-prompt-issue-wa1n2y branch March 30, 2026 02:59
originalix added a commit that referenced this pull request Apr 20, 2026
…list (#10932)

* docs: add macOS System Tray design spec

Design spec for adding a macOS menu bar tray icon with a read-only
popover panel showing portfolio overview, watchlist tickers, and
pending transaction status.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: address spec review findings

- Add panel renderer entry point strategy (shared index.html with ?render=tray)
- Add TrayManager.destroy() cleanup in before-quit lifecycle
- Fix blur/focus contradiction with delayed focus check
- Register IPC channels in ipcMessageKeys with namespace convention
- Add 5s timeout fallback for main window data requests
- Recalculate panel position on every show
- Add Notification.isSupported() check for graceful degradation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: add macOS System Tray implementation plan

13-task implementation plan covering main process tray module,
renderer panel components, IPC data flow, and system notifications.

Addresses review findings: correct renderer paths to packages/kit/,
shared types in @onekeyhq/shared, desktopApi abstraction instead of
direct ipcRenderer, Object.freeze-safe preload changes, Escape key
handler, and TamaguiProvider requirement.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(desktop): add tray shared types and IPC message keys

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(desktop): add tray template icon assets

* feat(desktop): add tray panel BrowserWindow with positioning and Escape handling

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(desktop): add transaction status diff and notification logic

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(desktop): add tray IPC handlers for data flow and navigation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(desktop): add TrayManager lifecycle orchestration

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(desktop): add tray IPC methods to preload desktopApi

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(desktop): integrate TrayManager into app lifecycle

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(desktop): add TrayPanel root component

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(desktop): add tray panel UI components

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(desktop): route tray panel via ?render=tray query parameter

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(desktop): add tray data provider hook (scaffold)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(desktop): replace Text with SizableText in tray components

@onekeyhq/components does not export Text — the correct component
is SizableText. Updated all tray panel components.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(desktop): regenerate tray icons as proper macOS template images

Previous icons were just resized PNGs with solid backgrounds. macOS
template images must be black shapes on transparent background — the
system automatically colorizes them for the menu bar.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(desktop): fix tray icon shape and panel rendering

1. Regenerate tray icons from OnekeyLogoMono SVG paths — proper key
   logo shape instead of square app icon
2. Replace ConfigProvider with direct TamaguiProvider in tray panel
   entry — ConfigProvider's FontProvider blocks rendering until fonts
   load, causing blank panel

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(desktop): remove splash overlay, add mock data, bolder tray icon

1. Remove HTML template splash image in tray panel mode
2. Add mock data (BTC/ETH/SOL watchlist, pending tx) to verify UI
3. Make tray icon larger (18px) and bolder for better visibility

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(desktop): move tray polling start to dom-ready event

The ipcMain APP_READY handler is used for recovery/relaunch flow and
never fires during normal startup. Move startPolling to the dom-ready
event with a 5s delay to ensure React tree is mounted and the
useTrayDataProvider hook is active.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(desktop): wire real data sources to tray data provider

Replace mock data with real reads:
- Wallet name from simpleDb.accountSelector
- Total balance from activeAccountValueAtom (global)
- Watchlist from serviceMarketV2
- Pending txs from serviceHistory

All reads are wrapped in try/catch for graceful degradation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(desktop): format tray balance with currency symbol and 2 decimals

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(desktop): format balance, fetch watchlist prices, remove splash

1. Format balance to 2 decimal places in data provider
2. Use fetchMarketTokenListBatch for watchlist with real prices
3. Remove HTML splash image via dom-ready executeJavaScript

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(desktop): send cached data to tray panel on open

The tray panel is lazily created — on first click, it registers IPC
listeners but misses data already polled. Now we send cachedTrayData
to the panel both on first creation (with 2s delay for renderer mount)
and on every subsequent open.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(desktop): fix all 6 tray issues

1. Remove splash logo via CSS injection on did-start-loading
2. Send cached data faster (500ms + 1500ms retries)
3. Show wallet emoji from parsed avatar JSON
4. Show token icons via Image component
5. Fetch both spot and perps tokens with full data
6. Pass navigation params (tokenAddress, networkId) for detail routing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(desktop): fix splash, currency symbol, focus outline, wallet emoji

1. Inject CSS earlier + double-inject on dom-ready to ensure splash hidden
2. Remove focus outline (was showing orange border on Watchlist)
3. Case-insensitive currency symbol matching (usd/USD both work)
4. Fallback emoji for watch-only (👁), hardware (🔑), and default (💰) wallets

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(desktop): show wallet avatar image in tray panel

Pass avatarImg name (e.g. 'rabbit') from wallet data to tray.
Render via AllWalletAvatarImages[img] — same require() paths work
since tray loads the same webpack bundle. Falls back to emoji, then
to type-based fallback emoji.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(desktop): fix tray navigation and eliminate splash flash

1. Token click now sends structured action (market-detail-v2) to main
   window renderer which navigates via rootNavigationRef
2. Add TRAY_ACTION to validChannels so main window can receive it
3. Defer showing tray window until dom-ready + splash removal complete
   to prevent green logo flash on open

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(desktop): faster tray open + instant wallet switch sync

1. Remove dom-ready wait on show — just inject CSS and show immediately
2. Push data to tray instantly when activeAccountValue changes (wallet
   switch, balance update) instead of waiting for 30s poll cycle

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(desktop): proper pending tx data mapping

Parse decodedTx.actions to determine tx type (send/swap/approve),
extract amount+symbol from first send transfer, and get recipient
address from transfer or decodedTx.to.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(desktop): fix pending tx lookup using correct account address

Use serviceAccount.getAccountAddressForApi() and getAccountXpub()
to resolve the account address from accountId, matching the same
pattern ServiceHistory.fetchAccountHistory uses internally.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(desktop): use fetchAccountHistory for pending tx detection

getAccountLocalHistoryPendingTxs requires specific networkId and
accountAddress, but the selected account may be in all-network mode.
Switch to fetchAccountHistory which handles all-network internally,
then filter by decodedTx.status === 'Pending'.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(desktop): refresh tray on tx status change via event bus

Listen for HistoryTxStatusChanged, RefreshHistoryList, and
AccountDataUpdate events to immediately refresh tray data when
a transaction is sent, confirmed, or fails.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(desktop): fix appEventBus import (named export, not default)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(desktop): read pending txs from simpleDb raw data directly

fetchAccountHistory requires specific networkId (not all-network) and
complex params. Instead, read simpleDb.localHistory.getRawData() and
iterate all pendingTxs entries across all networks to find any tx
with status 'Pending'.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(desktop): format pending tx amount to reasonable precision

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor(desktop): address PR review — security, privacy, cleanup

Security:
- Add ALLOWED_TRAY_ACTION_TYPES allowlist to validate IPC actions
- Reject unknown action types with warning log

Privacy:
- Remove wallet balance from logger.info (was writing to disk every 30s)

Code quality:
- Remove unused isDev import from TrayManager.ts
- Fix IPendingTx type: TOKEN_APPROVE now maps to 'approve' not 'contract'
- Replace as-any with proper ITrayAction interface in TrayPanel.tsx
- Remove unused hideTrayWindow export
- Move WINDOW_WIDTH/HEIGHT to module-scope constants
- Remove unnecessary block scope in pending tx section
- Add console.warn to silent catch blocks for debuggability
- Remove docs/plans files (not for production repo)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore(desktop): add i18n TODO markers for all tray hardcoded strings

Mark all hardcoded English strings with TODO comments listing the
i18n keys to register on the translation server:
- tray.loading_title/subtitle, tray.locked_title/subtitle
- tray.no_wallet_title/subtitle, tray.offline_title/subtitle
- tray.watchlist, tray.add_favorites
- tray.pending_transactions, tray.no_pending_transactions, tray.view_all
- tray.tx_send, tray.tx_swap, tray.tx_contract, tray.tx_approve
- tray.notification_tx_confirmed, tray.notification_tx_failed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(desktop): fix tray navigation for perps and native tokens

- Perps: switchTab to Perp + serviceHyperliquid.changeActiveAsset
- Spot: use networkUtils.getNetworkShortCode for correct network param
- Matches the exact navigation patterns from MarketTokenListBase

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(desktop): send all pending txs to avoid false confirmation notifications

Removing .slice(0,5) from the data provider. When >5 pending txs exist,
truncation caused older txs to disappear from the diff, triggering
false "Transaction Confirmed" notifications. The UI layer (PendingTransactions
component) already handles display truncation to 5 items.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(desktop): use loadFile with query option for tray production URL

loadURL with ?render=tray appended to a file:// URL breaks the
interceptFileProtocol handler, which doesn't strip query params
from the path. Use BrowserWindow.loadFile() with { query: { render:
'tray' } } instead — Electron handles the query string correctly
without polluting the file path.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(desktop): connect app lock state to tray panel for data protection

When the app is locked, the tray panel now shows a locked state UI
instead of sensitive wallet data (balance, watchlist, pending txs).
The renderer watches appIsLockedAtom and sends isLocked flag in the
data response, which the main process forwards to the tray panel.

* fix(desktop): skip tray init in recovery mode

Move initTrayManager() after the recovery mode check so the tray
icon is not created when the app is in recovery mode (3+ consecutive
boot failures). The recovery window has no tray data provider, so
the tray would be non-functional.

* fix(desktop): move splash removal out of render to module scope

DOM mutation (splash.remove()) was inside the component render body,
violating React's pure render rule. Moved to module-level so it
runs once at import time before React mounts.

* security(desktop): use minimal preload for tray window

Create a separate preloadTray.ts that only exposes 4 methods
(sendTrayData, sendTrayAction, addIpcEventListener,
removeIpcEventListener) instead of the full desktopApi. The tray
renderer renders external market data and should not have access
to sensitive operations like app restart or boot count reset.

* fix(desktop): handle open-page tray action for home and tx navigation

* Update packages/kit/src/hooks/useTrayDataProvider.ts

Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(desktop): fix useRef type to provide required initial value

* fix(desktop): add missing EDecodedTxStatus import for tray provider

* fix(desktop): fix lint errors in tray data provider

* fix(desktop): address PR review — watchlist index correlation, remove unused IPC from main preload

* fix(desktop): address all PR review comments — polling lifecycle, useActiveAccount, platform suffix, theme, preload

* fix(desktop): make sendTrayAction optional in IDesktopAPILegacy type

Main preload intentionally omits sendTrayAction (only tray preload
provides it), so the type must be optional to match.

* fix: resolve lint errors in tray feature

* fix: resolve remaining lint errors in tray feature

- Sort ITrayData before TRAY_IPC in import declarations
- Add empty lines between builtin and external import groups
- Replace nested ternary with IIFE in PortfolioOverview avatar
- Add eslint-disable for unsafe any calls
- Fix JSX expression formatting
- Remove unused contextBridge import

* feat(desktop): add menu bar tray toggle in settings

- Add enableMenuBarTray setting (default off) with Lokalise i18n
- Register toggle under Preferences, macOS-only (platformEnv.isDesktopMac)
- Tray init/destroy via TRAY_TOGGLE IPC (no longer auto-starts)
- Fix tray window preload: use full preload.js to avoid desktopApi crashes
- Add $mmkvSync bridge to preloadTray for storage init
- Improve tray empty state design with noContent state
- Fix i18n build script: sanitize dot separators in enum member names

* feat(discovery): add AI translate for DApp browser (#10393)

* feat(discovery): add AI translate UI skeleton for DApp browser

Add translate button (desktop) and menu item (iOS/Android) to DApp browser,
gated behind OneKey Prime. Click shows placeholder Toast for frontend team
to implement actual translation logic.

- Add translation types, Jotai atoms, Prime feature enum, i18n keys
- Add desktop translate button in DesktopBrowserInfoBar
- Add mobile translate menu item (iOS bottom sheet / Android ActionList)
- Add usePageTranslation hook (placeholder)

* feat(discovery): enhance translate UI with popover settings and i18n

- Add translate settings popover with engine, target language and display mode options
- Move translate button into desktop address bar as input addon
- Add dedicated translate button in mobile bottom bar (iOS/Android)
- Persist translate settings via globalAtom
- Add i18n translations for all supported languages

* refactor(discovery): extract TranslatePopoverTrigger and simplify settings logic

* chore: sync translations

* fix: resolve lint formatting and unnecessary type assertion

---------

Co-authored-by: limichange <limichange@hotmail.com>

* feat: add prime auth token to check-host request for Blockaid integration (#10945)

* feat: add prime auth token to check-host request for Blockaid integration

* Update packages/kit-bg/src/services/ServiceDiscovery.ts

Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix: prettier formatting for check-host auth token header

---------

Co-authored-by: morizon <sidmorizon@outlook.com>
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(lint): remove unused platformEnv import in prime consts (#10941)

* fix(ext): keep passkey switch default on in sidepanel password setup (#10952)

* feat(market): add PnL columns to portfolio and swap pro positions(OK-51929) (#10840)

* feat(market): add PnL columns to portfolio and swap pro positions

- Add unrealized PnL and total PnL columns to market detail portfolio view
- Update API type IMarketAccountPortfolioItem with pnl field
- Create shared PnlCell component for consistent PnL display
- Update mobile footer to show position value and unrealized PnL
- Add PnL data to Swap Pro positions list via parallel API fetching
- Use BigNumber for precise financial calculations

# Conflicts:
#	packages/kit/src/views/Market/MarketDetailV2/components/InformationTabs/components/Portfolio/Portfolio.tsx
#	packages/kit/src/views/Market/MarketDetailV2/components/InformationTabs/components/Portfolio/layout/PortfolioItemNormal.tsx
#	packages/kit/src/views/Market/MarketDetailV2/components/InformationTabs/components/Portfolio/layout/PortfolioItemSmall.tsx
#	packages/kit/src/views/Market/MarketDetailV2/layouts/MobileLayout.tsx
#	packages/shared/src/locale/enum/translations.ts
#	packages/shared/src/locale/json/bn.json
#	packages/shared/src/locale/json/de.json
#	packages/shared/src/locale/json/en_US.json
#	packages/shared/src/locale/json/es.json
#	packages/shared/src/locale/json/fr_FR.json
#	packages/shared/src/locale/json/hi_IN.json
#	packages/shared/src/locale/json/id.json
#	packages/shared/src/locale/json/it_IT.json
#	packages/shared/src/locale/json/ja_JP.json
#	packages/shared/src/locale/json/ko_KR.json
#	packages/shared/src/locale/json/pt.json
#	packages/shared/src/locale/json/pt_BR.json
#	packages/shared/src/locale/json/ru.json
#	packages/shared/src/locale/json/th_TH.json
#	packages/shared/src/locale/json/uk_UA.json
#	packages/shared/src/locale/json/vi.json
#	packages/shared/src/locale/json/zh_CN.json
#	packages/shared/src/locale/json/zh_HK.json
#	packages/shared/src/locale/json/zh_TW.json

* fix: use hardcoded $ symbol for USD PnL values instead of user currency

The unrealizedPnlUsd field is always in USD, so it should display $
instead of the user's selected currency symbol.

---------

Co-authored-by: morizon <sidmorizon@outlook.com>

* feat: add Perps Help Center guide (#10947)

* feat: add Perps Help Center guide with popover and contextual links

- Add "?" icon in Perps header that opens a categorized help center popover (desktop) or full-page modal (mobile)
- 8 articles from help.onekey.so organized into 4 categories: Getting Started, Trading Operations, Funds & Fees, Video Tutorials
- Search bar redirects to help center with query
- Contextual "?" help links in LeverageAdjustModal, MarginModeSelector, and EnableTradingModal
- Platform-aware URL opening: Discovery browser (desktop/mobile), new tab (web)
- 22 new i18n keys with zh-CN translations

* fix: match guide icon style with toolbar neighbors

* fix: use BookOpen icon for guide button

* fix: correct Intercom help center language codes in locale mapping

* fix: remove stray gitignore change and hardcoded a11y label

* chore: gitignore .gstack directory

* chore: revert gitignore to base branch

* fix: use Lokalise for i18n keys and fix enum dot-to-underscore conversion

* chore: remove tracked .gstack files

* chore: sync Lokalise translations for all languages

* chore: sync all language translations from Lokalise

* refactor: reuse useHelpLink pattern and use article IDs only

Address PR review feedback:
- Remove custom URL construction (localeToHelpCenterLang, buildArticleUrl, buildSearchUrl)
- Reuse useHelpLink pattern with buildHelpUrl for non-hook contexts
- Use article IDs only (e.g. '13987899') instead of full slugs with titles
- Rename CONTEXTUAL_ARTICLE_SLUGS to CONTEXTUAL_ARTICLE_IDS

* fix: add trailing comma in build-locale-json-map.js for CI lint

---------

Co-authored-by: morizon <sidmorizon@outlook.com>
Co-authored-by: Leon <lixiao.dev@gmail.com>

* fix(desktop): default menu bar tray to enabled and sync on startup

- Change enableMenuBarTray default to true
- Init tray on app startup (main process)
- Renderer syncs setting on mount: destroys tray if user previously disabled it

* fix(desktop): resolve 5 menu-bar tray issues from code review

- fix: TRAY_DATA_REQUEST forwarding broken under contextIsolation=true
  Preload's globalThis is isolated from the renderer window, so
  dispatchEvent() never reached the renderer. Switched the renderer
  to subscribe via desktopApi.addIpcEventListener(TRAY_IPC.DATA_REQUEST).
- fix: getEnableMenuBarTray defaulted to false while initialValue was true,
  causing the sync effect to destroy the tray on startup for upgrading
  users. Changed getter and Switch fallback to `?? true`.
- fix: outer catch in useTrayDataProvider sent empty pendingTxs on any
  error, triggering false "Transaction Confirmed" notifications for every
  tracked pending tx. Added isError flag; trayIpc now skips diffAndNotify
  on error fallbacks.
- fix: sendTrayAction was re-added to main preload during merge — remove
  it to avoid the self-forwarding IPC loop.
- fix: MenuBarTrayListItem Switch showed off state for migrated users
  whose persisted atom lacked the field.

* fix(desktop): resolve lint errors for menu-bar tray

- Prettier formatting on tray components and useTrayDataProvider
- Silence @typescript-eslint/no-unsafe-call on globalThis.desktopApi
  (cast pattern is intentional for preload-exposed API)

* fix(desktop): remove dead preloadTray.ts and fix import groups

- Delete apps/desktop/app/preloadTray.ts (dead code, trayWindow now uses
  the full preload.js) and remove from the esbuild entry list
- Add empty line between import groups in trayIpc.ts and TrayManager.ts
  per oxlint import-js/order rule

* fix(desktop): address critical tray runtime bugs from review

- fix: TrayPanel and navigation handlers received the wrong argument
  because addIpcEventListener strips the IpcRendererEvent (the listener
  gets (data), not (event, data)). The tray panel was silently never
  displaying data and clicks never navigated. Drop the leading _event
  parameter from both handlers.
- fix: IPC listeners were leaking because removeIpcEventListener is a
  documented no-op in the new preload. Switch to the unsubscribe function
  returned by addIpcEventListener (both in TrayPanel and useTrayDataProvider).
- fix: re-add sendTrayAction to the main preload. The tray window loads
  the same preload file, and TrayPanel.tsx needs sendTrayAction to forward
  user clicks back to the main process. Main renderer code never calls
  it, so the self-forwarding loop concern is moot in practice.
- fix: destroyTrayManager now resets the isLocked flag in trayIpc. Toggle
  off while locked, then toggle on after unlock, used to leave the flag
  stale and permanently skip data requests. Also guard destroy() against
  re-entry when not initialized.

* feat(desktop): i18n tray panel strings and OS notifications

- Push 23 tray-related keys to Lokalise (en_US + zh_CN), pull all locales
- TrayEmptyState: all 5 states (loading/locked/noWallet/noContent/offline)
  read titles and subtitles from ETranslations via useIntl
- WatchlistTickers: 'Watchlist', 'Add favorites in the app', and the
  'Perps' badge label now use translations
- PendingTransactions: TX_TYPE_LABELS mapped to ETranslations keys,
  'Pending Transactions', 'No pending transactions', 'View all', and
  the 'Pending' status badge all translated
- PendingTransactions: replace local truncateAddress() with
  accountUtils.shortenAddress() to match the codebase convention
- trayNotification (main process): OS notification titles use the main
  process i18nText() helper with ElectronTranslations constants

* fix(desktop): wrap TrayPanelApp in AppIntlProvider

TrayPanel children now call useIntl() for i18n, but the tray window's
root component only mounted TamaguiProvider — there was no IntlProvider
in the tree, so every formatMessage threw and the whole React subtree
crashed into a blank panel.

Resolve the user's locale via serviceSetting.getCurrentLocale() on mount
(matches the main app instead of defaulting to system locale), gate
render until it resolves to avoid flashing the wrong language, then wrap
TrayPanel in AppIntlProvider + TamaguiProvider.

* fix(desktop): address final review feedback

- fix: error fallback in trayIpc no longer overwrites cachedTrayData,
  preserving last known good data for the panel
- fix: destroyTrayManager now resets cachedTrayData via resetCachedTrayData()
  so re-init doesn't serve stale data from a previous session
- fix: tray files import electron-log/main (not electron-log) to match
  codebase convention for main-process modules
- fix: prettier formatting in build.js after removing preloadTray entry

* refactor(desktop): type desktopApi tray methods and drop executeJavaScript

Two pre-release security audit follow-ups (Low-severity):

1. Remove `webContents.executeJavaScript` from the tray BrowserWindow —
   the static splash-removal script is redundant because the injected
   CSS already contains `.onekey-index-html-preload-image { display:
   none !important }` and App.tsx module-scope code removes the element
   once React boots. Eliminates an `executeJavaScript` call site.

2. Strongly type `globalThis.desktopApi` tray methods: add
   `sendTrayData`, `sendTrayAction`, `toggleTray` to `IDesktopApiLegacy`
   (already declared on globalThis via @types/globals.d.ts). Export
   `ITrayAction` + add `isError?: boolean` to `ITrayData`. Drop all
   `(globalThis as any)` casts and `@typescript-eslint/no-unsafe-call`
   eslint-disables in tray consumers.

* fix(desktop): prevent false tx notifications in tray panel

Two fixes to the tray notification path caught in Devin review:

1. trayIpc.ts: when the renderer emits an error-fallback payload
   (isError=true), the main process now keeps the previous cached
   snapshot AND stops forwarding the empty placeholder to the tray
   window. Previously a transient data-gather failure would replace
   the displayed good data with a "No Data Yet" state.

2. useTrayDataProvider + trayNotification: the data provider
   hardcoded status:'pending' for every tracked tx and filtered
   out Failed ones, so a failed tx just disappeared from the next
   snapshot and diffAndNotify fired "Transaction Confirmed" for it.
   Now we include Pending+Failed in the tracked list with the real
   mapped status, which activates the existing failed branch in
   diffAndNotify. Panel/TrayPanel filter failed entries out of the
   visible list so they remain an invisible notification-only hop.

Also tightens IPendingTx.status from string to 'pending' | 'failed'.

* fix(desktop): resolve tray locale via main-window relay, not direct IPC

The tray panel renderer is a separate BrowserWindow and can NOT call
DESKTOP_API_CALL — the main-process validator restricts that channel
to the main window's webContents. The tray panel's bootstrap call to
backgroundApiProxy.serviceSetting.getCurrentLocale() was rejected on
every mount, leaving `locale` as null and blocking TrayPanelApp from
rendering anything at all (the `if (!locale) return null;` guard).

Fix by relaying locale through the existing ITrayData pipeline:
  - Add optional `locale` field to ITrayData
  - Main-window data provider resolves locale via backgroundApiProxy
    and includes it on every code path (normal, locked, isError)
  - Tray renderer drops the direct backgroundApiProxy call, defaults
    to 'en-US' so the loading state renders immediately, and updates
    locale when TRAY_UPDATE arrives with a real value

Also removes the orphaned backgroundApiProxy import from App.tsx.

* fix(desktop): stub desktopApiBridge.call in tray preload

The tray panel is a separate BrowserWindow that shares this preload
but can't legitimately call DESKTOP_API_CALL — the main-process
validator only trusts the main window's webContents. Firing the IPC
from the tray renderer produced a warning-per-call on the main side
and never returned usable data.

Detect tray mode via the render=tray query param and swap
`desktopApiBridge.call` with a local rejector that also console-warns.
This keeps the main-process log clean and surfaces, in the tray
devtools, any residual code path still trying to reach kit-bg from
the tray renderer (which should relay through TRAY_UPDATE instead).

* chore(desktop): allow electron BrowserWindow option names in cspell dict

* fix(desktop): clear isLocked in tray isError branch to unblock polling

Follow-up to the earlier isError-passthrough fix. The locked branch
sets isLocked=true; if the app is then unlocked and the renderer's
data gather throws, it sends { isError: true } which we handle with
an early return — that preserved the stale isLocked=true forever,
and requestDataFromMainWindow's `if (isLocked) return;` silently
killed all 30s polling until some other push event (account switch,
tx status change) happened to emit a non-error response.

The renderer only reaches the isError path when the app is already
unlocked (the locked branch in useTrayDataProvider short-circuits
before the try/catch), so it's safe — and necessary — to clear
isLocked here. Credit: Devin review thread PRRT_kwDOGay3kM577gQg.

* feat(shared): add calculateAccountTotalValue utility

Shared composition primitive for tokens + DeFi netWorth. Extracted
from inline implementations in HomeOverviewContainer and AccountValue.
Caller supplies currency-normalized inputs; utility returns the sum,
with branch selection controlled by optional filter parameters.

* feat(kit-bg): add getAccountTotalDeFiNetWorth service method

Sums DeFi netWorth across all networks for an account, converting
per-entry currency to the caller's target currency. Delegates tuple
resolution to getAccountsLocalDeFiOverview (handles All-Networks
expansion via serviceAllNetwork). Reads only from simpleDb.deFi
local cache; no network calls.

* feat(desktop): tray total balance includes DeFi and display currency

Tray's totalBalance now sums tokens (converted from atom's USD to
user's display currency) + DeFi netWorth (pulled per-request from
simpleDb.deFi cache via serviceDeFi.getAccountTotalDeFiNetWorth).
Uses All Networks semantic unconditionally — tray is "wallet at a
glance", independent of main window's network selection.

When currencyMap is not yet populated, falls back to USD labeling
to avoid showing a misleadingly labeled number.

* refactor(home): use calculateAccountTotalValue for overview total

Extract the inline tokens+DeFi composition to the shared utility.
No behavioral change — calculateAccountTotalValue with a string
tokensValue and a number deFiNetWorth returns the exact same sum
as the previous BigNumber(tokenWorth).plus(deFiWorth).toFixed().

* fix(shared): normalize deriveType via allowlist in calculateAccountTotalValue

Branch F's key parsing previously did just .toLowerCase() on the
raw deriveType string, missing the allowlist normalization that
the original AccountValue.tsx Branch 4 performed via
accountUtils.normalizeDeriveType. Stale or unknown deriveType
strings would be silently excluded instead of falling back to
'default' and matching networkInfoMap accordingly.

* refactor(account-selector): use calculateAccountTotalValue

Replace the 4-branch inline composition in AccountValue with the
shared utility. Behavior preserved branch-for-branch:
- "Others" scalar account: plus deFi for linkedNetworkId
- Merge-derive (BTC/LTC): sum per networkId match, no deFi
- Single network own account: pick key, plus deFi for that network
- Default (All Networks / wallet-scoped): filter by walletId+derive,
  plus summed deFi across all overview entries

Empty-string value now returns DeFi-only instead of NaN — strictly
better than prior behavior, surface unchanged.

* chore(kit-bg): fix lint in getAccountTotalDeFiNetWorth + tests

Replace continue statements with positive guards (no-continue rule).
Reformat test file mocks for prettier; add eslint-disable comments
for the intentional `as any` cast and post-mock import.

* docs(kit-bg): document getAccountTotalDeFiNetWorth + use real All-Networks id in tests

Add JSDoc explaining the All-Networks expectation, hasCache semantics,
and local-only contract. Replace the placeholder 'all--0' in service
tests with the real 'onekeyall--0' so the test data matches what
networkUtils.isAllNetwork actually compares against in production.

* fix: resolve lint + address tray review feedback

- Strongly type ServiceDeFi test factory to drop unsafe-any oxlint errors
- Validate TRAY_DATA_RESPONSE sender is the main window in trayIpc
- Drop locale dep from tray TRAY_UPDATE effect via functional setState

* fix(desktop): harden tray IPC and data pipeline per review

- close lock-state race: re-check appIsLockedRef before sending gathered
  data so balances don't leak after lock during an inflight fetch
- completion-driven guardedRequest: release inflight flag on
  TRAY_DATA_RESPONSE (with 20s backstop) instead of a 2s timer that
  expired mid-fetch and allowed overlapping requests
- sender validation: TRAY_ACTION only accepts events from the tray
  window, TRAY_TOGGLE only from the main window — the shared preload
  previously exposed both channels to either side
- route pending-tx clicks through the existing EVENT_OPEN_URL deep-link
  pipeline, regex-limited to /transaction/[A-Za-z0-9_-]+, so rows
  actually navigate to the detail page (fixes test-plan item)
- convert watchlist prices to user display currency via currencyMap
  rates and unit symbol; no more hardcoded en-US \$ formatting
- renderer-side inflight guard coalesces wallet-switch, eventBus, and
  poll requests into a single run with trailing re-fetch

* fix(desktop): harden tray window + HttpServer sender gate (Option C)

Flip tray BrowserWindow contextIsolation to true so the tray renderer
can no longer monkey-patch preload internals, and gate the OAuth-callback
HttpServer ipcMain handlers (SERVER_START/SERVER_RESPOND/SERVER_STOP)
on the main window's webContents.id so the tray preload's startServer/
serverRespond/stopServer surface cannot drive the local HTTP server.

* fix(desktop): gate sendTrayAction to tray preload context

`sendTrayAction` was being exposed on every window because the tray
renderer shares preload.ts with the main renderer. Hoist the
`isTrayWindow` detection and spread `sendTrayAction` into `desktopApi`
only when the preload runs inside the tray window, mark the field
optional in the shared type, and guard the TrayPanel call site with
optional chaining. The sender-id check in trayIpc.ts remains as
defense-in-depth.

* fix(desktop): split TRAY_* IPC channels per window

Previously `addIpcEventListener` accepted TRAY_ACTION / TRAY_UPDATE /
TRAY_DATA_REQUEST from any renderer, meaning a compromised main renderer
could sniff TRAY_UPDATE payloads (wallet balance + watchlist) and a
compromised tray renderer could hook into the data-request pipeline.
Scope the allowlist by `isTrayWindow`: tray gets TRAY_UPDATE only; main
gets TRAY_DATA_REQUEST + TRAY_ACTION only.

* fix(desktop): reset pending-tx diff baseline on account switch

The pending-tx notification diff kept a module-scope `previousPendingTxs`
snapshot with no awareness of which account produced it. Switching to
another wallet/account emptied the pending list from the diff's point
of view, so every pending tx of the prior account would fire a false
"Transaction Confirmed" notification on the next poll.

Thread `accountId` from the data provider (main + locked + error
branches) through ITrayData -> trayIpc -> diffAndNotify, and reset
both the baseline txs and accountId whenever the account changes.

* refactor(kit): gate tray data provider on isDesktopMac + menu-bar setting

`Bootstrap` mounted DesktopTrayDataProvider on every desktop platform and
the provider's effects gated on the broader `platformEnv.isDesktop`, so
Linux/Windows desktop builds (and macOS users with the menu bar toggled
off) were running the IPC listeners + account/lock/event-bus refresh
pipeline for nothing.

Tighten the mount predicate to `isDesktopMac` and derive an `isTrayActive`
flag combining it with the persisted `enableMenuBarTray` setting. Each
effect now early-returns on `!isTrayActive` and includes the flag in its
dependency list, so disabling the menu bar tears down IPC/event-bus
subscriptions and enabling it re-attaches them without remounting.

* chore(desktop): route tray hook errors through defaultLogger

Swap the `console.warn`/`console.error` calls scattered through
useTrayDataProvider.desktop.ts for `defaultLogger.app.error.log`, so
defi/balance/watchlist/pending-tx/perps-navigation failures land in the
usual app error pipeline (Sentry-backed) instead of sitting silently in
the main-renderer DevTools console.

* fix(desktop): preserve decimal precision + respect locale in tray balances

Pending-tx display formatted amounts via raw JS Number, so sub-cent
amounts on 18-decimal tokens (e.g. 0.000000123456 ETH) lost precision
or collapsed. PortfolioOverview additionally looked the currency symbol
up in a local 5-entry table that defaulted to "$", so ARS/CHF/KRW
balances were mislabeled as USD, and then ran the amount through
`Number(...).toLocaleString('en-US', ...)` which discards precision for
very large balances.

Switch the pending-tx formatter to BigNumber (preserving the existing
<0.01 -> toPrecision(3), otherwise toFixed(4) trimming) and its
fee-fallback branch to use the resolved `displaySymbol`. Thread the
display symbol through ITrayData.totalBalance and have PortfolioOverview
read it directly, formatting the amount via BigNumber.toFormat(2).

* feat(desktop): add view-all-transactions tray action

The tray's "View all" link dispatched `open-page` with an empty route,
which matched neither the transaction-detail regex nor the tab-home
branch in `handleTrayNavigation` — main window surfaced but nothing
navigated. Add a dedicated `view-all-transactions` action: whitelist
it in `ALLOWED_TRAY_ACTION_TYPES`, let PendingTransactions raise it via
an `onViewAll` callback, and route it to the Home tab (no public
sub-tab route exists for history, so Home is the best we can do
without deeper routing surgery).

* chore(desktop): tighten tray listener and blur-timer cleanup

`unregisterTrayIpcHandlers` called `ipcMain.removeAllListeners` on both
channels, which also nukes any unrelated subscribers added elsewhere.
Hold the handler references added here and remove them individually.

The tray window's blur-hide `setTimeout` kept firing after
`destroyTrayWindow`, risking a call into `trayWindow.hide()` on a freed
handle in the narrow window between blur and destroy. Track the pending
timer on the module and cancel it both on the next blur and on destroy.

* fix tray error fallback and shared currency types

* chore: clean code

* fix: resolve CI lint (24.x) failure

* fix: address PR review feedback

- suppress false tray confirmations after clear pending transactions
- propagate clear-pending hint through tray data payload

* fix: resolve CI lint (24.x) failure

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: morizon <sidmorizon@outlook.com>
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Leon <lixiao@onekey.so>
Co-authored-by: yikZero <i@yikzero.com>
Co-authored-by: limichange <limichange@hotmail.com>
Co-authored-by: Leon <lixiao.dev@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants