diff --git a/.circleci/config.yml b/.circleci/config.yml index 496486a16..c35a42449 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -101,6 +101,9 @@ workflows: build-type: [main, beta, flask, mmi, desktop] requires: - prep-deps + - prep-build-mmi: + requires: + - prep-deps - prep-build: requires: - prep-deps @@ -186,6 +189,9 @@ workflows: ignore: master requires: - prep-build-desktop + - validate-source-maps-mmi: + requires: + - prep-build-mmi - validate-source-maps-flask: requires: - prep-build-flask @@ -222,6 +228,7 @@ workflows: - validate-source-maps-beta - validate-source-maps-desktop - validate-source-maps-flask + - validate-source-maps-mmi - test-mozilla-lint - test-mozilla-lint-desktop - test-mozilla-lint-flask @@ -245,6 +252,7 @@ workflows: - prep-build - trigger-beta-build - prep-build-desktop + - prep-build-mmi - prep-build-flask - prep-build-storybook - prep-build-ts-migration-dashboard @@ -261,6 +269,7 @@ workflows: - prep-deps - prep-build - prep-build-desktop + - prep-build-mmi - prep-build-flask - all-tests-pass - job-publish-storybook: @@ -353,18 +362,15 @@ jobs: echo "Not a PR; skipping" fi - run: - name: Setup registry config for using package previews on draft PRs + name: Install dependencies command: | if [[ $IS_DRAFT == 'true' ]] then - printf '%s\n\n%s' '@metamask:registry=https://npm.pkg.github.com' "//npm.pkg.github.com/:_authToken=${GITHUB_PACKAGE_READ_TOKEN}" > .npmrc + # Use GitHub registry on draft PRs, allowing the use of preview builds + METAMASK_NPM_REGISTRY=https://npm.pkg.github.com yarn --immutable else - echo "Not draft; skipping GitHub registry setup" + yarn --immutable fi - - run: - name: Install deps - command: | - .circleci/scripts/deps-install.sh - save_cache: key: dependency-cache-v1-{{ checksum "yarn.lock" }} paths: @@ -475,6 +481,49 @@ jobs: - dist-desktop - builds-desktop + prep-build-mmi: + executor: node-browsers-medium-plus + steps: + - run: *shallow-git-clone + - attach_workspace: + at: . + - when: + condition: + not: + matches: + pattern: /^master$/ + value: << pipeline.git.branch >> + steps: + - run: + name: build:dist + command: yarn build --build-type mmi dist + - when: + condition: + matches: + pattern: /^master$/ + value: << pipeline.git.branch >> + steps: + - run: + name: build:prod + command: yarn build --build-type mmi prod + - run: + name: build:debug + command: find dist/ -type f -exec md5sum {} \; | sort -k 2 + - run: + name: Move mmi build to 'dist-mmi' to avoid conflict with production build + command: mv ./dist ./dist-mmi + - run: + name: Move mmi zips to 'builds-mmi' to avoid conflict with production build + command: mv ./builds ./builds-mmi + - persist_to_workspace: + root: . + paths: + - dist-mmi + - builds-mmi + - store_artifacts: + path: builds-mmi + destination: builds-mmi + prep-build-flask: executor: node-browsers-medium-plus steps: @@ -1191,6 +1240,22 @@ jobs: name: Validate source maps command: yarn validate-source-maps + validate-source-maps-mmi: + executor: node-browsers + steps: + - run: *shallow-git-clone + - attach_workspace: + at: . + - run: + name: Move mmi build to dist + command: mv ./dist-mmi ./dist + - run: + name: Move mmi zips to builds + command: mv ./builds-mmi ./builds + - run: + name: Validate source maps + command: yarn validate-source-maps + validate-source-maps-flask: executor: node-browsers steps: diff --git a/.circleci/scripts/deps-install.sh b/.circleci/scripts/deps-install.sh deleted file mode 100755 index ddcf2cf8c..000000000 --- a/.circleci/scripts/deps-install.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash - -# Print commands and their arguments as they are executed. -set -x -# Exit immediately if a command exits with a non-zero status. -set -e - -yarn install --frozen-lockfile - diff --git a/.eslintrc.base.js b/.eslintrc.base.js index b4e93c1c9..c13c95352 100644 --- a/.eslintrc.base.js +++ b/.eslintrc.base.js @@ -72,5 +72,8 @@ module.exports = { // upgrading eslint and dependencies. This rule should be evaluated and // if agreeable turned on upstream in @metamask/eslint-config 'import/no-named-as-default-member': 'off', + + // This is necessary to run eslint on Windows and not get a thousand CRLF errors + 'prettier/prettier': ['error', { endOfLine: 'auto' }], }, }; diff --git a/.github/workflows/stale-issues-pr.yml b/.github/workflows/stale-issues-pr.yml index 941a689d1..42da445b1 100644 --- a/.github/workflows/stale-issues-pr.yml +++ b/.github/workflows/stale-issues-pr.yml @@ -1,7 +1,9 @@ name: 'Close stale issues and PRs' + +# run every 2 hours on: schedule: - - cron: '0 12 * * *' + - cron: '0 */2 * * *' jobs: stale: @@ -12,17 +14,16 @@ jobs: steps: - uses: actions/stale@72afbce2b0dbd1d903bb142cebe2d15dc307ae57 with: - stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity in the last 90 days. It will be closed in 45 days. Thank you for your contributions.' stale-issue-label: 'stale' only-issue-labels: 'type-bug' - exempt-issue-labels: 'type-security, type-pinned, feature-request, awaiting-metamask' - stale-pr-message: 'This PR has been automatically marked as stale because it has not had recent activity in the last 60 days. It will be closed in 14 days. Thank you for your contributions.' - stale-pr-label: 'stale' - exempt-pr-labels: 'work-in-progress' - close-issue-message: 'This issue was closed because there has been no follow up activity in the last 7 days. If you feel this was closed in error, please reopen and provide evidence on the latest release of the extension. Thank you for your contributions.' - close-pr-message: 'This PR was closed because there has been no follow up activity in the last 7 days. Thank you for your contributions.' + exempt-issue-labels: 'type-security' days-before-issue-stale: 90 - days-before-pr-stale: 60 + stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity in the last 90 days. It will be closed in 45 days if there is no further activity. The MetaMask team intends on reviewing this issue before close, and removing the stale label if it is still a bug. We welcome new comments on this issue. We do not intend on closing issues if they report bugs that are still reproducible. Thank you for your contributions.' days-before-issue-close: 45 + close-issue-message: 'This issue was closed because there has been no follow up activity in the last 45 days. If you feel this was closed in error, please reopen and provide evidence on the latest release of the extension. Thank you for your contributions.' + stale-pr-label: 'stale' + days-before-pr-stale: 60 + stale-pr-message: 'This PR has been automatically marked as stale because it has not had recent activity in the last 60 days. It will be closed in 14 days. Thank you for your contributions.' days-before-pr-close: 14 - operations-per-run: 1 + close-pr-message: 'This PR was closed because there has been no follow up activity in the last 14 days. Thank you for your contributions.' + operations-per-run: 600 diff --git a/.iyarc b/.iyarc index 9e16de044..b738f7b0c 100644 --- a/.iyarc +++ b/.iyarc @@ -1,10 +1,6 @@ # improved-yarn-audit advisory exclusions GHSA-257v-vj4p-3w2h -# request library is subject to SSRF. -# addressed by temporary patch in .yarn/patches/request-npm-2.88.2-f4a57c72c4.patch -GHSA-p8p7-x288-28g6 - # Prototype pollution # Not easily patched # Minimal risk to us because we're using lockdown which also prevents this case of prototype pollution diff --git a/.metamaskrc.dist b/.metamaskrc.dist index 0e0bc421e..0bd4d3995 100644 --- a/.metamaskrc.dist +++ b/.metamaskrc.dist @@ -12,3 +12,4 @@ INFURA_PROJECT_ID=00000000000 ; Set this to test changes to the phishing warning page. ;PHISHING_WARNING_PAGE_URL= +BLOCKAID_FILE_CDN= diff --git a/.prettierrc.yml b/.prettierrc.yml index 3e9d085ce..9912c96b0 100644 --- a/.prettierrc.yml +++ b/.prettierrc.yml @@ -1,2 +1,5 @@ +# All of these are defaults except singleQuote and endOfLine, but we specify them +# for explicitness +endOfLine: auto singleQuote: true trailingComma: all diff --git a/.yarn/patches/@metamask-keyring-controller-npm-7.0.0-962008b200.patch b/.yarn/patches/@metamask-keyring-controller-npm-7.0.0-962008b200.patch new file mode 100644 index 000000000..15d28303c --- /dev/null +++ b/.yarn/patches/@metamask-keyring-controller-npm-7.0.0-962008b200.patch @@ -0,0 +1,46 @@ +diff --git a/dist/KeyringController.d.ts b/dist/KeyringController.d.ts +index 82de83a7bb1ad14bb23f3b6274e0c4d5bb773382..86a09b3f604f6feb26e2c7edbdcb0abebd4bae20 100644 +--- a/dist/KeyringController.d.ts ++++ b/dist/KeyringController.d.ts +@@ -1,10 +1,11 @@ + import type { TxData, TypedTransaction } from '@ethereumjs/tx'; +-import { type MetaMaskKeyring as QRKeyring, type IKeyringState as IQRKeyringState } from '@keystonehq/metamask-airgapped-keyring'; ++import type { MetaMaskKeyring as QRKeyring, IKeyringState as IQRKeyringState } from '@keystonehq/metamask-airgapped-keyring'; + import type { RestrictedControllerMessenger } from '@metamask/base-controller'; + import { BaseControllerV2 } from '@metamask/base-controller'; + import type { PersonalMessageParams, TypedMessageParams } from '@metamask/message-manager'; + import type { PreferencesController } from '@metamask/preferences-controller'; +-import { type Hex, type Keyring, type Json } from '@metamask/utils'; ++import type { Hex, Keyring, Json } from '@metamask/utils'; ++import type { KeyringController as EthKeyringController } from '@metamask/eth-keyring-controller'; + import type { Patch } from 'immer'; + declare const name = "KeyringController"; + /** +@@ -135,6 +136,10 @@ export declare class KeyringController extends BaseControllerV2 { -+ // Expecting reject error but throwing manually rather than waiting -+ }); - __classPrivateFieldGet(this, _SignatureController_instances, "m", _SignatureController_cancelAbstractMessage).call(this, messageManager, messageId); -- throw eth_rpc_errors_1.ethErrors.provider.userRejectedRequest('User rejected the request.'); -+ throw eth_rpc_errors_1.ethErrors.provider.userRejectedRequest(`MetaMask ${messageName} Signature: User denied message signature.`); - } - yield signMessage(messageParamsWithId, version, signingOpts); - return signaturePromise; diff --git a/.yarn/patches/@metamask-signature-controller-npm-5.3.0-225628460b.patch b/.yarn/patches/@metamask-signature-controller-npm-5.3.0-225628460b.patch new file mode 100644 index 000000000..ac0375763 --- /dev/null +++ b/.yarn/patches/@metamask-signature-controller-npm-5.3.0-225628460b.patch @@ -0,0 +1,26 @@ +diff --git a/dist/SignatureController.js b/dist/SignatureController.js +index a2f064efa2a2700db00767daa4ce6bd22b1932c4..17edb51b6c526f27fb4c19f2d2fda3d7140c66b4 100644 +--- a/dist/SignatureController.js ++++ b/dist/SignatureController.js +@@ -283,8 +283,11 @@ _SignatureController_keyringController = new WeakMap(), _SignatureController_isE + resultCallbacks = acceptResult.resultCallbacks; + } + catch (_a) { ++ signaturePromise.catch(() => { ++ // Expecting reject error but throwing manually rather than waiting ++ }); + __classPrivateFieldGet(this, _SignatureController_instances, "m", _SignatureController_cancelAbstractMessage).call(this, messageManager, messageId); +- throw eth_rpc_errors_1.ethErrors.provider.userRejectedRequest('User rejected the request.'); ++ throw eth_rpc_errors_1.ethErrors.provider.userRejectedRequest(`MetaMask ${messageName} Signature: User denied message signature.`); + } + yield signMessage(messageParamsWithId, signingOpts); + const signatureResult = yield signaturePromise; +@@ -305,7 +308,7 @@ _SignatureController_keyringController = new WeakMap(), _SignatureController_isE + return __awaiter(this, void 0, void 0, function* () { + return yield __classPrivateFieldGet(this, _SignatureController_instances, "m", _SignatureController_signAbstractMessage).call(this, __classPrivateFieldGet(this, _SignatureController_personalMessageManager, "f"), controller_utils_1.ApprovalType.PersonalSign, msgParams, (cleanMsgParams) => __awaiter(this, void 0, void 0, function* () { return yield __classPrivateFieldGet(this, _SignatureController_keyringController, "f").signPersonalMessage(cleanMsgParams); })); + }); +-}, _SignatureController_signTypedMessage = function _SignatureController_signTypedMessage(msgParams, ++}, _SignatureController_signTypedMessage = function _SignatureController_signTypedMessage(msgParams, + /* istanbul ignore next */ + opts = { parseJsonData: true }) { + return __awaiter(this, void 0, void 0, function* () { diff --git a/.yarn/patches/jsdom-npm-16.7.0-216c5c4bf9.patch b/.yarn/patches/jsdom-npm-16.7.0-216c5c4bf9.patch new file mode 100644 index 000000000..38915bce4 --- /dev/null +++ b/.yarn/patches/jsdom-npm-16.7.0-216c5c4bf9.patch @@ -0,0 +1,80 @@ +diff --git a/lib/jsdom/browser/Window.js b/lib/jsdom/browser/Window.js +index 9b2d75f55050f865382e2f0e8a88f066e0bff2da..d4a635da8eae02eaf0543693356f1252f8b6bac0 100644 +--- a/lib/jsdom/browser/Window.js ++++ b/lib/jsdom/browser/Window.js +@@ -24,7 +24,6 @@ const External = require("../living/generated/External"); + const Navigator = require("../living/generated/Navigator"); + const Performance = require("../living/generated/Performance"); + const Screen = require("../living/generated/Screen"); +-const Storage = require("../living/generated/Storage"); + const Selection = require("../living/generated/Selection"); + const reportException = require("../living/helpers/runtime-script-errors"); + const { getCurrentEventHandlerValue } = require("../living/helpers/create-event-accessor.js"); +@@ -285,40 +284,6 @@ function Window(options) { + this._pretendToBeVisual = options.pretendToBeVisual; + this._storageQuota = options.storageQuota; + +- // Some properties (such as localStorage and sessionStorage) share data +- // between windows in the same origin. This object is intended +- // to contain such data. +- if (options.commonForOrigin && options.commonForOrigin[documentOrigin]) { +- this._commonForOrigin = options.commonForOrigin; +- } else { +- this._commonForOrigin = { +- [documentOrigin]: { +- localStorageArea: new Map(), +- sessionStorageArea: new Map(), +- windowsInSameOrigin: [this] +- } +- }; +- } +- +- this._currentOriginData = this._commonForOrigin[documentOrigin]; +- +- // ### WEB STORAGE +- +- this._localStorage = Storage.create(window, [], { +- associatedWindow: this, +- storageArea: this._currentOriginData.localStorageArea, +- type: "localStorage", +- url: this._document.documentURI, +- storageQuota: this._storageQuota +- }); +- this._sessionStorage = Storage.create(window, [], { +- associatedWindow: this, +- storageArea: this._currentOriginData.sessionStorageArea, +- type: "sessionStorage", +- url: this._document.documentURI, +- storageQuota: this._storageQuota +- }); +- + // ### SELECTION + + // https://w3c.github.io/selection-api/#dfn-selection +@@ -416,26 +381,6 @@ function Window(options) { + configurable: true + }); + }, +- get localStorage() { +- if (idlUtils.implForWrapper(this._document)._origin === "null") { +- throw DOMException.create(window, [ +- "localStorage is not available for opaque origins", +- "SecurityError" +- ]); +- } +- +- return this._localStorage; +- }, +- get sessionStorage() { +- if (idlUtils.implForWrapper(this._document)._origin === "null") { +- throw DOMException.create(window, [ +- "sessionStorage is not available for opaque origins", +- "SecurityError" +- ]); +- } +- +- return this._sessionStorage; +- }, + get customElements() { + return customElementRegistry; + }, diff --git a/.yarn/patches/lavamoat-core-npm-14.2.0-c453f4f755.patch b/.yarn/patches/lavamoat-core-npm-14.2.0-c453f4f755.patch new file mode 100644 index 000000000..abae9b295 --- /dev/null +++ b/.yarn/patches/lavamoat-core-npm-14.2.0-c453f4f755.patch @@ -0,0 +1,18 @@ +diff --git a/src/loadPolicy.js b/src/loadPolicy.js +index ef71923f9282d6a5e9f74e6ec6fa0516f28f508b..0118fda7e1b0fa461ec01ceff8d7112d072f3dfb 100644 +--- a/src/loadPolicy.js ++++ b/src/loadPolicy.js +@@ -33,10 +33,9 @@ async function loadPolicyAndApplyOverrides({ debugMode, policyPath, policyOverri + } + const policyOverride = await readPolicyFile({ debugMode, policyPath: policyOverridePath }) + lavamoatPolicy = mergePolicy(policy, policyOverride) +- // TODO: Only write if merge results in changes. +- // Would have to make a deep equal check on whole policy, which is a waste of time. +- // mergePolicy() should be able to do it in one pass. +- fs.writeFileSync(policyPath, jsonStringify(lavamoatPolicy, { space: 2 })) ++ // Skip policy write step to prevent intermittent build failures ++ // The extension validates the policy in a separate step, we don't need it ++ // to be written to disk here. + } + return lavamoatPolicy + } diff --git a/.yarn/patches/parse5-npm-7.0.0-3158a72394.patch b/.yarn/patches/parse5-npm-7.1.2-aa9a92c270.patch similarity index 82% rename from .yarn/patches/parse5-npm-7.0.0-3158a72394.patch rename to .yarn/patches/parse5-npm-7.1.2-aa9a92c270.patch index 6ddebfde8..fbbccb66a 100644 --- a/.yarn/patches/parse5-npm-7.0.0-3158a72394.patch +++ b/.yarn/patches/parse5-npm-7.1.2-aa9a92c270.patch @@ -1,8 +1,8 @@ diff --git a/dist/index.d.ts b/dist/index.d.ts -index 81253d38280bb25de1e36443d919f0e95b3e023c..d2333bf6796ff3ec94f5857d23ef34cc39c9729a 100644 +index 66eb3236059f88f73355d4fddef9e06a0169b407..04f067d2bda8af760c0a95ca6b5d85bcdfb2421a 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts -@@ -1,10 +1,10 @@ +@@ -1,11 +1,12 @@ -import { type ParserOptions } from './parser/index.js'; +import { ParserOptions } from './parser/index.js'; import type { DefaultTreeAdapterMap } from './tree-adapters/default.js'; @@ -12,12 +12,15 @@ index 81253d38280bb25de1e36443d919f0e95b3e023c..d2333bf6796ff3ec94f5857d23ef34cc export type { TreeAdapter, TreeAdapterTypeMap } from './tree-adapters/interface.js'; -export { type ParserOptions, /** @internal */ Parser } from './parser/index.js'; -export { serialize, serializeOuter, type SerializerOptions } from './serializer/index.js'; +-export { ERR as ErrorCodes, type ParserError } from './common/error-codes.js'; +export { ParserOptions, /** @internal */ Parser } from './parser/index.js'; +export { serialize, serializeOuter, SerializerOptions } from './serializer/index.js'; - export type { ParserError } from './common/error-codes.js'; ++export type { ParserError } from './common/error-codes.js'; ++export { ERR as ErrorCodes } from './common/error-codes.js'; /** @internal */ export * as foreignContent from './common/foreign-content.js'; -@@ -13,7 +13,7 @@ export * as html from './common/html.js'; + /** @internal */ +@@ -13,7 +14,7 @@ export * as html from './common/html.js'; /** @internal */ export * as Token from './common/token.js'; /** @internal */ @@ -27,7 +30,7 @@ index 81253d38280bb25de1e36443d919f0e95b3e023c..d2333bf6796ff3ec94f5857d23ef34cc * Parses an HTML string. * diff --git a/dist/parser/index.d.ts b/dist/parser/index.d.ts -index 50a9bd0c73649e4a78edd0d18b4ee44ae9cdf3b7..df1863e335e64269298dea42a7481b26b9e77581 100644 +index 50a9bd0c73649e4a78edd0d18b4ee44ae9cdf3b7..85cc630db81d7a4ebd01691223d81187cdd8adcb 100644 --- a/dist/parser/index.d.ts +++ b/dist/parser/index.d.ts @@ -1,10 +1,10 @@ @@ -46,18 +49,18 @@ index 50a9bd0c73649e4a78edd0d18b4ee44ae9cdf3b7..df1863e335e64269298dea42a7481b26 INITIAL = 0, BEFORE_HTML = 1, diff --git a/dist/serializer/index.d.ts b/dist/serializer/index.d.ts -index d944fae103a245cb84623fd733c91cc7e79f72f1..432464c9e05ecfd93c66526bcf4f0c81f09bf00d 100644 +index bf759e63ba1be31a2ab14884fcfd6bd3e8ecd2d7..839e21e45dc13e678c9874c51524a8ed1a463591 100644 --- a/dist/serializer/index.d.ts +++ b/dist/serializer/index.d.ts @@ -1,5 +1,5 @@ - import type { TreeAdapter, TreeAdapterTypeMap } from '../tree-adapters/interface'; + import type { TreeAdapter, TreeAdapterTypeMap } from '../tree-adapters/interface.js'; -import { type DefaultTreeAdapterMap } from '../tree-adapters/default.js'; +import { DefaultTreeAdapterMap } from '../tree-adapters/default.js'; export interface SerializerOptions { /** * Specifies input tree format. diff --git a/dist/tokenizer/index.d.ts b/dist/tokenizer/index.d.ts -index de6e234cfb36bb3a4b928c47ab0d0fdf0b4311e1..89e2484b43f3487f3f157435a283ba932a879210 100644 +index 5afab96d6499bb0bba706aee7d2f153647db8713..3680d732d8a3570b6a1d9336c0ebdf8fe4f392db 100644 --- a/dist/tokenizer/index.d.ts +++ b/dist/tokenizer/index.d.ts @@ -1,6 +1,6 @@ @@ -69,8 +72,18 @@ index de6e234cfb36bb3a4b928c47ab0d0fdf0b4311e1..89e2484b43f3487f3f157435a283ba93 declare const enum State { DATA = 0, RCDATA = 1, +diff --git a/dist/tree-adapters/default.d.ts b/dist/tree-adapters/default.d.ts +index 547d714bdc5a664ba1414c16bdfc9247c71ab4de..d96a23d6ce3e80d78da21d958c059de194bb5146 100644 +--- a/dist/tree-adapters/default.d.ts ++++ b/dist/tree-adapters/default.d.ts +@@ -1,4 +1,4 @@ +-import { DOCUMENT_MODE, type NS } from '../common/html.js'; ++import { DOCUMENT_MODE, NS } from '../common/html.js'; + import type { Attribute, Location, ElementLocation } from '../common/token.js'; + import type { TreeAdapter, TreeAdapterTypeMap } from './interface.js'; + export interface Document { diff --git a/dist/tokenizer/preprocessor.d.ts b/dist/tokenizer/preprocessor.d.ts -index e74a590783b4688fb6498b019c1a75cfd9ac23e7..d145dcce97b104830e5b3d7f57f3a63377bbf89c 100644 +index e74a590783b4688fb6498b019c1a75cfd9ac23e7..7350e44b4ed952bcb8f167e30a94958e9fcf743a 100644 --- a/dist/tokenizer/preprocessor.d.ts +++ b/dist/tokenizer/preprocessor.d.ts @@ -1,4 +1,4 @@ @@ -79,13 +92,3 @@ index e74a590783b4688fb6498b019c1a75cfd9ac23e7..d145dcce97b104830e5b3d7f57f3a633 export declare class Preprocessor { private handler; html: string; -diff --git a/dist/tree-adapters/default.d.ts b/dist/tree-adapters/default.d.ts -index cccdf8f86d2295b3059c42943d896e81691c8419..d70b8fa2562f4dc6415d7ebaaba6cb322f66e9cb 100644 ---- a/dist/tree-adapters/default.d.ts -+++ b/dist/tree-adapters/default.d.ts -@@ -1,4 +1,4 @@ --import { DOCUMENT_MODE, type NS } from '../common/html.js'; -+import { DOCUMENT_MODE, NS } from '../common/html.js'; - import type { Attribute, Location, ElementLocation } from '../common/token.js'; - import type { TreeAdapter, TreeAdapterTypeMap } from './interface.js'; - export declare enum NodeType { diff --git a/.yarnrc.yml b/.yarnrc.yml index acf603710..43ef15953 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -8,6 +8,15 @@ logFilters: nodeLinker: node-modules +npmRegistries: + "https://npm.pkg.github.com": + npmAlwaysAuth: true + npmAuthToken: "${GITHUB_PACKAGE_READ_TOKEN-}" + +npmScopes: + metamask: + npmRegistryServer: "${METAMASK_NPM_REGISTRY:-https://registry.yarnpkg.com}" + plugins: - path: .yarn/plugins/@yarnpkg/plugin-allow-scripts.cjs spec: "https://raw.githubusercontent.com/LavaMoat/LavaMoat/main/packages/yarn-plugin-allow-scripts/bundles/@yarnpkg/plugin-allow-scripts.js" diff --git a/CHANGELOG.md b/CHANGELOG.md index 914787298..212f65a2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [10.34.1] +### Fixed +- Fix bug that could cause a failure in the persistence of network related data ([#20080](https://github.com/MetaMask/metamask-extension/pull/20080)) +- Fix ([#20080](https://github.com/MetaMask/metamask-extension/pull/20080)) + +## [10.34.0] +### Added +- Add a security quiz to the SRP reveal ([#19283](https://github.com/MetaMask/metamask-extension/pull/19283)) +- [FLASK] Add Snaps keyring and new snap accounts related pages ([#19710](https://github.com/MetaMask/metamask-extension/pull/19710)) + + +### Changed +- Decrease boldness of text in some labels ([#19731](https://github.com/MetaMask/metamask-extension/pull/19731)) + +### Fixed +- Fix design inconsistencies in the connect flow ([#19800](https://github.com/MetaMask/metamask-extension/pull/19800)) +- Fix connection issues on some dapps, and ensure that `eth_requestAccount` returns accounts when opening multiple tabs for the same dapp ([#19727](https://github.com/MetaMask/metamask-extension/pull/19727)) +- Fix UI bugs in contacts page ([#19646](https://github.com/MetaMask/metamask-extension/pull/19646)) +- Ensure correct logo shown on Linea ([#19717](https://github.com/MetaMask/metamask-extension/pull/19717)) +- Fix the autolock field in settings on firefox ([#19653](https://github.com/MetaMask/metamask-extension/pull/19653)) +- Prevent duplicate account names that only differ by letter casing ([#19616](https://github.com/MetaMask/metamask-extension/pull/19616)) +- Ensure token details stay within asset dropdown border ([#19626](https://github.com/MetaMask/metamask-extension/pull/19626)) +- Prevent rounded corners in account menu ([#19615](https://github.com/MetaMask/metamask-extension/pull/19615)) +- Ensure network changes before the user accepts a wallet_watchAsset request add the NFT to pre-change chain ID and address ([#19629](https://github.com/MetaMask/metamask-extension/pull/19629)) +- Fix performance degradations noticable on Firefox builds ([#19993](https://github.com/MetaMask/metamask-extension/pull/19993)) +- Fix copy to clipboard of public address, so that it is only cleared from the clipboard after 60 seconds ([#19948](https://github.com/MetaMask/metamask-extension/pull/19948)) +- Fix overlapping text, in some language, in home screen buttons ([#19920](https://github.com/MetaMask/metamask-extension/pull/19920)) + + ## [10.33.1] ### Fixed - Fix to bug causing users to see an infinite spinner when signing typed messages. ([#19894](https://github.com/MetaMask/metamask-extension/pull/19894)) @@ -3829,7 +3858,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Uncategorized - Added the ability to restore accounts from seed words. -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.33.1...HEAD +[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.34.1...HEAD +[10.34.1]: https://github.com/MetaMask/metamask-extension/compare/v10.34.0...v10.34.1 +[10.34.0]: https://github.com/MetaMask/metamask-extension/compare/v10.33.1...v10.34.0 [10.33.1]: https://github.com/MetaMask/metamask-extension/compare/v10.33.0...v10.33.1 [10.33.0]: https://github.com/MetaMask/metamask-extension/compare/v10.32.0...v10.33.0 [10.32.0]: https://github.com/MetaMask/metamask-extension/compare/v10.31.1...v10.32.0 diff --git a/app/_locales/am/messages.json b/app/_locales/am/messages.json index 60a718372..5b90a71ff 100644 --- a/app/_locales/am/messages.json +++ b/app/_locales/am/messages.json @@ -545,9 +545,6 @@ "privateNetwork": { "message": "የግል አውታረ መረብ" }, - "queue": { - "message": "ወረፋ" - }, "readdToken": { "message": "በመለያ አማራጮችዎ ምናሌ ውስጥ ወደ “ተለዋጭ ስም አክል” በመግባት ለወደፊቱ ይህን ተለዋጭ ስም መልሰው ማከል ይችላሉ።" }, diff --git a/app/_locales/ar/messages.json b/app/_locales/ar/messages.json index cb243675e..0d7e27e52 100644 --- a/app/_locales/ar/messages.json +++ b/app/_locales/ar/messages.json @@ -557,9 +557,6 @@ "privateNetwork": { "message": "شبكة خاصة" }, - "queue": { - "message": "اللائحة" - }, "readdToken": { "message": "يمكنك إضافة هذه العملة الرمزية مرة أخرى في المستقبل من خلال الانتقال إلى \"إضافة عملة رمزية\" في قائمة خيارات الحسابات الخاصة بك." }, diff --git a/app/_locales/bg/messages.json b/app/_locales/bg/messages.json index cfa823034..81ea9db35 100644 --- a/app/_locales/bg/messages.json +++ b/app/_locales/bg/messages.json @@ -556,9 +556,6 @@ "privateNetwork": { "message": "Частна мрежа" }, - "queue": { - "message": "Опашка" - }, "readdToken": { "message": "Можете да добавите този жетон в бъдеще, като отидете на „Добавяне на жетон“ в менюто с опции на акаунти." }, diff --git a/app/_locales/bn/messages.json b/app/_locales/bn/messages.json index fa8fa73c7..e9fc84fe1 100644 --- a/app/_locales/bn/messages.json +++ b/app/_locales/bn/messages.json @@ -554,9 +554,6 @@ "privateNetwork": { "message": "ব্যক্তিগত নেটওয়ার্ক" }, - "queue": { - "message": "অপেক্ষমাণ" - }, "readdToken": { "message": "আপনি আপনার অ্যাকাউন্টস বিকল্পের মেনুতে \"টোকেনগুলি যোগ করুন\" এ গিয়ে ভবিষ্যতে আবার এই টোকেনটি যোগ করতে পারবেন। " }, diff --git a/app/_locales/ca/messages.json b/app/_locales/ca/messages.json index 9e5c4dcc0..b4863d54d 100644 --- a/app/_locales/ca/messages.json +++ b/app/_locales/ca/messages.json @@ -541,9 +541,6 @@ "privateNetwork": { "message": "Xarxa privada" }, - "queue": { - "message": "Cua" - }, "readdToken": { "message": "Pots tornar a afegir aquesta fitxa en el futur anant a \"Afegir fitxa\" al menu d'opcions dels teus comptes." }, diff --git a/app/_locales/da/messages.json b/app/_locales/da/messages.json index abe777d47..d4b56c806 100644 --- a/app/_locales/da/messages.json +++ b/app/_locales/da/messages.json @@ -541,9 +541,6 @@ "privateNetwork": { "message": "Privat netværk" }, - "queue": { - "message": "Kø" - }, "readdToken": { "message": "Du kan tilføje denne token i fremtiden, ved at gå til \"Tilføj token\" under dine valgmenuen for dine konti." }, diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index 70ca5538a..d7a90dc46 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -2753,9 +2753,6 @@ "publicAddress": { "message": "Öffentliche Adresse" }, - "queue": { - "message": "Warteschlange" - }, "queued": { "message": "In Warteschlange" }, diff --git a/app/_locales/el/messages.json b/app/_locales/el/messages.json index ce06907b2..af006198f 100644 --- a/app/_locales/el/messages.json +++ b/app/_locales/el/messages.json @@ -2753,9 +2753,6 @@ "publicAddress": { "message": "Δημόσια Διεύθυνση" }, - "queue": { - "message": "Ουρά" - }, "queued": { "message": "Σε Αναμονή" }, diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 328441d1e..81a89b0a6 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -153,9 +153,6 @@ "accountSelectionRequired": { "message": "You need to select an account!" }, - "activated": { - "message": "Active" - }, "active": { "message": "Active" }, @@ -249,6 +246,9 @@ "addFromAListOfPopularNetworks": { "message": "Add from a list of popular networks or add a network manually. Only interact with the entities you trust." }, + "addHardwareWallet": { + "message": "Add hardware wallet" + }, "addMemo": { "message": "Add memo" }, @@ -373,9 +373,6 @@ "message": "Allow $1 to withdraw and spend up to the following amount:", "description": "The url of the site that requested permission to 'withdraw and spend'" }, - "amlCompliance": { - "message": "AML/CFT Compliance" - }, "amount": { "message": "Amount" }, @@ -528,6 +525,9 @@ "message": "This is a beta version. Please report bugs $1", "description": "$1 represents the word 'here' in a hyperlink" }, + "betaMetamaskInstitutionalVersion": { + "message": "MetaMask Institutional Beta Version" + }, "betaMetamaskVersion": { "message": "MetaMask Beta Version" }, @@ -565,6 +565,30 @@ "blockaid": { "message": "Blockaid" }, + "blockaidDescriptionApproveFarming": { + "message": "If you approve this request, a third party known for scams might take all your assets." + }, + "blockaidDescriptionBlurFarming": { + "message": "If you approve this request, someone can steal your assets listed on Blur." + }, + "blockaidDescriptionMaliciousDomain": { + "message": "You're interacting with a malicious domain. If you approve this request, you might lose your assets." + }, + "blockaidDescriptionMightLoseAssets": { + "message": "If you approve this request, you might lose your assets." + }, + "blockaidDescriptionSeaportFarming": { + "message": "If you approve this request, someone can steal your assets listed on OpenSea." + }, + "blockaidDescriptionTransferFarming": { + "message": "If you approve this request, a third party known for scams will take all your assets." + }, + "blockaidTitleDeceptive": { + "message": "This is a deceptive request" + }, + "blockaidTitleSuspicious": { + "message": "This is a suspicious request" + }, "blockies": { "message": "Blockies" }, @@ -670,45 +694,9 @@ "close": { "message": "Close" }, - "codefiCompliance": { - "message": "Codefi Compliance" - }, "coingecko": { "message": "CoinGecko" }, - "complianceActivatedDesc": { - "message": "You can now use compliance in MetaMask Institutional. Receiving AML/CFT analysis within the confirmation screen on all the addresses you interact with." - }, - "complianceActivatedTitle": { - "message": "Your compliance feature is activated" - }, - "complianceBlurb0": { - "message": "DeFi raises AML/CFT risk for institutions, given the decentralised pools and pseudonymous counterparties." - }, - "complianceBlurb1": { - "message": "Codefi Compliance is the only product capable of running AML/CFT analysis on DeFi pools. This allows you to identify and avoid pools and counterparties that fail your risk setting." - }, - "complianceBlurbStep1": { - "message": "Sign up to Codefi Compliance below" - }, - "complianceBlurbStep2": { - "message": "Create an organisation" - }, - "complianceBlurbStep3": { - "message": "Create a project" - }, - "complianceBlurbStep4": { - "message": "Set your compliance settings" - }, - "complianceBlurbStep5": { - "message": "Click the \"Enable Compliance in MMI\" button" - }, - "complianceBlurpStep0": { - "message": "Steps to enable AML/CFT Compliance:" - }, - "complianceSettingsExplanation": { - "message": "Change your settings or view reports by opening up Codefi Compliance or disconnect below." - }, "configureSnapPopupDescription": { "message": "You're now leaving MetaMask to configure this snap." }, @@ -832,9 +820,6 @@ "connectingToSepolia": { "message": "Connecting to Sepolia test network" }, - "connectionError": { - "message": "Connection error" - }, "connectionFailed": { "message": "Connection failed" }, @@ -982,6 +967,12 @@ "custodianAccount": { "message": "Custodian account" }, + "custodianAccountAddedDesc": { + "message": "You can now use your custodian accounts in MetaMask Institutional." + }, + "custodianAccountAddedTitle": { + "message": "Selected custodian accounts have been added." + }, "custodianReplaceRefreshTokenChangedFailed": { "message": "Please go to $1 and click the 'Connect to MMI' button within their user interface to connect your accounts to MMI again." }, @@ -1749,9 +1740,6 @@ "hardware": { "message": "Hardware" }, - "hardwareWallet": { - "message": "Hardware wallet" - }, "hardwareWalletConnected": { "message": "Hardware wallet connected" }, @@ -1765,8 +1753,11 @@ "hardwareWallets": { "message": "Connect a hardware wallet" }, + "hardwareWalletsInfo": { + "message": "Hardware wallet integrations use API calls to external servers, which can see your IP address and the smart contract addresses you interact with." + }, "hardwareWalletsMsg": { - "message": "Select a hardware wallet you'd like to use with MetaMask." + "message": "Select a hardware wallet you would like to use with MetaMask." }, "here": { "message": "here", @@ -1965,9 +1956,6 @@ "message": "Installed on $1", "description": "$1 is the date when the snap has been installed" }, - "institutionalFeatures": { - "message": "Institutional Features" - }, "insufficientBalance": { "message": "Insufficient balance." }, @@ -2262,6 +2250,9 @@ "metaMaskConnectStatusParagraphTwo": { "message": "The connection status button shows if the website you’re visiting is connected to your currently selected account." }, + "metamaskInstitutionalVersion": { + "message": "MetaMask Institutional Version" + }, "metamaskSwapsOfflineDescription": { "message": "MetaMask Swaps is undergoing maintenance. Please check back later." }, @@ -2303,8 +2294,8 @@ "mmiAddToken": { "message": "The page at $1 would like to authorise the following custodian token in MetaMask Institutional" }, - "mmiAuthenticate": { - "message": "The page at $1 would like to authorise the following project’s compliance settings in MetaMask Institutional" + "mmiBuiltAroundTheWorld": { + "message": "MetaMask Institutional is designed and built around the world." }, "more": { "message": "more" @@ -2529,9 +2520,6 @@ "noNFTs": { "message": "No NFTs yet" }, - "noReport": { - "message": "No Report" - }, "noSnaps": { "message": "You don't have any snaps installed." }, @@ -2973,9 +2961,6 @@ "onlyConnectTrust": { "message": "Only connect with sites you trust." }, - "openCodefiCompliance": { - "message": "Open Codefi Compliance" - }, "openFullScreenForLedgerWebHid": { "message": "Go to full screen to connect your Ledger.", "description": "Shown to the user on the confirm screen when they are viewing MetaMask in a popup window but need to connect their ledger via webhid." @@ -3071,9 +3056,6 @@ "message": "You have (1) pending transaction.", "description": "$1 is count of pending transactions" }, - "percentage": { - "message": "$1%" - }, "permissionRequest": { "message": "Permission request" }, @@ -3266,9 +3248,6 @@ "portfolioDashboard": { "message": "Portfolio Dashboard" }, - "portfolioView": { - "message": "Portfolio view" - }, "preferredLedgerConnectionType": { "message": "Preferred Ledger connection type", "description": "A header for a dropdown in Settings > Advanced. Appears above the ledgerConnectionPreferenceDescription message" @@ -3314,12 +3293,6 @@ "proceedWithTransaction": { "message": "I want to proceed anyway" }, - "projectIdInvalid": { - "message": "Provided Project ID is invalid" - }, - "projectName": { - "message": "Project Name" - }, "proposedApprovalLimit": { "message": "Proposed approval limit" }, @@ -3329,9 +3302,6 @@ "publicAddress": { "message": "Public address" }, - "queue": { - "message": "Queue" - }, "queued": { "message": "Queued" }, @@ -3441,12 +3411,6 @@ "replace": { "message": "replace" }, - "reportLastRun": { - "message": "Report last run" - }, - "reportLastRunTooltip": { - "message": "The date and time of when the last AML/CFT report was run" - }, "requestFlaggedAsMaliciousFallbackCopyReason": { "message": "The security provider has not shared additional details" }, @@ -3504,6 +3468,18 @@ "restoreUserDataDescription": { "message": "You can restore user settings containing preferences and account addresses from a previously backed up JSON file." }, + "resultPageError": { + "message": "Error" + }, + "resultPageErrorDefaultMessage": { + "message": "The operation failed." + }, + "resultPageSuccess": { + "message": "Success" + }, + "resultPageSuccessDefaultMessage": { + "message": "The operation completed successfully." + }, "retryTransaction": { "message": "Retry transaction" }, @@ -3573,18 +3549,9 @@ "revokeSpendingCapTooltipText": { "message": "This third party will be unable to spend any more of your current or future tokens." }, - "riskRating": { - "message": "Risk rating" - }, - "riskRatingTooltip": { - "message": "The risk rating of the address you are interacting with based on your risk settings" - }, "rpcUrl": { "message": "New RPC URL" }, - "runReport": { - "message": "Run report" - }, "safeTransferFrom": { "message": "Safe transfer from" }, @@ -3624,9 +3591,25 @@ "securityAlert": { "message": "Security alert from $1 and $2" }, + "securityAlerts": { + "message": "Security alerts" + }, + "securityAlertsDescription1": { + "message": "Enable this to have your transactions and signature requests reviewed locally (no data shared with third parties) and warnings displayed when malicious activity is detected." + }, + "securityAlertsDescription2": { + "message": "Always be sure to do your own due diligence before approving any requests. There's no guarantee all mailcious activity will be detected by this feature." + }, "securityAndPrivacy": { "message": "Security & privacy" }, + "securityProviderAdviceBy": { + "message": "Security advice by $1", + "description": "The security provider that is providing data" + }, + "seeDetails": { + "message": "See details" + }, "seedPhraseConfirm": { "message": "Confirm Secret Recovery Phrase" }, @@ -3809,9 +3792,6 @@ "showPrivateKeys": { "message": "Show Private Keys" }, - "showReport": { - "message": "Show report" - }, "showTestnetNetworks": { "message": "Show test networks" }, @@ -4442,6 +4422,10 @@ "message": "Includes a $1% MetaMask fee.", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number." }, + "swapIncludesMetaMaskFeeViewAllQuotes": { + "message": "Includes a $1% MetaMask fee – $2", + "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number and $2 is a link to view all quotes." + }, "swapLearnMore": { "message": "Learn more about Swaps" }, @@ -5206,6 +5190,9 @@ "viewAllDetails": { "message": "View all details" }, + "viewAllQuotes": { + "message": "view all quotes" + }, "viewContact": { "message": "View contact" }, diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index 71a4b61ec..22f8a2071 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -2753,9 +2753,6 @@ "publicAddress": { "message": "Dirección pública" }, - "queue": { - "message": "Cola" - }, "queued": { "message": "En cola" }, diff --git a/app/_locales/es_419/messages.json b/app/_locales/es_419/messages.json index 7628f9c7a..74d738b6e 100644 --- a/app/_locales/es_419/messages.json +++ b/app/_locales/es_419/messages.json @@ -1767,9 +1767,6 @@ "publicAddress": { "message": "Dirección pública" }, - "queue": { - "message": "Cola" - }, "queued": { "message": "En cola" }, diff --git a/app/_locales/et/messages.json b/app/_locales/et/messages.json index cc92f0f26..daaa5789a 100644 --- a/app/_locales/et/messages.json +++ b/app/_locales/et/messages.json @@ -550,9 +550,6 @@ "privateNetwork": { "message": "Privaatvõrk" }, - "queue": { - "message": "Järjekord" - }, "readdToken": { "message": "Saate selle loa tulevikus tagasi lisada, kui lähete oma kontovalikute menüüs vahelehele „Lisa luba“." }, diff --git a/app/_locales/fa/messages.json b/app/_locales/fa/messages.json index c94f0efef..7745c6653 100644 --- a/app/_locales/fa/messages.json +++ b/app/_locales/fa/messages.json @@ -560,9 +560,6 @@ "privateNetwork": { "message": "شبکه شخصی" }, - "queue": { - "message": "صف" - }, "readdToken": { "message": "شما میتوانید این رمزیاب را دوباره برای آینده با رفتن به گزینه \"Add token\" در مینوی تنظیمات حساب ها، اضافه نمایید." }, diff --git a/app/_locales/fi/messages.json b/app/_locales/fi/messages.json index 788eda6b4..a8ba1bdf8 100644 --- a/app/_locales/fi/messages.json +++ b/app/_locales/fi/messages.json @@ -557,9 +557,6 @@ "privateNetwork": { "message": "Yksityinen verkko" }, - "queue": { - "message": "Jono" - }, "readdToken": { "message": "Voit lisätä tämän tietueen myöhemmin takaisin siirtymällä tilisi vaihtoehtovalikon kohtaan ”Lisää tietue”." }, diff --git a/app/_locales/fil/messages.json b/app/_locales/fil/messages.json index 462856836..bda447cd7 100644 --- a/app/_locales/fil/messages.json +++ b/app/_locales/fil/messages.json @@ -484,9 +484,6 @@ "privateNetwork": { "message": "Pribadong Network" }, - "queue": { - "message": "I-queue" - }, "readdToken": { "message": "Puwede mong idagdag ulit ang token na ito sa hinaharap sa pamamagitan ng pagpunta sa “Magdagdag ng token” sa menu ng mga opsyon ng iyong mga accounts." }, diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index ca36fd57d..a8974ea1d 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -2753,9 +2753,6 @@ "publicAddress": { "message": "Adresse publique" }, - "queue": { - "message": "File d’attente" - }, "queued": { "message": "En attente" }, diff --git a/app/_locales/gu/messages.json b/app/_locales/gu/messages.json index 91c0cb076..ab3318667 100644 --- a/app/_locales/gu/messages.json +++ b/app/_locales/gu/messages.json @@ -103,9 +103,6 @@ "password": { "message": "પાસવર્ડ" }, - "queue": { - "message": "કતારમાં" - }, "reject": { "message": "નકારો" }, diff --git a/app/_locales/he/messages.json b/app/_locales/he/messages.json index ad633a3e5..8d1edf21e 100644 --- a/app/_locales/he/messages.json +++ b/app/_locales/he/messages.json @@ -557,9 +557,6 @@ "privateNetwork": { "message": "רשת פרטית" }, - "queue": { - "message": "תור" - }, "readdToken": { "message": "באפשרותך להוסיף טוקן זה בחזרה בעתיד על ידי מעבר אל \"הוסף טוקן\" בתפריט אפשרויות החשבונות שלך." }, diff --git a/app/_locales/hi/messages.json b/app/_locales/hi/messages.json index 446767290..b0ffcb805 100644 --- a/app/_locales/hi/messages.json +++ b/app/_locales/hi/messages.json @@ -2753,9 +2753,6 @@ "publicAddress": { "message": "सार्वजनिक पता" }, - "queue": { - "message": "कतार" - }, "queued": { "message": "कतारबद्ध" }, diff --git a/app/_locales/hr/messages.json b/app/_locales/hr/messages.json index aa2eeb937..ecec0755d 100644 --- a/app/_locales/hr/messages.json +++ b/app/_locales/hr/messages.json @@ -553,9 +553,6 @@ "privateNetwork": { "message": "Privatna mreža" }, - "queue": { - "message": "Red čekanja" - }, "readdToken": { "message": "Ovaj token možete dodati kasnije odlaskom pod stavku „Dodaj token” u izborniku mogućnosti računa. " }, diff --git a/app/_locales/hu/messages.json b/app/_locales/hu/messages.json index 09489674a..428077773 100644 --- a/app/_locales/hu/messages.json +++ b/app/_locales/hu/messages.json @@ -553,9 +553,6 @@ "privateNetwork": { "message": "Magánhálózat" }, - "queue": { - "message": "Nyomtatólista" - }, "readdToken": { "message": "Ezt a tokent a jövőben is hozzáadhatja, ha a fiókbeállítások menü „Token hozzáadása” elemére lép." }, diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json index 65fe2d24f..cf38c0ad8 100644 --- a/app/_locales/id/messages.json +++ b/app/_locales/id/messages.json @@ -2753,9 +2753,6 @@ "publicAddress": { "message": "Alamat publik" }, - "queue": { - "message": "Antrean" - }, "queued": { "message": "Antrean" }, diff --git a/app/_locales/it/messages.json b/app/_locales/it/messages.json index 4109f6831..05b14eaaf 100644 --- a/app/_locales/it/messages.json +++ b/app/_locales/it/messages.json @@ -1301,9 +1301,6 @@ "provide": { "message": "Fornisci" }, - "queue": { - "message": "Coda" - }, "queued": { "message": "In coda" }, diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index 715248ca8..f9738e5a1 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -2753,9 +2753,6 @@ "publicAddress": { "message": "パブリックアドレス" }, - "queue": { - "message": "キュー" - }, "queued": { "message": "キュー待ち" }, diff --git a/app/_locales/kn/messages.json b/app/_locales/kn/messages.json index 7458ec831..64a3052ee 100644 --- a/app/_locales/kn/messages.json +++ b/app/_locales/kn/messages.json @@ -560,9 +560,6 @@ "privateNetwork": { "message": "ಖಾಸಗಿ ನೆಟ್‌ವರ್ಕ್" }, - "queue": { - "message": "ಸರತಿ" - }, "readdToken": { "message": "ನಿಮ್ಮ ಖಾತೆಗಳ ಆಯ್ಕೆಗಳ ಮೆನುವಿನಲ್ಲಿ \"ಟೋಕನ್ ಸೇರಿಸು\" ಗೆ ಹೋಗುವ ಮೂಲಕ ನೀವು ಈ ಟೋಕನ್ ಅನ್ನು ಭವಿಷ್ಯದಲ್ಲಿ ಮರಳಿ ಸೇರಿಸಬಹುದು." }, diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index a214b7805..f45b9eca4 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -2753,9 +2753,6 @@ "publicAddress": { "message": "공개 주소" }, - "queue": { - "message": "대기열" - }, "queued": { "message": "대기열에 지정됨" }, diff --git a/app/_locales/lt/messages.json b/app/_locales/lt/messages.json index ed49b566b..f776afc2e 100644 --- a/app/_locales/lt/messages.json +++ b/app/_locales/lt/messages.json @@ -560,9 +560,6 @@ "privateNetwork": { "message": "Privatus tinklas" }, - "queue": { - "message": "Eilė" - }, "readdToken": { "message": "Šį žetoną galite bet kada galite įtraukti ir vėl, tiesiog savo paskyros parinkčių meniu nueikite į „Įtraukti žetoną“." }, diff --git a/app/_locales/lv/messages.json b/app/_locales/lv/messages.json index 231a48fc9..d3d35c00f 100644 --- a/app/_locales/lv/messages.json +++ b/app/_locales/lv/messages.json @@ -556,9 +556,6 @@ "privateNetwork": { "message": "Privātais tīkls" }, - "queue": { - "message": "Rinda" - }, "readdToken": { "message": "Jūs varat šo marķieri iestatīt atpakaļ nākotnē, konta opciju izvēlnē atverot \"Pievienot marķieri\"." }, diff --git a/app/_locales/ml/messages.json b/app/_locales/ml/messages.json index 0ee00d08f..e98b78f7b 100644 --- a/app/_locales/ml/messages.json +++ b/app/_locales/ml/messages.json @@ -103,9 +103,6 @@ "password": { "message": "പാസ്‌വേഡ്" }, - "queue": { - "message": "ക്യൂവിൽ" - }, "reject": { "message": "നിരസിക്കുക" }, diff --git a/app/_locales/mr/messages.json b/app/_locales/mr/messages.json index 5f19a2772..3ab6f88b3 100644 --- a/app/_locales/mr/messages.json +++ b/app/_locales/mr/messages.json @@ -103,9 +103,6 @@ "password": { "message": "पासवर्ड" }, - "queue": { - "message": "रांग" - }, "reject": { "message": "नाकारा" }, diff --git a/app/_locales/ms/messages.json b/app/_locales/ms/messages.json index c5e44b81d..86464cf6e 100644 --- a/app/_locales/ms/messages.json +++ b/app/_locales/ms/messages.json @@ -540,9 +540,6 @@ "privateNetwork": { "message": "Rangkaian Persendirian" }, - "queue": { - "message": "Baris Gilir" - }, "readdToken": { "message": "Anda boleh tambah token ini kembali pada masa depan dengan pergi ke \"Tambah token\" di dalam menu pilihan akaun anda." }, diff --git a/app/_locales/no/messages.json b/app/_locales/no/messages.json index 261ab1846..a575ffdcb 100644 --- a/app/_locales/no/messages.json +++ b/app/_locales/no/messages.json @@ -544,9 +544,6 @@ "privateNetwork": { "message": "Privat nettverk " }, - "queue": { - "message": "Kø" - }, "readdToken": { "message": "Du kan legge til dette tokenet igjen i fremtiden ved å gå til \"Legg til token\" i menyen for kontoalternativer." }, diff --git a/app/_locales/ph/messages.json b/app/_locales/ph/messages.json index f69ae1563..1a2f9ff87 100644 --- a/app/_locales/ph/messages.json +++ b/app/_locales/ph/messages.json @@ -1105,9 +1105,6 @@ "publicAddress": { "message": "Pampublikong Address" }, - "queue": { - "message": "Queue" - }, "queued": { "message": "Naka-queue" }, diff --git a/app/_locales/pl/messages.json b/app/_locales/pl/messages.json index e42eea2ae..b595f5322 100644 --- a/app/_locales/pl/messages.json +++ b/app/_locales/pl/messages.json @@ -554,9 +554,6 @@ "privateNetwork": { "message": "Sieć prywatna" }, - "queue": { - "message": "Kolejka" - }, "readdToken": { "message": "Możesz później ponownie dodać ten token poprzez \"Dodaj token\" w opcjach menu swojego konta." }, diff --git a/app/_locales/pt/messages.json b/app/_locales/pt/messages.json index 00c39a066..85e6744f6 100644 --- a/app/_locales/pt/messages.json +++ b/app/_locales/pt/messages.json @@ -2753,9 +2753,6 @@ "publicAddress": { "message": "Endereço público" }, - "queue": { - "message": "Fila" - }, "queued": { "message": "Na fila" }, diff --git a/app/_locales/pt_BR/messages.json b/app/_locales/pt_BR/messages.json index cb2c55d69..3ddc1aa19 100644 --- a/app/_locales/pt_BR/messages.json +++ b/app/_locales/pt_BR/messages.json @@ -1767,9 +1767,6 @@ "publicAddress": { "message": "Endereço público" }, - "queue": { - "message": "Fila" - }, "queued": { "message": "Na fila" }, diff --git a/app/_locales/pt_PT/messages.json b/app/_locales/pt_PT/messages.json index ba2364c6f..ee84964d5 100644 --- a/app/_locales/pt_PT/messages.json +++ b/app/_locales/pt_PT/messages.json @@ -113,9 +113,6 @@ "privacyMsg": { "message": "Política de Privacidade" }, - "queue": { - "message": "Fila" - }, "reject": { "message": "Rejeitar" }, diff --git a/app/_locales/ro/messages.json b/app/_locales/ro/messages.json index 1fa0e9d71..5788f8b07 100644 --- a/app/_locales/ro/messages.json +++ b/app/_locales/ro/messages.json @@ -547,9 +547,6 @@ "privateNetwork": { "message": "Rețea privată" }, - "queue": { - "message": "Coadă" - }, "readdToken": { "message": "Puteți adăuga din nou acest indicativ în viitor accesând „Adăugați indicativ” din meniul de opțiuni al contului dvs." }, diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index fb8a915ef..a72f54a58 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -2753,9 +2753,6 @@ "publicAddress": { "message": "Открытый адрес" }, - "queue": { - "message": "Очередь" - }, "queued": { "message": "В очереди" }, diff --git a/app/_locales/sk/messages.json b/app/_locales/sk/messages.json index bed99df90..21c7a8f9e 100644 --- a/app/_locales/sk/messages.json +++ b/app/_locales/sk/messages.json @@ -532,9 +532,6 @@ "privateNetwork": { "message": "Soukromá síť" }, - "queue": { - "message": "Poradie" - }, "readdToken": { "message": "Tento token můžete v budoucnu přidat zpět s „Přidat token“ v nastavení účtu." }, diff --git a/app/_locales/sl/messages.json b/app/_locales/sl/messages.json index b4e5faf7e..e041577a2 100644 --- a/app/_locales/sl/messages.json +++ b/app/_locales/sl/messages.json @@ -548,9 +548,6 @@ "privateNetwork": { "message": "Zasebno omrežje" }, - "queue": { - "message": "Čakalna vrsta" - }, "readdToken": { "message": "Ta žeton lahko dodate tudi kasneje z uporabo gumba “Dodaj žeton” v možnostih vašega računa." }, diff --git a/app/_locales/sr/messages.json b/app/_locales/sr/messages.json index 999f01d20..db06d7a5c 100644 --- a/app/_locales/sr/messages.json +++ b/app/_locales/sr/messages.json @@ -551,9 +551,6 @@ "privateNetwork": { "message": "Privatna mreža" }, - "queue": { - "message": "Ред" - }, "readdToken": { "message": "U budućnosti možete vratiti ovaj token tako što ćete otvoriti „Dodaj token“ u meniju opcija vašeg naloga." }, diff --git a/app/_locales/sv/messages.json b/app/_locales/sv/messages.json index 283a0f3ad..4c07edfb9 100644 --- a/app/_locales/sv/messages.json +++ b/app/_locales/sv/messages.json @@ -544,9 +544,6 @@ "privateNetwork": { "message": "Privat nätverk" }, - "queue": { - "message": "Utskriftskö" - }, "readdToken": { "message": "Du kan lägga till denna token i framtiden genom att välja \"Lägg till token\" i kontots alternativmeny." }, diff --git a/app/_locales/sw/messages.json b/app/_locales/sw/messages.json index 7949db571..e8921b243 100644 --- a/app/_locales/sw/messages.json +++ b/app/_locales/sw/messages.json @@ -538,9 +538,6 @@ "privateNetwork": { "message": "Mtandao Binafsi" }, - "queue": { - "message": "Foleni" - }, "readdToken": { "message": "Unaweza kuongeza tena kianzio hiki hapo baadaye kwa kwenda kwenye \"Ongeza kianzio\" kwenye machaguo yako ya menyu ya akaunti." }, diff --git a/app/_locales/ta/messages.json b/app/_locales/ta/messages.json index 2282edccb..eb6f2c499 100644 --- a/app/_locales/ta/messages.json +++ b/app/_locales/ta/messages.json @@ -322,9 +322,6 @@ "privateNetwork": { "message": "தனியார் நெட்வொர்க்" }, - "queue": { - "message": "வரிசை" - }, "readdToken": { "message": "உங்கள் கணக்கு விருப்பங்கள் மெனுவில் \"டோக்கனைச் சேர்\" என்பதன் மூலம் நீங்கள் எதிர்காலத்தில் இந்த டோக்கனை மீண்டும் சேர்க்கலாம்." }, diff --git a/app/_locales/te/messages.json b/app/_locales/te/messages.json index dee823b90..8a49e48b1 100644 --- a/app/_locales/te/messages.json +++ b/app/_locales/te/messages.json @@ -103,9 +103,6 @@ "password": { "message": "పాస్‌వర్డ్" }, - "queue": { - "message": "క్రమ వరుస" - }, "reject": { "message": "తిరస్కరించు" }, diff --git a/app/_locales/tl/messages.json b/app/_locales/tl/messages.json index f4877ea06..9203fa22b 100644 --- a/app/_locales/tl/messages.json +++ b/app/_locales/tl/messages.json @@ -2753,9 +2753,6 @@ "publicAddress": { "message": "Pampublikong Address" }, - "queue": { - "message": "Pila" - }, "queued": { "message": "Naka-queue" }, diff --git a/app/_locales/tr/messages.json b/app/_locales/tr/messages.json index 842dc5096..9a6f53aad 100644 --- a/app/_locales/tr/messages.json +++ b/app/_locales/tr/messages.json @@ -2753,9 +2753,6 @@ "publicAddress": { "message": "Genel adres" }, - "queue": { - "message": "Kuyruğa al" - }, "queued": { "message": "Kuyruğa alındı" }, diff --git a/app/_locales/uk/messages.json b/app/_locales/uk/messages.json index e7b83ffc6..3f4fb4f24 100644 --- a/app/_locales/uk/messages.json +++ b/app/_locales/uk/messages.json @@ -560,9 +560,6 @@ "privateNetwork": { "message": "Приватна мережа" }, - "queue": { - "message": "Черга" - }, "readdToken": { "message": "Ви можете знову додати цей токен у меню облікового запису у розділі “Додати токен”. " }, diff --git a/app/_locales/vi/messages.json b/app/_locales/vi/messages.json index 5c11445e5..4cee139f5 100644 --- a/app/_locales/vi/messages.json +++ b/app/_locales/vi/messages.json @@ -2753,9 +2753,6 @@ "publicAddress": { "message": "Địa chỉ công khai" }, - "queue": { - "message": "Hàng đợi" - }, "queued": { "message": "Đã đưa vào hàng đợi" }, diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index 58f7ffa97..c36fcce77 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -2753,9 +2753,6 @@ "publicAddress": { "message": "公共地址" }, - "queue": { - "message": "队列" - }, "queued": { "message": "队列中" }, diff --git a/app/_locales/zh_TW/messages.json b/app/_locales/zh_TW/messages.json index 27260c920..c1f1b9e65 100644 --- a/app/_locales/zh_TW/messages.json +++ b/app/_locales/zh_TW/messages.json @@ -1051,9 +1051,6 @@ "publicAddress": { "message": "公開位址" }, - "queue": { - "message": "佇列" - }, "queued": { "message": "已排入佇列" }, diff --git a/app/build-types/mmi/images/compliance-logo-small.svg b/app/build-types/mmi/images/compliance-logo-small.svg deleted file mode 100644 index 560b0b2a9..000000000 --- a/app/build-types/mmi/images/compliance-logo-small.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/app/build-types/mmi/images/compliance-logo.png b/app/build-types/mmi/images/compliance-logo.png deleted file mode 100644 index 23250fd4a..000000000 Binary files a/app/build-types/mmi/images/compliance-logo.png and /dev/null differ diff --git a/app/build-types/mmi/images/icons/compliance.svg b/app/build-types/mmi/images/icons/compliance.svg deleted file mode 100644 index 9269d3afb..000000000 --- a/app/build-types/mmi/images/icons/compliance.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - \ No newline at end of file diff --git a/app/images/gnosis.svg b/app/images/gnosis.svg new file mode 100644 index 000000000..ce0ed2045 --- /dev/null +++ b/app/images/gnosis.svg @@ -0,0 +1,47 @@ + + + +Created with Fabric.js 5.2.4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/images/icons/check-bold.svg b/app/images/icons/check-bold.svg new file mode 100644 index 000000000..a011e3386 --- /dev/null +++ b/app/images/icons/check-bold.svg @@ -0,0 +1 @@ + diff --git a/app/images/icons/minus-bold.svg b/app/images/icons/minus-bold.svg new file mode 100644 index 000000000..16026831c --- /dev/null +++ b/app/images/icons/minus-bold.svg @@ -0,0 +1 @@ + diff --git a/app/manifest/v2/chrome.json b/app/manifest/v2/chrome.json index a152130d8..10de9fdf6 100644 --- a/app/manifest/v2/chrome.json +++ b/app/manifest/v2/chrome.json @@ -1,5 +1,5 @@ { - "content_security_policy": "frame-ancestors 'none'; script-src 'self'; object-src 'self'", + "content_security_policy": "frame-ancestors 'none'; script-src 'self' 'wasm-unsafe-eval'; object-src 'self'", "externally_connectable": { "matches": ["https://metamask.io/*"], "ids": ["*"] diff --git a/app/scripts/controllers/incoming-transactions.js b/app/scripts/controllers/incoming-transactions.js index 987f0d87b..9b0b85f33 100644 --- a/app/scripts/controllers/incoming-transactions.js +++ b/app/scripts/controllers/incoming-transactions.js @@ -135,15 +135,12 @@ export default class IncomingTransactionsController { } start() { - const { featureFlags = {} } = this.preferencesController.store.getState(); - const { showIncomingTransactions } = featureFlags; + const chainId = this.getCurrentChainId(); - if (!showIncomingTransactions) { - return; + if (this._allowedToMakeFetchIncomingTx(chainId)) { + this.blockTracker.removeListener('latest', this._onLatestBlock); + this.blockTracker.addListener('latest', this._onLatestBlock); } - - this.blockTracker.removeListener('latest', this._onLatestBlock); - this.blockTracker.addListener('latest', this._onLatestBlock); } stop() { @@ -161,13 +158,9 @@ export default class IncomingTransactionsController { * @param {number} [newBlockNumberDec] - block number to begin fetching from */ async _update(address, newBlockNumberDec) { - const { completedOnboarding } = this.onboardingController.store.getState(); const chainId = this.getCurrentChainId(); - if ( - !Object.hasOwnProperty.call(ETHERSCAN_SUPPORTED_NETWORKS, chainId) || - !address || - !completedOnboarding - ) { + + if (!address || !this._allowedToMakeFetchIncomingTx(chainId)) { return; } try { @@ -302,4 +295,26 @@ export default class IncomingTransactionsController { type: TransactionType.incoming, }; } + + /** + * @param chainId - {string} The chainId of the current network + * @returns {boolean} Whether or not the user has consented to show incoming transactions + */ + _allowedToMakeFetchIncomingTx(chainId) { + const { featureFlags = {} } = this.preferencesController.store.getState(); + const { completedOnboarding } = this.onboardingController.store.getState(); + + const hasIncomingTransactionsFeatureEnabled = Boolean( + featureFlags.showIncomingTransactions, + ); + + const isEtherscanSupportedNetwork = Boolean( + ETHERSCAN_SUPPORTED_NETWORKS[chainId], + ); + return ( + completedOnboarding && + isEtherscanSupportedNetwork && + hasIncomingTransactionsFeatureEnabled + ); + } } diff --git a/app/scripts/controllers/incoming-transactions.test.js b/app/scripts/controllers/incoming-transactions.test.js index bdfac55a7..c46c3190b 100644 --- a/app/scripts/controllers/incoming-transactions.test.js +++ b/app/scripts/controllers/incoming-transactions.test.js @@ -78,11 +78,11 @@ function getMockPreferencesController({ }; } -function getMockOnboardingController() { +function getMockOnboardingController({ completedOnboarding = true } = {}) { return { store: { getState: sinon.stub().returns({ - completedOnboarding: true, + completedOnboarding, }), subscribe: sinon.spy(), }, @@ -98,6 +98,16 @@ function getMockBlockTracker() { }; } +function getDefaultControllerOpts() { + return { + blockTracker: getMockBlockTracker(), + ...getMockNetworkControllerMethods(CHAIN_IDS.GOERLI), + preferencesController: getMockPreferencesController(), + onboardingController: getMockOnboardingController(), + initState: getEmptyInitState(), + }; +} + /** * @typedef {import( * '../../../../app/scripts/controllers/incoming-transactions' @@ -226,6 +236,7 @@ describe('IncomingTransactionsController', function () { preferencesController: getMockPreferencesController(), onboardingController: getMockOnboardingController(), initState: {}, + getCurrentChainId: () => CHAIN_IDS.GOERLI, }, ); @@ -831,6 +842,97 @@ describe('IncomingTransactionsController', function () { }); }); + describe('block explorer lookup', function () { + let sandbox; + + beforeEach(function () { + sandbox = sinon.createSandbox(); + }); + + afterEach(function () { + sandbox.restore(); + }); + + function stubFetch() { + return sandbox.stub(window, 'fetch'); + } + + function assertStubNotCalled(stub) { + assert(stub.callCount === 0); + } + + async function triggerUpdate(incomingTransactionsController) { + const subscription = + incomingTransactionsController.preferencesController.store.subscribe.getCall( + 1, + ).args[0]; + + // Sets address causing a call to _update + await subscription({ selectedAddress: MOCK_SELECTED_ADDRESS }); + } + + it('should not happen when incoming transactions feature is disabled', async function () { + const incomingTransactionsController = new IncomingTransactionsController( + { + ...getDefaultControllerOpts(), + preferencesController: getMockPreferencesController({ + showIncomingTransactions: false, + }), + }, + ); + const fetchStub = stubFetch(); + await triggerUpdate(incomingTransactionsController); + assertStubNotCalled(fetchStub); + }); + + it('should not happen when onboarding is in progress', async function () { + const incomingTransactionsController = new IncomingTransactionsController( + { + ...getDefaultControllerOpts(), + onboardingController: getMockOnboardingController({ + completedOnboarding: false, + }), + }, + ); + + const fetchStub = stubFetch(); + await triggerUpdate(incomingTransactionsController); + assertStubNotCalled(fetchStub); + }); + + it('should not happen when chain id is not supported', async function () { + const incomingTransactionsController = new IncomingTransactionsController( + { + ...getDefaultControllerOpts(), + getCurrentChainId: () => FAKE_CHAIN_ID, + }, + ); + + const fetchStub = stubFetch(); + await triggerUpdate(incomingTransactionsController); + assertStubNotCalled(fetchStub); + }); + + it('should make api call when chain id, incoming features, and onboarding status are ok', async function () { + const incomingTransactionsController = new IncomingTransactionsController( + { + ...getDefaultControllerOpts(), + getCurrentChainId: () => CHAIN_IDS.GOERLI, + onboardingController: getMockOnboardingController({ + completedOnboarding: true, + }), + preferencesController: getMockPreferencesController({ + showIncomingTransactions: true, + }), + }, + ); + + const fetchStub = stubFetch(); + await triggerUpdate(incomingTransactionsController); + assert(fetchStub.callCount === 1); + }); + }); + describe('_update', function () { describe('when state is empty (initialized)', function () { it('should use provided block number and update the latest block seen', async function () { diff --git a/app/scripts/controllers/metametrics.js b/app/scripts/controllers/metametrics.js index 6de45393f..b5ef191fc 100644 --- a/app/scripts/controllers/metametrics.js +++ b/app/scripts/controllers/metametrics.js @@ -425,8 +425,12 @@ export default class MetaMetricsController { setParticipateInMetaMetrics(participateInMetaMetrics) { let { metaMetricsId } = this.state; if (participateInMetaMetrics && !metaMetricsId) { + // We also need to start sentry automatic session tracking at this point + globalThis.sentry?.startSession(); metaMetricsId = this.generateMetaMetricsId(); } else if (participateInMetaMetrics === false) { + // We also need to stop sentry automatic session tracking at this point + globalThis.sentry?.endSession(); metaMetricsId = null; } this.store.updateState({ participateInMetaMetrics, metaMetricsId }); diff --git a/app/scripts/controllers/metametrics.test.js b/app/scripts/controllers/metametrics.test.js index e881f4772..ceab26a5a 100644 --- a/app/scripts/controllers/metametrics.test.js +++ b/app/scripts/controllers/metametrics.test.js @@ -146,6 +146,14 @@ describe('MetaMetricsController', function () { const now = new Date(); let clock; beforeEach(function () { + globalThis.sentry = { + startSession: sinon.fake(() => { + /** NOOP */ + }), + endSession: sinon.fake(() => { + /** NOOP */ + }), + }; clock = sinon.useFakeTimers(now.getTime()); sinon.stub(Utils, 'generateRandomId').returns('DUMMY_RANDOM_ID'); }); @@ -312,6 +320,7 @@ describe('MetaMetricsController', function () { }); assert.equal(metaMetricsController.state.participateInMetaMetrics, null); metaMetricsController.setParticipateInMetaMetrics(true); + assert.ok(globalThis.sentry.startSession.calledOnce); assert.equal(metaMetricsController.state.participateInMetaMetrics, true); metaMetricsController.setParticipateInMetaMetrics(false); assert.equal(metaMetricsController.state.participateInMetaMetrics, false); @@ -328,6 +337,7 @@ describe('MetaMetricsController', function () { it('should nullify the metaMetricsId when set to false', function () { const metaMetricsController = getMetaMetricsController(); metaMetricsController.setParticipateInMetaMetrics(false); + assert.ok(globalThis.sentry.endSession.calledOnce); assert.equal(metaMetricsController.state.metaMetricsId, null); }); }); diff --git a/app/scripts/controllers/mmi-controller.js b/app/scripts/controllers/mmi-controller.js index 8923487b5..bfc44a796 100644 --- a/app/scripts/controllers/mmi-controller.js +++ b/app/scripts/controllers/mmi-controller.js @@ -2,10 +2,6 @@ import EventEmitter from 'events'; import log from 'loglevel'; import { captureException } from '@sentry/browser'; import { isEqual } from 'lodash'; -import { - PersonalMessageManager, - TypedMessageManager, -} from '@metamask/message-manager'; import { CUSTODIAN_TYPES } from '@metamask-institutional/custody-keyring'; import { updateCustodianTransactions, @@ -48,20 +44,10 @@ export default class MMIController extends EventEmitter { this.metaMetricsController = opts.metaMetricsController; this.networkController = opts.networkController; this.permissionController = opts.permissionController; + this.signatureController = opts.signatureController; this.platform = opts.platform; this.extension = opts.extension; - this.personalMessageManager = new PersonalMessageManager( - undefined, - undefined, - this.securityProviderRequest, - ); - this.typedMessageManager = new TypedMessageManager( - undefined, - undefined, - this.securityProviderRequest, - ); - // Prepare event listener after transactionUpdateController gets initiated this.transactionUpdateController.prepareEventListener( this.custodianEventHandlerFactory.bind(this), @@ -87,6 +73,20 @@ export default class MMIController extends EventEmitter { await this.prepareMmiPortfolio(); }, this.preferencesController.store.getState()), ); + + this.signatureController.hub.on( + 'personal_sign:signed', + async ({ signature, messageId }) => { + await this.handleSigningEvents(signature, messageId, 'personal'); + }, + ); + + this.signatureController.hub.on( + 'eth_signTypedData:signed', + async ({ signature, messageId }) => { + await this.handleSigningEvents(signature, messageId, 'v4'); + }, + ); } // End of constructor async persistKeyringsAfterRefreshTokenChange() { @@ -111,8 +111,7 @@ export default class MMIController extends EventEmitter { getState: () => this.getState(), getPendingNonce: (address) => this.getPendingNonce(address), setTxHash: (txId, txHash) => this.txController.setTxHash(txId, txHash), - typedMessageManager: this.typedMessageManager, - personalMessageManager: this.personalMessageManager, + signatureController: this.signatureController, txStateManager: this.txController.txStateManager, custodyController: this.custodyController, trackTransactionEvent: @@ -185,9 +184,10 @@ export default class MMIController extends EventEmitter { keyring, type, txList, - getPendingNonce: this.getPendingNonce.bind(this), + getPendingNonce: (address) => this.getPendingNonce(address), + setTxHash: (txId, txHash) => + this.txController.setTxHash(txId, txHash), txStateManager: this.txController.txStateManager, - setTxHash: this.txController.setTxHash.bind(this.txController), custodyController: this.custodyController, transactionUpdateController: this.transactionUpdateController, }); @@ -225,15 +225,6 @@ export default class MMIController extends EventEmitter { ) { this.transactionUpdateController.getCustomerProofForAddresses(addresses); } - - try { - if (this.institutionalFeaturesController.getComplianceProjectId()) { - this.institutionalFeaturesController.startPolling(); - } - } catch (e) { - log.error('Failed to start Compliance polling'); - log.error(e); - } } async connectCustodyAddresses(custodianType, custodianName, accounts) { @@ -442,25 +433,8 @@ export default class MMIController extends EventEmitter { return keyring.getTransactionDeepLink(from, custodyTxId); } - async getCustodianToken(custodianType) { - let currentCustodyType; - - const address = this.preferencesController.getSelectedAddress(); - - if (!custodianType) { - const resultCustody = this.custodyController.getCustodyTypeByAddress( - toChecksumHexAddress(address), - ); - currentCustodyType = resultCustody; - } - let keyring = await this.keyringController.getKeyringsByType( - currentCustodyType || `Custody - ${custodianType}`, - )[0]; - if (!keyring) { - keyring = await this.keyringController.addNewKeyring( - currentCustodyType || `Custody - ${custodianType}`, - ); - } + async getCustodianToken(address) { + const keyring = await this.keyringController.getKeyringForAccount(address); const { authDetails } = keyring.getAccountDetails(address); return keyring ? authDetails.jwt || authDetails.refreshToken : ''; } @@ -568,8 +542,13 @@ export default class MMIController extends EventEmitter { const getAccountDetails = (address) => this.custodyController.getAccountDetails(address); const extensionId = this.extension.runtime.id; + + const { networkConfigurations: networkConfigurationsById } = + this.networkController.state; + const networkConfigurations = Object.values(networkConfigurationsById); + const networks = [ - ...this.preferencesController.getRpcMethodPreferences(), + ...networkConfigurations, { chainId: CHAIN_IDS.MAINNET }, { chainId: CHAIN_IDS.GOERLI }, ]; @@ -598,6 +577,42 @@ export default class MMIController extends EventEmitter { } } + async newUnsignedMessage(msgParams, req, version) { + const updatedMsgParams = { ...msgParams, deferSetAsSigned: true }; + + if (req.method.includes('eth_signTypedData')) { + return await this.signatureController.newUnsignedTypedMessage( + updatedMsgParams, + req, + version, + ); + } else if (req.method.includes('personal_sign')) { + return await this.signatureController.newUnsignedPersonalMessage( + updatedMsgParams, + req, + ); + } + return await this.signatureController.newUnsignedMessage( + updatedMsgParams, + req, + ); + } + + async handleSigningEvents(signature, messageId, signOperation) { + if (signature.custodian_transactionId) { + this.transactionUpdateController.addTransactionToWatchList( + signature.custodian_transactionId, + signature.from, + signOperation, + true, + ); + } + + this.signatureController.setMessageMetadata(messageId, signature); + + return this.getState(); + } + async setAccountAndNetwork(origin, address, chainId) { await this.appStateController.getUnlockPromise(true); const selectedAddress = this.preferencesController.getSelectedAddress(); diff --git a/app/scripts/controllers/mmi-controller.test.js b/app/scripts/controllers/mmi-controller.test.js index f6f9cc5f7..de06940c8 100644 --- a/app/scripts/controllers/mmi-controller.test.js +++ b/app/scripts/controllers/mmi-controller.test.js @@ -2,6 +2,7 @@ import { KeyringController } from '@metamask/eth-keyring-controller'; import { MmiConfigurationController } from '@metamask-institutional/custody-keyring'; import { TransactionUpdateController } from '@metamask-institutional/transaction-update'; +import { SignatureController } from '@metamask/signature-controller'; import MMIController from './mmi-controller'; import TransactionController from './transactions'; @@ -33,6 +34,20 @@ describe('MMIController', function () { getNetworkId: jest.fn(), onNetworkStateChange: jest.fn(), }), + signatureController: new SignatureController({ + messenger: { + registerActionHandler: jest.fn(), + publish: jest.fn(), + call: jest.fn(), + }, + keyringController: new KeyringController({ + initState: {}, + }), + isEthSignEnabled: jest.fn(), + getAllState: jest.fn(), + securityProviderRequest: jest.fn(), + getCurrentChainId: jest.fn(), + }), preferencesController: new PreferencesController({ initState: {}, onInfuraIsBlocked: jest.fn(), diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 9be792c49..e21f3239e 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -41,6 +41,9 @@ export default class PreferencesController { useNftDetection: false, useCurrencyRateCheck: true, openSeaEnabled: false, + ///: BEGIN:ONLY_INCLUDE_IN(blockaid) + securityAlertsEnabled: false, + ///: END:ONLY_INCLUDE_IN advancedGasFee: null, // WARNING: Do not use feature flags for security-sensitive things. @@ -185,6 +188,19 @@ export default class PreferencesController { }); } + ///: BEGIN:ONLY_INCLUDE_IN(blockaid) + /** + * Setter for the `securityAlertsEnabled` property + * + * @param {boolean} securityAlertsEnabled - Whether or not the user prefers to use the security alerts. + */ + setSecurityAlertsEnabled(securityAlertsEnabled) { + this.store.updateState({ + securityAlertsEnabled, + }); + } + ///: END:ONLY_INCLUDE_IN + /** * Setter for the `advancedGasFee` property * diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index 37de2830e..5301d1b1c 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -315,22 +315,6 @@ export default class TransactionController extends EventEmitter { }); } - /** - * Adds a tx to the txlist - * - * @param txMeta - * @fires ${txMeta.id}:unapproved - */ - addTransaction(txMeta) { - this.txStateManager.addTransaction(txMeta); - this.emit(`${txMeta.id}:unapproved`, txMeta); - this._trackTransactionMetricsEvent( - txMeta, - TransactionMetaMetricsEvent.added, - txMeta.actionId, - ); - } - /** * Wipes the transactions for a given account * @@ -341,64 +325,52 @@ export default class TransactionController extends EventEmitter { } /** - * Add a new unapproved transaction to the pipeline + * Add a new unapproved transaction * - * @returns {Promise} the hash of the transaction after being submitted to the network - * @param {object} txParams - txParams for the transaction - * @param {object} opts - with the key origin to put the origin on the txMeta + * @param {object} txParams - Standard parameters for an Ethereum transaction + * @param {object} opts - Options + * @param {string} opts.actionId - Unique ID to prevent duplicate requests + * @param {string} opts.method - RPC method that requested the transaction + * @param {string} opts.origin - Origin of the transaction request, such as the hostname of a dApp + * @param {boolean} opts.requireApproval - Whether the transaction requires approval by the user + * @param {object[]} opts.sendFlowHistory - Associated history to store with the transaction + * @param {object} opts.swaps - Options specific to swap transactions + * @param {boolean} opts.swaps.hasApproveTx - Whether this transaction required an approval transaction + * @param {boolean} opts.swaps.meta - Additional metadata to store for the transaction + * @param {TransactionType} opts.type - Type of transaction to add, such as 'cancel' or 'swap' + * @returns {Promise<{transactionMeta: TransactionMeta, result: Promise}>} An object containing the transaction metadata, and a promise that resolves to the transaction hash after being submitted to the network */ - async newUnapprovedTransaction(txParams, opts = {}) { - log.debug( - `MetaMaskController newUnapprovedTransaction ${JSON.stringify(txParams)}`, - ); + async addTransaction( + txParams, + { + actionId, + method, + origin, + requireApproval, + sendFlowHistory, + swaps: { hasApproveTx, meta } = {}, + type, + } = {}, + ) { + log.debug(`MetaMaskController addTransaction ${JSON.stringify(txParams)}`); - const { txMeta: initialTxMeta, isExisting } = await this._createTransaction( - opts.method, - txParams, - opts.origin, - undefined, - undefined, - opts.id, - ); + const { txMeta, isExisting } = await this._createTransaction(txParams, { + actionId, + method, + origin, + sendFlowHistory, + swaps: { hasApproveTx, meta }, + type, + }); - const txId = initialTxMeta.id; - const isCompleted = this._isTransactionCompleted(initialTxMeta); - - const finishedPromise = isCompleted - ? Promise.resolve(initialTxMeta) - : this._waitForTransactionFinished(txId); - - if (!isExisting && !isCompleted) { - try { - await this._requestTransactionApproval(initialTxMeta); - } catch (error) { - // Errors generated from final status using finished event - } - } - - const finalTxMeta = await finishedPromise; - const finalStatus = finalTxMeta?.status; - - switch (finalStatus) { - case TransactionStatus.submitted: - return finalTxMeta.hash; - case TransactionStatus.rejected: - throw cleanErrorStack( - ethErrors.provider.userRejectedRequest( - 'MetaMask Tx Signature: User denied transaction signature.', - ), - ); - case TransactionStatus.failed: - throw cleanErrorStack(ethErrors.rpc.internal(finalTxMeta.err.message)); - default: - throw cleanErrorStack( - ethErrors.rpc.internal( - `MetaMask Tx Signature: Unknown problem: ${JSON.stringify( - finalTxMeta?.txParams, - )}`, - ), - ); - } + return { + transactionMeta: txMeta, + result: this._processApproval(txMeta, { + isExisting, + requireApproval, + actionId, + }), + }; } /** @@ -585,54 +557,6 @@ export default class TransactionController extends EventEmitter { return this._getTransaction(txId); } - /** - * updates the estimate base fees of the transaction with id if the transaction state is unapproved - * - * @param {string} txId - transaction id - * @param {object} txEstimateBaseFees - holds the estimate base fees parameters - * @param {string} txEstimateBaseFees.estimatedBaseFee - * @param {string} txEstimateBaseFees.decEstimatedBaseFee - * @returns {TransactionMeta} the txMeta of the updated transaction - */ - updateTransactionEstimatedBaseFee( - txId, - { estimatedBaseFee, decEstimatedBaseFee }, - ) { - this._throwErrorIfNotUnapprovedTx( - txId, - 'updateTransactionEstimatedBaseFee', - ); - - let txEstimateBaseFees = { estimatedBaseFee, decEstimatedBaseFee }; - // only update what is defined - txEstimateBaseFees = pickBy(txEstimateBaseFees); - - const note = `Update Transaction Estimated Base Fees for ${txId}`; - this._updateTransaction(txId, txEstimateBaseFees, note); - return this._getTransaction(txId); - } - - /** - * updates a transaction's user settings only if the transaction state is unapproved - * - * @param {string} txId - * @param {object} userSettings - holds the metadata - * @param {string} userSettings.userEditedGasLimit - * @param {string} userSettings.userFeeLevel - * @returns {TransactionMeta} the txMeta of the updated transaction - */ - updateTransactionUserSettings(txId, { userEditedGasLimit, userFeeLevel }) { - this._throwErrorIfNotUnapprovedTx(txId, 'updateTransactionUserSettings'); - - let userSettings = { userEditedGasLimit, userFeeLevel }; - // only update what is defined - userSettings = pickBy(userSettings); - - const note = `Update User Settings for ${txId}`; - this._updateTransaction(txId, userSettings, note); - return this._getTransaction(txId); - } - /** * append new sendFlowHistory to the transaction with id if the transaction * state is unapproved. Returns the updated transaction. @@ -694,7 +618,7 @@ export default class TransactionController extends EventEmitter { updateTxMeta.loadingDefaults = false; // The history note used here 'Added new unapproved transaction.' is confusing update call only updated the gas defaults. - // We need to improve `this.addTransaction` to accept history note and change note here. + // We need to improve `this._addTransaction` to accept history note and change note here. this.txStateManager.updateTransaction( updateTxMeta, 'Added new unapproved transaction.', @@ -705,58 +629,6 @@ export default class TransactionController extends EventEmitter { // ==================================================================================================================================================== - /** - * Validates and generates a txMeta with defaults and puts it in txStateManager - * store. - * - * actionId is used to uniquely identify a request to create a transaction. - * Only 1 transaction will be created for multiple requests with same actionId. - * actionId is fix used for making this action idempotent to deal with scenario when - * action is invoked multiple times with same parameters in MV3 due to service worker re-activation. - * - * @param txMethodType - * @param txParams - * @param origin - * @param transactionType - * @param sendFlowHistory - * @param actionId - * @param options - */ - async addUnapprovedTransaction( - txMethodType, - txParams, - origin, - transactionType, - sendFlowHistory = [], - actionId, - options, - ) { - const { txMeta, isExisting } = await this._createTransaction( - txMethodType, - txParams, - origin, - transactionType, - sendFlowHistory, - actionId, - options, - ); - if (isExisting) { - const isCompleted = this._isTransactionCompleted(txMeta); - - return isCompleted - ? txMeta - : await this._waitForTransactionFinished(txMeta.id); - } - - if (options?.requireApproval === false) { - await this._updateAndApproveTransaction(txMeta, actionId); - } else { - await this._requestTransactionApproval(txMeta, { actionId }); - } - - return txMeta; - } - /** * Adds the tx gas defaults: gas && gasPrice * @@ -1122,7 +994,7 @@ export default class TransactionController extends EventEmitter { newTxMeta.estimatedBaseFee = estimatedBaseFee; } - this.addTransaction(newTxMeta); + this._addTransaction(newTxMeta); await this._approveTransaction(newTxMeta.id, actionId, { hasApprovalRequest: false, }); @@ -1182,7 +1054,7 @@ export default class TransactionController extends EventEmitter { newTxMeta.estimatedBaseFee = estimatedBaseFee; } - this.addTransaction(newTxMeta); + this._addTransaction(newTxMeta); await this._approveTransaction(newTxMeta.id, actionId); return newTxMeta; } @@ -1593,21 +1465,14 @@ export default class TransactionController extends EventEmitter { } async _createTransaction( - txMethodType, txParams, - origin, - transactionType, - sendFlowHistory = [], - actionId, - options, + { actionId, method, origin, sendFlowHistory = [], swaps, type }, ) { if ( - transactionType !== undefined && - !VALID_UNAPPROVED_TRANSACTION_TYPES.includes(transactionType) + type !== undefined && + !VALID_UNAPPROVED_TRANSACTION_TYPES.includes(type) ) { - throw new Error( - `TransactionController - invalid transactionType value: ${transactionType}`, - ); + throw new Error(`TransactionController - invalid type value: ${type}`); } // If a transaction is found with the same actionId, do not create a new speed-up transaction. @@ -1665,40 +1530,32 @@ export default class TransactionController extends EventEmitter { } } - const { type } = await determineTransactionType( + const { type: determinedType } = await determineTransactionType( normalizedTxParams, this.query, ); - txMeta.type = transactionType || type; + txMeta.type = type || determinedType; // ensure value txMeta.txParams.value = txMeta.txParams.value ? addHexPrefix(txMeta.txParams.value) : '0x0'; - if (txMethodType && this.securityProviderRequest) { + if (method && this.securityProviderRequest) { const securityProviderResponse = await this.securityProviderRequest( txMeta, - txMethodType, + method, ); txMeta.securityProviderResponse = securityProviderResponse; } - this.addTransaction(txMeta); + this._addTransaction(txMeta); txMeta = await this.addTransactionGasDefaults(txMeta); - if ( - [TransactionType.swap, TransactionType.swapApproval].includes( - transactionType, - ) - ) { - txMeta = await this._createSwapsTransaction( - options?.swaps, - transactionType, - txMeta, - ); + if ([TransactionType.swap, TransactionType.swapApproval].includes(type)) { + txMeta = await this._createSwapsTransaction(swaps, type, txMeta); } return { txMeta, isExisting: false }; @@ -1830,6 +1687,51 @@ export default class TransactionController extends EventEmitter { await this._approveTransaction(txMeta.id, actionId); } + async _processApproval(txMeta, { actionId, isExisting, requireApproval }) { + const txId = txMeta.id; + const isCompleted = this._isTransactionCompleted(txMeta); + + const finishedPromise = isCompleted + ? Promise.resolve(txMeta) + : this._waitForTransactionFinished(txId); + + if (!isExisting && !isCompleted) { + try { + if (requireApproval === false) { + await this._updateAndApproveTransaction(txMeta, actionId); + } else { + await this._requestTransactionApproval(txMeta, { actionId }); + } + } catch (error) { + // Errors generated from final status using finished event + } + } + + const finalTxMeta = await finishedPromise; + const finalStatus = finalTxMeta?.status; + + switch (finalStatus) { + case TransactionStatus.submitted: + return finalTxMeta.hash; + case TransactionStatus.rejected: + throw cleanErrorStack( + ethErrors.provider.userRejectedRequest( + 'MetaMask Tx Signature: User denied transaction signature.', + ), + ); + case TransactionStatus.failed: + throw cleanErrorStack(ethErrors.rpc.internal(finalTxMeta.err.message)); + default: + throw cleanErrorStack( + ethErrors.rpc.internal( + `MetaMask Tx Signature: Unknown problem: ${JSON.stringify( + finalTxMeta?.txParams, + )}`, + ), + ); + } + } + /** * sets the tx status to approved * auto fills the nonce @@ -2762,6 +2664,22 @@ export default class TransactionController extends EventEmitter { ); } + /** + * Adds a tx to the txlist + * + * @param txMeta + * @fires ${txMeta.id}:unapproved + */ + _addTransaction(txMeta) { + this.txStateManager.addTransaction(txMeta); + this.emit(`${txMeta.id}:unapproved`, txMeta); + this._trackTransactionMetricsEvent( + txMeta, + TransactionMetaMetricsEvent.added, + txMeta.actionId, + ); + } + // Approvals async _requestTransactionApproval( diff --git a/app/scripts/controllers/transactions/index.test.js b/app/scripts/controllers/transactions/index.test.js index 8600f08dc..1237c9be3 100644 --- a/app/scripts/controllers/transactions/index.test.js +++ b/app/scripts/controllers/transactions/index.test.js @@ -30,7 +30,6 @@ import { GasEstimateTypes, GasRecommendations, } from '../../../../shared/constants/gas'; -import { METAMASK_CONTROLLER_EVENTS } from '../../metamask-controller'; import { ORIGIN_METAMASK } from '../../../../shared/constants/app'; import { NetworkStatus } from '../../../../shared/constants/network'; import { TRANSACTION_ENVELOPE_TYPE_NAMES } from '../../../../shared/lib/transactions-controller-utils'; @@ -328,14 +327,23 @@ describe('Transaction Controller', function () { }); }); - describe('#newUnapprovedTransaction', function () { - let txMeta, txParams, getPermittedAccounts, signStub; + describe('#addTransaction', function () { + const selectedAddress = '0xc684832530fcbddae4b4230a47e991ddcec2831d'; + const recipientAddress = '0xc684832530fcbddae4b4230a47e991ddcec2831d'; + + let txMeta, + txParams, + getPermittedAccounts, + signStub, + getSelectedAddress, + getDefaultGasFees; beforeEach(function () { txParams = { - from: '0xc684832530fcbddae4b4230a47e991ddcec2831d', - to: '0xc684832530fcbddae4b4230a47e991ddcec2831d', + from: selectedAddress, + to: recipientAddress, }; + txMeta = { status: TransactionStatus.unapproved, id: 1, @@ -343,151 +351,35 @@ describe('Transaction Controller', function () { txParams, history: [{}], }; + txController.txStateManager._addTransactionsToState([txMeta]); + getPermittedAccounts = sinon .stub(txController, 'getPermittedAccounts') .returns([txParams.from]); + + getSelectedAddress = sinon + .stub(txController, 'getSelectedAddress') + .returns(selectedAddress); + + getDefaultGasFees = sinon + .stub(txController, '_getDefaultGasFees') + .returns({}); }); afterEach(function () { txController.txStateManager._addTransactionsToState([]); getPermittedAccounts.restore(); signStub?.restore(); - }); - - it('should resolve when finished and status is submitted and resolve with the hash', async function () { - const hash = await txController.newUnapprovedTransaction(txParams); - assert.ok(hash, 'newUnapprovedTransaction needs to return the hash'); - }); - - it('should reject when finished and status is rejected', async function () { - messengerMock.call.returns( - Promise.reject({ code: errorCodes.provider.userRejectedRequest }), - ); - - await assert.rejects(txController.newUnapprovedTransaction(txParams), { - message: 'MetaMask Tx Signature: User denied transaction signature.', - }); - }); - - it('rejects when finished and status is failed', async function () { - const signError = new Error('TestSigningError'); - - signStub = sinon.stub(txController, 'signEthTx').throws(signError); - - await assert.rejects(txController.newUnapprovedTransaction(txParams), { - message: signError.message, - }); - }); - - it('creates an approval request', async function () { - await txController.newUnapprovedTransaction(txParams); - - const txId = getLastTxMeta().id; - - assert.equal(messengerMock.call.callCount, 1); - assert.deepEqual(messengerMock.call.getCall(0).args, [ - 'ApprovalController:addRequest', - { - id: String(txId), - origin: undefined, - requestData: { txId }, - type: ApprovalType.Transaction, - expectsResult: true, - }, - true, // Show popup - ]); - }); - - describe('if transaction with same actionId exists', function () { - it('does not create an additional approval request', async function () { - await txController.newUnapprovedTransaction(txParams, { id: '12345' }); - await txController.newUnapprovedTransaction(txParams, { id: '12345' }); - - const txId = getLastTxMeta().id; - - assert.equal(messengerMock.call.callCount, 1); - assert.deepEqual(messengerMock.call.getCall(0).args, [ - 'ApprovalController:addRequest', - { - id: String(txId), - origin: undefined, - requestData: { txId }, - type: ApprovalType.Transaction, - expectsResult: true, - }, - true, // Show popup - ]); - }); - - it('does not resolve until transaction approved', async function () { - let firstTransactionResolve; - let firstTransactionCompleted = false; - let secondTransactionCompleted = false; - - messengerMock.call.returns( - new Promise((resolve) => { - firstTransactionResolve = resolve; - }), - ); - - txController - .newUnapprovedTransaction(txParams, { id: '12345' }) - .then(() => { - firstTransactionCompleted = true; - }); - - await flushPromises(); - - txController - .newUnapprovedTransaction(txParams, { id: '12345' }) - .then(() => { - secondTransactionCompleted = true; - }); - - await flushPromises(); - - assert.equal(firstTransactionCompleted, false); - assert.equal(secondTransactionCompleted, false); - - firstTransactionResolve({ value: { txMeta: getLastTxMeta() } }); - - await flushPromises(); - - assert.equal(secondTransactionCompleted, true); - assert.equal(secondTransactionCompleted, true); - }); - }); - }); - - describe('#addUnapprovedTransaction', function () { - const selectedAddress = '0x1678a085c290ebd122dc42cba69373b5953b831d'; - const recipientAddress = '0xc42edfcc21ed14dda456aa0756c153f7985d8813'; - - let getSelectedAddress, getPermittedAccounts, getDefaultGasFees; - beforeEach(function () { - getSelectedAddress = sinon - .stub(txController, 'getSelectedAddress') - .returns(selectedAddress); - getDefaultGasFees = sinon - .stub(txController, '_getDefaultGasFees') - .returns({}); - getPermittedAccounts = sinon - .stub(txController, 'getPermittedAccounts') - .returns([selectedAddress]); - }); - - afterEach(function () { getSelectedAddress.restore(); - getPermittedAccounts.restore(); getDefaultGasFees.restore(); }); - it('should add an unapproved transaction and return a valid txMeta', async function () { - const txMeta = await txController.addUnapprovedTransaction(undefined, { + it('adds an unapproved transaction and returns transaction metadata', async function () { + ({ transactionMeta: txMeta } = await txController.addTransaction({ from: selectedAddress, to: recipientAddress, - }); + })); assert.ok('id' in txMeta, 'should have a id'); assert.ok('time' in txMeta, 'should have a time stamp'); assert.ok( @@ -506,103 +398,18 @@ describe('Transaction Controller', function () { assert.deepEqual(txMeta, memTxMeta); }); - it('should add only 1 unapproved transaction when called twice with same actionId', async function () { - await txController.addUnapprovedTransaction( - undefined, - { - from: selectedAddress, - to: recipientAddress, - }, - undefined, - undefined, - undefined, - '12345', - ); - const transactionCount1 = - txController.txStateManager.getTransactions().length; - await txController.addUnapprovedTransaction( - undefined, - { - from: selectedAddress, - to: recipientAddress, - }, - undefined, - undefined, - undefined, - '12345', - ); - const transactionCount2 = - txController.txStateManager.getTransactions().length; - assert.equal(transactionCount1, transactionCount2); - }); + it('creates an approval request', async function () { + await txController.addTransaction(txParams); - it('should add multiple transactions when called with different actionId', async function () { - await txController.addUnapprovedTransaction( - undefined, - { - from: selectedAddress, - to: recipientAddress, - }, - undefined, - undefined, - undefined, - '12345', - ); - const transactionCount1 = - txController.txStateManager.getTransactions().length; - await txController.addUnapprovedTransaction( - undefined, - { - from: selectedAddress, - to: recipientAddress, - }, - undefined, - undefined, - undefined, - '00000', - ); - const transactionCount2 = - txController.txStateManager.getTransactions().length; - assert.equal(transactionCount1 + 1, transactionCount2); - }); - - it("should fail if the from address isn't the selected address", async function () { - await assert.rejects(() => - txController.addUnapprovedTransaction({ - from: '0x0d1d4e623D10F9FBA5Db95830F7d3839406C6AF2', - }), - ); - }); - - it('should fail if the network status is not "available"', async function () { - networkStatusStore.putState(NetworkStatus.Unknown); - await assert.rejects( - () => - txController.addUnapprovedTransaction(undefined, { - from: selectedAddress, - to: '0x0d1d4e623D10F9FBA5Db95830F7d3839406C6AF2', - }), - { message: 'MetaMask is having trouble connecting to the network' }, - ); - }); - - it('should create an approval request', async function () { - const txMeta = await txController.addUnapprovedTransaction( - undefined, - { - from: selectedAddress, - to: recipientAddress, - }, - ORIGIN_METAMASK, - ); + const txId = getLastTxMeta().id; assert.equal(messengerMock.call.callCount, 1); assert.deepEqual(messengerMock.call.getCall(0).args, [ 'ApprovalController:addRequest', { - id: String(txMeta.id), - origin: ORIGIN_METAMASK, - requestData: { txId: txMeta.id }, + id: String(txId), + origin: undefined, + requestData: { txId }, type: ApprovalType.Transaction, expectsResult: true, }, @@ -610,18 +417,38 @@ describe('Transaction Controller', function () { ]); }); - it('updates meta if transaction type is swap approval', async function () { - await txController.addUnapprovedTransaction( - undefined, + it('throws if the from address is not the selected address', async function () { + await assert.rejects(() => + txController.addTransaction({ + from: '0x0d1d4e623D10F9FBA5Db95830F7d3839406C6AF2', + }), + ); + }); + + it('throws if the network status is not available', async function () { + networkStatusStore.putState(NetworkStatus.Unknown); + await assert.rejects( + () => + txController.addTransaction({ + from: selectedAddress, + to: '0x0d1d4e623D10F9FBA5Db95830F7d3839406C6AF2', + }), + { message: 'MetaMask is having trouble connecting to the network' }, + ); + }); + + it('updates meta if type is swap approval', async function () { + await txController.addTransaction( { from: selectedAddress, to: recipientAddress, }, - ORIGIN_METAMASK, - TransactionType.swapApproval, - undefined, - '12345', - { swaps: { meta: { type: 'swapApproval', sourceTokenSymbol: 'XBN' } } }, + { + origin: ORIGIN_METAMASK, + type: TransactionType.swapApproval, + actionId: '12345', + swaps: { meta: { type: 'swapApproval', sourceTokenSymbol: 'XBN' } }, + }, ); const transaction = txController.getTransactions({ @@ -632,18 +459,16 @@ describe('Transaction Controller', function () { assert.equal(transaction.sourceTokenSymbol, 'XBN'); }); - it('updates meta if transaction type is swap', async function () { - await txController.addUnapprovedTransaction( - undefined, + it('updates meta if type is swap', async function () { + await txController.addTransaction( { from: selectedAddress, to: recipientAddress, }, - ORIGIN_METAMASK, - TransactionType.swap, - undefined, - '12345', { + origin: ORIGIN_METAMASK, + type: TransactionType.swap, + actionId: '12345', swaps: { meta: { sourceTokenSymbol: 'BTCX', @@ -687,17 +512,15 @@ describe('Transaction Controller', function () { it('throws error', async function () { await assert.rejects( - txController.addUnapprovedTransaction( - undefined, + txController.addTransaction( { from: selectedAddress, to: recipientAddress, }, - ORIGIN_METAMASK, - TransactionType.swap, - undefined, - '12345', { + origin: ORIGIN_METAMASK, + type: TransactionType.swap, + actionId: '12345', swaps: { hasApproveTx: false, }, @@ -713,17 +536,15 @@ describe('Transaction Controller', function () { txController.on('tx:status-update', listener); try { - await txController.addUnapprovedTransaction( - undefined, + await txController.addTransaction( { from: selectedAddress, to: recipientAddress, }, - ORIGIN_METAMASK, - TransactionType.swap, - undefined, - '12345', { + origin: ORIGIN_METAMASK, + type: TransactionType.swap, + actionId: '12345', swaps: { hasApproveTx: false, }, @@ -742,39 +563,42 @@ describe('Transaction Controller', function () { }); }); - describe('if transaction with same actionId exists', function () { - it('does not create an additional approval request', async function () { - await txController.addUnapprovedTransaction( - undefined, + describe('with actionId', function () { + it('adds single unapproved transaction when called twice with same actionId', async function () { + await txController.addTransaction( { from: selectedAddress, to: recipientAddress, }, - ORIGIN_METAMASK, - undefined, - undefined, - '12345', + { actionId: '12345' }, ); + const transactionCount1 = + txController.txStateManager.getTransactions().length; + await txController.addTransaction( + { + from: selectedAddress, + to: recipientAddress, + }, + { actionId: '12345' }, + ); + const transactionCount2 = + txController.txStateManager.getTransactions().length; + assert.equal(transactionCount1, transactionCount2); + }); - const secondTxMeta = await txController.addUnapprovedTransaction( - undefined, - { - from: selectedAddress, - to: recipientAddress, - }, - undefined, - undefined, - undefined, - '12345', - ); + it('adds single approval request when called twice with same actionId', async function () { + await txController.addTransaction(txParams, { actionId: '12345' }); + await txController.addTransaction(txParams, { actionId: '12345' }); + + const txId = getLastTxMeta().id; assert.equal(messengerMock.call.callCount, 1); assert.deepEqual(messengerMock.call.getCall(0).args, [ 'ApprovalController:addRequest', { - id: String(secondTxMeta.id), - origin: ORIGIN_METAMASK, - requestData: { txId: secondTxMeta.id }, + id: String(txId), + origin: undefined, + requestData: { txId }, type: ApprovalType.Transaction, expectsResult: true, }, @@ -782,7 +606,29 @@ describe('Transaction Controller', function () { ]); }); - it('does not resolve until transaction approved', async function () { + it('adds multiple transactions when called with different actionId', async function () { + await txController.addTransaction( + { + from: selectedAddress, + to: recipientAddress, + }, + { actionId: '12345' }, + ); + const transactionCount1 = + txController.txStateManager.getTransactions().length; + await txController.addTransaction( + { + from: selectedAddress, + to: recipientAddress, + }, + { actionId: '00000' }, + ); + const transactionCount2 = + txController.txStateManager.getTransactions().length; + assert.equal(transactionCount1 + 1, transactionCount2); + }); + + it('resolves second result when first transaction is finished', async function () { let firstTransactionResolve; let firstTransactionCompleted = false; let secondTransactionCompleted = false; @@ -793,39 +639,23 @@ describe('Transaction Controller', function () { }), ); - txController - .addUnapprovedTransaction( - undefined, - { - from: selectedAddress, - to: recipientAddress, - }, - ORIGIN_METAMASK, - undefined, - undefined, - '12345', - ) - .then(() => { - firstTransactionCompleted = true; - }); + const { result: firstResult } = await txController.addTransaction( + txParams, + { actionId: '12345' }, + ); - await flushPromises(); + firstResult.then(() => { + firstTransactionCompleted = true; + }); - txController - .addUnapprovedTransaction( - undefined, - { - from: selectedAddress, - to: recipientAddress, - }, - undefined, - undefined, - undefined, - '12345', - ) - .then(() => { - secondTransactionCompleted = true; - }); + const { result: secondResult } = await txController.addTransaction( + txParams, + { actionId: '12345' }, + ); + + secondResult.then(() => { + secondTransactionCompleted = true; + }); await flushPromises(); @@ -835,26 +665,32 @@ describe('Transaction Controller', function () { firstTransactionResolve({ value: { txMeta: getLastTxMeta() } }); await flushPromises(); + await firstResult; + await secondResult; - assert.equal(secondTransactionCompleted, true); + assert.equal(firstTransactionCompleted, true); assert.equal(secondTransactionCompleted, true); }); }); - describe('on approval', function () { + describe('on success', function () { + it('resolves result with the transaction hash', async function () { + const { result } = await txController.addTransaction(txParams); + const hash = await result; + assert.ok(hash, 'addTransaction needs to return the hash'); + }); + it('changes status to submitted', async function () { - await txController.addUnapprovedTransaction( - undefined, + const { result } = await txController.addTransaction( { from: selectedAddress, to: recipientAddress, }, - ORIGIN_METAMASK, - undefined, - undefined, - '12345', + { origin: ORIGIN_METAMASK, actionId: '12345' }, ); + await result; + const transaction = txController.getTransactions({ searchCriteria: { id: getLastTxMeta().id }, })[0]; @@ -867,18 +703,16 @@ describe('Transaction Controller', function () { txController.on('tx:status-update', listener); - await txController.addUnapprovedTransaction( - undefined, + const { result } = await txController.addTransaction( { from: selectedAddress, to: recipientAddress, }, - ORIGIN_METAMASK, - undefined, - undefined, - '12345', + { origin: ORIGIN_METAMASK, actionId: '12345' }, ); + await result; + const txId = getLastTxMeta().id; assert.equal(listener.callCount, 3); @@ -891,18 +725,16 @@ describe('Transaction Controller', function () { }); it('reports success to approval request acceptor', async function () { - await txController.addUnapprovedTransaction( - undefined, + const { result } = await txController.addTransaction( { from: selectedAddress, to: recipientAddress, }, - ORIGIN_METAMASK, - undefined, - undefined, - '12345', + { origin: ORIGIN_METAMASK, actionId: '12345' }, ); + await result; + assert.equal(resultCallbacksMock.success.callCount, 1); }); @@ -913,7 +745,7 @@ describe('Transaction Controller', function () { providerResultStub.eth_gasPrice = wrongValue; providerResultStub.eth_estimateGas = '0x5209'; - const signStub = sinon + signStub = sinon .stub(txController, 'signTransaction') .callsFake(() => Promise.resolve()); @@ -925,8 +757,7 @@ describe('Transaction Controller', function () { txController.txStateManager.setTxStatusSubmitted(txId); }); - await txController.addUnapprovedTransaction( - undefined, + const { result } = await txController.addTransaction( { from: selectedAddress, to: recipientAddress, @@ -934,21 +765,20 @@ describe('Transaction Controller', function () { gas: originalValue, gasPrice: originalValue, }, - ORIGIN_METAMASK, - undefined, - undefined, - '12345', + { origin: ORIGIN_METAMASK, actionId: '12345' }, ); + await result; + const txId = getLastTxMeta().id; - const result = txController.txStateManager.getTransaction(txId); - const params = result.txParams; + const finalMeta = txController.txStateManager.getTransaction(txId); + const params = finalMeta.txParams; assert.equal(params.gas, originalValue, 'gas unmodified'); assert.equal(params.gasPrice, originalValue, 'gas price unmodified'); - assert.equal(result.hash, originalValue); + assert.equal(finalMeta.hash, originalValue); assert.equal( - result.status, + finalMeta.status, TransactionStatus.submitted, 'should have reached the submitted status.', ); @@ -965,21 +795,19 @@ describe('Transaction Controller', function () { ); }); - it('throws error', async function () { - await assert.rejects( - txController.addUnapprovedTransaction( - undefined, - { - from: selectedAddress, - to: recipientAddress, - }, - ORIGIN_METAMASK, - undefined, - undefined, - '12345', - ), - { code: ethErrors.provider.userRejectedRequest().code }, + it('rejects result', async function () { + const { result } = await txController.addTransaction( + { + from: selectedAddress, + to: recipientAddress, + }, + { origin: ORIGIN_METAMASK, actionId: '12345' }, ); + + await assert.rejects(result, { + code: ethErrors.provider.userRejectedRequest().code, + message: 'MetaMask Tx Signature: User denied transaction signature.', + }); }); it('emits rejected status event', async function () { @@ -987,18 +815,16 @@ describe('Transaction Controller', function () { txController.on('tx:status-update', listener); + const { result } = await txController.addTransaction( + { + from: selectedAddress, + to: recipientAddress, + }, + { origin: ORIGIN_METAMASK, actionid: '12345' }, + ); + try { - await txController.addUnapprovedTransaction( - undefined, - { - from: selectedAddress, - to: recipientAddress, - }, - ORIGIN_METAMASK, - undefined, - undefined, - '12345', - ); + await result; } catch (error) { // Expected error } @@ -1014,7 +840,6 @@ describe('Transaction Controller', function () { describe('on signing error', function () { const signError = new Error('TestSignError'); - let signStub; beforeEach(async function () { signStub = sinon.stub(txController, 'signEthTx').throws(signError); @@ -1025,18 +850,16 @@ describe('Transaction Controller', function () { }); it('changes status to failed', async function () { + const { result } = await txController.addTransaction( + { + from: selectedAddress, + to: recipientAddress, + }, + { origin: ORIGIN_METAMASK, actionId: '12345' }, + ); + try { - await txController.addUnapprovedTransaction( - undefined, - { - from: selectedAddress, - to: recipientAddress, - }, - ORIGIN_METAMASK, - undefined, - undefined, - '12345', - ); + await result; } catch { // Expected error } @@ -1048,21 +871,16 @@ describe('Transaction Controller', function () { assert.equal(transaction.status, TransactionStatus.failed); }); - it('throws error', async function () { - await assert.rejects( - txController.addUnapprovedTransaction( - undefined, - { - from: selectedAddress, - to: recipientAddress, - }, - ORIGIN_METAMASK, - undefined, - undefined, - '12345', - ), - signError, + it('rejects result', async function () { + const { result } = await txController.addTransaction( + { + from: selectedAddress, + to: recipientAddress, + }, + { origin: ORIGIN_METAMASK, actionId: '12345' }, ); + + await assert.rejects(result, signError); }); it('emits approved and failed status events', async function () { @@ -1070,18 +888,16 @@ describe('Transaction Controller', function () { txController.on('tx:status-update', listener); + const { result } = await txController.addTransaction( + { + from: selectedAddress, + to: recipientAddress, + }, + { origin: ORIGIN_METAMASK, actionId: '12345' }, + ); + try { - await txController.addUnapprovedTransaction( - undefined, - { - from: selectedAddress, - to: recipientAddress, - }, - ORIGIN_METAMASK, - undefined, - undefined, - '12345', - ); + await result; } catch (error) { // Expected error } @@ -1096,18 +912,16 @@ describe('Transaction Controller', function () { }); it('reports error to approval request acceptor', async function () { + const { result } = await txController.addTransaction( + { + from: selectedAddress, + to: recipientAddress, + }, + { origin: ORIGIN_METAMASK, actionId: '12345' }, + ); + try { - await txController.addUnapprovedTransaction( - undefined, - { - from: selectedAddress, - to: recipientAddress, - }, - ORIGIN_METAMASK, - undefined, - undefined, - '12345', - ); + await result; } catch { // Expected error } @@ -1137,18 +951,16 @@ describe('Transaction Controller', function () { }); it('changes status to failed', async function () { + const { result } = await txController.addTransaction( + { + from: selectedAddress, + to: recipientAddress, + }, + { origin: ORIGIN_METAMASK, actionId: '12345' }, + ); + try { - await txController.addUnapprovedTransaction( - undefined, - { - from: selectedAddress, - to: recipientAddress, - }, - ORIGIN_METAMASK, - undefined, - undefined, - '12345', - ); + await result; } catch { // Expected error } @@ -1160,21 +972,16 @@ describe('Transaction Controller', function () { assert.equal(transaction.status, TransactionStatus.failed); }); - it('throws error', async function () { - await assert.rejects( - txController.addUnapprovedTransaction( - undefined, - { - from: selectedAddress, - to: recipientAddress, - }, - ORIGIN_METAMASK, - undefined, - undefined, - '12345', - ), - publishError, + it('rejects result', async function () { + const { result } = await txController.addTransaction( + { + from: selectedAddress, + to: recipientAddress, + }, + { origin: ORIGIN_METAMASK, actionId: '12345' }, ); + + await assert.rejects(result, publishError); }); it('emits approved, signed, and failed status events', async function () { @@ -1182,18 +989,16 @@ describe('Transaction Controller', function () { txController.on('tx:status-update', listener); + const { result } = await txController.addTransaction( + { + from: selectedAddress, + to: recipientAddress, + }, + { origin: ORIGIN_METAMASK, actionId: '12345' }, + ); + try { - await txController.addUnapprovedTransaction( - undefined, - { - from: selectedAddress, - to: recipientAddress, - }, - ORIGIN_METAMASK, - undefined, - undefined, - '12345', - ); + await result; } catch (error) { // Expected error } @@ -1210,18 +1015,16 @@ describe('Transaction Controller', function () { }); it('reports error to approval request acceptor', async function () { + const { result } = await txController.addTransaction( + { + from: selectedAddress, + to: recipientAddress, + }, + { origin: ORIGIN_METAMASK, actionId: '12345' }, + ); + try { - await txController.addUnapprovedTransaction( - undefined, - { - from: selectedAddress, - to: recipientAddress, - }, - ORIGIN_METAMASK, - undefined, - undefined, - '12345', - ); + await result; } catch { // Expected error } @@ -1240,20 +1043,29 @@ describe('Transaction Controller', function () { messengerMock.call.callsFake(() => Promise.reject()); }); + it('resolves result with the transaction hash', async function () { + const { result } = await txController.addTransaction(txParams, { + requireApproval: false, + }); + const hash = await result; + assert.ok(hash, 'addTransaction needs to return the hash'); + }); + it('changes status to submitted', async function () { - await txController.addUnapprovedTransaction( - undefined, + const { result } = await txController.addTransaction( { from: selectedAddress, to: recipientAddress, }, - ORIGIN_METAMASK, - undefined, - undefined, - '12345', - { requireApproval: false }, + { + origin: ORIGIN_METAMASK, + actionid: '12345', + requireApproval: false, + }, ); + await result; + const transaction = txController.getTransactions({ searchCriteria: { id: getLastTxMeta().id }, })[0]; @@ -1266,19 +1078,20 @@ describe('Transaction Controller', function () { txController.on('tx:status-update', listener); - await txController.addUnapprovedTransaction( - undefined, + const { result } = await txController.addTransaction( { from: selectedAddress, to: recipientAddress, }, - ORIGIN_METAMASK, - undefined, - undefined, - '12345', - { requireApproval: false }, + { + origin: ORIGIN_METAMASK, + actionId: '12345', + requireApproval: false, + }, ); + await result; + const txId = getLastTxMeta().id; assert.equal(listener.callCount, 3); @@ -1326,11 +1139,13 @@ describe('Transaction Controller', function () { getDefaultGasLimit.restore(); }); - it('should add an cancel transaction and return a valid txMeta', async function () { - const txMeta = await txController.addUnapprovedTransaction(undefined, { - from: selectedAddress, - to: recipientAddress, - }); + it('should add a cancel transaction and return a valid txMeta', async function () { + const { transactionMeta: txMeta, result } = + await txController.addTransaction({ + from: selectedAddress, + to: recipientAddress, + }); + await result; const cancelTxMeta = await txController.createCancelTransaction( txMeta.id, {}, @@ -1345,10 +1160,12 @@ describe('Transaction Controller', function () { }); it('should add only 1 cancel transaction when called twice with same actionId', async function () { - const txMeta = await txController.addUnapprovedTransaction(undefined, { - from: selectedAddress, - to: recipientAddress, - }); + const { transactionMeta: txMeta, result } = + await txController.addTransaction({ + from: selectedAddress, + to: recipientAddress, + }); + await result; await txController.createCancelTransaction( txMeta.id, {}, @@ -1367,10 +1184,12 @@ describe('Transaction Controller', function () { }); it('should add multiple transactions when called with different actionId', async function () { - const txMeta = await txController.addUnapprovedTransaction(undefined, { - from: selectedAddress, - to: recipientAddress, - }); + const { transactionMeta: txMeta, result } = + await txController.addTransaction({ + from: selectedAddress, + to: recipientAddress, + }); + await result; await txController.createCancelTransaction( txMeta.id, {}, @@ -1710,94 +1529,9 @@ describe('Transaction Controller', function () { }); }); - describe('#addTransaction', function () { - let trackTransactionMetricsEventSpy; - - beforeEach(function () { - trackTransactionMetricsEventSpy = sinon.spy( - txController, - '_trackTransactionMetricsEvent', - ); - }); - - afterEach(function () { - trackTransactionMetricsEventSpy.restore(); - }); - - it('should emit updates', function (done) { - const txMeta = { - id: '1', - status: TransactionStatus.unapproved, - metamaskNetworkId: currentNetworkId, - txParams: { - to: VALID_ADDRESS, - from: VALID_ADDRESS_TWO, - }, - }; - - const eventNames = [ - METAMASK_CONTROLLER_EVENTS.UPDATE_BADGE, - '1:unapproved', - ]; - const listeners = []; - eventNames.forEach((eventName) => { - listeners.push( - new Promise((resolve) => { - txController.once(eventName, (arg) => { - resolve(arg); - }); - }), - ); - }); - Promise.all(listeners) - .then((returnValues) => { - assert.deepEqual( - returnValues.pop(), - txMeta, - 'last event 1:unapproved should return txMeta', - ); - done(); - }) - .catch(done); - txController.addTransaction(txMeta); - }); - - it('should call _trackTransactionMetricsEvent with the correct params', function () { - const txMeta = { - id: 1, - status: TransactionStatus.unapproved, - txParams: { - from: fromAccount.address, - to: '0x1678a085c290ebd122dc42cba69373b5953b831d', - gasPrice: '0x77359400', - gas: '0x7b0d', - nonce: '0x4b', - }, - type: TransactionType.simpleSend, - transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY, - origin: ORIGIN_METAMASK, - chainId: currentChainId, - time: 1624408066355, - metamaskNetworkId: currentNetworkId, - }; - - txController.addTransaction(txMeta); - - assert.equal(trackTransactionMetricsEventSpy.callCount, 1); - assert.deepEqual( - trackTransactionMetricsEventSpy.getCall(0).args[0], - txMeta, - ); - assert.equal( - trackTransactionMetricsEventSpy.getCall(0).args[1], - TransactionMetaMetricsEvent.added, - ); - }); - }); - describe('#sign replay-protected tx', function () { it('prepares a tx with the chainId set', async function () { - txController.addTransaction( + txController._addTransaction( { id: '1', status: TransactionStatus.unapproved, @@ -1847,7 +1581,7 @@ describe('Transaction Controller', function () { getDefaultGasLimit; beforeEach(function () { - addTransactionSpy = sinon.spy(txController, 'addTransaction'); + addTransactionSpy = sinon.spy(txController, '_addTransaction'); approveTransactionSpy = sinon.spy(txController, '_approveTransaction'); const hash = @@ -1940,10 +1674,12 @@ describe('Transaction Controller', function () { }); it('should add only 1 speedup transaction when called twice with same actionId', async function () { - const txMeta = await txController.addUnapprovedTransaction(undefined, { - from: selectedAddress, - to: recipientAddress, - }); + const { transactionMeta: txMeta, result } = + await txController.addTransaction({ + from: selectedAddress, + to: recipientAddress, + }); + await result; await txController.createSpeedUpTransaction( txMeta.id, {}, @@ -1962,10 +1698,12 @@ describe('Transaction Controller', function () { }); it('should add multiple transactions when called with different actionId', async function () { - const txMeta = await txController.addUnapprovedTransaction(undefined, { - from: selectedAddress, - to: recipientAddress, - }); + const { transactionMeta: txMeta, result } = + await txController.addTransaction({ + from: selectedAddress, + to: recipientAddress, + }); + await result; await txController.createSpeedUpTransaction( txMeta.id, {}, @@ -1984,13 +1722,15 @@ describe('Transaction Controller', function () { }); it('should add multiple transactions when called with different actionId and txMethodType defined', async function () { - const txMeta = await txController.addUnapprovedTransaction( - 'eth_sendTransaction', - { - from: selectedAddress, - to: recipientAddress, - }, - ); + const { transactionMeta: txMeta, result } = + await txController.addTransaction( + { + from: selectedAddress, + to: recipientAddress, + }, + { method: 'eth_sendTransaction' }, + ); + await result; await txController.createSpeedUpTransaction( txMeta.id, {}, @@ -2009,12 +1749,12 @@ describe('Transaction Controller', function () { }); it('should call securityProviderRequest and have flagAsDangerous inside txMeta', async function () { - const txMeta = await txController.addUnapprovedTransaction( - 'eth_sendTransaction', + const { transactionMeta: txMeta } = await txController.addTransaction( { from: selectedAddress, to: recipientAddress, }, + { method: 'eth_sendTransaction' }, ); assert.ok( @@ -3281,27 +3021,6 @@ describe('Transaction Controller', function () { assert.equal(result.estimateUsed, '0x0055'); }); - it('updates estimated base fee', function () { - txController.updateTransactionEstimatedBaseFee('1', { - estimatedBaseFee: '0x0066', - decEstimatedBaseFee: '66', - }); - const result = txStateManager.getTransaction('1'); - assert.equal(result.estimatedBaseFee, '0x0066'); - assert.equal(result.decEstimatedBaseFee, '66'); - }); - - it('updates transaction user settings', function () { - txController.updateTransactionUserSettings('1', { - userEditedGasLimit: '0x0088', - userFeeLevel: 'high', - }); - - const result = txStateManager.getTransaction('1'); - assert.equal(result.userEditedGasLimit, '0x0088'); - assert.equal(result.userFeeLevel, 'high'); - }); - it('should not update and should throw error if status is not type "unapproved"', function () { txStateManager.addTransaction({ id: '4', @@ -3490,8 +3209,8 @@ describe('Transaction Controller', function () { }, }; - txController.addTransaction(firstTxMeta); - txController.addTransaction(secondTxMeta); + txController._addTransaction(firstTxMeta); + txController._addTransaction(secondTxMeta); await txController.initApprovals(); @@ -3535,7 +3254,7 @@ describe('Transaction Controller', function () { }, }; - txController.addTransaction(txMeta); + txController._addTransaction(txMeta); const transaction1 = txController.updateTransactionSendFlowHistory( txId, diff --git a/app/scripts/lib/ppom/indexed-db-backend.test.ts b/app/scripts/lib/ppom/indexed-db-backend.test.ts new file mode 100644 index 000000000..3aca51959 --- /dev/null +++ b/app/scripts/lib/ppom/indexed-db-backend.test.ts @@ -0,0 +1,93 @@ +import 'fake-indexeddb/auto'; + +import { IndexedDBPPOMStorage } from './indexed-db-backend'; + +Object.defineProperty(globalThis, 'crypto', { + value: { + subtle: { + digest: () => new ArrayBuffer(12), + }, + }, +}); + +const enc = new TextEncoder(); +const dec = new TextDecoder('utf-8'); + +describe('IndexedDBPPOMStorage', () => { + it('should be able to initialise correctly', () => { + const indexDBBackend = new IndexedDBPPOMStorage('PPOMDB', 1); + expect(indexDBBackend).toBeDefined(); + }); + + it('should be able to write and read file data if checksum matches', async () => { + const indexDBBackend = new IndexedDBPPOMStorage('PPOMDB', 1); + await indexDBBackend.write( + { name: 'fake_name', chainId: '5' }, + enc.encode('fake_data'), + '000000000000000000000000', + ); + const file = await indexDBBackend.read( + { name: 'fake_name', chainId: '5' }, + '000000000000000000000000', + ); + expect(dec.decode(file)).toStrictEqual('fake_data'); + }); + + it('should fail to write if checksum does not match', async () => { + const indexDBBackend = new IndexedDBPPOMStorage('PPOMDB', 1); + await expect(async () => { + await indexDBBackend.write( + { name: 'fake_name', chainId: '5' }, + enc.encode('fake_data'), + 'XXX', + ); + }).rejects.toThrow('Checksum mismatch'); + }); + + it('should fail to read if checksum does not match', async () => { + const indexDBBackend = new IndexedDBPPOMStorage('PPOMDB', 1); + await expect(async () => { + await indexDBBackend.write( + { name: 'fake_name', chainId: '5' }, + enc.encode('fake_data'), + '000000000000000000000000', + ); + await indexDBBackend.read({ name: 'fake_name', chainId: '5' }, 'XXX'); + }).rejects.toThrow('Checksum mismatch'); + }); + + it('should delete a file when delete method is called', async () => { + const indexDBBackend = new IndexedDBPPOMStorage('PPOMDB', 1); + await indexDBBackend.write( + { name: 'fake_name', chainId: '5' }, + enc.encode('fake_data'), + '000000000000000000000000', + ); + await indexDBBackend.delete({ name: 'fake_name', chainId: '5' }); + const result = await indexDBBackend.read( + { name: 'fake_name', chainId: '5' }, + '000000000000000000000000', + ); + expect(result).toBeUndefined(); + }); + + it('should list all keys when dir is called', async () => { + const keys = [ + { chainId: '5', name: 'fake_name_1' }, + { chainId: '1', name: 'fake_name_2' }, + ]; + const indexDBBackend = new IndexedDBPPOMStorage('PPOMDB', 1); + await indexDBBackend.write( + keys[0], + enc.encode('fake_data_1'), + '000000000000000000000000', + ); + await indexDBBackend.write( + keys[1], + enc.encode('fake_data_2'), + '000000000000000000000000', + ); + const result = await indexDBBackend.dir(); + expect(result).toStrictEqual(keys); + }); +}); diff --git a/app/scripts/lib/ppom/indexed-db-backend.ts b/app/scripts/lib/ppom/indexed-db-backend.ts new file mode 100644 index 000000000..41c5af262 --- /dev/null +++ b/app/scripts/lib/ppom/indexed-db-backend.ts @@ -0,0 +1,127 @@ +import { StorageBackend } from '@metamask/ppom-validator'; + +type StorageKey = { + name: string; + chainId: string; +}; + +const validateChecksum = async ( + key: StorageKey, + data: ArrayBuffer, + checksum: string, +) => { + const hash = await crypto.subtle.digest('SHA-256', data); + const hashString = Array.from(new Uint8Array(hash)) + .map((b) => b.toString(16).padStart(2, '0')) + .join(''); + + if (hashString !== checksum) { + throw new Error(`Checksum mismatch for key ${key}`); + } +}; + +export class IndexedDBPPOMStorage implements StorageBackend { + private storeName: string; + + private dbVersion: number; + + constructor(storeName: string, dbVersion: number) { + this.storeName = storeName; + this.dbVersion = dbVersion; + } + + #getObjectStore(mode: IDBTransactionMode): Promise { + return new Promise((resolve, reject) => { + const request = indexedDB.open(this.storeName, this.dbVersion); + + request.onerror = (event: Event) => { + reject( + new Error( + `Failed to open database ${this.storeName}: ${ + (event.target as any)?.error + }`, + ), + ); + }; + + request.onupgradeneeded = (event) => { + const db = (event.target as IDBOpenDBRequest).result; + + if (!db.objectStoreNames.contains(this.storeName)) { + db.createObjectStore(this.storeName, { + keyPath: ['name', 'chainId'], + }); + } + }; + + request.onsuccess = (event) => { + const db = (event.target as IDBOpenDBRequest).result; + const transaction = db.transaction([this.storeName], mode); + const objectStore = transaction.objectStore(this.storeName); + resolve(objectStore); + }; + }); + } + + private async objectStoreAction( + method: 'get' | 'delete' | 'put' | 'getAllKeys', + args?: any, + mode: IDBTransactionMode = 'readonly', + ): Promise { + return new Promise((resolve, reject) => { + this.#getObjectStore(mode) + .then((objectStore) => { + const request = objectStore[method](args); + + request.onsuccess = async (event) => { + resolve(event); + }; + + request.onerror = (event) => { + reject( + new Error( + `Error in indexDB operation ${method}: ${ + (event.target as any)?.error + }`, + ), + ); + }; + }) + .catch((error) => { + reject(error); + }); + }); + } + + async read(key: StorageKey, checksum: string): Promise { + const event = await this.objectStoreAction('get', [key.name, key.chainId]); + const data = (event.target as any)?.result?.data; + await validateChecksum(key, data, checksum); + return data; + } + + async write( + key: StorageKey, + data: ArrayBuffer, + checksum: string, + ): Promise { + await validateChecksum(key, data, checksum); + await this.objectStoreAction('put', { ...key, data }, 'readwrite'); + } + + async delete(key: StorageKey): Promise { + await this.objectStoreAction( + 'delete', + [key.name, key.chainId], + 'readwrite', + ); + } + + async dir(): Promise { + const event = await this.objectStoreAction('getAllKeys'); + return (event.target as any)?.result.map(([name, chainId]: string[]) => ({ + name, + chainId, + })); + } +} diff --git a/app/scripts/lib/ppom/ppom-middleware.test.ts b/app/scripts/lib/ppom/ppom-middleware.test.ts new file mode 100644 index 000000000..be7b5558d --- /dev/null +++ b/app/scripts/lib/ppom/ppom-middleware.test.ts @@ -0,0 +1,110 @@ +import { createPPOMMiddleware } from './ppom-middleware'; + +Object.defineProperty(globalThis, 'fetch', { + writable: true, + value: () => undefined, +}); + +Object.defineProperty(globalThis, 'performance', { + writable: true, + value: () => undefined, +}); + +describe('PPOMMiddleware', () => { + it('should call ppomController.usePPOM for requests of type confirmation', async () => { + const useMock = jest.fn(); + const controller = { + usePPOM: useMock, + }; + const middlewareFunction = createPPOMMiddleware(controller as any); + await middlewareFunction( + { method: 'eth_sendTransaction' }, + undefined, + () => undefined, + ); + expect(useMock).toHaveBeenCalledTimes(1); + }); + + it('should add validation response on confirmation requests', async () => { + const controller = { + usePPOM: async () => Promise.resolve('VALIDATION_RESULT'), + }; + const middlewareFunction = createPPOMMiddleware(controller as any); + const req = { method: 'eth_sendTransaction', ppomResponse: undefined }; + await middlewareFunction(req, undefined, () => undefined); + expect(req.ppomResponse).toBeDefined(); + }); + + it('should call next method when ppomController.usePPOM completes', async () => { + const ppom = { + validateJsonRpc: () => undefined, + }; + const controller = { + usePPOM: async (callback: any) => { + callback(ppom); + }, + }; + const middlewareFunction = createPPOMMiddleware(controller as any); + const nextMock = jest.fn(); + await middlewareFunction( + { method: 'eth_sendTransaction' }, + undefined, + nextMock, + ); + expect(nextMock).toHaveBeenCalledTimes(1); + }); + + it('should call next method when ppomController.usePPOM throws error', async () => { + const controller = { + usePPOM: async (_callback: any) => { + throw Error('Some error'); + }, + }; + const middlewareFunction = createPPOMMiddleware(controller as any); + const nextMock = jest.fn(); + await middlewareFunction( + { method: 'eth_sendTransaction' }, + undefined, + nextMock, + ); + expect(nextMock).toHaveBeenCalledTimes(1); + }); + + it('should call ppom.validateJsonRpc when invoked', async () => { + const validateMock = jest.fn(); + const ppom = { + validateJsonRpc: validateMock, + }; + const controller = { + usePPOM: async (callback: any) => { + callback(ppom); + }, + }; + const middlewareFunction = createPPOMMiddleware(controller as any); + await middlewareFunction( + { method: 'eth_sendTransaction' }, + undefined, + () => undefined, + ); + expect(validateMock).toHaveBeenCalledTimes(1); + }); + + it('should not call ppom.validateJsonRpc when request is not for confirmation method', async () => { + const validateMock = jest.fn(); + const ppom = { + validateJsonRpc: validateMock, + }; + const controller = { + usePPOM: async (callback: any) => { + callback(ppom); + }, + }; + const middlewareFunction = createPPOMMiddleware(controller as any); + await middlewareFunction( + { method: 'eth_someRequest' }, + undefined, + () => undefined, + ); + expect(validateMock).toHaveBeenCalledTimes(0); + }); +}); diff --git a/app/scripts/lib/ppom/ppom-middleware.ts b/app/scripts/lib/ppom/ppom-middleware.ts new file mode 100644 index 000000000..c58f74d60 --- /dev/null +++ b/app/scripts/lib/ppom/ppom-middleware.ts @@ -0,0 +1,43 @@ +import { PPOM } from '@blockaid/ppom'; + +import { PPOMController } from '@metamask/ppom-validator'; + +const ConfirmationMethods = Object.freeze([ + 'eth_sendRawTransaction', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + 'personal_sign', +]); + +/** + * Middleware function that handles JSON RPC requests. + * This function will be called for every JSON RPC request. + * It will call the PPOM to check if the request is malicious or benign. + * If the request is benign, it will be forwarded to the next middleware. + * If the request is malicious or warning, it will trigger the PPOM alert dialog, + * after the user has confirmed or rejected the request, + * the request will be forwarded to the next middleware, together with the PPOM response. + * + * @param ppomController - Instance of PPOMController. + * @returns PPOMMiddleware function. + */ +export function createPPOMMiddleware(ppomController: PPOMController) { + return async (req: any, _res: any, next: () => void) => { + try { + if (ConfirmationMethods.includes(req.method)) { + // eslint-disable-next-line require-atomic-updates + req.ppomResponse = await ppomController.usePPOM(async (ppom: PPOM) => { + return ppom.validateJsonRpc(req); + }); + } + } catch (error: unknown) { + console.error('Error validating JSON RPC using PPOM: ', error); + } finally { + next(); + } + }; +} diff --git a/app/scripts/lib/ppom/ppom.js b/app/scripts/lib/ppom/ppom.js new file mode 100644 index 000000000..39915b3a4 --- /dev/null +++ b/app/scripts/lib/ppom/ppom.js @@ -0,0 +1,573 @@ +/* eslint-disable */ + +let wasm; + +const heap = new Array(128).fill(undefined); + +heap.push(undefined, null, true, false); + +function getObject(idx) { + return heap[idx]; +} + +let heap_next = heap.length; + +function dropObject(idx) { + if (idx < 132) return; + heap[idx] = heap_next; + heap_next = idx; +} + +function takeObject(idx) { + const ret = getObject(idx); + dropObject(idx); + return ret; +} + +let WASM_VECTOR_LEN = 0; + +let cachedUint8Memory0 = null; + +function getUint8Memory0() { + if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) { + cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer); + } + return cachedUint8Memory0; +} + +const cachedTextEncoder = + typeof TextEncoder !== 'undefined' + ? new TextEncoder('utf-8') + : { + encode: () => { + throw Error('TextEncoder not available'); + }, + }; + +const encodeString = + typeof cachedTextEncoder.encodeInto === 'function' + ? function (arg, view) { + return cachedTextEncoder.encodeInto(arg, view); + } + : function (arg, view) { + const buf = cachedTextEncoder.encode(arg); + view.set(buf); + return { + read: arg.length, + written: buf.length, + }; + }; + +function passStringToWasm0(arg, malloc, realloc) { + if (realloc === undefined) { + const buf = cachedTextEncoder.encode(arg); + const ptr = malloc(buf.length, 1) >>> 0; + getUint8Memory0() + .subarray(ptr, ptr + buf.length) + .set(buf); + WASM_VECTOR_LEN = buf.length; + return ptr; + } + + let len = arg.length; + let ptr = malloc(len, 1) >>> 0; + + const mem = getUint8Memory0(); + + let offset = 0; + + for (; offset < len; offset++) { + const code = arg.charCodeAt(offset); + if (code > 0x7f) break; + mem[ptr + offset] = code; + } + + if (offset !== len) { + if (offset !== 0) { + arg = arg.slice(offset); + } + ptr = realloc(ptr, len, (len = offset + arg.length * 3), 1) >>> 0; + const view = getUint8Memory0().subarray(ptr + offset, ptr + len); + const ret = encodeString(arg, view); + + offset += ret.written; + } + + WASM_VECTOR_LEN = offset; + return ptr; +} + +function isLikeNone(x) { + return x === undefined || x === null; +} + +let cachedInt32Memory0 = null; + +function getInt32Memory0() { + if (cachedInt32Memory0 === null || cachedInt32Memory0.byteLength === 0) { + cachedInt32Memory0 = new Int32Array(wasm.memory.buffer); + } + return cachedInt32Memory0; +} + +const cachedTextDecoder = + typeof TextDecoder !== 'undefined' + ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) + : { + decode: () => { + throw Error('TextDecoder not available'); + }, + }; + +if (typeof TextDecoder !== 'undefined') { + cachedTextDecoder.decode(); +} + +function getStringFromWasm0(ptr, len) { + ptr = ptr >>> 0; + return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len)); +} + +function addHeapObject(obj) { + if (heap_next === heap.length) heap.push(heap.length + 1); + const idx = heap_next; + heap_next = heap[idx]; + + heap[idx] = obj; + return idx; +} + +function debugString(val) { + // primitive types + const type = typeof val; + if (type == 'number' || type == 'boolean' || val == null) { + return `${val}`; + } + if (type == 'string') { + return `"${val}"`; + } + if (type == 'symbol') { + const description = val.description; + if (description == null) { + return 'Symbol'; + } else { + return `Symbol(${description})`; + } + } + if (type == 'function') { + const name = val.name; + if (typeof name == 'string' && name.length > 0) { + return `Function(${name})`; + } else { + return 'Function'; + } + } + // objects + if (Array.isArray(val)) { + const length = val.length; + let debug = '['; + if (length > 0) { + debug += debugString(val[0]); + } + for (let i = 1; i < length; i++) { + debug += ', ' + debugString(val[i]); + } + debug += ']'; + return debug; + } + // Test for built-in + const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val)); + let className; + if (builtInMatches.length > 1) { + className = builtInMatches[1]; + } else { + // Failed to match the standard '[object ClassName]' + return toString.call(val); + } + if (className == 'Object') { + // we're a user defined class or Object + // JSON.stringify avoids problems with cycles, and is generally much + // easier than looping through ownProperties of `val`. + try { + return 'Object(' + JSON.stringify(val) + ')'; + } catch (_) { + return 'Object'; + } + } + // errors + if (val instanceof Error) { + return `${val.name}: ${val.message}\n${val.stack}`; + } + // TODO we could test for more things here, like `Set`s and `Map`s. + return className; +} + +function makeMutClosure(arg0, arg1, dtor, f) { + const state = { a: arg0, b: arg1, cnt: 1 }; + const real = (...args) => { + // First up with a closure we increment the internal reference + // count. This ensures that the Rust closure environment won't + // be deallocated while we're invoking it. + state.cnt++; + const a = state.a; + state.a = 0; + try { + return f(a, state.b, ...args); + } finally { + if (--state.cnt === 0) { + dtor(a, state.b); + } else { + state.a = a; + } + } + }; + real.original = state; + + return real; +} +function __wbg_adapter_20(arg0, arg1, arg2) { + wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke( + arg0, + arg1, + addHeapObject(arg2), + ); +} + +function __wbg_adapter_21(arg0, arg1) { + wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__destroy( + arg0, + arg1, + ); +} + +/** + */ +export function main() { + wasm.main(); +} + +let cachedUint32Memory0 = null; + +function getUint32Memory0() { + if (cachedUint32Memory0 === null || cachedUint32Memory0.byteLength === 0) { + cachedUint32Memory0 = new Uint32Array(wasm.memory.buffer); + } + return cachedUint32Memory0; +} + +function passArrayJsValueToWasm0(array, malloc) { + const ptr = malloc(array.length * 4, 4) >>> 0; + const mem = getUint32Memory0(); + for (let i = 0; i < array.length; i++) { + mem[ptr / 4 + i] = addHeapObject(array[i]); + } + WASM_VECTOR_LEN = array.length; + return ptr; +} + +function handleError(f, args) { + try { + return f.apply(this, args); + } catch (e) { + wasm.__wbindgen_exn_store(addHeapObject(e)); + } +} +function __wbg_adapter_39(arg0, arg1, arg2, arg3) { + wasm.wasm_bindgen__convert__closures__invoke2_mut( + arg0, + arg1, + addHeapObject(arg2), + addHeapObject(arg3), + ); +} + +/** + * JavaScript wrapper for [`PPOM`] + */ +export class PPOM { + static __wrap(ptr) { + ptr = ptr >>> 0; + const obj = Object.create(PPOM.prototype); + obj.__wbg_ptr = ptr; + + return obj; + } + + __destroy_into_raw() { + const ptr = this.__wbg_ptr; + this.__wbg_ptr = 0; + + return ptr; + } + + free() { + const ptr = this.__destroy_into_raw(); + wasm.__wbg_ppom_free(ptr); + } + /** + * @param {Function} json_rpc_callback + * @param {any[]} files + * @returns {Promise} + */ + static new(json_rpc_callback, files) { + const ptr0 = passArrayJsValueToWasm0(files, wasm.__wbindgen_malloc); + const len0 = WASM_VECTOR_LEN; + const ret = wasm.ppom_new(addHeapObject(json_rpc_callback), ptr0, len0); + return takeObject(ret); + } + /** + * @param {any} request + * @returns {Promise} + */ + validateJsonRpc(request) { + const ret = wasm.ppom_validateJsonRpc( + this.__wbg_ptr, + addHeapObject(request), + ); + return takeObject(ret); + } +} + +async function __wbg_load(module, imports) { + if (typeof Response === 'function' && module instanceof Response) { + if (typeof WebAssembly.instantiateStreaming === 'function') { + try { + return await WebAssembly.instantiateStreaming(module, imports); + } catch (e) { + if (module.headers.get('Content-Type') != 'application/wasm') { + console.warn( + '`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n', + e, + ); + } else { + throw e; + } + } + } + + const bytes = await module.arrayBuffer(); + return await WebAssembly.instantiate(bytes, imports); + } else { + const instance = await WebAssembly.instantiate(module, imports); + + if (instance instanceof WebAssembly.Instance) { + return { instance, module }; + } else { + return instance; + } + } +} + +function __wbg_get_imports() { + const imports = {}; + imports.wbg = {}; + imports.wbg.__wbg_buffer_085ec1f694018c4f = function (arg0) { + const ret = getObject(arg0).buffer; + return addHeapObject(ret); + }; + imports.wbg.__wbg_call_01734de55d61e11d = function () { + return handleError(function (arg0, arg1, arg2) { + const ret = getObject(arg0).call(getObject(arg1), getObject(arg2)); + return addHeapObject(ret); + }, arguments); + }; + imports.wbg.__wbg_call_4c92f6aec1e1d6e6 = function () { + return handleError(function (arg0, arg1, arg2, arg3) { + const ret = getObject(arg0).call( + getObject(arg1), + getObject(arg2), + getObject(arg3), + ); + return addHeapObject(ret); + }, arguments); + }; + imports.wbg.__wbg_from_d7c216d4616bb368 = function (arg0) { + const ret = Array.from(getObject(arg0)); + return addHeapObject(ret); + }; + imports.wbg.__wbg_get_44be0491f933a435 = function (arg0, arg1) { + const ret = getObject(arg0)[arg1 >>> 0]; + return addHeapObject(ret); + }; + imports.wbg.__wbg_length_72e2208bbc0efc61 = function (arg0) { + const ret = getObject(arg0).length; + return ret; + }; + imports.wbg.__wbg_length_d813e535247d427e = function (arg0) { + const ret = getObject(arg0).length; + return ret; + }; + imports.wbg.__wbg_length_fff51ee6522a1a18 = function (arg0) { + const ret = getObject(arg0).length; + return ret; + }; + imports.wbg.__wbg_new_43f1b47c28813cbd = function (arg0, arg1) { + try { + var state0 = { a: arg0, b: arg1 }; + var cb0 = (arg0, arg1) => { + const a = state0.a; + state0.a = 0; + try { + return __wbg_adapter_39(a, state0.b, arg0, arg1); + } finally { + state0.a = a; + } + }; + const ret = new Promise(cb0); + return addHeapObject(ret); + } finally { + state0.a = state0.b = 0; + } + }; + imports.wbg.__wbg_new_8125e318e6245eed = function (arg0) { + const ret = new Uint8Array(getObject(arg0)); + return addHeapObject(ret); + }; + imports.wbg.__wbg_parse_670c19d4e984792e = function () { + return handleError(function (arg0, arg1) { + const ret = JSON.parse(getStringFromWasm0(arg0, arg1)); + return addHeapObject(ret); + }, arguments); + }; + imports.wbg.__wbg_ppom_new = function (arg0) { + const ret = PPOM.__wrap(arg0); + return addHeapObject(ret); + }; + imports.wbg.__wbg_resolve_53698b95aaf7fcf8 = function (arg0) { + const ret = Promise.resolve(getObject(arg0)); + return addHeapObject(ret); + }; + imports.wbg.__wbg_set_5cf90238115182c3 = function (arg0, arg1, arg2) { + getObject(arg0).set(getObject(arg1), arg2 >>> 0); + }; + imports.wbg.__wbg_stringify_e25465938f3f611f = function () { + return handleError(function (arg0) { + const ret = JSON.stringify(getObject(arg0)); + return addHeapObject(ret); + }, arguments); + }; + imports.wbg.__wbg_then_b2267541e2a73865 = function (arg0, arg1, arg2) { + const ret = getObject(arg0).then(getObject(arg1), getObject(arg2)); + return addHeapObject(ret); + }; + imports.wbg.__wbg_then_f7e06ee3c11698eb = function (arg0, arg1) { + const ret = getObject(arg0).then(getObject(arg1)); + return addHeapObject(ret); + }; + imports.wbg.__wbindgen_cb_drop = function (arg0) { + const obj = takeObject(arg0).original; + if (obj.cnt-- == 1) { + obj.a = 0; + return true; + } + const ret = false; + return ret; + }; + imports.wbg.__wbindgen_closure_wrapper_wasm_bindgen__closure__Closure_T___wrap__breaks_if_inlined = + function (arg0, arg1, arg2) { + const ret = makeMutClosure( + arg0, + arg1, + __wbg_adapter_21, + __wbg_adapter_20, + ); + return addHeapObject(ret); + }; + imports.wbg.__wbindgen_debug_string = function (arg0, arg1) { + const ret = debugString(getObject(arg1)); + const ptr1 = passStringToWasm0( + ret, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len1 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len1; + getInt32Memory0()[arg0 / 4 + 0] = ptr1; + }; + imports.wbg.__wbindgen_error_new = function (arg0, arg1) { + const ret = new Error(getStringFromWasm0(arg0, arg1)); + return addHeapObject(ret); + }; + imports.wbg.__wbindgen_is_undefined = function (arg0) { + const ret = getObject(arg0) === undefined; + return ret; + }; + imports.wbg.__wbindgen_memory = function () { + const ret = wasm.memory; + return addHeapObject(ret); + }; + imports.wbg.__wbindgen_object_drop_ref = function (arg0) { + takeObject(arg0); + }; + imports.wbg.__wbindgen_string_get = function (arg0, arg1) { + const obj = getObject(arg1); + const ret = typeof obj === 'string' ? obj : undefined; + var ptr1 = isLikeNone(ret) + ? 0 + : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + var len1 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len1; + getInt32Memory0()[arg0 / 4 + 0] = ptr1; + }; + imports.wbg.__wbindgen_string_new = function (arg0, arg1) { + const ret = getStringFromWasm0(arg0, arg1); + return addHeapObject(ret); + }; + imports.wbg.__wbindgen_throw = function (arg0, arg1) { + throw new Error(getStringFromWasm0(arg0, arg1)); + }; + + return imports; +} + +function __wbg_init_memory(imports, maybe_memory) {} + +function __wbg_finalize_init(instance, module) { + wasm = instance.exports; + __wbg_init.__wbindgen_wasm_module = module; + cachedInt32Memory0 = null; + cachedUint32Memory0 = null; + cachedUint8Memory0 = null; + + wasm.__wbindgen_start(); + return wasm; +} + +function initSync(module) { + if (wasm !== undefined) return wasm; + + const imports = __wbg_get_imports(); + + __wbg_init_memory(imports); + + if (!(module instanceof WebAssembly.Module)) { + module = new WebAssembly.Module(module); + } + + const instance = new WebAssembly.Instance(module, imports); + + return __wbg_finalize_init(instance, module); +} + +async function __wbg_init(input) { + if (wasm !== undefined) return wasm; + + const imports = __wbg_get_imports(); + + if ( + typeof input === 'string' || + (typeof Request === 'function' && input instanceof Request) || + (typeof URL === 'function' && input instanceof URL) + ) { + input = fetch(input); + } + + __wbg_init_memory(imports); + + const { instance, module } = await __wbg_load(await input, imports); + + return __wbg_finalize_init(instance, module); +} + +export { initSync }; +export default __wbg_init; diff --git a/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.js b/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.js index 6d71ba602..e2137da87 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.js +++ b/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.js @@ -116,7 +116,7 @@ async function switchEthereumChainHandler( if ( Object.values(BUILT_IN_INFURA_NETWORKS) .map(({ chainId: id }) => id) - .includes(chainId) + .includes(_chainId) ) { await setProviderType(approvedRequestData.type); } else { diff --git a/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.test.js b/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.test.js new file mode 100644 index 000000000..410697214 --- /dev/null +++ b/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.test.js @@ -0,0 +1,128 @@ +import { + CHAIN_IDS, + NETWORK_TYPES, +} from '../../../../../shared/constants/network'; +import switchEthereumChain from './switch-ethereum-chain'; + +const NON_INFURA_CHAIN_ID = '0x123456789'; + +const mockRequestUserApproval = ({ requestData }) => { + return Promise.resolve(requestData); +}; + +const MOCK_MAINNET_CONFIGURATION = { + id: 123, + chainId: CHAIN_IDS.MAINNET, + type: NETWORK_TYPES.MAINNET, +}; +const MOCK_LINEA_MAINNET_CONFIGURATION = { + id: 123, + chainId: CHAIN_IDS.LINEA_MAINNET, + type: NETWORK_TYPES.LINEA_MAINNET, +}; + +describe('switchEthereumChainHandler', () => { + it('should call setProviderType when switching to a built in infura network', async () => { + const mockSetProviderType = jest.fn(); + const mockSetActiveNetwork = jest.fn(); + const switchEthereumChainHandler = switchEthereumChain.implementation; + await switchEthereumChainHandler( + { + origin: 'example.com', + params: [{ chainId: CHAIN_IDS.MAINNET }], + }, + {}, + jest.fn(), + jest.fn(), + { + getCurrentChainId: () => NON_INFURA_CHAIN_ID, + findNetworkConfigurationBy: () => MOCK_MAINNET_CONFIGURATION, + setProviderType: mockSetProviderType, + setActiveNetwork: mockSetActiveNetwork, + requestUserApproval: mockRequestUserApproval, + }, + ); + expect(mockSetProviderType).toHaveBeenCalledTimes(1); + expect(mockSetProviderType).toHaveBeenCalledWith( + MOCK_MAINNET_CONFIGURATION.type, + ); + }); + + it('should call setProviderType when switching to a built in infura network, when chainId from request is lower case', async () => { + const mockSetProviderType = jest.fn(); + const mockSetActiveNetwork = jest.fn(); + const switchEthereumChainHandler = switchEthereumChain.implementation; + await switchEthereumChainHandler( + { + origin: 'example.com', + params: [{ chainId: CHAIN_IDS.LINEA_MAINNET.toLowerCase() }], + }, + {}, + jest.fn(), + jest.fn(), + { + getCurrentChainId: () => NON_INFURA_CHAIN_ID, + findNetworkConfigurationBy: () => MOCK_LINEA_MAINNET_CONFIGURATION, + setProviderType: mockSetProviderType, + setActiveNetwork: mockSetActiveNetwork, + requestUserApproval: mockRequestUserApproval, + }, + ); + expect(mockSetProviderType).toHaveBeenCalledTimes(1); + expect(mockSetProviderType).toHaveBeenCalledWith( + MOCK_LINEA_MAINNET_CONFIGURATION.type, + ); + }); + + it('should call setProviderType when switching to a built in infura network, when chainId from request is upper case', async () => { + const mockSetProviderType = jest.fn(); + const mockSetActiveNetwork = jest.fn(); + const switchEthereumChainHandler = switchEthereumChain.implementation; + await switchEthereumChainHandler( + { + origin: 'example.com', + params: [{ chainId: CHAIN_IDS.LINEA_MAINNET.toUpperCase() }], + }, + {}, + jest.fn(), + jest.fn(), + { + getCurrentChainId: () => NON_INFURA_CHAIN_ID, + findNetworkConfigurationBy: () => MOCK_LINEA_MAINNET_CONFIGURATION, + setProviderType: mockSetProviderType, + setActiveNetwork: mockSetActiveNetwork, + requestUserApproval: mockRequestUserApproval, + }, + ); + expect(mockSetProviderType).toHaveBeenCalledTimes(1); + expect(mockSetProviderType).toHaveBeenCalledWith( + MOCK_LINEA_MAINNET_CONFIGURATION.type, + ); + }); + + it('should call setActiveNetwork when switching to a custom network', async () => { + const mockSetProviderType = jest.fn(); + const mockSetActiveNetwork = jest.fn(); + const switchEthereumChainHandler = switchEthereumChain.implementation; + await switchEthereumChainHandler( + { + origin: 'example.com', + params: [{ chainId: NON_INFURA_CHAIN_ID }], + }, + {}, + jest.fn(), + jest.fn(), + { + getCurrentChainId: () => CHAIN_IDS.MAINNET, + findNetworkConfigurationBy: () => MOCK_MAINNET_CONFIGURATION, + setProviderType: mockSetProviderType, + setActiveNetwork: mockSetActiveNetwork, + requestUserApproval: mockRequestUserApproval, + }, + ); + expect(mockSetActiveNetwork).toHaveBeenCalledTimes(1); + expect(mockSetActiveNetwork).toHaveBeenCalledWith( + MOCK_MAINNET_CONFIGURATION.id, + ); + }); +}); diff --git a/app/scripts/lib/setupSentry.js b/app/scripts/lib/setupSentry.js index a383f8221..7df0cea78 100644 --- a/app/scripts/lib/setupSentry.js +++ b/app/scripts/lib/setupSentry.js @@ -133,8 +133,45 @@ export default function setupSentry({ release, getState }) { Sentry.init({ dsn: sentryTarget, debug: METAMASK_DEBUG, + /** + * autoSessionTracking defaults to true and operates by sending a session + * packet to sentry. This session packet does not appear to be filtered out + * via our beforeSend or FilterEvents integration. To avoid sending a + * request before we have the state tree and can validate the users + * preferences, we initiate this to false. Later, in startSession and + * endSession we modify this option and start the session or end the + * session manually. + * + * In sentry-install we call toggleSession after the page loads and state + * is available, this handles initiating the session for a user who has + * opted into MetaMetrics. This script is ran in both the background and UI + * so it should be effective at starting the session in both places. + * + * In the MetaMetricsController the session is manually started or stopped + * when the user opts in or out of MetaMetrics. This occurs in the + * setParticipateInMetaMetrics function which is exposed to the UI via the + * MetaMaskController. + * + * In actions.ts, after sending the updated participateInMetaMetrics flag + * to the background, we call toggleSession to ensure sentry is kept in + * sync with the user's preference. + * + * Types for the global Sentry object, and the new methods added as part of + * this effort were added to global.d.ts in the types folder. + */ + autoSessionTracking: false, environment, integrations: [ + /** + * Filtering of events must happen in this FilterEvents custom + * integration instead of in the beforeSend handler because the Dedupe + * integration is unaware of the beforeSend functionality. If an event is + * queued in the sentry context, additional events of the same name will + * be filtered out by Dedupe even if the original event was not sent due + * to the beforeSend method returning null. + * + * @see https://github.com/MetaMask/metamask-extension/pull/15677 + */ new FilterEvents({ getMetaMetricsEnabled }), new Dedupe(), new ExtraErrorData(), @@ -144,7 +181,64 @@ export default function setupSentry({ release, getState }) { beforeBreadcrumb: beforeBreadcrumb(getState), }); - return Sentry; + /** + * As long as a reference to the Sentry Hub can be found, and the user has + * opted into MetaMetrics, change the autoSessionTracking option and start + * a new sentry session. + */ + const startSession = () => { + const hub = Sentry.getCurrentHub?.(); + const options = hub.getClient?.().getOptions?.() ?? {}; + if (hub && getMetaMetricsEnabled() === true) { + options.autoSessionTracking = true; + hub.startSession(); + } + }; + + /** + * As long as a reference to the Sentry Hub can be found, and the user has + * opted out of MetaMetrics, change the autoSessionTracking option and end + * the current sentry session. + */ + const endSession = () => { + const hub = Sentry.getCurrentHub?.(); + const options = hub.getClient?.().getOptions?.() ?? {}; + if (hub && getMetaMetricsEnabled() === false) { + options.autoSessionTracking = false; + hub.endSession(); + } + }; + + /** + * Call the appropriate method (either startSession or endSession) depending + * on the state of metaMetrics optin and the state of autoSessionTracking on + * the Sentry client. + */ + const toggleSession = () => { + const hub = Sentry.getCurrentHub?.(); + const options = hub.getClient?.().getOptions?.() ?? { + autoSessionTracking: false, + }; + const isMetaMetricsEnabled = getMetaMetricsEnabled(); + if ( + isMetaMetricsEnabled === true && + options.autoSessionTracking === false + ) { + startSession(); + } else if ( + isMetaMetricsEnabled === false && + options.autoSessionTracking === true + ) { + endSession(); + } + }; + + return { + ...Sentry, + startSession, + endSession, + toggleSession, + }; } /** @@ -352,6 +446,6 @@ function toMetamaskUrl(origUrl) { if (!filePath) { return origUrl; } - const metamaskUrl = `metamask${filePath}`; + const metamaskUrl = `/metamask${filePath}`; return metamaskUrl; } diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 66326a010..dbea5e3ff 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -6,10 +6,8 @@ import { JsonRpcEngine } from 'json-rpc-engine'; import { createEngineStream } from 'json-rpc-middleware-stream'; import { providerAsMiddleware } from '@metamask/eth-json-rpc-middleware'; import { debounce } from 'lodash'; -import { - KeyringController, - keyringBuilderFactory, -} from '@metamask/eth-keyring-controller'; +import { keyringBuilderFactory } from '@metamask/eth-keyring-controller'; +import { KeyringController } from '@metamask/keyring-controller'; import createFilterMiddleware from 'eth-json-rpc-filters'; import createSubscriptionManager from 'eth-json-rpc-filters/subscriptionManager'; import { errorCodes as rpcErrorCodes, EthereumRpcError } from 'eth-rpc-errors'; @@ -76,6 +74,9 @@ import { CustodyController } from '@metamask-institutional/custody-controller'; import { TransactionUpdateController } from '@metamask-institutional/transaction-update'; ///: END:ONLY_INCLUDE_IN import { SignatureController } from '@metamask/signature-controller'; +///: BEGIN:ONLY_INCLUDE_IN(blockaid) +import { PPOMController } from '@metamask/ppom-validator'; +///: END:ONLY_INCLUDE_IN ///: BEGIN:ONLY_INCLUDE_IN(desktop) // eslint-disable-next-line import/order @@ -150,6 +151,10 @@ import { isManifestV3 } from '../../shared/modules/mv3.utils'; import { hexToDecimal } from '../../shared/modules/conversion.utils'; import { ACTION_QUEUE_METRICS_E2E_TEST } from '../../shared/constants/test-flags'; +///: BEGIN:ONLY_INCLUDE_IN(blockaid) +import { createPPOMMiddleware } from './lib/ppom/ppom-middleware'; +import * as PPOMModule from './lib/ppom/ppom'; +///: END:ONLY_INCLUDE_IN import { onMessageReceived, checkForMultipleVersionsRunning, @@ -210,6 +215,9 @@ import { } from './controllers/permissions'; import createRPCMethodTrackingMiddleware from './lib/createRPCMethodTrackingMiddleware'; import { securityProviderCheck } from './lib/security-provider-helpers'; +///: BEGIN:ONLY_INCLUDE_IN(blockaid) +import { IndexedDBPPOMStorage } from './lib/ppom/indexed-db-backend'; +///: END:ONLY_INCLUDE_IN import { updateCurrentLocale } from './translate'; export const METAMASK_CONTROLLER_EVENTS = { @@ -489,16 +497,14 @@ export default class MetamaskController extends EventEmitter { this.metaMetricsController.trackEvent({ event: MetaMetricsEventName.NftAdded, category: MetaMetricsEventCategory.Wallet, - properties: { + sensitiveProperties: { token_contract_address: address, token_symbol: symbol, - asset_type: AssetType.NFT, + token_id: tokenId, token_standard: standard, + asset_type: AssetType.NFT, source, }, - sensitiveProperties: { - tokenId, - }, }), }, {}, @@ -630,6 +636,29 @@ export default class MetamaskController extends EventEmitter { this.phishingController.setStalelistRefreshInterval(30 * SECOND); } + ///: BEGIN:ONLY_INCLUDE_IN(blockaid) + this.ppomController = new PPOMController({ + messenger: this.controllerMessenger.getRestricted({ + name: 'PPOMController', + }), + storageBackend: new IndexedDBPPOMStorage('PPOMDB', 1), + provider: this.provider, + ppomProvider: { PPOM: PPOMModule.PPOM, ppomInit: PPOMModule.default }, + state: initState.PPOMController, + chainId: this.networkController.state.providerConfig.chainId, + onNetworkChange: networkControllerMessenger.subscribe.bind( + networkControllerMessenger, + 'NetworkController:stateChange', + ), + securityAlertsEnabled: + this.preferencesController.store.getState().securityAlertsEnabled, + onPreferencesChange: this.preferencesController.store.subscribe.bind( + this.preferencesController.store, + ), + cdnBaseUrl: process.env.BLOCKAID_FILE_CDN, + }); + ///: END:ONLY_INCLUDE_IN + const announcementMessenger = this.controllerMessenger.getRestricted({ name: 'AnnouncementController', }); @@ -799,13 +828,43 @@ export default class MetamaskController extends EventEmitter { ); ///: END:ONLY_INCLUDE_IN - this.keyringController = new KeyringController({ + const keyringControllerMessenger = this.controllerMessenger.getRestricted({ + name: 'KeyringController', + allowedEvents: [ + 'KeyringController:accountRemoved', + 'KeyringController:lock', + 'KeyringController:stateChange', + 'KeyringController:unlock', + ], + allowedActions: ['KeyringController:getState'], + }); + + this.coreKeyringController = new KeyringController({ keyringBuilders: additionalKeyrings, - initState: initState.KeyringController, + state: initState.KeyringController, encryptor: opts.encryptor || undefined, cacheEncryptionKey: isManifestV3, + messenger: keyringControllerMessenger, + removeIdentity: this.preferencesController.removeAddress.bind( + this.preferencesController, + ), + setAccountLabel: this.preferencesController.setAccountLabel.bind( + this.preferencesController, + ), + setSelectedAddress: this.preferencesController.setSelectedAddress.bind( + this.preferencesController, + ), + syncIdentities: this.preferencesController.syncAddresses.bind( + this.preferencesController, + ), + updateIdentities: this.preferencesController.setAddresses.bind( + this.preferencesController, + ), }); + this.keyringController = + this.coreKeyringController.getEthKeyringController(); + this.keyringController.memStore.subscribe((state) => this._onKeyringControllerUpdate(state), ); @@ -892,10 +951,10 @@ export default class MetamaskController extends EventEmitter { }), setupSnapProvider: this.setupSnapProvider.bind(this), }; - this.snapExecutionService = - this.opts.overrides?.createSnapExecutionService?.( - snapExecutionServiceArgs, - ) || new IframeExecutionService(snapExecutionServiceArgs); + + this.snapExecutionService = new IframeExecutionService( + snapExecutionServiceArgs, + ); const snapControllerMessenger = this.controllerMessenger.getRestricted({ name: 'SnapController', @@ -1163,28 +1222,6 @@ export default class MetamaskController extends EventEmitter { }), }); - ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) - this.mmiController = new MMIController({ - mmiConfigurationController: this.mmiConfigurationController, - keyringController: this.keyringController, - txController: this.txController, - securityProviderRequest: this.securityProviderRequest.bind(this), - preferencesController: this.preferencesController, - appStateController: this.appStateController, - transactionUpdateController: this.transactionUpdateController, - custodyController: this.custodyController, - institutionalFeaturesController: this.institutionalFeaturesController, - getState: this.getState.bind(this), - getPendingNonce: this.getPendingNonce.bind(this), - accountTracker: this.accountTracker, - metaMetricsController: this.metaMetricsController, - networkController: this.networkController, - permissionController: this.permissionController, - platform: this.platform, - extension: this.extension, - }); - ///: END:ONLY_INCLUDE_IN - this.txController.on(`tx:status-update`, async (txId, status) => { if ( status === TransactionStatus.confirmed || @@ -1346,6 +1383,29 @@ export default class MetamaskController extends EventEmitter { }, ); + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + this.mmiController = new MMIController({ + mmiConfigurationController: this.mmiConfigurationController, + keyringController: this.keyringController, + txController: this.txController, + securityProviderRequest: this.securityProviderRequest.bind(this), + preferencesController: this.preferencesController, + appStateController: this.appStateController, + transactionUpdateController: this.transactionUpdateController, + custodyController: this.custodyController, + institutionalFeaturesController: this.institutionalFeaturesController, + getState: this.getState.bind(this), + getPendingNonce: this.getPendingNonce.bind(this), + accountTracker: this.accountTracker, + metaMetricsController: this.metaMetricsController, + networkController: this.networkController, + permissionController: this.permissionController, + signatureController: this.signatureController, + platform: this.platform, + extension: this.extension, + }); + ///: END:ONLY_INCLUDE_IN + this.swapsController = new SwapsController( { getBufferedGasLimit: @@ -1463,6 +1523,7 @@ export default class MetamaskController extends EventEmitter { // tx signing processTransaction: this.newUnapprovedTransaction.bind(this), // msg signing + ///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask) processEthSignMessage: this.signatureController.newUnsignedMessage.bind( this.signatureController, ), @@ -1482,8 +1543,25 @@ export default class MetamaskController extends EventEmitter { this.signatureController.newUnsignedPersonalMessage.bind( this.signatureController, ), + ///: END:ONLY_INCLUDE_IN ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + /* eslint-disable no-dupe-keys */ + processEthSignMessage: this.mmiController.newUnsignedMessage.bind( + this.mmiController, + ), + processTypedMessage: this.mmiController.newUnsignedMessage.bind( + this.mmiController, + ), + processTypedMessageV3: this.mmiController.newUnsignedMessage.bind( + this.mmiController, + ), + processTypedMessageV4: this.mmiController.newUnsignedMessage.bind( + this.mmiController, + ), + processPersonalMessage: this.mmiController.newUnsignedMessage.bind( + this.mmiController, + ), setTypedMessageInProgress: this.signatureController.setTypedMessageInProgress.bind( this.signatureController, @@ -1492,6 +1570,7 @@ export default class MetamaskController extends EventEmitter { this.signatureController.setPersonalMessageInProgress.bind( this.signatureController, ), + /* eslint-enable no-dupe-keys */ ///: END:ONLY_INCLUDE_IN processEncryptionPublicKey: @@ -1529,6 +1608,9 @@ export default class MetamaskController extends EventEmitter { SwapsController: this.swapsController.store, EnsController: this.ensController.store, ApprovalController: this.approvalController, + ///: BEGIN:ONLY_INCLUDE_IN(blockaid) + PPOMController: this.ppomController, + ///: END:ONLY_INCLUDE_IN }; this.store.updateStructure({ @@ -1571,6 +1653,9 @@ export default class MetamaskController extends EventEmitter { this.institutionalFeaturesController.store, MmiConfigurationController: this.mmiConfigurationController.store, ///: END:ONLY_INCLUDE_IN + ///: BEGIN:ONLY_INCLUDE_IN(blockaid) + PPOMController: this.ppomController, + ///: END:ONLY_INCLUDE_IN ...resetOnRestartStore, }); @@ -2053,9 +2138,21 @@ export default class MetamaskController extends EventEmitter { const { vault } = this.keyringController.store.getState(); const isInitialized = Boolean(vault); + const flatState = this.memStore.getFlatState(); + return { isInitialized, - ...this.memStore.getFlatState(), + ...flatState, + ///: BEGIN:ONLY_INCLUDE_IN(snaps) + // Snap state and source code is stripped out to prevent piping to the MetaMask UI. + snapStates: {}, + snaps: Object.values(flatState.snaps ?? {}).reduce((acc, snap) => { + // eslint-disable-next-line no-unused-vars + const { sourceCode, ...rest } = snap; + acc[snap.id] = rest; + return acc; + }, {}), + ///: END:ONLY_INCLUDE_IN }; } @@ -2125,6 +2222,12 @@ export default class MetamaskController extends EventEmitter { setOpenSeaEnabled: preferencesController.setOpenSeaEnabled.bind( preferencesController, ), + ///: BEGIN:ONLY_INCLUDE_IN(blockaid) + setSecurityAlertsEnabled: + preferencesController.setSecurityAlertsEnabled.bind( + preferencesController, + ), + ///: END:ONLY_INCLUDE_IN setIpfsGateway: preferencesController.setIpfsGateway.bind( preferencesController, ), @@ -2333,8 +2436,9 @@ export default class MetamaskController extends EventEmitter { createSpeedUpTransaction: this.createSpeedUpTransaction.bind(this), estimateGas: this.estimateGas.bind(this), getNextNonce: this.getNextNonce.bind(this), - addUnapprovedTransaction: - txController.addUnapprovedTransaction.bind(txController), + addTransaction: this.addTransaction.bind(this), + addTransactionAndWaitForPublish: + this.addTransactionAndWaitForPublish.bind(this), createTransactionEventFragment: txController.createTransactionEventFragment.bind(txController), getTransactions: txController.getTransactions.bind(txController), @@ -2443,34 +2547,14 @@ export default class MetamaskController extends EventEmitter { this.mmiConfigurationController.getConfiguration.bind( this.mmiConfigurationController, ), - setComplianceAuthData: - this.institutionalFeaturesController.setComplianceAuthData.bind( - this.institutionalFeaturesController, - ), - deleteComplianceAuthData: - this.institutionalFeaturesController.deleteComplianceAuthData.bind( - this.institutionalFeaturesController, - ), - generateComplianceReport: - this.institutionalFeaturesController.generateComplianceReport.bind( - this.institutionalFeaturesController, - ), - syncReportsInProgress: - this.institutionalFeaturesController.syncReportsInProgress.bind( - this.institutionalFeaturesController, - ), - removeConnectInstitutionalFeature: - this.institutionalFeaturesController.removeConnectInstitutionalFeature.bind( - this.institutionalFeaturesController, - ), - getComplianceHistoricalReportsByAddress: - this.institutionalFeaturesController.getComplianceHistoricalReportsByAddress.bind( - this.institutionalFeaturesController, - ), removeAddTokenConnectRequest: this.institutionalFeaturesController.removeAddTokenConnectRequest.bind( this.institutionalFeaturesController, ), + showInteractiveReplacementTokenBanner: + appStateController.showInteractiveReplacementTokenBanner.bind( + appStateController, + ), ///: END:ONLY_INCLUDE_IN ///: BEGIN:ONLY_INCLUDE_IN(snaps) @@ -3482,7 +3566,41 @@ export default class MetamaskController extends EventEmitter { * @param {object} [req] - The original request, containing the origin. */ async newUnapprovedTransaction(txParams, req) { - return await this.txController.newUnapprovedTransaction(txParams, req); + // Options are passed explicitly as an additional security measure + // to ensure approval is not disabled + const { result } = await this.txController.addTransaction(txParams, { + actionId: req.id, + method: req.method, + origin: req.origin, + // This is the default behaviour but specified here for clarity + requireApproval: true, + }); + + return await result; + } + + async addTransactionAndWaitForPublish(txParams, options) { + const { transactionMeta, result } = await this.txController.addTransaction( + txParams, + options, + ); + + await result; + + return transactionMeta; + } + + async addTransaction(txParams, options) { + const { transactionMeta, result } = await this.txController.addTransaction( + txParams, + options, + ); + + result.catch(() => { + // Not concerned with result + }); + + return transactionMeta; } /** @@ -3910,6 +4028,10 @@ export default class MetamaskController extends EventEmitter { engine.push(createLoggerMiddleware({ origin })); engine.push(this.permissionLogController.createMiddleware()); + ///: BEGIN:ONLY_INCLUDE_IN(blockaid) + engine.push(createPPOMMiddleware(this.ppomController)); + ///: END:ONLY_INCLUDE_IN + engine.push( createRPCMethodTrackingMiddleware({ trackEvent: this.metaMetricsController.trackEvent.bind( @@ -3963,6 +4085,12 @@ export default class MetamaskController extends EventEmitter { this.approvalController.setFlowLoadingText.bind( this.approvalController, ), + showApprovalSuccess: this.approvalController.success.bind( + this.approvalController, + ), + showApprovalError: this.approvalController.error.bind( + this.approvalController, + ), sendMetrics: this.metaMetricsController.trackEvent.bind( this.metaMetricsController, ), diff --git a/app/scripts/migrations/089.test.ts b/app/scripts/migrations/089.test.ts new file mode 100644 index 000000000..00868ff74 --- /dev/null +++ b/app/scripts/migrations/089.test.ts @@ -0,0 +1,224 @@ +import { migrate, version } from './089'; + +jest.mock('uuid', () => { + const actual = jest.requireActual('uuid'); + + return { + ...actual, + v4: jest.fn(), + }; +}); + +describe('migration #89', () => { + it('should update the version metadata', async () => { + const oldStorage = { + meta: { + version: 88, + }, + data: {}, + }; + + const newStorage = await migrate(oldStorage); + expect(newStorage.meta).toStrictEqual({ + version, + }); + }); + + it('should return state unaltered if there is no network controller state', async () => { + const oldData = { + other: 'data', + }; + const oldStorage = { + meta: { + version: 88, + }, + data: oldData, + }; + + const newStorage = await migrate(oldStorage); + expect(newStorage.data).toStrictEqual(oldData); + }); + + it('should return state unaltered if there is no network controller providerConfig state', async () => { + const oldData = { + other: 'data', + NetworkController: { + networkConfigurations: { + id1: { + foo: 'bar', + }, + }, + }, + }; + const oldStorage = { + meta: { + version: 88, + }, + data: oldData, + }; + + const newStorage = await migrate(oldStorage); + expect(newStorage.data).toStrictEqual(oldData); + }); + + it('should return state unaltered if the providerConfig already has an id', async () => { + const oldData = { + other: 'data', + NetworkController: { + networkConfigurations: { + id1: { + foo: 'bar', + }, + }, + providerConfig: { + id: 'test', + }, + }, + }; + const oldStorage = { + meta: { + version: 88, + }, + data: oldData, + }; + + const newStorage = await migrate(oldStorage); + expect(newStorage.data).toStrictEqual(oldData); + }); + + it('should return state unaltered if there is no network config with the same rpcUrl and the providerConfig', async () => { + const oldData = { + other: 'data', + NetworkController: { + networkConfigurations: { + id1: { + foo: 'bar', + rpcUrl: 'http://foo.bar', + }, + }, + providerConfig: { + rpcUrl: 'http://baz.buzz', + }, + }, + }; + const oldStorage = { + meta: { + version: 88, + }, + data: oldData, + }; + + const newStorage = await migrate(oldStorage); + expect(newStorage.data).toStrictEqual(oldData); + }); + + it('should update the provider config to have the id of a network config with the same rpcUrl', async () => { + const oldData = { + other: 'data', + NetworkController: { + networkConfigurations: { + id1: { + foo: 'bar', + rpcUrl: 'http://foo.bar', + id: 'test', + }, + }, + providerConfig: { + rpcUrl: 'http://foo.bar', + }, + }, + }; + const oldStorage = { + meta: { + version: 88, + }, + data: oldData, + }; + + const newStorage = await migrate(oldStorage); + expect(newStorage.data).toStrictEqual({ + other: 'data', + NetworkController: { + networkConfigurations: { + id1: { + foo: 'bar', + rpcUrl: 'http://foo.bar', + id: 'test', + }, + }, + providerConfig: { + rpcUrl: 'http://foo.bar', + id: 'test', + }, + }, + }); + }); + + it('should update the provider config to have the id of a network config with the same rpcUrl, even if there are other networks with the same chainId', async () => { + const oldData = { + other: 'data', + NetworkController: { + networkConfigurations: { + id1: { + foo: 'bar', + rpcUrl: 'http://fizz.buzz', + id: 'FAILEDtest', + chainId: 1, + }, + id2: { + foo: 'bar', + rpcUrl: 'http://foo.bar', + id: 'PASSEDtest', + }, + id3: { + foo: 'bar', + rpcUrl: 'http://baz.buzz', + id: 'FAILEDtest', + chainId: 1, + }, + }, + providerConfig: { + rpcUrl: 'http://foo.bar', + chainId: 1, + }, + }, + }; + const oldStorage = { + meta: { + version: 88, + }, + data: oldData, + }; + + const newStorage = await migrate(oldStorage); + expect(newStorage.data).toStrictEqual({ + other: 'data', + NetworkController: { + networkConfigurations: { + id1: { + foo: 'bar', + rpcUrl: 'http://fizz.buzz', + id: 'FAILEDtest', + chainId: 1, + }, + id2: { + foo: 'bar', + rpcUrl: 'http://foo.bar', + id: 'PASSEDtest', + }, + id3: { + foo: 'bar', + rpcUrl: 'http://baz.buzz', + id: 'FAILEDtest', + chainId: 1, + }, + }, + providerConfig: { + rpcUrl: 'http://foo.bar', + id: 'PASSEDtest', + chainId: 1, + }, + }, + }); + }); +}); diff --git a/app/scripts/migrations/089.ts b/app/scripts/migrations/089.ts new file mode 100644 index 000000000..cc1bfa4dc --- /dev/null +++ b/app/scripts/migrations/089.ts @@ -0,0 +1,71 @@ +import { hasProperty, isObject } from '@metamask/utils'; +import { cloneDeep } from 'lodash'; + +export const version = 89; + +/** + * Add an `id` to the `providerConfig` object. + * + * @param originalVersionedData - Versioned MetaMask extension state, exactly what we persist to dist. + * @param originalVersionedData.meta - State metadata. + * @param originalVersionedData.meta.version - The current state version. + * @param originalVersionedData.data - The persisted MetaMask state, keyed by controller. + * @returns Updated versioned MetaMask extension state. + */ +export async function migrate(originalVersionedData: { + meta: { version: number }; + data: Record; +}) { + const versionedData = cloneDeep(originalVersionedData); + versionedData.meta.version = version; + versionedData.data = transformState(versionedData.data); + return versionedData; +} + +function transformState(state: Record) { + if ( + hasProperty(state, 'NetworkController') && + isObject(state.NetworkController) && + hasProperty(state.NetworkController, 'providerConfig') && + isObject(state.NetworkController.providerConfig) + ) { + const { networkConfigurations, providerConfig } = state.NetworkController; + + if (!isObject(networkConfigurations)) { + return state; + } + + if (providerConfig.id) { + return state; + } + + let newProviderConfigId; + + for (const networkConfigurationId of Object.keys(networkConfigurations)) { + const networkConfiguration = + networkConfigurations[networkConfigurationId]; + if (!isObject(networkConfiguration)) { + return state; + } + if (networkConfiguration.rpcUrl === providerConfig.rpcUrl) { + newProviderConfigId = networkConfiguration.id; + break; + } + } + + if (!newProviderConfigId) { + return state; + } + + state.NetworkController.providerConfig = { + ...providerConfig, + id: newProviderConfigId, + }; + + return { + ...state, + NetworkController: state.NetworkController, + }; + } + return state; +} diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js index 813f5e799..429ef7959 100644 --- a/app/scripts/migrations/index.js +++ b/app/scripts/migrations/index.js @@ -92,6 +92,7 @@ import * as m085 from './085'; import * as m086 from './086'; import * as m087 from './087'; import * as m088 from './088'; +import * as m089 from './089'; const migrations = [ m002, @@ -181,6 +182,7 @@ const migrations = [ m086, m087, m088, + m089, ]; export default migrations; diff --git a/app/scripts/sentry-install.js b/app/scripts/sentry-install.js index fc654371b..aa1264c04 100644 --- a/app/scripts/sentry-install.js +++ b/app/scripts/sentry-install.js @@ -8,3 +8,22 @@ global.sentry = setupSentry({ release: process.env.METAMASK_VERSION, getState: () => global.stateHooks?.getSentryState?.() || {}, }); + +/** + * As soon as state is available via getSentryState we can call the + * toggleSession method added to sentry in setupSentry to start automatic + * session tracking. + */ +function waitForStateHooks() { + if (global.stateHooks.getSentryState) { + // sentry is not defined in dev mode, so if sentry doesn't exist at this + // point it means that we are in dev mode and do not need to toggle the + // session. Using optional chaining is sufficient to prevent the error in + // development. + global.sentry?.toggleSession(); + } else { + setTimeout(waitForStateHooks, 100); + } +} + +waitForStateHooks(); diff --git a/app/scripts/ui.js b/app/scripts/ui.js index 148ce0397..b3aa15c6c 100644 --- a/app/scripts/ui.js +++ b/app/scripts/ui.js @@ -1,6 +1,3 @@ -// polyfills -import '@formatjs/intl-relativetimeformat/polyfill'; - // dev only, "react-devtools" import is skipped in prod builds import 'react-devtools'; diff --git a/builds.yml b/builds.yml index fe4d755d3..eb178509f 100644 --- a/builds.yml +++ b/builds.yml @@ -47,12 +47,13 @@ buildTypes: - desktop - build-flask - keyring-snaps + # - blockaid env: - INFURA_FLASK_PROJECT_ID - SEGMENT_FLASK_WRITE_KEY - ALLOW_LOCAL_SNAPS: true - REQUIRE_SNAPS_ALLOWLIST: false - - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/0.36.1-flask.1/index.html + - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/0.37.1-flask.1/index.html - SUPPORT_LINK: https://metamask-flask.zendesk.com/hc - SUPPORT_REQUEST_LINK: https://metamask-flask.zendesk.com/hc/en-us/requests/new - INFURA_ENV_KEY_REF: INFURA_FLASK_PROJECT_ID @@ -71,7 +72,7 @@ buildTypes: - SEGMENT_FLASK_WRITE_KEY - ALLOW_LOCAL_SNAPS: true - REQUIRE_SNAPS_ALLOWLIST: false - - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/0.36.1-flask.1/index.html + - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.metamask.io/0.37.1-flask.1/index.html - SUPPORT_LINK: https://metamask-flask.zendesk.com/hc - SUPPORT_REQUEST_LINK: https://metamask-flask.zendesk.com/hc/en-us/requests/new - INFURA_ENV_KEY_REF: INFURA_FLASK_PROJECT_ID @@ -87,9 +88,9 @@ buildTypes: - SEGMENT_MMI_WRITE_KEY - INFURA_ENV_KEY_REF: INFURA_MMI_PROJECT_ID - SEGMENT_WRITE_KEY_REF: SEGMENT_MMI_WRITE_KEY + - MMI_CONFIGURATION_SERVICE_URL: https://configuration.metamask-institutional.io/v1/configuration/default - SUPPORT_LINK: https://mmi-support.zendesk.com/hc/en-us - SUPPORT_REQUEST_LINK: https://mmi-support.zendesk.com/hc/en-us/requests/new - - MMI_CONFIGURATION_SERVICE_URL # For some reason, MMI uses this type of versioning # Leaving it on for backwards compatibility isPrerelease: true @@ -116,6 +117,9 @@ features: - DISABLE_WEB_SOCKET_ENCRYPTION: false - SKIP_OTP_PAIRING_FLOW: false - WEB_SOCKET_PORT: null + blockaid: + env: + - BLOCKAID_FILE_CDN: null ### # Build Type code extensions. Things like different support links, warning pages, banners @@ -224,6 +228,8 @@ env: - NODE_DEBUG: '' # Used by react-devtools-core - EDITOR_URL: '' + # CDN for blockaid files + - BLOCKAID_FILE_CDN ### # Meta variables diff --git a/development/build/config.js b/development/build/config.js index 0eee28ce3..4e4ee1ea9 100644 --- a/development/build/config.js +++ b/development/build/config.js @@ -11,7 +11,12 @@ const VARIABLES_REQUIRED_IN_PRODUCTION = { main: ['INFURA_PROD_PROJECT_ID', 'SEGMENT_PROD_WRITE_KEY', 'SENTRY_DSN'], beta: ['INFURA_BETA_PROJECT_ID', 'SEGMENT_BETA_WRITE_KEY', 'SENTRY_DSN'], flask: ['INFURA_FLASK_PROJECT_ID', 'SEGMENT_FLASK_WRITE_KEY', 'SENTRY_DSN'], - mmi: ['INFURA_MMI_PROJECT_ID', 'SEGMENT_MMI_WRITE_KEY', 'SENTRY_DSN'], + mmi: [ + 'INFURA_MMI_PROJECT_ID', + 'MMI_CONFIGURATION_SERVICE_URL', + 'SEGMENT_MMI_WRITE_KEY', + 'SENTRY_DSN', + ], }; async function fromIniFile(filepath) { diff --git a/development/build/index.js b/development/build/index.js index 84ee91040..92a6ea678 100755 --- a/development/build/index.js +++ b/development/build/index.js @@ -99,6 +99,8 @@ async function defineAndRunBuildTasks() { 'navigator', 'harden', 'console', + 'WeakSet', + 'Event', 'Image', // Used by browser to generate notifications // globals chromedriver needs to function /cdc_[a-zA-Z0-9]+_[a-zA-Z]+/iu, diff --git a/development/build/manifest.js b/development/build/manifest.js index b3079f806..d9f0f71ca 100644 --- a/development/build/manifest.js +++ b/development/build/manifest.js @@ -137,7 +137,7 @@ function createManifestTasks({ const buildName = buildType === 'mmi' - ? `MetaMask Institutional ${mv3Str}${lavamoatStr}${snowStr}` + ? `MetaMask Institutional ${mv3Str}` : `MetaMask ${capitalize(buildType)}${mv3Str}${lavamoatStr}${snowStr}`; manifest.name = buildName; diff --git a/development/build/static.js b/development/build/static.js index 644105c87..d8ff8c539 100644 --- a/development/build/static.js +++ b/development/build/static.js @@ -3,7 +3,6 @@ const fs = require('fs-extra'); const watch = require('gulp-watch'); const glob = require('fast-glob'); -const locales = require('../../app/_locales/index.json'); const { loadBuildTypesConfig } = require('../lib/build-type'); const { TASKS } = require('./constants'); @@ -22,19 +21,20 @@ module.exports = function createStaticAssetTasks({ const copyTargetsProds = {}; const copyTargetsDevs = {}; + const buildConfig = loadBuildTypesConfig(); + + const activeFeatures = buildConfig.buildTypes[buildType].features ?? []; + browserPlatforms.forEach((browser) => { const [copyTargetsProd, copyTargetsDev] = getCopyTargets( shouldIncludeLockdown, shouldIncludeSnow, + activeFeatures, ); copyTargetsProds[browser] = copyTargetsProd; copyTargetsDevs[browser] = copyTargetsDev; }); - const buildConfig = loadBuildTypesConfig(); - - const activeFeatures = buildConfig.buildTypes[buildType].features ?? []; - const additionalAssets = activeFeatures.flatMap( (feature) => buildConfig.features[feature].assets?.filter( @@ -108,7 +108,11 @@ module.exports = function createStaticAssetTasks({ } }; -function getCopyTargets(shouldIncludeLockdown, shouldIncludeSnow) { +function getCopyTargets( + shouldIncludeLockdown, + shouldIncludeSnow, + activeFeatures, +) { const allCopyTargets = [ { src: `./app/_locales/`, @@ -198,20 +202,11 @@ function getCopyTargets(shouldIncludeLockdown, shouldIncludeSnow) { }, ]; - const languageTags = new Set(); - for (const locale of locales) { - const { code } = locale; - const tag = code.split('_')[0]; - languageTags.add(tag); - } - - for (const tag of languageTags) { + if (activeFeatures.includes('blockaid')) { allCopyTargets.push({ - src: getPathInsideNodeModules( - '@formatjs/intl-relativetimeformat', - `dist/locale-data/${tag}.json`, - ), - dest: `intl/${tag}/relative-time-format-data.json`, + src: getPathInsideNodeModules('@blockaid/ppom', '/'), + pattern: '*.wasm', + dest: '', }); } diff --git a/development/metamaskbot-build-announce.js b/development/metamaskbot-build-announce.js index 729f2ce5b..576b038f7 100755 --- a/development/metamaskbot-build-announce.js +++ b/development/metamaskbot-build-announce.js @@ -15,6 +15,29 @@ function capitalizeFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1); } +function getHumanReadableSize(bytes) { + if (!bytes) { + return '0 Bytes'; + } + + const absBytes = Math.abs(bytes); + const kibibyteSize = 1024; + const magnitudes = ['Bytes', 'KiB', 'MiB']; + let magnitudeIndex = 0; + if (absBytes > Math.pow(kibibyteSize, 2)) { + magnitudeIndex = 2; + } else if (absBytes > kibibyteSize) { + magnitudeIndex = 1; + } + return `${parseFloat( + (bytes / Math.pow(kibibyteSize, magnitudeIndex)).toFixed(2), + )} ${magnitudes[magnitudeIndex]}`; +} + +function getPercentageChange(from, to) { + return parseFloat(((to - from) / Math.abs(from)) * 100).toFixed(2); +} + async function start() { const { GITHUB_COMMENT_TOKEN, CIRCLE_PULL_REQUEST } = process.env; console.log('CIRCLE_PULL_REQUEST', CIRCLE_PULL_REQUEST); @@ -278,7 +301,11 @@ async function start() { }, {}); const sizeDiffRows = Object.keys(diffs).map( - (part) => `${part}: ${diffs[part]} bytes`, + (part) => + `${part}: ${getHumanReadableSize(diffs[part])} (${getPercentageChange( + devSizes[part], + prSizes[part], + )}%)`, ); const sizeDiffHiddenContent = `
    ${sizeDiffRows diff --git a/development/sentry-upload-artifacts.sh b/development/sentry-upload-artifacts.sh index 9d2fd32b4..e70989123 100755 --- a/development/sentry-upload-artifacts.sh +++ b/development/sentry-upload-artifacts.sh @@ -31,7 +31,7 @@ function upload_sourcemaps { local release="${1}"; shift local dist_directory="${1}"; shift - sentry-cli releases files "${release}" upload-sourcemaps "${dist_directory}"/chrome/*.js "${dist_directory}"/sourcemaps/ --rewrite --url-prefix 'metamask' + sentry-cli releases files "${release}" upload-sourcemaps "${dist_directory}"/chrome/*.js "${dist_directory}"/sourcemaps/ --rewrite --url-prefix '/metamask' } function main { diff --git a/development/ts-migration-dashboard/files-to-convert.json b/development/ts-migration-dashboard/files-to-convert.json index d1752ebf7..5f1189c98 100644 --- a/development/ts-migration-dashboard/files-to-convert.json +++ b/development/ts-migration-dashboard/files-to-convert.json @@ -1160,9 +1160,6 @@ "ui/hooks/useUserPreferencedCurrency.test.js", "ui/index.js", "ui/index.test.js", - "ui/pages/add-nft/add-nft.js", - "ui/pages/add-nft/add-nft.test.js", - "ui/pages/add-nft/index.js", "ui/pages/asset/asset.js", "ui/pages/asset/components/asset-breadcrumb.js", "ui/pages/asset/components/asset-navigation.js", diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index f3373a420..afb8f0b99 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -138,7 +138,6 @@ "@ethereumjs/tx": { "packages": { "@ethereumjs/common": true, - "@ethereumjs/tx>@chainsafe/ssz": true, "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util": true, "@ethereumjs/tx>ethereum-cryptography": true, @@ -146,21 +145,6 @@ "browserify>insert-module-globals>is-buffer": true } }, - "@ethereumjs/tx>@chainsafe/ssz": { - "packages": { - "@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": true, - "browserify>buffer": true - } - }, - "@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": { - "globals": { - "WeakRef": true - }, - "packages": { - "@ethereumjs/tx>@chainsafe/ssz>@chainsafe/as-sha256": true, - "@metamask/key-tree>@noble/hashes": true - } - }, "@ethereumjs/tx>@ethereumjs/rlp": { "globals": { "TextEncoder": true @@ -171,7 +155,6 @@ "console.warn": true }, "packages": { - "@ethereumjs/tx>@chainsafe/ssz": true, "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography": true, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, @@ -325,15 +308,7 @@ "packages": { "@ethersproject/abi>@ethersproject/bytes": true, "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/bignumber>bn.js": true - } - }, - "@ethersproject/bignumber>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true + "bn.js": true } }, "@ethersproject/contracts": { @@ -347,9 +322,17 @@ "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, "@ethersproject/bignumber": true, + "@ethersproject/contracts>@ethersproject/abstract-provider": true, "@ethersproject/hdnode>@ethersproject/abstract-signer": true, - "@ethersproject/hdnode>@ethersproject/transactions": true, - "@ethersproject/providers>@ethersproject/abstract-provider": true + "@ethersproject/hdnode>@ethersproject/transactions": true + } + }, + "@ethersproject/contracts>@ethersproject/abstract-provider": { + "packages": { + "@ethersproject/abi>@ethersproject/bytes": true, + "@ethersproject/abi>@ethersproject/logger": true, + "@ethersproject/abi>@ethersproject/properties": true, + "@ethersproject/bignumber": true } }, "@ethersproject/hdnode": { @@ -441,11 +424,11 @@ "@ethersproject/abi>@ethersproject/properties": true, "@ethersproject/abi>@ethersproject/strings": true, "@ethersproject/bignumber": true, + "@ethersproject/contracts>@ethersproject/abstract-provider": true, "@ethersproject/hdnode>@ethersproject/abstract-signer": true, "@ethersproject/hdnode>@ethersproject/basex": true, "@ethersproject/hdnode>@ethersproject/sha2": true, "@ethersproject/hdnode>@ethersproject/transactions": true, - "@ethersproject/providers>@ethersproject/abstract-provider": true, "@ethersproject/providers>@ethersproject/base64": true, "@ethersproject/providers>@ethersproject/networks": true, "@ethersproject/providers>@ethersproject/random": true, @@ -453,14 +436,6 @@ "@ethersproject/providers>bech32": true } }, - "@ethersproject/providers>@ethersproject/abstract-provider": { - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/abi>@ethersproject/properties": true, - "@ethersproject/bignumber": true - } - }, "@ethersproject/providers>@ethersproject/base64": { "globals": { "atob": true, @@ -501,19 +476,6 @@ "@ethersproject/providers>@ethersproject/base64": true } }, - "@formatjs/intl-relativetimeformat": { - "globals": { - "Intl": true - }, - "packages": { - "@formatjs/intl-relativetimeformat>@formatjs/intl-utils": true - } - }, - "@formatjs/intl-relativetimeformat>@formatjs/intl-utils": { - "globals": { - "Intl.getCanonicalLocales": true - } - }, "@keystonehq/bc-ur-registry-eth": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, @@ -531,7 +493,7 @@ "@ngraveio/bc-ur": true, "browserify>buffer": true, "ethereumjs-wallet>bs58check": true, - "wait-on>rxjs>tslib": true + "mockttp>graphql-tag>tslib": true } }, "@keystonehq/bc-ur-registry-eth>hdkey": { @@ -775,6 +737,9 @@ } }, "@metamask/approval-controller": { + "globals": { + "console.info": true + }, "packages": { "@metamask/approval-controller>nanoid": true, "@metamask/base-controller": true, @@ -855,6 +820,9 @@ } }, "@metamask/base-controller": { + "globals": { + "setTimeout": true + }, "packages": { "immer": true } @@ -881,8 +849,8 @@ "setTimeout": true }, "packages": { + "@metamask/controller-utils>@metamask/utils": true, "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/utils": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, "eth-ens-namehash": true, @@ -890,6 +858,19 @@ "ethjs>ethjs-unit": true } }, + "@metamask/controller-utils>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, "@metamask/controller-utils>@spruceid/siwe-parser": { "globals": { "console.error": true, @@ -931,12 +912,12 @@ }, "packages": { "@metamask/eth-json-rpc-middleware>@metamask/utils": true, + "@metamask/eth-json-rpc-middleware>clone": true, "@metamask/eth-json-rpc-middleware>pify": true, "@metamask/eth-json-rpc-middleware>safe-stable-stringify": true, "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, "eth-rpc-errors": true, - "json-rpc-engine": true, - "vinyl>clone": true + "json-rpc-engine": true } }, "@metamask/eth-json-rpc-middleware>@metamask/utils": { @@ -951,6 +932,11 @@ "superstruct": true } }, + "@metamask/eth-json-rpc-middleware>clone": { + "packages": { + "browserify>buffer": true + } + }, "@metamask/eth-keyring-controller": { "packages": { "@metamask/browser-passworder": true, @@ -1000,11 +986,11 @@ "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@scure/bip32": { "packages": { "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@noble/secp256k1": true, - "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@scure/bip39>@noble/hashes": true, + "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@scure/bip32>@noble/hashes": true, "@metamask/key-tree>@scure/base": true } }, - "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@scure/bip39>@noble/hashes": { + "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@scure/bip32>@noble/hashes": { "globals": { "TextEncoder": true, "crypto": true @@ -1014,9 +1000,9 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethjs-util": true, "bn.js": true, "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, "eth-sig-util>tweetnacl": true, "eth-sig-util>tweetnacl-util": true } @@ -1036,13 +1022,6 @@ "crypto": true } }, - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, @@ -1103,10 +1082,10 @@ }, "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util": { "packages": { - "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethjs-util": true, "bn.js": true, "browserify>assert": true, "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, @@ -1114,13 +1093,6 @@ "ganache>secp256k1>elliptic": true } }, - "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, "@metamask/eth-ledger-bridge-keyring>hdkey": { "packages": { "@metamask/eth-ledger-bridge-keyring>hdkey>secp256k1": true, @@ -1144,9 +1116,9 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethjs-util": true, "bn.js": true, "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, "eth-sig-util>tweetnacl": true, "eth-sig-util>tweetnacl-util": true } @@ -1166,13 +1138,6 @@ "crypto": true } }, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, "@metamask/eth-token-tracker": { "globals": { "console.warn": true @@ -1227,22 +1192,22 @@ "setInterval": true }, "packages": { - "@metamask/eth-token-tracker>ethjs>bn.js": true, "@metamask/eth-token-tracker>ethjs>ethjs-abi": true, "@metamask/eth-token-tracker>ethjs>ethjs-contract": true, "@metamask/eth-token-tracker>ethjs>ethjs-query": true, + "@metamask/eth-token-tracker>ethjs>ethjs-util": true, + "bn.js": true, "browserify>buffer": true, "ethjs>ethjs-filter": true, "ethjs>ethjs-provider-http": true, "ethjs>ethjs-unit": true, - "ethjs>ethjs-util": true, "ethjs>js-sha3": true, "ethjs>number-to-bn": true } }, "@metamask/eth-token-tracker>ethjs>ethjs-abi": { "packages": { - "@metamask/eth-token-tracker>ethjs>bn.js": true, + "bn.js": true, "browserify>buffer": true, "ethjs>js-sha3": true, "ethjs>number-to-bn": true @@ -1251,16 +1216,16 @@ "@metamask/eth-token-tracker>ethjs>ethjs-contract": { "packages": { "@metamask/eth-token-tracker>ethjs>ethjs-contract>ethjs-abi": true, + "@metamask/eth-token-tracker>ethjs>ethjs-util": true, "ethjs-query>babel-runtime": true, "ethjs>ethjs-filter": true, - "ethjs>ethjs-util": true, "ethjs>js-sha3": true, "promise-to-callback": true } }, "@metamask/eth-token-tracker>ethjs>ethjs-contract>ethjs-abi": { "packages": { - "@metamask/eth-token-tracker>ethjs>bn.js": true, + "bn.js": true, "browserify>buffer": true, "ethjs>js-sha3": true, "ethjs>number-to-bn": true @@ -1277,6 +1242,13 @@ "promise-to-callback": true } }, + "@metamask/eth-token-tracker>ethjs>ethjs-util": { + "packages": { + "browserify>buffer": true, + "ethjs>ethjs-util>is-hex-prefixed": true, + "ethjs>ethjs-util>strip-hex-prefix": true + } + }, "@metamask/eth-token-tracker>safe-event-emitter": { "globals": { "setTimeout": true @@ -1328,7 +1300,7 @@ "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect": true, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/utils": true, "browserify>events": true, - "wait-on>rxjs>tslib": true + "mockttp>graphql-tag>tslib": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect": { @@ -1343,7 +1315,7 @@ }, "packages": { "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect>@trezor/transport": true, - "wait-on>rxjs>tslib": true + "mockttp>graphql-tag>tslib": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect>@trezor/transport": { @@ -1508,28 +1480,6 @@ "jest-canvas-mock>moo-color>color-name": true } }, - "@metamask/key-tree": { - "packages": { - "@metamask/key-tree>@metamask/utils": true, - "@metamask/key-tree>@noble/ed25519": true, - "@metamask/key-tree>@noble/hashes": true, - "@metamask/key-tree>@noble/secp256k1": true, - "@metamask/key-tree>@scure/base": true, - "@metamask/scure-bip39": true - } - }, - "@metamask/key-tree>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "browserify>buffer": true, - "nock>debug": true, - "semver": true, - "superstruct": true - } - }, "@metamask/key-tree>@noble/ed25519": { "globals": { "crypto": true @@ -1558,6 +1508,94 @@ "TextEncoder": true } }, + "@metamask/keyring-controller": { + "packages": { + "@metamask/base-controller": true, + "@metamask/keyring-controller>@metamask/eth-keyring-controller": true, + "@metamask/keyring-controller>@metamask/utils": true, + "@metamask/keyring-controller>ethereumjs-wallet": true, + "eth-json-rpc-filters>async-mutex": true, + "ethereumjs-util": true + } + }, + "@metamask/keyring-controller>@metamask/eth-keyring-controller": { + "globals": { + "console.error": true + }, + "packages": { + "@metamask/browser-passworder": true, + "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring": true, + "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring": true, + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util": true, + "@metamask/keyring-controller>@metamask/utils": true, + "@metamask/obs-store": true, + "browserify>events": true + } + }, + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util": { + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, + "bn.js": true, + "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, + "eth-sig-util>tweetnacl": true, + "eth-sig-util>tweetnacl-util": true + } + }, + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": { + "globals": { + "TextDecoder": true, + "crypto": true + }, + "packages": { + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true + } + }, + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true + } + }, + "@metamask/keyring-controller>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, + "@metamask/keyring-controller>ethereumjs-wallet": { + "packages": { + "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": true, + "@truffle/codec>utf8": true, + "browserify>buffer": true, + "browserify>crypto-browserify": true, + "ethereumjs-util>ethereum-cryptography": true, + "ethereumjs-util>ethereum-cryptography>scrypt-js": true, + "ethereumjs-wallet>aes-js": true, + "ethereumjs-wallet>bs58check": true, + "ethereumjs-wallet>randombytes": true, + "uuid": true + } + }, + "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": { + "packages": { + "bn.js": true, + "browserify>assert": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true, + "ethereumjs-util>create-hash": true, + "ethereumjs-util>ethereum-cryptography": true, + "ethereumjs-util>rlp": true + } + }, "@metamask/logo": { "globals": { "addEventListener": true, @@ -1576,14 +1614,40 @@ "packages": { "@metamask/base-controller": true, "@metamask/controller-utils": true, + "@metamask/message-manager>@metamask/eth-sig-util": true, "@metamask/message-manager>jsonschema": true, "browserify>buffer": true, "browserify>events": true, - "eth-sig-util": true, "ethereumjs-util": true, "uuid": true } }, + "@metamask/message-manager>@metamask/eth-sig-util": { + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": true, + "bn.js": true, + "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, + "eth-sig-util>tweetnacl": true, + "eth-sig-util>tweetnacl-util": true + } + }, + "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": { + "globals": { + "TextDecoder": true, + "crypto": true + }, + "packages": { + "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true + } + }, + "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true + } + }, "@metamask/message-manager>jsonschema": { "packages": { "browserify>url": true @@ -1618,7 +1682,7 @@ }, "packages": { "@metamask/network-controller>@metamask/eth-json-rpc-infura>@metamask/utils": true, - "@metamask/network-controller>@metamask/eth-json-rpc-infura>eth-json-rpc-middleware": true, + "@metamask/network-controller>@metamask/eth-json-rpc-provider": true, "eth-rpc-errors": true, "json-rpc-engine": true, "node-fetch": true @@ -1636,26 +1700,6 @@ "superstruct": true } }, - "@metamask/network-controller>@metamask/eth-json-rpc-infura>eth-json-rpc-middleware": { - "globals": { - "URL": true, - "btoa": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, - "@metamask/network-controller>@metamask/eth-json-rpc-infura>@metamask/utils": true, - "@metamask/network-controller>@metamask/eth-json-rpc-infura>eth-json-rpc-middleware>pify": true, - "@metamask/safe-event-emitter": true, - "browserify>browser-resolve": true, - "eth-rpc-errors": true, - "json-rpc-engine": true, - "lavamoat>json-stable-stringify": true, - "vinyl>clone": true - } - }, "@metamask/network-controller>@metamask/eth-json-rpc-provider": { "packages": { "@metamask/safe-event-emitter": true, @@ -1764,9 +1808,9 @@ "@metamask/rpc-methods": { "packages": { "@metamask/browser-passworder": true, - "@metamask/key-tree": true, "@metamask/key-tree>@noble/hashes": true, "@metamask/permission-controller": true, + "@metamask/rpc-methods>@metamask/key-tree": true, "@metamask/rpc-methods>@metamask/utils": true, "@metamask/rpc-methods>nanoid": true, "@metamask/snaps-ui": true, @@ -1780,12 +1824,23 @@ "crypto.getRandomValues": true } }, + "@metamask/rpc-methods>@metamask/key-tree": { + "packages": { + "@metamask/key-tree>@noble/ed25519": true, + "@metamask/key-tree>@noble/hashes": true, + "@metamask/key-tree>@noble/secp256k1": true, + "@metamask/key-tree>@scure/base": true, + "@metamask/rpc-methods>@metamask/utils": true, + "@metamask/scure-bip39": true + } + }, "@metamask/rpc-methods>@metamask/utils": { "globals": { "TextDecoder": true, "TextEncoder": true }, "packages": { + "@metamask/key-tree>@noble/hashes": true, "browserify>buffer": true, "nock>debug": true, "semver": true, @@ -1848,34 +1903,13 @@ "@ethersproject/abi>@ethersproject/bytes": true, "@ethersproject/bignumber": true, "@ethersproject/providers": true, - "@metamask/smart-transactions-controller>@metamask/base-controller": true, - "@metamask/smart-transactions-controller>@metamask/controller-utils": true, + "@metamask/base-controller": true, + "@metamask/controller-utils": true, "@metamask/smart-transactions-controller>bignumber.js": true, - "@metamask/smart-transactions-controller>isomorphic-fetch": true, "fast-json-patch": true, "lodash": true } }, - "@metamask/smart-transactions-controller>@metamask/base-controller": { - "packages": { - "immer": true - } - }, - "@metamask/smart-transactions-controller>@metamask/controller-utils": { - "globals": { - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/smart-transactions-controller>isomorphic-fetch": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true, - "ethjs>ethjs-unit": true - } - }, "@metamask/smart-transactions-controller>@metamask/controllers>nanoid": { "globals": { "crypto.getRandomValues": true @@ -1887,25 +1921,6 @@ "define": true } }, - "@metamask/smart-transactions-controller>isomorphic-fetch": { - "globals": { - "fetch.bind": true - }, - "packages": { - "@metamask/smart-transactions-controller>isomorphic-fetch>whatwg-fetch": true - } - }, - "@metamask/smart-transactions-controller>isomorphic-fetch>whatwg-fetch": { - "globals": { - "Blob": true, - "FileReader": true, - "FormData": true, - "URLSearchParams.prototype.isPrototypeOf": true, - "XMLHttpRequest": true, - "define": true, - "setTimeout": true - } - }, "@metamask/snaps-controllers-flask>nanoid": { "globals": { "crypto.getRandomValues": true @@ -1928,6 +1943,7 @@ "TextEncoder": true }, "packages": { + "@metamask/key-tree>@noble/hashes": true, "browserify>buffer": true, "nock>debug": true, "semver": true, @@ -1945,9 +1961,9 @@ "document.createElement": true }, "packages": { - "@metamask/key-tree": true, "@metamask/key-tree>@noble/hashes": true, "@metamask/key-tree>@scure/base": true, + "@metamask/snaps-utils>@metamask/key-tree": true, "@metamask/snaps-utils>@metamask/utils": true, "@metamask/snaps-utils>cron-parser": true, "@metamask/snaps-utils>fast-json-stable-stringify": true, @@ -1957,12 +1973,23 @@ "superstruct": true } }, + "@metamask/snaps-utils>@metamask/key-tree": { + "packages": { + "@metamask/key-tree>@noble/ed25519": true, + "@metamask/key-tree>@noble/hashes": true, + "@metamask/key-tree>@noble/secp256k1": true, + "@metamask/key-tree>@scure/base": true, + "@metamask/scure-bip39": true, + "@metamask/snaps-utils>@metamask/utils": true + } + }, "@metamask/snaps-utils>@metamask/utils": { "globals": { "TextDecoder": true, "TextEncoder": true }, "packages": { + "@metamask/key-tree>@noble/hashes": true, "browserify>buffer": true, "nock>debug": true, "semver": true, @@ -2228,11 +2255,11 @@ "@truffle/codec>@truffle/abi-utils": true, "@truffle/codec>@truffle/compile-common": true, "@truffle/codec>big.js": true, - "@truffle/codec>bn.js": true, "@truffle/codec>cbor": true, "@truffle/codec>semver": true, "@truffle/codec>utf8": true, "@truffle/codec>web3-utils": true, + "bn.js": true, "browserify>buffer": true, "browserify>os-browserify": true, "browserify>util": true, @@ -2389,14 +2416,6 @@ "define": true } }, - "@truffle/codec>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "@truffle/codec>cbor": { "globals": { "TextDecoder": true @@ -2439,8 +2458,8 @@ }, "packages": { "@truffle/codec>utf8": true, - "@truffle/codec>web3-utils>bn.js": true, "@truffle/codec>web3-utils>ethereum-bloom-filters": true, + "bn.js": true, "browserify>buffer": true, "ethereumjs-util": true, "ethereumjs-wallet>randombytes": true, @@ -2448,14 +2467,6 @@ "ethjs>number-to-bn": true } }, - "@truffle/codec>web3-utils>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "@truffle/codec>web3-utils>ethereum-bloom-filters": { "packages": { "@truffle/codec>web3-utils>ethereum-bloom-filters>js-sha3": true @@ -2477,7 +2488,7 @@ "@truffle/codec>web3-utils": true, "@truffle/decoder>@truffle/encoder": true, "@truffle/decoder>@truffle/source-map-utils": true, - "@truffle/decoder>bn.js": true, + "bn.js": true, "nock>debug": true } }, @@ -2650,11 +2661,11 @@ "@ethersproject/abi>@ethersproject/keccak256": true, "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, + "@ethersproject/contracts>@ethersproject/abstract-provider": true, "@ethersproject/hdnode": true, "@ethersproject/hdnode>@ethersproject/abstract-signer": true, "@ethersproject/hdnode>@ethersproject/signing-key": true, "@ethersproject/hdnode>@ethersproject/transactions": true, - "@ethersproject/providers>@ethersproject/abstract-provider": true, "@ethersproject/providers>@ethersproject/random": true, "@truffle/decoder>@truffle/encoder>@ensdomains/ensjs>ethers>@ethersproject/json-wallets": true } @@ -2699,20 +2710,11 @@ "@truffle/decoder>@truffle/source-map-utils>node-interval-tree>shallowequal": true } }, - "@truffle/decoder>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "@zxing/browser": { "globals": { "HTMLElement": true, "HTMLImageElement": true, "HTMLVideoElement": true, - "URL.createObjectURL": true, "clearTimeout": true, "console.error": true, "console.warn": true, @@ -2726,17 +2728,20 @@ }, "@zxing/library": { "globals": { + "HTMLImageElement": true, + "HTMLVideoElement": true, "TextDecoder": true, "TextEncoder": true, + "URL.createObjectURL": true, "btoa": true, - "clearTimeout": true, - "define": true, - "document.createElement": true, - "document.createElementNS": true, - "document.getElementById": true, - "navigator.mediaDevices.enumerateDevices": true, - "navigator.mediaDevices.getUserMedia": true, + "console.log": true, + "console.warn": true, + "document": true, + "navigator": true, "setTimeout": true + }, + "packages": { + "@zxing/library>ts-custom-error": true } }, "addons-linter>sha.js": { @@ -3225,7 +3230,7 @@ "setTimeout": true }, "packages": { - "wait-on>rxjs>tslib": true + "mockttp>graphql-tag>tslib": true } }, "eth-keyring-controller>@metamask/browser-passworder": { @@ -3244,11 +3249,11 @@ }, "packages": { "@ethereumjs/tx>@ethereumjs/util": true, + "bn.js": true, "browserify>buffer": true, "browserify>crypto-browserify": true, "browserify>events": true, "eth-lattice-keyring>@ethereumjs/tx": true, - "eth-lattice-keyring>bn.js": true, "eth-lattice-keyring>gridplus-sdk": true, "eth-lattice-keyring>rlp": true } @@ -3296,14 +3301,6 @@ "crypto": true } }, - "eth-lattice-keyring>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "eth-lattice-keyring>gridplus-sdk": { "globals": { "AbortController": true, @@ -3356,27 +3353,11 @@ "@ethersproject/providers": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@chainsafe/ssz": true, + "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": true } }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@chainsafe/ssz": { - "packages": { - "browserify": true, - "browserify>buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>case": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": true - } - }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": { - "globals": { - "WeakRef": true - }, - "packages": { - "browserify": true - } - }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": { "packages": { "@ethereumjs/common>crc-32": true, @@ -3440,19 +3421,11 @@ "intToBuffer": true }, "packages": { - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>bn.js": true, + "bn.js": true, "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>buffer": true, "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>js-sha3": true } }, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>buffer": { "globals": { "console": true @@ -3575,39 +3548,24 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, - "ethereumjs-abi>ethereumjs-util>ethjs-util": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, "ganache>secp256k1>elliptic": true } }, - "ethereumjs-abi>ethereumjs-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, "ethereumjs-util": { "packages": { + "bn.js": true, "browserify>assert": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, - "ethereumjs-util>bn.js": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true } }, - "ethereumjs-util>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "ethereumjs-util>create-hash": { "packages": { "addons-linter>sha.js": true, @@ -3659,10 +3617,15 @@ }, "ethereumjs-util>ethereum-cryptography": { "packages": { + "browserify>assert": true, "browserify>buffer": true, + "browserify>crypto-browserify>create-hmac": true, + "ethereumjs-util>ethereum-cryptography>hash.js": true, "ethereumjs-util>ethereum-cryptography>keccak": true, "ethereumjs-util>ethereum-cryptography>secp256k1": true, - "ethereumjs-wallet>randombytes": true + "ethereumjs-wallet>bs58check": true, + "ethereumjs-wallet>randombytes": true, + "ethereumjs-wallet>safe-buffer": true } }, "ethereumjs-util>ethereum-cryptography>browserify-aes": { @@ -3719,16 +3682,8 @@ }, "ethereumjs-util>rlp": { "packages": { - "browserify>buffer": true, - "ethereumjs-util>rlp>bn.js": true - } - }, - "ethereumjs-util>rlp>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true + "bn.js": true, + "browserify>buffer": true } }, "ethereumjs-wallet": { @@ -3771,20 +3726,13 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, - "ethereumjs-wallet>ethereumjs-util>ethjs-util": true, "ganache>secp256k1>elliptic": true } }, - "ethereumjs-wallet>ethereumjs-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, "ethereumjs-wallet>randombytes": { "globals": { "crypto": true, @@ -3823,10 +3771,10 @@ "setInterval": true }, "packages": { + "bn.js": true, "browserify>buffer": true, "ethjs-contract": true, "ethjs-query": true, - "ethjs>bn.js": true, "ethjs>ethjs-abi": true, "ethjs>ethjs-filter": true, "ethjs>ethjs-provider-http": true, @@ -3839,21 +3787,28 @@ "ethjs-contract": { "packages": { "ethjs-contract>ethjs-abi": true, + "ethjs-contract>ethjs-util": true, "ethjs-query>babel-runtime": true, "ethjs>ethjs-filter": true, - "ethjs>ethjs-util": true, "ethjs>js-sha3": true, "promise-to-callback": true } }, "ethjs-contract>ethjs-abi": { "packages": { + "bn.js": true, "browserify>buffer": true, - "ethjs-contract>ethjs-abi>bn.js": true, "ethjs>js-sha3": true, "ethjs>number-to-bn": true } }, + "ethjs-contract>ethjs-util": { + "packages": { + "browserify>buffer": true, + "ethjs>ethjs-util>is-hex-prefixed": true, + "ethjs>ethjs-util>strip-hex-prefix": true + } + }, "ethjs-query": { "globals": { "console": true @@ -3884,11 +3839,18 @@ "ethjs-query>ethjs-format": { "packages": { "ethjs-query>ethjs-format>ethjs-schema": true, - "ethjs>ethjs-util": true, + "ethjs-query>ethjs-format>ethjs-util": true, "ethjs>ethjs-util>strip-hex-prefix": true, "ethjs>number-to-bn": true } }, + "ethjs-query>ethjs-format>ethjs-util": { + "packages": { + "browserify>buffer": true, + "ethjs>ethjs-util>is-hex-prefixed": true, + "ethjs>ethjs-util>strip-hex-prefix": true + } + }, "ethjs-query>ethjs-rpc": { "packages": { "promise-to-callback": true @@ -3896,8 +3858,8 @@ }, "ethjs>ethjs-abi": { "packages": { + "bn.js": true, "browserify>buffer": true, - "ethjs>bn.js": true, "ethjs>js-sha3": true, "ethjs>number-to-bn": true } @@ -3920,7 +3882,7 @@ }, "ethjs>ethjs-unit": { "packages": { - "ethjs>ethjs-unit>bn.js": true, + "bn.js": true, "ethjs>number-to-bn": true } }, @@ -3943,8 +3905,8 @@ }, "ethjs>number-to-bn": { "packages": { - "ethjs>ethjs-util>strip-hex-prefix": true, - "ethjs>number-to-bn>bn.js": true + "bn.js": true, + "ethjs>ethjs-util>strip-hex-prefix": true } }, "extension-port-stream": { @@ -4081,6 +4043,11 @@ "Intl": true } }, + "mockttp>graphql-tag>tslib": { + "globals": { + "define": true + } + }, "nanoid": { "globals": { "crypto": true, @@ -4285,7 +4252,7 @@ "setTimeout": true }, "packages": { - "wait-on>rxjs>tslib": true + "mockttp>graphql-tag>tslib": true } }, "react-focus-lock>react-clientside-effect": { @@ -4304,9 +4271,9 @@ "console.error": true }, "packages": { + "mockttp>graphql-tag>tslib": true, "react": true, - "react-focus-lock>use-sidecar>detect-node-es": true, - "wait-on>rxjs>tslib": true + "react-focus-lock>use-sidecar>detect-node-es": true } }, "react-idle-timer": { @@ -4322,29 +4289,12 @@ }, "react-inspector": { "globals": { - "Node.CDATA_SECTION_NODE": true, - "Node.COMMENT_NODE": true, - "Node.DOCUMENT_FRAGMENT_NODE": true, - "Node.DOCUMENT_NODE": true, - "Node.DOCUMENT_TYPE_NODE": true, - "Node.ELEMENT_NODE": true, - "Node.PROCESSING_INSTRUCTION_NODE": true, - "Node.TEXT_NODE": true + "Node": true, + "chromeDark": true, + "chromeLight": true }, "packages": { - "ethjs-query>babel-runtime": true, - "prop-types": true, - "react": true, - "react-inspector>is-dom": true - } - }, - "react-inspector>is-dom": { - "globals": { - "Node": true - }, - "packages": { - "@lavamoat/snow>is-cross-origin>is-window": true, - "proxyquire>fill-keys>is-object": true + "react": true } }, "react-popper": { @@ -4613,7 +4563,6 @@ }, "packages": { "browserify>process": true, - "browserify>util": true, "semver>lru-cache": true } }, @@ -4671,16 +4620,6 @@ "msCrypto": true } }, - "vinyl>clone": { - "packages": { - "browserify>buffer": true - } - }, - "wait-on>rxjs>tslib": { - "globals": { - "define": true - } - }, "web3": { "globals": { "XMLHttpRequest": true diff --git a/lavamoat/browserify/desktop/policy.json b/lavamoat/browserify/desktop/policy.json index e9b8572ae..9ea8e5e2c 100644 --- a/lavamoat/browserify/desktop/policy.json +++ b/lavamoat/browserify/desktop/policy.json @@ -138,7 +138,6 @@ "@ethereumjs/tx": { "packages": { "@ethereumjs/common": true, - "@ethereumjs/tx>@chainsafe/ssz": true, "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util": true, "@ethereumjs/tx>ethereum-cryptography": true, @@ -146,21 +145,6 @@ "browserify>insert-module-globals>is-buffer": true } }, - "@ethereumjs/tx>@chainsafe/ssz": { - "packages": { - "@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": true, - "browserify>buffer": true - } - }, - "@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": { - "globals": { - "WeakRef": true - }, - "packages": { - "@ethereumjs/tx>@chainsafe/ssz>@chainsafe/as-sha256": true, - "@metamask/key-tree>@noble/hashes": true - } - }, "@ethereumjs/tx>@ethereumjs/rlp": { "globals": { "TextEncoder": true @@ -171,7 +155,6 @@ "console.warn": true }, "packages": { - "@ethereumjs/tx>@chainsafe/ssz": true, "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography": true, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, @@ -325,15 +308,7 @@ "packages": { "@ethersproject/abi>@ethersproject/bytes": true, "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/bignumber>bn.js": true - } - }, - "@ethersproject/bignumber>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true + "bn.js": true } }, "@ethersproject/contracts": { @@ -347,9 +322,17 @@ "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, "@ethersproject/bignumber": true, + "@ethersproject/contracts>@ethersproject/abstract-provider": true, "@ethersproject/hdnode>@ethersproject/abstract-signer": true, - "@ethersproject/hdnode>@ethersproject/transactions": true, - "@ethersproject/providers>@ethersproject/abstract-provider": true + "@ethersproject/hdnode>@ethersproject/transactions": true + } + }, + "@ethersproject/contracts>@ethersproject/abstract-provider": { + "packages": { + "@ethersproject/abi>@ethersproject/bytes": true, + "@ethersproject/abi>@ethersproject/logger": true, + "@ethersproject/abi>@ethersproject/properties": true, + "@ethersproject/bignumber": true } }, "@ethersproject/hdnode": { @@ -441,11 +424,11 @@ "@ethersproject/abi>@ethersproject/properties": true, "@ethersproject/abi>@ethersproject/strings": true, "@ethersproject/bignumber": true, + "@ethersproject/contracts>@ethersproject/abstract-provider": true, "@ethersproject/hdnode>@ethersproject/abstract-signer": true, "@ethersproject/hdnode>@ethersproject/basex": true, "@ethersproject/hdnode>@ethersproject/sha2": true, "@ethersproject/hdnode>@ethersproject/transactions": true, - "@ethersproject/providers>@ethersproject/abstract-provider": true, "@ethersproject/providers>@ethersproject/base64": true, "@ethersproject/providers>@ethersproject/networks": true, "@ethersproject/providers>@ethersproject/random": true, @@ -453,14 +436,6 @@ "@ethersproject/providers>bech32": true } }, - "@ethersproject/providers>@ethersproject/abstract-provider": { - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/abi>@ethersproject/properties": true, - "@ethersproject/bignumber": true - } - }, "@ethersproject/providers>@ethersproject/base64": { "globals": { "atob": true, @@ -501,19 +476,6 @@ "@ethersproject/providers>@ethersproject/base64": true } }, - "@formatjs/intl-relativetimeformat": { - "globals": { - "Intl": true - }, - "packages": { - "@formatjs/intl-relativetimeformat>@formatjs/intl-utils": true - } - }, - "@formatjs/intl-relativetimeformat>@formatjs/intl-utils": { - "globals": { - "Intl.getCanonicalLocales": true - } - }, "@keystonehq/bc-ur-registry-eth": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, @@ -531,7 +493,7 @@ "@ngraveio/bc-ur": true, "browserify>buffer": true, "ethereumjs-wallet>bs58check": true, - "wait-on>rxjs>tslib": true + "mockttp>graphql-tag>tslib": true } }, "@keystonehq/bc-ur-registry-eth>hdkey": { @@ -775,6 +737,9 @@ } }, "@metamask/approval-controller": { + "globals": { + "console.info": true + }, "packages": { "@metamask/approval-controller>nanoid": true, "@metamask/base-controller": true, @@ -855,6 +820,9 @@ } }, "@metamask/base-controller": { + "globals": { + "setTimeout": true + }, "packages": { "immer": true } @@ -881,8 +849,8 @@ "setTimeout": true }, "packages": { + "@metamask/controller-utils>@metamask/utils": true, "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/utils": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, "eth-ens-namehash": true, @@ -890,6 +858,19 @@ "ethjs>ethjs-unit": true } }, + "@metamask/controller-utils>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, "@metamask/controller-utils>@spruceid/siwe-parser": { "globals": { "console.error": true, @@ -1002,12 +983,12 @@ }, "packages": { "@metamask/eth-json-rpc-middleware>@metamask/utils": true, + "@metamask/eth-json-rpc-middleware>clone": true, "@metamask/eth-json-rpc-middleware>pify": true, "@metamask/eth-json-rpc-middleware>safe-stable-stringify": true, "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, "eth-rpc-errors": true, - "json-rpc-engine": true, - "vinyl>clone": true + "json-rpc-engine": true } }, "@metamask/eth-json-rpc-middleware>@metamask/utils": { @@ -1022,6 +1003,11 @@ "superstruct": true } }, + "@metamask/eth-json-rpc-middleware>clone": { + "packages": { + "browserify>buffer": true + } + }, "@metamask/eth-keyring-controller": { "packages": { "@metamask/browser-passworder": true, @@ -1071,11 +1057,11 @@ "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@scure/bip32": { "packages": { "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@noble/secp256k1": true, - "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@scure/bip39>@noble/hashes": true, + "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@scure/bip32>@noble/hashes": true, "@metamask/key-tree>@scure/base": true } }, - "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@scure/bip39>@noble/hashes": { + "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@scure/bip32>@noble/hashes": { "globals": { "TextEncoder": true, "crypto": true @@ -1085,9 +1071,9 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethjs-util": true, "bn.js": true, "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, "eth-sig-util>tweetnacl": true, "eth-sig-util>tweetnacl-util": true } @@ -1107,13 +1093,6 @@ "crypto": true } }, - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, @@ -1174,10 +1153,10 @@ }, "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util": { "packages": { - "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethjs-util": true, "bn.js": true, "browserify>assert": true, "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, @@ -1185,13 +1164,6 @@ "ganache>secp256k1>elliptic": true } }, - "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, "@metamask/eth-ledger-bridge-keyring>hdkey": { "packages": { "@metamask/eth-ledger-bridge-keyring>hdkey>secp256k1": true, @@ -1229,9 +1201,9 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethjs-util": true, "bn.js": true, "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, "eth-sig-util>tweetnacl": true, "eth-sig-util>tweetnacl-util": true } @@ -1251,13 +1223,6 @@ "crypto": true } }, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, "@metamask/eth-snap-keyring>@metamask/keyring-api": { "packages": { "@metamask/eth-snap-keyring>@metamask/keyring-api>@metamask/utils": true, @@ -1271,6 +1236,7 @@ "TextEncoder": true }, "packages": { + "@metamask/key-tree>@noble/hashes": true, "browserify>buffer": true, "nock>debug": true, "semver": true, @@ -1288,6 +1254,7 @@ "TextEncoder": true }, "packages": { + "@metamask/key-tree>@noble/hashes": true, "browserify>buffer": true, "nock>debug": true, "semver": true, @@ -1353,22 +1320,22 @@ "setInterval": true }, "packages": { - "@metamask/eth-token-tracker>ethjs>bn.js": true, "@metamask/eth-token-tracker>ethjs>ethjs-abi": true, "@metamask/eth-token-tracker>ethjs>ethjs-contract": true, "@metamask/eth-token-tracker>ethjs>ethjs-query": true, + "@metamask/eth-token-tracker>ethjs>ethjs-util": true, + "bn.js": true, "browserify>buffer": true, "ethjs>ethjs-filter": true, "ethjs>ethjs-provider-http": true, "ethjs>ethjs-unit": true, - "ethjs>ethjs-util": true, "ethjs>js-sha3": true, "ethjs>number-to-bn": true } }, "@metamask/eth-token-tracker>ethjs>ethjs-abi": { "packages": { - "@metamask/eth-token-tracker>ethjs>bn.js": true, + "bn.js": true, "browserify>buffer": true, "ethjs>js-sha3": true, "ethjs>number-to-bn": true @@ -1377,16 +1344,16 @@ "@metamask/eth-token-tracker>ethjs>ethjs-contract": { "packages": { "@metamask/eth-token-tracker>ethjs>ethjs-contract>ethjs-abi": true, + "@metamask/eth-token-tracker>ethjs>ethjs-util": true, "ethjs-query>babel-runtime": true, "ethjs>ethjs-filter": true, - "ethjs>ethjs-util": true, "ethjs>js-sha3": true, "promise-to-callback": true } }, "@metamask/eth-token-tracker>ethjs>ethjs-contract>ethjs-abi": { "packages": { - "@metamask/eth-token-tracker>ethjs>bn.js": true, + "bn.js": true, "browserify>buffer": true, "ethjs>js-sha3": true, "ethjs>number-to-bn": true @@ -1403,6 +1370,13 @@ "promise-to-callback": true } }, + "@metamask/eth-token-tracker>ethjs>ethjs-util": { + "packages": { + "browserify>buffer": true, + "ethjs>ethjs-util>is-hex-prefixed": true, + "ethjs>ethjs-util>strip-hex-prefix": true + } + }, "@metamask/eth-token-tracker>safe-event-emitter": { "globals": { "setTimeout": true @@ -1454,7 +1428,7 @@ "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect": true, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/utils": true, "browserify>events": true, - "wait-on>rxjs>tslib": true + "mockttp>graphql-tag>tslib": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect": { @@ -1469,7 +1443,7 @@ }, "packages": { "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect>@trezor/transport": true, - "wait-on>rxjs>tslib": true + "mockttp>graphql-tag>tslib": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect>@trezor/transport": { @@ -1650,6 +1624,7 @@ "TextEncoder": true }, "packages": { + "@metamask/key-tree>@noble/hashes": true, "browserify>buffer": true, "nock>debug": true, "semver": true, @@ -1684,6 +1659,94 @@ "TextEncoder": true } }, + "@metamask/keyring-controller": { + "packages": { + "@metamask/base-controller": true, + "@metamask/keyring-controller>@metamask/eth-keyring-controller": true, + "@metamask/keyring-controller>@metamask/utils": true, + "@metamask/keyring-controller>ethereumjs-wallet": true, + "eth-json-rpc-filters>async-mutex": true, + "ethereumjs-util": true + } + }, + "@metamask/keyring-controller>@metamask/eth-keyring-controller": { + "globals": { + "console.error": true + }, + "packages": { + "@metamask/browser-passworder": true, + "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring": true, + "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring": true, + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util": true, + "@metamask/keyring-controller>@metamask/utils": true, + "@metamask/obs-store": true, + "browserify>events": true + } + }, + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util": { + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, + "bn.js": true, + "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, + "eth-sig-util>tweetnacl": true, + "eth-sig-util>tweetnacl-util": true + } + }, + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": { + "globals": { + "TextDecoder": true, + "crypto": true + }, + "packages": { + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true + } + }, + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true + } + }, + "@metamask/keyring-controller>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, + "@metamask/keyring-controller>ethereumjs-wallet": { + "packages": { + "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": true, + "@truffle/codec>utf8": true, + "browserify>buffer": true, + "browserify>crypto-browserify": true, + "ethereumjs-util>ethereum-cryptography": true, + "ethereumjs-util>ethereum-cryptography>scrypt-js": true, + "ethereumjs-wallet>aes-js": true, + "ethereumjs-wallet>bs58check": true, + "ethereumjs-wallet>randombytes": true, + "uuid": true + } + }, + "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": { + "packages": { + "bn.js": true, + "browserify>assert": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true, + "ethereumjs-util>create-hash": true, + "ethereumjs-util>ethereum-cryptography": true, + "ethereumjs-util>rlp": true + } + }, "@metamask/logo": { "globals": { "addEventListener": true, @@ -1702,14 +1765,40 @@ "packages": { "@metamask/base-controller": true, "@metamask/controller-utils": true, + "@metamask/message-manager>@metamask/eth-sig-util": true, "@metamask/message-manager>jsonschema": true, "browserify>buffer": true, "browserify>events": true, - "eth-sig-util": true, "ethereumjs-util": true, "uuid": true } }, + "@metamask/message-manager>@metamask/eth-sig-util": { + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": true, + "bn.js": true, + "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, + "eth-sig-util>tweetnacl": true, + "eth-sig-util>tweetnacl-util": true + } + }, + "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": { + "globals": { + "TextDecoder": true, + "crypto": true + }, + "packages": { + "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true + } + }, + "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true + } + }, "@metamask/message-manager>jsonschema": { "packages": { "browserify>url": true @@ -1744,7 +1833,7 @@ }, "packages": { "@metamask/network-controller>@metamask/eth-json-rpc-infura>@metamask/utils": true, - "@metamask/network-controller>@metamask/eth-json-rpc-infura>eth-json-rpc-middleware": true, + "@metamask/network-controller>@metamask/eth-json-rpc-provider": true, "eth-rpc-errors": true, "json-rpc-engine": true, "node-fetch": true @@ -1762,26 +1851,6 @@ "superstruct": true } }, - "@metamask/network-controller>@metamask/eth-json-rpc-infura>eth-json-rpc-middleware": { - "globals": { - "URL": true, - "btoa": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, - "@metamask/network-controller>@metamask/eth-json-rpc-infura>@metamask/utils": true, - "@metamask/network-controller>@metamask/eth-json-rpc-infura>eth-json-rpc-middleware>pify": true, - "@metamask/safe-event-emitter": true, - "browserify>browser-resolve": true, - "eth-rpc-errors": true, - "json-rpc-engine": true, - "lavamoat>json-stable-stringify": true, - "vinyl>clone": true - } - }, "@metamask/network-controller>@metamask/eth-json-rpc-provider": { "packages": { "@metamask/safe-event-emitter": true, @@ -2008,6 +2077,7 @@ "TextEncoder": true }, "packages": { + "@metamask/key-tree>@noble/hashes": true, "browserify>buffer": true, "nock>debug": true, "semver": true, @@ -2075,34 +2145,13 @@ "@ethersproject/abi>@ethersproject/bytes": true, "@ethersproject/bignumber": true, "@ethersproject/providers": true, - "@metamask/smart-transactions-controller>@metamask/base-controller": true, - "@metamask/smart-transactions-controller>@metamask/controller-utils": true, + "@metamask/base-controller": true, + "@metamask/controller-utils": true, "@metamask/smart-transactions-controller>bignumber.js": true, - "@metamask/smart-transactions-controller>isomorphic-fetch": true, "fast-json-patch": true, "lodash": true } }, - "@metamask/smart-transactions-controller>@metamask/base-controller": { - "packages": { - "immer": true - } - }, - "@metamask/smart-transactions-controller>@metamask/controller-utils": { - "globals": { - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/smart-transactions-controller>isomorphic-fetch": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true, - "ethjs>ethjs-unit": true - } - }, "@metamask/smart-transactions-controller>@metamask/controllers>nanoid": { "globals": { "crypto.getRandomValues": true @@ -2114,25 +2163,6 @@ "define": true } }, - "@metamask/smart-transactions-controller>isomorphic-fetch": { - "globals": { - "fetch.bind": true - }, - "packages": { - "@metamask/smart-transactions-controller>isomorphic-fetch>whatwg-fetch": true - } - }, - "@metamask/smart-transactions-controller>isomorphic-fetch>whatwg-fetch": { - "globals": { - "Blob": true, - "FileReader": true, - "FormData": true, - "URLSearchParams.prototype.isPrototypeOf": true, - "XMLHttpRequest": true, - "define": true, - "setTimeout": true - } - }, "@metamask/snaps-controllers-flask": { "globals": { "URL": true, @@ -2169,13 +2199,19 @@ "@metamask/key-tree": true, "@metamask/key-tree>@noble/hashes": true, "@metamask/permission-controller": true, + "@metamask/snaps-controllers-flask>@metamask/rpc-methods>@metamask/snaps-ui": true, "@metamask/snaps-controllers-flask>@metamask/snaps-utils": true, - "@metamask/snaps-controllers-flask>@metamask/snaps-utils>@metamask/snaps-ui": true, "@metamask/snaps-controllers-flask>@metamask/utils": true, "eth-rpc-errors": true, "superstruct": true } }, + "@metamask/snaps-controllers-flask>@metamask/rpc-methods>@metamask/snaps-ui": { + "packages": { + "@metamask/snaps-controllers-flask>@metamask/utils": true, + "superstruct": true + } + }, "@metamask/snaps-controllers-flask>@metamask/snaps-utils": { "globals": { "TextDecoder": true, @@ -2201,18 +2237,13 @@ "superstruct": true } }, - "@metamask/snaps-controllers-flask>@metamask/snaps-utils>@metamask/snaps-ui": { - "packages": { - "@metamask/snaps-controllers-flask>@metamask/utils": true, - "superstruct": true - } - }, "@metamask/snaps-controllers-flask>@metamask/utils": { "globals": { "TextDecoder": true, "TextEncoder": true }, "packages": { + "@metamask/key-tree>@noble/hashes": true, "browserify>buffer": true, "nock>debug": true, "semver": true, @@ -2382,6 +2413,7 @@ "TextEncoder": true }, "packages": { + "@metamask/key-tree>@noble/hashes": true, "browserify>buffer": true, "nock>debug": true, "semver": true, @@ -2419,6 +2451,7 @@ "TextEncoder": true }, "packages": { + "@metamask/key-tree>@noble/hashes": true, "browserify>buffer": true, "nock>debug": true, "semver": true, @@ -2452,6 +2485,7 @@ "TextEncoder": true }, "packages": { + "@metamask/key-tree>@noble/hashes": true, "browserify>buffer": true, "nock>debug": true, "semver": true, @@ -2717,11 +2751,11 @@ "@truffle/codec>@truffle/abi-utils": true, "@truffle/codec>@truffle/compile-common": true, "@truffle/codec>big.js": true, - "@truffle/codec>bn.js": true, "@truffle/codec>cbor": true, "@truffle/codec>semver": true, "@truffle/codec>utf8": true, "@truffle/codec>web3-utils": true, + "bn.js": true, "browserify>buffer": true, "browserify>os-browserify": true, "browserify>util": true, @@ -2878,14 +2912,6 @@ "define": true } }, - "@truffle/codec>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "@truffle/codec>cbor": { "globals": { "TextDecoder": true @@ -2928,8 +2954,8 @@ }, "packages": { "@truffle/codec>utf8": true, - "@truffle/codec>web3-utils>bn.js": true, "@truffle/codec>web3-utils>ethereum-bloom-filters": true, + "bn.js": true, "browserify>buffer": true, "ethereumjs-util": true, "ethereumjs-wallet>randombytes": true, @@ -2937,14 +2963,6 @@ "ethjs>number-to-bn": true } }, - "@truffle/codec>web3-utils>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "@truffle/codec>web3-utils>ethereum-bloom-filters": { "packages": { "@truffle/codec>web3-utils>ethereum-bloom-filters>js-sha3": true @@ -2966,7 +2984,7 @@ "@truffle/codec>web3-utils": true, "@truffle/decoder>@truffle/encoder": true, "@truffle/decoder>@truffle/source-map-utils": true, - "@truffle/decoder>bn.js": true, + "bn.js": true, "nock>debug": true } }, @@ -3139,11 +3157,11 @@ "@ethersproject/abi>@ethersproject/keccak256": true, "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, + "@ethersproject/contracts>@ethersproject/abstract-provider": true, "@ethersproject/hdnode": true, "@ethersproject/hdnode>@ethersproject/abstract-signer": true, "@ethersproject/hdnode>@ethersproject/signing-key": true, "@ethersproject/hdnode>@ethersproject/transactions": true, - "@ethersproject/providers>@ethersproject/abstract-provider": true, "@ethersproject/providers>@ethersproject/random": true, "@truffle/decoder>@truffle/encoder>@ensdomains/ensjs>ethers>@ethersproject/json-wallets": true } @@ -3188,20 +3206,11 @@ "@truffle/decoder>@truffle/source-map-utils>node-interval-tree>shallowequal": true } }, - "@truffle/decoder>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "@zxing/browser": { "globals": { "HTMLElement": true, "HTMLImageElement": true, "HTMLVideoElement": true, - "URL.createObjectURL": true, "clearTimeout": true, "console.error": true, "console.warn": true, @@ -3215,17 +3224,20 @@ }, "@zxing/library": { "globals": { + "HTMLImageElement": true, + "HTMLVideoElement": true, "TextDecoder": true, "TextEncoder": true, + "URL.createObjectURL": true, "btoa": true, - "clearTimeout": true, - "define": true, - "document.createElement": true, - "document.createElementNS": true, - "document.getElementById": true, - "navigator.mediaDevices.enumerateDevices": true, - "navigator.mediaDevices.getUserMedia": true, + "console.log": true, + "console.warn": true, + "document": true, + "navigator": true, "setTimeout": true + }, + "packages": { + "@zxing/library>ts-custom-error": true } }, "addons-linter>sha.js": { @@ -3714,7 +3726,7 @@ "setTimeout": true }, "packages": { - "wait-on>rxjs>tslib": true + "mockttp>graphql-tag>tslib": true } }, "eth-keyring-controller>@metamask/browser-passworder": { @@ -3733,11 +3745,11 @@ }, "packages": { "@ethereumjs/tx>@ethereumjs/util": true, + "bn.js": true, "browserify>buffer": true, "browserify>crypto-browserify": true, "browserify>events": true, "eth-lattice-keyring>@ethereumjs/tx": true, - "eth-lattice-keyring>bn.js": true, "eth-lattice-keyring>gridplus-sdk": true, "eth-lattice-keyring>rlp": true } @@ -3785,14 +3797,6 @@ "crypto": true } }, - "eth-lattice-keyring>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "eth-lattice-keyring>gridplus-sdk": { "globals": { "AbortController": true, @@ -3845,27 +3849,11 @@ "@ethersproject/providers": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@chainsafe/ssz": true, + "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": true } }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@chainsafe/ssz": { - "packages": { - "browserify": true, - "browserify>buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>case": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": true - } - }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": { - "globals": { - "WeakRef": true - }, - "packages": { - "browserify": true - } - }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": { "packages": { "@ethereumjs/common>crc-32": true, @@ -3929,19 +3917,11 @@ "intToBuffer": true }, "packages": { - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>bn.js": true, + "bn.js": true, "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>buffer": true, "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>js-sha3": true } }, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>buffer": { "globals": { "console": true @@ -4064,39 +4044,24 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, - "ethereumjs-abi>ethereumjs-util>ethjs-util": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, "ganache>secp256k1>elliptic": true } }, - "ethereumjs-abi>ethereumjs-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, "ethereumjs-util": { "packages": { + "bn.js": true, "browserify>assert": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, - "ethereumjs-util>bn.js": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true } }, - "ethereumjs-util>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "ethereumjs-util>create-hash": { "packages": { "addons-linter>sha.js": true, @@ -4148,10 +4113,15 @@ }, "ethereumjs-util>ethereum-cryptography": { "packages": { + "browserify>assert": true, "browserify>buffer": true, + "browserify>crypto-browserify>create-hmac": true, + "ethereumjs-util>ethereum-cryptography>hash.js": true, "ethereumjs-util>ethereum-cryptography>keccak": true, "ethereumjs-util>ethereum-cryptography>secp256k1": true, - "ethereumjs-wallet>randombytes": true + "ethereumjs-wallet>bs58check": true, + "ethereumjs-wallet>randombytes": true, + "ethereumjs-wallet>safe-buffer": true } }, "ethereumjs-util>ethereum-cryptography>browserify-aes": { @@ -4208,16 +4178,8 @@ }, "ethereumjs-util>rlp": { "packages": { - "browserify>buffer": true, - "ethereumjs-util>rlp>bn.js": true - } - }, - "ethereumjs-util>rlp>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true + "bn.js": true, + "browserify>buffer": true } }, "ethereumjs-wallet": { @@ -4260,20 +4222,13 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, - "ethereumjs-wallet>ethereumjs-util>ethjs-util": true, "ganache>secp256k1>elliptic": true } }, - "ethereumjs-wallet>ethereumjs-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, "ethereumjs-wallet>randombytes": { "globals": { "crypto": true, @@ -4312,10 +4267,10 @@ "setInterval": true }, "packages": { + "bn.js": true, "browserify>buffer": true, "ethjs-contract": true, "ethjs-query": true, - "ethjs>bn.js": true, "ethjs>ethjs-abi": true, "ethjs>ethjs-filter": true, "ethjs>ethjs-provider-http": true, @@ -4328,21 +4283,28 @@ "ethjs-contract": { "packages": { "ethjs-contract>ethjs-abi": true, + "ethjs-contract>ethjs-util": true, "ethjs-query>babel-runtime": true, "ethjs>ethjs-filter": true, - "ethjs>ethjs-util": true, "ethjs>js-sha3": true, "promise-to-callback": true } }, "ethjs-contract>ethjs-abi": { "packages": { + "bn.js": true, "browserify>buffer": true, - "ethjs-contract>ethjs-abi>bn.js": true, "ethjs>js-sha3": true, "ethjs>number-to-bn": true } }, + "ethjs-contract>ethjs-util": { + "packages": { + "browserify>buffer": true, + "ethjs>ethjs-util>is-hex-prefixed": true, + "ethjs>ethjs-util>strip-hex-prefix": true + } + }, "ethjs-query": { "globals": { "console": true @@ -4373,11 +4335,18 @@ "ethjs-query>ethjs-format": { "packages": { "ethjs-query>ethjs-format>ethjs-schema": true, - "ethjs>ethjs-util": true, + "ethjs-query>ethjs-format>ethjs-util": true, "ethjs>ethjs-util>strip-hex-prefix": true, "ethjs>number-to-bn": true } }, + "ethjs-query>ethjs-format>ethjs-util": { + "packages": { + "browserify>buffer": true, + "ethjs>ethjs-util>is-hex-prefixed": true, + "ethjs>ethjs-util>strip-hex-prefix": true + } + }, "ethjs-query>ethjs-rpc": { "packages": { "promise-to-callback": true @@ -4385,8 +4354,8 @@ }, "ethjs>ethjs-abi": { "packages": { + "bn.js": true, "browserify>buffer": true, - "ethjs>bn.js": true, "ethjs>js-sha3": true, "ethjs>number-to-bn": true } @@ -4409,7 +4378,7 @@ }, "ethjs>ethjs-unit": { "packages": { - "ethjs>ethjs-unit>bn.js": true, + "bn.js": true, "ethjs>number-to-bn": true } }, @@ -4432,8 +4401,8 @@ }, "ethjs>number-to-bn": { "packages": { - "ethjs>ethjs-util>strip-hex-prefix": true, - "ethjs>number-to-bn>bn.js": true + "bn.js": true, + "ethjs>ethjs-util>strip-hex-prefix": true } }, "extension-port-stream": { @@ -4588,6 +4557,11 @@ "readable-stream>util-deprecate": true } }, + "mockttp>graphql-tag>tslib": { + "globals": { + "define": true + } + }, "nanoid": { "globals": { "crypto": true, @@ -4792,7 +4766,7 @@ "setTimeout": true }, "packages": { - "wait-on>rxjs>tslib": true + "mockttp>graphql-tag>tslib": true } }, "react-focus-lock>react-clientside-effect": { @@ -4811,9 +4785,9 @@ "console.error": true }, "packages": { + "mockttp>graphql-tag>tslib": true, "react": true, - "react-focus-lock>use-sidecar>detect-node-es": true, - "wait-on>rxjs>tslib": true + "react-focus-lock>use-sidecar>detect-node-es": true } }, "react-idle-timer": { @@ -4829,29 +4803,12 @@ }, "react-inspector": { "globals": { - "Node.CDATA_SECTION_NODE": true, - "Node.COMMENT_NODE": true, - "Node.DOCUMENT_FRAGMENT_NODE": true, - "Node.DOCUMENT_NODE": true, - "Node.DOCUMENT_TYPE_NODE": true, - "Node.ELEMENT_NODE": true, - "Node.PROCESSING_INSTRUCTION_NODE": true, - "Node.TEXT_NODE": true + "Node": true, + "chromeDark": true, + "chromeLight": true }, "packages": { - "ethjs-query>babel-runtime": true, - "prop-types": true, - "react": true, - "react-inspector>is-dom": true - } - }, - "react-inspector>is-dom": { - "globals": { - "Node": true - }, - "packages": { - "@lavamoat/snow>is-cross-origin>is-window": true, - "proxyquire>fill-keys>is-object": true + "react": true } }, "react-markdown": { @@ -4931,9 +4888,9 @@ }, "react-markdown>unified": { "packages": { - "jsdom>request>extend": true, "mocha>yargs-unparser>is-plain-obj": true, "react-markdown>unified>bail": true, + "react-markdown>unified>extend": true, "react-markdown>unified>is-buffer": true, "react-markdown>unified>trough": true, "react-markdown>vfile": true @@ -5234,7 +5191,6 @@ }, "packages": { "browserify>process": true, - "browserify>util": true, "semver>lru-cache": true } }, @@ -5297,21 +5253,11 @@ "msCrypto": true } }, - "vinyl>clone": { - "packages": { - "browserify>buffer": true - } - }, "vinyl>replace-ext": { "packages": { "browserify>path-browserify": true } }, - "wait-on>rxjs>tslib": { - "globals": { - "define": true - } - }, "web3": { "globals": { "XMLHttpRequest": true diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index e9b8572ae..9ea8e5e2c 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -138,7 +138,6 @@ "@ethereumjs/tx": { "packages": { "@ethereumjs/common": true, - "@ethereumjs/tx>@chainsafe/ssz": true, "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util": true, "@ethereumjs/tx>ethereum-cryptography": true, @@ -146,21 +145,6 @@ "browserify>insert-module-globals>is-buffer": true } }, - "@ethereumjs/tx>@chainsafe/ssz": { - "packages": { - "@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": true, - "browserify>buffer": true - } - }, - "@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": { - "globals": { - "WeakRef": true - }, - "packages": { - "@ethereumjs/tx>@chainsafe/ssz>@chainsafe/as-sha256": true, - "@metamask/key-tree>@noble/hashes": true - } - }, "@ethereumjs/tx>@ethereumjs/rlp": { "globals": { "TextEncoder": true @@ -171,7 +155,6 @@ "console.warn": true }, "packages": { - "@ethereumjs/tx>@chainsafe/ssz": true, "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography": true, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, @@ -325,15 +308,7 @@ "packages": { "@ethersproject/abi>@ethersproject/bytes": true, "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/bignumber>bn.js": true - } - }, - "@ethersproject/bignumber>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true + "bn.js": true } }, "@ethersproject/contracts": { @@ -347,9 +322,17 @@ "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, "@ethersproject/bignumber": true, + "@ethersproject/contracts>@ethersproject/abstract-provider": true, "@ethersproject/hdnode>@ethersproject/abstract-signer": true, - "@ethersproject/hdnode>@ethersproject/transactions": true, - "@ethersproject/providers>@ethersproject/abstract-provider": true + "@ethersproject/hdnode>@ethersproject/transactions": true + } + }, + "@ethersproject/contracts>@ethersproject/abstract-provider": { + "packages": { + "@ethersproject/abi>@ethersproject/bytes": true, + "@ethersproject/abi>@ethersproject/logger": true, + "@ethersproject/abi>@ethersproject/properties": true, + "@ethersproject/bignumber": true } }, "@ethersproject/hdnode": { @@ -441,11 +424,11 @@ "@ethersproject/abi>@ethersproject/properties": true, "@ethersproject/abi>@ethersproject/strings": true, "@ethersproject/bignumber": true, + "@ethersproject/contracts>@ethersproject/abstract-provider": true, "@ethersproject/hdnode>@ethersproject/abstract-signer": true, "@ethersproject/hdnode>@ethersproject/basex": true, "@ethersproject/hdnode>@ethersproject/sha2": true, "@ethersproject/hdnode>@ethersproject/transactions": true, - "@ethersproject/providers>@ethersproject/abstract-provider": true, "@ethersproject/providers>@ethersproject/base64": true, "@ethersproject/providers>@ethersproject/networks": true, "@ethersproject/providers>@ethersproject/random": true, @@ -453,14 +436,6 @@ "@ethersproject/providers>bech32": true } }, - "@ethersproject/providers>@ethersproject/abstract-provider": { - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/abi>@ethersproject/properties": true, - "@ethersproject/bignumber": true - } - }, "@ethersproject/providers>@ethersproject/base64": { "globals": { "atob": true, @@ -501,19 +476,6 @@ "@ethersproject/providers>@ethersproject/base64": true } }, - "@formatjs/intl-relativetimeformat": { - "globals": { - "Intl": true - }, - "packages": { - "@formatjs/intl-relativetimeformat>@formatjs/intl-utils": true - } - }, - "@formatjs/intl-relativetimeformat>@formatjs/intl-utils": { - "globals": { - "Intl.getCanonicalLocales": true - } - }, "@keystonehq/bc-ur-registry-eth": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, @@ -531,7 +493,7 @@ "@ngraveio/bc-ur": true, "browserify>buffer": true, "ethereumjs-wallet>bs58check": true, - "wait-on>rxjs>tslib": true + "mockttp>graphql-tag>tslib": true } }, "@keystonehq/bc-ur-registry-eth>hdkey": { @@ -775,6 +737,9 @@ } }, "@metamask/approval-controller": { + "globals": { + "console.info": true + }, "packages": { "@metamask/approval-controller>nanoid": true, "@metamask/base-controller": true, @@ -855,6 +820,9 @@ } }, "@metamask/base-controller": { + "globals": { + "setTimeout": true + }, "packages": { "immer": true } @@ -881,8 +849,8 @@ "setTimeout": true }, "packages": { + "@metamask/controller-utils>@metamask/utils": true, "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/utils": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, "eth-ens-namehash": true, @@ -890,6 +858,19 @@ "ethjs>ethjs-unit": true } }, + "@metamask/controller-utils>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, "@metamask/controller-utils>@spruceid/siwe-parser": { "globals": { "console.error": true, @@ -1002,12 +983,12 @@ }, "packages": { "@metamask/eth-json-rpc-middleware>@metamask/utils": true, + "@metamask/eth-json-rpc-middleware>clone": true, "@metamask/eth-json-rpc-middleware>pify": true, "@metamask/eth-json-rpc-middleware>safe-stable-stringify": true, "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, "eth-rpc-errors": true, - "json-rpc-engine": true, - "vinyl>clone": true + "json-rpc-engine": true } }, "@metamask/eth-json-rpc-middleware>@metamask/utils": { @@ -1022,6 +1003,11 @@ "superstruct": true } }, + "@metamask/eth-json-rpc-middleware>clone": { + "packages": { + "browserify>buffer": true + } + }, "@metamask/eth-keyring-controller": { "packages": { "@metamask/browser-passworder": true, @@ -1071,11 +1057,11 @@ "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@scure/bip32": { "packages": { "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@noble/secp256k1": true, - "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@scure/bip39>@noble/hashes": true, + "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@scure/bip32>@noble/hashes": true, "@metamask/key-tree>@scure/base": true } }, - "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@scure/bip39>@noble/hashes": { + "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@scure/bip32>@noble/hashes": { "globals": { "TextEncoder": true, "crypto": true @@ -1085,9 +1071,9 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethjs-util": true, "bn.js": true, "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, "eth-sig-util>tweetnacl": true, "eth-sig-util>tweetnacl-util": true } @@ -1107,13 +1093,6 @@ "crypto": true } }, - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, @@ -1174,10 +1153,10 @@ }, "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util": { "packages": { - "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethjs-util": true, "bn.js": true, "browserify>assert": true, "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, @@ -1185,13 +1164,6 @@ "ganache>secp256k1>elliptic": true } }, - "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, "@metamask/eth-ledger-bridge-keyring>hdkey": { "packages": { "@metamask/eth-ledger-bridge-keyring>hdkey>secp256k1": true, @@ -1229,9 +1201,9 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethjs-util": true, "bn.js": true, "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, "eth-sig-util>tweetnacl": true, "eth-sig-util>tweetnacl-util": true } @@ -1251,13 +1223,6 @@ "crypto": true } }, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, "@metamask/eth-snap-keyring>@metamask/keyring-api": { "packages": { "@metamask/eth-snap-keyring>@metamask/keyring-api>@metamask/utils": true, @@ -1271,6 +1236,7 @@ "TextEncoder": true }, "packages": { + "@metamask/key-tree>@noble/hashes": true, "browserify>buffer": true, "nock>debug": true, "semver": true, @@ -1288,6 +1254,7 @@ "TextEncoder": true }, "packages": { + "@metamask/key-tree>@noble/hashes": true, "browserify>buffer": true, "nock>debug": true, "semver": true, @@ -1353,22 +1320,22 @@ "setInterval": true }, "packages": { - "@metamask/eth-token-tracker>ethjs>bn.js": true, "@metamask/eth-token-tracker>ethjs>ethjs-abi": true, "@metamask/eth-token-tracker>ethjs>ethjs-contract": true, "@metamask/eth-token-tracker>ethjs>ethjs-query": true, + "@metamask/eth-token-tracker>ethjs>ethjs-util": true, + "bn.js": true, "browserify>buffer": true, "ethjs>ethjs-filter": true, "ethjs>ethjs-provider-http": true, "ethjs>ethjs-unit": true, - "ethjs>ethjs-util": true, "ethjs>js-sha3": true, "ethjs>number-to-bn": true } }, "@metamask/eth-token-tracker>ethjs>ethjs-abi": { "packages": { - "@metamask/eth-token-tracker>ethjs>bn.js": true, + "bn.js": true, "browserify>buffer": true, "ethjs>js-sha3": true, "ethjs>number-to-bn": true @@ -1377,16 +1344,16 @@ "@metamask/eth-token-tracker>ethjs>ethjs-contract": { "packages": { "@metamask/eth-token-tracker>ethjs>ethjs-contract>ethjs-abi": true, + "@metamask/eth-token-tracker>ethjs>ethjs-util": true, "ethjs-query>babel-runtime": true, "ethjs>ethjs-filter": true, - "ethjs>ethjs-util": true, "ethjs>js-sha3": true, "promise-to-callback": true } }, "@metamask/eth-token-tracker>ethjs>ethjs-contract>ethjs-abi": { "packages": { - "@metamask/eth-token-tracker>ethjs>bn.js": true, + "bn.js": true, "browserify>buffer": true, "ethjs>js-sha3": true, "ethjs>number-to-bn": true @@ -1403,6 +1370,13 @@ "promise-to-callback": true } }, + "@metamask/eth-token-tracker>ethjs>ethjs-util": { + "packages": { + "browserify>buffer": true, + "ethjs>ethjs-util>is-hex-prefixed": true, + "ethjs>ethjs-util>strip-hex-prefix": true + } + }, "@metamask/eth-token-tracker>safe-event-emitter": { "globals": { "setTimeout": true @@ -1454,7 +1428,7 @@ "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect": true, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/utils": true, "browserify>events": true, - "wait-on>rxjs>tslib": true + "mockttp>graphql-tag>tslib": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect": { @@ -1469,7 +1443,7 @@ }, "packages": { "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect>@trezor/transport": true, - "wait-on>rxjs>tslib": true + "mockttp>graphql-tag>tslib": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect>@trezor/transport": { @@ -1650,6 +1624,7 @@ "TextEncoder": true }, "packages": { + "@metamask/key-tree>@noble/hashes": true, "browserify>buffer": true, "nock>debug": true, "semver": true, @@ -1684,6 +1659,94 @@ "TextEncoder": true } }, + "@metamask/keyring-controller": { + "packages": { + "@metamask/base-controller": true, + "@metamask/keyring-controller>@metamask/eth-keyring-controller": true, + "@metamask/keyring-controller>@metamask/utils": true, + "@metamask/keyring-controller>ethereumjs-wallet": true, + "eth-json-rpc-filters>async-mutex": true, + "ethereumjs-util": true + } + }, + "@metamask/keyring-controller>@metamask/eth-keyring-controller": { + "globals": { + "console.error": true + }, + "packages": { + "@metamask/browser-passworder": true, + "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring": true, + "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring": true, + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util": true, + "@metamask/keyring-controller>@metamask/utils": true, + "@metamask/obs-store": true, + "browserify>events": true + } + }, + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util": { + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, + "bn.js": true, + "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, + "eth-sig-util>tweetnacl": true, + "eth-sig-util>tweetnacl-util": true + } + }, + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": { + "globals": { + "TextDecoder": true, + "crypto": true + }, + "packages": { + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true + } + }, + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true + } + }, + "@metamask/keyring-controller>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, + "@metamask/keyring-controller>ethereumjs-wallet": { + "packages": { + "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": true, + "@truffle/codec>utf8": true, + "browserify>buffer": true, + "browserify>crypto-browserify": true, + "ethereumjs-util>ethereum-cryptography": true, + "ethereumjs-util>ethereum-cryptography>scrypt-js": true, + "ethereumjs-wallet>aes-js": true, + "ethereumjs-wallet>bs58check": true, + "ethereumjs-wallet>randombytes": true, + "uuid": true + } + }, + "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": { + "packages": { + "bn.js": true, + "browserify>assert": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true, + "ethereumjs-util>create-hash": true, + "ethereumjs-util>ethereum-cryptography": true, + "ethereumjs-util>rlp": true + } + }, "@metamask/logo": { "globals": { "addEventListener": true, @@ -1702,14 +1765,40 @@ "packages": { "@metamask/base-controller": true, "@metamask/controller-utils": true, + "@metamask/message-manager>@metamask/eth-sig-util": true, "@metamask/message-manager>jsonschema": true, "browserify>buffer": true, "browserify>events": true, - "eth-sig-util": true, "ethereumjs-util": true, "uuid": true } }, + "@metamask/message-manager>@metamask/eth-sig-util": { + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": true, + "bn.js": true, + "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, + "eth-sig-util>tweetnacl": true, + "eth-sig-util>tweetnacl-util": true + } + }, + "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": { + "globals": { + "TextDecoder": true, + "crypto": true + }, + "packages": { + "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true + } + }, + "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true + } + }, "@metamask/message-manager>jsonschema": { "packages": { "browserify>url": true @@ -1744,7 +1833,7 @@ }, "packages": { "@metamask/network-controller>@metamask/eth-json-rpc-infura>@metamask/utils": true, - "@metamask/network-controller>@metamask/eth-json-rpc-infura>eth-json-rpc-middleware": true, + "@metamask/network-controller>@metamask/eth-json-rpc-provider": true, "eth-rpc-errors": true, "json-rpc-engine": true, "node-fetch": true @@ -1762,26 +1851,6 @@ "superstruct": true } }, - "@metamask/network-controller>@metamask/eth-json-rpc-infura>eth-json-rpc-middleware": { - "globals": { - "URL": true, - "btoa": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, - "@metamask/network-controller>@metamask/eth-json-rpc-infura>@metamask/utils": true, - "@metamask/network-controller>@metamask/eth-json-rpc-infura>eth-json-rpc-middleware>pify": true, - "@metamask/safe-event-emitter": true, - "browserify>browser-resolve": true, - "eth-rpc-errors": true, - "json-rpc-engine": true, - "lavamoat>json-stable-stringify": true, - "vinyl>clone": true - } - }, "@metamask/network-controller>@metamask/eth-json-rpc-provider": { "packages": { "@metamask/safe-event-emitter": true, @@ -2008,6 +2077,7 @@ "TextEncoder": true }, "packages": { + "@metamask/key-tree>@noble/hashes": true, "browserify>buffer": true, "nock>debug": true, "semver": true, @@ -2075,34 +2145,13 @@ "@ethersproject/abi>@ethersproject/bytes": true, "@ethersproject/bignumber": true, "@ethersproject/providers": true, - "@metamask/smart-transactions-controller>@metamask/base-controller": true, - "@metamask/smart-transactions-controller>@metamask/controller-utils": true, + "@metamask/base-controller": true, + "@metamask/controller-utils": true, "@metamask/smart-transactions-controller>bignumber.js": true, - "@metamask/smart-transactions-controller>isomorphic-fetch": true, "fast-json-patch": true, "lodash": true } }, - "@metamask/smart-transactions-controller>@metamask/base-controller": { - "packages": { - "immer": true - } - }, - "@metamask/smart-transactions-controller>@metamask/controller-utils": { - "globals": { - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/smart-transactions-controller>isomorphic-fetch": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true, - "ethjs>ethjs-unit": true - } - }, "@metamask/smart-transactions-controller>@metamask/controllers>nanoid": { "globals": { "crypto.getRandomValues": true @@ -2114,25 +2163,6 @@ "define": true } }, - "@metamask/smart-transactions-controller>isomorphic-fetch": { - "globals": { - "fetch.bind": true - }, - "packages": { - "@metamask/smart-transactions-controller>isomorphic-fetch>whatwg-fetch": true - } - }, - "@metamask/smart-transactions-controller>isomorphic-fetch>whatwg-fetch": { - "globals": { - "Blob": true, - "FileReader": true, - "FormData": true, - "URLSearchParams.prototype.isPrototypeOf": true, - "XMLHttpRequest": true, - "define": true, - "setTimeout": true - } - }, "@metamask/snaps-controllers-flask": { "globals": { "URL": true, @@ -2169,13 +2199,19 @@ "@metamask/key-tree": true, "@metamask/key-tree>@noble/hashes": true, "@metamask/permission-controller": true, + "@metamask/snaps-controllers-flask>@metamask/rpc-methods>@metamask/snaps-ui": true, "@metamask/snaps-controllers-flask>@metamask/snaps-utils": true, - "@metamask/snaps-controllers-flask>@metamask/snaps-utils>@metamask/snaps-ui": true, "@metamask/snaps-controllers-flask>@metamask/utils": true, "eth-rpc-errors": true, "superstruct": true } }, + "@metamask/snaps-controllers-flask>@metamask/rpc-methods>@metamask/snaps-ui": { + "packages": { + "@metamask/snaps-controllers-flask>@metamask/utils": true, + "superstruct": true + } + }, "@metamask/snaps-controllers-flask>@metamask/snaps-utils": { "globals": { "TextDecoder": true, @@ -2201,18 +2237,13 @@ "superstruct": true } }, - "@metamask/snaps-controllers-flask>@metamask/snaps-utils>@metamask/snaps-ui": { - "packages": { - "@metamask/snaps-controllers-flask>@metamask/utils": true, - "superstruct": true - } - }, "@metamask/snaps-controllers-flask>@metamask/utils": { "globals": { "TextDecoder": true, "TextEncoder": true }, "packages": { + "@metamask/key-tree>@noble/hashes": true, "browserify>buffer": true, "nock>debug": true, "semver": true, @@ -2382,6 +2413,7 @@ "TextEncoder": true }, "packages": { + "@metamask/key-tree>@noble/hashes": true, "browserify>buffer": true, "nock>debug": true, "semver": true, @@ -2419,6 +2451,7 @@ "TextEncoder": true }, "packages": { + "@metamask/key-tree>@noble/hashes": true, "browserify>buffer": true, "nock>debug": true, "semver": true, @@ -2452,6 +2485,7 @@ "TextEncoder": true }, "packages": { + "@metamask/key-tree>@noble/hashes": true, "browserify>buffer": true, "nock>debug": true, "semver": true, @@ -2717,11 +2751,11 @@ "@truffle/codec>@truffle/abi-utils": true, "@truffle/codec>@truffle/compile-common": true, "@truffle/codec>big.js": true, - "@truffle/codec>bn.js": true, "@truffle/codec>cbor": true, "@truffle/codec>semver": true, "@truffle/codec>utf8": true, "@truffle/codec>web3-utils": true, + "bn.js": true, "browserify>buffer": true, "browserify>os-browserify": true, "browserify>util": true, @@ -2878,14 +2912,6 @@ "define": true } }, - "@truffle/codec>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "@truffle/codec>cbor": { "globals": { "TextDecoder": true @@ -2928,8 +2954,8 @@ }, "packages": { "@truffle/codec>utf8": true, - "@truffle/codec>web3-utils>bn.js": true, "@truffle/codec>web3-utils>ethereum-bloom-filters": true, + "bn.js": true, "browserify>buffer": true, "ethereumjs-util": true, "ethereumjs-wallet>randombytes": true, @@ -2937,14 +2963,6 @@ "ethjs>number-to-bn": true } }, - "@truffle/codec>web3-utils>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "@truffle/codec>web3-utils>ethereum-bloom-filters": { "packages": { "@truffle/codec>web3-utils>ethereum-bloom-filters>js-sha3": true @@ -2966,7 +2984,7 @@ "@truffle/codec>web3-utils": true, "@truffle/decoder>@truffle/encoder": true, "@truffle/decoder>@truffle/source-map-utils": true, - "@truffle/decoder>bn.js": true, + "bn.js": true, "nock>debug": true } }, @@ -3139,11 +3157,11 @@ "@ethersproject/abi>@ethersproject/keccak256": true, "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, + "@ethersproject/contracts>@ethersproject/abstract-provider": true, "@ethersproject/hdnode": true, "@ethersproject/hdnode>@ethersproject/abstract-signer": true, "@ethersproject/hdnode>@ethersproject/signing-key": true, "@ethersproject/hdnode>@ethersproject/transactions": true, - "@ethersproject/providers>@ethersproject/abstract-provider": true, "@ethersproject/providers>@ethersproject/random": true, "@truffle/decoder>@truffle/encoder>@ensdomains/ensjs>ethers>@ethersproject/json-wallets": true } @@ -3188,20 +3206,11 @@ "@truffle/decoder>@truffle/source-map-utils>node-interval-tree>shallowequal": true } }, - "@truffle/decoder>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "@zxing/browser": { "globals": { "HTMLElement": true, "HTMLImageElement": true, "HTMLVideoElement": true, - "URL.createObjectURL": true, "clearTimeout": true, "console.error": true, "console.warn": true, @@ -3215,17 +3224,20 @@ }, "@zxing/library": { "globals": { + "HTMLImageElement": true, + "HTMLVideoElement": true, "TextDecoder": true, "TextEncoder": true, + "URL.createObjectURL": true, "btoa": true, - "clearTimeout": true, - "define": true, - "document.createElement": true, - "document.createElementNS": true, - "document.getElementById": true, - "navigator.mediaDevices.enumerateDevices": true, - "navigator.mediaDevices.getUserMedia": true, + "console.log": true, + "console.warn": true, + "document": true, + "navigator": true, "setTimeout": true + }, + "packages": { + "@zxing/library>ts-custom-error": true } }, "addons-linter>sha.js": { @@ -3714,7 +3726,7 @@ "setTimeout": true }, "packages": { - "wait-on>rxjs>tslib": true + "mockttp>graphql-tag>tslib": true } }, "eth-keyring-controller>@metamask/browser-passworder": { @@ -3733,11 +3745,11 @@ }, "packages": { "@ethereumjs/tx>@ethereumjs/util": true, + "bn.js": true, "browserify>buffer": true, "browserify>crypto-browserify": true, "browserify>events": true, "eth-lattice-keyring>@ethereumjs/tx": true, - "eth-lattice-keyring>bn.js": true, "eth-lattice-keyring>gridplus-sdk": true, "eth-lattice-keyring>rlp": true } @@ -3785,14 +3797,6 @@ "crypto": true } }, - "eth-lattice-keyring>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "eth-lattice-keyring>gridplus-sdk": { "globals": { "AbortController": true, @@ -3845,27 +3849,11 @@ "@ethersproject/providers": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@chainsafe/ssz": true, + "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": true } }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@chainsafe/ssz": { - "packages": { - "browserify": true, - "browserify>buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>case": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": true - } - }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": { - "globals": { - "WeakRef": true - }, - "packages": { - "browserify": true - } - }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": { "packages": { "@ethereumjs/common>crc-32": true, @@ -3929,19 +3917,11 @@ "intToBuffer": true }, "packages": { - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>bn.js": true, + "bn.js": true, "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>buffer": true, "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>js-sha3": true } }, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>buffer": { "globals": { "console": true @@ -4064,39 +4044,24 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, - "ethereumjs-abi>ethereumjs-util>ethjs-util": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, "ganache>secp256k1>elliptic": true } }, - "ethereumjs-abi>ethereumjs-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, "ethereumjs-util": { "packages": { + "bn.js": true, "browserify>assert": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, - "ethereumjs-util>bn.js": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true } }, - "ethereumjs-util>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "ethereumjs-util>create-hash": { "packages": { "addons-linter>sha.js": true, @@ -4148,10 +4113,15 @@ }, "ethereumjs-util>ethereum-cryptography": { "packages": { + "browserify>assert": true, "browserify>buffer": true, + "browserify>crypto-browserify>create-hmac": true, + "ethereumjs-util>ethereum-cryptography>hash.js": true, "ethereumjs-util>ethereum-cryptography>keccak": true, "ethereumjs-util>ethereum-cryptography>secp256k1": true, - "ethereumjs-wallet>randombytes": true + "ethereumjs-wallet>bs58check": true, + "ethereumjs-wallet>randombytes": true, + "ethereumjs-wallet>safe-buffer": true } }, "ethereumjs-util>ethereum-cryptography>browserify-aes": { @@ -4208,16 +4178,8 @@ }, "ethereumjs-util>rlp": { "packages": { - "browserify>buffer": true, - "ethereumjs-util>rlp>bn.js": true - } - }, - "ethereumjs-util>rlp>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true + "bn.js": true, + "browserify>buffer": true } }, "ethereumjs-wallet": { @@ -4260,20 +4222,13 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, - "ethereumjs-wallet>ethereumjs-util>ethjs-util": true, "ganache>secp256k1>elliptic": true } }, - "ethereumjs-wallet>ethereumjs-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, "ethereumjs-wallet>randombytes": { "globals": { "crypto": true, @@ -4312,10 +4267,10 @@ "setInterval": true }, "packages": { + "bn.js": true, "browserify>buffer": true, "ethjs-contract": true, "ethjs-query": true, - "ethjs>bn.js": true, "ethjs>ethjs-abi": true, "ethjs>ethjs-filter": true, "ethjs>ethjs-provider-http": true, @@ -4328,21 +4283,28 @@ "ethjs-contract": { "packages": { "ethjs-contract>ethjs-abi": true, + "ethjs-contract>ethjs-util": true, "ethjs-query>babel-runtime": true, "ethjs>ethjs-filter": true, - "ethjs>ethjs-util": true, "ethjs>js-sha3": true, "promise-to-callback": true } }, "ethjs-contract>ethjs-abi": { "packages": { + "bn.js": true, "browserify>buffer": true, - "ethjs-contract>ethjs-abi>bn.js": true, "ethjs>js-sha3": true, "ethjs>number-to-bn": true } }, + "ethjs-contract>ethjs-util": { + "packages": { + "browserify>buffer": true, + "ethjs>ethjs-util>is-hex-prefixed": true, + "ethjs>ethjs-util>strip-hex-prefix": true + } + }, "ethjs-query": { "globals": { "console": true @@ -4373,11 +4335,18 @@ "ethjs-query>ethjs-format": { "packages": { "ethjs-query>ethjs-format>ethjs-schema": true, - "ethjs>ethjs-util": true, + "ethjs-query>ethjs-format>ethjs-util": true, "ethjs>ethjs-util>strip-hex-prefix": true, "ethjs>number-to-bn": true } }, + "ethjs-query>ethjs-format>ethjs-util": { + "packages": { + "browserify>buffer": true, + "ethjs>ethjs-util>is-hex-prefixed": true, + "ethjs>ethjs-util>strip-hex-prefix": true + } + }, "ethjs-query>ethjs-rpc": { "packages": { "promise-to-callback": true @@ -4385,8 +4354,8 @@ }, "ethjs>ethjs-abi": { "packages": { + "bn.js": true, "browserify>buffer": true, - "ethjs>bn.js": true, "ethjs>js-sha3": true, "ethjs>number-to-bn": true } @@ -4409,7 +4378,7 @@ }, "ethjs>ethjs-unit": { "packages": { - "ethjs>ethjs-unit>bn.js": true, + "bn.js": true, "ethjs>number-to-bn": true } }, @@ -4432,8 +4401,8 @@ }, "ethjs>number-to-bn": { "packages": { - "ethjs>ethjs-util>strip-hex-prefix": true, - "ethjs>number-to-bn>bn.js": true + "bn.js": true, + "ethjs>ethjs-util>strip-hex-prefix": true } }, "extension-port-stream": { @@ -4588,6 +4557,11 @@ "readable-stream>util-deprecate": true } }, + "mockttp>graphql-tag>tslib": { + "globals": { + "define": true + } + }, "nanoid": { "globals": { "crypto": true, @@ -4792,7 +4766,7 @@ "setTimeout": true }, "packages": { - "wait-on>rxjs>tslib": true + "mockttp>graphql-tag>tslib": true } }, "react-focus-lock>react-clientside-effect": { @@ -4811,9 +4785,9 @@ "console.error": true }, "packages": { + "mockttp>graphql-tag>tslib": true, "react": true, - "react-focus-lock>use-sidecar>detect-node-es": true, - "wait-on>rxjs>tslib": true + "react-focus-lock>use-sidecar>detect-node-es": true } }, "react-idle-timer": { @@ -4829,29 +4803,12 @@ }, "react-inspector": { "globals": { - "Node.CDATA_SECTION_NODE": true, - "Node.COMMENT_NODE": true, - "Node.DOCUMENT_FRAGMENT_NODE": true, - "Node.DOCUMENT_NODE": true, - "Node.DOCUMENT_TYPE_NODE": true, - "Node.ELEMENT_NODE": true, - "Node.PROCESSING_INSTRUCTION_NODE": true, - "Node.TEXT_NODE": true + "Node": true, + "chromeDark": true, + "chromeLight": true }, "packages": { - "ethjs-query>babel-runtime": true, - "prop-types": true, - "react": true, - "react-inspector>is-dom": true - } - }, - "react-inspector>is-dom": { - "globals": { - "Node": true - }, - "packages": { - "@lavamoat/snow>is-cross-origin>is-window": true, - "proxyquire>fill-keys>is-object": true + "react": true } }, "react-markdown": { @@ -4931,9 +4888,9 @@ }, "react-markdown>unified": { "packages": { - "jsdom>request>extend": true, "mocha>yargs-unparser>is-plain-obj": true, "react-markdown>unified>bail": true, + "react-markdown>unified>extend": true, "react-markdown>unified>is-buffer": true, "react-markdown>unified>trough": true, "react-markdown>vfile": true @@ -5234,7 +5191,6 @@ }, "packages": { "browserify>process": true, - "browserify>util": true, "semver>lru-cache": true } }, @@ -5297,21 +5253,11 @@ "msCrypto": true } }, - "vinyl>clone": { - "packages": { - "browserify>buffer": true - } - }, "vinyl>replace-ext": { "packages": { "browserify>path-browserify": true } }, - "wait-on>rxjs>tslib": { - "globals": { - "define": true - } - }, "web3": { "globals": { "XMLHttpRequest": true diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index f3373a420..afb8f0b99 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -138,7 +138,6 @@ "@ethereumjs/tx": { "packages": { "@ethereumjs/common": true, - "@ethereumjs/tx>@chainsafe/ssz": true, "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util": true, "@ethereumjs/tx>ethereum-cryptography": true, @@ -146,21 +145,6 @@ "browserify>insert-module-globals>is-buffer": true } }, - "@ethereumjs/tx>@chainsafe/ssz": { - "packages": { - "@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": true, - "browserify>buffer": true - } - }, - "@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": { - "globals": { - "WeakRef": true - }, - "packages": { - "@ethereumjs/tx>@chainsafe/ssz>@chainsafe/as-sha256": true, - "@metamask/key-tree>@noble/hashes": true - } - }, "@ethereumjs/tx>@ethereumjs/rlp": { "globals": { "TextEncoder": true @@ -171,7 +155,6 @@ "console.warn": true }, "packages": { - "@ethereumjs/tx>@chainsafe/ssz": true, "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography": true, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, @@ -325,15 +308,7 @@ "packages": { "@ethersproject/abi>@ethersproject/bytes": true, "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/bignumber>bn.js": true - } - }, - "@ethersproject/bignumber>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true + "bn.js": true } }, "@ethersproject/contracts": { @@ -347,9 +322,17 @@ "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, "@ethersproject/bignumber": true, + "@ethersproject/contracts>@ethersproject/abstract-provider": true, "@ethersproject/hdnode>@ethersproject/abstract-signer": true, - "@ethersproject/hdnode>@ethersproject/transactions": true, - "@ethersproject/providers>@ethersproject/abstract-provider": true + "@ethersproject/hdnode>@ethersproject/transactions": true + } + }, + "@ethersproject/contracts>@ethersproject/abstract-provider": { + "packages": { + "@ethersproject/abi>@ethersproject/bytes": true, + "@ethersproject/abi>@ethersproject/logger": true, + "@ethersproject/abi>@ethersproject/properties": true, + "@ethersproject/bignumber": true } }, "@ethersproject/hdnode": { @@ -441,11 +424,11 @@ "@ethersproject/abi>@ethersproject/properties": true, "@ethersproject/abi>@ethersproject/strings": true, "@ethersproject/bignumber": true, + "@ethersproject/contracts>@ethersproject/abstract-provider": true, "@ethersproject/hdnode>@ethersproject/abstract-signer": true, "@ethersproject/hdnode>@ethersproject/basex": true, "@ethersproject/hdnode>@ethersproject/sha2": true, "@ethersproject/hdnode>@ethersproject/transactions": true, - "@ethersproject/providers>@ethersproject/abstract-provider": true, "@ethersproject/providers>@ethersproject/base64": true, "@ethersproject/providers>@ethersproject/networks": true, "@ethersproject/providers>@ethersproject/random": true, @@ -453,14 +436,6 @@ "@ethersproject/providers>bech32": true } }, - "@ethersproject/providers>@ethersproject/abstract-provider": { - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/abi>@ethersproject/properties": true, - "@ethersproject/bignumber": true - } - }, "@ethersproject/providers>@ethersproject/base64": { "globals": { "atob": true, @@ -501,19 +476,6 @@ "@ethersproject/providers>@ethersproject/base64": true } }, - "@formatjs/intl-relativetimeformat": { - "globals": { - "Intl": true - }, - "packages": { - "@formatjs/intl-relativetimeformat>@formatjs/intl-utils": true - } - }, - "@formatjs/intl-relativetimeformat>@formatjs/intl-utils": { - "globals": { - "Intl.getCanonicalLocales": true - } - }, "@keystonehq/bc-ur-registry-eth": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, @@ -531,7 +493,7 @@ "@ngraveio/bc-ur": true, "browserify>buffer": true, "ethereumjs-wallet>bs58check": true, - "wait-on>rxjs>tslib": true + "mockttp>graphql-tag>tslib": true } }, "@keystonehq/bc-ur-registry-eth>hdkey": { @@ -775,6 +737,9 @@ } }, "@metamask/approval-controller": { + "globals": { + "console.info": true + }, "packages": { "@metamask/approval-controller>nanoid": true, "@metamask/base-controller": true, @@ -855,6 +820,9 @@ } }, "@metamask/base-controller": { + "globals": { + "setTimeout": true + }, "packages": { "immer": true } @@ -881,8 +849,8 @@ "setTimeout": true }, "packages": { + "@metamask/controller-utils>@metamask/utils": true, "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/utils": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, "eth-ens-namehash": true, @@ -890,6 +858,19 @@ "ethjs>ethjs-unit": true } }, + "@metamask/controller-utils>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, "@metamask/controller-utils>@spruceid/siwe-parser": { "globals": { "console.error": true, @@ -931,12 +912,12 @@ }, "packages": { "@metamask/eth-json-rpc-middleware>@metamask/utils": true, + "@metamask/eth-json-rpc-middleware>clone": true, "@metamask/eth-json-rpc-middleware>pify": true, "@metamask/eth-json-rpc-middleware>safe-stable-stringify": true, "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, "eth-rpc-errors": true, - "json-rpc-engine": true, - "vinyl>clone": true + "json-rpc-engine": true } }, "@metamask/eth-json-rpc-middleware>@metamask/utils": { @@ -951,6 +932,11 @@ "superstruct": true } }, + "@metamask/eth-json-rpc-middleware>clone": { + "packages": { + "browserify>buffer": true + } + }, "@metamask/eth-keyring-controller": { "packages": { "@metamask/browser-passworder": true, @@ -1000,11 +986,11 @@ "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@scure/bip32": { "packages": { "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@noble/secp256k1": true, - "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@scure/bip39>@noble/hashes": true, + "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@scure/bip32>@noble/hashes": true, "@metamask/key-tree>@scure/base": true } }, - "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@scure/bip39>@noble/hashes": { + "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@scure/bip32>@noble/hashes": { "globals": { "TextEncoder": true, "crypto": true @@ -1014,9 +1000,9 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethjs-util": true, "bn.js": true, "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, "eth-sig-util>tweetnacl": true, "eth-sig-util>tweetnacl-util": true } @@ -1036,13 +1022,6 @@ "crypto": true } }, - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, @@ -1103,10 +1082,10 @@ }, "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util": { "packages": { - "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethjs-util": true, "bn.js": true, "browserify>assert": true, "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, @@ -1114,13 +1093,6 @@ "ganache>secp256k1>elliptic": true } }, - "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, "@metamask/eth-ledger-bridge-keyring>hdkey": { "packages": { "@metamask/eth-ledger-bridge-keyring>hdkey>secp256k1": true, @@ -1144,9 +1116,9 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethjs-util": true, "bn.js": true, "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, "eth-sig-util>tweetnacl": true, "eth-sig-util>tweetnacl-util": true } @@ -1166,13 +1138,6 @@ "crypto": true } }, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, "@metamask/eth-token-tracker": { "globals": { "console.warn": true @@ -1227,22 +1192,22 @@ "setInterval": true }, "packages": { - "@metamask/eth-token-tracker>ethjs>bn.js": true, "@metamask/eth-token-tracker>ethjs>ethjs-abi": true, "@metamask/eth-token-tracker>ethjs>ethjs-contract": true, "@metamask/eth-token-tracker>ethjs>ethjs-query": true, + "@metamask/eth-token-tracker>ethjs>ethjs-util": true, + "bn.js": true, "browserify>buffer": true, "ethjs>ethjs-filter": true, "ethjs>ethjs-provider-http": true, "ethjs>ethjs-unit": true, - "ethjs>ethjs-util": true, "ethjs>js-sha3": true, "ethjs>number-to-bn": true } }, "@metamask/eth-token-tracker>ethjs>ethjs-abi": { "packages": { - "@metamask/eth-token-tracker>ethjs>bn.js": true, + "bn.js": true, "browserify>buffer": true, "ethjs>js-sha3": true, "ethjs>number-to-bn": true @@ -1251,16 +1216,16 @@ "@metamask/eth-token-tracker>ethjs>ethjs-contract": { "packages": { "@metamask/eth-token-tracker>ethjs>ethjs-contract>ethjs-abi": true, + "@metamask/eth-token-tracker>ethjs>ethjs-util": true, "ethjs-query>babel-runtime": true, "ethjs>ethjs-filter": true, - "ethjs>ethjs-util": true, "ethjs>js-sha3": true, "promise-to-callback": true } }, "@metamask/eth-token-tracker>ethjs>ethjs-contract>ethjs-abi": { "packages": { - "@metamask/eth-token-tracker>ethjs>bn.js": true, + "bn.js": true, "browserify>buffer": true, "ethjs>js-sha3": true, "ethjs>number-to-bn": true @@ -1277,6 +1242,13 @@ "promise-to-callback": true } }, + "@metamask/eth-token-tracker>ethjs>ethjs-util": { + "packages": { + "browserify>buffer": true, + "ethjs>ethjs-util>is-hex-prefixed": true, + "ethjs>ethjs-util>strip-hex-prefix": true + } + }, "@metamask/eth-token-tracker>safe-event-emitter": { "globals": { "setTimeout": true @@ -1328,7 +1300,7 @@ "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect": true, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/utils": true, "browserify>events": true, - "wait-on>rxjs>tslib": true + "mockttp>graphql-tag>tslib": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect": { @@ -1343,7 +1315,7 @@ }, "packages": { "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect>@trezor/transport": true, - "wait-on>rxjs>tslib": true + "mockttp>graphql-tag>tslib": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect>@trezor/transport": { @@ -1508,28 +1480,6 @@ "jest-canvas-mock>moo-color>color-name": true } }, - "@metamask/key-tree": { - "packages": { - "@metamask/key-tree>@metamask/utils": true, - "@metamask/key-tree>@noble/ed25519": true, - "@metamask/key-tree>@noble/hashes": true, - "@metamask/key-tree>@noble/secp256k1": true, - "@metamask/key-tree>@scure/base": true, - "@metamask/scure-bip39": true - } - }, - "@metamask/key-tree>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "browserify>buffer": true, - "nock>debug": true, - "semver": true, - "superstruct": true - } - }, "@metamask/key-tree>@noble/ed25519": { "globals": { "crypto": true @@ -1558,6 +1508,94 @@ "TextEncoder": true } }, + "@metamask/keyring-controller": { + "packages": { + "@metamask/base-controller": true, + "@metamask/keyring-controller>@metamask/eth-keyring-controller": true, + "@metamask/keyring-controller>@metamask/utils": true, + "@metamask/keyring-controller>ethereumjs-wallet": true, + "eth-json-rpc-filters>async-mutex": true, + "ethereumjs-util": true + } + }, + "@metamask/keyring-controller>@metamask/eth-keyring-controller": { + "globals": { + "console.error": true + }, + "packages": { + "@metamask/browser-passworder": true, + "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring": true, + "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring": true, + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util": true, + "@metamask/keyring-controller>@metamask/utils": true, + "@metamask/obs-store": true, + "browserify>events": true + } + }, + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util": { + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, + "bn.js": true, + "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, + "eth-sig-util>tweetnacl": true, + "eth-sig-util>tweetnacl-util": true + } + }, + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": { + "globals": { + "TextDecoder": true, + "crypto": true + }, + "packages": { + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true + } + }, + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true + } + }, + "@metamask/keyring-controller>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, + "@metamask/keyring-controller>ethereumjs-wallet": { + "packages": { + "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": true, + "@truffle/codec>utf8": true, + "browserify>buffer": true, + "browserify>crypto-browserify": true, + "ethereumjs-util>ethereum-cryptography": true, + "ethereumjs-util>ethereum-cryptography>scrypt-js": true, + "ethereumjs-wallet>aes-js": true, + "ethereumjs-wallet>bs58check": true, + "ethereumjs-wallet>randombytes": true, + "uuid": true + } + }, + "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": { + "packages": { + "bn.js": true, + "browserify>assert": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true, + "ethereumjs-util>create-hash": true, + "ethereumjs-util>ethereum-cryptography": true, + "ethereumjs-util>rlp": true + } + }, "@metamask/logo": { "globals": { "addEventListener": true, @@ -1576,14 +1614,40 @@ "packages": { "@metamask/base-controller": true, "@metamask/controller-utils": true, + "@metamask/message-manager>@metamask/eth-sig-util": true, "@metamask/message-manager>jsonschema": true, "browserify>buffer": true, "browserify>events": true, - "eth-sig-util": true, "ethereumjs-util": true, "uuid": true } }, + "@metamask/message-manager>@metamask/eth-sig-util": { + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": true, + "bn.js": true, + "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, + "eth-sig-util>tweetnacl": true, + "eth-sig-util>tweetnacl-util": true + } + }, + "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": { + "globals": { + "TextDecoder": true, + "crypto": true + }, + "packages": { + "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true + } + }, + "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true + } + }, "@metamask/message-manager>jsonschema": { "packages": { "browserify>url": true @@ -1618,7 +1682,7 @@ }, "packages": { "@metamask/network-controller>@metamask/eth-json-rpc-infura>@metamask/utils": true, - "@metamask/network-controller>@metamask/eth-json-rpc-infura>eth-json-rpc-middleware": true, + "@metamask/network-controller>@metamask/eth-json-rpc-provider": true, "eth-rpc-errors": true, "json-rpc-engine": true, "node-fetch": true @@ -1636,26 +1700,6 @@ "superstruct": true } }, - "@metamask/network-controller>@metamask/eth-json-rpc-infura>eth-json-rpc-middleware": { - "globals": { - "URL": true, - "btoa": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, - "@metamask/network-controller>@metamask/eth-json-rpc-infura>@metamask/utils": true, - "@metamask/network-controller>@metamask/eth-json-rpc-infura>eth-json-rpc-middleware>pify": true, - "@metamask/safe-event-emitter": true, - "browserify>browser-resolve": true, - "eth-rpc-errors": true, - "json-rpc-engine": true, - "lavamoat>json-stable-stringify": true, - "vinyl>clone": true - } - }, "@metamask/network-controller>@metamask/eth-json-rpc-provider": { "packages": { "@metamask/safe-event-emitter": true, @@ -1764,9 +1808,9 @@ "@metamask/rpc-methods": { "packages": { "@metamask/browser-passworder": true, - "@metamask/key-tree": true, "@metamask/key-tree>@noble/hashes": true, "@metamask/permission-controller": true, + "@metamask/rpc-methods>@metamask/key-tree": true, "@metamask/rpc-methods>@metamask/utils": true, "@metamask/rpc-methods>nanoid": true, "@metamask/snaps-ui": true, @@ -1780,12 +1824,23 @@ "crypto.getRandomValues": true } }, + "@metamask/rpc-methods>@metamask/key-tree": { + "packages": { + "@metamask/key-tree>@noble/ed25519": true, + "@metamask/key-tree>@noble/hashes": true, + "@metamask/key-tree>@noble/secp256k1": true, + "@metamask/key-tree>@scure/base": true, + "@metamask/rpc-methods>@metamask/utils": true, + "@metamask/scure-bip39": true + } + }, "@metamask/rpc-methods>@metamask/utils": { "globals": { "TextDecoder": true, "TextEncoder": true }, "packages": { + "@metamask/key-tree>@noble/hashes": true, "browserify>buffer": true, "nock>debug": true, "semver": true, @@ -1848,34 +1903,13 @@ "@ethersproject/abi>@ethersproject/bytes": true, "@ethersproject/bignumber": true, "@ethersproject/providers": true, - "@metamask/smart-transactions-controller>@metamask/base-controller": true, - "@metamask/smart-transactions-controller>@metamask/controller-utils": true, + "@metamask/base-controller": true, + "@metamask/controller-utils": true, "@metamask/smart-transactions-controller>bignumber.js": true, - "@metamask/smart-transactions-controller>isomorphic-fetch": true, "fast-json-patch": true, "lodash": true } }, - "@metamask/smart-transactions-controller>@metamask/base-controller": { - "packages": { - "immer": true - } - }, - "@metamask/smart-transactions-controller>@metamask/controller-utils": { - "globals": { - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/smart-transactions-controller>isomorphic-fetch": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true, - "ethjs>ethjs-unit": true - } - }, "@metamask/smart-transactions-controller>@metamask/controllers>nanoid": { "globals": { "crypto.getRandomValues": true @@ -1887,25 +1921,6 @@ "define": true } }, - "@metamask/smart-transactions-controller>isomorphic-fetch": { - "globals": { - "fetch.bind": true - }, - "packages": { - "@metamask/smart-transactions-controller>isomorphic-fetch>whatwg-fetch": true - } - }, - "@metamask/smart-transactions-controller>isomorphic-fetch>whatwg-fetch": { - "globals": { - "Blob": true, - "FileReader": true, - "FormData": true, - "URLSearchParams.prototype.isPrototypeOf": true, - "XMLHttpRequest": true, - "define": true, - "setTimeout": true - } - }, "@metamask/snaps-controllers-flask>nanoid": { "globals": { "crypto.getRandomValues": true @@ -1928,6 +1943,7 @@ "TextEncoder": true }, "packages": { + "@metamask/key-tree>@noble/hashes": true, "browserify>buffer": true, "nock>debug": true, "semver": true, @@ -1945,9 +1961,9 @@ "document.createElement": true }, "packages": { - "@metamask/key-tree": true, "@metamask/key-tree>@noble/hashes": true, "@metamask/key-tree>@scure/base": true, + "@metamask/snaps-utils>@metamask/key-tree": true, "@metamask/snaps-utils>@metamask/utils": true, "@metamask/snaps-utils>cron-parser": true, "@metamask/snaps-utils>fast-json-stable-stringify": true, @@ -1957,12 +1973,23 @@ "superstruct": true } }, + "@metamask/snaps-utils>@metamask/key-tree": { + "packages": { + "@metamask/key-tree>@noble/ed25519": true, + "@metamask/key-tree>@noble/hashes": true, + "@metamask/key-tree>@noble/secp256k1": true, + "@metamask/key-tree>@scure/base": true, + "@metamask/scure-bip39": true, + "@metamask/snaps-utils>@metamask/utils": true + } + }, "@metamask/snaps-utils>@metamask/utils": { "globals": { "TextDecoder": true, "TextEncoder": true }, "packages": { + "@metamask/key-tree>@noble/hashes": true, "browserify>buffer": true, "nock>debug": true, "semver": true, @@ -2228,11 +2255,11 @@ "@truffle/codec>@truffle/abi-utils": true, "@truffle/codec>@truffle/compile-common": true, "@truffle/codec>big.js": true, - "@truffle/codec>bn.js": true, "@truffle/codec>cbor": true, "@truffle/codec>semver": true, "@truffle/codec>utf8": true, "@truffle/codec>web3-utils": true, + "bn.js": true, "browserify>buffer": true, "browserify>os-browserify": true, "browserify>util": true, @@ -2389,14 +2416,6 @@ "define": true } }, - "@truffle/codec>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "@truffle/codec>cbor": { "globals": { "TextDecoder": true @@ -2439,8 +2458,8 @@ }, "packages": { "@truffle/codec>utf8": true, - "@truffle/codec>web3-utils>bn.js": true, "@truffle/codec>web3-utils>ethereum-bloom-filters": true, + "bn.js": true, "browserify>buffer": true, "ethereumjs-util": true, "ethereumjs-wallet>randombytes": true, @@ -2448,14 +2467,6 @@ "ethjs>number-to-bn": true } }, - "@truffle/codec>web3-utils>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "@truffle/codec>web3-utils>ethereum-bloom-filters": { "packages": { "@truffle/codec>web3-utils>ethereum-bloom-filters>js-sha3": true @@ -2477,7 +2488,7 @@ "@truffle/codec>web3-utils": true, "@truffle/decoder>@truffle/encoder": true, "@truffle/decoder>@truffle/source-map-utils": true, - "@truffle/decoder>bn.js": true, + "bn.js": true, "nock>debug": true } }, @@ -2650,11 +2661,11 @@ "@ethersproject/abi>@ethersproject/keccak256": true, "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, + "@ethersproject/contracts>@ethersproject/abstract-provider": true, "@ethersproject/hdnode": true, "@ethersproject/hdnode>@ethersproject/abstract-signer": true, "@ethersproject/hdnode>@ethersproject/signing-key": true, "@ethersproject/hdnode>@ethersproject/transactions": true, - "@ethersproject/providers>@ethersproject/abstract-provider": true, "@ethersproject/providers>@ethersproject/random": true, "@truffle/decoder>@truffle/encoder>@ensdomains/ensjs>ethers>@ethersproject/json-wallets": true } @@ -2699,20 +2710,11 @@ "@truffle/decoder>@truffle/source-map-utils>node-interval-tree>shallowequal": true } }, - "@truffle/decoder>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "@zxing/browser": { "globals": { "HTMLElement": true, "HTMLImageElement": true, "HTMLVideoElement": true, - "URL.createObjectURL": true, "clearTimeout": true, "console.error": true, "console.warn": true, @@ -2726,17 +2728,20 @@ }, "@zxing/library": { "globals": { + "HTMLImageElement": true, + "HTMLVideoElement": true, "TextDecoder": true, "TextEncoder": true, + "URL.createObjectURL": true, "btoa": true, - "clearTimeout": true, - "define": true, - "document.createElement": true, - "document.createElementNS": true, - "document.getElementById": true, - "navigator.mediaDevices.enumerateDevices": true, - "navigator.mediaDevices.getUserMedia": true, + "console.log": true, + "console.warn": true, + "document": true, + "navigator": true, "setTimeout": true + }, + "packages": { + "@zxing/library>ts-custom-error": true } }, "addons-linter>sha.js": { @@ -3225,7 +3230,7 @@ "setTimeout": true }, "packages": { - "wait-on>rxjs>tslib": true + "mockttp>graphql-tag>tslib": true } }, "eth-keyring-controller>@metamask/browser-passworder": { @@ -3244,11 +3249,11 @@ }, "packages": { "@ethereumjs/tx>@ethereumjs/util": true, + "bn.js": true, "browserify>buffer": true, "browserify>crypto-browserify": true, "browserify>events": true, "eth-lattice-keyring>@ethereumjs/tx": true, - "eth-lattice-keyring>bn.js": true, "eth-lattice-keyring>gridplus-sdk": true, "eth-lattice-keyring>rlp": true } @@ -3296,14 +3301,6 @@ "crypto": true } }, - "eth-lattice-keyring>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "eth-lattice-keyring>gridplus-sdk": { "globals": { "AbortController": true, @@ -3356,27 +3353,11 @@ "@ethersproject/providers": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@chainsafe/ssz": true, + "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": true } }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@chainsafe/ssz": { - "packages": { - "browserify": true, - "browserify>buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>case": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": true - } - }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": { - "globals": { - "WeakRef": true - }, - "packages": { - "browserify": true - } - }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": { "packages": { "@ethereumjs/common>crc-32": true, @@ -3440,19 +3421,11 @@ "intToBuffer": true }, "packages": { - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>bn.js": true, + "bn.js": true, "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>buffer": true, "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>js-sha3": true } }, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>buffer": { "globals": { "console": true @@ -3575,39 +3548,24 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, - "ethereumjs-abi>ethereumjs-util>ethjs-util": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, "ganache>secp256k1>elliptic": true } }, - "ethereumjs-abi>ethereumjs-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, "ethereumjs-util": { "packages": { + "bn.js": true, "browserify>assert": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, - "ethereumjs-util>bn.js": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true } }, - "ethereumjs-util>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "ethereumjs-util>create-hash": { "packages": { "addons-linter>sha.js": true, @@ -3659,10 +3617,15 @@ }, "ethereumjs-util>ethereum-cryptography": { "packages": { + "browserify>assert": true, "browserify>buffer": true, + "browserify>crypto-browserify>create-hmac": true, + "ethereumjs-util>ethereum-cryptography>hash.js": true, "ethereumjs-util>ethereum-cryptography>keccak": true, "ethereumjs-util>ethereum-cryptography>secp256k1": true, - "ethereumjs-wallet>randombytes": true + "ethereumjs-wallet>bs58check": true, + "ethereumjs-wallet>randombytes": true, + "ethereumjs-wallet>safe-buffer": true } }, "ethereumjs-util>ethereum-cryptography>browserify-aes": { @@ -3719,16 +3682,8 @@ }, "ethereumjs-util>rlp": { "packages": { - "browserify>buffer": true, - "ethereumjs-util>rlp>bn.js": true - } - }, - "ethereumjs-util>rlp>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true + "bn.js": true, + "browserify>buffer": true } }, "ethereumjs-wallet": { @@ -3771,20 +3726,13 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, - "ethereumjs-wallet>ethereumjs-util>ethjs-util": true, "ganache>secp256k1>elliptic": true } }, - "ethereumjs-wallet>ethereumjs-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, "ethereumjs-wallet>randombytes": { "globals": { "crypto": true, @@ -3823,10 +3771,10 @@ "setInterval": true }, "packages": { + "bn.js": true, "browserify>buffer": true, "ethjs-contract": true, "ethjs-query": true, - "ethjs>bn.js": true, "ethjs>ethjs-abi": true, "ethjs>ethjs-filter": true, "ethjs>ethjs-provider-http": true, @@ -3839,21 +3787,28 @@ "ethjs-contract": { "packages": { "ethjs-contract>ethjs-abi": true, + "ethjs-contract>ethjs-util": true, "ethjs-query>babel-runtime": true, "ethjs>ethjs-filter": true, - "ethjs>ethjs-util": true, "ethjs>js-sha3": true, "promise-to-callback": true } }, "ethjs-contract>ethjs-abi": { "packages": { + "bn.js": true, "browserify>buffer": true, - "ethjs-contract>ethjs-abi>bn.js": true, "ethjs>js-sha3": true, "ethjs>number-to-bn": true } }, + "ethjs-contract>ethjs-util": { + "packages": { + "browserify>buffer": true, + "ethjs>ethjs-util>is-hex-prefixed": true, + "ethjs>ethjs-util>strip-hex-prefix": true + } + }, "ethjs-query": { "globals": { "console": true @@ -3884,11 +3839,18 @@ "ethjs-query>ethjs-format": { "packages": { "ethjs-query>ethjs-format>ethjs-schema": true, - "ethjs>ethjs-util": true, + "ethjs-query>ethjs-format>ethjs-util": true, "ethjs>ethjs-util>strip-hex-prefix": true, "ethjs>number-to-bn": true } }, + "ethjs-query>ethjs-format>ethjs-util": { + "packages": { + "browserify>buffer": true, + "ethjs>ethjs-util>is-hex-prefixed": true, + "ethjs>ethjs-util>strip-hex-prefix": true + } + }, "ethjs-query>ethjs-rpc": { "packages": { "promise-to-callback": true @@ -3896,8 +3858,8 @@ }, "ethjs>ethjs-abi": { "packages": { + "bn.js": true, "browserify>buffer": true, - "ethjs>bn.js": true, "ethjs>js-sha3": true, "ethjs>number-to-bn": true } @@ -3920,7 +3882,7 @@ }, "ethjs>ethjs-unit": { "packages": { - "ethjs>ethjs-unit>bn.js": true, + "bn.js": true, "ethjs>number-to-bn": true } }, @@ -3943,8 +3905,8 @@ }, "ethjs>number-to-bn": { "packages": { - "ethjs>ethjs-util>strip-hex-prefix": true, - "ethjs>number-to-bn>bn.js": true + "bn.js": true, + "ethjs>ethjs-util>strip-hex-prefix": true } }, "extension-port-stream": { @@ -4081,6 +4043,11 @@ "Intl": true } }, + "mockttp>graphql-tag>tslib": { + "globals": { + "define": true + } + }, "nanoid": { "globals": { "crypto": true, @@ -4285,7 +4252,7 @@ "setTimeout": true }, "packages": { - "wait-on>rxjs>tslib": true + "mockttp>graphql-tag>tslib": true } }, "react-focus-lock>react-clientside-effect": { @@ -4304,9 +4271,9 @@ "console.error": true }, "packages": { + "mockttp>graphql-tag>tslib": true, "react": true, - "react-focus-lock>use-sidecar>detect-node-es": true, - "wait-on>rxjs>tslib": true + "react-focus-lock>use-sidecar>detect-node-es": true } }, "react-idle-timer": { @@ -4322,29 +4289,12 @@ }, "react-inspector": { "globals": { - "Node.CDATA_SECTION_NODE": true, - "Node.COMMENT_NODE": true, - "Node.DOCUMENT_FRAGMENT_NODE": true, - "Node.DOCUMENT_NODE": true, - "Node.DOCUMENT_TYPE_NODE": true, - "Node.ELEMENT_NODE": true, - "Node.PROCESSING_INSTRUCTION_NODE": true, - "Node.TEXT_NODE": true + "Node": true, + "chromeDark": true, + "chromeLight": true }, "packages": { - "ethjs-query>babel-runtime": true, - "prop-types": true, - "react": true, - "react-inspector>is-dom": true - } - }, - "react-inspector>is-dom": { - "globals": { - "Node": true - }, - "packages": { - "@lavamoat/snow>is-cross-origin>is-window": true, - "proxyquire>fill-keys>is-object": true + "react": true } }, "react-popper": { @@ -4613,7 +4563,6 @@ }, "packages": { "browserify>process": true, - "browserify>util": true, "semver>lru-cache": true } }, @@ -4671,16 +4620,6 @@ "msCrypto": true } }, - "vinyl>clone": { - "packages": { - "browserify>buffer": true - } - }, - "wait-on>rxjs>tslib": { - "globals": { - "define": true - } - }, "web3": { "globals": { "XMLHttpRequest": true diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index a097c6d55..63c7e9bb2 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -138,7 +138,6 @@ "@ethereumjs/tx": { "packages": { "@ethereumjs/common": true, - "@ethereumjs/tx>@chainsafe/ssz": true, "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util": true, "@ethereumjs/tx>ethereum-cryptography": true, @@ -146,21 +145,6 @@ "browserify>insert-module-globals>is-buffer": true } }, - "@ethereumjs/tx>@chainsafe/ssz": { - "packages": { - "@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": true, - "browserify>buffer": true - } - }, - "@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": { - "globals": { - "WeakRef": true - }, - "packages": { - "@ethereumjs/tx>@chainsafe/ssz>@chainsafe/as-sha256": true, - "@metamask/key-tree>@noble/hashes": true - } - }, "@ethereumjs/tx>@ethereumjs/rlp": { "globals": { "TextEncoder": true @@ -171,7 +155,6 @@ "console.warn": true }, "packages": { - "@ethereumjs/tx>@chainsafe/ssz": true, "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography": true, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, @@ -325,15 +308,7 @@ "packages": { "@ethersproject/abi>@ethersproject/bytes": true, "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/bignumber>bn.js": true - } - }, - "@ethersproject/bignumber>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true + "bn.js": true } }, "@ethersproject/contracts": { @@ -347,9 +322,17 @@ "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, "@ethersproject/bignumber": true, + "@ethersproject/contracts>@ethersproject/abstract-provider": true, "@ethersproject/hdnode>@ethersproject/abstract-signer": true, - "@ethersproject/hdnode>@ethersproject/transactions": true, - "@ethersproject/providers>@ethersproject/abstract-provider": true + "@ethersproject/hdnode>@ethersproject/transactions": true + } + }, + "@ethersproject/contracts>@ethersproject/abstract-provider": { + "packages": { + "@ethersproject/abi>@ethersproject/bytes": true, + "@ethersproject/abi>@ethersproject/logger": true, + "@ethersproject/abi>@ethersproject/properties": true, + "@ethersproject/bignumber": true } }, "@ethersproject/hdnode": { @@ -441,11 +424,11 @@ "@ethersproject/abi>@ethersproject/properties": true, "@ethersproject/abi>@ethersproject/strings": true, "@ethersproject/bignumber": true, + "@ethersproject/contracts>@ethersproject/abstract-provider": true, "@ethersproject/hdnode>@ethersproject/abstract-signer": true, "@ethersproject/hdnode>@ethersproject/basex": true, "@ethersproject/hdnode>@ethersproject/sha2": true, "@ethersproject/hdnode>@ethersproject/transactions": true, - "@ethersproject/providers>@ethersproject/abstract-provider": true, "@ethersproject/providers>@ethersproject/base64": true, "@ethersproject/providers>@ethersproject/networks": true, "@ethersproject/providers>@ethersproject/random": true, @@ -453,14 +436,6 @@ "@ethersproject/providers>bech32": true } }, - "@ethersproject/providers>@ethersproject/abstract-provider": { - "packages": { - "@ethersproject/abi>@ethersproject/bytes": true, - "@ethersproject/abi>@ethersproject/logger": true, - "@ethersproject/abi>@ethersproject/properties": true, - "@ethersproject/bignumber": true - } - }, "@ethersproject/providers>@ethersproject/base64": { "globals": { "atob": true, @@ -501,19 +476,6 @@ "@ethersproject/providers>@ethersproject/base64": true } }, - "@formatjs/intl-relativetimeformat": { - "globals": { - "Intl": true - }, - "packages": { - "@formatjs/intl-relativetimeformat>@formatjs/intl-utils": true - } - }, - "@formatjs/intl-relativetimeformat>@formatjs/intl-utils": { - "globals": { - "Intl.getCanonicalLocales": true - } - }, "@keystonehq/bc-ur-registry-eth": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, @@ -531,7 +493,7 @@ "@ngraveio/bc-ur": true, "browserify>buffer": true, "ethereumjs-wallet>bs58check": true, - "wait-on>rxjs>tslib": true + "mockttp>graphql-tag>tslib": true } }, "@keystonehq/bc-ur-registry-eth>hdkey": { @@ -815,11 +777,18 @@ }, "packages": { "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask-institutional/custody-controller": true, + "@metamask-institutional/extension>@metamask-institutional/custody-controller": true, "@metamask-institutional/sdk": true, "@metamask-institutional/sdk>@metamask-institutional/types": true } }, + "@metamask-institutional/extension>@metamask-institutional/custody-controller": { + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask-institutional/custody-keyring": true, + "@metamask/obs-store": true + } + }, "@metamask-institutional/institutional-features": { "globals": { "chrome.runtime.id": true, @@ -996,6 +965,9 @@ } }, "@metamask/approval-controller": { + "globals": { + "console.info": true + }, "packages": { "@metamask/approval-controller>nanoid": true, "@metamask/base-controller": true, @@ -1076,6 +1048,9 @@ } }, "@metamask/base-controller": { + "globals": { + "setTimeout": true + }, "packages": { "immer": true } @@ -1102,8 +1077,8 @@ "setTimeout": true }, "packages": { + "@metamask/controller-utils>@metamask/utils": true, "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/utils": true, "browserify>buffer": true, "eslint>fast-deep-equal": true, "eth-ens-namehash": true, @@ -1111,6 +1086,19 @@ "ethjs>ethjs-unit": true } }, + "@metamask/controller-utils>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, "@metamask/controller-utils>@spruceid/siwe-parser": { "globals": { "console.error": true, @@ -1152,12 +1140,12 @@ }, "packages": { "@metamask/eth-json-rpc-middleware>@metamask/utils": true, + "@metamask/eth-json-rpc-middleware>clone": true, "@metamask/eth-json-rpc-middleware>pify": true, "@metamask/eth-json-rpc-middleware>safe-stable-stringify": true, "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, "eth-rpc-errors": true, - "json-rpc-engine": true, - "vinyl>clone": true + "json-rpc-engine": true } }, "@metamask/eth-json-rpc-middleware>@metamask/utils": { @@ -1172,6 +1160,11 @@ "superstruct": true } }, + "@metamask/eth-json-rpc-middleware>clone": { + "packages": { + "browserify>buffer": true + } + }, "@metamask/eth-keyring-controller": { "packages": { "@metamask/browser-passworder": true, @@ -1221,11 +1214,11 @@ "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@scure/bip32": { "packages": { "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@noble/secp256k1": true, - "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@scure/bip39>@noble/hashes": true, + "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@scure/bip32>@noble/hashes": true, "@metamask/key-tree>@scure/base": true } }, - "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@scure/bip39>@noble/hashes": { + "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography>@scure/bip32>@noble/hashes": { "globals": { "TextEncoder": true, "crypto": true @@ -1235,9 +1228,9 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethjs-util": true, "bn.js": true, "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, "eth-sig-util>tweetnacl": true, "eth-sig-util>tweetnacl-util": true } @@ -1257,13 +1250,6 @@ "crypto": true } }, - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, @@ -1324,10 +1310,10 @@ }, "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util": { "packages": { - "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethjs-util": true, "bn.js": true, "browserify>assert": true, "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, @@ -1335,13 +1321,6 @@ "ganache>secp256k1>elliptic": true } }, - "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, "@metamask/eth-ledger-bridge-keyring>hdkey": { "packages": { "@metamask/eth-ledger-bridge-keyring>hdkey>secp256k1": true, @@ -1365,9 +1344,9 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethjs-util": true, "bn.js": true, "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, "eth-sig-util>tweetnacl": true, "eth-sig-util>tweetnacl-util": true } @@ -1387,13 +1366,6 @@ "crypto": true } }, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, "@metamask/eth-token-tracker": { "globals": { "console.warn": true @@ -1448,22 +1420,22 @@ "setInterval": true }, "packages": { - "@metamask/eth-token-tracker>ethjs>bn.js": true, "@metamask/eth-token-tracker>ethjs>ethjs-abi": true, "@metamask/eth-token-tracker>ethjs>ethjs-contract": true, "@metamask/eth-token-tracker>ethjs>ethjs-query": true, + "@metamask/eth-token-tracker>ethjs>ethjs-util": true, + "bn.js": true, "browserify>buffer": true, "ethjs>ethjs-filter": true, "ethjs>ethjs-provider-http": true, "ethjs>ethjs-unit": true, - "ethjs>ethjs-util": true, "ethjs>js-sha3": true, "ethjs>number-to-bn": true } }, "@metamask/eth-token-tracker>ethjs>ethjs-abi": { "packages": { - "@metamask/eth-token-tracker>ethjs>bn.js": true, + "bn.js": true, "browserify>buffer": true, "ethjs>js-sha3": true, "ethjs>number-to-bn": true @@ -1472,16 +1444,16 @@ "@metamask/eth-token-tracker>ethjs>ethjs-contract": { "packages": { "@metamask/eth-token-tracker>ethjs>ethjs-contract>ethjs-abi": true, + "@metamask/eth-token-tracker>ethjs>ethjs-util": true, "ethjs-query>babel-runtime": true, "ethjs>ethjs-filter": true, - "ethjs>ethjs-util": true, "ethjs>js-sha3": true, "promise-to-callback": true } }, "@metamask/eth-token-tracker>ethjs>ethjs-contract>ethjs-abi": { "packages": { - "@metamask/eth-token-tracker>ethjs>bn.js": true, + "bn.js": true, "browserify>buffer": true, "ethjs>js-sha3": true, "ethjs>number-to-bn": true @@ -1498,6 +1470,13 @@ "promise-to-callback": true } }, + "@metamask/eth-token-tracker>ethjs>ethjs-util": { + "packages": { + "browserify>buffer": true, + "ethjs>ethjs-util>is-hex-prefixed": true, + "ethjs>ethjs-util>strip-hex-prefix": true + } + }, "@metamask/eth-token-tracker>safe-event-emitter": { "globals": { "setTimeout": true @@ -1549,7 +1528,7 @@ "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect": true, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/utils": true, "browserify>events": true, - "wait-on>rxjs>tslib": true + "mockttp>graphql-tag>tslib": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect": { @@ -1564,7 +1543,7 @@ }, "packages": { "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect>@trezor/transport": true, - "wait-on>rxjs>tslib": true + "mockttp>graphql-tag>tslib": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect>@trezor/transport": { @@ -1729,28 +1708,6 @@ "jest-canvas-mock>moo-color>color-name": true } }, - "@metamask/key-tree": { - "packages": { - "@metamask/key-tree>@metamask/utils": true, - "@metamask/key-tree>@noble/ed25519": true, - "@metamask/key-tree>@noble/hashes": true, - "@metamask/key-tree>@noble/secp256k1": true, - "@metamask/key-tree>@scure/base": true, - "@metamask/scure-bip39": true - } - }, - "@metamask/key-tree>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "browserify>buffer": true, - "nock>debug": true, - "semver": true, - "superstruct": true - } - }, "@metamask/key-tree>@noble/ed25519": { "globals": { "crypto": true @@ -1779,6 +1736,94 @@ "TextEncoder": true } }, + "@metamask/keyring-controller": { + "packages": { + "@metamask/base-controller": true, + "@metamask/keyring-controller>@metamask/eth-keyring-controller": true, + "@metamask/keyring-controller>@metamask/utils": true, + "@metamask/keyring-controller>ethereumjs-wallet": true, + "eth-json-rpc-filters>async-mutex": true, + "ethereumjs-util": true + } + }, + "@metamask/keyring-controller>@metamask/eth-keyring-controller": { + "globals": { + "console.error": true + }, + "packages": { + "@metamask/browser-passworder": true, + "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring": true, + "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring": true, + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util": true, + "@metamask/keyring-controller>@metamask/utils": true, + "@metamask/obs-store": true, + "browserify>events": true + } + }, + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util": { + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, + "bn.js": true, + "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, + "eth-sig-util>tweetnacl": true, + "eth-sig-util>tweetnacl-util": true + } + }, + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": { + "globals": { + "TextDecoder": true, + "crypto": true + }, + "packages": { + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true + } + }, + "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true + } + }, + "@metamask/keyring-controller>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, + "@metamask/keyring-controller>ethereumjs-wallet": { + "packages": { + "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": true, + "@truffle/codec>utf8": true, + "browserify>buffer": true, + "browserify>crypto-browserify": true, + "ethereumjs-util>ethereum-cryptography": true, + "ethereumjs-util>ethereum-cryptography>scrypt-js": true, + "ethereumjs-wallet>aes-js": true, + "ethereumjs-wallet>bs58check": true, + "ethereumjs-wallet>randombytes": true, + "uuid": true + } + }, + "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": { + "packages": { + "bn.js": true, + "browserify>assert": true, + "browserify>buffer": true, + "browserify>insert-module-globals>is-buffer": true, + "ethereumjs-util>create-hash": true, + "ethereumjs-util>ethereum-cryptography": true, + "ethereumjs-util>rlp": true + } + }, "@metamask/logo": { "globals": { "addEventListener": true, @@ -1797,14 +1842,40 @@ "packages": { "@metamask/base-controller": true, "@metamask/controller-utils": true, + "@metamask/message-manager>@metamask/eth-sig-util": true, "@metamask/message-manager>jsonschema": true, "browserify>buffer": true, "browserify>events": true, - "eth-sig-util": true, "ethereumjs-util": true, "uuid": true } }, + "@metamask/message-manager>@metamask/eth-sig-util": { + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": true, + "bn.js": true, + "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, + "eth-sig-util>tweetnacl": true, + "eth-sig-util>tweetnacl-util": true + } + }, + "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": { + "globals": { + "TextDecoder": true, + "crypto": true + }, + "packages": { + "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true + } + }, + "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true + } + }, "@metamask/message-manager>jsonschema": { "packages": { "browserify>url": true @@ -1839,7 +1910,7 @@ }, "packages": { "@metamask/network-controller>@metamask/eth-json-rpc-infura>@metamask/utils": true, - "@metamask/network-controller>@metamask/eth-json-rpc-infura>eth-json-rpc-middleware": true, + "@metamask/network-controller>@metamask/eth-json-rpc-provider": true, "eth-rpc-errors": true, "json-rpc-engine": true, "node-fetch": true @@ -1857,26 +1928,6 @@ "superstruct": true } }, - "@metamask/network-controller>@metamask/eth-json-rpc-infura>eth-json-rpc-middleware": { - "globals": { - "URL": true, - "btoa": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, - "@metamask/network-controller>@metamask/eth-json-rpc-infura>@metamask/utils": true, - "@metamask/network-controller>@metamask/eth-json-rpc-infura>eth-json-rpc-middleware>pify": true, - "@metamask/safe-event-emitter": true, - "browserify>browser-resolve": true, - "eth-rpc-errors": true, - "json-rpc-engine": true, - "lavamoat>json-stable-stringify": true, - "vinyl>clone": true - } - }, "@metamask/network-controller>@metamask/eth-json-rpc-provider": { "packages": { "@metamask/safe-event-emitter": true, @@ -1985,9 +2036,9 @@ "@metamask/rpc-methods": { "packages": { "@metamask/browser-passworder": true, - "@metamask/key-tree": true, "@metamask/key-tree>@noble/hashes": true, "@metamask/permission-controller": true, + "@metamask/rpc-methods>@metamask/key-tree": true, "@metamask/rpc-methods>@metamask/utils": true, "@metamask/rpc-methods>nanoid": true, "@metamask/snaps-ui": true, @@ -2001,12 +2052,23 @@ "crypto.getRandomValues": true } }, + "@metamask/rpc-methods>@metamask/key-tree": { + "packages": { + "@metamask/key-tree>@noble/ed25519": true, + "@metamask/key-tree>@noble/hashes": true, + "@metamask/key-tree>@noble/secp256k1": true, + "@metamask/key-tree>@scure/base": true, + "@metamask/rpc-methods>@metamask/utils": true, + "@metamask/scure-bip39": true + } + }, "@metamask/rpc-methods>@metamask/utils": { "globals": { "TextDecoder": true, "TextEncoder": true }, "packages": { + "@metamask/key-tree>@noble/hashes": true, "browserify>buffer": true, "nock>debug": true, "semver": true, @@ -2069,34 +2131,13 @@ "@ethersproject/abi>@ethersproject/bytes": true, "@ethersproject/bignumber": true, "@ethersproject/providers": true, - "@metamask/smart-transactions-controller>@metamask/base-controller": true, - "@metamask/smart-transactions-controller>@metamask/controller-utils": true, + "@metamask/base-controller": true, + "@metamask/controller-utils": true, "@metamask/smart-transactions-controller>bignumber.js": true, - "@metamask/smart-transactions-controller>isomorphic-fetch": true, "fast-json-patch": true, "lodash": true } }, - "@metamask/smart-transactions-controller>@metamask/base-controller": { - "packages": { - "immer": true - } - }, - "@metamask/smart-transactions-controller>@metamask/controller-utils": { - "globals": { - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/smart-transactions-controller>isomorphic-fetch": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true, - "ethjs>ethjs-unit": true - } - }, "@metamask/smart-transactions-controller>@metamask/controllers>nanoid": { "globals": { "crypto.getRandomValues": true @@ -2108,25 +2149,6 @@ "define": true } }, - "@metamask/smart-transactions-controller>isomorphic-fetch": { - "globals": { - "fetch.bind": true - }, - "packages": { - "@metamask/smart-transactions-controller>isomorphic-fetch>whatwg-fetch": true - } - }, - "@metamask/smart-transactions-controller>isomorphic-fetch>whatwg-fetch": { - "globals": { - "Blob": true, - "FileReader": true, - "FormData": true, - "URLSearchParams.prototype.isPrototypeOf": true, - "XMLHttpRequest": true, - "define": true, - "setTimeout": true - } - }, "@metamask/snaps-controllers-flask>nanoid": { "globals": { "crypto.getRandomValues": true @@ -2149,6 +2171,7 @@ "TextEncoder": true }, "packages": { + "@metamask/key-tree>@noble/hashes": true, "browserify>buffer": true, "nock>debug": true, "semver": true, @@ -2166,9 +2189,9 @@ "document.createElement": true }, "packages": { - "@metamask/key-tree": true, "@metamask/key-tree>@noble/hashes": true, "@metamask/key-tree>@scure/base": true, + "@metamask/snaps-utils>@metamask/key-tree": true, "@metamask/snaps-utils>@metamask/utils": true, "@metamask/snaps-utils>cron-parser": true, "@metamask/snaps-utils>fast-json-stable-stringify": true, @@ -2178,12 +2201,23 @@ "superstruct": true } }, + "@metamask/snaps-utils>@metamask/key-tree": { + "packages": { + "@metamask/key-tree>@noble/ed25519": true, + "@metamask/key-tree>@noble/hashes": true, + "@metamask/key-tree>@noble/secp256k1": true, + "@metamask/key-tree>@scure/base": true, + "@metamask/scure-bip39": true, + "@metamask/snaps-utils>@metamask/utils": true + } + }, "@metamask/snaps-utils>@metamask/utils": { "globals": { "TextDecoder": true, "TextEncoder": true }, "packages": { + "@metamask/key-tree>@noble/hashes": true, "browserify>buffer": true, "nock>debug": true, "semver": true, @@ -2449,11 +2483,11 @@ "@truffle/codec>@truffle/abi-utils": true, "@truffle/codec>@truffle/compile-common": true, "@truffle/codec>big.js": true, - "@truffle/codec>bn.js": true, "@truffle/codec>cbor": true, "@truffle/codec>semver": true, "@truffle/codec>utf8": true, "@truffle/codec>web3-utils": true, + "bn.js": true, "browserify>buffer": true, "browserify>os-browserify": true, "browserify>util": true, @@ -2610,14 +2644,6 @@ "define": true } }, - "@truffle/codec>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "@truffle/codec>cbor": { "globals": { "TextDecoder": true @@ -2660,8 +2686,8 @@ }, "packages": { "@truffle/codec>utf8": true, - "@truffle/codec>web3-utils>bn.js": true, "@truffle/codec>web3-utils>ethereum-bloom-filters": true, + "bn.js": true, "browserify>buffer": true, "ethereumjs-util": true, "ethereumjs-wallet>randombytes": true, @@ -2669,14 +2695,6 @@ "ethjs>number-to-bn": true } }, - "@truffle/codec>web3-utils>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "@truffle/codec>web3-utils>ethereum-bloom-filters": { "packages": { "@truffle/codec>web3-utils>ethereum-bloom-filters>js-sha3": true @@ -2698,7 +2716,7 @@ "@truffle/codec>web3-utils": true, "@truffle/decoder>@truffle/encoder": true, "@truffle/decoder>@truffle/source-map-utils": true, - "@truffle/decoder>bn.js": true, + "bn.js": true, "nock>debug": true } }, @@ -2871,11 +2889,11 @@ "@ethersproject/abi>@ethersproject/keccak256": true, "@ethersproject/abi>@ethersproject/logger": true, "@ethersproject/abi>@ethersproject/properties": true, + "@ethersproject/contracts>@ethersproject/abstract-provider": true, "@ethersproject/hdnode": true, "@ethersproject/hdnode>@ethersproject/abstract-signer": true, "@ethersproject/hdnode>@ethersproject/signing-key": true, "@ethersproject/hdnode>@ethersproject/transactions": true, - "@ethersproject/providers>@ethersproject/abstract-provider": true, "@ethersproject/providers>@ethersproject/random": true, "@truffle/decoder>@truffle/encoder>@ensdomains/ensjs>ethers>@ethersproject/json-wallets": true } @@ -2920,20 +2938,11 @@ "@truffle/decoder>@truffle/source-map-utils>node-interval-tree>shallowequal": true } }, - "@truffle/decoder>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "@zxing/browser": { "globals": { "HTMLElement": true, "HTMLImageElement": true, "HTMLVideoElement": true, - "URL.createObjectURL": true, "clearTimeout": true, "console.error": true, "console.warn": true, @@ -2947,17 +2956,20 @@ }, "@zxing/library": { "globals": { + "HTMLImageElement": true, + "HTMLVideoElement": true, "TextDecoder": true, "TextEncoder": true, + "URL.createObjectURL": true, "btoa": true, - "clearTimeout": true, - "define": true, - "document.createElement": true, - "document.createElementNS": true, - "document.getElementById": true, - "navigator.mediaDevices.enumerateDevices": true, - "navigator.mediaDevices.getUserMedia": true, + "console.log": true, + "console.warn": true, + "document": true, + "navigator": true, "setTimeout": true + }, + "packages": { + "@zxing/library>ts-custom-error": true } }, "addons-linter>sha.js": { @@ -3446,7 +3458,7 @@ "setTimeout": true }, "packages": { - "wait-on>rxjs>tslib": true + "mockttp>graphql-tag>tslib": true } }, "eth-keyring-controller>@metamask/browser-passworder": { @@ -3465,11 +3477,11 @@ }, "packages": { "@ethereumjs/tx>@ethereumjs/util": true, + "bn.js": true, "browserify>buffer": true, "browserify>crypto-browserify": true, "browserify>events": true, "eth-lattice-keyring>@ethereumjs/tx": true, - "eth-lattice-keyring>bn.js": true, "eth-lattice-keyring>gridplus-sdk": true, "eth-lattice-keyring>rlp": true } @@ -3517,14 +3529,6 @@ "crypto": true } }, - "eth-lattice-keyring>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "eth-lattice-keyring>gridplus-sdk": { "globals": { "AbortController": true, @@ -3577,27 +3581,11 @@ "@ethersproject/providers": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@chainsafe/ssz": true, + "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": true } }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@chainsafe/ssz": { - "packages": { - "browserify": true, - "browserify>buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>case": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": true - } - }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": { - "globals": { - "WeakRef": true - }, - "packages": { - "browserify": true - } - }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": { "packages": { "@ethereumjs/common>crc-32": true, @@ -3661,19 +3649,11 @@ "intToBuffer": true }, "packages": { - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>bn.js": true, + "bn.js": true, "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>buffer": true, "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>js-sha3": true } }, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>buffer": { "globals": { "console": true @@ -3796,39 +3776,24 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, - "ethereumjs-abi>ethereumjs-util>ethjs-util": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, "ganache>secp256k1>elliptic": true } }, - "ethereumjs-abi>ethereumjs-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, "ethereumjs-util": { "packages": { + "bn.js": true, "browserify>assert": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, - "ethereumjs-util>bn.js": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true } }, - "ethereumjs-util>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "ethereumjs-util>create-hash": { "packages": { "addons-linter>sha.js": true, @@ -3880,10 +3845,15 @@ }, "ethereumjs-util>ethereum-cryptography": { "packages": { + "browserify>assert": true, "browserify>buffer": true, + "browserify>crypto-browserify>create-hmac": true, + "ethereumjs-util>ethereum-cryptography>hash.js": true, "ethereumjs-util>ethereum-cryptography>keccak": true, "ethereumjs-util>ethereum-cryptography>secp256k1": true, - "ethereumjs-wallet>randombytes": true + "ethereumjs-wallet>bs58check": true, + "ethereumjs-wallet>randombytes": true, + "ethereumjs-wallet>safe-buffer": true } }, "ethereumjs-util>ethereum-cryptography>browserify-aes": { @@ -3940,16 +3910,8 @@ }, "ethereumjs-util>rlp": { "packages": { - "browserify>buffer": true, - "ethereumjs-util>rlp>bn.js": true - } - }, - "ethereumjs-util>rlp>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true + "bn.js": true, + "browserify>buffer": true } }, "ethereumjs-wallet": { @@ -3992,20 +3954,13 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, - "ethereumjs-wallet>ethereumjs-util>ethjs-util": true, "ganache>secp256k1>elliptic": true } }, - "ethereumjs-wallet>ethereumjs-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, "ethereumjs-wallet>randombytes": { "globals": { "crypto": true, @@ -4044,10 +3999,10 @@ "setInterval": true }, "packages": { + "bn.js": true, "browserify>buffer": true, "ethjs-contract": true, "ethjs-query": true, - "ethjs>bn.js": true, "ethjs>ethjs-abi": true, "ethjs>ethjs-filter": true, "ethjs>ethjs-provider-http": true, @@ -4060,21 +4015,28 @@ "ethjs-contract": { "packages": { "ethjs-contract>ethjs-abi": true, + "ethjs-contract>ethjs-util": true, "ethjs-query>babel-runtime": true, "ethjs>ethjs-filter": true, - "ethjs>ethjs-util": true, "ethjs>js-sha3": true, "promise-to-callback": true } }, "ethjs-contract>ethjs-abi": { "packages": { + "bn.js": true, "browserify>buffer": true, - "ethjs-contract>ethjs-abi>bn.js": true, "ethjs>js-sha3": true, "ethjs>number-to-bn": true } }, + "ethjs-contract>ethjs-util": { + "packages": { + "browserify>buffer": true, + "ethjs>ethjs-util>is-hex-prefixed": true, + "ethjs>ethjs-util>strip-hex-prefix": true + } + }, "ethjs-query": { "globals": { "console": true @@ -4105,11 +4067,18 @@ "ethjs-query>ethjs-format": { "packages": { "ethjs-query>ethjs-format>ethjs-schema": true, - "ethjs>ethjs-util": true, + "ethjs-query>ethjs-format>ethjs-util": true, "ethjs>ethjs-util>strip-hex-prefix": true, "ethjs>number-to-bn": true } }, + "ethjs-query>ethjs-format>ethjs-util": { + "packages": { + "browserify>buffer": true, + "ethjs>ethjs-util>is-hex-prefixed": true, + "ethjs>ethjs-util>strip-hex-prefix": true + } + }, "ethjs-query>ethjs-rpc": { "packages": { "promise-to-callback": true @@ -4117,8 +4086,8 @@ }, "ethjs>ethjs-abi": { "packages": { + "bn.js": true, "browserify>buffer": true, - "ethjs>bn.js": true, "ethjs>js-sha3": true, "ethjs>number-to-bn": true } @@ -4141,7 +4110,7 @@ }, "ethjs>ethjs-unit": { "packages": { - "ethjs>ethjs-unit>bn.js": true, + "bn.js": true, "ethjs>number-to-bn": true } }, @@ -4164,8 +4133,8 @@ }, "ethjs>number-to-bn": { "packages": { - "ethjs>ethjs-util>strip-hex-prefix": true, - "ethjs>number-to-bn>bn.js": true + "bn.js": true, + "ethjs>ethjs-util>strip-hex-prefix": true } }, "extension-port-stream": { @@ -4302,6 +4271,11 @@ "Intl": true } }, + "mockttp>graphql-tag>tslib": { + "globals": { + "define": true + } + }, "nanoid": { "globals": { "crypto": true, @@ -4506,7 +4480,7 @@ "setTimeout": true }, "packages": { - "wait-on>rxjs>tslib": true + "mockttp>graphql-tag>tslib": true } }, "react-focus-lock>react-clientside-effect": { @@ -4525,9 +4499,9 @@ "console.error": true }, "packages": { + "mockttp>graphql-tag>tslib": true, "react": true, - "react-focus-lock>use-sidecar>detect-node-es": true, - "wait-on>rxjs>tslib": true + "react-focus-lock>use-sidecar>detect-node-es": true } }, "react-idle-timer": { @@ -4543,29 +4517,12 @@ }, "react-inspector": { "globals": { - "Node.CDATA_SECTION_NODE": true, - "Node.COMMENT_NODE": true, - "Node.DOCUMENT_FRAGMENT_NODE": true, - "Node.DOCUMENT_NODE": true, - "Node.DOCUMENT_TYPE_NODE": true, - "Node.ELEMENT_NODE": true, - "Node.PROCESSING_INSTRUCTION_NODE": true, - "Node.TEXT_NODE": true + "Node": true, + "chromeDark": true, + "chromeLight": true }, "packages": { - "ethjs-query>babel-runtime": true, - "prop-types": true, - "react": true, - "react-inspector>is-dom": true - } - }, - "react-inspector>is-dom": { - "globals": { - "Node": true - }, - "packages": { - "@lavamoat/snow>is-cross-origin>is-window": true, - "proxyquire>fill-keys>is-object": true + "react": true } }, "react-popper": { @@ -4834,7 +4791,6 @@ }, "packages": { "browserify>process": true, - "browserify>util": true, "semver>lru-cache": true } }, @@ -4892,16 +4848,6 @@ "msCrypto": true } }, - "vinyl>clone": { - "packages": { - "browserify>buffer": true - } - }, - "wait-on>rxjs>tslib": { - "globals": { - "define": true - } - }, "web3": { "globals": { "XMLHttpRequest": true diff --git a/lavamoat/build-system/policy.json b/lavamoat/build-system/policy.json index a615563a8..521216647 100644 --- a/lavamoat/build-system/policy.json +++ b/lavamoat/build-system/policy.json @@ -838,24 +838,11 @@ "packages": { "@babel/core": true, "@babel/preset-env>@babel/compat-data": true, - "@babel/preset-env>babel-plugin-polyfill-corejs2>semver": true, - "@babel/preset-env>babel-plugin-polyfill-corejs3>@babel/helper-define-polyfill-provider": true + "@babel/preset-env>babel-plugin-polyfill-corejs2>@babel/helper-define-polyfill-provider": true, + "@babel/preset-env>babel-plugin-polyfill-corejs2>semver": true } }, - "@babel/preset-env>babel-plugin-polyfill-corejs2>semver": { - "globals": { - "console": true, - "process": true - } - }, - "@babel/preset-env>babel-plugin-polyfill-corejs3": { - "packages": { - "@babel/core": true, - "@babel/preset-env>babel-plugin-polyfill-corejs3>@babel/helper-define-polyfill-provider": true, - "@babel/preset-env>core-js-compat": true - } - }, - "@babel/preset-env>babel-plugin-polyfill-corejs3>@babel/helper-define-polyfill-provider": { + "@babel/preset-env>babel-plugin-polyfill-corejs2>@babel/helper-define-polyfill-provider": { "builtin": { "module": true, "path": true @@ -870,19 +857,32 @@ "@babel/core": true, "@babel/core>@babel/helper-compilation-targets": true, "@babel/preset-env>@babel/helper-plugin-utils": true, - "@babel/preset-env>babel-plugin-polyfill-corejs3>@babel/helper-define-polyfill-provider>lodash.debounce": true, + "@babel/preset-env>babel-plugin-polyfill-corejs2>@babel/helper-define-polyfill-provider>lodash.debounce": true, "brfs>resolve": true } }, - "@babel/preset-env>babel-plugin-polyfill-corejs3>@babel/helper-define-polyfill-provider>lodash.debounce": { + "@babel/preset-env>babel-plugin-polyfill-corejs2>@babel/helper-define-polyfill-provider>lodash.debounce": { "globals": { "clearTimeout": true, "setTimeout": true } }, + "@babel/preset-env>babel-plugin-polyfill-corejs2>semver": { + "globals": { + "console": true, + "process": true + } + }, + "@babel/preset-env>babel-plugin-polyfill-corejs3": { + "packages": { + "@babel/core": true, + "@babel/preset-env>babel-plugin-polyfill-corejs2>@babel/helper-define-polyfill-provider": true, + "@babel/preset-env>core-js-compat": true + } + }, "@babel/preset-env>babel-plugin-polyfill-regenerator": { "packages": { - "@babel/preset-env>babel-plugin-polyfill-corejs3>@babel/helper-define-polyfill-provider": true + "@babel/preset-env>babel-plugin-polyfill-corejs2>@babel/helper-define-polyfill-provider": true } }, "@babel/preset-env>semver": { @@ -1119,18 +1119,16 @@ "koa>is-generator-function>has-tostringtag": true } }, + "@metamask/jazzicon>color>clone": { + "globals": { + "Buffer": true + } + }, "@metamask/jazzicon>color>color-convert": { "packages": { "@metamask/jazzicon>color>color-convert>color-name": true } }, - "@sentry/cli>mkdirp": { - "builtin": { - "fs": true, - "path.dirname": true, - "path.resolve": true - } - }, "@storybook/addon-knobs>qs": { "packages": { "string.prototype.matchall>side-channel": true @@ -1196,12 +1194,7 @@ "process": true }, "packages": { - "@storybook/test-runner>glob>minimatch>brace-expansion": true - } - }, - "@storybook/test-runner>glob>minimatch>brace-expansion": { - "packages": { - "stylelint>balanced-match": true + "addons-linter>glob>minimatch>brace-expansion": true } }, "@typescript-eslint/eslint-plugin": { @@ -1307,6 +1300,11 @@ "typescript": true } }, + "addons-linter>glob>minimatch>brace-expansion": { + "packages": { + "stylelint>balanced-match": true + } + }, "babel-plugin-module-resolver": { "builtin": { "fs": true, @@ -2008,7 +2006,12 @@ "process.platform": true }, "packages": { - "sinon>supports-color>has-flag": true + "chalk>supports-color>has-flag": true + } + }, + "chalk>supports-color>has-flag": { + "globals": { + "process.argv": true } }, "chokidar": { @@ -2047,14 +2050,30 @@ "setTimeout": true }, "packages": { + "chokidar>anymatch": true, "chokidar>braces": true, "chokidar>fsevents": true, "chokidar>is-binary-path": true, "chokidar>normalize-path": true, + "chokidar>readdirp": true, "del>is-glob": true, - "depcheck>readdirp": true, - "eslint>glob-parent": true, - "watchify>anymatch": true + "eslint>glob-parent": true + } + }, + "chokidar>anymatch": { + "packages": { + "chokidar>anymatch>picomatch": true, + "chokidar>normalize-path": true + } + }, + "chokidar>anymatch>picomatch": { + "builtin": { + "path.basename": true, + "path.sep": true + }, + "globals": { + "process.platform": true, + "process.version.slice": true } }, "chokidar>braces": { @@ -2090,6 +2109,24 @@ "chokidar>is-binary-path>binary-extensions": true } }, + "chokidar>readdirp": { + "builtin": { + "fs": true, + "path.join": true, + "path.relative": true, + "path.resolve": true, + "path.sep": true, + "stream.Readable": true, + "util.promisify": true + }, + "globals": { + "process.platform": true, + "process.versions.node.split": true + }, + "packages": { + "chokidar>anymatch>picomatch": true + } + }, "copy-webpack-plugin>p-limit": { "packages": { "copy-webpack-plugin>p-limit>yocto-queue": true @@ -2158,9 +2195,9 @@ "del>is-path-cwd": true, "del>is-path-inside": true, "del>p-map": true, + "del>rimraf": true, "del>slash": true, - "globby": true, - "nyc>rimraf": true + "globby": true } }, "del>graceful-fs": { @@ -2203,7 +2240,56 @@ }, "del>p-map": { "packages": { - "nyc>p-map>aggregate-error": true + "del>p-map>aggregate-error": true + } + }, + "del>p-map>aggregate-error": { + "packages": { + "@testing-library/jest-dom>redent>indent-string": true, + "del>p-map>aggregate-error>clean-stack": true + } + }, + "del>p-map>aggregate-error>clean-stack": { + "builtin": { + "os.homedir": true + } + }, + "del>rimraf": { + "builtin": { + "assert": true, + "fs": true, + "path.join": true + }, + "globals": { + "process.platform": true, + "setTimeout": true + }, + "packages": { + "del>rimraf>glob": true + } + }, + "del>rimraf>glob": { + "builtin": { + "assert": true, + "events.EventEmitter": true, + "fs": true, + "path.join": true, + "path.resolve": true, + "util": true + }, + "globals": { + "console.error": true, + "process.cwd": true, + "process.nextTick": true, + "process.platform": true + }, + "packages": { + "eslint>minimatch": true, + "gulp-watch>path-is-absolute": true, + "nyc>glob>fs.realpath": true, + "nyc>glob>inflight": true, + "pump>once": true, + "pumpify>inherits": true } }, "depcheck>@babel/traverse": { @@ -2280,34 +2366,6 @@ "console.warn": true } }, - "depcheck>readdirp": { - "builtin": { - "fs": true, - "path.join": true, - "path.relative": true, - "path.resolve": true, - "path.sep": true, - "stream.Readable": true, - "util.promisify": true - }, - "globals": { - "process.platform": true, - "process.versions.node.split": true - }, - "packages": { - "depcheck>readdirp>picomatch": true - } - }, - "depcheck>readdirp>picomatch": { - "builtin": { - "path.basename": true, - "path.sep": true - }, - "globals": { - "process.platform": true, - "process.version.slice": true - } - }, "duplexify": { "globals": { "Buffer": true, @@ -2401,6 +2459,7 @@ "eslint>glob-parent": true, "eslint>globals": true, "eslint>grapheme-splitter": true, + "eslint>ignore": true, "eslint>imurmurhash": true, "eslint>js-sdsl": true, "eslint>json-stable-stringify-without-jsonify": true, @@ -2408,7 +2467,6 @@ "eslint>lodash.merge": true, "eslint>minimatch": true, "eslint>natural-compare": true, - "globby>ignore": true, "mocha>escape-string-regexp": true, "mocha>find-up": true, "nock>debug": true @@ -2799,8 +2857,8 @@ "eslint-plugin-node>eslint-plugin-es": true, "eslint-plugin-node>eslint-utils": true, "eslint-plugin-node>semver": true, - "eslint>minimatch": true, - "globby>ignore": true + "eslint>ignore": true, + "eslint>minimatch": true } }, "eslint-plugin-node>eslint-plugin-es": { @@ -3012,8 +3070,8 @@ "eslint-plugin-react-hooks": true, "eslint>@eslint/eslintrc>globals": true, "eslint>ajv": true, + "eslint>ignore": true, "eslint>minimatch": true, - "globby>ignore": true, "mocha>strip-json-comments": true, "nock>debug": true } @@ -3112,12 +3170,12 @@ "packages": { "eslint>eslint-visitor-keys": true, "eslint>espree>acorn-jsx": true, - "terser>acorn": true + "jsdom>acorn": true } }, "eslint>espree>acorn-jsx": { "packages": { - "terser>acorn": true + "jsdom>acorn": true } }, "eslint>esquery": { @@ -3151,8 +3209,8 @@ "__dirname": true }, "packages": { - "eslint>file-entry-cache>flat-cache>flatted": true, - "nyc>rimraf": true + "del>rimraf": true, + "eslint>file-entry-cache>flat-cache>flatted": true } }, "eslint>glob-parent": { @@ -3164,6 +3222,11 @@ "del>is-glob": true } }, + "eslint>ignore": { + "globals": { + "process": true + } + }, "eslint>import-fresh": { "builtin": { "path.dirname": true @@ -3209,7 +3272,13 @@ "console": true }, "packages": { - "mocha>minimatch>brace-expansion": true + "eslint>minimatch>brace-expansion": true + } + }, + "eslint>minimatch>brace-expansion": { + "packages": { + "mocha>minimatch>brace-expansion>concat-map": true, + "stylelint>balanced-match": true } }, "eslint>strip-ansi": { @@ -3271,8 +3340,8 @@ "eslint>@nodelib/fs.walk": true, "eslint>glob-parent": true, "fast-glob>@nodelib/fs.stat": true, - "globby>merge2": true, - "stylelint>micromatch": true + "fast-glob>micromatch": true, + "globby>merge2": true } }, "fast-glob>@nodelib/fs.stat": { @@ -3283,6 +3352,15 @@ "fs.statSync": true } }, + "fast-glob>micromatch": { + "builtin": { + "util.inspect": true + }, + "packages": { + "chokidar>anymatch>picomatch": true, + "chokidar>braces": true + } + }, "fs-extra": { "builtin": { "assert": true, @@ -3371,10 +3449,10 @@ }, "packages": { "del>slash": true, + "eslint>ignore": true, "fast-glob": true, "globby>array-union": true, "globby>dir-glob": true, - "globby>ignore": true, "globby>merge2": true } }, @@ -3398,11 +3476,6 @@ "util.promisify": true } }, - "globby>ignore": { - "globals": { - "process": true - } - }, "globby>merge2": { "builtin": { "stream.PassThrough": true @@ -4321,7 +4394,7 @@ "gulp-watch>anymatch>micromatch>object.omit": { "packages": { "gulp-watch>anymatch>micromatch>object.omit>for-own": true, - "gulp-watch>chokidar>braces>extend-shallow>is-extendable": true + "gulp-watch>anymatch>micromatch>object.omit>is-extendable": true } }, "gulp-watch>anymatch>micromatch>object.omit>for-own": { @@ -4415,8 +4488,132 @@ "path.sep": true }, "packages": { - "gulp-watch>chokidar>anymatch>normalize-path": true, - "gulp-watch>chokidar>readdirp>micromatch": true + "gulp-watch>chokidar>anymatch>micromatch": true, + "gulp-watch>chokidar>anymatch>normalize-path": true + } + }, + "gulp-watch>chokidar>anymatch>micromatch": { + "builtin": { + "path.basename": true, + "path.sep": true, + "util.inspect": true + }, + "globals": { + "process.platform": true + }, + "packages": { + "@babel/register>clone-deep>kind-of": true, + "gulp-watch>chokidar>anymatch>micromatch>define-property": true, + "gulp-watch>chokidar>anymatch>micromatch>extglob": true, + "gulp-watch>chokidar>braces": true, + "gulp-watch>chokidar>braces>array-unique": true, + "gulp-watch>chokidar>braces>snapdragon": true, + "gulp-watch>chokidar>braces>to-regex": true, + "gulp-zip>plugin-error>arr-diff": true, + "gulp-zip>plugin-error>extend-shallow": true, + "gulp>gulp-cli>liftoff>fined>object.pick": true, + "gulp>gulp-cli>matchdep>micromatch>fragment-cache": true, + "gulp>gulp-cli>matchdep>micromatch>nanomatch": true, + "gulp>gulp-cli>matchdep>micromatch>regex-not": true + } + }, + "gulp-watch>chokidar>anymatch>micromatch>define-property": { + "packages": { + "gulp>gulp-cli>isobject": true, + "gulp>gulp-cli>matchdep>micromatch>define-property>is-descriptor": true + } + }, + "gulp-watch>chokidar>anymatch>micromatch>extglob": { + "packages": { + "gulp-watch>chokidar>anymatch>micromatch>extglob>define-property": true, + "gulp-watch>chokidar>anymatch>micromatch>extglob>expand-brackets": true, + "gulp-watch>chokidar>anymatch>micromatch>extglob>extend-shallow": true, + "gulp-watch>chokidar>braces>array-unique": true, + "gulp-watch>chokidar>braces>snapdragon": true, + "gulp-watch>chokidar>braces>to-regex": true, + "gulp>gulp-cli>matchdep>micromatch>fragment-cache": true, + "gulp>gulp-cli>matchdep>micromatch>regex-not": true + } + }, + "gulp-watch>chokidar>anymatch>micromatch>extglob>define-property": { + "packages": { + "gulp>gulp-cli>matchdep>micromatch>define-property>is-descriptor": true + } + }, + "gulp-watch>chokidar>anymatch>micromatch>extglob>expand-brackets": { + "globals": { + "__filename": true + }, + "packages": { + "gulp-watch>chokidar>anymatch>micromatch>extglob>expand-brackets>debug": true, + "gulp-watch>chokidar>anymatch>micromatch>extglob>expand-brackets>define-property": true, + "gulp-watch>chokidar>anymatch>micromatch>extglob>expand-brackets>extend-shallow": true, + "gulp-watch>chokidar>braces>snapdragon": true, + "gulp-watch>chokidar>braces>to-regex": true, + "gulp>gulp-cli>matchdep>micromatch>extglob>expand-brackets>posix-character-classes": true, + "gulp>gulp-cli>matchdep>micromatch>regex-not": true + } + }, + "gulp-watch>chokidar>anymatch>micromatch>extglob>expand-brackets>debug": { + "builtin": { + "fs.SyncWriteStream": true, + "net.Socket": true, + "tty.WriteStream": true, + "tty.isatty": true, + "util": true + }, + "globals": { + "chrome": true, + "console": true, + "document": true, + "localStorage": true, + "navigator": true, + "process": true + }, + "packages": { + "gulp-watch>chokidar>anymatch>micromatch>extglob>expand-brackets>debug>ms": true + } + }, + "gulp-watch>chokidar>anymatch>micromatch>extglob>expand-brackets>define-property": { + "packages": { + "gulp-watch>chokidar>anymatch>micromatch>extglob>expand-brackets>define-property>is-descriptor": true + } + }, + "gulp-watch>chokidar>anymatch>micromatch>extglob>expand-brackets>define-property>is-descriptor": { + "packages": { + "gulp-watch>chokidar>anymatch>micromatch>extglob>expand-brackets>define-property>is-descriptor>is-accessor-descriptor": true, + "gulp-watch>chokidar>anymatch>micromatch>extglob>expand-brackets>define-property>is-descriptor>is-data-descriptor": true, + "gulp-watch>chokidar>anymatch>micromatch>extglob>expand-brackets>define-property>is-descriptor>kind-of": true + } + }, + "gulp-watch>chokidar>anymatch>micromatch>extglob>expand-brackets>define-property>is-descriptor>is-accessor-descriptor": { + "packages": { + "gulp-watch>chokidar>anymatch>micromatch>extglob>expand-brackets>define-property>is-descriptor>is-accessor-descriptor>kind-of": true + } + }, + "gulp-watch>chokidar>anymatch>micromatch>extglob>expand-brackets>define-property>is-descriptor>is-accessor-descriptor>kind-of": { + "packages": { + "browserify>insert-module-globals>is-buffer": true + } + }, + "gulp-watch>chokidar>anymatch>micromatch>extglob>expand-brackets>define-property>is-descriptor>is-data-descriptor": { + "packages": { + "gulp-watch>chokidar>anymatch>micromatch>extglob>expand-brackets>define-property>is-descriptor>is-data-descriptor>kind-of": true + } + }, + "gulp-watch>chokidar>anymatch>micromatch>extglob>expand-brackets>define-property>is-descriptor>is-data-descriptor>kind-of": { + "packages": { + "browserify>insert-module-globals>is-buffer": true + } + }, + "gulp-watch>chokidar>anymatch>micromatch>extglob>expand-brackets>extend-shallow": { + "packages": { + "gulp-watch>anymatch>micromatch>object.omit>is-extendable": true + } + }, + "gulp-watch>chokidar>anymatch>micromatch>extglob>extend-shallow": { + "packages": { + "gulp-watch>anymatch>micromatch>object.omit>is-extendable": true } }, "gulp-watch>chokidar>anymatch>normalize-path": { @@ -4445,7 +4642,7 @@ }, "gulp-watch>chokidar>braces>extend-shallow": { "packages": { - "gulp-watch>chokidar>braces>extend-shallow>is-extendable": true + "gulp-watch>anymatch>micromatch>object.omit>is-extendable": true } }, "gulp-watch>chokidar>braces>fill-range": { @@ -4461,7 +4658,7 @@ }, "gulp-watch>chokidar>braces>fill-range>extend-shallow": { "packages": { - "gulp-watch>chokidar>braces>extend-shallow>is-extendable": true + "gulp-watch>anymatch>micromatch>object.omit>is-extendable": true } }, "gulp-watch>chokidar>braces>fill-range>is-number": { @@ -4599,14 +4796,14 @@ "gulp-watch>chokidar>braces>snapdragon>base>cache-base>set-value": { "packages": { "@babel/register>clone-deep>is-plain-object": true, - "gulp-watch>chokidar>braces>extend-shallow>is-extendable": true, + "gulp-watch>anymatch>micromatch>object.omit>is-extendable": true, "gulp-watch>chokidar>braces>snapdragon>base>cache-base>set-value>extend-shallow": true, "gulp-watch>chokidar>braces>split-string": true } }, "gulp-watch>chokidar>braces>snapdragon>base>cache-base>set-value>extend-shallow": { "packages": { - "gulp-watch>chokidar>braces>extend-shallow>is-extendable": true + "gulp-watch>anymatch>micromatch>object.omit>is-extendable": true } }, "gulp-watch>chokidar>braces>snapdragon>base>cache-base>to-object-path": { @@ -4621,7 +4818,7 @@ }, "gulp-watch>chokidar>braces>snapdragon>base>cache-base>union-value": { "packages": { - "gulp-watch>chokidar>braces>extend-shallow>is-extendable": true, + "gulp-watch>anymatch>micromatch>object.omit>is-extendable": true, "gulp-watch>chokidar>braces>snapdragon>base>cache-base>set-value": true, "gulp-zip>plugin-error>arr-union": true, "gulp>gulp-cli>array-sort>get-value": true @@ -4742,7 +4939,7 @@ }, "gulp-watch>chokidar>braces>snapdragon>extend-shallow": { "packages": { - "gulp-watch>chokidar>braces>extend-shallow>is-extendable": true + "gulp-watch>anymatch>micromatch>object.omit>is-extendable": true } }, "gulp-watch>chokidar>braces>snapdragon>use": { @@ -4929,134 +5126,10 @@ }, "packages": { "del>graceful-fs": true, - "gulp-watch>chokidar>readdirp>micromatch": true, + "gulp-watch>chokidar>anymatch>micromatch": true, "readable-stream": true } }, - "gulp-watch>chokidar>readdirp>micromatch": { - "builtin": { - "path.basename": true, - "path.sep": true, - "util.inspect": true - }, - "globals": { - "process.platform": true - }, - "packages": { - "@babel/register>clone-deep>kind-of": true, - "gulp-watch>chokidar>braces": true, - "gulp-watch>chokidar>braces>array-unique": true, - "gulp-watch>chokidar>braces>snapdragon": true, - "gulp-watch>chokidar>braces>to-regex": true, - "gulp-watch>chokidar>readdirp>micromatch>define-property": true, - "gulp-watch>chokidar>readdirp>micromatch>extglob": true, - "gulp-zip>plugin-error>arr-diff": true, - "gulp-zip>plugin-error>extend-shallow": true, - "gulp>gulp-cli>liftoff>fined>object.pick": true, - "gulp>gulp-cli>matchdep>micromatch>fragment-cache": true, - "gulp>gulp-cli>matchdep>micromatch>nanomatch": true, - "gulp>gulp-cli>matchdep>micromatch>regex-not": true - } - }, - "gulp-watch>chokidar>readdirp>micromatch>define-property": { - "packages": { - "gulp>gulp-cli>isobject": true, - "gulp>gulp-cli>matchdep>micromatch>define-property>is-descriptor": true - } - }, - "gulp-watch>chokidar>readdirp>micromatch>extglob": { - "packages": { - "gulp-watch>chokidar>braces>array-unique": true, - "gulp-watch>chokidar>braces>snapdragon": true, - "gulp-watch>chokidar>braces>to-regex": true, - "gulp-watch>chokidar>readdirp>micromatch>extglob>define-property": true, - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets": true, - "gulp-watch>chokidar>readdirp>micromatch>extglob>extend-shallow": true, - "gulp>gulp-cli>matchdep>micromatch>fragment-cache": true, - "gulp>gulp-cli>matchdep>micromatch>regex-not": true - } - }, - "gulp-watch>chokidar>readdirp>micromatch>extglob>define-property": { - "packages": { - "gulp>gulp-cli>matchdep>micromatch>define-property>is-descriptor": true - } - }, - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets": { - "globals": { - "__filename": true - }, - "packages": { - "gulp-watch>chokidar>braces>snapdragon": true, - "gulp-watch>chokidar>braces>to-regex": true, - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>debug": true, - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property": true, - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>extend-shallow": true, - "gulp>gulp-cli>matchdep>micromatch>extglob>expand-brackets>posix-character-classes": true, - "gulp>gulp-cli>matchdep>micromatch>regex-not": true - } - }, - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>debug": { - "builtin": { - "fs.SyncWriteStream": true, - "net.Socket": true, - "tty.WriteStream": true, - "tty.isatty": true, - "util": true - }, - "globals": { - "chrome": true, - "console": true, - "document": true, - "localStorage": true, - "navigator": true, - "process": true - }, - "packages": { - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>debug>ms": true - } - }, - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property": { - "packages": { - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property>is-descriptor": true - } - }, - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property>is-descriptor": { - "packages": { - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property>is-descriptor>is-accessor-descriptor": true, - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property>is-descriptor>is-data-descriptor": true, - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property>is-descriptor>kind-of": true - } - }, - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property>is-descriptor>is-accessor-descriptor": { - "packages": { - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property>is-descriptor>is-accessor-descriptor>kind-of": true - } - }, - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property>is-descriptor>is-accessor-descriptor>kind-of": { - "packages": { - "browserify>insert-module-globals>is-buffer": true - } - }, - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property>is-descriptor>is-data-descriptor": { - "packages": { - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property>is-descriptor>is-data-descriptor>kind-of": true - } - }, - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>define-property>is-descriptor>is-data-descriptor>kind-of": { - "packages": { - "browserify>insert-module-globals>is-buffer": true - } - }, - "gulp-watch>chokidar>readdirp>micromatch>extglob>expand-brackets>extend-shallow": { - "packages": { - "gulp-watch>chokidar>braces>extend-shallow>is-extendable": true - } - }, - "gulp-watch>chokidar>readdirp>micromatch>extglob>extend-shallow": { - "packages": { - "gulp-watch>chokidar>braces>extend-shallow>is-extendable": true - } - }, "gulp-watch>chokidar>upath": { "builtin": { "path": true @@ -5137,16 +5210,11 @@ "process.cwd": true }, "packages": { - "gulp-watch>vinyl-file>vinyl>clone": true, + "@metamask/jazzicon>color>clone": true, "gulp-watch>vinyl-file>vinyl>clone-stats": true, "gulp-watch>vinyl-file>vinyl>replace-ext": true } }, - "gulp-watch>vinyl-file>vinyl>clone": { - "globals": { - "Buffer": true - } - }, "gulp-watch>vinyl-file>vinyl>clone-stats": { "builtin": { "fs.Stats": true @@ -5397,12 +5465,12 @@ }, "gulp>glob-watcher>anymatch>micromatch>extglob>expand-brackets>extend-shallow": { "packages": { - "gulp-watch>chokidar>braces>extend-shallow>is-extendable": true + "gulp-watch>anymatch>micromatch>object.omit>is-extendable": true } }, "gulp>glob-watcher>anymatch>micromatch>extglob>extend-shallow": { "packages": { - "gulp-watch>chokidar>braces>extend-shallow>is-extendable": true + "gulp-watch>anymatch>micromatch>object.omit>is-extendable": true } }, "gulp>glob-watcher>anymatch>normalize-path": { @@ -5483,7 +5551,7 @@ }, "gulp>glob-watcher>chokidar>braces>extend-shallow": { "packages": { - "gulp-watch>chokidar>braces>extend-shallow>is-extendable": true + "gulp-watch>anymatch>micromatch>object.omit>is-extendable": true } }, "gulp>glob-watcher>chokidar>braces>fill-range": { @@ -5499,7 +5567,7 @@ }, "gulp>glob-watcher>chokidar>braces>fill-range>extend-shallow": { "packages": { - "gulp-watch>chokidar>braces>extend-shallow>is-extendable": true + "gulp-watch>anymatch>micromatch>object.omit>is-extendable": true } }, "gulp>glob-watcher>chokidar>braces>fill-range>is-number": { @@ -5838,7 +5906,7 @@ "gulp>vinyl-fs>glob-stream>pumpify": true, "gulp>vinyl-fs>glob-stream>to-absolute-glob": true, "gulp>vinyl-fs>glob-stream>unique-stream": true, - "jsdom>request>extend": true, + "react-markdown>unified>extend": true, "readable-stream": true, "vinyl>remove-trailing-separator": true } @@ -6111,6 +6179,12 @@ "process": true } }, + "jsdom>acorn": { + "globals": { + "console": true, + "define": true + } + }, "koa>is-generator-function>has-tostringtag": { "packages": { "string.prototype.matchall>has-symbols": true @@ -6283,7 +6357,6 @@ "events": true, "fs.existsSync": true, "fs.readFileSync": true, - "fs.writeFileSync": true, "path.extname": true, "path.join": true }, @@ -6333,7 +6406,7 @@ }, "lavamoat>lavamoat-core>merge-deep>clone-deep>shallow-clone": { "packages": { - "gulp-watch>chokidar>braces>extend-shallow>is-extendable": true, + "gulp-watch>anymatch>micromatch>object.omit>is-extendable": true, "lavamoat>lavamoat-core>merge-deep>clone-deep>shallow-clone>kind-of": true, "lavamoat>lavamoat-core>merge-deep>clone-deep>shallow-clone>lazy-cache": true, "lavamoat>lavamoat-core>merge-deep>clone-deep>shallow-clone>mixin-object": true @@ -6354,7 +6427,7 @@ }, "lavamoat>lavamoat-core>merge-deep>clone-deep>shallow-clone>mixin-object": { "packages": { - "gulp-watch>chokidar>braces>extend-shallow>is-extendable": true, + "gulp-watch>anymatch>micromatch>object.omit>is-extendable": true, "lavamoat>lavamoat-core>merge-deep>clone-deep>shallow-clone>mixin-object>for-in": true } }, @@ -6390,7 +6463,7 @@ "loose-envify>js-tokens": true } }, - "madge>detective-scss>gonzales-pe": { + "madge>detective-less>gonzales-pe": { "globals": { "console.error": true, "define": true @@ -6443,12 +6516,6 @@ "madge>ora>is-unicode-supported": true } }, - "mocha>minimatch>brace-expansion": { - "packages": { - "mocha>minimatch>brace-expansion>concat-map": true, - "stylelint>balanced-match": true - } - }, "mocha>supports-color": { "builtin": { "os.release": true, @@ -6459,7 +6526,7 @@ "process.platform": true }, "packages": { - "sinon>supports-color>has-flag": true + "chalk>supports-color>has-flag": true } }, "mocha>which": { @@ -6561,17 +6628,6 @@ "pump>once>wrappy": true } }, - "nyc>p-map>aggregate-error": { - "packages": { - "@testing-library/jest-dom>redent>indent-string": true, - "nyc>p-map>aggregate-error>clean-stack": true - } - }, - "nyc>p-map>aggregate-error>clean-stack": { - "builtin": { - "os.homedir": true - } - }, "nyc>resolve-from": { "builtin": { "fs.realpathSync": true, @@ -6581,44 +6637,6 @@ "path.resolve": true } }, - "nyc>rimraf": { - "builtin": { - "assert": true, - "fs": true, - "path.join": true - }, - "globals": { - "process.platform": true, - "setTimeout": true - }, - "packages": { - "nyc>rimraf>glob": true - } - }, - "nyc>rimraf>glob": { - "builtin": { - "assert": true, - "events.EventEmitter": true, - "fs": true, - "path.join": true, - "path.resolve": true, - "util": true - }, - "globals": { - "console.error": true, - "process.cwd": true, - "process.nextTick": true, - "process.platform": true - }, - "packages": { - "eslint>minimatch": true, - "gulp-watch>path-is-absolute": true, - "nyc>glob>fs.realpath": true, - "nyc>glob>inflight": true, - "pump>once": true, - "pumpify>inherits": true - } - }, "nyc>signal-exit": { "builtin": { "assert.equal": true, @@ -7489,9 +7507,9 @@ }, "react-markdown>unified": { "packages": { - "jsdom>request>extend": true, "mocha>yargs-unparser>is-plain-obj": true, "react-markdown>unified>bail": true, + "react-markdown>unified>extend": true, "react-markdown>unified>is-buffer": true, "react-markdown>unified>trough": true, "react-markdown>vfile": true @@ -7677,9 +7695,6 @@ } }, "semver": { - "builtin": { - "util.inspect": true - }, "globals": { "console.error": true, "process": true @@ -7693,11 +7708,6 @@ "semver>lru-cache>yallist": true } }, - "sinon>supports-color>has-flag": { - "globals": { - "process.argv": true - } - }, "source-map": { "builtin": { "fs.readFile": true, @@ -7867,9 +7877,10 @@ "packages": { "chalk": true, "del>slash": true, + "eslint>ignore": true, "eslint>imurmurhash": true, + "fast-glob>micromatch": true, "globby": true, - "globby>ignore": true, "lodash": true, "mocha>log-symbols": true, "nock>debug": true, @@ -7888,7 +7899,6 @@ "stylelint>known-css-properties": true, "stylelint>leven": true, "stylelint>mathml-tag-names": true, - "stylelint>micromatch": true, "stylelint>normalize-selector": true, "stylelint>postcss": true, "stylelint>postcss-html": true, @@ -8153,7 +8163,14 @@ "path.dirname": true }, "packages": { - "@sentry/cli>mkdirp": true + "stylelint>file-entry-cache>flat-cache>write>mkdirp": true + } + }, + "stylelint>file-entry-cache>flat-cache>write>mkdirp": { + "builtin": { + "fs": true, + "path.dirname": true, + "path.resolve": true } }, "stylelint>global-modules": { @@ -8215,15 +8232,6 @@ "path.join": true } }, - "stylelint>micromatch": { - "builtin": { - "util.inspect": true - }, - "packages": { - "chokidar>braces": true, - "depcheck>readdirp>picomatch": true - } - }, "stylelint>normalize-selector": { "globals": { "define": true @@ -8377,7 +8385,7 @@ }, "stylelint>postcss-sass": { "packages": { - "madge>detective-scss>gonzales-pe": true, + "madge>detective-less>gonzales-pe": true, "stylelint>postcss-sass>postcss": true } }, @@ -8572,8 +8580,8 @@ }, "packages": { "eslint>imurmurhash": true, - "jsdom>request>is-typedarray": true, "nyc>signal-exit": true, + "stylelint>write-file-atomic>is-typedarray": true, "stylelint>write-file-atomic>typedarray-to-buffer": true } }, @@ -8582,7 +8590,7 @@ "Buffer.from": true }, "packages": { - "jsdom>request>is-typedarray": true + "stylelint>write-file-atomic>is-typedarray": true } }, "superstruct": { @@ -8602,8 +8610,8 @@ "process": true }, "packages": { - "terser>@jridgewell/source-map": true, - "terser>acorn": true + "jsdom>acorn": true, + "terser>@jridgewell/source-map": true } }, "terser>@jridgewell/source-map": { @@ -8649,12 +8657,6 @@ "define": true } }, - "terser>acorn": { - "globals": { - "console": true, - "define": true - } - }, "terser>source-map-support": { "builtin": { "fs": true, @@ -8883,17 +8885,11 @@ }, "packages": { "chokidar": true, + "chokidar>anymatch": true, "through2": true, - "watchify>anymatch": true, "watchify>xtend": true } }, - "watchify>anymatch": { - "packages": { - "chokidar>normalize-path": true, - "depcheck>readdirp>picomatch": true - } - }, "watchify>browserify>shasum-object": { "builtin": { "crypto.createHash": true diff --git a/package.json b/package.json index fdb303c67..2ef54b75c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metamask-crx", - "version": "10.33.1", + "version": "10.34.1", "private": true, "repository": { "type": "git", @@ -63,7 +63,7 @@ "lint:lockfile:dedupe:fix": "yarn dedupe", "lint:lockfile": "lockfile-lint --path yarn.lock --allowed-hosts npm yarn github.com codeload.github.com --empty-hostname true --allowed-schemes \"https:\" \"git+https:\" \"npm:\" \"patch:\" \"workspace:\"", "lint:shellcheck": "./development/shellcheck.sh", - "lint:styles": "stylelint -- */**/*.scss", + "lint:styles": "stylelint '*/**/*.scss'", "lint:styles:fix": "yarn lint:styles --fix", "lint:tsc": "tsc --project tsconfig.json --noEmit", "validate-source-maps": "node ./development/sourcemap-validator.js", @@ -98,11 +98,13 @@ "add-release-label-to-pr-and-linked-issues": "ts-node ./.github/scripts/add-release-label-to-pr-and-linked-issues.ts" }, "resolutions": { + "simple-update-notifier@^1.0.0": "^2.0.0", "@babel/core": "patch:@babel/core@npm%3A7.21.5#./.yarn/patches/@babel-core-npm-7.21.5-c72c337956.patch", "@babel/runtime": "patch:@babel/runtime@npm%3A7.18.9#./.yarn/patches/@babel-runtime-npm-7.18.9-28ca6b5f61.patch", - "@metamask/approval-controller": "^3.3.0", + "@metamask/approval-controller": "^3.4.0", "@types/react": "^16.9.53", "analytics-node/axios": "^0.21.2", + "bn.js": "^5.2.1", "ganache-core/lodash": "^4.17.21", "git-url-parse@^12.0.0": "^13.1.0", "glob-parent": "^6.0.2", @@ -165,15 +167,15 @@ "regenerator-runtime@^0.13.4": "patch:regenerator-runtime@npm%3A0.13.7#./.yarn/patches/regenerator-runtime-npm-0.13.7-41bcbe64ea.patch", "regenerator-runtime@^0.13.7": "patch:regenerator-runtime@npm%3A0.13.7#./.yarn/patches/regenerator-runtime-npm-0.13.7-41bcbe64ea.patch", "regenerator-runtime@^0.11.0": "patch:regenerator-runtime@npm%3A0.13.7#./.yarn/patches/regenerator-runtime-npm-0.13.7-41bcbe64ea.patch", + "jsdom@^16.7.0": "patch:jsdom@npm%3A16.7.0#./.yarn/patches/jsdom-npm-16.7.0-216c5c4bf9.patch", "trim": "^0.0.3", "@eslint/eslintrc@^2.0.1": "patch:@eslint/eslintrc@npm%3A2.0.2#./.yarn/patches/@eslint-eslintrc-npm-2.0.2-d308674d86.patch", - "@formatjs/intl-utils@^3.3.1": "patch:@formatjs/intl-utils@npm%3A3.3.1#./.yarn/patches/@formatjs-intl-utils-npm-3.3.1-08510c16ad.patch", "@fortawesome/fontawesome-free@^5.13.0": "patch:@fortawesome/fontawesome-free@npm%3A5.13.0#./.yarn/patches/@fortawesome-fontawesome-free-npm-5.13.0-f20fc0388d.patch", "@keystonehq/bc-ur-registry@^0.5.0-alpha.5": "patch:@keystonehq/bc-ur-registry@npm%3A0.5.0-alpha.5#./.yarn/patches/@keystonehq-bc-ur-registry-npm-0.5.0-alpha.5-b95c7992a6.patch", "@lavamoat/lavapack@^3.1.0": "patch:@lavamoat/lavapack@npm%3A3.1.0#./.yarn/patches/@lavamoat-lavapack-npm-3.1.0-34c65d233b.patch", "fast-json-patch@^3.1.0": "patch:fast-json-patch@npm%3A3.1.1#./.yarn/patches/fast-json-patch-npm-3.1.1-7e8bb70a45.patch", "@reduxjs/toolkit@^1.6.2": "patch:@reduxjs/toolkit@npm%3A1.6.2#./.yarn/patches/@reduxjs-toolkit-npm-1.6.2-67af09515f.patch", - "parse5@^7.0.0": "patch:parse5@npm%3A7.0.0#./.yarn/patches/parse5-npm-7.0.0-3158a72394.patch", + "parse5@^7.0.0": "patch:parse5@npm%3A7.1.2#./.yarn/patches/parse5-npm-7.1.2-aa9a92c270.patch", "@types/madge@^5.0.0": "patch:@types/madge@npm%3A5.0.0#./.yarn/patches/@types-madge-npm-5.0.0-654566c2d2.patch", "zxcvbn@^4.4.2": "patch:zxcvbn@npm%3A4.4.2#./.yarn/patches/zxcvbn-npm-4.4.2-6527983856.patch", "web3@^0.20.7": "patch:web3@npm%3A0.20.7#./.yarn/patches/web3-npm-0.20.7-ee7ef00c57.patch", @@ -196,10 +198,13 @@ "request@^2.83.0": "patch:request@npm%3A2.88.2#./.yarn/patches/request-npm-2.88.2-f4a57c72c4.patch", "request@^2.88.2": "patch:request@npm%3A2.88.2#./.yarn/patches/request-npm-2.88.2-f4a57c72c4.patch", "request@^2.85.0": "patch:request@npm%3A2.88.2#./.yarn/patches/request-npm-2.88.2-f4a57c72c4.patch", - "@metamask/signature-controller@^4.0.1": "patch:@metamask/signature-controller@npm%3A4.0.1#./.yarn/patches/@metamask-signature-controller-npm-4.0.1-013e64c9fd.patch" + "lavamoat-core@^14.2.0": "patch:lavamoat-core@npm%3A14.2.0#./.yarn/patches/lavamoat-core-npm-14.2.0-c453f4f755.patch", + "@metamask/keyring-controller@^7.0.0": "patch:@metamask/keyring-controller@npm%3A7.0.0#./.yarn/patches/@metamask-keyring-controller-npm-7.0.0-962008b200.patch", + "@metamask/signature-controller@^5.3.0": "patch:@metamask/signature-controller@npm%3A5.3.0#./.yarn/patches/@metamask-signature-controller-npm-5.3.0-225628460b.patch" }, "dependencies": { "@babel/runtime": "^7.18.9", + "@blockaid/ppom": "^0.1.2", "@download/blockies": "^1.0.3", "@ensdomains/content-hash": "^2.5.6", "@ethereumjs/common": "^3.1.1", @@ -209,7 +214,6 @@ "@ethersproject/contracts": "^5.7.0", "@ethersproject/hdnode": "^5.6.2", "@ethersproject/providers": "^5.7.2", - "@formatjs/intl-relativetimeformat": "^5.2.6", "@fortawesome/fontawesome-free": "^5.13.0", "@keystonehq/bc-ur-registry-eth": "^0.19.1", "@keystonehq/metamask-airgapped-keyring": "^0.13.1", @@ -217,7 +221,7 @@ "@material-ui/core": "^4.11.0", "@metamask-institutional/custody-controller": "0.2.6", "@metamask-institutional/custody-keyring": "^0.0.25", - "@metamask-institutional/extension": "^0.1.3", + "@metamask-institutional/extension": "^0.2.1", "@metamask-institutional/institutional-features": "^1.1.8", "@metamask-institutional/portfolio-dashboard": "^1.1.3", "@metamask-institutional/rpc-allowlist": "^1.0.0", @@ -225,12 +229,12 @@ "@metamask-institutional/transaction-update": "^0.1.21", "@metamask/address-book-controller": "^3.0.0", "@metamask/announcement-controller": "^4.0.0", - "@metamask/approval-controller": "^3.3.0", + "@metamask/approval-controller": "^3.4.0", "@metamask/assets-controllers": "^9.2.0", - "@metamask/base-controller": "^3.0.0", + "@metamask/base-controller": "^3.2.0", "@metamask/browser-passworder": "^4.1.0", "@metamask/contract-metadata": "^2.3.1", - "@metamask/controller-utils": "^4.1.0", + "@metamask/controller-utils": "^4.2.0", "@metamask/design-tokens": "^1.12.0", "@metamask/desktop": "^0.3.0", "@metamask/eth-json-rpc-middleware": "^11.0.0", @@ -242,31 +246,33 @@ "@metamask/etherscan-link": "^2.2.0", "@metamask/gas-fee-controller": "^6.0.1", "@metamask/jazzicon": "^2.0.0", - "@metamask/key-tree": "^7.0.0", + "@metamask/key-tree": "^9.0.0", + "@metamask/keyring-controller": "^7.0.0", "@metamask/logo": "^3.1.1", "@metamask/message-manager": "^7.0.2", "@metamask/metamask-eth-abis": "^3.0.0", - "@metamask/network-controller": "^10.3.0", + "@metamask/network-controller": "^10.3.1", "@metamask/notification-controller": "^3.0.0", "@metamask/obs-store": "^8.1.0", "@metamask/permission-controller": "^4.0.0", "@metamask/phishing-controller": "^3.0.0", "@metamask/post-message-stream": "^6.0.0", + "@metamask/ppom-validator": "^0.1.2", "@metamask/providers": "^11.1.0", "@metamask/rate-limit-controller": "^3.0.0", "@metamask/rpc-methods": "^1.0.0-prerelease.1", - "@metamask/rpc-methods-flask": "npm:@metamask/rpc-methods@0.36.1-flask.1", + "@metamask/rpc-methods-flask": "npm:@metamask/rpc-methods@0.37.1-flask.1", "@metamask/safe-event-emitter": "^2.0.0", "@metamask/scure-bip39": "^2.0.3", - "@metamask/signature-controller": "^4.0.1", + "@metamask/signature-controller": "^5.3.0", "@metamask/slip44": "^3.0.0", - "@metamask/smart-transactions-controller": "^3.1.0", + "@metamask/smart-transactions-controller": "^4.0.0", "@metamask/snaps-controllers": "^1.0.0-prerelease.1", - "@metamask/snaps-controllers-flask": "npm:@metamask/snaps-controllers@0.36.1-flask.1", + "@metamask/snaps-controllers-flask": "npm:@metamask/snaps-controllers@0.37.1-flask.1", "@metamask/snaps-ui": "^1.0.0-prerelease.1", - "@metamask/snaps-ui-flask": "npm:@metamask/snaps-ui@0.36.1-flask.1", + "@metamask/snaps-ui-flask": "npm:@metamask/snaps-ui@0.37.1-flask.1", "@metamask/snaps-utils": "^1.0.0-prerelease.1", - "@metamask/snaps-utils-flask": "npm:@metamask/snaps-utils@0.36.1-flask.1", + "@metamask/snaps-utils-flask": "npm:@metamask/snaps-utils@0.37.1-flask.1", "@metamask/subject-metadata-controller": "^2.0.0", "@metamask/utils": "^5.0.0", "@ngraveio/bc-ur": "^1.1.6", @@ -279,16 +285,16 @@ "@sentry/utils": "^7.53.0", "@truffle/codec": "^0.14.12", "@truffle/decoder": "^5.3.5", - "@zxing/browser": "^0.0.10", - "@zxing/library": "0.8.0", + "@zxing/browser": "^0.1.3", + "@zxing/library": "0.20.0", "await-semaphore": "^0.1.1", "base32-encode": "^1.2.0", "base64-js": "^1.5.1", "bignumber.js": "^4.1.0", - "bn.js": "^4.11.7", + "bn.js": "^5.2.1", "bowser": "^2.11.0", "classnames": "^2.2.6", - "copy-to-clipboard": "^3.0.8", + "copy-to-clipboard": "^3.3.3", "currency-formatter": "^1.4.2", "debounce-stream": "^2.0.0", "deep-freeze-strict": "1.1.1", @@ -336,7 +342,7 @@ "react-dom": "^16.12.0", "react-focus-lock": "^2.9.4", "react-idle-timer": "^4.2.5", - "react-inspector": "^2.3.0", + "react-inspector": "^6.0.2", "react-markdown": "^6.0.3", "react-popper": "^2.2.3", "react-redux": "^7.2.0", @@ -371,7 +377,7 @@ "@babel/preset-typescript": "^7.16.7", "@babel/register": "^7.5.5", "@ethersproject/bignumber": "^5.7.0", - "@lavamoat/allow-scripts": "^2.0.3", + "@lavamoat/allow-scripts": "^2.3.1", "@lavamoat/lavapack": "^5.2.0", "@metamask/auto-changelog": "^2.1.0", "@metamask/eslint-config": "^9.0.0", @@ -382,7 +388,7 @@ "@metamask/forwarder": "^1.1.0", "@metamask/phishing-warning": "^2.1.0", "@metamask/test-dapp": "^7.0.1", - "@sentry/cli": "^1.58.0", + "@sentry/cli": "^2.19.4", "@storybook/addon-a11y": "^7.0.11", "@storybook/addon-actions": "^7.0.11", "@storybook/addon-essentials": "^7.0.11", @@ -429,7 +435,7 @@ "@types/yargs": "^17.0.8", "@typescript-eslint/eslint-plugin": "^5.30.7", "@typescript-eslint/parser": "^5.30.7", - "@whitespace/storybook-addon-html": "^5.1.4", + "@whitespace/storybook-addon-html": "^5.1.6", "addons-linter": "^5.2.0", "babel-plugin-module-resolver": "^5.0.0", "babelify": "^10.0.0", @@ -463,6 +469,7 @@ "eslint-plugin-react": "^7.23.1", "eslint-plugin-react-hooks": "^4.2.0", "eslint-plugin-storybook": "^0.6.12", + "fake-indexeddb": "^4.0.1", "fancy-log": "^1.3.3", "fast-glob": "^3.2.2", "fs-extra": "^8.1.0", @@ -492,7 +499,7 @@ "jest-canvas-mock": "^2.3.1", "jest-environment-jsdom": "^29.1.2", "js-yaml": "^4.1.0", - "jsdom": "^11.2.0", + "jsdom": "^16.7.0", "junit-report-merger": "^4.0.0", "koa": "^2.7.0", "lavamoat": "^7.1.0", @@ -522,7 +529,7 @@ "sass": "^1.32.4", "sass-loader": "^10.1.1", "selenium-webdriver": "^4.9.0", - "semver": "^7.3.5", + "semver": "^7.5.4", "serve-handler": "^6.1.2", "sinon": "^9.0.0", "source-map": "^0.7.2", diff --git a/shared/constants/metametrics.ts b/shared/constants/metametrics.ts index 453ba97ea..32f8fc22d 100644 --- a/shared/constants/metametrics.ts +++ b/shared/constants/metametrics.ts @@ -484,6 +484,8 @@ export enum MetaMetricsEventName { AccountPasswordCreated = 'Account Password Created', AccountReset = 'Account Reset', AccountRenamed = 'Account Renamed', + ActivityDetailsOpened = 'Activity Details Opened', + ActivityDetailsClosed = 'Activity Details Closed', AppInstalled = 'App Installed', AppUnlocked = 'App Unlocked', AppUnlockedFailed = 'App Unlocked Failed', @@ -583,10 +585,21 @@ export enum MetaMetricsEventName { WalletSetupFailed = 'Wallet Setup Failed', WalletCreated = 'Wallet Created', ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) - UserClickedDeepLink = 'User Clicked Deeplink', - UserClickedConnectCustodialAccount = 'Clicked Connect Custodial Account', - UserClickedPortfolioButton = 'Clicked Portfolio Button', - UserClickedCompliance = 'Clicked Compliance', + DeeplinkClicked = 'Deeplink Clicked', + ConnectCustodialAccountClicked = 'Connect Custodial Account Clicked', + MMIPortfolioButtonClicked = 'MMI Portfolio Button Clicked', + PortfolioDashboardModalButtonClicked = 'Portfolio Dashboard Modal Button Clicked', + PortfolioDashboardModalOpened = 'Portfolio Dashboard Modal Opened', + StakeButtonClicked = 'Stake Button Clicked', + InteractiveReplacementTokenButtonClicked = 'Interactive Replacement Token Button Clicked', + RefreshTokenListClicked = 'Refresh Token List Clicked', + SignatureDeeplinkDisplayed = 'Signature Deeplink Displayed', + InstitutionalFeatureConnected = 'Institutional Feature Connected', + CustodianSelected = 'Custodian Selected', + CustodianConnected = 'Custodian Connected', + CustodianConnectionCanceled = 'Custodian Connection Canceled', + CustodianConnectionFailed = 'Custodian Connection Failed', + CustodialAccountsConnected = 'Custodial Accounts Connected', ///: END:ONLY_INCLUDE_IN AccountDetailMenuOpened = 'Account Details Menu Opened', BlockExplorerLinkClicked = 'Block Explorer Clicked', diff --git a/shared/constants/network.ts b/shared/constants/network.ts index c3eb9dc1d..d9f0fb99e 100644 --- a/shared/constants/network.ts +++ b/shared/constants/network.ts @@ -156,6 +156,7 @@ export const CHAIN_IDS = { MOONBEAM_TESTNET: '0x507', MOONRIVER: '0x505', CRONOS: '0x19', + GNOSIS: '0x64', } as const; /** @@ -181,6 +182,7 @@ export const HARMONY_DISPLAY_NAME = 'Harmony Mainnet Shard 0'; export const PALM_DISPLAY_NAME = 'Palm'; export const AURORA_DISPLAY_NAME = 'Aurora Mainnet'; export const CELO_DISPLAY_NAME = 'Celo Mainnet'; +export const GNOSIS_DISPLAY_NAME = 'Gnosis'; export const infuraProjectId = process.env.INFURA_PROJECT_ID; export const getRpcUrl = ({ @@ -218,6 +220,7 @@ export const CURRENCY_SYMBOLS = { BUSD: 'BUSD', CELO: 'CELO', DAI: 'DAI', + GNOSIS: 'XDAI', ETH: 'ETH', FANTOM: 'FTM', HARMONY: 'ONE', @@ -248,6 +251,7 @@ export const OPTIMISM_TOKEN_IMAGE_URL = './images/optimism.svg'; export const PALM_TOKEN_IMAGE_URL = './images/palm.svg'; export const AURORA_TOKEN_IMAGE_URL = './images/aurora.png'; export const CELO_TOKEN_IMAGE_URL = './images/celo.svg'; +export const GNOSIS_TOKEN_IMAGE_URL = './images/gnosis.svg'; export const INFURA_PROVIDER_TYPES = [ NETWORK_TYPES.MAINNET, @@ -382,6 +386,7 @@ export const CHAIN_ID_TO_NETWORK_IMAGE_URL_MAP = { [CHAIN_IDS.PALM]: PALM_TOKEN_IMAGE_URL, [CHAIN_IDS.AURORA]: AURORA_TOKEN_IMAGE_URL, [CHAIN_IDS.CELO]: CELO_TOKEN_IMAGE_URL, + [CHAIN_IDS.GNOSIS]: GNOSIS_TOKEN_IMAGE_URL, } as const; export const NETWORK_ID_TO_ETHERS_NETWORK_NAME_MAP = { @@ -410,6 +415,7 @@ export const NATIVE_CURRENCY_TOKEN_IMAGE_MAP = { [CURRENCY_SYMBOLS.OPTIMISM]: OPTIMISM_TOKEN_IMAGE_URL, [CURRENCY_SYMBOLS.CELO]: CELO_TOKEN_IMAGE_URL, [CURRENCY_SYMBOLS.AURORA_ETH]: ETH_TOKEN_IMAGE_URL, + [CURRENCY_SYMBOLS.GNOSIS]: GNOSIS_TOKEN_IMAGE_URL, } as const; export const INFURA_BLOCKED_KEY = 'countryBlocked'; @@ -514,6 +520,11 @@ export const ETHERSCAN_SUPPORTED_NETWORKS = { subdomain: `${defaultEtherscanSubdomainPrefix}-moonriver`, networkId: parseInt(CHAIN_IDS.MOONRIVER, 16).toString(), }, + [CHAIN_IDS.GNOSIS]: { + domain: 'gnosisscan.io', + subdomain: `${defaultEtherscanSubdomainPrefix}-gnosis`, + networkId: parseInt(CHAIN_IDS.GNOSIS, 16).toString(), + }, }; export const CHAIN_ID_TO_GAS_LIMIT_BUFFER_MAP = { @@ -549,6 +560,7 @@ export const BUYABLE_CHAINS_MAP: { | typeof CHAIN_IDS.MOONBEAM_TESTNET | typeof CHAIN_IDS.LINEA_GOERLI | typeof CHAIN_IDS.GOERLI + | typeof CHAIN_IDS.GNOSIS >]: BuyableChainSettings; } = { [CHAIN_IDS.MAINNET]: { @@ -718,6 +730,16 @@ export const FEATURED_RPCS: RPCDefinition[] = [ imageUrl: CELO_TOKEN_IMAGE_URL, }, }, + { + chainId: CHAIN_IDS.GNOSIS, + nickname: GNOSIS_DISPLAY_NAME, + rpcUrl: `https://rpc.gnosischain.com`, + ticker: CURRENCY_SYMBOLS.GNOSIS, + rpcPrefs: { + blockExplorerUrl: 'https://gnosisscan.io', + imageUrl: GNOSIS_TOKEN_IMAGE_URL, + }, + }, ]; /** diff --git a/shared/constants/security-provider.ts b/shared/constants/security-provider.ts index 1862e8181..b956a8e75 100644 --- a/shared/constants/security-provider.ts +++ b/shared/constants/security-provider.ts @@ -1,3 +1,60 @@ +export enum SecurityProvider { + Blockaid = 'blockaid', +} + +type SecurityProviderConfig = Record< + SecurityProvider, + { + /** translation key for security provider name */ + readonly tKeyName: string; + /** URL to securty provider website */ + readonly url: string; + } +>; + +export const SECURITY_PROVIDER_CONFIG: Readonly = { + [SecurityProvider.Blockaid]: { + tKeyName: 'blockaid', + url: 'https://blockaid.io/', + }, +}; + +/** The reason, also referred to as the attack type, provided in the PPOM Response */ +export enum BlockaidReason { + /** Approval for a malicious spender */ + approvalFarming = 'approval_farming', + /** Malicious signature on Blur order */ + blurFarming = 'blur_farming', + /** A known malicous site invoked that transaction */ + maliciousDomain = 'malicious_domain', + /** Malicious signature on a Permit order */ + permitFarming = 'permit_farming', + /** Direct theft of native assets (ETH/MATIC/AVAX/ etc …) */ + rawNativeTokenTransfer = 'raw_native_token_transfer', + /** Malicious raw signature from the user */ + rawSignatureFarming = 'raw_signature_farming', + /** Malicious signature on a Seaport order */ + seaportFarming = 'seaport_farming', + /** setApprovalForAll for a malicious operator */ + setApprovalForAll = 'set_approval_for_all', + /** Malicious signature on other type of trade order (Zero-X / Rarible / etc..) */ + tradeOrderFarming = 'trade_order_farming', + /** Direct theft of assets using transfer */ + transferFarming = 'transfer_farming', + /** Direct theft of assets using transferFrom */ + transferFromFarming = 'transfer_from_farming', + /** Malicious trade that results in the victim being rained */ + unfairTrade = 'unfair_trade', + + other = 'other', +} + +export enum BlockaidResultType { + Malicious = 'Malicious', + Warning = 'Warning', + Benign = 'Benign', +} + /** * @typedef {object} SecurityProviderMessageSeverity * @property {0} NOT_MALICIOUS - Indicates message is not malicious diff --git a/test/data/mock-state.json b/test/data/mock-state.json index 07153cf85..77d17841f 100644 --- a/test/data/mock-state.json +++ b/test/data/mock-state.json @@ -115,13 +115,22 @@ "type": "rpc", "chainId": "0x5", "ticker": "ETH", - "id": "testNetworkConfigurationId" + "id": "chain5" }, "networkConfigurations": { "testNetworkConfigurationId": { "rpcUrl": "https://testrpc.com", "chainId": "0x1", - "nickname": "Custom Mainnet RPC" + "nickname": "Custom Mainnet RPC", + "type": "rpc", + "id": "testNetworkConfigurationId" + }, + "chain5": { + "type": "rpc", + "chainId": "0x5", + "ticker": "ETH", + "nickname": "Chain 5", + "id": "chain5" } }, "keyrings": [ diff --git a/test/e2e/fixture-builder.js b/test/e2e/fixture-builder.js index 884c9b94e..bbbcd49cf 100644 --- a/test/e2e/fixture-builder.js +++ b/test/e2e/fixture-builder.js @@ -215,6 +215,7 @@ function defaultFixture() { rpcUrl: 'http://localhost:8545', ticker: 'ETH', type: 'rpc', + id: 'networkConfigurationId', }, networkConfigurations: { networkConfigurationId: { @@ -346,6 +347,7 @@ function onboardingFixture() { rpcUrl: 'http://localhost:8545', chainId: CHAIN_IDS.LOCALHOST, nickname: 'Localhost 8545', + id: 'networkConfigurationId', }, networkConfigurations: { networkConfigurationId: { @@ -355,6 +357,7 @@ function onboardingFixture() { rpcUrl: 'http://localhost:8545', ticker: 'ETH', networkConfigurationId: 'networkConfigurationId', + type: 'rpc', }, }, }, diff --git a/test/e2e/helpers.js b/test/e2e/helpers.js index 8c0ffb76a..b1e17b350 100644 --- a/test/e2e/helpers.js +++ b/test/e2e/helpers.js @@ -313,10 +313,10 @@ const onboardingBeginCreateNewWallet = async (driver) => { * Choose either "I Agree" or "No Thanks" on the MetaMetrics onboarding screen * * @param {WebDriver} driver - * @param {boolean} optin - true to opt into metrics, default is false + * @param {boolean} option - true to opt into metrics, default is false */ -const onboardingChooseMetametricsOption = async (driver, optin = false) => { - const optionIdentifier = optin ? 'i-agree' : 'no-thanks'; +const onboardingChooseMetametricsOption = async (driver, option = false) => { + const optionIdentifier = option ? 'i-agree' : 'no-thanks'; // metrics await driver.clickElement(`[data-testid="metametrics-${optionIdentifier}"]`); }; @@ -692,12 +692,6 @@ function generateRandNumBetween(x, y) { return randomNumber; } -async function switchToWindow(driver, windowTitle) { - const windowHandles = await driver.getAllWindowHandles(); - - return await driver.switchToWindowWithTitle(windowTitle, windowHandles); -} - async function sleepSeconds(sec) { return new Promise((resolve) => setTimeout(resolve, sec * 1000)); } @@ -714,7 +708,8 @@ async function terminateServiceWorker(driver) { tag: 'button', }); - const serviceWorkerElements = await driver.findElements({ + await driver.delay(tinyDelayMs); + const serviceWorkerElements = await driver.findClickableElements({ text: 'terminate', tag: 'span', }); @@ -722,8 +717,7 @@ async function terminateServiceWorker(driver) { // 1st one is app-init.js; while 2nd one is service-worker.js await serviceWorkerElements[serviceWorkerElements.length - 1].click(); - const serviceWorkerTab = await switchToWindow( - driver, + const serviceWorkerTab = await driver.switchToWindowWithTitle( WINDOW_TITLES.ServiceWorkerSettings, ); @@ -750,15 +744,17 @@ async function switchToNotificationWindow(driver) { * * @param {WebDriver} driver * @param {import('mockttp').Mockttp} mockedEndpoints + * @param {boolean} hasRequest * @returns {import('mockttp/dist/pluggable-admin').MockttpClientResponse[]} */ -async function getEventPayloads(driver, mockedEndpoints) { +async function getEventPayloads(driver, mockedEndpoints, hasRequest = true) { await driver.wait(async () => { let isPending = true; for (const mockedEndpoint of mockedEndpoints) { isPending = await mockedEndpoint.isPending(); } - return isPending === false; + + return isPending === !hasRequest; }, 10000); const mockedRequests = []; for (const mockedEndpoint of mockedEndpoints) { @@ -810,7 +806,6 @@ module.exports = { generateETHBalance, roundToXDecimalPlaces, generateRandNumBetween, - switchToWindow, sleepSeconds, terminateServiceWorker, switchToNotificationWindow, diff --git a/test/e2e/metamask-ui.spec.js b/test/e2e/metamask-ui.spec.js index b52f6d938..ac5ac1861 100644 --- a/test/e2e/metamask-ui.spec.js +++ b/test/e2e/metamask-ui.spec.js @@ -339,12 +339,12 @@ describe('MetaMask', function () { it('finds the transaction in the transactions list', async function () { await driver.waitForSelector({ - css: '.transaction-list__completed-transactions .transaction-list-item__primary-currency', + css: '.transaction-list__completed-transactions [data-testid="transaction-list-item-primary-currency"]', text: '-1 TST', }); await driver.waitForSelector({ - css: '.list-item__heading', + css: '[data-testid="activity-list-item-action"]', text: 'Send TST', }); }); @@ -370,10 +370,12 @@ describe('MetaMask', function () { await driver.findElements('.transaction-list__pending-transactions'); await driver.waitForSelector({ - css: '.transaction-list-item__primary-currency', + css: '[data-testid="transaction-list-item-primary-currency"]', text: '-1.5 TST', }); - await driver.clickElement('.transaction-list-item__primary-currency'); + await driver.clickElement( + '[data-testid="transaction-list-item-primary-currency"]', + ); await driver.delay(regularDelayMs); const transactionAmounts = await driver.findElements( @@ -415,12 +417,12 @@ describe('MetaMask', function () { it('finds the transaction in the transactions list', async function () { await driver.waitForSelector({ - css: '.transaction-list__completed-transactions .transaction-list-item__primary-currency', + css: '.transaction-list__completed-transactions [data-testid="transaction-list-item-primary-currency"]', text: '-1.5 TST', }); await driver.waitForSelector({ - css: '.list-item__heading', + css: '[data-testid="activity-list-item-action"]', text: 'Send TST', }); }); @@ -462,20 +464,20 @@ describe('MetaMask', function () { }); await driver.switchToWindow(extension); - await driver.delay(regularDelayMs); + await driver.delay(veryLargeDelayMs); await driver.wait(async () => { const pendingTxes = await driver.findElements( - '.transaction-list__pending-transactions .transaction-list-item', + '.transaction-list__pending-transactions .activity-list-item', ); return pendingTxes.length === 1; }, 10000); await driver.waitForSelector({ - css: '.transaction-list-item__primary-currency', + css: '[data-testid="transaction-list-item-primary-currency"]', text: '-1.5 TST', }); - await driver.clickElement('.transaction-list-item'); + await driver.clickElement('.activity-list-item'); await driver.delay(regularDelayMs); }); @@ -489,12 +491,12 @@ describe('MetaMask', function () { await driver.waitForSelector({ // Select the heading of the first transaction list item in the // completed transaction list with text matching Send TST - css: '.transaction-list__completed-transactions .transaction-list-item:first-child .list-item__heading', + css: '.transaction-list__completed-transactions .activity-list-item [data-testid="activity-list-item-action"]', text: 'Send TST', }); await driver.waitForSelector({ - css: '.transaction-list__completed-transactions .transaction-list-item:first-child .transaction-list-item__primary-currency', + css: '.transaction-list__completed-transactions .activity-list-item [data-testid="transaction-list-item-primary-currency"]', text: '-1.5 TST', }); }); diff --git a/test/e2e/metrics/permissions-approved.spec.js b/test/e2e/metrics/permissions-approved.spec.js index df479b952..1a7b7cc71 100644 --- a/test/e2e/metrics/permissions-approved.spec.js +++ b/test/e2e/metrics/permissions-approved.spec.js @@ -5,6 +5,7 @@ const { withFixtures, openDapp, unlockWallet, + getEventPayloads, } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); @@ -43,28 +44,6 @@ async function mockSegment(mockServer) { ]; } -/** - * This method handles getting the mocked requests to the segment server - * - * @param {WebDriver} driver - * @param {import('mockttp').Mockttp} mockedEndpoints - * @returns {import('mockttp/dist/pluggable-admin').MockttpClientResponse[]} - */ -async function getEventPayloads(driver, mockedEndpoints) { - await driver.wait(async () => { - let isPending = true; - for (const mockedEndpoint of mockedEndpoints) { - isPending = await mockedEndpoint.isPending(); - } - return isPending === false; - }, 10000); - const mockedRequests = []; - for (const mockedEndpoint of mockedEndpoints) { - mockedRequests.push(...(await mockedEndpoint.getSeenRequests())); - } - return mockedRequests.map((req) => req.body.json.batch).flat(); -} - describe('Permissions Approved Event', function () { it('Successfully tracked when connecting to dapp', async function () { await withFixtures( diff --git a/test/e2e/tests/metrics.spec.js b/test/e2e/metrics/unlock-wallet.spec.js similarity index 55% rename from test/e2e/tests/metrics.spec.js rename to test/e2e/metrics/unlock-wallet.spec.js index ac99d3fe3..b980b0bb7 100644 --- a/test/e2e/tests/metrics.spec.js +++ b/test/e2e/metrics/unlock-wallet.spec.js @@ -1,8 +1,12 @@ const { strict: assert } = require('assert'); -const { convertToHexValue, withFixtures } = require('../helpers'); +const { + withFixtures, + unlockWallet, + defaultGanacheOptions, +} = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); -describe('Segment metrics', function () { +describe('Unlock wallet', function () { async function mockSegment(mockServer) { return await mockServer .forPost('https://api.segment.io/v1/batch') @@ -14,15 +18,7 @@ describe('Segment metrics', function () { }; }); } - const ganacheOptions = { - accounts: [ - { - secretKey: - '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', - balance: convertToHexValue(25000000000000000000), - }, - ], - }; + it('should send first three Page metric events upon fullscreen page load', async function () { await withFixtures( { @@ -32,14 +28,13 @@ describe('Segment metrics', function () { participateInMetaMetrics: true, }) .build(), - ganacheOptions, + ganacheOptions: defaultGanacheOptions, title: this.test.title, testSpecificMock: mockSegment, }, async ({ driver, mockedEndpoint }) => { await driver.navigate(); - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); + await unlockWallet(driver); await driver.wait(async () => { const isPending = await mockedEndpoint.isPending(); return isPending === false; @@ -47,19 +42,17 @@ describe('Segment metrics', function () { const mockedRequests = await mockedEndpoint.getSeenRequests(); assert.equal(mockedRequests.length, 3); const [firstMock, secondMock, thirdMock] = mockedRequests; - let [mockJson] = firstMock.body.json.batch; - let { title, path } = mockJson.context.page; - assert.equal(title, 'Home'); - assert.equal(path, '/'); - [mockJson] = secondMock.body.json.batch; - ({ title, path } = mockJson.context.page); - assert.equal(title, 'Unlock Page'); - assert.equal(path, '/unlock'); - [mockJson] = thirdMock.body.json.batch; - ({ title, path } = mockJson.context.page); - assert.equal(title, 'Home'); - assert.equal(path, '/'); + assertBatchValue(firstMock, 'Home', '/'); + assertBatchValue(secondMock, 'Unlock Page', '/unlock'); + assertBatchValue(thirdMock, 'Home', '/'); }, ); }); }); + +function assertBatchValue(mockRequest, assertedTitle, assertedPath) { + const [mockJson] = mockRequest.body.json.batch; + const { title, path } = mockJson.context.page; + assert.equal(title, assertedTitle); + assert.equal(path, assertedPath); +} diff --git a/test/e2e/metrics/wallet-created.spec.js b/test/e2e/metrics/wallet-created.spec.js index 8b04ee956..c1c573e00 100644 --- a/test/e2e/metrics/wallet-created.spec.js +++ b/test/e2e/metrics/wallet-created.spec.js @@ -48,8 +48,8 @@ async function mockSegment(mockServer) { ]; } -describe('Wallet Created Event', function () { - it('Successfully tracked when onboarding', async function () { +describe('Wallet Created Events', function () { + it('are sent when onboarding user who chooses to opt in metrics', async function () { await withFixtures( { fixtures: new FixtureBuilder({ onboarding: true }) @@ -73,6 +73,7 @@ describe('Wallet Created Event', function () { await onboardingPinExtension(driver); const events = await getEventPayloads(driver, mockedEndpoints); + assert.equal(events.length, 2); assert.deepStrictEqual(events[0].properties, { account_type: 'metamask', category: 'Onboarding', @@ -90,4 +91,36 @@ describe('Wallet Created Event', function () { }, ); }); + + it('are not sent when onboarding user who chooses to opt out metrics', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder({ onboarding: true }) + .withMetaMetricsController({ + metaMetricsId: 'fake-metrics-id', + }) + .build(), + defaultGanacheOptions, + title: this.test.title, + testSpecificMock: mockSegment, + }, + async ({ driver, mockedEndpoint: mockedEndpoints }) => { + await driver.navigate(); + await onboardingBeginCreateNewWallet(driver); + await onboardingChooseMetametricsOption(driver, false); + + await onboardingCreatePassword(driver, WALLET_PASSWORD); + await onboardingRevealAndConfirmSRP(driver); + await onboardingCompleteWalletCreation(driver); + await onboardingPinExtension(driver); + + const mockedRequests = await getEventPayloads( + driver, + mockedEndpoints, + false, + ); + assert.equal(mockedRequests.length, 0); + }, + ); + }); }); diff --git a/test/e2e/mv3/multiple-restarts.spec.js b/test/e2e/mv3/multiple-restarts.spec.js index 91f34896d..a90111d2a 100644 --- a/test/e2e/mv3/multiple-restarts.spec.js +++ b/test/e2e/mv3/multiple-restarts.spec.js @@ -9,10 +9,10 @@ const { generateETHBalance, roundToXDecimalPlaces, generateRandNumBetween, - switchToWindow, sleepSeconds, terminateServiceWorker, unlockWallet, + largeDelayMs, } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); @@ -114,7 +114,9 @@ describe('MV3 - Restart service worker multiple times', function () { ); async function simpleSendETH(driver, value, recipient) { - await switchToWindow(driver, WINDOW_TITLES.ExtensionInFullScreenView); + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); await driver.clickElement('[data-testid="eth-overview-send"]'); await driver.fill('[data-testid="ens-input"]', recipient); @@ -130,7 +132,7 @@ describe('MV3 - Restart service worker multiple times', function () { await driver.clickElement('[data-testid="page-container-footer-next"]'); await driver.clickElement('[data-testid="home__activity-tab"]'); - await driver.findElement('.transaction-list-item'); + await driver.findElement('.activity-list-item'); // reset view to assets tab await driver.clickElement('[data-testid="home__asset-tab"]'); @@ -138,7 +140,9 @@ describe('MV3 - Restart service worker multiple times', function () { } async function assertETHBalance(driver, expectedBalance) { - await switchToWindow(driver, WINDOW_TITLES.ExtensionInFullScreenView); + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); const isETHBalanceOverviewPresentAndVisible = await driver.isElementPresentAndVisible({ @@ -175,12 +179,11 @@ describe('MV3 - Restart service worker multiple times', function () { await openDapp(driver); // Click add Ethereum chain - await switchToWindow(driver, WINDOW_TITLES.TestDApp); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); await driver.clickElement('#addEthereumChain'); - await driver.waitUntilXWindowHandles(2); // Notification pop up opens - await switchToWindow(driver, WINDOW_TITLES.Notification); + await driver.switchToWindowWithTitle(WINDOW_TITLES.Notification); let notification = await driver.isElementPresent({ text: 'Allow this site to add a network?', tag: 'h3', @@ -189,19 +192,18 @@ describe('MV3 - Restart service worker multiple times', function () { // Cancel Notification await driver.clickElement({ text: 'Cancel', tag: 'button' }); - await driver.waitUntilXWindowHandles(2); // Terminate Service Worker - await switchToWindow(driver, WINDOW_TITLES.TestDApp); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + await terminateServiceWorker(driver); // Click add Ethereum chain #2 - await switchToWindow(driver, WINDOW_TITLES.TestDApp); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); await driver.clickElement('#addEthereumChain'); - await driver.waitUntilXWindowHandles(2); // Notification pop up opens - await switchToWindow(driver, WINDOW_TITLES.Notification); + await driver.switchToWindowWithTitle(WINDOW_TITLES.Notification); notification = await driver.isElementPresent({ text: 'Allow this site to add a network?', tag: 'h3', @@ -210,19 +212,17 @@ describe('MV3 - Restart service worker multiple times', function () { // Cancel Notification await driver.clickElement({ text: 'Cancel', tag: 'button' }); - await driver.waitUntilXWindowHandles(2); // Terminate Service Worker - await switchToWindow(driver, WINDOW_TITLES.TestDApp); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); await terminateServiceWorker(driver); // Click add Ethereum chain #3 - await switchToWindow(driver, WINDOW_TITLES.TestDApp); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); await driver.clickElement('#addEthereumChain'); - await driver.waitUntilXWindowHandles(2); // Notification pop up opens - await switchToWindow(driver, WINDOW_TITLES.Notification); + await driver.switchToWindowWithTitle(WINDOW_TITLES.Notification); notification = await driver.isElementPresent({ text: 'Allow this site to add a network?', tag: 'h3', @@ -232,7 +232,6 @@ describe('MV3 - Restart service worker multiple times', function () { // Accept Notification await driver.clickElement({ text: 'Approve', tag: 'button' }); await driver.clickElement({ text: 'Switch network', tag: 'button' }); - await driver.waitUntilXWindowHandles(2); }, ); }); @@ -257,21 +256,20 @@ describe('MV3 - Restart service worker multiple times', function () { await openDapp(driver); - await clickSendButton(driver); - await driver.waitUntilXWindowHandles(2); - - await switchToWindow(driver, WINDOW_TITLES.TestDApp); - await terminateServiceWorker(driver); - await driver.waitUntilXWindowHandles(2); + await driver.delay(largeDelayMs); await clickSendButton(driver); - await driver.waitUntilXWindowHandles(2); - await switchToWindow(driver, WINDOW_TITLES.TestDApp); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + + await terminateServiceWorker(driver); + + await clickSendButton(driver); + + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); await terminateServiceWorker(driver); await clickSendButton(driver); - await driver.waitUntilXWindowHandles(2); await assertNumberOfTransactionsInPopUp(driver, 3); @@ -287,7 +285,7 @@ describe('MV3 - Restart service worker multiple times', function () { async function clickSendButton(driver) { // Click send button - await switchToWindow(driver, WINDOW_TITLES.TestDApp); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); await driver.waitForSelector({ css: '#sendButton', @@ -297,7 +295,7 @@ describe('MV3 - Restart service worker multiple times', function () { } async function confirmETHSendNotification(driver, amount) { - await switchToWindow(driver, WINDOW_TITLES.Notification); + await driver.switchToWindowWithTitle(WINDOW_TITLES.Notification); await driver.clickElement({ text: 'Edit', @@ -318,14 +316,16 @@ describe('MV3 - Restart service worker multiple times', function () { } async function assertNumberOfTransactionsInPopUp(driver, number) { - await switchToWindow(driver, WINDOW_TITLES.Notification); - const navEl = await driver.findElement( - '.confirm-page-container-navigation__navtext', - ); + await driver.delay(largeDelayMs); - const notificationProgress = await navEl.getText(); + await driver.switchToWindowWithTitle(WINDOW_TITLES.Notification); - assert.ok(notificationProgress, `1 of ${number}`); + const foundElement = await driver.findElements({ + css: '.confirm-page-container-navigation__navtext', + text: `1 of ${number}`, + }); + + assert.ok(foundElement, true); } }); @@ -365,7 +365,9 @@ describe('MV3 - Restart service worker multiple times', function () { ); async function reloadExtension(driver, extensionId) { - await switchToWindow(driver, WINDOW_TITLES.ExtensionInFullScreenView); + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); await driver.openNewPage('chrome://extensions/'); diff --git a/test/e2e/nft/erc1155-interaction.spec.js b/test/e2e/nft/erc1155-interaction.spec.js index c4d83d875..c6cb2020c 100644 --- a/test/e2e/nft/erc1155-interaction.spec.js +++ b/test/e2e/nft/erc1155-interaction.spec.js @@ -66,7 +66,7 @@ describe('ERC1155 NFTs testdapp interaction', function () { await driver.switchToWindow(extension); await driver.clickElement('[data-testid="home__activity-tab"]'); const transactionItem = await driver.waitForSelector({ - css: '.list-item__title', + css: '[data-testid="activity-list-item-action"]', text: 'Deposit', }); assert.equal( @@ -120,7 +120,7 @@ describe('ERC1155 NFTs testdapp interaction', function () { await driver.switchToWindow(extension); await driver.clickElement('[data-testid="home__activity-tab"]'); const transactionItem = await driver.waitForSelector({ - css: '.list-item__title', + css: '[data-testid="activity-list-item-action"]', text: 'Deposit', }); assert.equal( diff --git a/test/e2e/nft/erc721-interaction.spec.js b/test/e2e/nft/erc721-interaction.spec.js index e886be2e9..d88f31f64 100644 --- a/test/e2e/nft/erc721-interaction.spec.js +++ b/test/e2e/nft/erc721-interaction.spec.js @@ -58,7 +58,7 @@ describe('ERC721 NFTs testdapp interaction', function () { await driver.switchToWindow(extension); await driver.clickElement('[data-testid="home__activity-tab"]'); const transactionItem = await driver.waitForSelector({ - css: '.list-item__title', + css: '[data-testid="activity-list-item-action"]', text: 'Deposit', }); assert.equal(await transactionItem.isDisplayed(), true); @@ -169,7 +169,7 @@ describe('ERC721 NFTs testdapp interaction', function () { await driver.switchToWindow(extension); await driver.clickElement('[data-testid="home__activity-tab"]'); const transactionItem = await driver.waitForSelector({ - css: '.list-item__title', + css: '[data-testid="activity-list-item-action"]', text: 'Deposit', }); assert.equal(await transactionItem.isDisplayed(), true); @@ -266,7 +266,7 @@ describe('ERC721 NFTs testdapp interaction', function () { await driver.switchToWindow(extension); await driver.clickElement('[data-testid="home__activity-tab"]'); await driver.waitForSelector( - '.transaction-list__completed-transactions .transaction-list-item:nth-of-type(1)', + '.transaction-list__completed-transactions .activity-list-item:nth-of-type(1)', ); // Verify transaction @@ -339,7 +339,7 @@ describe('ERC721 NFTs testdapp interaction', function () { // Verify transaction const completedTx = await driver.waitForSelector({ - css: '.list-item__title', + css: '[data-testid="activity-list-item-action"]', text: 'Approve TDN spending cap', }); assert.equal(await completedTx.isDisplayed(), true); @@ -405,12 +405,12 @@ describe('ERC721 NFTs testdapp interaction', function () { await driver.switchToWindow(extension); await driver.clickElement('[data-testid="home__activity-tab"]'); await driver.waitForSelector( - '.transaction-list__completed-transactions .transaction-list-item:nth-of-type(1)', + '.transaction-list__completed-transactions .activity-list-item:nth-of-type(1)', ); // Verify transaction const completedTx = await driver.waitForSelector({ - css: '.list-item__title', + css: '[data-testid="activity-list-item-action"]', text: 'Approve TDN with no spend limit', }); assert.equal(await completedTx.isDisplayed(), true); @@ -484,7 +484,7 @@ describe('ERC721 NFTs testdapp interaction', function () { // Verify transaction const completedTx = await driver.waitForSelector({ - css: '.list-item__title', + css: '[data-testid="activity-list-item-action"]', text: 'Approve TDN with no spend limit', }); assert.equal(await completedTx.isDisplayed(), true); diff --git a/test/e2e/nft/import-erc1155.spec.js b/test/e2e/nft/import-erc1155.spec.js index e27155e3c..516b82aba 100644 --- a/test/e2e/nft/import-erc1155.spec.js +++ b/test/e2e/nft/import-erc1155.spec.js @@ -38,9 +38,11 @@ describe('Import ERC1155 NFT', function () { await driver.clickElement({ text: 'Import NFT', tag: 'button' }); // Enter a valid NFT that belongs to user and check success message appears - await driver.fill('[data-testid="address"]', contractAddress); - await driver.fill('[data-testid="token-id"]', '1'); - await driver.clickElement({ text: 'Add', tag: 'button' }); + await driver.fill('#address', contractAddress); + await driver.fill('#token-id', '1'); + await driver.clickElement( + '[data-testid="import-nfts-modal-import-button"]', + ); const newNftNotification = await driver.findVisibleElement({ text: 'NFT was successfully added!', @@ -86,14 +88,15 @@ describe('Import ERC1155 NFT', function () { await driver.clickElement({ text: 'Import NFT', tag: 'button' }); // Enter an NFT that not belongs to user with a valid address and an invalid token id - await driver.fill('[data-testid="address"]', contractAddress); - await driver.fill('[data-testid="token-id"]', '4'); - await driver.clickElement({ text: 'Add', tag: 'button' }); - + await driver.fill('#address', contractAddress); + await driver.fill('#token-id', '4'); + await driver.clickElement( + '[data-testid="import-nfts-modal-import-button"]', + ); // Check error message appears const invalidNftNotification = await driver.findElement({ text: 'NFT can’t be added as the ownership details do not match. Make sure you have entered correct information.', - tag: 'h6', + tag: 'p', }); assert.equal(await invalidNftNotification.isDisplayed(), true); }, diff --git a/test/e2e/nft/import-nft.spec.js b/test/e2e/nft/import-nft.spec.js index 373edc70a..c0fc22876 100644 --- a/test/e2e/nft/import-nft.spec.js +++ b/test/e2e/nft/import-nft.spec.js @@ -38,9 +38,11 @@ describe('Import NFT', function () { await driver.clickElement({ text: 'Import NFT', tag: 'button' }); // Enter a valid NFT that belongs to user and check success message appears - await driver.fill('[data-testid="address"]', contractAddress); - await driver.fill('[data-testid="token-id"]', '1'); - await driver.clickElement({ text: 'Add', tag: 'button' }); + await driver.fill('#address', contractAddress); + await driver.fill('#token-id', '1'); + await driver.clickElement( + '[data-testid="import-nfts-modal-import-button"]', + ); const newNftNotification = await driver.findElement({ text: 'NFT was successfully added!', @@ -85,14 +87,16 @@ describe('Import NFT', function () { await driver.clickElement({ text: 'Import NFT', tag: 'button' }); // Enter an NFT that not belongs to user with a valid address and an invalid token id - await driver.fill('[data-testid="address"]', contractAddress); - await driver.fill('[data-testid="token-id"]', '2'); - await driver.clickElement({ text: 'Add', tag: 'button' }); + await driver.fill('#address', contractAddress); + await driver.fill('#token-id', '2'); + await driver.clickElement( + '[data-testid="import-nfts-modal-import-button"]', + ); // Check error message appears const invalidNftNotification = await driver.findElement({ text: 'NFT can’t be added as the ownership details do not match. Make sure you have entered correct information.', - tag: 'h6', + tag: 'p', }); assert.equal(await invalidNftNotification.isDisplayed(), true); }, diff --git a/test/e2e/nft/send-nft.spec.js b/test/e2e/nft/send-nft.spec.js index e08d12eb1..9e801ec70 100644 --- a/test/e2e/nft/send-nft.spec.js +++ b/test/e2e/nft/send-nft.spec.js @@ -40,9 +40,6 @@ describe('Send NFT', function () { await driver.clickElement({ text: 'Next', tag: 'button' }); // Edit the NFT, ensure same address, and move forward - await driver.isElementPresentAndVisible( - '[data-testid="confirm-page-back-edit-button"]', - ); await driver.clickElement( '[data-testid="confirm-page-back-edit-button"]', ); @@ -64,13 +61,13 @@ describe('Send NFT', function () { // When transaction complete, check the send NFT is displayed in activity tab await driver.wait(async () => { const confirmedTxes = await driver.findElements( - '.transaction-list__completed-transactions .transaction-list-item', + '.transaction-list__completed-transactions .activity-list-item', ); return confirmedTxes.length === 1; }, 10000); const sendNftItem = await driver.findElement({ - css: 'h2', + css: '[data-testid="activity-list-item-action"]', text: 'Send Test Dapp NFTs', }); assert.equal(await sendNftItem.isDisplayed(), true); diff --git a/test/e2e/snaps/enums.js b/test/e2e/snaps/enums.js index d19c74967..acf8f3298 100644 --- a/test/e2e/snaps/enums.js +++ b/test/e2e/snaps/enums.js @@ -1,5 +1,6 @@ module.exports = { - TEST_SNAPS_WEBSITE_URL: 'https://metamask.github.io/test-snaps/5.5.0/', + TEST_SNAPS_WEBSITE_URL: + 'https://metamask.github.io/snaps/test-snaps/0.37.3-flask.1/', TEST_SNAPS_SIMPLE_KEYRING_WEBSITE_URL: 'https://metamask.github.io/snap-simple-keyring/latest/', }; diff --git a/test/e2e/snaps/test-snap-bip-32.spec.js b/test/e2e/snaps/test-snap-bip-32.spec.js index 0cd744f2c..5b69c5766 100644 --- a/test/e2e/snaps/test-snap-bip-32.spec.js +++ b/test/e2e/snaps/test-snap-bip-32.spec.js @@ -31,10 +31,10 @@ describe('Test Snap bip-32', function () { await driver.delay(1000); // find and scroll to the bip32 test and connect - const snapButton1 = await driver.findElement('#connectBip32'); + const snapButton1 = await driver.findElement('#connectbip32'); await driver.scrollToElement(snapButton1); await driver.delay(1000); - await driver.clickElement('#connectBip32'); + await driver.clickElement('#connectbip32'); await driver.delay(1000); // switch to metamask extension and click connect @@ -84,7 +84,7 @@ describe('Test Snap bip-32', function () { // wait for npm installation success await driver.waitForSelector({ - css: '#connectBip32', + css: '#connectbip32', text: 'Reconnect to BIP-32 Snap', }); diff --git a/test/e2e/snaps/test-snap-bip-44.spec.js b/test/e2e/snaps/test-snap-bip-44.spec.js index 5df417861..48b2bbfc2 100644 --- a/test/e2e/snaps/test-snap-bip-44.spec.js +++ b/test/e2e/snaps/test-snap-bip-44.spec.js @@ -32,10 +32,10 @@ describe('Test Snap bip-44', function () { await driver.delay(1000); // find and scroll to the bip44 test and connect - const snapButton1 = await driver.findElement('#connectBip44Snap'); + const snapButton1 = await driver.findElement('#connectbip44'); await driver.scrollToElement(snapButton1); await driver.delay(1000); - await driver.clickElement('#connectBip44Snap'); + await driver.clickElement('#connectbip44'); await driver.delay(1000); // switch to metamask extension and click connect and approve @@ -53,6 +53,9 @@ describe('Test Snap bip-44', function () { tag: 'button', }); await driver.waitForSelector({ text: 'Install' }); + + await driver.clickElementSafe('[data-testid="snap-install-scroll"]'); + await driver.clickElement({ text: 'Install', tag: 'button', @@ -61,6 +64,7 @@ describe('Test Snap bip-44', function () { // deal with permissions popover await driver.delay(500); await driver.clickElement('#key-access-bip44-1-0'); + await driver.clickElement('#key-access-bip44-3-1'); await driver.clickElement({ text: 'Confirm', tag: 'button', @@ -76,7 +80,7 @@ describe('Test Snap bip-44', function () { // wait for npm installation success await driver.waitForSelector({ - css: '#connectBip44Snap', + css: '#connectbip44', text: 'Reconnect to BIP-44 Snap', }); diff --git a/test/e2e/snaps/test-snap-cronjob.spec.js b/test/e2e/snaps/test-snap-cronjob.spec.js index 7fb31e361..8495e953d 100644 --- a/test/e2e/snaps/test-snap-cronjob.spec.js +++ b/test/e2e/snaps/test-snap-cronjob.spec.js @@ -31,10 +31,10 @@ describe('Test Snap Cronjob', function () { // navigate to test snaps page and connect await driver.openNewPage(TEST_SNAPS_WEBSITE_URL); await driver.delay(1000); - const snapButton = await driver.findElement('#connectCronjobSnap'); + const snapButton = await driver.findElement('#connectcronjobs'); await driver.scrollToElement(snapButton); await driver.delay(1000); - await driver.clickElement('#connectCronjobSnap'); + await driver.clickElement('#connectcronjobs'); await driver.delay(1000); // switch to metamask extension and click connect @@ -71,8 +71,8 @@ describe('Test Snap Cronjob', function () { // wait for npm installation success await driver.waitForSelector({ - css: '#connectCronjobSnap', - text: 'Reconnect to Cronjob Snap', + css: '#connectcronjobs', + text: 'Reconnect to Cronjobs Snap', }); // switch to dialog popup, wait for a maximum of 65 seconds @@ -86,7 +86,10 @@ describe('Test Snap Cronjob', function () { // look for the dialog popup to verify cronjob fired const error = await driver.findElement('.snap-delineator__content'); const text = await error.getText(); - assert.equal(text.includes(`Cronjob\nfired`), true); + assert.equal( + text.includes(`Cronjob\nThis dialog was triggered by a cronjob.`), + true, + ); // try to click on the Ok button and pass test if it works await driver.clickElement({ diff --git a/test/e2e/snaps/test-snap-dialog.spec.js b/test/e2e/snaps/test-snap-dialog.spec.js index 28825c0e2..e675a9910 100644 --- a/test/e2e/snaps/test-snap-dialog.spec.js +++ b/test/e2e/snaps/test-snap-dialog.spec.js @@ -31,10 +31,10 @@ describe('Test Snap Dialog', function () { // navigate to test snaps page and connect to dialog snap await driver.openNewPage(TEST_SNAPS_WEBSITE_URL); await driver.delay(1000); - const dialogButton = await driver.findElement('#connectDialogSnap'); + const dialogButton = await driver.findElement('#connectdialogs'); await driver.scrollToElement(dialogButton); await driver.delay(1000); - await driver.clickElement('#connectDialogSnap'); + await driver.clickElement('#connectdialogs'); await driver.delay(1000); // switch to metamask extension and click connect @@ -71,8 +71,8 @@ describe('Test Snap Dialog', function () { // wait for npm installation success await driver.waitForSelector({ - css: '#connectDialogSnap', - text: 'Reconnect to Dialog Snap', + css: '#connectdialogs', + text: 'Reconnect to Dialogs Snap', }); // click on alert dialog @@ -91,7 +91,10 @@ describe('Test Snap Dialog', function () { let result = await driver.findElement('.snap-ui-renderer__panel'); await driver.scrollToElement(result); await driver.delay(500); - assert.equal(await result.getText(), 'Alert Dialog\nText here'); + assert.equal( + await result.getText(), + 'Alert Dialog\nThis is an alert dialog. It has a single button: "OK".', + ); // click ok button await driver.clickElement({ @@ -109,7 +112,7 @@ describe('Test Snap Dialog', function () { assert.equal(await result.getText(), 'null'); // click conf button - await driver.clickElement('#sendConfButton'); + await driver.clickElement('#sendConfirmationButton'); await driver.delay(500); // switch to dialog popup @@ -136,7 +139,7 @@ describe('Test Snap Dialog', function () { assert.equal(await result.getText(), 'false'); // click conf button again - await driver.clickElement('#sendConfButton'); + await driver.clickElement('#sendConfirmationButton'); await driver.delay(500); // switch to dialog popup diff --git a/test/e2e/snaps/test-snap-error.spec.js b/test/e2e/snaps/test-snap-error.spec.js index c8e17efdc..9c19cd723 100644 --- a/test/e2e/snaps/test-snap-error.spec.js +++ b/test/e2e/snaps/test-snap-error.spec.js @@ -31,10 +31,10 @@ describe('Test Snap Error', function () { // navigate to test snaps page and connect await driver.openNewPage(TEST_SNAPS_WEBSITE_URL); await driver.delay(1000); - const snapButton = await driver.findElement('#connectErrorSnap'); + const snapButton = await driver.findElement('#connecterrors'); await driver.scrollToElement(snapButton); await driver.delay(1000); - await driver.clickElement('#connectErrorSnap'); + await driver.clickElement('#connecterrors'); await driver.delay(1000); // switch to metamask extension and click connect @@ -72,8 +72,8 @@ describe('Test Snap Error', function () { // wait for npm installation success await driver.waitForSelector({ - css: '#connectErrorSnap', - text: 'Reconnect to Error Snap', + css: '#connecterrors', + text: 'Reconnect to Errors Snap', }); // find and click on send error @@ -90,7 +90,7 @@ describe('Test Snap Error', function () { const text = await error.getText(); assert.equal( text.includes( - "Snap Error: 'random error inside'. Error Code: '-32603'", + "Snap Error: 'Random error inside a promise.'. Error Code: '-32603'", ), true, ); diff --git a/test/e2e/snaps/test-snap-ethprovider.spec.js b/test/e2e/snaps/test-snap-ethprovider.spec.js index 694c25aef..0baa9e805 100644 --- a/test/e2e/snaps/test-snap-ethprovider.spec.js +++ b/test/e2e/snaps/test-snap-ethprovider.spec.js @@ -30,10 +30,12 @@ describe('Test Snap ethereum_provider', function () { // navigate to test snaps page and connect await driver.driver.get(TEST_SNAPS_WEBSITE_URL); await driver.delay(1000); - const snapButton = await driver.findElement('#connectEthproviderSnap'); + const snapButton = await driver.findElement( + '#connectethereum-provider', + ); await driver.scrollToElement(snapButton); await driver.delay(1000); - await driver.clickElement('#connectEthproviderSnap'); + await driver.clickElement('#connectethereum-provider'); await driver.delay(1000); // switch to metamask extension and click connect @@ -65,16 +67,16 @@ describe('Test Snap ethereum_provider', function () { tag: 'button', }); - // click send inputs on test snap page + // switch to test snap page await driver.switchToWindowWithTitle('Test Snaps', windowHandles); // wait for npm installation success await driver.waitForSelector({ - css: '#connectEthproviderSnap', - text: 'Reconnect to ethereum-provider Snap', + css: '#connectethereum-provider', + text: 'Reconnect to Ethereum Provider Snap', }); - // find and click on send test + // find and click on send get version const snapButton2 = await driver.findElement('#sendEthprovider'); await driver.scrollToElement(snapButton2); await driver.delay(500); @@ -83,7 +85,44 @@ describe('Test Snap ethereum_provider', function () { // check the results of the message signature using waitForSelector await driver.waitForSelector({ css: '#ethproviderResult', - text: 'true', + text: '"1337"', + }); + + // find and click on send get version + const snapButton3 = await driver.findElement( + '#sendEthproviderAccounts', + ); + await driver.scrollToElement(snapButton3); + await driver.delay(500); + await driver.clickElement('#sendEthproviderAccounts'); + + // switch to metamask window and click through confirmations + const windowHandles2 = await driver.waitUntilXWindowHandles( + 2, + 1000, + 10000, + ); + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles2, + ); + await driver.clickElement({ + text: 'Next', + tag: 'button', + }); + await driver.delay(500); + await driver.clickElement({ + text: 'Connect', + tag: 'button', + }); + + // switch to test snap page + await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + + // check the results of the message signature using waitForSelector + await driver.waitForSelector({ + css: '#ethproviderResult', + text: '"0x5cfe73b6021e818b776b421b1c4db2474086a7e1"', }); }, ); diff --git a/test/e2e/snaps/test-snap-getentropy.spec.js b/test/e2e/snaps/test-snap-getentropy.spec.js index 8b5586d24..de6ecc4dc 100644 --- a/test/e2e/snaps/test-snap-getentropy.spec.js +++ b/test/e2e/snaps/test-snap-getentropy.spec.js @@ -53,6 +53,8 @@ describe('Test Snap getEntropy', function () { await driver.waitForSelector({ text: 'Install' }); + await driver.clickElementSafe('[data-testid="snap-install-scroll"]'); + await driver.clickElement({ text: 'Install', tag: 'button', @@ -71,7 +73,7 @@ describe('Test Snap getEntropy', function () { // wait for npm installation success await driver.waitForSelector({ css: '#connectGetEntropySnap', - text: 'Reconnect to getEntropy Snap', + text: 'Reconnect to Get Entropy Snap', }); // find and click on send test @@ -100,7 +102,7 @@ describe('Test Snap getEntropy', function () { // check the results of the message signature using waitForSelector await driver.waitForSelector({ css: '#entropySignResult', - text: '"0xb9c20d675976e12c8bb53c3fd8fdff2dee11ad2b132eb453b5a8f35b0553c52d3bcac0fd3324d22ff0c53b3445ef48c119ba6435bc9bfb03234806719599aa6f6245593238c734bcf9d94d2873cacdd65a3176be3ae7e5b84f95fdd4487a395f"', + text: '"0x9341785782b512c86235612365f1076b16731ed9473beb4d0804c30b7fcc3a055aa7103b02dc64014d923220712dfbef023ddcf6327b313ea2dfd4d83dc5a53e1c5e7f4e10bce49830eded302294054df8a7a46e5b6cb3e50eec564ecba17941"', }); }, ); diff --git a/test/e2e/snaps/test-snap-installed.spec.js b/test/e2e/snaps/test-snap-installed.spec.js index 71614a6f0..f3ee0ba6e 100644 --- a/test/e2e/snaps/test-snap-installed.spec.js +++ b/test/e2e/snaps/test-snap-installed.spec.js @@ -30,10 +30,10 @@ describe('Test Snap Installed', function () { // navigate to test snaps page and connect await driver.openNewPage(TEST_SNAPS_WEBSITE_URL); await driver.delay(1000); - const confirmButton = await driver.findElement('#connectDialogSnap'); + const confirmButton = await driver.findElement('#connectdialogs'); await driver.scrollToElement(confirmButton); await driver.delay(500); - await driver.clickElement('#connectDialogSnap'); + await driver.clickElement('#connectdialogs'); await driver.delay(500); // switch to metamask extension and click connect @@ -70,14 +70,14 @@ describe('Test Snap Installed', function () { // wait for npm installation success await driver.waitForSelector({ - css: '#connectDialogSnap', - text: 'Reconnect to Dialog Snap', + css: '#connectdialogs', + text: 'Reconnect to Dialogs Snap', }); - const errorButton = await driver.findElement('#connectErrorSnap'); + const errorButton = await driver.findElement('#connecterrors'); await driver.scrollToElement(errorButton); await driver.delay(500); - await driver.clickElement('#connectErrorSnap'); + await driver.clickElement('#connecterrors'); // switch to metamask extension and click connect windowHandles = await driver.waitUntilXWindowHandles(3, 1000, 10000); @@ -109,7 +109,7 @@ describe('Test Snap Installed', function () { // wait for npm installation success await driver.waitForSelector({ css: '#installedSnapsResult', - text: 'npm:@metamask/test-snap-dialog, npm:@metamask/test-snap-error', + text: 'npm:@metamask/dialog-example-snap, npm:@metamask/error-example-snap', }); }, ); diff --git a/test/e2e/snaps/test-snap-manageAccount.spec.js b/test/e2e/snaps/test-snap-manageAccount.spec.js index 9ba5dce54..44ca13dbc 100644 --- a/test/e2e/snaps/test-snap-manageAccount.spec.js +++ b/test/e2e/snaps/test-snap-manageAccount.spec.js @@ -52,11 +52,7 @@ describe('Test Snap Account', function () { tag: 'button', }); - try { - await driver.clickElement('[data-testid="snap-install-scroll"]'); - } catch (_) { - console.log('Missing scroll'); - } + await driver.clickElementSafe('[data-testid="snap-install-scroll"]'); await driver.waitForSelector({ text: 'Install' }); diff --git a/test/e2e/snaps/test-snap-management.spec.js b/test/e2e/snaps/test-snap-management.spec.js index df520d30a..6af006bd9 100644 --- a/test/e2e/snaps/test-snap-management.spec.js +++ b/test/e2e/snaps/test-snap-management.spec.js @@ -33,10 +33,10 @@ describe('Test Snap Management', function () { await driver.delay(1000); // find and scroll to the correct card and click first - const snapButton = await driver.findElement('#connectNotification'); + const snapButton = await driver.findElement('#connectnotifications'); await driver.scrollToElement(snapButton); await driver.delay(1000); - await driver.clickElement('#connectNotification'); + await driver.clickElement('#connectnotifications'); await driver.delay(1000); // switch to metamask extension and click connect @@ -91,7 +91,7 @@ describe('Test Snap Management', function () { // try to disable the snap await driver.clickElement({ - text: 'Notification Test Snap', + text: 'Notifications Example Snap', tag: 'p', }); await driver.clickElement('.toggle-button > div'); @@ -138,7 +138,7 @@ describe('Test Snap Management', function () { // try to remove snap await driver.clickElement({ - text: 'Remove Notification Test Snap', + text: 'Remove Notifications Example Snap', tag: 'p', }); await driver.delay(1000); diff --git a/test/e2e/snaps/test-snap-managestate.spec.js b/test/e2e/snaps/test-snap-managestate.spec.js index 5bcc9bcbb..dbd4f0891 100644 --- a/test/e2e/snaps/test-snap-managestate.spec.js +++ b/test/e2e/snaps/test-snap-managestate.spec.js @@ -34,10 +34,10 @@ describe('Test Snap manageState', function () { await driver.delay(1000); // find and scroll to the connect button and click it - const snapButton1 = await driver.findElement('#connectManageState'); + const snapButton1 = await driver.findElement('#connectmanage-state'); await driver.scrollToElement(snapButton1); await driver.delay(1000); - await driver.clickElement('#connectManageState'); + await driver.clickElement('#connectmanage-state'); await driver.delay(1000); // switch to metamask extension and click connect @@ -74,7 +74,7 @@ describe('Test Snap manageState', function () { // wait for npm installation success await driver.waitForSelector({ - css: '#connectManageState', + css: '#connectmanage-state', text: 'Reconnect to Manage State Snap', }); @@ -101,7 +101,7 @@ describe('Test Snap manageState', function () { ); assert.equal( await retrieveManageStateResult.getText(), - '{ "testState": [ "23" ] }', + '{ "items": [ "23" ] }', ); // click clear results @@ -121,7 +121,7 @@ describe('Test Snap manageState', function () { ); assert.equal( await retrieveManageStateResult2.getText(), - '{ "testState": [] }', + '{ "items": [] }', ); }, ); diff --git a/test/e2e/snaps/test-snap-networkaccess.spec.js b/test/e2e/snaps/test-snap-networkaccess.spec.js index e80012a55..0a6538680 100644 --- a/test/e2e/snaps/test-snap-networkaccess.spec.js +++ b/test/e2e/snaps/test-snap-networkaccess.spec.js @@ -1,4 +1,3 @@ -const { strict: assert } = require('assert'); const { withFixtures } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); const { TEST_SNAPS_WEBSITE_URL } = require('./enums'); @@ -31,16 +30,14 @@ describe('Test Snap networkAccess', function () { // navigate to test snaps page and connect to dialog snap await driver.openNewPage(TEST_SNAPS_WEBSITE_URL); await driver.delay(1000); - const dialogButton = await driver.findElement( - '#connectNetworkAccessSnap', - ); + const dialogButton = await driver.findElement('#connectnetwork-access'); await driver.scrollToElement(dialogButton); await driver.delay(1000); - await driver.clickElement('#connectNetworkAccessSnap'); + await driver.clickElement('#connectnetwork-access'); await driver.delay(1000); // switch to metamask extension and click connect - let windowHandles = await driver.waitUntilXWindowHandles( + const windowHandles = await driver.waitUntilXWindowHandles( 3, 1000, 10000, @@ -73,32 +70,18 @@ describe('Test Snap networkAccess', function () { // wait for npm installation success await driver.waitForSelector({ - css: '#connectNetworkAccessSnap', - text: 'Reconnect to networkAccess Snap', + css: '#connectnetwork-access', + text: 'Reconnect to Network Access Snap', }); // click on alert dialog await driver.clickElement('#sendNetworkAccessTest'); await driver.delay(500); - // switch to dialog popup - windowHandles = await driver.waitUntilXWindowHandles(3, 1000, 10000); - await driver.switchToWindowWithTitle( - 'MetaMask Notification', - windowHandles, - ); - await driver.delay(500); - - // check dialog contents - const result = await driver.findElement('.snap-ui-renderer__panel'); - await driver.scrollToElement(result); - await driver.delay(500); - assert.equal(await result.getText(), 'FETCHED_SUCCESSFULLY'); - - // click ok button - await driver.clickElement({ - text: 'OK', - tag: 'button', + // check for result correctness + await driver.waitForSelector({ + css: '#networkAccessResult', + text: '"hello": "world"', }); }, ); diff --git a/test/e2e/snaps/test-snap-notification.spec.js b/test/e2e/snaps/test-snap-notification.spec.js index d53fe06b9..64587b9e7 100644 --- a/test/e2e/snaps/test-snap-notification.spec.js +++ b/test/e2e/snaps/test-snap-notification.spec.js @@ -33,10 +33,10 @@ describe('Test Snap Notification', function () { await driver.delay(1000); // find and scroll down to snapId5 and connect - const snapButton = await driver.findElement('#connectNotification'); + const snapButton = await driver.findElement('#connectnotifications'); await driver.scrollToElement(snapButton); await driver.delay(1000); - await driver.clickElement('#connectNotification'); + await driver.clickElement('#connectnotifications'); await driver.delay(1000); // switch to metamask extension and click connect @@ -74,8 +74,8 @@ describe('Test Snap Notification', function () { // wait for npm installation success await driver.waitForSelector({ - css: '#connectNotification', - text: 'Reconnect to Notification Snap', + css: '#connectnotifications', + text: 'Reconnect to Notifications Snap', }); await driver.clickElement('#sendInAppNotification'); @@ -113,7 +113,7 @@ describe('Test Snap Notification', function () { ); assert.equal( await notificationResultMessage.getText(), - 'TEST INAPP NOTIFICATION', + 'Hello from within MetaMask!', ); }, ); diff --git a/test/e2e/snaps/test-snap-rpc.spec.js b/test/e2e/snaps/test-snap-rpc.spec.js index 5fe574490..2c955e9e7 100644 --- a/test/e2e/snaps/test-snap-rpc.spec.js +++ b/test/e2e/snaps/test-snap-rpc.spec.js @@ -32,10 +32,10 @@ describe('Test Snap RPC', function () { await driver.delay(1000); // find and scroll to the bip32 test and connect - const snapButton1 = await driver.findElement('#connectBip32'); + const snapButton1 = await driver.findElement('#connectbip32'); await driver.scrollToElement(snapButton1); await driver.delay(1000); - await driver.clickElement('#connectBip32'); + await driver.clickElement('#connectbip32'); await driver.delay(1000); // switch to metamask extension and click connect @@ -84,10 +84,10 @@ describe('Test Snap RPC', function () { // switch back to test-snaps window await driver.switchToWindowWithTitle('Test Snaps', windowHandles); - const snapButton2 = await driver.findElement('#connectRpcSnap'); + const snapButton2 = await driver.findElement('#connectjson-rpc'); await driver.scrollToElement(snapButton2); await driver.delay(1000); - await driver.clickElement('#connectRpcSnap'); + await driver.clickElement('#connectjson-rpc'); await driver.delay(1000); windowHandles = await driver.waitUntilXWindowHandles(2, 1000, 10000); @@ -118,8 +118,8 @@ describe('Test Snap RPC', function () { // wait for npm installation success await driver.waitForSelector({ - css: '#connectRpcSnap', - text: 'Reconnect to RPC Snap', + css: '#connectjson-rpc', + text: 'Reconnect to JSON-RPC Snap', }); // click send inputs on test snap page diff --git a/test/e2e/snaps/test-snap-txinsights.spec.js b/test/e2e/snaps/test-snap-txinsights.spec.js index cb8bfc3b1..4130abb50 100644 --- a/test/e2e/snaps/test-snap-txinsights.spec.js +++ b/test/e2e/snaps/test-snap-txinsights.spec.js @@ -32,10 +32,12 @@ describe('Test Snap TxInsights', function () { await driver.delay(1000); // find and scroll to the bip32 test and connect - const snapButton1 = await driver.findElement('#connectInsightsSnap'); + const snapButton1 = await driver.findElement( + '#connecttransaction-insights', + ); await driver.scrollToElement(snapButton1); await driver.delay(1000); - await driver.clickElement('#connectInsightsSnap'); + await driver.clickElement('#connecttransaction-insights'); await driver.delay(1000); // switch to metamask extension and click connect @@ -100,18 +102,16 @@ describe('Test Snap TxInsights', function () { 'MetaMask Notification', windowHandles, ); - await driver.delay(1000); - await driver.clickElement({ - text: 'TxInsightsTest', - tag: 'button', - }); // check that txinsightstest tab contains the right info await driver.delay(1000); const txInsightsResult = await driver.findElement( '.snap-ui-renderer__content', ); - assert.equal(await txInsightsResult.getText(), 'Test: Successful'); + assert.equal( + await txInsightsResult.getText(), + 'Transaction type:\nERC-20', + ); }, ); }); diff --git a/test/e2e/snaps/test-snap-update.spec.js b/test/e2e/snaps/test-snap-update.spec.js index 485c87b66..ea8dcbc11 100644 --- a/test/e2e/snaps/test-snap-update.spec.js +++ b/test/e2e/snaps/test-snap-update.spec.js @@ -127,7 +127,7 @@ describe('Test Snap update', function () { // look for the correct version text await driver.waitForSelector({ css: '#updateSnapVersion', - text: '"5.1.2"', + text: '"0.35.2-flask.1"', }); }, ); diff --git a/test/e2e/snaps/test-snap-wasm.spec.js b/test/e2e/snaps/test-snap-wasm.spec.js index 1af49492f..f0e301ca5 100644 --- a/test/e2e/snaps/test-snap-wasm.spec.js +++ b/test/e2e/snaps/test-snap-wasm.spec.js @@ -30,10 +30,10 @@ describe('Test Snap WASM', function () { // navigate to test snaps page and connect await driver.openNewPage(TEST_SNAPS_WEBSITE_URL); await driver.delay(1000); - const snapButton = await driver.findElement('#connectWasmSnap'); + const snapButton = await driver.findElement('#connectwasm'); await driver.scrollToElement(snapButton); await driver.delay(1000); - await driver.clickElement('#connectWasmSnap'); + await driver.clickElement('#connectwasm'); await driver.delay(1000); // switch to metamask extension and click connect @@ -71,7 +71,7 @@ describe('Test Snap WASM', function () { // wait for npm installation success await driver.waitForSelector({ - css: '#connectWasmSnap', + css: '#connectwasm', text: 'Reconnect to WebAssembly Snap', }); diff --git a/test/e2e/swaps/shared.js b/test/e2e/swaps/shared.js index 12fbe4ccb..f8f149385 100644 --- a/test/e2e/swaps/shared.js +++ b/test/e2e/swaps/shared.js @@ -122,10 +122,10 @@ const waitForTransactionToComplete = async (driver, options) => { const checkActivityTransaction = async (driver, options) => { await driver.clickElement('[data-testid="home__activity-tab"]'); - await driver.waitForSelector('[data-testid="list-item-title"]'); + await driver.waitForSelector('.activity-list-item'); const transactionList = await driver.findElements( - '[data-testid="list-item-title"]', + '[data-testid="activity-list-item-action"]', ); const transactionText = await transactionList[options.index].getText(); assert.equal( @@ -135,7 +135,7 @@ const checkActivityTransaction = async (driver, options) => { ); await driver.findElement({ - css: '[data-testid="list-item-right-content"]', + css: '[data-testid="transaction-list-item-primary-currency"]', text: `-${options.amount} ${options.swapFrom}`, }); @@ -143,8 +143,8 @@ const checkActivityTransaction = async (driver, options) => { await driver.delay(regularDelayMs); await driver.findElement({ - css: '[data-testid="transaction-list-item-details-tx-status"]', - text: `Confirmed`, + css: '.transaction-status-label', + text: 'Confirmed', }); await driver.findElement({ @@ -173,9 +173,7 @@ const checkNotification = async (driver, options) => { }; const changeExchangeRate = async (driver) => { - await driver.clickElement( - '[data-testid="exchange-rate-display-base-symbol"]', - ); + await driver.clickElement('[data-testid="review-quote-view-all-quotes"]'); await driver.waitForSelector({ text: 'Quote details', tag: 'h2' }); const networkFees = await driver.findElements( diff --git a/test/e2e/swaps/swaps-notifications.spec.js b/test/e2e/swaps/swaps-notifications.spec.js index 4d24bf5fe..25c0595b8 100644 --- a/test/e2e/swaps/swaps-notifications.spec.js +++ b/test/e2e/swaps/swaps-notifications.spec.js @@ -141,7 +141,7 @@ describe('Swaps - notifications', function () { swapToContractAddress: '0x72c9Fb7ED19D3ce51cea5C56B3e023cd918baaDf', }); await driver.clickElement( - '[data-testid="page-container__import-button"]', + '[data-testid="import-tokens-import-button"]', ); await checkNotification(driver, { title: 'Token added manually', diff --git a/test/e2e/tests/account-details.spec.js b/test/e2e/tests/account-details.spec.js index 9e70e6ee5..728271365 100644 --- a/test/e2e/tests/account-details.spec.js +++ b/test/e2e/tests/account-details.spec.js @@ -12,6 +12,34 @@ describe('Show account details', function () { }, ], }; + + const PASSWORD = 'correct horse battery staple'; + + async function revealPrivateKey(driver, useAccountMenu = true) { + if (useAccountMenu) { + await driver.clickElement('[data-testid="account-menu-icon"]'); + await driver.clickElement( + '[data-testid="account-list-item-menu-button"]', + ); + await driver.clickElement('[data-testid="account-list-menu-details"]'); + } else { + // Global Menu + await driver.clickElement('[data-testid="account-options-menu-button"]'); + await driver.clickElement('[data-testid="account-list-menu-details"]'); + } + + await driver.clickElement({ css: 'button', text: 'Show private key' }); + + await driver.fill('#account-details-authenticate', PASSWORD); + await driver.press('#account-details-authenticate', driver.Key.ENTER); + + const keyContainer = await driver.findElement( + '[data-testid="account-details-key"]', + ); + const key = await keyContainer.getText(); + return key; + } + it('should show the QR code for the account', async function () { await withFixtures( { @@ -21,7 +49,7 @@ describe('Show account details', function () { }, async ({ driver }) => { await driver.navigate(); - await driver.fill('#password', 'correct horse battery staple'); + await driver.fill('#password', PASSWORD); await driver.press('#password', driver.Key.ENTER); await driver.clickElement('[data-testid="account-menu-icon"]'); @@ -35,4 +63,104 @@ describe('Show account details', function () { }, ); }); + + it('should show the correct private key from account menu', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + await driver.fill('#password', PASSWORD); + await driver.press('#password', driver.Key.ENTER); + + const key = await revealPrivateKey(driver); + assert.equal( + key, + '7c9529a67102755b7e6102d6d950ac5d5863c98713805cec576b945b15b71eac', + ); + }, + ); + }); + + it('should show the correct private key for an unselected account from account menu', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + await driver.fill('#password', PASSWORD); + await driver.press('#password', driver.Key.ENTER); + + // Create and focus on different account + await driver.clickElement('[data-testid="account-menu-icon"]'); + await driver.clickElement( + '[data-testid="multichain-account-menu-popover-add-account"]', + ); + await driver.fill('[placeholder="Account 2"]', '2nd account'); + await driver.clickElement({ text: 'Create', tag: 'button' }); + + const key = await revealPrivateKey(driver); + assert.equal( + key, + '7c9529a67102755b7e6102d6d950ac5d5863c98713805cec576b945b15b71eac', + ); + }, + ); + }); + + it('should show the correct private key from global menu', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + await driver.fill('#password', PASSWORD); + await driver.press('#password', driver.Key.ENTER); + + const key = await revealPrivateKey(driver, false); + assert.equal( + key, + '7c9529a67102755b7e6102d6d950ac5d5863c98713805cec576b945b15b71eac', + ); + }, + ); + }); + + it('should show the correct private key for a second account from global menu', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + await driver.fill('#password', PASSWORD); + await driver.press('#password', driver.Key.ENTER); + + // Create and focus on different account + await driver.clickElement('[data-testid="account-menu-icon"]'); + await driver.clickElement( + '[data-testid="multichain-account-menu-popover-add-account"]', + ); + await driver.fill('[placeholder="Account 2"]', '2nd account'); + await driver.clickElement({ text: 'Create', tag: 'button' }); + + const key = await revealPrivateKey(driver, false); + assert.equal( + key, + 'f444f52ea41e3a39586d7069cb8e8233e9f6b9dea9cbb700cce69ae860661cc8', + ); + }, + ); + }); }); diff --git a/test/e2e/tests/add-custom-network.spec.js b/test/e2e/tests/add-custom-network.spec.js index efea4d1d2..d094324ea 100644 --- a/test/e2e/tests/add-custom-network.spec.js +++ b/test/e2e/tests/add-custom-network.spec.js @@ -363,7 +363,7 @@ describe('Custom network', function () { const arbitrumNetwork = await driver.findElements({ text: 'Arbitrum One', - tag: 'span', + tag: 'button', }); assert.ok(arbitrumNetwork.length, 1); }, diff --git a/test/e2e/tests/address-book.spec.js b/test/e2e/tests/address-book.spec.js index 19f526fa2..d88ea9e20 100644 --- a/test/e2e/tests/address-book.spec.js +++ b/test/e2e/tests/address-book.spec.js @@ -62,13 +62,13 @@ describe('Address Book', function () { await driver.clickElement('[data-testid="home__activity-tab"]'); await driver.wait(async () => { const confirmedTxes = await driver.findElements( - '.transaction-list__completed-transactions .transaction-list-item', + '.transaction-list__completed-transactions .activity-list-item', ); return confirmedTxes.length === 1; }, 10000); await driver.waitForSelector({ - css: '.transaction-list-item__primary-currency', + css: '[data-testid="transaction-list-item-primary-currency"]', text: '-2 ETH', }); }, diff --git a/test/e2e/tests/backup-restore.spec.js b/test/e2e/tests/backup-restore.spec.js index d52cf1fa6..dfba955c6 100644 --- a/test/e2e/tests/backup-restore.spec.js +++ b/test/e2e/tests/backup-restore.spec.js @@ -56,6 +56,10 @@ describe('Backup and Restore', function () { ], }; it('should backup the account settings', async function () { + if (process.env.SELENIUM_BROWSER === 'chrome') { + // Chrome shows OS level download prompt which can't be dismissed by Selenium + this.skip(); + } await withFixtures( { fixtures: new FixtureBuilder().build(), @@ -97,6 +101,10 @@ describe('Backup and Restore', function () { }); it('should restore the account settings', async function () { + if (process.env.SELENIUM_BROWSER === 'chrome') { + // Chrome shows OS level download prompt which can't be dismissed by Selenium + this.skip(); + } await withFixtures( { fixtures: new FixtureBuilder().build(), diff --git a/test/e2e/tests/chain-interactions.spec.js b/test/e2e/tests/chain-interactions.spec.js index 3135ab168..efb83f35e 100644 --- a/test/e2e/tests/chain-interactions.spec.js +++ b/test/e2e/tests/chain-interactions.spec.js @@ -63,7 +63,7 @@ describe('Chain Interactions', function () { await driver.clickElement('[data-testid="network-display"]'); const ganacheChain = await driver.findElements({ text: `Localhost ${port}`, - tag: 'span', + tag: 'button', }); assert.ok(ganacheChain.length, 1); }, diff --git a/test/e2e/tests/clear-activity.spec.js b/test/e2e/tests/clear-activity.spec.js index c6767271c..96f6bc358 100644 --- a/test/e2e/tests/clear-activity.spec.js +++ b/test/e2e/tests/clear-activity.spec.js @@ -35,11 +35,11 @@ describe('Clear account activity', function () { // Check send transaction and receive transaction history are all displayed await driver.clickElement('[data-testid="home__activity-tab"]'); await driver.waitForSelector({ - css: '.list-item__title', + css: '[data-testid="activity-list-item-action"]', text: 'Send', }); await driver.waitForSelector({ - css: '.list-item__title', + css: '[data-testid="activity-list-item-action"]', text: 'Receive', }); @@ -58,11 +58,11 @@ describe('Clear account activity', function () { // Check send transaction history is cleared and receive transaction history is kept const sendTransaction = await driver.isElementPresent({ - css: '.list-item__title', + css: '[data-testid="activity-list-item-action"]', text: 'Send', }); const receiveTransaction = await driver.isElementPresent({ - css: '.list-item__title', + css: '[data-testid="activity-list-item-action"]', text: 'Receive', }); assert.equal(sendTransaction, false); diff --git a/test/e2e/tests/contract-interactions.spec.js b/test/e2e/tests/contract-interactions.spec.js index c5c0e6600..4a98d9d48 100644 --- a/test/e2e/tests/contract-interactions.spec.js +++ b/test/e2e/tests/contract-interactions.spec.js @@ -65,10 +65,10 @@ describe('Deploy contract and call contract methods', function () { ); await driver.clickElement({ text: 'Activity', tag: 'button' }); await driver.waitForSelector( - '.transaction-list__completed-transactions .transaction-list-item:nth-of-type(1)', + '.transaction-list__completed-transactions .activity-list-item:nth-of-type(1)', ); await driver.waitForSelector({ - css: '.transaction-list-item__primary-currency', + css: '[data-testid="transaction-list-item-primary-currency"]', text: '-4 ETH', }); @@ -84,10 +84,10 @@ describe('Deploy contract and call contract methods', function () { WINDOW_TITLES.ExtensionInFullScreenView, ); await driver.waitForSelector( - '.transaction-list__completed-transactions .transaction-list-item:nth-of-type(2)', + '.transaction-list__completed-transactions .activity-list-item:nth-of-type(2)', ); await driver.waitForSelector({ - css: '.transaction-list-item__primary-currency', + css: '[data-testid="transaction-list-item-primary-currency"]', text: '-0 ETH', }); diff --git a/test/e2e/tests/custom-rpc-history.spec.js b/test/e2e/tests/custom-rpc-history.spec.js index 8b43ab712..46bde39df 100644 --- a/test/e2e/tests/custom-rpc-history.spec.js +++ b/test/e2e/tests/custom-rpc-history.spec.js @@ -185,7 +185,7 @@ describe('Stores custom RPC history', function () { await driver.waitForElementNotPresent('.loading-overlay'); await driver.clickElement('[data-testid="network-display"]'); - await driver.clickElement({ text: 'Ethereum Mainnet', tag: 'span' }); + await driver.clickElement({ text: 'Ethereum Mainnet', tag: 'button' }); }, ); }); @@ -196,19 +196,21 @@ describe('Stores custom RPC history', function () { fixtures: new FixtureBuilder() .withNetworkController({ networkConfigurations: { - networkConfigurationId: { + networkConfigurationIdOne: { rpcUrl: 'http://127.0.0.1:8545/1', chainId: '0x539', ticker: 'ETH', nickname: 'http://127.0.0.1:8545/1', rpcPrefs: {}, + type: 'rpc', }, - networkConfigurationId2: { + networkConfigurationIdTwo: { rpcUrl: 'http://127.0.0.1:8545/2', chainId: '0x539', ticker: 'ETH', nickname: 'http://127.0.0.1:8545/2', rpcPrefs: {}, + type: 'rpc', }, }, }) @@ -235,7 +237,7 @@ describe('Stores custom RPC history', function () { }); // click Mainnet to dismiss network dropdown - await driver.clickElement({ text: 'Ethereum Mainnet', tag: 'span' }); + await driver.clickElement({ text: 'Ethereum Mainnet', tag: 'button' }); assert.equal(customRpcs.length, 2); }, @@ -248,14 +250,14 @@ describe('Stores custom RPC history', function () { fixtures: new FixtureBuilder() .withNetworkController({ networkConfigurations: { - networkConfigurationId: { + networkConfigurationIdOne: { rpcUrl: 'http://127.0.0.1:8545/1', chainId: '0x539', ticker: 'ETH', nickname: 'http://127.0.0.1:8545/1', rpcPrefs: {}, }, - networkConfigurationId2: { + networkConfigurationIdTwo: { rpcUrl: 'http://127.0.0.1:8545/2', chainId: '0x539', ticker: 'ETH', diff --git a/test/e2e/tests/custom-token-add-approve.spec.js b/test/e2e/tests/custom-token-add-approve.spec.js index 57d2a3d6a..f694cd564 100644 --- a/test/e2e/tests/custom-token-add-approve.spec.js +++ b/test/e2e/tests/custom-token-add-approve.spec.js @@ -159,7 +159,7 @@ describe('Create token, approve token and approve token without gas', function ( const defaultSpendingCap = await driver.findElement({ text: '7 TST', - css: '.box--flex-direction-row > h6', + css: '.mm-box > h6', }); assert.equal( @@ -178,15 +178,13 @@ describe('Create token, approve token and approve token without gas', function ( // check list of pending transactions in extension await driver.wait(async () => { - const pendingTxes = await driver.findElements( - '.transaction-list-item', - ); + const pendingTxes = await driver.findElements('.activity-list-item'); return pendingTxes.length === 1; }, 10000); const approveTokenTask = await driver.waitForSelector({ // Selects only the very first transaction list item immediately following the 'Pending' header - css: '.transaction-list__completed-transactions .transaction-list-item:first-child .list-item__heading', + css: '.transaction-list__completed-transactions .activity-list-item [data-testid="activity-list-item-action"]', text: 'Approve TST spending cap', }); assert.equal( @@ -251,7 +249,7 @@ describe('Create token, approve token and approve token without gas', function ( let spendingCap = await driver.findElement({ text: '5 TST', - css: '.box--flex-direction-row > h6', + css: '.mm-box > h6', }); assert.equal( @@ -307,7 +305,7 @@ describe('Create token, approve token and approve token without gas', function ( spendingCap = await driver.findElement({ text: '9 TST', - css: '.box--flex-direction-row > h6', + css: '.mm-box > h6', }); assert.equal( await spendingCap.getText(), @@ -323,14 +321,12 @@ describe('Create token, approve token and approve token without gas', function ( await driver.clickElement({ tag: 'button', text: 'Activity' }); await driver.wait(async () => { - const pendingTxes = await driver.findElements( - '.transaction-list-item', - ); + const pendingTxes = await driver.findElements('.activity-list-item'); return pendingTxes.length === 1; }, 10000); const approveTokenTask = await driver.waitForSelector({ // Select only the heading of the first entry in the transaction list. - css: '.transaction-list__completed-transactions .transaction-list-item:first-child .list-item__heading', + css: '.transaction-list__completed-transactions .activity-list-item [data-testid="activity-list-item-action"]', text: 'Approve TST spending cap', }); assert.equal( @@ -374,7 +370,7 @@ describe('Create token, approve token and approve token without gas', function ( await driver.clickElement({ tag: 'button', text: 'Activity' }); const pendingTxes = await driver.findElements( - '.transaction-list__pending-transactions .transaction-list-item', + '.transaction-list__pending-transactions .activity-list-item', ); pendingTxes[0].click(); @@ -397,7 +393,7 @@ describe('Create token, approve token and approve token without gas', function ( const maxSpendingCap = await driver.findElement({ text: '10 TST', - css: '.box--flex-direction-row > h6', + css: '.mm-box > h6', }); assert.equal( @@ -414,7 +410,7 @@ describe('Create token, approve token and approve token without gas', function ( const approveTokenTask = await driver.waitForSelector({ // Select only the heading of the first entry in the transaction list. - css: '.transaction-list__completed-transactions .transaction-list-item:first-child .list-item__heading', + css: '.transaction-list__completed-transactions .activity-list-item [data-testid="activity-list-item-action"]', text: 'Approve TST spending cap', }); assert.equal( @@ -459,7 +455,7 @@ describe('Create token, approve token and approve token without gas', function ( await driver.switchToWindow(extension); await driver.clickElement({ tag: 'button', text: 'Activity' }); - const pendingTxes = await driver.findElements('.transaction-list-item'); + const pendingTxes = await driver.findElements('.activity-list-item'); pendingTxes[0].click(); // set custom spending cap @@ -483,7 +479,7 @@ describe('Create token, approve token and approve token without gas', function ( // check transaction in Activity tab const approveTokenTask = await driver.waitForSelector({ - css: '.transaction-list__completed-transactions .transaction-list-item:first-child .list-item__heading', + css: '.transaction-list__completed-transactions .activity-list-item [data-testid="activity-list-item-action"]', text: 'Approve TST spending cap', }); assert.equal( diff --git a/test/e2e/tests/dapp-interactions.spec.js b/test/e2e/tests/dapp-interactions.spec.js index dae045ef0..4fb9a99a2 100644 --- a/test/e2e/tests/dapp-interactions.spec.js +++ b/test/e2e/tests/dapp-interactions.spec.js @@ -5,13 +5,12 @@ const { openDapp, DAPP_URL, DAPP_ONE_URL, + unlockWallet, + WINDOW_TITLES, } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); describe('Dapp interactions', function () { - let windowHandles; - let extension; - let popup; const ganacheOptions = { accounts: [ { @@ -34,30 +33,13 @@ describe('Dapp interactions', function () { }, async ({ driver }) => { await driver.navigate(); - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); - await openDapp(driver); - windowHandles = await driver.getAllWindowHandles(); - extension = windowHandles[0]; - - // Lock Account - await driver.switchToWindow(extension); - await driver.clickElement( - '[data-testid="account-options-menu-button"]', - ); - await driver.clickElement({ text: 'Lock', tag: 'div' }); // Trigger Notification - await driver.switchToWindowWithTitle('E2E Test Dapp', windowHandles); await driver.clickElement('#addEthereumChain'); await driver.waitUntilXWindowHandles(3); - await driver.switchToWindowWithTitle( - 'MetaMask Notification', - windowHandles, - ); - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); + await driver.switchToWindowWithTitle('MetaMask Notification'); + await unlockWallet(driver); const notification = await driver.isElementPresent({ text: 'Allow this site to add a network?', tag: 'h3', @@ -81,45 +63,34 @@ describe('Dapp interactions', function () { }, async ({ driver }) => { await driver.navigate(); - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); - await openDapp(driver); - windowHandles = await driver.getAllWindowHandles(); - extension = windowHandles[0]; - - // Lock Account - await driver.switchToWindow(extension); - await driver.clickElement( - '[data-testid="account-options-menu-button"]', - ); - await driver.clickElement({ text: 'Lock', tag: 'div' }); - - // Connect to Dapp1 + // Connect to 2nd dapp => DAPP_ONE await openDapp(driver, null, DAPP_ONE_URL); await driver.clickElement({ text: 'Connect', tag: 'button' }); - await driver.waitUntilXWindowHandles(4); - windowHandles = await driver.getAllWindowHandles(); + await driver.waitUntilXWindowHandles(3); - popup = await driver.switchToWindowWithTitle( - 'MetaMask Notification', - windowHandles, - ); + await driver.switchToWindowWithTitle(WINDOW_TITLES.Notification); - await driver.switchToWindow(popup); - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); + await unlockWallet(driver); await driver.clickElement({ text: 'Next', tag: 'button' }); await driver.clickElement({ text: 'Connect', tag: 'button' }); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + await driver.waitForSelector({ + css: '#accounts', + text: '0x5cfe73b6021e818b776b421b1c4db2474086a7e1', + }); // Assert Connection - await driver.switchToWindow(extension); - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); + await unlockWallet(driver); await driver.clickElement( '[data-testid ="account-options-menu-button"]', ); + await driver.clickElement({ text: 'Connected sites', tag: 'div' }); + const connectedDapp1 = await driver.isElementPresent({ text: DAPP_URL, tag: 'bdi', diff --git a/test/e2e/tests/edit-gas-fee.spec.js b/test/e2e/tests/edit-gas-fee.spec.js index b304ba2f6..965ffaec7 100644 --- a/test/e2e/tests/edit-gas-fee.spec.js +++ b/test/e2e/tests/edit-gas-fee.spec.js @@ -80,13 +80,13 @@ describe('Editing Confirm Transaction', function () { await driver.clickElement('[data-testid="home__activity-tab"]'); await driver.wait(async () => { const confirmedTxes = await driver.findElements( - '.transaction-list__completed-transactions .transaction-list-item', + '.transaction-list__completed-transactions .activity-list-item', ); return confirmedTxes.length === 1; }, 10000); const txValues = await driver.findElements( - '.transaction-list-item__primary-currency', + '[data-testid="transaction-list-item-primary-currency"]', ); assert.equal(txValues.length, 1); assert.ok(/-1\s*ETH/u.test(await txValues[0].getText())); @@ -165,13 +165,13 @@ describe('Editing Confirm Transaction', function () { await driver.clickElement('[data-testid="home__activity-tab"]'); await driver.wait(async () => { const confirmedTxes = await driver.findElements( - '.transaction-list__completed-transactions .transaction-list-item', + '.transaction-list__completed-transactions .activity-list-item', ); return confirmedTxes.length === 1; }, 10000); const txValues = await driver.findElements( - '.transaction-list-item__primary-currency', + '[data-testid="transaction-list-item-primary-currency"]', ); assert.equal(txValues.length, 1); assert.ok(/-1\s*ETH/u.test(await txValues[0].getText())); @@ -254,13 +254,13 @@ describe('Editing Confirm Transaction', function () { await driver.clickElement('[data-testid="home__activity-tab"]'); await driver.wait(async () => { const confirmedTxes = await driver.findElements( - '.transaction-list__completed-transactions .transaction-list-item', + '.transaction-list__completed-transactions .activity-list-item', ); return confirmedTxes.length === 1; }, 10000); const txValues = await driver.findElements( - '.transaction-list-item__primary-currency', + '[data-testid="transaction-list-item-primary-currency"]', ); assert.equal(txValues.length, 1); assert.ok(/-0\s*ETH/u.test(await txValues[0].getText())); diff --git a/test/e2e/tests/errors.spec.js b/test/e2e/tests/errors.spec.js index 194578558..6285ac3b6 100644 --- a/test/e2e/tests/errors.spec.js +++ b/test/e2e/tests/errors.spec.js @@ -23,6 +23,36 @@ describe('Sentry errors', function () { }, ], }; + it('should NOT send error events when participateInMetaMetrics is false', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder() + .withMetaMetricsController({ + metaMetricsId: null, + participateInMetaMetrics: false, + }) + .build(), + ganacheOptions, + title: this.test.title, + failOnConsoleError: false, + testSpecificMock: mockSentry, + }, + async ({ driver, mockedEndpoint }) => { + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + // Trigger error + driver.executeScript('window.stateHooks.throwTestError()'); + driver.delay(3000); + // Wait for Sentry request + const isPending = await mockedEndpoint.isPending(); + assert.ok( + isPending, + 'A request to sentry was sent when it should not have been', + ); + }, + ); + }); it('should send error events', async function () { await withFixtures( { diff --git a/test/e2e/tests/eth-sign.spec.js b/test/e2e/tests/eth-sign.spec.js index 26d585ea5..682cb9f5e 100644 --- a/test/e2e/tests/eth-sign.spec.js +++ b/test/e2e/tests/eth-sign.spec.js @@ -136,7 +136,7 @@ describe('Eth sign', function () { await driver.waitForSelector({ text: 'Reject 2 requests', - tag: 'a', + tag: 'button', }); await verifyAndAssertEthSign(driver, DAPP_URL, expectedEthSignMessage); diff --git a/test/e2e/tests/failing-contract.spec.js b/test/e2e/tests/failing-contract.spec.js index cc25bc3c8..6a896b47e 100644 --- a/test/e2e/tests/failing-contract.spec.js +++ b/test/e2e/tests/failing-contract.spec.js @@ -68,12 +68,12 @@ describe('Failing contract interaction ', function () { await driver.switchToWindow(extension); await driver.clickElement({ text: 'Activity', tag: 'button' }); await driver.waitForSelector( - '.transaction-list__completed-transactions .transaction-list-item:nth-of-type(1)', + '.transaction-list__completed-transactions .activity-list-item:nth-of-type(1)', ); // display the transaction status const transactionStatus = await driver.findElement( - '.transaction-list-item:nth-of-type(1) .transaction-status-label', + '.activity-list-item:nth-of-type(1) .transaction-status-label', ); assert.equal(await transactionStatus.getText(), 'Failed'); }, @@ -151,12 +151,12 @@ describe('Failing contract interaction on non-EIP1559 network', function () { await driver.switchToWindow(extension); await driver.clickElement({ text: 'Activity', tag: 'button' }); await driver.waitForSelector( - '.transaction-list__completed-transactions .transaction-list-item:nth-of-type(1)', + '.transaction-list__completed-transactions .activity-list-item:nth-of-type(1)', ); // display the transaction status const transactionStatus = await driver.findElement( - '.transaction-list-item:nth-of-type(1) .transaction-status-label', + '.activity-list-item:nth-of-type(1) .transaction-status-label', ); assert.equal(await transactionStatus.getText(), 'Failed'); }, diff --git a/test/e2e/tests/import-flow.spec.js b/test/e2e/tests/import-flow.spec.js index b89e2bbf5..3991350a6 100644 --- a/test/e2e/tests/import-flow.spec.js +++ b/test/e2e/tests/import-flow.spec.js @@ -79,7 +79,7 @@ describe('Import flow', function () { await driver.delay(largeDelayMs); await driver.clickElement('[data-testid="network-display"]'); await driver.clickElement('.toggle-button'); - await driver.clickElement({ text: 'Localhost', tag: 'span' }); + await driver.clickElement({ text: 'Localhost', tag: 'button' }); // choose Create account from the account menu await driver.clickElement('[data-testid="account-menu-icon"]'); @@ -124,13 +124,13 @@ describe('Import flow', function () { await driver.clickElement('[data-testid="home__activity-tab"]'); await driver.wait(async () => { const confirmedTxes = await driver.findElements( - '.transaction-list__completed-transactions .transaction-list-item', + '.transaction-list__completed-transactions .activity-list-item', ); return confirmedTxes.length === 1; }, 10000); const txValues = await driver.findElements( - '.transaction-list-item__primary-currency', + '[data-testid="transaction-list-item-primary-currency"]', ); assert.equal(txValues.length, 1); assert.ok(/-1\s*ETH/u.test(await txValues[0].getText())); @@ -374,7 +374,7 @@ describe('Import flow', function () { // choose Connect hardware wallet from the account menu await driver.clickElement('[data-testid="account-menu-icon"]'); await driver.clickElement({ - text: 'Hardware wallet', + text: 'Add hardware wallet', tag: 'button', }); await driver.delay(regularDelayMs); diff --git a/test/e2e/tests/metamask-responsive-ui.spec.js b/test/e2e/tests/metamask-responsive-ui.spec.js index a930a3235..3e89d5e25 100644 --- a/test/e2e/tests/metamask-responsive-ui.spec.js +++ b/test/e2e/tests/metamask-responsive-ui.spec.js @@ -159,13 +159,13 @@ describe('MetaMask Responsive UI', function () { await driver.clickElement('[data-testid="home__activity-tab"]'); await driver.wait(async () => { const confirmedTxes = await driver.findElements( - '.transaction-list__completed-transactions .transaction-list-item', + '.transaction-list__completed-transactions .activity-list-item', ); return confirmedTxes.length === 1; }, 10000); await driver.waitForSelector({ - css: '.transaction-list-item__primary-currency', + css: '[data-testid="transaction-list-item-primary-currency"]', text: '-1 ETH', }); }, diff --git a/test/e2e/tests/multiple-transactions.spec.js b/test/e2e/tests/multiple-transactions.spec.js index d18120575..b213f3dca 100644 --- a/test/e2e/tests/multiple-transactions.spec.js +++ b/test/e2e/tests/multiple-transactions.spec.js @@ -72,7 +72,7 @@ describe('Multiple transactions', function () { await driver.clickElement('[data-testid="home__activity-tab"]'); const confirmedTxes = await driver.findElements( - '.transaction-list__completed-transactions .transaction-list-item', + '.transaction-list__completed-transactions .activity-list-item', ); assert.equal(confirmedTxes.length, 2); @@ -137,7 +137,7 @@ describe('Multiple transactions', function () { // should not be present await driver.assertElementNotPresent( - '.transaction-list__completed-transactions .transaction-list-item', + '.transaction-list__completed-transactions .activity-list-item', ); }, ); diff --git a/test/e2e/tests/onboarding.spec.js b/test/e2e/tests/onboarding.spec.js index d0f494fd7..0f1ba862a 100644 --- a/test/e2e/tests/onboarding.spec.js +++ b/test/e2e/tests/onboarding.spec.js @@ -162,12 +162,11 @@ describe('MetaMask onboarding', function () { ); // Check that the error message is displayed for the password fields - await driver.isElementPresent( - // eslint-disable-next-line prettier/prettier - { text: "Passwords don't match", tag: 'h6' }, - true, - ); - + const passwordErrorIsDisplayed = await driver.isElementPresent({ + text: "Passwords don't match", + css: 'h6', + }); + assert.equal(passwordErrorIsDisplayed, true); // Check that the "Confirm Password" button is disabled const confirmPasswordButton = await driver.findElement( '[data-testid="create-password-wallet"]', diff --git a/test/e2e/tests/permissions.spec.js b/test/e2e/tests/permissions.spec.js index 648e0552e..be4fa78e7 100644 --- a/test/e2e/tests/permissions.spec.js +++ b/test/e2e/tests/permissions.spec.js @@ -55,7 +55,7 @@ describe('Permissions', function () { await driver.clickElement( '[data-testid="account-options-menu-button"]', ); - await driver.clickElement('.menu-item'); + await driver.clickElement('.menu-item:nth-of-type(3)'); await driver.findElement({ text: 'Connected sites', diff --git a/test/e2e/tests/personal-sign.spec.js b/test/e2e/tests/personal-sign.spec.js index 10e37a7c7..780d84796 100644 --- a/test/e2e/tests/personal-sign.spec.js +++ b/test/e2e/tests/personal-sign.spec.js @@ -102,7 +102,7 @@ describe('Personal sign', function () { await driver.waitForSelector({ text: 'Reject 2 requests', - tag: 'a', + tag: 'button', }); const personalMessageRow = await driver.findElement( diff --git a/test/e2e/tests/provider-api.spec.js b/test/e2e/tests/provider-api.spec.js index b8c0e0edc..79ac8f9fe 100644 --- a/test/e2e/tests/provider-api.spec.js +++ b/test/e2e/tests/provider-api.spec.js @@ -47,7 +47,7 @@ describe('MetaMask', function () { await driver.switchToWindow(windowHandles[0]); await driver.clickElement('[data-testid="network-display"]'); - await driver.clickElement({ text: 'Ethereum Mainnet', tag: 'span' }); + await driver.clickElement({ text: 'Ethereum Mainnet', tag: 'button' }); await driver.switchToWindowWithTitle('E2E Test Dapp', windowHandles); const switchedNetworkDiv = await driver.waitForSelector({ diff --git a/test/e2e/tests/send-edit.spec.js b/test/e2e/tests/send-edit.spec.js index 6157f2e66..4d9955660 100644 --- a/test/e2e/tests/send-edit.spec.js +++ b/test/e2e/tests/send-edit.spec.js @@ -68,13 +68,13 @@ describe('Editing Confirm Transaction', function () { await driver.clickElement('[data-testid="home__activity-tab"]'); await driver.wait(async () => { const confirmedTxes = await driver.findElements( - '.transaction-list__completed-transactions .transaction-list-item', + '.transaction-list__completed-transactions .activity-list-item', ); return confirmedTxes.length === 1; }, 10000); const txValues = await driver.findElements( - '.transaction-list-item__primary-currency', + '[data-testid="transaction-list-item-primary-currency"]', ); assert.equal(txValues.length, 1); assert.ok(/-2.2\s*ETH/u.test(await txValues[0].getText())); @@ -159,13 +159,13 @@ describe('Editing Confirm Transaction', function () { await driver.clickElement('[data-testid="home__activity-tab"]'); await driver.wait(async () => { const confirmedTxes = await driver.findElements( - '.transaction-list__completed-transactions .transaction-list-item', + '.transaction-list__completed-transactions .activity-list-item', ); return confirmedTxes.length === 1; }, 10000); const txValues = await driver.findElements( - '.transaction-list-item__primary-currency', + '[data-testid="transaction-list-item-primary-currency"]', ); assert.equal(txValues.length, 1); assert.ok(/-2.2\s*ETH/u.test(await txValues[0].getText())); diff --git a/test/e2e/tests/send-eth.spec.js b/test/e2e/tests/send-eth.spec.js index 64bdaace0..b0c4838c6 100644 --- a/test/e2e/tests/send-eth.spec.js +++ b/test/e2e/tests/send-eth.spec.js @@ -79,13 +79,13 @@ describe('Send ETH from inside MetaMask using default gas', function () { await driver.clickElement('[data-testid="home__activity-tab"]'); await driver.wait(async () => { const confirmedTxes = await driver.findElements( - '.transaction-list__completed-transactions .transaction-list-item', + '.transaction-list__completed-transactions .activity-list-item', ); return confirmedTxes.length === 1; }, 10000); await driver.waitForSelector({ - css: '.transaction-list-item__primary-currency', + css: '[data-testid="transaction-list-item-primary-currency"]', text: '-1 ETH', }); }, @@ -199,13 +199,13 @@ describe('Send ETH from inside MetaMask using advanced gas modal', function () { await driver.wait(async () => { const confirmedTxes = await driver.findElements( - '.transaction-list__completed-transactions .transaction-list-item', + '.transaction-list__completed-transactions .activity-list-item', ); return confirmedTxes.length === 1; }, 10000); await driver.waitForSelector({ - css: '.transaction-list-item__primary-currency', + css: '[data-testid="transaction-list-item-primary-currency"]', text: '-1 ETH', }); }, @@ -279,16 +279,16 @@ describe('Send ETH from dapp using advanced gas controls', function () { // finds the transaction in the transactions list await driver.clickElement('[data-testid="home__activity-tab"]'); await driver.waitForSelector( - '.transaction-list__completed-transactions .transaction-list-item:nth-of-type(1)', + '.transaction-list__completed-transactions .activity-list-item:nth-of-type(1)', ); await driver.waitForSelector({ - css: '.transaction-list-item__primary-currency', + css: '[data-testid="transaction-list-item-primary-currency"]', text: '-0 ETH', }); // the transaction has the expected gas price const txValue = await driver.findClickableElement( - '.transaction-list-item__primary-currency', + '[data-testid="transaction-list-item-primary-currency"]', ); await txValue.click(); const gasPrice = await driver.waitForSelector({ @@ -363,16 +363,16 @@ describe('Send ETH from dapp using advanced gas controls', function () { await driver.clickElement('[data-testid="home__activity-tab"]'); await driver.waitForSelector( - '.transaction-list__completed-transactions .transaction-list-item:nth-of-type(1)', + '.transaction-list__completed-transactions .activity-list-item:nth-of-type(1)', ); await driver.waitForSelector({ - css: '.transaction-list-item__primary-currency', + css: '[data-testid="transaction-list-item-primary-currency"]', text: '-0 ETH', }); // the transaction has the expected gas value const txValue = await driver.findClickableElement( - '.transaction-list-item__primary-currency', + '[data-testid="transaction-list-item-primary-currency"]', ); await txValue.click(); const baseFeeValue = await driver.waitForSelector( @@ -432,7 +432,7 @@ describe('Send ETH from inside MetaMask to a Multisig Address', function () { await assertAccountBalanceForDOM(driver, ganacheServer); await driver.clickElement('[data-testid="home__activity-tab"]'); const txn = await driver.isElementPresent( - '.transaction-list__completed-transactions .transaction-list-item', + '.transaction-list__completed-transactions .activity-list-item', ); assert.equal(txn, true); diff --git a/test/e2e/tests/send-hex-address.spec.js b/test/e2e/tests/send-hex-address.spec.js index f4f3c22b5..cd656e996 100644 --- a/test/e2e/tests/send-hex-address.spec.js +++ b/test/e2e/tests/send-hex-address.spec.js @@ -50,7 +50,7 @@ describe('Send ETH to a 40 character hexadecimal address', function () { await driver.clickElement({ text: 'Confirm', tag: 'button' }); await driver.clickElement('[data-testid="home__activity-tab"]'); const sendTransactionListItem = await driver.waitForSelector( - '.transaction-list__completed-transactions .transaction-list-item', + '.transaction-list__completed-transactions .activity-list-item', ); await sendTransactionListItem.click(); await driver.clickElement({ text: 'Activity log', tag: 'summary' }); @@ -95,7 +95,7 @@ describe('Send ETH to a 40 character hexadecimal address', function () { await driver.clickElement({ text: 'Confirm', tag: 'button' }); await driver.clickElement('[data-testid="home__activity-tab"]'); const sendTransactionListItem = await driver.waitForSelector( - '.transaction-list__completed-transactions .transaction-list-item', + '.transaction-list__completed-transactions .activity-list-item', ); await sendTransactionListItem.click(); await driver.clickElement({ text: 'Activity log', tag: 'summary' }); @@ -166,10 +166,10 @@ describe('Send ERC20 to a 40 character hexadecimal address', function () { await driver.clickElement({ text: 'Confirm', tag: 'button' }); await driver.clickElement('[data-testid="home__activity-tab"]'); await driver.waitForSelector( - '.transaction-list__completed-transactions .transaction-list-item:nth-of-type(1)', + '.transaction-list__completed-transactions .activity-list-item:nth-of-type(1)', ); const sendTransactionListItem = await driver.waitForSelector( - '.transaction-list__completed-transactions .transaction-list-item:nth-of-type(1)', + '.transaction-list__completed-transactions .activity-list-item:nth-of-type(1)', ); await sendTransactionListItem.click(); await driver.clickElement({ text: 'Activity log', tag: 'summary' }); @@ -227,10 +227,10 @@ describe('Send ERC20 to a 40 character hexadecimal address', function () { await driver.clickElement({ text: 'Confirm', tag: 'button' }); await driver.clickElement('[data-testid="home__activity-tab"]'); await driver.waitForSelector( - '.transaction-list__completed-transactions .transaction-list-item:nth-of-type(1)', + '.transaction-list__completed-transactions .activity-list-item:nth-of-type(1)', ); const sendTransactionListItem = await driver.waitForSelector( - '.transaction-list__completed-transactions .transaction-list-item:nth-of-type(1)', + '.transaction-list__completed-transactions .activity-list-item:nth-of-type(1)', ); await sendTransactionListItem.click(); await driver.clickElement({ text: 'Activity log', tag: 'summary' }); diff --git a/test/e2e/tests/settings-security-reveal-srp.spec.js b/test/e2e/tests/settings-security-reveal-srp.spec.js index 1a7cc14c0..ea84cb6bc 100644 --- a/test/e2e/tests/settings-security-reveal-srp.spec.js +++ b/test/e2e/tests/settings-security-reveal-srp.spec.js @@ -27,13 +27,11 @@ describe('Reveal SRP through settings', function () { await completeSRPRevealQuiz(driver); await driver.fill('#password-box', wrongTestPassword); await driver.press('#password-box', driver.Key.ENTER); - await driver.isElementPresent( - { - css: '.mm-help-text', - text: 'Incorrect password', - }, - true, - ); + const passwordErrorIsDisplayed = await driver.isElementPresent({ + css: '.mm-help-text', + text: 'Incorrect password', + }); + assert.equal(passwordErrorIsDisplayed, true); }, ); }); diff --git a/test/e2e/tests/signature-request.spec.js b/test/e2e/tests/signature-request.spec.js index 9ef703389..375f643be 100644 --- a/test/e2e/tests/signature-request.spec.js +++ b/test/e2e/tests/signature-request.spec.js @@ -160,7 +160,7 @@ describe('Sign Typed Data Signature Request', function () { await driver.waitForSelector({ text: 'Reject 2 requests', - tag: 'a', + tag: 'button', }); await verifyAndAssertSignTypedData( diff --git a/test/e2e/tests/state-logs.spec.js b/test/e2e/tests/state-logs.spec.js index f08a38fd1..8cccbcf91 100644 --- a/test/e2e/tests/state-logs.spec.js +++ b/test/e2e/tests/state-logs.spec.js @@ -30,7 +30,12 @@ describe('State logs', function () { }, ], }; + it('should download state logs for the account', async function () { + if (process.env.SELENIUM_BROWSER === 'chrome') { + // Chrome shows OS level download prompt which can't be dismissed by Selenium + this.skip(); + } await withFixtures( { fixtures: new FixtureBuilder().build(), diff --git a/test/e2e/tests/stuck-approved-transaction.spec.js b/test/e2e/tests/stuck-approved-transaction.spec.js index daf73265d..74c031385 100644 --- a/test/e2e/tests/stuck-approved-transaction.spec.js +++ b/test/e2e/tests/stuck-approved-transaction.spec.js @@ -31,13 +31,13 @@ describe('Editing Confirm Transaction', function () { await driver.clickElement('[data-testid="home__activity-tab"]'); await driver.wait(async () => { const confirmedTxes = await driver.findElements( - '.transaction-list__completed-transactions .transaction-list-item', + '.transaction-list__completed-transactions .activity-list-item', ); return confirmedTxes.length === 1; }, 10000); const txValues = await driver.findElements( - '.transaction-list-item__primary-currency', + '[data-testid="transaction-list-item-primary-currency"]', ); assert.equal(txValues.length, 1); assert.ok(/-1\s*ETH/u.test(await txValues[0].getText())); diff --git a/test/e2e/tests/switch-custom-network.spec.js b/test/e2e/tests/switch-custom-network.spec.js index 9e0cf6857..67c3ad1fc 100644 --- a/test/e2e/tests/switch-custom-network.spec.js +++ b/test/e2e/tests/switch-custom-network.spec.js @@ -2,7 +2,7 @@ const { strict: assert } = require('assert'); const FixtureBuilder = require('../fixture-builder'); const { convertToHexValue, withFixtures, openDapp } = require('../helpers'); -describe('Swtich ethereum chain', function () { +describe('Switch ethereum chain', function () { const ganacheOptions = { accounts: [ { diff --git a/test/e2e/webdriver/driver.js b/test/e2e/webdriver/driver.js index c1284f70c..d6592c44f 100644 --- a/test/e2e/webdriver/driver.js +++ b/test/e2e/webdriver/driver.js @@ -58,7 +58,7 @@ class Driver { * @param extensionUrl * @param {number} timeout */ - constructor(driver, browser, extensionUrl, timeout = 10000) { + constructor(driver, browser, extensionUrl, timeout = 10 * 1000) { this.driver = driver; this.browser = browser; this.extensionUrl = extensionUrl; @@ -249,6 +249,18 @@ class Driver { await element.click(); } + async clickElementSafe(rawLocator) { + // for instances where an element such as a scroll button does not + // show up because of render differences, proceed to the next step + // without causing a test failure, but provide a console log of why. + try { + const element = await this.findClickableElement(rawLocator); + await element.click(); + } catch (e) { + console.log(`Element ${rawLocator} not found (${e})`); + } + } + async clickPoint(rawLocator, x, y) { const element = await this.findElement(rawLocator); await this.driver @@ -376,6 +388,7 @@ class Driver { let windowHandles = []; while (timeElapsed <= timeout) { windowHandles = await this.driver.getAllWindowHandles(); + if (windowHandles.length === x) { return windowHandles; } @@ -389,7 +402,7 @@ class Driver { title, initialWindowHandles, delayStep = 1000, - timeout = 5000, + timeout = this.timeout, ) { let windowHandles = initialWindowHandles || (await this.driver.getAllWindowHandles()); @@ -397,6 +410,7 @@ class Driver { while (timeElapsed <= timeout) { for (const handle of windowHandles) { await this.driver.switchTo().window(handle); + const handleTitle = await this.driver.getTitle(); if (handleTitle === title) { return handle; diff --git a/types/global.d.ts b/types/global.d.ts index f1e8c1b18..2c9c1d126 100644 --- a/types/global.d.ts +++ b/types/global.d.ts @@ -1,6 +1,7 @@ // In order for variables to be considered on the global scope they must be // declared using var and not const or let, which is why this rule is disabled /* eslint-disable no-var */ +import * as Sentry from '@sentry/browser'; declare class Platform { openTab: (opts: { url: string }) => void; @@ -8,8 +9,23 @@ declare class Platform { closeCurrentWindow: () => void; } +declare class SentryObject extends Sentry { + // Verifies that the user has opted into metrics and then updates the sentry + // instance to track sessions and begins the session. + startSession: () => void; + + // Verifies that the user has opted out of metrics and then updates the + // sentry instance to NOT track sessions and ends the current session. + endSession: () => void; + + // Calls either startSession or endSession based on optin status + toggleSession: () => void; +} + export declare global { var platform: Platform; + // Sentry is undefined in dev, so use optional chaining + var sentry: SentryObject | undefined; namespace jest { interface Matchers { diff --git a/ui/components/app/add-network/add-network.js b/ui/components/app/add-network/add-network.js index 0998f0b8e..a44c5258d 100644 --- a/ui/components/app/add-network/add-network.js +++ b/ui/components/app/add-network/add-network.js @@ -14,7 +14,6 @@ import { BackgroundColor, TextColor, IconColor, - Size, } from '../../../helpers/constants/design-system'; import Button from '../../ui/button'; import Tooltip from '../../ui/tooltip'; @@ -36,11 +35,12 @@ import { ADD_NETWORK_ROUTE } from '../../../helpers/constants/routes'; import { getEnvironmentType } from '../../../../app/scripts/lib/util'; import ZENDESK_URLS from '../../../helpers/constants/zendesk-url'; import { - Text, Icon, IconName, IconSize, AvatarNetwork, + AvatarNetworkSize, + Text, } from '../../component-library'; import { MetaMetricsNetworkEventSource } from '../../../../shared/constants/metametrics'; @@ -199,7 +199,7 @@ const AddNetwork = () => { > diff --git a/ui/components/app/app-components.scss b/ui/components/app/app-components.scss index c439006bc..313e755ca 100644 --- a/ui/components/app/app-components.scss +++ b/ui/components/app/app-components.scss @@ -10,12 +10,12 @@ @import 'confirm-page-container/index'; @import 'confirm-data/index'; @import 'confirmation-warning-modal/index'; +@import 'custom-nonce/index'; @import 'nfts-items/index'; @import 'nfts-tab/index'; @import 'nft-details/index'; @import 'nft-default-image/index'; @import 'nft-options/index'; -@import 'nfts-detection-notice/index'; @import 'connected-accounts-list/index'; @import 'connected-accounts-permissions/index'; @import 'connected-sites-list/index'; @@ -31,7 +31,6 @@ @import 'flask/experimental-area/index'; @import 'snaps/snap-content-footer/index'; @import 'snaps/snap-install-warning/index'; -@import 'snaps/snap-remove-warning/index'; @import 'snaps/snap-ui-renderer/index'; @import 'snaps/snap-ui-markdown/index'; @import 'snaps/snap-delineator/index'; @@ -97,8 +96,9 @@ @import 'network-account-balance-header/index'; @import 'approve-content-card/index'; @import 'transaction-alerts/transaction-alerts'; -@import '../institutional/compliance-details/index'; +///: BEGIN:ONLY_INCLUDE_IN(build-mmi) @import '../institutional/interactive-replacement-token-notification/index'; @import '../institutional/confirm-remove-jwt-modal/index'; @import '../institutional/custody-confirm-link-modal/index'; @import '../institutional/transaction-failed-modal/index'; +///: END:ONLY_INCLUDE_IN diff --git a/ui/components/app/approve-content-card/approve-content-card.js b/ui/components/app/approve-content-card/approve-content-card.js index b9b177fe7..69998930d 100644 --- a/ui/components/app/approve-content-card/approve-content-card.js +++ b/ui/components/app/approve-content-card/approve-content-card.js @@ -184,7 +184,7 @@ export default function ApproveContentCard({ {formatCurrency( diff --git a/ui/components/app/beta-header/__snapshots__/beta-header.test.js.snap b/ui/components/app/beta-header/__snapshots__/beta-header.test.js.snap index 72b1c312c..3e0c260d1 100644 --- a/ui/components/app/beta-header/__snapshots__/beta-header.test.js.snap +++ b/ui/components/app/beta-header/__snapshots__/beta-header.test.js.snap @@ -6,7 +6,7 @@ exports[`Beta Header should match snapshot 1`] = ` class="box beta-header box--padding-2 box--display-flex box--flex-direction-row box--align-items-center box--width-full box--background-color-warning-default" >
    @@ -28,7 +28,7 @@ exports[`Beta Header should match snapshot 1`] = ` data-testid="beta-header-close" > diff --git a/ui/components/app/beta-header/index.js b/ui/components/app/beta-header/index.js index 41352723d..5e0751083 100644 --- a/ui/components/app/beta-header/index.js +++ b/ui/components/app/beta-header/index.js @@ -14,6 +14,7 @@ import { import { BETA_BUGS_URL } from '../../../helpers/constants/beta'; import { hideBetaHeader } from '../../../store/actions'; + import { ButtonIcon, ButtonIconSize, diff --git a/ui/components/app/cancel-speedup-popover/cancel-speedup-popover.js b/ui/components/app/cancel-speedup-popover/cancel-speedup-popover.js index 377d7eaeb..a1eda061c 100644 --- a/ui/components/app/cancel-speedup-popover/cancel-speedup-popover.js +++ b/ui/components/app/cancel-speedup-popover/cancel-speedup-popover.js @@ -18,7 +18,7 @@ import Box from '../../ui/box'; import InfoTooltip from '../../ui/info-tooltip'; import Popover from '../../ui/popover'; import AppLoadingSpinner from '../app-loading-spinner'; -import { Text, Button, ButtonLink } from '../../component-library'; +import { Button, ButtonLink, Text } from '../../component-library'; const CancelSpeedupPopover = () => { const { diff --git a/ui/components/app/configure-snap-popup/configure-snap-popup.tsx b/ui/components/app/configure-snap-popup/configure-snap-popup.tsx index d62edd27c..ac9b77129 100644 --- a/ui/components/app/configure-snap-popup/configure-snap-popup.tsx +++ b/ui/components/app/configure-snap-popup/configure-snap-popup.tsx @@ -3,12 +3,12 @@ import PropTypes from 'prop-types'; import { BUTTON_VARIANT, Button, - Text, Box, Modal, ModalOverlay, ModalContent, ModalHeader, + Text, } from '../../component-library'; import { useI18nContext } from '../../../hooks/useI18nContext'; import { diff --git a/ui/components/app/confirm-gas-display/__snapshots__/confirm-gas-display.test.js.snap b/ui/components/app/confirm-gas-display/__snapshots__/confirm-gas-display.test.js.snap index edd5c141f..32e18b8ab 100644 --- a/ui/components/app/confirm-gas-display/__snapshots__/confirm-gas-display.test.js.snap +++ b/ui/components/app/confirm-gas-display/__snapshots__/confirm-gas-display.test.js.snap @@ -10,7 +10,7 @@ exports[`ConfirmGasDisplay should match snapshot 1`] = ` class="transaction-detail-item__row" >
    - 0 @@ -79,25 +76,22 @@ exports[`ConfirmGasDisplay should match snapshot 1`] = `
    - 0 ETH @@ -117,7 +111,7 @@ exports[`ConfirmGasDisplay should match snapshot 1`] = `
    - 0 ETH diff --git a/ui/components/app/confirm-gas-display/confirm-legacy-gas-display/__snapshots__/confirm-legacy-gas-display.test.js.snap b/ui/components/app/confirm-gas-display/confirm-legacy-gas-display/__snapshots__/confirm-legacy-gas-display.test.js.snap index 0d19b899c..a380323e7 100644 --- a/ui/components/app/confirm-gas-display/confirm-legacy-gas-display/__snapshots__/confirm-legacy-gas-display.test.js.snap +++ b/ui/components/app/confirm-gas-display/confirm-legacy-gas-display/__snapshots__/confirm-legacy-gas-display.test.js.snap @@ -9,7 +9,7 @@ exports[`ConfirmLegacyGasDisplay should match snapshot 1`] = ` class="transaction-detail-item__row" >
    Estimated gas fee
    - 0.000021 @@ -61,23 +58,20 @@ exports[`ConfirmLegacyGasDisplay should match snapshot 1`] = `
    - 0.000021 ETH @@ -91,26 +85,23 @@ exports[`ConfirmLegacyGasDisplay should match snapshot 1`] = ` >
    Max fee:
    - 0.000021 ETH diff --git a/ui/components/app/confirm-gas-display/confirm-legacy-gas-display/confirm-legacy-gas-display.js b/ui/components/app/confirm-gas-display/confirm-legacy-gas-display/confirm-legacy-gas-display.js index 15e0abfb6..a98f2ca28 100644 --- a/ui/components/app/confirm-gas-display/confirm-legacy-gas-display/confirm-legacy-gas-display.js +++ b/ui/components/app/confirm-gas-display/confirm-legacy-gas-display/confirm-legacy-gas-display.js @@ -18,7 +18,6 @@ import TransactionDetailItem from '../../transaction-detail-item'; import UserPreferencedCurrencyDisplay from '../../user-preferenced-currency-display'; import InfoTooltip from '../../../ui/info-tooltip'; import LoadingHeartBeat from '../../../ui/loading-heartbeat'; -import { Text } from '../../../component-library/text'; import { FONT_STYLE, TextVariant, @@ -27,7 +26,7 @@ import { import { useDraftTransactionWithTxParams } from '../../../../hooks/useDraftTransactionWithTxParams'; import { getNativeCurrency } from '../../../../ducks/metamask/metamask'; import MultilayerFeeMessage from '../../multilayer-fee-message/multi-layer-fee-message'; -import { Icon, IconName } from '../../../component-library'; +import { Icon, IconName, Text } from '../../../component-library'; const renderHeartBeatIfNotInTest = () => process.env.IN_TEST ? null : ; diff --git a/ui/components/app/confirm-page-container/confirm-detail-row/__snapshots__/confirm-detail-row.component.test.js.snap b/ui/components/app/confirm-page-container/confirm-detail-row/__snapshots__/confirm-detail-row.component.test.js.snap index 880b74bcd..68086ec61 100644 --- a/ui/components/app/confirm-page-container/confirm-detail-row/__snapshots__/confirm-detail-row.component.test.js.snap +++ b/ui/components/app/confirm-page-container/confirm-detail-row/__snapshots__/confirm-detail-row.component.test.js.snap @@ -12,37 +12,39 @@ exports[`Confirm Detail Row Component should match snapshot 1`] = ` class="confirm-detail-row__details" >
    - - +
    0
    - - +
    0 diff --git a/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js b/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js index 713cd9293..b100cdb6b 100644 --- a/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js +++ b/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js @@ -2,7 +2,9 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; import { Tabs, Tab } from '../../../ui/tabs'; +///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask) import Button from '../../../ui/button'; +///: END:ONLY_INCLUDE_IN import ActionableMessage from '../../../ui/actionable-message/actionable-message'; import { PageContainerFooter } from '../../../ui/page-container'; import ErrorMessage from '../../../ui/error-message'; @@ -57,7 +59,9 @@ export default class ConfirmPageContainerContent extends Component { toAddress: PropTypes.string, transactionType: PropTypes.string, isBuyableChain: PropTypes.bool, + ///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask) openBuyCryptoInPdapp: PropTypes.func, + ///: END:ONLY_INCLUDE_IN txData: PropTypes.object, ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) noteComponent: PropTypes.node, @@ -123,9 +127,10 @@ export default class ConfirmPageContainerContent extends Component { ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) noteComponent && ( { this.context.trackEvent({ category: 'Note to trader', @@ -196,7 +201,9 @@ export default class ConfirmPageContainerContent extends Component { toAddress, transactionType, isBuyableChain, + ///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask) openBuyCryptoInPdapp, + ///: END:ONLY_INCLUDE_IN txData, } = this.props; diff --git a/ui/components/app/confirm-page-container/confirm-page-container-header/__snapshots__/confirm-page-container-header.component.test.js.snap b/ui/components/app/confirm-page-container/confirm-page-container-header/__snapshots__/confirm-page-container-header.component.test.js.snap index 788540730..6bcd678b7 100644 --- a/ui/components/app/confirm-page-container/confirm-page-container-header/__snapshots__/confirm-page-container-header.component.test.js.snap +++ b/ui/components/app/confirm-page-container/confirm-page-container-header/__snapshots__/confirm-page-container-header.component.test.js.snap @@ -14,7 +14,7 @@ exports[`Confirm Detail Row Component should match snapshot 1`] = ` style="visibility: hidden;" > { } = props; const t = useI18nContext(); + ///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask) const trackEvent = useContext(MetaMetricsContext); - + ///: END:ONLY_INCLUDE_IN const [collectionBalance, setCollectionBalance] = useState('0'); const isBuyableChain = useSelector(getIsBuyableChain); diff --git a/ui/components/app/connected-sites-list/connected-sites-list.component.js b/ui/components/app/connected-sites-list/connected-sites-list.component.js index 00372f64e..72b4cacfe 100644 --- a/ui/components/app/connected-sites-list/connected-sites-list.component.js +++ b/ui/components/app/connected-sites-list/connected-sites-list.component.js @@ -1,9 +1,10 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import Button from '../../ui/button'; -import SiteIcon from '../../ui/site-icon'; +import { AvatarFavicon } from '../../component-library'; import { stripHttpsSchemeWithoutPort } from '../../../helpers/utils/util'; import SiteOrigin from '../../ui/site-origin'; +import { BorderColor, Size } from '../../../helpers/constants/design-system'; export default class ConnectedSitesList extends Component { static contextTypes = { @@ -33,11 +34,12 @@ export default class ConnectedSitesList extends Component { className="connected-sites-list__content-row" >
    - {submitText} diff --git a/ui/components/app/currency-input/__snapshots__/currency-input.test.js.snap b/ui/components/app/currency-input/__snapshots__/currency-input.test.js.snap index de6f2afcc..339ef4441 100644 --- a/ui/components/app/currency-input/__snapshots__/currency-input.test.js.snap +++ b/ui/components/app/currency-input/__snapshots__/currency-input.test.js.snap @@ -27,19 +27,16 @@ exports[`CurrencyInput Component rendering should render properly with a fiat va
    - 0.00432788 ETH @@ -128,19 +125,16 @@ exports[`CurrencyInput Component rendering should render properly with an ETH va
    - $231.06 USD @@ -185,19 +179,16 @@ exports[`CurrencyInput Component rendering should render properly without a suff
    - $0.00 USD diff --git a/ui/components/app/custom-nonce/custom-nonce.js b/ui/components/app/custom-nonce/custom-nonce.js new file mode 100644 index 000000000..a7ad0a658 --- /dev/null +++ b/ui/components/app/custom-nonce/custom-nonce.js @@ -0,0 +1,75 @@ +import React, { useContext } from 'react'; +import PropTypes from 'prop-types'; +import { I18nContext } from '../../../../.storybook/i18n'; +import { Box, ButtonLink, Text } from '../../component-library'; +import { + AlignItems, + BorderRadius, + Display, + JustifyContent, + Size, + TextVariant, +} from '../../../helpers/constants/design-system'; + +export default function CustomNonce({ + nextNonce, + customNonceValue, + showCustomizeNonceModal, +}) { + const t = useContext(I18nContext); + + return ( + + + + {t('nonce')} + + showCustomizeNonceModal()} + > + {t('edit')} + + + + {customNonceValue || nextNonce} + + + ); +} + +CustomNonce.propTypes = { + /** + * Getting the next suggested nonce + */ + nextNonce: PropTypes.number, + /** + * Custom nonce value + */ + customNonceValue: PropTypes.string, + /** + * Function that is supposed to open the customized nonce modal + */ + showCustomizeNonceModal: PropTypes.func, +}; diff --git a/ui/components/app/custom-nonce/custom-nonce.test.js b/ui/components/app/custom-nonce/custom-nonce.test.js new file mode 100644 index 000000000..2b8beca85 --- /dev/null +++ b/ui/components/app/custom-nonce/custom-nonce.test.js @@ -0,0 +1,65 @@ +import React from 'react'; +import configureMockStore from 'redux-mock-store'; +import { fireEvent } from '@testing-library/react'; +import { renderWithProvider } from '../../../../test/lib/render-helpers'; +import CustomNonce from './custom-nonce'; + +describe('CustomNonce', () => { + const store = configureMockStore()({}); + let props = {}; + + beforeEach(() => { + props = { + nextNonce: 1, + customNonceValue: '', + showCustomizeNonceModal: jest.fn(), + }; + }); + + it('should render CustomNonce component header', () => { + const { queryByText } = renderWithProvider( + , + store, + ); + + expect(queryByText('Nonce')).toBeInTheDocument(); + expect(queryByText('Edit')).toBeInTheDocument(); + }); + + it('should render CustomNonce component value when custom nonce value is a empty string', () => { + const { queryByText } = renderWithProvider( + , + store, + ); + + expect(queryByText('Nonce')).toBeInTheDocument(); + expect(queryByText('Edit')).toBeInTheDocument(); + expect(queryByText('1')).toBeInTheDocument(); + }); + + it('should render CustomNonce component value when custom nonce value is edited', () => { + props.customNonceValue = '3'; + const { queryByText } = renderWithProvider( + , + store, + ); + + expect(queryByText('Nonce')).toBeInTheDocument(); + expect(queryByText('Edit')).toBeInTheDocument(); + expect(queryByText('3')).toBeInTheDocument(); + }); + + it('should render CustomNonce component to show customize nonce modal', () => { + const { queryByText, getByText } = renderWithProvider( + , + store, + ); + + const editButton = getByText('Edit'); + expect(queryByText('Nonce')).toBeInTheDocument(); + expect(editButton).toBeInTheDocument(); + expect(queryByText('1')).toBeInTheDocument(); + fireEvent.click(editButton); + expect(props.showCustomizeNonceModal).toHaveBeenCalledTimes(1); + }); +}); diff --git a/ui/components/app/custom-nonce/index.js b/ui/components/app/custom-nonce/index.js new file mode 100644 index 000000000..60b5eedde --- /dev/null +++ b/ui/components/app/custom-nonce/index.js @@ -0,0 +1 @@ +export { default } from './custom-nonce'; diff --git a/ui/components/app/custom-nonce/index.scss b/ui/components/app/custom-nonce/index.scss new file mode 100644 index 000000000..be5994928 --- /dev/null +++ b/ui/components/app/custom-nonce/index.scss @@ -0,0 +1,15 @@ +.custom-nonce { + &__content { + height: 49px; + border: 1px solid var(--color-border-muted); + box-sizing: border-box; + } + + &__header { + flex: 1; + } + + &__value { + flex: 0; + } +} diff --git a/ui/components/app/custom-spending-cap/__snapshots__/custom-spending-cap.test.js.snap b/ui/components/app/custom-spending-cap/__snapshots__/custom-spending-cap.test.js.snap index 2b2dff9b4..720dbe6e4 100644 --- a/ui/components/app/custom-spending-cap/__snapshots__/custom-spending-cap.test.js.snap +++ b/ui/components/app/custom-spending-cap/__snapshots__/custom-spending-cap.test.js.snap @@ -24,9 +24,7 @@ exports[`CustomSpendingCap should match snapshot 1`] = ` class="mm-box form-field__heading-title mm-box--display-flex mm-box--align-items-baseline" >
    Custom spending cap
    @@ -44,7 +42,7 @@ exports[`CustomSpendingCap should match snapshot 1`] = ` tabindex="0" >
    @@ -67,7 +65,7 @@ exports[`CustomSpendingCap should match snapshot 1`] = ` class="box custom-spending-cap__max box--margin-left-auto box--padding-right-4 box--padding-bottom-2 box--flex-direction-row box--text-align-end box--width-max" > @@ -76,24 +74,24 @@ exports[`CustomSpendingCap should match snapshot 1`] = ` class="box custom-spending-cap__description box--flex-direction-row" >
    This allows the third party to spend -
    7 TST -
    +
    from your current balance.
    diff --git a/ui/components/app/custom-spending-cap/custom-spending-cap-tooltip.js b/ui/components/app/custom-spending-cap/custom-spending-cap-tooltip.js index 1c68eb297..b2bac1b14 100644 --- a/ui/components/app/custom-spending-cap/custom-spending-cap-tooltip.js +++ b/ui/components/app/custom-spending-cap/custom-spending-cap-tooltip.js @@ -4,8 +4,8 @@ import Box from '../../ui/box'; import Tooltip from '../../ui/tooltip'; import { TextColor, - DISPLAY, TextVariant, + Display, } from '../../../helpers/constants/design-system'; import { Icon, IconName, IconSize, Text } from '../../component-library'; @@ -14,7 +14,7 @@ export const CustomSpendingCapTooltip = ({ tooltipContentText, tooltipIcon, }) => ( - + {replaceCommaToDot(inputNumber)} {tokenName} @@ -196,7 +197,7 @@ export default function CustomSpendingCap({ {t('beCareful')} @@ -212,15 +213,15 @@ export default function CustomSpendingCap({ paddingTop={2} paddingRight={6} paddingLeft={6} - display={DISPLAY.FLEX} + display={Display.Flex} alignItems={AlignItems.flexStart} - flexDirection={FLEX_DIRECTION.COLUMN} + flexDirection={FlexDirection.Column} backgroundColor={BackgroundColor.backgroundAlternative} gap={2} >
    @@ -18,26 +18,26 @@ exports[`LedgerInstructionField Component rendering should render properly with class="ledger-live-dialog" >
    Prior to clicking confirm:
    • Be sure your Ledger is plugged in and to select the Ethereum app.
    • Enable "smart contract data" or "blind signing" on your Ledger device.
    diff --git a/ui/components/app/metamask-template-renderer/safe-component-list.js b/ui/components/app/metamask-template-renderer/safe-component-list.js index f8ae5650e..68101cfb3 100644 --- a/ui/components/app/metamask-template-renderer/safe-component-list.js +++ b/ui/components/app/metamask-template-renderer/safe-component-list.js @@ -12,6 +12,8 @@ import TextField from '../../ui/text-field'; import ConfirmationNetworkSwitch from '../../../pages/confirmation/components/confirmation-network-switch'; import UrlIcon from '../../ui/url-icon'; import Tooltip from '../../ui/tooltip/tooltip'; +import { AvatarIcon } from '../../component-library'; +import ActionableMessage from '../../ui/actionable-message/actionable-message'; ///: BEGIN:ONLY_INCLUDE_IN(snaps) import { SnapDelineator } from '../snaps/snap-delineator'; import { Copyable } from '../snaps/copyable'; @@ -21,19 +23,21 @@ import { SnapUIMarkdown } from '../snaps/snap-ui-markdown'; export const safeComponentList = { a: 'a', + ActionableMessage, + AvatarIcon, b: 'b', - i: 'i', - p: 'p', - div: 'div', - span: 'span', Box, Button, Chip, ConfirmationNetworkSwitch, DefinitionList, + div: 'div', + i: 'i', MetaMaskTranslation, NetworkDisplay, + p: 'p', Popover, + span: 'span', TextArea, TextField, Tooltip, @@ -41,9 +45,9 @@ export const safeComponentList = { Typography, UrlIcon, ///: BEGIN:ONLY_INCLUDE_IN(snaps) - SnapDelineator, Copyable, - Spinner, + SnapDelineator, SnapUIMarkdown, + Spinner, ///: END:ONLY_INCLUDE_IN }; diff --git a/ui/components/app/modals/cancel-transaction/cancel-transaction-gas-fee/__snapshots__/cancel-transaction-gas-fee.component.test.js.snap b/ui/components/app/modals/cancel-transaction/cancel-transaction-gas-fee/__snapshots__/cancel-transaction-gas-fee.component.test.js.snap index c23cca668..83e638ca1 100644 --- a/ui/components/app/modals/cancel-transaction/cancel-transaction-gas-fee/__snapshots__/cancel-transaction-gas-fee.component.test.js.snap +++ b/ui/components/app/modals/cancel-transaction/cancel-transaction-gas-fee/__snapshots__/cancel-transaction-gas-fee.component.test.js.snap @@ -6,37 +6,31 @@ exports[`CancelTransactionGasFee Component should render 1`] = ` class="cancel-transaction-gas-fee" >
    - 0 ETH
    - 0 ETH diff --git a/ui/components/app/modals/convert-token-to-nft-modal/convert-token-to-nft-modal.js b/ui/components/app/modals/convert-token-to-nft-modal/convert-token-to-nft-modal.js index c818c80f1..9311153fc 100644 --- a/ui/components/app/modals/convert-token-to-nft-modal/convert-token-to-nft-modal.js +++ b/ui/components/app/modals/convert-token-to-nft-modal/convert-token-to-nft-modal.js @@ -7,12 +7,9 @@ import Typography from '../../../ui/typography'; import { TypographyVariant } from '../../../../helpers/constants/design-system'; import withModalProps from '../../../../helpers/higher-order-components/with-modal-props'; import { useI18nContext } from '../../../../hooks/useI18nContext'; -import { - ADD_NFT_ROUTE, - ASSET_ROUTE, -} from '../../../../helpers/constants/routes'; +import { ASSET_ROUTE } from '../../../../helpers/constants/routes'; import { getNfts } from '../../../../ducks/metamask/metamask'; -import { ignoreTokens } from '../../../../store/actions'; +import { ignoreTokens, showImportNftsModal } from '../../../../store/actions'; import { isEqualCaseInsensitive } from '../../../../../shared/modules/string-utils'; const ConvertTokenToNFTModal = ({ hideModal, tokenAddress }) => { @@ -39,10 +36,7 @@ const ConvertTokenToNFTModal = ({ hideModal, tokenAddress }) => { pathname: `${ASSET_ROUTE}/${tokenAddress}/${tokenId}`, }); } else { - history.push({ - pathname: ADD_NFT_ROUTE, - state: { tokenAddress }, - }); + dispatch(showImportNftsModal()); } hideModal(); }} diff --git a/ui/components/app/modals/customize-nonce/__snapshots__/customize-nonce.test.js.snap b/ui/components/app/modals/customize-nonce/__snapshots__/customize-nonce.test.js.snap index b35c12b39..7dc9032a9 100644 --- a/ui/components/app/modals/customize-nonce/__snapshots__/customize-nonce.test.js.snap +++ b/ui/components/app/modals/customize-nonce/__snapshots__/customize-nonce.test.js.snap @@ -15,7 +15,7 @@ exports[`Customize Nonce should match snapshot 1`] = ` class="customize-nonce-modal__main-header" >

    Edit nonce

    @@ -24,20 +24,20 @@ exports[`Customize Nonce should match snapshot 1`] = ` class="box mm-button-icon mm-button-icon--size-sm customize-nonce-modal__close box--display-inline-flex box--flex-direction-row box--justify-content-center box--align-items-center box--color-icon-default box--background-color-transparent box--rounded-lg" >
    {t('editNonceField')} @@ -68,39 +66,32 @@ const CustomizeNonce = ({
    - + {t('editNonceMessage')} - + - - + + {t('editNonceField')} - - +
    diff --git a/ui/components/app/modals/customize-nonce/index.scss b/ui/components/app/modals/customize-nonce/index.scss index fb7a5656b..1bd22dc56 100644 --- a/ui/components/app/modals/customize-nonce/index.scss +++ b/ui/components/app/modals/customize-nonce/index.scss @@ -31,7 +31,7 @@ } & &__reset { - @include H7; + @include H6; } &__input { diff --git a/ui/components/app/modals/eth-sign-modal/__snapshots__/eth-sign-modal.test.js.snap b/ui/components/app/modals/eth-sign-modal/__snapshots__/eth-sign-modal.test.js.snap index d0c0d7d53..1e96bdb57 100644 --- a/ui/components/app/modals/eth-sign-modal/__snapshots__/eth-sign-modal.test.js.snap +++ b/ui/components/app/modals/eth-sign-modal/__snapshots__/eth-sign-modal.test.js.snap @@ -9,7 +9,7 @@ exports[`Eth Sign Modal should match snapshot 1`] = ` class="box box--margin-bottom-4 box--display-flex box--flex-direction-row box--justify-content-center" >

    Use at your own risk

    Allowing eth_sign requests can make you vulnerable to phishing attacks. Always review the URL and be careful when signing messages that contain code.

    @@ -63,11 +63,11 @@ exports[`Eth Sign Modal should match snapshot 1`] = ` type="checkbox" />

    Warning: Never disclose this key. Anyone with your private keys can steal any assets held in your account.

    @@ -120,13 +120,13 @@ exports[`Export PrivateKey Modal should match snapshot 1`] = ` class="box box--margin-top-3 box--padding-5 box--md:padding-5 box--display-flex box--flex-direction-row box--justify-content-space-between box--width-full" >
    @@ -44,7 +44,7 @@ exports[`Multi layer fee message when balance and token price checker is disable class="transaction-detail-item__row" >
    Total
    @@ -52,7 +52,7 @@ exports[`Multi layer fee message when balance and token price checker is disable class="transaction-detail-item__detail-values" >
    0.001000021000 ETH
    @@ -62,12 +62,12 @@ exports[`Multi layer fee message when balance and token price checker is disable class="transaction-detail-item__row" >
    Amount + fees
    @@ -87,7 +87,7 @@ exports[`Multi layer fee message when balance and token price checker is enabled class="transaction-detail-item__row" >
    Layer 1 fees
    @@ -95,12 +95,12 @@ exports[`Multi layer fee message when balance and token price checker is enabled class="transaction-detail-item__detail-values" >
    Unknown
    Unknown
    @@ -110,10 +110,10 @@ exports[`Multi layer fee message when balance and token price checker is enabled class="transaction-detail-item__row" >
    @@ -124,7 +124,7 @@ exports[`Multi layer fee message when balance and token price checker is enabled class="transaction-detail-item__row" >
    Total
    @@ -132,24 +132,21 @@ exports[`Multi layer fee message when balance and token price checker is enabled class="transaction-detail-item__detail-values" >
    - $0.56
    0.001000021000 ETH
    @@ -159,12 +156,12 @@ exports[`Multi layer fee message when balance and token price checker is enabled class="transaction-detail-item__row" >
    Amount + fees
    diff --git a/ui/components/app/nft-default-image/__snapshots__/nft-default-image.test.js.snap b/ui/components/app/nft-default-image/__snapshots__/nft-default-image.test.js.snap index e70892df2..7fd606daa 100644 --- a/ui/components/app/nft-default-image/__snapshots__/nft-default-image.test.js.snap +++ b/ui/components/app/nft-default-image/__snapshots__/nft-default-image.test.js.snap @@ -8,7 +8,7 @@ exports[`NFT Default Image should match snapshot with all provided props 1`] = ` tabindex="0" >
    NFT Name @@ -28,7 +28,7 @@ exports[`NFT Default Image should match snapshot with missing clickable prop 1`] tabindex="0" >
    NFT Name @@ -48,7 +48,7 @@ exports[`NFT Default Image should render with no props 1`] = ` tabindex="0" >
    [unknownCollection] diff --git a/ui/components/app/nft-details/__snapshots__/nft-details.test.js.snap b/ui/components/app/nft-details/__snapshots__/nft-details.test.js.snap index 6be92d2bd..6ce126fef 100644 --- a/ui/components/app/nft-details/__snapshots__/nft-details.test.js.snap +++ b/ui/components/app/nft-details/__snapshots__/nft-details.test.js.snap @@ -9,7 +9,7 @@ exports[`NFT Details should match minimal props and state snapshot 1`] = ` class="asset-breadcrumb" > @@ -30,7 +30,7 @@ exports[`NFT Details should match minimal props and state snapshot 1`] = ` data-testid="nft-options__button" > @@ -50,7 +50,7 @@ exports[`NFT Details should match minimal props and state snapshot 1`] = ` data-testid="nft-item" >
    MUNK #1 1
    - G + C
    @@ -77,12 +77,12 @@ exports[`NFT Details should match minimal props and state snapshot 1`] = ` >

    MUNK #1

    # 1 @@ -109,7 +109,7 @@ exports[`NFT Details should match minimal props and state snapshot 1`] = ` class="box box--display-flex box--flex-direction-row" >
    @@ -117,7 +117,7 @@ exports[`NFT Details should match minimal props and state snapshot 1`] = ` class="box nft-details__contract-wrapper box--display-flex box--flex-direction-row" >
    1/18/2023
    @@ -127,7 +127,7 @@ exports[`NFT Details should match minimal props and state snapshot 1`] = ` class="box box--display-flex box--flex-direction-row" > @@ -135,7 +135,7 @@ exports[`NFT Details should match minimal props and state snapshot 1`] = ` class="box nft-details__contract-wrapper box--display-flex box--flex-direction-row" >
    0.0049 ETH
    @@ -145,12 +145,12 @@ exports[`NFT Details should match minimal props and state snapshot 1`] = ` class="box box--display-flex box--flex-direction-row" >
    @@ -174,7 +174,7 @@ exports[`NFT Details should match minimal props and state snapshot 1`] = ` class="box nft-details__contract-wrapper box--display-flex box--flex-direction-row" >
    0xDc7...6414
    @@ -195,7 +195,7 @@ exports[`NFT Details should match minimal props and state snapshot 1`] = ` data-testid="nft-address-copy" > @@ -204,7 +204,7 @@ exports[`NFT Details should match minimal props and state snapshot 1`] = `
    Disclaimer: MetaMask pulls the media file from the source url. This url sometimes is changed by the marketplace the NFT was minted on.
    diff --git a/ui/components/app/nft-details/nft-details.js b/ui/components/app/nft-details/nft-details.js index c0a9cbd33..f36b3bbe9 100644 --- a/ui/components/app/nft-details/nft-details.js +++ b/ui/components/app/nft-details/nft-details.js @@ -111,12 +111,13 @@ export default function NftDetails({ nft }) { const getOpenSeaLink = () => { switch (currentNetwork) { case CHAIN_IDS.MAINNET: - return `https://opensea.io/assets/${address}/${tokenId}`; + return `https://opensea.io/assets/ethereum/${address}/${tokenId}`; case CHAIN_IDS.POLYGON: return `https://opensea.io/assets/matic/${address}/${tokenId}`; case CHAIN_IDS.GOERLI: + return `https://testnets.opensea.io/assets/goerli/${address}/${tokenId}`; case CHAIN_IDS.SEPOLIA: - return `https://testnets.opensea.io/assets/${address}/${tokenId}`; + return `https://testnets.opensea.io/assets/sepolia/${address}/${tokenId}`; default: return null; } diff --git a/ui/components/app/nft-details/nft-details.test.js b/ui/components/app/nft-details/nft-details.test.js index 3909406b2..7733e75ae 100644 --- a/ui/components/app/nft-details/nft-details.test.js +++ b/ui/components/app/nft-details/nft-details.test.js @@ -13,6 +13,12 @@ import { removeAndIgnoreNft, setRemoveNftMessage, } from '../../../store/actions'; +import { + CHAIN_IDS, + CURRENCY_SYMBOLS, + MAINNET_DISPLAY_NAME, + NETWORK_TYPES, +} from '../../../../shared/constants/network'; import NftDetails from './nft-details'; jest.mock('copy-to-clipboard'); @@ -159,7 +165,7 @@ describe('NFT Details', () => { await waitFor(() => { expect(global.platform.openTab).toHaveBeenCalledWith({ - url: `https://testnets.opensea.io/assets/${nfts[5].address}/${nfts[5].tokenId}`, + url: `https://testnets.opensea.io/assets/goerli/${nfts[5].address}/${nfts[5].tokenId}`, }); }); }); @@ -172,7 +178,10 @@ describe('NFT Details', () => { metamask: { ...mockState.metamask, providerConfig: { - chainId: '0x1', + chainId: CHAIN_IDS.MAINNET, + type: NETWORK_TYPES.MAINNET, + ticker: CURRENCY_SYMBOLS.ETH, + nickname: MAINNET_DISPLAY_NAME, }, }, }; @@ -191,7 +200,7 @@ describe('NFT Details', () => { await waitFor(() => { expect(global.platform.openTab).toHaveBeenCalledWith({ - url: `https://opensea.io/assets/${nfts[5].address}/${nfts[5].tokenId}`, + url: `https://opensea.io/assets/ethereum/${nfts[5].address}/${nfts[5].tokenId}`, }); }); }); @@ -203,12 +212,16 @@ describe('NFT Details', () => { ...mockState.metamask, providerConfig: { chainId: '0x89', + type: 'rpc', + id: 'custom-mainnet', }, networkConfigurations: { testNetworkConfigurationId: { rpcUrl: 'https://testrpc.com', chainId: '0x89', nickname: 'Custom Mainnet RPC', + type: 'rpc', + id: 'custom-mainnet', }, }, }, @@ -239,7 +252,8 @@ describe('NFT Details', () => { metamask: { ...mockState.metamask, providerConfig: { - chainId: '0xaa36a7', + chainId: CHAIN_IDS.SEPOLIA, + type: NETWORK_TYPES.SEPOLIA, }, }, }; @@ -258,7 +272,7 @@ describe('NFT Details', () => { await waitFor(() => { expect(global.platform.openTab).toHaveBeenCalledWith({ - url: `https://testnets.opensea.io/assets/${nfts[5].address}/${nfts[5].tokenId}`, + url: `https://testnets.opensea.io/assets/sepolia/${nfts[5].address}/${nfts[5].tokenId}`, }); }); }); diff --git a/ui/components/app/nfts-detection-notice/index.scss b/ui/components/app/nfts-detection-notice/index.scss deleted file mode 100644 index 95d13a24c..000000000 --- a/ui/components/app/nfts-detection-notice/index.scss +++ /dev/null @@ -1,25 +0,0 @@ -.nfts-detection-notice { - margin: 16px 16px 0 16px; - - &__message { - position: relative; - padding: 0.75rem 0.75rem 1rem 0.75rem !important; - - & &__close-button { - color: var(--color-icon-default); - background: none; - position: absolute; - cursor: pointer; - right: 8px; - } - - a.nfts-detection-notice__message__link { - @include H7; - - width: 100%; - padding: 0; - justify-content: flex-start; - font-weight: bold; - } - } -} diff --git a/ui/components/app/nfts-detection-notice/nfts-detection-notice.js b/ui/components/app/nfts-detection-notice/nfts-detection-notice.js index f93718906..1b17ad786 100644 --- a/ui/components/app/nfts-detection-notice/nfts-detection-notice.js +++ b/ui/components/app/nfts-detection-notice/nfts-detection-notice.js @@ -1,18 +1,7 @@ import React from 'react'; import { useHistory } from 'react-router-dom'; -import Box from '../../ui/box'; -import Dialog from '../../ui/dialog'; -import { Icon, IconName, Text } from '../../component-library'; -import { - TextVariant, - TextAlign, - FontWeight, - DISPLAY, - TextColor, - IconColor, -} from '../../../helpers/constants/design-system'; +import { BannerAlert } from '../../component-library'; import { useI18nContext } from '../../../hooks/useI18nContext'; -import Button from '../../ui/button'; import { EXPERIMENTAL_ROUTE } from '../../../helpers/constants/routes'; export default function NftsDetectionNotice() { @@ -20,48 +9,16 @@ export default function NftsDetectionNotice() { const history = useHistory(); return ( - - - - - - - - - {t('newNFTsDetected')} - - - {t('newNFTDetectedMessage')} - - - - - - + { + e.preventDefault(); + history.push(`${EXPERIMENTAL_ROUTE}#autodetect-nfts`); + }} + > + {t('newNFTDetectedMessage')} + ); } diff --git a/ui/components/app/nfts-tab/nfts-tab.js b/ui/components/app/nfts-tab/nfts-tab.js index 69f9b3e11..2e1918c0d 100644 --- a/ui/components/app/nfts-tab/nfts-tab.js +++ b/ui/components/app/nfts-tab/nfts-tab.js @@ -1,5 +1,4 @@ import React from 'react'; -import PropTypes from 'prop-types'; import { useDispatch, useSelector } from 'react-redux'; import { useHistory } from 'react-router-dom'; import NftsItems from '../nfts-items'; @@ -19,13 +18,14 @@ import { EXPERIMENTAL_ROUTE } from '../../../helpers/constants/routes'; import { checkAndUpdateAllNftsOwnershipStatus, detectNfts, + showImportNftsModal, } from '../../../store/actions'; import { useNftsCollections } from '../../../hooks/useNftsCollections'; import { Box, ButtonLink, IconName, Text } from '../../component-library'; import NftsDetectionNotice from '../nfts-detection-notice'; import ZENDESK_URLS from '../../../helpers/constants/zendesk-url'; -export default function NftsTab({ onAddNFT }) { +export default function NftsTab() { const useNftDetection = useSelector(getUseNftDetection); const isMainnet = useSelector(getIsMainnet); const history = useHistory(); @@ -60,7 +60,11 @@ export default function NftsTab({ onAddNFT }) { /> ) : ( <> - {isMainnet && !useNftDetection ? : null}{' '} + {isMainnet && !useNftDetection ? ( + + + + ) : null} @@ -113,7 +116,9 @@ export default function NftsTab({ onAddNFT }) { size={Size.MD} data-testid="import-nft-button" startIconName={IconName.Add} - onClick={onAddNFT} + onClick={() => { + dispatch(showImportNftsModal()); + }} > {t('importNFT')} @@ -149,7 +154,3 @@ export default function NftsTab({ onAddNFT }) { ); } - -NftsTab.propTypes = { - onAddNFT: PropTypes.func.isRequired, -}; diff --git a/ui/components/app/nfts-tab/nfts-tab.test.js b/ui/components/app/nfts-tab/nfts-tab.test.js index 2cc2048d1..1bdd19e8a 100644 --- a/ui/components/app/nfts-tab/nfts-tab.test.js +++ b/ui/components/app/nfts-tab/nfts-tab.test.js @@ -150,7 +150,6 @@ const render = ({ selectedAddress, chainId = '0x1', useNftDetection, - onAddNFT = jest.fn(), }) => { const store = configureStore({ metamask: { @@ -170,7 +169,7 @@ const render = ({ nftsDropdownState, }, }); - return renderWithProvider(, store); + return renderWithProvider(, store); }; describe('NFT Items', () => { @@ -295,16 +294,5 @@ describe('NFT Items', () => { expect(historyPushMock).toHaveBeenCalledTimes(1); expect(historyPushMock).toHaveBeenCalledWith(EXPERIMENTAL_ROUTE); }); - it('should render a link "Import NFTs" when some NFTs are present, which, when clicked calls the passed in onAddNFT method', () => { - const onAddNFTStub = jest.fn(); - render({ - selectedAddress: ACCOUNT_1, - nfts: NFTS, - onAddNFT: onAddNFTStub, - }); - expect(onAddNFTStub).toHaveBeenCalledTimes(0); - fireEvent.click(screen.queryByText('Import NFT')); - expect(onAddNFTStub).toHaveBeenCalledTimes(1); - }); }); }); diff --git a/ui/components/app/permission-cell/permission-cell.js b/ui/components/app/permission-cell/permission-cell.js index c5fca8fa8..ea8f49c34 100644 --- a/ui/components/app/permission-cell/permission-cell.js +++ b/ui/components/app/permission-cell/permission-cell.js @@ -13,10 +13,10 @@ import { } from '../../../helpers/constants/design-system'; import { AvatarIcon, - Text, Icon, IconName, IconSize, + Text, } from '../../component-library'; import { formatDate } from '../../../helpers/utils/util'; import { useI18nContext } from '../../../hooks/useI18nContext'; diff --git a/ui/components/app/qr-hardware-popover/qr-hardware-sign-request/player.js b/ui/components/app/qr-hardware-popover/qr-hardware-sign-request/player.js index 1ac48080b..fcd03f7b7 100644 --- a/ui/components/app/qr-hardware-popover/qr-hardware-sign-request/player.js +++ b/ui/components/app/qr-hardware-popover/qr-hardware-sign-request/player.js @@ -2,16 +2,15 @@ import React, { useEffect, useMemo, useState } from 'react'; import QRCode from 'qrcode.react'; import { UR, UREncoder } from '@ngraveio/bc-ur'; import PropTypes from 'prop-types'; -import Box from '../../../ui/box'; import { useI18nContext } from '../../../../hooks/useI18nContext'; import { AlignItems, - DISPLAY, - FLEX_DIRECTION, + Display, + FlexDirection, TextAlign, } from '../../../../helpers/constants/design-system'; import { PageContainerFooter } from '../../../ui/page-container'; -import { Text } from '../../../component-library'; +import { Text, Box } from '../../../component-library'; const Player = ({ type, cbor, cancelQRHardwareSignRequest, toRead }) => { const t = useI18nContext(); @@ -39,9 +38,9 @@ const Player = ({ type, cbor, cancelQRHardwareSignRequest, toRead }) => {
    ; + +DefaultStory.storyName = 'Default'; diff --git a/ui/components/app/security-provider-banner-alert/__snapshots__/security-provider-banner-alert.test.js.snap b/ui/components/app/security-provider-banner-alert/__snapshots__/security-provider-banner-alert.test.js.snap new file mode 100644 index 000000000..db26f9e91 --- /dev/null +++ b/ui/components/app/security-provider-banner-alert/__snapshots__/security-provider-banner-alert.test.js.snap @@ -0,0 +1,73 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Security Provider Banner Alert should match snapshot 1`] = ` +
    +
    + +
    +
    + Malicious third party detected +
    +

    + This is a description to warn the user of malicious or suspicious transactions. +

    +
    +
    + +

    + [seeDetails] +

    + +
    +
    +
      +
    • + List item +
    • +
    • + List item +
    • +
    • + List item +
    • +
    +
    +
    +
    +

    + + [securityProviderAdviceBy] +

    +
    +
    +
    +`; diff --git a/ui/components/app/security-provider-banner-alert/blockaid-banner-alert/__snapshots__/blockaid-banner-alert.test.js.snap b/ui/components/app/security-provider-banner-alert/blockaid-banner-alert/__snapshots__/blockaid-banner-alert.test.js.snap new file mode 100644 index 000000000..23b9c5825 --- /dev/null +++ b/ui/components/app/security-provider-banner-alert/blockaid-banner-alert/__snapshots__/blockaid-banner-alert.test.js.snap @@ -0,0 +1,179 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Blockaid Banner Alert should render 'danger' UI when ppomResponse.resultType is 'Malicious 1`] = ` +
    +`; + +exports[`Blockaid Banner Alert should render 'warning' UI when ppomResponse.resultType is 'Warning 1`] = ` +
    + +
    +
    + This is a deceptive request +
    +

    + If you approve this request, a third party known for scams might take all your assets. +

    +

    + + + + Security advice by + + Blockaid + + + + +

    +
    +
    +`; + +exports[`Blockaid Banner Alert should render details when provided 1`] = ` +
    +
    + +
    +
    + This is a deceptive request +
    +

    + If you approve this request, a third party known for scams might take all your assets. +

    +
    +
    + +

    + See details +

    + +
    +
    +
      +
    • + • + Operator is an EOA +
    • +
    • + • + Operator is untrusted according to previous activity +
    • +
    +
    +
    +
    +

    + + + + Security advice by + + Blockaid + + + + +

    +
    +
    +
    +`; diff --git a/ui/components/app/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.js b/ui/components/app/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.js new file mode 100644 index 000000000..1ced5b805 --- /dev/null +++ b/ui/components/app/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.js @@ -0,0 +1,90 @@ +import React, { useContext } from 'react'; +import PropTypes from 'prop-types'; +import { captureException } from '@sentry/browser'; + +import { Text } from '../../../component-library'; +import { Severity } from '../../../../helpers/constants/design-system'; +import { I18nContext } from '../../../../contexts/i18n'; + +import { + BlockaidReason, + BlockaidResultType, + SecurityProvider, +} from '../../../../../shared/constants/security-provider'; +import SecurityProviderBannerAlert from '../security-provider-banner-alert'; + +/** Reason to description translation key mapping. Grouped by translations. */ +const REASON_TO_DESCRIPTION_TKEY = Object.freeze({ + [BlockaidReason.approvalFarming]: 'blockaidDescriptionApproveFarming', + [BlockaidReason.permitFarming]: 'blockaidDescriptionApproveFarming', + [BlockaidReason.setApprovalForAll]: 'blockaidDescriptionApproveFarming', + + [BlockaidReason.blurFarming]: 'blockaidDescriptionBlurFarming', + + [BlockaidReason.seaportFarming]: 'blockaidDescriptionSeaportFarming', + + [BlockaidReason.maliciousDomain]: 'blockaidDescriptionMaliciousDomain', + + [BlockaidReason.rawSignatureFarming]: 'blockaidDescriptionMightLoseAssets', + [BlockaidReason.tradeOrderFarming]: 'blockaidDescriptionMightLoseAssets', + [BlockaidReason.unfairTrade]: 'blockaidDescriptionMightLoseAssets', + + [BlockaidReason.rawNativeTokenTransfer]: 'blockaidDescriptionTransferFarming', + [BlockaidReason.transferFarming]: 'blockaidDescriptionTransferFarming', + [BlockaidReason.transferFromFarming]: 'blockaidDescriptionTransferFarming', + + [BlockaidReason.other]: 'blockaidDescriptionMightLoseAssets', +}); + +/** List of suspicious reason(s). Other reasons will be deemed as deceptive. */ +const SUSPCIOUS_REASON = [BlockaidReason.rawSignatureFarming]; + +function BlockaidBannerAlert({ + ppomResponse: { reason, resultType, features }, +}) { + const t = useContext(I18nContext); + + if (resultType === BlockaidResultType.Benign) { + return null; + } + + if (!REASON_TO_DESCRIPTION_TKEY[reason]) { + captureException(`BlockaidBannerAlert: Unidentified reason '${reason}'`); + } + + const description = t(REASON_TO_DESCRIPTION_TKEY[reason] || 'other'); + + const details = Boolean(features?.length) && ( + + {features.map((feature, i) => ( +
  • • {feature}
  • + ))} +
    + ); + + const severity = + resultType === BlockaidResultType.Malicious + ? Severity.Danger + : Severity.Warning; + + const title = + SUSPCIOUS_REASON.indexOf(reason) > -1 + ? t('blockaidTitleSuspicious') + : t('blockaidTitleDeceptive'); + + return ( + + ); +} + +BlockaidBannerAlert.propTypes = { + ppomResponse: PropTypes.object, +}; + +export default BlockaidBannerAlert; diff --git a/ui/components/app/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.stories.js b/ui/components/app/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.stories.js new file mode 100644 index 000000000..c12130871 --- /dev/null +++ b/ui/components/app/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.stories.js @@ -0,0 +1,42 @@ +import React from 'react'; +import { + BlockaidReason, + BlockaidResultType, +} from '../../../../../shared/constants/security-provider'; +import BlockaidBannerAlert from '.'; + +const mockFeatures = [ + 'Operator is an EOA', + 'Operator is untrusted according to previous activity', +]; + +export default { + title: 'Components/App/SecurityProviderBannerAlert/BlockaidBannerAlert', + argTypes: { + features: { + control: 'array', + description: + 'ppomResponse.features value which is a list displayed as SecurityProviderBannerAlert details', + }, + reason: { + control: 'select', + options: Object.values(BlockaidReason), + description: 'ppomResponse.reason value', + }, + resultType: { + control: 'select', + options: Object.values(BlockaidResultType), + description: 'ppomResponse.resultType value', + }, + }, + args: { + features: mockFeatures, + reason: BlockaidReason.setApprovalForAll, + resultType: BlockaidResultType.Warning, + }, +}; + +export const DefaultStory = (args) => ( + +); +DefaultStory.storyName = 'Default'; diff --git a/ui/components/app/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.test.js b/ui/components/app/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.test.js new file mode 100644 index 000000000..7e7188645 --- /dev/null +++ b/ui/components/app/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.test.js @@ -0,0 +1,144 @@ +import React from 'react'; +import { renderWithLocalization } from '../../../../../test/lib/render-helpers'; +import { Severity } from '../../../../helpers/constants/design-system'; +import { + BlockaidReason, + BlockaidResultType, +} from '../../../../../shared/constants/security-provider'; +import BlockaidBannerAlert from '.'; + +const mockPpomResponse = { + resultType: BlockaidResultType.Warning, + reason: BlockaidReason.setApprovalForAll, + description: + 'A SetApprovalForAll request was made on {contract}. We found the operator {operator} to be malicious', + args: { + contract: '0xa7206d878c5c3871826dfdb42191c49b1d11f466', + operator: '0x92a3b9773b1763efa556f55ccbeb20441962d9b2', + }, +}; + +describe('Blockaid Banner Alert', () => { + it(`should not render when ppomResponse.resultType is '${BlockaidResultType.Benign}'`, () => { + const { container } = renderWithLocalization( + , + ); + + expect(container.querySelector('.mm-banner-alert')).toBeNull(); + }); + + it(`should render '${Severity.Danger}' UI when ppomResponse.resultType is '${BlockaidResultType.Malicious}`, () => { + const { container } = renderWithLocalization( + , + ); + const dangerBannerAlert = container.querySelector( + '.mm-banner-alert--severity-danger', + ); + + expect(dangerBannerAlert).toBeInTheDocument(); + expect(dangerBannerAlert).toMatchSnapshot(); + }); + + it(`should render '${Severity.Warning}' UI when ppomResponse.resultType is '${BlockaidResultType.Warning}`, () => { + const { container } = renderWithLocalization( + , + ); + const warningBannerAlert = container.querySelector( + '.mm-banner-alert--severity-warning', + ); + + expect(warningBannerAlert).toBeInTheDocument(); + expect(warningBannerAlert).toMatchSnapshot(); + }); + + it('should render title, "This is a deceptive request"', () => { + const { getByText } = renderWithLocalization( + , + ); + + expect(getByText('This is a deceptive request')).toBeInTheDocument(); + }); + + it('should render title, "This is a suspicious request", when the reason is "raw_signature_farming"', () => { + const { getByText } = renderWithLocalization( + , + ); + + expect(getByText('This is a suspicious request')).toBeInTheDocument(); + }); + + it('should render details when provided', () => { + const mockFeatures = [ + 'Operator is an EOA', + 'Operator is untrusted according to previous activity', + ]; + + const { container, getByText } = renderWithLocalization( + , + ); + + expect(container).toMatchSnapshot(); + expect(container.querySelector('.disclosure')).toBeInTheDocument(); + mockFeatures.forEach((feature) => { + expect(getByText(`• ${feature}`)).toBeInTheDocument(); + }); + }); + + describe('when rendering description', () => { + Object.entries({ + [BlockaidReason.approvalFarming]: + 'If you approve this request, a third party known for scams might take all your assets.', + [BlockaidReason.blurFarming]: + 'If you approve this request, someone can steal your assets listed on Blur.', + [BlockaidReason.maliciousDomain]: + "You're interacting with a malicious domain. If you approve this request, you might lose your assets.", + [BlockaidReason.other]: + 'If you approve this request, you might lose your assets.', + [BlockaidReason.permitFarming]: + 'If you approve this request, a third party known for scams might take all your assets.', + [BlockaidReason.rawNativeTokenTransfer]: + 'If you approve this request, a third party known for scams will take all your assets.', + [BlockaidReason.rawSignatureFarming]: + 'If you approve this request, you might lose your assets.', + [BlockaidReason.seaportFarming]: + 'If you approve this request, someone can steal your assets listed on OpenSea.', + [BlockaidReason.setApprovalForAll]: + 'If you approve this request, a third party known for scams might take all your assets.', + [BlockaidReason.tradeOrderFarming]: + 'If you approve this request, you might lose your assets.', + [BlockaidReason.transferFromFarming]: + 'If you approve this request, a third party known for scams will take all your assets.', + [BlockaidReason.transferFarming]: + 'If you approve this request, a third party known for scams will take all your assets.', + [BlockaidReason.unfairTrade]: + 'If you approve this request, you might lose your assets.', + }).forEach(([reason, expectedDescription]) => { + it(`should render for '${reason}' correctly`, () => { + const { getByText } = renderWithLocalization( + , + ); + + expect(getByText(expectedDescription)).toBeInTheDocument(); + }); + }); + }); +}); diff --git a/ui/components/app/security-provider-banner-alert/blockaid-banner-alert/index.js b/ui/components/app/security-provider-banner-alert/blockaid-banner-alert/index.js new file mode 100644 index 000000000..693cf2748 --- /dev/null +++ b/ui/components/app/security-provider-banner-alert/blockaid-banner-alert/index.js @@ -0,0 +1 @@ +export { default } from './blockaid-banner-alert'; diff --git a/ui/components/app/security-provider-banner-alert/index.js b/ui/components/app/security-provider-banner-alert/index.js new file mode 100644 index 000000000..f89920127 --- /dev/null +++ b/ui/components/app/security-provider-banner-alert/index.js @@ -0,0 +1 @@ +export { default } from './security-provider-banner-alert'; diff --git a/ui/components/app/security-provider-banner-alert/security-provider-banner-alert.js b/ui/components/app/security-provider-banner-alert/security-provider-banner-alert.js new file mode 100644 index 000000000..f6046d4e9 --- /dev/null +++ b/ui/components/app/security-provider-banner-alert/security-provider-banner-alert.js @@ -0,0 +1,104 @@ +import React, { useContext } from 'react'; +import PropTypes from 'prop-types'; +import { + BannerAlert, + ButtonLink, + Icon, + IconName, + IconSize, + Text, +} from '../../component-library'; +import Disclosure from '../../ui/disclosure'; +import { DisclosureVariant } from '../../ui/disclosure/disclosure.constants'; + +import { I18nContext } from '../../../contexts/i18n'; +import { + AlignItems, + Color, + IconColor, + Severity, + Size, + TextVariant, +} from '../../../helpers/constants/design-system'; + +import { + SecurityProvider, + SECURITY_PROVIDER_CONFIG, +} from '../../../../shared/constants/security-provider'; + +function SecurityProviderBannerAlert({ + description, + details, + provider, + severity, + title, +}) { + const t = useContext(I18nContext); + + return ( + + {description} + + {details && ( + + {details} + + )} + + + + {t('securityProviderAdviceBy', [ + + {t(SECURITY_PROVIDER_CONFIG[provider].tKeyName)} + , + ])} + + + ); +} + +SecurityProviderBannerAlert.propTypes = { + /** Description content that may be plain text or contain hyperlinks */ + description: PropTypes.oneOfType([PropTypes.string, PropTypes.element]) + .isRequired, + + /** Name of the security provider */ + provider: PropTypes.oneOfType(Object.values(SecurityProvider)).isRequired, + + /** Severity level */ + severity: PropTypes.oneOfType([Severity.Danger, Severity.Warning]).isRequired, + + /** Title to be passed as param */ + title: PropTypes.string.isRequired, + + /** + * Optional + */ + + /** Additional details to be displayed under the description */ + details: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), +}; + +export default SecurityProviderBannerAlert; diff --git a/ui/components/app/security-provider-banner-alert/security-provider-banner-alert.stories.js b/ui/components/app/security-provider-banner-alert/security-provider-banner-alert.stories.js new file mode 100644 index 000000000..c78ce3f8f --- /dev/null +++ b/ui/components/app/security-provider-banner-alert/security-provider-banner-alert.stories.js @@ -0,0 +1,87 @@ +import React from 'react'; +import { Severity } from '../../../helpers/constants/design-system'; +import { ButtonLink, BUTTON_LINK_SIZES, Text } from '../../component-library'; +import { SecurityProvider } from '../../../../shared/constants/security-provider'; +import SecurityProviderBannerAlert from './security-provider-banner-alert'; + +const mockPlainText = + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus sapien tellus, elementum sit ' + + 'amet laoreet vitae, semper in est. Nulla vel tristique felis. Donec non tellus eget neque cursus malesuada.'; + +const MockDescriptionWithLinks = () => ( + <> + Description shouldn’t repeat title. 1-3 lines. Can contain a{' '} + hyperlink. It can + also contain a toggle to enable progressive disclosure. + +); + +const MockDetailsList = () => ( + +
  • • List item
  • +
  • • List item
  • +
  • • List item
  • +
  • • List item
  • +
    +); + +export default { + title: 'Components/App/SecurityProviderBannerAlert', + argTypes: { + description: { + control: { + type: 'select', + }, + options: ['plainText', 'withLinks'], + mapping: { + plainText: mockPlainText, + withLinks: , + }, + }, + details: { + control: { + type: 'select', + }, + options: ['none', 'plainText', 'withList'], + mapping: { + none: null, + plainText: mockPlainText, + withList: , + }, + }, + provider: { + control: { + type: 'select', + }, + options: [Object.values(SecurityProvider)], + }, + severity: { + control: { + type: 'select', + }, + options: [Severity.Danger, Severity.Warning], + }, + title: { + control: 'text', + }, + }, + args: { + title: 'Title is sentence case no period', + description: , + details: , + provider: SecurityProvider.Blockaid, + }, +}; + +export const DefaultStory = (args) => ( + +); +DefaultStory.storyName = 'Default'; + +export const Danger = (args) => ( + +); + +export const Warning = (args) => ( + +); diff --git a/ui/components/app/security-provider-banner-alert/security-provider-banner-alert.test.js b/ui/components/app/security-provider-banner-alert/security-provider-banner-alert.test.js new file mode 100644 index 000000000..c11a1202e --- /dev/null +++ b/ui/components/app/security-provider-banner-alert/security-provider-banner-alert.test.js @@ -0,0 +1,61 @@ +import React from 'react'; +import { Severity } from '../../../helpers/constants/design-system'; +import { renderWithProvider } from '../../../../test/lib/render-helpers'; +import { SecurityProvider } from '../../../../shared/constants/security-provider'; +import SecurityProviderBannerAlert from '.'; + +const mockTitle = 'Malicious third party detected'; +const mockDescription = + 'This is a description to warn the user of malicious or suspicious transactions.'; +const mockDetails = ( +
      +
    • List item
    • +
    • List item
    • +
    • List item
    • +
    +); + +describe('Security Provider Banner Alert', () => { + it('should match snapshot', () => { + const { container } = renderWithProvider( + , + ); + + expect(container).toMatchSnapshot(); + }); + + it('should render', () => { + const { container, getByText } = renderWithProvider( + , + ); + + expect(getByText(mockTitle)).toBeInTheDocument(); + expect(getByText(mockDescription)).toBeInTheDocument(); + expect(container.querySelector('.disclosure')).toBeInTheDocument(); + }); + + it('should not render disclosure component if no details were provided', () => { + const { container } = renderWithProvider( + , + ); + + expect(container.querySelector('.disclosure')).not.toBeInTheDocument(); + }); +}); diff --git a/ui/components/app/selected-account/__snapshots__/selected-account-component.test.js.snap b/ui/components/app/selected-account/__snapshots__/selected-account-component.test.js.snap index 6031f8d0b..32e618365 100644 --- a/ui/components/app/selected-account/__snapshots__/selected-account-component.test.js.snap +++ b/ui/components/app/selected-account/__snapshots__/selected-account-component.test.js.snap @@ -33,7 +33,7 @@ exports[`SelectedAccount Component should match snapshot 1`] = ` class="selected-account__copy" >
    diff --git a/ui/components/app/set-approval-for-all-warning/set-approval-for-all-warning.js b/ui/components/app/set-approval-for-all-warning/set-approval-for-all-warning.js index c311eaeb2..424fca315 100644 --- a/ui/components/app/set-approval-for-all-warning/set-approval-for-all-warning.js +++ b/ui/components/app/set-approval-for-all-warning/set-approval-for-all-warning.js @@ -16,9 +16,9 @@ import { shortenAddress } from '../../../helpers/utils/util'; import { Icon, IconName, - Text, Button, BUTTON_VARIANT, + Text, } from '../../component-library'; const SetApproveForAllWarning = ({ diff --git a/ui/components/app/signature-request-header/__snapshots__/signature-request-header.test.js.snap b/ui/components/app/signature-request-header/__snapshots__/signature-request-header.test.js.snap index 58642cc3e..26c4468e8 100644 --- a/ui/components/app/signature-request-header/__snapshots__/signature-request-header.test.js.snap +++ b/ui/components/app/signature-request-header/__snapshots__/signature-request-header.test.js.snap @@ -69,12 +69,12 @@ exports[`SignatureRequestHeader should match snapshot 1`] = ` class="box box--display-flex box--flex-direction-column box--align-items-flex-start" >
    Unknown private network
    Test Account
    @@ -84,13 +84,13 @@ exports[`SignatureRequestHeader should match snapshot 1`] = ` class="box box--display-flex box--flex-direction-column box--align-items-flex-end" >
    Balance
    966.987986 diff --git a/ui/components/app/signature-request-original/__snapshots__/signature-request-original.test.js.snap b/ui/components/app/signature-request-original/__snapshots__/signature-request-original.test.js.snap index 368ebeec2..6cd7195bd 100644 --- a/ui/components/app/signature-request-original/__snapshots__/signature-request-original.test.js.snap +++ b/ui/components/app/signature-request-original/__snapshots__/signature-request-original.test.js.snap @@ -145,12 +145,12 @@ exports[`SignatureRequestOriginal should match snapshot 1`] = ` class="box box--display-flex box--flex-direction-column box--align-items-flex-start" >
    Unknown private network
    Test Account
    @@ -160,13 +160,13 @@ exports[`SignatureRequestOriginal should match snapshot 1`] = ` class="box box--display-flex box--flex-direction-column box--align-items-flex-end" >
    Balance
    966.987986 diff --git a/ui/components/app/signature-request-original/signature-request-original-warning/signature-request-original-warning.js b/ui/components/app/signature-request-original/signature-request-original-warning/signature-request-original-warning.js index 13ac14b76..c792ddb38 100644 --- a/ui/components/app/signature-request-original/signature-request-original-warning/signature-request-original-warning.js +++ b/ui/components/app/signature-request-original/signature-request-original-warning/signature-request-original-warning.js @@ -3,21 +3,18 @@ import PropTypes from 'prop-types'; import { useI18nContext } from '../../../../hooks/useI18nContext'; import Popover from '../../../ui/popover'; -import Box from '../../../ui/box'; -import Button from '../../../ui/button'; -import Typography from '../../../ui/typography'; import { IconColor, - DISPLAY, - FLEX_DIRECTION, - FONT_WEIGHT, + Display, + FlexDirection, + FontWeight, JustifyContent, TextColor, - TypographyVariant, + TextVariant, } from '../../../../helpers/constants/design-system'; import Identicon from '../../../ui/identicon'; import { shortenAddress } from '../../../../helpers/utils/util'; -import { Icon, IconName } from '../../../component-library'; +import { Icon, IconName, Box, Text, Button } from '../../../component-library'; const SignatureRequestOriginalWarning = ({ senderAddress, @@ -30,8 +27,8 @@ const SignatureRequestOriginalWarning = ({ return ( @@ -40,37 +37,36 @@ const SignatureRequestOriginalWarning = ({ color={IconColor.errorDefault} className="signature-request-warning__content__header__warning-icon" /> - + {t('yourFundsMayBeAtRisk')} - + - + - {name} {` (${shortenAddress(senderAddress)})`} - + - {t('signatureRequestWarning', [ , ])} - + ( + +); + +DefaultStory.storyName = 'Default'; diff --git a/ui/components/app/signature-request-original/signature-request-original.component.js b/ui/components/app/signature-request-original/signature-request-original.component.js index 6dc18e4a4..fbd13dba9 100644 --- a/ui/components/app/signature-request-original/signature-request-original.component.js +++ b/ui/components/app/signature-request-original/signature-request-original.component.js @@ -3,6 +3,9 @@ import PropTypes from 'prop-types'; import classnames from 'classnames'; import { ObjectInspector } from 'react-inspector'; import { ethErrors, serializeError } from 'eth-rpc-errors'; +///: BEGIN:ONLY_INCLUDE_IN(snaps) +import { SubjectType } from '@metamask/permission-controller'; +///: END:ONLY_INCLUDE_IN import LedgerInstructionField from '../ledger-instruction-field'; import { MESSAGE_TYPE } from '../../../../shared/constants/app'; import { @@ -14,7 +17,6 @@ import { } from '../../../helpers/utils/util'; import { stripHexPrefix } from '../../../../shared/modules/hexstring-utils'; import { isSuspiciousResponse } from '../../../../shared/modules/security-provider.utils'; -import Button from '../../ui/button'; import SiteOrigin from '../../ui/site-origin'; import Typography from '../../ui/typography/typography'; import { PageContainerFooter } from '../../ui/page-container'; @@ -23,6 +25,7 @@ import { FontWeight, TextAlign, TextColor, + Size, ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) IconColor, DISPLAY, @@ -31,13 +34,24 @@ import { BackgroundColor, ///: END:ONLY_INCLUDE_IN } from '../../../helpers/constants/design-system'; -import ConfirmPageContainerNavigation from '../confirm-page-container/confirm-page-container-navigation'; -import SecurityProviderBannerMessage from '../security-provider-banner-message/security-provider-banner-message'; +import { + ButtonLink, + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + Icon, + IconName, + Text, + ///: END:ONLY_INCLUDE_IN +} from '../../component-library'; ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) -import { Icon, IconName, Text } from '../../component-library'; import Box from '../../ui/box/box'; ///: END:ONLY_INCLUDE_IN +import ConfirmPageContainerNavigation from '../confirm-page-container/confirm-page-container-navigation'; +import SecurityProviderBannerMessage from '../security-provider-banner-message/security-provider-banner-message'; + import SignatureRequestHeader from '../signature-request-header'; +///: BEGIN:ONLY_INCLUDE_IN(snaps) +import SnapLegacyAuthorshipHeader from '../snaps/snap-legacy-authorship-header'; +///: END:ONLY_INCLUDE_IN import SignatureRequestOriginalWarning from './signature-request-original-warning'; export default class SignatureRequestOriginal extends Component { @@ -50,9 +64,6 @@ export default class SignatureRequestOriginal extends Component { address: PropTypes.string.isRequired, name: PropTypes.string, }).isRequired, - clearConfirmTransaction: PropTypes.func.isRequired, - history: PropTypes.object.isRequired, - mostRecentOverviewPage: PropTypes.string.isRequired, txData: PropTypes.object.isRequired, subjectMetadata: PropTypes.object, hardwareWalletRequiresConnection: PropTypes.bool, @@ -61,6 +72,9 @@ export default class SignatureRequestOriginal extends Component { showRejectTransactionsConfirmationModal: PropTypes.func.isRequired, cancelAllApprovals: PropTypes.func.isRequired, rejectPendingApproval: PropTypes.func.isRequired, + clearConfirmTransaction: PropTypes.func.isRequired, + history: PropTypes.object.isRequired, + mostRecentOverviewPage: PropTypes.string.isRequired, resolvePendingApproval: PropTypes.func.isRequired, completedTx: PropTypes.func.isRequired, ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) @@ -171,16 +185,31 @@ export default class SignatureRequestOriginal extends Component { }
    - + { + // Use legacy authorship header for snaps + ///: BEGIN:ONLY_INCLUDE_IN(snaps) + targetSubjectMetadata?.subjectType === SubjectType.Snap ? ( + + ) : ( + ///: END:ONLY_INCLUDE_IN + + ///: BEGIN:ONLY_INCLUDE_IN(snaps) + ) + ///: END:ONLY_INCLUDE_IN + }
    { const { + resolvePendingApproval, + completedTx, clearConfirmTransaction, history, mostRecentOverviewPage, - resolvePendingApproval, - completedTx, - txData: { id }, + txData, } = this.props; + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + if (this.props.mmiOnSignCallback) { + await this.props.mmiOnSignCallback(txData); + return; + } + ///: END:ONLY_INCLUDE_IN - await resolvePendingApproval(id); - completedTx(id); + await resolvePendingApproval(txData.id); + completedTx(txData.id); clearConfirmTransaction(); history.push(mostRecentOverviewPage); }; @@ -366,13 +401,13 @@ export default class SignatureRequestOriginal extends Component { )} {this.renderFooter()} {messagesCount > 1 ? ( - + ) : null} ); diff --git a/ui/components/app/signature-request-original/signature-request-original.container.js b/ui/components/app/signature-request-original/signature-request-original.container.js index 242ace8f8..8913c1ace 100644 --- a/ui/components/app/signature-request-original/signature-request-original.container.js +++ b/ui/components/app/signature-request-original/signature-request-original.container.js @@ -17,7 +17,7 @@ import { setPersonalMessageInProgress, } from '../../../store/institutional/institution-background'; import { getEnvironmentType } from '../../../../app/scripts/lib/util'; -import { checkForUnapprovedMessages } from '../../../store/institutional/institution-actions'; +import { showCustodyConfirmLink } from '../../../store/institutional/institution-actions'; import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../../shared/constants/app'; ///: END:ONLY_INCLUDE_IN import { @@ -27,7 +27,6 @@ import { unconfirmedMessagesHashSelector, getTotalUnapprovedMessagesCount, ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) - unapprovedPersonalMsgsSelector, getAccountType, getSelectedAccount, ///: END:ONLY_INCLUDE_IN @@ -68,59 +67,12 @@ function mapStateToProps(state, ownProps) { accountType: getAccountType(state), isNotification: envType === ENVIRONMENT_TYPE_NOTIFICATION, selectedAccount: getSelectedAccount(state), - unapprovedPersonalMessages: unapprovedPersonalMsgsSelector(state), ///: END:ONLY_INCLUDE_IN }; } let mapDispatchToProps = null; -///: BEGIN:ONLY_INCLUDE_IN(build-mmi) -function mmiMapDispatchToProps(dispatch) { - const mmiActions = mmiActionsFactory(); - return { - clearConfirmTransaction: () => dispatch(clearConfirmTransaction()), - setMsgInProgress: (msgId) => dispatch(setPersonalMessageInProgress(msgId)), - showCustodianDeepLink: ({ - custodyId, - fromAddress, - closeNotification, - onDeepLinkFetched, - onDeepLinkShown, - }) => - showCustodianDeepLink({ - dispatch, - mmiActions, - txId: undefined, - fromAddress, - custodyId, - isSignature: true, - closeNotification, - onDeepLinkFetched, - onDeepLinkShown, - }), - showTransactionsFailedModal: ({ - errorMessage, - closeNotification, - operationFailed, - }) => - dispatch( - showModal({ - name: 'TRANSACTION_FAILED', - errorMessage, - closeNotification, - operationFailed, - }), - ), - setWaitForConfirmDeepLinkDialog: (wait) => - dispatch(mmiActions.setWaitForConfirmDeepLinkDialog(wait)), - goHome: () => dispatch(goHome()), - }; -} - -mapDispatchToProps = mmiMapDispatchToProps; -///: END:ONLY_INCLUDE_IN - mapDispatchToProps = function (dispatch) { return { goHome: () => dispatch(goHome()), @@ -150,6 +102,74 @@ mapDispatchToProps = function (dispatch) { }; }; +///: BEGIN:ONLY_INCLUDE_IN(build-mmi) +function mmiMapDispatchToProps(dispatch) { + const mmiActions = mmiActionsFactory(); + return { + setMsgInProgress: (msgId) => dispatch(setPersonalMessageInProgress(msgId)), + showCustodianDeepLink: ({ + custodyId, + fromAddress, + closeNotification, + onDeepLinkFetched, + onDeepLinkShown, + }) => + showCustodianDeepLink({ + dispatch, + mmiActions, + txId: undefined, + fromAddress, + custodyId, + isSignature: true, + closeNotification, + onDeepLinkFetched, + onDeepLinkShown, + showCustodyConfirmLink, + }), + showTransactionsFailedModal: ({ + errorMessage, + closeNotification, + operationFailed, + }) => + dispatch( + showModal({ + name: 'TRANSACTION_FAILED', + errorMessage, + closeNotification, + operationFailed, + }), + ), + setWaitForConfirmDeepLinkDialog: (wait) => + dispatch(mmiActions.setWaitForConfirmDeepLinkDialog(wait)), + clearConfirmTransaction: () => dispatch(clearConfirmTransaction()), + showRejectTransactionsConfirmationModal: ({ + onSubmit, + unapprovedTxCount: messagesCount, + }) => { + return dispatch( + showModal({ + name: 'REJECT_TRANSACTIONS', + onSubmit, + unapprovedTxCount: messagesCount, + isRequestType: true, + }), + ); + }, + completedTx: (txId) => dispatch(completedTx(txId)), + resolvePendingApproval: (id) => { + dispatch(resolvePendingApproval(id)); + }, + rejectPendingApproval: (id, error) => + dispatch(rejectPendingApproval(id, error)), + cancelAllApprovals: (messagesList) => { + dispatch(rejectAllMessages(messagesList)); + }, + }; +} + +mapDispatchToProps = mmiMapDispatchToProps; +///: END:ONLY_INCLUDE_IN + function mergeProps(stateProps, dispatchProps, ownProps) { const { txData } = ownProps; @@ -159,7 +179,6 @@ function mergeProps(stateProps, dispatchProps, ownProps) { ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) accountType, isNotification, - unapprovedPersonalMessages, ///: END:ONLY_INCLUDE_IN ...otherStateProps } = stateProps; @@ -176,25 +195,17 @@ function mergeProps(stateProps, dispatchProps, ownProps) { const mmiOnSignCallback = async (_msgData) => { if (accountType === 'custody') { try { - let msgData = _msgData; - let id = _msgData.custodyId; - if (!_msgData.custodyId) { - msgData = checkForUnapprovedMessages( - _msgData, - unapprovedPersonalMessages, - ); - id = msgData.custodyId; - } + await dispatchProps.resolvePendingApproval(_msgData.id); + dispatchProps.completedTx(_msgData.id); + dispatchProps.showCustodianDeepLink({ - custodyId: id, + custodyId: null, fromAddress: fromAccount.address, closeNotification: isNotification, onDeepLinkFetched: () => undefined, onDeepLinkShown: () => undefined, }); - await dispatchProps.setMsgInProgress(msgData.metamaskId); await dispatchProps.setWaitForConfirmDeepLinkDialog(true); - await goHome(); } catch (err) { await dispatchProps.setWaitForConfirmDeepLinkDialog(true); await dispatchProps.showTransactionsFailedModal({ @@ -203,6 +214,10 @@ function mergeProps(stateProps, dispatchProps, ownProps) { operationFailed: true, }); } + } else { + // Non Custody accounts follow normal flow + await dispatchProps.resolvePendingApproval(_msgData.id); + dispatchProps.completedTx(_msgData.id); } }; ///: END:ONLY_INCLUDE_IN diff --git a/ui/components/app/signature-request-siwe/__snapshots__/signature-request-siwe.test.js.snap b/ui/components/app/signature-request-siwe/__snapshots__/signature-request-siwe.test.js.snap index bf99efd34..30bf2f736 100644 --- a/ui/components/app/signature-request-siwe/__snapshots__/signature-request-siwe.test.js.snap +++ b/ui/components/app/signature-request-siwe/__snapshots__/signature-request-siwe.test.js.snap @@ -142,12 +142,12 @@ exports[`SignatureRequestSIWE (Sign in with Ethereum) should match snapshot 1`] class="box box--display-flex box--flex-direction-column box--align-items-flex-start" >
    Unknown private network
    Test Account
    @@ -157,13 +157,13 @@ exports[`SignatureRequestSIWE (Sign in with Ethereum) should match snapshot 1`] class="box box--display-flex box--flex-direction-column box--align-items-flex-end" >
    Balance
    966.987986 @@ -288,12 +288,12 @@ exports[`SignatureRequestSIWE (Sign in with Ethereum) should match snapshot 1`] class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row" >

    Message:

    Click to sign in and accept the Terms of Service: https://community.metamask.io/tos

    @@ -302,12 +302,12 @@ exports[`SignatureRequestSIWE (Sign in with Ethereum) should match snapshot 1`] class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row" >

    URI:

    http://localhost:8080

    @@ -316,12 +316,12 @@ exports[`SignatureRequestSIWE (Sign in with Ethereum) should match snapshot 1`] class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row" >

    Version:

    1

    @@ -330,12 +330,12 @@ exports[`SignatureRequestSIWE (Sign in with Ethereum) should match snapshot 1`] class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row" >

    Chain ID:

    1

    @@ -344,12 +344,12 @@ exports[`SignatureRequestSIWE (Sign in with Ethereum) should match snapshot 1`] class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row" >

    Nonce:

    STMt6KQMwwdOXE306

    @@ -358,12 +358,12 @@ exports[`SignatureRequestSIWE (Sign in with Ethereum) should match snapshot 1`] class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row" >

    Issued At:

    2023-03-18T21:40:40.823Z

    @@ -372,12 +372,12 @@ exports[`SignatureRequestSIWE (Sign in with Ethereum) should match snapshot 1`] class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row" >

    Resources: 2

    ipfs://Qme7ss3ARVgxv6rXqVPiikMJ8u2NLgmgszg13pYrDKEoiu https://example.com/my-web2-claim.json diff --git a/ui/components/app/signature-request-siwe/signature-request-siwe-icon/index.js b/ui/components/app/signature-request-siwe/signature-request-siwe-icon/index.js index ef85b2e6b..f59e36ddd 100644 --- a/ui/components/app/signature-request-siwe/signature-request-siwe-icon/index.js +++ b/ui/components/app/signature-request-siwe/signature-request-siwe-icon/index.js @@ -1,18 +1,17 @@ import React from 'react'; import { - DISPLAY, + Display, AlignItems, Color, JustifyContent, } from '../../../../helpers/constants/design-system'; -import Box from '../../../ui/box'; -import { Icon, IconName } from '../../../component-library'; +import { Icon, IconName, Box } from '../../../component-library'; const SignatureRequestSIWEIcon = () => { return ( {

    @@ -142,14 +142,14 @@ exports[`Signature Request Component render should match snapshot when we are us class="box box--display-flex box--flex-direction-column box--align-items-flex-start" >
    - Unknown private network + Localhost 8545
    - Antonio + John Doe
    @@ -157,17 +157,17 @@ exports[`Signature Request Component render should match snapshot when we are us class="box box--display-flex box--flex-direction-column box--align-items-flex-end" >
    Balance
    - 966.987986 + 0 - ABC + ETH
    @@ -179,56 +179,48 @@ exports[`Signature Request Component render should match snapshot when we are us class="signature-request__origin" >
    -
    -
    - - T - -
    -
    - test - + class="mm-box mm-icon mm-icon--size-md mm-box--display-inline-block mm-box--color-icon-default" + style="mask-image: url('./images/icons/global.svg');" + />
    +

    + test +

    -

    Signature request -

    +
    Only sign this message if you fully understand the content and trust the requesting site.
    - -
    - Verify third-party details -
    -
    +
    + Verify third-party details +
    + +

    Mail

    -
    -
    - Contents : - - +
    Hello, Bob! - -
    -
    + +
  • - From : - -
    +
      -
      - Name : - - +
      Cow - -
      -
      + +
    • - Wallets : - -
      +
        -
        - 0 : - - +
        -
        -
        - -
        -
        +
        + +
      • - 1 : - - +
        -
        -
        - -
        -
      • -
      -
    • -
      -
      +
      + +
    +
  • +
+ +
  • - To : - -
    +
      -
      - 0 : - -
      +
        -
        - Name : - - +
        Bob - -
        -
        + +
      • - Wallets : - -
        +
          -
          - 0 : - - +
          -
          -
          - -
          -
          +
          + +
        • - 1 : - - +
          -
          -
          - -
          -
          +
          +
        • +
        • - 2 : - - +
          -
          -
          - -
          -
        • -
        -
      • -
        -
      -
      -
    + + +
  • + + + + + + +
    + `; @@ -818,7 +816,7 @@ exports[`Signature Request Component render should match snapshot when we want t of - 1 + 0
    @@ -919,14 +917,14 @@ exports[`Signature Request Component render should match snapshot when we want t class="box box--display-flex box--flex-direction-column box--align-items-flex-start" >
    - Unknown private network + Localhost 8545
    - Antonio + John Doe
    @@ -934,17 +932,17 @@ exports[`Signature Request Component render should match snapshot when we want t class="box box--display-flex box--flex-direction-column box--align-items-flex-end" >
    Balance
    - 1515270.174798 + 0 - DEF + ETH
    @@ -956,56 +954,48 @@ exports[`Signature Request Component render should match snapshot when we want t class="signature-request__origin" >
    -
    -
    - - T - -
    -
    - test - + class="mm-box mm-icon mm-icon--size-md mm-box--display-inline-block mm-box--color-icon-default" + style="mask-image: url('./images/icons/global.svg');" + />
    +

    + test +

    -

    Signature request -

    +
    Only sign this message if you fully understand the content and trust the requesting site.
    - -
    - Verify third-party details -
    -
    +
    + Verify third-party details +
    + +

    Mail

    -
    -
    - Contents : - - +
    Hello, Bob! - -
    -
    + +
  • - From : - -
    +
      -
      - Name : - - +
      Cow - -
      -
      + +
    • - Wallets : - -
      +
        -
        - 0 : - - +
        -
        -
        - -
        -
        +
        + +
      • - 1 : - - +
        -
        -
        - -
        -
      • -
      -
    • -
      -
      +
      + +
    +
  • + + +
  • - To : - -
    +
      -
      - 0 : - -
      +
        -
        - Name : - - +
        Bob - -
        -
        + +
      • - Wallets : - -
        +
          -
          - 0 : - - +
          -
          -
          - -
          -
          +
          + +
        • - 1 : - - +
          -
          -
          - -
          -
          +
          +
        • +
        • - 2 : - - +
          -
          -
          - -
          -
        • -
        -
      • -
        -
      -
      -
    +
  • +
    + + + + + + + +
    + `; diff --git a/ui/components/app/signature-request/index.js b/ui/components/app/signature-request/index.js index 8a01d820e..18ba8b157 100644 --- a/ui/components/app/signature-request/index.js +++ b/ui/components/app/signature-request/index.js @@ -1 +1 @@ -export { default } from './signature-request.container'; +export { default } from './signature-request'; diff --git a/ui/components/app/signature-request/index.scss b/ui/components/app/signature-request/index.scss index 5cc2a0981..5467f2a84 100644 --- a/ui/components/app/signature-request/index.scss +++ b/ui/components/app/signature-request/index.scss @@ -14,7 +14,7 @@ border-radius: 8px; @include screen-sm-min { - max-height: 80vh; + max-height: max-content; min-height: 570px; flex: 0 0 auto; margin-left: auto; @@ -22,7 +22,7 @@ } &__reject-all-button { - margin-top: -15px; + padding-bottom: 20px; } &__origin { @@ -58,12 +58,6 @@ font-weight: 500; } - - p { - @include H6; - - color: var(--color-text-muted); - } } a.signature-request-content__verify-contract-details { diff --git a/ui/components/app/signature-request/signature-request-data/signature-request-data.js b/ui/components/app/signature-request/signature-request-data/signature-request-data.js index 82932a1de..260945aba 100644 --- a/ui/components/app/signature-request/signature-request-data/signature-request-data.js +++ b/ui/components/app/signature-request/signature-request-data/signature-request-data.js @@ -11,45 +11,46 @@ import { isValidHexAddress, toChecksumHexAddress, } from '../../../../../shared/modules/hexstring-utils'; -import Box from '../../../ui/box'; -import Typography from '../../../ui/typography'; import { - DISPLAY, - FONT_WEIGHT, - TypographyVariant, + Display, + FontWeight, + TextVariant, TextColor, } from '../../../../helpers/constants/design-system'; import { sanitizeString } from '../../../../helpers/utils/util'; +import { Box, Text } from '../../../component-library'; function SignatureRequestData({ data }) { const identities = useSelector(getMemoizedMetaMaskIdentities); return ( - + {Object.entries(data).map(([label, { value, type }], i) => ( - {sanitizeString(label.charAt(0).toUpperCase() + label.slice(1))}:{' '} - + {typeof value === 'object' && value !== null ? ( ) : ( - @@ -68,11 +70,11 @@ function SignatureRequestData({ data }) { checksummedRecipientAddress={toChecksumHexAddress(value)} recipientName={getAccountName(identities, value)} /> - + ) : ( sanitizeString(`${value}`) )} - + )} ))} diff --git a/ui/components/app/signature-request/signature-request.component.js b/ui/components/app/signature-request/signature-request.component.js deleted file mode 100644 index 97062ed60..000000000 --- a/ui/components/app/signature-request/signature-request.component.js +++ /dev/null @@ -1,422 +0,0 @@ -import React, { PureComponent } from 'react'; -import { memoize } from 'lodash'; -import PropTypes from 'prop-types'; -import { ethErrors, serializeError } from 'eth-rpc-errors'; -// import LedgerInstructionField from '../ledger-instruction-field'; -import { - sanitizeMessage, - getURLHostName, - getNetworkNameFromProviderType, - ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) - shortenAddress, - ///: END:ONLY_INCLUDE_IN -} from '../../../helpers/utils/util'; -import { MetaMetricsEventCategory } from '../../../../shared/constants/metametrics'; -import SiteOrigin from '../../ui/site-origin'; -import Button from '../../ui/button'; -import ContractDetailsModal from '../modals/contract-details-modal/contract-details-modal'; -import { - TextAlign, - TextColor, - TextVariant, - ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) - IconColor, - Display, - BlockSize, - BackgroundColor, - ///: END:ONLY_INCLUDE_IN -} from '../../../helpers/constants/design-system'; -import NetworkAccountBalanceHeader from '../network-account-balance-header'; -import { Numeric } from '../../../../shared/modules/Numeric'; -import { isSuspiciousResponse } from '../../../../shared/modules/security-provider.utils'; -import { EtherDenomination } from '../../../../shared/constants/common'; -import ConfirmPageContainerNavigation from '../confirm-page-container/confirm-page-container-navigation'; -import SecurityProviderBannerMessage from '../security-provider-banner-message/security-provider-banner-message'; -import { formatCurrency } from '../../../helpers/utils/confirm-tx.util'; -import { getValueFromWeiHex } from '../../../../shared/modules/conversion.utils'; - -import { - ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) - Box, - Icon, - IconName, - ///: END:ONLY_INCLUDE_IN - Text, -} from '../../component-library'; -import Footer from './signature-request-footer'; -import Message from './signature-request-message'; - -export default class SignatureRequest extends PureComponent { - static propTypes = { - /** - * The display content of transaction data - */ - txData: PropTypes.object.isRequired, - /** - * The display content of sender account - */ - fromAccount: PropTypes.shape({ - address: PropTypes.string.isRequired, - balance: PropTypes.string, - name: PropTypes.string, - }).isRequired, - /** - * Check if the wallet is ledget wallet or not - */ - // isLedgerWallet: PropTypes.bool, - - /** - * Whether the hardware wallet requires a connection disables the sign button if true. - */ - hardwareWalletRequiresConnection: PropTypes.bool.isRequired, - /** - * Current network chainId - */ - chainId: PropTypes.string, - /** - * RPC prefs of the current network - */ - rpcPrefs: PropTypes.object, - nativeCurrency: PropTypes.string, - currentCurrency: PropTypes.string.isRequired, - conversionRate: PropTypes.number, - providerConfig: PropTypes.object, - subjectMetadata: PropTypes.object, - unapprovedMessagesCount: PropTypes.number, - clearConfirmTransaction: PropTypes.func.isRequired, - history: PropTypes.object, - mostRecentOverviewPage: PropTypes.string, - showRejectTransactionsConfirmationModal: PropTypes.func.isRequired, - cancelAllApprovals: PropTypes.func.isRequired, - resolvePendingApproval: PropTypes.func.isRequired, - rejectPendingApproval: PropTypes.func.isRequired, - completedTx: PropTypes.func.isRequired, - ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) - showCustodianDeepLink: PropTypes.func, - isNotification: PropTypes.bool, - mmiOnSignCallback: PropTypes.func, - // Used to show a warning if the signing account is not the selected account - // Largely relevant for contract wallet custodians - selectedAccount: PropTypes.object, - ///: END:ONLY_INCLUDE_IN - }; - - static contextTypes = { - t: PropTypes.func, - trackEvent: PropTypes.func, - }; - - state = { - hasScrolledMessage: false, - showContractDetails: false, - }; - - ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) - componentDidMount() { - if (this.props.txData.custodyId) { - this.props.showCustodianDeepLink({ - custodyId: this.props.txData.custodyId, - fromAddress: this.props.fromAccount.address, - closeNotification: this.props.isNotification, - onDeepLinkFetched: () => undefined, - onDeepLinkShown: () => { - this.context.trackEvent({ - category: 'MMI', - event: 'Show deeplink for signature', - }); - }, - }); - } - } - ///: END:ONLY_INCLUDE_IN - - setMessageRootRef(ref) { - this.messageRootRef = ref; - } - - formatWallet(wallet) { - return `${wallet.slice(0, 8)}...${wallet.slice( - wallet.length - 8, - wallet.length, - )}`; - } - - memoizedParseMessage = memoize((data) => { - const { message, domain = {}, primaryType, types } = JSON.parse(data); - const sanitizedMessage = sanitizeMessage(message, primaryType, types); - return { sanitizedMessage, domain, primaryType }; - }); - - handleCancelAll = () => { - const { - clearConfirmTransaction, - history, - mostRecentOverviewPage, - showRejectTransactionsConfirmationModal, - unapprovedMessagesCount, - cancelAllApprovals, - } = this.props; - - showRejectTransactionsConfirmationModal({ - unapprovedTxCount: unapprovedMessagesCount, - onSubmit: async () => { - await cancelAllApprovals(); - clearConfirmTransaction(); - history.push(mostRecentOverviewPage); - }, - }); - }; - - render() { - const { - providerConfig, - txData: { - msgParams: { data, origin, version }, - type, - id, - }, - fromAccount: { address, balance, name }, - // isLedgerWallet, - hardwareWalletRequiresConnection, - chainId, - rpcPrefs, - txData, - subjectMetadata, - nativeCurrency, - currentCurrency, - conversionRate, - unapprovedMessagesCount, - resolvePendingApproval, - rejectPendingApproval, - completedTx, - } = this.props; - - const { t, trackEvent } = this.context; - const { - sanitizedMessage, - domain: { verifyingContract }, - primaryType, - } = this.memoizedParseMessage(data); - const rejectNText = t('rejectRequestsN', [unapprovedMessagesCount]); - const networkName = getNetworkNameFromProviderType(providerConfig.type); - const currentNetwork = - networkName === '' - ? providerConfig.nickname || t('unknownNetwork') - : t(networkName); - - const balanceInBaseAsset = conversionRate - ? formatCurrency( - getValueFromWeiHex({ - value: balance, - fromCurrency: nativeCurrency, - toCurrency: currentCurrency, - conversionRate, - numberOfDecimals: 6, - toDenomination: EtherDenomination.ETH, - }), - currentCurrency, - ) - : new Numeric(balance, 16, EtherDenomination.WEI) - .toDenomination(EtherDenomination.ETH) - .round(6) - .toBase(10) - .toString(); - - const onSign = async () => { - ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) - if (this.props.mmiOnSignCallback) { - await this.props.mmiOnSignCallback(txData); - return; - } - ///: END:ONLY_INCLUDE_IN - - await resolvePendingApproval(id); - completedTx(id); - - trackEvent({ - category: MetaMetricsEventCategory.Transactions, - event: 'Confirm', - properties: { - action: 'Sign Request', - legacy_event: true, - type, - version, - }, - }); - }; - - const onCancel = async () => { - await rejectPendingApproval( - id, - serializeError(ethErrors.provider.userRejectedRequest()), - ); - trackEvent({ - category: MetaMetricsEventCategory.Transactions, - event: 'Cancel', - properties: { - action: 'Sign Request', - legacy_event: true, - type, - version, - }, - }); - }; - - const messageIsScrollable = - this.messageRootRef?.scrollHeight > this.messageRootRef?.clientHeight; - - const targetSubjectMetadata = txData.msgParams.origin - ? subjectMetadata?.[txData.msgParams.origin] - : null; - - return ( -
    - -
    - -
    -
    - {isSuspiciousResponse(txData?.securityProviderResponse) && ( - - )} - - { - ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) - this.props.selectedAccount.address === address ? null : ( - - - - {this.context.t('mismatchAccount', [ - shortenAddress(this.props.selectedAccount.address), - shortenAddress(address), - ])} - - - ) - ///: END:ONLY_INCLUDE_IN - } - -
    - -
    - - - {this.context.t('sigRequest')} - - - {this.context.t('signatureRequestGuidance')} - - {verifyingContract ? ( -
    - -
    - ) : null} -
    - {/* {isLedgerWallet ? ( -
    - -
    - ) : null} */} - this.setState({ hasScrolledMessage: true })} - setMessageRootRef={this.setMessageRootRef.bind(this)} - messageRootRef={this.messageRootRef} - messageIsScrollable={messageIsScrollable} - primaryType={primaryType} - /> -
    - {this.state.showContractDetails && ( - this.setState({ showContractDetails: false })} - isContractRequestingSignature - /> - )} - {unapprovedMessagesCount > 1 ? ( - - ) : null} -
    - ); - } -} diff --git a/ui/components/app/signature-request/signature-request.constants.js b/ui/components/app/signature-request/signature-request.constants.js deleted file mode 100644 index e17841a0c..000000000 --- a/ui/components/app/signature-request/signature-request.constants.js +++ /dev/null @@ -1,3 +0,0 @@ -import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../../shared/constants/app'; - -export { ENVIRONMENT_TYPE_NOTIFICATION }; diff --git a/ui/components/app/signature-request/signature-request.container.js b/ui/components/app/signature-request/signature-request.container.js deleted file mode 100644 index f6f3e8fea..000000000 --- a/ui/components/app/signature-request/signature-request.container.js +++ /dev/null @@ -1,274 +0,0 @@ -import { connect } from 'react-redux'; -import { - accountsWithSendEtherInfoSelector, - doesAddressRequireLedgerHidConnection, - getCurrentChainId, - getRpcPrefsForCurrentProvider, - getSubjectMetadata, - unconfirmedMessagesHashSelector, - getTotalUnapprovedMessagesCount, - getCurrentCurrency, - getPreferences, - conversionRateSelector, - ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) - getAccountType, - getSelectedAccount, - unapprovedTypedMessagesSelector, - ///: END:ONLY_INCLUDE_IN -} from '../../../selectors'; -import { - isAddressLedger, - getNativeCurrency, - getProviderConfig, -} from '../../../ducks/metamask/metamask'; -import { getAccountByAddress, valuesFor } from '../../../helpers/utils/util'; -///: BEGIN:ONLY_INCLUDE_IN(build-mmi) -// eslint-disable-next-line import/order -import { showCustodianDeepLink } from '@metamask-institutional/extension'; -import { - mmiActionsFactory, - setTypedMessageInProgress, -} from '../../../store/institutional/institution-background'; -import { getEnvironmentType } from '../../../../app/scripts/lib/util'; -import { checkForUnapprovedMessages } from '../../../store/institutional/institution-actions'; -///: END:ONLY_INCLUDE_IN -import { - ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) - ENVIRONMENT_TYPE_NOTIFICATION, - ///: END:ONLY_INCLUDE_IN -} from '../../../../shared/constants/app'; - -import { - showModal, - resolvePendingApproval, - rejectPendingApproval, - rejectAllMessages, - completedTx, - ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) - goHome, - ///: END:ONLY_INCLUDE_IN -} from '../../../store/actions'; -import { getMostRecentOverviewPage } from '../../../ducks/history/history'; -import { clearConfirmTransaction } from '../../../ducks/confirm-transaction/confirm-transaction.duck'; -import SignatureRequest from './signature-request.component'; - -function mapStateToProps(state, ownProps) { - const { txData } = ownProps; - - ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) - const envType = getEnvironmentType(); - ///: END:ONLY_INCLUDE_IN - - const { - msgParams: { from }, - } = txData; - const providerConfig = getProviderConfig(state); - - const hardwareWalletRequiresConnection = - doesAddressRequireLedgerHidConnection(state, from); - const isLedgerWallet = isAddressLedger(state, from); - const chainId = getCurrentChainId(state); - const rpcPrefs = getRpcPrefsForCurrentProvider(state); - const unconfirmedMessagesList = unconfirmedMessagesHashSelector(state); - const unapprovedMessagesCount = getTotalUnapprovedMessagesCount(state); - const { useNativeCurrencyAsPrimaryCurrency } = getPreferences(state); - - return { - providerConfig, - isLedgerWallet, - hardwareWalletRequiresConnection, - chainId, - rpcPrefs, - unconfirmedMessagesList, - unapprovedMessagesCount, - mostRecentOverviewPage: getMostRecentOverviewPage(state), - nativeCurrency: getNativeCurrency(state), - currentCurrency: getCurrentCurrency(state), - conversionRate: useNativeCurrencyAsPrimaryCurrency - ? null - : conversionRateSelector(state), - subjectMetadata: getSubjectMetadata(state), - // not forwarded to component - allAccounts: accountsWithSendEtherInfoSelector(state), - ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) - accountType: getAccountType(state), - isNotification: envType === ENVIRONMENT_TYPE_NOTIFICATION, - selectedAccount: getSelectedAccount(state), - unapprovedTypedMessages: unapprovedTypedMessagesSelector(state), - ///: END:ONLY_INCLUDE_IN - }; -} - -let mapDispatchToProps = null; - -///: BEGIN:ONLY_INCLUDE_IN(build-mmi) -function mmiMapDispatchToProps(dispatch) { - const mmiActions = mmiActionsFactory(); - return { - clearConfirmTransaction: () => dispatch(clearConfirmTransaction()), - setMsgInProgress: (msgId) => dispatch(setTypedMessageInProgress(msgId)), - showCustodianDeepLink: ({ - custodyId, - fromAddress, - closeNotification, - onDeepLinkFetched, - onDeepLinkShown, - }) => - showCustodianDeepLink({ - dispatch, - mmiActions, - txId: undefined, - fromAddress, - custodyId, - isSignature: true, - closeNotification, - onDeepLinkFetched, - onDeepLinkShown, - }), - showTransactionsFailedModal: ({ - errorMessage, - closeNotification, - operationFailed, - }) => - dispatch( - showModal({ - name: 'TRANSACTION_FAILED', - errorMessage, - closeNotification, - operationFailed, - }), - ), - setWaitForConfirmDeepLinkDialog: (wait) => - dispatch(mmiActions.setWaitForConfirmDeepLinkDialog(wait)), - goHome: () => dispatch(goHome()), - }; -} - -mapDispatchToProps = mmiMapDispatchToProps; -///: END:ONLY_INCLUDE_IN - -mapDispatchToProps = function (dispatch) { - return { - resolvePendingApproval: (id) => dispatch(resolvePendingApproval(id)), - completedTx: (id) => dispatch(completedTx(id)), - rejectPendingApproval: (id, error) => - dispatch(rejectPendingApproval(id, error)), - clearConfirmTransaction: () => dispatch(clearConfirmTransaction()), - showRejectTransactionsConfirmationModal: ({ - onSubmit, - unapprovedTxCount: unapprovedMessagesCount, - }) => { - return dispatch( - showModal({ - name: 'REJECT_TRANSACTIONS', - onSubmit, - unapprovedTxCount: unapprovedMessagesCount, - isRequestType: true, - }), - ); - }, - cancelAllApprovals: (unconfirmedMessagesList) => { - dispatch(rejectAllMessages(unconfirmedMessagesList)); - }, - }; -}; - -function mergeProps(stateProps, dispatchProps, ownProps) { - const { - allAccounts, - isLedgerWallet, - hardwareWalletRequiresConnection, - chainId, - rpcPrefs, - nativeCurrency, - currentCurrency, - conversionRate, - providerConfig, - subjectMetadata, - unconfirmedMessagesList, - unapprovedMessagesCount, - mostRecentOverviewPage, - ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) - accountType, - isNotification, - unapprovedTypedMessages, - ///: END:ONLY_INCLUDE_IN - } = stateProps; - const { txData } = ownProps; - - const { - cancelAll: dispatchCancelAll, - cancelAllApprovals: dispatchCancelAllApprovals, - } = dispatchProps; - - const { - msgParams: { from }, - } = txData; - - const fromAccount = getAccountByAddress(allAccounts, from); - - ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) - const mmiOnSignCallback = async (_msgData) => { - if (accountType === 'custody') { - try { - let msgData = _msgData; - let id = _msgData.custodyId; - if (!_msgData.custodyId) { - msgData = checkForUnapprovedMessages( - _msgData, - unapprovedTypedMessages, - ); - id = msgData.custodyId; - } - dispatchProps.showCustodianDeepLink({ - custodyId: id, - fromAddress: fromAccount.address, - closeNotification: isNotification, - onDeepLinkFetched: () => undefined, - onDeepLinkShown: () => undefined, - }); - await dispatchProps.setMsgInProgress(msgData.metamaskId); - await dispatchProps.setWaitForConfirmDeepLinkDialog(true); - await goHome(); - } catch (err) { - await dispatchProps.setWaitForConfirmDeepLinkDialog(true); - await dispatchProps.showTransactionsFailedModal({ - errorMessage: err.message, - closeNotification: true, - operationFailed: true, - }); - } - } - }; - ///: END:ONLY_INCLUDE_IN - - return { - ...ownProps, - ...dispatchProps, - fromAccount, - txData, - isLedgerWallet, - hardwareWalletRequiresConnection, - chainId, - rpcPrefs, - nativeCurrency, - currentCurrency, - conversionRate, - providerConfig, - subjectMetadata, - unapprovedMessagesCount, - mostRecentOverviewPage, - cancelAll: () => dispatchCancelAll(valuesFor(unconfirmedMessagesList)), - cancelAllApprovals: () => - dispatchCancelAllApprovals(valuesFor(unconfirmedMessagesList)), - ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) - mmiOnSignCallback, - ///: END:ONLY_INCLUDE_IN - }; -} - -export default connect( - mapStateToProps, - mapDispatchToProps, - mergeProps, -)(SignatureRequest); diff --git a/ui/components/app/signature-request/signature-request.container.test.js b/ui/components/app/signature-request/signature-request.container.test.js deleted file mode 100644 index f7c5522ce..000000000 --- a/ui/components/app/signature-request/signature-request.container.test.js +++ /dev/null @@ -1,237 +0,0 @@ -import React from 'react'; -import sinon from 'sinon'; -import { fireEvent, screen, act } from '@testing-library/react'; -import configureMockStore from 'redux-mock-store'; -import { renderWithProvider } from '../../../../test/lib/render-helpers'; -import SignatureRequest from './signature-request.container'; - -const mockStoreWithEth = { - metamask: { - tokenList: { - '0x514910771af9ca656af840dff83e8264ecf986ca': { - address: '0x514910771af9ca656af840dff83e8264ecf986ca', - symbol: 'LINK', - decimals: 18, - name: 'ChainLink Token', - iconUrl: 'https://crypto.com/price/coin-data/icon/LINK/color_icon.png', - aggregators: [ - 'Aave', - 'Bancor', - 'CMC', - 'Crypto.com', - 'CoinGecko', - '1inch', - 'Paraswap', - 'PMM', - 'Zapper', - 'Zerion', - '0x', - ], - occurrences: 12, - unlisted: false, - }, - }, - identities: { - '0xb19ac54efa18cc3a14a5b821bfec73d284bf0c5e': { - name: 'Account 2', - address: '0xb19ac54efa18cc3a14a5b821bfec73d284bf0c5e', - }, - }, - addressBook: { - undefined: { - 0: { - address: '0x39a4e4Af7cCB654dB9500F258c64781c8FbD39F0', - name: '', - isEns: false, - }, - }, - }, - providerConfig: { - type: 'rpc', - }, - preferences: { - useNativeCurrencyAsPrimaryCurrency: true, - }, - accounts: { - '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5': { - address: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5', - balance: '0x03', - }, - }, - cachedBalances: {}, - unapprovedDecryptMsgs: {}, - unapprovedEncryptionPublicKeyMsgs: {}, - unconfirmedTransactions: {}, - selectedAddress: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5', - nativeCurrency: 'ETH', - currentCurrency: 'usd', - conversionRate: 231.06, - }, -}; - -const mockStoreWithFiat = { - ...mockStoreWithEth, - preferences: { - useNativeCurrencyAsPrimaryCurrency: false, - }, -}; -describe('Signature Request', () => { - const propsWithEth = { - fromAccount: { - address: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5', - balance: '0x346ba7725f412cbfdb', - name: 'John Doe', - }, - history: { - push: sinon.spy(), - }, - hardwareWalletRequiresConnection: false, - mostRecentOverviewPage: '/', - clearConfirmTransaction: sinon.spy(), - cancelMessage: sinon.spy(), - cancel: sinon.stub().resolves(), - rejectPendingApproval: sinon.stub().resolves(), - showRejectTransactionsConfirmationModal: sinon.stub().resolves(), - cancelAll: sinon.stub().resolves(), - providerConfig: { - type: 'rpc', - }, - unapprovedMessagesCount: 2, - sign: sinon.stub().resolves(), - cancelAllApprovals: sinon.stub().resolves(), - resolvePendingApproval: sinon.stub().resolves(), - completedTx: sinon.stub().resolves(), - txData: { - msgParams: { - id: 1, - data: '{"types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"Person":[{"name":"name","type":"string"},{"name":"wallet","type":"address"}],"Mail":[{"name":"from","type":"Person"},{"name":"to","type":"Person"},{"name":"contents","type":"string"}]},"primaryType":"Mail","domain":{"name":"Ether Mail","version":"1","chainId":"4","verifyingContract":"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"},"message":{"from":{"name":"Cow","wallet":"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"},"to":{"name":"Bob","wallet":"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"},"contents":"Hello, Bob!"}}', - from: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5', - origin: 'test.domain', - }, - status: 'unapproved', - time: 1, - type: 'eth_sign', - }, - nativeCurrency: 'ETH', - currentCurrency: 'usd', - conversionRate: null, - selectedAccount: { - address: '0x123456789abcdef', - }, - }; - - const propsWithFiat = { - ...propsWithEth, - conversionRate: 156.72, - }; - - describe('Render with different currencies', () => { - it('should render balance with ETH when conversionRate is not provided', () => { - const store = configureMockStore()(mockStoreWithEth); - renderWithProvider( - , - store, - ); - expect( - screen.getByTestId('request-signature-account').textContent, - ).toMatchInlineSnapshot( - `"UUnknown private networkJohn DoeBalance966.987986 ETH"`, - ); - }); - - it('should render balance with fiat when conversionRate not provided', () => { - const store = configureMockStore()(mockStoreWithFiat); - renderWithProvider( - , - store, - ); - expect( - screen.getByTestId('request-signature-account').textContent, - ).toMatchInlineSnapshot( - `"UUnknown private networkJohn DoeBalance$151,546.36 USD"`, - ); - }); - }); - - describe('functionality check', () => { - beforeEach(() => { - const store = configureMockStore()(mockStoreWithFiat); - renderWithProvider( - , - store, - ); - }); - - afterEach(() => { - propsWithFiat.clearConfirmTransaction.resetHistory(); - }); - - it('cancel', async () => { - const cancelButton = screen.getByTestId('page-container-footer-cancel'); - await act(() => { - fireEvent.click(cancelButton); - }); - expect(propsWithFiat.rejectPendingApproval.calledOnce).toStrictEqual( - true, - ); - }); - - it('sign', async () => { - const signButton = screen.getByTestId('page-container-footer-next'); - await act(() => { - fireEvent.click(signButton); - }); - expect(propsWithFiat.resolvePendingApproval.calledOnce).toStrictEqual( - true, - ); - }); - - it('have user warning', () => { - const warningText = screen.getByText( - 'Only sign this message if you fully understand the content and trust the requesting site.', - ); - - expect(warningText).toBeInTheDocument(); - }); - }); - - describe('contract details', () => { - let store; - beforeEach(() => { - store = configureMockStore()(mockStoreWithFiat); - }); - it('shows verify contract details link when verifyingContract is set', () => { - renderWithProvider( - , - store, - ); - const verifyingContractLink = screen.getByTestId( - 'verify-contract-details', - ); - expect(verifyingContractLink).toBeInTheDocument(); - }); - - it('should not show verify contract details link when verifyingContract is not set', () => { - const newData = JSON.parse(propsWithFiat.txData.msgParams.data); - delete newData.domain.verifyingContract; - - const newProps = { - ...propsWithFiat, - txData: { - ...propsWithFiat.txData, - msgParams: { - ...propsWithFiat.txData.msgParams, - data: JSON.stringify(newData), - }, - }, - }; - - renderWithProvider( - , - store, - ); - - expect(screen.queryByTestId('verify-contract-details')).toBeNull(); - }); - }); -}); diff --git a/ui/components/app/signature-request/signature-request.js b/ui/components/app/signature-request/signature-request.js new file mode 100644 index 000000000..6838f4254 --- /dev/null +++ b/ui/components/app/signature-request/signature-request.js @@ -0,0 +1,385 @@ +import React, { useContext, useState, useEffect } from 'react'; +import { + useDispatch, + useSelector, + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + shallowEqual, + ///: END:ONLY_INCLUDE_IN +} from 'react-redux'; +import PropTypes from 'prop-types'; +import { memoize } from 'lodash'; +import { ethErrors, serializeError } from 'eth-rpc-errors'; +///: BEGIN:ONLY_INCLUDE_IN(build-mmi) +import { showCustodianDeepLink } from '@metamask-institutional/extension'; +///: END:ONLY_INCLUDE_IN +import { + ///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask) + resolvePendingApproval, + completedTx, + ///: END:ONLY_INCLUDE_IN + rejectPendingApproval, +} from '../../../store/actions'; +import { + doesAddressRequireLedgerHidConnection, + getSubjectMetadata, + getTotalUnapprovedMessagesCount, + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + accountsWithSendEtherInfoSelector, + getSelectedAccount, + getAccountType, + ///: END:ONLY_INCLUDE_IN +} from '../../../selectors'; +import { + getProviderConfig, + isAddressLedger, +} from '../../../ducks/metamask/metamask'; +import { + sanitizeMessage, + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + getAccountByAddress, + shortenAddress, + ///: END:ONLY_INCLUDE_IN +} from '../../../helpers/utils/util'; +import { useI18nContext } from '../../../hooks/useI18nContext'; +import { useRejectTransactionModal } from '../../../hooks/useRejectTransactionModal'; + +import { ConfirmPageContainerNavigation } from '../confirm-page-container'; +import SignatureRequestHeader from '../signature-request-header/signature-request-header'; +import SecurityProviderBannerMessage from '../security-provider-banner-message'; +import LedgerInstructionField from '../ledger-instruction-field'; +import ContractDetailsModal from '../modals/contract-details-modal'; +import { MetaMetricsContext } from '../../../contexts/metametrics'; +import { + MetaMetricsEventCategory, + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + MetaMetricsEventName, + ///: END:ONLY_INCLUDE_IN +} from '../../../../shared/constants/metametrics'; +import { SECURITY_PROVIDER_MESSAGE_SEVERITY } from '../../../../shared/constants/security-provider'; + +import { + TextAlign, + TextColor, + TextVariant, + Size, + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + IconColor, + BackgroundColor, + Display, + BlockSize, + ///: END:ONLY_INCLUDE_IN +} from '../../../helpers/constants/design-system'; +import { + BUTTON_VARIANT, + Button, + ButtonLink, + TagUrl, + Text, + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + Icon, + IconName, + ///: END:ONLY_INCLUDE_IN +} from '../../component-library'; + +///: BEGIN:ONLY_INCLUDE_IN(build-mmi) +// eslint-disable-next-line import/order +import Box from '../../ui/box/box'; +import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../../shared/constants/app'; +import { getEnvironmentType } from '../../../../app/scripts/lib/util'; +import { mmiActionsFactory } from '../../../store/institutional/institution-background'; +import { showCustodyConfirmLink } from '../../../store/institutional/institution-actions'; +import { useMMICustodySignMessage } from '../../../hooks/useMMICustodySignMessage'; +///: END:ONLY_INCLUDE_IN + +import Message from './signature-request-message'; +import Footer from './signature-request-footer'; + +const SignatureRequest = ({ txData }) => { + const trackEvent = useContext(MetaMetricsContext); + const dispatch = useDispatch(); + const t = useI18nContext(); + + const [hasScrolledMessage, setHasScrolledMessage] = useState(false); + const [showContractDetails, setShowContractDetails] = useState(false); + const [messageRootRef, setMessageRootRef] = useState(null); + const [messageIsScrollable, setMessageIsScrollable] = useState(false); + + const { + id, + type, + msgParams: { from, data, origin, version }, + } = txData; + + // not forwarded to component + const hardwareWalletRequiresConnection = useSelector((state) => + doesAddressRequireLedgerHidConnection(state, from), + ); + const { chainId, rpcPrefs } = useSelector(getProviderConfig); + const unapprovedMessagesCount = useSelector(getTotalUnapprovedMessagesCount); + const subjectMetadata = useSelector(getSubjectMetadata); + const isLedgerWallet = useSelector((state) => isAddressLedger(state, from)); + const { handleCancelAll } = useRejectTransactionModal(); + + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + // Used to show a warning if the signing account is not the selected account + // Largely relevant for contract wallet custodians + const selectedAccount = useSelector(getSelectedAccount); + const mmiActions = mmiActionsFactory(); + const accountType = useSelector(getAccountType); + const isNotification = getEnvironmentType() === ENVIRONMENT_TYPE_NOTIFICATION; + const allAccounts = useSelector( + accountsWithSendEtherInfoSelector, + shallowEqual, + ); + const { address } = getAccountByAddress(allAccounts, from) || {}; + const { custodySignFn } = useMMICustodySignMessage(); + ///: END:ONLY_INCLUDE_IN + + useEffect(() => { + setMessageIsScrollable( + messageRootRef?.scrollHeight > messageRootRef?.clientHeight, + ); + }, [messageRootRef]); + + const targetSubjectMetadata = subjectMetadata?.[origin] || null; + + const parseMessage = memoize((dataToParse) => { + const { + message, + domain = {}, + primaryType, + types, + } = JSON.parse(dataToParse); + const sanitizedMessage = sanitizeMessage(message, primaryType, types); + return { sanitizedMessage, domain, primaryType }; + }); + + const onSign = async () => { + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + if (accountType === 'custody') { + await custodySignFn(txData); + return; + } + ///: END:ONLY_INCLUDE_IN + + ///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask) + await dispatch(resolvePendingApproval(id)); + completedTx(id); + ///: END:ONLY_INCLUDE_IN + + trackEvent({ + category: MetaMetricsEventCategory.Transactions, + event: 'Confirm', + properties: { + action: 'Sign Request', + legacy_event: true, + type, + version, + }, + }); + }; + + const onCancel = async () => { + await dispatch( + rejectPendingApproval( + id, + serializeError(ethErrors.provider.userRejectedRequest()), + ), + ); + trackEvent({ + category: MetaMetricsEventCategory.Transactions, + event: 'Cancel', + properties: { + action: 'Sign Request', + legacy_event: true, + type, + version, + }, + }); + }; + + const { + sanitizedMessage, + domain: { verifyingContract }, + primaryType, + } = parseMessage(data); + + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + useEffect(() => { + if (txData.custodyId) { + showCustodianDeepLink({ + dispatch, + mmiActions, + txId: undefined, + custodyId: txData.custodyId, + fromAddress: address, + isSignature: true, + closeNotification: isNotification, + onDeepLinkFetched: () => undefined, + onDeepLinkShown: () => { + trackEvent({ + category: MetaMetricsEventCategory.MMI, + event: MetaMetricsEventName.SignatureDeeplinkDisplayed, + }); + }, + showCustodyConfirmLink, + }); + } + }, [ + dispatch, + mmiActions, + txData.custodyId, + address, + isNotification, + trackEvent, + ]); + ///: END:ONLY_INCLUDE_IN + + return ( +
    + +
    + +
    +
    + {(txData?.securityProviderResponse?.flagAsDangerous !== undefined && + txData?.securityProviderResponse?.flagAsDangerous !== + SECURITY_PROVIDER_MESSAGE_SEVERITY.NOT_MALICIOUS) || + (txData?.securityProviderResponse && + Object.keys(txData.securityProviderResponse).length === 0) ? ( + + ) : null} + { + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + selectedAccount.address === address ? null : ( + + + + {t('mismatchAccount', [ + shortenAddress(selectedAccount.address), + shortenAddress(address), + ])} + + + ) + ///: END:ONLY_INCLUDE_IN + } +
    + +
    + + {t('sigRequest')} + + + {t('signatureRequestGuidance')} + + {verifyingContract ? ( +
    + +
    + ) : null} +
    + {isLedgerWallet ? ( +
    + +
    + ) : null} + setHasScrolledMessage(true)} + setMessageRootRef={setMessageRootRef} + messageRootRef={messageRootRef} + messageIsScrollable={messageIsScrollable} + primaryType={primaryType} + /> +
    + {showContractDetails && ( + setShowContractDetails(false)} + isContractRequestingSignature + /> + )} + {unapprovedMessagesCount > 1 ? ( + + {t('rejectRequestsN', [unapprovedMessagesCount])} + + ) : null} +
    + ); +}; + +SignatureRequest.propTypes = { + txData: PropTypes.object, +}; + +export default SignatureRequest; diff --git a/ui/components/app/signature-request/signature-request.stories.js b/ui/components/app/signature-request/signature-request.stories.js index 1fc2e555b..c74ac7457 100644 --- a/ui/components/app/signature-request/signature-request.stories.js +++ b/ui/components/app/signature-request/signature-request.stories.js @@ -1,14 +1,22 @@ import React from 'react'; +import { Provider } from 'react-redux'; +import configureStore from '../../../store/store'; import testData from '../../../../.storybook/test-data'; import README from './README.mdx'; -import SignatureRequest from './signature-request.component'; +import SignatureRequest from './signature-request'; -const [MOCK_PRIMARY_IDENTITY, MOCK_SECONDARY_IDENTITY] = Object.values( - testData.metamask.identities, -); +const store = configureStore({ + ...testData, + metamask: { + ...testData.metamask, + selectedAddress: '0xb19ac54efa18cc3a14a5b821bfec73d284bf0c5e', + }, +}); export default { title: 'Components/App/SignatureRequest', + decorators: [(story) => {story()}], + component: SignatureRequest, parameters: { docs: { @@ -17,22 +25,6 @@ export default { }, argTypes: { txData: { control: 'object' }, - fromAccount: { - table: { - address: { control: 'text' }, - balance: { control: 'text' }, - name: { control: 'text' }, - }, - }, - hardwareWalletRequiresConnection: { control: 'boolean' }, - isLedgerWallet: { control: 'boolean' }, - clearConfirmTransaction: { action: 'Clean Confirm' }, - cancel: { action: 'Cancel' }, - sign: { action: 'Sign' }, - showRejectTransactionsConfirmationModal: { - action: 'showRejectTransactionsConfirmationModal', - }, - cancelAll: { action: 'cancelAll' }, }, }; @@ -45,6 +37,7 @@ DefaultStory.storyName = 'Default'; DefaultStory.args = { txData: { msgParams: { + from: '0xb19ac54efa18cc3a14a5b821bfec73d284bf0c5e', data: JSON.stringify({ domain: { name: 'happydapp.website', @@ -79,11 +72,6 @@ DefaultStory.args = { origin: 'https://happydapp.website/', }, }, - fromAccount: MOCK_PRIMARY_IDENTITY, - providerConfig: { name: 'Goerli ETH' }, - selectedAccount: MOCK_PRIMARY_IDENTITY, - hardwareWalletRequiresConnection: false, - currentCurrency: 'usd', }; export const AccountMismatchStory = (args) => { @@ -94,5 +82,10 @@ AccountMismatchStory.storyName = 'AccountMismatch'; AccountMismatchStory.args = { ...DefaultStory.args, - selectedAccount: MOCK_SECONDARY_IDENTITY, + txData: { + msgParams: { + ...DefaultStory.args.txData.msgParams, + from: '0x64a845a5b02460acf8a3d84503b0d68d028b4bb4', + }, + }, }; diff --git a/ui/components/app/signature-request/signature-request.component.test.js b/ui/components/app/signature-request/signature-request.test.js similarity index 67% rename from ui/components/app/signature-request/signature-request.component.test.js rename to ui/components/app/signature-request/signature-request.test.js index 81f18932a..4c500d3fd 100644 --- a/ui/components/app/signature-request/signature-request.component.test.js +++ b/ui/components/app/signature-request/signature-request.test.js @@ -1,33 +1,98 @@ import React from 'react'; +import { useSelector } from 'react-redux'; import { fireEvent } from '@testing-library/react'; import configureMockStore from 'redux-mock-store'; import mockState from '../../../../test/data/mock-state.json'; import { renderWithProvider } from '../../../../test/lib/render-helpers'; import { SECURITY_PROVIDER_MESSAGE_SEVERITY } from '../../../../shared/constants/security-provider'; -import SignatureRequest from './signature-request.component'; +import { + getNativeCurrency, + getProviderConfig, +} from '../../../ducks/metamask/metamask'; +import { + accountsWithSendEtherInfoSelector, + conversionRateSelector, + getCurrentCurrency, + getMemoizedAddressBook, + getMemoizedMetaMaskIdentities, + getPreferences, + getSelectedAccount, + getTotalUnapprovedMessagesCount, + unconfirmedTransactionsHashSelector, +} from '../../../selectors'; +import SignatureRequest from './signature-request'; const baseProps = { - hardwareWalletRequiresConnection: false, - clearConfirmTransaction: () => undefined, - cancel: () => undefined, - cancelAll: () => undefined, - mostRecentOverviewPage: '/', - showRejectTransactionsConfirmationModal: () => undefined, - sign: () => undefined, - history: { push: '/' }, - providerConfig: { type: 'rpc' }, - nativeCurrency: 'ABC', - currentCurrency: 'def', - fromAccount: { - address: '0x123456789abcdef', - balance: '0x346ba7725f412cbfdb', - name: 'Antonio', - }, - selectedAccount: { - address: '0x123456789abcdef', + clearConfirmTransaction: () => jest.fn(), + cancel: () => jest.fn(), + cancelAll: () => jest.fn(), + showRejectTransactionsConfirmationModal: () => jest.fn(), + sign: () => jest.fn(), +}; +const mockStore = { + metamask: { + providerConfig: { + chainId: '0x539', + nickname: 'Localhost 8545', + rpcPrefs: {}, + rpcUrl: 'http://localhost:8545', + ticker: 'ETH', + type: 'rpc', + }, + preferences: { + useNativeCurrencyAsPrimaryCurrency: true, + }, + accounts: { + '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5': { + address: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5', + balance: '0x03', + name: 'John Doe', + }, + }, + selectedAddress: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5', + nativeCurrency: 'ETH', + currentCurrency: 'usd', + conversionRate: null, + unapprovedTypedMessagesCount: 2, }, }; +jest.mock('react-redux', () => { + const actual = jest.requireActual('react-redux'); + return { + ...actual, + useSelector: jest.fn(), + useDispatch: () => jest.fn(), + }; +}); + +const generateUseSelectorRouter = (opts) => (selector) => { + switch (selector) { + case getProviderConfig: + return opts.metamask.providerConfig; + case getCurrentCurrency: + return opts.metamask.currentCurrency; + case getNativeCurrency: + return opts.metamask.nativeCurrency; + case getTotalUnapprovedMessagesCount: + return opts.metamask.unapprovedTypedMessagesCount; + case getPreferences: + return opts.metamask.preferences; + case conversionRateSelector: + return opts.metamask.conversionRate; + case getSelectedAccount: + return opts.metamask.accounts[opts.metamask.selectedAddress]; + case getMemoizedAddressBook: + return []; + case accountsWithSendEtherInfoSelector: + return Object.values(opts.metamask.accounts); + case unconfirmedTransactionsHashSelector: + case getMemoizedMetaMaskIdentities: + return {}; + default: + return undefined; + } +}; describe('Signature Request Component', () => { const store = configureMockStore()(mockState); @@ -35,6 +100,7 @@ describe('Signature Request Component', () => { let messageData; beforeEach(() => { + useSelector.mockImplementation(generateUseSelectorRouter(mockStore)); messageData = { domain: { chainId: 97, @@ -84,7 +150,17 @@ describe('Signature Request Component', () => { }); it('should match snapshot when we want to switch to fiat', () => { + useSelector.mockImplementation( + generateUseSelectorRouter({ + ...mockStore, + metamask: { + ...mockStore.metamask, + conversionRate: 231.06, + }, + }), + ); const msgParams = { + from: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5', data: JSON.stringify(messageData), version: 'V4', origin: 'test', @@ -95,7 +171,6 @@ describe('Signature Request Component', () => { txData={{ msgParams, }} - conversionRate={1567} />, store, ); @@ -105,6 +180,7 @@ describe('Signature Request Component', () => { it('should match snapshot when we are using eth', () => { const msgParams = { + from: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5', data: JSON.stringify(messageData), version: 'V4', origin: 'test', @@ -115,7 +191,6 @@ describe('Signature Request Component', () => { txData={{ msgParams, }} - conversionRate={null} />, store, ); @@ -125,6 +200,7 @@ describe('Signature Request Component', () => { it('should render navigation', () => { const msgParams = { + from: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5', data: JSON.stringify(messageData), version: 'V4', origin: 'test', @@ -135,7 +211,6 @@ describe('Signature Request Component', () => { txData={{ msgParams, }} - conversionRate={null} />, store, ); @@ -149,6 +224,7 @@ describe('Signature Request Component', () => { do_not_display: 'two', }; const msgParams = { + from: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5', data: JSON.stringify(messageData), version: 'V4', origin: 'test', @@ -159,7 +235,6 @@ describe('Signature Request Component', () => { txData={{ msgParams, }} - conversionRate={null} />, store, ); @@ -171,7 +246,17 @@ describe('Signature Request Component', () => { }); it('should not render a reject multiple requests link if there is not multiple requests', () => { + useSelector.mockImplementation( + generateUseSelectorRouter({ + ...mockStore, + metamask: { + ...mockStore.metamask, + unapprovedTypedMessagesCount: 0, + }, + }), + ); const msgParams = { + from: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5', data: JSON.stringify(messageData), version: 'V4', origin: 'test', @@ -182,7 +267,6 @@ describe('Signature Request Component', () => { txData={{ msgParams, }} - conversionRate={null} />, store, ); @@ -194,6 +278,7 @@ describe('Signature Request Component', () => { it('should render a reject multiple requests link if there is multiple requests (greater than 1)', () => { const msgParams = { + from: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5', data: JSON.stringify(messageData), version: 'V4', origin: 'test', @@ -204,8 +289,6 @@ describe('Signature Request Component', () => { txData={{ msgParams, }} - conversionRate={null} - unapprovedMessagesCount={2} />, store, ); @@ -217,6 +300,7 @@ describe('Signature Request Component', () => { it('should call reject all button when button is clicked', () => { const msgParams = { + from: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5', data: JSON.stringify(messageData), version: 'V4', origin: 'test', @@ -227,8 +311,6 @@ describe('Signature Request Component', () => { txData={{ msgParams, }} - conversionRate={null} - unapprovedMessagesCount={2} />, store, ); @@ -242,6 +324,7 @@ describe('Signature Request Component', () => { it('should render text of reject all button', () => { const msgParams = { + from: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5', data: JSON.stringify(messageData), version: 'V4', origin: 'test', @@ -252,8 +335,6 @@ describe('Signature Request Component', () => { txData={{ msgParams, }} - conversionRate={null} - unapprovedMessagesCount={2} />, store, ); @@ -263,6 +344,7 @@ describe('Signature Request Component', () => { it('should render SecurityProviderBannerMessage component properly', () => { const msgParams = { + from: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5', data: JSON.stringify(messageData), version: 'V4', origin: 'test', @@ -271,7 +353,6 @@ describe('Signature Request Component', () => { const { queryByText } = renderWithProvider( { reason_header: 'Some reason header...', }, }} - unapprovedMessagesCount={2} />, store, ); @@ -296,6 +376,7 @@ describe('Signature Request Component', () => { it('should not render SecurityProviderBannerMessage component when flagAsDangerous is not malicious', () => { const msgParams = { + from: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5', data: JSON.stringify(messageData), version: 'V4', origin: 'test', @@ -304,14 +385,12 @@ describe('Signature Request Component', () => { const { queryByText } = renderWithProvider( , store, ); @@ -327,27 +406,39 @@ describe('Signature Request Component', () => { it('should render a warning when the selected account is not the one being used to sign', () => { const msgParams = { + from: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5', data: JSON.stringify(messageData), version: 'V4', origin: 'test', }; + useSelector.mockImplementation( + generateUseSelectorRouter({ + ...mockStore, + metamask: { + ...mockStore.metamask, + selectedAddress: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + accounts: { + ...mockStore.metamask.accounts, + '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + balance: '0x0', + name: 'Account 1', + }, + }, + }, + }), + ); + const { container } = renderWithProvider( , store, ); diff --git a/ui/components/app/snaps/snap-authorship-expanded/snap-authorship-expanded.js b/ui/components/app/snaps/snap-authorship-expanded/snap-authorship-expanded.js index 8c5e54a10..ac3fefd72 100644 --- a/ui/components/app/snaps/snap-authorship-expanded/snap-authorship-expanded.js +++ b/ui/components/app/snaps/snap-authorship-expanded/snap-authorship-expanded.js @@ -25,7 +25,7 @@ import { removeSnapIdPrefix, } from '../../../../helpers/utils/util'; -import { Text, ButtonLink } from '../../../component-library'; +import { ButtonLink, Text } from '../../../component-library'; import { getTargetSubjectMetadata } from '../../../../selectors'; import SnapAvatar from '../snap-avatar'; import { useI18nContext } from '../../../../hooks/useI18nContext'; diff --git a/ui/components/app/snaps/snap-connect-cell/snap-connect-cell.js b/ui/components/app/snaps/snap-connect-cell/snap-connect-cell.js index a62b5ff1d..f168b7920 100644 --- a/ui/components/app/snaps/snap-connect-cell/snap-connect-cell.js +++ b/ui/components/app/snaps/snap-connect-cell/snap-connect-cell.js @@ -13,8 +13,8 @@ import { Icon, IconName, IconSize, - Text, ValidTag, + Text, } from '../../../component-library'; import Tooltip from '../../../ui/tooltip/tooltip'; import { useI18nContext } from '../../../../hooks/useI18nContext'; diff --git a/ui/components/app/snaps/snap-delineator/snap-delineator.js b/ui/components/app/snaps/snap-delineator/snap-delineator.js index de872cff3..a1338abba 100644 --- a/ui/components/app/snaps/snap-delineator/snap-delineator.js +++ b/ui/components/app/snaps/snap-delineator/snap-delineator.js @@ -14,9 +14,9 @@ import { import Box from '../../../ui/box'; import { AvatarIcon, - Text, IconName, IconSize, + Text, } from '../../../component-library'; import { DelineatorType, diff --git a/ui/components/app/snaps/snap-install-warning/snap-install-warning.js b/ui/components/app/snaps/snap-install-warning/snap-install-warning.js index e4337c3d6..0eff25f13 100644 --- a/ui/components/app/snaps/snap-install-warning/snap-install-warning.js +++ b/ui/components/app/snaps/snap-install-warning/snap-install-warning.js @@ -16,7 +16,7 @@ import { } from '../../../../helpers/constants/design-system'; import Popover from '../../../ui/popover'; import Button from '../../../ui/button'; -import { AvatarIcon, Text, IconName } from '../../../component-library'; +import { AvatarIcon, IconName, Text } from '../../../component-library'; import Box from '../../../ui/box/box'; /** diff --git a/ui/components/app/snaps/snap-legacy-authorship-header/index.js b/ui/components/app/snaps/snap-legacy-authorship-header/index.js new file mode 100644 index 000000000..608dfb6e5 --- /dev/null +++ b/ui/components/app/snaps/snap-legacy-authorship-header/index.js @@ -0,0 +1 @@ +export { default } from './snap-legacy-authorship-header'; diff --git a/ui/components/app/snaps/snap-legacy-authorship-header/snap-legacy-authorship-header.js b/ui/components/app/snaps/snap-legacy-authorship-header/snap-legacy-authorship-header.js new file mode 100644 index 000000000..0d2f3e66b --- /dev/null +++ b/ui/components/app/snaps/snap-legacy-authorship-header/snap-legacy-authorship-header.js @@ -0,0 +1,91 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classnames from 'classnames'; +import { useSelector } from 'react-redux'; +import { + BackgroundColor, + TextColor, + TextVariant, + AlignItems, + FontWeight, + Display, + FlexDirection, + BlockSize, + BorderColor, + BorderRadius, +} from '../../../../helpers/constants/design-system'; +import { + getSnapName, + removeSnapIdPrefix, +} from '../../../../helpers/utils/util'; + +import { Box, Text } from '../../../component-library'; +import { getTargetSubjectMetadata } from '../../../../selectors'; +import SnapAvatar from '../snap-avatar'; + +const SnapLegacyAuthorshipHeader = ({ + snapId, + className, + marginLeft, + marginRight, +}) => { + const packageName = snapId && removeSnapIdPrefix(snapId); + + const subjectMetadata = useSelector((state) => + getTargetSubjectMetadata(state, snapId), + ); + + const friendlyName = snapId && getSnapName(snapId, subjectMetadata); + + return ( + + + + + + + {friendlyName} + + + {packageName} + + + + ); +}; + +SnapLegacyAuthorshipHeader.propTypes = { + /** + * The id of the snap + */ + snapId: PropTypes.string, + /** + * The className of the SnapLegacyAuthorshipHeader + */ + className: PropTypes.string, + marginLeft: PropTypes.number, + marginRight: PropTypes.number, +}; + +export default SnapLegacyAuthorshipHeader; diff --git a/ui/components/app/snaps/snap-legacy-authorship-header/snap-legacy-authorship-header.stories.js b/ui/components/app/snaps/snap-legacy-authorship-header/snap-legacy-authorship-header.stories.js new file mode 100644 index 000000000..6e71f4ee6 --- /dev/null +++ b/ui/components/app/snaps/snap-legacy-authorship-header/snap-legacy-authorship-header.stories.js @@ -0,0 +1,21 @@ +import React from 'react'; +import SnapLegacyAuthorshipHeader from './snap-legacy-authorship-header'; + +export default { + title: 'Components/App/Snaps/SnapLegacyAuthorshipHeader', + + component: SnapLegacyAuthorshipHeader, + argTypes: { + snapId: { + control: 'text', + }, + }, +}; + +export const DefaultStory = (args) => ; + +DefaultStory.storyName = 'Default'; + +DefaultStory.args = { + snapId: 'npm:@metamask/test-snap-bip44', +}; diff --git a/ui/components/app/snaps/snap-remove-warning/index.scss b/ui/components/app/snaps/snap-remove-warning/index.scss deleted file mode 100644 index c2a561dad..000000000 --- a/ui/components/app/snaps/snap-remove-warning/index.scss +++ /dev/null @@ -1,12 +0,0 @@ -.snap-remove-warning { - color: var(--color-text-default); - - &__footer-button { - height: 40px; - margin-inline-end: 24px; - - &:last-of-type { - margin-inline-end: 0; - } - } -} diff --git a/ui/components/app/snaps/snap-remove-warning/snap-remove-warning.js b/ui/components/app/snaps/snap-remove-warning/snap-remove-warning.js index cffa7ca30..593cf1c3b 100644 --- a/ui/components/app/snaps/snap-remove-warning/snap-remove-warning.js +++ b/ui/components/app/snaps/snap-remove-warning/snap-remove-warning.js @@ -1,51 +1,64 @@ import React from 'react'; import PropTypes from 'prop-types'; import { useI18nContext } from '../../../../hooks/useI18nContext'; -import Typography from '../../../ui/typography/typography'; -import { TypographyVariant } from '../../../../helpers/constants/design-system'; -import Box from '../../../ui/box/box'; -import Popover from '../../../ui/popover'; -import Button from '../../../ui/button'; +import { + Text, + Box, + Button, + Modal, + ModalContent, + ModalHeader, + ModalOverlay, + BUTTON_VARIANT, + BUTTON_SIZES, +} from '../../../component-library'; -export default function SnapRemoveWarning({ onCancel, onSubmit, snapName }) { +import { + BlockSize, + Display, + FlexDirection, +} from '../../../../helpers/constants/design-system'; + +export default function SnapRemoveWarning({ + isOpen, + onCancel, + onSubmit, + snapName, +}) { const t = useI18nContext(); - - const SnapRemoveWarningFooter = () => { - return ( - <> - - - - ); - }; - return ( - } - onClose={onCancel} - headerProps={{ padding: [6, 4, 0, 6] }} - > - - - {t('removeSnapConfirmation', [snapName])} - - - + + + + {t('pleaseConfirm')} + {t('removeSnapConfirmation', [snapName])} + + + + + + ); } @@ -62,4 +75,8 @@ SnapRemoveWarning.propTypes = { * Name of snap */ snapName: PropTypes.string, + /** + * Whether the modal is open + */ + isOpen: PropTypes.bool, }; diff --git a/ui/components/app/snaps/snap-remove-warning/snap-remove-warning.stories.js b/ui/components/app/snaps/snap-remove-warning/snap-remove-warning.stories.js new file mode 100644 index 000000000..c38ef8113 --- /dev/null +++ b/ui/components/app/snaps/snap-remove-warning/snap-remove-warning.stories.js @@ -0,0 +1,29 @@ +import React from 'react'; +import SnapRemoveWarning from './snap-remove-warning'; + +export default { + title: 'Components/App/Snaps/SnapRemoveWarning', + component: SnapRemoveWarning, + argTypes: { + onCancel: { + action: 'onCancel', + }, + onSubmit: { + action: 'onSubmit', + }, + snapName: { + control: 'text', + }, + isOpen: { + control: 'boolean', + }, + }, + args: { + snapName: 'Snap Name', + isOpen: true, + }, +}; + +export const DefaultStory = (args) => ; + +DefaultStory.storyName = 'Default'; diff --git a/ui/components/app/snaps/snap-ui-markdown/snap-ui-markdown.js b/ui/components/app/snaps/snap-ui-markdown/snap-ui-markdown.js index 359521152..10932993a 100644 --- a/ui/components/app/snaps/snap-ui-markdown/snap-ui-markdown.js +++ b/ui/components/app/snaps/snap-ui-markdown/snap-ui-markdown.js @@ -2,21 +2,25 @@ import React from 'react'; import PropTypes from 'prop-types'; import ReactMarkdown from 'react-markdown'; import { - TypographyVariant, - OVERFLOW_WRAP, + TextVariant, + OverflowWrap, } from '../../../../helpers/constants/design-system'; -import Typography from '../../../ui/typography/typography'; +import { Text } from '../../../component-library'; const Paragraph = (props) => ( - ); -export const SnapUIMarkdown = ({ children }) => { +export const SnapUIMarkdown = ({ children, markdown }) => { + if (markdown === false) { + return {children}; + } + return ( { SnapUIMarkdown.propTypes = { children: PropTypes.string, + markdown: PropTypes.bool, }; diff --git a/ui/components/app/snaps/snap-ui-markdown/snap-ui-markdown.stories.js b/ui/components/app/snaps/snap-ui-markdown/snap-ui-markdown.stories.js new file mode 100644 index 000000000..e936fb248 --- /dev/null +++ b/ui/components/app/snaps/snap-ui-markdown/snap-ui-markdown.stories.js @@ -0,0 +1,19 @@ +import React from 'react'; +import { SnapUIMarkdown } from './snap-ui-markdown'; + +export default { + title: 'Components/App/Snaps/SnapUIMarkdown', + component: SnapUIMarkdown, + argTypes: { + children: { + control: 'text', + }, + }, + args: { + children: 'A Test String', + }, +}; + +export const DefaultStory = (args) => ; + +DefaultStory.storyName = 'Default'; diff --git a/ui/components/app/snaps/snap-ui-renderer/snap-ui-renderer.js b/ui/components/app/snaps/snap-ui-renderer/snap-ui-renderer.js index 37d83c2c9..82a9a1c2f 100644 --- a/ui/components/app/snaps/snap-ui-renderer/snap-ui-renderer.js +++ b/ui/components/app/snaps/snap-ui-renderer/snap-ui-renderer.js @@ -46,6 +46,9 @@ export const UI_MAPPING = { text: (props) => ({ element: 'SnapUIMarkdown', children: props.value, + props: { + markdown: props.markdown, + }, }), spinner: () => ({ element: 'Spinner', diff --git a/ui/components/app/srp-quiz-modal/QuizContent/QuizContent.tsx b/ui/components/app/srp-quiz-modal/QuizContent/QuizContent.tsx index 67b1f4c06..8994573c2 100644 --- a/ui/components/app/srp-quiz-modal/QuizContent/QuizContent.tsx +++ b/ui/components/app/srp-quiz-modal/QuizContent/QuizContent.tsx @@ -9,7 +9,7 @@ import { TextVariant, } from '../../../../helpers/constants/design-system'; import { useI18nContext } from '../../../../hooks/useI18nContext'; -import { Button, Text, Box } from '../../../component-library'; +import { Button, Box, Text } from '../../../component-library'; import { IQuizInformationProps } from '../types'; export default function QuizContent({ diff --git a/ui/components/app/tab-bar/index.scss b/ui/components/app/tab-bar/index.scss index 67c9e08d9..49fb2461f 100644 --- a/ui/components/app/tab-bar/index.scss +++ b/ui/components/app/tab-bar/index.scss @@ -36,6 +36,7 @@ display: flex; align-items: center; position: relative; + width: 100%; &__title { @include H4; diff --git a/ui/components/app/tab-bar/tab-bar.js b/ui/components/app/tab-bar/tab-bar.js index b686a1274..6d9e41eb4 100644 --- a/ui/components/app/tab-bar/tab-bar.js +++ b/ui/components/app/tab-bar/tab-bar.js @@ -2,12 +2,11 @@ import React from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; -import { Icon, IconName, IconSize } from '../../component-library'; -import Box from '../../ui/box'; +import { Icon, IconName, IconSize, Box } from '../../component-library'; import { BorderRadius, Color, - DISPLAY, + Display, } from '../../../helpers/constants/design-system'; const TabBar = (props) => { @@ -33,7 +32,7 @@ const TabBar = (props) => { className="tab-bar__tab__selected-indicator" borderRadius={BorderRadius.pill} backgroundColor={Color.primaryDefault} - display={[DISPLAY.NONE, DISPLAY.BLOCK]} + display={[Display.None, Display.Block]} /> )}
    diff --git a/ui/components/app/terms-of-use-popup/terms-of-use-popup.js b/ui/components/app/terms-of-use-popup/terms-of-use-popup.js index 1b8097a70..ed16507ea 100644 --- a/ui/components/app/terms-of-use-popup/terms-of-use-popup.js +++ b/ui/components/app/terms-of-use-popup/terms-of-use-popup.js @@ -11,11 +11,11 @@ import { TextColor, } from '../../../helpers/constants/design-system'; import { - Text, Button, BUTTON_VARIANT, ButtonLink, Label, + Text, } from '../../component-library'; import Box from '../../ui/box'; import CheckBox from '../../ui/check-box/check-box.component'; diff --git a/ui/components/app/token-cell/__snapshots__/token-cell.test.js.snap b/ui/components/app/token-cell/__snapshots__/token-cell.test.js.snap index 7c0f9962a..6013ae4af 100644 --- a/ui/components/app/token-cell/__snapshots__/token-cell.test.js.snap +++ b/ui/components/app/token-cell/__snapshots__/token-cell.test.js.snap @@ -12,21 +12,21 @@ exports[`Token Cell should match snapshot 1`] = ` href="#" >
    T
    TEST logo @@ -51,7 +51,7 @@ exports[`Token Cell should match snapshot 1`] = ` title="" >

    TEST

    @@ -59,11 +59,11 @@ exports[`Token Cell should match snapshot 1`] = `

    5.000 diff --git a/ui/components/app/token-cell/token-cell.stories.js b/ui/components/app/token-cell/token-cell.stories.js new file mode 100644 index 000000000..caa3a55cb --- /dev/null +++ b/ui/components/app/token-cell/token-cell.stories.js @@ -0,0 +1,33 @@ +import React from 'react'; +import TokenListItem from '.'; + +export default { + title: 'Components/App/TokenCell', + argTypes: { + address: { + control: 'text', + }, + symbol: { + control: 'text', + }, + string: { + control: 'text', + }, + onClick: { + action: 'onClick', + }, + image: { + control: 'text', + }, + }, + args: { + address: '0xAnotherToken', + symbol: 'TEST', + string: '5.000', + currentCurrency: 'usd', + }, +}; + +export const DefaultStory = (args) => ; + +DefaultStory.storyName = 'Default'; diff --git a/ui/components/app/token-list/token-list.js b/ui/components/app/token-list/token-list.js index 5ff3eb382..2ed841033 100644 --- a/ui/components/app/token-list/token-list.js +++ b/ui/components/app/token-list/token-list.js @@ -8,6 +8,12 @@ import { useI18nContext } from '../../../hooks/useI18nContext'; import { useTokenTracker } from '../../../hooks/useTokenTracker'; import { getShouldHideZeroBalanceTokens } from '../../../selectors'; import { getTokens } from '../../../ducks/metamask/metamask'; +import { Box } from '../../component-library'; +import { + AlignItems, + Display, + JustifyContent, +} from '../../../helpers/constants/design-system'; export default function TokenList({ onTokenClick }) { const t = useI18nContext(); @@ -25,17 +31,14 @@ export default function TokenList({ onTokenClick }) { ); if (loading) { return ( -

    {t('loadingTokens')} -
    + ); } diff --git a/ui/components/app/transaction-activity-log/__snapshots__/transaction-activity-log.component.test.js.snap b/ui/components/app/transaction-activity-log/__snapshots__/transaction-activity-log.component.test.js.snap index f99da1fac..31d7667af 100644 --- a/ui/components/app/transaction-activity-log/__snapshots__/transaction-activity-log.component.test.js.snap +++ b/ui/components/app/transaction-activity-log/__snapshots__/transaction-activity-log.component.test.js.snap @@ -20,7 +20,7 @@ exports[`TransactionActivityLog Component should match snapshot 1`] = ` class="transaction-activity-log-icon transaction-activity-log__activity-icon" >
    @@ -42,7 +42,7 @@ exports[`TransactionActivityLog Component should match snapshot 1`] = ` class="transaction-activity-log-icon transaction-activity-log__activity-icon" > @@ -64,7 +64,7 @@ exports[`TransactionActivityLog Component should match snapshot 1`] = ` class="transaction-activity-log-icon transaction-activity-log__activity-icon" > @@ -86,7 +86,7 @@ exports[`TransactionActivityLog Component should match snapshot 1`] = ` class="transaction-activity-log-icon transaction-activity-log__activity-icon" > diff --git a/ui/components/app/transaction-decoding/components/ui/accreditation/accrediation.component.stories.js b/ui/components/app/transaction-decoding/components/ui/accreditation/accrediation.component.stories.js index 5eb2e730d..c9df36cb4 100644 --- a/ui/components/app/transaction-decoding/components/ui/accreditation/accrediation.component.stories.js +++ b/ui/components/app/transaction-decoding/components/ui/accreditation/accrediation.component.stories.js @@ -11,6 +11,7 @@ export default { address: { control: 'string' }, }, args: { + fetchVia: 'fetchVia', address: '0x6b175474e89094c44da98b954eedeac495271d0f', }, }; diff --git a/ui/components/app/transaction-decoding/components/ui/accreditation/accreditation.component.js b/ui/components/app/transaction-decoding/components/ui/accreditation/accreditation.component.js index cf0f40073..62e5a0a00 100644 --- a/ui/components/app/transaction-decoding/components/ui/accreditation/accreditation.component.js +++ b/ui/components/app/transaction-decoding/components/ui/accreditation/accreditation.component.js @@ -8,11 +8,22 @@ import { } from '../../../../../../selectors'; import { I18nContext } from '../../../../../../contexts/i18n'; -import { TypographyVariant } from '../../../../../../helpers/constants/design-system'; - -import Button from '../../../../../ui/button'; -import Typography from '../../../../../ui/typography'; -import { Icon, IconName } from '../../../../../component-library'; +import { + BUTTON_VARIANT, + Button, + Icon, + IconName, + Text, + Box, + BUTTON_SIZES, +} from '../../../../../component-library'; +import { + AlignItems, + Display, + TextVariant, + FlexDirection, + FlexWrap, +} from '../../../../../../helpers/constants/design-system'; const Accreditation = ({ fetchVia, address }) => { const t = useContext(I18nContext); @@ -20,48 +31,37 @@ const Accreditation = ({ fetchVia, address }) => { const rpcPrefs = useSelector(getRpcPrefsForCurrentProvider); const addressLink = getAccountLink(address, chainId, rpcPrefs); - const AccreditationLink = () => { - return ( - <> - + return ( + + + + {t('transactionDecodingAccreditationVerified', [ , ])} - - + + {t('transactionDecodingAccreditationDecoded')} - - - ); - }; - - return ( -
    -
    - -
    -
    - -
    -
    + +
    +
    ); }; diff --git a/ui/components/app/transaction-decoding/components/ui/accreditation/index.scss b/ui/components/app/transaction-decoding/components/ui/accreditation/index.scss deleted file mode 100644 index e71dfcdf3..000000000 --- a/ui/components/app/transaction-decoding/components/ui/accreditation/index.scss +++ /dev/null @@ -1,24 +0,0 @@ -.accreditation { - display: flex; - align-items: center; - margin-top: 8px; - - &__icon { - margin-right: 8px; - } - - &__info { - color: var(--color-text-default); - display: flex; - flex-flow: column; - flex-wrap: wrap; - } - - &__link.btn-link { - @include H7; - - display: inherit; - padding: 0 4px; - } -} - diff --git a/ui/components/app/transaction-decoding/index.scss b/ui/components/app/transaction-decoding/index.scss index e1da1080e..ac822449f 100644 --- a/ui/components/app/transaction-decoding/index.scss +++ b/ui/components/app/transaction-decoding/index.scss @@ -1,6 +1,5 @@ //styling for ui components @import './components/ui/copy-raw-data/index'; -@import './components/ui/accreditation/index'; //styling for decoding components @import './components/decoding/address/index'; diff --git a/ui/components/app/transaction-detail-item/transaction-detail-item.component.js b/ui/components/app/transaction-detail-item/transaction-detail-item.component.js index ed1578b62..840380b7f 100644 --- a/ui/components/app/transaction-detail-item/transaction-detail-item.component.js +++ b/ui/components/app/transaction-detail-item/transaction-detail-item.component.js @@ -2,16 +2,16 @@ import React from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; -import Typography from '../../ui/typography/typography'; import { Color, FontWeight, - TypographyVariant, - DISPLAY, - FLEX_WRAP, AlignItems, TextAlign, + TextVariant, + Display, + FlexWrap, } from '../../../helpers/constants/design-system'; +import { Text } from '../../component-library'; export default function TransactionDetailItem({ 'data-testid': dataTestId, @@ -27,18 +27,16 @@ export default function TransactionDetailItem({ return (
    - {detailTitle} - +
    {detailText && ( - + {detailText} - + )} - {detailTotal} - +
    {React.isValidElement(subTitle) ? (
    {subTitle}
    ) : ( - {subTitle} - + )} - {subText} - +
    ); diff --git a/ui/components/app/transaction-detail-item/transaction-detail-item.stories.js b/ui/components/app/transaction-detail-item/transaction-detail-item.stories.js index dcb8f1c07..bb35249bf 100644 --- a/ui/components/app/transaction-detail-item/transaction-detail-item.stories.js +++ b/ui/components/app/transaction-detail-item/transaction-detail-item.stories.js @@ -9,7 +9,6 @@ import TransactionDetailItem from '.'; export default { title: 'Components/App/TransactionDetailItem', - component: TransactionDetailItem, parameters: { docs: { diff --git a/ui/components/app/transaction-icon/transaction-icon.js b/ui/components/app/transaction-icon/transaction-icon.js index bb42a71b9..820c4969d 100644 --- a/ui/components/app/transaction-icon/transaction-icon.js +++ b/ui/components/app/transaction-icon/transaction-icon.js @@ -1,47 +1,56 @@ import React from 'react'; import { useDispatch } from 'react-redux'; import PropTypes from 'prop-types'; -import Approve from '../../ui/icon/approve-icon.component'; -import Interaction from '../../ui/icon/interaction-icon.component'; -import Receive from '../../ui/icon/receive-icon.component'; -import Send from '../../ui/icon/send-icon.component'; -import Sign from '../../ui/icon/sign-icon.component'; -import Swap from '../../ui/icon/swap-icon-for-list.component'; import { TransactionGroupCategory, TransactionGroupStatus, TransactionStatus, } from '../../../../shared/constants/transaction'; import { captureSingleException } from '../../../store/actions'; +import { AvatarIcon, IconName } from '../../component-library'; +import { + BackgroundColor, + IconColor, + Size, +} from '../../../helpers/constants/design-system'; const ICON_MAP = { - [TransactionGroupCategory.approval]: Approve, - [TransactionGroupCategory.interaction]: Interaction, - [TransactionGroupCategory.receive]: Receive, - [TransactionGroupCategory.send]: Send, - [TransactionGroupCategory.signatureRequest]: Sign, - [TransactionGroupCategory.swap]: Swap, + [TransactionGroupCategory.approval]: IconName.Check, + [TransactionGroupCategory.interaction]: IconName.ProgrammingArrows, + [TransactionGroupCategory.receive]: IconName.Received, + [TransactionGroupCategory.send]: IconName.Arrow2UpRight, + [TransactionGroupCategory.signatureRequest]: IconName.SecurityTick, + [TransactionGroupCategory.swap]: IconName.SwapHorizontal, }; -const FAIL_COLOR = 'var(--color-error-default)'; -const PENDING_COLOR = 'var(--color-icon-default)'; -const OK_COLOR = 'var(--color-primary-default)'; - const COLOR_MAP = { - [TransactionGroupStatus.pending]: PENDING_COLOR, - [TransactionGroupStatus.cancelled]: FAIL_COLOR, - [TransactionStatus.approved]: PENDING_COLOR, - [TransactionStatus.dropped]: FAIL_COLOR, - [TransactionStatus.failed]: FAIL_COLOR, - [TransactionStatus.rejected]: FAIL_COLOR, - [TransactionStatus.submitted]: PENDING_COLOR, - [TransactionStatus.unapproved]: PENDING_COLOR, + [TransactionGroupStatus.pending]: IconColor.primaryDefault, + [TransactionGroupStatus.cancelled]: IconColor.errorDefault, + [TransactionStatus.approved]: IconColor.primaryDefault, + [TransactionStatus.dropped]: IconColor.errorDefault, + [TransactionStatus.failed]: IconColor.errorDefault, + [TransactionStatus.rejected]: IconColor.errorDefault, + [TransactionStatus.submitted]: IconColor.primaryDefault, + [TransactionStatus.unapproved]: IconColor.primaryDefault, +}; + +const BACKGROUND_COLOR_MAP = { + [TransactionGroupStatus.pending]: BackgroundColor.primaryMuted, + [TransactionGroupStatus.cancelled]: BackgroundColor.errorMuted, + [TransactionStatus.approved]: BackgroundColor.primaryMuted, + [TransactionStatus.dropped]: BackgroundColor.errorMuted, + [TransactionStatus.failed]: BackgroundColor.errorMuted, + [TransactionStatus.rejected]: BackgroundColor.errorMuted, + [TransactionStatus.submitted]: BackgroundColor.primaryMuted, + [TransactionStatus.unapproved]: BackgroundColor.primaryMuted, }; export default function TransactionIcon({ status, category }) { const dispatch = useDispatch(); - const color = COLOR_MAP[status] || OK_COLOR; + const color = COLOR_MAP[status] || IconColor.primaryDefault; + const backgroundColor = + BACKGROUND_COLOR_MAP[status] || BackgroundColor.primaryMuted; const Icon = ICON_MAP[category]; if (!Icon) { @@ -50,10 +59,22 @@ export default function TransactionIcon({ status, category }) { `The category prop passed to TransactionIcon is not supported. The prop is: ${category}`, ), ); - return
    ; + return ( + + ); } - return ; + return ( + + ); } TransactionIcon.propTypes = { diff --git a/ui/components/app/transaction-list-item/index.scss b/ui/components/app/transaction-list-item/index.scss index 069510062..8c1296b4d 100644 --- a/ui/components/app/transaction-list-item/index.scss +++ b/ui/components/app/transaction-list-item/index.scss @@ -23,14 +23,12 @@ } &__pending-actions { - padding-top: 12px; display: flex; .button { - @include H8; + @include H6; - padding: 8px; - width: 75px; + width: 90px; white-space: nowrap; } @@ -57,11 +55,6 @@ text-overflow: initial; } - .transaction-status-label::after { - content: "·"; - margin: 0 4px; - } - &__address { overflow: hidden; text-overflow: ellipsis; diff --git a/ui/components/app/transaction-list-item/smart-transaction-list-item.component.js b/ui/components/app/transaction-list-item/smart-transaction-list-item.component.js index 7c71e3a44..206fa0ec3 100644 --- a/ui/components/app/transaction-list-item/smart-transaction-list-item.component.js +++ b/ui/components/app/transaction-list-item/smart-transaction-list-item.component.js @@ -1,7 +1,6 @@ import React, { useState, useCallback } from 'react'; import PropTypes from 'prop-types'; -import { useDispatch } from 'react-redux'; -import ListItem from '../../ui/list-item'; +import { useDispatch, useSelector } from 'react-redux'; import TransactionStatusLabel from '../transaction-status-label/transaction-status-label'; import TransactionIcon from '../transaction-icon'; import { useI18nContext } from '../../../hooks/useI18nContext'; @@ -15,8 +14,20 @@ import { import CancelButton from '../cancel-button'; import { cancelSwapsSmartTransaction } from '../../../ducks/swaps/swaps'; -import SiteOrigin from '../../ui/site-origin'; import TransactionListItemDetails from '../transaction-list-item-details'; +import { ActivityListItem } from '../../multichain'; +import { + AvatarNetwork, + AvatarNetworkSize, + BadgeWrapper, + BadgeWrapperAnchorElementShape, + Box, +} from '../../component-library'; +import { + BackgroundColor, + Display, +} from '../../../helpers/constants/design-system'; +import { getCurrentNetwork } from '../../../selectors'; export default function SmartTransactionListItem({ smartTransaction, @@ -29,6 +40,8 @@ export default function SmartTransactionListItem({ const [showDetails, setShowDetails] = useState(false); const { primaryCurrency, recipientAddress, isPending, senderAddress } = useTransactionDisplayData(transactionGroup); + const currentChain = useSelector(getCurrentNetwork); + const { sourceTokenSymbol, destinationTokenSymbol, time, status } = smartTransaction; const category = TransactionGroupCategory.swap; @@ -36,8 +49,7 @@ export default function SmartTransactionListItem({ sourceTokenSymbol, destinationTokenSymbol, ]); - const subtitle = 'metamask'; - const date = formatDateWithYearContext(time); + const date = formatDateWithYearContext(time, 'MMM d, y', 'MMM d'); let displayedStatusKey; if (status === SmartTransactionStatus.pending) { displayedStatusKey = TransactionGroupStatus.pending; @@ -52,32 +64,45 @@ export default function SmartTransactionListItem({ }, []); return ( <> - + + } + > + + } subtitle={ -

    - - -

    + } > {displayedStatusKey === TransactionGroupStatus.pending && showCancelSwapLink && ( -
    + { @@ -86,9 +111,9 @@ export default function SmartTransactionListItem({ setCancelSwapLinkClicked(true); }} /> -
    + )} -
    + {showDetails && ( !prev); - }, [isUnapproved, history, id]); + setShowDetails((prev) => { + trackEvent({ + event: prev + ? MetaMetricsEventName.ActivityDetailsClosed + : MetaMetricsEventName.ActivityDetailsOpened, + category: MetaMetricsEventCategory.Navigation, + properties: { + activity_type: category, + }, + }); + return !prev; + }); + }, [isUnapproved, history, id, trackEvent, category]); ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) const debugTransactionMeta = { @@ -195,7 +233,7 @@ function TransactionListItemInner({ isCustodian, ///: END:ONLY_INCLUDE_IN ]); - + const currentChain = useSelector(getCurrentNetwork); let showCancelButton = !hasCancelled && isPending && !isUnapproved; ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) @@ -219,14 +257,15 @@ function TransactionListItemInner({ return ( <> - + -
    + ) : ( ///: END:ONLY_INCLUDE_IN - + + } + > + + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) ) ///: END:ONLY_INCLUDE_IN } subtitle={ -

    - - {subtitleContainsOrigin ? ( - - ) : ( - - {subtitle} - - )} -

    + } rightContent={ !isSignatureReq && !isApproval && ( <> -

    {primaryCurrency} -

    -

    + + {secondaryCurrency} -

    + ) } > -
    - {speedUpButton} + {showCancelButton && ( )} -
    + {speedUpButton} + { ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) ///: END:ONLY_INCLUDE_IN } - + {showDetails && ( { return { ...actual, useSelector: jest.fn(), - useDispatch: () => jest.fn(), + useDispatch: jest.fn(), }; }); @@ -97,6 +104,8 @@ const generateUseSelectorRouter = (opts) => (selector) => { }; } else if (selector === getTokenExchangeRates) { return opts.tokenExchangeRates ?? {}; + } else if (selector === getCurrentNetwork) { + return { nickname: 'Ethereum Mainnet' }; } else if (selector === getPreferences) { return ( opts.preferences ?? { @@ -112,6 +121,53 @@ const generateUseSelectorRouter = (opts) => (selector) => { }; describe('TransactionListItem', () => { + describe('ActivityListItem interactions', () => { + beforeAll(() => { + useGasFeeEstimates.mockImplementation( + () => FEE_MARKET_ESTIMATE_RETURN_VALUE, + ); + }); + + afterAll(() => { + useGasFeeEstimates.mockRestore(); + }); + + it('should show the activity details popover and log metrics when the activity list item is clicked', () => { + useSelector.mockImplementation( + generateUseSelectorRouter({ + balance: '0x3', + }), + ); + + const store = mockStore(mockState); + const mockTrackEvent = jest.fn(); + const { queryByTestId } = renderWithProvider( + + + , + store, + ); + const activityListItem = queryByTestId('activity-list-item'); + fireEvent.click(activityListItem); + expect(mockTrackEvent).toHaveBeenCalledWith({ + event: MetaMetricsEventName.ActivityDetailsOpened, + category: MetaMetricsEventCategory.Navigation, + properties: { + activity_type: 'send', + }, + }); + const popoverClose = queryByTestId('popover-close'); + fireEvent.click(popoverClose); + expect(mockTrackEvent).toHaveBeenCalledWith({ + event: MetaMetricsEventName.ActivityDetailsClosed, + category: MetaMetricsEventCategory.Navigation, + properties: { + activity_type: 'send', + }, + }); + }); + }); + describe('when account has insufficient balance to cover gas', () => { beforeAll(() => { useGasFeeEstimates.mockImplementation( diff --git a/ui/components/app/transaction-list/transaction-list.component.js b/ui/components/app/transaction-list/transaction-list.component.js index be50d01f9..93111fa6a 100644 --- a/ui/components/app/transaction-list/transaction-list.component.js +++ b/ui/components/app/transaction-list/transaction-list.component.js @@ -14,6 +14,12 @@ import { TOKEN_CATEGORY_HASH } from '../../../helpers/constants/transactions'; import { SWAPS_CHAINID_CONTRACT_ADDRESS_MAP } from '../../../../shared/constants/swaps'; import { TransactionType } from '../../../../shared/constants/transaction'; import { isEqualCaseInsensitive } from '../../../../shared/modules/string-utils'; +import { Box, Text } from '../../component-library'; +import { + TextColor, + TextVariant, +} from '../../../helpers/constants/design-system'; +import { formatDateWithYearContext } from '../../../helpers/utils/util'; const PAGE_INCREMENT = 10; @@ -64,6 +70,35 @@ const getFilteredTransactionGroups = ( return transactionGroups; }; +const groupTransactionsByDate = (transactionGroups) => { + const groupedTransactions = []; + + transactionGroups.forEach((transactionGroup) => { + const date = formatDateWithYearContext( + transactionGroup.primaryTransaction.time, + 'MMM d, y', + 'MMM d', + ); + + const existingGroup = groupedTransactions.find( + (group) => group.date === date, + ); + + if (existingGroup) { + existingGroup.transactionGroups.push(transactionGroup); + } else { + groupedTransactions.push({ + date, + dateMillis: transactionGroup.primaryTransaction.time, + transactionGroups: [transactionGroup], + }); + } + groupedTransactions.sort((a, b) => b.dateMillis - a.dateMillis); + }); + + return groupedTransactions; +}; + export default function TransactionList({ hideTokenTransactions, tokenAddress, @@ -78,14 +113,29 @@ export default function TransactionList({ nonceSortedCompletedTransactionsSelector, ); const chainId = useSelector(getCurrentChainId); + const renderDateStamp = (index, dateGroup) => { + return index === 0 ? ( + + {dateGroup.date} + + ) : null; + }; const pendingTransactions = useMemo( () => - getFilteredTransactionGroups( - unfilteredPendingTransactions, - hideTokenTransactions, - tokenAddress, - chainId, + groupTransactionsByDate( + getFilteredTransactionGroups( + unfilteredPendingTransactions, + hideTokenTransactions, + tokenAddress, + chainId, + ), ), [ hideTokenTransactions, @@ -94,13 +144,16 @@ export default function TransactionList({ chainId, ], ); + const completedTransactions = useMemo( () => - getFilteredTransactionGroups( - unfilteredCompletedTransactions, - hideTokenTransactions, - tokenAddress, - chainId, + groupTransactionsByDate( + getFilteredTransactionGroups( + unfilteredCompletedTransactions, + hideTokenTransactions, + tokenAddress, + chainId, + ), ), [ hideTokenTransactions, @@ -116,78 +169,78 @@ export default function TransactionList({ ); return ( -
    -
    + + {pendingTransactions.length > 0 && ( -
    -
    - {`${t('queue')} (${pendingTransactions.length})`} -
    - {pendingTransactions - ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) - .sort( - (a, b) => b.primaryTransaction.time - a.primaryTransaction.time, - ) - ///: END:ONLY_INCLUDE_IN - .map((transactionGroup, index) => { - ///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask) - if ( - transactionGroup.initialTransaction.transactionType === - TransactionType.smart - ) { + + {pendingTransactions.map((dateGroup) => { + return dateGroup.transactionGroups.map( + (transactionGroup, index) => { + if ( + transactionGroup.initialTransaction.transactionType === + TransactionType.smart + ) { + return ( + <> + {renderDateStamp(index, dateGroup)} + + + ); + } return ( - + <> + {renderDateStamp(index, dateGroup)} + + ); - } - ///: END:ONLY_INCLUDE_IN - return ( - - ); - })} -
    + }, + ); + })} +
    )} -
    - {pendingTransactions.length > 0 ? ( -
    {t('history')}
    - ) : null} + {completedTransactions.length > 0 ? ( - completedTransactions - ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) - .sort( - (a, b) => b.primaryTransaction.time - a.primaryTransaction.time, - ) - ///: END:ONLY_INCLUDE_IN - .slice(0, limit) - .map((transactionGroup, index) => - transactionGroup.initialTransaction?.transactionType === - 'smart' ? ( - - ) : ( - - ), - ) + completedTransactions.slice(0, limit).map((dateGroup) => { + return dateGroup.transactionGroups.map( + (transactionGroup, index) => { + return ( + <> + {renderDateStamp(index, dateGroup)} + {transactionGroup.initialTransaction?.transactionType === + TransactionType.smart ? ( + + ) : ( + + )} + + ); + }, + ); + }) ) : ( -
    -
    + + {t('noTransactions')} -
    -
    +
    + )} {completedTransactions.length > limit && (
    -
    -
    + + + ); } diff --git a/ui/components/app/user-preferenced-currency-display/__snapshots__/user-preferenced-currency-display.test.js.snap b/ui/components/app/user-preferenced-currency-display/__snapshots__/user-preferenced-currency-display.test.js.snap index 61224fdb0..b29efce54 100644 --- a/ui/components/app/user-preferenced-currency-display/__snapshots__/user-preferenced-currency-display.test.js.snap +++ b/ui/components/app/user-preferenced-currency-display/__snapshots__/user-preferenced-currency-display.test.js.snap @@ -3,19 +3,16 @@ exports[`UserPreferencedCurrencyDisplay Component rendering should match snapshot 1`] = `
    - 0 ETH diff --git a/ui/components/app/wallet-overview/token-overview.test.js b/ui/components/app/wallet-overview/token-overview.test.js index 8a5495858..21a4faa57 100644 --- a/ui/components/app/wallet-overview/token-overview.test.js +++ b/ui/components/app/wallet-overview/token-overview.test.js @@ -233,48 +233,6 @@ describe('TokenOverview', () => { ); }); - it('should always show the Portfolio button', () => { - const mockToken = { - name: 'test', - isERC721: false, - address: '0x7ceb23fd6bc0add59e62ac25578270cff1B9f619', - symbol: 'test', - }; - const { queryByTestId } = renderWithProvider( - , - store, - ); - const portfolioButton = queryByTestId('home__portfolio-site'); - expect(portfolioButton).toBeInTheDocument(); - }); - - it('should open the Portfolio URI when clicking on Portfolio button', async () => { - const mockToken = { - name: 'test', - isERC721: false, - address: '0x7ceb23fd6bc0add59e62ac25578270cff1B9f619', - symbol: 'test', - }; - const { queryByTestId } = renderWithProvider( - , - store, - ); - - const portfolioButton = queryByTestId('home__portfolio-site'); - - expect(portfolioButton).toBeInTheDocument(); - expect(portfolioButton).not.toBeDisabled(); - - fireEvent.click(portfolioButton); - expect(openTabSpy).toHaveBeenCalledTimes(1); - - await waitFor(() => - expect(openTabSpy).toHaveBeenCalledWith({ - url: expect.stringContaining(`?metamaskEntry=ext`), - }), - ); - }); - it('should show the Bridge button if chain id and token are supported', async () => { const mockToken = { name: 'test', diff --git a/ui/components/app/whats-new-popup/whats-new-popup.js b/ui/components/app/whats-new-popup/whats-new-popup.js index 5743cc841..fb4ea7286 100644 --- a/ui/components/app/whats-new-popup/whats-new-popup.js +++ b/ui/components/app/whats-new-popup/whats-new-popup.js @@ -9,11 +9,11 @@ import { I18nContext } from '../../../contexts/i18n'; import { useEqualityCheck } from '../../../hooks/useEqualityCheck'; import Popover from '../../ui/popover'; import { + Text, Button, ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) IconName, ///: END:ONLY_INCLUDE_IN - Text, } from '../../component-library'; import { updateViewedNotifications } from '../../../store/actions'; import { getTranslatedUINotifications } from '../../../../shared/notifications'; @@ -347,10 +347,26 @@ export default function WhatsNewPopup({ observer.observe(ref.current); }); + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + trackEvent({ + category: MetaMetricsEventCategory.MMI, + event: MetaMetricsEventName.MMIPortfolioDashboardModalOpen, + properties: { + action: 'Modal was opened', + }, + }); + ///: END:ONLY_INCLUDE_IN + return () => { observer.disconnect(); }; - }, [idRefMap, setSeenNotifications]); + }, [ + idRefMap, + setSeenNotifications, + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + trackEvent, + ///: END:ONLY_INCLUDE_IN + ]); // Display the swaps notification with full image // Displays the NFTs & OpenSea notifications 18,19 with full image @@ -377,6 +393,15 @@ export default function WhatsNewPopup({ completed_all: true, }, }); + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + trackEvent({ + category: MetaMetricsEventCategory.MMI, + event: MetaMetricsEventName.MMIPortfolioDashboardModalButton, + properties: { + action: 'Button was clicked', + }, + }); + ///: END:ONLY_INCLUDE_IN onClose(); }} popoverRef={popoverRef} diff --git a/ui/components/component-library/README.md b/ui/components/component-library/README.md index 7abd2d06f..44849d787 100644 --- a/ui/components/component-library/README.md +++ b/ui/components/component-library/README.md @@ -4,21 +4,25 @@ This folder contains design system components that are built 1:1 with the Figma ## Architecture -All components are built on top of the `Box` component and accept all `Box` [component props](https://metamask.github.io/metamask-storybook/?path=/docs/components-ui-box--default-story#props) +All components are built on top of the `Box` component and accept all `Box` [component props](/docs/components-componentlibrary-box--docs#props). -#### Layout +### Layout -`component-library` components accept all utility props for layout +`component-library` components accept all `Box` component style utility props for layout. They can be used in conjunction with the enums from `ui/helpers/constants/design-system.ts` ```jsx +import { Display } from '../../../helpers/constants/design-system'; import { Text } from '../../component-library'; -This text has a margin-bottom of 16px; + + This text has a margin-bottom of 16px + It also has a display of flex and gap of 16px +; ``` -#### Polymorphic `as` prop +### Polymorphic `as` prop and semantic HTML -`component-library` components accept a polymorphic as prop to change the root html element of a component +`component-library` components accept a polymorphic `as` prop to change the root html element of a component ```jsx import { Text } from '../../component-library'; @@ -28,9 +32,61 @@ import { Text } from '../../component-library'; ; ``` +### Style customization and access child components + +We understand some customization to styles or access to children components is necessary when building UI. To ensure our components are flexible we intend to allow for customization and access though a pattern called inversion of control. + +#### Styles + +> Note: If you are seeing a disparity between styles in Figma and code that's a red flag and could mean there is bug between design system Figma and code component. We recommend posting it on our slack channel [#metamask-design-system](https://consensys.slack.com/archives/C0354T27M5M) so we can support you on it + +We try to utilize the `Box` component style utility props as much as possible in our components. Style utility prop overrides should be your first option. This allows you to change styles right inside of the component and reduces the amount of CSS in the codebase. If there are no style utility props for the customization required you can attach a class name to the component using the `className` prop and add styling using CSS. + +```jsx +import { BackgroundColor } from '../../../helpers/constants/design-system'; +import { Button } from '../../component-library'; + +// Overriding the browser default styling using style utility props + + Renders as a button but has a transparent background +; + + + Adding a custom className to add additional styles using CSS +; +``` + +### Access to child components + +All of our components should allow access to children components through an object prop. The example below adds a data test id to the child `Text` component inside `BannerAlert`. + +```jsx +import { Severity } from '../../../helpers/constants/design-system'; +import { BannerAlert } from '../../component-library'; + +; +``` + +### Accessibility + +Allowing everyone to access web3 regardless of disability is an important part of what we do at MetaMask. Ensuring accessibility in our components is a priority. We strive to achieve this by maintaining proper color contrast in our components and implementing necessary aria label props. If you have any questions regarding accessibility reach out and we will support you as much as possible. Additionally, your suggestions for improvement are welcome, as we continue our journey towards greater accessibility. Together, let's create an inclusive web3 experience for all 🦾 + ## TypeScript -We are currently in the process of migrating all component-library components to TypeScript. Feel free to contribute by creating a PR against one of [these issues](https://github.com/MetaMask/metamask-extension/issues?q=is%3Aissue+is%3Aopen+DS%2FExtension%2F2023%2FQ2%2FO1%2FKR3) +We are currently in the process of migrating all component-library components to TypeScript. Feel free to contribute by creating a PR against one of [these issues](https://github.com/MetaMask/metamask-extension/issues?q=is%3Aissue+is%3Aopen+Migrate+components+to+TS) ## Support diff --git a/ui/components/component-library/avatar-account/__snapshots__/avatar-account.test.js.snap b/ui/components/component-library/avatar-account/__snapshots__/avatar-account.test.js.snap index 6a46eb546..667bbe8a3 100644 --- a/ui/components/component-library/avatar-account/__snapshots__/avatar-account.test.js.snap +++ b/ui/components/component-library/avatar-account/__snapshots__/avatar-account.test.js.snap @@ -3,7 +3,7 @@ exports[`AvatarAccount should render correctly 1`] = `