Skip to content

Fix/cardano partial sign OK-53179 OK-53133#11212

Merged
ByteZhang1024 merged 8 commits into
xfrom
fix/cardano-partial-sign
Apr 15, 2026
Merged

Fix/cardano partial sign OK-53179 OK-53133#11212
ByteZhang1024 merged 8 commits into
xfrom
fix/cardano-partial-sign

Conversation

@ByteZhang1024

@ByteZhang1024 ByteZhang1024 commented Apr 14, 2026

Copy link
Copy Markdown
Contributor

@revan-zhang

revan-zhang commented Apr 14, 2026

Copy link
Copy Markdown
Contributor

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.

@socket-security

socket-security Bot commented Apr 14, 2026

Copy link
Copy Markdown

All alerts resolved. Learn more about Socket for GitHub.

This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored.

View full report

devin-ai-integration[bot]

This comment was marked as resolved.

@ByteZhang1024
ByteZhang1024 force-pushed the fix/cardano-partial-sign branch from f5a3560 to 6b9f057 Compare April 14, 2026 13:22
devin-ai-integration[bot]

This comment was marked as resolved.

@ByteZhang1024
ByteZhang1024 force-pushed the fix/cardano-partial-sign branch from cddc397 to 7b7ae30 Compare April 14, 2026 15:35
devin-ai-integration[bot]

This comment was marked as resolved.

Comment thread packages/core/package.json Outdated
@socket-security

socket-security Bot commented Apr 15, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedpassport-desktop-win32-x64-msvc@​0.1.2491003575100
Addedelectron-check-biometric-auth-changed@​1.0.0701006192100
Addedpassport-desktop@​0.1.2731009976100
Addedtailwindcss@​3.4.18961008798100
Addedws@​8.18.39810010090100
Added@​stoprocent/​noble@​2.3.169110010094100

View full report

@ByteZhang1024
ByteZhang1024 force-pushed the fix/cardano-partial-sign branch from 7ee7236 to 37284f1 Compare April 15, 2026 01:34
wabicai
wabicai previously approved these changes Apr 15, 2026
devin-ai-integration[bot]

This comment was marked as resolved.

sidmorizon
sidmorizon previously approved these changes Apr 15, 2026
dApps send `partialSign: true` via CIP-30 signTx when they build txs
that include key hashes the wallet can't sign (e.g. Minswap puts its
own required_signers into the tx body). The flag was dropped between
the provider and CoreChainSoftware, where partialSign was hard-coded
to false — the library then threw ProofGeneration on any unknown key
hash, breaking every DeFi dApp signing on software wallets.

Thread the flag through:
  ProviderApiCardano.signTx -> Vault.buildTxCborToEncodeTx ->
  IEncodedTxAda.partialSign -> CoreChainSoftware.signTransaction.

Default is false (plumbed via `!!encodedTx.partialSign`) so non-dApp
flows (regular ADA transfers, internal staking) keep their current
behaviour exactly.
The SDK 1.1.10 release contains two CSL 13 compat fixes needed by the
hardware signing path:
  - reference_inputs: drop .to_str() on TransactionInput.index() which
    CSL 13 returns as a JS number directly
  - mint: iterate Mint.get(policy) as the CSL 13 MintsAssets list
    instead of treating it as a single MintAssets map

Both were previously applied locally via patch-package against 1.1.10-
alpha.8; the patch is dropped here because the fixes now live in the
published package.
Three bugs were blocking hardware signing of Plutus dApp txs such as
Minswap / SundaeSwap liquidity actions. None are reachable from normal
ADA transfers (that path goes through the ORDINARY_TRANSACTION branch
and touches none of this code).

1. keys.payment.path was the account-level path (m/1852'/1815'/0')
   which firmware rejects with "Not a valid path : 405". The stake
   path was built correctly with /2/0 appended; we now build the
   payment path symmetrically with /0/0 so firmware accepts both.

2. Firmware rebuilds the body CBOR from the inputs we send and signs
   the hash of its reconstruction; if that reconstruction doesn't
   byte-match the broadcast body, every witness fails on-chain with
   InvalidWitnessesUTXOW. The SDK's convertCborTxToEncodeTx pre-
   filters encodedTx.inputs down to user-owned UTXOs (correct for
   software signing, which only picks keys for UTXOs it owns), but
   that drops external contract UTXOs from the inputs set firmware
   sees. We re-derive the full inputs list from rawTxHex via
   CardanoWasm's Transaction.from_hex and only attach payment path to
   inputs the wallet actually owns — external/script inputs pass
   through without a path so firmware only emits a payment witness
   when one is actually needed.

3. The SDK unconditionally adds stakingPath to additionalWitnessRequests
   whenever the tx mints, so firmware returns a stake vkey witness even
   for DeFi mints (Minswap LP tokens) where the mint is script-authorized
   and no user stake signature is required. The extra ~101 bytes pushed
   the broadcast tx past the dApp's fee budget, producing FeeTooSmallUTxO
   on Minswap. We drop the stake path from the witness request set when
   the body has no certs, no withdrawals, and the user's stake hash is
   absent from required_signers. User's stake hash is extracted from the
   base address via CardanoWasm's Address / BaseAddress / Credential
   helpers; any parse failure falls through to keeping the witness (safe
   default).

All tx body parsing and address decoding go through the official
@emurgo/cardano-serialization-lib-asmjs via a shared parseRawTxWithWasm
helper, surfaced on IAdaSdkApi so the three hosts (web direct, extension
offscreen, native webembed) share a single Rust-backed implementation.
Move parseRawTxInputs / parseRawTxBodyStakeInfo /
extractStakeKeyHashFromBaseAddress out of the local
parseRawTxWithWasm.ts shim and into the shared
@onekeyfe/cardano-coin-selection-asmjs package, so all three hosts
(web direct, extension offscreen, native webembed) consume one
implementation instead of duplicating the CardanoWasm helper code in
the monorepo.

KeyringHardware.signTransaction's post-processing (full-inputs rebuild
+ stake witness filter) is unchanged — still calls the same helper
methods through CardanoApi, just resolved from the sdk now.
The 1.1.11 release publishes the three CardanoWasm-backed tx body
parser helpers (parseRawTxInputs, parseRawTxBodyStakeInfo,
extractStakeKeyHashFromBaseAddress) that KeyringHardware's dApp
signOnly path already consumes via CardanoApi after the previous
refactor commit. Bumping the dep so the published package backs the
helpers instead of the local sync.
@ByteZhang1024
ByteZhang1024 dismissed stale reviews from sidmorizon and wabicai via 61d79a3 April 15, 2026 04:45
@ByteZhang1024
ByteZhang1024 force-pushed the fix/cardano-partial-sign branch from a54133c to 61d79a3 Compare April 15, 2026 04:45
@ByteZhang1024
ByteZhang1024 enabled auto-merge (squash) April 15, 2026 04:46

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

View 13 additional findings in Devin Review.

Open in Devin Review

Comment thread packages/shared/src/locale/json/en_US.json
@ByteZhang1024
ByteZhang1024 merged commit d566f79 into x Apr 15, 2026
12 checks passed
@ByteZhang1024
ByteZhang1024 deleted the fix/cardano-partial-sign branch April 15, 2026 05:04
franco-chan added a commit that referenced this pull request Apr 25, 2026
* remove illustrations

* docs: add onboarding dev cleanup design spec

* docs: add onboarding dev cleanup implementation plan

* chore: temporary onboarding-dev cleanup for redesign work

Disable non-onboarding routes, containers, and services to speed up
dev iteration. All changes marked with [ONBOARDING-DEV] comment.

To restore: git revert this commit

* fix(i18n): improve bulk send mode subtitles across all languages (#11155)

Replace redundant mechanism descriptions with use-case-based copy for
the three bulk send modes (OneToMany, ManyToOne, ManyToMany).

* fix(prime): remove auto-scroll and highlight on subscription page (OK-53009) (#11154)

* fix(discovery): block prompt() and javascript: URL in WebView for anti-phishing (#11153)

* fix(discovery): block javascript: URL navigation in parseDappRedirect

* fix(discovery): block prompt() dialogs on iOS and Android via native patch

---------

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

* fix: keep desktop footer meta row inline and restrict native buy for ondo stock(OK-53016)(OK-52964) (#11157)

* fix(swap): keep desktop footer meta row inline

* fix: restrict native buy for ondo stock OK-52964

---------

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

* fix(swap): remove OneKey fee related UI fields (#11158)

* fix(swap): remove OneKey fee related UI fields

Remove OneKey fee/wallet fee display from swap pages:
- History detail: remove OneKey fee row
- Order preview: remove wallet fee row
- Pro mode: remove wallet fee row
- Limit order: remove estimated fee row
- FAQ: remove fee question
- Provider panel: remove stablecoin zero fee feature description
- Provider tooltip: remove fee comparison chart, update translation key
- SignatureConfirm: clean up dead onekeyFee prop

* fix(swap): remove dead onekeyFee prop in TxActionSwapInfo

* fix(swap): resolve lint errors in SwapQuoteResult

- Remove unused useMemo import
- Remove empty lines within import group
- Remove stray blank lines in JSX props

* fix(swap): remove empty line within import group in SwapHistoryDetailModal

* feat(discovery): add DApp translate analytics tracking and activate Prime feature (#11152)

Add client-side analytics events (dappTranslateToggle, dappTranslateSuccess) for
DApp browser translation and move AI Translate from "Coming soon" to active Prime
feature with subscription-based navigation.

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

* fix(send): tab search, count flicker, address book fixes (OK-52952, OK-53017, OK-53019, OK-52683, OK-53022, OK-53026) (#11151)

* fix(send): quick-select tab search fixes (OK-52953, OK-52952) (#11143)

* fix(send): match all account addresses in fresh-address mode (OK-52953)

BTC fresh-address mode rotates receive addresses; historical entries are
kept on IDBUtxoAccount.addresses. The Accounts tab only checked the
current receive address, so a user searching an old address would not
find the account that owned it. Also check masterAddress and the full
addresses map.

* refactor(send): tighten types and include customAddresses

- Narrow the UTXO cast to Partial<IDBUtxoAccount>
- Also match account.customAddresses so user-added custom receive
  addresses are searchable
- Collapse the imperative Set-build into a candidates array + dedup

* fix(send): pre-mount all visible quick-select tabs (OK-52952)

When a BTC account defaulted to the Accounts tab (OK-52809), the
AddressBook tab never mounted until the user clicked it — so its match
count stayed hidden and auto-switch could not jump to it. Pre-mount
every visible tab so each reports its match status immediately.

* fix(send): tab count flicker and address book network label

- Reset tabMatchCounts/tabMatchStatus when debounced search key changes
  to prevent stale pre-search counts (e.g. 19) flashing before children
  report the filtered count (OK-53017)
- Address book entries in recent recipients no longer show network name
  for non-EVM chains — only show "地址簿" label (OK-53019)

* fix(send): truncate long memo/note with middle ellipsis in recipient lists (OK-53022)

Use shortenAddress to abbreviate long memos (e.g. Cosmos) while keeping
short ones (e.g. XRP destination tags) fully visible.

* fix(send): children report 0 during debounce instead of parent reset (OK-53017)

The parent useEffect reset was overwriting child-reported counts due to
React's bottom-up effect execution order. Now each child tab reports
(false, 0) when entering the debounce gap, clearing stale counts without
a parent-level reset that races with child re-reports.

* fix(send): persist memo in local store so it survives address book deletion (OK-53026)

The recent recipients local store only saved {address, networkId, updatedAt}.
When the address book entry was deleted, the memo (sourced from addressMemo)
disappeared because the store had no fallback.

Now saves memo/note/paymentId at transaction time and reads it back in
loadStoredRecipients.

* fix: remove duplicate visibleTabKeys declaration from cherry-pick merge

* fix: lint — return type formatting and import order

* fix(send): propagate stored memo through API merge and freshness overlay (OK-53026)

When both API and local store have the same address, the API entry took
priority but didn't fall back to the stored memo. Now merges stored memo
into API entries that lack it, and the freshness overlay also propagates
memo from local store.

* fix(send): use local.memo directly in freshness overlay to avoid stale memo leak

* fix(send): restore ?? fallback for recipientMemo in freshness overlay

Pre-existing local store entries lack the memo field (added in this PR),
so local.memo is undefined for them. Without ??, valid API memos (XRP
tags, Cosmos memos) would be wiped for all existing users after deploy.

* fix(send): don't store user note as blockchain memo in recent recipients

note is a user annotation from address book, not a blockchain memo.
Storing it as memo could auto-fill the blockchain memo field on future
sends, risking misrouted funds at exchanges.

---------

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

* fix: dynamic invite code column width for referral table(OK-52822) (#11147)

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

* feat(send): add quick send recipient selection analytics (#11114)

* feat(send): add quick send analytics events

Add three @LogToServer() events for the recipient quick select flow:
- quickSelectTap: which tab and recipient type was selected
- quickSelectNavigation: whether selection skipped to amount page
- quickSelectTabSwitch: manual and auto tab switches with dedup

* feat(send): add search context to quick select analytics

- Add isSearchMode, searchKeyLength, matchCount to quickSelectTap
- Add quickSelectSearchNoResult event (fires when all tabs report
  no matches, deduped per search key)
- Pass search context from RecipientQuickSelect through onSelect

* fix(send): pre-mount quick select tabs so no-result analytics fires

The quickSelectSearchNoResult event never fired because tabMatchStatus
required all three tabs to report, but unvisited tabs never mounted and
their components never called onMatchStatusChange. The auto-switch
fallback could not bridge this either — it only triggers when at least
one tab has matches.

- derive visibleTabKeys from hideTabs + Lightning network detection
- pre-mount visible tabs (display:none until active) so each tab's data
  fetch and onMatchStatusChange callback always runs
- limit allReported / anyTabHasMatches to visibleTabKeys so hidden tabs
  no longer block the no-result analytics or onMatchStatusChange callers
- collapse tabOptions to a single map over visibleTabKeys, removing the
  duplicated Lightning + hideTabs filtering that lived inside the memo

* feat(send): correlate analytics via sendFlowId and add swap quick select

- generate a sendFlowId on sendSelect, propagate through addressInput,
  amountInput, sendConfirm and the four quickSelect events so funnels
  and completion-time analyses can group by a single flow
- auto-capture addressInputMethod inside SendScene and emit it on
  sendConfirm so completion rates can be segmented by input method
  without each call site having to thread the value through
- emit quickSelectTap from SwapToAnotherAddressModal so the swap edit
  recipient flow is covered by the same dashboard

* fix(send): filter hidden tabs from analytics matchCount

getSearchContext summed Object.values(tabMatchCounts), which includes
hidden tabs like the 'recent' tab in the swap modal (hideTabs={['recent']}).
Those tabs are still mounted (visitedTabs.recent defaults to true) so they
report match counts that would otherwise inflate the quickSelectTap
analytics event. Filter through visibleTabKeys so only visible tabs
contribute to the total.

Addresses Devin review on PR #11114.

* fix(send): replace nested ternary with if/else for CI lint

* chore(analytics): add @LogToLocal to new quickSelect scenes

Per review on PR #11114: new scene methods should also emit to the
local debug logger, matching the dialog scene pattern.

---------

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

* fix(send): BTC address search and non-EVM badge (OK-53019, OK-52953) (#11161)

* fix(send): hide badge for non-EVM address book entries in recent list (OK-53019)

* fix(send): match BTC fresh/base/display addresses in Accounts tab search (OK-52953)

* fix(send): only match displayAddress in Accounts search to respect fresh address (OK-52953)

When fresh address is enabled, matching the first/base address would
mislead users — they search for a stale address but the actual send
uses the current fresh address. Now only matches displayAddress.

* fix(send): show all derive types in Accounts search results (OK-52953)

When searching, skip derive type filtering so matches on non-active
derive paths (e.g. Taproot when Native SegWit is selected) are visible.
Restore derive type filtering when search is cleared.

* fix(send): fallback to account.address for imported wallets without addressDetail (OK-52953)

* fix(send): use displayAddress for account display and selection, matching search logic (OK-52953)

* refactor(dapp): remove unused remember checkbox from clipboard permission modal(OK-53081) (#11172)

* refactor(dapp): remove unused remember checkbox from clipboard permission modal (OK-53081)

* chore: upgrade cross-inpage-provider version

* fix(send): analytics matchCount and noResult false positives (OK-53075, OK-53073) (#11166)

- OK-53075: getSearchContext returns matchCount=0 in non-search mode
  instead of summing all tab counts (which equals total recipient count)
- OK-53073: quickSelectSearchNoResult skips firing during debounce gap
  when children temporarily report (false, 0) before settling

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

* fix: show loading indicator instead of no-wallet during wallet deletion (OK-51091, OK-51094) (#11163)

* fix: show loading indicator instead of no-wallet during wallet deletion

When deleting a wallet with other wallets present, the UI briefly
flashed the "No Wallet" empty state before auto-selecting the next
wallet. Wrap removeWallet in accountSelectorSyncLoadingAtom to show
a spinner during the async transition instead.

- Add accountUtils.hasNoUsableWallet() to replace coarse `if (wallet)`
  with precise `!wallet || (isOthersWallet && !account)` detection
- Add useIsAccountSelectorSyncLoading(num) hook for centralized reads
- Extract NoWalletContent component to isolate sync loading subscription
  from HomePageView page memo
- Hide account selector / header UI during no-wallet state across
  AccountSelectorTriggerHome, SelectorTrigger, WalletConnectionGroup,
  MDHeader, and InPageHeader with isWebDappMode exclusion

OK-51091 OK-51094

* fix: NoWalletContent tabBarHeight type mismatch with useScrollContentTabBarOffset

* fix: import order in TabPageHeader index

---------

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

* feat(swap): enhance value drop warning with red card, countdown and analytics (#11162)

- Wrap value drop warning in a red critical card (bgCritical + borderCritical)
- Change title color to textCritical and button to destructive variant
- Add 5-second countdown timer after checkbox is checked before enabling Continue
- Reset countdown on checkbox uncheck/re-check
- Add analytics tracking for Continue and Cancel actions with full order info

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

* feat(market): redesign token selector dialog to match perps style (#11160)

* fix(swap): remove OneKey fee related UI fields

Remove OneKey fee/wallet fee display from swap pages:
- History detail: remove OneKey fee row
- Order preview: remove wallet fee row
- Pro mode: remove wallet fee row
- Limit order: remove estimated fee row
- FAQ: remove fee question
- Provider panel: remove stablecoin zero fee feature description
- Provider tooltip: remove fee comparison chart, update translation key
- SignatureConfirm: clean up dead onekeyFee prop

* fix(swap): remove dead onekeyFee prop in TxActionSwapInfo

* fix(swap): resolve lint errors in SwapQuoteResult

- Remove unused useMemo import
- Remove empty lines within import group
- Remove stray blank lines in JSX props

* fix(swap): remove empty line within import group in SwapHistoryDetailModal

* feat(market): redesign token selector dialog to match perps style

- Replace Table-based rendering with custom ListView + Row components
- Add perps-style underline tabs (自选/热门/X热议/股票/贵金属)
- Use category filtering instead of network selector
- Default to all networks with 1h timeframe
- Match perps font sizes ($bodySmMedium/$bodySm), token logo (xs), star icon ($3)
- Add fixed header row outside scroll area
- Remove category icons from homepage
- Reduce detail page star button size to match perps

* fix(market): address code review findings

- Fix lint errors: import order, duplicate imports, nested ternary, prettier
- Fix parent depth import (use absolute @onekeyhq/kit path)
- Fix timeRange type (use IMarketTimeRangeValue instead of string)
- Add empty state for watchlist when no items
- Extract ListContent component to avoid nested ternary
- Revert detail page star size change (linter restored original)

* refactor(market): extract shared constants and reduce code duplication

- Extract convertSearchTokenToMarketToken to constants.ts (shared with MarketSearchTokenTable)
- Extract column width constants (COLUMN_WIDTH_NAME/PRICE/CHANGE/etc.)
- Extract ALL_NETWORK_ID as module-level constant (avoid per-render computation)
- Extract TokenSelectorListView to eliminate 80% duplication across 3 list variants
- Remove redundant watchlist useMemo wrapper

* fix(market): address CI lint failures

- Remove `as any` type cast on timeRange, use IMarketTimeRangeValue type
- Replace hardcoded English fallback strings with i18n translation keys
- Add intl to useMemo dependency array

* fix(market): add missing tokenImageUris prop to Token component

Pass tokenImageUris for fallback image sources when primary image fails

* fix(market): remove unnecessary type assertion on watchlist data

* fix(market): remove unused IMarketWatchListItemV2 import

---------

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

* fix(send): use send-time memo, truncate long memo, store Algo note (OK-53026, OK-53077) (#11173)

* fix(send): use only send-time memo in recent list, not address book (OK-53026)

- RecentRecipients: use recipientMemo only (from send history or API),
  remove addressMemo/addressNote (from address book). Address book memo
  is unreliable when the same address has multiple entries with different
  memos, and disappears when the address book entry is deleted.
- TxConfirmActions: store Algo note on send success so it persists as
  recipientMemo. Previously only memo and paymentId were stored, missing
  Algo's withNote chain data.

* fix(send): truncate long memo in address book tab (OK-53077)

* feat: stellar soroban hardware signing support (#11170)

* fix: optimize browser submenu expand/collapse performance (OK-53056) (#11174)

* feat(perp): improve responsive layouts and guide entry points (#11159)

* fix(perps): remove question mark help icon from margin mode selector

* feat(perp): make desktop layout responsive

* feat(perp): refine order book layouts

* fix: refine perp guide entry points

* fix(perps): add i18n key for Perps Guide menu item

Replace hardcoded "Perps Guide" string with ETranslations.perp_guide_title.

* fix(perps): fix import ordering in OrderBook to resolve lint CI failure

* fix(perp): correct desktop layout import order

---------

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

* fix(swap): use dynamic fee rate in service fee tooltip (#11177)

The tooltip previously hardcoded 0.85%, now uses the server-returned
percentageFee so different pairs and routes show their actual rate.

* fix(discovery): add AccountSelectorProviderMirror to Browser pages (#11179)

MDHeader now calls useActiveAccount and useIsAccountSelectorSyncLoading
directly, requiring AccountSelectorProviderMirror in the component tree.
Browser.native.tsx and Browser.ext.tsx were missing this provider,
causing "useContextStore ERROR: store not initialized" on the Discovery tab.

* fix: show perps position tpsl lines on tradingview (#11181)

* refactor(header): move AccountSelector hooks into Home-only subcomponents (#11180)

* fix(discovery): move AccountSelector hooks into Home-only subcomponents

MDHeader and InPageHeader called useActiveAccount / useIsAccountSelectorSyncLoading
at the top level, forcing every page using TabPageHeader to wrap with
AccountSelectorProviderMirror. This broke Discovery tab on native/ext
which only has DiscoveryBrowserProviderMirror.

Extract HomeWalletConnectionRow and HomeWalletConnectionInPage so the
hooks are only called when rendering the Home tab (which always has the
provider), keeping MDHeader/InPageHeader context-free for other tabs.

This also reverts the temporary fix from #11179 that added
AccountSelectorProviderMirror to Browser pages, as it is no longer needed.

* Update index.tsx

* fix: remove unused useMemo import in TabPageHeader

---------

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

* refactor(discovery): remove sign typed data reporting (#11178)

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

* fix: market foldable detail layout (#11185)

* fix(swap,market): address recipient input, review fiat values, and iOS settings dialog layout (OK-53097)(OK-53090)(OK-53070) (#11176)

* fix(swap): support incognito recipient input (OK-53097)

* fix(market): restore review fiat values (OK-53090)

* fix(swap): address recipient input review feedback (OK-53097)

* fix(swap): guard incognito recipient validation state

* fix: restore swap recipient footer state

* fix(swap): keep advanced settings below safe area on iOS keyboard

* fix(swap): clear hidden incognito recipient state

* test(swap): fix recipient input hook props typing

* test(swap): satisfy oxlint hook formatting

* fix(swap): clear incognito recipient input on reset

* fix: review issues

---------

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

* Feat: Bot wallet management (#10990)

* feat: add bot wallet management and sync

* fix prime transfer bot wallet export flow

* fix: resolve transfer lint issues

* chore: format prime transfer service

* feat: improve bot wallet management sync

* chore: tidy import order

* refactor: simplify account id wallet parsing

* test: align bot wallet manager section titles

* feat: add cli auth and app transfer login flow

* feat: harden cli auth app transfer flow

* fix: resolve PR CI failures

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

* fix: align desktop noble versions for lint

* docs: tighten PR CI monitor workflow

* fix: ignore packaged desktop app in version lint

* fix: align desktop noble versions

* revert: remove local patch for cross-inpage-provider-core

* feat: support top-level bot wallet cloud sync

* fix: share hd wallet hash for bot wallet labels

* fix(market): restore buy button and review fiat display (OK-53037)(OK-53039)(OK-53032) (#11189)

* fix(market): restore stock buy button fiat value (OK-53037)

* fix(market): correct market fiat display and agent guidance (OK-53039)

* fix(market): skip empty payment token polling

* fix(discovery): android browser translate popover not opening (OK-53050) (#11190)

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

* refactor(market): memoize token list requests and improve category press responsiveness (#11188)

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

* fix(market): resolve selector flicker, wrapped history rate, and token preference init (OK-53053, OK-52558, OK-53079) (#11193)

* fix(market): prevent address selector flicker OK-53053

* fix(market): correct wrapped history rate OK-52558

* chore(i18n): pull latest translations

* fix(market): delay token preference init until async load finishes (OK-53079)

---------

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

* fix: show market create address before first click(OK-52946) (#11195)

* fix: show create address before first click OK-52946

* fix: align create address click guard OK-52946

* fix(app-update): use fresh response for changelogViewed isForceUpdate (OK-53186) (#11196)

The tracking effect captured stale `isForceUpdate` from the initial
useState(appUpdateInfo) snapshot — when the persisted atom hadn't yet
reflected the latest server strategy, the event fired with `false` and
locked via hasLoggedRef before fetchAppUpdateInfo resolved.

Move the log call into the existing fetch's .then so it reads the
fresh updateStrategy from the server response directly.

* feat(discovery): add AI translate unavailable fallback to standard engine(OK-52888) (#11192)

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

* feat(prime): activate Enhanced DApp Security feature (#11175)

* feat(prime): activate Enhanced DApp Security (Blockaid Site Scan) feature

* fix(prime): move Coming soon comment after DAppTranslate (active feature)

---------

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

* fix(send): isolate recent recipients by account (#11186)

* fix(send): isolate recent recipients storage by accountId

Storage key changed from networkImpl (e.g. 'evm') to
networkImpl__accountId so different accounts no longer share
recent recipient lists. BTC/LTC uses stable accountId rather
than rotating addresses, ensuring correct per-account isolation.

* refactor: use named params for loadStoredRecipients

* fix: remove legacy migration code for recent recipients

V1/V2 migration is unnecessary — the feature has not shipped to
production yet. Old data can be cleared via dev tools in test builds.

---------

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

* fix(swap): use swap direction token network for recipient picker (OK-53211) (#11203)

* fix(swap): use swap direction token network for recipient picker (OK-53211)

useSwapAddressInfo previously returned activeAccount.network?.id when
the account selector was not in all-network mode. On cross-chain swaps
this is the wrong chain whenever the TO-side account selector mirror
has not yet been re-synced to the toToken network — most reproducibly
the first time a user opens "send to another address" on a
cross-chain swap from EVM into Aptos, Solana, Cosmos, TON, Aptos,
Sui, Move, etc. The address picker then filters by the stale EVM
network and the user can confirm an EVM address that the swap can
never actually deliver to.

Always derive networkId from tokenNetworkId (the swap direction's
selected token network), with activeAccount.network as a defensive
fallback only when no token has been chosen yet. The fix is symmetric
across the FROM/TO directions so the same race cannot recur on the
FROM side either.

* chore(swap): tighten useSwapAddressInfo comment

Per simplify review: shorten verbose 4-line comment to a one-line
why explanation matching the file's existing comment style.

---------

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

* fix(send): prevent false quickSelectSearchNoResult from debounce race (OK-53073) (#11182)

* fix(send): reset tabMatchStatus on searchKey change to prevent noResult race (OK-53073)

Parent and children each independently useDebounce(searchKey, 300).
When parent's debounce settles before children's, it sees stale
tabMatchStatus and fires a false quickSelectSearchNoResult event.

Fix: reset tabMatchStatus to null and tabMatchCounts to 0 on every
raw searchKey change. This keeps allReported=false until children
actually re-filter and re-report with the new key, regardless of
which debounce timer settles first.

* fix(send): skip match status reporting during debounce for all tabs

AccountRecipients and AddressBookRecipients were still reporting
(false, 0) during debounce, defeating the null-reset guard when
the recent tab is hidden (e.g. SwapToAnotherAddressModal).

---------

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

* fix: use percentOriginFee in swap confirm(OK-53072) (#11197)

* fix: use percentOriginFee in swap confirm OK-53072

* fix: resolve swap keyboard overlap OK-53209

* fix: preserve swap recipient edits OK-53214

* fix: show limit recipient entry OK-53216

* refactor(perp): remove fee compare tab (#11207)

Co-authored-by: wabiwabo <68363074+wabicai@users.noreply.github.com>

* fix(market): remove sharesPerToken field from stock info (OK-53084) (#11201)

FMP API does not return shares per token ratio, hardcoding to 1 causes
user confusion. Remove the field from type definition and UI display.

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

* feat(send): multi-derive parallel query, badge integration, derive type auto-default (OK-52897, OK-52728, OK-52737, OK-52435) (#11138)

* fix(send): request all xpubs for merge-derive chains (OK-52897)

Backend added xpub query parameter support to three Send-related APIs so
that merge-derive chains (BTC/LTC) can get data across ALL four derive
paths (Legacy / Nested SegWit / Native SegWit / Taproot) instead of just
the one bound to the currently selected address.

- Add ServiceAccount.getAccountXpubsForAllDeriveTypes() which enumerates
  every derive type for chains with mergeDeriveAssetsEnabled, returning
  one { accountId, xpub, deriveType } per resolvable derive path. Non-
  merge chains fall back to a single entry.

- ServiceHistory.fetchTransferRecipients: fan out to /transfer-recipient
  once per xpub and merge by lowercase address, keeping the newest time
  per recipient. Marks supported=true if any of the parallel calls were
  supported. Sliced to `limit` after merge so the caller still gets the
  expected list size.

- ServiceAccountProfile.checkAccountBadges: fan out to /badges once per
  xpub and fold the results — any-true wins for the boolean risk flags
  (isScam / isContract / isCex), interacted is promoted from UNKNOWN to
  NOT_INTERACTED/INTERACTED, label and similarAddress take the first
  non-empty response, badges are deduped by (type, label).

- ServiceSend.parseTransaction: pass the single xpub owning the encoded
  tx. This call is intrinsically scoped to one derive path (its inputs
  come from that xpub), so no fan-out is needed — the change is just
  adding the xpub parameter the backend now expects.

Adds `xpubs`, `Xpub`, `Xpubs` to the spell-checker skip list so the new
method name and docs pass lint.

* perf(send): address simplify feedback on OK-52897 xpub fan-out

Simplify pass surfaced four actionable issues on the initial commit:

1. parseTransaction called serviceAccount.getAccountXpub without a
   try/catch, so a failure resolving the xpub would crash the whole
   send flow. The backend uses xpub only as an additional identity
   hint, the tx is parsed from encodedTx regardless, so the call now
   falls back to undefined with a console.warn on failure.

2. getAccountXpubsForAllDeriveTypes ran the full enumeration
   (getDBAccountSafe → getNetworkAccountsInSameIndexedAccountIdWithDeriveTypes
   → Promise.all(getAccountXpub × N)) on every checkAccountBadges
   invocation, which fires once per recipient on the Send page. Wrap
   it with the same memoizee pattern already used by
   getAccountXpubOrAddressWithMemo (5s TTL, keyed by accountId+networkId)
   and keep the @backgroundMethod wrapper thin so IPC callers still
   see a stable surface.

3. Both fan-out sites (fetchTransferRecipients and checkAccountBadges)
   used bare Promise.all, so a single slow/failing derive path would
   block the whole lookup. Switched both to promiseAllSettledEnhanced
   with continueOnError:true — matches the existing pattern in
   ServiceHistory and ServiceUniversalSearch.

4. fetchTransferRecipients previously asked each of the 4 xpubs for
   the full `limit` rows only to slice the merge down to `limit`,
   wasting ~4x bandwidth. Ask for `ceil(limit/N) + 2` per xpub with a
   floor of 5 to keep enough headroom for dedup overlap, then slice
   the merged list as before.

Also extracts the ~30-line badge-merge fold into a pure
mergeAccountBadgeResults helper at module scope (and its partner
emptyAccountBadgeResult), replacing the awkward inline
`type IBadgeResult = Awaited<ReturnType<typeof this.…>>` /
mutable-let dance.

* fix(send): keep newest timestamp when deduping xpub fan-out recipients

When the same address appears across multiple xpub responses with
different timestamps, keep the entry with the most recent time instead
of whichever is encountered first.

* feat(send): integrate badge data from transfer-recipient API

Use isContract/isCex/badges returned by /transfer-recipient to skip
N individual /wallet/v1/account/badges calls during recent-recipient
enrichment. Also remove the forced Accounts-tab default for BTC/LTC
now that the API supports multi-derive chains.

* fix(send): request full limit per xpub to avoid truncating single-path recipients

When all recent sends concentrate on one derive path, the previous
ceil(limit/N)+2 formula would truncate results. Each xpub now requests
the full limit — the response is small (~20 addresses) so bandwidth
impact is negligible.

* feat(send): infer last-used derive type from xpub query results

For BTC/LTC multi-derive chains, the parallel xpub query now tracks
which derive type produced the most recent transfer. This is returned
as lastUsedDeriveType and bubbled through to the Accounts tab, which
defaults the derive type picker to it.

Fixes the issue where entering Send from the home screen (merged view)
would default to an arbitrary derive type instead of the one the user
last sent from.

* fix: lint — prettier formatting and chained assignment

* fix: lint — use IAccountDeriveTypes in type predicate, move setLastUsedDeriveType after isStale check

* fix: lint — move type import to correct group

* fix(send): reset lastUsedDeriveType on load to prevent stale value across account switches

* fix(account): degrade gracefully when xpub lookup fails in checkAccountBadges

Devin caught that getAccountXpubsForAllDeriveTypes was added without
a try/catch. queryAddress (Send flow) treats checkAccountBadges as
infallible — its only previous async dependency, getAddressAccountBadge,
already swallows errors internally — so any throw here propagates
through queryAddress and breaks the entire address validation pipeline
for callers that pass enableAddressContract with an accountId.

Wrap the xpub lookup in a try/catch that falls back to an empty
array, restoring the "never throws" contract. Also extract a local
serviceAccount alias since the reference is now used twice in this
method.

https://github.com/OneKeyHQ/app-monorepo/pull/11138#discussion_r3076019470

* refactor(account): extract safeGetAccountXpubsForAllDeriveTypes helper

Devin caught the same missing-try/catch pattern in ServiceHistory
that was already fixed in ServiceAccountProfile. Rather than
duplicating the try/catch/fallback-to-empty-array block a second
time, hoist it into a shared safe wrapper on ServiceAccount so any
future caller that just wants "return the xpubs or empty on error"
gets the right behavior by construction.

- Adds safeGetAccountXpubsForAllDeriveTypes on ServiceAccount
- ServiceAccountProfile.checkAccountBadges drops the inline try/catch
  and calls the safe variant
- ServiceHistory.fetchTransferRecipients now uses the safe variant,
  so a transient xpub lookup failure degrades to a single-xpub
  transfer-recipient fetch instead of throwing the whole method

https://github.com/OneKeyHQ/app-monorepo/pull/11138#discussion_r3078452030

---------

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

* fix(discovery): translate settings UX and Prime gate (OK-53020) (#11208)

- Lift showSettings state to survive Popover remounts on settings change
- Fix custom language default when intl.locale is filtered from options
- Add Prime membership gate before translation with upgrade modal
- Add Prime badge on translate button for non-Prime users
- Add primeEntryClick analytics with browserTranslate entryPoint

* fix(address-book): lock routing fields (address/memo/note) in edit mode (#11202)

* fix(address-book): disable address field editing in edit mode

Restore the lockdown originally added in 286c504681. The
cloud sync layer keys address book items by (networkImpl + address)
in CloudSyncFlowManagerAddressBook.buildSyncRawKey, with the local
uuid stripped from the payload. Allowing users to edit the address
of an existing entry creates a new sync key on the server while the
old key remains, so other devices pull both records and end up with
duplicates that bypass the name uniqueness check.

Name, memo, note, and create-mode address entry are unaffected.

* fix(address-book): disable memo field editing in edit mode

Memo (destination tag) is part of the routing identity for chains
like Cosmos / XRP / Stellar / TON / EOS / BNB Beacon — exchange
deposit addresses are shared across users and the memo is the only
field that routes funds to the correct account. Editing memo on an
existing entry has the same "wrong value loses funds" risk profile
as editing the address.

Mirrors the disabledAddressEdit lockdown via a new disabledMemoEdit
prop. Note remains editable since it is a pure local label.

* fix(address-book): disable note field editing in edit mode

Algorand is the only chain in the codebase that sets withNote: true
in vault settings, and on Algorand the note field is forwarded
through transferInfo straight into the on-chain transaction note
bytes (see vaults/impls/algo/Vault.ts buildEncodedTx). Major CEXes
(Binance, Coinbase, KuCoin, OKX, Kraken) require this note as the
destination tag for ALGO deposits, so it acts as the routing key
exactly the way memo does on XRP / Cosmos / Stellar.

Editing the note on an existing address book entry can therefore
silently send funds to the wrong account on the next quick-select
send. Lock note in edit mode for the same reason as memo.

* fix(address-book): disable network selector in edit mode

Without this, users editing an existing entry can change the network
while address/memo/note are locked. If the existing address is invalid
on the new network the form becomes unrecoverable (no field is
editable to fix it). If the address happens to validate on both
networks (common for EVM chains) the user can silently corrupt the
entry by saving the wrong network.

Mirrors the existing disabledAddressEdit / disabledMemoEdit /
disabledNoteEdit pattern via a new disabledNetworkEdit prop wired
through to ChainSelectorInput's existing disabled prop. Caught by
Devin in PR review: https://github.com/OneKeyHQ/app-monorepo/pull/11202#discussion_r3077758213

* refactor(address-book): collapse 4 field lock props into lockRoutingFields

Per simplify review: the four disabled*Edit props were always set to
the same value (!isCreateMode) at the only call site, and the missing
chain-selector lock that Devin caught was caused by exactly this kind
of fan-out — adding a new field and forgetting one of the four wiring
points. Collapsing to a single prop closes that class of bug, since
any future routing field added to CreateOrEditContent only has to
honor one signal instead of four.

---------

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

* fix: bulk send sender wallet priority and repeated account selector picks(OK-53187)(OK-52777)(OK-52755) (#11198)

* fix: align bulk send sender wallet priority

* fix: handle repeated account selector picks

* fix: use connectId instead of deviceId for HW wallet connection check

walletDeviceId now uses associatedDeviceInfo.connectId (USB serial number)
instead of deviceId (firmware features.device_id), matching the WebUSB
serialNumber collected by useHardwareWalletConnectStatus.

* fix: allow fallback to other wallets when current wallet is unusable

Remove currentWalletCandidates filter that prevented fallback to
HD/imported wallets when all current-wallet candidates are watching
accounts. The ranking system already sorts current-wallet candidates
to rank 0, so they are tried first without needing an explicit filter.

* fix: derive currentWalletId from page-selected account and fix cross-wallet indexedAccountId drift

- currentWalletId now derives from selectedAccountId (via route params)
  first, falling back to mirrored activeAccount wallet
- resolvedSenderAccountIds now carries both accountId and indexedAccountId
  from the same resolveBulkSendSenderSelection() call, preventing
  cross-wallet context drift in AssetSelectorTrigger

* fix: lint

* fix: match BLE-originated HW wallets by usbConnectId for connected status

- Return usbConnectId alongside connectId from getAccountNameFromAddress
- Check both connectId and usbConnectId against WebUSB serial numbers
- Fixes ranking for BLE-paired devices later connected via USB

* fix: lint

---------

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

* fix(swap): show only keyless wallet accounts in web recipient picker (OK-52685) (#11209)

* feat(send): warn when native token balance is zero before send flow (#11184)

* feat(send): warn when native token balance is zero before entering send flow

For multi-token networks (EVM, Tron, SOL, etc.), check native token
balance when user taps Send. If balance is zero, show a dialog warning
that the token is required for network fees. User can continue anyway
or cancel. Single-token networks (BTC, etc.) skip this check since
balance is validated at the amount input step.

* fix(send): use allTokens for native balance check instead of getNativeToken (no balance)

* feat(send): zero gas warning dialog with receive/buy actions and tracking

- Custom dialog with Receive and Buy action cards when native balance is zero
- Buy button directly opens fiat widget, skipping token selection
- Fix balanceParsed: use map[token.$key] instead of IAccountToken field
- Add zeroNativeBalanceDialog tracking event (shown/receive/buy/continue)
- Add i18n key: insufficient_native_for_network_fees__msg
- SafeResolve guard to prevent double-resolve on dialog close

* fix(send): skip zero gas warning for allowZeroFee chains (e.g. TRON)

* fix(send): guard zero gas warning against all-networks mode and undefined vaultSettings

* feat(send): add sendFlowId to zero gas dialog and insufficient fee tracking

- Start sendFlowId at actionSend (before token selection) so the entire
  flow can be measured end-to-end including the zero gas warning dialog
- Add insufficientFeeOnConfirm event in TxConfirmAlert for measuring
  how often users reach confirm page only to be blocked by insufficient fees
- Pass sendFlowId through zeroNativeBalanceDialog for correlation

* fix(send): resolve before close in zero-gas continue button

Dialog.close() may invoke onClose synchronously. The onClose handler
calls safeResolve(false); the prior ordering (close, then
safeResolve(true)) meant the guard was already set by the time the
Continue button tried to resolve, so the promise silently resolved
with false and the send flow was cancelled even when the user tapped
Continue. Receive and Buy don't hit this because they also intend to
resolve with false.

https://github.com/OneKeyHQ/app-monorepo/pull/11184#discussion_r3076905619

* fix(send): keep insufficientFee logging in sync with rendered alert

The useEffect that logs insufficientFeeOnConfirm gated on
sendTxStatus.isInsufficientTokenBalance alone, but the rendered
alert additionally requires payWithTokenInfo.enabled. When the
token balance was short but pay-with-token was disabled, the user
saw the native alert while analytics recorded feeType 'token' with
the token symbol and fillUpTokenBalance.

Hoist the compound gate into a single isTokenFeeAlert const used by
both the logging effect and renderInsufficientNativeBalanceAlert so
they can't drift again.

https://github.com/OneKeyHQ/app-monorepo/pull/11184#discussion_r3077979618

---------

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

* refactor(perp): remove fee tier entry points (#11215)

* fix(keyboard): use KeyboardController.dismiss for real global dismiss (OK-42598) (#11217)

RN's `Keyboard.dismiss()` is implemented as
`TextInputState.blurTextInput(TextInputState.currentlyFocusedInput())`
(see react-native/Libraries/Utilities/dismissKeyboard.js) — it only
blurs RN-managed TextInputs. Keyboards raised by native inputs outside
RN's tracking (e.g. UITextField inside @onekeyfe/react-native-auto-size-
input's Nitro HybridView, used by Send amount input) are untouched, so
Dialog/Popover/ActionList/Toast.show/etc. kept firing while the system
keyboard was still on screen. On iOS that let the keyboard physically
cover the Dialog Sheet, leaving only the \$bgBackdrop overlay visible.

Switch dismissKeyboard/dismissKeyboardWithDelay to
`KeyboardController.dismiss()` from react-native-keyboard-controller,
which is a true global dismiss on both platforms:
- iOS: `UIResponder.current?.resignFirstResponder()`
- Android: `InputMethodManager.hideSoftInputFromWindow(view.windowToken, 0)`

Also drop the `Keyboard.isVisible()` guard — it only reflected RN's
own tracking and silently skipped dismiss whenever the focused input
was a native one.

* fix: use tab container width for market split view (#11214)

* fix(core): pin ethereumjs-util to 7.1.5 for correct personal_sign behavior (#11216)

* fix: restrict restore sync policy to transfer and icloud restore (#11211)

* fix: restrict restore sync policy to transfer and icloud restore

* fix: resolve CI lint failure

* fix: handle existing imported account restore

* fix(market): simplify watchlist empty state layout (OK-52427) (#11206)

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

* fix(market): hide extended stats columns for compact spot categories(OK-53080) (#11204)

Categories backed by per-token OKX detail APIs only expose a compact
metric set, so desktop list pages now hide extended stats columns
(transactions, uniqueTraders, holders, tokenAge) to match watchlist
behavior. Categories with full stats (trending, x_mentioned) remain
unchanged.

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

* fix: preserve keyless cloud sync mode after migration (#11194)

* fix: require Prime auth before cloud sync

* fix: preserve keyless cloud sync mode

* fix(market,swap): keep token preference and refine recipient input(OK-53079) (#11210)

* fix(market): keep native token preference (OK-53079)

* fix(swap): refine incognito recipient input growth

---------

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

* fix: chunk batch token details requests into groups of 50 for bulk send (#11220)

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

* chore(skill): add Jira field update step to 1k-create-pr workflow (#11221)

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

* fix: clear swap recipient input on network change (#11223)

* fix(discovery): add safe area bottom padding to browser tab switcher toolbar(OK-53268) (#11219)

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

* Fix/cardano partial sign OK-53179 OK-53133 (#11212)

* fix(ada): forward dApp partialSign through software signing path

dApps send `partialSign: true` via CIP-30 signTx when they build txs
that include key hashes the wallet can't sign (e.g. Minswap puts its
own required_signers into the tx body). The flag was dropped between
the provider and CoreChainSoftware, where partialSign was hard-coded
to false — the library then threw ProofGeneration on any unknown key
hash, breaking every DeFi dApp signing on software wallets.

Thread the flag through:
  ProviderApiCardano.signTx -> Vault.buildTxCborToEncodeTx ->
  IEncodedTxAda.partialSign -> CoreChainSoftware.signTransaction.

Default is false (plumbed via `!!encodedTx.partialSign`) so non-dApp
flows (regular ADA transfers, internal staking) keep their current
behaviour exactly.

* chore(ada): bump cardano-coin-selection-asmjs to 1.1.10

The SDK 1.1.10 release contains two CSL 13 compat fixes needed by the
hardware signing path:
  - reference_inputs: drop .to_str() on TransactionInput.index() which
    CSL 13 returns as a JS number directly
  - mint: iterate Mint.get(policy) as the CSL 13 MintsAssets list
    instead of treating it as a single MintAssets map

Both were previously applied locally via patch-package against 1.1.10-
alpha.8; the patch is dropped here because the fixes now live in the
published package.

* fix(stellar): reject memo on contract token transfers

* chore(hardware): add diagnostic logs for unverified device regression

* fix(ada): hardware wallet signing for Plutus dApp transactions

Three bugs were blocking hardware signing of Plutus dApp txs such as
Minswap / SundaeSwap liquidity actions. None are reachable from normal
ADA transfers (that path goes through the ORDINARY_TRANSACTION branch
and touches none of this code).

1. keys.payment.path was the account-level path (m/1852'/1815'/0')
   which firmware rejects with "Not a valid path : 405". The stake
   path was built correctly with /2/0 appended; we now build the
   payment path symmetrically with /0/0 so firmware accepts both.

2. Firmware rebuilds the body CBOR from the inputs we send and signs
   the hash of its reconstruction; if that reconstruction doesn't
   byte-match the broadcast body, every witness fails on-chain with
   InvalidWitnessesUTXOW. The SDK's convertCborTxToEncodeTx pre-
   filters encodedTx.inputs down to user-owned UTXOs (correct for
   software signing, which only picks keys for UTXOs it owns), but
   that drops external contract UTXOs from the inputs set firmware
   sees. We re-derive the full inputs list from rawTxHex via
   CardanoWasm's Transaction.from_hex and only attach payment path to
   inputs the wallet actually owns — external/script inputs pass
   through without a path so firmware only emits a payment witness
   when one is actually needed.

3. The SDK unconditionally adds stakingPath to additionalWitnessRequests
   whenever the tx mints, so firmware returns a stake vkey witness even
   for DeFi mints (Minswap LP tokens) where the mint is script-authorized
   and no user stake signature is required. The extra ~101 bytes pushed
   the broadcast tx past the dApp's fee budget, producing FeeTooSmallUTxO
   on Minswap. We drop the stake path from the witness request set when
   the body has no certs, no withdrawals, and the user's stake hash is
   absent from required_signers. User's stake hash is extracted from the
   base address via CardanoWasm's Address / BaseAddress / Credential
   helpers; any parse failure falls through to keeping the witness (safe
   default).

All tx body parsing and address decoding go through the official
@emurgo/cardano-serialization-lib-asmjs via a shared parseRawTxWithWasm
helper, surfaced on IAdaSdkApi so the three hosts (web direct, extension
offscreen, native webembed) share a single Rust-backed implementation.

* chore(ada): suppress cspell warning on Credential.to_keyhash()

* refactor(ada): source tx body parser helpers from coin-selection sdk

Move parseRawTxInputs / parseRawTxBodyStakeInfo /
extractStakeKeyHashFromBaseAddress out of the local
parseRawTxWithWasm.ts shim and into the shared
@onekeyfe/cardano-coin-selection-asmjs package, so all three hosts
(web direct, extension offscreen, native webembed) consume one
implementation instead of duplicating the CardanoWasm helper code in
the monorepo.

KeyringHardware.signTransaction's post-processing (full-inputs rebuild
+ stake witness filter) is unchanged — still calls the same helper
methods through CardanoApi, just resolved from the sdk now.

* chore(ada): bump cardano-coin-selection-asmjs to 1.1.11

The 1.1.11 release publishes the three CardanoWasm-backed tx body
parser helpers (parseRawTxInputs, parseRawTxBodyStakeInfo,
extractStakeKeyHashFromBaseAddress) that KeyringHardware's dApp
signOnly path already consumes via CardanoApi after the previous
refactor commit. Bumping the dep so the published package backs the
helpers instead of the local sync.

* fix: skip stale swap token address (OK-53281) (#11230)

* feat: rename referral invite event and add binding completed tracking (#11227)

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

* fix(send): skip amount input page for ERC-721 NFTs (OK-53248) (#11232)

ERC-721 tokens are 1-of-1, so the existing SendAmountInput page had
nothing to render — renderNFTAmountInput returned null and the body
fell through to an empty Form, leaving the page visually broken and
pointless to navigate through.

Short-circuit in handleNavigateToAmountInput the same way the
Lightning fixed-amount invoice flow does: build transfersInfo with
amount='1' and nftInfo from the selected NFT, then jump straight to
signatureConfirm.navigationToTxConfirm. ERC-1155 flows are unchanged
because they still hit the amount page to enter a quantity.

* fix(address-input): hide account selector when default-layout input has content (OK-53255) (#11231)

Default-layout AddressInput rendered the account selector / contacts
picker alongside the clear button whenever the input had content,
which landed the selector icon in a half-floating position next to
the committed address. Send flow avoids this because it uses the
recipient layout, which collapses to a plain clear button.

Collapse the default layout to the same behavior: non-empty input
shows only the clear button, empty input keeps the full action
cluster (clipboard / scan / selector) so the account picking entry
point is still available before the user has typed anything.

The only production caller of default layout + selector/contacts is
Referral EditAddress — AddressBook and ImportAddressCore don't pass
accountSelector/contacts so their render output is unchanged. The
recipient layout (Send / Swap flows) is untouched.

* feat(referral): add marquee text animation for long invite codes (#11234)

Add MarqueeText component that automatically scrolls when invite code
text exceeds the viewport width, improving readability for custom codes.

* feat: gate botwallet manager with dev setting (#11229)

Co-authored-by: ByteZhang <ByteZhang@protonmail.com>

* fix(market): allow stock name to display without ellipsis on mobile(OK-52417) (#11226)

* fix(market): allow stock name to display without ellipsis on mobile(OK-52417)

- Change XStack alignItems from center to flex-start for proper alignment when name wraps
- Change Stack flex={1} to flexShrink={1} to allow text to wrap naturally instead of truncating

* Revert "fix(market): allow stock name to display without ellipsis on mobile(OK-52417)"

This reverts commit afb3550597bebb90e4ad99477486a05424ff939e.

* fix(market): show full stock subtitle without ellipsis on mobile detail(OK-52417)

- Add noTruncate prop to SubtitleBadge component
- Add noTruncateSubtitle prop to TokenTagsPopover
- Use noTruncateSubtitle in InformationPanel for stock tokens

---------

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

* fix(send): recent recipients API/local split + BTC badge merge fixes (OK-53278, OK-53284) (#11233)

* fix(send): use indexer API exclusively when supported, stop mixing with local (OK-53284)

useRecentRecipientsData previously fetched the transfer-recipient API
and the local store in parallel, then merged the two lists whenever
the API returned any data. That merging is the root cause of
cross-chain leaks: a stale local-storage entry or a chain-mismatched
history tx could slip into the final list for a chain where the
indexer itself was clean. It also made the "转账过 / 首次转账" badge
diverge from the list, because the badges API knew nothing about the
local-only entries that snuck in.

Refactor the load flow so the API is the single source of truth when
it reports `supported: true`, and local storage + chain history are
only consulted when the chain isn't supported by the indexer at all
(fall through on failures too). Drop the freshness overlay and the
localOnlyAddresses merge, which were the leak paths.

Add a defense-in-depth `filterByNetworkFormat` helper that runs the
chain's local address validator over every recipient before it
reaches queryAddress, so any cross-chain format (e.g. a 0x address
sneaking into a SOL recent list) is dropped no matter which source
produced it.

* fix(badges): strip contradictory xpub-scoped interaction badges (OK-53278)

PR #11138 introduced multi-xpub fan-out to /wallet/v1/account/badges so
BTC merge-derive accounts see every derive path's history. The merge
function escalates `interacted` correctly (any INTERACTED wins), but it
still concatenated+deduped the `badges` arrays across all responses.
Because "First transfer" and "Transferred" are both xpub-scoped labels,
a BTC recipient previously used from e.g. bip84 ended up with BOTH
badges in the final array: "Transferred" contributed by the bip84
response and "First transfer" contributed by the other three derive
paths.

Only take badges from responses whose own `interacted` matches the
merged status. Address-scoped static labels (Scam / CEX / OKX / ...)
are returned by every response regardless of xpub, so they still
surface through the matching subset.

* fix(badges): stop forcing checkInteraction=false on BTC fresh address (OK-53278)

PR #11138 switched BTC /badges calls to fan out per xpub, and the
server's interaction check is xpub-based. Whichever derive path
actually sent to `toAddress` will report INTERACTED regardless of
which fresh fromAddress is currently selected. The leftover client
gate that forced checkInteraction=false on fresh-address mode was
short-circuiting every xpub response to UNKNOWN, so users with BTC
fresh address enabled never saw "Transferred" even for recipients
they had clearly sent to (visible via the Recent tab).

Drop the gate from checkAccountBadges. ServiceSend keeps its own
checkInteraction=false because that caller only reads isContract /
isScam and the flag saves a server-side interaction lookup for a
pre-send check that doesn't use the result.

---------

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

* fix(perps): recover WS subscriptions on browser tab switch(OK-53250) (#11222)

* fix(perps): recover WS subscriptions on browser tab switch

AutoPauseSubscriptions only monitored in-app route changes via
useListenTabFocusState; browser-level tab switches were invisible,
leaving TickerBar and K-line frozen on web/desktop.

Add platform-level visibility listeners (visibilitychange + blur/focus
for web, desktopApi.onAppState for desktop) with dedup guard.
Replace WebView reload with FORCE_RECOVER_WS postMessage to iframe.
Add _forceReconnectTransport to avoid async cleanup race and
post-open data check to detect half-open connections.

* fix(perps): clear network timeout in _forceReconnectTransport

Stale 60s timeout from previous connection can fire after new
connection opens and override connected status.

* fix(perps): clear post-open data check timer on socket close

* fix(perps): fix dedup guard blocking native resume and desktop fullscreen

Reset lastFocusStateRef before native resume-from-background to
prevent dedup guard from skipping resumeSubscriptions.
Skip undefined app state from desktop fullscreen transitions.

* fix(perps): cap post-open data check retries to prevent reconnect loop

* fix(perps): reset post-open data check retries on resume

---------

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

* fix(bulk-send): navigate to previous page on cancel instead of home(OK-53202) (#11224)

* fix(bulk-send): navigate to previous page on cancel instead of home(OK-53202)

* fix: format dependency array to single line

---------

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

* fix: scope keyless permission params to onekey (#11236)

* feat(market): improve recommend list UI and fix Android layout (#11237)

- Add title display for web, desktop, and extension expand tab
- Add dynamic padding top based on window height
- Simplify recommendMaxSize logic using platformEnv
- Fix Android secondary header height for spot and empty watchlist states

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

* fix(refer): remove duplicate error toast on referral code operations(OK-52810) (#11225)

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

* fix(webembed): clip hidden WebView container to prevent ErrorView overflow (#11240)

The WebEmbed singleton WebView uses width: 0 / height: 0 to stay
invisible while keeping WKWebView alive for bundled JS (RevenueCat
etc.). Without overflow: hidden, children with intrinsic sizes
(NativeWebView's ErrorView illustration, ~144px) leak onto the screen
at top: 15% / left: 5% when the WebView errors out or hits the 60s
load timeout after iOS backgrounding, showing a stray GlobeError
icon over any current screen.

* fix(perps): mobile detach breaks WS lifecycle(OK-53208, OK-53244) (#11239)

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

* fix(keyless-web): polish connect UI and gate legacy ext (OK-49859) (#11242)

- Hide Google/Apple social-login buttons when installed OneKey extension
  is at or below KEYLESS_WEB_LEGACY_EXTENSION_VERSION_MAX (6.1.0); fetched
  via wallet_getConnectWalletInfo and resolved with usePromiseResult.
- Refactor KeylessProviderButtons: horizontal Google/Apple layout shared
  via KEYLESS_SOCIAL_PROVIDERS list, "or" divider below.
- Replace hardcoded Chinese install-extension dialog copy with
  ETranslations.install_extension_first / install_extension_first_desc.
- Migrate hardcoded "OneKey is connecting to your X account..." in
  Onboarding v2 GetStarted to ETranslations.extension_connecting_platform_account.
- AccountSelectorTriggerBase: split the keyless "Connect" button and the
  account avatar XStack into two independent branches to remove nested
  hover layering.
- AccountSelectorTriggerHome: hide wallet-type badge in web dapp mode.
- Tighten card padding (px=\$5 -> pl=\$3 pr=\$5) and outer container
  spacing in ExternalWalletList.

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

* fix(market): scroll network selector to selected network on open(OK-53324) (#11246)

* fix(send): share recent recipients across same-mnemonic wallets via on-chain identity (OK-53307) (#11241)

Switch SimpleDbEntityRecentRecipients storage key from
`networkImpl__accountId` to `(networkImplOrId, accountIdentity)` so two HD
wallets that wrap the same mnemonic share a single recent-recipient list,
instead of each maintaining its own per-accountId bucket as introduced by
PR #11186.

The accountIdentity is resolved via `serviceAccount.getAccountXpubOrAddress`
which returns the xpub (or address as fallback). EVM networkIds are still
collapsed to their impl (`evm--1` / `evm--56` -> `evm`) before keying so
recipients stay shared across all EVM chains, matching the pre-#11186
behavior. Non-EVM networkIds pass through unchanged.

This brings RecentRecipients closer to LocalHistory / LocalTokens / LocalNFTs
which already key on-chain data by identity via `buildAccountLocalAssetsKey`.
Resolves the divergence reported on Lightning where the API
`/transfer-recipient` doesn't index, leaving the local fallback as the only
source.

- Entity: take `accountIdentity` instead of `accountId`, expose
  `IRecentRecipientEntry` and `RECENT_RECIPIENTS_BUCKET_CAP` for callers,
  delete unused `deleteRecentRecipient` dead code.
- Service: resolve `accountId` -> identity via `getAccountXpubOrAddress`.
  On read, fan out across all derive-type xpubs
  (`safeGetAccountXpubsForAllDeriveTypes`) and merge so BTC/LTC merge-derive
  accounts see a unified list regardless of the currently-active derive
  type - mirrors `ServiceHistory.fetchTransferRecipients`.
- Logger: add `transaction.send.recentRecipientsSkipWrite` event for the
  near-impossible case where identity can't be resolved during a confirmed
  tx.

Feature is unreleased so no migration is needed; orphaned old-key data is
cleared by dev tools in test builds.

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

* fix(ios): surgical modal close helpers to avoid RNSScreenStack freeze (#11247)

navigation.popStack() / pop() / goBack() on a modal triggers a native
animated UIViewController dismiss that leaves RNSScreenStack instances
inside detached tab views with window=NIL, causing a ~5s (50x100ms)
retry storm that freezes the underlying page until a touch restores
layout.

Add resetModalRouteByName(modalName) — a generic primitive that drops
only routes whose inner screen matches modalName via CommonActions.reset,
preserving parent overlays. Wrap it as resetChainSelectorModal,
resetPrimeModal, resetOnboardingModal for grep-able intent.

Replace 7 unsafe close sites across chain selector (Home/DApp/BulkSend/
Settings/Onboarding contexts), Prime OneKey ID logout, Prime transfer
exit, and external wallet connect. resetAboveMainRoute() in those
sites could kill parent Modals (Settings, AccountManagerStacks,
ApprovalManagement, LiteCard, KeyTag, Swap, Perp) that the user came
from. The surgical wrappers only drop the target modal.

Add ios-overlay-navigation-freeze.md under 1k-ui-recipes with the
diagnostic procedure (log signatures, decision rules), the
atomic-vs-surgical-reset decision matrix, and the full replacement
pattern.

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

* feat(onboarding-v2): scaffold Layout.tsx with drag-style helpers

* feat(onboarding-v2): add LayoutHeader container with desktop drag region

* feat(onboarding-v2): add LayoutHeaderBack with exit variant

* feat(onboarding-v2): add LayoutHeaderTitle (absolute-centered)

* feat(onboarding-v2): add LayoutHeaderLanguageSelector

* feat(onboarding-v2): redesign GetStarted with rotating hero word

Replace OnboardingLayout + AnimatedDeviceAvatar with new Layout primitives
and a per-grapheme slot-machine animation cycling trading/earning/swapping/
buying. Web uses inline CSS transitions (browser blur), native uses Moti.

Native flex treats text as rectangular, so HeroSentenceNative measures the
prefix via onTextLayout and absolute-positions the rotating word at line
tail to avoid false wraps. Sentence uses a localized template with an
injected sentinel so translators can restructure around the action word.

Apply safe-area top inset to LayoutHeader.

* chore(i18n): sync translations from Lokalise

* feat(onboarding-v2): add CreateNewWallet page for Google/Apple/Seed phrase

Register EOnboardingPagesV2.CreateNewWallet with /create-new-wallet rewrite.
Extract useKeylessLocalExistenceLogin hook so CreateNewWallet and
CreateOrImportWallet share keyless local-existence detection and auto-start
handling. Accept fromExt/autoLoginKeylessProvider params so the extension
side panel can land here directly and trigger auto-login.

* feat(onboarding-v2): unify CreateOrImportWallet as single entry with 9 options

Replace AddExistingWallet and the card-style CreateOrImportWallet with one
plain ListItem page covering Google, Apple, Seed phrase/private key,
Transfer, iCloud/Google Drive, KeyTag, Lite (native only), External wallet,
and Watch-only. Migrate keyless login, cloud backup gating, and analytics
from the deleted AddExistingWallet, reusing useKeylessLocalExistenceLogin.

* feat(onboarding-v2): slim GetStarted to Create/More options/Hardware buttons

Replace the inline Google/Apple keyless login UI with a three-button layout:
Primary Create new wallet, Secondary Add existing wallet, Tertiary Connect
hardware wallet. Keyless login now lives in CreateNewWallet and the extension
side panel navigates there directly, so GetStarted no longer needs Dialog
loading, auto-start hooks, or side-panel mode branching.

* refactor(onboarding): drop isFullModal and point extension entry to CreateNewWallet

OnboardingModal is always full-screen now, so useToOnBoardingPage no longer
takes isFullModal/params and the dev-only fullScreen button is gone. Extension
side panel and keyless web bridge open /onboarding/create-new-wallet instead
of /get-started so first-time keyless users land on the page that owns the
auto-login logic.

* refactor(onboarding-v2): force dark theme and tune Layout spacing

Wrap OnboardingNavigator in Theme name="dark" so the flow uses the dark
palette regardless of user theme. Bump LayoutHeader top padding on desktop,
shrink the back button on gtMd, and soften TermsAndPrivacy links to
$textDisabled. Replace the deprecated useThemeVariant with useThemeName in
the three v2 pages that still depended on it.

* chore(icons): simplify OnekeyText SVG

Drop the unused clip path and fillOpacity attributes so the icon renders at…
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants