From d43466942f62fe904f7c29f81f7e5472d41e8c07 Mon Sep 17 00:00:00 2001 From: Lucas Lovato Date: Thu, 27 Jun 2024 11:07:51 -0300 Subject: [PATCH 01/17] chore: wip - build updates --- package.json | 12 +- patches/webextension-polyfill+0.8.0.patch | 21 - ...fill-ts++webextension-polyfill+0.7.0.patch | 21 - .../wext-manifest-webpack-plugin+1.2.1.patch | 139 - source/config/generateManifest.js | 25 +- source/config/manifest.json | 87 + source/config/webpack.common.js | 199 + source/config/webpack.dev.js | 14 + source/config/webpack.prod.js | 35 + .../Home/Panel/components/Assets/EvmList.tsx | 4 +- source/pages/Settings/About.tsx | 4 +- tests/e2e/AccountSettings.test.ts | 73 - tests/e2e/GeneralSettings.test.ts | 66 - tests/e2e/Home.test.ts | 27 - tests/e2e/Receive.test.ts | 60 - tests/e2e/Send.test.ts | 45 - tests/e2e/driver/chrome.js | 60 - tests/e2e/driver/driver.ts | 361 - tests/e2e/driver/firefox.js | 58 - tests/e2e/driver/index.ts | 36 - tests/e2e/initialize.ts | 14 - tests/mocks.ts | 108 - tests/psbt.json | 4 - tests/unit/priceStore.spec.ts | 31 - tests/unit/vaultStore.spec.ts | 261 - webpack.config.js | 284 - yarn.lock | 7959 +++++++++-------- 27 files changed, 4609 insertions(+), 5399 deletions(-) delete mode 100644 patches/webextension-polyfill+0.8.0.patch delete mode 100644 patches/webextension-polyfill-ts++webextension-polyfill+0.7.0.patch delete mode 100644 patches/wext-manifest-webpack-plugin+1.2.1.patch create mode 100644 source/config/manifest.json create mode 100644 source/config/webpack.common.js create mode 100644 source/config/webpack.dev.js create mode 100644 source/config/webpack.prod.js delete mode 100644 tests/e2e/AccountSettings.test.ts delete mode 100644 tests/e2e/GeneralSettings.test.ts delete mode 100644 tests/e2e/Home.test.ts delete mode 100644 tests/e2e/Receive.test.ts delete mode 100644 tests/e2e/Send.test.ts delete mode 100644 tests/e2e/driver/chrome.js delete mode 100644 tests/e2e/driver/driver.ts delete mode 100644 tests/e2e/driver/firefox.js delete mode 100644 tests/e2e/driver/index.ts delete mode 100644 tests/e2e/initialize.ts delete mode 100644 tests/mocks.ts delete mode 100644 tests/psbt.json delete mode 100644 tests/unit/priceStore.spec.ts delete mode 100644 tests/unit/vaultStore.spec.ts delete mode 100755 webpack.config.js diff --git a/package.json b/package.json index 9aefe96a7..4cab8c830 100644 --- a/package.json +++ b/package.json @@ -14,11 +14,11 @@ }, "scripts": { "generate-manifest": "node ./source/config/generateManifest.js", - "dev:chrome": "yarn generate-manifest && jq 'del(.environment) | .permissions = if .permissions then (if (.permissions | index(\"webRequest\")) == null then .permissions + [\"webRequest\"] else .permissions end) else [\"webRequest\"] end' manifest.json > modified_manifest.json && mv modified_manifest.json manifest.json && cross-env NODE_ENV=development cross-env TARGET_BROWSER=chrome webpack --watch", + "dev:chrome": "yarn generate-manifest && cross-env NODE_ENV=development cross-env TARGET_BROWSER=chrome webpack --config source/config/webpack.dev.js --watch", + "build:chrome": "yarn generate-manifest && cross-env NODE_ENV=production cross-env TARGET_BROWSER=chrome webpack --config source/config/webpack.prod.js", "dev-watch-requests:chrome": "jq '.permissions = if .permissions then (if (.permissions | index(\"webRequest\")) == null then .permissions + [\"webRequest\"] else .permissions end) else [\"webRequest\"] end | .environment = {\"WATCH_REQUESTS\": \"active\"}' manifest.json > modified_manifest.json && mv modified_manifest.json manifest.json && cross-env NODE_ENV=development cross-env TARGET_BROWSER=chrome webpack --watch", "dev:firefox": "jq '.permissions = if .permissions then (if (.permissions | index(\"webRequest\")) == null then .permissions + [\"webRequest\"] else .permissions end) else [\"webRequest\"] end' manifest.json > modified_manifest.json && mv modified_manifest.json manifest.json && cross-env NODE_ENV=development cross-env TARGET_BROWSER=firefox webpack --watch", "dev:opera": "jq '.permissions = if .permissions then (if (.permissions | index(\"webRequest\")) == null then .permissions + [\"webRequest\"] else .permissions end) else [\"webRequest\"] end' manifest.json > modified_manifest.json && mv modified_manifest.json manifest.json && cross-env NODE_ENV=development cross-env TARGET_BROWSER=opera webpack --watch", - "build:chrome": "jq '.permissions = if .permissions then (.permissions | map(select(. != \"webRequest\"))) else .permissions end' manifest.json > modified_manifest.json && mv modified_manifest.json manifest.json && cross-env NODE_ENV=production cross-env TARGET_BROWSER=chrome webpack", "build:firefox": "jq '.permissions = if .permissions then (.permissions | map(select(. != \"webRequest\"))) else .permissions end' manifest.json > modified_manifest.json && mv modified_manifest.json manifest.json && cross-env NODE_ENV=production cross-env TARGET_BROWSER=firefox webpack", "build:opera": "jq '.permissions = if .permissions then (.permissions | map(select(. != \"webRequest\"))) else .permissions end' manifest.json > modified_manifest.json && mv modified_manifest.json manifest.json && cross-env NODE_ENV=production cross-env TARGET_BROWSER=opera webpack", "build": "yarn run build:chrome && yarn run build:firefox && yarn run build:opera", @@ -49,7 +49,7 @@ "@babel/runtime": "^7.21.5", "@headlessui/react": "^1.6.0", "@heroicons/react": "^1.0.5", - "@pollum-io/sysweb3-keyring": "^1.0.479", + "@pollum-io/sysweb3-keyring": "/Users/lucaslovato/Documents/sysweb3/packages/sysweb3-keyring/dist", "@pollum-io/sysweb3-network": "^1.0.95", "@pollum-io/sysweb3-utils": "^1.1.232", "@reduxjs/toolkit": "^1.4.0", @@ -170,10 +170,12 @@ "ts-jest": "^27.1.3", "typescript": "4.1.5", "webpack": "^5.82.0", + "webpack-bundle-analyzer": "^4.10.2", "webpack-cli": "^5.0.2", "webpack-dev-server": "^4.13.3", + "webpack-merge": "^5.10.0", "wext-manifest-loader": "^3.0.0", - "wext-manifest-webpack-plugin": "^1.2.1" + "wext-manifest-webpack-plugin": "^1.4.1" }, "main": "index.js", "bugs": { @@ -181,4 +183,4 @@ }, "homepage": "https://github.com/syscoin/pali_wallet#readme", "author": "pollum labs" -} \ No newline at end of file +} diff --git a/patches/webextension-polyfill+0.8.0.patch b/patches/webextension-polyfill+0.8.0.patch deleted file mode 100644 index a967b8215..000000000 --- a/patches/webextension-polyfill+0.8.0.patch +++ /dev/null @@ -1,21 +0,0 @@ -diff --git a/node_modules/webextension-polyfill/dist/browser-polyfill.js b/node_modules/webextension-polyfill/dist/browser-polyfill.js -index 230b763..68170c4 100644 ---- a/node_modules/webextension-polyfill/dist/browser-polyfill.js -+++ b/node_modules/webextension-polyfill/dist/browser-polyfill.js -@@ -24,6 +24,7 @@ - - if (typeof browser === "undefined" || Object.getPrototypeOf(browser) !== Object.prototype) { - const CHROME_SEND_MESSAGE_CALLBACK_NO_RESPONSE_MESSAGE = "The message port closed before a response was received."; -+ const CHROME_SEND_MESSAGE_CALLBACK_NO_LISTENER_MESSAGE = "A listener indicated an asynchronous response by returning true, but the message channel closed before a response was received"; // No period - const SEND_RESPONSE_DEPRECATION_WARNING = "Returning a Promise is the preferred way to send a reply from an onMessage/onMessageExternal listener, as the sendResponse will be removed from the specs (See https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage)"; // Wrapping the bulk of this polyfill in a one-time-use function is a minor - // optimization for Firefox. Since Spidermonkey does not fully parse the - // contents of a function until the first time it's called, and since it will -@@ -1181,7 +1182,7 @@ - // Detect when none of the listeners replied to the sendMessage call and resolve - // the promise to undefined as in Firefox. - // See https://github.com/mozilla/webextension-polyfill/issues/130 -- if (extensionAPIs.runtime.lastError.message === CHROME_SEND_MESSAGE_CALLBACK_NO_RESPONSE_MESSAGE) { -+ if (extensionAPIs.runtime.lastError.message === CHROME_SEND_MESSAGE_CALLBACK_NO_RESPONSE_MESSAGE || extensionAPIs.runtime.lastError.message === CHROME_SEND_MESSAGE_CALLBACK_NO_LISTENER_MESSAGE) { - resolve(); - } else { - reject(new Error(extensionAPIs.runtime.lastError.message)); diff --git a/patches/webextension-polyfill-ts++webextension-polyfill+0.7.0.patch b/patches/webextension-polyfill-ts++webextension-polyfill+0.7.0.patch deleted file mode 100644 index 37b569812..000000000 --- a/patches/webextension-polyfill-ts++webextension-polyfill+0.7.0.patch +++ /dev/null @@ -1,21 +0,0 @@ -diff --git a/node_modules/webextension-polyfill-ts/node_modules/webextension-polyfill/dist/browser-polyfill.js b/node_modules/webextension-polyfill-ts/node_modules/webextension-polyfill/dist/browser-polyfill.js -index 51f7fb6..eae5bce 100644 ---- a/node_modules/webextension-polyfill-ts/node_modules/webextension-polyfill/dist/browser-polyfill.js -+++ b/node_modules/webextension-polyfill-ts/node_modules/webextension-polyfill/dist/browser-polyfill.js -@@ -24,6 +24,7 @@ - - if (typeof browser === "undefined" || Object.getPrototypeOf(browser) !== Object.prototype) { - const CHROME_SEND_MESSAGE_CALLBACK_NO_RESPONSE_MESSAGE = "The message port closed before a response was received."; -+ const CHROME_SEND_MESSAGE_CALLBACK_NO_LISTENER_MESSAGE = "A listener indicated an asynchronous response by returning true, but the message channel closed before a response was received"; // No period - const SEND_RESPONSE_DEPRECATION_WARNING = "Returning a Promise is the preferred way to send a reply from an onMessage/onMessageExternal listener, as the sendResponse will be removed from the specs (See https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage)"; // Wrapping the bulk of this polyfill in a one-time-use function is a minor - // optimization for Firefox. Since Spidermonkey does not fully parse the - // contents of a function until the first time it's called, and since it will -@@ -1147,7 +1148,7 @@ - // Detect when none of the listeners replied to the sendMessage call and resolve - // the promise to undefined as in Firefox. - // See https://github.com/mozilla/webextension-polyfill/issues/130 -- if (extensionAPIs.runtime.lastError.message === CHROME_SEND_MESSAGE_CALLBACK_NO_RESPONSE_MESSAGE) { -+ if (extensionAPIs.runtime.lastError.message === CHROME_SEND_MESSAGE_CALLBACK_NO_RESPONSE_MESSAGE || extensionAPIs.runtime.lastError.message === CHROME_SEND_MESSAGE_CALLBACK_NO_LISTENER_MESSAGE) { - resolve(); - } else { - reject(extensionAPIs.runtime.lastError); diff --git a/patches/wext-manifest-webpack-plugin+1.2.1.patch b/patches/wext-manifest-webpack-plugin+1.2.1.patch deleted file mode 100644 index e43ea43b6..000000000 --- a/patches/wext-manifest-webpack-plugin+1.2.1.patch +++ /dev/null @@ -1,139 +0,0 @@ -diff --git a/node_modules/wext-manifest-webpack-plugin/lib/plugin.js b/node_modules/wext-manifest-webpack-plugin/lib/plugin.js -index d52d6cd..1be21ae 100644 ---- a/node_modules/wext-manifest-webpack-plugin/lib/plugin.js -+++ b/node_modules/wext-manifest-webpack-plugin/lib/plugin.js -@@ -8,18 +8,34 @@ exports.WextManifestWebpackPlugin = void 0; - * @author abhijithvijayan - * @license MIT License - */ -+ -+const defaultOptions = { -+ extensions: ["css", "scss", "sass", "less", "styl"], -+ scriptExtensions: ["js", "mjs"], -+ ignore: undefined, -+}; -+ - require("emoji-log"); - const PLUGIN_NAME = 'wext-manifest-webpack-plugin'; --function getEntryResource(module) { -- const resource = null; -- if (module && typeof module.resource === 'string') { -- return module.resource; -- } -- return resource; --} -+ - class WextManifestWebpackPlugin { -+ constructor(options) { -+ this.apply = this.apply.bind(this); -+ this.options = Object.assign({}, defaultOptions, options); -+ } - // Define `apply` as its prototype method which is supplied with compiler as its argument - apply(compiler) { -+ const extensionsWithoutDots = this.options.extensions.map(e => -+ e[0] === "." ? e.substring(1) : e -+ ); -+ -+ const patternOneOfExtensions = extensionsWithoutDots -+ .map(ext => escapeRegExp(ext)) -+ .join("|"); -+ -+ const resourcesRegex = new RegExp( -+ `[.](${patternOneOfExtensions})([?].*)?$` -+ ); - /** - * webpack 4+ comes with a new plugin system. - * -@@ -30,19 +46,33 @@ class WextManifestWebpackPlugin { - if (hooks) { - // Runs plugin after a compilation has been created. - hooks.compilation.tap(PLUGIN_NAME, (compilation) => { -+ const resourcesCache = []; - // Triggered when an asset from a chunk was added to the compilation. - compilation.hooks.chunkAsset.tap(PLUGIN_NAME, (chunk, file) => { -+ - // Only handle js files with entry modules -- if (!file.endsWith('.js') || !chunk.hasEntryModule()) { -- return; -- } -+ let isNotScript = defaultOptions.scriptExtensions.every((ext) => file.lastIndexOf('.' + ext) < 0) -+ if(isNotScript) return -+ -+ // has entry modules -+ if (compilation.chunkGraph.getNumberOfEntryModules(chunk) < 1) return; -+ const entryModules = Array.from(compilation.chunkGraph.getChunkEntryModulesIterable(chunk)); -+ if (entryModules.length < 1) return; -+ -+ const entryModule = entryModules[0]; -+ const rawResources = collectEntryResources(compilation, entryModule, resourcesCache); -+ - // Returns path containing name of asset -- const resource = getEntryResource(chunk.entryModule); -- const isManifest = (resource && /manifest\.json$/.test(resource)) || false; -+ const resources = defaultOptions.ignore ? -+ rawResources.filter(r => !r.match(this.options.ignore)) -+ : rawResources; -+ -+ const isManifest = resources.length && -+ resources.every(resource => resourcesRegex.test(resource) || /manifest\.json$/.test(resource)); -+ - if (isManifest) { -- chunk.files = chunk.files.filter((f) => { -- return f !== file; -- }); -+ chunk.files.delete(file) -+ - delete compilation.assets[file]; - // https://github.com/abhijithvijayan/wext-manifest-webpack-plugin/issues/1 - // console.emoji('🦄', `${PLUGIN_NAME}: removed ${file}`, 29); -@@ -53,4 +83,49 @@ class WextManifestWebpackPlugin { - } - } - } -+function collectEntryResources(compilation, module, cache) { -+ const index = compilation.moduleGraph.getPreOrderIndex(module); -+ -+ // index of module is unique per compilation -+ // module.id can be null, not used here -+ if (cache[index] !== undefined) { -+ return cache[index]; -+ } -+ -+ if (typeof module.resource == "string") { -+ const resources = [module.resource]; -+ cache[index] = resources; -+ return resources; -+ } -+ -+ const resources = []; -+ if (module.dependencies) { -+ const hasModuleGraphSupport = compilation.hasOwnProperty('moduleGraph'); -+ module.dependencies.forEach(dep => { -+ if(dep) { -+ const module = hasModuleGraphSupport ? compilation.moduleGraph.getModule(dep) : dep.module; -+ const originModule = hasModuleGraphSupport ? compilation.moduleGraph.getParentModule(dep) : dep.originModule; -+ const nextModule = module || originModule; -+ if (nextModule) { -+ const depResources = collectEntryResources(compilation, nextModule, cache); -+ for (let index = 0, length = depResources.length; index !== length; index++) { -+ resources.push(depResources[index]); -+ } -+ } -+ } -+ }); -+ } -+ -+ cache[index] = resources; -+ return resources; -+} -+ -+const reRegExpChar = /[\\^$.*+?()[\]{}|]/g; -+const reHasRegExpChar = RegExp(reRegExpChar.source); -+function escapeRegExp(string) { -+ string = String(string); -+ return string && reHasRegExpChar.test(string) -+ ? string.replace(reRegExpChar, "\\$&") -+ : string; -+} - exports.WextManifestWebpackPlugin = WextManifestWebpackPlugin; -\ No newline at end of file diff --git a/source/config/generateManifest.js b/source/config/generateManifest.js index 0e982ae23..d62e0f6ca 100644 --- a/source/config/generateManifest.js +++ b/source/config/generateManifest.js @@ -2,18 +2,41 @@ const dotenv = require('dotenv'); const fs = require('fs'); +const path = require('path'); const { MV2_OPTIONS, MV3_OPTIONS } = require('./consts.js'); dotenv.config(); +const manifestPath = path.join(__dirname, 'manifest.json'); + function generateManifest() { console.log(process.env.MANIFEST_TYPE); const manifestOptions = process.env.MANIFEST_TYPE === 'MV2' ? MV2_OPTIONS : MV3_OPTIONS; + // dev + if (process.env.NODE_ENV === 'development') { + delete manifestOptions.environment; + if (!manifestOptions.permissions) { + manifestOptions.permissions = []; + } + if (!manifestOptions.permissions.includes('webRequest')) { + manifestOptions.permissions.push('webRequest'); + } + } + + // prod + if (process.env.NODE_ENV === 'production') { + if (manifestOptions.permissions) { + manifestOptions.permissions = manifestOptions.permissions.filter( + (permission) => permission !== 'webRequest' + ); + } + } + const manifestContent = JSON.stringify(manifestOptions, null, 2); - fs.writeFileSync('manifest.json', manifestContent); + fs.writeFileSync(manifestPath, manifestContent); } generateManifest(); diff --git a/source/config/manifest.json b/source/config/manifest.json new file mode 100644 index 000000000..087627c4a --- /dev/null +++ b/source/config/manifest.json @@ -0,0 +1,87 @@ +{ + "manifest_version": 3, + "name": "Pali Wallet", + "version": "2.0.18", + "icons": { + "16": "assets/icons/favicon-16.png", + "32": "assets/icons/favicon-32.png", + "48": "assets/icons/favicon-48.png", + "128": "assets/icons/favicon-128.png" + }, + "description": "A Non-Custodial Crypto Wallet", + "short_name": "pali", + "permissions": [ + "storage", + "activeTab", + "clipboardWrite", + "unlimitedStorage", + "offscreen" + ], + "host_permissions": [ + "http://*/*", + "https://*/*", + "*://connect.trezor.io/9/*", + "*://*.eth/", + "http://localhost:8545/" + ], + "content_security_policy": { + "extension_pages": "script-src 'self'; object-src 'self'" + }, + "author": "pollum labs", + "minimum_chrome_version": "49", + "action": { + "default_popup": "app.html", + "default_icon": { + "16": "assets/icons/favicon-16.png", + "32": "assets/icons/favicon-32.png", + "48": "assets/icons/favicon-48.png", + "128": "assets/icons/favicon-128.png" + }, + "default_title": "Pali Wallet" + }, + "background": { + "service_worker": "js/background.bundle.js" + }, + "content_scripts": [ + { + "all_frames": true, + "matches": [ + "file://*/*", + "http://*/*", + "https://*/*" + ], + "run_at": "document_start", + "js": [ + "js/contentScript.bundle.js" + ] + }, + { + "matches": [ + "*://connect.trezor.io/9/popup.html", + "https://localhost:8088/*" + ], + "js": [ + "js/trezorScript.bundle.js" + ] + } + ], + "web_accessible_resources": [ + { + "resources": [ + "js/inpage.bundle.js", + "js/handleWindowProperties.bundle.js", + "js/pali.bundle.js" + ], + "matches": [ + "" + ] + } + ], + "commands": { + "_execute_action": { + "suggested_key": { + "default": "Ctrl+Shift+P" + } + } + } +} \ No newline at end of file diff --git a/source/config/webpack.common.js b/source/config/webpack.common.js new file mode 100644 index 000000000..cff1bac06 --- /dev/null +++ b/source/config/webpack.common.js @@ -0,0 +1,199 @@ +const CopyWebpackPlugin = require('copy-webpack-plugin'); +const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); +const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); +const NodePolyfillPlugin = require('node-polyfill-webpack-plugin'); +const { join, resolve } = require('path'); +const TerserPlugin = require('terser-webpack-plugin'); +const { DefinePlugin } = require('webpack'); + +const viewsPath = join(__dirname, '../../views'); +const sourcePath = join(__dirname, '../../source'); +const destPath = join(__dirname, '../../build'); +const targetBrowser = process.env.TARGET_BROWSER || 'chrome'; + +module.exports = { + entry: { + manifest: join(__dirname, '../../manifest.json'), + background: join(sourcePath, 'scripts/Background', 'index.ts'), + inpage: join(sourcePath, 'scripts/ContentScript', 'inject/inpage.ts'), + pali: join(sourcePath, 'scripts/ContentScript', 'inject/pali.ts'), + handleWindowProperties: join( + sourcePath, + 'scripts/ContentScript', + 'inject/handleWindowProperties.ts' + ), + contentScript: join(sourcePath, 'scripts/ContentScript', 'index.ts'), + app: join(sourcePath, 'pages/App', 'index.tsx'), + external: join(sourcePath, 'pages/External', 'index.tsx'), + trezorScript: join( + sourcePath, + 'scripts/ContentScript/trezor', + 'trezor-content-script.ts' + ), + trezorUSB: join( + sourcePath, + 'scripts/ContentScript/trezor', + 'trezor-usb-permissions.ts' + ), + offscreenScript: join( + sourcePath, + 'scripts/ContentScript/offscreen', + 'index.ts' + ), + }, + output: { + path: join(destPath, targetBrowser), + filename: 'js/[name].bundle.js', + clean: true, + }, + resolve: { + extensions: ['.ts', '.tsx', '.js', '.json'], + alias: { + assets: resolve(__dirname, '../../source/assets'), + components: resolve(__dirname, '../../source/components'), + scripts: resolve(__dirname, '../../source/scripts'), + containers: resolve(__dirname, '../../source/containers'), + pages: resolve(__dirname, '../../source/pages'), + routers: resolve(__dirname, '../../source/routers'), + state: resolve(__dirname, '../../source/state'), + constants: resolve(__dirname, '../../source/constants'), + services: resolve(__dirname, '../../source/services'), + hooks: resolve(__dirname, '../../source/hooks'), + utils: resolve(__dirname, '../../source/utils'), + helpers: resolve(__dirname, '../../source/helpers'), + }, + fallback: { + fs: false, + }, + }, + module: { + rules: [ + { + test: /\.(jpg|png|xlsx|xls|csv)$/i, + type: 'asset/resource', + generator: { + filename: '[path][name][ext]', + }, + exclude: /node_modules/, + }, + { + test: /\.(svg)$/i, + type: 'asset/inline', + exclude: /node_modules/, + }, + { + test: /\.(js|ts)x?$/, + loader: 'babel-loader', + exclude: /node_modules/, + }, + { + test: /\.less$/, + use: [ + 'style-loader', + 'css-loader', + { + loader: 'less-loader', + options: { + lessOptions: { + modifyVars: { + 'primary-color': '#1DA57A', + 'link-color': '#1DA57A', + 'border-radius-base': '2rem', + }, + javascriptEnabled: true, + }, + }, + }, + ], + }, + { + test: /\.(ttf)$/, + type: 'asset/resource', + generator: { + filename: '[path][name][ext]', + }, + }, + { + test: /\.(sa|sc|c)ss$/, + use: [ + MiniCssExtractPlugin.loader, + 'css-loader', + 'postcss-loader', + 'resolve-url-loader', + 'sass-loader', + ], + }, + ], + }, + plugins: [ + new ForkTsCheckerWebpackPlugin(), + new DefinePlugin({ + NODE_ENV: JSON.stringify(process.env.NODE_ENV), + TARGET_BROWSER: JSON.stringify(targetBrowser), + }), + new HtmlWebpackPlugin({ + template: join(viewsPath, 'app.html'), + inject: 'body', + chunks: ['app'], + hash: true, + filename: 'app.html', + }), + new HtmlWebpackPlugin({ + template: join(viewsPath, 'external.html'), + inject: 'body', + chunks: ['external'], + hash: true, + filename: 'external.html', + }), + new HtmlWebpackPlugin({ + template: join(viewsPath, 'trezor-usb-permissions.html'), + filename: 'trezor-usb-permissions.html', + inject: 'body', + chunks: ['trezorUSB'], + }), + new HtmlWebpackPlugin({ + template: join(viewsPath, 'offscreen.html'), + filename: 'offscreen.html', + inject: 'body', + chunks: ['offscreenScript'], + }), + new MiniCssExtractPlugin({ filename: 'css/[name].css' }), + new CopyWebpackPlugin({ + patterns: [{ from: 'source/assets', to: 'assets' }], + }), + new CopyWebpackPlugin({ + patterns: [ + { + from: './manifest.json', + to: join(__dirname, '../../build/chrome'), + force: true, + transform: function (content) { + return Buffer.from( + JSON.stringify({ ...JSON.parse(content.toString()) }) + ); + }, + }, + ], + }), + new NodePolyfillPlugin(), + ], + optimization: { + minimizer: [ + new CssMinimizerPlugin(), + new TerserPlugin({ + parallel: true, + terserOptions: { + compress: { + drop_console: true, + }, + output: { + comments: false, + }, + }, + extractComments: false, + }), + ], + }, +}; diff --git a/source/config/webpack.dev.js b/source/config/webpack.dev.js new file mode 100644 index 000000000..da415ba56 --- /dev/null +++ b/source/config/webpack.dev.js @@ -0,0 +1,14 @@ +const { merge } = require('webpack-merge'); +const common = require('./webpack.common'); +const path = require('path'); + +module.exports = merge(common, { + mode: 'development', + devtool: 'inline-source-map', + devServer: { + compress: true, + port: 9090, + hot: true, + watchFiles: ['*'], + }, +}); diff --git a/source/config/webpack.prod.js b/source/config/webpack.prod.js new file mode 100644 index 000000000..7626a5005 --- /dev/null +++ b/source/config/webpack.prod.js @@ -0,0 +1,35 @@ +const { merge } = require('webpack-merge'); +const path = require('path'); +const ZipPlugin = require('zip-webpack-plugin'); +const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); +const common = require('./webpack.common'); +const version = require('../../package.json').version; + +const targetBrowser = process.env.TARGET_BROWSER || 'chrome'; + +module.exports = merge(common, { + mode: 'production', + devtool: 'source-map', + plugins: [ + new ZipPlugin({ + filename: `pali-wallet-${targetBrowser}-${version}`, + path: path.join(__dirname, '../../build'), + extension: `${ + targetBrowser === 'opera' + ? 'crx' + : targetBrowser === 'firefox' + ? 'xpi' + : 'zip' + }`, + }), + new BundleAnalyzerPlugin({ + analyzerMode: 'static', + openAnalyzer: false, + reportFilename: path.join( + __dirname, + '../../build', + `${targetBrowser}-report.html` + ), + }), + ], +}); diff --git a/source/pages/Home/Panel/components/Assets/EvmList.tsx b/source/pages/Home/Panel/components/Assets/EvmList.tsx index 6e2a4d18b..4c7323485 100644 --- a/source/pages/Home/Panel/components/Assets/EvmList.tsx +++ b/source/pages/Home/Panel/components/Assets/EvmList.tsx @@ -1,11 +1,11 @@ import { uniqueId } from 'lodash'; import React, { Fragment, useState } from 'react'; import { useTranslation } from 'react-i18next'; +import { HiTrash as DeleteIcon } from 'react-icons/hi'; import { - FiTrash as DeleteIcon, RiEditLine as EditIcon, RiShareForward2Line as DetailsIcon, -} from 'react-icons/all'; +} from 'react-icons/ri'; import { useSelector } from 'react-redux'; import { EvmNftsList } from '../Nfts/EvmNftsList'; diff --git a/source/pages/Settings/About.tsx b/source/pages/Settings/About.tsx index 47d033381..ef93aba32 100644 --- a/source/pages/Settings/About.tsx +++ b/source/pages/Settings/About.tsx @@ -1,7 +1,7 @@ import React, { FC } from 'react'; import { useTranslation } from 'react-i18next'; -import { version } from '../../../package.json'; +import packageJson from '../../../package.json'; import paliLogo from 'assets/images/paliLogoSmall.png'; import { Layout, Icon, SimpleCard, IconButton, Button } from 'components/index'; import { useUtils } from 'hooks/index'; @@ -30,7 +30,7 @@ const AboutView: FC = () => {

Pali Wallet Browser Extension

- {t('settings.version')}: {version} + {t('settings.version')}: {packageJson.version}

- - Import using wallet seed phrase - - - ); + console.log(isFirstStep, 'isFirstStep'); + + useEffect(() => { + const checkAccounts = async () => { + const result = await controllerEmitter(['wallet', 'getActiveAccount']); + + console.log(result, 'result'); + setHasAccount(!!result); + }; + + checkAccounts(); + + return () => { + checkAccounts(); + }; + }, []); const onSubmit = async ({ password }: { password: string }) => { try { - await migrateWalletState('persist:root', 'state'); + // await controllerEmitter( + // ['migrateWalletState'], + // ['persist:root', 'state', hasAccount] + // ); + await migrateWalletState('persist:root', 'state', hasAccount); + + const result = false; - const result = await wallet.unlockFromController(password); + // const result = await controllerEmitter( + // ['wallet', 'unlockFromController'], + // [password] + // ); if (!result) { setErrorMessage(t('start.wrongPassword')); @@ -66,6 +71,28 @@ export const Start = (props: any) => { } }; + const getStarted = ( + <> + + + Import using wallet seed phrase + + + ); + const unLock = ( <>
{ - const { appRoute, wallet } = getController(); const { navigate, alert } = useUtils(); const { pathname, search } = useLocation(); + const { isUnlocked, isLoading, controllerEmitter } = useController(); // defaultRoute stores info from createPopup // used to redirect after unlocking the wallet const query = useQuery(); const [defaultRoute] = useState(query.route + '?data=' + query.data); - const isUnlocked = wallet.isUnlocked(); - useEffect(() => { if (isUnlocked && defaultRoute) { navigate(`/external/${defaultRoute}`); @@ -57,15 +55,25 @@ export const ExternalRoute = () => { return; } - const externalRoute = appRoute(null, true); - if (externalRoute !== '/') navigate(externalRoute); + async function checkExternalRoute() { + const externalRoute = await controllerEmitter(['appRoute'], [null, true]); + if (externalRoute !== '/') navigate(externalRoute); + } + + checkExternalRoute(); + + return () => { + checkExternalRoute(); + }; }, [isUnlocked]); useEffect(() => { alert.removeAll(); - appRoute(pathname + search, true); + controllerEmitter(['appRoute'], [pathname + search, true]); }, [pathname]); + if (isLoading && !isUnlocked) return ; + return ( }> diff --git a/source/routers/ProtectedRoute.tsx b/source/routers/ProtectedRoute.tsx index f09ea29be..26a649070 100644 --- a/source/routers/ProtectedRoute.tsx +++ b/source/routers/ProtectedRoute.tsx @@ -1,12 +1,17 @@ import React from 'react'; import { Navigate } from 'react-router-dom'; -import { getController } from 'scripts/Background'; +import { Loading } from 'components/Loading'; +import { useController } from 'hooks/useController'; export function ProtectedRoute({ element }: { element: JSX.Element }) { - const { isUnlocked } = getController().wallet; - console.log('isUnlocked', isUnlocked()); - if (!isUnlocked()) { + const { isUnlocked, isLoading } = useController(); + + if (isLoading) { + return ; + } + + if (!isUnlocked) { return ; } diff --git a/source/routers/index.tsx b/source/routers/index.tsx index 9d92be0cb..aa98af031 100644 --- a/source/routers/index.tsx +++ b/source/routers/index.tsx @@ -40,6 +40,7 @@ import { } from '../pages'; import { WarningModal } from 'components/Modal'; import { useUtils } from 'hooks/index'; +import { useController } from 'hooks/useController'; import { ChainErrorPage } from 'pages/Chain'; import { Faucet } from 'pages/Faucet'; import { SwitchNetwork } from 'pages/SwitchNetwork'; @@ -50,9 +51,7 @@ import { resetPaliRequestsCount, verifyPaliRequests, } from 'scripts/Background'; -// import MasterController from 'scripts/Background/controllers'; import { RootState } from 'state/store'; -// import { getController } from 'utils/browser'; import { ProtectedRoute } from './ProtectedRoute'; @@ -69,7 +68,7 @@ export const Router = () => { const accounts = useSelector((state: RootState) => state.vault.accounts); const { serverHasAnError, errorMessage }: CustomJsonRpcProvider = wallet.ethereumTransaction.web3Provider; - const isUnlocked = wallet.isUnlocked(); + const { isUnlocked } = useController(); const utf8ErrorData = JSON.parse( window.localStorage.getItem('sysweb3-utf8Error') ?? JSON.stringify({ hasUtf8Error: false }) diff --git a/source/scripts/Background/controllers/controllerEmitter.ts b/source/scripts/Background/controllers/controllerEmitter.ts new file mode 100644 index 000000000..020e5dc04 --- /dev/null +++ b/source/scripts/Background/controllers/controllerEmitter.ts @@ -0,0 +1,59 @@ +import { migrateWalletState } from 'state/migrateWalletState'; + +import { IMasterController } from '.'; + +type Methods = { + [K in keyof T]: T[K] extends (...args: any[]) => any + ? [K] + : T[K] extends object + ? [K, ...Methods] + : never; +}[keyof T]; + +type Controller = IMasterController & { + migrateWalletState: typeof migrateWalletState; +}; + +export default function controllerEmitter< + T extends IMasterController, + P extends Methods +>(methods: P, params?: any[], importMethod = false) { + return new Promise((resolve, reject) => { + chrome.runtime.sendMessage( + { + type: `controller_action`, + data: { + methods, + params: params || [], + importMethod, + }, + }, + (response) => { + if (chrome.runtime.lastError) { + return reject(chrome.runtime.lastError); + } + resolve(response); + } + ); + }); +} + +export function controllerState( + action: string, + state: T +) { + chrome.runtime.sendMessage( + { + type: `controller_state`, + data: { + action, + state, + }, + }, + (response) => { + if (chrome.runtime.lastError) { + console.log(chrome.runtime.lastError); + } + } + ); +} diff --git a/source/scripts/Background/controllers/index.ts b/source/scripts/Background/controllers/index.ts index dc74e5aca..812085615 100755 --- a/source/scripts/Background/controllers/index.ts +++ b/source/scripts/Background/controllers/index.ts @@ -52,6 +52,7 @@ export interface IMasterController { utils: Readonly; wallet: MainController; } + export const vaultToWalletState = (vaultState: IVaultState) => { const accounts: { [key in KeyringAccountType]: accountType } = Object.entries( vaultState.accounts diff --git a/source/scripts/Background/index.ts b/source/scripts/Background/index.ts index b203c602d..44461db17 100755 --- a/source/scripts/Background/index.ts +++ b/source/scripts/Background/index.ts @@ -9,16 +9,11 @@ import { rehydrate as priceRehydrate } from 'state/price'; import store from 'state/store'; import { rehydrate as vaultRehydrate, setIsPolling } from 'state/vault'; import { TransactionsType } from 'state/vault/types'; -// import { i18next } from 'utils/i18n'; -import { parseJsonRecursively } from 'utils/format'; import { log } from 'utils/logger'; import { PaliLanguages } from 'utils/types'; import MasterController, { IMasterController } from './controllers'; -import { - handleRehydrateStore, - handleStoreSubscribe, -} from './controllers/handlers'; +import { handleRehydrateStore } from './controllers/handlers'; import { IEvmTransactionResponse } from './controllers/transactions/types'; /* eslint-disable @typescript-eslint/ban-ts-comment */ @@ -33,7 +28,6 @@ let paliPopupPort: chrome.runtime.Port; let dappMethods = {} as any; let walletMethods = {} as any; -// rehydrateStore(store).then(() => {}); let MasterControllerInstance = {} as IMasterController; (async () => { const storageState = await loadState(); @@ -162,7 +156,41 @@ const updateRequestsPerSecond = () => { // Interval to perform the information update and display the requests per second every second. setInterval(updateRequestsPerSecond, 1000); -chrome.runtime.onMessage.addListener(async ({ type, target, data }) => { +chrome.runtime.onMessage.addListener((message: any, _, sendResponse) => { + const { type, data } = message; + + const isValidEvent = ['controller_action', 'controller_state'].includes(type); + + if (type === 'controller_action') { + const { methods, params, importMethod } = data; + + let targetMethod = MasterControllerInstance; + + for (const method of methods) { + if (targetMethod && method in targetMethod) { + targetMethod = targetMethod[method]; + } else { + throw new Error('Method not found'); + } + } + + if (typeof targetMethod === 'function' || importMethod) { + new Promise(async (resolve) => { + const response = importMethod + ? targetMethod + : await (targetMethod as any)(...params); + + resolve(response); + }).then(sendResponse); + } else { + throw new Error('Target is not a function'); + } + } + + return isValidEvent; +}); + +chrome.runtime.onMessage.addListener(({ type, target, data }) => { switch (type) { case 'ping': if (target === 'background') diff --git a/source/state/migrateWalletState.ts b/source/state/migrateWalletState.ts index 9b9b665d3..57abe5fbd 100644 --- a/source/state/migrateWalletState.ts +++ b/source/state/migrateWalletState.ts @@ -1,4 +1,3 @@ -import { getController } from 'scripts/Background'; import { parseJsonRecursively } from 'utils/format'; import { rehydrateStore } from './rehydrate'; @@ -6,18 +5,19 @@ import store from './store'; export async function migrateWalletState( oldStateName: string, - newStateName: string + newStateName: string, + hasAccount: boolean ) { try { - const { wallet } = getController(); const vault = JSON.parse(localStorage.getItem('sysweb3-vault')); const vaultKeys = JSON.parse(localStorage.getItem('sysweb3-vault-keys')); - const hasAccount = !!wallet.getActiveAccount().activeAccount.address; if (vault && vaultKeys && !hasAccount) { const oldState = await chrome.storage.local.get(oldStateName); const newState = parseJsonRecursively(oldState[oldStateName] || '{}'); + console.log(oldState, 'oldState'); + await chrome.storage.local.set({ 'sysweb3-vault': vault, 'sysweb3-vault-keys': vaultKeys, From ab3d727c7176a119c7e4b8eae0c18184e3d28e2f Mon Sep 17 00:00:00 2001 From: Ricardo Vieira Date: Wed, 21 Aug 2024 11:52:03 -0300 Subject: [PATCH 10/17] chore: change getController to controllerEmitter --- source/components/Header/AccountHeader.tsx | 33 +++- source/components/Header/Header.tsx | 29 +++- .../components/Header/Menus/GeneralMenu.tsx | 30 ++-- .../components/Header/Menus/NetworkMenu.tsx | 11 +- .../Header/SetActiveAccountModal.tsx | 16 +- .../hooks/useWalletProviderDefault.tsx | 36 ++-- .../TransactionOptions/TransactionOptions.tsx | 3 - source/hooks/useController.ts | 73 ++++++-- source/pages/Chain/ChainErrorPage.tsx | 19 ++- source/pages/Connections/ChangeAccount.tsx | 34 +++- .../Connections/ChangeConnectedAccount.tsx | 19 ++- source/pages/Connections/ConnectWallet.tsx | 54 +++--- source/pages/Home/Home.tsx | 27 +-- .../Home/Panel/components/Assets/EvmList.tsx | 17 +- .../Panel/components/Nfts/EvmNftsList.tsx | 12 +- .../Transactions/EVM/EvmDetails.tsx | 6 +- .../components/Transactions/EVM/EvmList.tsx | 20 +-- .../Panel/components/Transactions/List.tsx | 3 - .../Transactions/UTXO/SyscoinDetails.tsx | 32 ++-- .../utils/useTransactionsInfos.tsx | 38 +++-- source/pages/Import/CreatePass.tsx | 7 +- source/pages/Import/ImportPhrase.tsx | 45 +++-- source/pages/SeedConfirm/CreatePhrase.tsx | 15 +- source/pages/SeedConfirm/index.tsx | 9 +- source/pages/Send/Approve.tsx | 22 ++- source/pages/Send/Confirm.tsx | 83 ++++----- source/pages/Send/SendEth.tsx | 1 + source/pages/Send/SendNTokenTransaction.tsx | 161 +++++++++++------- source/pages/Send/SendSys.tsx | 24 +-- source/pages/Send/SendTransaction.tsx | 72 ++++---- source/pages/Settings/Advanced.tsx | 11 +- source/pages/Settings/AutoLock.tsx | 8 +- .../pages/Settings/ConnectHardwareWallet.tsx | 54 +++--- source/pages/Settings/ConnectedSites.tsx | 18 +- source/pages/Settings/CreateAccount.tsx | 13 +- source/pages/Settings/Currency.tsx | 12 +- source/pages/Settings/CustomRPC.tsx | 17 +- source/pages/Settings/EditAccount.tsx | 9 +- source/pages/Settings/ExternalAddRPC.tsx | 24 +-- source/pages/Settings/ExternalWatchAsset.tsx | 20 ++- source/pages/Settings/ForgetWallet.tsx | 46 ++--- source/pages/Settings/ImportAccount.tsx | 11 +- source/pages/Settings/ManageNetwork.tsx | 12 +- source/pages/Settings/Phrase.tsx | 23 ++- source/pages/Settings/PrivateKey.tsx | 28 +-- source/pages/Settings/RemoveEth.tsx | 36 ++-- source/pages/Settings/SwitchEthereumChain.tsx | 9 +- .../pages/Settings/SwitchNetworkUtxoEvm.tsx | 9 +- source/pages/Start/Start.tsx | 25 +-- source/pages/SwitchNetwork/NetworkList.tsx | 9 +- source/pages/Tokens/AddToken.tsx | 8 +- source/pages/Tokens/CustomToken.tsx | 32 ++-- source/pages/Tokens/ImportToken.tsx | 19 ++- source/pages/Tokens/SyscoinImport.tsx | 18 +- source/pages/Transactions/Decrypt.tsx | 18 +- source/pages/Transactions/EncryptPubKey.tsx | 18 +- source/pages/Transactions/Fee.tsx | 11 +- source/pages/Transactions/Sign.tsx | 14 +- source/pages/Transactions/SignEth.tsx | 51 +++--- source/pages/Transactions/Transaction.tsx | 21 ++- .../Transactions/TransactionConfirmation.tsx | 21 ++- source/routers/ExternalRoute.tsx | 4 +- source/routers/index.tsx | 49 ++++-- .../Background/controllers/DAppController.ts | 1 + .../Background/controllers/MainController.ts | 111 ++++++------ .../controllers/controllerEmitter.ts | 30 +--- .../Background/controllers/handlers.ts | 9 +- .../scripts/Background/controllers/index.ts | 6 +- .../message-handler/popup-promise.ts | 26 ++- .../controllers/message-handler/requests.ts | 2 +- source/scripts/Background/index.ts | 53 ++++-- source/state/migrateWalletState.ts | 15 +- source/state/rehydrate.ts | 4 +- source/state/store.ts | 1 + source/utils/fetchGasAndDecodeFunction.ts | 58 ++++--- source/utils/removeScientificNotation.ts | 2 +- source/utils/transactions.ts | 127 ++++++++------ source/utils/types.ts | 2 - 78 files changed, 1235 insertions(+), 841 deletions(-) diff --git a/source/components/Header/AccountHeader.tsx b/source/components/Header/AccountHeader.tsx index 05c9a2a9a..165a8db47 100644 --- a/source/components/Header/AccountHeader.tsx +++ b/source/components/Header/AccountHeader.tsx @@ -21,7 +21,7 @@ import { DefaultModal, } from 'components/index'; import { useUtils } from 'hooks/index'; -import { getController } from 'scripts/Background'; +import { useController } from 'hooks/useController'; import { RootState } from 'state/store'; import { ellipsis } from 'utils/index'; @@ -288,7 +288,7 @@ const RenderAccountsListByBitcoinBased = ( export const AccountMenu: React.FC = () => { const { navigate } = useUtils(); - const { wallet, dapp } = getController(); + const { controllerEmitter } = useController(); const isBitcoinBased = useSelector( (state: RootState) => state.vault.isBitcoinBased ); @@ -301,11 +301,18 @@ export const AccountMenu: React.FC = () => { currentWindow: true, }); const host = new URL(tabs[0].url).hostname; - const connectedAccount = dapp.getAccount(host); - wallet.setAccount(Number(id), type, host, connectedAccount); + + controllerEmitter(['dapp', 'getAccount'], [host]).then(async (res) => { + controllerEmitter( + ['wallet', 'setAccount'], + [Number(id), type, host, res] + ); + }); + return; } - wallet.setAccount(Number(id), type); + + controllerEmitter(['wallet', 'setAccount'], [Number(id), type]); }; const cursorType = isBitcoinBased ? 'cursor-not-allowed' : 'cursor-pointer'; @@ -409,7 +416,7 @@ export const AccountHeader: React.FC = () => { const [isLoading, setIsLoading] = useState(false); const [isOpenModal, setIsOpenModal] = useState(false); const [isReconectModalOpen, setIsReconectModalOpen] = useState(false); - const controller = getController(); + const { controllerEmitter } = useController(); const isLedger = activeAccount.type === KeyringAccountType.Ledger; const url = chrome.runtime.getURL('app.html'); @@ -443,25 +450,35 @@ export const AccountHeader: React.FC = () => { const handleVerifyAddress = async () => { try { setIsLoading(true); - await controller.wallet.ledgerSigner.utxo.verifyUtxoAddress( - activeAccount.id + + await controllerEmitter( + ['wallet', 'ledgerSigner', 'utxo', 'verifyUtxoAddress'], + [activeAccount.id] ); + setIsLoading(false); + setIsOpenModal(false); + alert.success(t('home.addressVerified')); } catch (error) { const isNecessaryReconnect = error.message.includes( 'read properties of undefined' ); + if (isNecessaryReconnect) { setIsReconectModalOpen(true); return; } + const wasDeniedByUser = error?.message?.includes('denied by the user'); + if (wasDeniedByUser) { alert.error(t('home.verificationDeniedByUser')); } + setIsOpenModal(false); + setIsLoading(false); } }; diff --git a/source/components/Header/Header.tsx b/source/components/Header/Header.tsx index aed331794..77613943b 100755 --- a/source/components/Header/Header.tsx +++ b/source/components/Header/Header.tsx @@ -6,7 +6,8 @@ import { useSelector } from 'react-redux'; import { INetwork } from '@pollum-io/sysweb3-network'; import { ErrorModal, Icon, Modal, PrimaryButton, SecondaryButton } from '..'; -import { getController } from 'scripts/Background'; +import { useController } from 'hooks/useController'; +import dapp from 'state/dapp'; import { RootState } from 'state/store'; import { AccountHeader } from '.'; @@ -18,7 +19,7 @@ interface IHeader { } export const Header: React.FC = ({ accountHeader = false }) => { - const { wallet, dapp } = getController(); + const { controllerEmitter } = useController(); const { t } = useTranslation(); const error = useSelector((state: RootState) => state.vault.error); @@ -54,18 +55,26 @@ export const Header: React.FC = ({ accountHeader = false }) => { title: t('header.errorSwitching'), }); - wallet.resolveError(); + controllerEmitter(['wallet', 'resolveError']); } }, [error]); const hanldeDisconnectFromDapp = () => { - dapp.disconnect(host); - wallet.resolveAccountConflict(); + controllerEmitter(['dapp', 'disconnect'], [host]); + controllerEmitter(['wallet', 'resolveAccountConflict']); }; const handleChangeConnectedAccount = () => { - dapp.changeAccount(host, newConnectedAccount.id, connectedAccountType); - wallet.setAccount(newConnectedAccount.id, connectedAccountType); - wallet.resolveAccountConflict(); + controllerEmitter( + ['dapp', 'changeAccount'], + [host, newConnectedAccount.id, connectedAccountType] + ); + + controllerEmitter( + ['wallet', 'setAccount'], + [newConnectedAccount.id, connectedAccountType] + ); + + controllerEmitter(['wallet', 'resolveAccountConflict']); }; return ( @@ -100,7 +109,9 @@ export const Header: React.FC = ({ accountHeader = false }) => { wallet.resolveAccountConflict()} + onClose={() => + controllerEmitter(['wallet', 'resolveAccountConflict']) + } >
{ - const { wallet, dapp, refresh } = getController(); - + const { controllerEmitter } = useController(); + const { t } = useTranslation(); + const { navigate } = useUtils(); const { changingConnectedAccount: { isChangingConnectedAccount }, advancedSettings, } = useSelector((state: RootState) => state.vault); - const { t } = useTranslation(); - const { navigate } = useUtils(); - const [currentTab, setCurrentTab] = useState({ host: '', isConnected: false, @@ -28,7 +26,7 @@ export const GeneralMenu: React.FC = () => { const className = currentTab.isConnected ? 'success' : 'error'; const handleLogout = () => { - wallet.lock(); + controllerEmitter(['wallet', 'lock']); navigate('/'); }; @@ -37,9 +35,14 @@ export const GeneralMenu: React.FC = () => { const getTabData = async () => { const url = await getTabUrl(); const host = getHost(url); - const isConnected = dapp.isConnected(host); - setCurrentTab({ host, isConnected }); + + controllerEmitter(['dapp', 'isConnected'], [host]).then( + (isConnected: boolean) => { + setCurrentTab({ host, isConnected }); + } + ); }; + getTabData(); }, []); @@ -47,9 +50,12 @@ export const GeneralMenu: React.FC = () => { if (!isChangingConnectedAccount) { getTabUrl().then(async (url: string) => { const host = getHost(url); - const isConnected = dapp.isConnected(host); - setCurrentTab({ host, isConnected }); + controllerEmitter(['dapp', 'isConnected'], [host]).then( + (isConnected: boolean) => { + setCurrentTab({ host, isConnected }); + } + ); }); } }, [isChangingConnectedAccount]); @@ -77,7 +83,7 @@ export const GeneralMenu: React.FC = () => { {advancedSettings['refresh'] && (
refresh()} + onClick={() => controllerEmitter(['refresh'], [])} className="mx-1.5 hover:text-brand-royalblue text-brand-white cursor-pointer" > diff --git a/source/components/Header/Menus/NetworkMenu.tsx b/source/components/Header/Menus/NetworkMenu.tsx index 335e45b77..e92094132 100644 --- a/source/components/Header/Menus/NetworkMenu.tsx +++ b/source/components/Header/Menus/NetworkMenu.tsx @@ -12,10 +12,8 @@ import btcIcon from 'assets/images/btcIcon.svg'; import ethIcon from 'assets/images/ethIcon.svg'; import { Icon } from 'components/index'; import { useUtils } from 'hooks/index'; -import { - dispatchChangeNetworkBgEvent, - getController, -} from 'scripts/Background'; +import { useController } from 'hooks/useController'; +import { dispatchChangeNetworkBgEvent } from 'scripts/Background'; import { FaucetChainIds } from 'scripts/Background/controllers/message-handler/types'; import { RootState } from 'state/store'; import { NetworkType } from 'utils/types'; @@ -37,7 +35,7 @@ export const NetworkMenu: React.FC = ( props: INetworkComponent ) => { const { setActiveAccountModalIsOpen, setSelectedNetwork } = props; - const { wallet } = getController(); + const { controllerEmitter } = useController(); const { t, i18n } = useTranslation(); const { language } = i18n; const { dapps } = useSelector((state: RootState) => state.dapp); @@ -97,7 +95,8 @@ export const NetworkMenu: React.FC = ( setActiveAccountModalIsOpen(true); return; } - await wallet.setActiveNetwork(network, chain); + await controllerEmitter(['wallet', 'setActiveNetwork'], [network, chain]); + dispatchChangeNetworkBgEvent(network, !!network?.slip44); } catch (networkError) { navigate('/home'); diff --git a/source/components/Header/SetActiveAccountModal.tsx b/source/components/Header/SetActiveAccountModal.tsx index 6b6bd46e3..d51417758 100644 --- a/source/components/Header/SetActiveAccountModal.tsx +++ b/source/components/Header/SetActiveAccountModal.tsx @@ -6,8 +6,8 @@ import { KeyringAccountType } from '@pollum-io/sysweb3-keyring'; import { INetwork } from '@pollum-io/sysweb3-network'; import { Icon, Modal, PrimaryButton, SecondaryButton } from 'components/index'; +import { useController } from 'hooks/useController'; import { useUtils } from 'hooks/useUtils'; -import { getController } from 'scripts/Background'; import { RootState } from 'state/store'; interface ISetActiveAccountModalProps { @@ -17,12 +17,13 @@ interface ISetActiveAccountModalProps { } export const SetActiveAccountModal = (props: ISetActiveAccountModalProps) => { + const { controllerEmitter } = useController(); const { showModal, setIsOpen, selectedNetwork } = props; const { accounts, isBitcoinBased, activeAccount } = useSelector( (state: RootState) => state.vault ); const { t } = useTranslation(); - const { wallet } = getController(); + const { alert } = useUtils(); const [accountId, setAccountId] = useState(activeAccount.id); @@ -41,11 +42,14 @@ export const SetActiveAccountModal = (props: ISetActiveAccountModalProps) => { alert.error(t('header.pleaseSelect')); return; } - wallet.setAccount(accountId, accountType); - await wallet.setActiveNetwork( - selectedNetwork.network, - selectedNetwork.chain + + controllerEmitter(['wallet', 'setAccount'], [accountId, accountType]); + + controllerEmitter( + ['wallet', 'setActiveAccount'], + [selectedNetwork.network, selectedNetwork.chain] ); + setIsOpen(false); }; diff --git a/source/components/Modal/WalletProviderDafault/hooks/useWalletProviderDefault.tsx b/source/components/Modal/WalletProviderDafault/hooks/useWalletProviderDefault.tsx index c110769e6..5e5a24916 100644 --- a/source/components/Modal/WalletProviderDafault/hooks/useWalletProviderDefault.tsx +++ b/source/components/Modal/WalletProviderDafault/hooks/useWalletProviderDefault.tsx @@ -6,17 +6,16 @@ import { getContainerStyleAnimation, getIconStyleAnimation, } from '../utils/getModalStyleAnimation'; +import { useController } from 'hooks/useController'; import { RootState } from 'state/store'; -import { getController } from 'utils/browser'; export const useWalletProviderDefault = () => { + const { controllerEmitter } = useController(); const { hasEthProperty } = useSelector((state: RootState) => state.vault); const [isHovered, setIsHovered] = useState(false); const [isEnabled, setIsEnabled] = useState(hasEthProperty); const [isNotVisible, setIsNotVisible] = useState(!!isEnabled); - const controller = getController(); - const containerStyleAnimation = getContainerStyleAnimation( isHovered, isNotVisible @@ -27,19 +26,28 @@ export const useWalletProviderDefault = () => { const turnPaliAsDefault = () => { setIsEnabled(!isEnabled); if (isEnabled) { - controller.wallet.removeWindowEthProperty(); - controller.wallet.setHasEthProperty(false); - const dapps = Object.values(controller.dapp.getAll()); - // disconnect from all dapps when remove window.ethereum property - if (dapps.length) { - for (const dapp of dapps) { - if (controller.dapp.isConnected(dapp.host)) - controller.dapp.disconnect(dapp.host); + controllerEmitter(['wallet', 'removeWindowEthProperty']); + + controllerEmitter(['wallet', 'setHasEthProperty'], [false]); + + controllerEmitter(['dapp', 'getAll']).then(async (response) => { + const dapps = Object.values(response); + + if (dapps.length) { + for (const dapp of dapps) { + await controllerEmitter(['dapp', 'isConnected'], [dapp.host]).then( + async (isConnected: boolean) => { + if (isConnected) { + await controllerEmitter(['dapp', 'disconnect'], [dapp.host]); + } + } + ); + } } - } + }); } else { - controller.wallet.addWindowEthProperty(); - controller.wallet.setHasEthProperty(true); + controllerEmitter(['wallet', 'addWindowEthProperty']); + controllerEmitter(['wallet', 'setHasEthProperty'], [true]); } }; diff --git a/source/components/TransactionOptions/TransactionOptions.tsx b/source/components/TransactionOptions/TransactionOptions.tsx index 736f3f903..e773ce8a3 100644 --- a/source/components/TransactionOptions/TransactionOptions.tsx +++ b/source/components/TransactionOptions/TransactionOptions.tsx @@ -13,7 +13,6 @@ export const TransactionOptions: React.FC = ({ transaction, alert, chainId, - wallet, setIsOpenModal, setModalData, }) => { @@ -41,7 +40,6 @@ export const TransactionOptions: React.FC = ({ isLegacy: isLegacyTransaction, txHash: transaction.hash, updateType: UpdateTxAction.Cancel, - wallet, }, }); setIsOpenModal(false); @@ -62,7 +60,6 @@ export const TransactionOptions: React.FC = ({ isLegacy: isLegacyTransaction, txHash: transaction.hash, updateType: UpdateTxAction.SpeedUp, - wallet, }, }); setIsOpenModal(false); diff --git a/source/hooks/useController.ts b/source/hooks/useController.ts index 85905e920..65c6ff17f 100644 --- a/source/hooks/useController.ts +++ b/source/hooks/useController.ts @@ -1,31 +1,82 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; -import controllerEmitter from 'scripts/Background/controllers/controllerEmitter'; +import { CustomJsonRpcProvider } from '@pollum-io/sysweb3-keyring'; +import { INetwork } from '@pollum-io/sysweb3-network'; + +import { controllerEmitter } from 'scripts/Background/controllers/controllerEmitter'; +// import { rehydrateStore } from 'state/rehydrate'; +// import store from 'state/store'; export function useController() { const [isUnlocked, setIsUnlocked] = useState(false); const [isLoading, setIsLoading] = useState(true); + const [activeNetwork, setActiveNetwork] = useState(null); + const [web3Provider, setWeb3Provider] = useState({ + serverHasAnError: false, + errorMessage: '', + } as CustomJsonRpcProvider); + + const abortController = new AbortController(); + + const fetchControllerData = useCallback( + async (shouldSetIsLoading = true) => { + if (shouldSetIsLoading) setIsLoading(true); + + const network = (await controllerEmitter([ + 'wallet', + 'getNetwork', + ])) as INetwork; + + const _web3Provider = new CustomJsonRpcProvider( + abortController.signal, + network.url + ); - const fetchIsUnlocked = useCallback(async () => { - // setIsLoading(true); + const _isUnlocked = await controllerEmitter(['wallet', 'isUnlocked'], []); - const response = await controllerEmitter(['wallet', 'isUnlocked'], []); + setActiveNetwork(network); - setIsUnlocked(!!response); + setWeb3Provider(_web3Provider); - setIsLoading(false); - }, [setIsUnlocked, setIsLoading, controllerEmitter]); + setIsUnlocked(!!_isUnlocked); + + setIsLoading(false); + }, + [setIsUnlocked, web3Provider, setIsLoading, controllerEmitter] + ); useEffect(() => { - fetchIsUnlocked(); + fetchControllerData(); return () => { - fetchIsUnlocked(); + fetchControllerData(); }; }, []); + // useEffect(() => { + // function handleStateChange(message: any) { + // if (message.type === 'CONTROLLER_STATE_CHANGE') { + // rehydrateStore(store, message.data).then(() => { + // fetchControllerData(false); + // }); + // } + // } + + // chrome.runtime.onMessage.addListener(handleStateChange); + + // return () => { + // chrome.runtime.onMessage.removeListener(handleStateChange); + // }; + // }, []); + return useMemo( - () => ({ isUnlocked, isLoading, controllerEmitter }), - [isUnlocked, isLoading, controllerEmitter] + () => ({ + isUnlocked, + web3Provider, + activeNetwork, + isLoading, + controllerEmitter, + }), + [isUnlocked, web3Provider, activeNetwork, isLoading, controllerEmitter] ); } diff --git a/source/pages/Chain/ChainErrorPage.tsx b/source/pages/Chain/ChainErrorPage.tsx index c9dd496a6..128772510 100644 --- a/source/pages/Chain/ChainErrorPage.tsx +++ b/source/pages/Chain/ChainErrorPage.tsx @@ -8,19 +8,22 @@ import rolluxChainImg from 'assets/images/rolluxChain.png'; import sysChainImg from 'assets/images/sysChain.svg'; import { Button } from 'components/Button'; import { Header } from 'components/Header'; +import { useController } from 'hooks/useController'; import { useUtils } from 'hooks/useUtils'; -import { getController } from 'scripts/Background'; import { RootState } from 'state/store'; export const ChainErrorPage = () => { + const { controllerEmitter } = useController(); + const { navigate } = useUtils(); + const { t } = useTranslation(); const activeNetwork = useSelector( (state: RootState) => state.vault.activeNetwork ); - const { navigate } = useUtils(); - const { wallet } = getController(); - const { t } = useTranslation(); const handleRetryToConnect = async () => { - await wallet.setActiveNetwork(activeNetwork, String(activeNetwork.chainId)); + await controllerEmitter( + ['wallet', 'setActiveNetwork'], + [activeNetwork, String(activeNetwork.chainId)] + ); }; const CurrentChains = () => { @@ -112,7 +115,11 @@ export const ChainErrorPage = () => { type="submit" className="bg-transparent rounded-[100px] w-[10.25rem] h-[40px] text-white text-base font-medium border border-white" onClick={() => { - wallet.setIsPaliNetworkChanging(false); + controllerEmitter( + ['wallet', 'setIsPaliNetworkChanging'], + [false] + ); + navigate('/home'); }} > diff --git a/source/pages/Connections/ChangeAccount.tsx b/source/pages/Connections/ChangeAccount.tsx index 630510f48..4bd740740 100644 --- a/source/pages/Connections/ChangeAccount.tsx +++ b/source/pages/Connections/ChangeAccount.tsx @@ -6,21 +6,27 @@ import { KeyringAccountType } from '@pollum-io/sysweb3-keyring'; import { Layout, SecondaryButton, PrimaryButton, Icon } from 'components/index'; import { useQueryData } from 'hooks/index'; -import { getController } from 'scripts/Background'; +import { useController } from 'hooks/useController'; import { RootState } from 'state/store'; import { dispatchBackgroundEvent } from 'utils/browser'; import { ellipsis } from 'utils/index'; export const ChangeAccount = () => { + const { controllerEmitter } = useController(); const { accounts, isBitcoinBased } = useSelector( (state: RootState) => state.vault ); - const { dapp, wallet } = getController(); const { host, eventName } = useQueryData(); const { t } = useTranslation(); - const currentAccountId = dapp.get(host).accountId; - const currentAccountType = dapp.get(host).accountType; + let currentAccountId: number; + let currentAccountType: KeyringAccountType; + + controllerEmitter(['dapp', 'get'], [host]).then((res: any) => { + currentAccountId = res?.accountId; + currentAccountType = res?.accountType; + }); + const [accountId, setAccountId] = useState(currentAccountId); const [accountType, setCurrentAccountType] = useState(currentAccountType); @@ -38,12 +44,24 @@ export const ChangeAccount = () => { return; } //this should be passed to constant instead of being hardcoded - if (eventName === 'requestPermissions') - dapp.requestPermissions(host, accountId, accountType); - else dapp.changeAccount(host, accountId, accountType); - wallet.setAccount(accountId, accountType); + if (eventName === 'requestPermissions') { + controllerEmitter( + ['dapp', 'requestPermissions'], + [host, accountId, accountType] + ); + } else { + controllerEmitter( + ['dapp', 'changeAccount'], + [host, accountId, accountType] + ); + } + + controllerEmitter(['wallet', 'setAccount'], [accountId, accountType]); + const response = { accountId, accountType }; + dispatchBackgroundEvent(`${eventName}.${host}`, response); + window.close(); }; diff --git a/source/pages/Connections/ChangeConnectedAccount.tsx b/source/pages/Connections/ChangeConnectedAccount.tsx index 4e6d2f965..298c1640d 100644 --- a/source/pages/Connections/ChangeConnectedAccount.tsx +++ b/source/pages/Connections/ChangeConnectedAccount.tsx @@ -4,31 +4,40 @@ import { useSelector } from 'react-redux'; import { Layout, SecondaryButton, PrimaryButton } from 'components/index'; import { useQueryData } from 'hooks/index'; -import { getController } from 'scripts/Background'; +import { useController } from 'hooks/useController'; import { RootState } from 'state/store'; import { dispatchBackgroundEvent } from 'utils/browser'; import { ellipsis } from 'utils/index'; export const ChangeConnectedAccount = () => { + const { controllerEmitter } = useController(); const { t } = useTranslation(); const activeAccount = useSelector( (state: RootState) => state.vault.activeAccount ); const { accounts } = useSelector((state: RootState) => state.vault); - const { dapp, wallet } = getController(); //TODO: validate this const { host, eventName, connectedAccount, accountType } = useQueryData(); const handleConnectedAccount = () => { - wallet.setAccount(connectedAccount.id, accountType); + controllerEmitter( + ['wallet', 'setAccount'], + [connectedAccount.id, accountType] + ); + dispatchBackgroundEvent(`${eventName}.${host}`, true); + window.close(); }; const handleActiveAccount = () => { - dapp.changeAccount(host, activeAccount.id, activeAccount.type); + controllerEmitter( + ['dapp', 'changeAccount'], + [host, activeAccount.id, activeAccount.type] + ); //this should be passed to constant instead of being hardcoded dispatchBackgroundEvent(`${eventName}.${host}`, false); + window.close(); }; @@ -46,7 +55,7 @@ export const ChangeConnectedAccount = () => { {host}{' '} {t('header.hostIsConnected')} {connectedAccount.label} ( {ellipsis(connectedAccount.address)}). - {t('header.yourAcctiveAccountIs')}{' '} + {t('header.yourAcctiveAccountIs')} {accounts[activeAccount.type][activeAccount.id].label} ( {ellipsis(accounts[activeAccount.type][activeAccount.id].address)}). {t('connections.withWitchAccount')} diff --git a/source/pages/Connections/ConnectWallet.tsx b/source/pages/Connections/ConnectWallet.tsx index 2340b5be8..f97dcb131 100644 --- a/source/pages/Connections/ConnectWallet.tsx +++ b/source/pages/Connections/ConnectWallet.tsx @@ -14,13 +14,13 @@ import { } from 'components/index'; import trustedApps from 'constants/trustedApps.json'; import { useQueryData } from 'hooks/index'; -import { getController } from 'scripts/Background'; +import { useController } from 'hooks/useController'; import { RootState } from 'state/store'; import { dispatchBackgroundEvent } from 'utils/browser'; import { ellipsis } from 'utils/index'; export const ConnectWallet = () => { - const { dapp, wallet } = getController(); + const { controllerEmitter, isUnlocked } = useController(); const { host, chain, chainId, eventName } = useQueryData(); const { t } = useTranslation(); const accounts = useSelector((state: RootState) => state.vault.accounts); @@ -33,23 +33,29 @@ export const ConnectWallet = () => { (state: RootState) => state.vault.isBitcoinBased ); - const currentAccountId = dapp.get(host)?.accountId; - const currentAccountType = dapp.get(host)?.accountType; + let currentAccountId: number; + let currentAccountType: KeyringAccountType; + + controllerEmitter(['dapp', 'get'], [host]).then((res: any) => { + currentAccountId = res?.accountId; + currentAccountType = res?.accountType; + }); const [accountId, setAccountId] = useState(currentAccountId); const [accountType, setAccountType] = useState(currentAccountType); const [confirmUntrusted, setConfirmUntrusted] = useState(false); const date = Date.now(); - const isUnlocked = wallet.isUnlocked(); const handleConnect = () => { - dapp.connect({ host, chain, chainId, accountId, accountType, date }); - wallet.setAccount(accountId, accountType); - dispatchBackgroundEvent( - `${eventName}.${host}`, - // dapp.getAccount(host).address - activeAccount.address + controllerEmitter( + ['dapp', 'connect'], + [host, chain, chainId, accountId, accountType, date] ); + + controllerEmitter(['wallet', 'setAccount'], [accountId, accountType]); + + dispatchBackgroundEvent(`${eventName}.${host}`, activeAccount.address); + window.close(); }; @@ -60,16 +66,24 @@ export const ConnectWallet = () => { }; useEffect(() => { - if (dapp.isConnected(host) && isUnlocked) { - dapp.connect( - { host, chain, chainId, accountId, accountType, date: 0 }, - true - ); - dispatchBackgroundEvent( - `${eventName}.${host}`, - dapp.getAccount(host).address + if (isUnlocked) { + controllerEmitter(['dapp', 'isConnected'], [host]).then( + (isConnected: boolean) => { + if (isConnected) { + controllerEmitter( + ['dapp', 'connect'], + [host, chain, chainId, accountId, accountType, date] + ); + + dispatchBackgroundEvent( + `${eventName}.${host}`, + activeAccount.address + ); + + window.close(); + } + } ); - window.close(); } }, [isUnlocked]); diff --git a/source/pages/Home/Home.tsx b/source/pages/Home/Home.tsx index 5c0bcaa49..000c930f5 100755 --- a/source/pages/Home/Home.tsx +++ b/source/pages/Home/Home.tsx @@ -13,7 +13,6 @@ import { WalletProviderDefaultModal } from 'components/Modal/WalletProviderDafau import { ConnectHardwareWallet } from 'components/Modal/WarningBaseModal'; import { usePrice, useUtils } from 'hooks/index'; import { useController } from 'hooks/useController'; -import { getController } from 'scripts/Background'; import { FaucetChainIds } from 'scripts/Background/controllers/message-handler/types'; import { RootState } from 'state/store'; import { setFaucetModalState } from 'state/vault'; @@ -33,7 +32,7 @@ export const Home = () => { const { navigate } = useUtils(); const { t } = useTranslation(); const { state } = useLocation(); - const { isUnlocked } = useController(); + const { controllerEmitter, isUnlocked } = useController(); //* Selectors const { asset: fiatAsset, price: fiatPrice } = useSelector( @@ -58,15 +57,16 @@ export const Home = () => { //* Constants const { url } = activeNetwork; - const controller = getController(); - const { wallet } = controller; - const { isInCooldown }: CustomJsonRpcProvider = - controller.wallet.ethereumTransaction.web3Provider; + let isInCooldown: boolean; - // const isUnlocked = - // controller.wallet.isUnlocked() && - // accounts[activeAccount.type][activeAccount.id].address !== ''; + controllerEmitter( + ['wallet', 'ethereumTransaction', 'web3Provider'], + [], + true + ).then((response: CustomJsonRpcProvider) => { + isInCooldown = response?.isInCooldown || false; + }); const bgColor = isNetworkChanging ? 'bg-bkg-2' : 'bg-bkg-3'; const { syscoin: syscoinBalance, ethereum: ethereumBalance } = @@ -74,7 +74,7 @@ export const Home = () => { const actualBalance = useMemo( () => (isBitcoinBased ? syscoinBalance : ethereumBalance), - [syscoinBalance, ethereumBalance] + [accounts[activeAccount.type][activeAccount.id]] ); const moreThanMillion = useMemo( @@ -141,7 +141,10 @@ export const Home = () => { }, [fiatPriceValue, isTestnet, moreThanMillion]); const handleOnCloseFaucetModal = useCallback(() => { - wallet.setFaucetModalState(activeNetwork.chainId); + controllerEmitter( + ['wallet', 'setFaucetModalState'], + [activeNetwork.chainId] + ); }, [activeNetwork, setFaucetModalState]); const shouldShowFaucetFirstModal = useMemo( @@ -192,7 +195,7 @@ export const Home = () => { id="home-balance" className={`font-rubik text-5xl font-medium`} > - {formattedBalance}{' '} + {formattedBalance}

{ - const controller = getController(); const { navigate } = useUtils(); - + const { controllerEmitter } = useController(); const { t } = useTranslation(); + const { accounts, activeAccount, @@ -150,11 +150,12 @@ const DefaultEvmAssets = ({ searchValue, sortByValue }: IDefaultEvmAssets) => { className="cursor-pointer hover:text-fields-input-borderfocus" color="text-brand-white" size={16} - onClick={() => - controller.wallet.account.eth.deleteTokenInfo( - token.contractAddress - ) - } + onClick={() => { + controllerEmitter( + ['wallet', 'account', 'eth', 'deleteTokenInfo'], + [token.contractAddress] + ); + }} />

diff --git a/source/pages/Home/Panel/components/Nfts/EvmNftsList.tsx b/source/pages/Home/Panel/components/Nfts/EvmNftsList.tsx index a3c75eeb8..8a0213374 100644 --- a/source/pages/Home/Panel/components/Nfts/EvmNftsList.tsx +++ b/source/pages/Home/Panel/components/Nfts/EvmNftsList.tsx @@ -5,14 +5,14 @@ import { INftsStructure } from '@pollum-io/sysweb3-utils'; import dafaultImage from 'assets/images/pali-blank.png'; import { useUtils } from 'hooks/index'; -import { getController } from 'scripts/Background'; +import { useController } from 'hooks/useController'; import { RootState } from 'state/store'; import { nftsVideoFormats } from 'utils/index'; import { getChainImage } from './GetChainImage'; export const EvmNftsList = () => { - const controller = getController(); + const { controllerEmitter } = useController(); const { navigate } = useUtils(); const { accounts, activeAccount, activeNetwork } = useSelector( (state: RootState) => state.vault @@ -26,10 +26,10 @@ export const EvmNftsList = () => { const getUserNfts = async () => { try { - await controller.wallet.fetchAndUpdateNftsState({ - activeAccount, - activeNetwork, - }); + await controllerEmitter( + ['wallet', 'fetchAndUpdateNftsState'], + [activeAccount, activeNetwork] + ); } catch (error) { console.error('Error on get NFTs:', error); } diff --git a/source/pages/Home/Panel/components/Transactions/EVM/EvmDetails.tsx b/source/pages/Home/Panel/components/Transactions/EVM/EvmDetails.tsx index c2ab13bfd..c1021488f 100644 --- a/source/pages/Home/Panel/components/Transactions/EVM/EvmDetails.tsx +++ b/source/pages/Home/Panel/components/Transactions/EVM/EvmDetails.tsx @@ -72,7 +72,9 @@ export const EvmTransactionDetails = ({ hash }: { hash: string }) => { chainId ] as IEvmTransaction[]; - ethereumTransactions?.find((tx: any) => { + ethereumTransactions?.forEach((transaction: any) => { + const tx = { ...transaction }; + tx.value = !!tx.value?.hex ? tx.value?.hex : tx.value; if (tx?.hash !== hash) return null; @@ -106,8 +108,6 @@ export const EvmTransactionDetails = ({ hash }: { hash: string }) => { if (isValid) formattedTransaction.push(formattedValue); } - - return formattedTransaction; }); const formattedTransactionDetails = formattedTransaction diff --git a/source/pages/Home/Panel/components/Transactions/EVM/EvmList.tsx b/source/pages/Home/Panel/components/Transactions/EVM/EvmList.tsx index 06bc0c4ac..fc9d6dfda 100644 --- a/source/pages/Home/Panel/components/Transactions/EVM/EvmList.tsx +++ b/source/pages/Home/Panel/components/Transactions/EVM/EvmList.tsx @@ -5,9 +5,9 @@ import { useTransactionsListConfig } from '../utils/useTransactionsInfos'; import { ConfirmationModal } from 'components/Modal'; import { StatusModal } from 'components/Modal/StatusModal'; import { TransactionOptions } from 'components/TransactionOptions'; +import { useController } from 'hooks/useController'; import { usePrice } from 'hooks/usePrice'; import { useUtils } from 'hooks/useUtils'; -import { getController } from 'scripts/Background'; import { IEvmTransaction } from 'scripts/Background/controllers/transactions/types'; import { RootState } from 'state/store'; import { ITransactionInfoEvm, modalDataType } from 'types/useTransactionsInfo'; @@ -42,7 +42,7 @@ export const EvmTransactionsList = ({ } = useTransactionsListConfig(userTransactions); const { navigate } = useUtils(); const { getFiatAmount } = usePrice(); - const { wallet } = getController(); + const { controllerEmitter } = useController(); const [modalData, setModalData] = useState(); const [isOpenModal, setIsOpenModal] = useState(false); @@ -64,7 +64,6 @@ export const EvmTransactionsList = ({ handleUpdateTransaction={handleUpdateTransaction} alert={alert} chainId={chainId} - wallet={wallet} transaction={tx as any} setIsOpenModal={setIsOpenModal} setModalData={setModalData} @@ -73,14 +72,7 @@ export const EvmTransactionsList = ({ } return null; }, - [ - handleUpdateTransaction, - alert, - chainId, - wallet, - setIsOpenModal, - setModalData, - ] + [handleUpdateTransaction, alert, chainId, setIsOpenModal, setModalData] ); const EvmTransactionsListComponent = useCallback(({ tx }) => { @@ -94,7 +86,7 @@ export const EvmTransactionsList = ({ ? typeof tx?.value === 'string' ? tx?.value : Number(tx?.value?.hex) / 1e18 - : Number(tx?.value) / 1e18; + : Number(tx?.value?.hex) / 1e18; const finalTxValue = isErc20Tx ? Number(getERC20TransferValue(tx as any)) / 1e18 : tokenValue; @@ -170,12 +162,12 @@ export const EvmTransactionsList = ({ return; } if (lastTx?.confirmations === 0) { - wallet.setIsLastTxConfirmed(chainId, false); + controllerEmitter(['wallet', 'setIsLastTxConfirmed'], [chainId, false]); return; } if (lastTx?.confirmations > 0 && !isLastTxConfirmed?.[chainId]) { setShowModal(true); - wallet.setIsLastTxConfirmed(chainId, true); + controllerEmitter(['wallet', 'setIsLastTxConfirmed'], [chainId, true]); } }, [currentAccount]); diff --git a/source/pages/Home/Panel/components/Transactions/List.tsx b/source/pages/Home/Panel/components/Transactions/List.tsx index 540f46f79..674830e56 100644 --- a/source/pages/Home/Panel/components/Transactions/List.tsx +++ b/source/pages/Home/Panel/components/Transactions/List.tsx @@ -8,7 +8,6 @@ import { IconButton } from 'components/IconButton'; import { ConfirmationModal } from 'components/Modal'; import { TransactionOptions } from 'components/TransactionOptions'; import { useUtils } from 'hooks/index'; -import { getController } from 'scripts/Background'; import { RootState } from 'state/store'; import { ellipsis, formatDate, handleUpdateTransaction } from 'utils/index'; @@ -17,7 +16,6 @@ export const TransactionsList = ({ }: { userTransactions: any[]; //todo: adjust type }) => { - const { wallet } = getController(); const { t } = useTranslation(); const { activeNetwork: { chainId }, @@ -127,7 +125,6 @@ export const TransactionsList = ({ handleUpdateTransaction={handleUpdateTransaction} alert={alert} chainId={chainId} - wallet={wallet} transaction={tx} setIsOpenModal={setIsOpenModal} setModalData={setModalData} diff --git a/source/pages/Home/Panel/components/Transactions/UTXO/SyscoinDetails.tsx b/source/pages/Home/Panel/components/Transactions/UTXO/SyscoinDetails.tsx index 76321bd50..27b4427b3 100644 --- a/source/pages/Home/Panel/components/Transactions/UTXO/SyscoinDetails.tsx +++ b/source/pages/Home/Panel/components/Transactions/UTXO/SyscoinDetails.tsx @@ -8,14 +8,14 @@ import { Icon } from 'components/Icon'; import { IconButton } from 'components/IconButton'; import { Tooltip } from 'components/Tooltip'; import { useTransactionsListConfig, useUtils } from 'hooks/index'; -import { getController } from 'scripts/Background'; +import { useController } from 'hooks/useController'; import { ISysTransaction } from 'scripts/Background/controllers/transactions/types'; import { RootState } from 'state/store'; import { TransactionsType } from 'state/vault/types'; import { camelCaseToText, ellipsis } from 'utils/index'; export const SyscoinTransactionDetails = ({ hash }: { hash: string }) => { - const controller = getController(); + const { controllerEmitter } = useController(); const { accounts, activeAccount, @@ -51,7 +51,10 @@ export const SyscoinTransactionDetails = ({ hash }: { hash: string }) => { const setTx = async () => setRawTransaction( - await controller.utils.getRawTransaction(activeNetworkUrl, hash) + await controllerEmitter( + ['utils', 'getRawTransaction'], + [activeNetworkUrl, hash] + ) ); useEffect(() => { @@ -84,18 +87,19 @@ export const SyscoinTransactionDetails = ({ hash }: { hash: string }) => { return; } } else { - controller.utils - .getRawTransaction(activeNetworkUrl, item.txid) - .then((response: any) => { - for (const responseVout of response.vout) { - if (responseVout.n === item.vout) { - senders[item.addresses[0]] = { - address: item.addresses[0], - value: item.value, - }; - } + controllerEmitter( + ['utils', 'getRawTransaction'], + [activeNetworkUrl, item.txid] + ).then((response: any) => { + for (const responseVout of response.vout) { + if (responseVout.n === item.vout) { + senders[item.addresses[0]] = { + address: item.addresses[0], + value: item.value, + }; } - }); + } + }); } } } diff --git a/source/pages/Home/Panel/components/Transactions/utils/useTransactionsInfos.tsx b/source/pages/Home/Panel/components/Transactions/utils/useTransactionsInfos.tsx index ab6827b82..328222305 100644 --- a/source/pages/Home/Panel/components/Transactions/utils/useTransactionsInfos.tsx +++ b/source/pages/Home/Panel/components/Transactions/utils/useTransactionsInfos.tsx @@ -189,16 +189,30 @@ export const useTransactionsListConfig = ( return ''; }; - return { - getTxStatus, - getTxStatusIcons, - formatTimeStamp, - formatTimeStampUtxo, - filteredTransactions, - isShowedGroupBar, - txId, - getTxType, - blocktime, - getTokenSymbol, - }; + return useMemo( + () => ({ + getTxStatus, + getTxStatusIcons, + formatTimeStamp, + formatTimeStampUtxo, + filteredTransactions, + isShowedGroupBar, + txId, + getTxType, + blocktime, + getTokenSymbol, + }), + [ + getTxStatus, + getTxStatusIcons, + formatTimeStamp, + formatTimeStampUtxo, + filteredTransactions, + isShowedGroupBar, + txId, + getTxType, + blocktime, + getTokenSymbol, + ] + ); }; diff --git a/source/pages/Import/CreatePass.tsx b/source/pages/Import/CreatePass.tsx index 53e17cae0..9f16574df 100755 --- a/source/pages/Import/CreatePass.tsx +++ b/source/pages/Import/CreatePass.tsx @@ -3,11 +3,10 @@ import { useLocation } from 'react-router-dom'; import { PasswordForm } from 'components/index'; import { useUtils } from 'hooks/index'; -import { getController } from 'scripts/Background'; -// import { getController } from 'utils/browser'; +import { useController } from 'hooks/useController'; export const CreatePasswordImport = () => { - const controller = getController(); + const { controllerEmitter } = useController(); const { state } = useLocation(); const { navigate } = useUtils(); @@ -19,7 +18,7 @@ export const CreatePasswordImport = () => { }); const onSubmit = async ({ password }: { password: string }) => { - await controller.wallet.createWallet(password, phrase); + await controllerEmitter(['wallet', 'createWallet'], [password, phrase]); next(); }; diff --git a/source/pages/Import/ImportPhrase.tsx b/source/pages/Import/ImportPhrase.tsx index 59ec75a65..bf8d78177 100755 --- a/source/pages/Import/ImportPhrase.tsx +++ b/source/pages/Import/ImportPhrase.tsx @@ -5,9 +5,8 @@ import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; import { OnboardingLayout, Button } from 'components/index'; -// import { getController } from 'utils/browser'; import { StatusModal } from 'components/Modal/StatusModal'; -import { getController } from 'scripts/Background'; +import { useController } from 'hooks/useController'; import { formatSeedPhrase } from 'utils/format'; type SeedValidationType = { @@ -19,7 +18,7 @@ const eyeStyle = 'w-[18px] max-w-none cursor-pointer hover:cursor-pointer z-20'; const ImportPhrase: React.FC = () => { const { TextArea } = Input; - const controller = getController(); + const { controllerEmitter } = useController(); const [form] = useForm(); const navigate = useNavigate(); const { t } = useTranslation(); @@ -42,11 +41,15 @@ const ImportPhrase: React.FC = () => { ); const onSubmit = ({ phrase }: { phrase: string }) => { - if (controller.wallet.isSeedValid(phrase)) { - navigate('/create-password-import', { - state: { phrase, isWalletImported: true }, - }); - } + controllerEmitter(['wallet', 'isSeedValid'], [phrase]).then( + (isSeedValid: boolean) => { + if (isSeedValid) { + navigate('/create-password-import', { + state: { phrase, isWalletImported: true }, + }); + } + } + ); }; const handleKeypress = (event) => { @@ -88,19 +91,27 @@ const ImportPhrase: React.FC = () => { form.setFieldsValue({ phrase: value }); //todo: we should validate the seed phrase with the new fn - setSeedIsValid(controller.wallet.isSeedValid(value) && value); - if (controller.wallet.isSeedValid(value)) { + return controllerEmitter( + ['wallet', 'isSeedValid'], + [value] + ).then((isSeedValid: boolean) => { + if (isSeedValid) { + setSeedIsValid(isSeedValid && value); + + setSeedValidation({ + seedLength: value.seedLength, + seedLengthError: false, + }); + + return Promise.resolve(); + } + setSeedValidation({ seedLength: value.seedLength, - seedLengthError: false, + seedLengthError: value.seedLengthError, }); - return Promise.resolve(); - } - setSeedValidation({ - seedLength: value.seedLength, - seedLengthError: value.seedLengthError, + return Promise.reject(); }); - return Promise.reject(); }, }), ]} diff --git a/source/pages/SeedConfirm/CreatePhrase.tsx b/source/pages/SeedConfirm/CreatePhrase.tsx index 8dced7598..fb22fc8fc 100644 --- a/source/pages/SeedConfirm/CreatePhrase.tsx +++ b/source/pages/SeedConfirm/CreatePhrase.tsx @@ -1,12 +1,13 @@ -import React, { useMemo, useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; import { OnboardingLayout, Button } from 'components/index'; -import { getController } from 'scripts/Background'; +import { useController } from 'hooks/useController'; export const CreatePhrase = ({ password }: { password: string }) => { - const controller = getController(); + const { controllerEmitter } = useController(); + const [seed, setSeed] = useState(''); const { t } = useTranslation(); const [visible, setVisible] = useState(false); @@ -15,8 +16,12 @@ export const CreatePhrase = ({ password }: { password: string }) => { const navigate = useNavigate(); - //todo: we need to call keyring manager with the new seed phrase function - const seed = useMemo(() => controller.wallet.createNewSeed(), []); + useEffect(() => { + //todo: we need to call keyring manager with the new seed phrase function + controllerEmitter(['wallet', 'createNewSeed']).then((response: string) => { + setSeed(response); + }); + }, []); const handleCopyToClipboard = () => { navigator.clipboard.writeText(seed); diff --git a/source/pages/SeedConfirm/index.tsx b/source/pages/SeedConfirm/index.tsx index 99f98e435..4c5952c8c 100755 --- a/source/pages/SeedConfirm/index.tsx +++ b/source/pages/SeedConfirm/index.tsx @@ -1,14 +1,14 @@ import React, { useEffect, useState } from 'react'; import { useLocation } from 'react-router-dom'; +import { useController } from 'hooks/useController'; import { useUtils } from 'hooks/useUtils'; -import { getController } from 'scripts/Background'; import { ConfirmPhrase } from './ConfirmPhrase'; import { CreatePhrase } from './CreatePhrase'; export const SeedConfirm = () => { - const controller = getController(); + const { controllerEmitter } = useController(); const { navigate } = useUtils(); @@ -20,7 +20,10 @@ export const SeedConfirm = () => { const handleConfirm = async () => { if (passed) { - await controller.wallet.createWallet(password, createdSeed); + await controllerEmitter( + ['wallet', 'createWallet'], + [password, createdSeed] + ); navigate('/home'); } diff --git a/source/pages/Send/Approve.tsx b/source/pages/Send/Approve.tsx index 17e3c428b..955550c93 100644 --- a/source/pages/Send/Approve.tsx +++ b/source/pages/Send/Approve.tsx @@ -1,5 +1,5 @@ import { Form } from 'antd'; -import { ethers } from 'ethers'; +import { BigNumber, ethers } from 'ethers'; import React, { useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useSelector } from 'react-redux'; @@ -16,8 +16,8 @@ import { IconButton, } from 'components/index'; import { usePrice, useUtils } from 'hooks/index'; +import { useController } from 'hooks/useController'; import { useQueryData } from 'hooks/useQuery'; -import { getController } from 'scripts/Background'; import { RootState } from 'state/store'; import { IApprovedTokenInfos, @@ -35,7 +35,7 @@ import { EditApprovedAllowanceValueModal } from './EditApprovedAllowanceValueMod import { EditPriorityModal } from './EditPriority'; export const ApproveTransactionComponent = () => { - const { wallet } = getController(); + const { controllerEmitter, web3Provider } = useController(); const { t } = useTranslation(); const { getFiatAmount } = usePrice(); @@ -176,7 +176,7 @@ export const ApproveTransactionComponent = () => { ), 9 ), - gasLimit: wallet.ethereumTransaction.toBigNumber( + gasLimit: BigNumber.from( Boolean(customFee.isCustom && customFee.gasLimit > 0) ? customFee.gasLimit : fee.gasLimit @@ -184,10 +184,14 @@ export const ApproveTransactionComponent = () => { }; try { - const response = - await wallet.ethereumTransaction.sendFormattedTransaction(newTxValue); + const response = (await controllerEmitter( + ['wallet', 'ethereumTransaction', 'sendFormattedTransaction'], + [newTxValue] + )) as { hash: string }; + if (activeAccountMeta.type === KeyringAccountType.Trezor) - wallet.sendAndSaveTransaction(response); + controllerEmitter(['wallet', 'sendAndSaveTransaction'], [response]); + setConfirmedDefaultModal(true); setLoading(false); if (isExternal) @@ -248,12 +252,12 @@ export const ApproveTransactionComponent = () => { const abortController = new AbortController(); const getTokenName = async (contractAddress: string) => { - const getProvider = wallet.ethereumTransaction.contentScriptWeb3Provider; + // const getProvider = wallet.ethereumTransaction.contentScriptWeb3Provider; const contractInstance = new ethers.Contract( contractAddress, getErc20Abi(), - getProvider + web3Provider ); const [tokenSymbolByContract, tokenDecimalsByContract] = diff --git a/source/pages/Send/Confirm.tsx b/source/pages/Send/Confirm.tsx index c2b999863..e57942636 100755 --- a/source/pages/Send/Confirm.tsx +++ b/source/pages/Send/Confirm.tsx @@ -38,7 +38,7 @@ import { import { EditPriorityModal } from './EditPriority'; export const SendConfirm = () => { - const { controllerEmitter } = useController(); + const { controllerEmitter, web3Provider, isLoading } = useController(); const { t } = useTranslation(); const { alert, navigate, useCopyClipboard } = useUtils(); const url = chrome.runtime.getURL('app.html'); @@ -75,8 +75,7 @@ export const SendConfirm = () => { const [confirmedTx, setConfirmedTx] = useState(); const [isEIP1559Compatible, setIsEIP1559Compatible] = useState(); const [copied, copy] = useCopyClipboard(); - const [isReconectModalOpen, setIsReconectModalOpen] = - useState(false); + const [isReconectModalOpen, setIsReconectModalOpen] = useState(false); const basicTxValues = state.tx; @@ -100,22 +99,22 @@ export const SendConfirm = () => { 'wallet', 'ethereumTransaction', 'getRecommendedGasPrice', - ]); + ]).then((gas) => BigNumber.from(gas).toNumber()); const gasLimit: any = await controllerEmitter( ['wallet', 'ethereumTransaction', 'getTxGasLimit'], [basicTxValues] - ); + ).then((gas) => BigNumber.from(gas).toNumber()); const initialFee = INITIAL_FEE; - initialFee.gasPrice = Number(correctGasPrice); + initialFee.gasPrice = correctGasPrice; setFee({ ...initialFee, gasLimit }); - setGasPrice(Number(correctGasPrice)); + setGasPrice(correctGasPrice); - return { gasLimit, gasPrice: Number(correctGasPrice) }; + return { gasLimit, gasPrice: correctGasPrice }; }; const handleConfirm = async () => { @@ -210,27 +209,21 @@ export const SendConfirm = () => { if (isEIP1559Compatible === false) { try { - await ( - controllerEmitter( - [ - 'wallet', - 'ethereumTransaction', - 'sendFormattedTransaction', - ], - [ - { - ...restTx, - value, - gasPrice: ethers.utils.hexlify(gasPrice), - gasLimit: BigNumber.from( - validateCustomGasLimit - ? customFee.gasLimit - : fee.gasLimit - ), - }, - !isEIP1559Compatible, - ] - ) as Promise + await controllerEmitter( + ['wallet', 'ethereumTransaction', 'sendFormattedTransaction'], + [ + { + ...restTx, + value, + gasPrice: ethers.utils.hexlify(gasPrice), + gasLimit: BigNumber.from( + validateCustomGasLimit + ? customFee.gasLimit + : fee.gasLimit + ), + }, + !isEIP1559Compatible, + ] ) .then((response) => { if (activeAccountMeta.type === KeyringAccountType.Trezor) @@ -239,6 +232,8 @@ export const SendConfirm = () => { [response] ); + console.log('response', response); + setConfirmedTx(response); setConfirmed(true); @@ -605,12 +600,6 @@ export const SendConfirm = () => { //HANDLE ERC721/ERC1155 NFTS TRANSACTIONS case true: - const web3Provider = await controllerEmitter( - ['wallet', 'ethereumTransaction', 'web3Provider'], - [], - true - ); - const { type } = await getContractType( basicTxValues.token.contractAddress, web3Provider @@ -843,19 +832,22 @@ export const SendConfirm = () => { const getFeeRecomendation = async () => { try { - const { maxFeePerGas, maxPriorityFeePerGas } = await (controllerEmitter( + const { maxFeePerGas, maxPriorityFeePerGas } = (await controllerEmitter( [ 'wallet', 'ethereumTransaction', 'getFeeDataWithDynamicMaxPriorityFeePerGas', ] - ) as Promise); + )) as any; const initialFeeDetails = { - maxFeePerGas: Number(maxFeePerGas) / 10 ** 9, + maxFeePerGas: BigNumber.from(maxFeePerGas).toNumber() / 10 ** 9, baseFee: - (Number(maxFeePerGas) - Number(maxPriorityFeePerGas)) / 10 ** 9, - maxPriorityFeePerGas: Number(maxPriorityFeePerGas) / 10 ** 9, + (BigNumber.from(maxFeePerGas).toNumber() - + BigNumber.from(maxPriorityFeePerGas).toNumber()) / + 10 ** 9, + maxPriorityFeePerGas: + BigNumber.from(maxPriorityFeePerGas).toNumber() / 10 ** 9, gasLimit: BigNumber.from(0), }; @@ -872,7 +864,7 @@ export const SendConfirm = () => { const getGasLimit = await controllerEmitter( ['wallet', 'ethereumTransaction', 'getTxGasLimit'], [formattedTxObject] - ); + ).then((gas) => BigNumber.from(gas).toNumber()); const finalFeeDetails = { ...initialFeeDetails, @@ -925,13 +917,8 @@ export const SendConfirm = () => { }, [copied]); useEffect(() => { + if (isLoading) return; const validateEIP1559Compatibility = async () => { - const web3Provider = (await controllerEmitter( - ['wallet', 'ethereumTransaction', 'web3Provider'], - [], - true - )) as any; - const isCompatible = await verifyNetworkEIP1559Compatibility( web3Provider, currentBlock @@ -941,7 +928,7 @@ export const SendConfirm = () => { }; validateEIP1559Compatibility(); - }, []); + }, [isLoading, web3Provider]); return ( diff --git a/source/pages/Send/SendEth.tsx b/source/pages/Send/SendEth.tsx index d34b531fc..e98155146 100644 --- a/source/pages/Send/SendEth.tsx +++ b/source/pages/Send/SendEth.tsx @@ -23,6 +23,7 @@ export const SendEth = () => { const activeNetwork = useSelector( (state: RootState) => state.vault.activeNetwork ); + const { accounts, activeAccount: activeAccountMeta, diff --git a/source/pages/Send/SendNTokenTransaction.tsx b/source/pages/Send/SendNTokenTransaction.tsx index 4f8da6fbf..f12a6450f 100644 --- a/source/pages/Send/SendNTokenTransaction.tsx +++ b/source/pages/Send/SendNTokenTransaction.tsx @@ -1,4 +1,4 @@ -import { ethers } from 'ethers'; +import { BigNumber, ethers } from 'ethers'; import omit from 'lodash/omit'; import React, { useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; @@ -10,7 +10,7 @@ import { IconButton } from 'components/IconButton'; import { Layout, DefaultModal, Button, Icon } from 'components/index'; import { Tooltip } from 'components/Tooltip'; import { useQueryData, useUtils } from 'hooks/index'; -import { getController } from 'scripts/Background'; +import { useController } from 'hooks/useController'; import { RootState } from 'state/store'; import { ICustomFeeParams, IFeeState, ITxState } from 'types/transactions'; import { dispatchBackgroundEvent } from 'utils/browser'; @@ -25,9 +25,11 @@ import { import { EditPriorityModal } from './EditPriority'; export const SendNTokenTransaction = () => { - const { - wallet: { ethereumTransaction, sendAndSaveTransaction }, //TODO: validates this gets doesn't leads into bugs - } = getController(); + // const { + // wallet: { ethereumTransaction, sendAndSaveTransaction }, //TODO: validates this gets doesn't leads into bugs + // } + + const { controllerEmitter, web3Provider } = useController(); const { t } = useTranslation(); const { alert, navigate, useCopyClipboard } = useUtils(); const [copied, copy] = useCopyClipboard(); @@ -119,22 +121,32 @@ export const SendNTokenTransaction = () => { customFee.isCustom && customFee.gasPrice > 0 ) ? customFee.gasPrice * 10 ** 9 // Calculate custom value to send to transaction because it comes without decimals, only 8 -> 10 -> 12 - : await ethereumTransaction.getRecommendedGasPrice(); - - await ethereumTransaction - .sendFormattedTransaction( + : await controllerEmitter([ + 'wallet', + 'ethereumTransaction', + 'getRecommendedGasPrice', + ]); + + await controllerEmitter( + ['wallet', 'ethereumTransaction', 'sendFormattedTransaction'], + [ { ...finalLegacyTx, gasPrice: ethers.utils.hexlify(Number(getLegacyGasFee)), - gasLimit: ethereumTransaction.toBigNumber( + gasLimit: BigNumber.from( validateCustomGasLimit ? customFee.gasLimit : fee.gasLimit ), }, - isLegacyTransaction - ) + isLegacyTransaction, + ] + ) .then((response) => { if (activeAccountMeta.type === KeyringAccountType.Trezor) - sendAndSaveTransaction(response); + controllerEmitter( + ['wallet', 'sendAndSaveTransaction'], + [response] + ); + setConfirmedTx(response); setConfirmed(true); setLoading(false); @@ -177,33 +189,37 @@ export const SendNTokenTransaction = () => { } } else { try { - await ethereumTransaction - .sendFormattedTransaction({ - ...txWithoutType, - maxPriorityFeePerGas: ethers.utils.parseUnits( - String( - Boolean( - customFee.isCustom && customFee.maxPriorityFeePerGas > 0 - ) - ? customFee.maxPriorityFeePerGas.toFixed(9) - : fee.maxPriorityFeePerGas.toFixed(9) + await controllerEmitter( + ['wallet', 'ethereumTransaction', 'sendFormattedTransaction'], + [ + { + ...txWithoutType, + maxPriorityFeePerGas: ethers.utils.parseUnits( + String( + Boolean( + customFee.isCustom && customFee.maxPriorityFeePerGas > 0 + ) + ? customFee.maxPriorityFeePerGas.toFixed(9) + : fee.maxPriorityFeePerGas.toFixed(9) + ), + 9 ), - 9 - ), - maxFeePerGas: ethers.utils.parseUnits( - String( - Boolean(customFee.isCustom && customFee.maxFeePerGas > 0) - ? customFee.maxFeePerGas.toFixed(9) - : fee.maxFeePerGas.toFixed(9) + maxFeePerGas: ethers.utils.parseUnits( + String( + Boolean(customFee.isCustom && customFee.maxFeePerGas > 0) + ? customFee.maxFeePerGas.toFixed(9) + : fee.maxFeePerGas.toFixed(9) + ), + 9 ), - 9 - ), - gasLimit: ethereumTransaction.toBigNumber( - validateCustomGasLimit - ? customFee.gasLimit * 10 ** 9 // Multiply gasLimit to reach correctly decimal value - : fee.gasLimit - ), - }) + gasLimit: BigNumber.from( + validateCustomGasLimit + ? customFee.gasLimit * 10 ** 9 // Multiply gasLimit to reach correctly decimal value + : fee.gasLimit + ), + }, + ] + ) .then((response) => { setConfirmedTx(response); setConfirmed(true); @@ -253,7 +269,10 @@ export const SendNTokenTransaction = () => { const abortController = new AbortController(); const getInitialFeeRecomendation = async () => { - const nonce = await ethereumTransaction.getRecommendedNonce(tx.from); + const nonce = await controllerEmitter( + ['wallet', 'ethereumTransaction', 'getRecommendedNonce'], + [tx.from] + ); const baseTx = transactionDataValidation ? { from: tx.from, @@ -273,19 +292,22 @@ export const SendNTokenTransaction = () => { let eip1559GasError = false; let gasLimitError = false; if (tx.gas) { - gasLimitResult = ethereumTransaction.toBigNumber(0); + gasLimitResult = BigNumber.from(0); } else { - const currentBlockRequest = - await ethereumTransaction.contentScriptWeb3Provider.send( - 'eth_getBlockByNumber', - ['latest', false] - ); + const currentBlockRequest = (await controllerEmitter( + [ + 'wallet', + 'ethereumTransaction', + 'contentScriptWeb3Provider', + 'send', + ], + ['eth_getBlockByNumber', ['latest', false]] + )) as any; + const gasLimitFromCurrentBlock = Math.floor( Number(currentBlockRequest.gasLimit) * 0.95 ); //GasLimit from current block with 5% discount, whole limit from block is too much - gasLimitResult = ethereumTransaction.toBigNumber( - gasLimitFromCurrentBlock - ); + gasLimitResult = BigNumber.from(gasLimitFromCurrentBlock); gasLimitError = false; // verify tx data @@ -298,9 +320,14 @@ export const SendNTokenTransaction = () => { delete clonedTx.maxPriorityFeePerGas; delete clonedTx.maxFeePerGas; delete clonedTx.gasPrice; - await ethereumTransaction.contentScriptWeb3Provider.send( - 'eth_call', - [clonedTx, 'latest'] + await controllerEmitter( + [ + 'wallet', + 'ethereumTransaction', + 'contentScriptWeb3Provider', + 'send', + ], + ['eth_call', [clonedTx, 'latest']] ); } } catch (error) { @@ -312,8 +339,9 @@ export const SendNTokenTransaction = () => { try { // if tx data is valid, Pali is able to estimate gas. if (!isInvalidTxData) { - gasLimitResult = await ethereumTransaction.getTxGasLimit( - baseTx as any + gasLimitResult = await controllerEmitter( + ['wallet', 'ethereumTransaction', 'getTxGasLimit'], + [baseTx as any] ); } } catch (error) { @@ -325,11 +353,17 @@ export const SendNTokenTransaction = () => { tx.gasLimit = (tx?.gas && Number(tx?.gas) > Number(gasLimitResult)) || (tx?.gasLimit && Number(tx?.gasLimit) > Number(gasLimitResult)) - ? ethereumTransaction.toBigNumber(tx.gas || tx.gasLimit) + ? BigNumber.from(tx.gas || tx.gasLimit) : gasLimitResult; try { - const { maxFeePerGas, maxPriorityFeePerGas } = - await ethereumTransaction.getFeeDataWithDynamicMaxPriorityFeePerGas(); + const { maxFeePerGas, maxPriorityFeePerGas } = (await controllerEmitter( + [ + 'wallet', + 'ethereumTransaction', + 'getFeeDataWithDynamicMaxPriorityFeePerGas', + ] + )) as any; + const feeRecomendation = { maxFeePerGas: tx?.maxFeePerGas ? Number(tx?.maxFeePerGas) / 10 ** 9 @@ -345,7 +379,13 @@ export const SendNTokenTransaction = () => { gasLimit: tx.gasLimit, gasPrice: tx?.gasPrice ? Number(tx.gasPrice) / 10 ** 9 - : Number(await ethereumTransaction.getRecommendedGasPrice()) / + : Number( + await controllerEmitter([ + 'wallet', + 'ethereumTransaction', + 'getRecommendedGasPrice', + ]) + ) / 10 ** 9, }; @@ -394,7 +434,7 @@ export const SendNTokenTransaction = () => { useEffect(() => { const validateEIP1559Compatibility = async () => { const isCompatible = await verifyNetworkEIP1559Compatibility( - ethereumTransaction.contentScriptWeb3Provider, + web3Provider, currentBlock ); setIsEIP1559Compatible(isCompatible); @@ -409,7 +449,10 @@ export const SendNTokenTransaction = () => { title={t('send.txSuccessfull')} description={t('send.txSuccessfullMessage')} onClose={() => { - sendAndSaveTransaction(confirmedTx); + controllerEmitter( + ['wallet', 'sendAndSaveTransaction'], + [confirmedTx] + ); if (isExternal) window.close(); else navigate('/home'); }} diff --git a/source/pages/Send/SendSys.tsx b/source/pages/Send/SendSys.tsx index 2018df941..ac24d7353 100644 --- a/source/pages/Send/SendSys.tsx +++ b/source/pages/Send/SendSys.tsx @@ -12,7 +12,7 @@ import { isValidSYSAddress } from '@pollum-io/sysweb3-utils'; import { Tooltip, Fee, NeutralButton, Layout, Icon } from 'components/index'; import { usePrice, useUtils } from 'hooks/index'; -import { getController } from 'scripts/Background'; +import { useController } from 'hooks/useController'; import { IPriceState } from 'state/price/types'; import { RootState } from 'state/store'; import { ITokenSysProps } from 'types/tokens'; @@ -26,7 +26,7 @@ import { export const SendSys = () => { const { getFiatAmount } = usePrice(); - const controller = getController(); + const { controllerEmitter } = useController(); const { t } = useTranslation(); const { alert, navigate } = useUtils(); const activeNetwork = useSelector( @@ -47,15 +47,15 @@ export const SendSys = () => { const [form] = Form.useForm(); const handleGetFee = useCallback(async () => { - const getRecommendedFee = - await controller.wallet.syscoinTransaction.getRecommendedFee( - activeNetwork.url - ); + const getRecommendedFee = (await controllerEmitter( + ['wallet', 'syscoinTransaction', 'getRecommendedFee'], + [activeNetwork.url] + )) as number; setRecommendedFee(getRecommendedFee || Number(0.00001)); form.setFieldsValue({ fee: getRecommendedFee || Number(0.00001) }); - }, [controller.wallet.account, form]); + }, [activeAccount, form]); const isAccountImported = accounts[activeAccountMeta.type][activeAccountMeta.id]?.isImported; @@ -120,10 +120,10 @@ export const SendSys = () => { const nextStep = async ({ receiver, amount }: any) => { try { setIsLoading(true); - const transactionFee = - await controller.wallet.syscoinTransaction.getEstimateSysTransactionFee( - { amount, receivingAddress: receiver } - ); + const transactionFee = await controllerEmitter( + ['wallet', 'syscoinTransaction', 'getEstimateSysTransactionFee'], + [{ amount, receivingAddress: receiver }] + ); setIsLoading(false); navigate('/send/confirm', { state: { @@ -300,7 +300,7 @@ export const SendSys = () => { as="div" className="scrollbar-styled absolute z-10 left-0 mt-2 py-3 w-44 h-56 text-brand-white font-poppins bg-brand-blue800 border border-fields-input-border focus:border-fields-input-borderfocus rounded-2xl shadow-2xl overflow-auto origin-top-right" > - +