From 9786cea9d7ca1a5e381e8b107df11df520761a18 Mon Sep 17 00:00:00 2001 From: Tomas Martykan Date: Mon, 16 Dec 2024 11:03:03 +0100 Subject: [PATCH] chore(suite): separate popup logic from `@suite-common/connect-init` --- packages/suite/package.json | 1 + .../suite/src/actions/suite/initAction.ts | 3 +- .../middlewares/wallet/discoveryMiddleware.ts | 2 +- packages/suite/tsconfig.json | 3 + suite-common/connect-init/package.json | 1 - .../connect-init/src/connectInitThunks.ts | 98 +----------------- suite-common/connect-init/tsconfig.json | 3 - suite-common/connect-popup/package.json | 27 +++++ suite-common/connect-popup/redux.d.ts | 7 ++ .../connect-popup/src/connectPopupThunks.ts | 99 +++++++++++++++++++ suite-common/connect-popup/src/index.ts | 1 + suite-common/connect-popup/tsconfig.json | 17 ++++ yarn.lock | 19 ++++ 13 files changed, 179 insertions(+), 102 deletions(-) create mode 100644 suite-common/connect-popup/package.json create mode 100644 suite-common/connect-popup/redux.d.ts create mode 100644 suite-common/connect-popup/src/connectPopupThunks.ts create mode 100644 suite-common/connect-popup/src/index.ts create mode 100644 suite-common/connect-popup/tsconfig.json diff --git a/packages/suite/package.json b/packages/suite/package.json index 4d98b750653a..fb2da581ff55 100644 --- a/packages/suite/package.json +++ b/packages/suite/package.json @@ -30,6 +30,7 @@ "@suite-common/analytics": "workspace:*", "@suite-common/assets": "workspace:*", "@suite-common/connect-init": "workspace:*", + "@suite-common/connect-popup": "workspace:*", "@suite-common/device-authenticity": "workspace:*", "@suite-common/fiat-services": "workspace:*", "@suite-common/firmware": "workspace:*", diff --git a/packages/suite/src/actions/suite/initAction.ts b/packages/suite/src/actions/suite/initAction.ts index 520723204eae..aabe6bf8b518 100644 --- a/packages/suite/src/actions/suite/initAction.ts +++ b/packages/suite/src/actions/suite/initAction.ts @@ -1,5 +1,6 @@ import { initMessageSystemThunk } from '@suite-common/message-system'; import * as trezorConnectActions from '@suite-common/connect-init'; +import * as trezorConnectPopupActions from '@suite-common/connect-popup'; import { initBlockchainThunk, initDevices, @@ -115,7 +116,7 @@ export const init = () => async (dispatch: Dispatch, getState: GetState) => { // 14. init connect popup handler if (isDesktop()) { - dispatch(trezorConnectActions.connectPopupInitThunk()); + dispatch(trezorConnectPopupActions.connectPopupInitThunk()); } // 15. backend connected, suite is ready to use diff --git a/packages/suite/src/middlewares/wallet/discoveryMiddleware.ts b/packages/suite/src/middlewares/wallet/discoveryMiddleware.ts index 0d27ec73480a..a5bd60726f51 100644 --- a/packages/suite/src/middlewares/wallet/discoveryMiddleware.ts +++ b/packages/suite/src/middlewares/wallet/discoveryMiddleware.ts @@ -15,7 +15,7 @@ import { UI } from '@trezor/connect'; import { isDeviceAcquired } from '@suite-common/suite-utils'; import { DiscoveryStatus } from '@suite-common/wallet-constants'; import { createMiddlewareWithExtraDeps } from '@suite-common/redux-utils'; -import { connectPopupCallThunk } from '@suite-common/connect-init'; +import { connectPopupCallThunk } from '@suite-common/connect-popup'; import { SUITE, ROUTER, MODAL } from 'src/actions/suite/constants'; import * as walletSettingsActions from 'src/actions/settings/walletSettingsActions'; diff --git a/packages/suite/tsconfig.json b/packages/suite/tsconfig.json index 9d9fe32a3681..076591ae0f22 100644 --- a/packages/suite/tsconfig.json +++ b/packages/suite/tsconfig.json @@ -19,6 +19,9 @@ { "path": "../../suite-common/connect-init" }, + { + "path": "../../suite-common/connect-popup" + }, { "path": "../../suite-common/device-authenticity" }, diff --git a/suite-common/connect-init/package.json b/suite-common/connect-init/package.json index 67992798a112..ec1f66da017d 100644 --- a/suite-common/connect-init/package.json +++ b/suite-common/connect-init/package.json @@ -18,7 +18,6 @@ "@suite-common/wallet-core": "workspace:*", "@trezor/connect": "workspace:*", "@trezor/env-utils": "workspace:^", - "@trezor/suite-desktop-api": "workspace:*", "@trezor/urls": "workspace:*", "@trezor/utils": "workspace:*" }, diff --git a/suite-common/connect-init/src/connectInitThunks.ts b/suite-common/connect-init/src/connectInitThunks.ts index 97702c941f97..ccafbd2551e2 100644 --- a/suite-common/connect-init/src/connectInitThunks.ts +++ b/suite-common/connect-init/src/connectInitThunks.ts @@ -3,16 +3,13 @@ import TrezorConnect, { BLOCKCHAIN_EVENT, DEVICE, DEVICE_EVENT, - ERRORS, TRANSPORT_EVENT, UI_EVENT, } from '@trezor/connect'; import { DATA_URL } from '@trezor/urls'; -import { createDeferred, getSynchronize } from '@trezor/utils'; -import { deviceConnectThunks, selectDevice } from '@suite-common/wallet-core'; +import { getSynchronize } from '@trezor/utils'; +import { deviceConnectThunks } from '@suite-common/wallet-core'; import { isDesktop, isNative } from '@trezor/env-utils'; -import { desktopApi } from '@trezor/suite-desktop-api'; -import { serializeError } from '@trezor/connect/src/constants/errors'; import { cardanoConnectPatch } from './cardanoConnectPatch'; @@ -167,94 +164,3 @@ export const connectInitThunk = createThunk( } }, ); - -export const connectPopupCallThunk = createThunk( - `${CONNECT_INIT_MODULE}/callThunk`, - async ( - { - id, - method, - payload, - processName, - origin, - }: { - id: number; - method: string; - payload: any; - processName?: string; - origin?: string; - }, - { dispatch, getState, extra }, - ) => { - try { - const device = selectDevice(getState()); - - if (!device) { - console.error('Device not found'); - - // TODO: wait for device selection and continue - throw ERRORS.TypedError('Device_NotFound'); - } - - // @ts-expect-error: method is dynamic - const methodInfo = await TrezorConnect[method]({ - ...payload, - __info: true, - }); - if (!methodInfo.success) { - throw methodInfo; - } - - const confirmation = createDeferred(); - dispatch(extra.actions.lockDevice(true)); - dispatch( - extra.actions.openModal({ - type: 'connect-popup', - onCancel: () => confirmation.reject(ERRORS.TypedError('Method_Cancel')), - onConfirm: () => confirmation.resolve(), - method: methodInfo.payload.info, - processName, - origin, - }), - ); - await confirmation.promise; - dispatch(extra.actions.lockDevice(false)); - - // @ts-expect-error: method is dynamic - const response = await TrezorConnect[method]({ - device: { - path: device.path, - instance: device.instance, - state: device.state, - }, - ...payload, - }); - - dispatch(extra.actions.onModalCancel()); - - desktopApi.connectPopupResponse({ - ...response, - id, - }); - } catch (error) { - console.error('connectPopupCallThunk', error); - desktopApi.connectPopupResponse({ - success: false, - payload: serializeError(error), - id, - }); - } - }, -); - -export const connectPopupInitThunk = createThunk( - `${CONNECT_INIT_MODULE}/initPopupThunk`, - async (_, { dispatch }) => { - if (desktopApi.available && (await desktopApi.connectPopupEnabled())) { - desktopApi.on('connect-popup/call', params => { - dispatch(connectPopupCallThunk(params)); - }); - desktopApi.connectPopupReady(); - } - }, -); diff --git a/suite-common/connect-init/tsconfig.json b/suite-common/connect-init/tsconfig.json index a64595e6886f..cb4b183f706c 100644 --- a/suite-common/connect-init/tsconfig.json +++ b/suite-common/connect-init/tsconfig.json @@ -8,9 +8,6 @@ { "path": "../wallet-core" }, { "path": "../../packages/connect" }, { "path": "../../packages/env-utils" }, - { - "path": "../../packages/suite-desktop-api" - }, { "path": "../../packages/urls" }, { "path": "../../packages/utils" } ] diff --git a/suite-common/connect-popup/package.json b/suite-common/connect-popup/package.json new file mode 100644 index 000000000000..ec41cee9f5d5 --- /dev/null +++ b/suite-common/connect-popup/package.json @@ -0,0 +1,27 @@ +{ + "name": "@suite-common/connect-popup", + "version": "1.0.0", + "private": true, + "license": "See LICENSE.md in repo root", + "sideEffects": false, + "main": "src/index", + "scripts": { + "type-check": "yarn g:tsc --build tsconfig.json" + }, + "dependencies": { + "@reduxjs/toolkit": "1.9.5", + "@suite-common/redux-utils": "workspace:*", + "@suite-common/suite-types": "workspace:*", + "@suite-common/test-utils": "workspace:*", + "@suite-common/wallet-core": "workspace:*", + "@trezor/connect": "workspace:*", + "@trezor/env-utils": "workspace:^", + "@trezor/suite-desktop-api": "workspace:*", + "@trezor/urls": "workspace:*", + "@trezor/utils": "workspace:*" + }, + "devDependencies": { + "redux-mock-store": "^1.5.4", + "redux-thunk": "^2.4.2" + } +} diff --git a/suite-common/connect-popup/redux.d.ts b/suite-common/connect-popup/redux.d.ts new file mode 100644 index 000000000000..df9a0c3f969a --- /dev/null +++ b/suite-common/connect-popup/redux.d.ts @@ -0,0 +1,7 @@ +import { AsyncThunkAction } from '@reduxjs/toolkit'; + +declare module 'redux' { + export interface Dispatch { + >(thunk: TThunk): ReturnType; + } +} diff --git a/suite-common/connect-popup/src/connectPopupThunks.ts b/suite-common/connect-popup/src/connectPopupThunks.ts new file mode 100644 index 000000000000..797762ced290 --- /dev/null +++ b/suite-common/connect-popup/src/connectPopupThunks.ts @@ -0,0 +1,99 @@ +import { createThunk } from '@suite-common/redux-utils'; +import TrezorConnect, { ERRORS } from '@trezor/connect'; +import { createDeferred } from '@trezor/utils'; +import { selectDevice } from '@suite-common/wallet-core'; +import { desktopApi } from '@trezor/suite-desktop-api'; +import { serializeError } from '@trezor/connect/src/constants/errors'; + +const CONNECT_POPUP_MODULE = '@common/connect-popup'; + +export const connectPopupCallThunk = createThunk( + `${CONNECT_POPUP_MODULE}/callThunk`, + async ( + { + id, + method, + payload, + processName, + origin, + }: { + id: number; + method: string; + payload: any; + processName?: string; + origin?: string; + }, + { dispatch, getState, extra }, + ) => { + try { + const device = selectDevice(getState()); + + if (!device) { + console.error('Device not found'); + + // TODO: wait for device selection and continue + throw ERRORS.TypedError('Device_NotFound'); + } + + // @ts-expect-error: method is dynamic + const methodInfo = await TrezorConnect[method]({ + ...payload, + __info: true, + }); + if (!methodInfo.success) { + throw methodInfo; + } + + const confirmation = createDeferred(); + dispatch(extra.actions.lockDevice(true)); + dispatch( + extra.actions.openModal({ + type: 'connect-popup', + onCancel: () => confirmation.reject(ERRORS.TypedError('Method_Cancel')), + onConfirm: () => confirmation.resolve(), + method: methodInfo.payload.info, + processName, + origin, + }), + ); + await confirmation.promise; + dispatch(extra.actions.lockDevice(false)); + + // @ts-expect-error: method is dynamic + const response = await TrezorConnect[method]({ + device: { + path: device.path, + instance: device.instance, + state: device.state, + }, + ...payload, + }); + + dispatch(extra.actions.onModalCancel()); + + desktopApi.connectPopupResponse({ + ...response, + id, + }); + } catch (error) { + console.error('connectPopupCallThunk', error); + desktopApi.connectPopupResponse({ + success: false, + payload: serializeError(error), + id, + }); + } + }, +); + +export const connectPopupInitThunk = createThunk( + `${CONNECT_POPUP_MODULE}/initPopupThunk`, + async (_, { dispatch }) => { + if (desktopApi.available && (await desktopApi.connectPopupEnabled())) { + desktopApi.on('connect-popup/call', params => { + dispatch(connectPopupCallThunk(params)); + }); + desktopApi.connectPopupReady(); + } + }, +); diff --git a/suite-common/connect-popup/src/index.ts b/suite-common/connect-popup/src/index.ts new file mode 100644 index 000000000000..e56779802e7a --- /dev/null +++ b/suite-common/connect-popup/src/index.ts @@ -0,0 +1 @@ +export * from './connectPopupThunks'; diff --git a/suite-common/connect-popup/tsconfig.json b/suite-common/connect-popup/tsconfig.json new file mode 100644 index 000000000000..a64595e6886f --- /dev/null +++ b/suite-common/connect-popup/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { "outDir": "libDev" }, + "references": [ + { "path": "../redux-utils" }, + { "path": "../suite-types" }, + { "path": "../test-utils" }, + { "path": "../wallet-core" }, + { "path": "../../packages/connect" }, + { "path": "../../packages/env-utils" }, + { + "path": "../../packages/suite-desktop-api" + }, + { "path": "../../packages/urls" }, + { "path": "../../packages/utils" } + ] +} diff --git a/yarn.lock b/yarn.lock index 01d362de1116..2d6f7c7edb9f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9414,6 +9414,24 @@ __metadata: "@suite-common/connect-init@workspace:*, @suite-common/connect-init@workspace:suite-common/connect-init": version: 0.0.0-use.local resolution: "@suite-common/connect-init@workspace:suite-common/connect-init" + dependencies: + "@reduxjs/toolkit": "npm:1.9.5" + "@suite-common/redux-utils": "workspace:*" + "@suite-common/suite-types": "workspace:*" + "@suite-common/test-utils": "workspace:*" + "@suite-common/wallet-core": "workspace:*" + "@trezor/connect": "workspace:*" + "@trezor/env-utils": "workspace:^" + "@trezor/urls": "workspace:*" + "@trezor/utils": "workspace:*" + redux-mock-store: "npm:^1.5.4" + redux-thunk: "npm:^2.4.2" + languageName: unknown + linkType: soft + +"@suite-common/connect-popup@workspace:*, @suite-common/connect-popup@workspace:suite-common/connect-popup": + version: 0.0.0-use.local + resolution: "@suite-common/connect-popup@workspace:suite-common/connect-popup" dependencies: "@reduxjs/toolkit": "npm:1.9.5" "@suite-common/redux-utils": "workspace:*" @@ -12541,6 +12559,7 @@ __metadata: "@suite-common/analytics": "workspace:*" "@suite-common/assets": "workspace:*" "@suite-common/connect-init": "workspace:*" + "@suite-common/connect-popup": "workspace:*" "@suite-common/device-authenticity": "workspace:*" "@suite-common/fiat-services": "workspace:*" "@suite-common/firmware": "workspace:*"