Skip to content

Commit 231f780

Browse files
committed
(wip) refactor: use @metamask/eth-qr-keyring
1 parent 7eaac6a commit 231f780

File tree

21 files changed

+396
-481
lines changed

21 files changed

+396
-481
lines changed

app/actions/modals/index.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,10 @@ export function toggleSignModal(show) {
3131
show,
3232
};
3333
}
34+
35+
export function toggleQrKeyringScanModal(show) {
36+
return {
37+
type: 'TOGGLE_QR_KEYRING_SCAN_MODAL',
38+
show,
39+
};
40+
}

app/components/Approvals/TransactionApproval/TransactionApproval.tsx

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import Approval from '../../Views/confirmations/legacy/Approval';
55
import Approve from '../../Views/confirmations/legacy/ApproveView/Approve';
66
import QRSigningModal from '../../UI/QRHardware/QRSigningModal';
77
import withQRHardwareAwareness from '../../UI/QRHardware/withQRHardwareAwareness';
8-
import { IQRState } from '../../UI/QRHardware/types';
98
import { useConfirmationRedesignEnabled } from '../../Views/confirmations/hooks/useConfirmationRedesignEnabled';
9+
import { QrScanRequest, QrScanRequestType } from '@metamask/eth-qr-keyring';
1010

1111
export enum TransactionModalType {
1212
Transaction = 'transaction',
@@ -19,15 +19,22 @@ export interface TransactionApprovalProps {
1919
// eslint-disable-next-line @typescript-eslint/no-explicit-any
2020
navigation: any;
2121
onComplete: () => void;
22-
QRState?: IQRState;
22+
pendingScanRequest?: QrScanRequest;
2323
isSigningQRObject?: boolean;
2424
}
2525

2626
const TransactionApprovalInternal = (props: TransactionApprovalProps) => {
2727
const { approvalRequest } = useApprovalRequest();
2828
const { isRedesignedEnabled } = useConfirmationRedesignEnabled();
29-
const { onComplete: propsOnComplete } = props;
30-
const isQRSigning = props.isSigningQRObject && !props.transactionType;
29+
const {
30+
onComplete: propsOnComplete,
31+
pendingScanRequest,
32+
isSigningQRObject,
33+
} = props;
34+
const isQRSigning =
35+
isSigningQRObject &&
36+
pendingScanRequest?.type === QrScanRequestType.SIGN &&
37+
!props.transactionType;
3138

3239
const onComplete = useCallback(() => {
3340
propsOnComplete();
@@ -64,9 +71,7 @@ const TransactionApprovalInternal = (props: TransactionApprovalProps) => {
6471
return (
6572
<QRSigningModal
6673
isVisible
67-
// TODO: Replace "any" with type
68-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
69-
QRState={props.QRState as any}
74+
pendingScanRequest={pendingScanRequest}
7075
onSuccess={onComplete}
7176
onCancel={onComplete}
7277
onFailure={onComplete}

app/components/UI/QRHardware/AnimatedQRScanner.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import Icon, {
3232
IconName,
3333
IconSize,
3434
} from '../../../component-library/components/Icons/Icon';
35+
import { QrScanRequestType } from '@metamask/eth-qr-keyring';
3536

3637
const createStyles = (theme: Theme) =>
3738
StyleSheet.create({
@@ -95,7 +96,7 @@ const frameImage = require('../../../images/frame.png'); // eslint-disable-line
9596

9697
interface AnimatedQRScannerProps {
9798
visible: boolean;
98-
purpose: 'sync' | 'sign';
99+
purpose: QrScanRequestType;
99100
onScanSuccess: (ur: UR) => void;
100101
onScanError: (error: string) => void;
101102
hideModal: () => void;
@@ -122,7 +123,7 @@ const AnimatedQRScannerModal = (props: AnimatedQRScannerProps) => {
122123
const { hasPermission, requestPermission } = useCameraPermission();
123124

124125
let expectedURTypes: string[];
125-
if (purpose === 'sync') {
126+
if (purpose === QrScanRequestType.PAIR) {
126127
expectedURTypes = [
127128
SUPPORTED_UR_TYPE.CRYPTO_HDKEY,
128129
SUPPORTED_UR_TYPE.CRYPTO_ACCOUNT,
@@ -148,7 +149,7 @@ const AnimatedQRScannerModal = (props: AnimatedQRScannerProps) => {
148149
{strings('connect_qr_hardware.hint_text')}
149150
<Text style={styles.bold}>
150151
{strings(
151-
purpose === 'sync'
152+
purpose === QrScanRequestType.PAIR
152153
? 'connect_qr_hardware.purpose_connect'
153154
: 'connect_qr_hardware.purpose_sign',
154155
)}
@@ -198,7 +199,7 @@ const AnimatedQRScannerModal = (props: AnimatedQRScannerProps) => {
198199
onScanSuccess(ur);
199200
setProgress(0);
200201
setURDecoder(new URRegistryDecoder());
201-
} else if (purpose === 'sync') {
202+
} else if (purpose === QrScanRequestType.PAIR) {
202203
trackEvent(
203204
createEventBuilder(MetaMetricsEvents.HARDWARE_WALLET_ERROR)
204205
.addProperties({

app/components/UI/QRHardware/QRSigningDetails.tsx

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import AnimatedQRScannerModal from './AnimatedQRScanner';
2323
import { fontStyles } from '../../../styles/common';
2424
import AccountInfoCard from '../AccountInfoCard';
2525
import ActionView from '../ActionView';
26-
import { IQRState } from './types';
2726
import { UR } from '@ngraveio/bc-ur';
2827
import { ETHSignature } from '@keystonehq/bc-ur-registry-eth';
2928
import { stringify as uuidStringify } from 'uuid';
@@ -34,9 +33,10 @@ import { useNavigation } from '@react-navigation/native';
3433
import { useTheme } from '../../../util/theme';
3534
import Device from '../../../util/device';
3635
import { useMetrics } from '../../../components/hooks/useMetrics';
36+
import { QrScanRequest, QrScanRequestType } from '@metamask/eth-qr-keyring';
3737

3838
interface IQRSigningDetails {
39-
QRState: IQRState;
39+
pendingScanRequest: QrScanRequest;
4040
successCallback?: () => void;
4141
failureCallback?: (error: string) => void;
4242
cancelCallback?: () => void;
@@ -117,7 +117,7 @@ const createStyles = (colors: any) =>
117117
});
118118

119119
const QRSigningDetails = ({
120-
QRState,
120+
pendingScanRequest,
121121
successCallback,
122122
failureCallback,
123123
cancelCallback,
@@ -228,11 +228,11 @@ const QRSigningDetails = ({
228228
const buffer = signature.getRequestId();
229229
if (buffer) {
230230
const requestId = uuidStringify(buffer);
231-
if (QRState.sign.request?.requestId === requestId) {
232-
KeyringController.submitQRSignature(
233-
QRState.sign.request?.requestId as string,
234-
ur.cbor.toString('hex'),
235-
);
231+
if (pendingScanRequest?.request?.requestId === requestId) {
232+
Engine.resolveQrKeyringScanRequest({
233+
type: ur.type,
234+
cbor: ur.cbor.toString('hex'),
235+
});
236236
setSentOrCanceled(true);
237237
successCallback?.();
238238
return;
@@ -250,8 +250,7 @@ const QRSigningDetails = ({
250250
failureCallback?.(strings('transaction.mismatched_qr_request_id'));
251251
},
252252
[
253-
KeyringController,
254-
QRState.sign.request?.requestId,
253+
pendingScanRequest?.request?.requestId,
255254
failureCallback,
256255
successCallback,
257256
trackEvent,
@@ -287,7 +286,7 @@ const QRSigningDetails = ({
287286

288287
return (
289288
<Fragment>
290-
{QRState?.sign?.request && (
289+
{pendingScanRequest?.request && (
291290
<ScrollView contentContainerStyle={styles.wrapper}>
292291
<ActionView
293292
confirmDisabled={!hasCameraPermission}
@@ -326,8 +325,8 @@ const QRSigningDetails = ({
326325
</Text>
327326
</View>
328327
<AnimatedQRCode
329-
cbor={QRState.sign.request.payload.cbor}
330-
type={QRState.sign.request.payload.type}
328+
cbor={pendingScanRequest.request.payload.cbor}
329+
type={pendingScanRequest.request.payload.type}
331330
shouldPause={
332331
scannerVisible || !shouldStartAnimated || shouldPause
333332
}
@@ -366,7 +365,7 @@ const QRSigningDetails = ({
366365
<AnimatedQRScannerModal
367366
pauseQRCode={setShouldPause}
368367
visible={scannerVisible}
369-
purpose={'sign'}
368+
purpose={QrScanRequestType.SIGN}
370369
onScanSuccess={onScanSuccess}
371370
onScanError={onScanError}
372371
hideModal={hideScanner}

app/components/UI/QRHardware/QRSigningModal/index.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
import React, { useState } from 'react';
22
import Modal from 'react-native-modal';
3-
import { IQRState } from '../types';
43
import { StyleSheet, View } from 'react-native';
54
import QRSigningDetails from '../QRSigningDetails';
65
import { useTheme } from '../../../../util/theme';
76
import { useDispatch, useSelector } from 'react-redux';
87
import { getNormalizedTxState } from '../../../../util/transactions';
98
import { resetTransaction } from '../../../../actions/transaction';
109
import { selectSelectedInternalAccount } from '../../../../selectors/accountsController';
10+
import { QrScanRequest } from '@metamask/eth-qr-keyring';
1111

1212
interface IQRSigningModalProps {
1313
isVisible: boolean;
14-
QRState: IQRState;
14+
pendingScanRequest: QrScanRequest;
1515
onSuccess?: () => void;
1616
onCancel?: () => void;
1717
onFailure?: (error: string) => void;
@@ -37,7 +37,7 @@ const createStyles = (colors: any) =>
3737

3838
const QRSigningModal = ({
3939
isVisible,
40-
QRState,
40+
pendingScanRequest,
4141
onSuccess,
4242
onCancel,
4343
onFailure,
@@ -85,7 +85,7 @@ const QRSigningModal = ({
8585
>
8686
<View style={styles.contentWrapper}>
8787
<QRSigningDetails
88-
QRState={QRState}
88+
pendingScanRequest={pendingScanRequest}
8989
showCancelButton
9090
tighten
9191
showHint

app/components/UI/QRHardware/types.tsx

Lines changed: 0 additions & 14 deletions
This file was deleted.

app/components/UI/QRHardware/withQRHardwareAwareness.tsx

Lines changed: 13 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,30 @@
1-
import React, { useState, useEffect, ComponentClass } from 'react';
2-
import Engine from '../../../core/Engine';
3-
import { IQRState } from './types';
1+
import React, { ComponentClass } from 'react';
2+
import { useSelector } from 'react-redux';
3+
import { RootState } from 'app/reducers';
4+
import { QrScanRequest, QrScanRequestType } from '@metamask/eth-qr-keyring';
45

56
const withQRHardwareAwareness = (
67
Children: ComponentClass<{
7-
QRState?: IQRState;
8+
pendingScanRequest?: QrScanRequest;
89
isSigningQRObject?: boolean;
910
isSyncingQRHardware?: boolean;
1011
}>,
1112
) => {
1213
// TODO: Replace "any" with type
1314
// eslint-disable-next-line @typescript-eslint/no-explicit-any
1415
const QRHardwareAwareness = (props: any) => {
15-
const [QRState, SetQRState] = useState<IQRState>({
16-
sync: {
17-
reading: false,
18-
},
19-
sign: {},
20-
});
21-
22-
// TODO: Replace "any" with type
23-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
24-
const subscribeKeyringState = (value: any) => {
25-
SetQRState(value);
26-
};
27-
28-
useEffect(() => {
29-
// This ensures that a QR keyring gets created if it doesn't already exist.
30-
// This is intentionally not awaited (the subscription still gets setup correctly if called
31-
// before the keyring is created).
32-
// TODO: Stop automatically creating keyrings
33-
Engine.context.KeyringController.getOrAddQRKeyring();
34-
Engine.controllerMessenger.subscribe(
35-
'KeyringController:qrKeyringStateChange',
36-
subscribeKeyringState,
37-
);
38-
return () => {
39-
Engine.controllerMessenger.unsubscribe(
40-
'KeyringController:qrKeyringStateChange',
41-
subscribeKeyringState,
42-
);
43-
};
44-
}, []);
16+
const { pendingScanRequest } = useSelector(
17+
(state: RootState) => state.qrKeyringScanner,
18+
);
4519

4620
return (
4721
<Children
4822
{...props}
49-
isSigningQRObject={!!QRState.sign?.request}
50-
isSyncingQRHardware={QRState.sync.reading}
51-
QRState={QRState}
23+
isSigningQRObject={pendingScanRequest?.type === QrScanRequestType.SIGN}
24+
isSyncingQRHardware={
25+
pendingScanRequest?.type === QrScanRequestType.PAIR
26+
}
27+
pendingScanRequest={pendingScanRequest}
5228
/>
5329
);
5430
};

app/components/Views/AccountActions/AccountActions.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import { useEIP7702Networks } from '../confirmations/hooks/7702/useEIP7702Networ
4747
import { isEvmAccountType } from '@metamask/keyring-api';
4848
import { toHex } from '@metamask/controller-utils';
4949
import { getMultichainBlockExplorer } from '../../../core/Multichain/networks';
50+
import { forgetQrDevice } from 'app/core/QrKeyring/QrKeyring';
5051

5152
interface AccountActionsParams {
5253
selectedAccount: InternalAccount;
@@ -308,7 +309,7 @@ const AccountActions = () => {
308309
);
309310
break;
310311
case ExtendedKeyringTypes.qr:
311-
await controllers.KeyringController.forgetQRDevice();
312+
await forgetQrDevice();
312313
trackEvent(
313314
createEventBuilder(MetaMetricsEvents.HARDWARE_WALLET_FORGOTTEN)
314315
.addProperties({
@@ -429,8 +430,8 @@ const AccountActions = () => {
429430
)
430431
///: END:ONLY_INCLUDE_IF
431432
}
432-
{(networkSupporting7702Present &&
433-
!isHardwareAccount(selectedAddress)) && (
433+
{networkSupporting7702Present &&
434+
!isHardwareAccount(selectedAddress) && (
434435
<AccountAction
435436
actionTitle={strings('account_actions.switch_to_smart_account')}
436437
iconName={IconName.SwapHorizontal}

0 commit comments

Comments
 (0)