Skip to content

Commit

Permalink
Add support for ledger wallet in new signature designs
Browse files Browse the repository at this point in the history
  • Loading branch information
jpuri committed Feb 13, 2025
1 parent b3f0ee7 commit 1bce16a
Show file tree
Hide file tree
Showing 13 changed files with 391 additions and 673 deletions.
91 changes: 79 additions & 12 deletions app/components/UI/LedgerModals/LedgerMessageSignModal.test.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,85 @@
import { renderScreen } from '../../../util/test/renderWithProvider';
import React from 'react';
import { Button, Text, View } from 'react-native';
import { fireEvent } from '@testing-library/react-native';

import renderWithProvider from '../../../util/test/renderWithProvider';
// eslint-disable-next-line import/no-namespace
import * as NavUtils from '../../../util/navigation/navUtils';
// eslint-disable-next-line import/no-namespace
import * as rpcEventsFuncs from '../../../actions/rpcEvents';
import { personalSignatureConfirmationState } from '../../../util/test/confirm-data-helpers';
import LedgerMessageSignModal from './LedgerMessageSignModal';
import { RPCStageTypes } from '../../../reducers/rpcEvents';

const initialState = {
rpcEvents: { signingEvent: RPCStageTypes.IDLE },
};
const MockView = View;
const MockText = Text;
const MockButton = Button;
jest.mock('./LedgerConfirmationModal', () => ({
__esModule: true,
default: ({
onConfirmation,
onRejection,
deviceId,
}: {
onConfirmation: () => void;
onRejection: () => void;
deviceId: string;
}) => (
<MockView>
<MockText>Mock LedgerConfirmationModal</MockText>
<MockText>{deviceId}</MockText>
<MockButton onPress={onConfirmation} title="onConfirmation" />
<MockButton onPress={onRejection} title="onRejection" />
</MockView>
),
}));

const DummyDeviceId = 'DummyDeviceId';

describe('LedgerMessageSignModal', () => {
it('should render correctly', () => {
const { toJSON } = renderScreen(
LedgerMessageSignModal,
{ name: 'LederMessageSignModal' },
{ state: initialState },
);
expect(toJSON()).toMatchSnapshot();
it('should render LedgerConfirmationModal correctly', () => {
jest
.spyOn(NavUtils, 'useParams')
.mockReturnValue({ deviceId: DummyDeviceId });
const { getByText } = renderWithProvider(<LedgerMessageSignModal />, {
state: personalSignatureConfirmationState,
});
expect(getByText('Mock LedgerConfirmationModal')).toBeTruthy();
expect(getByText(DummyDeviceId)).toBeTruthy();
});

it('should call onConfirmationComplete when request is confirmed', () => {
const mockOnConfirmationComplete = jest.fn();
jest
.spyOn(NavUtils, 'useParams')
.mockReturnValue({
onConfirmationComplete: mockOnConfirmationComplete,
deviceId: DummyDeviceId,
});
const { getByText } = renderWithProvider(<LedgerMessageSignModal />, {
state: personalSignatureConfirmationState,
});
fireEvent.press(getByText('onConfirmation'));
expect(mockOnConfirmationComplete).toHaveBeenCalledTimes(1);
expect(mockOnConfirmationComplete).toHaveBeenCalledWith(true);
});

it('should call onConfirmationComplete when request is rejected', () => {
const mockOnConfirmationComplete = jest.fn();
jest
.spyOn(NavUtils, 'useParams')
.mockReturnValue({
onConfirmationComplete: mockOnConfirmationComplete,
deviceId: DummyDeviceId,
});
jest
.spyOn(rpcEventsFuncs, 'resetEventStage')
.mockImplementation(() => ({ rpcName: 'dummy', type: 'DUMMY' }));
const { getByText } = renderWithProvider(<LedgerMessageSignModal />, {
state: personalSignatureConfirmationState,
});
fireEvent.press(getByText('onRejection'));
expect(mockOnConfirmationComplete).toHaveBeenCalledTimes(1);
expect(mockOnConfirmationComplete).toHaveBeenCalledWith(false);
expect(rpcEventsFuncs.resetEventStage).toHaveBeenCalledTimes(1);
});
});
20 changes: 11 additions & 9 deletions app/components/UI/LedgerModals/LedgerMessageSignModal.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useCallback, useEffect, useRef } from 'react';
import React, { useCallback, useEffect, useState } from 'react';
import Modal from 'react-native-modal';

import LedgerConfirmationModal from './LedgerConfirmationModal';
import ReusableModal, { ReusableModalRef } from '../ReusableModal';
import { createStyles } from './styles';
import {
createNavigationDetails,
Expand Down Expand Up @@ -28,9 +29,6 @@ export interface LedgerMessageSignModalParams {
) => Promise<void>;
// TODO: Replace "any" with type
// eslint-disable-next-line @typescript-eslint/no-explicit-any
version: any;
// TODO: Replace "any" with type
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type: any;
// TODO: Replace "any" with type
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand All @@ -44,7 +42,7 @@ export const createLedgerMessageSignModalNavDetails =

const LedgerMessageSignModal = () => {
const dispatch = useDispatch();
const modalRef = useRef<ReusableModalRef | null>(null);
const [requestCompleted, setRequestCompleted] = useState(false);
const { colors } = useAppThemeFromContext() || mockTheme;
const styles = createStyles(colors);
const { signingEvent }: iEventGroup = useSelector(
Expand All @@ -55,7 +53,7 @@ const LedgerMessageSignModal = () => {
useParams<LedgerMessageSignModalParams>();

const dismissModal = useCallback(() => {
modalRef?.current?.dismissModal();
setRequestCompleted(false);
dispatch(resetEventStage(signingEvent.rpcName));
}, [dispatch, signingEvent.rpcName]);

Expand Down Expand Up @@ -85,16 +83,20 @@ const LedgerMessageSignModal = () => {
dismissModal();
}, [dismissModal, onConfirmationComplete]);

if (requestCompleted) {
return null;
}

return (
<ReusableModal ref={modalRef} style={styles.modal}>
<Modal isVisible style={styles.modal}>
<View style={styles.contentWrapper}>
<LedgerConfirmationModal
onConfirmation={executeOnLedger}
onRejection={onRejection}
deviceId={deviceId}
/>
</View>
</ReusableModal>
</Modal>
);
};

Expand Down
Loading

0 comments on commit 1bce16a

Please sign in to comment.