diff --git a/packages/connect/src/core/index.ts b/packages/connect/src/core/index.ts index be985ad7d8ae..85fcc8ee3a2c 100644 --- a/packages/connect/src/core/index.ts +++ b/packages/connect/src/core/index.ts @@ -447,7 +447,6 @@ const onCall = async (context: CoreContext, message: IFrameCallMessage) => { 'onCall: message.id or message.payload is missing', ); } - const { uiPromises, callMethods, @@ -526,7 +525,17 @@ const onCall = async (context: CoreContext, message: IFrameCallMessage) => { return Promise.resolve(); } - return await onCallDevice(context, message, method); + if (method.useDevice) { + sendCoreMessage(createUiMessage(UI.CALL_IN_PROGRESS, { value: true })); + } + + try { + return await onCallDevice(context, message, method); + } finally { + if (method.useDevice) { + sendCoreMessage(createUiMessage(UI.CALL_IN_PROGRESS, { value: true })); + } + } }; const onCallDevice = async ( @@ -578,7 +587,6 @@ const onCallDevice = async ( const device = tempDevice; method.setDevice(device); - // find pending calls to this device const previousCall = callMethods.filter( call => call && call !== method && call.devicePath === method.devicePath, diff --git a/packages/connect/src/events/ui-request.ts b/packages/connect/src/events/ui-request.ts index 12d797b63c27..f5856d477904 100644 --- a/packages/connect/src/events/ui-request.ts +++ b/packages/connect/src/events/ui-request.ts @@ -24,6 +24,7 @@ export const UI_REQUEST = { FIRMWARE_NOT_COMPATIBLE: 'ui-device_firmware_not_compatible', FIRMWARE_NOT_INSTALLED: 'ui-device_firmware_not_installed', FIRMWARE_PROGRESS: 'ui-firmware-progress', + CALL_IN_PROGRESS: 'ui-call_in_progress', /** connect is waiting for device to be automatically reconnected */ FIRMWARE_RECONNECT: 'ui-firmware_reconnect', @@ -157,6 +158,13 @@ export interface UiRequestSetOperation { payload: string; } +export interface UiRequestCallInProgress { + type: typeof UI_REQUEST.CALL_IN_PROGRESS; + payload: { + value: boolean; // is in progress? + }; +} + export interface UiRequestPermission { type: typeof UI_REQUEST.REQUEST_PERMISSION; payload: { @@ -292,7 +300,8 @@ export type UiEvent = | FirmwareException | FirmwareReconnect | UiRequestAddressValidation - | UiRequestSetOperation; + | UiRequestSetOperation + | UiRequestCallInProgress; export type UiEventMessage = UiEvent & { event: typeof UI_EVENT }; diff --git a/packages/suite/src/actions/backup/__tests__/backupActions.test.ts b/packages/suite/src/actions/backup/__tests__/backupActions.test.ts index 1cda432723ab..321d4360bc68 100644 --- a/packages/suite/src/actions/backup/__tests__/backupActions.test.ts +++ b/packages/suite/src/actions/backup/__tests__/backupActions.test.ts @@ -2,12 +2,13 @@ import { mergeDeepObject } from '@trezor/utils'; import { connectInitThunk } from '@suite-common/connect-init'; import { testMocks } from '@suite-common/test-utils'; import { notificationsActions } from '@suite-common/toast-notifications'; -import { CommonParams, DeviceModelInternal } from '@trezor/connect'; +import { CommonParams, DeviceModelInternal, UI, UI_EVENT } from '@trezor/connect'; import { configureStore } from 'src/support/tests/configureStore'; import { SUITE } from 'src/actions/suite/constants'; import { BACKUP } from 'src/actions/backup/constants'; import * as backupActions from 'src/actions/backup/backupActions'; +import { value } from '@trezor/utxo-lib/src/payments/lazy'; export const getInitialState = (override: any) => { const defaults = { @@ -51,17 +52,26 @@ describe('Backup Actions', () => { }); it('backup success', async () => { + const { emitTestEvent } = testMocks.getTrezorConnectMock(); testMocks.setTrezorConnectFixtures({ success: true }); - const state = getInitialState({}); const store = mockStore(state); await store.dispatch(connectInitThunk()); - await store.dispatch( + const p = store.dispatch( backupActions.backupDevice({ device: store.getState().device.selectedDevice as CommonParams['device'], }), ); + emitTestEvent(UI_EVENT, { + type: UI.CALL_IN_PROGRESS, + payload: { value: true }, + }); + emitTestEvent(UI_EVENT, { + type: UI.CALL_IN_PROGRESS, + payload: { value: false }, + }); + await p; expect(store.getActions().shift()).toMatchObject({ type: connectInitThunk.pending.type, @@ -76,7 +86,15 @@ describe('Backup Actions', () => { payload: 'in-progress', }); expect(store.getActions().shift()).toEqual({ type: SUITE.LOCK_DEVICE, payload: true }); + expect(store.getActions().shift()).toEqual({ + type: UI.CALL_IN_PROGRESS, + payload: { value: true }, + }); expect(store.getActions().shift()).toEqual({ type: SUITE.LOCK_DEVICE, payload: false }); + expect(store.getActions().shift()).toEqual({ + type: UI.CALL_IN_PROGRESS, + payload: { value: false }, + }); expect(store.getActions().shift()).toMatchObject({ type: notificationsActions.addToast.type, payload: { type: 'backup-success' }, @@ -84,6 +102,7 @@ describe('Backup Actions', () => { }); it('backup error', async () => { + const { emitTestEvent } = testMocks.getTrezorConnectMock(); testMocks.setTrezorConnectFixtures({ success: false, payload: { error: 'avadakedavra' }, @@ -93,11 +112,20 @@ describe('Backup Actions', () => { const store = mockStore(state); await store.dispatch(connectInitThunk()); - await store.dispatch( + const p = store.dispatch( backupActions.backupDevice({ device: store.getState().device.selectedDevice as CommonParams['device'], }), ); + emitTestEvent(UI_EVENT, { + type: UI.CALL_IN_PROGRESS, + payload: { value: true }, + }); + emitTestEvent(UI_EVENT, { + type: UI.CALL_IN_PROGRESS, + payload: { value: false }, + }); + await p; expect(store.getActions().shift()).toMatchObject({ type: connectInitThunk.pending.type, @@ -112,7 +140,15 @@ describe('Backup Actions', () => { payload: 'in-progress', }); expect(store.getActions().shift()).toEqual({ type: SUITE.LOCK_DEVICE, payload: true }); + expect(store.getActions().shift()).toEqual({ + type: UI.CALL_IN_PROGRESS, + payload: { value: true }, + }); expect(store.getActions().shift()).toEqual({ type: SUITE.LOCK_DEVICE, payload: false }); + expect(store.getActions().shift()).toEqual({ + type: UI.CALL_IN_PROGRESS, + payload: { value: false }, + }); expect(store.getActions().shift()).toMatchObject({ type: notificationsActions.addToast.type, payload: { type: 'backup-failed' }, diff --git a/packages/suite/src/actions/suite/__fixtures__/suiteActions.ts b/packages/suite/src/actions/suite/__fixtures__/suiteActions.ts index 5c212ac752bb..96f2c2c009c4 100644 --- a/packages/suite/src/actions/suite/__fixtures__/suiteActions.ts +++ b/packages/suite/src/actions/suite/__fixtures__/suiteActions.ts @@ -734,23 +734,6 @@ const observeSelectedDevice = [ ]; const acquireDevice = [ - { - description: `success`, - state: { - device: { - selectedDevice: SUITE_DEVICE, - }, - }, - result: SUITE.LOCK_DEVICE, - }, - { - description: `success with requestedDevice param`, - state: { - device: {}, - }, - requestedDevice: SUITE_DEVICE, - result: SUITE.LOCK_DEVICE, - }, { description: `with TrezorConnect error`, state: { diff --git a/packages/suite/src/actions/suite/__tests__/trezorConnectActions.test.ts b/packages/suite/src/actions/suite/__tests__/trezorConnectActions.test.ts index a32f352ff52b..e1af937aa578 100644 --- a/packages/suite/src/actions/suite/__tests__/trezorConnectActions.test.ts +++ b/packages/suite/src/actions/suite/__tests__/trezorConnectActions.test.ts @@ -1,4 +1,4 @@ -import { DEVICE_EVENT, UI_EVENT, TRANSPORT_EVENT, BLOCKCHAIN_EVENT } from '@trezor/connect'; +import { DEVICE_EVENT, UI_EVENT, TRANSPORT_EVENT, BLOCKCHAIN_EVENT, UI } from '@trezor/connect'; import { connectInitThunk } from '@suite-common/connect-init'; import { testMocks } from '@suite-common/test-utils'; import { prepareDeviceReducer } from '@suite-common/wallet-core'; @@ -113,13 +113,27 @@ describe('TrezorConnect Actions', () => { const state = getInitialState(); const store = initStore(state); await store.dispatch(connectInitThunk()); - await testMocks.getTrezorConnectMock().getFeatures(); + const p = testMocks.getTrezorConnectMock().getFeatures(); + + const { emitTestEvent } = testMocks.getTrezorConnectMock(); + emitTestEvent(UI_EVENT, { type: UI.CALL_IN_PROGRESS, payload: { value: true } }); + emitTestEvent(UI_EVENT, { type: UI.CALL_IN_PROGRESS, payload: { value: false } }); + + await p; const actions = store.getActions(); // check actions in reversed order + expect(actions.pop()).toEqual({ + type: UI.CALL_IN_PROGRESS, + payload: { value: false }, + }); expect(actions.pop()).toEqual({ type: SUITE.LOCK_DEVICE, payload: false, }); + expect(actions.pop()).toEqual({ + type: UI.CALL_IN_PROGRESS, + payload: { value: true }, + }); expect(actions.pop()).toEqual({ type: SUITE.LOCK_DEVICE, payload: true, diff --git a/packages/suite/src/actions/wallet/__fixtures__/publicKeyActions.ts b/packages/suite/src/actions/wallet/__fixtures__/publicKeyActions.ts index 8226a4f2d051..0bd3e5be0f1d 100644 --- a/packages/suite/src/actions/wallet/__fixtures__/publicKeyActions.ts +++ b/packages/suite/src/actions/wallet/__fixtures__/publicKeyActions.ts @@ -7,8 +7,6 @@ import { MODAL } from 'src/actions/suite/constants'; const { getSuiteDevice } = testMocks; -const LOCK_DEVICE = '@mocked/extraDependency/action/notImplemented/lockDevice'; - export default [ { description: 'Show unverified public key', @@ -33,8 +31,6 @@ export default [ { type: connectInitThunk.pending.type, payload: undefined }, { type: connectInitThunk.fulfilled.type, payload: undefined }, { type: MODAL.PRESERVE }, - { type: LOCK_DEVICE }, - { type: LOCK_DEVICE }, { type: MODAL.OPEN_USER_CONTEXT }, ], }, @@ -51,8 +47,6 @@ export default [ { type: connectInitThunk.pending.type, payload: undefined }, { type: connectInitThunk.fulfilled.type, payload: undefined }, { type: MODAL.PRESERVE }, - { type: LOCK_DEVICE }, - { type: LOCK_DEVICE }, { type: MODAL.OPEN_USER_CONTEXT }, ], }, @@ -127,8 +121,6 @@ export default [ { type: connectInitThunk.pending.type, payload: undefined }, { type: connectInitThunk.fulfilled.type, payload: undefined }, { type: MODAL.PRESERVE }, - { type: LOCK_DEVICE }, - { type: LOCK_DEVICE }, { type: MODAL.CLOSE }, { type: notificationsActions.addToast.type, @@ -152,8 +144,6 @@ export default [ { type: connectInitThunk.pending.type, payload: undefined }, { type: connectInitThunk.fulfilled.type, payload: undefined }, { type: MODAL.PRESERVE }, - { type: LOCK_DEVICE }, - { type: LOCK_DEVICE }, { type: MODAL.CLOSE }, ], }, diff --git a/packages/suite/src/actions/wallet/__fixtures__/receiveActions.ts b/packages/suite/src/actions/wallet/__fixtures__/receiveActions.ts index 7cb2e22b43e6..22e374cbd8fb 100644 --- a/packages/suite/src/actions/wallet/__fixtures__/receiveActions.ts +++ b/packages/suite/src/actions/wallet/__fixtures__/receiveActions.ts @@ -40,8 +40,6 @@ export default [ { type: connectInitThunk.fulfilled.type, payload: undefined }, { type: MODAL.PRESERVE }, { type: confirmAddressOnDeviceThunk.pending.type, payload: undefined }, - { type: SUITE.LOCK_DEVICE, payload: true }, - { type: SUITE.LOCK_DEVICE, payload: false }, { type: confirmAddressOnDeviceThunk.fulfilled.type, payload: { success: true } }, { type: MODAL.OPEN_USER_CONTEXT }, { type: RECEIVE.SHOW_ADDRESS, path: PATH, address: ADDRESS }, @@ -72,8 +70,6 @@ export default [ { type: connectInitThunk.fulfilled.type, payload: undefined }, { type: MODAL.PRESERVE }, { type: confirmAddressOnDeviceThunk.pending.type, payload: undefined }, - { type: SUITE.LOCK_DEVICE, payload: true }, - { type: SUITE.LOCK_DEVICE, payload: false }, { type: confirmAddressOnDeviceThunk.fulfilled.type, payload: { success: true } }, { type: MODAL.OPEN_USER_CONTEXT }, { type: RECEIVE.SHOW_ADDRESS, path: PATH, address: ADDRESS }, @@ -104,8 +100,6 @@ export default [ { type: connectInitThunk.fulfilled.type, payload: undefined }, { type: MODAL.PRESERVE }, { type: confirmAddressOnDeviceThunk.pending.type, payload: undefined }, - { type: SUITE.LOCK_DEVICE, payload: true }, - { type: SUITE.LOCK_DEVICE, payload: false }, { type: confirmAddressOnDeviceThunk.fulfilled.type, payload: { success: true } }, { type: MODAL.OPEN_USER_CONTEXT }, { type: RECEIVE.SHOW_ADDRESS, path: PATH, address: ADDRESS }, @@ -182,8 +176,6 @@ export default [ { type: connectInitThunk.fulfilled.type, payload: undefined }, { type: MODAL.PRESERVE }, { type: confirmAddressOnDeviceThunk.pending.type, payload: undefined }, - { type: SUITE.LOCK_DEVICE, payload: true }, - { type: SUITE.LOCK_DEVICE, payload: false }, { type: confirmAddressOnDeviceThunk.fulfilled.type, payload: { success: false } }, { type: MODAL.CLOSE }, { @@ -209,8 +201,6 @@ export default [ { type: connectInitThunk.fulfilled.type, payload: undefined }, { type: MODAL.PRESERVE }, { type: confirmAddressOnDeviceThunk.pending.type, payload: undefined }, - { type: SUITE.LOCK_DEVICE, payload: true }, - { type: SUITE.LOCK_DEVICE, payload: false }, { type: confirmAddressOnDeviceThunk.fulfilled.type, payload: { success: false } }, { type: MODAL.CLOSE }, ], diff --git a/packages/suite/src/actions/wallet/__tests__/receiveActions.test.ts b/packages/suite/src/actions/wallet/__tests__/receiveActions.test.ts index 8e003b8ffe42..b76a2a80411b 100644 --- a/packages/suite/src/actions/wallet/__tests__/receiveActions.test.ts +++ b/packages/suite/src/actions/wallet/__tests__/receiveActions.test.ts @@ -148,7 +148,6 @@ describe('ReceiveActions', () => { const store = initStore(state); await store.dispatch(connectInitThunk()); await store.dispatch(f.action()); - if (f.result && f.result.actions) { expect(store.getActions()).toMatchObject(f.result.actions); } diff --git a/packages/suite/src/middlewares/suite/__tests__/buttonRequestMiddleware.test.ts b/packages/suite/src/middlewares/suite/__tests__/buttonRequestMiddleware.test.ts index a49c2c2af5bb..72c024eebdbd 100644 --- a/packages/suite/src/middlewares/suite/__tests__/buttonRequestMiddleware.test.ts +++ b/packages/suite/src/middlewares/suite/__tests__/buttonRequestMiddleware.test.ts @@ -50,6 +50,10 @@ describe('buttonRequest middleware', () => { // fake few ui events, just like when user is changing PIN await Promise.resolve(); + emitTestEvent(UI_EVENT, { + type: UI.CALL_IN_PROGRESS, + payload: { value: true }, + }); emitTestEvent(UI_EVENT, { type: UI.REQUEST_BUTTON, payload: { code: 'ButtonRequest_ProtectCall' }, @@ -58,6 +62,10 @@ describe('buttonRequest middleware', () => { type: UI.REQUEST_PIN, payload: { type: 'PinMatrixRequestType_NewFirst', device }, }); + emitTestEvent(UI_EVENT, { + type: UI.CALL_IN_PROGRESS, + payload: { value: false }, + }); await call; @@ -67,6 +75,7 @@ describe('buttonRequest middleware', () => { { type: connectInitThunk.pending.type, payload: undefined }, { type: connectInitThunk.fulfilled.type, payload: undefined }, { type: SUITE.LOCK_DEVICE, payload: true }, + { type: UI.CALL_IN_PROGRESS, payload: { value: true } }, { type: UI.REQUEST_BUTTON, payload: { code: 'ButtonRequest_ProtectCall' } }, { type: deviceActions.addButtonRequest.type, @@ -79,6 +88,7 @@ describe('buttonRequest middleware', () => { }, { type: SUITE.LOCK_DEVICE, payload: false }, { type: deviceActions.removeButtonRequests.type, payload: { device } }, + { type: UI.CALL_IN_PROGRESS, payload: { value: false } }, ]); }); }); diff --git a/suite-common/connect-init/src/__tests__/connectInitThunks.test.ts b/suite-common/connect-init/src/__tests__/connectInitThunks.test.ts index 3f483b0ef769..5679eaeede35 100644 --- a/suite-common/connect-init/src/__tests__/connectInitThunks.test.ts +++ b/suite-common/connect-init/src/__tests__/connectInitThunks.test.ts @@ -124,13 +124,13 @@ describe('TrezorConnect Actions', () => { it('Wrapped method', async () => { testMocks.setTrezorConnectFixtures(); await store.dispatch(connectInitThunk()); - await testMocks.getTrezorConnectMock().getFeatures(); + const { getFeatures, emitTestEvent } = testMocks.getTrezorConnectMock(); + await getFeatures(); + emitTestEvent(UI_EVENT, { type: 'ui-call_in_progress', payload: { value: true } }); + const actions = store.getActions(); // check actions in reversed order - expect(actions.pop()).toEqual({ - type: extraDependenciesMock.actions.lockDevice.type, - payload: false, - }); + expect(actions.pop()).toEqual({ type: 'ui-call_in_progress', payload: { value: true } }); expect(actions.pop()).toEqual({ type: extraDependenciesMock.actions.lockDevice.type, payload: true, diff --git a/suite-common/connect-init/src/connectInitThunks.ts b/suite-common/connect-init/src/connectInitThunks.ts index fdb8c3dd5224..c8b2cccf2637 100644 --- a/suite-common/connect-init/src/connectInitThunks.ts +++ b/suite-common/connect-init/src/connectInitThunks.ts @@ -43,10 +43,11 @@ export const connectInitThunk = createThunk( }); TrezorConnect.on(UI_EVENT, ({ event: _, ...action }) => { - // dispatch event as action + if (action.type === 'ui-call_in_progress') { + dispatch(lockDevice(action.payload.value)); + } dispatch(action); }); - TrezorConnect.on(TRANSPORT_EVENT, ({ event: _, ...action }) => { // dispatch event as action dispatch(action); @@ -97,11 +98,9 @@ export const connectInitThunk = createThunk( infoResult.payload.useDeviceState && !!enabledNetworks.find(a => a === 'ada' || a === 'tada'); - dispatch(lockDevice(true)); const result = await synchronize(() => original({ ...params, useCardanoDerivation: cardanoEnabled }), ); - dispatch(lockDevice(false)); return result; };