From 2ba4341f73817ee64cc2bfbe2c49e87401df4802 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Ortiz karliatto Date: Wed, 6 Nov 2024 22:31:02 +0100 Subject: [PATCH] wip --- docs/packages/suite-desktop.md | 2 + docs/releases/adding-new-firmwares.md | 2 +- packages/connect-iframe/package.json | 3 +- .../webpack/base.webpack.config.ts | 12 +- .../webpack/core.webpack.config.ts | 12 +- ...ack.config.ts => iframe.webpack.config.ts} | 9 +- .../webpack/sessions.webpack.config.ts | 35 +++ packages/connect-iframe/webpack/utils.ts | 30 ++ packages/connect-web/src/module/index.ts | 70 +++++ packages/connect-web/tsconfig.json | 3 +- .../connect-web/webpack/dev.webpack.config.ts | 2 +- packages/connect/src/backend/Blockchain.ts | 2 + packages/connect/src/data/DataManager.ts | 158 +++++++--- packages/connect/src/impl/core-in-module.ts | 294 ++++++++++++++++++ .../src/utils/resolveStaticPath.ts | 7 +- .../configs/base.webpack.config.ts | 2 +- .../suite-build/configs/web.webpack.config.ts | 11 +- packages/suite-build/package.json | 3 +- packages/suite-build/tsconfig.json | 2 +- packages/suite-web/e2e/run_tests.ts | 5 +- packages/suite-web/e2e/stubs/metadata.ts | 11 +- .../suite-web/e2e/support/utils/shortcuts.ts | 2 +- .../tests/metadata/interval-fetching.test.ts | 36 ++- .../tests/metadata/wallet-metadata.test.ts | 7 + .../tests/onboarding/firmware-update.test.ts | 4 +- .../tests/suite/passphrase-cardano.test.ts | 5 + .../src/components/suite/WebUsbButton.tsx | 1 + .../suite/src/support/extraDependencies.ts | 3 +- .../connect-init/src/connectInitThunks.ts | 7 +- .../suite-utils/src/resolveStaticPath.ts | 12 + .../src/firmware/getBinFilesBaseUrlThunk.ts | 5 +- .../wallet-core/src/send/sendFormReducer.ts | 1 + 32 files changed, 664 insertions(+), 94 deletions(-) rename packages/connect-iframe/webpack/{prod.webpack.config.ts => iframe.webpack.config.ts} (68%) create mode 100644 packages/connect-iframe/webpack/sessions.webpack.config.ts create mode 100644 packages/connect-iframe/webpack/utils.ts create mode 100644 packages/connect-web/src/module/index.ts create mode 100644 packages/connect/src/impl/core-in-module.ts diff --git a/docs/packages/suite-desktop.md b/docs/packages/suite-desktop.md index 01c06e373f9..ae99770f911 100644 --- a/docs/packages/suite-desktop.md +++ b/docs/packages/suite-desktop.md @@ -6,6 +6,8 @@ - suite-web + + `@trezor/connect` is hosted at `[url]/build/static/connect` and injected as an iframe into DOM. `@trezor/connect` imports from `@trezor/suite` are replaced to `@trezor/connect-web` see [webpack config](https://github.com/trezor/trezor-suite/blob/develop/packages/suite-build/configs/web.webpack.config.ts) diff --git a/docs/releases/adding-new-firmwares.md b/docs/releases/adding-new-firmwares.md index 921dc0dd8f9..b6b09b80301 100644 --- a/docs/releases/adding-new-firmwares.md +++ b/docs/releases/adding-new-firmwares.md @@ -37,7 +37,7 @@ After Suite is released, distribute new firmware by releasing new `@trezor/conne Firmware `releases.json` files provide data about all available firmware versions and they are used to offer the correct firmware version for the user to update depending on the current version of firmware, bootloader and bridge. See the table below for a description of every param. -Those `releases.json` files are bundled inside `@trezor/connect` in `/static/connect/data` folder. Therefore, `suite-web` takes if from [`https://suite.trezor.io/web/static/connect/data/firmware/{deviceModel}/releases.json?r={timestamp to prevent caching}`](https://suite.trezor.io/web/static/connect/data/firmware/t1b1/releases.json?r=1654786865680) and `suite-desktop` has it on `file:///static/connect/data/firmware/{deviceModel}/releases.json`. Neither the `suite-web` nor the `suite-desktop` take it from [https://data.trezor.io](https://data.trezor.io). +Those `releases.json` files are bundled inside `@trezor/connect` in `/data` folder. Therefore, `suite-web` takes if from [`https://suite.trezor.io/web/data/firmware/{deviceModel}/releases.json?r={timestamp to prevent caching}`](https://suite.trezor.io/web/data/firmware/t1b1/releases.json?r=1654786865680) and `suite-desktop` has it on `file:///data/firmware/{deviceModel}/releases.json`. Neither the `suite-web` nor the `suite-desktop` take it from [https://data.trezor.io](https://data.trezor.io). | key | type | example value | description | | ----------------------- | ------------------------ | --------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | diff --git a/packages/connect-iframe/package.json b/packages/connect-iframe/package.json index 8ff040d47ad..15921f2f7bf 100644 --- a/packages/connect-iframe/package.json +++ b/packages/connect-iframe/package.json @@ -4,7 +4,8 @@ "private": true, "scripts": { "lint:js": "yarn g:eslint '**/*.{ts,tsx,js}'", - "build:iframe": "TS_NODE_PROJECT=\"tsconfig.json\" yarn webpack --config ./webpack/prod.webpack.config.ts --stats-children", + "build:iframe": "TS_NODE_PROJECT=\"tsconfig.json\" yarn webpack --config ./webpack/iframe.webpack.config.ts --stats-children", + "build:sessions": "TS_NODE_PROJECT=\"tsconfig.json\" yarn webpack --config ./webpack/sessions.webpack.config.ts --stats-children", "build:core-module": "TS_NODE_PROJECT=\"tsconfig.json\" yarn webpack --config ./webpack/core.webpack.config.ts --stats-children", "build": "yarn rimraf build && yarn build:iframe && yarn build:core-module", "___NOTE__": "iframe build is one of the prerequisites of suite-web. build:lib script provides it together with other libraries", diff --git a/packages/connect-iframe/webpack/base.webpack.config.ts b/packages/connect-iframe/webpack/base.webpack.config.ts index 8a8238ae09b..ef698bac4fa 100644 --- a/packages/connect-iframe/webpack/base.webpack.config.ts +++ b/packages/connect-iframe/webpack/base.webpack.config.ts @@ -1,16 +1,24 @@ -import path from 'path'; +// import path from 'path'; import { execSync } from 'child_process'; import webpack from 'webpack'; import CopyWebpackPlugin from 'copy-webpack-plugin'; import TerserPlugin from 'terser-webpack-plugin'; import { version } from '../package.json'; +import { getDistPathForProject } from './utils'; const COMMON_DATA_SRC = '../../packages/connect-common/files'; const MESSAGES_SRC = '../../packages/protobuf/messages.json'; -const DIST = path.resolve(__dirname, '../build'); +// const DIST = path.resolve(__dirname, '../build'); +const project = process.env.PROJECT || 'iframe'; +if (project !== 'iframe' && project !== 'suite-web') { + throw new Error(`Unsupported project: ${project}`); +} +const DIST = getDistPathForProject(project); + +console.log('DIST', DIST); // Because of Expo EAS, we need to use the commit hash from expo to avoid failing git command inside EAS // because we need to call `yarn build:libs during native build` const commitHash = diff --git a/packages/connect-iframe/webpack/core.webpack.config.ts b/packages/connect-iframe/webpack/core.webpack.config.ts index a3c08cdd86e..e4313f897c5 100644 --- a/packages/connect-iframe/webpack/core.webpack.config.ts +++ b/packages/connect-iframe/webpack/core.webpack.config.ts @@ -3,8 +3,15 @@ import webpack from 'webpack'; import merge from 'webpack-merge'; import baseConfig from './base.webpack.config'; +import { getDistPathForProject } from './utils'; -const DIST = path.resolve(__dirname, '../build'); +const project = process.env.PROJECT || 'iframe'; + +if (project !== 'iframe' && project !== 'suite-web') { + throw new Error(`Unsupported project: ${project}`); +} +const DIST = getDistPathForProject(project); +console.log('DIST', DIST); export const config: webpack.Configuration = { target: 'web', @@ -15,7 +22,8 @@ export const config: webpack.Configuration = { output: { filename: 'js/[name].js', path: DIST, - publicPath: './', + publicPath: '/suite-web/feat/use-core-in-suite-web/web/', + // publicPath: '/', library: { type: 'module', }, diff --git a/packages/connect-iframe/webpack/prod.webpack.config.ts b/packages/connect-iframe/webpack/iframe.webpack.config.ts similarity index 68% rename from packages/connect-iframe/webpack/prod.webpack.config.ts rename to packages/connect-iframe/webpack/iframe.webpack.config.ts index 0ed04b4c1f9..518e80f87f5 100644 --- a/packages/connect-iframe/webpack/prod.webpack.config.ts +++ b/packages/connect-iframe/webpack/iframe.webpack.config.ts @@ -6,17 +6,10 @@ import HtmlWebpackPlugin from 'html-webpack-plugin'; import { config as baseConfig } from './base.webpack.config'; const DIST = path.resolve(__dirname, '../build'); + const config: webpack.Configuration = { - // common instructions that are able to build correctly imports from @trezor/connect (reusing this in popup) entry: { iframe: path.resolve(__dirname, '../src/index.ts'), - ['sessions-background-sharedworker']: { - filename: 'workers/[name].js', - import: path.resolve( - __dirname, - '../../transport/src/sessions/background-sharedworker.ts', - ), - }, }, output: { filename: 'js/[name].[contenthash].js', diff --git a/packages/connect-iframe/webpack/sessions.webpack.config.ts b/packages/connect-iframe/webpack/sessions.webpack.config.ts new file mode 100644 index 00000000000..003dd70fdef --- /dev/null +++ b/packages/connect-iframe/webpack/sessions.webpack.config.ts @@ -0,0 +1,35 @@ +import path from 'path'; +import webpack from 'webpack'; +import merge from 'webpack-merge'; + +import { config as baseConfig } from './base.webpack.config'; +import { getSharedworkerDistPathForProject } from './utils'; + +const project = process.env.PROJECT || 'iframe'; + +if (project !== 'iframe' && project !== 'suite-web') { + throw new Error(`Unsupported project: ${project}`); +} +const DIST = getSharedworkerDistPathForProject(project); + +console.log('DIST', DIST); + +const config: webpack.Configuration = { + // common instructions that are able to build correctly imports from @trezor/connect (reusing this in popup) + entry: { + ['sessions-background-sharedworker']: { + filename: 'workers/[name].js', + import: path.resolve( + __dirname, + '../../transport/src/sessions/background-sharedworker.ts', + ), + }, + }, + output: { + filename: 'js/[name].[contenthash].js', + path: DIST, + publicPath: './', + }, +}; + +export default merge([config, baseConfig]); diff --git a/packages/connect-iframe/webpack/utils.ts b/packages/connect-iframe/webpack/utils.ts new file mode 100644 index 00000000000..38c1ae1b75c --- /dev/null +++ b/packages/connect-iframe/webpack/utils.ts @@ -0,0 +1,30 @@ +import path from 'path'; + +type Project = 'iframe' | 'suite-web'; + +export const getDistPathForProject = (project: Project = 'iframe') => { + const basePath = path.join(__dirname, '..', '..'); + switch (project) { + case 'iframe': + return path.join(basePath, 'connect-iframe', 'build'); + case 'suite-web': + return path.join(basePath, 'suite-web', 'build'); + default: + throw new Error('Missing project.'); + } +}; + +export const getSharedworkerDistPathForProject = (project: Project = 'iframe') => { + const basePath = path.join(__dirname, '..', '..'); + switch (project) { + case 'iframe': + return path.join(basePath, 'connect-iframe', 'build'); + case 'suite-web': + // It is hardcoded in suite-web: + // https://github.com/trezor/trezor-suite/blob/feat/use-core-in-suite-web/suite-common/connect-init/src/connectInitThunks.ts#L120 + // return path.join(basePath, 'suite-web', 'build', 'static', 'connect'); + return path.join(basePath, 'suite-web', 'build'); + default: + throw new Error('Missing project.'); + } +}; diff --git a/packages/connect-web/src/module/index.ts b/packages/connect-web/src/module/index.ts new file mode 100644 index 00000000000..d9555abfaff --- /dev/null +++ b/packages/connect-web/src/module/index.ts @@ -0,0 +1,70 @@ +import { factory } from '@trezor/connect/src/factory'; +import { config } from '@trezor/connect/src/data/config'; +import { TrezorConnectDynamic } from '@trezor/connect/src/impl/dynamic'; +import { CoreInModule } from '@trezor/connect/src/impl/core-in-module'; +// import webUSBB utton from '../webusb/button'; +import type { ConnectSettingsPublic } from '@trezor/connect/src/types'; +import type { ConnectFactoryDependencies } from '@trezor/connect/src/factory'; +import { ERRORS, TRANSPORT } from '@trezor/connect/src/exports'; + +const impl = new TrezorConnectDynamic< + 'core-in-module', + ConnectSettingsPublic, + ConnectFactoryDependencies +>({ + implementations: [ + { + type: 'core-in-module', + impl: new CoreInModule(), + }, + ], + getInitTarget: () => 'core-in-module', + handleErrorFallback: () => new Promise(resolve => resolve(false)), +}); + +const disableWebUSB = () => { + if (!impl.lastSettings) { + throw ERRORS.TypedError('Init_NotInitialized'); + } + + // @ts-ignore + impl.handleCoreMessage({ type: TRANSPORT.DISABLE_WEBUSB }); +}; + +const requestWebUSBDevice = async () => { + try { + await window.navigator.usb.requestDevice({ filters: config.webusb }); + // @ts-ignore + impl.handleCoreMessage({ type: TRANSPORT.REQUEST_DEVICE }); + } catch (_err) { + console.log('_err', _err); + } +}; + +// const renderWebUSBButton = (className?: string) => { +// if (!impl.lastSettings) { +// throw ERRORS.TypedError('Init_NotInitialized'); +// } +// webUSBButton(className, impl.lastSettings.webusbSrc); +// }; + +const TrezorConnect = factory( + { + eventEmitter: impl.eventEmitter, + init: impl.init.bind(impl), + call: impl.call.bind(impl), + manifest: impl.manifest.bind(impl), + requestLogin: impl.requestLogin.bind(impl), + uiResponse: impl.uiResponse.bind(impl), + cancel: impl.cancel.bind(impl), + dispose: impl.dispose.bind(impl), + }, + { + // renderWebUSBButton: renderWebUSBButton.bind(impl), + disableWebUSB: disableWebUSB.bind(impl), + requestWebUSBDevice: requestWebUSBDevice.bind(impl), + }, +); + +export default TrezorConnect; +export * from '@trezor/connect/src/exports'; diff --git a/packages/connect-web/tsconfig.json b/packages/connect-web/tsconfig.json index a9b9b19bebd..3db3e1cbfea 100644 --- a/packages/connect-web/tsconfig.json +++ b/packages/connect-web/tsconfig.json @@ -15,7 +15,8 @@ "include": [ ".", "../connect-iframe/webpack/base.webpack.config.ts", - "../connect-iframe/webpack/prod.webpack.config.ts", + "../connect-iframe/webpack/iframe.webpack.config.ts", + "../connect-iframe/webpack/utils.ts", "../connect-iframe/package.json", "../connect-popup/webpack/prod.webpack.config.ts", "../connect-popup/package.json" diff --git a/packages/connect-web/webpack/dev.webpack.config.ts b/packages/connect-web/webpack/dev.webpack.config.ts index febebc2b2a3..8da0328121b 100644 --- a/packages/connect-web/webpack/dev.webpack.config.ts +++ b/packages/connect-web/webpack/dev.webpack.config.ts @@ -6,7 +6,7 @@ import { WebpackPluginServe } from 'webpack-plugin-serve'; // todo: https://github.com/trezor/trezor-suite/issues/5305 import popup from '../../connect-popup/webpack/prod.webpack.config'; // todo: https://github.com/trezor/trezor-suite/issues/5305 -import iframe from '../../connect-iframe/webpack/prod.webpack.config'; +import iframe from '../../connect-iframe/webpack/iframe.webpack.config'; import prod from './prod.webpack.config'; const dev = { diff --git a/packages/connect/src/backend/Blockchain.ts b/packages/connect/src/backend/Blockchain.ts index a20ed76536c..f0f9cf57065 100644 --- a/packages/connect/src/backend/Blockchain.ts +++ b/packages/connect/src/backend/Blockchain.ts @@ -17,6 +17,8 @@ import { import type { CoinInfo, Proxy } from '../types'; const getWorker = (type: string) => { + console.log('getWorker in connect/src/backend'); + console.log('type', type); switch (type) { case 'blockbook': return BlockbookWorker; diff --git a/packages/connect/src/data/DataManager.ts b/packages/connect/src/data/DataManager.ts index 2413c2037e7..c165c557b6a 100644 --- a/packages/connect/src/data/DataManager.ts +++ b/packages/connect/src/data/DataManager.ts @@ -1,51 +1,75 @@ // origin: https://github.com/trezor/connect/blob/develop/src/js/data/DataManager.js -import { httpRequest } from '../utils/assets'; +// import { httpRequest } from '../utils/assets'; import { parseCoinsJson } from './coinInfo'; import { parseFirmware } from './firmwareInfo'; import { parseBridgeJSON } from './transportInfo'; import { ConnectSettings, DeviceModelInternal } from '../types'; +// TODO(karliatto): look at packages/connect/src/utils/assetUtils.ts !!! +// We require all the files to include them in the core.js bundle for web, +// if we do not include them in the bundle we would have to handle relative paths. +require('@trezor/connect-common/files/coins.json'); +require('@trezor/connect-common/files/coins-eth.json'); +require('@trezor/connect-common/files/bridge/releases.json'); +require('@trezor/connect-common/files/firmware/t1b1/releases.json'); +require('@trezor/connect-common/files/firmware/t2t1/releases.json'); +require('@trezor/connect-common/files/firmware/t2b1/releases.json'); +require('@trezor/connect-common/files/firmware/t3b1/releases.json'); +require('@trezor/connect-common/files/firmware/t3t1/releases.json'); +require('@trezor/connect-common/files/firmware/t3w1/releases.json'); +require('@trezor/protobuf/messages.json'); + +import coins from '@trezor/connect-common/files/coins.json'; +import coinsEth from '@trezor/connect-common/files/coins-eth.json'; +import bridge from '@trezor/connect-common/files/bridge/releases.json'; +import t1b1 from '@trezor/connect-common/files/firmware/t1b1/releases.json'; +import t2t2 from '@trezor/connect-common/files/firmware/t2t1/releases.json'; +import t2b1 from '@trezor/connect-common/files/firmware/t2b1/releases.json'; +import t3b1 from '@trezor/connect-common/files/firmware/t3b1/releases.json'; +import t3t1 from '@trezor/connect-common/files/firmware/t3t1/releases.json'; +import t3w1 from '@trezor/connect-common/files/firmware/t3w1/releases.json'; + type AssetCollection = { [key: string]: Record }; -const assets = [ - { - name: 'coins', - url: './data/coins.json', - }, - { - name: 'coinsEth', - url: './data/coins-eth.json', - }, - { - name: 'bridge', - url: './data/bridge/releases.json', - }, - { - name: 'firmware-t1b1', - url: './data/firmware/t1b1/releases.json', - }, - { - name: 'firmware-t2t1', - url: './data/firmware/t2t1/releases.json', - }, - { - name: 'firmware-t2b1', - url: './data/firmware/t2b1/releases.json', - }, - { - name: 'firmware-t3b1', - url: './data/firmware/t3b1/releases.json', - }, - { - name: 'firmware-t3t1', - url: './data/firmware/t3t1/releases.json', - }, - { - name: 'firmware-t3tw1', - url: './data/firmware/t3w1/releases.json', - }, -]; +// const assets = [ +// { +// name: 'coins', +// url: './data/coins.json', +// }, +// { +// name: 'coinsEth', +// url: './data/coins-eth.json', +// }, +// { +// name: 'bridge', +// url: './data/bridge/releases.json', +// }, +// { +// name: 'firmware-t1b1', +// url: './data/firmware/t1b1/releases.json', +// }, +// { +// name: 'firmware-t2t1', +// url: './data/firmware/t2t1/releases.json', +// }, +// { +// name: 'firmware-t2b1', +// url: './data/firmware/t2b1/releases.json', +// }, +// { +// name: 'firmware-t3b1', +// url: './data/firmware/t3b1/releases.json', +// }, +// { +// name: 'firmware-t3t1', +// url: './data/firmware/t3t1/releases.json', +// }, +// { +// name: 'firmware-t3tw1', +// url: './data/firmware/t3w1/releases.json', +// }, +// ]; export class DataManager { static assets: AssetCollection = {}; @@ -54,18 +78,60 @@ export class DataManager { private static messages: Record; static async load(settings: ConnectSettings, withAssets = true) { - const ts = settings.env === 'web' ? `?r=${settings.timestamp}` : ''; + // const ts = settings.env === 'web' ? `?r=${settings.timestamp}` : ''; this.settings = settings; if (!withAssets) return; - const assetPromises = assets.map(async asset => { - const json = await httpRequest(`${asset.url}${ts}`, 'json'); - this.assets[asset.name] = json; - }); - await Promise.all(assetPromises); + // const assetPromises = assets.map(async asset => { + // const json = await httpRequest(`${asset.url}${ts}`, 'json'); + // this.assets[asset.name] = json; + // }); + // await Promise.all(assetPromises); + + // this.messages = await httpRequest('./data/messages/messages.json', 'json'); + this.assets['coins'] = coins; + this.assets['coinsEth'] = coinsEth; + this.assets['bridge'] = bridge; + this.assets['firmware-t1b1'] = t1b1; + this.assets['firmware-t2t1'] = t2t2; + this.assets['firmware-t2b1'] = t2b1; + this.assets['firmware-t3b1'] = t3b1; + this.assets['firmware-t3t1'] = t3t1; + this.assets['firmware-t3w1'] = t3w1; + + // We need to declare those imports explicitly so webpack does not include the whole directories. + // this.assets['coins'] = (await import('@trezor/connect-common/files/coins.json')).default; + // this.assets['coinsEth'] = ( + // await import('@trezor/connect-common/files/coins-eth.json') + // ).default; + // this.assets['bridge'] = ( + // await import('@trezor/connect-common/files/bridge/releases.json') + // ).default; + // this.assets['firmware-t1b1'] = ( + // await import('@trezor/connect-common/files/firmware/t1b1/releases.json') + // ).default; + // this.assets['firmware-t2t1'] = ( + // await import('@trezor/connect-common/files/firmware/t2t1/releases.json') + // ).default; + // this.assets['firmware-t2b1'] = ( + // await import('@trezor/connect-common/files/firmware/t2b1/releases.json') + // ).default; + // this.assets['firmware-t3b1'] = ( + // await import('@trezor/connect-common/files/firmware/t3b1/releases.json') + // ).default; + // this.assets['firmware-t3t1'] = ( + // await import('@trezor/connect-common/files/firmware/t3t1/releases.json') + // ).default; + // this.assets['firmware-t3tw1'] = ( + // await import('@trezor/connect-common/files/firmware/t3w1/releases.json') + // ).default; + + console.log('this.assets in DataManager', this.assets); - this.messages = await httpRequest('./data/messages/messages.json', 'json'); + // this.messages = await httpRequest(`${config.messages}${ts}`, 'json'); + this.messages = (await import('@trezor/protobuf/messages.json')).default; + console.log('this.messages in DataManager', this.messages); // parse bridge JSON parseBridgeJSON(this.assets.bridge); diff --git a/packages/connect/src/impl/core-in-module.ts b/packages/connect/src/impl/core-in-module.ts new file mode 100644 index 00000000000..3b31938441d --- /dev/null +++ b/packages/connect/src/impl/core-in-module.ts @@ -0,0 +1,294 @@ +import EventEmitter from 'events'; + +// NOTE: @trezor/connect part is intentionally not imported from the index due to NormalReplacementPlugin +// in packages/suite-build/configs/web.webpack.config.ts +import * as ERRORS from '../constants/errors'; +import { + POPUP, + IFRAME, + UI, + UI_EVENT, + DEVICE_EVENT, + RESPONSE_EVENT, + TRANSPORT_EVENT, + BLOCKCHAIN_EVENT, + createErrorMessage, + UiResponseEvent, + CoreEventMessage, + CallMethodPayload, + CORE_EVENT, + CoreRequestMessage, +} from '../events'; +import type { ConnectSettings, ConnectSettingsPublic, DeviceIdentity, Manifest } from '../types'; +import { ConnectFactoryDependencies, factory } from '../factory'; +import { Log, initLog } from '../utils/debug'; +import { DeferredManager, createDeferredManager } from '@trezor/utils'; + +import { parseConnectSettings } from '../data/connectSettings'; + +export class CoreInModule implements ConnectFactoryDependencies { + public eventEmitter = new EventEmitter(); + public _settings: ConnectSettings; + + private _coreManager?: any; + private _log: Log; + private _messagePromises: DeferredManager<{ + id: number; + success: boolean; + payload: any; + device?: DeviceIdentity; + }>; + + private readonly boundOnCoreEvent = this.onCoreEvent.bind(this); + + public constructor() { + this._settings = parseConnectSettings(); + this._log = initLog('@trezor/connect-web'); + this._messagePromises = createDeferredManager({ initialId: 1 }); + } + + private async initCoreManager() { + const { connectSrc } = this._settings; + const { initCoreState, initTransport } = await import( + /* webpackIgnore: true */ `${connectSrc}js/core.js` + ).catch(_err => { + this._log.error('_err', _err); + }); + + if (!initCoreState) return; + + if (initTransport) { + this._log.debug('initiating transport with settings: ', this._settings); + await initTransport(this._settings); + } + + this._coreManager = initCoreState(); + + return this._coreManager; + } + + public manifest(data: Manifest) { + this._settings = parseConnectSettings({ + ...this._settings, + manifest: data, + }); + } + + public dispose() { + this.eventEmitter.removeAllListeners(); + this._settings = parseConnectSettings(); + if (this._coreManager) { + this._coreManager.dispose(); + } + + return Promise.resolve(undefined); + } + + public cancel(error?: string) { + if (this._coreManager) { + const core = this._coreManager.get(); + if (!core) { + throw ERRORS.TypedError('Runtime', 'postMessage: _core not found'); + } + + core.handleMessage({ + type: POPUP.CLOSED, + payload: error ? { error } : null, + }); + } + } + + // handle messages to core + public handleCoreMessage(message: CoreRequestMessage) { + const core = this._coreManager.get(); + core?.handleMessage(message); + } + + // handle message received from Core + private onCoreEvent(message: CoreEventMessage) { + const { event, type, payload } = message; + + if (type === UI.REQUEST_UI_WINDOW) { + this._coreManager.get()?.handleMessage({ type: POPUP.HANDSHAKE }); + + return; + } + + if (type === POPUP.CANCEL_POPUP_REQUEST) return; + + switch (event) { + case RESPONSE_EVENT: { + const { id = 0, success, device } = message; + const resolved = this._messagePromises.resolve(id, { + id, + success, + payload, + device, + }); + if (!resolved) this._log.warn(`Unknown message id ${id}`); + break; + } + case DEVICE_EVENT: + // pass DEVICE event up to html + this.eventEmitter.emit(event, message); + this.eventEmitter.emit(type, payload); // DEVICE_EVENT also emit single events (connect/disconnect...) + break; + + case TRANSPORT_EVENT: + this.eventEmitter.emit(event, message); + this.eventEmitter.emit(type, payload); + break; + + case BLOCKCHAIN_EVENT: + this.eventEmitter.emit(event, message); + this.eventEmitter.emit(type, payload); + break; + + case UI_EVENT: + // pass UI event up + this.eventEmitter.emit(event, message); + this.eventEmitter.emit(type, payload); + break; + + default: + this._log.warn('Undefined message', event, message); + } + } + + public async init(settings: Partial = {}) { + if (this._coreManager && (this._coreManager.get() || this._coreManager.getPending())) { + throw ERRORS.TypedError('Init_AlreadyInitialized'); + } + + this._settings = parseConnectSettings({ ...this._settings, ...settings }); + + if (!this._settings.manifest) { + throw ERRORS.TypedError('Init_ManifestMissing'); + } + this._settings.lazyLoad = true; + + // defaults for connect-web + if (!this._settings.transports?.length) { + this._settings.transports = ['BridgeTransport', 'WebUsbTransport']; + } + + if (!this._coreManager) { + this._coreManager = await this.initCoreManager(); + await this._coreManager.getOrInit(this._settings, this.boundOnCoreEvent); + } + + this._log.enabled = !!this._settings.debug; + } + + private initSettings = (settings: Partial = {}) => { + this._settings = parseConnectSettings({ + ...this._settings, + ...settings, + popup: false, + }); + + if (!this._settings.manifest) { + throw ERRORS.TypedError('Init_ManifestMissing'); + } + + if (!this._settings.transports?.length) { + // default fallback for node + this._settings.transports = ['BridgeTransport']; + } + }; + + public initCore() { + this.initSettings({ lazyLoad: false }); + + return this._coreManager.getOrInit(this._settings, this.boundOnCoreEvent); + } + + public async call(params: CallMethodPayload) { + let core; + try { + core = + this._coreManager.get() ?? + (await this._coreManager.getPending()) ?? + (await this.initCore()); + } catch (error) { + return createErrorMessage(error); + } + + try { + const { promiseId, promise } = this._messagePromises.create(); + core.handleMessage({ + type: IFRAME.CALL, + payload: params, + id: promiseId, + }); + const response = await promise; + + return response ?? createErrorMessage(ERRORS.TypedError('Method_NoResponse')); + } catch (error) { + this._log.error('call', error); + + return createErrorMessage(error); + } + } + + public uiResponse(response: UiResponseEvent) { + const core = this._coreManager.get(); + if (!core) { + throw ERRORS.TypedError('Init_NotInitialized'); + } + core.handleMessage(response); + } + + public async requestLogin(params: any) { + if (typeof params.callback === 'function') { + const { callback } = params; + const core = this._coreManager.get(); + + // TODO: set message listener only if _core is loaded correctly + const loginChallengeListener = async (event: MessageEvent) => { + const { data } = event; + if (data && data.type === UI.LOGIN_CHALLENGE_REQUEST) { + try { + const payload = await callback(); + core?.handleMessage({ + type: UI.LOGIN_CHALLENGE_RESPONSE, + payload, + }); + } catch (error) { + core?.handleMessage({ + type: UI.LOGIN_CHALLENGE_RESPONSE, + payload: error.message, + }); + } + } + }; + + core?.on(CORE_EVENT, loginChallengeListener); + const response = await this.call({ + method: 'requestLogin', + ...params, + asyncChallenge: true, + callback: null, + }); + core?.removeListener(CORE_EVENT, loginChallengeListener); + + return response; + } + + return this.call({ method: 'requestLogin', ...params }); + } +} + +const impl = new CoreInModule(); + +// Exported to enable using directly +export const TrezorConnect = factory({ + eventEmitter: impl.eventEmitter, + manifest: impl.manifest.bind(impl), + init: impl.init.bind(impl), + call: impl.call.bind(impl), + requestLogin: impl.requestLogin.bind(impl), + uiResponse: impl.uiResponse.bind(impl), + cancel: impl.cancel.bind(impl), + dispose: impl.dispose.bind(impl), +}); diff --git a/packages/product-components/src/utils/resolveStaticPath.ts b/packages/product-components/src/utils/resolveStaticPath.ts index 373a1bd387e..81c17c441af 100644 --- a/packages/product-components/src/utils/resolveStaticPath.ts +++ b/packages/product-components/src/utils/resolveStaticPath.ts @@ -1,4 +1,9 @@ export const resolveStaticPath = ( path: string, pathPrefix: string | undefined = process.env.ASSET_PREFIX, -) => `${pathPrefix || ''}/static/${path.replace(/^\/+/, '')}`; +) => { + console.log('resolve static path!!!'); + console.log('pathPrefix', pathPrefix); + console.log('path', path); + return `${pathPrefix || ''}/static/${path.replace(/^\/+/, '')}`; +}; diff --git a/packages/suite-build/configs/base.webpack.config.ts b/packages/suite-build/configs/base.webpack.config.ts index 30ad065ce8c..05f34549fc4 100644 --- a/packages/suite-build/configs/base.webpack.config.ts +++ b/packages/suite-build/configs/base.webpack.config.ts @@ -132,7 +132,7 @@ const config: webpack.Configuration = { }, ], }, - // Workers + // Workers TODO(karliatto): is this worker-loader really loading anything here? { test: /\/workers\/[^/]+\/index\.ts$/, use: [ diff --git a/packages/suite-build/configs/web.webpack.config.ts b/packages/suite-build/configs/web.webpack.config.ts index 316d05652fc..ec9de0e1ac3 100644 --- a/packages/suite-build/configs/web.webpack.config.ts +++ b/packages/suite-build/configs/web.webpack.config.ts @@ -35,12 +35,6 @@ const config: webpack.Configuration = { ), to: path.join(baseDir, 'build', 'static', 'message-system'), }, - ]) - .concat([ - { - from: path.join(__dirname, '..', '..', 'connect-iframe', 'build'), - to: path.join(baseDir, 'build', 'static', 'connect'), - }, ]), options: { concurrency: 100, @@ -73,7 +67,10 @@ const config: webpack.Configuration = { }), ), // imports from @trezor/connect in @trezor/suite package need to be replaced by imports from @trezor/connect-web - new webpack.NormalModuleReplacementPlugin(/@trezor\/connect$/, '@trezor/connect-web'), + new webpack.NormalModuleReplacementPlugin( + /@trezor\/connect$/, + '@trezor/connect-web/src/module', + ), ...(!isDev ? [new CssMinimizerPlugin()] : []), ], }; diff --git a/packages/suite-build/package.json b/packages/suite-build/package.json index 0e39dde4a85..d59254df889 100644 --- a/packages/suite-build/package.json +++ b/packages/suite-build/package.json @@ -11,7 +11,8 @@ "description": "trezor suite build", "scripts": { "base": "TS_NODE_PROJECT=\"tsconfig.json\" webpack --config ./webpack.config.ts", - "web": "PROJECT=web yarn run base", + "core:web": "PROJECT=\"suite-web\" yarn workspace @trezor/connect-iframe build:sessions && PROJECT=\"suite-web\" yarn workspace @trezor/connect-iframe build:core-module", + "web": "yarn run core:web && PROJECT=web yarn run base", "dev:web": "yarn run web", "build:web": "NODE_ENV=production yarn run web", "desktop": "PROJECT=desktop yarn run base", diff --git a/packages/suite-build/tsconfig.json b/packages/suite-build/tsconfig.json index ec831118d03..510741e3110 100644 --- a/packages/suite-build/tsconfig.json +++ b/packages/suite-build/tsconfig.json @@ -1,7 +1,7 @@ { "extends": "../../tsconfig.base.json", "compilerOptions": { "outDir": "./libDev" }, - "include": ["."], + "include": [".", "**/*.json"], "references": [ { "path": "../../suite-common/suite-config" diff --git a/packages/suite-web/e2e/run_tests.ts b/packages/suite-web/e2e/run_tests.ts index 199f38f503e..2a0bff50849 100644 --- a/packages/suite-web/e2e/run_tests.ts +++ b/packages/suite-web/e2e/run_tests.ts @@ -84,6 +84,7 @@ function parse(expected: 'string', str: any): string; function parse(expected: 'number', str: any): number; function parse(expected: 'boolean', str: any): boolean; function parse(expected: any, str: any): any { + console.log('str', str); if (str && typeof str !== 'string') { throw new Error(`Expected string, got ${str} (type ${typeof str})`); } @@ -109,8 +110,8 @@ const collectCIEnvVars = (): CIEnvVars => { const BROWSER = parse('string', process.env.BROWSER) || 'chrome'; const CYPRESS_baseUrl = parse('string', process.env.CYPRESS_baseUrl); const TRACK_SUITE_URL = parse('string', process.env.TRACK_SUITE_URL); - const ALLOW_RETRY = parse('boolean', process.env.ALLOW_RETRY); - const CYPRESS_updateSnapshots = parse('boolean', process.env.CYPRESS_updateSnapshots); + const ALLOW_RETRY = parse('boolean', 'true'); + const CYPRESS_updateSnapshots = parse('boolean', 'false'); const CYPRESS_TEST_URLS = parse('string', process.env.CYPRESS_TEST_URLS); const CI_JOB_URL = parse('string', process.env.CI_JOB_URL); const CI_COMMIT_BRANCH = parse('string', process.env.CI_COMMIT_BRANCH); diff --git a/packages/suite-web/e2e/stubs/metadata.ts b/packages/suite-web/e2e/stubs/metadata.ts index 4824b6d0e23..d8960979deb 100644 --- a/packages/suite-web/e2e/stubs/metadata.ts +++ b/packages/suite-web/e2e/stubs/metadata.ts @@ -13,13 +13,20 @@ export const rerouteMetadataToMockProvider = ( uri: string, options: Parameters[1], ) => { + console.log('rerouteMetadataToMockProvider uri', uri); + console.log('options', options); let url; try { url = new URL(uri); - } catch { - // catching absolute next.js urls which throw in URL constructor + } catch (_err) { + console.log('_err', _err); + // When requests like `./data/firmware/t3w1/releases.json` from connect they need to be + // provided with baseUrl so cypress can figure out where it is going. + const baseUrl = window.location.origin; + uri = new URL(uri, baseUrl).href; return fetch(uri, options); } + console.log('url', url); const dropboxOrigins = ['https://content.dropboxapi.com', 'https://api.dropboxapi.com']; diff --git a/packages/suite-web/e2e/support/utils/shortcuts.ts b/packages/suite-web/e2e/support/utils/shortcuts.ts index cf8f47200a1..2262c9c56ed 100644 --- a/packages/suite-web/e2e/support/utils/shortcuts.ts +++ b/packages/suite-web/e2e/support/utils/shortcuts.ts @@ -97,7 +97,7 @@ export const enableDebugMode = () => { export const disableFirmwareHashCheck = () => { // window.store may not be ready at this point, we need to wait for app to load - cy.getTestElement('@welcome-layout/body'); + cy.getTestElement('@welcome-layout/body'); cy.window().then(window => { window.store.dispatch({ type: SuiteActions.DEVICE_FIRMWARE_HASH_CHECK, diff --git a/packages/suite-web/e2e/tests/metadata/interval-fetching.test.ts b/packages/suite-web/e2e/tests/metadata/interval-fetching.test.ts index 5f2830e605a..ca7382209cd 100644 --- a/packages/suite-web/e2e/tests/metadata/interval-fetching.test.ts +++ b/packages/suite-web/e2e/tests/metadata/interval-fetching.test.ts @@ -26,12 +26,24 @@ describe('Metadata - suite is watching cloud provider and syncs periodically', ( }); fixtures.forEach(f => { it(`${f.provider}-${f.desc}`, () => { + // cy.visit('/'); + // prepare test cy.task('startEmu', { wipe: true }); cy.task('setupEmu', { mnemonic: 'mnemonic_all' }); cy.task('startBridge'); + // cy.clock(); + cy.prefixedVisit('/', { + onBeforeLoad: win => { + cy.stub(win, 'open').callsFake(stubOpen(win)); + cy.stub(win, 'fetch').callsFake(rerouteMetadataToMockProvider); + }, + }); + cy.getTestElement('@welcome-layout/body', { timeout: 60_000 }); cy.task('metadataStartProvider', f.provider); - cy.clock(); + + cy.log('before first metadataSetFileContent'); + // prepare some initial files cy.task('metadataSetFileContent', { provider: f.provider, @@ -44,13 +56,20 @@ describe('Metadata - suite is watching cloud provider and syncs periodically', ( }, aesKey: 'c785ef250807166bffc141960c525df97647fcc1bca57f6892ca3742ba86ed8d', }); - cy.prefixedVisit('/', { - onBeforeLoad: win => { - cy.stub(win, 'open').callsFake(stubOpen(win)); - cy.stub(win, 'fetch').callsFake(rerouteMetadataToMockProvider); - }, - }); + cy.log('after first metadataSetFileContent'); + + // cy.prefixedVisit('/', { + // onBeforeLoad: win => { + // cy.stub(win, 'open').callsFake(stubOpen(win)); + // cy.stub(win, 'fetch').callsFake(rerouteMetadataToMockProvider); + // }, + // }); + cy.log('after prefixedVisit'); + // cy.getTestElement('@welcome-layout/body', { timeout: 60_000 }); + cy.disableFirmwareHashCheck(); + cy.log('after disableFirmwareHashCheck'); + cy.clock(); cy.tick(1000); cy.getTestElement('@analytics/continue-button', { timeout: 30_000 }) .click() @@ -73,6 +92,7 @@ describe('Metadata - suite is watching cloud provider and syncs periodically', ( 'contain', 'already existing label', ); + cy.log('before metadataSetFileContent'); // now change data in provider and fast forward time, see if it updated cy.task('metadataSetFileContent', { provider: f.provider, @@ -85,7 +105,7 @@ describe('Metadata - suite is watching cloud provider and syncs periodically', ( }, aesKey: 'c785ef250807166bffc141960c525df97647fcc1bca57f6892ca3742ba86ed8d', }); - + cy.log('after metadataSetFileContent'); // and this does the time travel to trigger fetch cy.tick(METADATA_LABELING.FETCH_INTERVAL); cy.getTestElement('@account-menu/btc/normal/0/label').should('contain', f.content); diff --git a/packages/suite-web/e2e/tests/metadata/wallet-metadata.test.ts b/packages/suite-web/e2e/tests/metadata/wallet-metadata.test.ts index 76210114956..d8cf3f79e56 100644 --- a/packages/suite-web/e2e/tests/metadata/wallet-metadata.test.ts +++ b/packages/suite-web/e2e/tests/metadata/wallet-metadata.test.ts @@ -42,17 +42,24 @@ function checkStateNotificationsForErrors(): void { describe('Metadata - wallet labeling', () => { beforeEach(() => { cy.viewport('macbook-13').resetDb(); + cy.log('in beforeEach'); + cy.viewport(1440, 2560).resetDb(); cy.task('startEmu', { wipe: true }); cy.task('setupEmu', { mnemonic: 'mnemonic_all', passphrase_protection: true, }); + cy.log('before startBridge'); cy.task('startBridge'); + cy.log('before metadataStartProvider'); cy.task('metadataStartProvider', MetadataProvider.Dropbox); + console.log('before openApp'); openApp(); + console.log('before passThroughInitialRun'); cy.passThroughInitialRun(); + console.log('before discoveryShouldFinish'); cy.discoveryShouldFinish(); }); diff --git a/packages/suite-web/e2e/tests/onboarding/firmware-update.test.ts b/packages/suite-web/e2e/tests/onboarding/firmware-update.test.ts index ffd4d2054ca..f8f7fab2625 100644 --- a/packages/suite-web/e2e/tests/onboarding/firmware-update.test.ts +++ b/packages/suite-web/e2e/tests/onboarding/firmware-update.test.ts @@ -33,7 +33,7 @@ describe.skip('fw update from empty device bootloader 2.0.3 to firmware 2.5.1', cy.task('startMockedBridge', har); // make sure that we always upgrade to version 2.5.1 - cy.intercept('*', { pathname: '/static/connect/data/firmware/t2t1/releases.json' }, [ + cy.intercept('*', { pathname: '/data/firmware/t2t1/releases.json' }, [ { required: false, version: [2, 5, 1], @@ -53,7 +53,7 @@ describe.skip('fw update from empty device bootloader 2.0.3 to firmware 2.5.1', // make sure that 2.5.1 does not return 404 cy.intercept( '*', - { pathname: '/static/connect/data/firmware/t2t1/trezor-t2t1-2.5.1.bin' }, + { pathname: '/data/firmware/t2t1/trezor-t2t1-2.5.1.bin' }, // seems like response does not matter. I thought there was firmware validation but it is probably // only in place for custom firmware? 'foo-bar', diff --git a/packages/suite-web/e2e/tests/suite/passphrase-cardano.test.ts b/packages/suite-web/e2e/tests/suite/passphrase-cardano.test.ts index 6df59fa2c95..8e7441fa4d8 100644 --- a/packages/suite-web/e2e/tests/suite/passphrase-cardano.test.ts +++ b/packages/suite-web/e2e/tests/suite/passphrase-cardano.test.ts @@ -1,6 +1,11 @@ // @group_passphrase // @retry=2 +/** + * TODO(karliatto): + * This test currently fail because Cardano Serialization requires wasm module and cannot find it. + */ + import { onNavBar } from '../../support/pageObjects/topBarObject'; const correctPassphraseAddr = diff --git a/packages/suite/src/components/suite/WebUsbButton.tsx b/packages/suite/src/components/suite/WebUsbButton.tsx index dd65fe3ac91..0b2107b91d6 100644 --- a/packages/suite/src/components/suite/WebUsbButton.tsx +++ b/packages/suite/src/components/suite/WebUsbButton.tsx @@ -11,6 +11,7 @@ interface WebUsbButtonProps extends Omit { const handleClick = (e: React.MouseEvent) => { e.stopPropagation(); + console.log('TrezorConnect', TrezorConnect); (TrezorConnect as typeof TrezorConnectWeb).requestWebUSBDevice(); }; diff --git a/packages/suite/src/support/extraDependencies.ts b/packages/suite/src/support/extraDependencies.ts index 2c5127b54ce..a7e73163668 100644 --- a/packages/suite/src/support/extraDependencies.ts +++ b/packages/suite/src/support/extraDependencies.ts @@ -1,7 +1,6 @@ import { saveAs } from 'file-saver'; import { PayloadAction } from '@reduxjs/toolkit'; -import { resolveStaticPath } from '@suite-common/suite-utils'; import { getAccountKey, buildHistoricRatesFromStorage } from '@suite-common/wallet-utils'; import { DeviceRootState, @@ -40,7 +39,7 @@ import { AppState, ButtonRequest, TrezorDevice } from '../types/suite'; import { METADATA, STORAGE } from '../actions/suite/constants'; import { selectSuiteSettings } from '../reducers/suite/suiteReducer'; -const connectSrc = resolveStaticPath('connect/'); +const connectSrc = '../'; // 'https://localhost:8088/'; // 'https://connect.corp.sldev.cz/develop/'; diff --git a/suite-common/connect-init/src/connectInitThunks.ts b/suite-common/connect-init/src/connectInitThunks.ts index a0c78433c9d..b5409d9a519 100644 --- a/suite-common/connect-init/src/connectInitThunks.ts +++ b/suite-common/connect-init/src/connectInitThunks.ts @@ -8,7 +8,7 @@ import TrezorConnect, { } from '@trezor/connect'; import { getSynchronize } from '@trezor/utils'; import { deviceConnectThunks } from '@suite-common/wallet-core'; -import { resolveStaticPath } from '@suite-common/suite-utils'; +import { resolveConnectPath } from '@suite-common/suite-utils'; import { isDesktop, isNative } from '@trezor/env-utils'; import { cardanoConnectPatch } from './cardanoConnectPatch'; @@ -145,9 +145,12 @@ export const connectInitThunk = createThunk( // and it would be impossible to test this thunk in isolation (many unit tests depend on it). const binFilesBaseUrl = isDesktop() ? extra.selectors.selectDesktopBinDir(getState()) - : resolveStaticPath('connect/data'); + : resolveConnectPath('data'); + + console.log('binFilesBaseUrl', binFilesBaseUrl); try { + console.log('TrezorConnect', TrezorConnect); await TrezorConnect.init({ ...connectInitSettings, binFilesBaseUrl, diff --git a/suite-common/suite-utils/src/resolveStaticPath.ts b/suite-common/suite-utils/src/resolveStaticPath.ts index 373a1bd387e..a43c3aa3463 100644 --- a/suite-common/suite-utils/src/resolveStaticPath.ts +++ b/suite-common/suite-utils/src/resolveStaticPath.ts @@ -2,3 +2,15 @@ export const resolveStaticPath = ( path: string, pathPrefix: string | undefined = process.env.ASSET_PREFIX, ) => `${pathPrefix || ''}/static/${path.replace(/^\/+/, '')}`; + +export const resolveConnectPath = ( + path: string, + pathPrefix: string | undefined = process.env.ASSET_PREFIX, +) => { + console.log('resolveConnectPath'); + console.log('path', path); + console.log('pathPrefix', pathPrefix); + const resolvedPath = `${pathPrefix || ''}/${path.replace(/^\/+/, '')}`; + console.log('resolvedPath', resolvedPath); + return resolvedPath; +}; diff --git a/suite-common/wallet-core/src/firmware/getBinFilesBaseUrlThunk.ts b/suite-common/wallet-core/src/firmware/getBinFilesBaseUrlThunk.ts index 6e5d898890b..f1ce9d29296 100644 --- a/suite-common/wallet-core/src/firmware/getBinFilesBaseUrlThunk.ts +++ b/suite-common/wallet-core/src/firmware/getBinFilesBaseUrlThunk.ts @@ -1,5 +1,5 @@ import { isDesktop } from '@trezor/env-utils'; -import { resolveStaticPath } from '@suite-common/suite-utils'; +import { resolveConnectPath } from '@suite-common/suite-utils'; import { createThunk } from '@suite-common/redux-utils'; import { FIRMWARE_MODULE_PREFIX } from './firmwareActions'; @@ -12,5 +12,6 @@ export const getBinFilesBaseUrlThunk = createThunk( (_params, { getState, extra }) => isDesktop() ? extra.selectors.selectDesktopBinDir(getState()) - : resolveStaticPath('connect/data'), + : // TODO(karliatto): should this be fixed? probably yes. + resolveConnectPath('data'), ); diff --git a/suite-common/wallet-core/src/send/sendFormReducer.ts b/suite-common/wallet-core/src/send/sendFormReducer.ts index 52385050b20..354310ccdae 100644 --- a/suite-common/wallet-core/src/send/sendFormReducer.ts +++ b/suite-common/wallet-core/src/send/sendFormReducer.ts @@ -48,6 +48,7 @@ export type SendRootState = { }; export const prepareSendFormReducer = createReducerWithExtraDeps(initialState, (builder, extra) => { + console.log('prepareSendFormReducer'); builder .addCase( sendFormActions.storeDraft,