Fix/cardano partial sign OK-53179 OK-53133#11212
Merged
Merged
Conversation
ByteZhang1024
requested review from
ezailWang,
huhuanming,
originalix,
revan-zhang and
sidmorizon
as code owners
April 14, 2026 12:46
Contributor
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
|
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. |
ByteZhang1024
force-pushed
the
fix/cardano-partial-sign
branch
from
April 14, 2026 13:22
f5a3560 to
6b9f057
Compare
ByteZhang1024
force-pushed
the
fix/cardano-partial-sign
branch
from
April 14, 2026 15:35
cddc397 to
7b7ae30
Compare
originalix
requested changes
Apr 15, 2026
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
ByteZhang1024
force-pushed
the
fix/cardano-partial-sign
branch
from
April 15, 2026 01:34
7ee7236 to
37284f1
Compare
wabicai
previously approved these changes
Apr 15, 2026
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
force-pushed
the
fix/cardano-partial-sign
branch
from
April 15, 2026 04:45
a54133c to
61d79a3
Compare
ByteZhang1024
enabled auto-merge (squash)
April 15, 2026 04:46
huhuanming
approved these changes
Apr 15, 2026
originalix
approved these changes
Apr 15, 2026
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…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
OneKeyHQ/coin-selection#15