Skip to content

Commit a9c779f

Browse files
authored
fix: qr scanner appearing before the confirmations screen cp-7.77.0 (#30088)
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** This PR fixes the issue where the qr scanning appears before the confirmation screen. <!-- 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: fixes the the qr scanner appearing before confirmations page ## **Related issues** Fixes: #29949 ## **Manual testing steps** ```gherkin Scenario: QR hardware wallet transaction shows confirmation screen first Given the user has a QR hardware wallet account (e.g. Keystone) set up And the user is on that QR account in MetaMask When the user initiates a send transaction to an address Then the confirmation screen is displayed (NOT the QR scanner) And the user sees transaction details (amount, recipient, gas) Scenario: QR hardware wallet user confirms a transaction Given the user is on the confirmation screen for a QR account transaction When the user taps "Confirm" Then the QR scanner screen appears And the app waits for the QR code scan to complete the transaction Scenario: QR hardware wallet user rejects a transaction Given the user is on the confirmation screen for a QR account transaction When the user taps "Reject" Then the transaction is cancelled And the QR scanner does NOT appear Scenario: QR hardware wallet signature request shows confirmation first Given the user is on a QR hardware wallet account When a dApp requests a signature (personal_sign or eth_signTypedData) Then the confirmation screen is displayed And the QR scanner does NOT appear until the user taps "Confirm" Scenario: QR hardware wallet signature request shows QRInfo after confirm Given the user is on the confirmation screen for a QR account signature request When the user taps "Confirm" Then the QR scanner / QRInfo view is shown And the user can scan the QR code to complete signing ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** https://github.com/user-attachments/assets/ee6004b2-2f63-47b2-b007-d623b7ed990e https://github.com/user-attachments/assets/9798e0f2-6756-4e4b-87fd-ee2cc1ebf98b <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [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** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] 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** > Changes confirmation submit flow for QR hardware wallets by adding new state and altering when scanning UI is shown; mistakes could block or prematurely trigger signing for QR accounts. Scope is contained to confirmations/QR hardware paths with updated tests. > > **Overview** > Prevents the QR scanner/`QRInfo` view from appearing before the confirmations screen by introducing `signingConfirmed` in `QRHardwareContext` and only rendering `QRInfo` when QR signing is active *and* the user has confirmed. > > Updates `useConfirmActions` so tapping Confirm during an in-progress QR signing session sets `signingConfirmed` and explicitly shows the scanner, while still delegating to `useQrConfirm` for QR-hardware accounts; also ensures `signingConfirmed` is set before executing the default approval/transaction paths. > > Adjusts QR confirm UX so `useQrConfirm` re-shows the awaiting-confirmation bottom sheet when QR signing is already in progress (instead of opening the `QRInfo` scanner), and updates footer behavior/tests so the button label remains `Confirm` during QR signing. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 864f724. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent e3a3c5f commit a9c779f

11 files changed

Lines changed: 138 additions & 47 deletions

File tree

app/components/Views/confirmations/components/footer/footer.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,14 +160,14 @@ describe('Footer', () => {
160160
});
161161
});
162162

163-
it('renders confirm button text "Get signature" if QR signing is in progress', () => {
163+
it('renders confirm button text "Confirm" even if QR signing is in progress', () => {
164164
jest.spyOn(QRHardwareHook, 'useQRHardwareContext').mockReturnValue({
165165
isSigningQRObject: true,
166166
} as QRHardwareHook.QRHardwareContextType);
167167
const { getByText } = renderWithProvider(<Footer />, {
168168
state: personalSignatureConfirmationState,
169169
});
170-
expect(getByText('Get signature')).toBeTruthy();
170+
expect(getByText('Confirm')).toBeTruthy();
171171
});
172172

173173
it('confirm button is disabled if `needsCameraPermission` is true', () => {

app/components/Views/confirmations/components/footer/footer.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import { PredictClaimFooter } from '../predict-confirmations/predict-claim-foote
3939
import { useIsTransactionPayLoading } from '../../hooks/pay/useTransactionPayData';
4040
import { Skeleton } from '../../../../../component-library/components-temp/Skeleton';
4141
import { useQRHardwareContext } from '../../context/qr-hardware-context';
42+
import { useIsConfirmationFromQrAccount } from '../../../../../core/HardwareWallet/hooks/useIsConfirmationFromQrAccount';
4243
import { useIsGaslessLoading } from '../../hooks/gas/useIsGaslessLoading';
4344

4445
const HIDE_FOOTER_BY_DEFAULT_TYPES = [
@@ -61,7 +62,7 @@ export const Footer = () => {
6162
hasUnconfirmedDangerAlerts,
6263
} = useAlerts();
6364
const { onConfirm, onReject } = useConfirmActions();
64-
const { isSigningQRObject, needsCameraPermission } = useQRHardwareContext();
65+
const { needsCameraPermission } = useQRHardwareContext();
6566
const { securityAlertResponse } = useSecurityAlertResponse();
6667
const transactionMetadata = useTransactionMetadataRequest();
6768
const { trackAlertMetrics } = useConfirmationAlertMetrics();
@@ -121,10 +122,6 @@ export const Footer = () => {
121122
});
122123

123124
const confirmButtonLabel = () => {
124-
if (isSigningQRObject) {
125-
return strings('confirm.qr_get_sign');
126-
}
127-
128125
if (isPayLoading) {
129126
return strings('confirm.confirm');
130127
}

app/components/Views/confirmations/components/info-root/info-root.test.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,10 @@ describe('Info', () => {
174174
).toBeDefined();
175175
});
176176

177-
it('renders QRInfo if user is signing using QR hardware', () => {
177+
it('renders QRInfo if user is signing using QR hardware and has confirmed', () => {
178178
jest.spyOn(QRHardwareHook, 'useQRHardwareContext').mockReturnValue({
179179
isSigningQRObject: true,
180+
signingConfirmed: true,
180181
} as unknown as QRHardwareHook.QRHardwareContextType);
181182
const { getByTestId } = renderWithProvider(<Info />, {
182183
state: personalSignatureConfirmationState,

app/components/Views/confirmations/components/info-root/info-root.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ interface InfoProps {
8888
const Info = ({ route }: InfoProps) => {
8989
const { approvalRequest } = useApprovalRequest();
9090
const transactionMetadata = useTransactionMetadataRequest();
91-
const { isSigningQRObject } = useQRHardwareContext();
91+
const { isSigningQRObject, signingConfirmed } = useQRHardwareContext();
9292
const { isDowngrade, isUpgradeOnly } = use7702TransactionType();
9393
// Refresh STX liveness for the transaction's network
9494
useRefreshSmartTransactionsLiveness(transactionMetadata?.chainId);
@@ -102,7 +102,7 @@ const Info = ({ route }: InfoProps) => {
102102
return <SwitchAccountType />;
103103
}
104104

105-
if (isSigningQRObject) {
105+
if (isSigningQRObject && signingConfirmed) {
106106
return <QRInfo />;
107107
}
108108

app/components/Views/confirmations/context/qr-hardware-context/qr-hardware-context.test.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ jest.mock('../../hooks/useIsConfirmationFromLedgerAccount', () => ({
105105
jest.mock(
106106
'../../../../../core/HardwareWallet/hooks/useIsConfirmationFromQrAccount',
107107
() => ({
108-
useIsConfirmationFromQrAccount: jest.fn(() => true),
108+
useIsConfirmationFromQrAccount: jest.fn(() => false),
109109
}),
110110
);
111111

@@ -229,7 +229,7 @@ describe('QRHardwareContext', () => {
229229
expect(getByText('Scan with your hardware wallet')).toBeTruthy();
230230
});
231231

232-
it('passes correct value of scannerVisible to child components', async () => {
232+
it('renders Confirm button when QR signing is in progress', async () => {
233233
createCameraSpy({ cameraError: undefined, hasCameraPermission: true });
234234
createQRHardwareAwarenessSpy({
235235
isSigningQRObject: true,
@@ -246,10 +246,7 @@ describe('QRHardwareContext', () => {
246246
state: personalSignatureConfirmationState,
247247
},
248248
);
249-
await userEvent.press(getByText('Get signature'));
250-
expect(
251-
getByText('Scan your hardware wallet to confirm the transaction'),
252-
).toBeTruthy();
249+
expect(getByText('Confirm')).toBeTruthy();
253250
});
254251
});
255252

app/components/Views/confirmations/context/qr-hardware-context/qr-hardware-context.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ export interface QRHardwareContextType {
2222
scannerVisible: boolean;
2323
setRequestCompleted: () => void;
2424
setScannerVisible: (visibility: boolean) => void;
25+
setSigningConfirmed: () => void;
26+
signingConfirmed: boolean;
2527
}
2628

2729
export const QRHardwareContext = createContext<QRHardwareContextType>({
@@ -33,6 +35,8 @@ export const QRHardwareContext = createContext<QRHardwareContextType>({
3335
scannerVisible: false,
3436
setRequestCompleted: () => undefined,
3537
setScannerVisible: () => undefined,
38+
setSigningConfirmed: () => undefined,
39+
signingConfirmed: false,
3640
});
3741

3842
export const QRHardwareContextProvider: React.FC<{
@@ -43,6 +47,7 @@ export const QRHardwareContextProvider: React.FC<{
4347
const { cameraError, hasCameraPermission } = useCamera(isSigningQRObject);
4448
const [scannerVisible, setScannerVisible] = useState(false);
4549
const [isRequestCompleted, setRequestCompleted] = useState(false);
50+
const [signingConfirmed, setSigningConfirmed] = useState(false);
4651

4752
const cancelRequest = useCallback(
4853
(e: { preventDefault: () => void; data: { action: NavigationAction } }) => {
@@ -87,6 +92,8 @@ export const QRHardwareContextProvider: React.FC<{
8792
scannerVisible,
8893
setRequestCompleted: () => setRequestCompleted(true),
8994
setScannerVisible,
95+
setSigningConfirmed: () => setSigningConfirmed(true),
96+
signingConfirmed,
9097
}}
9198
>
9299
{children}

app/components/Views/confirmations/hooks/send/useSendActions.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,20 +77,20 @@ describe('useSendActions', () => {
7777
expect(result.current.handleCancelPress).toBeDefined();
7878
});
7979

80-
it('calls navigation.navigate with correct params when evm ', () => {
80+
it('calls navigation.navigate with correct params when evm ', async () => {
8181
const { result } = renderHookWithProvider(
8282
() => useSendActions(),
8383
mockState,
8484
);
8585
jest.spyOn(SendUtils, 'submitEvmTransaction').mockImplementation(jest.fn());
86-
result.current.handleSubmitPress();
86+
await result.current.handleSubmitPress();
8787
expect(mockNavigate).toHaveBeenCalledWith('RedesignedConfirmations', {
8888
params: { maxValueMode: undefined },
8989
loader: 'transfer',
9090
});
9191
});
9292

93-
it('normalizes trailing dot values before submitting evm transaction', () => {
93+
it('normalizes trailing dot values before submitting evm transaction', async () => {
9494
mockUseSendContext.mockReturnValue({
9595
asset: {
9696
chainId: '0x1',
@@ -111,7 +111,7 @@ describe('useSendActions', () => {
111111
() => useSendActions(),
112112
mockState,
113113
);
114-
result.current.handleSubmitPress();
114+
await result.current.handleSubmitPress();
115115

116116
expect(submitSpy).toHaveBeenCalledWith(
117117
expect.objectContaining({ value: '0' }),

app/components/Views/confirmations/hooks/useConfirmActions.test.ts

Lines changed: 76 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ jest.mock('../../../../core/HardwareWallet/hooks/useQrConfirm', () => ({
3636
useQrConfirm: () => ({ onConfirm: mockOnQrConfirm }),
3737
}));
3838

39+
const mockIsConfirmationFromQrAccount = jest.requireMock(
40+
'../../../../core/HardwareWallet/hooks/useIsConfirmationFromQrAccount',
41+
).useIsConfirmationFromQrAccount;
42+
3943
jest.mock('@react-navigation/native', () => ({
4044
...jest.requireActual('@react-navigation/native'),
4145
useNavigation: jest.fn(),
@@ -91,34 +95,50 @@ describe('useConfirmAction', () => {
9195
});
9296
});
9397

94-
it('delegates to useQrConfirm when QR signing is in progress', async () => {
98+
it('sets signing confirmed and shows scanner when QR signing is in progress', async () => {
9599
const clearSecurityAlertResponseSpy = jest.spyOn(
96100
PPOMUtil,
97101
'clearSignatureSecurityAlertResponse',
98102
);
99-
const { useIsConfirmationFromQrAccount } = jest.requireMock(
100-
'../../../../core/HardwareWallet/hooks/useIsConfirmationFromQrAccount',
101-
);
102-
useIsConfirmationFromQrAccount.mockReturnValue(true);
103-
103+
const mockSetScannerVisible = jest.fn().mockResolvedValue(undefined);
104+
const mockSetSigningConfirmed = jest.fn();
105+
jest.spyOn(QRHardwareHook, 'useQRHardwareContext').mockReturnValue({
106+
isSigningQRObject: true,
107+
setScannerVisible: mockSetScannerVisible,
108+
setSigningConfirmed: mockSetSigningConfirmed,
109+
} as unknown as QRHardwareHook.QRHardwareContextType);
104110
const { result } = renderHookWithProvider(() => useConfirmActions(), {
105111
state: personalSignatureConfirmationState,
106112
});
107-
await result?.current?.onConfirm();
108-
expect(mockOnQrConfirm).toHaveBeenCalledTimes(1);
113+
result?.current?.onConfirm();
114+
expect(mockSetSigningConfirmed).toHaveBeenCalledTimes(1);
115+
expect(mockSetScannerVisible).toHaveBeenCalledTimes(1);
116+
expect(mockSetScannerVisible).toHaveBeenLastCalledWith(true);
109117
expect(Engine.acceptPendingApproval).toHaveBeenCalledTimes(0);
110118
await flushPromises();
111119
expect(mockCaptureSignatureMetrics).toHaveBeenCalledTimes(0);
112120
expect(clearSecurityAlertResponseSpy).toHaveBeenCalledTimes(0);
121+
});
122+
123+
it('delegates to useQrConfirm when account is QR hardware and request is a transaction', async () => {
124+
mockIsConfirmationFromQrAccount.mockReturnValue(true);
125+
mockOnQrConfirm.mockClear();
113126

114-
useIsConfirmationFromQrAccount.mockReturnValue(false);
127+
const { result } = renderHookWithProvider(() => useConfirmActions(), {
128+
state: stakingDepositConfirmationState,
129+
});
130+
131+
await result?.current?.onConfirm();
132+
133+
expect(mockOnQrConfirm).toHaveBeenCalledTimes(1);
134+
expect(Engine.acceptPendingApproval).not.toHaveBeenCalled();
135+
136+
mockIsConfirmationFromQrAccount.mockReturnValue(false);
115137
});
116138

117-
it('delegates to useQrConfirm when account is QR', async () => {
118-
const { useIsConfirmationFromQrAccount } = jest.requireMock(
119-
'../../../../core/HardwareWallet/hooks/useIsConfirmationFromQrAccount',
120-
);
121-
useIsConfirmationFromQrAccount.mockReturnValue(true);
139+
it('delegates to useQrConfirm when account is QR hardware and request is a signature', async () => {
140+
mockIsConfirmationFromQrAccount.mockReturnValue(true);
141+
mockOnQrConfirm.mockClear();
122142

123143
const { result } = renderHookWithProvider(() => useConfirmActions(), {
124144
state: personalSignatureConfirmationState,
@@ -129,7 +149,48 @@ describe('useConfirmAction', () => {
129149
expect(mockOnQrConfirm).toHaveBeenCalledTimes(1);
130150
expect(Engine.acceptPendingApproval).not.toHaveBeenCalled();
131151

132-
useIsConfirmationFromQrAccount.mockReturnValue(false);
152+
mockIsConfirmationFromQrAccount.mockReturnValue(false);
153+
});
154+
155+
it('calls setSigningConfirmed before executeApproval on default confirm path', async () => {
156+
const mockSetSigningConfirmed = jest.fn();
157+
jest.spyOn(QRHardwareHook, 'useQRHardwareContext').mockReturnValue({
158+
isSigningQRObject: false,
159+
setScannerVisible: jest.fn(),
160+
setSigningConfirmed: mockSetSigningConfirmed,
161+
} as unknown as QRHardwareHook.QRHardwareContextType);
162+
const { result } = renderHookWithProvider(() => useConfirmActions(), {
163+
state: personalSignatureConfirmationState,
164+
});
165+
result?.current?.onConfirm();
166+
expect(mockSetSigningConfirmed).toHaveBeenCalledTimes(1);
167+
expect(Engine.acceptPendingApproval).toHaveBeenCalledTimes(1);
168+
await flushPromises();
169+
});
170+
171+
it('calls setSigningConfirmed before confirming a transaction', async () => {
172+
const mockSetSigningConfirmed = jest.fn();
173+
const mockTransactionConfirm = jest.fn().mockResolvedValue(undefined);
174+
useTransactionConfirmMock.mockReturnValue({
175+
onConfirm: mockTransactionConfirm,
176+
});
177+
jest.spyOn(QRHardwareHook, 'useQRHardwareContext').mockReturnValue({
178+
isSigningQRObject: false,
179+
setScannerVisible: jest.fn(),
180+
setSigningConfirmed: mockSetSigningConfirmed,
181+
} as unknown as QRHardwareHook.QRHardwareContextType);
182+
183+
const { result } = renderHookWithProvider(() => useConfirmActions(), {
184+
state: stakingDepositConfirmationState,
185+
});
186+
187+
await result?.current?.onConfirm();
188+
189+
expect(mockSetSigningConfirmed).toHaveBeenCalledTimes(1);
190+
expect(mockTransactionConfirm).toHaveBeenCalledTimes(1);
191+
expect(mockSetSigningConfirmed.mock.invocationCallOrder[0]).toBeLessThan(
192+
mockTransactionConfirm.mock.invocationCallOrder[0],
193+
);
133194
});
134195

135196
it('delegates to useLedgerConfirm when account is Ledger', async () => {

app/components/Views/confirmations/hooks/useConfirmActions.ts

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { ApprovalType } from '@metamask/controller-utils';
55
import PPOMUtil from '../../../../lib/ppom/ppom-util';
66
import Routes from '../../../../constants/navigation/Routes';
77
import { MetaMetricsEvents } from '../../../../core/Analytics';
8+
89
import { isSignatureRequest } from '../utils/confirm';
910
import { useQRHardwareContext } from '../context/qr-hardware-context';
1011
import useApprovalRequest from './useApprovalRequest';
@@ -23,7 +24,12 @@ export const useConfirmActions = () => {
2324
} = useApprovalRequest();
2425
const { onConfirm: onTransactionConfirm } = useTransactionConfirm();
2526
const { captureSignatureMetrics } = useSignatureMetrics();
26-
const { cancelQRScanRequestIfPresent } = useQRHardwareContext();
27+
const {
28+
cancelQRScanRequestIfPresent,
29+
isSigningQRObject,
30+
setScannerVisible,
31+
setSigningConfirmed,
32+
} = useQRHardwareContext();
2733
const navigation = useNavigation();
2834
const approvalType = approvalRequest?.type;
2935
const isSignatureReq = approvalType && isSignatureRequest(approvalType);
@@ -85,7 +91,7 @@ export const useConfirmActions = () => {
8591
captureSignatureMetrics,
8692
]);
8793

88-
const hardwareConfirmOptions = useMemo(
94+
const sharedConfirmOptions = useMemo(
8995
() => ({
9096
onReject,
9197
onTransactionConfirm,
@@ -95,10 +101,8 @@ export const useConfirmActions = () => {
95101
[onReject, onTransactionConfirm, executeApproval, isTransactionReq],
96102
);
97103

98-
const { onConfirm: onLedgerConfirm } = useLedgerConfirm(
99-
hardwareConfirmOptions,
100-
);
101-
const { onConfirm: onQrConfirm } = useQrConfirm(hardwareConfirmOptions);
104+
const { onConfirm: onLedgerConfirm } = useLedgerConfirm(sharedConfirmOptions);
105+
const { onConfirm: onQrConfirm } = useQrConfirm(sharedConfirmOptions);
102106

103107
const onConfirm = useCallback(async () => {
104108
if (isLedgerAccount) {
@@ -111,16 +115,27 @@ export const useConfirmActions = () => {
111115
return;
112116
}
113117

118+
if (isSigningQRObject) {
119+
setSigningConfirmed();
120+
setScannerVisible(true);
121+
return;
122+
}
123+
114124
if (isTransactionReq) {
125+
setSigningConfirmed();
115126
await onTransactionConfirm();
116127
return;
117128
}
118129

130+
setSigningConfirmed();
119131
await executeApproval();
120132
}, [
121133
isLedgerAccount,
122134
isQrAccount,
135+
isSigningQRObject,
123136
isTransactionReq,
137+
setScannerVisible,
138+
setSigningConfirmed,
124139
onTransactionConfirm,
125140
executeApproval,
126141
onLedgerConfirm,

0 commit comments

Comments
 (0)