Skip to content

[LWM] fix(mobile): reset navigation for token deeplinks#19807

Open
sarneijim wants to merge 2 commits into
developfrom
bugfix/fix-token-deeplink-navigation
Open

[LWM] fix(mobile): reset navigation for token deeplinks#19807
sarneijim wants to merge 2 commits into
developfrom
bugfix/fix-token-deeplink-navigation

Conversation

@sarneijim

@sarneijim sarneijim commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

✅ Checklist

  • npx changeset was attached.
  • Covered by automatic tests. Unit tests cover token, coin, and Stake navigation actions. The original native crash still requires validation on the affected physical iPhone/build.
  • Impact of the changes:
    • Open a token deeplink followed by another token deeplink, both immediately and after a delay.
    • Verify each token opens the expected Asset Detail screen without crashing.
    • Verify coin Asset Detail and earn?action=stake deeplinks keep their existing navigation behavior.
    • Verify Back returns to the main screen after opening a token deeplink.

📝 Description

Opening a token Asset Detail deeplink followed by another token deeplink can crash Ledger Wallet Mobile on iOS. The available crash report shows a secondary React Native/Hermes failure while converting a native exception, but it does not expose the original native module, method, or exception reason.

Before: Token Asset Detail deeplinks used React Navigation's default action generation, allowing the existing Asset Detail route to be reused for the next token.

After: Token Asset Detail states are dispatched as reset actions so every token deeplink creates a fresh navigation state and remounts the screen. Coin Asset Detail, Stake, and all other deeplinks continue using React Navigation's default action generation. This is independent of how quickly the links are opened.

This is a targeted mitigation for route reuse. Confirming the native root cause still requires reproducing the original exception on the affected physical iPhone/build.

Automatic validation:

  • Targeted Jest suite: 1 passed, 3 tests passed.
  • Formatting: passed.
  • Lint: passed with 0 warnings and 0 errors.
  • Mobile typecheck: blocked by 180 existing errors across 119 files on develop, primarily React 18/19 type conflicts and locally unbuilt domain package exports. No typecheck error is reported in the new utility or test.

🎥 Demo

Non-existent token deeplink:

ledgerlive://market/ethereum/erc20/does_not_exist

pr-19807-nonexistent-token-deeplink.mp4

❓ Context


🧐 Checklist for the PR Reviewers

  • The code aligns with the requirements described in the linked JIRA or GitHub issue.
  • The PR description clearly documents the changes made and explains any technical trade-offs or design decisions.
  • There are no undocumented trade-offs, technical debt, or maintainability issues.
  • The PR has been tested thoroughly, and any potential edge cases have been considered and handled.
  • Any new dependencies have been justified and documented.
  • Performance considerations have been taken into account. (changes have been profiled or benchmarked if necessary)

Copilot AI review requested due to automatic review settings July 20, 2026 21:58
@live-github-bot live-github-bot Bot added the mobile Has changes in LLM label Jul 20, 2026
@sarneijim
sarneijim marked this pull request as ready for review July 20, 2026 21:58
@sarneijim
sarneijim requested a review from a team as a code owner July 20, 2026 21:58
@live-github-bot live-github-bot Bot changed the title fix(mobile): reset navigation for token deeplinks [LWM] fix(mobile): reset navigation for token deeplinks Jul 20, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Web Tools Build Status

Build Status Deployment
Web Tools Build ⏭️ Skipped
Native Storybook Build ⏭️ Skipped
React Storybook Build ⏭️ Skipped

Copilot AI 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.

Pull request overview

This PR mitigates an iOS crash scenario in Ledger Wallet Mobile where sequential token Asset Detail deeplinks can reuse an existing route, by forcing token deeplink navigation to dispatch a reset action (remounting the screen) while leaving other deeplinks’ navigation behavior unchanged.

Changes:

  • Overrides React Navigation linking’s getActionFromState to reset navigation only for token Asset Detail deeplink states.
  • Adds a feature-scoped MVVM utility to detect token Asset Detail deeplink states and generate the appropriate action.
  • Adds Jest coverage to validate reset behavior for token deeplinks and default behavior for coin + stake deeplinks.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
apps/ledger-live-mobile/src/navigation/DeeplinksProvider.tsx Hooks the custom getActionFromState into the app’s deeplink linking config.
apps/ledger-live-mobile/src/mvvm/features/AssetDetail/utils/getActionFromAssetDetailDeeplinkState.ts Implements token-AssetDetail state detection and emits a reset action for those deeplinks.
apps/ledger-live-mobile/src/mvvm/features/AssetDetail/utils/tests/getActionFromAssetDetailDeeplinkState.test.ts Adds unit tests asserting RESET for token Asset Detail states and NAVIGATE for coin/stake cases.
.changeset/calm-tokens-reset.md Declares the mobile release note/version bump for the navigation behavior change.

@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Rsdoctor Bundle Diff Analysis

Found 7 projects in monorepo, 1 project with changes.

📊 Quick Summary
Project Total Size Change
desktop-main 2.8 MB 0
desktop-preloader 7.1 KB 0
desktop-renderer 80.7 MB 0
desktop-webviewDappPreloader 36.9 KB 0
desktop-webviewPreloader 200.0 B 0
desktop-workers 36.8 KB 0
mobile 260.9 MB +6.2 KB (0.0%)
📋 Detailed Reports (Click to expand)

📁 mobile

Path: rsdoctor/mobile/rsdoctor-data.json

📌 Baseline Commit: 61cc19c5e5 | PR: #19873

Metric Current Baseline Change
📊 Total Size 260.9 MB 260.9 MB +6.2 KB (0.0%)
📄 JavaScript 110.0 MB 110.0 MB +2.7 KB (0.0%)
🎨 CSS 0 B 0 B 0
🌐 HTML 0 B 0 B 0
📁 Other Assets 150.9 MB 150.9 MB +3.5 KB (0.0%)

📦 Download Diff Report: mobile Bundle Diff

Generated by Rsdoctor GitHub Action

Copilot AI review requested due to automatic review settings July 20, 2026 22:37
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ E2E tests are required

Changes detected require e2e testing before merge (even before asking for any review).

📱 Mobile

-> Run Mobile E2E

  • Select "Run workflow"
  • Branch: bugfix/fix-token-deeplink-navigation
  • Device: nanoX

Copilot AI 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.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

@sarneijim
sarneijim force-pushed the bugfix/fix-token-deeplink-navigation branch from 3e6f8d2 to 7d6d2bd Compare July 20, 2026 22:44
Copilot AI review requested due to automatic review settings July 20, 2026 23:05

Copilot AI 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.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

apps/ledger-live-mobile/src/mvvm/features/AssetDetail/utils/getActionFromAssetDetailDeeplinkState.ts:17

  • hasMarketStateParam narrows params to object, but then reads params.marketState directly. This defeats the purpose of taking unknown (and can fail type-checking under strict settings). It’s safer to cast to a dictionary type and use hasOwnProperty to avoid matching prototype properties.
function hasMarketStateParam(params: unknown): params is { marketState: unknown } {
  if (typeof params !== "object" || params === null) {
    return false;
  }

  return "marketState" in params && params.marketState !== undefined;
}

LucasWerey
LucasWerey previously approved these changes Jul 21, 2026
Copilot AI review requested due to automatic review settings July 21, 2026 15:36
@sarneijim
sarneijim requested a review from LucasWerey July 21, 2026 15:41

Copilot AI 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.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings July 21, 2026 15:45

Copilot AI 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.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.

Comment on lines 1 to 5
import React, { useEffect, useLayoutEffect } from "react";
import type { NativeStackHeaderRightProps } from "@react-navigation/native-stack";
import { useNavigation } from "@react-navigation/native";
import type { CompositeNavigationProp } from "@react-navigation/native";
import { NativeStackNavigationProp } from "@react-navigation/native-stack";
Copilot AI review requested due to automatic review settings July 21, 2026 21:43

Copilot AI 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.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated no new comments.

const Stack = createNativeStackNavigator<BaseNavigatorStackParamList, typeof BASE_NAVIGATOR_ID>();
const MARKET_LIST_TEST_ID = "market-list-screen";

function MarketListScreen() {

@LucasWerey LucasWerey Jul 22, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we should use a real existing screen rather than creating a non-existent one so we can test the real behavior

const { currency, coinOptions, shouldRedirectToMarket } = viewModel;
const navigation = useNavigation<NavigationProps>();

useEffect(() => {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You should do it in the viewModel file

@LucasWerey

Copy link
Copy Markdown
Member

Can you add a demo video please

Reset nested asset-detail navigation state for token deeplinks.

Redirect unresolved token assets to Market while preserving loading and error states.

Co-authored-by: Cursor <cursoragent@cursor.com>
@sarneijim
sarneijim force-pushed the bugfix/fix-token-deeplink-navigation branch from 639db7a to de69968 Compare July 22, 2026 10:11
@sonarqubecloud

Copy link
Copy Markdown

Copilot AI review requested due to automatic review settings July 22, 2026 18:48

Copilot AI 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.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated no new comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

mobile Has changes in LLM

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants