Skip to content

feat(hw): qr wallet consumer wiring. #29087

Merged
montelaidev merged 35 commits into
mainfrom
feat/mul-1507-split-5-consumers
Apr 28, 2026
Merged

feat(hw): qr wallet consumer wiring. #29087
montelaidev merged 35 commits into
mainfrom
feat/mul-1507-split-5-consumers

Conversation

@montelaidev

@montelaidev montelaidev commented Apr 21, 2026

Copy link
Copy Markdown
Contributor

Description

This PR is split 5 of the QR hardware wallet feature (MUL-1507). It migrates the transaction signing consumers — RootRPCMethodsUI, Transactions view, and useUnifiedTxActions — from the old per-site Ledger modal navigation pattern to the shared executeHardwareWalletOperation utility and useHardwareWallet context hook introduced in splits 3–4. This ensures both Ledger and QR hardware wallets use a single, unified signing flow with consistent device readiness checks, awaiting-confirmation UI, error handling, and rejection callbacks.

Changelog

CHANGELOG entry: QR wallet shares the signing flow with Ledger now.

Related issues

Related to: https://consensyssoftware.atlassian.net/browse/MUL-1741

Manual testing steps

Feature: Hardware wallet transaction signing via shared flow
  Scenario: User signs a new transaction with a Ledger hardware wallet
    Given the user has a Ledger hardware wallet account
    And the user is on the transaction confirmation screen
    When the user confirms the transaction
    Then the shared hardware wallet execution flow runs
    And the awaiting-confirmation bottom sheet appears
    And the transaction is signed via ApprovalController.acceptRequest

  Scenario: User speeds up a transaction with a Ledger hardware wallet
    Given the user has a Ledger hardware wallet account
    And the user has a pending transaction
    When the user taps "Speed up" and confirms the gas fee
    Then the shared hardware wallet execution flow runs
    And the transaction is sped up with the correct gas fee params
  
Scenario: User cancels a transaction with a Ledger hardware wallet
    Given the user has a Ledger hardware wallet account
    And the user has a pending transaction
    When the user taps "Cancel" and confirms
    Then the shared hardware wallet execution flow runs
    And stopTransaction is called with the correct gas fee params
  
Scenario: User rejects a speed up on the awaiting-confirmation sheet
    Given the user has a Ledger hardware wallet account
    And the speed up awaiting-confirmation bottom sheet is open
    When the user taps the reject button
    Then the speed up modal state is cleaned up
    And speedUpIsOpen is false and speedUpTxId is null
  
Scenario: User rejects a cancel on the awaiting-confirmation sheet
    Given the user has a Ledger hardware wallet account
    And the cancel awaiting-confirmation bottom sheet is open
    When the user taps the reject button
    Then the cancel modal state is cleaned up
    And cancelIsOpen is false and cancelTxId is null
  
Scenario: Speed up with EIP-1559 gas fees
    Given the user has a Ledger hardware wallet account
    And the user has a pending transaction with EIP-1559 gas fees
    When the user speeds up the transaction
    Then maxFeePerGas and maxPriorityFeePerGas are passed to speedUpTx
  
Scenario: Speed up with legacy gas price
    Given the user has a Ledger hardware wallet account
    And the user has a pending transaction with legacy gas price
    When the user speeds up the transaction
    Then gasPrice is passed to speedUpTx

Screenshots/Recordings

Before

After

Pre-merge author checklist

Performance checks (if applicable)

  • I've tested on Android
    • Ideally on a mid-range device; emulator is acceptable
  • I've tested with a power user scenario
    • Use these power-user SRPs to import wallets with many accounts and tokens
  • I've instrumented key operations with Sentry traces for production performance metrics

For performance guidelines and tooling, see the Performance Guide.

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

Note

Medium Risk
Refactors hardware-wallet transaction signing, speed-up, and cancel paths to use a new shared execution utility and context, which can affect approval acceptance/rejection and modal lifecycle. Risk is mitigated by extensive updated test coverage but impacts core transaction flows for hardware wallets.

Overview
Unifies hardware-wallet transaction signing across the app. RootRPCMethodsUI, Transactions, and useUnifiedTxActions now route Ledger signing (including speed-up/cancel replacements) through executeHardwareWalletOperation + useHardwareWallet for consistent device-readiness checks, awaiting-confirmation UI, and rejection handling, while QR signing continues to navigate to the QR signing modal.

Consolidates QR signing state into the hardware wallet context. Removes the standalone QRSigningContext, adds a qr sub-state on HardwareWalletContext, and memoizes the provider’s qr value to keep context references stable.

Tests updated/expanded to cover the new shared flow (accept/reject paths, cancel analytics, gas param normalization for replacements, modal close behavior) and provider/context memoization.

Reviewed by Cursor Bugbot for commit 5e70ff7. Bugbot is set up for automated code reviews on this repo. Configure here.

Add normalizeReplacementGasFeeParams gas utility, getDeviceIdForAddress
helper, QR connection tips, widen setTargetWalletType type, and refactor
LedgerTransactionModal to use normalizeReplacementGasFeeParams.
Add QRSigningContext for QR hardware wallet signing state, useQRSigningState
hook for managing QR scan request lifecycle, and export from index files.
Add shared utility that runs hardware wallet operations behind the
standard readiness + awaiting-confirmation flow. Includes foundation
helpers (getDeviceIdForAddress, normalizeReplacementGasFeeParams) as
prerequisites.
- useDeviceConnectionFlow: skip device discovery for QR wallets, walletType-aware
  ready handling
- HardwareWalletProvider: integrate QRSigningContext, bug fixes for reject ref
  cleanup and double close
- AwaitingConfirmationContent: full QR signing UI with QR code display, scanner,
  error handling, and scan result verification
Replace wallet-type-specific modal navigation (LedgerTransactionModal,
QRSigningTransactionModal) in RootRPCMethodsUI, Transactions, and
useUnifiedTxActions with the shared executeHardwareWalletOperation flow.
This unifies Ledger and QR hardware wallet signing behind a single code path.
@github-actions

Copy link
Copy Markdown
Contributor

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@metamaskbotv2 metamaskbotv2 Bot added the team-accounts-framework Accounts team label Apr 21, 2026
pull Bot pushed a commit to Reality2byte/metamask-mobile that referenced this pull request Apr 21, 2026
…29083)

<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

Adds:

- `QRSigningContext` for QR hardware wallet signing state
- `useQRSigningState` hook for managing QR scan request lifecycle
- Index files. 

Note: This is currently dead code until 

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: null

## **Related issues**

Related to: https://consensyssoftware.atlassian.net/browse/MUL-1741

## **Manual testing steps**

This can only be tested via
MetaMask#29087

## **Screenshots/Recordings**

Not applicable

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: adds new QR-signing context/hook and tests without modifying
existing signing/connection flows; primary risk is incorrect
cancellation/completion behavior once wired into navigation.
> 
> **Overview**
> Adds a new `QRSigningContext` (and `useQRSigning`) to standardize
access to pending QR keyring scan requests and related lifecycle
actions.
> 
> Introduces `useQRSigningState`, which derives the current pending scan
request from Redux, tracks per-request completion state, and provides
`cancelQRScanRequestIfPresent()` to reject an active SIGN request via
the QR keyring scanner. Exports the new context/hook via the
HardwareWallet `contexts`/`hooks` index files and adds unit tests for
both the context guard and hook behavior.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
fbe188d. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…ress

The provider now auto-derives the wallet type from the pending operation
address, so callers only need to supply the address — not the wallet type.
This removes the need for executeHardwareWalletOperation to compute and
forward the wallet type explicitly.
…ationAddress

LedgerSelectAccount uses setTargetWalletType for the Add Hardware Wallet
flow, so it must remain in the context interface unchanged.
Add pendingOperationAddress state to the provider. The effective wallet
type is now derived from targetWalletType OR the pending operation address
OR the selected account, keeping setTargetWalletType unchanged for
Add Hardware Wallet flows.
…gOperationAddress

The provider now auto-derives wallet type from the pending operation address,
so consumers pass setPendingOperationAddress instead of setTargetWalletType.
@montelaidev montelaidev force-pushed the feat/mul-1507-split-5-consumers branch from 209ec3a to 560d797 Compare April 22, 2026 01:50
pull Bot pushed a commit to Reality2byte/metamask-mobile that referenced this pull request Apr 23, 2026
…ger (MetaMask#29084)

<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: null

## **Related issues**

Related to: https://consensyssoftware.atlassian.net/browse/MUL-1741

## **Manual testing steps**

This can only be tested via
MetaMask#29087

## **Screenshots/Recordings**

Not applicable

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Medium risk because it changes the gas fee parameters forwarded into
cancel/speed-up transaction flows and adjusts hardware wallet context
typing, which could affect transaction replacement behavior and hardware
wallet connection UX.
> 
> **Overview**
> Improves hardware-wallet and replacement-transaction handling by
**normalizing replacement gas fee params** before calling
`speedUpTransaction`/`stopTransaction`, ensuring only complete
controller-supported fee fields are forwarded (otherwise `undefined`).
Tests were added to cover legacy vs EIP-1559 normalization and the
incomplete-fee edge case in `LedgerTransactionModal`.
> 
> Extends hardware wallet utilities by adding `getDeviceIdForAddress`
(Ledger-only) and updating connection tips to include **QR-specific
guidance** with new i18n strings. The hardware wallet context API is
also loosened to allow `setTargetWalletType(null)`.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
da33c39. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
@montelaidev montelaidev changed the base branch from main to feat/mul-1507-split-4-connection-ui April 24, 2026 09:11
Comment thread app/components/UI/Transactions/index.js Outdated
Comment thread app/components/UI/Transactions/index.js Outdated
Comment thread app/components/UI/Transactions/index.js
Comment thread app/components/Views/UnifiedTransactionsView/useUnifiedTxActions.ts
Comment thread app/components/Nav/Main/RootRPCMethodsUI.test.js Outdated
Comment thread app/components/UI/Transactions/index.test.tsx
Comment thread app/components/Views/UnifiedTransactionsView/useUnifiedTxActions.test.ts Outdated
Comment thread app/components/Views/UnifiedTransactionsView/useUnifiedTxActions.ts
Base automatically changed from feat/mul-1507-split-4-connection-ui to main April 24, 2026 14:55
Comment thread app/core/HardwareWallet/HardwareWalletProvider.tsx

@cursor cursor 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.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit b57d458. Configure here.

Comment thread app/components/Nav/Main/RootRPCMethodsUI.js Outdated
Comment thread app/components/Nav/Main/RootRPCMethodsUI.js Outdated
@github-actions

Copy link
Copy Markdown
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokeAccounts, SmokeConfirmations, SmokeWalletPlatform
  • Selected Performance tags: None (no tests recommended)
  • Risk Level: high
  • AI Confidence: 82%
click to see 🤖 AI reasoning details

E2E Test Selection:

The PR makes significant architectural changes to the HardwareWallet subsystem:

  1. QRSigningContext elimination: The separate QRSigningContext React context has been removed and its state merged into HardwareWalletContext as a qr property. This is a breaking API change for any component consuming useQRSigning() - now they must use useHardwareWallet().qr. The AwaitingConfirmationContent.tsx has been updated accordingly.

  2. RootRPCMethodsUI.js refactoring: The auto-sign flow for hardware wallet transactions (triggered by dApps) has been significantly changed. Ledger-specific navigation via createLedgerTransactionModalNavDetails has been removed and replaced with executeHardwareWalletOperation. This affects how dApp-initiated transactions are handled for Ledger accounts.

  3. Transactions/index.js and useUnifiedTxActions.ts: The signLedgerTransaction function has been rewritten - no longer navigates to the Ledger modal, instead uses executeHardwareWalletOperation. This affects speed-up and cancel flows for Ledger transactions.

Tag Selection Rationale:

  • SmokeAccounts: Directly covers "adding QR-based hardware wallet accounts" - the QR signing context refactoring affects this flow. The context API change could break QR hardware wallet account addition.
  • SmokeConfirmations: The transaction signing flow for hardware wallets (both Ledger and QR) has been substantially changed in RootRPCMethodsUI.js, Transactions/index.js, and useUnifiedTxActions.ts. Transaction confirmations, speed-up, and cancel flows for hardware wallet accounts are all affected.
  • SmokeWalletPlatform: The Transactions/index.js component (transaction history display) has been modified with the hardware wallet integration changes. This component is used in the wallet's transaction history view, which is tested under SmokeWalletPlatform (incoming-transactions.spec.ts).

No performance tests are needed as these are architectural/refactoring changes to hardware wallet context management, not UI rendering or data loading performance-sensitive code.

Performance Test Selection:
The changes are architectural refactoring of the HardwareWallet context system (merging QRSigningContext into HardwareWalletContext) and replacing Ledger modal navigation with executeHardwareWalletOperation. These are not performance-sensitive changes - they don't affect UI rendering performance, data loading, account/network list components, or app startup. No performance tests are warranted.

View GitHub Actions results

@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown
Contributor

E2E Fixture Validation — Schema is up to date
12 value mismatches detected (expected — fixture represents an existing user).
View details

@ccharly ccharly 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.

LGTM (not tested)

@montelaidev montelaidev self-assigned this Apr 27, 2026
@montelaidev montelaidev added this pull request to the merge queue Apr 28, 2026
Merged via the queue into main with commit 84c0b14 Apr 28, 2026
106 of 107 checks passed
@montelaidev montelaidev deleted the feat/mul-1507-split-5-consumers branch April 28, 2026 00:42
@github-actions github-actions Bot locked and limited conversation to collaborators Apr 28, 2026
@metamaskbotv2 metamaskbotv2 Bot added the release-7.76.0 Issue or pull request that will be included in release 7.76.0 label Apr 28, 2026
@montelaidev montelaidev restored the feat/mul-1507-split-5-consumers branch April 28, 2026 00:55
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

release-7.76.0 Issue or pull request that will be included in release 7.76.0 risk:high AI analysis: high risk size-XL team-accounts-framework Accounts team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants