Skip to content

Commit b0bf4be

Browse files
authored
feat: gasless QR hardware wallet swap hooks, components, and utils. (MetaMask#42611)
<!-- 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** Add inline QR hardware wallet signing support for swap/bridge transactions. The global `QRHardwarePopover` is now suppressed on the bridge hardware wallet signing page to avoid conflicting with the inline signing experience. A new `useHwSwapQrState` hook manages QR wallet detection, sign request state, and provides handlers for successful scans and cancellations. Supporting utilities (`hardware-wallet-signatures.utils.ts`) handle step-status tracking, titles/labels, and QR request type guards, while two new UI components render the animated QR code (`QrSignatureCode`) and per-step status icons (`SignatureStatusIcon`). Shared types for bridge transaction history and QR sign request payloads are also included. <!-- 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-1717 ## **Manual testing steps** Not applicable. ## **Screenshots/Recordings** Not applicable. ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/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-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **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** > Touches swap/bridge signing, pending approval rejection, and tx cancellation on QR cancel; behavior is well covered by tests but affects transaction approval paths. > > **Overview** > Adds **inline QR hardware wallet signing** for swap/bridge flows: a dedicated route (`/swaps/hardware-wallet-signatures`), **`useHwSwapQrState`** to detect QR wallets, surface active sign requests, and handle scan success / cancel (including rejecting pending approvals and canceling txs), plus supporting UI and helpers. > > **`hardware-wallet-signatures.utils`** centralizes step progress (`getStepStatus`), copy (`getTitle`, step labels/descriptions), bridge approval lookup, and **`isQrHardwareSignRequest`**. New **`QrSignatureCode`** (animated UR QR fragments) and **`SignatureStatusIcon`** (per-step pending/active/complete/error UI) back the inline experience. > > The signature **state machine** is reorganized: types move to **`types.ts`**, reducer transitions use named handlers, and test helpers live under **`test-helpers`**. **`SignatureStepStatus`** and related bridge/QR types are extended in **`types.ts`**. Existing HW swap hook tests only update imports for the new helper path. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 22f88a5. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 42f1b96 commit b0bf4be

23 files changed

Lines changed: 2044 additions & 87 deletions

ui/helpers/constants/routes.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ export const CROSS_CHAIN_SWAP_TX_DETAILS_ROUTE = '/cross-chain/tx-details';
137137
export const PREPARE_SWAP_ROUTE = '/swaps/prepare-bridge-page';
138138
export const SWAP_PATH = `${CROSS_CHAIN_SWAP_ROUTE}${PREPARE_SWAP_ROUTE}`;
139139
export const AWAITING_SIGNATURES_ROUTE = '/swaps/awaiting-signatures';
140+
export const HARDWARE_WALLET_SIGNATURES_ROUTE =
141+
'/swaps/hardware-wallet-signatures';
140142
export const ONBOARDING_ROUTE = '/onboarding';
141143
export const ONBOARDING_REVEAL_SRP_ROUTE = '/onboarding/reveal-recovery-phrase';
142144
export const ONBOARDING_REVIEW_SRP_ROUTE = '/onboarding/review-recovery-phrase';
@@ -634,6 +636,11 @@ export const ROUTES = [
634636
label: 'Swaps Awaiting Signatures',
635637
trackInAnalytics: false,
636638
},
639+
{
640+
path: HARDWARE_WALLET_SIGNATURES_ROUTE,
641+
label: 'Swaps Hardware Wallet Signatures',
642+
trackInAnalytics: false,
643+
},
637644
{
638645
path: INITIALIZE_EXPERIMENTAL_AREA,
639646
label: 'Initialize Experimental Area',

ui/hooks/hardware-wallets/useHwSwapConfirmationMonitoring.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {
22
HardwareWalletSignatureEvent,
33
HardwareWalletSignatureStatus,
44
} from '../../pages/hardware-wallets/swap/hardware-wallet-signatures-state-machine';
5-
import { createSignatureState } from '../../pages/hardware-wallets/swap/hardware-wallet-signatures-state-machine.test-helpers';
5+
import { createSignatureState } from '../../pages/hardware-wallets/swap/hardware-wallet-signatures-state-machine/test-helpers';
66
import { renderHookWithProvider } from '../../../test/lib/render-helpers-navigate';
77
import { useHwSwapConfirmationMonitoring } from './useHwSwapConfirmationMonitoring';
88

ui/hooks/hardware-wallets/useHwSwapConnectionMonitoring.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
HardwareWalletSignatureEvent,
55
HardwareWalletSignatureStatus,
66
} from '../../pages/hardware-wallets/swap/hardware-wallet-signatures-state-machine';
7-
import { createSignatureState } from '../../pages/hardware-wallets/swap/hardware-wallet-signatures-state-machine.test-helpers';
7+
import { createSignatureState } from '../../pages/hardware-wallets/swap/hardware-wallet-signatures-state-machine/test-helpers';
88
import { renderHookWithProvider } from '../../../test/lib/render-helpers-navigate';
99
import { useHwSwapConnectionMonitoring } from './useHwSwapConnectionMonitoring';
1010

ui/hooks/hardware-wallets/useHwSwapNavigation.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { act } from '@testing-library/react-hooks';
22
import { HardwareWalletSignatureStatus } from '../../pages/hardware-wallets/swap/hardware-wallet-signatures-state-machine';
3-
import { createSignatureState } from '../../pages/hardware-wallets/swap/hardware-wallet-signatures-state-machine.test-helpers';
3+
import { createSignatureState } from '../../pages/hardware-wallets/swap/hardware-wallet-signatures-state-machine/test-helpers';
44
import { renderHookWithProvider } from '../../../test/lib/render-helpers-navigate';
55
import { useHwSwapNavigation } from './useHwSwapNavigation';
66

ui/hooks/hardware-wallets/useHwSwapSubmission.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
HardwareWalletSignatureEvent,
88
HardwareWalletSignatureStatus,
99
} from '../../pages/hardware-wallets/swap/hardware-wallet-signatures-state-machine';
10-
import { createSignatureState } from '../../pages/hardware-wallets/swap/hardware-wallet-signatures-state-machine.test-helpers';
10+
import { createSignatureState } from '../../pages/hardware-wallets/swap/hardware-wallet-signatures-state-machine/test-helpers';
1111
import { renderHookWithProvider } from '../../../test/lib/render-helpers-navigate';
1212
import { rejectPendingApproval } from '../../store/actions';
1313
import { useHwSwapSubmission } from './useHwSwapSubmission';

0 commit comments

Comments
 (0)