diff --git a/.circleci/config.yml b/.circleci/config.yml index 1755e91b46a1..8884b4efb241 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -125,6 +125,9 @@ workflows: - prep-build-test-flask: requires: - prep-deps + - prep-build-test-mmi: + requires: + - prep-deps - prep-build-storybook: requires: - prep-deps @@ -162,6 +165,12 @@ workflows: - test-e2e-firefox-snaps-flask: requires: - prep-build-test-flask + - test-e2e-chrome-mmi: + requires: + - prep-build-test-mmi + - test-e2e-chrome-rpc-mmi: + requires: + - prep-build-test-mmi - test-e2e-chrome-mv3: requires: - prep-build-test-mv3 @@ -248,6 +257,8 @@ workflows: - test-e2e-firefox-snaps - test-e2e-chrome-snaps-flask - test-e2e-firefox-snaps-flask + - test-e2e-chrome-mmi + - test-e2e-chrome-rpc-mmi - test-storybook - benchmark: requires: @@ -350,23 +361,28 @@ jobs: executor: node-browsers steps: - run: *shallow-git-clone + - run: + name: Save Yarn version + command: | + yarn --version > /tmp/YARN_VERSION - restore_cache: keys: # First try to get the specific cache for the checksum of the yarn.lock file. # This cache key lookup will fail if the lock file is modified and a cache # has not yet been persisted for the new checksum. - - dependency-cache-v1-{{ checksum "yarn.lock" }} + - dependency-cache-{{ checksum "/tmp/YARN_VERSION" }}-{{ checksum "yarn.lock" }} # To prevent having to do a full install of every node_module when # dependencies change, restore from the last known cache of any - # branch/checksum, the install step will remove cached items that are no longer - # required and add the new dependencies, and the cache will be persisted. - - dependency-cache-v1- + # branch/checksum with the same Yarn version, the install step will remove + # cached items that are no longer required and add the new dependencies, and + # the cache will be persisted. + - dependency-cache-{{ checksum "/tmp/YARN_VERSION" }}- - gh/install - run: name: Install dependencies command: .circleci/scripts/install-dependencies.sh - save_cache: - key: dependency-cache-v1-{{ checksum "yarn.lock" }} + key: dependency-cache-{{ checksum "/tmp/YARN_VERSION" }}-{{ checksum "yarn.lock" }} paths: - .yarn/cache - persist_to_workspace: @@ -568,10 +584,10 @@ jobs: name: Build extension for testing command: yarn build:test:flask - run: - name: Move test build to 'dist-test' to avoid conflict with production build + name: Move test build to 'dist-test-flask' to avoid conflict with production build command: mv ./dist ./dist-test-flask - run: - name: Move test zips to 'builds-test' to avoid conflict with production build + name: Move test zips to 'builds-test-flask' to avoid conflict with production build command: mv ./builds ./builds-test-flask - persist_to_workspace: root: . @@ -579,6 +595,27 @@ jobs: - dist-test-flask - builds-test-flask + prep-build-test-mmi: + executor: node-browsers-medium-plus + steps: + - run: *shallow-git-clone + - attach_workspace: + at: . + - run: + name: Build extension for testing + command: yarn build:test:mmi + - run: + name: Move test build to 'dist-test' to avoid conflict with production build + command: mv ./dist ./dist-test-mmi + - run: + name: Move test zips to 'builds-test' to avoid conflict with production build + command: mv ./builds ./builds-test-mmi + - persist_to_workspace: + root: . + paths: + - dist-test-mmi + - builds-test-mmi + prep-build-test-mv3: executor: node-browsers-medium-plus steps: @@ -592,7 +629,7 @@ jobs: name: Move test build to 'dist-test' to avoid conflict with production build command: mv ./dist ./dist-test-mv3 - run: - name: Move test zips to 'builds-test' to avoid conflict with production build + name: Move test zips to 'builds-test-mv3' to avoid conflict with production build command: mv ./builds ./builds-test-mv3 - persist_to_workspace: root: . @@ -855,6 +892,42 @@ jobs: - store_test_results: path: test/test-results/e2e.xml + test-e2e-chrome-rpc-mmi: + executor: node-browsers + steps: + - checkout + - run: + name: Re-Install Chrome + command: ./.circleci/scripts/chrome-install.sh + - attach_workspace: + at: . + - run: + name: Move test build to dist + command: mv ./dist-test-mmi ./dist + - run: + name: Move test zips to builds + command: mv ./builds-test-mmi ./builds + - run: + name: test:e2e:chrome:rpc + command: | + if .circleci/scripts/test-run-e2e.sh + then + yarn test:e2e:chrome:rpc --retries 2 --debug --build-type=mmi + fi + no_output_timeout: 20m + - run: + name: Merge JUnit report + command: | + if [ "$(ls -A test/test-results/e2e)" ]; then + yarn test:e2e:report + fi + when: always + - store_artifacts: + path: test-artifacts + destination: test-artifacts + - store_test_results: + path: test/test-results/e2e.xml + test-e2e-firefox-snaps: executor: node-browsers parallelism: 4 @@ -950,7 +1023,7 @@ jobs: command: | if .circleci/scripts/test-run-e2e.sh then - yarn test:e2e:firefox:snaps --retries 2 --debug + yarn test:e2e:firefox:snaps --retries 2 --debug --build-type=flask fi no_output_timeout: 20m - run: @@ -987,7 +1060,44 @@ jobs: command: | if .circleci/scripts/test-run-e2e.sh then - yarn test:e2e:chrome:snaps --retries 2 --debug + yarn test:e2e:chrome:snaps --retries 2 --debug --build-type=flask + fi + no_output_timeout: 20m + - run: + name: Merge JUnit report + command: | + if [ "$(ls -A test/test-results/e2e)" ]; then + yarn test:e2e:report + fi + when: always + - store_artifacts: + path: test-artifacts + destination: test-artifacts + - store_test_results: + path: test/test-results/e2e.xml + + test-e2e-chrome-mmi: + executor: node-browsers + parallelism: 4 + steps: + - run: *shallow-git-clone + - run: + name: Re-Install Chrome + command: ./.circleci/scripts/chrome-install.sh + - attach_workspace: + at: . + - run: + name: Move test build to dist + command: mv ./dist-test-mmi ./dist + - run: + name: Move test zips to builds + command: mv ./builds-test-mmi ./builds + - run: + name: test:e2e:chrome:mmi + command: | + if .circleci/scripts/test-run-e2e.sh + then + yarn test:e2e:chrome:mmi --retries 2 --debug --build-type=mmi fi no_output_timeout: 20m - run: @@ -1162,6 +1272,10 @@ jobs: - store_artifacts: path: builds-mmi destination: builds-mmi + - store_artifacts: + path: builds-test + - store_artifacts: + path: builds-test-flask - store_artifacts: path: coverage destination: coverage diff --git a/.depcheckrc.yml b/.depcheckrc.yml index 187fd0b1eafc..972b13b06e8a 100644 --- a/.depcheckrc.yml +++ b/.depcheckrc.yml @@ -10,14 +10,6 @@ ignores: - '@fortawesome/fontawesome-free' - 'punycode' - # - # snaps flask deps - # - - '@metamask/rpc-methods-flask' - - '@metamask/snaps-controllers-flask' - - '@metamask/snaps-ui-flask' - - '@metamask/snaps-utils-flask' - # # dev deps # diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 546f26ec89bd..626825e79323 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -9,7 +9,6 @@ * @MetaMask/extension-devs **/snaps/** @MetaMask/snaps-devs -**/flask/** @MetaMask/snaps-devs development/ @MetaMask/extension-devs @kumavis lavamoat/ @MetaMask/extension-devs @MetaMask/supply-chain @MetaMask/snaps-devs diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 74131102ecea..a7d720258e0b 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -6,13 +6,14 @@ If you're submitting code to MetaMask, there are some simple things we'd appreci Before taking the time to code and implement something, feel free to open an issue and discuss it! There may even be an issue already open, and together we may come up with a specific strategy before you take your precious time to write code. -There are also plenty of open issues we'd love help with. Search the [`good first issue`](https://github.com/MetaMask/metamask-extension/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) label, or head to Gitcoin and earn ETH for completing projects we've posted bounties on. +There are also plenty of open issues we'd love help with. Search the [`good first issue`](https://github.com/MetaMask/metamask-extension/contribute) label, or head to Gitcoin and earn ETH for completing projects we've posted bounties on. If you're picking up a bounty or an existing issue, feel free to ask clarifying questions on the issue as you go about your work. ### Submitting a pull request When you're done with your project / bugfix / feature and ready to submit a PR, there are a couple guidelines we ask you to follow: +- [ ] **Make sure you followed our [`coding guidelines`](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md)**: These guidelines aim to maintain consistency and readability across the codebase. They help ensure that the code is easy to understand, maintain, and modify, which is particularly important when working with multiple contributors. - [ ] **Test it**: For any new programmatic functionality, we like unit tests when possible, so if you can keep your code cleanly isolated, please do add a test file to the `tests` folder. - [ ] **Add to the CHANGELOG**: Help us keep track of all the moving pieces by adding an entry to the [`CHANGELOG.md`](https://github.com/MetaMask/metamask-extension/blob/develop/CHANGELOG.md) with a link to your PR. - [ ] **Meet the spec**: Make sure the PR adds functionality that matches the issue you're closing. This is especially important for bounties: sometimes design or implementation details are included in the conversation, so read carefully! diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index 90450a3953aa..df752860bfb1 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -16,17 +16,30 @@ body: id: what-happened attributes: label: Describe the bug - description: What happened? What did you expect to happen? Please include screenshots if applicable! - placeholder: Tell us what you see! + description: What happened? + placeholder: A clear and concise description of what the bug is validations: required: true + - type: textarea + id: expected-behavior + attributes: + label: Expected behavior + description: What did you expect to happen? + - type: textarea + id: screenshot + attributes: + label: Screenshots + description: Please include screenshots if applicable! - type: textarea id: reproduce attributes: label: Steps to reproduce - description: List all steps needed to reproduce the problem - value: | - 1. + description: "List all steps needed to reproduce the problem:" + placeholder: | + 1. Go to '...' + 2. Click on '...' + 3. Scroll down to '...' + 4. See error validations: required: true - type: textarea @@ -96,3 +109,14 @@ body: attributes: label: Additional context description: Add any other context about the problem here, e.g. related issues, additional error messages or logs, or any potentially relevant details about the environment or situation the bug occurred in. + - type: textarea + id: severity + attributes: + label: Severity + description: | + To be added after bug submission by internal support / PM: + placeholder: | + - How critical is the impact of this bug on a user? + - Add stats if available on % of customers impacted + - Is this visible to all users? + - Is this tech debt? diff --git a/.github/ISSUE_TEMPLATE/general-issue.yml b/.github/ISSUE_TEMPLATE/general-issue.yml new file mode 100644 index 000000000000..f23b47082e5a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/general-issue.yml @@ -0,0 +1,105 @@ +name: General issue +description: For any issues +labels: [] +assignees: [] + +body: + - type: markdown + attributes: + value: | + ## **Description** + + - type: textarea + id: description + attributes: + label: What is this about? + placeholder: Describe the issue here. + validations: + required: true + + - type: markdown + attributes: + value: | + ## **Scenario (for user stories only)** + + - type: textarea + id: scenario + attributes: + label: Scenario + placeholder: | + - GIVEN a user is in x state + - WHEN a user does x + - AND a user does x + - THEN x should occur + + - type: markdown + attributes: + value: | + ## **Design (for user stories only)** + + - type: textarea + id: design + attributes: + label: Design + placeholder: If available, provide a link to the design (e.g., Figma) or screenshots. If you're an external contributor and don't have access to the design, feel free to skip this step or provide any visual representation of the issue if possible. + + - type: markdown + attributes: + value: | + ## **Technical Details (for technical tasks only)** + + - type: textarea + id: technical-details + attributes: + label: Technical Details + placeholder: | + - Implementation details + - Insight to what needs to be done + - Etc. + + - type: markdown + attributes: + value: | + ## **[Threat Modeling Framework](https://github.com/adamshostack/4QuestionFrame) (for technical tasks only)** + + - type: textarea + id: threat-modeling + attributes: + label: Threat Modeling Framework + placeholder: | + - What are we working on? What does this aim to solve? + - What can go wrong? + - What are we going to do about it? + - Did we do a good job? + + - type: markdown + attributes: + value: | + ## **Acceptance Criteria** + + - type: textarea + id: acceptance-criteria + attributes: + label: Acceptance Criteria + placeholder: | + - Are metrics required? + - Are translations required? + - Cases to satisfy + - XYZ should work + - Etc. + + - type: markdown + attributes: + value: | + ## **References** + + - type: textarea + id: references + attributes: + label: References + placeholder: | + - References go here. + - Screenshots. + - Issue numbers. Links. + - Slack threads. + - Etc. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 8f4c7ba9eac2..000000000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,53 +0,0 @@ -## Explanation - - - -## Screenshots/Screencaps - - - -### Before - - - -### After - - - -## Manual Testing Steps - - - -## Pre-merge author checklist - -- [ ] I've clearly explained: - - [ ] What problem this PR is solving - - [ ] How this problem was solved - - [ ] How reviewers can test my changes -- [ ] Sufficient automated test coverage has been added - -## Pre-merge reviewer checklist - -- [ ] Manual testing (e.g. pull and build branch, run in browser, test code being changed) -- [ ] PR is linked to the appropriate GitHub issue -- [ ] **IF** this PR fixes a bug in the release milestone, add this PR to the release milestone - -If further QA is required (e.g. new feature, complex testing steps, large refactor), add the `Extension QA Board` label. - -In this case, a QA Engineer approval will be be required. diff --git a/.github/guidelines/CODING_GUIDELINES.md b/.github/guidelines/CODING_GUIDELINES.md new file mode 100644 index 000000000000..a59e3fd71fa5 --- /dev/null +++ b/.github/guidelines/CODING_GUIDELINES.md @@ -0,0 +1,64 @@ +# MetaMask Coding Guidelines + +### 1. New Code Should be TypeScript +- New components and utilities should be written in TypeScript and enforce typing. +- Existing code should be refactored into TypeScript where time allows. If you are replacing a component, use TypeScript. +- Follow contributor doc [TypeScript Guidelines](https://github.com/MetaMask/contributor-docs/blob/main/docs/typescript.md). + +### 2. Using Functional Components and Hooks Instead of Classes +- Use functional components and hooks as they result in more concise and readable code compared to classes. + +### 3. Organize Files Related to the Same Component in One Folder +- An example of a component file structure: + +```.tsx +avatar-account +├── avatar-account.stories.tsx +├── avatar-account.scss +├── avatar-account.test.tsx +├── avatar-account.tsx +├── avatar-account.types.ts +├── README.md +├── __snapshots__ +│   └── avatar-account.test.tsx.snap +└── index.ts +``` + +### 4. Follow Naming Conventions +- You should always use PascalCase when naming components. For example: *TextField*, *NavMenu*, and *SuccessButton*. +- Use camelCase for functions declared inside components like *handleInput()* or *showElement()*. +- When creating hooks use *withHookName()*. + +### 5. Avoid Repetitive Code +- If you notice you are writing duplicated code or components, convert it into a component, utility functions or hooks that can be reused. Do this with [scalable intention](https://sandimetz.com/blog/2016/1/20/the-wrong-abstraction). + +### 6. Component Optimization +- For functional components, instead of having large return statements, breaking the component down into smaller sub-components. +- Use memoizing techniques where possible. Utilize the `useMemo` hook for values and `useCallback` for functions. Follow recommended React guidance. +- Use the useEffect hook for performing side effects like data fetching or DOM manipulation after the component has rendered. However, use it judiciously as unnecessary effects can complicate code and affect performance. For a deeper understanding, we recommend reading [this article](https://react.dev/learn/you-might-not-need-an-effect). + +### 7. Use Object Destructuring For Props +- Instead of passing the props object, use object destructuring to pass the prop name. This discards the need to refer to the props object each time you need to use it. + +```tsx +import React from 'react'; +const MyComponent = ({ id }) => { + return
; +}; + +``` + +### 8. Document Each Component/Utility +- New utility functions should be documented [TSDoc](https://tsdoc.org) commenting format. +- Referencing our component docs. +- If applicable add URL to online resources if they are meaningful for the component/method. + +### 9. Write Tests for Each Component/Utility +- Write tests for the components you create as it reduces the possibilities of errors. Testing ensures that the components are behaving as you would expect. In this project Jest is used, and it provides an environment where you can execute your tests. +- Follow the contributor docs [Unit Testing Guidelines](https://github.com/MetaMask/contributor-docs/blob/main/docs/unit-testing.md). + +### 10. External packages should be well maintained +- New packages should only be integrated if the application doesn’t have the existing functionality and it cannot be added by implementing a small utility function. Use the https://snyk.io/advisor/ to assess the popularity, maintainability and security analysis. The package must be in good standing to be added to the project. +- Update existing dependencies when you notice they are out of date. + +[Source](https://www.makeuseof.com/must-follow-react-practices/) diff --git a/.github/LABELING_GUIDELINES.md b/.github/guidelines/LABELING_GUIDELINES.md similarity index 83% rename from .github/LABELING_GUIDELINES.md rename to .github/guidelines/LABELING_GUIDELINES.md index 27247b7dfefb..ec7ad636c729 100644 --- a/.github/LABELING_GUIDELINES.md +++ b/.github/guidelines/LABELING_GUIDELINES.md @@ -1,17 +1,20 @@ # PR Labeling Guidelines To maintain a consistent and efficient development workflow, we have set specific label guidelines for all pull requests (PRs). Please ensure you adhere to the following instructions: -### Mandatory Labels: +### Mandatory team labels: - **Internal Developers**: Every PR raised by an internal developer must include a label prefixed with `team-` (e.g., `team-extension-ux`, `team-extension-platform`, etc.). This indicates the respective internal team responsible for the PR. - **External Contributors**: PRs from contributors outside the organization must have the `external-contributor` label. It's essential to ensure that PRs have the appropriate labels before they are considered for merging. -### Prohibited Labels: +### Optional QA labels: +- **needs-qa**: If the PR includes a new features, complex testing steps, or large refactors, this label must be added to indicated PR requires a full manual QA prior being merged and added to a release. + +### Labels prohibited when PR needs to be merged: Any PR that includes one of the following labels can not be merged: -- **needs-qa**: The PR requires a full manual QA prior to being added to a release. +- **needs-qa**: The PR requires a full manual QA prior to being merged and added to a release. - **QA'd but questions**: The PR has been checked by QA, but there are pending questions or clarifications needed on minor issues that were found. - **issues-found**: The PR has been checked by QA or other reviewers, and appeared to include issues that need to be addressed. - **need-ux-ds-review**: The PR requires a review from the User Experience or Design System teams. diff --git a/.github/pull-request-template.md b/.github/pull-request-template.md new file mode 100644 index 000000000000..fcdebbcb5215 --- /dev/null +++ b/.github/pull-request-template.md @@ -0,0 +1,46 @@ +## **Description** +_Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions:_ +_1. What is the reason for the change?_ +_2. What is the improvement/solution?_ + +## **Manual testing steps** + +_1. Step1:_ +_2. Step2:_ +_3. ..._ + +## **Screenshots/Recordings** + +_If applicable, add screenshots and/or recordings to visualize the before and after of your change._ + +### **Before** + +_[screenshot]_ + +### **After** + +_[screenshot]_ + +## **Related issues** + +_Fixes #???_ + +## **Pre-merge author checklist** + +- [ ] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). +- [ ] I've clearly explained: + - [ ] What problem this PR is solving. + - [ ] How this problem was solved. + - [ ] How reviewers can test my changes. +- [ ] I’ve indicated what issue this PR is linked to: Fixes #??? +- [ ] I’ve included tests if applicable. +- [ ] I’ve documented any added code. +- [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)). +- [ ] I’ve properly set the pull request status: + - [ ] In case it's not yet "ready for review", I've set it to "draft". + - [ ] In case it's "ready for review", I've changed it from "draft" to "non-draft". + +## **Pre-merge reviewer checklist** + +- [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). +- [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. diff --git a/.github/workflows/trigger-metamask-institutional-e2e-ci.yml b/.github/workflows/trigger-metamask-institutional-e2e-ci.yml new file mode 100644 index 000000000000..3701c04241ad --- /dev/null +++ b/.github/workflows/trigger-metamask-institutional-e2e-ci.yml @@ -0,0 +1,28 @@ +name: Trigger MetaMask Institutional E2E CI + +on: + push: + branches: [ Version-v*, master ] + pull_request: + branches: [ Version-v*, master ] + types: + - opened + - reopened + - synchronize + - ready_for_review + +jobs: + trigger-mmi-e2e-ci: + runs-on: ubuntu-latest + if: ${{ (!github.event.pull_request.draft && (startsWith(github.head_ref, 'Version-v') || github.head_ref == 'master')) || (!github.event.pull_request) }} + steps: + - name: Trigger MetaMask Institutional E2E CI + env: + MMI_E2E_CI_TOKEN: ${{ secrets.MMI_E2E_CI_TOKEN }} + run: | + curl -L -X POST \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer $MMI_E2E_CI_TOKEN" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + https://api.github.com/repos/consensys-vertical-apps/mmi-extension-e2e/dispatches \ + -d '{"event_type": "mm-triggered", "client_payload":{"ref_name": "${{ github.ref_name }}", "sha": "${{ github.sha }}"}}' diff --git a/.metamaskrc.dist b/.metamaskrc.dist index 151c29808c86..2b723c2b1c78 100644 --- a/.metamaskrc.dist +++ b/.metamaskrc.dist @@ -5,7 +5,7 @@ INFURA_PROJECT_ID=00000000000 ;PASSWORD=METAMASK PASSWORD -,SEGMENT_WRITE_KEY= +;SEGMENT_WRITE_KEY= ;SWAPS_USE_DEV_APIS= ;PORTFOLIO_URL= ;TRANSACTION_SECURITY_PROVIDER= diff --git a/.storybook/test-data.js b/.storybook/test-data.js index 7acce27bc431..b78ae04c0620 100644 --- a/.storybook/test-data.js +++ b/.storybook/test-data.js @@ -1062,12 +1062,6 @@ const state = { unapprovedEncryptionPublicKeyMsgCount: 0, unapprovedTypedMessages: {}, unapprovedTypedMessagesCount: 0, - keyringTypes: [ - KeyringType.imported, - KeyringType.hdKeyTree, - KeyringType.trezor, - KeyringType.ledger, - ], keyrings: [ { type: KeyringType.hdKeyTree, @@ -1137,7 +1131,6 @@ const state = { lostIdentities: {}, forgottenPassword: false, ipfsGateway: 'dweb.link', - infuraBlocked: false, migratedPrivacyMode: false, selectedAddress: '0x9d0ba4ddac06032527b140912ec808ab9451b788', metaMetricsId: diff --git a/.yarn/patches/@babel-core-npm-7.21.5-c72c337956.patch b/.yarn/patches/@babel-core-npm-7.21.5-c72c337956.patch deleted file mode 100644 index c6a1743a7167..000000000000 --- a/.yarn/patches/@babel-core-npm-7.21.5-c72c337956.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/lib/index.js b/lib/index.js -index c991f62dc64553502e9911a7f21e77e008d7f438..e503c7494d21b13df85b10e1657b2af8ca4d964f 100644 ---- a/lib/index.js -+++ b/lib/index.js -@@ -222,7 +222,6 @@ var _transform = require("./transform"); - var _transformFile = require("./transform-file"); - var _transformAst = require("./transform-ast"); - var _parse = require("./parse"); --var thisFile = require("./index"); - const version = "7.21.5"; - exports.version = version; - const DEFAULT_EXTENSIONS = Object.freeze([".js", ".jsx", ".es6", ".es", ".mjs", ".cjs"]); diff --git a/.yarn/patches/@babel-core-npm-7.23.2-b93f586907.patch b/.yarn/patches/@babel-core-npm-7.23.2-b93f586907.patch new file mode 100644 index 000000000000..fdae8d6b2b4e --- /dev/null +++ b/.yarn/patches/@babel-core-npm-7.23.2-b93f586907.patch @@ -0,0 +1,12 @@ +diff --git a/lib/index.js b/lib/index.js +index 64ff8344f6280d20988f8c3c81e1f248a1869e53..6739e7bd2271be6b861479ec384bbd007bdb5df8 100644 +--- a/lib/index.js ++++ b/lib/index.js +@@ -222,7 +222,6 @@ var _transform = require("./transform.js"); + var _transformFile = require("./transform-file.js"); + var _transformAst = require("./transform-ast.js"); + var _parse = require("./parse.js"); +-var thisFile = require("./index.js"); + ; + const version = "7.23.2"; + exports.version = version; diff --git a/.yarn/patches/@babel-runtime-npm-7.18.9-28ca6b5f61.patch b/.yarn/patches/@babel-runtime-npm-7.23.2-d013d6cf7e.patch similarity index 91% rename from .yarn/patches/@babel-runtime-npm-7.18.9-28ca6b5f61.patch rename to .yarn/patches/@babel-runtime-npm-7.23.2-d013d6cf7e.patch index 30144e224f5e..1197cddf1a1b 100644 --- a/.yarn/patches/@babel-runtime-npm-7.18.9-28ca6b5f61.patch +++ b/.yarn/patches/@babel-runtime-npm-7.23.2-d013d6cf7e.patch @@ -1,30 +1,10 @@ diff --git a/helpers/construct.js b/helpers/construct.js -index ecc013db4703c1c6ca8a5bba3db3955e75c1a972..08826bea9453f1351c08d44be9fffca92923fd76 100644 +index 3d3c232dcb226892cdf6181c6f4f4f40f2325fcc..da7e2696a244fadd35f0eeb5cae5f577ee3c7442 100644 --- a/helpers/construct.js +++ b/helpers/construct.js -@@ -1,22 +1,21 @@ +@@ -1,18 +1,21 @@ -var setPrototypeOf = require("./setPrototypeOf.js"); -+// All of MetaMask's supported browsers include `Reflect.construct` support, so -+// we don't need this polyfill. - -var isNativeReflectConstruct = require("./isNativeReflectConstruct.js"); -+// This Proxy preseves the two properties that were added by `@babel/runtime`. -+// I am not entire sure what these properties are for (maybe ES5/ES6 -+// interoperability?) but they have been preserved just in case. -+const reflectProxy = new Proxy( -+ Reflect.construct, -+ { -+ get: function (target, property) { -+ if (property === 'default') { -+ return target; -+ } else if (property === '__esModule') { -+ return true; -+ } -+ return Reflect.get(...arguments); -+ } -+ } -+); - -function _construct(Parent, args, Class) { - if (isNativeReflectConstruct()) { - module.exports = _construct = Reflect.construct.bind(), module.exports.__esModule = true, module.exports["default"] = module.exports; @@ -38,11 +18,28 @@ index ecc013db4703c1c6ca8a5bba3db3955e75c1a972..08826bea9453f1351c08d44be9fffca9 - return instance; - }, module.exports.__esModule = true, module.exports["default"] = module.exports; - } -- - return _construct.apply(null, arguments); -} -- -module.exports = _construct, module.exports.__esModule = true, module.exports["default"] = module.exports; \ No newline at end of file ++// All of MetaMask's supported browsers include `Reflect.construct` support, so ++// we don't need this polyfill. ++ ++// This Proxy preseves the two properties that were added by `@babel/runtime`. ++// I am not entire sure what these properties are for (maybe ES5/ES6 ++// interoperability?) but they have been preserved just in case. ++const reflectProxy = new Proxy( ++ Reflect.construct, ++ { ++ get: function (target, property) { ++ if (property === 'default') { ++ return target; ++ } else if (property === '__esModule') { ++ return true; ++ } ++ return Reflect.get(...arguments); ++ } ++ } ++); ++ +module.exports = reflectProxy; -\ No newline at end of file diff --git a/.yarn/patches/@metamask-keyring-controller-npm-7.2.0-fcc0c7893b.patch b/.yarn/patches/@metamask-keyring-controller-npm-7.2.0-fcc0c7893b.patch deleted file mode 100644 index 956b9fe308f7..000000000000 --- a/.yarn/patches/@metamask-keyring-controller-npm-7.2.0-fcc0c7893b.patch +++ /dev/null @@ -1,46 +0,0 @@ -diff --git a/dist/KeyringController.d.ts b/dist/KeyringController.d.ts -index ccfd5ca9accf782b0a612ab1666501898cf2abb9..f772552156491b308f2aa29a734a5138237d951e 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, 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/@metamask-signature-controller-npm-6.0.0-90e8e479a9.patch b/.yarn/patches/@metamask-signature-controller-npm-6.0.0-90e8e479a9.patch new file mode 100644 index 000000000000..128ad3f80189 --- /dev/null +++ b/.yarn/patches/@metamask-signature-controller-npm-6.0.0-90e8e479a9.patch @@ -0,0 +1,17 @@ +diff --git a/dist/SignatureController.js b/dist/SignatureController.js +index 46d4b4d0553f86d368d30b7e90a9dc2e03d26ef9..e7063a3753bc3821e661c11132e33304b4fce416 100644 +--- a/dist/SignatureController.js ++++ b/dist/SignatureController.js +@@ -280,8 +280,11 @@ _SignatureController_isEthSignEnabled = new WeakMap(), _SignatureController_getA + 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; diff --git a/.yarn/patches/lavamoat-core-npm-14.4.1-c4e8bbb016.patch b/.yarn/patches/lavamoat-core-npm-14.4.1-c4e8bbb016.patch index abae9b29583c..07a662583315 100644 --- a/.yarn/patches/lavamoat-core-npm-14.4.1-c4e8bbb016.patch +++ b/.yarn/patches/lavamoat-core-npm-14.4.1-c4e8bbb016.patch @@ -1,3 +1,16 @@ +diff --git a/src/kernelTemplate.js b/src/kernelTemplate.js +index de8d73048b7bb7c4e74009b5c85ad919fe197ef0..e5bcb987cff013def8b2e8c767eb75a57ea0bd7a 100644 +--- a/src/kernelTemplate.js ++++ b/src/kernelTemplate.js +@@ -60,6 +60,8 @@ + errorTaming: 'unsafe', + // shows the full call stack + stackFiltering: 'verbose', ++ // prevents most common override mistake cases from tripping up users ++ overrideTaming: 'severe', + } + + lockdown(lockdownOptions) diff --git a/src/loadPolicy.js b/src/loadPolicy.js index ef71923f9282d6a5e9f74e6ec6fa0516f28f508b..0118fda7e1b0fa461ec01ceff8d7112d072f3dfb 100644 --- a/src/loadPolicy.js diff --git a/.yarn/patches/typescript-npm-4.4.4-3fedcc07a3.patch b/.yarn/patches/typescript-npm-4.4.4-3fedcc07a3.patch deleted file mode 100644 index 95cb488b1435..000000000000 --- a/.yarn/patches/typescript-npm-4.4.4-3fedcc07a3.patch +++ /dev/null @@ -1,242 +0,0 @@ -diff --git a/lib/typescript.js b/lib/typescript.js -index 323de6f4da00612e90e685142120736bfaeed37b..350e352e36f8bb6a870d7c24eaeae6bf7d648840 100644 ---- a/lib/typescript.js -+++ b/lib/typescript.js -@@ -24,11 +24,58 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { - return to.concat(ar || Array.prototype.slice.call(from)); - }; - var __assign = (this && this.__assign) || function () { -- __assign = Object.assign || function(t) { -+ __assign = function(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; -- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) -- t[p] = s[p]; -+ for (var p in s) { -+ if (Object.prototype.hasOwnProperty.call(s, p)) { -+ /** -+ * In the original version of this package, this was: -+ * -+ * t[p] = s[p] -+ * -+ * Unfortunately LavaMoat trips up on this, so we have to change -+ * it. -+ * -+ * Internally LavaMoat uses `lockdown` (part of SES, which is -+ * part of Endo) to freeze modifications to "intrinsics" — core -+ * things like `Object.prototype`, `Function.prototype`, etc. -+ * This will cause code which is responsible for said -+ * modifications to fail at runtime, because it makes the -+ * properties of these intrinsics non-writable. -+ * -+ * The reason we have to change *this* code is that later on, -+ * this `__assign` function is used to merge two objects, and -+ * one of those objects contains a `constructor` property. As we -+ * know, `constructor` is a special property, as it's a property -+ * on `Object.prototype` that stores the constructor used to -+ * create that object. But when used in this context, there is -+ * nothing inherently special about it – it's just a property on -+ * an object we're setting. Unfortunately, that's not how it's -+ * being treated. Because `lockdown` freezes `Object.prototype`, -+ * `Object.prototype.constructor` is non-writable, and due to a -+ * "mistake" in the ES5 spec [1], that means `constructor` on -+ * *any* object is non-writable too. So an error is thrown when -+ * this code is executed. -+ * -+ * There is a way to get around this, which is to configure -+ * `lockdown` with the option `overrideTaming: 'severe'`. -+ * The mechanics of this option, as well as more information -+ * about the "mistake" this option solves, are explained here -+ * [2]. Unfortunately, we cannot enable this option because -+ * LavaMoat is the one running `lockdown` here [3]. So to work -+ * around this, we use `Object.defineProperty` to define the -+ * property we want. As this does not use property assignment -+ * (`object[key] = value`) but rather defines the property more -+ * directly, this bypasses the "override mistake". -+ * -+ * [1]: https://web.archive.org/web/20141230041441/http://wiki.ecmascript.org/doku.php?id=strawman:fixing_override_mistake -+ * [2]: https://github.com/endojs/endo/blob/864f086f87e1e7ef78a401a7550ff0aeb664bba0/packages/ses/src/enable-property-overrides.js#L28 -+ * [3]: https://github.com/LavaMoat/LavaMoat/blob/7c15bf8ba34ba1a9ceb3ffe591b1b2bfb084bead/packages/core/src/kernelTemplate.js#L32-L43 -+ */ -+ Object.defineProperty(t, p, Object.getOwnPropertyDescriptor(s, p)) -+ } -+ } - } - return t; - }; -@@ -9820,87 +9867,94 @@ var ts; - } - ts.tokenIsIdentifierOrKeywordOrGreaterThan = tokenIsIdentifierOrKeywordOrGreaterThan; - /** @internal */ -- ts.textToKeywordObj = (_a = { -- abstract: 126 /* AbstractKeyword */, -- any: 129 /* AnyKeyword */, -- as: 127 /* AsKeyword */, -- asserts: 128 /* AssertsKeyword */, -- bigint: 156 /* BigIntKeyword */, -- boolean: 132 /* BooleanKeyword */, -- break: 81 /* BreakKeyword */, -- case: 82 /* CaseKeyword */, -- catch: 83 /* CatchKeyword */, -- class: 84 /* ClassKeyword */, -- continue: 86 /* ContinueKeyword */, -- const: 85 /* ConstKeyword */ -- }, -- _a["" + "constructor"] = 133 /* ConstructorKeyword */, -- _a.debugger = 87 /* DebuggerKeyword */, -- _a.declare = 134 /* DeclareKeyword */, -- _a.default = 88 /* DefaultKeyword */, -- _a.delete = 89 /* DeleteKeyword */, -- _a.do = 90 /* DoKeyword */, -- _a.else = 91 /* ElseKeyword */, -- _a.enum = 92 /* EnumKeyword */, -- _a.export = 93 /* ExportKeyword */, -- _a.extends = 94 /* ExtendsKeyword */, -- _a.false = 95 /* FalseKeyword */, -- _a.finally = 96 /* FinallyKeyword */, -- _a.for = 97 /* ForKeyword */, -- _a.from = 154 /* FromKeyword */, -- _a.function = 98 /* FunctionKeyword */, -- _a.get = 135 /* GetKeyword */, -- _a.if = 99 /* IfKeyword */, -- _a.implements = 117 /* ImplementsKeyword */, -- _a.import = 100 /* ImportKeyword */, -- _a.in = 101 /* InKeyword */, -- _a.infer = 136 /* InferKeyword */, -- _a.instanceof = 102 /* InstanceOfKeyword */, -- _a.interface = 118 /* InterfaceKeyword */, -- _a.intrinsic = 137 /* IntrinsicKeyword */, -- _a.is = 138 /* IsKeyword */, -- _a.keyof = 139 /* KeyOfKeyword */, -- _a.let = 119 /* LetKeyword */, -- _a.module = 140 /* ModuleKeyword */, -- _a.namespace = 141 /* NamespaceKeyword */, -- _a.never = 142 /* NeverKeyword */, -- _a.new = 103 /* NewKeyword */, -- _a.null = 104 /* NullKeyword */, -- _a.number = 145 /* NumberKeyword */, -- _a.object = 146 /* ObjectKeyword */, -- _a.package = 120 /* PackageKeyword */, -- _a.private = 121 /* PrivateKeyword */, -- _a.protected = 122 /* ProtectedKeyword */, -- _a.public = 123 /* PublicKeyword */, -- _a.override = 157 /* OverrideKeyword */, -- _a.readonly = 143 /* ReadonlyKeyword */, -- _a.require = 144 /* RequireKeyword */, -- _a.global = 155 /* GlobalKeyword */, -- _a.return = 105 /* ReturnKeyword */, -- _a.set = 147 /* SetKeyword */, -- _a.static = 124 /* StaticKeyword */, -- _a.string = 148 /* StringKeyword */, -- _a.super = 106 /* SuperKeyword */, -- _a.switch = 107 /* SwitchKeyword */, -- _a.symbol = 149 /* SymbolKeyword */, -- _a.this = 108 /* ThisKeyword */, -- _a.throw = 109 /* ThrowKeyword */, -- _a.true = 110 /* TrueKeyword */, -- _a.try = 111 /* TryKeyword */, -- _a.type = 150 /* TypeKeyword */, -- _a.typeof = 112 /* TypeOfKeyword */, -- _a.undefined = 151 /* UndefinedKeyword */, -- _a.unique = 152 /* UniqueKeyword */, -- _a.unknown = 153 /* UnknownKeyword */, -- _a.var = 113 /* VarKeyword */, -- _a.void = 114 /* VoidKeyword */, -- _a.while = 115 /* WhileKeyword */, -- _a.with = 116 /* WithKeyword */, -- _a.yield = 125 /* YieldKeyword */, -- _a.async = 130 /* AsyncKeyword */, -- _a.await = 131 /* AwaitKeyword */, -- _a.of = 158 /* OfKeyword */, -- _a); -+ /** -+ * In the original version of this package, this object was built by -+ * initializing one object and then adding more properties to that object. -+ * This ends up throwing an error when this code is executed due to -+ * the same issue as explained at the top of this file: essentially, -+ * the `constructor` property of any object cannot be set due to the -+ * "override mistake". The fix for this is to just build one big object. -+ */ -+ ts.textToKeywordObj = { -+ abstract: 126 /* AbstractKeyword */, -+ any: 129 /* AnyKeyword */, -+ as: 127 /* AsKeyword */, -+ asserts: 128 /* AssertsKeyword */, -+ bigint: 156 /* BigIntKeyword */, -+ boolean: 132 /* BooleanKeyword */, -+ break: 81 /* BreakKeyword */, -+ case: 82 /* CaseKeyword */, -+ catch: 83 /* CatchKeyword */, -+ class: 84 /* ClassKeyword */, -+ continue: 86 /* ContinueKeyword */, -+ const: 85 /* ConstKeyword */, -+ ["constructor"]: 133 /* ConstructorKeyword */, -+ debugger: 87 /* DebuggerKeyword */, -+ declare: 134 /* DeclareKeyword */, -+ default: 88 /* DefaultKeyword */, -+ delete: 89 /* DeleteKeyword */, -+ do: 90 /* DoKeyword */, -+ else: 91 /* ElseKeyword */, -+ enum: 92 /* EnumKeyword */, -+ export: 93 /* ExportKeyword */, -+ extends: 94 /* ExtendsKeyword */, -+ false: 95 /* FalseKeyword */, -+ finally: 96 /* FinallyKeyword */, -+ for: 97 /* ForKeyword */, -+ from: 154 /* FromKeyword */, -+ function: 98 /* FunctionKeyword */, -+ get: 135 /* GetKeyword */, -+ if: 99 /* IfKeyword */, -+ implements: 117 /* ImplementsKeyword */, -+ import: 100 /* ImportKeyword */, -+ in: 101 /* InKeyword */, -+ infer: 136 /* InferKeyword */, -+ instanceof: 102 /* InstanceOfKeyword */, -+ interface: 118 /* InterfaceKeyword */, -+ intrinsic: 137 /* IntrinsicKeyword */, -+ is: 138 /* IsKeyword */, -+ keyof: 139 /* KeyOfKeyword */, -+ let: 119 /* LetKeyword */, -+ module: 140 /* ModuleKeyword */, -+ namespace: 141 /* NamespaceKeyword */, -+ never: 142 /* NeverKeyword */, -+ new: 103 /* NewKeyword */, -+ null: 104 /* NullKeyword */, -+ number: 145 /* NumberKeyword */, -+ object: 146 /* ObjectKeyword */, -+ package: 120 /* PackageKeyword */, -+ private: 121 /* PrivateKeyword */, -+ protected: 122 /* ProtectedKeyword */, -+ public: 123 /* PublicKeyword */, -+ override: 157 /* OverrideKeyword */, -+ readonly: 143 /* ReadonlyKeyword */, -+ require: 144 /* RequireKeyword */, -+ global: 155 /* GlobalKeyword */, -+ return: 105 /* ReturnKeyword */, -+ set: 147 /* SetKeyword */, -+ static: 124 /* StaticKeyword */, -+ string: 148 /* StringKeyword */, -+ super: 106 /* SuperKeyword */, -+ switch: 107 /* SwitchKeyword */, -+ symbol: 149 /* SymbolKeyword */, -+ this: 108 /* ThisKeyword */, -+ throw: 109 /* ThrowKeyword */, -+ true: 110 /* TrueKeyword */, -+ try: 111 /* TryKeyword */, -+ type: 150 /* TypeKeyword */, -+ typeof: 112 /* TypeOfKeyword */, -+ undefined: 151 /* UndefinedKeyword */, -+ unique: 152 /* UniqueKeyword */, -+ unknown: 153 /* UnknownKeyword */, -+ var: 113 /* VarKeyword */, -+ void: 114 /* VoidKeyword */, -+ while: 115 /* WhileKeyword */, -+ with: 116 /* WithKeyword */, -+ yield: 125 /* YieldKeyword */, -+ async: 130 /* AsyncKeyword */, -+ await: 131 /* AwaitKeyword */, -+ of: 158 /* OfKeyword */ -+ }; - var textToKeyword = new ts.Map(ts.getEntries(ts.textToKeywordObj)); - var textToToken = new ts.Map(ts.getEntries(__assign(__assign({}, ts.textToKeywordObj), { "{": 18 /* OpenBraceToken */, "}": 19 /* CloseBraceToken */, "(": 20 /* OpenParenToken */, ")": 21 /* CloseParenToken */, "[": 22 /* OpenBracketToken */, "]": 23 /* CloseBracketToken */, ".": 24 /* DotToken */, "...": 25 /* DotDotDotToken */, ";": 26 /* SemicolonToken */, ",": 27 /* CommaToken */, "<": 29 /* LessThanToken */, ">": 31 /* GreaterThanToken */, "<=": 32 /* LessThanEqualsToken */, ">=": 33 /* GreaterThanEqualsToken */, "==": 34 /* EqualsEqualsToken */, "!=": 35 /* ExclamationEqualsToken */, "===": 36 /* EqualsEqualsEqualsToken */, "!==": 37 /* ExclamationEqualsEqualsToken */, "=>": 38 /* EqualsGreaterThanToken */, "+": 39 /* PlusToken */, "-": 40 /* MinusToken */, "**": 42 /* AsteriskAsteriskToken */, "*": 41 /* AsteriskToken */, "/": 43 /* SlashToken */, "%": 44 /* PercentToken */, "++": 45 /* PlusPlusToken */, "--": 46 /* MinusMinusToken */, "<<": 47 /* LessThanLessThanToken */, ">": 48 /* GreaterThanGreaterThanToken */, ">>>": 49 /* GreaterThanGreaterThanGreaterThanToken */, "&": 50 /* AmpersandToken */, "|": 51 /* BarToken */, "^": 52 /* CaretToken */, "!": 53 /* ExclamationToken */, "~": 54 /* TildeToken */, "&&": 55 /* AmpersandAmpersandToken */, "||": 56 /* BarBarToken */, "?": 57 /* QuestionToken */, "??": 60 /* QuestionQuestionToken */, "?.": 28 /* QuestionDotToken */, ":": 58 /* ColonToken */, "=": 63 /* EqualsToken */, "+=": 64 /* PlusEqualsToken */, "-=": 65 /* MinusEqualsToken */, "*=": 66 /* AsteriskEqualsToken */, "**=": 67 /* AsteriskAsteriskEqualsToken */, "/=": 68 /* SlashEqualsToken */, "%=": 69 /* PercentEqualsToken */, "<<=": 70 /* LessThanLessThanEqualsToken */, ">>=": 71 /* GreaterThanGreaterThanEqualsToken */, ">>>=": 72 /* GreaterThanGreaterThanGreaterThanEqualsToken */, "&=": 73 /* AmpersandEqualsToken */, "|=": 74 /* BarEqualsToken */, "^=": 78 /* CaretEqualsToken */, "||=": 75 /* BarBarEqualsToken */, "&&=": 76 /* AmpersandAmpersandEqualsToken */, "??=": 77 /* QuestionQuestionEqualsToken */, "@": 59 /* AtToken */, "#": 62 /* HashToken */, "`": 61 /* BacktickToken */ }))); - /* diff --git a/CHANGELOG.md b/CHANGELOG.md index 5283ec097070..a75f094c96b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,47 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [11.3.0] +### Added +- Display total fiat balance on home screen ([#20941](https://github.com/MetaMask/metamask-extension/pull/20941)) +- Give the user the ability to opt out of 3rd party network validation when adding a new network ([#20816](https://github.com/MetaMask/metamask-extension/pull/20816)) +- Adds conversion buttons to buy, receive, and learn more about NFTs when an account is empty. ([#21049](https://github.com/MetaMask/metamask-extension/pull/21049)) +- What's New modal for the latest Buy and Sell features ([#20965](https://github.com/MetaMask/metamask-extension/pull/20965)) +- [Flask] Suggest names for Ethereum addresses in signature requests using installed snaps ([#20959](https://github.com/MetaMask/metamask-extension/pull/20959)) + +### Changed +- Move the token detection prompt to the top of the assets list ([#20932](https://github.com/MetaMask/metamask-extension/pull/20932)) +- Adds address validation to the Import NFT modal ([#21028](https://github.com/MetaMask/metamask-extension/pull/21028)) +- Add error message to the Import NFT modal if an NFT with that tokenId already exists ([#20940](https://github.com/MetaMask/metamask-extension/pull/20940)) +- Show a warning when sending 0 tokens ([#21091](https://github.com/MetaMask/metamask-extension/pull/21091)) +- Enable bridge button on the zkSync network, and for some tokens on other networks ([#21085](https://github.com/MetaMask/metamask-extension/pull/21085)) +- Stop displaying a mismatched account warning on the Sign In With Ethereum page ([#21107](https://github.com/MetaMask/metamask-extension/pull/21107)) +- Ensure "Enhanced Token Detection" is toggled off when opening "Advanced Configuration" during onboarding ([#20960](https://github.com/MetaMask/metamask-extension/pull/20960)) +- Improve loading speed/performance upon opening MetaMask ([#20843](https://github.com/MetaMask/metamask-extension/pull/20843)) +- Ensure logos are displayed on "Popular Networks" added from within MetaMask ([#20895](https://github.com/MetaMask/metamask-extension/pull/20895)) +- Show more characters in the addresses in the Connected Sites account list ([#21048](https://github.com/MetaMask/metamask-extension/pull/21048)) +- Replaces the "Add / Import / Hardware" links with a single button that takes the user to another quick modal to add, import, or connect a hardware wallet.([#21081](https://github.com/MetaMask/metamask-extension/pull/21081)) +- Disable the "Buy" button on the Sepolia network ([#20839](https://github.com/MetaMask/metamask-extension/pull/20839)) +- Update the "Buy" button to a "Buy & Sell" button ([#20891](https://github.com/MetaMask/metamask-extension/pull/20891)) +- Only display the Notification item in the dropdown menu if the user has installed a snap using the notifications permission ([#20913](https://github.com/MetaMask/metamask-extension/pull/20913)) +- Update Snaps Settings screen ([#21061](https://github.com/MetaMask/metamask-extension/pull/21061)) +- Site connection icon now indicates a connection if a dapp is connected to a snap ([#20811](https://github.com/MetaMask/metamask-extension/pull/20811)) +- Update copy on the remove snap modal ([#21065](https://github.com/MetaMask/metamask-extension/pull/21065)) +- Update the padding of the transaction insight dropdown ([#21022](https://github.com/MetaMask/metamask-extension/pull/21022)) +- [Flask] Suggest names for Ethereum addresses in signature requests using services such as ENS and Etherscan ([#20831](https://github.com/MetaMask/metamask-extension/pull/20831)) + +### Fixed +- Fix to ensure contract address is pre-populated, and NFT is removed from token list, when converting a token to an NFT ([#20747](https://github.com/MetaMask/metamask-extension/pull/20747)) +- Fix autodetect tokens link so that the user is correctly taken to the right scroll position in settings ([#20978](https://github.com/MetaMask/metamask-extension/pull/20978)) +- Ensure safe batch NFT transfers show display recipient address correctly ([#21042](https://github.com/MetaMask/metamask-extension/pull/21042)) +- Fix bug that can prevent MetaMask from loading, and be stuck on the loading screen, on Firefox ([#20992](https://github.com/MetaMask/metamask-extension/pull/20992)) +- Ensure correct network icon is displayed in the "You have switched to" modal when switching to "Popular Networks" ([#21016](https://github.com/MetaMask/metamask-extension/pull/21016)) +- Ensure disconnecting a single dapp from a snap only disconnects that dapp ([#20983](https://github.com/MetaMask/metamask-extension/pull/20983)) +- Fix the Snap npm link so that it leads to the stated version of the npm package ([#20897](https://github.com/MetaMask/metamask-extension/pull/20897)) +- Fix to prevent crashes when switching network during a snaps confirmation ([#21088](https://github.com/MetaMask/metamask-extension/pull/21088)) +- Fix issue that could cause crashes when attempting to render certain NFTs ([#21418](https://github.com/MetaMask/metamask-extension/pull/21418)) + + ## [11.2.0] ### Added - Adds Swaps support for the zkSync Era network ([#20809](https://github.com/MetaMask/metamask-extension/pull/20809)) @@ -4066,7 +4107,8 @@ Update styles and spacing on the critical error page ([#20350](https://github.c ### Uncategorized - Added the ability to restore accounts from seed words. -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.2.0...HEAD +[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.3.0...HEAD +[11.3.0]: https://github.com/MetaMask/metamask-extension/compare/v11.2.0...v11.3.0 [11.2.0]: https://github.com/MetaMask/metamask-extension/compare/v11.1.2...v11.2.0 [11.1.2]: https://github.com/MetaMask/metamask-extension/compare/v11.1.1...v11.1.2 [11.1.1]: https://github.com/MetaMask/metamask-extension/compare/v11.1.0...v11.1.1 diff --git a/README.md b/README.md index c817f3c570d6..adad35727fbc 100644 --- a/README.md +++ b/README.md @@ -17,17 +17,22 @@ To learn how to contribute to the MetaMask project itself, visit our [Internal D - Install [Node.js](https://nodejs.org) version 18 - If you are using [nvm](https://github.com/nvm-sh/nvm#installing-and-updating) (recommended) running `nvm use` will automatically choose the right node version for you. - Enable Corepack by executing the command `corepack enable` within the metamask-extension project. Corepack is a utility included with Node.js by default. It manages Yarn on a per-project basis, using the version specified by the `packageManager` property in the project's package.json file. Please note that modern releases of [Yarn](https://yarnpkg.com/getting-started/install) are not intended to be installed globally or via npm. -- Duplicate `.metamaskrc.dist` within the root and rename it to `.metamaskrc` - - Replace the `INFURA_PROJECT_ID` value with your own personal [Infura Project ID](https://infura.io/docs). +- Duplicate `.metamaskrc.dist` within the root and rename it to `.metamaskrc` by running `cp .metamaskrc{.dist,}`. + - Replace the `INFURA_PROJECT_ID` value with your own personal [Infura API Key](https://docs.infura.io/networks/ethereum/how-to/secure-a-project/project-id). + - If you don't have an Infura account, you can create one for free on the [Infura website](https://app.infura.io/register). - If debugging MetaMetrics, you'll need to add a value for `SEGMENT_WRITE_KEY` [Segment write key](https://segment.com/docs/connections/find-writekey/), see [Developing on MetaMask - Segment](./development/README.md#segment). - If debugging unhandled exceptions, you'll need to add a value for `SENTRY_DSN` [Sentry Dsn](https://docs.sentry.io/product/sentry-basics/dsn-explainer/), see [Developing on MetaMask - Sentry](./development/README.md#sentry). - Optionally, replace the `PASSWORD` value with your development wallet password to avoid entering it each time you open the app. +- Run `yarn install` to install the dependencies. - Build the project to the `./dist/` folder with `yarn dist`. - Optionally, you may run `yarn start` to run dev mode. + - Uncompressed builds can be found in `/dist`, compressed builds can be found in `/builds` once they're built. + - See the [build system readme](./development/build/README.md) for build system usage information. -Uncompressed builds can be found in `/dist`, compressed builds can be found in `/builds` once they're built. +- Follow these instructions to verify that your local build runs correctly: + - [How to add custom build to Chrome](./docs/add-to-chrome.md) + - [How to add custom build to Firefox](./docs/add-to-firefox.md) -See the [build system readme](./development/build/README.md) for build system usage information. ## Git Hooks @@ -37,6 +42,8 @@ To get quick feedback from our shared code quality fitness functions before comm You can read more about them in our [testing documentation](./docs/testing.md#fitness-functions-measuring-progress-in-code-quality-and-preventing-regressions-using-custom-git-hooks). +If you are using VS Code and are unable to make commits from the source control sidebar due to a "command not found" error, try these steps from the [Husky docs](https://typicode.github.io/husky/troubleshooting.html#command-not-found). + ## Contributing ### Development builds @@ -102,6 +109,16 @@ Single e2e tests can be run with `yarn test:e2e:single test/e2e/tests/TEST_NAME. For example, to run the `account-details` tests using Chrome, with debug logging and with the browser set to remain open upon failure, you would use: `yarn test:e2e:single test/e2e/tests/account-details.spec.js --browser=chrome --debug --leave-running` +#### Running specific builds types e2e test + +Differnt build types have different e2e tests sets. In order to run them look in the `packaje.json` file. You will find: +```console + "test:e2e:chrome:mmi": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js --mmi", + "test:e2e:chrome:snaps": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js --snaps", + "test:e2e:chrome:mv3": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js --mv3", +``` +Note: MMI runs a subset of MetaMask's e2e tests. To facilitate this, we have appended the `@no-mmi` tags to the names of those tests that are not applicable to this build type. + ### Changing dependencies Whenever you change dependencies (adding, removing, or updating, either in `package.json` or `yarn.lock`), there are various files that must be kept up-to-date. @@ -138,8 +155,6 @@ Whenever you change dependencies (adding, removing, or updating, either in `pack ## Other Docs -- [How to add custom build to Chrome](./docs/add-to-chrome.md) -- [How to add custom build to Firefox](./docs/add-to-firefox.md) - [How to add a new translation to MetaMask](./docs/translating-guide.md) - [Publishing Guide](./docs/publishing.md) - [How to use the TREZOR emulator](./docs/trezor-emulator.md) diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index 851cdaeb7c49..213d8876df39 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -611,19 +611,10 @@ "busy": { "message": "Ausgelastet" }, - "buy": { - "message": "Kaufen" - }, "buyAsset": { "message": "$1 kaufen", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyDescription": { - "message": "Halten Sie Ihre Kryptowährung und erzielen Sie potenzielle Gewinne" - }, - "buyDisabled": { - "message": "Kaufen ist in diesem Netzwerk nicht verfügbar" - }, "buyMoreAsset": { "message": "Mehr $1 kaufen", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" @@ -1408,9 +1399,6 @@ "enableAutoDetect": { "message": " Automatische Erkennung aktivieren" }, - "enableForAllNetworks": { - "message": "Für alle Netzwerke aktivieren" - }, "enableFromSettings": { "message": " In den Einstellungen aktivieren." }, @@ -1550,11 +1538,9 @@ "experimental": { "message": "Experimentell" }, - "exploreMetaMaskSnaps": { - "message": "MetaMask Snaps erforschen" - }, "extendWalletWithSnaps": { - "message": "Erweitern Sie Ihr Wallet-Erlebnis." + "message": "Erweitern Sie Ihr Wallet-Erlebnis.", + "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, "externalExtension": { "message": "Externe Erweiterung" @@ -1585,9 +1571,6 @@ "message": "Dateiimport fehlgeschlagen? Bitte hier klicken!", "description": "Helps user import their account from a JSON file" }, - "fileTooBig": { - "message": "Die abgelegte Datei ist zu groß." - }, "flaskWelcomeUninstall": { "message": "Sie sollten diese Erweiterung deinstallieren.", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -3203,14 +3186,6 @@ "message": "Erlauben Sie dem Snap Lebenszyklus-Hooks zu verwenden, um den Code während seines Lebenszyklus zu bestimmten Zeiten auszuführen.", "description": "An extended description for the `endowment:lifecycle-hooks` permission" }, - "permission_longRunning": { - "message": "Für unbestimmte Zeit ausführen.", - "description": "The description for the `endowment:long-running` permission" - }, - "permission_longRunningDescription": { - "message": "Gestatten Sie dem Snap, unbegrenzt ausgeführt zu werden, während es zum Beispiel große Datenmengen verarbeitet.", - "description": "An extended description for the `endowment:long-running` permission" - }, "permission_manageAccounts": { "message": "Ethereum-Konten hinzufügen und kontrollieren", "description": "The description for `snap_manageAccounts` permission" diff --git a/app/_locales/el/messages.json b/app/_locales/el/messages.json index 9ba54b66e1d7..b5f4828434af 100644 --- a/app/_locales/el/messages.json +++ b/app/_locales/el/messages.json @@ -611,19 +611,10 @@ "busy": { "message": "Απασχολημένο" }, - "buy": { - "message": "Αγορά" - }, "buyAsset": { "message": "Αγορά $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyDescription": { - "message": "Κρατήστε τα κρυπτονομίσματά σας και κερδίστε πιθανά κέρδη" - }, - "buyDisabled": { - "message": "Η αγορά δεν είναι διαθέσιμη σε αυτό το δίκτυο" - }, "buyMoreAsset": { "message": "Αγοράστε περισσότερα $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" @@ -1408,9 +1399,6 @@ "enableAutoDetect": { "message": " Ενεργοποίηση αυτόματου εντοπισμού" }, - "enableForAllNetworks": { - "message": "Ενεργοποίηση σε όλα τα δίκτυα" - }, "enableFromSettings": { "message": "Ενεργοποιήστε το από τις Ρυθμίσεις." }, @@ -1550,11 +1538,9 @@ "experimental": { "message": "Πειραματικά" }, - "exploreMetaMaskSnaps": { - "message": "Εξερευνήστε το MetaMask Snaps" - }, "extendWalletWithSnaps": { - "message": "Προσαρμόστε την εμπειρία του πορτοφολιού σας." + "message": "Προσαρμόστε την εμπειρία του πορτοφολιού σας.", + "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, "externalExtension": { "message": "Εξωτερική επέκταση" @@ -1585,9 +1571,6 @@ "message": "Η εισαγωγή αρχείων δεν λειτουργεί; Κάντε κλικ εδώ!", "description": "Helps user import their account from a JSON file" }, - "fileTooBig": { - "message": "Το υποβαλλόμενο αρχείο είναι πολύ μεγάλο." - }, "flaskWelcomeUninstall": { "message": "θα πρέπει να απεγκαταστήσετε αυτή την επέκταση", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -3203,14 +3186,6 @@ "message": "Επιτρέψτε στο snap να χρησιμοποιεί επιχειρηματικά μοντέλα για την εκτέλεση κώδικα σε συγκεκριμένες χρονικές στιγμές κατά τη διάρκεια του κύκλου ζωής του.", "description": "An extended description for the `endowment:lifecycle-hooks` permission" }, - "permission_longRunning": { - "message": "Εκτέλεση επ' αόριστον.", - "description": "The description for the `endowment:long-running` permission" - }, - "permission_longRunningDescription": { - "message": "Επιτρέψτε στο snap να εκτελείται επ' αόριστον, ενώ, για παράδειγμα, επεξεργάζεται μεγάλες ποσότητες δεδομένων.", - "description": "An extended description for the `endowment:long-running` permission" - }, "permission_manageAccounts": { "message": "Προσθήκη και έλεγχος λογαριασμών στο Ethereum", "description": "The description for `snap_manageAccounts` permission" diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 6eeddd86044e..780889ab8ace 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -153,6 +153,9 @@ "accountSelectionRequired": { "message": "You need to select an account!" }, + "accountsConnected": { + "message": "Accounts connected" + }, "active": { "message": "Active" }, @@ -243,6 +246,9 @@ "addIPFSGateway": { "message": "Add your preferred IPFS gateway" }, + "addImportAccount": { + "message": "Add account or hardware wallet" + }, "addMemo": { "message": "Add memo" }, @@ -256,6 +262,9 @@ "message": "This network connection relies on third parties. This connection may be less reliable or enable third-parties to track activity. $1", "description": "$1 is Learn more link" }, + "addNewAccount": { + "message": "Add a new account" + }, "addNewToken": { "message": "Add new token" }, @@ -268,6 +277,12 @@ "addSnapAccountModalDescription": { "message": "Discover options to keep your account secure with MetaMask Snaps" }, + "addSnapAccountToggle": { + "message": "Enable \"Add Snap account\"" + }, + "addSnapAccountsDescription": { + "message": "Turning on this feature will give you the option to add a Snap account right from your account list. If you install a Snap account, remember that it is a third-party service." + }, "addSuggestedNFTs": { "message": "Add suggested NFTs" }, @@ -620,16 +635,19 @@ "buy": { "message": "Buy" }, + "buyAndSell": { + "message": "Buy & Sell" + }, + "buyAndSellDescription": { + "message": "Buy crypto or sell your crypto for cash" + }, + "buyAndSellDisabled": { + "message": "Buy & Sell is not available in this network" + }, "buyAsset": { "message": "Buy $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyDescription": { - "message": "Hold up your crypto and earn potential profits" - }, - "buyDisabled": { - "message": "Buy is not available in this network" - }, "buyMoreAsset": { "message": "Buy more $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" @@ -717,6 +735,10 @@ "coingecko": { "message": "CoinGecko" }, + "comboNoOptions": { + "message": "No options found", + "description": "Default text shown in the combo field dropdown if no options." + }, "configureSnapPopupDescription": { "message": "You're now leaving MetaMask to configure this snap." }, @@ -831,6 +853,9 @@ "message": "$1 is not connected to any sites.", "description": "$1 is the account name" }, + "connectedSnapAndNoAccountDescription": { + "message": "MetaMask is connected to this site, but no accounts are connected yet" + }, "connecting": { "message": "Connecting..." }, @@ -947,6 +972,12 @@ "createPassword": { "message": "Create password" }, + "createSnapAccountDescription": { + "message": "$1 wants to add a new Snap account to your wallet" + }, + "createSnapAccountTitle": { + "message": "Create Snap account" + }, "cryptoCompare": { "message": "CryptoCompare" }, @@ -1295,6 +1326,10 @@ "disconnectThisAccount": { "message": "Disconnect this account" }, + "discoverSnaps": { + "message": "Discover Snaps", + "description": "Text that links to the Snaps website. Displayed in a banner on Snaps list page in settings." + }, "dismiss": { "message": "Dismiss" }, @@ -1426,9 +1461,6 @@ "enableAutoDetect": { "message": " Enable autodetect" }, - "enableForAllNetworks": { - "message": "Enable for all networks" - }, "enableFromSettings": { "message": " Enable it from Settings." }, @@ -1580,11 +1612,9 @@ "experimental": { "message": "Experimental" }, - "exploreMetaMaskSnaps": { - "message": "Explore MetaMask Snaps" - }, "extendWalletWithSnaps": { - "message": "Customize your wallet experience." + "message": "Explore community-built Snaps to customize your web3 experience", + "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, "externalExtension": { "message": "External extension" @@ -1615,9 +1645,6 @@ "message": "File import not working? Click here!", "description": "Helps user import their account from a JSON file" }, - "fileTooBig": { - "message": "The dropped file is too big." - }, "flaskWelcomeUninstall": { "message": "you should uninstall this extension", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -2374,6 +2401,38 @@ "name": { "message": "Name" }, + "nameAddressLabel": { + "message": "Address", + "description": "Label above address field in name component modal." + }, + "nameInstructionsNew": { + "message": "You are interacting with an unknown contract address. If you trust this author, set a personal display name to identify it going forward.", + "description": "Instruction text in name component modal when value is not recognised." + }, + "nameInstructionsSaved": { + "message": "Interactions with this address will always be identified using this personal display name.", + "description": "Instruction text in name component modal when value is saved." + }, + "nameLabel": { + "message": "Display name", + "description": "Label above name input field in name component modal." + }, + "nameModalTitleNew": { + "message": "Unknown address", + "description": "Title of the modal created by the name component when value is not recognised." + }, + "nameModalTitleSaved": { + "message": "Saved address", + "description": "Title of the modal created by the name component when value is saved." + }, + "nameNoProposedNames": { + "message": "No proposed names found", + "description": "Text shown in the proposed name dropdown if none found." + }, + "nameSetPlaceholder": { + "message": "Set a personal display name...", + "description": "Placeholder text for name input field in name component modal." + }, "nativeToken": { "message": "The native token on this network is $1. It is the token used for gas fees.", "description": "$1 represents the name of the native token on the current network" @@ -2544,9 +2603,15 @@ "message": "This token is an NFT. Add on the $1", "description": "$1 is a clickable link with text defined by the 'importNFTPage' key" }, + "nftAlreadyAdded": { + "message": "NFT has already been added." + }, "nftDisclaimer": { "message": "Disclaimer: MetaMask pulls the media file from the source url. This url sometimes is changed by the marketplace the NFT was minted on." }, + "nftLearnMore": { + "message": "Learn more about NFTs" + }, "nftOptions": { "message": "NFT Options" }, @@ -2898,6 +2963,15 @@ "notifications9Title": { "message": "👓 We are making transactions easier to read." }, + "notificationsBuySellActionText": { + "message": "Try it on MetaMask Portfolio" + }, + "notificationsBuySellDescription": { + "message": "Introducing the ‘Buy & Sell’ button, giving you easy access to our latest feature: Sell. When clicked, you’ll be redirected to MetaMask Portfolio, where you’ll be able to convert your crypto to cash in a flash. Initially available for ETH on mainnet in the US (state restrictions apply), UK, and parts of Europe." + }, + "notificationsBuySellTitle": { + "message": "Sell your crypto, get cash" + }, "notificationsDropLedgerFirefoxDescription": { "message": "Firefox no longer supports U2F, so Ledger won't work with MetaMask on Firefox. Try MetaMask on Google Chrome instead.", "description": "Description of a notification in the 'See What's New' popup. Describes that ledger will not longer be supported for firefox users and they should use MetaMask on chrome for ledger support instead." @@ -3260,18 +3334,14 @@ "message": "Allow the snap to use lifecycle hooks to run code at specific times during its lifecycle.", "description": "An extended description for the `endowment:lifecycle-hooks` permission" }, - "permission_longRunning": { - "message": "Run indefinitely.", - "description": "The description for the `endowment:long-running` permission" - }, - "permission_longRunningDescription": { - "message": "Allow the snap to run indefinitely while, for example, processing large amounts of data.", - "description": "An extended description for the `endowment:long-running` permission" - }, "permission_manageAccounts": { "message": "Add and control Ethereum accounts", "description": "The description for `snap_manageAccounts` permission" }, + "permission_manageAccountsDescription": { + "message": "Allow this Snap to add or remove Ethereum accounts, then transact and sign with these accounts.", + "description": "An extended description for the `snap_manageAccounts` permission" + }, "permission_manageBip32Keys": { "message": "Control your accounts and assets under $1 ($2).", "description": "The description for the `snap_getBip32Entropy` permission. $1 is a derivation path, e.g. 'm/44'/0'/0''. $2 is the elliptic curve name, e.g. 'secp256k1'." @@ -3535,7 +3605,16 @@ "message": "NFT was successfully removed!" }, "removeSnap": { - "message": "Remove snap" + "message": "Remove Snap" + }, + "removeSnapAccountBannerDescription": { + "message": "Be sure you can access this account on your own before removing it" + }, + "removeSnapAccountDescription": { + "message": "$1 wants to remove this account from MetaMask:" + }, + "removeSnapAccountTitle": { + "message": "Remove account" }, "removeSnapConfirmation": { "message": "Are you sure you want to remove $1?", @@ -3872,6 +3951,9 @@ "message": "Warning: you are about to send to a token contract which could result in a loss of funds. $1", "description": "$1 is a clickable link with text defined by the 'learnMoreUpperCase' key. The link will open to a support article regarding the known contract address warning" }, + "sendingZeroAmount": { + "message": "You are sending 0 $1." + }, "sepolia": { "message": "Sepolia test network" }, @@ -3991,6 +4073,18 @@ "smartSwapsSubDescription": { "message": "* Smart Swaps will attempt to submit your transaction privately, multiple times. If all attempts fail, the transaction will be broadcast publicly to ensure your Swap successfully goes through." }, + "snapAccountCreated": { + "message": "Your account is ready!" + }, + "snapAccountRemoved": { + "message": "Account removed" + }, + "snapAccounts": { + "message": "Snap accounts" + }, + "snapAccountsDescription": { + "message": "Accounts controlled by third-party Snaps." + }, "snapConfigure": { "message": "Configure" }, @@ -4120,6 +4214,9 @@ "snaps": { "message": "Snaps" }, + "snapsConnected": { + "message": "Snaps connected" + }, "snapsInsightLoading": { "message": "Loading transaction insight..." }, @@ -4141,6 +4238,9 @@ "message": "Consensys has no access to information you share with Third Party Services.", "description": "Third part of a message in popup modal displayed when installing a snap for the first time." }, + "snapsSettings": { + "message": "Snap settings" + }, "snapsSettingsDescription": { "message": "Manage your Snaps" }, @@ -5304,6 +5404,16 @@ "usePhishingDetectionDescription": { "message": "Display a warning for phishing domains targeting Ethereum users" }, + "useSafeChainsListValidation": { + "message": "Network details check" + }, + "useSafeChainsListValidationDescription": { + "message": "MetaMask uses a third-party service called $1 to show accurate and standardized network details. This reduces your chances of connecting to malicious or incorrect network. When using this feature, your IP address is exposed to chainid.network." + }, + "useSafeChainsListValidationWebsite": { + "message": "chainid.network", + "description": "useSafeChainsListValidationWebsite is separated from the rest of the text so that we can bold the third party service name in the middle of them" + }, "useSiteSuggestion": { "message": "Use site suggestion" }, diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index 69914a0c3d90..7f9b105957b4 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -611,19 +611,10 @@ "busy": { "message": "Ocupado" }, - "buy": { - "message": "Comprar" - }, "buyAsset": { "message": "Comprar $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyDescription": { - "message": "Guarde sus criptomonedas y obtenga ganancias potenciales" - }, - "buyDisabled": { - "message": "Comprar no está disponible en esta red" - }, "buyMoreAsset": { "message": "Comprar más $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" @@ -1408,9 +1399,6 @@ "enableAutoDetect": { "message": " Activar autodetección" }, - "enableForAllNetworks": { - "message": "Habilitar para todas las redes" - }, "enableFromSettings": { "message": " Actívela en Configuración." }, @@ -1550,11 +1538,9 @@ "experimental": { "message": "Experimental" }, - "exploreMetaMaskSnaps": { - "message": "Explore MetaMask Snaps" - }, "extendWalletWithSnaps": { - "message": "Amplíe la experiencia de uso de su monedero." + "message": "Amplíe la experiencia de uso de su monedero.", + "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, "externalExtension": { "message": "Extensión externa" @@ -1585,9 +1571,6 @@ "message": "¿No funciona la importación del archivo? Haga clic aquí.", "description": "Helps user import their account from a JSON file" }, - "fileTooBig": { - "message": "El archivo arrastrado es demasiado grande." - }, "flaskWelcomeUninstall": { "message": "le recomendamos que desinstale esta extensión", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -3203,14 +3186,6 @@ "message": "Permita que el snap use ganchos de ciclo de vida para ejecutar código en momentos específicos durante su ciclo de vida.", "description": "An extended description for the `endowment:lifecycle-hooks` permission" }, - "permission_longRunning": { - "message": "Ejecutar indefinidamente.", - "description": "The description for the `endowment:long-running` permission" - }, - "permission_longRunningDescription": { - "message": "Permita que el snap se ejecute indefinidamente mientras, por ejemplo, procesa grandes cantidades de datos.", - "description": "An extended description for the `endowment:long-running` permission" - }, "permission_manageAccounts": { "message": "Agregar y controlar cuentas de Ethereum", "description": "The description for `snap_manageAccounts` permission" diff --git a/app/_locales/es_419/messages.json b/app/_locales/es_419/messages.json index d148117d7e48..77d571d76648 100644 --- a/app/_locales/es_419/messages.json +++ b/app/_locales/es_419/messages.json @@ -299,9 +299,6 @@ "busy": { "message": "Ocupado" }, - "buy": { - "message": "Comprar" - }, "bytes": { "message": "Bytes" }, diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index 423f49b172b1..33cca3bfc540 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -611,19 +611,10 @@ "busy": { "message": "Occupé" }, - "buy": { - "message": "Acheter" - }, "buyAsset": { "message": "Acheter $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyDescription": { - "message": "Conservez vos crypto-actifs et dégagez des bénéfices potentiels" - }, - "buyDisabled": { - "message": "Impossible d’effectuer un achat sur ce réseau" - }, "buyMoreAsset": { "message": "Acheter plus de $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" @@ -1408,9 +1399,6 @@ "enableAutoDetect": { "message": " Activer la détection automatique" }, - "enableForAllNetworks": { - "message": "Activer pour tous les réseaux" - }, "enableFromSettings": { "message": " Activez-la depuis les Paramètres." }, @@ -1550,11 +1538,9 @@ "experimental": { "message": "Expérimental" }, - "exploreMetaMaskSnaps": { - "message": "Explorer les Snaps MetaMask" - }, "extendWalletWithSnaps": { - "message": "Personnalisez votre expérience de portefeuille." + "message": "Personnalisez votre expérience de portefeuille.", + "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, "externalExtension": { "message": "Extension externe" @@ -1585,9 +1571,6 @@ "message": "L’importation de fichier ne fonctionne pas ? Cliquez ici !", "description": "Helps user import their account from a JSON file" }, - "fileTooBig": { - "message": "Le fichier déconnecté est trop volumineux." - }, "flaskWelcomeUninstall": { "message": "vous devriez désinstaller cette extension", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -3203,14 +3186,6 @@ "message": "Autorisez le Snap à utiliser des hooks de cycle de vie pour exécuter du code à des moments spécifiques de son cycle de vie.", "description": "An extended description for the `endowment:lifecycle-hooks` permission" }, - "permission_longRunning": { - "message": "Fonctionner indéfiniment.", - "description": "The description for the `endowment:long-running` permission" - }, - "permission_longRunningDescription": { - "message": "Autoriser l’exécution illimitée du snap pendant, par exemple, le traitement de volumes importants de données.", - "description": "An extended description for the `endowment:long-running` permission" - }, "permission_manageAccounts": { "message": "Ajouter et gérer des comptes Ethereum", "description": "The description for `snap_manageAccounts` permission" diff --git a/app/_locales/hi/messages.json b/app/_locales/hi/messages.json index b1cbf1c5464c..658e6bb42e33 100644 --- a/app/_locales/hi/messages.json +++ b/app/_locales/hi/messages.json @@ -611,19 +611,10 @@ "busy": { "message": "बिज़ी" }, - "buy": { - "message": "खरीदें" - }, "buyAsset": { "message": "$1 खरीदें", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyDescription": { - "message": "अपने क्रिप्टो को रोक कर रखें और शानदार लाभ कमाएं" - }, - "buyDisabled": { - "message": "इस नेटवर्क में खरीदारी उपलब्ध नहीं है" - }, "buyMoreAsset": { "message": "ज्यादा $1 खरीदें", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" @@ -1408,9 +1399,6 @@ "enableAutoDetect": { "message": " ऑटो डिटेक्ट इनेबल करें" }, - "enableForAllNetworks": { - "message": "सभी नेटवर्क पर इनेबल करें" - }, "enableFromSettings": { "message": " इसे सेटिंग्स से इनेबल करें।" }, @@ -1550,11 +1538,9 @@ "experimental": { "message": "एक्सपेरिमेंटल" }, - "exploreMetaMaskSnaps": { - "message": "MetaMask Snaps को एक्सप्लोर करें" - }, "extendWalletWithSnaps": { - "message": "वॉलेट एक्सपीरियंस को कस्टमाइज़ करें।" + "message": "वॉलेट एक्सपीरियंस को कस्टमाइज़ करें।", + "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, "externalExtension": { "message": "बाहरी एक्स्टेन्शन" @@ -1585,9 +1571,6 @@ "message": "फाइल इम्पोर्ट काम नहीं कर रहा है? यहां क्लिक करें!", "description": "Helps user import their account from a JSON file" }, - "fileTooBig": { - "message": "ड्रॉप की गई फाइल बहुत बड़ी है।" - }, "flaskWelcomeUninstall": { "message": "आपको इस एक्सटेन्शन को अनइंस्टाल करना चाहिए", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -3203,14 +3186,6 @@ "message": "Snap को उसके लाइफसाइकल के दौरान खास समयों पर कोड चलाने के लिए लाइफसाइकल हुक का इस्तेमाल करने की अनुमति दें।", "description": "An extended description for the `endowment:lifecycle-hooks` permission" }, - "permission_longRunning": { - "message": "अनिश्चित काल तक चलाएं।", - "description": "The description for the `endowment:long-running` permission" - }, - "permission_longRunningDescription": { - "message": "उदाहरण के लिए, बड़ी मात्रा में डेटा प्रॉसेस करते समय Snap को अनिश्चित काल तक चलने दें।", - "description": "An extended description for the `endowment:long-running` permission" - }, "permission_manageAccounts": { "message": "Ethereum अकाउंट जोड़ें और नियंत्रित करें", "description": "The description for `snap_manageAccounts` permission" diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json index beda6288f89f..4c4d238492bf 100644 --- a/app/_locales/id/messages.json +++ b/app/_locales/id/messages.json @@ -611,19 +611,10 @@ "busy": { "message": "Sibuk" }, - "buy": { - "message": "Beli" - }, "buyAsset": { "message": "Beli $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyDescription": { - "message": "Pertahankan kripto Anda dan dapatkan potensi keuntungan" - }, - "buyDisabled": { - "message": "Beli tidak tersedia di jaringan ini" - }, "buyMoreAsset": { "message": "Beli lebih banyak $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" @@ -1408,9 +1399,6 @@ "enableAutoDetect": { "message": " Aktifkan deteksi otomatis" }, - "enableForAllNetworks": { - "message": "Aktifkan untuk semua jaringan" - }, "enableFromSettings": { "message": " Aktifkan dari Pengaturan." }, @@ -1550,11 +1538,9 @@ "experimental": { "message": "Eksperimental" }, - "exploreMetaMaskSnaps": { - "message": "Jelajahi MetaMask Snaps" - }, "extendWalletWithSnaps": { - "message": "Perluas pengalaman dompet." + "message": "Perluas pengalaman dompet.", + "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, "externalExtension": { "message": "Ekstensi eksternal" @@ -1585,9 +1571,6 @@ "message": "Impor file tidak bekerja? Klik di sini!", "description": "Helps user import their account from a JSON file" }, - "fileTooBig": { - "message": "File yang didrop terlalu besar." - }, "flaskWelcomeUninstall": { "message": "Anda harus menghapus ekstensi ini", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -3203,14 +3186,6 @@ "message": "Izinkan snap menggunakan lifecycle hook untuk menjalankan kode pada waktu tertentu selama siklus hidupnya.", "description": "An extended description for the `endowment:lifecycle-hooks` permission" }, - "permission_longRunning": { - "message": "Operasikan sepanjang waktu.", - "description": "The description for the `endowment:long-running` permission" - }, - "permission_longRunningDescription": { - "message": "Izinkan snap beroperasi sepanjang waktu saat, sebagai contoh, memproses data dalam jumlah besar.", - "description": "An extended description for the `endowment:long-running` permission" - }, "permission_manageAccounts": { "message": "Tambah dan kontrol akun Ethereum", "description": "The description for `snap_manageAccounts` permission" diff --git a/app/_locales/it/messages.json b/app/_locales/it/messages.json index 1748e0659637..5a7106a79aaf 100644 --- a/app/_locales/it/messages.json +++ b/app/_locales/it/messages.json @@ -380,9 +380,6 @@ "busy": { "message": "Occupato" }, - "buy": { - "message": "Compra" - }, "buyAsset": { "message": "Compra $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index ec33d33bef47..267ab31b4fdb 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -611,19 +611,10 @@ "busy": { "message": "ビジー状態" }, - "buy": { - "message": "購入" - }, "buyAsset": { "message": "$1を購入", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyDescription": { - "message": "仮想通貨を保持して利益を得ます" - }, - "buyDisabled": { - "message": "このネットワークでは購入できません" - }, "buyMoreAsset": { "message": "$1を追加購入", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" @@ -1408,9 +1399,6 @@ "enableAutoDetect": { "message": " 自動検出を有効にする" }, - "enableForAllNetworks": { - "message": "すべてのネットワークで有効にする" - }, "enableFromSettings": { "message": " 設定で有効にします。" }, @@ -1550,11 +1538,9 @@ "experimental": { "message": "試験運用" }, - "exploreMetaMaskSnaps": { - "message": "MetaMask Snapsを閲覧" - }, "extendWalletWithSnaps": { - "message": "ウォレットのユーザー体験をカスタマイズします。" + "message": "ウォレットのユーザー体験をカスタマイズします。", + "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, "externalExtension": { "message": "外部拡張機能" @@ -1585,9 +1571,6 @@ "message": "ファイルのインポートが機能していない場合、ここをクリックしてください!", "description": "Helps user import their account from a JSON file" }, - "fileTooBig": { - "message": "ドロップされたファイルが大きすぎます。" - }, "flaskWelcomeUninstall": { "message": "この拡張機能はアンインストールしてください", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -3203,14 +3186,6 @@ "message": "snapがライフサイクルフックを使用して、ライフサイクルの特定のタイミングでコードを実行することを許可します。", "description": "An extended description for the `endowment:lifecycle-hooks` permission" }, - "permission_longRunning": { - "message": "無期限で実行。", - "description": "The description for the `endowment:long-running` permission" - }, - "permission_longRunningDescription": { - "message": "大きなデータの処理中など、snapが無期限で実行されることを許可します。", - "description": "An extended description for the `endowment:long-running` permission" - }, "permission_manageAccounts": { "message": "イーサリアムアカウントを追加して管理します", "description": "The description for `snap_manageAccounts` permission" diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index f98405e900d7..6e6e5f1af2ce 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -611,19 +611,10 @@ "busy": { "message": "바쁨" }, - "buy": { - "message": "구매" - }, "buyAsset": { "message": "$1 구매", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyDescription": { - "message": "암호화폐를 보유하고 잠재적인 수익을 얻으세요" - }, - "buyDisabled": { - "message": "이 네트워크에서는 매수할 수 없습니다" - }, "buyMoreAsset": { "message": "$1 추가 구매", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" @@ -1408,9 +1399,6 @@ "enableAutoDetect": { "message": " 자동 감지 활성화" }, - "enableForAllNetworks": { - "message": "모든 네트워크에 활성화" - }, "enableFromSettings": { "message": " 설정에서 이 기능을 활성화합니다." }, @@ -1550,11 +1538,9 @@ "experimental": { "message": "실험적" }, - "exploreMetaMaskSnaps": { - "message": "MetaMask 스냅 탐색" - }, "extendWalletWithSnaps": { - "message": "지갑 경험을 개인 맞춤하세요." + "message": "지갑 경험을 개인 맞춤하세요.", + "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, "externalExtension": { "message": "외부 확장" @@ -1585,9 +1571,6 @@ "message": "파일 가져오기가 작동하지 않나요? 여기를 클릭하세요.", "description": "Helps user import their account from a JSON file" }, - "fileTooBig": { - "message": "드롭한 파일 크기가 너무 큽니다." - }, "flaskWelcomeUninstall": { "message": "이 확장 프로그램을 삭제해야 합니다", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -3203,14 +3186,6 @@ "message": "스냅으로 라이프사이클 훅을 사용하도록 허용하면 라이프사이클 동안 코드를 특정 횟수만큼 실행합니다.", "description": "An extended description for the `endowment:lifecycle-hooks` permission" }, - "permission_longRunning": { - "message": "무기한 운용됩니다.", - "description": "The description for the `endowment:long-running` permission" - }, - "permission_longRunningDescription": { - "message": "예를 들어 많은 양의 데이터를 처리하는 동안 스냅이 무기한 실행되도록 허용합니다.", - "description": "An extended description for the `endowment:long-running` permission" - }, "permission_manageAccounts": { "message": "이더리움 계정 추가 및 제어", "description": "The description for `snap_manageAccounts` permission" diff --git a/app/_locales/ph/messages.json b/app/_locales/ph/messages.json index c51311aabafe..50002410ea2a 100644 --- a/app/_locales/ph/messages.json +++ b/app/_locales/ph/messages.json @@ -195,9 +195,6 @@ "buildContactList": { "message": "Buuin ang iyong listahan ng contact" }, - "buy": { - "message": "Bumili" - }, "bytes": { "message": "Bytes" }, diff --git a/app/_locales/pt/messages.json b/app/_locales/pt/messages.json index 92ff97f1b260..908dcf4cf6c9 100644 --- a/app/_locales/pt/messages.json +++ b/app/_locales/pt/messages.json @@ -611,19 +611,10 @@ "busy": { "message": "Ocupado" }, - "buy": { - "message": "Comprar" - }, "buyAsset": { "message": "Comprar $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyDescription": { - "message": "Segure seus criptoativos e ganhe lucros em potencial" - }, - "buyDisabled": { - "message": "A compra não está disponível nesta rede" - }, "buyMoreAsset": { "message": "Comprar mais $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" @@ -1408,9 +1399,6 @@ "enableAutoDetect": { "message": " Ativar detecção automática" }, - "enableForAllNetworks": { - "message": "Ativar para todas as redes" - }, "enableFromSettings": { "message": " Ative nas Configurações." }, @@ -1550,11 +1538,9 @@ "experimental": { "message": "Experimental" }, - "exploreMetaMaskSnaps": { - "message": "Explorar os snaps da MetaMask" - }, "extendWalletWithSnaps": { - "message": "Personalize sua experiência com a carteira." + "message": "Personalize sua experiência com a carteira.", + "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, "externalExtension": { "message": "Extensão externa" @@ -1585,9 +1571,6 @@ "message": "A importação de arquivo não está funcionando? Clique aqui!", "description": "Helps user import their account from a JSON file" }, - "fileTooBig": { - "message": "O arquivo inserido é grande demais." - }, "flaskWelcomeUninstall": { "message": "você deve desinstalar essa extensão", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -3203,14 +3186,6 @@ "message": "Permitir que o snap use ganchos de ciclo de vida para executar códigos em momentos específicos durante seu ciclo de vida.", "description": "An extended description for the `endowment:lifecycle-hooks` permission" }, - "permission_longRunning": { - "message": "Executar indefinidamente.", - "description": "The description for the `endowment:long-running` permission" - }, - "permission_longRunningDescription": { - "message": "Permitir que o snap seja executado indefinidamente, por exemplo, enquanto processa grandes volumes de dados.", - "description": "An extended description for the `endowment:long-running` permission" - }, "permission_manageAccounts": { "message": "Adicionar e controlar contas Ethereum", "description": "The description for `snap_manageAccounts` permission" diff --git a/app/_locales/pt_BR/messages.json b/app/_locales/pt_BR/messages.json index c51166be26bd..f8db416d5650 100644 --- a/app/_locales/pt_BR/messages.json +++ b/app/_locales/pt_BR/messages.json @@ -299,9 +299,6 @@ "busy": { "message": "Ocupado" }, - "buy": { - "message": "Comprar" - }, "bytes": { "message": "Bytes" }, diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index 7becb2d165ab..a43db33c1199 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -611,19 +611,10 @@ "busy": { "message": "Занят" }, - "buy": { - "message": "Купить" - }, "buyAsset": { "message": "Купить $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyDescription": { - "message": "Держите свою криптовалюту и зарабатывайте потенциально прибыль" - }, - "buyDisabled": { - "message": "В этой сети недоступна покупка" - }, "buyMoreAsset": { "message": "Купить еще $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" @@ -1408,9 +1399,6 @@ "enableAutoDetect": { "message": " Включить автоопределение" }, - "enableForAllNetworks": { - "message": "Включить для всех сетей" - }, "enableFromSettings": { "message": " Включите его в Настройках." }, @@ -1550,11 +1538,9 @@ "experimental": { "message": "Экспериментальные" }, - "exploreMetaMaskSnaps": { - "message": "Обзор MetaMask Snaps" - }, "extendWalletWithSnaps": { - "message": "Настройте кошелек под себя." + "message": "Настройте кошелек под себя.", + "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, "externalExtension": { "message": "Внешнее расширение" @@ -1585,9 +1571,6 @@ "message": "Импорт файлов не работает? Нажмите здесь!", "description": "Helps user import their account from a JSON file" }, - "fileTooBig": { - "message": "Добавленный файл слишком велик." - }, "flaskWelcomeUninstall": { "message": "вам нужно должны удалить это расширение", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -3203,14 +3186,6 @@ "message": "Разрешите snap использовать обработчики жизненного цикла для запуска кода в определенное время в течение его жизненного цикла.", "description": "An extended description for the `endowment:lifecycle-hooks` permission" }, - "permission_longRunning": { - "message": "Выполнять бесконечно.", - "description": "The description for the `endowment:long-running` permission" - }, - "permission_longRunningDescription": { - "message": "Разрешите snap работать бесконечно, например, при обработке больших объемов данных.", - "description": "An extended description for the `endowment:long-running` permission" - }, "permission_manageAccounts": { "message": "Добавляйте счета Ethereum и управляйте ими", "description": "The description for `snap_manageAccounts` permission" diff --git a/app/_locales/tl/messages.json b/app/_locales/tl/messages.json index 45135ff62f6d..014e1a06c385 100644 --- a/app/_locales/tl/messages.json +++ b/app/_locales/tl/messages.json @@ -611,19 +611,10 @@ "busy": { "message": "Busy" }, - "buy": { - "message": "Bumili" - }, "buyAsset": { "message": "Bumili ng $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyDescription": { - "message": "I-hold ang iyong crypto at makaipon ng potensyal na tubo" - }, - "buyDisabled": { - "message": "Hindi available ang pagbili sa network na ito" - }, "buyMoreAsset": { "message": "Bumili pa ng $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" @@ -1408,9 +1399,6 @@ "enableAutoDetect": { "message": " Paganahin ang autodetect" }, - "enableForAllNetworks": { - "message": "Paganahin para sa lahat ng network" - }, "enableFromSettings": { "message": " Paganahin ito mula sa Mga Setting." }, @@ -1550,11 +1538,9 @@ "experimental": { "message": "Eksperimental" }, - "exploreMetaMaskSnaps": { - "message": "Galugarin ang MetaMask Snaps" - }, "extendWalletWithSnaps": { - "message": "I-customize ang iyong karanasan sa wallet." + "message": "I-customize ang iyong karanasan sa wallet.", + "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, "externalExtension": { "message": "External Extension" @@ -1585,9 +1571,6 @@ "message": "Hindi gumagana ang pag-import ng file? Mag-click dito!", "description": "Helps user import their account from a JSON file" }, - "fileTooBig": { - "message": "Napakalaki ng na-drop na file." - }, "flaskWelcomeUninstall": { "message": "dapat mong i-uninstall ang extension na ito", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -3203,14 +3186,6 @@ "message": "Pinapayagan ang snap na gumamit ng mga lifecycle hook para paganahin ang code sa mga espisipikong panahon sa oras ng lifecycle nito.", "description": "An extended description for the `endowment:lifecycle-hooks` permission" }, - "permission_longRunning": { - "message": "Patakbuhin ng walang katapusan.", - "description": "The description for the `endowment:long-running` permission" - }, - "permission_longRunningDescription": { - "message": "Payagan ang snap para gumana nang walang limitasyon sa tagal habang, halimbawa, nagpoproseso ng maraming data.", - "description": "An extended description for the `endowment:long-running` permission" - }, "permission_manageAccounts": { "message": "Magdagdag at kontrolin ang mga Ethereum account", "description": "The description for `snap_manageAccounts` permission" diff --git a/app/_locales/tr/messages.json b/app/_locales/tr/messages.json index 0543827c83c4..1ceb3c54d670 100644 --- a/app/_locales/tr/messages.json +++ b/app/_locales/tr/messages.json @@ -611,19 +611,10 @@ "busy": { "message": "Meşgul" }, - "buy": { - "message": "Satın Al" - }, "buyAsset": { "message": "$1 satın al", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyDescription": { - "message": "Kriptonuzu tutun ve potansiyel kârlar elde edin" - }, - "buyDisabled": { - "message": "Satın al bu ağda kullanılamaz" - }, "buyMoreAsset": { "message": "Daha fazla $1 satın al", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" @@ -1408,9 +1399,6 @@ "enableAutoDetect": { "message": " Otomatik algılamayı etkinleştir" }, - "enableForAllNetworks": { - "message": "Tüm ağlar için etkinleştir" - }, "enableFromSettings": { "message": " Ayarlardan etkinleştir." }, @@ -1550,11 +1538,9 @@ "experimental": { "message": "Deneysel" }, - "exploreMetaMaskSnaps": { - "message": "MetaMask Snaplerini keşfedin" - }, "extendWalletWithSnaps": { - "message": "Cüzdan deneyimini kişiselleştirin." + "message": "Cüzdan deneyimini kişiselleştirin.", + "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, "externalExtension": { "message": "Harici uzantı" @@ -1585,9 +1571,6 @@ "message": "Dosya içe aktarma çalışmıyor mu? Buraya tıklayın!", "description": "Helps user import their account from a JSON file" }, - "fileTooBig": { - "message": "Bırakılan dosya çok büyük." - }, "flaskWelcomeUninstall": { "message": "bu uzantıyı kaldırmalısın", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -3203,14 +3186,6 @@ "message": "Bu yaşam döngüsü sırasında belirli zamanlarda kod çalıştırmak için snapin yaşam döngüsü kancalarını kullanmasına izin verin.", "description": "An extended description for the `endowment:lifecycle-hooks` permission" }, - "permission_longRunning": { - "message": "Süresiz çalıştır.", - "description": "The description for the `endowment:long-running` permission" - }, - "permission_longRunningDescription": { - "message": "Snapin örneğin büyük miktarda veri işlerken belirsiz süreyle çalışmasına izin verin.", - "description": "An extended description for the `endowment:long-running` permission" - }, "permission_manageAccounts": { "message": "Ethereum hesaplarını ekle ve kontrol et", "description": "The description for `snap_manageAccounts` permission" diff --git a/app/_locales/vi/messages.json b/app/_locales/vi/messages.json index 699efc6a3830..d17b243151f6 100644 --- a/app/_locales/vi/messages.json +++ b/app/_locales/vi/messages.json @@ -611,19 +611,10 @@ "busy": { "message": "Đang bận" }, - "buy": { - "message": "Mua" - }, "buyAsset": { "message": "Mua $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyDescription": { - "message": "Giữ tiền mã hóa và kiếm lợi nhuận tiềm năng" - }, - "buyDisabled": { - "message": "Mua không khả dụng trong mạng này" - }, "buyMoreAsset": { "message": "Mua thêm $1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" @@ -1408,9 +1399,6 @@ "enableAutoDetect": { "message": " Bật tự động phát hiện" }, - "enableForAllNetworks": { - "message": "Bật cho tất cả các mạng" - }, "enableFromSettings": { "message": " Bật trong Cài Đặt." }, @@ -1550,11 +1538,9 @@ "experimental": { "message": "Thử nghiệm" }, - "exploreMetaMaskSnaps": { - "message": "Khám phá MetaMask Snap" - }, "extendWalletWithSnaps": { - "message": "Tuỳ biến trải nghiệm sử dụng ví." + "message": "Tuỳ biến trải nghiệm sử dụng ví.", + "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, "externalExtension": { "message": "Tiện ích bên ngoài" @@ -1585,9 +1571,6 @@ "message": "Tính năng nhập tập tin không hoạt động? Nhấp vào đây!", "description": "Helps user import their account from a JSON file" }, - "fileTooBig": { - "message": "Kích thước tập tin thả vào quá lớn." - }, "flaskWelcomeUninstall": { "message": "bạn nên gỡ cài đặt tiện ích mở rộng này", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -3203,14 +3186,6 @@ "message": "Cho phép Snap sử dụng hook vòng đời để chạy mã vào những thời điểm cụ thể trong vòng đời của nó.", "description": "An extended description for the `endowment:lifecycle-hooks` permission" }, - "permission_longRunning": { - "message": "Chạy không giới hạn.", - "description": "The description for the `endowment:long-running` permission" - }, - "permission_longRunningDescription": { - "message": "Ví dụ: cho phép Snap chạy vô thời hạn trong quá trình xử lý lượng lớn dữ liệu.", - "description": "An extended description for the `endowment:long-running` permission" - }, "permission_manageAccounts": { "message": "Thêm và kiểm soát các tài khoản Ethereum", "description": "The description for `snap_manageAccounts` permission" diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index e94f426e1398..d07fc2f81d7b 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -611,19 +611,10 @@ "busy": { "message": "忙碌中" }, - "buy": { - "message": "购买" - }, "buyAsset": { "message": "购买$1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" }, - "buyDescription": { - "message": "继续持有加密货币,赚取潜在利润" - }, - "buyDisabled": { - "message": "在此网络中无法购买" - }, "buyMoreAsset": { "message": "购买更多$1", "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" @@ -1408,9 +1399,6 @@ "enableAutoDetect": { "message": " 启用自动检测" }, - "enableForAllNetworks": { - "message": "为所有网络启用" - }, "enableFromSettings": { "message": " 从设置中启用它。" }, @@ -1550,11 +1538,9 @@ "experimental": { "message": "实验性" }, - "exploreMetaMaskSnaps": { - "message": "探索 MetaMask Snaps" - }, "extendWalletWithSnaps": { - "message": "扩展钱包体验。" + "message": "扩展钱包体验。", + "description": "Banner description displayed on Snaps list page in Settings when less than 6 Snaps is installed." }, "externalExtension": { "message": "外部扩展程序" @@ -1585,9 +1571,6 @@ "message": "文件导入失败?点击这里!", "description": "Helps user import their account from a JSON file" }, - "fileTooBig": { - "message": "拖放的文件太大。" - }, "flaskWelcomeUninstall": { "message": "您应该卸载此扩展程序", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -3203,14 +3186,6 @@ "message": "允许snap使用生命周期挂钩在其生命周期的特定时间运行代码。", "description": "An extended description for the `endowment:lifecycle-hooks` permission" }, - "permission_longRunning": { - "message": "无限期运行。", - "description": "The description for the `endowment:long-running` permission" - }, - "permission_longRunningDescription": { - "message": "允许snap无限期运行,例如在处理大量数据时。", - "description": "An extended description for the `endowment:long-running` permission" - }, "permission_manageAccounts": { "message": "添加并控制以太坊账户", "description": "The description for `snap_manageAccounts` permission" diff --git a/app/_locales/zh_TW/messages.json b/app/_locales/zh_TW/messages.json index 5f26256160f8..6d442e961816 100644 --- a/app/_locales/zh_TW/messages.json +++ b/app/_locales/zh_TW/messages.json @@ -188,9 +188,6 @@ "browserNotSupported": { "message": "您的瀏覽器尚未支援..." }, - "buy": { - "message": "買" - }, "bytes": { "message": "位元組" }, diff --git a/app/background.html b/app/background.html index eabb3bf3a704..beed01def0ce 100644 --- a/app/background.html +++ b/app/background.html @@ -4,23 +4,7 @@ - - - - - {{@if(it.applyLavaMoat)}} - - - - {{#else}} - - - - - {{/if}} - {{@each(it.jsBundles) => val}} - - {{/each}} + diff --git a/app/home.html b/app/home.html index bb0333dcf820..5ff8f98edbaa 100644 --- a/app/home.html +++ b/app/home.html @@ -16,22 +16,6 @@
- - - - - {{@if(it.applyLavaMoat)}} - - - - {{#else}} - - - - - {{/if}} - {{@each(it.jsBundles) => val}} - - {{/each}} + diff --git a/app/images/blockaid-security-provider.png b/app/images/blockaid-security-provider.png deleted file mode 100644 index 34f9ac1a476d..000000000000 Binary files a/app/images/blockaid-security-provider.png and /dev/null differ diff --git a/app/images/blockaid-security-provider.svg b/app/images/blockaid-security-provider.svg new file mode 100644 index 000000000000..5646ed66987c --- /dev/null +++ b/app/images/blockaid-security-provider.svg @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/images/icons/plus-minus.svg b/app/images/icons/plus-minus.svg new file mode 100644 index 000000000000..afe3afba1a0a --- /dev/null +++ b/app/images/icons/plus-minus.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/images/sell_button_whatsnew.png b/app/images/sell_button_whatsnew.png new file mode 100644 index 000000000000..fea8c079cf7a Binary files /dev/null and b/app/images/sell_button_whatsnew.png differ diff --git a/app/images/token-list-buy-background.png b/app/images/token-list-buy-background.png new file mode 100644 index 000000000000..655669316397 Binary files /dev/null and b/app/images/token-list-buy-background.png differ diff --git a/app/images/token-list-nfts-background.png b/app/images/token-list-nfts-background.png new file mode 100644 index 000000000000..fd07c1c6f335 Binary files /dev/null and b/app/images/token-list-nfts-background.png differ diff --git a/app/images/token-list-receive-background.png b/app/images/token-list-receive-background.png new file mode 100644 index 000000000000..70f0944fc7e0 Binary files /dev/null and b/app/images/token-list-receive-background.png differ diff --git a/app/notification.html b/app/notification.html index 766aef2baba3..b696f195a300 100644 --- a/app/notification.html +++ b/app/notification.html @@ -36,22 +36,6 @@
- - - - - {{@if(it.applyLavaMoat)}} - - - - {{#else}} - - - - - {{/if}} - {{@each(it.jsBundles) => val}} - - {{/each}} + diff --git a/app/popup.html b/app/popup.html index 978c237db181..90b4c162b33c 100644 --- a/app/popup.html +++ b/app/popup.html @@ -13,22 +13,6 @@
- - - - - {{@if(it.applyLavaMoat)}} - - - - {{#else}} - - - - - {{/if}} - {{@each(it.jsBundles) => val}} - - {{/each}} + diff --git a/app/scripts/background.js b/app/scripts/background.js index b68936848354..f3ddc274360f 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -28,6 +28,9 @@ import { ENVIRONMENT_TYPE_FULLSCREEN, EXTENSION_MESSAGES, PLATFORM_FIREFOX, + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) + SNAP_MANAGE_ACCOUNTS_CONFIRMATION_TYPES, + ///: END:ONLY_INCLUDE_IN } from '../../shared/constants/app'; import { REJECT_NOTIFICATION_CLOSE, @@ -245,7 +248,6 @@ browser.runtime.onConnectExternal.addListener(async (...args) => { * @property {object} unapprovedTypedMsgs - An object of messages pending approval, mapping a unique ID to the options. * @property {number} unapprovedTypedMsgCount - The number of messages in unapprovedTypedMsgs. * @property {number} pendingApprovalCount - The number of pending request in the approval controller. - * @property {string[]} keyringTypes - An array of unique keyring identifying strings, representing available strategies for creating accounts. * @property {Keyring[]} keyrings - An array of keyring descriptions, summarizing the accounts that are available for use, and what keyrings they belong to. * @property {string} selectedAddress - A lower case hex string of the currently selected address. * @property {string} currentCurrency - A string identifying the user's preferred display currency, for use in showing conversion rates. @@ -802,6 +804,14 @@ export function setupController( controller.approvalController.accept(id, false); break; ///: END:ONLY_INCLUDE_IN + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) + case SNAP_MANAGE_ACCOUNTS_CONFIRMATION_TYPES.confirmAccountCreation: + controller.approvalController.accept(id, false); + break; + case SNAP_MANAGE_ACCOUNTS_CONFIRMATION_TYPES.confirmAccountRemoval: + controller.approvalController.accept(id, false); + break; + ///: END:ONLY_INCLUDE_IN default: controller.approvalController.reject( id, @@ -890,15 +900,18 @@ const addAppInstalledEvent = () => { }; // On first install, open a new tab with MetaMask -browser.runtime.onInstalled.addListener(({ reason }) => { +async function onInstall() { + const storeAlreadyExisted = Boolean(await localStore.get()); + // If the store doesn't exist, then this is the first time running this script, + // and is therefore an install if ( - reason === 'install' && + !storeAlreadyExisted && !(process.env.METAMASK_DEBUG || process.env.IN_TEST) ) { addAppInstalledEvent(); platform.openExtensionInBrowser(); } -}); +} function setupSentryGetStateGlobal(store) { global.stateHooks.getSentryAppState = function () { @@ -907,7 +920,8 @@ function setupSentryGetStateGlobal(store) { }; } -function initBackground() { +async function initBackground() { + await onInstall(); initialize().catch(log.error); } diff --git a/app/scripts/controllers/app-state.js b/app/scripts/controllers/app-state.js index 4a50e61cf60b..0d219d751e5b 100644 --- a/app/scripts/controllers/app-state.js +++ b/app/scripts/controllers/app-state.js @@ -26,7 +26,6 @@ export default class AppStateController extends EventEmitter { initState, onInactiveTimeout, preferencesStore, - qrHardwareStore, messenger, extension, } = opts; @@ -78,9 +77,13 @@ export default class AppStateController extends EventEmitter { } }); - qrHardwareStore.subscribe((state) => { - this.store.updateState({ qrHardware: state }); - }); + messenger.subscribe( + 'KeyringController:qrKeyringStateChange', + (qrHardware) => + this.store.updateState({ + qrHardware, + }), + ); const { preferences } = preferencesStore.getState(); this._setInactiveTimeout(preferences.autoLockTimeLimit); diff --git a/app/scripts/controllers/app-state.test.js b/app/scripts/controllers/app-state.test.js index 4716e30cd3d7..5e88c47d68e8 100644 --- a/app/scripts/controllers/app-state.test.js +++ b/app/scripts/controllers/app-state.test.js @@ -21,13 +21,11 @@ describe('AppStateController', () => { }, })), }, - qrHardwareStore: { - subscribe: jest.fn(), - }, messenger: { call: jest.fn(() => ({ catch: jest.fn(), })), + subscribe: jest.fn(), }, }); }; diff --git a/app/scripts/controllers/decrypt-message.test.ts b/app/scripts/controllers/decrypt-message.test.ts index 032a15289a03..21235b30a94f 100644 --- a/app/scripts/controllers/decrypt-message.test.ts +++ b/app/scripts/controllers/decrypt-message.test.ts @@ -15,6 +15,8 @@ const messageMock = { type: 'testType', rawSig: undefined, } as any as AbstractMessage; +const messageDataMock = + '0x7b2276657273696f6e223a227832353531392d7873616c736132302d706f6c7931333035222c226e6f6e6365223a226b45586143524c3045646142766f77756e35675979357175784a4a6967304548222c22657068656d5075626c69634b6579223a224863334636506d314734385a567955424763365866537839682b77784b6958587238456a51434253466e553d222c2263697068657274657874223a22546a41556b68554a5968656e7a2f655a6e57454a2b31456c7861354f77765939613830507a62746c7a7a48746934634175525941227d'; const mockExtState = {}; @@ -52,7 +54,7 @@ const createDecryptMessageManagerMock = () => }, } as any as jest.Mocked); -describe('EncryptionPublicKeyController', () => { +describe('DecryptMessageController', () => { let decryptMessageController: DecryptMessageController; const decryptMessageManagerConstructorMock = @@ -65,6 +67,19 @@ describe('EncryptionPublicKeyController', () => { const decryptMessageManagerMock = createDecryptMessageManagerMock(); + const mockMessengerAction = ( + action: string, + callback: (actionName: string, ...args: any[]) => any, + ) => { + messengerMock.call.mockImplementation((actionName, ...rest) => { + if (actionName === action) { + return callback(actionName, ...rest); + } + + return Promise.resolve(); + }); + }; + beforeEach(() => { jest.resetAllMocks(); @@ -116,12 +131,18 @@ describe('EncryptionPublicKeyController', () => { it('should decrypt message', async () => { const messageToDecrypt = { ...messageMock, - data: '0x7b22666f6f223a22626172227d', + data: messageDataMock, }; + const decryptMessageActionCallbackMock = jest + .fn() + .mockReturnValue('decryptedMessage'); decryptMessageManagerMock.approveMessage.mockResolvedValue( messageToDecrypt, ); - keyringControllerMock.decryptMessage.mockResolvedValue('decryptedMessage'); + mockMessengerAction( + 'KeyringController:decryptMessage', + decryptMessageActionCallbackMock, + ); getStateMock.mockReturnValue(mockExtState); const result = await decryptMessageController.decryptMessage( @@ -132,8 +153,9 @@ describe('EncryptionPublicKeyController', () => { expect(decryptMessageManagerMock.approveMessage).toBeCalledWith( messageToDecrypt, ); - expect(keyringControllerMock.decryptMessage).toBeCalledTimes(1); - expect(keyringControllerMock.decryptMessage).toBeCalledWith( + expect(decryptMessageActionCallbackMock).toBeCalledTimes(1); + expect(decryptMessageActionCallbackMock).toBeCalledWith( + 'KeyringController:decryptMessage', messageToDecrypt, ); expect(decryptMessageManagerMock.setMessageStatusAndResult).toBeCalledTimes( @@ -147,15 +169,31 @@ describe('EncryptionPublicKeyController', () => { expect(result).toBe(mockExtState); }); + it('should throw when decrypting invalid message', async () => { + const messageToDecrypt = { + ...messageMock, + data: '0x7b2022666f6f223a202262617222207d', + }; + decryptMessageManagerMock.approveMessage.mockResolvedValue( + messageToDecrypt, + ); + + expect( + decryptMessageController.decryptMessage(messageToDecrypt), + ).rejects.toThrow('Invalid encrypted data.'); + }); + it('should cancel decrypt request', async () => { const messageToDecrypt = { ...messageMock, - data: '0x7b22666f6f223a22626172227d', + data: messageDataMock, }; decryptMessageManagerMock.approveMessage.mockResolvedValue( messageToDecrypt, ); - keyringControllerMock.decryptMessage.mockRejectedValue(new Error('error')); + mockMessengerAction('KeyringController:decryptMessage', async () => { + throw new Error('error'); + }); getStateMock.mockReturnValue(mockExtState); return expect( @@ -166,10 +204,13 @@ describe('EncryptionPublicKeyController', () => { it('should decrypt message inline', async () => { const messageToDecrypt = { ...messageMock, - data: '0x7b22666f6f223a22626172227d', + data: messageDataMock, }; decryptMessageManagerMock.getMessage.mockReturnValue(messageToDecrypt); - keyringControllerMock.decryptMessage.mockResolvedValue('decryptedMessage'); + mockMessengerAction( + 'KeyringController:decryptMessage', + async () => 'decryptedMessage', + ); getStateMock.mockReturnValue(mockExtState); const result = await decryptMessageController.decryptMessageInline( @@ -184,6 +225,17 @@ describe('EncryptionPublicKeyController', () => { expect(result).toBe(mockExtState); }); + it('should throw when decrypting invalid message inline', async () => { + const messageToDecrypt = { + ...messageMock, + data: '0x7b2022666f6f223a202262617222207d', + }; + + expect( + decryptMessageController.decryptMessageInline(messageToDecrypt), + ).rejects.toThrow('Invalid encrypted data.'); + }); + it('should be able to cancel decrypt message', async () => { decryptMessageManagerMock.rejectMessage.mockResolvedValue(messageMock); getStateMock.mockReturnValue(mockExtState); diff --git a/app/scripts/controllers/decrypt-message.ts b/app/scripts/controllers/decrypt-message.ts index a0d1808063f1..1ace629dd995 100644 --- a/app/scripts/controllers/decrypt-message.ts +++ b/app/scripts/controllers/decrypt-message.ts @@ -5,7 +5,6 @@ import { DecryptMessageParams, DecryptMessageParamsMetamask, } from '@metamask/message-manager'; -import { KeyringController } from '@metamask/eth-keyring-controller'; import { AbstractMessage, AbstractMessageManager, @@ -25,6 +24,8 @@ import { } from '@metamask/approval-controller'; import { ApprovalType, ORIGIN_METAMASK } from '@metamask/controller-utils'; import { Patch } from 'immer'; +import type { KeyringControllerDecryptMessageAction } from '@metamask/keyring-controller'; +import { Eip1024EncryptedData, hasProperty, isObject } from '@metamask/utils'; import { MetaMetricsEventCategory } from '../../../shared/constants/metametrics'; import { stripHexPrefix } from '../../../shared/modules/hexstring-utils'; @@ -35,6 +36,37 @@ const stateMetadata = { unapprovedDecryptMsgCount: { persist: false, anonymous: false }, }; +/** + * Type guard that checks for the presence of the required properties + * for EIP-1024 encrypted data. + * + * See: https://eips.ethereum.org/EIPS/eip-1024 + * + * @param message - The message to check. + * @param message.from - The sender of the message. + * @param message.data - The EIP-1024 encrypted data. + * @returns Whether the message is an EIP-1024 encrypted message. + */ +export const isEIP1024EncryptedMessage = (message: { + from: string; + data: unknown; +}): message is { + from: string; + data: Eip1024EncryptedData; +} => { + if ( + isObject(message.data) && + hasProperty(message.data, 'version') && + hasProperty(message.data, 'nonce') && + hasProperty(message.data, 'ephemPublicKey') && + hasProperty(message.data, 'ciphertext') + ) { + return true; + } + + return false; +}; + export const getDefaultState = () => ({ unapprovedDecryptMsgs: {}, unapprovedDecryptMsgCount: 0, @@ -70,7 +102,11 @@ export type DecryptMessageControllerActions = GetDecryptMessageState; export type DecryptMessageControllerEvents = DecryptMessageStateChange; -type AllowedActions = AddApprovalRequest | AcceptRequest | RejectRequest; +type AllowedActions = + | AddApprovalRequest + | AcceptRequest + | RejectRequest + | KeyringControllerDecryptMessageAction; export type DecryptMessageControllerMessenger = RestrictedControllerMessenger< typeof controllerName, @@ -82,7 +118,6 @@ export type DecryptMessageControllerMessenger = RestrictedControllerMessenger< export type DecryptMessageControllerOptions = { getState: () => any; - keyringController: KeyringController; messenger: DecryptMessageControllerMessenger; metricsEvent: (payload: any, options?: any) => void; }; @@ -99,8 +134,6 @@ export default class DecryptMessageController extends BaseControllerV2< private _getState: () => any; - private _keyringController: KeyringController; - private _metricsEvent: (payload: any, options?: any) => void; private _decryptMessageManager: DecryptMessageManager; @@ -110,13 +143,11 @@ export default class DecryptMessageController extends BaseControllerV2< * * @param options - The controller options. * @param options.getState - Callback to retrieve all user state. - * @param options.keyringController - An instance of a keyring controller used to decrypt message * @param options.messenger - A reference to the messaging system. * @param options.metricsEvent - A function for emitting a metric event. */ constructor({ getState, - keyringController, metricsEvent, messenger, }: DecryptMessageControllerOptions) { @@ -127,7 +158,6 @@ export default class DecryptMessageController extends BaseControllerV2< state: getDefaultState(), }); this._getState = getState; - this._keyringController = keyringController; this._metricsEvent = metricsEvent; this.hub = new EventEmitter(); @@ -216,7 +246,12 @@ export default class DecryptMessageController extends BaseControllerV2< await this._decryptMessageManager.approveMessage(messageParams); cleanMessageParams.data = this._parseMessageData(cleanMessageParams.data); - const rawMessage = await this._keyringController.decryptMessage( + if (!isEIP1024EncryptedMessage(cleanMessageParams)) { + throw new Error('Invalid encrypted data.'); + } + + const rawMessage = await this.messagingSystem.call( + 'KeyringController:decryptMessage', cleanMessageParams, ); @@ -243,7 +278,11 @@ export default class DecryptMessageController extends BaseControllerV2< async decryptMessageInline(messageParams: DecryptMessageParamsMetamask) { const messageId = messageParams.metamaskId as string; messageParams.data = this._parseMessageData(messageParams.data); - const rawMessage = await this._keyringController.decryptMessage( + if (!isEIP1024EncryptedMessage(messageParams)) { + throw new Error('Invalid encrypted data.'); + } + const rawMessage = await this.messagingSystem.call( + 'KeyringController:decryptMessage', messageParams, ); diff --git a/app/scripts/controllers/detect-tokens.js b/app/scripts/controllers/detect-tokens.js index 46719aebcced..86c8cc222856 100644 --- a/app/scripts/controllers/detect-tokens.js +++ b/app/scripts/controllers/detect-tokens.js @@ -28,7 +28,6 @@ export default class DetectTokensController { * @param config.interval * @param config.preferences * @param config.network - * @param config.keyringMemStore * @param config.tokenList * @param config.tokensController * @param config.assetsContractController @@ -40,7 +39,6 @@ export default class DetectTokensController { interval = DEFAULT_INTERVAL, preferences, network, - keyringMemStore, tokenList, tokensController, assetsContractController = null, @@ -52,7 +50,6 @@ export default class DetectTokensController { this.preferences = preferences; this.interval = interval; this.network = network; - this.keyringMemStore = keyringMemStore; this.tokenList = tokenList; this.useTokenDetection = this.preferences?.store.getState().useTokenDetection; @@ -91,6 +88,8 @@ export default class DetectTokensController { this.restartTokenDetection({ chainId: this.chainId }); } }); + + this.#registerKeyringHandlers(); } /** @@ -236,26 +235,6 @@ export default class DetectTokensController { }, interval); } - /** - * In setter when isUnlocked is updated to true, detectNewTokens and restart polling - * - * @type {object} - */ - set keyringMemStore(keyringMemStore) { - if (!keyringMemStore) { - return; - } - this._keyringMemStore = keyringMemStore; - this._keyringMemStore.subscribe(({ isUnlocked }) => { - if (this.isUnlocked !== isUnlocked) { - this.isUnlocked = isUnlocked; - if (isUnlocked) { - this.restartTokenDetection(); - } - } - }); - } - /** * @type {object} */ @@ -275,4 +254,22 @@ export default class DetectTokensController { return this.isOpen && this.isUnlocked; } /* eslint-enable accessor-pairs */ + + /** + * Constructor helper to register listeners on the keyring + * locked state changes + */ + #registerKeyringHandlers() { + const { isUnlocked } = this.messenger.call('KeyringController:getState'); + this.isUnlocked = isUnlocked; + + this.messenger.subscribe('KeyringController:unlock', () => { + this.isUnlocked = true; + this.restartTokenDetection(); + }); + + this.messenger.subscribe('KeyringController:lock', () => { + this.isUnlocked = false; + }); + } } diff --git a/app/scripts/controllers/detect-tokens.test.js b/app/scripts/controllers/detect-tokens.test.js index 8d1c182c249e..17927cfcfbd2 100644 --- a/app/scripts/controllers/detect-tokens.test.js +++ b/app/scripts/controllers/detect-tokens.test.js @@ -1,7 +1,6 @@ import { strict as assert } from 'assert'; import sinon from 'sinon'; import nock from 'nock'; -import { ObservableStore } from '@metamask/obs-store'; import BigNumber from 'bignumber.js'; import { ControllerMessenger } from '@metamask/base-controller'; import { @@ -16,25 +15,30 @@ import { toChecksumHexAddress } from '../../../shared/modules/hexstring-utils'; import DetectTokensController from './detect-tokens'; import PreferencesController from './preferences'; -function buildMessenger() { - return new ControllerMessenger().getRestricted({ - name: 'DetectTokensController', - allowedEvents: ['NetworkController:stateChange'], - }); -} - describe('DetectTokensController', function () { let sandbox, assetsContractController, - keyringMemStore, network, preferences, provider, tokensController, - tokenListController; + tokenListController, + messenger; const noop = () => undefined; + const getRestrictedMessenger = () => { + return messenger.getRestricted({ + name: 'DetectTokensController', + allowedActions: ['KeyringController:getState'], + allowedEvents: [ + 'NetworkController:stateChange', + 'KeyringController:lock', + 'KeyringController:unlock', + ], + }); + }; + const networkControllerProviderConfig = { getAccounts: noop, }; @@ -198,7 +202,11 @@ describe('DetectTokensController', function () { .reply(200, { error: 'ChainId 3 is not supported' }) .persist(); - keyringMemStore = new ObservableStore({ isUnlocked: false }); + messenger = new ControllerMessenger(); + messenger.registerActionHandler('KeyringController:getState', () => ({ + isUnlocked: true, + })); + const networkControllerMessenger = new ControllerMessenger(); network = new NetworkController({ messenger: networkControllerMessenger, @@ -223,8 +231,6 @@ describe('DetectTokensController', function () { network, provider, tokenListController, - onInfuraIsBlocked: sinon.stub(), - onInfuraIsUnblocked: sinon.stub(), networkConfigurations: {}, onAccountRemoved: sinon.stub(), }); @@ -263,7 +269,11 @@ describe('DetectTokensController', function () { it('should poll on correct interval', async function () { const stub = sinon.stub(global, 'setInterval'); - new DetectTokensController({ messenger: buildMessenger(), interval: 1337 }); // eslint-disable-line no-new + // eslint-disable-next-line no-new + new DetectTokensController({ + messenger: getRestrictedMessenger(), + interval: 1337, + }); assert.strictEqual(stub.getCall(0).args[1], 1337); stub.restore(); }); @@ -272,10 +282,9 @@ describe('DetectTokensController', function () { const clock = sandbox.useFakeTimers(); await network.setProviderType(NETWORK_TYPES.MAINNET); const controller = new DetectTokensController({ - messenger: buildMessenger(), + messenger: getRestrictedMessenger(), preferences, network, - keyringMemStore, tokenList: tokenListController, tokensController, assetsContractController, @@ -309,10 +318,9 @@ describe('DetectTokensController', function () { }); await tokenListController.start(); const controller = new DetectTokensController({ - messenger: buildMessenger(), + messenger: getRestrictedMessenger(), preferences, network, - keyringMemStore, tokenList: tokenListController, tokensController, assetsContractController, @@ -333,10 +341,9 @@ describe('DetectTokensController', function () { sandbox.useFakeTimers(); await network.setProviderType(NETWORK_TYPES.MAINNET); const controller = new DetectTokensController({ - messenger: buildMessenger(), + messenger: getRestrictedMessenger(), preferences, network, - keyringMemStore, tokenList: tokenListController, tokensController, assetsContractController, @@ -385,10 +392,9 @@ describe('DetectTokensController', function () { sandbox.useFakeTimers(); await network.setProviderType(NETWORK_TYPES.MAINNET); const controller = new DetectTokensController({ - messenger: buildMessenger(), + messenger: getRestrictedMessenger(), preferences, network, - keyringMemStore, tokenList: tokenListController, tokensController, assetsContractController, @@ -444,10 +450,9 @@ describe('DetectTokensController', function () { it('should trigger detect new tokens when change address', async function () { sandbox.useFakeTimers(); const controller = new DetectTokensController({ - messenger: buildMessenger(), + messenger: getRestrictedMessenger(), preferences, network, - keyringMemStore, tokenList: tokenListController, tokensController, assetsContractController, @@ -464,10 +469,9 @@ describe('DetectTokensController', function () { it('should trigger detect new tokens when submit password', async function () { sandbox.useFakeTimers(); const controller = new DetectTokensController({ - messenger: buildMessenger(), + messenger: getRestrictedMessenger(), preferences, network, - keyringMemStore, tokenList: tokenListController, tokensController, assetsContractController, @@ -475,18 +479,38 @@ describe('DetectTokensController', function () { controller.isOpen = true; controller.selectedAddress = '0x0'; const stub = sandbox.stub(controller, 'detectNewTokens'); - await controller._keyringMemStore.updateState({ isUnlocked: true }); + + messenger.publish('KeyringController:unlock'); + sandbox.assert.called(stub); + assert.equal(controller.isUnlocked, true); + }); + + it('should not be active after lock event is emitted', async function () { + sandbox.useFakeTimers(); + const controller = new DetectTokensController({ + messenger: getRestrictedMessenger(), + preferences, + network, + tokenList: tokenListController, + tokensController, + assetsContractController, + }); + controller.isOpen = true; + + messenger.publish('KeyringController:lock'); + + assert.equal(controller.isUnlocked, false); + assert.equal(controller.isActive, false); }); it('should not trigger detect new tokens when not unlocked', async function () { const clock = sandbox.useFakeTimers(); await network.setProviderType(NETWORK_TYPES.MAINNET); const controller = new DetectTokensController({ - messenger: buildMessenger(), + messenger: getRestrictedMessenger(), preferences, network, - keyringMemStore, tokenList: tokenListController, tokensController, assetsContractController, @@ -505,10 +529,9 @@ describe('DetectTokensController', function () { const clock = sandbox.useFakeTimers(); await network.setProviderType(NETWORK_TYPES.MAINNET); const controller = new DetectTokensController({ - messenger: buildMessenger(), + messenger: getRestrictedMessenger(), preferences, network, - keyringMemStore, tokensController, assetsContractController, }); diff --git a/app/scripts/controllers/metametrics.js b/app/scripts/controllers/metametrics.js index d92e1ce5f808..a72e64219df4 100644 --- a/app/scripts/controllers/metametrics.js +++ b/app/scripts/controllers/metametrics.js @@ -11,6 +11,7 @@ import { import { ObservableStore } from '@metamask/obs-store'; import { bufferToHex, keccak } from 'ethereumjs-util'; import { v4 as uuidv4 } from 'uuid'; +import { NameType } from '@metamask/name-controller'; import { ENVIRONMENT_TYPE_BACKGROUND } from '../../../shared/constants/app'; import { METAMETRICS_ANONYMOUS_ID, @@ -21,9 +22,26 @@ import { SECOND } from '../../../shared/constants/time'; import { isManifestV3 } from '../../../shared/modules/mv3.utils'; import { METAMETRICS_FINALIZE_EVENT_FRAGMENT_ALARM } from '../../../shared/constants/alarms'; import { checkAlarmExists, generateRandomId, isValidDate } from '../lib/util'; +import { + AnonymousTransactionMetaMetricsEvent, + TransactionMetaMetricsEvent, +} from '../../../shared/constants/transaction'; const EXTENSION_UNINSTALL_URL = 'https://metamask.io/uninstalled'; +export const overrideAnonymousEventNames = { + [TransactionMetaMetricsEvent.added]: + AnonymousTransactionMetaMetricsEvent.added, + [TransactionMetaMetricsEvent.approved]: + AnonymousTransactionMetaMetricsEvent.approved, + [TransactionMetaMetricsEvent.finalized]: + AnonymousTransactionMetaMetricsEvent.finalized, + [TransactionMetaMetricsEvent.rejected]: + AnonymousTransactionMetaMetricsEvent.rejected, + [TransactionMetaMetricsEvent.submitted]: + AnonymousTransactionMetaMetricsEvent.submitted, +}; + const defaultCaptureException = (err) => { // throw error on clean stack so its captured by platform integrations (eg sentry) // but does not interrupt the call stack @@ -540,15 +558,23 @@ export default class MetaMetricsController { ); } + // change anonymous event names + const anonymousEventName = + overrideAnonymousEventNames[`${payload.event}`]; + const anonymousPayload = { + ...payload, + event: anonymousEventName ?? payload.event, + }; + const combinedProperties = merge( - payload.sensitiveProperties, - payload.properties, + anonymousPayload.sensitiveProperties, + anonymousPayload.properties, ); events.push( this._track( this._buildEventPayload({ - ...payload, + ...anonymousPayload, properties: combinedProperties, isDuplicateAnonymizedEvent: true, }), @@ -775,6 +801,10 @@ export default class MetaMetricsController { ///: END:ONLY_INCLUDE_IN [MetaMetricsUserTrait.SecurityProviders]: metamaskState.transactionSecurityCheckEnabled ? ['opensea'] : [], + ///: BEGIN:ONLY_INCLUDE_IN(petnames) + [MetaMetricsUserTrait.PetnameAddressCount]: + this._getPetnameAddressCount(metamaskState), + ///: END:ONLY_INCLUDE_IN }; if (!previousUserTraits) { @@ -1051,4 +1081,29 @@ export default class MetaMetricsController { }; this.segment[eventType](modifiedPayload, modifiedCallback); } + + /** + * Returns the total number of Ethereum addresses with saved petnames, + * including all chain ID variations. + * + * @param {object} metamaskState + * @returns {number} + */ + _getPetnameAddressCount(metamaskState) { + const addressNames = metamaskState.names?.[NameType.ETHEREUM_ADDRESS] ?? {}; + + return Object.keys(addressNames).reduce((totalCount, address) => { + const addressEntry = addressNames[address]; + + const addressNameCount = Object.keys(addressEntry).reduce( + (count, chainId) => { + const hasName = Boolean(addressEntry[chainId].name?.length); + return count + (hasName ? 1 : 0); + }, + 0, + ); + + return totalCount + addressNameCount; + }, 0); + } } diff --git a/app/scripts/controllers/metametrics.test.js b/app/scripts/controllers/metametrics.test.js index 09170d4eee8f..3532e3b15de3 100644 --- a/app/scripts/controllers/metametrics.test.js +++ b/app/scripts/controllers/metametrics.test.js @@ -1,6 +1,7 @@ import { strict as assert } from 'assert'; import sinon from 'sinon'; import { toHex } from '@metamask/controller-utils'; +import { NameType } from '@metamask/name-controller'; import { ENVIRONMENT_TYPE_BACKGROUND } from '../../../shared/constants/app'; import { createSegmentMock } from '../lib/segment'; import { @@ -561,6 +562,80 @@ describe('MetaMetricsController', function () { }); }); + describe('Change Transaction XXX anonymous event namnes', function () { + it('should change "Transaction Added" anonymous event names to "Transaction Added Anon"', function () { + const metaMetricsController = getMetaMetricsController(); + const spy = sinon.spy(segment, 'track'); + metaMetricsController.submitEvent({ + event: 'Transaction Added', + category: 'Unit Test', + sensitiveProperties: { foo: 'bar' }, + }); + assert.ok(spy.calledTwice); + assert.ok( + spy.calledWith({ + event: `Transaction Added Anon`, + anonymousId: METAMETRICS_ANONYMOUS_ID, + context: DEFAULT_TEST_CONTEXT, + properties: { + foo: 'bar', + ...DEFAULT_EVENT_PROPERTIES, + }, + messageId: Utils.generateRandomId(), + timestamp: new Date(), + }), + ); + }); + + it('should change "Transaction Submitted" anonymous event names to "Transaction Added Anon"', function () { + const metaMetricsController = getMetaMetricsController(); + const spy = sinon.spy(segment, 'track'); + metaMetricsController.submitEvent({ + event: 'Transaction Submitted', + category: 'Unit Test', + sensitiveProperties: { foo: 'bar' }, + }); + assert.ok(spy.calledTwice); + assert.ok( + spy.calledWith({ + event: `Transaction Submitted Anon`, + anonymousId: METAMETRICS_ANONYMOUS_ID, + context: DEFAULT_TEST_CONTEXT, + properties: { + foo: 'bar', + ...DEFAULT_EVENT_PROPERTIES, + }, + messageId: Utils.generateRandomId(), + timestamp: new Date(), + }), + ); + }); + + it('should change "Transaction Finalized" anonymous event names to "Transaction Added Anon"', function () { + const metaMetricsController = getMetaMetricsController(); + const spy = sinon.spy(segment, 'track'); + metaMetricsController.submitEvent({ + event: 'Transaction Finalized', + category: 'Unit Test', + sensitiveProperties: { foo: 'bar' }, + }); + assert.ok(spy.calledTwice); + assert.ok( + spy.calledWith({ + event: `Transaction Finalized Anon`, + anonymousId: METAMETRICS_ANONYMOUS_ID, + context: DEFAULT_TEST_CONTEXT, + properties: { + foo: 'bar', + ...DEFAULT_EVENT_PROPERTIES, + }, + messageId: Utils.generateRandomId(), + timestamp: new Date(), + }), + ); + }); + }); + describe('trackPage', function () { it('should track a page view', function () { const mock = sinon.mock(segment); @@ -954,6 +1029,38 @@ describe('MetaMetricsController', function () { useTokenDetection: true, desktopEnabled: false, security_providers: [], + names: { + [NameType.ETHEREUM_ADDRESS]: { + '0x123': { + '0x1': { + name: 'Test 1', + }, + '0x2': { + name: 'Test 2', + }, + '0x3': { + name: null, + }, + }, + '0x456': { + '0x1': { + name: 'Test 3', + }, + }, + '0x789': { + '0x1': { + name: null, + }, + }, + }, + otherType: { + otherValue: { + otherVariation: { + name: 'Test 4', + }, + }, + }, + }, }); assert.deepEqual(traits, { @@ -982,6 +1089,9 @@ describe('MetaMetricsController', function () { [MetaMetricsUserTrait.MmiAccountAddress]: null, [MetaMetricsUserTrait.MmiIsCustodian]: false, ///: END:ONLY_INCLUDE_IN + ///: BEGIN:ONLY_INCLUDE_IN(petnames) + [MetaMetricsUserTrait.PetnameAddressCount]: 3, + ///: END:ONLY_INCLUDE_IN }); }); diff --git a/app/scripts/controllers/mmi-controller.js b/app/scripts/controllers/mmi-controller.js index bdf84c5f8877..969b26427a13 100644 --- a/app/scripts/controllers/mmi-controller.js +++ b/app/scripts/controllers/mmi-controller.js @@ -1,7 +1,6 @@ import EventEmitter from 'events'; import log from 'loglevel'; import { captureException } from '@sentry/browser'; -import { isEqual } from 'lodash'; import { CUSTODIAN_TYPES } from '@metamask-institutional/custody-keyring'; import { updateCustodianTransactions, @@ -11,17 +10,10 @@ import { REFRESH_TOKEN_CHANGE_EVENT, INTERACTIVE_REPLACEMENT_TOKEN_CHANGE_EVENT, } from '@metamask-institutional/sdk'; -import { - handleMmiPortfolio, - setDashboardCookie, -} from '@metamask-institutional/portfolio-dashboard'; +import { handleMmiPortfolio } from '@metamask-institutional/portfolio-dashboard'; import { toChecksumHexAddress } from '../../../shared/modules/hexstring-utils'; import { CHAIN_IDS } from '../../../shared/constants/network'; -import { - BUILD_QUOTE_ROUTE, - CONNECT_HARDWARE_ROUTE, -} from '../../../ui/helpers/constants/routes'; -import { previousValueComparator } from '../lib/util'; +import { CONNECT_HARDWARE_ROUTE } from '../../../ui/helpers/constants/routes'; import { getPermissionBackgroundApiMethods } from './permissions'; export default class MMIController extends EventEmitter { @@ -63,17 +55,6 @@ export default class MMIController extends EventEmitter { }); } - this.preferencesController.store.subscribe( - previousValueComparator(async (prevState, currState) => { - const { identities: prevIdentities } = prevState; - const { identities: currIdentities } = currState; - if (isEqual(prevIdentities, currIdentities)) { - return; - } - await this.prepareMmiPortfolio(); - }, this.preferencesController.store.getState()), - ); - this.signatureController.hub.on( 'personal_sign:signed', async ({ signature, messageId }) => { @@ -293,7 +274,7 @@ export default class MMIController extends EventEmitter { ); for (let i = 0; i < newAccounts.length; i++) { - await this.keyringController.addNewAccount(keyring); + await this.keyringController.addNewAccountForKeyring(keyring); } const allAccounts = await this.keyringController.getAccounts(); @@ -584,20 +565,6 @@ export default class MMIController extends EventEmitter { }); } - async prepareMmiPortfolio() { - if (!process.env.IN_TEST) { - try { - const mmiDashboardData = await this.handleMmiDashboardData(); - const cookieSetUrls = - this.mmiConfigurationController.store.mmiConfiguration?.portfolio - ?.cookieSetUrls || []; - setDashboardCookie(mmiDashboardData, cookieSetUrls); - } catch (error) { - console.error(error); - } - } - } - async newUnsignedMessage(msgParams, req, version) { // The code path triggered by deferSetAsSigned: true is for custodial accounts const accountDetails = this.custodyController.getAccountDetails( @@ -673,12 +640,6 @@ export default class MMIController extends EventEmitter { return true; } - async handleMmiOpenSwaps(origin, address, chainId) { - await this.setAccountAndNetwork(origin, address, chainId); - this.platform.openExtensionInBrowser(BUILD_QUOTE_ROUTE); - return true; - } - async handleMmiOpenAddHardwareWallet() { await this.appStateController.getUnlockPromise(true); this.platform.openExtensionInBrowser(CONNECT_HARDWARE_ROUTE); diff --git a/app/scripts/controllers/mmi-controller.test.js b/app/scripts/controllers/mmi-controller.test.js index e4b26dd62f5b..f8c06d62981d 100644 --- a/app/scripts/controllers/mmi-controller.test.js +++ b/app/scripts/controllers/mmi-controller.test.js @@ -1,5 +1,5 @@ /* eslint-disable */ -import { KeyringController } from '@metamask/eth-keyring-controller'; +import { KeyringController } from '@metamask/keyring-controller'; import { MmiConfigurationController } from '@metamask-institutional/custody-keyring'; import { TransactionUpdateController } from '@metamask-institutional/transaction-update'; import { SignatureController } from '@metamask/signature-controller'; @@ -13,9 +13,19 @@ describe('MMIController', function () { let mmiController; beforeEach(function () { + const mockMessenger = { + call: jest.fn(() => ({ + catch: jest.fn(), + })), + registerActionHandler: jest.fn(), + publish: jest.fn(), + subscribe: jest.fn(), + }; + mmiController = new MMIController({ mmiConfigurationController: new MmiConfigurationController(), keyringController: new KeyringController({ + messenger: mockMessenger, initState: {}, }), transactionUpdateController: new TransactionUpdateController({ @@ -35,13 +45,10 @@ describe('MMIController', function () { onNetworkStateChange: jest.fn(), }), signatureController: new SignatureController({ - messenger: { - registerActionHandler: jest.fn(), - publish: jest.fn(), - call: jest.fn(), - }, + messenger: mockMessenger, keyringController: new KeyringController({ initState: {}, + messenger: mockMessenger, }), isEthSignEnabled: jest.fn(), getAllState: jest.fn(), @@ -50,8 +57,6 @@ describe('MMIController', function () { }), preferencesController: new PreferencesController({ initState: {}, - onInfuraIsBlocked: jest.fn(), - onInfuraIsUnblocked: jest.fn(), onAccountRemoved: jest.fn(), provider: {}, networkConfigurations: {}, @@ -70,14 +75,7 @@ describe('MMIController', function () { }, })), }, - qrHardwareStore: { - subscribe: jest.fn(), - }, - messenger: { - call: jest.fn(() => ({ - catch: jest.fn(), - })), - }, + messenger: mockMessenger, }), custodianEventHandlerFactory: jest.fn(), }); diff --git a/app/scripts/controllers/permissions/specifications.test.js b/app/scripts/controllers/permissions/specifications.test.js index f716ddaba269..892ee3cadaec 100644 --- a/app/scripts/controllers/permissions/specifications.test.js +++ b/app/scripts/controllers/permissions/specifications.test.js @@ -27,8 +27,8 @@ describe('PermissionController specifications', () => { expect(caveatSpecifications.permittedCoinTypes.type).toStrictEqual( SnapCaveatType.PermittedCoinTypes, ); - expect(caveatSpecifications.snapKeyring.type).toStrictEqual( - SnapCaveatType.SnapKeyring, + expect(caveatSpecifications.chainIds.type).toStrictEqual( + SnapCaveatType.ChainIds, ); expect(caveatSpecifications.snapCronjob.type).toStrictEqual( SnapCaveatType.SnapCronjob, diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 5c1f169834ab..ac209b576480 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -55,7 +55,7 @@ export default class PreferencesController { eth_sign: false, }, useMultiAccountBalanceChecker: true, - + useSafeChainsListValidation: true, // set to true means the dynamic list from the API is being used // set to false will be using the static list from contract-metadata useTokenDetection: false, @@ -66,6 +66,9 @@ export default class PreferencesController { ///: BEGIN:ONLY_INCLUDE_IN(blockaid) securityAlertsEnabled: false, ///: END:ONLY_INCLUDE_IN + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) + addSnapAccountEnabled: false, + ///: END:ONLY_INCLUDE_IN advancedGasFee: {}, // WARNING: Do not use feature flags for security-sensitive things. @@ -93,7 +96,6 @@ export default class PreferencesController { // ENS decentralized website resolution ipfsGateway: IPFS_DEFAULT_GATEWAY_URL, useAddressBarEnsResolution: true, - infuraBlocked: null, ledgerTransportType: window.navigator.hid ? LedgerTransportTypes.webhid : LedgerTransportTypes.u2f, @@ -109,14 +111,10 @@ export default class PreferencesController { this.network = opts.network; - this._onInfuraIsBlocked = opts.onInfuraIsBlocked; - this._onInfuraIsUnblocked = opts.onInfuraIsUnblocked; this.store = new ObservableStore(initState); this.store.setMaxListeners(13); this.tokenListController = opts.tokenListController; - this._subscribeToInfuraAvailability(); - // subscribe to account removal opts.onAccountRemoved((address) => this.removeAddress(address)); @@ -173,6 +171,15 @@ export default class PreferencesController { this.store.updateState({ useMultiAccountBalanceChecker: val }); } + /** + * Setter for the `useSafeChainsListValidation` property + * + * @param {boolean} val - Whether or not the user prefers to turn off/on validation for manually adding networks + */ + setUseSafeChainsListValidation(val) { + this.store.updateState({ useSafeChainsListValidation: val }); + } + /** * Setter for the `useTokenDetection` property * @@ -240,6 +247,20 @@ export default class PreferencesController { } ///: END:ONLY_INCLUDE_IN + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) + /** + * Setter for the `addSnapAccountEnabled` property. + * + * @param {boolean} addSnapAccountEnabled - Whether or not the user wants to + * enable the "Add Snap accounts" button. + */ + setAddSnapAccountEnabled(addSnapAccountEnabled) { + this.store.updateState({ + addSnapAccountEnabled, + }); + } + ///: END:ONLY_INCLUDE_IN + /** * Setter for the `advancedGasFee` property * @@ -621,36 +642,6 @@ export default class PreferencesController { ///: END:ONLY_INCLUDE_IN - // - // PRIVATE METHODS - // - - _subscribeToInfuraAvailability() { - this._onInfuraIsBlocked(() => { - this._setInfuraBlocked(true); - }); - - this._onInfuraIsUnblocked(() => { - this._setInfuraBlocked(false); - }); - } - - /** - * - * A setter for the `infuraBlocked` property - * - * @param {boolean} isBlocked - Bool indicating whether Infura is blocked - */ - _setInfuraBlocked(isBlocked) { - const { infuraBlocked } = this.store.getState(); - - if (infuraBlocked === isBlocked) { - return; - } - - this.store.updateState({ infuraBlocked: isBlocked }); - } - /** * A method to check is the linea mainnet network should be displayed */ diff --git a/app/scripts/controllers/preferences.test.js b/app/scripts/controllers/preferences.test.js index de312b7e0fa3..106871aa5d71 100644 --- a/app/scripts/controllers/preferences.test.js +++ b/app/scripts/controllers/preferences.test.js @@ -40,8 +40,6 @@ describe('preferences controller', () => { preferencesController = new PreferencesController({ initLangCode: 'en_US', tokenListController, - onInfuraIsBlocked: jest.fn(), - onInfuraIsUnblocked: jest.fn(), onAccountRemoved: jest.fn(), networkConfigurations: NETWORK_CONFIGURATION_DATA, }); @@ -120,8 +118,6 @@ describe('preferences controller', () => { preferencesController = new PreferencesController({ initLangCode: 'en_US', tokenListController, - onInfuraIsBlocked: jest.fn(), - onInfuraIsUnblocked: jest.fn(), initState: { identities: { [testAddress]: { @@ -150,8 +146,6 @@ describe('preferences controller', () => { preferencesController = new PreferencesController({ initLangCode: 'en_US', tokenListController, - onInfuraIsBlocked: jest.fn(), - onInfuraIsUnblocked: jest.fn(), initState: { identities: { '0x7e57e2': { @@ -257,12 +251,32 @@ describe('preferences controller', () => { }); }); - describe('setUseTokenDetection', () => { - it('should default to false', () => { + describe('setUseSafeChainsListValidation', function () { + it('should default to true', function () { + const state = preferencesController.store.getState(); + + expect(state.useSafeChainsListValidation).toStrictEqual(true); + }); + + it('should set the `setUseSafeChainsListValidation` property in state', function () { expect( - preferencesController.store.getState().useTokenDetection, + preferencesController.store.getState().useSafeChainsListValidation, + ).toStrictEqual(true); + + preferencesController.setUseSafeChainsListValidation(false); + + expect( + preferencesController.store.getState().useSafeChainsListValidation, ).toStrictEqual(false); }); + }); + + describe('setUseTokenDetection', function () { + it('should default to false', function () { + const state = preferencesController.store.getState(); + + expect(state.useTokenDetection).toStrictEqual(false); + }); it('should set the useTokenDetection property in state', () => { preferencesController.setUseTokenDetection(true); diff --git a/app/scripts/controllers/transactions/EtherscanRemoteTransactionSource.test.ts b/app/scripts/controllers/transactions/EtherscanRemoteTransactionSource.test.ts index 2e7effd2c7bb..ee53f04d3741 100644 --- a/app/scripts/controllers/transactions/EtherscanRemoteTransactionSource.test.ts +++ b/app/scripts/controllers/transactions/EtherscanRemoteTransactionSource.test.ts @@ -3,7 +3,6 @@ import { TransactionStatus, TransactionType, } from '../../../../shared/constants/transaction'; -import createRandomId from '../../../../shared/modules/random-id'; import type { EtherscanTokenTransactionMeta, EtherscanTransactionMeta, @@ -21,9 +20,15 @@ jest.mock('./etherscan', () => ({ fetchEtherscanTokenTransactions: jest.fn(), })); -jest.mock('../../../../shared/modules/random-id'); +const ID_MOCK = '123'; +jest.mock('uuid', () => { + const actual = jest.requireActual('uuid'); -const ID_MOCK = 123; + return { + ...actual, + v1: () => ID_MOCK, + }; +}); const ETHERSCAN_TRANSACTION_BASE_MOCK: EtherscanTransactionMetaBase = { blockNumber: '4535105', @@ -105,6 +110,7 @@ const EXPECTED_NORMALISED_TRANSACTION_BASE = { value: '0xb1a2bc2ec50000', }, type: TransactionType.incoming, + verifiedOnBlockchain: false, }; const EXPECTED_NORMALISED_TRANSACTION_SUCCESS = { @@ -135,8 +141,6 @@ describe('EtherscanRemoteTransactionSource', () => { typeof fetchEtherscanTokenTransactions >; - const createIdMock = createRandomId as jest.MockedFn; - beforeEach(() => { jest.resetAllMocks(); @@ -147,8 +151,6 @@ describe('EtherscanRemoteTransactionSource', () => { fetchEtherscanTokenTransactionsMock.mockResolvedValue( ETHERSCAN_TOKEN_TRANSACTION_RESPONSE_EMPTY_MOCK, ); - - createIdMock.mockReturnValue(ID_MOCK); }); describe('isSupportedNetwork', () => { diff --git a/app/scripts/controllers/transactions/EtherscanRemoteTransactionSource.ts b/app/scripts/controllers/transactions/EtherscanRemoteTransactionSource.ts index ee37d0d4b2ec..0fe179d59b6c 100644 --- a/app/scripts/controllers/transactions/EtherscanRemoteTransactionSource.ts +++ b/app/scripts/controllers/transactions/EtherscanRemoteTransactionSource.ts @@ -1,7 +1,7 @@ import { BNToHex } from '@metamask/controller-utils'; import type { Hex } from '@metamask/utils'; import { BN } from 'ethereumjs-util'; -import createId from '../../../../shared/modules/random-id'; +import { v1 as uuid } from 'uuid'; import { TransactionMeta, @@ -138,7 +138,7 @@ export class EtherscanRemoteTransactionSource blockNumber: txMeta.blockNumber, chainId: currentChainId, hash: txMeta.hash, - id: createId(), + id: uuid(), metamaskNetworkId: currentNetworkId, status: TransactionStatus.confirmed, time, @@ -151,6 +151,7 @@ export class EtherscanRemoteTransactionSource value: BNToHex(new BN(txMeta.value)), }, type: TransactionType.incoming, + verifiedOnBlockchain: false, } as TransactionMeta; } } diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index 872bfd4401c8..e5147f35feb7 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -1,7 +1,7 @@ import EventEmitter from '@metamask/safe-event-emitter'; import { ObservableStore } from '@metamask/obs-store'; import { bufferToHex, keccak, toBuffer, isHexString } from 'ethereumjs-util'; -import EthQuery from 'ethjs-query'; +import EthQuery from '@metamask/ethjs-query'; import { errorCodes, ethErrors } from 'eth-rpc-errors'; import { Common, Hardfork } from '@ethereumjs/common'; import { TransactionFactory } from '@ethereumjs/tx'; @@ -345,7 +345,7 @@ export default class TransactionController extends EventEmitter { this._requestTransactionApproval(txMeta, { shouldShowRequest: false, }).catch((error) => { - if (error.code === errorCodes.provider.userRejectedRequest) { + if (error?.code === errorCodes.provider.userRejectedRequest) { return; } log.error('Error during persisted transaction approval', error); @@ -963,6 +963,7 @@ export default class TransactionController extends EventEmitter { if (blockTimestamp) { txMeta.blockTimestamp = blockTimestamp; } + txMeta.verifiedOnBlockchain = true; this.txStateManager.setTxStatusConfirmed(txId); this._markNonceDuplicatesDropped(txId); @@ -2424,7 +2425,10 @@ export default class TransactionController extends EventEmitter { ) { if (dappProposedTokenAmount === '0' || customTokenAmount === '0') { transactionApprovalAmountType = TransactionApprovalAmountType.revoke; - } else if (customTokenAmount) { + } else if ( + customTokenAmount && + customTokenAmount !== dappProposedTokenAmount + ) { transactionApprovalAmountType = TransactionApprovalAmountType.custom; } else if (dappProposedTokenAmount) { transactionApprovalAmountType = @@ -2840,7 +2844,7 @@ export default class TransactionController extends EventEmitter { const { origin } = txMeta; const approvalResult = await this._requestApproval( - String(txId), + txId, origin, { txId }, { diff --git a/app/scripts/controllers/transactions/pending-tx-tracker.js b/app/scripts/controllers/transactions/pending-tx-tracker.js index 403c94acec56..1fee4e292332 100644 --- a/app/scripts/controllers/transactions/pending-tx-tracker.js +++ b/app/scripts/controllers/transactions/pending-tx-tracker.js @@ -1,6 +1,6 @@ import EventEmitter from '@metamask/safe-event-emitter'; import log from 'loglevel'; -import EthQuery from 'ethjs-query'; +import EthQuery from '@metamask/ethjs-query'; import { TransactionStatus } from '../../../../shared/constants/transaction'; import { ERROR_SUBMITTING } from './tx-state-manager'; @@ -181,7 +181,10 @@ export default class PendingTransactionTracker extends EventEmitter { const txId = txMeta.id; // Only check submitted txs - if (txMeta.status !== TransactionStatus.submitted) { + if ( + txMeta.status !== TransactionStatus.submitted || + txMeta.verifiedOnBlockchain + ) { return; } diff --git a/app/scripts/controllers/transactions/pending-tx-tracker.test.js b/app/scripts/controllers/transactions/pending-tx-tracker.test.js index 13d812eebdb2..586a4f820d00 100644 --- a/app/scripts/controllers/transactions/pending-tx-tracker.test.js +++ b/app/scripts/controllers/transactions/pending-tx-tracker.test.js @@ -148,6 +148,53 @@ describe('PendingTransactionTracker', function () { assert.ok(resubmitTx.calledOnce, 'should call _resubmitTx'); assert.ok(warningListener.calledOnce, "should emit 'tx:warning'"); }); + + it('should NOT publish the given transaction if custodyId is in txMeta', async function () { + const txMeta = { + id: 1, + hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb', + status: TransactionStatus.signed, + txParams: { + from: '0x1678a085c290ebd122dc42cba69373b5953b831d', + nonce: '0x1', + value: '0xfffff', + }, + history: [{}], + rawTx: + '0xf86c808504a817c800827b0d940c62bb85faa3311a996e176d4d2593dd760e74ccac753e6a0ea0d00cc9789d0d7ff1f471d', + retryCount: 4, + firstRetryBlockNumber: '0x1', + custodyId: 'testid', + }; + const approveTransaction = sinon.spy(); + const publishTransaction = sinon.spy(); + const pendingTxTracker = new PendingTransactionTracker({ + query: { + getTransactionReceipt: sinon.stub(), + }, + nonceTracker: { + getGlobalLock: sinon.stub().resolves({ + releaseLock: sinon.spy(), + }), + }, + getPendingTransactions: sinon.stub().returns([]), + getCompletedTransactions: sinon.stub().returns([]), + publishTransaction, + approveTransaction, + confirmTransaction: sinon.spy(), + }); + + await pendingTxTracker._resubmitTx(txMeta, '0x11' /* 16 */); + + assert.ok( + publishTransaction.notCalled, + 'should NOT try to publish transaction', + ); + assert.ok( + approveTransaction.notCalled, + 'should NOT try to approve transaction', + ); + }); }); describe('#updatePendingTxs', function () { diff --git a/app/scripts/controllers/transactions/tx-gas-utils.js b/app/scripts/controllers/transactions/tx-gas-utils.js index 006de767ff33..3a3c6bea33a1 100644 --- a/app/scripts/controllers/transactions/tx-gas-utils.js +++ b/app/scripts/controllers/transactions/tx-gas-utils.js @@ -1,4 +1,4 @@ -import EthQuery from 'ethjs-query'; +import EthQuery from '@metamask/ethjs-query'; import log from 'loglevel'; import { addHexPrefix } from 'ethereumjs-util'; import { cloneDeep } from 'lodash'; diff --git a/app/scripts/controllers/transactions/tx-state-manager.js b/app/scripts/controllers/transactions/tx-state-manager.js index 20e142c6c052..c2a4dc56ea14 100644 --- a/app/scripts/controllers/transactions/tx-state-manager.js +++ b/app/scripts/controllers/transactions/tx-state-manager.js @@ -2,7 +2,7 @@ import EventEmitter from '@metamask/safe-event-emitter'; import { ObservableStore } from '@metamask/obs-store'; import log from 'loglevel'; import { values, keyBy, mapValues, omitBy, pickBy, sortBy } from 'lodash'; -import createId from '../../../../shared/modules/random-id'; +import { v1 as uuid } from 'uuid'; import { TransactionStatus } from '../../../../shared/constants/transaction'; import { METAMASK_CONTROLLER_EVENTS } from '../../metamask-controller'; import { transactionMatchesNetwork } from '../../../../shared/modules/transaction.utils'; @@ -130,7 +130,7 @@ export default class TransactionStateManager extends EventEmitter { } return { - id: createId(), + id: uuid(), time: new Date().getTime(), status: TransactionStatus.unapproved, metamaskNetworkId: networkId, @@ -140,6 +140,7 @@ export default class TransactionStateManager extends EventEmitter { loadingDefaults: true, dappSuggestedGasFees, sendFlowHistory: [], + verifiedOnBlockchain: false, ...opts, }; } diff --git a/app/scripts/lib/AddressBookPetnamesBridge.test.ts b/app/scripts/lib/AddressBookPetnamesBridge.test.ts new file mode 100644 index 000000000000..3d7ab4ee58af --- /dev/null +++ b/app/scripts/lib/AddressBookPetnamesBridge.test.ts @@ -0,0 +1,266 @@ +import { NameController, NameType } from '@metamask/name-controller'; +import { AddressBookController } from '@metamask/address-book-controller'; +import { + AddressBookPetnamesBridge, + AddressBookPetnamesBridgeMessenger, +} from './AddressBookPetnamesBridge'; + +const ADDRESS_MOCK = '0xabc'; +const NAME_MOCK = 'testName'; +const NAME_2_MOCK = 'testName2'; +const CHAIN_ID_MOCK = '0x1'; + +function createAddressBookControllerMock( + state: any = {}, +): jest.Mocked { + return { + state: { + addressBook: state, + }, + set: jest.fn(), + delete: jest.fn(), + subscribe: jest.fn(), + } as any; +} + +function createNameControllerMock( + state: any = {}, +): jest.Mocked { + return { + state: { + names: { + ethereumAddress: state, + }, + }, + setName: jest.fn(), + } as any; +} + +function createMessengerMock(): jest.Mocked { + return { + subscribe: jest.fn(), + } as any; +} + +describe('AddressBookPetnamesBridge', () => { + let addressBookControllerDefault; + let nameControllerDefault; + let messengerDefault; + let options: any; + + beforeEach(() => { + jest.resetAllMocks(); + + addressBookControllerDefault = createAddressBookControllerMock(); + nameControllerDefault = createNameControllerMock(); + messengerDefault = createMessengerMock(); + + options = { + addressBookController: addressBookControllerDefault, + nameController: nameControllerDefault, + messenger: messengerDefault, + }; + }); + + describe('NameController', () => { + it('adds entry when address book entry added', () => { + new AddressBookPetnamesBridge(options).init(); + + addressBookControllerDefault.subscribe.mock.calls[0][0]({ + addressBook: { + [CHAIN_ID_MOCK]: { + [ADDRESS_MOCK]: { + address: ADDRESS_MOCK, + name: NAME_MOCK, + chainId: CHAIN_ID_MOCK, + isEns: true, + } as any, + }, + }, + }); + + expect(nameControllerDefault.setName).toHaveBeenCalledTimes(1); + expect(nameControllerDefault.setName).toHaveBeenCalledWith({ + value: ADDRESS_MOCK, + type: NameType.ETHEREUM_ADDRESS, + name: NAME_MOCK, + sourceId: 'ens', + variation: CHAIN_ID_MOCK, + }); + }); + + it('updates entry when address book entry is updated', () => { + const nameController = createNameControllerMock({ + [ADDRESS_MOCK]: { + [CHAIN_ID_MOCK]: { + name: NAME_MOCK, + sourceId: null, + proposedNames: {}, + }, + }, + }); + + new AddressBookPetnamesBridge({ + ...options, + nameController, + }).init(); + + addressBookControllerDefault.subscribe.mock.calls[0][0]({ + addressBook: { + [CHAIN_ID_MOCK]: { + [ADDRESS_MOCK]: { + address: ADDRESS_MOCK, + name: NAME_2_MOCK, + chainId: CHAIN_ID_MOCK, + isEns: false, + } as any, + }, + }, + }); + + expect(nameController.setName).toHaveBeenCalledTimes(1); + expect(nameController.setName).toHaveBeenCalledWith({ + value: ADDRESS_MOCK, + type: NameType.ETHEREUM_ADDRESS, + name: NAME_2_MOCK, + sourceId: undefined, + variation: CHAIN_ID_MOCK, + }); + }); + + it('deletes entry when address book entry is deleted', () => { + const nameController = createNameControllerMock({ + [ADDRESS_MOCK]: { + [CHAIN_ID_MOCK]: { + name: NAME_MOCK, + sourceId: null, + proposedNames: {}, + } as any, + }, + }); + + new AddressBookPetnamesBridge({ + ...options, + nameController, + }).init(); + + addressBookControllerDefault.subscribe.mock.calls[0][0]({ + addressBook: {}, + }); + + expect(nameController.setName).toHaveBeenCalledTimes(1); + expect(nameController.setName).toHaveBeenCalledWith({ + value: ADDRESS_MOCK, + type: NameType.ETHEREUM_ADDRESS, + name: null, + sourceId: undefined, + variation: CHAIN_ID_MOCK, + }); + }); + }); + + describe('AddressBookController', () => { + it('adds entry when petname added', () => { + new AddressBookPetnamesBridge(options).init(); + + messengerDefault.subscribe.mock.calls[0][1]( + { + names: { + [NameType.ETHEREUM_ADDRESS]: { + [ADDRESS_MOCK]: { + [CHAIN_ID_MOCK]: { + name: NAME_MOCK, + sourceId: null, + proposedNames: {}, + }, + }, + }, + }, + }, + undefined, + ); + + expect(addressBookControllerDefault.set).toHaveBeenCalledTimes(1); + expect(addressBookControllerDefault.set).toHaveBeenCalledWith( + ADDRESS_MOCK, + NAME_MOCK, + CHAIN_ID_MOCK, + ); + }); + + it('updates entry when petname updated', () => { + const addressBookController = createAddressBookControllerMock({ + [CHAIN_ID_MOCK]: { + [ADDRESS_MOCK]: { + address: ADDRESS_MOCK, + name: NAME_MOCK, + chainId: CHAIN_ID_MOCK, + isEns: false, + } as any, + }, + }); + + new AddressBookPetnamesBridge({ + ...options, + addressBookController, + }).init(); + + messengerDefault.subscribe.mock.calls[0][1]( + { + names: { + [NameType.ETHEREUM_ADDRESS]: { + [ADDRESS_MOCK]: { + [CHAIN_ID_MOCK]: { + name: NAME_2_MOCK, + sourceId: null, + proposedNames: {}, + }, + }, + }, + }, + }, + undefined, + ); + + expect(addressBookController.set).toHaveBeenCalledTimes(1); + expect(addressBookController.set).toHaveBeenCalledWith( + ADDRESS_MOCK, + NAME_2_MOCK, + CHAIN_ID_MOCK, + ); + }); + + it('deletes entry when petname deleted', () => { + const addressBookController = createAddressBookControllerMock({ + [CHAIN_ID_MOCK]: { + [ADDRESS_MOCK]: { + address: ADDRESS_MOCK, + name: NAME_MOCK, + chainId: CHAIN_ID_MOCK, + isEns: false, + } as any, + }, + }); + + new AddressBookPetnamesBridge({ + ...options, + addressBookController, + }).init(); + + messengerDefault.subscribe.mock.calls[0][1]( + { + names: { + [NameType.ETHEREUM_ADDRESS]: {}, + }, + }, + undefined, + ); + + expect(addressBookController.delete).toHaveBeenCalledTimes(1); + expect(addressBookController.delete).toHaveBeenCalledWith( + CHAIN_ID_MOCK, + ADDRESS_MOCK, + ); + }); + }); +}); diff --git a/app/scripts/lib/AddressBookPetnamesBridge.ts b/app/scripts/lib/AddressBookPetnamesBridge.ts new file mode 100644 index 000000000000..94f2edb18fc3 --- /dev/null +++ b/app/scripts/lib/AddressBookPetnamesBridge.ts @@ -0,0 +1,247 @@ +import { + AddressBookController, + AddressBookState, +} from '@metamask/address-book-controller'; +import { RestrictedControllerMessenger } from '@metamask/base-controller'; +import { + NameController, + NameControllerState, + NameStateChange, + NameType, +} from '@metamask/name-controller'; +import { cloneDeep } from 'lodash'; +import log from 'loglevel'; + +type Entry = { + address: string; + name: string; + chainId: string; + isEns: boolean; +}; + +type AllowedEvents = NameStateChange; + +export type AddressBookPetnamesBridgeMessenger = RestrictedControllerMessenger< + 'AddressBookPetnamesBridge', + never, + AllowedEvents, + never, + AllowedEvents['type'] +>; + +export class AddressBookPetnamesBridge { + #addressBookController: AddressBookController; + + #addressBookState: AddressBookState; + + #nameController: NameController; + + #nameState: NameControllerState; + + #messenger: AddressBookPetnamesBridgeMessenger; + + #updating: boolean; + + constructor({ + addressBookController, + nameController, + messenger, + }: { + addressBookController: AddressBookController; + nameController: NameController; + messenger: AddressBookPetnamesBridgeMessenger; + }) { + this.#addressBookController = addressBookController; + this.#addressBookState = addressBookController.state; + this.#nameController = nameController; + this.#nameState = nameController.state; + this.#messenger = messenger; + this.#updating = false; + } + + init() { + this.#addressBookController.subscribe((state) => { + try { + this.#onAddressBookStateChange(state); + } catch (error) { + log.debug( + 'Error synchronising address book update with petnames', + error, + ); + } + }); + + this.#messenger.subscribe('NameController:stateChange', (state) => { + try { + this.#onPetnameStateChange(state); + } catch (error) { + log.debug('Error synchronising petname update with petnames', error); + } + }); + } + + #onPetnameStateChange(newState: NameControllerState) { + if (this.#updating) { + return; + } + + this.#updating = true; + + const newEntries = this.#getPetnameEntries(newState); + const oldEntries = this.#getAddressBookEntries(this.#addressBookState); + + const { added, updated, deleted } = this.#groupEntries( + oldEntries, + newEntries, + ); + + for (const entry of [...added, ...updated]) { + this.#addressBookController.set( + entry.address, + entry.name, + entry.chainId as any, + ); + + log.debug('Updated address book following petname update', entry); + } + + for (const entry of deleted) { + this.#addressBookController.delete(entry.chainId as any, entry.address); + log.debug('Removed address book entry following petname removal', entry); + } + + this.#addressBookState = cloneDeep(this.#addressBookController.state); + this.#nameState = cloneDeep(newState); + this.#updating = false; + } + + #onAddressBookStateChange(newState: AddressBookState) { + if (this.#updating) { + return; + } + + this.#updating = true; + + const newEntries = this.#getAddressBookEntries(newState); + const oldEntries = this.#getPetnameEntries(this.#nameState); + + const { added, updated, deleted } = this.#groupEntries( + oldEntries, + newEntries, + ); + + for (const entry of [...added, ...updated]) { + this.#nameController.setName({ + value: entry.address, + type: NameType.ETHEREUM_ADDRESS, + name: entry.name, + sourceId: entry.isEns ? 'ens' : undefined, + variation: entry.chainId, + }); + + log.debug('Updated petname following address book update', entry); + } + + for (const entry of deleted) { + this.#nameController.setName({ + value: entry.address, + type: NameType.ETHEREUM_ADDRESS, + name: null, + variation: entry.chainId, + }); + + log.debug('Removed petname following address book removal', entry); + } + + this.#addressBookState = cloneDeep(newState); + this.#nameState = cloneDeep(this.#nameController.state); + this.#updating = false; + } + + #groupEntries(oldEntries: Entry[], newEntries: Entry[]) { + const added = newEntries.filter( + (newEntry) => + !oldEntries.some( + (oldEntry) => + oldEntry.address === newEntry.address && + oldEntry.chainId === newEntry.chainId, + ), + ); + + const updated = newEntries.filter((newEntry) => + oldEntries.some( + (oldEntry) => + oldEntry.address === newEntry.address && + oldEntry.chainId === newEntry.chainId && + oldEntry.name !== newEntry.name, + ), + ); + + const deleted = oldEntries.filter( + (oldEntry) => + !newEntries.some( + (newEntry) => + newEntry.address === oldEntry.address && + newEntry.chainId === oldEntry.chainId, + ), + ); + + return { added, updated, deleted }; + } + + #getPetnameEntries(state: NameControllerState): Entry[] { + const entries: Entry[] = []; + + for (const address of Object.keys(state.names.ethereumAddress)) { + const addressEntries = state.names.ethereumAddress[address]; + + for (const chainId of Object.keys(addressEntries)) { + const entry = state.names.ethereumAddress[address][chainId as any]; + const normalizedAddress = address.toLowerCase(); + const normalizedChainId = chainId.toLowerCase(); + const { sourceId, name } = entry; + + if (!name?.length) { + continue; + } + + entries.push({ + address: normalizedAddress, + name, + chainId: normalizedChainId, + isEns: sourceId === 'ens', + }); + } + } + + return entries; + } + + #getAddressBookEntries(state: AddressBookState): Entry[] { + const entries: Entry[] = []; + + for (const chainId of Object.keys(state.addressBook)) { + const chainEntries = state.addressBook[chainId as any]; + + for (const address of Object.keys(chainEntries)) { + const entry = state.addressBook[chainId as any][address]; + const normalizedAddress = address.toLowerCase(); + const normalizedChainId = chainId.toLowerCase(); + const { name, isEns } = entry; + + if (!name?.length || !normalizedAddress?.length) { + continue; + } + + entries.push({ + address: normalizedAddress, + name, + chainId: normalizedChainId, + isEns, + }); + } + } + + return entries; + } +} diff --git a/app/scripts/lib/SnapsNameProvider.test.ts b/app/scripts/lib/SnapsNameProvider.test.ts new file mode 100644 index 000000000000..cef4356e379c --- /dev/null +++ b/app/scripts/lib/SnapsNameProvider.test.ts @@ -0,0 +1,240 @@ +import { NameType } from '@metamask/name-controller'; +import { HandlerType } from '@metamask/snaps-utils'; +import { + GetAllSnaps, + GetSnap, + HandleSnapRequest, +} from '@metamask/snaps-controllers'; +import { GetPermissionControllerState } from '@metamask/permission-controller'; +import { + SnapsNameProvider, + SnapsNameProviderMessenger, +} from './SnapsNameProvider'; + +const VALUE_MOCK = 'TestValue'; +const CHAIN_ID_MOCK = '0x1'; +const NAME_MOCK = 'TestName'; +const NAME_MOCK_2 = 'TestName2'; +const ERROR_MOCK = 'TestError'; + +const SNAP_MOCK = { + id: 'testSnap1', + manifest: { + proposedName: 'Test Snap 1', + }, +}; + +const SNAP_MOCK_2 = { + id: 'testSnap2', + manifest: { + proposedName: 'Test Snap 2', + }, +}; + +const SNAP_MOCK_3 = { + id: 'testSnap3', + manifest: { + proposedName: 'Test Snap 3', + }, +}; + +function createMockMessenger({ + getAllSnaps, + getSnap, + handleSnapRequest, + getPermissionControllerState, +}: { + getAllSnaps?: jest.Mocked; + getSnap?: jest.Mocked; + handleSnapRequest?: jest.Mocked; + getPermissionControllerState?: jest.Mocked< + GetPermissionControllerState['handler'] + >; +} = {}): SnapsNameProviderMessenger { + const getAllSnapsMock = + getAllSnaps || + jest.fn().mockReturnValue([SNAP_MOCK, SNAP_MOCK_2, SNAP_MOCK_3]); + + const getSnapMock = + getSnap || + jest + .fn() + .mockImplementation((snapId) => + [SNAP_MOCK, SNAP_MOCK_2, SNAP_MOCK_3].find(({ id }) => id === snapId), + ); + + const handleSnapRequestMock = + handleSnapRequest || jest.fn().mockResolvedValue(Promise.resolve()); + + const getPermissionControllerStateMock = + getPermissionControllerState || + jest.fn().mockReturnValue({ + subjects: { + [SNAP_MOCK.id]: { permissions: { 'endowment:name-lookup': true } }, + [SNAP_MOCK_2.id]: { permissions: { 'endowment:name-lookup': true } }, + [SNAP_MOCK_3.id]: { permissions: {} }, + }, + }); + + const callMock = jest.fn().mockImplementation((method, ...args) => { + switch (method) { + case 'SnapController:getAll': + return getAllSnapsMock(); + case 'SnapController:get': + return getSnapMock(args[0]); + case 'SnapController:handleRequest': + return handleSnapRequestMock(args[0]); + case 'PermissionController:getState': + return getPermissionControllerStateMock(); + default: + return undefined; + } + }); + + return { + call: callMock, + } as any; +} + +describe('SnapsNameProvider', () => { + beforeEach(() => { + jest.resetAllMocks(); + }); + + describe('getMetadata', () => { + it('returns metadata for installed snap with permissions', () => { + const provider = new SnapsNameProvider({ + messenger: createMockMessenger(), + }); + + const metadata = provider.getMetadata(); + const { sourceIds, sourceLabels } = metadata; + + expect(sourceIds).toStrictEqual({ + [NameType.ETHEREUM_ADDRESS]: [SNAP_MOCK.id, SNAP_MOCK_2.id], + }); + + expect(sourceLabels).toStrictEqual({ + [SNAP_MOCK.id]: SNAP_MOCK.manifest.proposedName, + [SNAP_MOCK_2.id]: SNAP_MOCK_2.manifest.proposedName, + }); + }); + }); + + describe('getProposedNames', () => { + it('returns the resolved names from name lookup requests to snaps with permissions', async () => { + const handleSnapRequest = jest + .fn() + .mockResolvedValueOnce({ + resolvedDomain: NAME_MOCK, + }) + .mockResolvedValueOnce({ + resolvedDomain: NAME_MOCK_2, + }); + + const provider = new SnapsNameProvider({ + messenger: createMockMessenger({ handleSnapRequest }), + }); + + const response = await provider.getProposedNames({ + value: VALUE_MOCK, + type: NameType.ETHEREUM_ADDRESS, + variation: CHAIN_ID_MOCK, + }); + + expect(response).toStrictEqual({ + results: { + [SNAP_MOCK.id]: { + proposedNames: [NAME_MOCK], + error: undefined, + }, + [SNAP_MOCK_2.id]: { + proposedNames: [NAME_MOCK_2], + error: undefined, + }, + }, + }); + + expect(handleSnapRequest).toHaveBeenCalledTimes(2); + + for (const snapId of [SNAP_MOCK.id, SNAP_MOCK_2.id]) { + expect(handleSnapRequest).toHaveBeenCalledWith({ + snapId, + origin: '', + handler: HandlerType.OnNameLookup, + request: { + jsonrpc: '2.0', + method: ' ', + params: { + chainId: `eip155:1`, + address: VALUE_MOCK, + }, + }, + }); + } + }); + + it('returns errors if name lookup requests fail', async () => { + const handleSnapRequest = jest + .fn() + .mockImplementationOnce(() => { + throw new Error(ERROR_MOCK); + }) + .mockResolvedValueOnce({ + resolvedDomain: NAME_MOCK_2, + }); + + const errorMock = new Error('TestError'); + + const provider = new SnapsNameProvider({ + messenger: createMockMessenger({ handleSnapRequest }), + }); + + const response = await provider.getProposedNames({ + value: VALUE_MOCK, + type: NameType.ETHEREUM_ADDRESS, + variation: CHAIN_ID_MOCK, + }); + + expect(response).toStrictEqual({ + results: { + [SNAP_MOCK.id]: { + proposedNames: undefined, + error: errorMock, + }, + [SNAP_MOCK_2.id]: { + proposedNames: [NAME_MOCK_2], + error: undefined, + }, + }, + }); + }); + + it('returns empty array if name lookup request returns undefined', async () => { + const getAllSnaps = jest.fn().mockReturnValue([SNAP_MOCK]); + + const handleSnapRequest = jest.fn().mockResolvedValueOnce({ + resolvedName: undefined, + }); + + const provider = new SnapsNameProvider({ + messenger: createMockMessenger({ getAllSnaps, handleSnapRequest }), + }); + + const response = await provider.getProposedNames({ + value: VALUE_MOCK, + type: NameType.ETHEREUM_ADDRESS, + variation: CHAIN_ID_MOCK, + }); + + expect(response).toStrictEqual({ + results: { + [SNAP_MOCK.id]: { + proposedNames: [], + error: undefined, + }, + }, + }); + }); + }); +}); diff --git a/app/scripts/lib/SnapsNameProvider.ts b/app/scripts/lib/SnapsNameProvider.ts new file mode 100644 index 000000000000..abf6cc8761b1 --- /dev/null +++ b/app/scripts/lib/SnapsNameProvider.ts @@ -0,0 +1,158 @@ +import { + NameProvider, + NameProviderMetadata, + NameProviderRequest, + NameProviderResult, + NameProviderSourceResult, + NameType, +} from '@metamask/name-controller'; +import { GetPermissionControllerState } from '@metamask/permission-controller'; +import { + OnNameLookupArgs, + HandlerType, + OnNameLookupResponse, + TruncatedSnap, +} from '@metamask/snaps-utils'; +import log from 'loglevel'; +import { + GetAllSnaps, + GetSnap, + HandleSnapRequest, +} from '@metamask/snaps-controllers'; +import { RestrictedControllerMessenger } from '@metamask/base-controller'; + +type AllowedActions = + | GetAllSnaps + | GetSnap + | HandleSnapRequest + | GetPermissionControllerState; + +export type SnapsNameProviderMessenger = RestrictedControllerMessenger< + 'SnapsNameProvider', + AllowedActions, + never, + AllowedActions['type'], + never +>; + +export class SnapsNameProvider implements NameProvider { + #messenger: SnapsNameProviderMessenger; + + constructor({ messenger }: { messenger: SnapsNameProviderMessenger }) { + this.#messenger = messenger; + } + + getMetadata(): NameProviderMetadata { + const snaps = this.#getNameLookupSnaps(); + + const sourceIds = { + [NameType.ETHEREUM_ADDRESS]: snaps.map((snap) => snap.id), + }; + + const sourceLabels = snaps.reduce( + (acc: NameProviderMetadata['sourceLabels'], snap) => { + const snapDetails = this.#messenger.call('SnapController:get', snap.id); + const snapName = snapDetails?.manifest.proposedName; + + return { + ...acc, + [snap.id]: snapName || snap.id, + }; + }, + {}, + ); + + return { + sourceIds, + sourceLabels, + }; + } + + async getProposedNames( + request: NameProviderRequest, + ): Promise { + const nameSnaps = this.#getNameLookupSnaps(); + + const snapResults = await Promise.all( + nameSnaps.map((snap) => this.#getSnapProposedName(snap, request)), + ); + + const results = snapResults.reduce( + (acc: Record, snapResult) => { + const { sourceId, result } = snapResult; + return { + ...acc, + [sourceId]: result, + }; + }, + {}, + ); + + return { results }; + } + + #getNameLookupSnaps(): TruncatedSnap[] { + const permissionSubjects = this.#messenger.call( + 'PermissionController:getState', + ).subjects; + + const snaps = this.#messenger.call('SnapController:getAll'); + + return snaps.filter( + ({ id }) => permissionSubjects[id]?.permissions['endowment:name-lookup'], + ); + } + + async #getSnapProposedName( + snap: TruncatedSnap, + request: NameProviderRequest, + ): Promise<{ sourceId: string; result: NameProviderSourceResult }> { + const { variation: chainIdHex, value } = request; + const sourceId = snap.id; + const chainIdDecimal = parseInt(chainIdHex, 16); + + const nameLookupRequest: OnNameLookupArgs = { + chainId: `eip155:${chainIdDecimal}`, + address: value, + }; + + let proposedNames; + let resultError; + + try { + const result = (await this.#messenger.call( + 'SnapController:handleRequest', + { + snapId: snap.id, + origin: '', + handler: HandlerType.OnNameLookup, + request: { + jsonrpc: '2.0', + method: ' ', + params: nameLookupRequest, + }, + }, + )) as OnNameLookupResponse; + + const domain = result?.resolvedDomain; + + proposedNames = domain ? [domain] : []; + } catch (error) { + log.error('Snap name provider request failed', { + snapId: snap.id, + request: nameLookupRequest, + error, + }); + + resultError = error; + } + + return { + sourceId, + result: { + proposedNames, + error: resultError, + }, + }; + } +} diff --git a/app/scripts/lib/backup.test.js b/app/scripts/lib/backup.test.js index 93aee74bddd7..8097e9030f4b 100644 --- a/app/scripts/lib/backup.test.js +++ b/app/scripts/lib/backup.test.js @@ -1,10 +1,11 @@ -import { strict as assert } from 'assert'; -import sinon from 'sinon'; +/** + * @jest-environment node + */ import Backup from './backup'; function getMockPreferencesController() { const mcState = { - getSelectedAddress: sinon.stub().returns('0x01'), + getSelectedAddress: jest.fn().mockReturnValue('0x01'), selectedAddress: '0x01', identities: { '0x295e26495CEF6F69dFA69911d9D8e4F3bBadB89B': { @@ -24,7 +25,7 @@ function getMockPreferencesController() { }; mcState.store = { - getState: sinon.stub().returns(mcState), + getState: jest.fn().mockReturnValue(mcState), updateState: (store) => (mcState.store = store), }; @@ -49,7 +50,7 @@ function getMockAddressBookController() { }; mcState.store = { - getState: sinon.stub().returns(mcState), + getState: jest.fn().mockReturnValue(mcState), updateState: (store) => (mcState.store = store), }; @@ -142,7 +143,6 @@ const jsonData = JSON.stringify({ useNativeCurrencyAsPrimaryCurrency: true, }, ipfsGateway: 'dweb.link', - infuraBlocked: false, ledgerTransportType: 'webhid', theme: 'light', customNetworkListEnabled: false, @@ -156,7 +156,7 @@ describe('Backup', function () { preferencesController: getMockPreferencesController(), addressBookController: getMockAddressBookController(), networkController: getMockNetworkController(), - trackMetaMetricsEvent: sinon.stub(), + trackMetaMetricsEvent: jest.fn(), }); }; @@ -164,83 +164,80 @@ describe('Backup', function () { it('should setup correctly', async function () { const backup = getBackup(); const selectedAddress = backup.preferencesController.getSelectedAddress(); - assert.equal(selectedAddress, '0x01'); + expect(selectedAddress).toStrictEqual('0x01'); }); it('should restore backup', async function () { const backup = getBackup(); await backup.restoreUserData(jsonData); // check networks backup - assert.equal( + expect( backup.networkController.state.networkConfigurations[ 'network-configuration-id-1' ].chainId, - '0x539', - ); - assert.equal( + ).toStrictEqual('0x539'); + expect( backup.networkController.state.networkConfigurations[ 'network-configuration-id-2' ].chainId, - '0x38', - ); - assert.equal( + ).toStrictEqual('0x38'); + expect( backup.networkController.state.networkConfigurations[ 'network-configuration-id-3' ].chainId, - '0x61', - ); - assert.equal( + ).toStrictEqual('0x61'); + expect( backup.networkController.state.networkConfigurations[ 'network-configuration-id-4' ].chainId, - '0x89', - ); + ).toStrictEqual('0x89'); // make sure identities are not lost after restore - assert.equal( + expect( backup.preferencesController.store.identities[ '0x295e26495CEF6F69dFA69911d9D8e4F3bBadB89B' ].lastSelected, - 1655380342907, - ); - assert.equal( + ).toStrictEqual(1655380342907); + + expect( backup.preferencesController.store.identities[ '0x295e26495CEF6F69dFA69911d9D8e4F3bBadB89B' ].name, - 'Account 3', - ); - assert.equal( + ).toStrictEqual('Account 3'); + + expect( backup.preferencesController.store.lostIdentities[ '0xfd59bbe569376e3d3e4430297c3c69ea93f77435' ].lastSelected, - 1655379648197, - ); - assert.equal( + ).toStrictEqual(1655379648197); + + expect( backup.preferencesController.store.lostIdentities[ '0xfd59bbe569376e3d3e4430297c3c69ea93f77435' ].name, - 'Ledger 1', - ); + ).toStrictEqual('Ledger 1'); // make sure selected address is not lost after restore - assert.equal(backup.preferencesController.store.selectedAddress, '0x01'); + expect(backup.preferencesController.store.selectedAddress).toStrictEqual( + '0x01', + ); + // check address book backup - assert.equal( + expect( backup.addressBookController.store.addressBook['0x61'][ '0x42EB768f2244C8811C63729A21A3569731535f06' ].chainId, - '0x61', - ); - assert.equal( + ).toStrictEqual('0x61'); + + expect( backup.addressBookController.store.addressBook['0x61'][ '0x42EB768f2244C8811C63729A21A3569731535f06' ].address, - '0x42EB768f2244C8811C63729A21A3569731535f06', - ); - assert.equal( + ).toStrictEqual('0x42EB768f2244C8811C63729A21A3569731535f06'); + + expect( backup.addressBookController.store.addressBook['0x61'][ '0x42EB768f2244C8811C63729A21A3569731535f06' ].isEns, - false, - ); + ).toBeFalsy(); }); }); }); diff --git a/app/scripts/lib/createRPCMethodTrackingMiddleware.js b/app/scripts/lib/createRPCMethodTrackingMiddleware.js index d34404beb4be..bd9e4b357998 100644 --- a/app/scripts/lib/createRPCMethodTrackingMiddleware.js +++ b/app/scripts/lib/createRPCMethodTrackingMiddleware.js @@ -11,6 +11,12 @@ import { MetaMetricsEventName, MetaMetricsEventUiCustomization, } from '../../../shared/constants/metametrics'; +///: BEGIN:ONLY_INCLUDE_IN(blockaid) +import { + BlockaidReason, + BlockaidResultType, +} from '../../../shared/constants/security-provider'; +///: END:ONLY_INCLUDE_IN /** * These types determine how the method tracking middleware handles incoming @@ -183,6 +189,14 @@ export default function createRPCMethodTrackingMiddleware({ } const paramsExamplePassword = req?.params?.[2]; + ///: BEGIN:ONLY_INCLUDE_IN(blockaid) + eventProperties.security_alert_response = + req.securityAlertResponse?.result_type ?? + BlockaidResultType.NotApplicable; + eventProperties.security_alert_reason = + req.securityAlertResponse?.reason ?? BlockaidReason.notApplicable; + ///: END:ONLY_INCLUDE_IN + const msgData = { msgParams: { ...paramsExamplePassword, diff --git a/app/scripts/lib/createRPCMethodTrackingMiddleware.test.js b/app/scripts/lib/createRPCMethodTrackingMiddleware.test.js index 5da8206fa763..16c83c31f2b2 100644 --- a/app/scripts/lib/createRPCMethodTrackingMiddleware.test.js +++ b/app/scripts/lib/createRPCMethodTrackingMiddleware.test.js @@ -6,6 +6,10 @@ import { MetaMetricsEventUiCustomization, } from '../../../shared/constants/metametrics'; import { SECOND } from '../../../shared/constants/time'; +import { + BlockaidReason, + BlockaidResultType, +} from '../../../shared/constants/security-provider'; import createRPCMethodTrackingMiddleware from './createRPCMethodTrackingMiddleware'; const trackEvent = jest.fn(); @@ -115,6 +119,10 @@ describe('createRPCMethodTrackingMiddleware', () => { const req = { method: MESSAGE_TYPE.ETH_SIGN, origin: 'some.dapp', + securityAlertResponse: { + result_type: BlockaidResultType.Malicious, + reason: BlockaidReason.maliciousDomain, + }, }; const res = { @@ -128,6 +136,8 @@ describe('createRPCMethodTrackingMiddleware', () => { event: MetaMetricsEventName.SignatureRequested, properties: { signature_type: MESSAGE_TYPE.ETH_SIGN, + security_alert_response: BlockaidResultType.Malicious, + security_alert_reason: BlockaidReason.maliciousDomain, }, referrer: { url: 'some.dapp' }, }); diff --git a/app/scripts/lib/ens-ipfs/resolver.js b/app/scripts/lib/ens-ipfs/resolver.js index 602134498ab9..710a8ddd4b70 100644 --- a/app/scripts/lib/ens-ipfs/resolver.js +++ b/app/scripts/lib/ens-ipfs/resolver.js @@ -1,5 +1,5 @@ import namehash from 'eth-ens-namehash'; -import Eth from 'ethjs-query'; +import Eth from '@metamask/ethjs-query'; import EthContract from 'ethjs-contract'; import contentHash from '@ensdomains/content-hash'; import registryAbi from './contracts/registry'; diff --git a/app/scripts/lib/rpc-method-middleware/handlers/index.js b/app/scripts/lib/rpc-method-middleware/handlers/index.js index 126da76f9de4..a4c02fa71d66 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/index.js +++ b/app/scripts/lib/rpc-method-middleware/handlers/index.js @@ -11,7 +11,6 @@ import watchAsset from './watch-asset'; import mmiSupported from './institutional/mmi-supported'; import mmiAuthenticate from './institutional/mmi-authenticate'; import mmiPortfolio from './institutional/mmi-portfolio'; -import mmiOpenSwaps from './institutional/mmi-open-swaps'; import mmiCheckIfTokenIsPresent from './institutional/mmi-check-if-token-is-present'; import mmiSetAccountAndNetwork from './institutional/mmi-set-account-and-network'; import mmiOpenAddHardwareWallet from './institutional/mmi-open-add-hardware-wallet'; @@ -30,7 +29,6 @@ const handlers = [ mmiAuthenticate, mmiSupported, mmiPortfolio, - mmiOpenSwaps, mmiCheckIfTokenIsPresent, mmiSetAccountAndNetwork, mmiOpenAddHardwareWallet, diff --git a/app/scripts/lib/rpc-method-middleware/handlers/institutional/mmi-open-swaps.js b/app/scripts/lib/rpc-method-middleware/handlers/institutional/mmi-open-swaps.js deleted file mode 100644 index f0cdbd026c24..000000000000 --- a/app/scripts/lib/rpc-method-middleware/handlers/institutional/mmi-open-swaps.js +++ /dev/null @@ -1,68 +0,0 @@ -import { ethErrors } from 'eth-rpc-errors'; -import { RPC_ALLOWED_ORIGINS } from '@metamask-institutional/rpc-allowlist'; -import { MESSAGE_TYPE } from '../../../../../../shared/constants/app'; - -const mmiOpenSwaps = { - methodNames: [MESSAGE_TYPE.MMI_OPEN_SWAPS], - implementation: mmiOpenSwapsHandler, - hookNames: { - handleMmiOpenSwaps: true, - }, -}; -export default mmiOpenSwaps; - -/** - * @typedef {object} MmiOpenSwapsOptions - * @property {Function} handleMmiOpenSwaps - The metmaskinsititutional_open_swaps method implementation. - */ - -/** - * @typedef {object} MmiOpenSwapsParam - * @property {string} service - The service to which we are authenticating, e.g. 'codefi-compliance' - * @property {object} token - The token used to authenticate - */ - -/** - * @param {import('json-rpc-engine').JsonRpcRequest} req - The JSON-RPC request object. - * @param {import('json-rpc-engine').JsonRpcResponse} res - The JSON-RPC response object. - * @param {Function} _next - The json-rpc-engine 'next' callback. - * @param {Function} end - The json-rpc-engine 'end' callback. - * @param {WatchAssetOptions} options - */ -async function mmiOpenSwapsHandler( - req, - res, - _next, - end, - { handleMmiOpenSwaps }, -) { - try { - let validUrl = false; - // if (!RPC_ALLOWED_ORIGINS[MESSAGE_TYPE.MMI_PORTFOLIO].includes(req.origin)) { - RPC_ALLOWED_ORIGINS[MESSAGE_TYPE.MMI_PORTFOLIO].forEach((regexp) => { - // eslint-disable-next-line require-unicode-regexp - if (regexp.test(req.origin)) { - validUrl = true; - } - }); - // eslint-disable-next-line no-negated-condition - if (!validUrl) { - throw new Error('Unauthorized'); - } - - if (!req.params?.[0] || typeof req.params[0] !== 'object') { - return end( - ethErrors.rpc.invalidParams({ - message: `Expected single, object parameter. Received:\n${JSON.stringify( - req.params, - )}`, - }), - ); - } - const { address, network } = req.params[0]; - res.result = await handleMmiOpenSwaps(req.origin, address, network); - return end(); - } catch (error) { - return end(error); - } -} diff --git a/app/scripts/lib/setupSentry.js b/app/scripts/lib/setupSentry.js index 077d0329049d..2b908647deea 100644 --- a/app/scripts/lib/setupSentry.js +++ b/app/scripts/lib/setupSentry.js @@ -113,7 +113,9 @@ export const SENTRY_BACKGROUND_STATE = { KeyringController: { isUnlocked: true, keyrings: false, - keyringTypes: false, + }, + LoggingController: { + logs: false, }, MetaMetricsController: { eventsBeforeMetricsOptIn: false, @@ -170,7 +172,6 @@ export const SENTRY_BACKGROUND_STATE = { forgottenPassword: true, identities: false, incomingTransactionsPreferences: true, - infuraBlocked: true, ipfsGateway: false, isLineaMainnetReleased: true, knownMethodData: false, @@ -318,6 +319,7 @@ export const SENTRY_UI_STATE = { nextNonce: true, pendingTokens: false, welcomeScreenSeen: true, + useSafeChainsListValidation: true, }, unconnectedAccount: true, }; diff --git a/app/scripts/lib/snap-keyring/index.ts b/app/scripts/lib/snap-keyring/index.ts new file mode 100644 index 000000000000..5ef2a2be9501 --- /dev/null +++ b/app/scripts/lib/snap-keyring/index.ts @@ -0,0 +1 @@ +export { snapKeyringBuilder, getAccountsBySnapId } from './snap-keyring'; diff --git a/app/scripts/lib/snap-keyring/snap-keyring.ts b/app/scripts/lib/snap-keyring/snap-keyring.ts new file mode 100644 index 000000000000..26ab295cffe1 --- /dev/null +++ b/app/scripts/lib/snap-keyring/snap-keyring.ts @@ -0,0 +1,160 @@ +import { SnapKeyring } from '@metamask/eth-snap-keyring'; +import type { SnapController } from '@metamask/snaps-controllers'; +import type { + ApprovalController, + ResultComponent, +} from '@metamask/approval-controller'; +import type { KeyringController } from '@metamask/keyring-controller'; +import { SNAP_MANAGE_ACCOUNTS_CONFIRMATION_TYPES } from '../../../../shared/constants/app'; +import { t } from '../../translate'; +import MetamaskController from '../../metamask-controller'; + +/** + * Get the addresses of the accounts managed by a given Snap. + * + * @param controller - Instance of the MetaMask Controller. + * @param snapId - Snap ID to get accounts for. + * @returns The addresses of the accounts. + */ +export const getAccountsBySnapId = async ( + controller: MetamaskController, + snapId: string, +) => { + const snapKeyring: SnapKeyring = await controller.getSnapKeyring(); + return await snapKeyring.getAccountsBySnapId(snapId); +}; + +/** + * Constructs a SnapKeyring builder with specified handlers for managing snap accounts. + * + * @param getSnapController - A function that retrieves the Snap Controller instance. + * @param getApprovalController - A function that retrieves the Approval Controller instance. + * @param getCoreKeyringController - A function that retrieves the Core Keyring Controller instance. + * @param removeAccountHelper - A function to help remove an account based on its address. + * @returns The constructed SnapKeyring builder instance with the following methods: + * - `saveState`: Persists all keyrings in the keyring controller. + * - `addAccount`: Initiates the process of adding an account with user confirmation and handling the user input. + * - `removeAccount`: Initiates the process of removing an account with user confirmation and handling the user input. + */ +export const snapKeyringBuilder = ( + getSnapController: () => SnapController, + getApprovalController: () => ApprovalController, + getCoreKeyringController: () => KeyringController, + removeAccountHelper: (address: string) => Promise, +) => { + const builder = (() => { + return new SnapKeyring(getSnapController() as any, { + addressExists: async (address) => { + const addresses = await getCoreKeyringController().getAccounts(); + return addresses.includes(address.toLowerCase()); + }, + saveState: async () => { + await getCoreKeyringController().persistAllKeyrings(); + }, + addAccount: async ( + _address: string, + origin: string, + handleUserInput: (accepted: boolean) => Promise, + ) => { + const { id: addAccountApprovalId } = + getApprovalController().startFlow(); + + const snapAuthorshipHeader: ResultComponent = { + name: 'SnapAuthorshipHeader', + key: 'snapHeader', + properties: { snapId: origin }, + }; + + try { + const confirmationResult: boolean = + (await getApprovalController().addAndShowApprovalRequest({ + origin, + type: SNAP_MANAGE_ACCOUNTS_CONFIRMATION_TYPES.confirmAccountCreation, + })) as boolean; + + if (confirmationResult) { + try { + await handleUserInput(confirmationResult); + await getCoreKeyringController().persistAllKeyrings(); + await getApprovalController().success({ + message: t('snapAccountCreated') ?? 'Your account is ready!', + header: [snapAuthorshipHeader], + }); + } catch (error) { + await getApprovalController().error({ + error: (error as Error).message, + header: [snapAuthorshipHeader], + }); + throw new Error( + `Error occurred while creating snap account: ${ + (error as Error).message + }`, + ); + } + } else { + await handleUserInput(confirmationResult); + throw new Error('User denied account creation'); + } + } finally { + getApprovalController().endFlow({ + id: addAccountApprovalId, + }); + } + }, + removeAccount: async ( + address: string, + snapId: string, + handleUserInput: (accepted: boolean) => Promise, + ) => { + const { id: removeAccountApprovalId } = + getApprovalController().startFlow(); + + const snapAuthorshipHeader: ResultComponent = { + name: 'SnapAuthorshipHeader', + key: 'snapHeader', + properties: { snapId }, + }; + + try { + const confirmationResult: boolean = + (await getApprovalController().addAndShowApprovalRequest({ + origin: snapId, + type: SNAP_MANAGE_ACCOUNTS_CONFIRMATION_TYPES.confirmAccountRemoval, + requestData: { publicAddress: address }, + })) as boolean; + + if (confirmationResult) { + try { + await removeAccountHelper(address); + await handleUserInput(confirmationResult); + await getCoreKeyringController().persistAllKeyrings(); + await getApprovalController().success({ + message: t('snapAccountRemoved') ?? 'Account removed', + header: [snapAuthorshipHeader], + }); + } catch (error) { + await getApprovalController().error({ + error: (error as Error).message, + header: [snapAuthorshipHeader], + }); + throw new Error( + `Error occurred while removing snap account: ${ + (error as Error).message + }`, + ); + } + } else { + await handleUserInput(confirmationResult); + throw new Error('User denied account removal'); + } + } finally { + getApprovalController().endFlow({ + id: removeAccountApprovalId, + }); + } + }, + }); + }) as any; + builder.type = SnapKeyring.type; + return builder; +}; diff --git a/app/scripts/load-app.js b/app/scripts/load-app.js new file mode 100644 index 000000000000..16dd34383c2a --- /dev/null +++ b/app/scripts/load-app.js @@ -0,0 +1,28 @@ +// eslint-disable-next-line import/unambiguous +'use strict'; + +setTimeout(() => { + // eslint-disable-next-line spaced-comment + const scriptsToLoad = [ + /* SCRIPTS */ + ]; + + const loadScript = (src) => { + const script = document.createElement('script'); + script.type = 'text/javascript'; + script.async = true; + script.onload = loadNext; + script.src = src; + document.body.appendChild(script); + }; + + loadNext(); + + function loadNext() { + if (scriptsToLoad.length) { + loadScript(scriptsToLoad.shift()); + } else { + document.documentElement.classList.add('metamask-loaded'); + } + } +}, 10); diff --git a/app/scripts/metamask-controller.actions.test.js b/app/scripts/metamask-controller.actions.test.js index a0dba444b2df..51b69a12008f 100644 --- a/app/scripts/metamask-controller.actions.test.js +++ b/app/scripts/metamask-controller.actions.test.js @@ -177,7 +177,7 @@ describe('MetaMaskController', function () { ]), Promise.resolve(1).then(() => { keyringControllerState1 = JSON.stringify( - metamaskController.keyringController.memStore.getState(), + metamaskController.coreKeyringController.state, ); metamaskController.importAccountWithStrategy('privateKey', [ importPrivkey, @@ -185,7 +185,7 @@ describe('MetaMaskController', function () { }), Promise.resolve(2).then(() => { keyringControllerState2 = JSON.stringify( - metamaskController.keyringController.memStore.getState(), + metamaskController.coreKeyringController.state, ); }), ]); diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index ee08fe92682b..7ea284f05771 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -57,12 +57,12 @@ import { SelectedNetworkController, createSelectedNetworkMiddleware, } from '@metamask/selected-network-controller'; +import { LoggingController } from '@metamask/logging-controller'; ///: BEGIN:ONLY_INCLUDE_IN(snaps) import { encrypt, decrypt } from '@metamask/browser-passworder'; import { RateLimitController } from '@metamask/rate-limit-controller'; import { NotificationController } from '@metamask/notification-controller'; - import { CronjobController, JsonSnapsRegistry, @@ -70,9 +70,6 @@ import { IframeExecutionService, } from '@metamask/snaps-controllers'; ///: END:ONLY_INCLUDE_IN -///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) -import { SnapKeyring } from '@metamask/eth-snap-keyring'; -///: END:ONLY_INCLUDE_IN ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) import { @@ -101,6 +98,16 @@ import { } from '@metamask/controller-utils'; import { wordlist } from '@metamask/scure-bip39/dist/wordlists/english'; +///: BEGIN:ONLY_INCLUDE_IN(petnames) +import { + NameController, + ENSNameProvider, + EtherscanNameProvider, + TokenNameProvider, + LensNameProvider, +} from '@metamask/name-controller'; +///: END:ONLY_INCLUDE_IN + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) import { toChecksumHexAddress } from '../../shared/modules/hexstring-utils'; ///: END:ONLY_INCLUDE_IN @@ -162,6 +169,11 @@ 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(petnames) +import { SnapsNameProvider } from './lib/SnapsNameProvider'; +import { AddressBookPetnamesBridge } from './lib/AddressBookPetnamesBridge'; +///: END:ONLY_INCLUDE_IN + ///: BEGIN:ONLY_INCLUDE_IN(blockaid) import { createPPOMMiddleware } from './lib/ppom/ppom-middleware'; import * as PPOMModule from './lib/ppom/ppom'; @@ -228,6 +240,9 @@ import { securityProviderCheck } from './lib/security-provider-helpers'; import { IndexedDBPPOMStorage } from './lib/ppom/indexed-db-backend'; ///: END:ONLY_INCLUDE_IN import { updateCurrentLocale } from './translate'; +///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) +import { snapKeyringBuilder, getAccountsBySnapId } from './lib/snap-keyring'; +///: END:ONLY_INCLUDE_IN export const METAMASK_CONTROLLER_EVENTS = { // Fired after state changes that impact the extension badge (unapproved msg count) @@ -337,6 +352,13 @@ export default class MetamaskController extends EventEmitter { ], }); + this.loggingController = new LoggingController({ + messenger: this.controllerMessenger.getRestricted({ + name: 'LoggingController', + }), + state: initState.LoggingController, + }); + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) this.mmiConfigurationController = new MmiConfigurationController({ initState: initState.MmiConfigurationController, @@ -359,23 +381,22 @@ export default class MetamaskController extends EventEmitter { if (initState.NetworkController) { initialNetworkControllerState = initState.NetworkController; } else if (process.env.IN_TEST) { + const networkConfig = { + chainId: CHAIN_IDS.LOCALHOST, + nickname: 'Localhost 8545', + rpcPrefs: {}, + rpcUrl: 'http://localhost:8545', + ticker: 'ETH', + id: 'networkConfigurationId', + }; initialNetworkControllerState = { providerConfig: { - chainId: CHAIN_IDS.LOCALHOST, - nickname: 'Localhost 8545', - rpcPrefs: {}, - rpcUrl: 'http://localhost:8545', - ticker: 'ETH', + ...networkConfig, type: 'rpc', }, networkConfigurations: { networkConfigurationId: { - chainId: CHAIN_IDS.LOCALHOST, - nickname: 'Localhost 8545', - rpcPrefs: {}, - rpcUrl: 'http://localhost:8545', - ticker: 'ETH', - networkConfigurationId: 'networkConfigurationId', + ...networkConfig, }, }, }; @@ -424,14 +445,6 @@ export default class MetamaskController extends EventEmitter { this.preferencesController = new PreferencesController({ initState: initState.PreferencesController, initLangCode: opts.initLangCode, - onInfuraIsBlocked: networkControllerMessenger.subscribe.bind( - networkControllerMessenger, - 'NetworkController:infuraIsBlocked', - ), - onInfuraIsUnblocked: networkControllerMessenger.subscribe.bind( - networkControllerMessenger, - 'NetworkController:infuraIsUnblocked', - ), onAccountRemoved: this.controllerMessenger.subscribe.bind( this.controllerMessenger, 'KeyringController:accountRemoved', @@ -627,21 +640,19 @@ export default class MetamaskController extends EventEmitter { getChainId: () => this.networkController.state.providerConfig.chainId, }); - this.qrHardwareKeyring = new QRHardwareKeyring(); - this.appStateController = new AppStateController({ addUnlockListener: this.on.bind(this, 'unlock'), isUnlocked: this.isUnlocked.bind(this), initState: initState.AppStateController, onInactiveTimeout: () => this.setLocked(), preferencesStore: this.preferencesController.store, - qrHardwareStore: this.qrHardwareKeyring.getMemStore(), messenger: this.controllerMessenger.getRestricted({ name: 'AppStateController', allowedActions: [ `${this.approvalController.name}:addRequest`, `${this.approvalController.name}:acceptRequest`, ], + allowedEvents: [`KeyringController:qrKeyringStateChange`], }), extension: this.extension, }); @@ -845,29 +856,41 @@ export default class MetamaskController extends EventEmitter { } ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) + const getSnapController = () => this.snapController; + const getApprovalController = () => this.approvalController; + const getCoreKeyringController = () => this.coreKeyringController; + additionalKeyrings.push( - (() => { - const builder = () => - new SnapKeyring(this.snapController, { - saveState: async () => { - await this.keyringController.persistAllKeyrings(); - }, - }); - builder.type = SnapKeyring.type; - return builder; - })(), + snapKeyringBuilder( + getSnapController, + getApprovalController, + getCoreKeyringController, + (address) => this.removeAccount(address), + ), ); + ///: END:ONLY_INCLUDE_IN const keyringControllerMessenger = this.controllerMessenger.getRestricted({ name: 'KeyringController', + allowedActions: [ + 'KeyringController:getState', + 'KeyringController:signMessage', + 'KeyringController:signPersonalMessage', + 'KeyringController:signTypedMessage', + 'KeyringController:decryptMessage', + 'KeyringController:getEncryptionPublicKey', + 'KeyringController:getKeyringsByType', + 'KeyringController:getKeyringForAccount', + 'KeyringController:getAccounts', + ], allowedEvents: [ - 'KeyringController:accountRemoved', - 'KeyringController:lock', 'KeyringController:stateChange', + 'KeyringController:lock', 'KeyringController:unlock', + 'KeyringController:accountRemoved', + 'KeyringController:qrKeyringStateChange', ], - allowedActions: ['KeyringController:getState'], }); this.coreKeyringController = new KeyringController({ @@ -906,9 +929,6 @@ export default class MetamaskController extends EventEmitter { }, ); - this.keyringController = - this.coreKeyringController.getEthKeyringController(); - const getIdentities = () => this.preferencesController.store.getState().identities; @@ -930,8 +950,8 @@ export default class MetamaskController extends EventEmitter { permissionSpecifications: { ...getPermissionSpecifications({ getIdentities, - getAllAccounts: this.keyringController.getAccounts.bind( - this.keyringController, + getAllAccounts: this.coreKeyringController.getAccounts.bind( + this.coreKeyringController, ), captureKeyringTypesWithMissingIdentities: ( identities = {}, @@ -1101,6 +1121,8 @@ export default class MetamaskController extends EventEmitter { 'SnapController:snapInstalled', 'SnapController:snapUpdated', 'SnapController:snapRemoved', + 'SnapController:snapEnabled', + 'SnapController:snapDisabled', ], allowedActions: [ `${this.permissionController.name}:getPermissions`, @@ -1142,7 +1164,12 @@ export default class MetamaskController extends EventEmitter { const detectTokensControllerMessenger = this.controllerMessenger.getRestricted({ name: 'DetectTokensController', - allowedEvents: ['NetworkController:stateChange'], + allowedActions: ['KeyringController:getState'], + allowedEvents: [ + 'NetworkController:stateChange', + 'KeyringController:lock', + 'KeyringController:unlock', + ], }); this.detectTokensController = new DetectTokensController({ messenger: detectTokensControllerMessenger, @@ -1150,7 +1177,6 @@ export default class MetamaskController extends EventEmitter { tokensController: this.tokensController, assetsContractController: this.assetsContractController, network: this.networkController, - keyringMemStore: this.keyringController.memStore, tokenList: this.tokenListController, trackMetaMetricsEvent: this.metaMetricsController.trackEvent.bind( this.metaMetricsController, @@ -1222,8 +1248,8 @@ export default class MetamaskController extends EventEmitter { this.networkController.state.providerConfig.chainId, preferencesStore: this.preferencesController.store, txHistoryLimit: 60, - signTransaction: this.keyringController.signTransaction.bind( - this.keyringController, + signTransaction: this.coreKeyringController.signTransaction.bind( + this.coreKeyringController, ), provider: this.provider, blockTracker: this.blockTracker, @@ -1369,13 +1395,13 @@ export default class MetamaskController extends EventEmitter { this.networkController.lookupNetwork(); this.decryptMessageController = new DecryptMessageController({ getState: this.getState.bind(this), - keyringController: this.keyringController, messenger: this.controllerMessenger.getRestricted({ name: 'DecryptMessageController', allowedActions: [ `${this.approvalController.name}:addRequest`, `${this.approvalController.name}:acceptRequest`, `${this.approvalController.name}:rejectRequest`, + `${this.coreKeyringController.name}:decryptMessage`, ], }), metricsEvent: this.metaMetricsController.trackEvent.bind( @@ -1409,9 +1435,13 @@ export default class MetamaskController extends EventEmitter { this.signatureController = new SignatureController({ messenger: this.controllerMessenger.getRestricted({ name: 'SignatureController', - allowedActions: [`${this.approvalController.name}:addRequest`], + allowedActions: [ + `${this.approvalController.name}:addRequest`, + `${this.coreKeyringController.name}:signMessage`, + `${this.coreKeyringController.name}:signPersonalMessage`, + `${this.coreKeyringController.name}:signTypedMessage`, + ], }), - keyringController: this.keyringController, isEthSignEnabled: () => this.preferencesController.store.getState() ?.disabledRpcMethodPreferences?.eth_sign, @@ -1438,7 +1468,7 @@ export default class MetamaskController extends EventEmitter { ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) this.mmiController = new MMIController({ mmiConfigurationController: this.mmiConfigurationController, - keyringController: this.keyringController, + keyringController: this.coreKeyringController, txController: this.txController, securityProviderRequest: this.securityProviderRequest.bind(this), preferencesController: this.preferencesController, @@ -1507,6 +1537,46 @@ export default class MetamaskController extends EventEmitter { initState.SmartTransactionsController, ); + ///: BEGIN:ONLY_INCLUDE_IN(petnames) + this.nameController = new NameController({ + messenger: this.controllerMessenger.getRestricted({ + name: 'NameController', + allowedActions: [], + }), + providers: [ + new ENSNameProvider({ + reverseLookup: this.ensController.reverseResolveAddress.bind( + this.ensController, + ), + }), + new EtherscanNameProvider({}), + new TokenNameProvider({}), + new LensNameProvider(), + new SnapsNameProvider({ + messenger: this.controllerMessenger.getRestricted({ + name: 'SnapsNameProvider', + allowedActions: [ + 'SnapController:getAll', + 'SnapController:get', + 'SnapController:handleRequest', + 'PermissionController:getState', + ], + }), + }), + ], + state: initState.NameController, + }); + + new AddressBookPetnamesBridge({ + addressBookController: this.addressBookController, + nameController: this.nameController, + messenger: this.controllerMessenger.getRestricted({ + name: 'AddressBookPetnamesBridge', + allowedEvents: ['NameController:stateChange'], + }), + }).init(); + ///: END:ONLY_INCLUDE_IN + this.txController.on('newSwapApproval', (txMeta) => { this.swapsController.setApproveTxId(txMeta.id); }); @@ -1673,7 +1743,7 @@ export default class MetamaskController extends EventEmitter { AppStateController: this.appStateController.store, AppMetadataController: this.appMetadataController.store, TransactionController: this.txController.store, - KeyringController: this.keyringController.store, + KeyringController: this.coreKeyringController, PreferencesController: this.preferencesController.store, MetaMetricsController: this.metaMetricsController.store, AddressBookController: this.addressBookController, @@ -1693,6 +1763,7 @@ export default class MetamaskController extends EventEmitter { NftController: this.nftController, PhishingController: this.phishingController, SelectedNetworkController: this.selectedNetworkController, + LoggingController: this.loggingController, ///: BEGIN:ONLY_INCLUDE_IN(snaps) SnapController: this.snapController, CronjobController: this.cronjobController, @@ -1712,6 +1783,9 @@ export default class MetamaskController extends EventEmitter { ///: BEGIN:ONLY_INCLUDE_IN(blockaid) PPOMController: this.ppomController, ///: END:ONLY_INCLUDE_IN + ///: BEGIN:ONLY_INCLUDE_IN(petnames) + NameController: this.nameController, + ///: END:ONLY_INCLUDE_IN ...resetOnRestartStore, }); @@ -1721,7 +1795,7 @@ export default class MetamaskController extends EventEmitter { AppMetadataController: this.appMetadataController.store, NetworkController: this.networkController, CachedBalancesController: this.cachedBalancesController.store, - KeyringController: this.keyringController.memStore, + KeyringController: this.coreKeyringController, PreferencesController: this.preferencesController.store, MetaMetricsController: this.metaMetricsController.store, AddressBookController: this.addressBookController, @@ -1738,6 +1812,7 @@ export default class MetamaskController extends EventEmitter { SmartTransactionsController: this.smartTransactionsController, NftController: this.nftController, SelectedNetworkController: this.selectedNetworkController, + LoggingController: this.loggingController, ///: BEGIN:ONLY_INCLUDE_IN(snaps) SnapController: this.snapController, CronjobController: this.cronjobController, @@ -1747,13 +1822,15 @@ export default class MetamaskController extends EventEmitter { ///: BEGIN:ONLY_INCLUDE_IN(desktop) DesktopController: this.desktopController.store, ///: END:ONLY_INCLUDE_IN - ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) CustodyController: this.custodyController.store, InstitutionalFeaturesController: this.institutionalFeaturesController.store, MmiConfigurationController: this.mmiConfigurationController.store, ///: END:ONLY_INCLUDE_IN + ///: BEGIN:ONLY_INCLUDE_IN(petnames) + NameController: this.nameController, + ///: END:ONLY_INCLUDE_IN ...resetOnRestartStore, }, controllerMessenger: this.controllerMessenger, @@ -1861,6 +1938,8 @@ export default class MetamaskController extends EventEmitter { ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) /** * Initialize the snap keyring if it is not present. + * + * @returns {SnapKeyring} */ async getSnapKeyring() { let [snapKeyring] = this.coreKeyringController.getKeyringsByType( @@ -2226,11 +2305,14 @@ export default class MetamaskController extends EventEmitter { * @returns {object} status */ getState() { - const { vault } = this.keyringController.store.getState(); + const { vault } = this.coreKeyringController.state; const isInitialized = Boolean(vault); const flatState = this.memStore.getFlatState(); + // The vault should not be exposed to the UI + delete flatState.vault; + return { isInitialized, ...flatState, @@ -2259,6 +2341,7 @@ export default class MetamaskController extends EventEmitter { addressBookController, alertController, appStateController, + coreKeyringController, nftController, nftDetectionController, currencyRateController, @@ -2271,7 +2354,6 @@ export default class MetamaskController extends EventEmitter { onboardingController, permissionController, preferencesController, - qrHardwareKeyring, swapsController, tokensController, smartTransactionsController, @@ -2300,6 +2382,10 @@ export default class MetamaskController extends EventEmitter { preferencesController.setUseMultiAccountBalanceChecker.bind( preferencesController, ), + setUseSafeChainsListValidation: + preferencesController.setUseSafeChainsListValidation.bind( + preferencesController, + ), setUseTokenDetection: preferencesController.setUseTokenDetection.bind( preferencesController, ), @@ -2322,6 +2408,12 @@ export default class MetamaskController extends EventEmitter { preferencesController, ), ///: END:ONLY_INCLUDE_IN + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) + setAddSnapAccountEnabled: + preferencesController.setAddSnapAccountEnabled.bind( + preferencesController, + ), + ///: END:ONLY_INCLUDE_IN setIpfsGateway: preferencesController.setIpfsGateway.bind( preferencesController, ), @@ -2351,12 +2443,15 @@ export default class MetamaskController extends EventEmitter { requestUserApproval: approvalController.addAndShowApprovalRequest.bind(approvalController), - // primary HD keyring management + // primary keyring management addNewAccount: this.addNewAccount.bind(this), verifySeedPhrase: this.verifySeedPhrase.bind(this), resetAccount: this.resetAccount.bind(this), removeAccount: this.removeAccount.bind(this), importAccountWithStrategy: this.importAccountWithStrategy.bind(this), + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) + getAccountsBySnapId: (snapId) => getAccountsBySnapId(this, snapId), + ///: END:ONLY_INCLUDE_IN // hardware wallets connectHardware: this.connectHardware.bind(this), @@ -2372,15 +2467,17 @@ export default class MetamaskController extends EventEmitter { // qr hardware devices submitQRHardwareCryptoHDKey: - qrHardwareKeyring.submitCryptoHDKey.bind(qrHardwareKeyring), + coreKeyringController.submitQRCryptoHDKey.bind(coreKeyringController), submitQRHardwareCryptoAccount: - qrHardwareKeyring.submitCryptoAccount.bind(qrHardwareKeyring), - cancelSyncQRHardware: - qrHardwareKeyring.cancelSync.bind(qrHardwareKeyring), - submitQRHardwareSignature: - qrHardwareKeyring.submitSignature.bind(qrHardwareKeyring), + coreKeyringController.submitQRCryptoAccount.bind(coreKeyringController), + cancelSyncQRHardware: coreKeyringController.cancelQRSynchronization.bind( + coreKeyringController, + ), + submitQRHardwareSignature: coreKeyringController.submitQRSignature.bind( + coreKeyringController, + ), cancelQRHardwareSignRequest: - qrHardwareKeyring.cancelSignRequest.bind(qrHardwareKeyring), + coreKeyringController.cancelQRSignRequest.bind(coreKeyringController), // vault management submitPassword: this.submitPassword.bind(this), @@ -2684,6 +2781,7 @@ export default class MetamaskController extends EventEmitter { ), dismissNotifications: this.dismissNotifications.bind(this), markNotificationsAsRead: this.markNotificationsAsRead.bind(this), + updateCaveat: this.updateCaveat.bind(this), ///: END:ONLY_INCLUDE_IN ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) updateSnapRegistry: this.preferencesController.updateSnapRegistry.bind( @@ -2850,12 +2948,19 @@ export default class MetamaskController extends EventEmitter { // E2E testing throwTestError: this.throwTestError.bind(this), + + ///: BEGIN:ONLY_INCLUDE_IN(petnames) + updateProposedNames: this.nameController.updateProposedNames.bind( + this.nameController, + ), + setName: this.nameController.setName.bind(this.nameController), + ///: END:ONLY_INCLUDE_IN }; } async exportAccount(address, password) { await this.verifyPassword(password); - return this.keyringController.exportAccount(address, password); + return this.coreKeyringController.exportAccount(password, address); } async getTokenStandardAndDetails(address, userAddress, tokenId) { @@ -2952,18 +3057,13 @@ export default class MetamaskController extends EventEmitter { async createNewVaultAndKeychain(password) { const releaseLock = await this.createVaultMutex.acquire(); try { - let vault; - const accounts = await this.keyringController.getAccounts(); - if (accounts.length > 0) { - vault = await this.keyringController.fullUpdate(); - } else { - vault = await this.keyringController.createNewVaultAndKeychain( - password, - ); - const addresses = await this.keyringController.getAccounts(); - this.preferencesController.setAddresses(addresses); - this.selectFirstIdentity(); - } + const vault = await this.coreKeyringController.createNewVaultAndKeychain( + password, + ); + + const accounts = await this.coreKeyringController.getAccounts(); + this.preferencesController.setAddresses(accounts); + this.selectFirstIdentity(); return vault; } finally { @@ -3153,7 +3253,7 @@ export default class MetamaskController extends EventEmitter { } _startUISync() { - // Message startUISync is used in MV3 to start syncing state with UI + // Message startUISync is used to start syncing state with UI // Sending this message after login is completed helps to ensure that incomplete state without // account details are not flushed to UI. this.emit('startUISync'); @@ -3204,7 +3304,7 @@ export default class MetamaskController extends EventEmitter { * @param {string} password - The user's password */ async verifyPassword(password) { - await this.keyringController.verifyPassword(password); + await this.coreKeyringController.verifyPassword(password); } /** @@ -3284,7 +3384,7 @@ export default class MetamaskController extends EventEmitter { keyringName, ); if (!keyring) { - keyring = await this.keyringController.addNewKeyring(keyringName); + keyring = await this.coreKeyringController.addNewKeyring(keyringName); } if (hdPath && keyring.setHdPath) { keyring.setHdPath(hdPath); @@ -3314,7 +3414,7 @@ export default class MetamaskController extends EventEmitter { } /** - * Fetch account list from a trezor device. + * Fetch account list from a hardware device. * * @param deviceName * @param page @@ -3323,6 +3423,7 @@ export default class MetamaskController extends EventEmitter { */ async connectHardware(deviceName, page, hdPath) { const keyring = await this.getKeyringForDevice(deviceName, hdPath); + let accounts = []; switch (page) { case -1: @@ -3337,7 +3438,7 @@ export default class MetamaskController extends EventEmitter { // Merge with existing accounts // and make sure addresses are not repeated - const oldAccounts = await this.keyringController.getAccounts(); + const oldAccounts = await this.coreKeyringController.getAccounts(); const accountsToTrack = [ ...new Set( oldAccounts.concat(accounts.map((a) => a.address.toLowerCase())), @@ -3453,9 +3554,11 @@ export default class MetamaskController extends EventEmitter { const keyring = await this.getKeyringForDevice(deviceName, hdPath); keyring.setAccountToUnlock(index); - const oldAccounts = await this.keyringController.getAccounts(); - const keyState = await this.keyringController.addNewAccount(keyring); - const newAccounts = await this.keyringController.getAccounts(); + const oldAccounts = await this.coreKeyringController.getAccounts(); + const keyState = await this.coreKeyringController.addNewAccountForKeyring( + keyring, + ); + const newAccounts = await this.coreKeyringController.getAccounts(); this.preferencesController.setAddresses(newAccounts); newAccounts.forEach((address) => { if (!oldAccounts.includes(address)) { @@ -3604,7 +3707,7 @@ export default class MetamaskController extends EventEmitter { address, ); // Remove account from the keyring - await this.keyringController.removeAccount(address); + await this.coreKeyringController.removeAccount(address); const updatedKeyringAccounts = keyring ? await keyring.getAccounts() : {}; if (updatedKeyringAccounts?.length === 0) { keyring.destroy?.(); @@ -4254,9 +4357,6 @@ export default class MetamaskController extends EventEmitter { handleMmiDashboardData: this.mmiController.handleMmiDashboardData.bind( this.mmiController, ), - handleMmiOpenSwaps: this.mmiController.handleMmiOpenSwaps.bind( - this.mmiController, - ), handleMmiSetAccountAndNetwork: this.mmiController.setAccountAndNetwork.bind(this.mmiController), handleMmiOpenAddHardwareWallet: @@ -4562,7 +4662,7 @@ export default class MetamaskController extends EventEmitter { * @returns {boolean} Whether the extension is unlocked. */ isUnlocked() { - return this.keyringController.memStore.getState().isUnlocked; + return this.coreKeyringController.state.isUnlocked; } //============================================================================= diff --git a/app/scripts/metamask-controller.test.js b/app/scripts/metamask-controller.test.js index c8e6c070e14d..40ad6d240527 100644 --- a/app/scripts/metamask-controller.test.js +++ b/app/scripts/metamask-controller.test.js @@ -318,13 +318,16 @@ describe('MetaMaskController', () => { }); jest.spyOn( - metamaskController.keyringController, + metamaskController.coreKeyringController, 'createNewVaultAndKeychain', ); jest.spyOn( metamaskController.coreKeyringController, 'createNewVaultAndRestore', ); + jest + .spyOn(metamaskController.preferencesController, 'removeAddress') + .mockImplementation((address) => address); }); describe('should reset states on first time profile load', () => { @@ -363,7 +366,7 @@ describe('MetaMaskController', () => { it('adds 1 account', async () => { const keyringAccounts = - await metamaskController.keyringController.getAccounts(); + await metamaskController.coreKeyringController.getAccounts(); expect(keyringAccounts[keyringAccounts.length - 1]).toStrictEqual( '0xe18035bf8712672935fdb4e5e431b1a0183d2dfc', ); @@ -413,15 +416,16 @@ describe('MetaMaskController', () => { describe('#createNewVaultAndKeychain', () => { it('can only create new vault on keyringController once', async () => { jest.spyOn(metamaskController, 'selectFirstIdentity').mockReturnValue(); - const password = 'a-fake-password'; - await metamaskController.createNewVaultAndKeychain(password); - await metamaskController.createNewVaultAndKeychain(password); + const vault1 = await metamaskController.createNewVaultAndKeychain( + password, + ); + const vault2 = await metamaskController.createNewVaultAndKeychain( + password, + ); - expect( - metamaskController.keyringController.createNewVaultAndKeychain, - ).toHaveBeenCalledTimes(1); + expect(vault1).toStrictEqual(vault2); }); }); @@ -622,7 +626,7 @@ describe('MetaMaskController', () => { }); it('should add the Trezor Hardware keyring', async () => { - jest.spyOn(metamaskController.keyringController, 'addNewKeyring'); + jest.spyOn(metamaskController.coreKeyringController, 'addNewKeyring'); await metamaskController .connectHardware(HardwareDeviceNames.trezor, 0) .catch(() => null); @@ -631,13 +635,13 @@ describe('MetaMaskController', () => { KeyringType.trezor, ); expect( - metamaskController.keyringController.addNewKeyring, + metamaskController.coreKeyringController.addNewKeyring, ).toHaveBeenCalledWith(KeyringType.trezor); expect(keyrings).toHaveLength(1); }); it('should add the Ledger Hardware keyring', async () => { - jest.spyOn(metamaskController.keyringController, 'addNewKeyring'); + jest.spyOn(metamaskController.coreKeyringController, 'addNewKeyring'); await metamaskController .connectHardware(HardwareDeviceNames.ledger, 0) .catch(() => null); @@ -646,7 +650,7 @@ describe('MetaMaskController', () => { KeyringType.ledger, ); expect( - metamaskController.keyringController.addNewKeyring, + metamaskController.coreKeyringController.addNewKeyring, ).toHaveBeenCalledWith(KeyringType.ledger); expect(keyrings).toHaveLength(1); }); @@ -729,13 +733,20 @@ describe('MetaMaskController', () => { describe('unlockHardwareWalletAccount', () => { const accountToUnlock = 10; beforeEach(async () => { + await metamaskController.coreKeyringController.createNewVaultAndRestore( + 'password', + TEST_SEED, + ); jest.spyOn(window, 'open').mockReturnValue(); jest - .spyOn(metamaskController.keyringController, 'addNewAccount') + .spyOn( + metamaskController.coreKeyringController, + 'addNewAccountForKeyring', + ) .mockReturnValue('0x123'); jest - .spyOn(metamaskController.keyringController, 'getAccounts') + .spyOn(metamaskController.coreKeyringController, 'getAccounts') .mockResolvedValueOnce(['0x1']) .mockResolvedValueOnce(['0x2']) .mockResolvedValueOnce(['0x3']); @@ -749,9 +760,6 @@ describe('MetaMaskController', () => { .spyOn(metamaskController.preferencesController, 'setAccountLabel') .mockReturnValue(); - await metamaskController - .connectHardware(HardwareDeviceNames.trezor, 0, `m/44'/1'/0'/0`) - .catch(() => null); await metamaskController.unlockHardwareWalletAccount( accountToUnlock, HardwareDeviceNames.trezor, @@ -769,14 +777,14 @@ describe('MetaMaskController', () => { it('should call keyringController.addNewAccount', async () => { expect( - metamaskController.keyringController.addNewAccount, + metamaskController.coreKeyringController.addNewAccountForKeyring, ).toHaveBeenCalledTimes(1); }); it('should call keyringController.getAccounts', async () => { expect( - metamaskController.keyringController.getAccounts, - ).toHaveBeenCalledTimes(3); + metamaskController.coreKeyringController.getAccounts, + ).toHaveBeenCalledTimes(2); }); it('should call preferencesController.setAddresses', async () => { @@ -817,7 +825,7 @@ describe('MetaMaskController', () => { await metamaskController.createNewVaultAndKeychain('password'); await metamaskController.addNewAccount(1); const getAccounts = - await metamaskController.keyringController.getAccounts(); + await metamaskController.coreKeyringController.getAccounts(); expect(getAccounts).toHaveLength(2); }); }); @@ -876,7 +884,7 @@ describe('MetaMaskController', () => { destroy: jest.fn(), }; jest - .spyOn(metamaskController.keyringController, 'removeAccount') + .spyOn(metamaskController.coreKeyringController, 'removeAccount') .mockReturnValue(); jest .spyOn(metamaskController, 'removeAllAccountPermissions') @@ -894,7 +902,7 @@ describe('MetaMaskController', () => { it('should call keyringController.removeAccount', async () => { expect( - metamaskController.keyringController.removeAccount, + metamaskController.coreKeyringController.removeAccount, ).toHaveBeenCalledWith(addressToRemove); }); it('should call metamaskController.removeAllAccountPermissions', async () => { diff --git a/app/scripts/migrations/098.test.ts b/app/scripts/migrations/098.test.ts new file mode 100644 index 000000000000..9675870f2c40 --- /dev/null +++ b/app/scripts/migrations/098.test.ts @@ -0,0 +1,117 @@ +import { migrate, version } from './098'; + +const oldVersion = 97; +describe('migration #98', () => { + it('updates the version metadata', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: {}, + }; + + const newStorage = await migrate(oldStorage); + + expect(newStorage.meta).toStrictEqual({ version }); + }); + + it('handles missing TransactionController', async () => { + const oldState = { + OtherController: {}, + }; + + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: oldState, + }); + + expect(transformedState.data).toEqual(oldState); + }); + + it('handles empty transactions', async () => { + const oldState = { + TransactionController: { + transactions: {}, + }, + }; + + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: oldState, + }); + + expect(transformedState.data).toEqual(oldState); + }); + + it('handles missing state', async () => { + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: {}, + }); + + expect(transformedState.data).toEqual({}); + }); + + it('adds verifiedOnBlockchain in transaction based on the presence of txReceipt', async () => { + const oldState = { + TransactionController: { + transactions: { + tx1: { + to: '0x9ef57335bc7d5b6cbc06dca6064a604b75e09ace', + txReceipt: { + blockHash: + '0xafa4e1fd95e429d9c6e6c7c1d282b2bd0bbeb50d0a68743e9392b9c95a06e2eb', + }, + otherProp: 'value', + }, + tx2: { + to: '0x9ef57335bc7d5b6cbc06dca6064a604b75e09ace', + otherProp: 'value', + }, + tx3: { + to: '0x9ef57335bc7d5b6cbc06dca6064a604b75e09ace', + txReceipt: { + blockHash: + '0xafa4e1fd95e429d9c6e6c7c1d282b2bd0bbeb50d0a68743e9392b9c95a06e2eb', + }, + otherProp: 'value', + }, + }, + }, + }; + const oldStorage = { + meta: { version: oldVersion }, + data: oldState, + }; + + const newStorage = await migrate(oldStorage); + + expect(newStorage.data).toEqual({ + TransactionController: { + transactions: { + tx1: { + to: '0x9ef57335bc7d5b6cbc06dca6064a604b75e09ace', + txReceipt: { + blockHash: + '0xafa4e1fd95e429d9c6e6c7c1d282b2bd0bbeb50d0a68743e9392b9c95a06e2eb', + }, + otherProp: 'value', + verifiedOnBlockchain: true, + }, + tx2: { + to: '0x9ef57335bc7d5b6cbc06dca6064a604b75e09ace', + otherProp: 'value', + verifiedOnBlockchain: false, + }, + tx3: { + to: '0x9ef57335bc7d5b6cbc06dca6064a604b75e09ace', + txReceipt: { + blockHash: + '0xafa4e1fd95e429d9c6e6c7c1d282b2bd0bbeb50d0a68743e9392b9c95a06e2eb', + }, + otherProp: 'value', + verifiedOnBlockchain: true, + }, + }, + }, + }); + }); +}); diff --git a/app/scripts/migrations/098.ts b/app/scripts/migrations/098.ts new file mode 100644 index 000000000000..3085827b4c6a --- /dev/null +++ b/app/scripts/migrations/098.ts @@ -0,0 +1,52 @@ +import { cloneDeep, isEmpty } from 'lodash'; + +type VersionedData = { + meta: { version: number }; + data: Record; +}; + +export const version = 98; // Increment the version number + +/** + * Add `verifiedOnBlockchain` property to transactions based on the presence of `txReceipt` + * + * @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: VersionedData, +): Promise { + const versionedData = cloneDeep(originalVersionedData); + versionedData.meta.version = version; + transformState(versionedData.data); + return versionedData; +} + +function transformState(state: Record) { + const transactionControllerState = state?.TransactionController || {}; + const transactions = transactionControllerState?.transactions || {}; + + if (isEmpty(transactions)) { + return; + } + + const newTxs = Object.keys(transactions).reduce((txs, txId) => { + const transaction = transactions[txId]; + + // Add the `verifiedOnBlockchain` property based on the presence of `txReceipt` + transaction.verifiedOnBlockchain = Boolean(transaction.txReceipt); + + return { + ...txs, + [txId]: transaction, + }; + }, {}); + + state.TransactionController = { + ...transactionControllerState, + transactions: newTxs, + }; +} diff --git a/app/scripts/migrations/099.test.ts b/app/scripts/migrations/099.test.ts new file mode 100644 index 000000000000..1feba98e6fa3 --- /dev/null +++ b/app/scripts/migrations/099.test.ts @@ -0,0 +1,91 @@ +import { migrate, version } from './099'; + +const oldVersion = 98; +describe('migration #99', () => { + it('updates the version metadata', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: {}, + }; + + const newStorage = await migrate(oldStorage); + + expect(newStorage.meta).toStrictEqual({ version }); + }); + + it('handles missing TransactionController', async () => { + const oldState = { + OtherController: {}, + }; + + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: oldState, + }); + + expect(transformedState.data).toEqual(oldState); + }); + + it('handles empty transactions', async () => { + const oldState = { + TransactionController: { + transactions: {}, + }, + }; + + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: oldState, + }); + + expect(transformedState.data).toEqual(oldState); + }); + + it('handles missing state', async () => { + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: {}, + }); + + expect(transformedState.data).toEqual({}); + }); + + it('updates transaction ids', async () => { + const oldState = { + TransactionController: { + transactions: { + 1: { + id: 1, + otherProp: 1, + }, + 2: { + id: 2, + otherProp: 2, + }, + }, + }, + }; + const oldStorage = { + meta: { version: oldVersion }, + data: oldState, + }; + + const newStorage = await migrate(oldStorage); + + const migratedTransactions = (newStorage.data.TransactionController as any) + .transactions; + + const [firstTxId, secondTxId] = Object.keys(migratedTransactions); + + expect(migratedTransactions).toStrictEqual({ + [firstTxId]: { + id: firstTxId, + otherProp: 1, + }, + [secondTxId]: { + id: secondTxId, + otherProp: 2, + }, + }); + }); +}); diff --git a/app/scripts/migrations/099.ts b/app/scripts/migrations/099.ts new file mode 100644 index 000000000000..9464d19a64df --- /dev/null +++ b/app/scripts/migrations/099.ts @@ -0,0 +1,56 @@ +import { cloneDeep, isEmpty } from 'lodash'; +import { v1 as uuid } from 'uuid'; + +type VersionedData = { + meta: { version: number }; + data: Record; +}; + +export const version = 99; + +/** + * The core TransactionController uses strings for transaction IDs, specifically UUIDs generated by the uuid package. + * For the sake of standardisation and minimising code maintenance, the use of UUIDs is preferred. + * This migration updates the transaction IDs to UUIDs. + * + * @param originalVersionedData + */ +export async function migrate( + originalVersionedData: VersionedData, +): Promise { + const versionedData = cloneDeep(originalVersionedData); + versionedData.meta.version = version; + transformState(versionedData.data); + return versionedData; +} + +function transformState(state: Record) { + const transactionControllerState = state?.TransactionController || {}; + const transactions = transactionControllerState?.transactions || {}; + + if (isEmpty(transactions)) { + return; + } + + const newTxs = Object.keys(transactions).reduce( + (txs: { [key: string]: any }, oldTransactionId) => { + // Clone the transaction + const transaction = cloneDeep(transactions[oldTransactionId]); + + // Assign a new id to the transaction + const newTransactionID = uuid(); + transaction.id = newTransactionID; + + return { + ...txs, + [newTransactionID]: transaction, + }; + }, + {}, + ); + + state.TransactionController = { + ...transactionControllerState, + transactions: newTxs, + }; +} diff --git a/app/scripts/migrations/100.test.ts b/app/scripts/migrations/100.test.ts new file mode 100644 index 000000000000..15d52131b153 --- /dev/null +++ b/app/scripts/migrations/100.test.ts @@ -0,0 +1,259 @@ +import { migrate, version } from './100'; + +const oldVersion = 99; + +describe('migration #100', () => { + it('updates the version metadata', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: {}, + }; + + const newStorage = await migrate(oldStorage); + + expect(newStorage.meta).toStrictEqual({ version }); + }); + + it('does nothing if no address book state', async () => { + const oldState = { + OtherController: {}, + }; + + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: oldState, + }); + + expect(transformedState.data).toEqual(oldState); + }); + + it('does nothing if no address book entries', async () => { + const oldState = { + OtherController: {}, + AddressBookController: { + addressBook: {}, + }, + }; + + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: oldState, + }); + + expect(transformedState.data).toEqual(oldState); + }); + + it('adds name entries', async () => { + const oldState = { + OtherController: {}, + AddressBookController: { + addressBook: { + '0x1': { + '0xc0ffee254729296a45a3885639AC7E10F9d54979': { + name: 'TestName1', + isEns: false, + }, + '0xc0ffee254729296a45a3885639AC7E10F9d54978': { + name: 'TestName2', + isEns: true, + }, + }, + '0x2': { + '0xc0ffee254729296a45a3885639AC7E10F9d54977': { + name: 'TestName3', + isEns: false, + }, + '0xc0ffee254729296a45a3885639AC7E10F9d54978': { + name: 'TestName4', + isEns: false, + }, + }, + }, + }, + }; + + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: oldState, + }); + + expect(transformedState.data).toEqual({ + ...oldState, + NameController: { + names: { + ethereumAddress: { + '0xc0ffee254729296a45a3885639ac7e10f9d54979': { + '0x1': { + name: 'TestName1', + sourceId: null, + proposedNames: {}, + }, + }, + '0xc0ffee254729296a45a3885639ac7e10f9d54978': { + '0x1': { + name: 'TestName2', + sourceId: 'ens', + proposedNames: {}, + }, + '0x2': { + name: 'TestName4', + sourceId: null, + proposedNames: {}, + }, + }, + '0xc0ffee254729296a45a3885639ac7e10f9d54977': { + '0x2': { + name: 'TestName3', + sourceId: null, + proposedNames: {}, + }, + }, + }, + }, + }, + }); + }); + + it('keeps existing name entries', async () => { + const oldState = { + OtherController: {}, + AddressBookController: { + addressBook: { + '0x1': { + '0xc0ffee254729296a45a3885639AC7E10F9d54979': { + name: 'TestName1', + isEns: false, + }, + }, + }, + }, + NameController: { + names: { + ethereumAddress: { + '0xc0ffee254729296a45a3885639ac7e10f9d54978': { + '0x1': { + name: 'TestName2', + sourceId: 'ens', + proposedNames: {}, + }, + }, + }, + }, + }, + }; + + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: oldState, + }); + + expect(transformedState.data).toEqual({ + ...oldState, + NameController: { + names: { + ethereumAddress: { + '0xc0ffee254729296a45a3885639ac7e10f9d54979': { + '0x1': { + name: 'TestName1', + sourceId: null, + proposedNames: {}, + }, + }, + '0xc0ffee254729296a45a3885639ac7e10f9d54978': { + '0x1': { + name: 'TestName2', + sourceId: 'ens', + proposedNames: {}, + }, + }, + }, + }, + }, + }); + }); + + it('ignores address book entry if existing petname', async () => { + const oldState = { + OtherController: {}, + AddressBookController: { + addressBook: { + '0x1': { + '0xc0ffee254729296a45a3885639AC7E10F9d54979': { + name: 'TestName1', + isEns: false, + }, + }, + }, + }, + NameController: { + names: { + ethereumAddress: { + '0xc0ffee254729296a45a3885639ac7e10f9d54979': { + '0x1': { + name: 'TestName2', + sourceId: 'ens', + proposedNames: {}, + }, + }, + }, + }, + }, + }; + + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: oldState, + }); + + expect(transformedState.data).toEqual({ + ...oldState, + NameController: { + names: { + ethereumAddress: { + '0xc0ffee254729296a45a3885639ac7e10f9d54979': { + '0x1': { + name: 'TestName2', + sourceId: 'ens', + proposedNames: {}, + }, + }, + }, + }, + }, + }); + }); + + it('ignores address book entry if no name or address', async () => { + const oldState = { + OtherController: {}, + AddressBookController: { + addressBook: { + '0x1': { + '': { + name: 'TestName1', + isEns: false, + }, + '0xc0ffee254729296a45a3885639AC7E10F9d54979': { + name: '', + isEns: false, + }, + }, + }, + }, + }; + + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: oldState, + }); + + expect(transformedState.data).toEqual({ + ...oldState, + NameController: { + names: { + ethereumAddress: {}, + }, + }, + }); + }); +}); diff --git a/app/scripts/migrations/100.ts b/app/scripts/migrations/100.ts new file mode 100644 index 000000000000..c9b4a99afceb --- /dev/null +++ b/app/scripts/migrations/100.ts @@ -0,0 +1,70 @@ +import { cloneDeep, isEmpty } from 'lodash'; + +type VersionedData = { + meta: { version: number }; + data: Record; +}; + +export const version = 100; + +/** + * Copy all entries from AddressBookController to NameController. + * + * @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: VersionedData, +): Promise { + const versionedData = cloneDeep(originalVersionedData); + versionedData.meta.version = version; + transformState(versionedData.data); + return versionedData; +} + +function transformState(state: Record) { + const addressBook = state?.AddressBookController?.addressBook ?? {}; + const names = state?.NameController?.names?.ethereumAddress ?? {}; + + if (isEmpty(Object.keys(addressBook))) { + return; + } + + for (const chainId of Object.keys(addressBook)) { + const chainAddressBook = addressBook[chainId]; + + for (const address of Object.keys(chainAddressBook)) { + const addressBookEntry = chainAddressBook[address]; + const normalizedAddress = address.toLowerCase(); + const nameEntry = names[normalizedAddress] ?? {}; + const nameChainEntry = nameEntry[chainId] ?? {}; + + // Ignore if petname already set, or if address book entry is missing name or address. + if ( + nameChainEntry.name?.length || + !addressBookEntry.name?.length || + !normalizedAddress?.length + ) { + continue; + } + + names[normalizedAddress] = nameEntry; + + nameEntry[chainId] = { + name: addressBookEntry.name, + sourceId: addressBookEntry.isEns ? 'ens' : null, + proposedNames: {}, + }; + } + } + + state.NameController = { + ...state.NameController, + names: { + ethereumAddress: names, + }, + }; +} diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js index c8b27ac352b0..c163d18c03c4 100644 --- a/app/scripts/migrations/index.js +++ b/app/scripts/migrations/index.js @@ -104,6 +104,9 @@ import * as m094 from './094'; import * as m095 from './095'; import * as m096 from './096'; import * as m097 from './097'; +import * as m098 from './098'; +import * as m099 from './099'; +import * as m100 from './100'; const migrations = [ m002, @@ -205,5 +208,8 @@ const migrations = [ m095, m096, m097, + m098, + m099, + m100, ]; export default migrations; diff --git a/app/scripts/platforms/extension.test.js b/app/scripts/platforms/extension.test.js index 27cc0e8b9052..1016efef21a7 100644 --- a/app/scripts/platforms/extension.test.js +++ b/app/scripts/platforms/extension.test.js @@ -10,6 +10,9 @@ jest.mock('webextension-polyfill', () => { getManifest: jest.fn(), getURL: jest.fn(), }, + notifications: { + create: jest.fn(), + }, }; }); @@ -121,4 +124,64 @@ describe('extension platform', () => { ).toStrictEqual(`${TEST_URL}?${QUERY_STRING}`); }); }); + + describe('_showFailedTransaction', () => { + it('should show failed transaction with nonce', async () => { + const txMeta = { + txParams: { nonce: '0x1' }, + err: { message: 'Error message' }, + }; + const extensionPlatform = new ExtensionPlatform(); + const showNotificationSpy = jest.spyOn( + extensionPlatform, + '_showNotification', + ); + + await extensionPlatform._showFailedTransaction(txMeta); + + expect(showNotificationSpy).toHaveBeenCalledWith( + 'Failed transaction', + `Transaction 1 failed! ${txMeta.err.message}`, + ); + }); + + it('should show failed transaction with errorMessage', async () => { + const errorMessage = 'Test error message'; + const txMeta = { + txParams: { nonce: '0x1' }, + err: { message: 'Error message' }, + }; + const extensionPlatform = new ExtensionPlatform(); + const showNotificationSpy = jest.spyOn( + extensionPlatform, + '_showNotification', + ); + + await extensionPlatform._showFailedTransaction(txMeta, errorMessage); + + expect(showNotificationSpy).toHaveBeenCalledWith( + 'Failed transaction', + `Transaction 1 failed! ${errorMessage}`, + ); + }); + + it('should show failed transaction without nonce', async () => { + const txMeta = { + txParams: {}, + err: { message: 'Error message' }, + }; + const extensionPlatform = new ExtensionPlatform(); + const showNotificationSpy = jest.spyOn( + extensionPlatform, + '_showNotification', + ); + + await extensionPlatform._showFailedTransaction(txMeta); + + expect(showNotificationSpy).toHaveBeenCalledWith( + 'Failed transaction', + `Transaction failed! ${txMeta.err.message}`, + ); + }); + }); }); diff --git a/app/scripts/ui.js b/app/scripts/ui.js index 570b02c0ba3b..df85aa2f957d 100644 --- a/app/scripts/ui.js +++ b/app/scripts/ui.js @@ -257,7 +257,13 @@ async function start() { extensionPort.onMessage.addListener(messageListener); extensionPort.onDisconnect.addListener(resetExtensionStreamAndListeners); } else { - initializeUiWithTab(activeTab); + const messageListener = async (message) => { + if (message?.data?.method === 'startUISync') { + initializeUiWithTab(activeTab); + extensionPort.onMessage.removeListener(messageListener); + } + }; + extensionPort.onMessage.addListener(messageListener); } function initializeUiWithTab(tab) { diff --git a/builds.yml b/builds.yml index 8be1a0d482a4..c096b51509ec 100644 --- a/builds.yml +++ b/builds.yml @@ -25,7 +25,7 @@ buildTypes: - SEGMENT_WRITE_KEY_REF: SEGMENT_PROD_WRITE_KEY - ALLOW_LOCAL_SNAPS: false - REQUIRE_SNAPS_ALLOWLIST: true - - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.consensys.io/1.0.2/index.html + - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.consensys.io/2.0.1/index.html # Main build uses the default browser manifest manifestOverrides: false @@ -52,12 +52,13 @@ buildTypes: - build-flask - keyring-snaps - blockaid + - petnames env: - INFURA_FLASK_PROJECT_ID - SEGMENT_FLASK_WRITE_KEY - ALLOW_LOCAL_SNAPS: true - REQUIRE_SNAPS_ALLOWLIST: false - - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.consensys.io/0.38.3-flask.1/index.html + - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.consensys.io/2.0.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 @@ -76,7 +77,7 @@ buildTypes: - SEGMENT_FLASK_WRITE_KEY - ALLOW_LOCAL_SNAPS: true - REQUIRE_SNAPS_ALLOWLIST: false - - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.consensys.io/0.38.3-flask.1/index.html + - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.consensys.io/2.0.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 @@ -95,7 +96,7 @@ buildTypes: - SEGMENT_WRITE_KEY_REF: SEGMENT_MMI_WRITE_KEY - ALLOW_LOCAL_SNAPS: false - REQUIRE_SNAPS_ALLOWLIST: true - - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.consensys.io/1.0.2/index.html + - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.consensys.io/2.0.1/index.html - MMI_CONFIGURATION_SERVICE_URL: https://configuration.metamask-institutional.io/v2/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 @@ -129,6 +130,7 @@ features: env: - BLOCKAID_FILE_CDN: static.metafi.codefi.network/api/v1/confirmations/ppom - BLOCKAID_PUBLIC_KEY: 066ad3e8af5583385e312c156d238055215d5f25247c1e91055afa756cb98a88 + petnames: ### # Build Type code extensions. Things like different support links, warning pages, banners diff --git a/development/README.md b/development/README.md index 560defc57ad2..d00880addb83 100644 --- a/development/README.md +++ b/development/README.md @@ -76,24 +76,26 @@ To debug in a production Sentry environment: Errors reported whilst using the extension will be displayed in Sentry's `Issues` page. +To debug in test build we need to comment out the IF condition https://github.com/MetaMask/metamask-extension/blob/develop/app/scripts/lib/setupSentry.js#L392 + ## Source Maps ### Debugging production builds using Source Maps To unbundle the extensions compiled and minified JavaScript using Source Maps: -- Open Chrome DevTools to inspect the `background.html` or `home.html` view +- Open Chrome DevTools to inspect the `background.html` or `home.html` view - Click on the `Sources` tab in Chrome DevTools - In the Sources tab, click on the `Page` panel - Expand the file directory in the Page panel until you see the source files you're after -- Select a source file in the Page panel +- Select a source file in the Page panel ``` chrome-extension://{EXTENSION_ID}/common-0.js ``` - Double click the source file to open it in the Workspace - Right click in the body of the source file and select `Add source map...` - Enter the path to the corresponding source map file, and Click `Add` -``` +``` file:///{LOCAL_FILE_SYSTEM}/metamask-extension/dist/sourcemaps/common-0.js.map ``` - Repeat the steps above as necessary adding all the relevant source map files diff --git a/development/build/scripts.js b/development/build/scripts.js index ccd344f3eda7..fa50a925c09f 100644 --- a/development/build/scripts.js +++ b/development/build/scripts.js @@ -27,7 +27,6 @@ const Sqrl = require('squirrelly'); const lavapack = require('@lavamoat/lavapack'); const lavamoatBrowserify = require('lavamoat-browserify'); const terser = require('terser'); -const moduleResolver = require('babel-plugin-module-resolver'); const bifyModuleGroups = require('bify-module-groups'); @@ -714,26 +713,27 @@ function createFactoredBuild({ case 'ui': { renderHtmlFile({ htmlName: 'popup', - groupSet, - commonSet, browserPlatforms, applyLavaMoat, }); renderHtmlFile({ htmlName: 'notification', - groupSet, - commonSet, browserPlatforms, applyLavaMoat, isMMI: buildType === 'mmi', }); renderHtmlFile({ htmlName: 'home', + browserPlatforms, + applyLavaMoat, + isMMI: buildType === 'mmi', + }); + renderJavaScriptLoader({ groupSet, commonSet, browserPlatforms, applyLavaMoat, - isMMI: buildType === 'mmi', + destinationFileName: 'load-app.js', }); break; } @@ -745,6 +745,13 @@ function createFactoredBuild({ browserPlatforms, applyLavaMoat, }); + renderJavaScriptLoader({ + groupSet, + commonSet, + browserPlatforms, + applyLavaMoat, + destinationFileName: 'load-background.js', + }); if (process.env.ENABLE_MV3) { const jsBundles = [ ...commonSet.values(), @@ -923,9 +930,6 @@ function setupBundlerDefaults( const { bundlerOpts } = buildConfiguration; const extensions = ['.js', '.ts', '.tsx']; - const isSnapsFlask = - features.active.has('snaps') && features.active.has('build-flask'); - Object.assign(bundlerOpts, { // Source transforms transform: [ @@ -937,22 +941,6 @@ function setupBundlerDefaults( // Run TypeScript files through Babel { extensions, - plugins: isSnapsFlask - ? [ - [ - moduleResolver, - { - alias: { - '@metamask/snaps-controllers': - '@metamask/snaps-controllers-flask', - '@metamask/snaps-ui': '@metamask/snaps-ui-flask', - '@metamask/snaps-utils': '@metamask/snaps-utils-flask', - '@metamask/rpc-methods': '@metamask/rpc-methods-flask', - }, - }, - ], - ] - : [], }, ], // Inline `fs.readFileSync` files @@ -1210,29 +1198,65 @@ async function setEnvironmentVariables({ }); } -function renderHtmlFile({ - htmlName, +function renderJavaScriptLoader({ groupSet, commonSet, browserPlatforms, applyLavaMoat, - isMMI, + destinationFileName, }) { if (applyLavaMoat === undefined) { throw new Error( 'build/scripts/renderHtmlFile - must specify "applyLavaMoat" option', ); } - const htmlFilePath = `./app/${htmlName}.html`; - const htmlTemplate = readFileSync(htmlFilePath, 'utf8'); + const jsBundles = [...commonSet.values(), ...groupSet.values()].map( (label) => `./${label}.js`, ); - const htmlOutput = Sqrl.render(htmlTemplate, { - jsBundles, - applyLavaMoat, - isMMI, + + const securityScripts = applyLavaMoat + ? ['./runtime-lavamoat.js', './lockdown-more.js', './policy-load.js'] + : [ + './lockdown-install.js', + './lockdown-run.js', + './lockdown-more.js', + './runtime-cjs.js', + ]; + + const requiredScripts = [ + './snow.js', + './use-snow.js', + './globalthis.js', + './sentry-install.js', + ...securityScripts, + ...jsBundles, + ]; + + browserPlatforms.forEach((platform) => { + const appLoadFilePath = './app/scripts/load-app.js'; + const appLoadContents = readFileSync(appLoadFilePath, 'utf8'); + + const scriptDest = `./dist/${platform}/${destinationFileName}`; + const scriptOutput = appLoadContents.replace( + '/* SCRIPTS */', + `...${JSON.stringify(requiredScripts)}`, + ); + + writeFileSync(scriptDest, scriptOutput); }); +} + +function renderHtmlFile({ htmlName, browserPlatforms, applyLavaMoat, isMMI }) { + if (applyLavaMoat === undefined) { + throw new Error( + 'build/scripts/renderHtmlFile - must specify "applyLavaMoat" option', + ); + } + const htmlFilePath = `./app/${htmlName}.html`; + const htmlTemplate = readFileSync(htmlFilePath, 'utf8'); + + const htmlOutput = Sqrl.render(htmlTemplate, { isMMI }); browserPlatforms.forEach((platform) => { const dest = `./dist/${platform}/${htmlName}.html`; // we dont have a way of creating async events atm diff --git a/development/build/static.js b/development/build/static.js index 940aea6e932b..82bd91483472 100644 --- a/development/build/static.js +++ b/development/build/static.js @@ -178,6 +178,10 @@ function getCopyTargets( src: './app/scripts/init-globals.js', dest: 'init-globals.js', }, + { + src: './app/scripts/load-app.js', + dest: 'load-app.js', + }, { src: shouldIncludeLockdown ? `./app/scripts/lockdown-run.js` diff --git a/development/fitness-functions/common/shared.ts b/development/fitness-functions/common/shared.ts index e24c8cf01c3b..f7f22101378d 100644 --- a/development/fitness-functions/common/shared.ts +++ b/development/fitness-functions/common/shared.ts @@ -32,6 +32,14 @@ function filterDiffByFilePath(diff: string, regex: string): string { return filteredDiff; } +// This function returns all lines that are additions to files that are being +// modified but that previously already existed. Example: +// diff --git a/test.js b/test.js +// index 0000000000..872e0d8293 +// --- /dev/null +// +++ b/test.js +// @@ -0,0 +1 @@ +// +new line change to a previously existing file function filterDiffLineAdditions(diff: string): string { const diffLines = diff.split('\n'); @@ -44,6 +52,15 @@ function filterDiffLineAdditions(diff: string): string { return diffAdditionLines.join('/n'); } +// This function returns all lines that are additions to new files that are being +// created. Example: +// diff --git a/test.js b/test.js +// new file mode 100644 +// index 0000000000..872e0d8293 +// --- /dev/null +// +++ b/test.js +// @@ -0,0 +1 @@ +// +new line change as the new file is created function filterDiffFileCreations(diff: string): string { // split by `diff --git` and remove the first element which is empty const diffBlocks = diff.split(`diff --git`).slice(1); @@ -91,7 +108,7 @@ function hasNumberOfCodeBlocksIncreased( export { filterDiffByFilePath, - filterDiffLineAdditions, filterDiffFileCreations, + filterDiffLineAdditions, hasNumberOfCodeBlocksIncreased, }; diff --git a/development/fitness-functions/rules/sinon-assert-syntax.test.ts b/development/fitness-functions/rules/sinon-assert-syntax.test.ts index ea403d4a0fe9..6ae70bb139ba 100644 --- a/development/fitness-functions/rules/sinon-assert-syntax.test.ts +++ b/development/fitness-functions/rules/sinon-assert-syntax.test.ts @@ -1,4 +1,7 @@ -import { generateModifyFilesDiff } from '../common/test-data'; +import { + generateCreateFileDiff, + generateModifyFilesDiff, +} from '../common/test-data'; import { preventSinonAssertSyntax } from './sinon-assert-syntax'; describe('preventSinonAssertSyntax()', (): void => { @@ -10,7 +13,7 @@ describe('preventSinonAssertSyntax()', (): void => { expect(hasRulePassed).toBe(true); }); - it('should not pass when receiving a diff with one of the blocked expressions', (): void => { + it('should pass when receiving a diff with an existing file with one of the blocked expressions', (): void => { const infringingExpression = 'assert.equal'; const testDiff = [ generateModifyFilesDiff('new-file.ts', 'foo', 'bar'), @@ -24,6 +27,22 @@ describe('preventSinonAssertSyntax()', (): void => { const hasRulePassed = preventSinonAssertSyntax(testDiff); + expect(hasRulePassed).toBe(true); + }); + + it('should not pass when receiving a diff with a new file with one of the blocked expressions', (): void => { + const infringingExpression = 'assert.equal'; + const testDiff = [ + generateModifyFilesDiff('new-file.ts', 'foo', 'bar'), + generateCreateFileDiff('old-file.js', 'pong'), + generateCreateFileDiff( + 'test.js', + `yada yada ${infringingExpression} yada yada`, + ), + ].join(''); + + const hasRulePassed = preventSinonAssertSyntax(testDiff); + expect(hasRulePassed).toBe(false); }); }); diff --git a/development/fitness-functions/rules/sinon-assert-syntax.ts b/development/fitness-functions/rules/sinon-assert-syntax.ts index 57551f929249..2cc56ec37762 100644 --- a/development/fitness-functions/rules/sinon-assert-syntax.ts +++ b/development/fitness-functions/rules/sinon-assert-syntax.ts @@ -1,7 +1,7 @@ import { EXCLUDE_E2E_TESTS_REGEX } from '../common/constants'; import { - filterDiffLineAdditions, filterDiffByFilePath, + filterDiffFileCreations, hasNumberOfCodeBlocksIncreased, } from '../common/shared'; @@ -16,7 +16,7 @@ const codeBlocks = [ function preventSinonAssertSyntax(diff: string): boolean { const diffByFilePath = filterDiffByFilePath(diff, EXCLUDE_E2E_TESTS_REGEX); - const diffAdditions = filterDiffLineAdditions(diffByFilePath); + const diffAdditions = filterDiffFileCreations(diffByFilePath); const hashmap = hasNumberOfCodeBlocksIncreased(diffAdditions, codeBlocks); const haveOccurencesOfAtLeastOneCodeBlockIncreased = diff --git a/development/metamaskbot-build-announce.js b/development/metamaskbot-build-announce.js index 16cbef70513e..e49bd848ca55 100755 --- a/development/metamaskbot-build-announce.js +++ b/development/metamaskbot-build-announce.js @@ -39,15 +39,19 @@ function getPercentageChange(from, to) { } async function start() { - const { GITHUB_COMMENT_TOKEN, CIRCLE_PULL_REQUEST } = process.env; + const { + GITHUB_COMMENT_TOKEN, + CIRCLE_PULL_REQUEST, + CIRCLE_SHA1, + CIRCLE_BUILD_NUM, + CIRCLE_WORKFLOW_JOB_ID, + PARENT_COMMIT, + } = process.env; + console.log('CIRCLE_PULL_REQUEST', CIRCLE_PULL_REQUEST); - const { CIRCLE_SHA1 } = process.env; console.log('CIRCLE_SHA1', CIRCLE_SHA1); - const { CIRCLE_BUILD_NUM } = process.env; console.log('CIRCLE_BUILD_NUM', CIRCLE_BUILD_NUM); - const { CIRCLE_WORKFLOW_JOB_ID } = process.env; console.log('CIRCLE_WORKFLOW_JOB_ID', CIRCLE_WORKFLOW_JOB_ID); - const { PARENT_COMMIT } = process.env; console.log('PARENT_COMMIT', PARENT_COMMIT); if (!CIRCLE_PULL_REQUEST) { @@ -81,6 +85,18 @@ async function start() { return `${platform}`; }) .join(', '); + const testBuildLinks = platforms + .map((platform) => { + const url = `${BUILD_LINK_BASE}/builds-test/metamask-${platform}-${VERSION}.zip`; + return `${platform}`; + }) + .join(', '); + const testFlaskBuildLinks = platforms + .map((platform) => { + const url = `${BUILD_LINK_BASE}/builds-test-flask/metamask-flask-${platform}-${VERSION}-flask.0.zip`; + return `${platform}`; + }) + .join(', '); // links to bundle browser builds const bundles = {}; @@ -147,6 +163,8 @@ async function start() { `builds (beta): ${betaBuildLinks}`, `builds (flask): ${flaskBuildLinks}`, `builds (MMI): ${mmiBuildLinks}`, + `builds (test): ${testBuildLinks}`, + `builds (test-flask): ${testFlaskBuildLinks}`, `build viz: ${depVizLink}`, `mv3: ${moduleInitStatsBackgroundLink}`, `mv3: ${moduleInitStatsUILink}`, diff --git a/development/verify-locale-strings.js b/development/verify-locale-strings.js index 1bdc4339f8ac..1a0a3a8d1a61 100755 --- a/development/verify-locale-strings.js +++ b/development/verify-locale-strings.js @@ -187,6 +187,8 @@ async function verifyEnglishLocale() { 'shared/**/*.js', 'shared/**/*.ts', 'shared/**/*.tsx', + 'app/scripts/lib/**/*.js', + 'app/scripts/lib/**/*.ts', 'app/scripts/constants/**/*.js', 'app/scripts/constants/**/*.ts', 'app/scripts/platforms/**/*.js', diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 0530d84fa850..6fe9f30b7f91 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -5,11 +5,6 @@ "regeneratorRuntime": "write" } }, - "@babel/runtime>regenerator-runtime": { - "globals": { - "regeneratorRuntime": "write" - } - }, "@download/blockies": { "globals": { "document.createElement": true @@ -131,7 +126,7 @@ "@ethereumjs/common>crc-32": true, "@ethereumjs/tx>@ethereumjs/util": true, "browserify>buffer": true, - "browserify>events": true + "webpack>events": true } }, "@ethereumjs/common>crc-32": { @@ -161,27 +156,11 @@ }, "packages": { "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography": true, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, + "@ethereumjs/tx>ethereum-cryptography": true, "browserify>buffer": true, - "browserify>events": true, - "browserify>insert-module-globals>is-buffer": true - } - }, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography>@noble/hashes": true, - "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true - } - }, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true + "browserify>insert-module-globals>is-buffer": true, + "webpack>events": true } }, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": { @@ -208,6 +187,7 @@ "crypto": true }, "packages": { + "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true, "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true } }, @@ -517,9 +497,9 @@ "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring": true, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": true, "browserify>buffer": true, - "browserify>events": true, "ethereumjs-util>rlp": true, - "uuid": true + "uuid": true, + "webpack>events": true } }, "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring": { @@ -542,7 +522,7 @@ "packages": { "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2": true, "@metamask/safe-event-emitter": true, - "browserify>stream-browserify": true + "stream-browserify": true } }, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2": { @@ -780,12 +760,12 @@ "@metamask/controller-utils": true, "@metamask/metamask-eth-abis": true, "@metamask/utils": true, - "browserify>events": true, "eth-json-rpc-filters>async-mutex": true, "eth-query": true, "ethereumjs-util": true, "single-call-balance-checker-abi": true, - "uuid": true + "uuid": true, + "webpack>events": true } }, "@metamask/assets-controllers>@metamask/abi-utils": { @@ -922,25 +902,24 @@ "setTimeout": true }, "packages": { - "@metamask/eth-json-rpc-middleware>@metamask/utils": true, + "@metamask/eth-json-rpc-middleware>@metamask/eth-sig-util": 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, + "@metamask/utils": true, "eth-rpc-errors": true, "json-rpc-engine": true } }, - "@metamask/eth-json-rpc-middleware>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, + "@metamask/eth-json-rpc-middleware>@metamask/eth-sig-util": { "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "bn.js": true, "browserify>buffer": true, - "nock>debug": true, - "semver": true, - "superstruct": true + "eth-sig-util>ethereumjs-util>ethjs-util": true, + "eth-sig-util>tweetnacl": true, + "eth-sig-util>tweetnacl-util": true } }, "@metamask/eth-json-rpc-middleware>clone": { @@ -949,13 +928,17 @@ } }, "@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-sig-util": true, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring": true, - "@metamask/eth-keyring-controller>obs-store": true, - "browserify>events": true + "@metamask/eth-keyring-controller>@metamask/utils": true, + "@metamask/obs-store": true, + "webpack>events": true } }, "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring": { @@ -965,7 +948,7 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true, "@metamask/scure-bip39": true, "browserify>buffer": true } @@ -1010,7 +993,7 @@ "@metamask/eth-keyring-controller>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, + "@ethereumjs/tx>ethereum-cryptography": true, "bn.js": true, "browserify>buffer": true, "eth-sig-util>ethereumjs-util>ethjs-util": true, @@ -1018,29 +1001,14 @@ "eth-sig-util>tweetnacl-util": true } }, - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true - } - }, - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring>ethereum-cryptography": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true, "browserify>buffer": true, - "browserify>events": true, - "mocha>serialize-javascript>randombytes": true + "mocha>serialize-javascript>randombytes": true, + "webpack>events": true } }, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring>ethereum-cryptography": { @@ -1058,10 +1026,17 @@ "crypto": true } }, - "@metamask/eth-keyring-controller>obs-store": { + "@metamask/eth-keyring-controller>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, "packages": { - "@metamask/eth-token-tracker>safe-event-emitter": true, - "watchify>xtend": true + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true } }, "@metamask/eth-ledger-bridge-keyring": { @@ -1078,8 +1053,8 @@ "@metamask/eth-ledger-bridge-keyring>eth-sig-util": true, "@metamask/eth-ledger-bridge-keyring>hdkey": true, "browserify>buffer": true, - "browserify>events": true, - "ethereumjs-util": true + "ethereumjs-util": true, + "webpack>events": true } }, "@metamask/eth-ledger-bridge-keyring>eth-sig-util": { @@ -1093,17 +1068,25 @@ }, "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util": { "packages": { + "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethereum-cryptography": true, "@metamask/ppom-validator>elliptic": 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, "koa>content-disposition>safe-buffer": true } }, + "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethereum-cryptography": { + "packages": { + "browserify>buffer": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "mocha>serialize-javascript>randombytes": true + } + }, "@metamask/eth-ledger-bridge-keyring>hdkey": { "packages": { "@metamask/eth-ledger-bridge-keyring>hdkey>secp256k1": true, @@ -1123,32 +1106,6 @@ "koa>content-disposition>safe-buffer": true } }, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": { - "packages": { - "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/eth-snap-keyring>@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/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true - } - }, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "@metamask/eth-token-tracker": { "globals": { "console.warn": true @@ -1161,25 +1118,19 @@ "@metamask/eth-token-tracker>human-standard-token-abi": true, "@metamask/eth-token-tracker>safe-event-emitter": true, "ethjs-contract": true, - "ethjs-query": true + "ethjs>ethjs-query": true } }, "@metamask/eth-token-tracker>deep-equal": { "packages": { - "@metamask/eth-token-tracker>deep-equal>is-arguments": true, "@metamask/eth-token-tracker>deep-equal>is-date-object": true, "@ngraveio/bc-ur>assert>object-is": true, + "browserify>util>is-arguments": true, "globalthis>define-properties>object-keys": true, "string.prototype.matchall>es-abstract>is-regex": true, "string.prototype.matchall>regexp.prototype.flags": true } }, - "@metamask/eth-token-tracker>deep-equal>is-arguments": { - "packages": { - "koa>is-generator-function>has-tostringtag": true, - "string.prototype.matchall>call-bind": true - } - }, "@metamask/eth-token-tracker>deep-equal>is-date-object": { "packages": { "koa>is-generator-function>has-tostringtag": true @@ -1228,7 +1179,7 @@ "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-contract>babel-runtime": true, "ethjs>ethjs-filter": true, "ethjs>js-sha3": true, "promise-to-callback": true @@ -1247,9 +1198,9 @@ "console": true }, "packages": { - "ethjs-query>babel-runtime": true, - "ethjs-query>ethjs-format": true, - "ethjs-query>ethjs-rpc": true, + "@metamask/ethjs-query>ethjs-format": true, + "@metamask/ethjs-query>ethjs-rpc": true, + "ethjs-contract>babel-runtime": true, "promise-to-callback": true } }, @@ -1281,7 +1232,18 @@ "@metamask/eth-trezor-keyring>@trezor/connect-web": true, "@metamask/eth-trezor-keyring>hdkey": true, "browserify>buffer": true, - "browserify>events": true + "webpack>events": true + } + }, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": { + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@ethereumjs/tx>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/eth-trezor-keyring>@metamask/utils": { @@ -1298,7 +1260,7 @@ }, "@metamask/eth-trezor-keyring>@trezor/connect-plugin-ethereum": { "packages": { - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web": { @@ -1323,8 +1285,8 @@ "packages": { "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect": true, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/utils": true, - "browserify>events": true, - "mockttp>graphql-tag>tslib": true + "mockttp>graphql-tag>tslib": true, + "webpack>events": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect": { @@ -1355,8 +1317,8 @@ "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect>@trezor/transport>protobufjs": true, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/utils": true, "browserify>buffer": true, - "browserify>events": true, - "lavamoat>json-stable-stringify": true + "lavamoat>json-stable-stringify": true, + "webpack>events": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect>@trezor/transport>bytebuffer": { @@ -1457,6 +1419,36 @@ "URL": true } }, + "@metamask/ethjs-query": { + "globals": { + "console": true + }, + "packages": { + "@metamask/ethjs-query>ethjs-format": true, + "@metamask/ethjs-query>ethjs-rpc": true, + "promise-to-callback": true + } + }, + "@metamask/ethjs-query>ethjs-format": { + "packages": { + "@metamask/ethjs-query>ethjs-format>ethjs-schema": true, + "@metamask/ethjs-query>ethjs-format>ethjs-util": true, + "ethjs>ethjs-util>strip-hex-prefix": true, + "ethjs>number-to-bn": true + } + }, + "@metamask/ethjs-query>ethjs-format>ethjs-util": { + "packages": { + "browserify>buffer": true, + "ethjs>ethjs-util>is-hex-prefixed": true, + "ethjs>ethjs-util>strip-hex-prefix": true + } + }, + "@metamask/ethjs-query>ethjs-rpc": { + "packages": { + "promise-to-callback": true + } + }, "@metamask/gas-fee-controller": { "globals": { "clearInterval": true, @@ -1504,6 +1496,29 @@ "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": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, "@metamask/key-tree>@noble/ed25519": { "globals": { "crypto": true @@ -1535,53 +1550,13 @@ "@metamask/keyring-controller": { "packages": { "@metamask/base-controller": true, - "@metamask/keyring-controller>@metamask/eth-keyring-controller": true, + "@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, @@ -1597,29 +1572,48 @@ }, "@metamask/keyring-controller>ethereumjs-wallet": { "packages": { + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": true, "@truffle/codec>utf8": true, "browserify>buffer": true, "browserify>crypto-browserify": true, "eth-lattice-keyring>gridplus-sdk>aes-js": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>ethereum-cryptography>bs58check": true, "ethereumjs-util>ethereum-cryptography>scrypt-js": true, "mocha>serialize-javascript>randombytes": true, "uuid": true } }, + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": { + "packages": { + "browserify>assert": true, + "browserify>buffer": true, + "browserify>crypto-browserify>create-hmac": true, + "ethereumjs-util>ethereum-cryptography>bs58check": true, + "ethereumjs-util>ethereum-cryptography>hash.js": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "koa>content-disposition>safe-buffer": true, + "mocha>serialize-javascript>randombytes": true + } + }, "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": { "packages": { + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, "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/logging-controller": { + "packages": { + "@metamask/base-controller": true, + "uuid": true + } + }, "@metamask/logo": { "globals": { "addEventListener": true, @@ -1637,39 +1631,87 @@ "@metamask/message-manager": { "packages": { "@metamask/base-controller": true, - "@metamask/controller-utils": true, + "@metamask/message-manager>@metamask/controller-utils": true, "@metamask/message-manager>@metamask/eth-sig-util": true, "@metamask/message-manager>jsonschema": true, "browserify>buffer": true, - "browserify>events": true, "ethereumjs-util": true, - "uuid": true + "uuid": true, + "webpack>events": true + } + }, + "@metamask/message-manager>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/message-manager>@metamask/utils": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true, + "ethereumjs-util": true, + "ethjs>ethjs-unit": 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, + "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/abi-utils": true, + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/utils": 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": { + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/abi-utils": { + "packages": { + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/abi-utils>@metamask/utils": true, + "superstruct": true + } + }, + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/abi-utils>@metamask/utils": { "globals": { "TextDecoder": true, - "crypto": true + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true }, "packages": { - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true } }, - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { + "@metamask/message-manager>@metamask/utils": { "globals": { - "TextEncoder": true, - "crypto": true + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true } }, "@metamask/message-manager>jsonschema": { @@ -1677,6 +1719,29 @@ "browserify>url": true } }, + "@metamask/name-controller": { + "globals": { + "fetch": true + }, + "packages": { + "@metamask/base-controller": true, + "@metamask/name-controller>@metamask/utils": true, + "eth-json-rpc-filters>async-mutex": true + } + }, + "@metamask/name-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/network-controller": { "globals": { "URL": true, @@ -1761,7 +1826,7 @@ "setTimeout": true }, "packages": { - "browserify>events": true + "webpack>events": true } }, "@metamask/notification-controller>nanoid": { @@ -1773,7 +1838,7 @@ "packages": { "@metamask/obs-store>through2": true, "@metamask/safe-event-emitter": true, - "browserify>stream-browserify": true + "stream-browserify": true } }, "@metamask/obs-store>through2": { @@ -1862,12 +1927,10 @@ }, "@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, "@metamask/snaps-utils": true, "eth-rpc-errors": true, @@ -1879,16 +1942,6 @@ "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, @@ -1912,7 +1965,7 @@ "setTimeout": true }, "packages": { - "browserify>events": true + "webpack>events": true } }, "@metamask/scure-bip39": { @@ -1944,10 +1997,10 @@ "@metamask/controller-utils": true, "@metamask/message-manager": true, "browserify>buffer": true, - "browserify>events": true, "eth-rpc-errors": true, "ethereumjs-util": true, - "lodash": true + "lodash": true, + "webpack>events": true } }, "@metamask/smart-transactions-controller": { @@ -2021,28 +2074,23 @@ "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, + "@metamask/snaps-utils>is-svg": true, "@metamask/snaps-utils>rfdc": true, "@metamask/snaps-utils>validate-npm-package-name": true, + "browserify>buffer": true, + "browserify>path-browserify": true, + "browserify>process": true, + "chalk": true, "semver": true, "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, @@ -2062,6 +2110,20 @@ "luxon": true } }, + "@metamask/snaps-utils>is-svg": { + "packages": { + "@metamask/snaps-utils>is-svg>fast-xml-parser": true + } + }, + "@metamask/snaps-utils>is-svg>fast-xml-parser": { + "globals": { + "entityName": true, + "val": true + }, + "packages": { + "@metamask/snaps-utils>is-svg>fast-xml-parser>strnum": true + } + }, "@metamask/snaps-utils>rfdc": { "packages": { "browserify>buffer": true @@ -2310,6 +2372,11 @@ "browserify>process": true } }, + "@storybook/addon-knobs>qs": { + "packages": { + "string.prototype.matchall>side-channel": true + } + }, "@truffle/codec": { "packages": { "@truffle/codec>@truffle/abi-utils": true, @@ -2485,9 +2552,9 @@ "@truffle/codec>cbor>nofilter": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, - "browserify>stream-browserify": true, "browserify>url": true, - "browserify>util": true + "browserify>util": true, + "stream-browserify": true } }, "@truffle/codec>cbor>bignumber.js": { @@ -2499,8 +2566,8 @@ "@truffle/codec>cbor>nofilter": { "packages": { "browserify>buffer": true, - "browserify>stream-browserify": true, - "browserify>util": true + "browserify>util": true, + "stream-browserify": true } }, "@truffle/codec>web3-utils": { @@ -2831,6 +2898,15 @@ "define": true } }, + "brfs>static-module>object-inspect": { + "globals": { + "HTMLElement": true, + "WeakRef": true + }, + "packages": { + "browserify>browser-resolve": true + } + }, "browserify>assert": { "globals": { "Buffer": true @@ -2863,8 +2939,8 @@ "browserify>browserify-zlib>pako": true, "browserify>buffer": true, "browserify>process": true, - "browserify>stream-browserify": true, - "browserify>util": true + "browserify>util": true, + "stream-browserify": true } }, "browserify>buffer": { @@ -2925,9 +3001,9 @@ "browserify>crypto-browserify>create-hmac": true, "browserify>crypto-browserify>public-encrypt>browserify-rsa": true, "browserify>crypto-browserify>public-encrypt>parse-asn1": true, - "browserify>stream-browserify": true, "ethereumjs-util>create-hash": true, - "pumpify>inherits": true + "pumpify>inherits": true, + "stream-browserify": true } }, "browserify>crypto-browserify>create-ecdh": { @@ -3023,11 +3099,6 @@ "mocha>serialize-javascript>randombytes": true } }, - "browserify>events": { - "globals": { - "console": true - } - }, "browserify>has": { "packages": { "browserify>has>function-bind": true @@ -3061,13 +3132,6 @@ "define": true } }, - "browserify>stream-browserify": { - "packages": { - "browserify>events": true, - "pumpify>inherits": true, - "readable-stream": true - } - }, "browserify>stream-http": { "globals": { "AbortController": true, @@ -3096,11 +3160,11 @@ "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "browserify>string_decoder": { @@ -3121,20 +3185,53 @@ }, "browserify>url": { "packages": { - "browserify>punycode": true, - "browserify>querystring-es3": true + "@storybook/addon-knobs>qs": true, + "browserify>punycode": true } }, "browserify>util": { "globals": { "console.error": true, "console.log": true, - "console.trace": true, - "process": true + "console.trace": true }, "packages": { "browserify>process": true, - "browserify>util>inherits": true + "browserify>util>is-arguments": true, + "browserify>util>is-typed-array": true, + "browserify>util>which-typed-array": true, + "koa>is-generator-function": true, + "pumpify>inherits": true + } + }, + "browserify>util>is-arguments": { + "packages": { + "koa>is-generator-function>has-tostringtag": true, + "string.prototype.matchall>call-bind": true + } + }, + "browserify>util>is-typed-array": { + "packages": { + "browserify>util>is-typed-array>for-each": true, + "koa>is-generator-function>has-tostringtag": true, + "string.prototype.matchall>call-bind": true, + "string.prototype.matchall>es-abstract>available-typed-arrays": true, + "string.prototype.matchall>es-abstract>gopd": true + } + }, + "browserify>util>is-typed-array>for-each": { + "packages": { + "string.prototype.matchall>es-abstract>is-callable": true + } + }, + "browserify>util>which-typed-array": { + "packages": { + "browserify>util>is-typed-array": true, + "browserify>util>is-typed-array>for-each": true, + "koa>is-generator-function>has-tostringtag": true, + "string.prototype.matchall>call-bind": true, + "string.prototype.matchall>es-abstract>available-typed-arrays": true, + "string.prototype.matchall>es-abstract>gopd": true } }, "browserify>vm-browserify": { @@ -3144,6 +3241,22 @@ "document.createElement": true } }, + "chalk": { + "packages": { + "chalk>ansi-styles": true, + "chalk>supports-color": true + } + }, + "chalk>ansi-styles": { + "packages": { + "chalk>ansi-styles>color-convert": true + } + }, + "chalk>ansi-styles>color-convert": { + "packages": { + "jest-canvas-mock>moo-color>color-name": true + } + }, "classnames": { "globals": { "classNames": "write", @@ -3206,13 +3319,13 @@ }, "debounce-stream>duplexer": { "packages": { - "browserify>stream-browserify": true + "stream-browserify": true } }, "debounce-stream>through": { "packages": { "browserify>process": true, - "browserify>stream-browserify": true + "stream-browserify": true } }, "depcheck>@vue/compiler-sfc>postcss>nanoid": { @@ -3303,10 +3416,10 @@ "bn.js": true, "browserify>buffer": true, "browserify>crypto-browserify": true, - "browserify>events": true, "eth-lattice-keyring>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk": true, - "eth-lattice-keyring>rlp": true + "eth-lattice-keyring>rlp": true, + "webpack>events": true } }, "eth-lattice-keyring>@ethereumjs/tx": { @@ -3394,7 +3507,7 @@ "@ethereumjs/common>crc-32": true, "@ethereumjs/tx>@ethereumjs/util": true, "browserify>buffer": true, - "browserify>events": true + "webpack>events": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": { @@ -3414,7 +3527,7 @@ "@ethereumjs/common>crc-32": true, "@ethereumjs/tx>@ethereumjs/util": true, "browserify>buffer": true, - "browserify>events": true + "webpack>events": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": { @@ -3559,13 +3672,21 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethereum-cryptography": true, "eth-sig-util>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, "koa>content-disposition>safe-buffer": true } }, + "eth-sig-util>ethereumjs-util>ethereum-cryptography": { + "packages": { + "browserify>buffer": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "mocha>serialize-javascript>randombytes": true + } + }, "eth-sig-util>ethereumjs-util>ethjs-util": { "packages": { "browserify>buffer": true, @@ -3606,11 +3727,19 @@ "browserify>assert": true, "browserify>buffer": true, "eth-sig-util>ethereumjs-util>ethjs-util": true, + "ethereumjs-abi>ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true } }, + "ethereumjs-abi>ethereumjs-util>ethereum-cryptography": { + "packages": { + "browserify>buffer": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "mocha>serialize-javascript>randombytes": true + } + }, "ethereumjs-util": { "packages": { "bn.js": true, @@ -3633,10 +3762,10 @@ }, "ethereumjs-util>create-hash>cipher-base": { "packages": { - "browserify>stream-browserify": true, "browserify>string_decoder": true, "koa>content-disposition>safe-buffer": true, - "pumpify>inherits": true + "pumpify>inherits": true, + "stream-browserify": true } }, "ethereumjs-util>create-hash>md5.js": { @@ -3657,11 +3786,11 @@ "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "ethereumjs-util>create-hash>ripemd160": { @@ -3673,14 +3802,9 @@ }, "ethereumjs-util>ethereum-cryptography": { "packages": { - "browserify>assert": true, "browserify>buffer": true, - "browserify>crypto-browserify>create-hmac": true, - "ethereumjs-util>ethereum-cryptography>bs58check": true, - "ethereumjs-util>ethereum-cryptography>hash.js": true, "ethereumjs-util>ethereum-cryptography>keccak": true, "ethereumjs-util>ethereum-cryptography>secp256k1": true, - "koa>content-disposition>safe-buffer": true, "mocha>serialize-javascript>randombytes": true } }, @@ -3727,11 +3851,11 @@ "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "ethereumjs-util>ethereum-cryptography>scrypt-js": { @@ -3773,10 +3897,10 @@ "bn.js": true, "browserify>buffer": true, "ethjs-contract": true, - "ethjs-query": true, "ethjs>ethjs-abi": true, "ethjs>ethjs-filter": true, "ethjs>ethjs-provider-http": true, + "ethjs>ethjs-query": true, "ethjs>ethjs-unit": true, "ethjs>ethjs-util": true, "ethjs>js-sha3": true, @@ -3785,47 +3909,21 @@ }, "ethjs-contract": { "packages": { + "ethjs-contract>babel-runtime": true, "ethjs-contract>ethjs-abi": true, "ethjs-contract>ethjs-util": true, - "ethjs-query>babel-runtime": true, "ethjs>ethjs-filter": true, "ethjs>js-sha3": true, "promise-to-callback": true } }, - "ethjs-contract>ethjs-abi": { - "packages": { - "bn.js": true, - "browserify>buffer": 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 - }, - "packages": { - "ethjs-query>ethjs-format": true, - "ethjs-query>ethjs-rpc": true, - "promise-to-callback": true - } - }, - "ethjs-query>babel-runtime": { + "ethjs-contract>babel-runtime": { "packages": { - "@babel/runtime": true, - "@babel/runtime>regenerator-runtime": true, - "ethjs-query>babel-runtime>core-js": true + "ethjs-contract>babel-runtime>core-js": true, + "ethjs-contract>babel-runtime>regenerator-runtime": true } }, - "ethjs-query>babel-runtime>core-js": { + "ethjs-contract>babel-runtime>core-js": { "globals": { "PromiseRejectionEvent": true, "__e": "write", @@ -3835,24 +3933,29 @@ "setTimeout": true } }, - "ethjs-query>ethjs-format": { + "ethjs-contract>babel-runtime>regenerator-runtime": { + "globals": { + "regeneratorRuntime": "write" + } + }, + "ethjs-contract>ethjs-abi": { "packages": { - "ethjs-query>ethjs-format>ethjs-schema": true, - "ethjs-query>ethjs-format>ethjs-util": true, - "ethjs>ethjs-util>strip-hex-prefix": true, + "bn.js": true, + "browserify>buffer": true, + "ethjs>js-sha3": true, "ethjs>number-to-bn": true } }, - "ethjs-query>ethjs-format>ethjs-util": { + "ethjs-contract>ethjs-util": { "packages": { "browserify>buffer": true, "ethjs>ethjs-util>is-hex-prefixed": true, "ethjs>ethjs-util>strip-hex-prefix": true } }, - "ethjs-query>ethjs-rpc": { + "ethjs-query>babel-runtime": { "packages": { - "promise-to-callback": true + "@babel/runtime": true } }, "ethjs>ethjs-abi": { @@ -3879,6 +3982,16 @@ "XMLHttpRequest": true } }, + "ethjs>ethjs-query": { + "globals": { + "console": true + }, + "packages": { + "@metamask/ethjs-query>ethjs-format": true, + "@metamask/ethjs-query>ethjs-rpc": true, + "promise-to-callback": true + } + }, "ethjs>ethjs-unit": { "packages": { "bn.js": true, @@ -3911,7 +4024,7 @@ "extension-port-stream": { "packages": { "browserify>buffer": true, - "browserify>stream-browserify": true + "stream-browserify": true } }, "fast-json-patch": { @@ -3960,6 +4073,11 @@ "browserify>buffer": true } }, + "koa>is-generator-function": { + "packages": { + "koa>is-generator-function>has-tostringtag": true + } + }, "koa>is-generator-function>has-tostringtag": { "packages": { "string.prototype.matchall>has-symbols": true @@ -4067,7 +4185,7 @@ "packages": { "await-semaphore": true, "browserify>assert": true, - "ethjs-query": true + "ethjs>ethjs-query": true } }, "obj-multiplex": { @@ -4497,7 +4615,6 @@ "readable-stream": { "packages": { "browserify>browser-resolve": true, - "browserify>events": true, "browserify>process": true, "browserify>timers-browserify": true, "pumpify>inherits": true, @@ -4506,7 +4623,8 @@ "readable-stream>process-nextick-args": true, "readable-stream>safe-buffer": true, "readable-stream>string_decoder": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "readable-stream>core-util-is": { @@ -4563,12 +4681,40 @@ "sinon>nise>path-to-regexp>isarray": true } }, + "stream-browserify": { + "packages": { + "pumpify>inherits": true, + "stream-browserify>readable-stream": true, + "webpack>events": true + } + }, + "stream-browserify>readable-stream": { + "packages": { + "browserify>browser-resolve": true, + "browserify>buffer": true, + "browserify>process": true, + "browserify>string_decoder": true, + "pumpify>inherits": true, + "readable-stream>util-deprecate": true, + "webpack>events": true + } + }, "string.prototype.matchall>call-bind": { "packages": { "browserify>has>function-bind": true, "string.prototype.matchall>get-intrinsic": true } }, + "string.prototype.matchall>es-abstract>gopd": { + "packages": { + "string.prototype.matchall>get-intrinsic": true + } + }, + "string.prototype.matchall>es-abstract>is-callable": { + "globals": { + "document": true + } + }, "string.prototype.matchall>es-abstract>is-regex": { "packages": { "koa>is-generator-function>has-tostringtag": true, @@ -4595,6 +4741,13 @@ "string.prototype.matchall>regexp.prototype.flags>functions-have-names": true } }, + "string.prototype.matchall>side-channel": { + "packages": { + "brfs>static-module>object-inspect": true, + "string.prototype.matchall>call-bind": true, + "string.prototype.matchall>get-intrinsic": true + } + }, "superstruct": { "globals": { "console.warn": true, diff --git a/lavamoat/browserify/desktop/policy.json b/lavamoat/browserify/desktop/policy.json index bdd2ba925bb9..c515a8db6e58 100644 --- a/lavamoat/browserify/desktop/policy.json +++ b/lavamoat/browserify/desktop/policy.json @@ -5,11 +5,6 @@ "regeneratorRuntime": "write" } }, - "@babel/runtime>regenerator-runtime": { - "globals": { - "regeneratorRuntime": "write" - } - }, "@download/blockies": { "globals": { "document.createElement": true @@ -131,7 +126,7 @@ "@ethereumjs/common>crc-32": true, "@ethereumjs/tx>@ethereumjs/util": true, "browserify>buffer": true, - "browserify>events": true + "webpack>events": true } }, "@ethereumjs/common>crc-32": { @@ -161,27 +156,11 @@ }, "packages": { "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography": true, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, + "@ethereumjs/tx>ethereum-cryptography": true, "browserify>buffer": true, - "browserify>events": true, - "browserify>insert-module-globals>is-buffer": true - } - }, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography>@noble/hashes": true, - "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true - } - }, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true + "browserify>insert-module-globals>is-buffer": true, + "webpack>events": true } }, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": { @@ -208,6 +187,7 @@ "crypto": true }, "packages": { + "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true, "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true } }, @@ -517,9 +497,9 @@ "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring": true, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": true, "browserify>buffer": true, - "browserify>events": true, "ethereumjs-util>rlp": true, - "uuid": true + "uuid": true, + "webpack>events": true } }, "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring": { @@ -542,7 +522,7 @@ "packages": { "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2": true, "@metamask/safe-event-emitter": true, - "browserify>stream-browserify": true + "stream-browserify": true } }, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2": { @@ -780,12 +760,12 @@ "@metamask/controller-utils": true, "@metamask/metamask-eth-abis": true, "@metamask/utils": true, - "browserify>events": true, "eth-json-rpc-filters>async-mutex": true, "eth-query": true, "ethereumjs-util": true, "single-call-balance-checker-abi": true, - "uuid": true + "uuid": true, + "webpack>events": true } }, "@metamask/assets-controllers>@metamask/abi-utils": { @@ -938,14 +918,14 @@ "@metamask/desktop>eciesjs": true, "@metamask/desktop>otpauth": true, "browserify>buffer": true, - "browserify>events": true, - "browserify>stream-browserify": true, "end-of-stream": true, "extension-port-stream": true, "loglevel": true, "obj-multiplex": true, + "stream-browserify": true, "uuid": true, - "webextension-polyfill": true + "webextension-polyfill": true, + "webpack>events": true } }, "@metamask/desktop>@metamask/obs-store": { @@ -955,7 +935,7 @@ "packages": { "@metamask/desktop>@metamask/obs-store>through2": true, "@metamask/safe-event-emitter": true, - "browserify>stream-browserify": true + "stream-browserify": true } }, "@metamask/desktop>@metamask/obs-store>through2": { @@ -993,25 +973,24 @@ "setTimeout": true }, "packages": { - "@metamask/eth-json-rpc-middleware>@metamask/utils": true, + "@metamask/eth-json-rpc-middleware>@metamask/eth-sig-util": 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, + "@metamask/utils": true, "eth-rpc-errors": true, "json-rpc-engine": true } }, - "@metamask/eth-json-rpc-middleware>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, + "@metamask/eth-json-rpc-middleware>@metamask/eth-sig-util": { "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "bn.js": true, "browserify>buffer": true, - "nock>debug": true, - "semver": true, - "superstruct": true + "eth-sig-util>ethereumjs-util>ethjs-util": true, + "eth-sig-util>tweetnacl": true, + "eth-sig-util>tweetnacl-util": true } }, "@metamask/eth-json-rpc-middleware>clone": { @@ -1020,13 +999,17 @@ } }, "@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-sig-util": true, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring": true, - "@metamask/eth-keyring-controller>obs-store": true, - "browserify>events": true + "@metamask/eth-keyring-controller>@metamask/utils": true, + "@metamask/obs-store": true, + "webpack>events": true } }, "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring": { @@ -1036,7 +1019,7 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true, "@metamask/scure-bip39": true, "browserify>buffer": true } @@ -1081,7 +1064,7 @@ "@metamask/eth-keyring-controller>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, + "@ethereumjs/tx>ethereum-cryptography": true, "bn.js": true, "browserify>buffer": true, "eth-sig-util>ethereumjs-util>ethjs-util": true, @@ -1089,29 +1072,14 @@ "eth-sig-util>tweetnacl-util": true } }, - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true - } - }, - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring>ethereum-cryptography": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true, "browserify>buffer": true, - "browserify>events": true, - "mocha>serialize-javascript>randombytes": true + "mocha>serialize-javascript>randombytes": true, + "webpack>events": true } }, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring>ethereum-cryptography": { @@ -1129,10 +1097,17 @@ "crypto": true } }, - "@metamask/eth-keyring-controller>obs-store": { + "@metamask/eth-keyring-controller>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, "packages": { - "@metamask/eth-token-tracker>safe-event-emitter": true, - "watchify>xtend": true + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true } }, "@metamask/eth-ledger-bridge-keyring": { @@ -1149,8 +1124,8 @@ "@metamask/eth-ledger-bridge-keyring>eth-sig-util": true, "@metamask/eth-ledger-bridge-keyring>hdkey": true, "browserify>buffer": true, - "browserify>events": true, - "ethereumjs-util": true + "ethereumjs-util": true, + "webpack>events": true } }, "@metamask/eth-ledger-bridge-keyring>eth-sig-util": { @@ -1164,17 +1139,25 @@ }, "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util": { "packages": { + "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethereum-cryptography": true, "@metamask/ppom-validator>elliptic": 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, "koa>content-disposition>safe-buffer": true } }, + "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethereum-cryptography": { + "packages": { + "browserify>buffer": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "mocha>serialize-javascript>randombytes": true + } + }, "@metamask/eth-ledger-bridge-keyring>hdkey": { "packages": { "@metamask/eth-ledger-bridge-keyring>hdkey>secp256k1": true, @@ -1197,43 +1180,30 @@ "@metamask/eth-snap-keyring": { "globals": { "console.error": true, - "console.warn": true + "console.log": true }, "packages": { "@ethereumjs/tx": true, + "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, "@metamask/eth-snap-keyring>@metamask/keyring-api": true, "@metamask/eth-snap-keyring>@metamask/utils": true, "@metamask/eth-snap-keyring>uuid": true, - "browserify>events": true, - "superstruct": true + "superstruct": true, + "webpack>events": true } }, "@metamask/eth-snap-keyring>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": true, - "bn.js": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/eth-snap-keyring>@metamask/utils": true, + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/abi-utils": true, "browserify>buffer": true, "eth-sig-util>ethereumjs-util>ethjs-util": true, "eth-sig-util>tweetnacl": true, "eth-sig-util>tweetnacl-util": true } }, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true - } - }, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "@metamask/eth-snap-keyring>@metamask/keyring-api": { "packages": { "@metamask/eth-snap-keyring>@metamask/keyring-api>@metamask/utils": true, @@ -1289,25 +1259,19 @@ "@metamask/eth-token-tracker>human-standard-token-abi": true, "@metamask/eth-token-tracker>safe-event-emitter": true, "ethjs-contract": true, - "ethjs-query": true + "ethjs>ethjs-query": true } }, "@metamask/eth-token-tracker>deep-equal": { "packages": { - "@metamask/eth-token-tracker>deep-equal>is-arguments": true, "@metamask/eth-token-tracker>deep-equal>is-date-object": true, "@ngraveio/bc-ur>assert>object-is": true, + "browserify>util>is-arguments": true, "globalthis>define-properties>object-keys": true, "string.prototype.matchall>es-abstract>is-regex": true, "string.prototype.matchall>regexp.prototype.flags": true } }, - "@metamask/eth-token-tracker>deep-equal>is-arguments": { - "packages": { - "koa>is-generator-function>has-tostringtag": true, - "string.prototype.matchall>call-bind": true - } - }, "@metamask/eth-token-tracker>deep-equal>is-date-object": { "packages": { "koa>is-generator-function>has-tostringtag": true @@ -1356,7 +1320,7 @@ "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-contract>babel-runtime": true, "ethjs>ethjs-filter": true, "ethjs>js-sha3": true, "promise-to-callback": true @@ -1375,9 +1339,9 @@ "console": true }, "packages": { - "ethjs-query>babel-runtime": true, - "ethjs-query>ethjs-format": true, - "ethjs-query>ethjs-rpc": true, + "@metamask/ethjs-query>ethjs-format": true, + "@metamask/ethjs-query>ethjs-rpc": true, + "ethjs-contract>babel-runtime": true, "promise-to-callback": true } }, @@ -1409,7 +1373,18 @@ "@metamask/eth-trezor-keyring>@trezor/connect-web": true, "@metamask/eth-trezor-keyring>hdkey": true, "browserify>buffer": true, - "browserify>events": true + "webpack>events": true + } + }, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": { + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@ethereumjs/tx>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/eth-trezor-keyring>@metamask/utils": { @@ -1426,7 +1401,7 @@ }, "@metamask/eth-trezor-keyring>@trezor/connect-plugin-ethereum": { "packages": { - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web": { @@ -1451,8 +1426,8 @@ "packages": { "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect": true, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/utils": true, - "browserify>events": true, - "mockttp>graphql-tag>tslib": true + "mockttp>graphql-tag>tslib": true, + "webpack>events": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect": { @@ -1483,8 +1458,8 @@ "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect>@trezor/transport>protobufjs": true, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/utils": true, "browserify>buffer": true, - "browserify>events": true, - "lavamoat>json-stable-stringify": true + "lavamoat>json-stable-stringify": true, + "webpack>events": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect>@trezor/transport>bytebuffer": { @@ -1585,6 +1560,36 @@ "URL": true } }, + "@metamask/ethjs-query": { + "globals": { + "console": true + }, + "packages": { + "@metamask/ethjs-query>ethjs-format": true, + "@metamask/ethjs-query>ethjs-rpc": true, + "promise-to-callback": true + } + }, + "@metamask/ethjs-query>ethjs-format": { + "packages": { + "@metamask/ethjs-query>ethjs-format>ethjs-schema": true, + "@metamask/ethjs-query>ethjs-format>ethjs-util": true, + "ethjs>ethjs-util>strip-hex-prefix": true, + "ethjs>number-to-bn": true + } + }, + "@metamask/ethjs-query>ethjs-format>ethjs-util": { + "packages": { + "browserify>buffer": true, + "ethjs>ethjs-util>is-hex-prefixed": true, + "ethjs>ethjs-util>strip-hex-prefix": true + } + }, + "@metamask/ethjs-query>ethjs-rpc": { + "packages": { + "promise-to-callback": true + } + }, "@metamask/gas-fee-controller": { "globals": { "clearInterval": true, @@ -1686,53 +1691,13 @@ "@metamask/keyring-controller": { "packages": { "@metamask/base-controller": true, - "@metamask/keyring-controller>@metamask/eth-keyring-controller": true, + "@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, @@ -1748,29 +1713,48 @@ }, "@metamask/keyring-controller>ethereumjs-wallet": { "packages": { + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": true, "@truffle/codec>utf8": true, "browserify>buffer": true, "browserify>crypto-browserify": true, "eth-lattice-keyring>gridplus-sdk>aes-js": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>ethereum-cryptography>bs58check": true, "ethereumjs-util>ethereum-cryptography>scrypt-js": true, "mocha>serialize-javascript>randombytes": true, "uuid": true } }, + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": { + "packages": { + "browserify>assert": true, + "browserify>buffer": true, + "browserify>crypto-browserify>create-hmac": true, + "ethereumjs-util>ethereum-cryptography>bs58check": true, + "ethereumjs-util>ethereum-cryptography>hash.js": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "koa>content-disposition>safe-buffer": true, + "mocha>serialize-javascript>randombytes": true + } + }, "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": { "packages": { + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, "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/logging-controller": { + "packages": { + "@metamask/base-controller": true, + "uuid": true + } + }, "@metamask/logo": { "globals": { "addEventListener": true, @@ -1788,39 +1772,87 @@ "@metamask/message-manager": { "packages": { "@metamask/base-controller": true, - "@metamask/controller-utils": true, + "@metamask/message-manager>@metamask/controller-utils": true, "@metamask/message-manager>@metamask/eth-sig-util": true, "@metamask/message-manager>jsonschema": true, "browserify>buffer": true, - "browserify>events": true, "ethereumjs-util": true, - "uuid": true + "uuid": true, + "webpack>events": true + } + }, + "@metamask/message-manager>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/message-manager>@metamask/utils": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true, + "ethereumjs-util": true, + "ethjs>ethjs-unit": 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, + "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/abi-utils": true, + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/utils": 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": { + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/abi-utils": { + "packages": { + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/abi-utils>@metamask/utils": true, + "superstruct": true + } + }, + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/abi-utils>@metamask/utils": { "globals": { "TextDecoder": true, - "crypto": true + "TextEncoder": true }, "packages": { - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true } }, - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/utils": { "globals": { - "TextEncoder": true, - "crypto": true + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, + "@metamask/message-manager>@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/message-manager>jsonschema": { @@ -1828,6 +1860,29 @@ "browserify>url": true } }, + "@metamask/name-controller": { + "globals": { + "fetch": true + }, + "packages": { + "@metamask/base-controller": true, + "@metamask/name-controller>@metamask/utils": true, + "eth-json-rpc-filters>async-mutex": true + } + }, + "@metamask/name-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/network-controller": { "globals": { "URL": true, @@ -1912,7 +1967,7 @@ "setTimeout": true }, "packages": { - "browserify>events": true + "webpack>events": true } }, "@metamask/notification-controller": { @@ -1931,7 +1986,7 @@ "packages": { "@metamask/obs-store>through2": true, "@metamask/safe-event-emitter": true, - "browserify>stream-browserify": true + "stream-browserify": true } }, "@metamask/obs-store>through2": { @@ -2037,66 +2092,24 @@ "eth-rpc-errors": true } }, - "@metamask/rpc-methods-flask": { + "@metamask/rpc-methods": { "packages": { "@metamask/key-tree": true, "@metamask/key-tree>@noble/hashes": true, "@metamask/permission-controller": true, - "@metamask/rpc-methods-flask>@metamask/snaps-ui": true, - "@metamask/rpc-methods-flask>@metamask/snaps-utils": true, - "@metamask/rpc-methods-flask>@metamask/utils": true, + "@metamask/rpc-methods>@metamask/utils": true, + "@metamask/snaps-ui": true, + "@metamask/snaps-utils": true, "eth-rpc-errors": true, "superstruct": true } }, - "@metamask/rpc-methods-flask>@metamask/snaps-ui": { - "packages": { - "@metamask/rpc-methods-flask>@metamask/snaps-ui>@metamask/utils": true, - "superstruct": true - } - }, - "@metamask/rpc-methods-flask>@metamask/snaps-ui>@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/rpc-methods-flask>@metamask/snaps-utils": { + "@metamask/rpc-methods-flask>nanoid": { "globals": { - "TextDecoder": true, - "URL": true, - "console.error": true, - "console.log": true, - "console.warn": true, - "document.body.appendChild": true, - "document.createElement": true - }, - "packages": { - "@metamask/key-tree": true, - "@metamask/key-tree>@noble/hashes": true, - "@metamask/key-tree>@scure/base": true, - "@metamask/rpc-methods-flask>@metamask/utils": true, - "@metamask/snaps-utils-flask>is-svg": true, - "@metamask/snaps-utils>cron-parser": true, - "@metamask/snaps-utils>fast-json-stable-stringify": true, - "@metamask/snaps-utils>rfdc": true, - "@metamask/snaps-utils>validate-npm-package-name": true, - "browserify>buffer": true, - "browserify>path-browserify": true, - "browserify>process": true, - "chalk": true, - "semver": true, - "superstruct": true + "crypto.getRandomValues": true } }, - "@metamask/rpc-methods-flask>@metamask/utils": { + "@metamask/rpc-methods>@metamask/utils": { "globals": { "TextDecoder": true, "TextEncoder": true @@ -2109,11 +2122,6 @@ "superstruct": true } }, - "@metamask/rpc-methods-flask>nanoid": { - "globals": { - "crypto.getRandomValues": true - } - }, "@metamask/rpc-methods>nanoid": { "globals": { "crypto.getRandomValues": true @@ -2124,7 +2132,7 @@ "setTimeout": true }, "packages": { - "browserify>events": true + "webpack>events": true } }, "@metamask/scure-bip39": { @@ -2156,10 +2164,10 @@ "@metamask/controller-utils": true, "@metamask/message-manager": true, "browserify>buffer": true, - "browserify>events": true, "eth-rpc-errors": true, "ethereumjs-util": true, - "lodash": true + "lodash": true, + "webpack>events": true } }, "@metamask/smart-transactions-controller": { @@ -2193,7 +2201,7 @@ "define": true } }, - "@metamask/snaps-controllers-flask": { + "@metamask/snaps-controllers": { "globals": { "URL": true, "chrome.offscreen.createDocument": true, @@ -2207,24 +2215,29 @@ "@metamask/base-controller": true, "@metamask/permission-controller": true, "@metamask/providers>@metamask/object-multiplex": true, - "@metamask/snaps-controllers-flask>@metamask/post-message-stream": true, - "@metamask/snaps-controllers-flask>@metamask/rpc-methods": true, - "@metamask/snaps-controllers-flask>@metamask/snaps-utils": true, - "@metamask/snaps-controllers-flask>@metamask/utils": true, - "@metamask/snaps-controllers-flask>concat-stream": true, - "@metamask/snaps-controllers-flask>nanoid": true, + "@metamask/rpc-methods": true, + "@metamask/snaps-controllers>@metamask/post-message-stream": true, + "@metamask/snaps-controllers>@metamask/utils": true, "@metamask/snaps-controllers>@xstate/fsm": true, + "@metamask/snaps-controllers>concat-stream": true, "@metamask/snaps-controllers>gunzip-maybe": true, + "@metamask/snaps-controllers>nanoid": true, "@metamask/snaps-controllers>readable-web-to-node-stream": true, "@metamask/snaps-controllers>tar-stream": true, + "@metamask/snaps-utils": true, "@metamask/snaps-utils>@metamask/snaps-registry": true, "eth-rpc-errors": true, "json-rpc-engine": true, "json-rpc-middleware-stream": true, - "pump": true + "stream-browserify": true + } + }, + "@metamask/snaps-controllers-flask>nanoid": { + "globals": { + "crypto.getRandomValues": true } }, - "@metamask/snaps-controllers-flask>@metamask/post-message-stream": { + "@metamask/snaps-controllers>@metamask/post-message-stream": { "globals": { "MessageEvent.prototype": true, "WorkerGlobalScope": true, @@ -2236,82 +2249,23 @@ "removeEventListener": true }, "packages": { - "@metamask/snaps-controllers-flask>@metamask/post-message-stream>@metamask/utils": true, - "@metamask/snaps-controllers-flask>concat-stream>readable-stream": true - } - }, - "@metamask/snaps-controllers-flask>@metamask/post-message-stream>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "browserify>buffer": true, - "nock>debug": true, - "semver": true, - "superstruct": true - } - }, - "@metamask/snaps-controllers-flask>@metamask/rpc-methods": { - "packages": { - "@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/utils": true, - "eth-rpc-errors": true, - "superstruct": true - } - }, - "@metamask/snaps-controllers-flask>@metamask/rpc-methods>@metamask/snaps-ui": { - "packages": { - "@metamask/snaps-controllers-flask>@metamask/rpc-methods>@metamask/snaps-ui>@metamask/utils": true, - "superstruct": true + "@metamask/snaps-controllers>@metamask/post-message-stream>@metamask/utils": true, + "@metamask/snaps-controllers>concat-stream>readable-stream": true } }, - "@metamask/snaps-controllers-flask>@metamask/rpc-methods>@metamask/snaps-ui>@metamask/utils": { + "@metamask/snaps-controllers>@metamask/post-message-stream>@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/snaps-controllers-flask>@metamask/snaps-utils": { - "globals": { - "TextDecoder": true, - "URL": true, - "console.error": true, - "console.log": true, - "console.warn": true, - "document.body.appendChild": true, - "document.createElement": true - }, - "packages": { - "@metamask/key-tree": true, - "@metamask/key-tree>@noble/hashes": true, - "@metamask/key-tree>@scure/base": true, - "@metamask/snaps-controllers-flask>@metamask/utils": true, - "@metamask/snaps-utils-flask>is-svg": true, - "@metamask/snaps-utils>cron-parser": true, - "@metamask/snaps-utils>fast-json-stable-stringify": true, - "@metamask/snaps-utils>rfdc": true, - "@metamask/snaps-utils>validate-npm-package-name": true, - "browserify>buffer": true, - "browserify>path-browserify": true, - "browserify>process": true, - "chalk": true, - "semver": true, - "superstruct": true - } - }, - "@metamask/snaps-controllers-flask>@metamask/utils": { + "@metamask/snaps-controllers>@metamask/utils": { "globals": { "TextDecoder": true, "TextEncoder": true @@ -2324,29 +2278,24 @@ "superstruct": true } }, - "@metamask/snaps-controllers-flask>concat-stream": { + "@metamask/snaps-controllers>concat-stream": { "packages": { - "@metamask/snaps-controllers-flask>concat-stream>readable-stream": true, + "@metamask/snaps-controllers>concat-stream>readable-stream": true, "browserify>buffer": true, "browserify>concat-stream>typedarray": true, "pumpify>inherits": true, "terser>source-map-support>buffer-from": true } }, - "@metamask/snaps-controllers-flask>concat-stream>readable-stream": { + "@metamask/snaps-controllers>concat-stream>readable-stream": { "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true - } - }, - "@metamask/snaps-controllers-flask>nanoid": { - "globals": { - "crypto.getRandomValues": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "@metamask/snaps-controllers>gunzip-maybe": { @@ -2441,11 +2390,11 @@ "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "@metamask/snaps-controllers>tar-stream": { @@ -2470,20 +2419,20 @@ "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, - "@metamask/snaps-ui-flask": { + "@metamask/snaps-ui": { "packages": { - "@metamask/snaps-ui-flask>@metamask/utils": true, + "@metamask/snaps-ui>@metamask/utils": true, "superstruct": true } }, - "@metamask/snaps-ui-flask>@metamask/utils": { + "@metamask/snaps-ui>@metamask/utils": { "globals": { "TextDecoder": true, "TextEncoder": true @@ -2496,7 +2445,7 @@ "superstruct": true } }, - "@metamask/snaps-utils-flask": { + "@metamask/snaps-utils": { "globals": { "TextDecoder": true, "URL": true, @@ -2510,10 +2459,10 @@ "@metamask/key-tree": true, "@metamask/key-tree>@noble/hashes": true, "@metamask/key-tree>@scure/base": true, - "@metamask/snaps-utils-flask>@metamask/utils": true, - "@metamask/snaps-utils-flask>is-svg": true, + "@metamask/snaps-utils>@metamask/utils": true, "@metamask/snaps-utils>cron-parser": true, "@metamask/snaps-utils>fast-json-stable-stringify": true, + "@metamask/snaps-utils>is-svg": true, "@metamask/snaps-utils>rfdc": true, "@metamask/snaps-utils>validate-npm-package-name": true, "browserify>buffer": true, @@ -2524,7 +2473,14 @@ "superstruct": true } }, - "@metamask/snaps-utils-flask>@metamask/utils": { + "@metamask/snaps-utils>@metamask/snaps-registry": { + "packages": { + "@metamask/key-tree>@noble/secp256k1": true, + "@metamask/snaps-utils>@metamask/snaps-registry>@metamask/utils": true, + "superstruct": true + } + }, + "@metamask/snaps-utils>@metamask/snaps-registry>@metamask/utils": { "globals": { "TextDecoder": true, "TextEncoder": true @@ -2537,28 +2493,7 @@ "superstruct": true } }, - "@metamask/snaps-utils-flask>is-svg": { - "packages": { - "@metamask/snaps-utils-flask>is-svg>fast-xml-parser": true - } - }, - "@metamask/snaps-utils-flask>is-svg>fast-xml-parser": { - "globals": { - "entityName": true, - "val": true - }, - "packages": { - "@metamask/snaps-utils-flask>is-svg>fast-xml-parser>strnum": true - } - }, - "@metamask/snaps-utils>@metamask/snaps-registry": { - "packages": { - "@metamask/key-tree>@noble/secp256k1": true, - "@metamask/snaps-utils>@metamask/snaps-registry>@metamask/utils": true, - "superstruct": true - } - }, - "@metamask/snaps-utils>@metamask/snaps-registry>@metamask/utils": { + "@metamask/snaps-utils>@metamask/utils": { "globals": { "TextDecoder": true, "TextEncoder": true @@ -2577,6 +2512,20 @@ "luxon": true } }, + "@metamask/snaps-utils>is-svg": { + "packages": { + "@metamask/snaps-utils>is-svg>fast-xml-parser": true + } + }, + "@metamask/snaps-utils>is-svg>fast-xml-parser": { + "globals": { + "entityName": true, + "val": true + }, + "packages": { + "@metamask/snaps-utils>is-svg>fast-xml-parser>strnum": true + } + }, "@metamask/snaps-utils>rfdc": { "packages": { "browserify>buffer": true @@ -2825,6 +2774,11 @@ "browserify>process": true } }, + "@storybook/addon-knobs>qs": { + "packages": { + "string.prototype.matchall>side-channel": true + } + }, "@truffle/codec": { "packages": { "@truffle/codec>@truffle/abi-utils": true, @@ -3000,9 +2954,9 @@ "@truffle/codec>cbor>nofilter": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, - "browserify>stream-browserify": true, "browserify>url": true, - "browserify>util": true + "browserify>util": true, + "stream-browserify": true } }, "@truffle/codec>cbor>bignumber.js": { @@ -3014,8 +2968,8 @@ "@truffle/codec>cbor>nofilter": { "packages": { "browserify>buffer": true, - "browserify>stream-browserify": true, - "browserify>util": true + "browserify>util": true, + "stream-browserify": true } }, "@truffle/codec>web3-utils": { @@ -3346,6 +3300,15 @@ "define": true } }, + "brfs>static-module>object-inspect": { + "globals": { + "HTMLElement": true, + "WeakRef": true + }, + "packages": { + "browserify>browser-resolve": true + } + }, "browserify>assert": { "globals": { "Buffer": true @@ -3378,8 +3341,8 @@ "browserify>browserify-zlib>pako": true, "browserify>buffer": true, "browserify>process": true, - "browserify>stream-browserify": true, - "browserify>util": true + "browserify>util": true, + "stream-browserify": true } }, "browserify>buffer": { @@ -3440,9 +3403,9 @@ "browserify>crypto-browserify>create-hmac": true, "browserify>crypto-browserify>public-encrypt>browserify-rsa": true, "browserify>crypto-browserify>public-encrypt>parse-asn1": true, - "browserify>stream-browserify": true, "ethereumjs-util>create-hash": true, - "pumpify>inherits": true + "pumpify>inherits": true, + "stream-browserify": true } }, "browserify>crypto-browserify>create-ecdh": { @@ -3538,11 +3501,6 @@ "mocha>serialize-javascript>randombytes": true } }, - "browserify>events": { - "globals": { - "console": true - } - }, "browserify>has": { "packages": { "browserify>has>function-bind": true @@ -3576,13 +3534,6 @@ "define": true } }, - "browserify>stream-browserify": { - "packages": { - "browserify>events": true, - "pumpify>inherits": true, - "readable-stream": true - } - }, "browserify>stream-http": { "globals": { "AbortController": true, @@ -3611,11 +3562,11 @@ "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "browserify>string_decoder": { @@ -3636,20 +3587,53 @@ }, "browserify>url": { "packages": { - "browserify>punycode": true, - "browserify>querystring-es3": true + "@storybook/addon-knobs>qs": true, + "browserify>punycode": true } }, "browserify>util": { "globals": { "console.error": true, "console.log": true, - "console.trace": true, - "process": true + "console.trace": true }, "packages": { "browserify>process": true, - "browserify>util>inherits": true + "browserify>util>is-arguments": true, + "browserify>util>is-typed-array": true, + "browserify>util>which-typed-array": true, + "koa>is-generator-function": true, + "pumpify>inherits": true + } + }, + "browserify>util>is-arguments": { + "packages": { + "koa>is-generator-function>has-tostringtag": true, + "string.prototype.matchall>call-bind": true + } + }, + "browserify>util>is-typed-array": { + "packages": { + "browserify>util>is-typed-array>for-each": true, + "koa>is-generator-function>has-tostringtag": true, + "string.prototype.matchall>call-bind": true, + "string.prototype.matchall>es-abstract>available-typed-arrays": true, + "string.prototype.matchall>es-abstract>gopd": true + } + }, + "browserify>util>is-typed-array>for-each": { + "packages": { + "string.prototype.matchall>es-abstract>is-callable": true + } + }, + "browserify>util>which-typed-array": { + "packages": { + "browserify>util>is-typed-array": true, + "browserify>util>is-typed-array>for-each": true, + "koa>is-generator-function>has-tostringtag": true, + "string.prototype.matchall>call-bind": true, + "string.prototype.matchall>es-abstract>available-typed-arrays": true, + "string.prototype.matchall>es-abstract>gopd": true } }, "browserify>vm-browserify": { @@ -3737,13 +3721,13 @@ }, "debounce-stream>duplexer": { "packages": { - "browserify>stream-browserify": true + "stream-browserify": true } }, "debounce-stream>through": { "packages": { "browserify>process": true, - "browserify>stream-browserify": true + "stream-browserify": true } }, "depcheck>@vue/compiler-sfc>postcss>nanoid": { @@ -3834,10 +3818,10 @@ "bn.js": true, "browserify>buffer": true, "browserify>crypto-browserify": true, - "browserify>events": true, "eth-lattice-keyring>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk": true, - "eth-lattice-keyring>rlp": true + "eth-lattice-keyring>rlp": true, + "webpack>events": true } }, "eth-lattice-keyring>@ethereumjs/tx": { @@ -3925,7 +3909,7 @@ "@ethereumjs/common>crc-32": true, "@ethereumjs/tx>@ethereumjs/util": true, "browserify>buffer": true, - "browserify>events": true + "webpack>events": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": { @@ -3945,7 +3929,7 @@ "@ethereumjs/common>crc-32": true, "@ethereumjs/tx>@ethereumjs/util": true, "browserify>buffer": true, - "browserify>events": true + "webpack>events": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": { @@ -4090,13 +4074,21 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethereum-cryptography": true, "eth-sig-util>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, "koa>content-disposition>safe-buffer": true } }, + "eth-sig-util>ethereumjs-util>ethereum-cryptography": { + "packages": { + "browserify>buffer": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "mocha>serialize-javascript>randombytes": true + } + }, "eth-sig-util>ethereumjs-util>ethjs-util": { "packages": { "browserify>buffer": true, @@ -4137,11 +4129,19 @@ "browserify>assert": true, "browserify>buffer": true, "eth-sig-util>ethereumjs-util>ethjs-util": true, + "ethereumjs-abi>ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true } }, + "ethereumjs-abi>ethereumjs-util>ethereum-cryptography": { + "packages": { + "browserify>buffer": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "mocha>serialize-javascript>randombytes": true + } + }, "ethereumjs-util": { "packages": { "bn.js": true, @@ -4164,10 +4164,10 @@ }, "ethereumjs-util>create-hash>cipher-base": { "packages": { - "browserify>stream-browserify": true, "browserify>string_decoder": true, "koa>content-disposition>safe-buffer": true, - "pumpify>inherits": true + "pumpify>inherits": true, + "stream-browserify": true } }, "ethereumjs-util>create-hash>md5.js": { @@ -4188,11 +4188,11 @@ "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "ethereumjs-util>create-hash>ripemd160": { @@ -4204,14 +4204,9 @@ }, "ethereumjs-util>ethereum-cryptography": { "packages": { - "browserify>assert": true, "browserify>buffer": true, - "browserify>crypto-browserify>create-hmac": true, - "ethereumjs-util>ethereum-cryptography>bs58check": true, - "ethereumjs-util>ethereum-cryptography>hash.js": true, "ethereumjs-util>ethereum-cryptography>keccak": true, "ethereumjs-util>ethereum-cryptography>secp256k1": true, - "koa>content-disposition>safe-buffer": true, "mocha>serialize-javascript>randombytes": true } }, @@ -4258,11 +4253,11 @@ "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "ethereumjs-util>ethereum-cryptography>scrypt-js": { @@ -4304,10 +4299,10 @@ "bn.js": true, "browserify>buffer": true, "ethjs-contract": true, - "ethjs-query": true, "ethjs>ethjs-abi": true, "ethjs>ethjs-filter": true, "ethjs>ethjs-provider-http": true, + "ethjs>ethjs-query": true, "ethjs>ethjs-unit": true, "ethjs>ethjs-util": true, "ethjs>js-sha3": true, @@ -4316,47 +4311,21 @@ }, "ethjs-contract": { "packages": { + "ethjs-contract>babel-runtime": true, "ethjs-contract>ethjs-abi": true, "ethjs-contract>ethjs-util": true, - "ethjs-query>babel-runtime": true, "ethjs>ethjs-filter": true, "ethjs>js-sha3": true, "promise-to-callback": true } }, - "ethjs-contract>ethjs-abi": { - "packages": { - "bn.js": true, - "browserify>buffer": 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 - }, - "packages": { - "ethjs-query>ethjs-format": true, - "ethjs-query>ethjs-rpc": true, - "promise-to-callback": true - } - }, - "ethjs-query>babel-runtime": { + "ethjs-contract>babel-runtime": { "packages": { - "@babel/runtime": true, - "@babel/runtime>regenerator-runtime": true, - "ethjs-query>babel-runtime>core-js": true + "ethjs-contract>babel-runtime>core-js": true, + "ethjs-contract>babel-runtime>regenerator-runtime": true } }, - "ethjs-query>babel-runtime>core-js": { + "ethjs-contract>babel-runtime>core-js": { "globals": { "PromiseRejectionEvent": true, "__e": "write", @@ -4366,24 +4335,29 @@ "setTimeout": true } }, - "ethjs-query>ethjs-format": { + "ethjs-contract>babel-runtime>regenerator-runtime": { + "globals": { + "regeneratorRuntime": "write" + } + }, + "ethjs-contract>ethjs-abi": { "packages": { - "ethjs-query>ethjs-format>ethjs-schema": true, - "ethjs-query>ethjs-format>ethjs-util": true, - "ethjs>ethjs-util>strip-hex-prefix": true, + "bn.js": true, + "browserify>buffer": true, + "ethjs>js-sha3": true, "ethjs>number-to-bn": true } }, - "ethjs-query>ethjs-format>ethjs-util": { + "ethjs-contract>ethjs-util": { "packages": { "browserify>buffer": true, "ethjs>ethjs-util>is-hex-prefixed": true, "ethjs>ethjs-util>strip-hex-prefix": true } }, - "ethjs-query>ethjs-rpc": { + "ethjs-query>babel-runtime": { "packages": { - "promise-to-callback": true + "@babel/runtime": true } }, "ethjs>ethjs-abi": { @@ -4410,6 +4384,16 @@ "XMLHttpRequest": true } }, + "ethjs>ethjs-query": { + "globals": { + "console": true + }, + "packages": { + "@metamask/ethjs-query>ethjs-format": true, + "@metamask/ethjs-query>ethjs-rpc": true, + "promise-to-callback": true + } + }, "ethjs>ethjs-unit": { "packages": { "bn.js": true, @@ -4442,7 +4426,7 @@ "extension-port-stream": { "packages": { "browserify>buffer": true, - "browserify>stream-browserify": true + "stream-browserify": true } }, "fast-json-patch": { @@ -4491,6 +4475,11 @@ "browserify>buffer": true } }, + "koa>is-generator-function": { + "packages": { + "koa>is-generator-function>has-tostringtag": true + } + }, "koa>is-generator-function>has-tostringtag": { "packages": { "string.prototype.matchall>has-symbols": true @@ -4562,11 +4551,11 @@ "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "mocha>serialize-javascript>randombytes": { @@ -4616,7 +4605,7 @@ "packages": { "await-semaphore": true, "browserify>assert": true, - "ethjs-query": true + "ethjs>ethjs-query": true } }, "obj-multiplex": { @@ -5160,7 +5149,6 @@ "readable-stream": { "packages": { "browserify>browser-resolve": true, - "browserify>events": true, "browserify>process": true, "browserify>timers-browserify": true, "pumpify>inherits": true, @@ -5169,7 +5157,8 @@ "readable-stream>process-nextick-args": true, "readable-stream>safe-buffer": true, "readable-stream>string_decoder": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "readable-stream>core-util-is": { @@ -5226,12 +5215,40 @@ "sinon>nise>path-to-regexp>isarray": true } }, + "stream-browserify": { + "packages": { + "pumpify>inherits": true, + "stream-browserify>readable-stream": true, + "webpack>events": true + } + }, + "stream-browserify>readable-stream": { + "packages": { + "browserify>browser-resolve": true, + "browserify>buffer": true, + "browserify>process": true, + "browserify>string_decoder": true, + "pumpify>inherits": true, + "readable-stream>util-deprecate": true, + "webpack>events": true + } + }, "string.prototype.matchall>call-bind": { "packages": { "browserify>has>function-bind": true, "string.prototype.matchall>get-intrinsic": true } }, + "string.prototype.matchall>es-abstract>gopd": { + "packages": { + "string.prototype.matchall>get-intrinsic": true + } + }, + "string.prototype.matchall>es-abstract>is-callable": { + "globals": { + "document": true + } + }, "string.prototype.matchall>es-abstract>is-regex": { "packages": { "koa>is-generator-function>has-tostringtag": true, @@ -5258,6 +5275,13 @@ "string.prototype.matchall>regexp.prototype.flags>functions-have-names": true } }, + "string.prototype.matchall>side-channel": { + "packages": { + "brfs>static-module>object-inspect": true, + "string.prototype.matchall>call-bind": true, + "string.prototype.matchall>get-intrinsic": true + } + }, "superstruct": { "globals": { "console.warn": true, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index 2f97fd964747..d4abe53e94ed 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -5,11 +5,6 @@ "regeneratorRuntime": "write" } }, - "@babel/runtime>regenerator-runtime": { - "globals": { - "regeneratorRuntime": "write" - } - }, "@download/blockies": { "globals": { "document.createElement": true @@ -131,7 +126,7 @@ "@ethereumjs/common>crc-32": true, "@ethereumjs/tx>@ethereumjs/util": true, "browserify>buffer": true, - "browserify>events": true + "webpack>events": true } }, "@ethereumjs/common>crc-32": { @@ -161,27 +156,11 @@ }, "packages": { "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography": true, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, + "@ethereumjs/tx>ethereum-cryptography": true, "browserify>buffer": true, - "browserify>events": true, - "browserify>insert-module-globals>is-buffer": true - } - }, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography>@noble/hashes": true, - "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true - } - }, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true + "browserify>insert-module-globals>is-buffer": true, + "webpack>events": true } }, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": { @@ -208,6 +187,7 @@ "crypto": true }, "packages": { + "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true, "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true } }, @@ -517,9 +497,9 @@ "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring": true, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": true, "browserify>buffer": true, - "browserify>events": true, "ethereumjs-util>rlp": true, - "uuid": true + "uuid": true, + "webpack>events": true } }, "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring": { @@ -542,7 +522,7 @@ "packages": { "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2": true, "@metamask/safe-event-emitter": true, - "browserify>stream-browserify": true + "stream-browserify": true } }, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2": { @@ -780,12 +760,12 @@ "@metamask/controller-utils": true, "@metamask/metamask-eth-abis": true, "@metamask/utils": true, - "browserify>events": true, "eth-json-rpc-filters>async-mutex": true, "eth-query": true, "ethereumjs-util": true, "single-call-balance-checker-abi": true, - "uuid": true + "uuid": true, + "webpack>events": true } }, "@metamask/assets-controllers>@metamask/abi-utils": { @@ -938,14 +918,14 @@ "@metamask/desktop>eciesjs": true, "@metamask/desktop>otpauth": true, "browserify>buffer": true, - "browserify>events": true, - "browserify>stream-browserify": true, "end-of-stream": true, "extension-port-stream": true, "loglevel": true, "obj-multiplex": true, + "stream-browserify": true, "uuid": true, - "webextension-polyfill": true + "webextension-polyfill": true, + "webpack>events": true } }, "@metamask/desktop>@metamask/obs-store": { @@ -955,7 +935,7 @@ "packages": { "@metamask/desktop>@metamask/obs-store>through2": true, "@metamask/safe-event-emitter": true, - "browserify>stream-browserify": true + "stream-browserify": true } }, "@metamask/desktop>@metamask/obs-store>through2": { @@ -993,25 +973,24 @@ "setTimeout": true }, "packages": { - "@metamask/eth-json-rpc-middleware>@metamask/utils": true, + "@metamask/eth-json-rpc-middleware>@metamask/eth-sig-util": 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, + "@metamask/utils": true, "eth-rpc-errors": true, "json-rpc-engine": true } }, - "@metamask/eth-json-rpc-middleware>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, + "@metamask/eth-json-rpc-middleware>@metamask/eth-sig-util": { "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "bn.js": true, "browserify>buffer": true, - "nock>debug": true, - "semver": true, - "superstruct": true + "eth-sig-util>ethereumjs-util>ethjs-util": true, + "eth-sig-util>tweetnacl": true, + "eth-sig-util>tweetnacl-util": true } }, "@metamask/eth-json-rpc-middleware>clone": { @@ -1020,13 +999,17 @@ } }, "@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-sig-util": true, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring": true, - "@metamask/eth-keyring-controller>obs-store": true, - "browserify>events": true + "@metamask/eth-keyring-controller>@metamask/utils": true, + "@metamask/obs-store": true, + "webpack>events": true } }, "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring": { @@ -1036,7 +1019,7 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true, "@metamask/scure-bip39": true, "browserify>buffer": true } @@ -1081,7 +1064,7 @@ "@metamask/eth-keyring-controller>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, + "@ethereumjs/tx>ethereum-cryptography": true, "bn.js": true, "browserify>buffer": true, "eth-sig-util>ethereumjs-util>ethjs-util": true, @@ -1089,29 +1072,14 @@ "eth-sig-util>tweetnacl-util": true } }, - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true - } - }, - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring>ethereum-cryptography": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true, "browserify>buffer": true, - "browserify>events": true, - "mocha>serialize-javascript>randombytes": true + "mocha>serialize-javascript>randombytes": true, + "webpack>events": true } }, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring>ethereum-cryptography": { @@ -1129,10 +1097,17 @@ "crypto": true } }, - "@metamask/eth-keyring-controller>obs-store": { + "@metamask/eth-keyring-controller>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, "packages": { - "@metamask/eth-token-tracker>safe-event-emitter": true, - "watchify>xtend": true + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true } }, "@metamask/eth-ledger-bridge-keyring": { @@ -1149,8 +1124,8 @@ "@metamask/eth-ledger-bridge-keyring>eth-sig-util": true, "@metamask/eth-ledger-bridge-keyring>hdkey": true, "browserify>buffer": true, - "browserify>events": true, - "ethereumjs-util": true + "ethereumjs-util": true, + "webpack>events": true } }, "@metamask/eth-ledger-bridge-keyring>eth-sig-util": { @@ -1164,17 +1139,25 @@ }, "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util": { "packages": { + "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethereum-cryptography": true, "@metamask/ppom-validator>elliptic": 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, "koa>content-disposition>safe-buffer": true } }, + "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethereum-cryptography": { + "packages": { + "browserify>buffer": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "mocha>serialize-javascript>randombytes": true + } + }, "@metamask/eth-ledger-bridge-keyring>hdkey": { "packages": { "@metamask/eth-ledger-bridge-keyring>hdkey>secp256k1": true, @@ -1197,43 +1180,30 @@ "@metamask/eth-snap-keyring": { "globals": { "console.error": true, - "console.warn": true + "console.log": true }, "packages": { "@ethereumjs/tx": true, + "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, "@metamask/eth-snap-keyring>@metamask/keyring-api": true, "@metamask/eth-snap-keyring>@metamask/utils": true, "@metamask/eth-snap-keyring>uuid": true, - "browserify>events": true, - "superstruct": true + "superstruct": true, + "webpack>events": true } }, "@metamask/eth-snap-keyring>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": true, - "bn.js": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/eth-snap-keyring>@metamask/utils": true, + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/abi-utils": true, "browserify>buffer": true, "eth-sig-util>ethereumjs-util>ethjs-util": true, "eth-sig-util>tweetnacl": true, "eth-sig-util>tweetnacl-util": true } }, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true - } - }, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "@metamask/eth-snap-keyring>@metamask/keyring-api": { "packages": { "@metamask/eth-snap-keyring>@metamask/keyring-api>@metamask/utils": true, @@ -1289,25 +1259,19 @@ "@metamask/eth-token-tracker>human-standard-token-abi": true, "@metamask/eth-token-tracker>safe-event-emitter": true, "ethjs-contract": true, - "ethjs-query": true + "ethjs>ethjs-query": true } }, "@metamask/eth-token-tracker>deep-equal": { "packages": { - "@metamask/eth-token-tracker>deep-equal>is-arguments": true, "@metamask/eth-token-tracker>deep-equal>is-date-object": true, "@ngraveio/bc-ur>assert>object-is": true, + "browserify>util>is-arguments": true, "globalthis>define-properties>object-keys": true, "string.prototype.matchall>es-abstract>is-regex": true, "string.prototype.matchall>regexp.prototype.flags": true } }, - "@metamask/eth-token-tracker>deep-equal>is-arguments": { - "packages": { - "koa>is-generator-function>has-tostringtag": true, - "string.prototype.matchall>call-bind": true - } - }, "@metamask/eth-token-tracker>deep-equal>is-date-object": { "packages": { "koa>is-generator-function>has-tostringtag": true @@ -1356,7 +1320,7 @@ "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-contract>babel-runtime": true, "ethjs>ethjs-filter": true, "ethjs>js-sha3": true, "promise-to-callback": true @@ -1375,9 +1339,9 @@ "console": true }, "packages": { - "ethjs-query>babel-runtime": true, - "ethjs-query>ethjs-format": true, - "ethjs-query>ethjs-rpc": true, + "@metamask/ethjs-query>ethjs-format": true, + "@metamask/ethjs-query>ethjs-rpc": true, + "ethjs-contract>babel-runtime": true, "promise-to-callback": true } }, @@ -1409,7 +1373,18 @@ "@metamask/eth-trezor-keyring>@trezor/connect-web": true, "@metamask/eth-trezor-keyring>hdkey": true, "browserify>buffer": true, - "browserify>events": true + "webpack>events": true + } + }, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": { + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@ethereumjs/tx>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/eth-trezor-keyring>@metamask/utils": { @@ -1426,7 +1401,7 @@ }, "@metamask/eth-trezor-keyring>@trezor/connect-plugin-ethereum": { "packages": { - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web": { @@ -1451,8 +1426,8 @@ "packages": { "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect": true, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/utils": true, - "browserify>events": true, - "mockttp>graphql-tag>tslib": true + "mockttp>graphql-tag>tslib": true, + "webpack>events": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect": { @@ -1483,8 +1458,8 @@ "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect>@trezor/transport>protobufjs": true, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/utils": true, "browserify>buffer": true, - "browserify>events": true, - "lavamoat>json-stable-stringify": true + "lavamoat>json-stable-stringify": true, + "webpack>events": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect>@trezor/transport>bytebuffer": { @@ -1585,6 +1560,36 @@ "URL": true } }, + "@metamask/ethjs-query": { + "globals": { + "console": true + }, + "packages": { + "@metamask/ethjs-query>ethjs-format": true, + "@metamask/ethjs-query>ethjs-rpc": true, + "promise-to-callback": true + } + }, + "@metamask/ethjs-query>ethjs-format": { + "packages": { + "@metamask/ethjs-query>ethjs-format>ethjs-schema": true, + "@metamask/ethjs-query>ethjs-format>ethjs-util": true, + "ethjs>ethjs-util>strip-hex-prefix": true, + "ethjs>number-to-bn": true + } + }, + "@metamask/ethjs-query>ethjs-format>ethjs-util": { + "packages": { + "browserify>buffer": true, + "ethjs>ethjs-util>is-hex-prefixed": true, + "ethjs>ethjs-util>strip-hex-prefix": true + } + }, + "@metamask/ethjs-query>ethjs-rpc": { + "packages": { + "promise-to-callback": true + } + }, "@metamask/gas-fee-controller": { "globals": { "clearInterval": true, @@ -1686,53 +1691,13 @@ "@metamask/keyring-controller": { "packages": { "@metamask/base-controller": true, - "@metamask/keyring-controller>@metamask/eth-keyring-controller": true, + "@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, @@ -1748,29 +1713,48 @@ }, "@metamask/keyring-controller>ethereumjs-wallet": { "packages": { + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": true, "@truffle/codec>utf8": true, "browserify>buffer": true, "browserify>crypto-browserify": true, "eth-lattice-keyring>gridplus-sdk>aes-js": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>ethereum-cryptography>bs58check": true, "ethereumjs-util>ethereum-cryptography>scrypt-js": true, "mocha>serialize-javascript>randombytes": true, "uuid": true } }, + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": { + "packages": { + "browserify>assert": true, + "browserify>buffer": true, + "browserify>crypto-browserify>create-hmac": true, + "ethereumjs-util>ethereum-cryptography>bs58check": true, + "ethereumjs-util>ethereum-cryptography>hash.js": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "koa>content-disposition>safe-buffer": true, + "mocha>serialize-javascript>randombytes": true + } + }, "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": { "packages": { + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, "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/logging-controller": { + "packages": { + "@metamask/base-controller": true, + "uuid": true + } + }, "@metamask/logo": { "globals": { "addEventListener": true, @@ -1788,39 +1772,87 @@ "@metamask/message-manager": { "packages": { "@metamask/base-controller": true, - "@metamask/controller-utils": true, + "@metamask/message-manager>@metamask/controller-utils": true, "@metamask/message-manager>@metamask/eth-sig-util": true, "@metamask/message-manager>jsonschema": true, "browserify>buffer": true, - "browserify>events": true, "ethereumjs-util": true, - "uuid": true + "uuid": true, + "webpack>events": true + } + }, + "@metamask/message-manager>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/message-manager>@metamask/utils": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true, + "ethereumjs-util": true, + "ethjs>ethjs-unit": 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, + "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/abi-utils": true, + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/utils": 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": { + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/abi-utils": { + "packages": { + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/abi-utils>@metamask/utils": true, + "superstruct": true + } + }, + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/abi-utils>@metamask/utils": { "globals": { "TextDecoder": true, - "crypto": true + "TextEncoder": true }, "packages": { - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true } }, - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/utils": { "globals": { - "TextEncoder": true, - "crypto": true + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, + "@metamask/message-manager>@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/message-manager>jsonschema": { @@ -1828,6 +1860,29 @@ "browserify>url": true } }, + "@metamask/name-controller": { + "globals": { + "fetch": true + }, + "packages": { + "@metamask/base-controller": true, + "@metamask/name-controller>@metamask/utils": true, + "eth-json-rpc-filters>async-mutex": true + } + }, + "@metamask/name-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/network-controller": { "globals": { "URL": true, @@ -1912,7 +1967,7 @@ "setTimeout": true }, "packages": { - "browserify>events": true + "webpack>events": true } }, "@metamask/notification-controller": { @@ -1931,7 +1986,7 @@ "packages": { "@metamask/obs-store>through2": true, "@metamask/safe-event-emitter": true, - "browserify>stream-browserify": true + "stream-browserify": true } }, "@metamask/obs-store>through2": { @@ -2053,66 +2108,24 @@ "eth-rpc-errors": true } }, - "@metamask/rpc-methods-flask": { + "@metamask/rpc-methods": { "packages": { "@metamask/key-tree": true, "@metamask/key-tree>@noble/hashes": true, "@metamask/permission-controller": true, - "@metamask/rpc-methods-flask>@metamask/snaps-ui": true, - "@metamask/rpc-methods-flask>@metamask/snaps-utils": true, - "@metamask/rpc-methods-flask>@metamask/utils": true, + "@metamask/rpc-methods>@metamask/utils": true, + "@metamask/snaps-ui": true, + "@metamask/snaps-utils": true, "eth-rpc-errors": true, "superstruct": true } }, - "@metamask/rpc-methods-flask>@metamask/snaps-ui": { - "packages": { - "@metamask/rpc-methods-flask>@metamask/snaps-ui>@metamask/utils": true, - "superstruct": true - } - }, - "@metamask/rpc-methods-flask>@metamask/snaps-ui>@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/rpc-methods-flask>@metamask/snaps-utils": { + "@metamask/rpc-methods-flask>nanoid": { "globals": { - "TextDecoder": true, - "URL": true, - "console.error": true, - "console.log": true, - "console.warn": true, - "document.body.appendChild": true, - "document.createElement": true - }, - "packages": { - "@metamask/key-tree": true, - "@metamask/key-tree>@noble/hashes": true, - "@metamask/key-tree>@scure/base": true, - "@metamask/rpc-methods-flask>@metamask/utils": true, - "@metamask/snaps-utils-flask>is-svg": true, - "@metamask/snaps-utils>cron-parser": true, - "@metamask/snaps-utils>fast-json-stable-stringify": true, - "@metamask/snaps-utils>rfdc": true, - "@metamask/snaps-utils>validate-npm-package-name": true, - "browserify>buffer": true, - "browserify>path-browserify": true, - "browserify>process": true, - "chalk": true, - "semver": true, - "superstruct": true + "crypto.getRandomValues": true } }, - "@metamask/rpc-methods-flask>@metamask/utils": { + "@metamask/rpc-methods>@metamask/utils": { "globals": { "TextDecoder": true, "TextEncoder": true @@ -2125,11 +2138,6 @@ "superstruct": true } }, - "@metamask/rpc-methods-flask>nanoid": { - "globals": { - "crypto.getRandomValues": true - } - }, "@metamask/rpc-methods>nanoid": { "globals": { "crypto.getRandomValues": true @@ -2140,7 +2148,7 @@ "setTimeout": true }, "packages": { - "browserify>events": true + "webpack>events": true } }, "@metamask/scure-bip39": { @@ -2172,10 +2180,10 @@ "@metamask/controller-utils": true, "@metamask/message-manager": true, "browserify>buffer": true, - "browserify>events": true, "eth-rpc-errors": true, "ethereumjs-util": true, - "lodash": true + "lodash": true, + "webpack>events": true } }, "@metamask/smart-transactions-controller": { @@ -2209,7 +2217,7 @@ "define": true } }, - "@metamask/snaps-controllers-flask": { + "@metamask/snaps-controllers": { "globals": { "URL": true, "chrome.offscreen.createDocument": true, @@ -2223,24 +2231,29 @@ "@metamask/base-controller": true, "@metamask/permission-controller": true, "@metamask/providers>@metamask/object-multiplex": true, - "@metamask/snaps-controllers-flask>@metamask/post-message-stream": true, - "@metamask/snaps-controllers-flask>@metamask/rpc-methods": true, - "@metamask/snaps-controllers-flask>@metamask/snaps-utils": true, - "@metamask/snaps-controllers-flask>@metamask/utils": true, - "@metamask/snaps-controllers-flask>concat-stream": true, - "@metamask/snaps-controllers-flask>nanoid": true, + "@metamask/rpc-methods": true, + "@metamask/snaps-controllers>@metamask/post-message-stream": true, + "@metamask/snaps-controllers>@metamask/utils": true, "@metamask/snaps-controllers>@xstate/fsm": true, + "@metamask/snaps-controllers>concat-stream": true, "@metamask/snaps-controllers>gunzip-maybe": true, + "@metamask/snaps-controllers>nanoid": true, "@metamask/snaps-controllers>readable-web-to-node-stream": true, "@metamask/snaps-controllers>tar-stream": true, + "@metamask/snaps-utils": true, "@metamask/snaps-utils>@metamask/snaps-registry": true, "eth-rpc-errors": true, "json-rpc-engine": true, "json-rpc-middleware-stream": true, - "pump": true + "stream-browserify": true + } + }, + "@metamask/snaps-controllers-flask>nanoid": { + "globals": { + "crypto.getRandomValues": true } }, - "@metamask/snaps-controllers-flask>@metamask/post-message-stream": { + "@metamask/snaps-controllers>@metamask/post-message-stream": { "globals": { "MessageEvent.prototype": true, "WorkerGlobalScope": true, @@ -2252,82 +2265,23 @@ "removeEventListener": true }, "packages": { - "@metamask/snaps-controllers-flask>@metamask/post-message-stream>@metamask/utils": true, - "@metamask/snaps-controllers-flask>concat-stream>readable-stream": true - } - }, - "@metamask/snaps-controllers-flask>@metamask/post-message-stream>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "browserify>buffer": true, - "nock>debug": true, - "semver": true, - "superstruct": true - } - }, - "@metamask/snaps-controllers-flask>@metamask/rpc-methods": { - "packages": { - "@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/utils": true, - "eth-rpc-errors": true, - "superstruct": true - } - }, - "@metamask/snaps-controllers-flask>@metamask/rpc-methods>@metamask/snaps-ui": { - "packages": { - "@metamask/snaps-controllers-flask>@metamask/rpc-methods>@metamask/snaps-ui>@metamask/utils": true, - "superstruct": true + "@metamask/snaps-controllers>@metamask/post-message-stream>@metamask/utils": true, + "@metamask/snaps-controllers>concat-stream>readable-stream": true } }, - "@metamask/snaps-controllers-flask>@metamask/rpc-methods>@metamask/snaps-ui>@metamask/utils": { + "@metamask/snaps-controllers>@metamask/post-message-stream>@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/snaps-controllers-flask>@metamask/snaps-utils": { - "globals": { - "TextDecoder": true, - "URL": true, - "console.error": true, - "console.log": true, - "console.warn": true, - "document.body.appendChild": true, - "document.createElement": true - }, - "packages": { - "@metamask/key-tree": true, - "@metamask/key-tree>@noble/hashes": true, - "@metamask/key-tree>@scure/base": true, - "@metamask/snaps-controllers-flask>@metamask/utils": true, - "@metamask/snaps-utils-flask>is-svg": true, - "@metamask/snaps-utils>cron-parser": true, - "@metamask/snaps-utils>fast-json-stable-stringify": true, - "@metamask/snaps-utils>rfdc": true, - "@metamask/snaps-utils>validate-npm-package-name": true, - "browserify>buffer": true, - "browserify>path-browserify": true, - "browserify>process": true, - "chalk": true, - "semver": true, - "superstruct": true - } - }, - "@metamask/snaps-controllers-flask>@metamask/utils": { + "@metamask/snaps-controllers>@metamask/utils": { "globals": { "TextDecoder": true, "TextEncoder": true @@ -2340,29 +2294,24 @@ "superstruct": true } }, - "@metamask/snaps-controllers-flask>concat-stream": { + "@metamask/snaps-controllers>concat-stream": { "packages": { - "@metamask/snaps-controllers-flask>concat-stream>readable-stream": true, + "@metamask/snaps-controllers>concat-stream>readable-stream": true, "browserify>buffer": true, "browserify>concat-stream>typedarray": true, "pumpify>inherits": true, "terser>source-map-support>buffer-from": true } }, - "@metamask/snaps-controllers-flask>concat-stream>readable-stream": { + "@metamask/snaps-controllers>concat-stream>readable-stream": { "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true - } - }, - "@metamask/snaps-controllers-flask>nanoid": { - "globals": { - "crypto.getRandomValues": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "@metamask/snaps-controllers>gunzip-maybe": { @@ -2457,11 +2406,11 @@ "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "@metamask/snaps-controllers>tar-stream": { @@ -2486,20 +2435,20 @@ "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, - "@metamask/snaps-ui-flask": { + "@metamask/snaps-ui": { "packages": { - "@metamask/snaps-ui-flask>@metamask/utils": true, + "@metamask/snaps-ui>@metamask/utils": true, "superstruct": true } }, - "@metamask/snaps-ui-flask>@metamask/utils": { + "@metamask/snaps-ui>@metamask/utils": { "globals": { "TextDecoder": true, "TextEncoder": true @@ -2512,7 +2461,7 @@ "superstruct": true } }, - "@metamask/snaps-utils-flask": { + "@metamask/snaps-utils": { "globals": { "TextDecoder": true, "URL": true, @@ -2526,10 +2475,10 @@ "@metamask/key-tree": true, "@metamask/key-tree>@noble/hashes": true, "@metamask/key-tree>@scure/base": true, - "@metamask/snaps-utils-flask>@metamask/utils": true, - "@metamask/snaps-utils-flask>is-svg": true, + "@metamask/snaps-utils>@metamask/utils": true, "@metamask/snaps-utils>cron-parser": true, "@metamask/snaps-utils>fast-json-stable-stringify": true, + "@metamask/snaps-utils>is-svg": true, "@metamask/snaps-utils>rfdc": true, "@metamask/snaps-utils>validate-npm-package-name": true, "browserify>buffer": true, @@ -2540,7 +2489,14 @@ "superstruct": true } }, - "@metamask/snaps-utils-flask>@metamask/utils": { + "@metamask/snaps-utils>@metamask/snaps-registry": { + "packages": { + "@metamask/key-tree>@noble/secp256k1": true, + "@metamask/snaps-utils>@metamask/snaps-registry>@metamask/utils": true, + "superstruct": true + } + }, + "@metamask/snaps-utils>@metamask/snaps-registry>@metamask/utils": { "globals": { "TextDecoder": true, "TextEncoder": true @@ -2553,28 +2509,7 @@ "superstruct": true } }, - "@metamask/snaps-utils-flask>is-svg": { - "packages": { - "@metamask/snaps-utils-flask>is-svg>fast-xml-parser": true - } - }, - "@metamask/snaps-utils-flask>is-svg>fast-xml-parser": { - "globals": { - "entityName": true, - "val": true - }, - "packages": { - "@metamask/snaps-utils-flask>is-svg>fast-xml-parser>strnum": true - } - }, - "@metamask/snaps-utils>@metamask/snaps-registry": { - "packages": { - "@metamask/key-tree>@noble/secp256k1": true, - "@metamask/snaps-utils>@metamask/snaps-registry>@metamask/utils": true, - "superstruct": true - } - }, - "@metamask/snaps-utils>@metamask/snaps-registry>@metamask/utils": { + "@metamask/snaps-utils>@metamask/utils": { "globals": { "TextDecoder": true, "TextEncoder": true @@ -2593,6 +2528,20 @@ "luxon": true } }, + "@metamask/snaps-utils>is-svg": { + "packages": { + "@metamask/snaps-utils>is-svg>fast-xml-parser": true + } + }, + "@metamask/snaps-utils>is-svg>fast-xml-parser": { + "globals": { + "entityName": true, + "val": true + }, + "packages": { + "@metamask/snaps-utils>is-svg>fast-xml-parser>strnum": true + } + }, "@metamask/snaps-utils>rfdc": { "packages": { "browserify>buffer": true @@ -2841,6 +2790,11 @@ "browserify>process": true } }, + "@storybook/addon-knobs>qs": { + "packages": { + "string.prototype.matchall>side-channel": true + } + }, "@truffle/codec": { "packages": { "@truffle/codec>@truffle/abi-utils": true, @@ -3016,9 +2970,9 @@ "@truffle/codec>cbor>nofilter": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, - "browserify>stream-browserify": true, "browserify>url": true, - "browserify>util": true + "browserify>util": true, + "stream-browserify": true } }, "@truffle/codec>cbor>bignumber.js": { @@ -3030,8 +2984,8 @@ "@truffle/codec>cbor>nofilter": { "packages": { "browserify>buffer": true, - "browserify>stream-browserify": true, - "browserify>util": true + "browserify>util": true, + "stream-browserify": true } }, "@truffle/codec>web3-utils": { @@ -3362,6 +3316,15 @@ "define": true } }, + "brfs>static-module>object-inspect": { + "globals": { + "HTMLElement": true, + "WeakRef": true + }, + "packages": { + "browserify>browser-resolve": true + } + }, "browserify>assert": { "globals": { "Buffer": true @@ -3394,8 +3357,8 @@ "browserify>browserify-zlib>pako": true, "browserify>buffer": true, "browserify>process": true, - "browserify>stream-browserify": true, - "browserify>util": true + "browserify>util": true, + "stream-browserify": true } }, "browserify>buffer": { @@ -3456,9 +3419,9 @@ "browserify>crypto-browserify>create-hmac": true, "browserify>crypto-browserify>public-encrypt>browserify-rsa": true, "browserify>crypto-browserify>public-encrypt>parse-asn1": true, - "browserify>stream-browserify": true, "ethereumjs-util>create-hash": true, - "pumpify>inherits": true + "pumpify>inherits": true, + "stream-browserify": true } }, "browserify>crypto-browserify>create-ecdh": { @@ -3554,11 +3517,6 @@ "mocha>serialize-javascript>randombytes": true } }, - "browserify>events": { - "globals": { - "console": true - } - }, "browserify>has": { "packages": { "browserify>has>function-bind": true @@ -3592,13 +3550,6 @@ "define": true } }, - "browserify>stream-browserify": { - "packages": { - "browserify>events": true, - "pumpify>inherits": true, - "readable-stream": true - } - }, "browserify>stream-http": { "globals": { "AbortController": true, @@ -3627,11 +3578,11 @@ "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "browserify>string_decoder": { @@ -3652,20 +3603,53 @@ }, "browserify>url": { "packages": { - "browserify>punycode": true, - "browserify>querystring-es3": true + "@storybook/addon-knobs>qs": true, + "browserify>punycode": true } }, "browserify>util": { "globals": { "console.error": true, "console.log": true, - "console.trace": true, - "process": true + "console.trace": true }, "packages": { "browserify>process": true, - "browserify>util>inherits": true + "browserify>util>is-arguments": true, + "browserify>util>is-typed-array": true, + "browserify>util>which-typed-array": true, + "koa>is-generator-function": true, + "pumpify>inherits": true + } + }, + "browserify>util>is-arguments": { + "packages": { + "koa>is-generator-function>has-tostringtag": true, + "string.prototype.matchall>call-bind": true + } + }, + "browserify>util>is-typed-array": { + "packages": { + "browserify>util>is-typed-array>for-each": true, + "koa>is-generator-function>has-tostringtag": true, + "string.prototype.matchall>call-bind": true, + "string.prototype.matchall>es-abstract>available-typed-arrays": true, + "string.prototype.matchall>es-abstract>gopd": true + } + }, + "browserify>util>is-typed-array>for-each": { + "packages": { + "string.prototype.matchall>es-abstract>is-callable": true + } + }, + "browserify>util>which-typed-array": { + "packages": { + "browserify>util>is-typed-array": true, + "browserify>util>is-typed-array>for-each": true, + "koa>is-generator-function>has-tostringtag": true, + "string.prototype.matchall>call-bind": true, + "string.prototype.matchall>es-abstract>available-typed-arrays": true, + "string.prototype.matchall>es-abstract>gopd": true } }, "browserify>vm-browserify": { @@ -3753,13 +3737,13 @@ }, "debounce-stream>duplexer": { "packages": { - "browserify>stream-browserify": true + "stream-browserify": true } }, "debounce-stream>through": { "packages": { "browserify>process": true, - "browserify>stream-browserify": true + "stream-browserify": true } }, "depcheck>@vue/compiler-sfc>postcss>nanoid": { @@ -3850,10 +3834,10 @@ "bn.js": true, "browserify>buffer": true, "browserify>crypto-browserify": true, - "browserify>events": true, "eth-lattice-keyring>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk": true, - "eth-lattice-keyring>rlp": true + "eth-lattice-keyring>rlp": true, + "webpack>events": true } }, "eth-lattice-keyring>@ethereumjs/tx": { @@ -3941,7 +3925,7 @@ "@ethereumjs/common>crc-32": true, "@ethereumjs/tx>@ethereumjs/util": true, "browserify>buffer": true, - "browserify>events": true + "webpack>events": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": { @@ -3961,7 +3945,7 @@ "@ethereumjs/common>crc-32": true, "@ethereumjs/tx>@ethereumjs/util": true, "browserify>buffer": true, - "browserify>events": true + "webpack>events": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": { @@ -4106,13 +4090,21 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethereum-cryptography": true, "eth-sig-util>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, "koa>content-disposition>safe-buffer": true } }, + "eth-sig-util>ethereumjs-util>ethereum-cryptography": { + "packages": { + "browserify>buffer": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "mocha>serialize-javascript>randombytes": true + } + }, "eth-sig-util>ethereumjs-util>ethjs-util": { "packages": { "browserify>buffer": true, @@ -4153,11 +4145,19 @@ "browserify>assert": true, "browserify>buffer": true, "eth-sig-util>ethereumjs-util>ethjs-util": true, + "ethereumjs-abi>ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true } }, + "ethereumjs-abi>ethereumjs-util>ethereum-cryptography": { + "packages": { + "browserify>buffer": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "mocha>serialize-javascript>randombytes": true + } + }, "ethereumjs-util": { "packages": { "bn.js": true, @@ -4180,10 +4180,10 @@ }, "ethereumjs-util>create-hash>cipher-base": { "packages": { - "browserify>stream-browserify": true, "browserify>string_decoder": true, "koa>content-disposition>safe-buffer": true, - "pumpify>inherits": true + "pumpify>inherits": true, + "stream-browserify": true } }, "ethereumjs-util>create-hash>md5.js": { @@ -4204,11 +4204,11 @@ "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "ethereumjs-util>create-hash>ripemd160": { @@ -4220,14 +4220,9 @@ }, "ethereumjs-util>ethereum-cryptography": { "packages": { - "browserify>assert": true, "browserify>buffer": true, - "browserify>crypto-browserify>create-hmac": true, - "ethereumjs-util>ethereum-cryptography>bs58check": true, - "ethereumjs-util>ethereum-cryptography>hash.js": true, "ethereumjs-util>ethereum-cryptography>keccak": true, "ethereumjs-util>ethereum-cryptography>secp256k1": true, - "koa>content-disposition>safe-buffer": true, "mocha>serialize-javascript>randombytes": true } }, @@ -4274,11 +4269,11 @@ "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "ethereumjs-util>ethereum-cryptography>scrypt-js": { @@ -4320,10 +4315,10 @@ "bn.js": true, "browserify>buffer": true, "ethjs-contract": true, - "ethjs-query": true, "ethjs>ethjs-abi": true, "ethjs>ethjs-filter": true, "ethjs>ethjs-provider-http": true, + "ethjs>ethjs-query": true, "ethjs>ethjs-unit": true, "ethjs>ethjs-util": true, "ethjs>js-sha3": true, @@ -4332,47 +4327,21 @@ }, "ethjs-contract": { "packages": { + "ethjs-contract>babel-runtime": true, "ethjs-contract>ethjs-abi": true, "ethjs-contract>ethjs-util": true, - "ethjs-query>babel-runtime": true, "ethjs>ethjs-filter": true, "ethjs>js-sha3": true, "promise-to-callback": true } }, - "ethjs-contract>ethjs-abi": { - "packages": { - "bn.js": true, - "browserify>buffer": 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 - }, - "packages": { - "ethjs-query>ethjs-format": true, - "ethjs-query>ethjs-rpc": true, - "promise-to-callback": true - } - }, - "ethjs-query>babel-runtime": { + "ethjs-contract>babel-runtime": { "packages": { - "@babel/runtime": true, - "@babel/runtime>regenerator-runtime": true, - "ethjs-query>babel-runtime>core-js": true + "ethjs-contract>babel-runtime>core-js": true, + "ethjs-contract>babel-runtime>regenerator-runtime": true } }, - "ethjs-query>babel-runtime>core-js": { + "ethjs-contract>babel-runtime>core-js": { "globals": { "PromiseRejectionEvent": true, "__e": "write", @@ -4382,24 +4351,29 @@ "setTimeout": true } }, - "ethjs-query>ethjs-format": { + "ethjs-contract>babel-runtime>regenerator-runtime": { + "globals": { + "regeneratorRuntime": "write" + } + }, + "ethjs-contract>ethjs-abi": { "packages": { - "ethjs-query>ethjs-format>ethjs-schema": true, - "ethjs-query>ethjs-format>ethjs-util": true, - "ethjs>ethjs-util>strip-hex-prefix": true, + "bn.js": true, + "browserify>buffer": true, + "ethjs>js-sha3": true, "ethjs>number-to-bn": true } }, - "ethjs-query>ethjs-format>ethjs-util": { + "ethjs-contract>ethjs-util": { "packages": { "browserify>buffer": true, "ethjs>ethjs-util>is-hex-prefixed": true, "ethjs>ethjs-util>strip-hex-prefix": true } }, - "ethjs-query>ethjs-rpc": { + "ethjs-query>babel-runtime": { "packages": { - "promise-to-callback": true + "@babel/runtime": true } }, "ethjs>ethjs-abi": { @@ -4426,6 +4400,16 @@ "XMLHttpRequest": true } }, + "ethjs>ethjs-query": { + "globals": { + "console": true + }, + "packages": { + "@metamask/ethjs-query>ethjs-format": true, + "@metamask/ethjs-query>ethjs-rpc": true, + "promise-to-callback": true + } + }, "ethjs>ethjs-unit": { "packages": { "bn.js": true, @@ -4458,7 +4442,7 @@ "extension-port-stream": { "packages": { "browserify>buffer": true, - "browserify>stream-browserify": true + "stream-browserify": true } }, "fast-json-patch": { @@ -4507,6 +4491,11 @@ "browserify>buffer": true } }, + "koa>is-generator-function": { + "packages": { + "koa>is-generator-function>has-tostringtag": true + } + }, "koa>is-generator-function>has-tostringtag": { "packages": { "string.prototype.matchall>has-symbols": true @@ -4578,11 +4567,11 @@ "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "mocha>serialize-javascript>randombytes": { @@ -4632,7 +4621,7 @@ "packages": { "await-semaphore": true, "browserify>assert": true, - "ethjs-query": true + "ethjs>ethjs-query": true } }, "obj-multiplex": { @@ -5176,7 +5165,6 @@ "readable-stream": { "packages": { "browserify>browser-resolve": true, - "browserify>events": true, "browserify>process": true, "browserify>timers-browserify": true, "pumpify>inherits": true, @@ -5185,7 +5173,8 @@ "readable-stream>process-nextick-args": true, "readable-stream>safe-buffer": true, "readable-stream>string_decoder": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "readable-stream>core-util-is": { @@ -5242,12 +5231,40 @@ "sinon>nise>path-to-regexp>isarray": true } }, + "stream-browserify": { + "packages": { + "pumpify>inherits": true, + "stream-browserify>readable-stream": true, + "webpack>events": true + } + }, + "stream-browserify>readable-stream": { + "packages": { + "browserify>browser-resolve": true, + "browserify>buffer": true, + "browserify>process": true, + "browserify>string_decoder": true, + "pumpify>inherits": true, + "readable-stream>util-deprecate": true, + "webpack>events": true + } + }, "string.prototype.matchall>call-bind": { "packages": { "browserify>has>function-bind": true, "string.prototype.matchall>get-intrinsic": true } }, + "string.prototype.matchall>es-abstract>gopd": { + "packages": { + "string.prototype.matchall>get-intrinsic": true + } + }, + "string.prototype.matchall>es-abstract>is-callable": { + "globals": { + "document": true + } + }, "string.prototype.matchall>es-abstract>is-regex": { "packages": { "koa>is-generator-function>has-tostringtag": true, @@ -5274,6 +5291,13 @@ "string.prototype.matchall>regexp.prototype.flags>functions-have-names": true } }, + "string.prototype.matchall>side-channel": { + "packages": { + "brfs>static-module>object-inspect": true, + "string.prototype.matchall>call-bind": true, + "string.prototype.matchall>get-intrinsic": true + } + }, "superstruct": { "globals": { "console.warn": true, diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 8f1f171aa469..926ef5d12307 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -5,11 +5,6 @@ "regeneratorRuntime": "write" } }, - "@babel/runtime>regenerator-runtime": { - "globals": { - "regeneratorRuntime": "write" - } - }, "@download/blockies": { "globals": { "document.createElement": true @@ -131,7 +126,7 @@ "@ethereumjs/common>crc-32": true, "@ethereumjs/tx>@ethereumjs/util": true, "browserify>buffer": true, - "browserify>events": true + "webpack>events": true } }, "@ethereumjs/common>crc-32": { @@ -161,27 +156,11 @@ }, "packages": { "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography": true, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, + "@ethereumjs/tx>ethereum-cryptography": true, "browserify>buffer": true, - "browserify>events": true, - "browserify>insert-module-globals>is-buffer": true - } - }, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography>@noble/hashes": true, - "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true - } - }, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true + "browserify>insert-module-globals>is-buffer": true, + "webpack>events": true } }, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": { @@ -208,6 +187,7 @@ "crypto": true }, "packages": { + "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true, "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true } }, @@ -517,9 +497,9 @@ "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring": true, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": true, "browserify>buffer": true, - "browserify>events": true, "ethereumjs-util>rlp": true, - "uuid": true + "uuid": true, + "webpack>events": true } }, "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring": { @@ -542,7 +522,7 @@ "packages": { "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2": true, "@metamask/safe-event-emitter": true, - "browserify>stream-browserify": true + "stream-browserify": true } }, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2": { @@ -780,12 +760,12 @@ "@metamask/controller-utils": true, "@metamask/metamask-eth-abis": true, "@metamask/utils": true, - "browserify>events": true, "eth-json-rpc-filters>async-mutex": true, "eth-query": true, "ethereumjs-util": true, "single-call-balance-checker-abi": true, - "uuid": true + "uuid": true, + "webpack>events": true } }, "@metamask/assets-controllers>@metamask/abi-utils": { @@ -922,25 +902,24 @@ "setTimeout": true }, "packages": { - "@metamask/eth-json-rpc-middleware>@metamask/utils": true, + "@metamask/eth-json-rpc-middleware>@metamask/eth-sig-util": 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, + "@metamask/utils": true, "eth-rpc-errors": true, "json-rpc-engine": true } }, - "@metamask/eth-json-rpc-middleware>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, + "@metamask/eth-json-rpc-middleware>@metamask/eth-sig-util": { "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "bn.js": true, "browserify>buffer": true, - "nock>debug": true, - "semver": true, - "superstruct": true + "eth-sig-util>ethereumjs-util>ethjs-util": true, + "eth-sig-util>tweetnacl": true, + "eth-sig-util>tweetnacl-util": true } }, "@metamask/eth-json-rpc-middleware>clone": { @@ -949,13 +928,17 @@ } }, "@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-sig-util": true, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring": true, - "@metamask/eth-keyring-controller>obs-store": true, - "browserify>events": true + "@metamask/eth-keyring-controller>@metamask/utils": true, + "@metamask/obs-store": true, + "webpack>events": true } }, "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring": { @@ -965,7 +948,7 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true, "@metamask/scure-bip39": true, "browserify>buffer": true } @@ -1010,7 +993,7 @@ "@metamask/eth-keyring-controller>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, + "@ethereumjs/tx>ethereum-cryptography": true, "bn.js": true, "browserify>buffer": true, "eth-sig-util>ethereumjs-util>ethjs-util": true, @@ -1018,29 +1001,14 @@ "eth-sig-util>tweetnacl-util": true } }, - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true - } - }, - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring>ethereum-cryptography": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true, "browserify>buffer": true, - "browserify>events": true, - "mocha>serialize-javascript>randombytes": true + "mocha>serialize-javascript>randombytes": true, + "webpack>events": true } }, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring>ethereum-cryptography": { @@ -1058,10 +1026,17 @@ "crypto": true } }, - "@metamask/eth-keyring-controller>obs-store": { + "@metamask/eth-keyring-controller>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, "packages": { - "@metamask/eth-token-tracker>safe-event-emitter": true, - "watchify>xtend": true + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true } }, "@metamask/eth-ledger-bridge-keyring": { @@ -1078,8 +1053,8 @@ "@metamask/eth-ledger-bridge-keyring>eth-sig-util": true, "@metamask/eth-ledger-bridge-keyring>hdkey": true, "browserify>buffer": true, - "browserify>events": true, - "ethereumjs-util": true + "ethereumjs-util": true, + "webpack>events": true } }, "@metamask/eth-ledger-bridge-keyring>eth-sig-util": { @@ -1093,17 +1068,25 @@ }, "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util": { "packages": { + "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethereum-cryptography": true, "@metamask/ppom-validator>elliptic": 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, "koa>content-disposition>safe-buffer": true } }, + "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethereum-cryptography": { + "packages": { + "browserify>buffer": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "mocha>serialize-javascript>randombytes": true + } + }, "@metamask/eth-ledger-bridge-keyring>hdkey": { "packages": { "@metamask/eth-ledger-bridge-keyring>hdkey>secp256k1": true, @@ -1123,32 +1106,6 @@ "koa>content-disposition>safe-buffer": true } }, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": { - "packages": { - "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/eth-snap-keyring>@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/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true - } - }, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "@metamask/eth-token-tracker": { "globals": { "console.warn": true @@ -1161,25 +1118,19 @@ "@metamask/eth-token-tracker>human-standard-token-abi": true, "@metamask/eth-token-tracker>safe-event-emitter": true, "ethjs-contract": true, - "ethjs-query": true + "ethjs>ethjs-query": true } }, "@metamask/eth-token-tracker>deep-equal": { "packages": { - "@metamask/eth-token-tracker>deep-equal>is-arguments": true, "@metamask/eth-token-tracker>deep-equal>is-date-object": true, "@ngraveio/bc-ur>assert>object-is": true, + "browserify>util>is-arguments": true, "globalthis>define-properties>object-keys": true, "string.prototype.matchall>es-abstract>is-regex": true, "string.prototype.matchall>regexp.prototype.flags": true } }, - "@metamask/eth-token-tracker>deep-equal>is-arguments": { - "packages": { - "koa>is-generator-function>has-tostringtag": true, - "string.prototype.matchall>call-bind": true - } - }, "@metamask/eth-token-tracker>deep-equal>is-date-object": { "packages": { "koa>is-generator-function>has-tostringtag": true @@ -1228,7 +1179,7 @@ "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-contract>babel-runtime": true, "ethjs>ethjs-filter": true, "ethjs>js-sha3": true, "promise-to-callback": true @@ -1247,9 +1198,9 @@ "console": true }, "packages": { - "ethjs-query>babel-runtime": true, - "ethjs-query>ethjs-format": true, - "ethjs-query>ethjs-rpc": true, + "@metamask/ethjs-query>ethjs-format": true, + "@metamask/ethjs-query>ethjs-rpc": true, + "ethjs-contract>babel-runtime": true, "promise-to-callback": true } }, @@ -1281,7 +1232,18 @@ "@metamask/eth-trezor-keyring>@trezor/connect-web": true, "@metamask/eth-trezor-keyring>hdkey": true, "browserify>buffer": true, - "browserify>events": true + "webpack>events": true + } + }, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": { + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@ethereumjs/tx>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/eth-trezor-keyring>@metamask/utils": { @@ -1298,7 +1260,7 @@ }, "@metamask/eth-trezor-keyring>@trezor/connect-plugin-ethereum": { "packages": { - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web": { @@ -1323,8 +1285,8 @@ "packages": { "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect": true, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/utils": true, - "browserify>events": true, - "mockttp>graphql-tag>tslib": true + "mockttp>graphql-tag>tslib": true, + "webpack>events": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect": { @@ -1355,8 +1317,8 @@ "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect>@trezor/transport>protobufjs": true, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/utils": true, "browserify>buffer": true, - "browserify>events": true, - "lavamoat>json-stable-stringify": true + "lavamoat>json-stable-stringify": true, + "webpack>events": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect>@trezor/transport>bytebuffer": { @@ -1457,6 +1419,36 @@ "URL": true } }, + "@metamask/ethjs-query": { + "globals": { + "console": true + }, + "packages": { + "@metamask/ethjs-query>ethjs-format": true, + "@metamask/ethjs-query>ethjs-rpc": true, + "promise-to-callback": true + } + }, + "@metamask/ethjs-query>ethjs-format": { + "packages": { + "@metamask/ethjs-query>ethjs-format>ethjs-schema": true, + "@metamask/ethjs-query>ethjs-format>ethjs-util": true, + "ethjs>ethjs-util>strip-hex-prefix": true, + "ethjs>number-to-bn": true + } + }, + "@metamask/ethjs-query>ethjs-format>ethjs-util": { + "packages": { + "browserify>buffer": true, + "ethjs>ethjs-util>is-hex-prefixed": true, + "ethjs>ethjs-util>strip-hex-prefix": true + } + }, + "@metamask/ethjs-query>ethjs-rpc": { + "packages": { + "promise-to-callback": true + } + }, "@metamask/gas-fee-controller": { "globals": { "clearInterval": true, @@ -1504,6 +1496,29 @@ "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": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, "@metamask/key-tree>@noble/ed25519": { "globals": { "crypto": true @@ -1535,53 +1550,13 @@ "@metamask/keyring-controller": { "packages": { "@metamask/base-controller": true, - "@metamask/keyring-controller>@metamask/eth-keyring-controller": true, + "@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, @@ -1597,29 +1572,48 @@ }, "@metamask/keyring-controller>ethereumjs-wallet": { "packages": { + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": true, "@truffle/codec>utf8": true, "browserify>buffer": true, "browserify>crypto-browserify": true, "eth-lattice-keyring>gridplus-sdk>aes-js": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>ethereum-cryptography>bs58check": true, "ethereumjs-util>ethereum-cryptography>scrypt-js": true, "mocha>serialize-javascript>randombytes": true, "uuid": true } }, + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": { + "packages": { + "browserify>assert": true, + "browserify>buffer": true, + "browserify>crypto-browserify>create-hmac": true, + "ethereumjs-util>ethereum-cryptography>bs58check": true, + "ethereumjs-util>ethereum-cryptography>hash.js": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "koa>content-disposition>safe-buffer": true, + "mocha>serialize-javascript>randombytes": true + } + }, "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": { "packages": { + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, "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/logging-controller": { + "packages": { + "@metamask/base-controller": true, + "uuid": true + } + }, "@metamask/logo": { "globals": { "addEventListener": true, @@ -1637,39 +1631,87 @@ "@metamask/message-manager": { "packages": { "@metamask/base-controller": true, - "@metamask/controller-utils": true, + "@metamask/message-manager>@metamask/controller-utils": true, "@metamask/message-manager>@metamask/eth-sig-util": true, "@metamask/message-manager>jsonschema": true, "browserify>buffer": true, - "browserify>events": true, "ethereumjs-util": true, - "uuid": true + "uuid": true, + "webpack>events": true + } + }, + "@metamask/message-manager>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/message-manager>@metamask/utils": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true, + "ethereumjs-util": true, + "ethjs>ethjs-unit": 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, + "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/abi-utils": true, + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/utils": 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": { + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/abi-utils": { + "packages": { + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/abi-utils>@metamask/utils": true, + "superstruct": true + } + }, + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/abi-utils>@metamask/utils": { "globals": { "TextDecoder": true, - "crypto": true + "TextEncoder": true }, "packages": { - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true } }, - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/utils": { "globals": { - "TextEncoder": true, - "crypto": true + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, + "@metamask/message-manager>@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/message-manager>jsonschema": { @@ -1677,6 +1719,29 @@ "browserify>url": true } }, + "@metamask/name-controller": { + "globals": { + "fetch": true + }, + "packages": { + "@metamask/base-controller": true, + "@metamask/name-controller>@metamask/utils": true, + "eth-json-rpc-filters>async-mutex": true + } + }, + "@metamask/name-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/network-controller": { "globals": { "URL": true, @@ -1761,7 +1826,7 @@ "setTimeout": true }, "packages": { - "browserify>events": true + "webpack>events": true } }, "@metamask/notification-controller": { @@ -1780,7 +1845,7 @@ "packages": { "@metamask/obs-store>through2": true, "@metamask/safe-event-emitter": true, - "browserify>stream-browserify": true + "stream-browserify": true } }, "@metamask/obs-store>through2": { @@ -1802,88 +1867,42 @@ "@metamask/permission-controller>nanoid": true, "deep-freeze-strict": true, "eth-rpc-errors": true, - "immer": true, - "json-rpc-engine": true - } - }, - "@metamask/permission-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/permission-controller>nanoid": { - "globals": { - "crypto.getRandomValues": true - } - }, - "@metamask/phishing-controller": { - "globals": { - "fetch": true - }, - "packages": { - "@metamask/base-controller": true, - "@metamask/controller-utils": true, - "@metamask/phishing-warning>eth-phishing-detect": true, - "punycode": true - } - }, - "@metamask/phishing-warning>eth-phishing-detect": { - "packages": { - "eslint>optionator>fast-levenshtein": true - } - }, - "@metamask/post-message-stream": { - "globals": { - "MessageEvent.prototype": true, - "WorkerGlobalScope": true, - "addEventListener": true, - "browser": true, - "chrome": true, - "location.origin": true, - "postMessage": true, - "removeEventListener": true - }, - "packages": { - "@metamask/post-message-stream>readable-stream": true, - "@metamask/utils": true - } - }, - "@metamask/post-message-stream>readable-stream": { - "packages": { - "@metamask/post-message-stream>readable-stream>process-nextick-args": true, - "@metamask/post-message-stream>readable-stream>safe-buffer": true, - "@metamask/post-message-stream>readable-stream>string_decoder": true, - "browserify>browser-resolve": true, - "browserify>events": true, - "browserify>process": true, - "browserify>timers-browserify": true, - "pumpify>inherits": true, - "readable-stream>core-util-is": true, - "readable-stream>isarray": true, - "readable-stream>util-deprecate": true + "immer": true, + "json-rpc-engine": true } }, - "@metamask/post-message-stream>readable-stream>process-nextick-args": { + "@metamask/permission-controller>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, "packages": { - "browserify>process": true + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, + "@metamask/permission-controller>nanoid": { + "globals": { + "crypto.getRandomValues": true } }, - "@metamask/post-message-stream>readable-stream>safe-buffer": { + "@metamask/phishing-controller": { + "globals": { + "fetch": true + }, "packages": { - "browserify>buffer": true + "@metamask/base-controller": true, + "@metamask/controller-utils": true, + "@metamask/phishing-warning>eth-phishing-detect": true, + "punycode": true } }, - "@metamask/post-message-stream>readable-stream>string_decoder": { + "@metamask/phishing-warning>eth-phishing-detect": { "packages": { - "@metamask/post-message-stream>readable-stream>safe-buffer": true + "eslint>optionator>fast-levenshtein": true } }, "@metamask/ppom-validator>elliptic": { @@ -1934,12 +1953,10 @@ }, "@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, "@metamask/snaps-utils": true, "eth-rpc-errors": true, @@ -1951,16 +1968,6 @@ "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, @@ -1984,7 +1991,7 @@ "setTimeout": true }, "packages": { - "browserify>events": true + "webpack>events": true } }, "@metamask/scure-bip39": { @@ -2016,10 +2023,10 @@ "@metamask/controller-utils": true, "@metamask/message-manager": true, "browserify>buffer": true, - "browserify>events": true, "eth-rpc-errors": true, "ethereumjs-util": true, - "lodash": true + "lodash": true, + "webpack>events": true } }, "@metamask/smart-transactions-controller": { @@ -2066,9 +2073,9 @@ "packages": { "@metamask/base-controller": true, "@metamask/permission-controller": true, - "@metamask/post-message-stream": true, "@metamask/providers>@metamask/object-multiplex": true, "@metamask/rpc-methods": true, + "@metamask/snaps-controllers>@metamask/post-message-stream": true, "@metamask/snaps-controllers>@metamask/utils": true, "@metamask/snaps-controllers>@xstate/fsm": true, "@metamask/snaps-controllers>concat-stream": true, @@ -2081,7 +2088,7 @@ "eth-rpc-errors": true, "json-rpc-engine": true, "json-rpc-middleware-stream": true, - "pump": true + "stream-browserify": true } }, "@metamask/snaps-controllers-flask>nanoid": { @@ -2089,6 +2096,34 @@ "crypto.getRandomValues": true } }, + "@metamask/snaps-controllers>@metamask/post-message-stream": { + "globals": { + "MessageEvent.prototype": true, + "WorkerGlobalScope": true, + "addEventListener": true, + "browser": true, + "chrome": true, + "location.origin": true, + "postMessage": true, + "removeEventListener": true + }, + "packages": { + "@metamask/snaps-controllers>@metamask/post-message-stream>@metamask/utils": true, + "@metamask/snaps-controllers>concat-stream>readable-stream": true + } + }, + "@metamask/snaps-controllers>@metamask/post-message-stream>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, "@metamask/snaps-controllers>@metamask/utils": { "globals": { "TextDecoder": true, @@ -2115,11 +2150,11 @@ "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "@metamask/snaps-controllers>gunzip-maybe": { @@ -2214,11 +2249,11 @@ "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "@metamask/snaps-controllers>tar-stream": { @@ -2243,11 +2278,11 @@ "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "@metamask/snaps-ui": { @@ -2280,28 +2315,23 @@ "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, + "@metamask/snaps-utils>is-svg": true, "@metamask/snaps-utils>rfdc": true, "@metamask/snaps-utils>validate-npm-package-name": true, + "browserify>buffer": true, + "browserify>path-browserify": true, + "browserify>process": true, + "chalk": true, "semver": true, "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/snaps-registry": { "packages": { "@metamask/key-tree>@noble/secp256k1": true, @@ -2341,6 +2371,20 @@ "luxon": true } }, + "@metamask/snaps-utils>is-svg": { + "packages": { + "@metamask/snaps-utils>is-svg>fast-xml-parser": true + } + }, + "@metamask/snaps-utils>is-svg>fast-xml-parser": { + "globals": { + "entityName": true, + "val": true + }, + "packages": { + "@metamask/snaps-utils>is-svg>fast-xml-parser>strnum": true + } + }, "@metamask/snaps-utils>rfdc": { "packages": { "browserify>buffer": true @@ -2589,6 +2633,11 @@ "browserify>process": true } }, + "@storybook/addon-knobs>qs": { + "packages": { + "string.prototype.matchall>side-channel": true + } + }, "@truffle/codec": { "packages": { "@truffle/codec>@truffle/abi-utils": true, @@ -2764,9 +2813,9 @@ "@truffle/codec>cbor>nofilter": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, - "browserify>stream-browserify": true, "browserify>url": true, - "browserify>util": true + "browserify>util": true, + "stream-browserify": true } }, "@truffle/codec>cbor>bignumber.js": { @@ -2778,8 +2827,8 @@ "@truffle/codec>cbor>nofilter": { "packages": { "browserify>buffer": true, - "browserify>stream-browserify": true, - "browserify>util": true + "browserify>util": true, + "stream-browserify": true } }, "@truffle/codec>web3-utils": { @@ -3110,6 +3159,15 @@ "define": true } }, + "brfs>static-module>object-inspect": { + "globals": { + "HTMLElement": true, + "WeakRef": true + }, + "packages": { + "browserify>browser-resolve": true + } + }, "browserify>assert": { "globals": { "Buffer": true @@ -3142,8 +3200,8 @@ "browserify>browserify-zlib>pako": true, "browserify>buffer": true, "browserify>process": true, - "browserify>stream-browserify": true, - "browserify>util": true + "browserify>util": true, + "stream-browserify": true } }, "browserify>buffer": { @@ -3204,9 +3262,9 @@ "browserify>crypto-browserify>create-hmac": true, "browserify>crypto-browserify>public-encrypt>browserify-rsa": true, "browserify>crypto-browserify>public-encrypt>parse-asn1": true, - "browserify>stream-browserify": true, "ethereumjs-util>create-hash": true, - "pumpify>inherits": true + "pumpify>inherits": true, + "stream-browserify": true } }, "browserify>crypto-browserify>create-ecdh": { @@ -3302,11 +3360,6 @@ "mocha>serialize-javascript>randombytes": true } }, - "browserify>events": { - "globals": { - "console": true - } - }, "browserify>has": { "packages": { "browserify>has>function-bind": true @@ -3340,13 +3393,6 @@ "define": true } }, - "browserify>stream-browserify": { - "packages": { - "browserify>events": true, - "pumpify>inherits": true, - "readable-stream": true - } - }, "browserify>stream-http": { "globals": { "AbortController": true, @@ -3375,11 +3421,11 @@ "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "browserify>string_decoder": { @@ -3400,20 +3446,53 @@ }, "browserify>url": { "packages": { - "browserify>punycode": true, - "browserify>querystring-es3": true + "@storybook/addon-knobs>qs": true, + "browserify>punycode": true } }, "browserify>util": { "globals": { "console.error": true, "console.log": true, - "console.trace": true, - "process": true + "console.trace": true }, "packages": { "browserify>process": true, - "browserify>util>inherits": true + "browserify>util>is-arguments": true, + "browserify>util>is-typed-array": true, + "browserify>util>which-typed-array": true, + "koa>is-generator-function": true, + "pumpify>inherits": true + } + }, + "browserify>util>is-arguments": { + "packages": { + "koa>is-generator-function>has-tostringtag": true, + "string.prototype.matchall>call-bind": true + } + }, + "browserify>util>is-typed-array": { + "packages": { + "browserify>util>is-typed-array>for-each": true, + "koa>is-generator-function>has-tostringtag": true, + "string.prototype.matchall>call-bind": true, + "string.prototype.matchall>es-abstract>available-typed-arrays": true, + "string.prototype.matchall>es-abstract>gopd": true + } + }, + "browserify>util>is-typed-array>for-each": { + "packages": { + "string.prototype.matchall>es-abstract>is-callable": true + } + }, + "browserify>util>which-typed-array": { + "packages": { + "browserify>util>is-typed-array": true, + "browserify>util>is-typed-array>for-each": true, + "koa>is-generator-function>has-tostringtag": true, + "string.prototype.matchall>call-bind": true, + "string.prototype.matchall>es-abstract>available-typed-arrays": true, + "string.prototype.matchall>es-abstract>gopd": true } }, "browserify>vm-browserify": { @@ -3423,6 +3502,22 @@ "document.createElement": true } }, + "chalk": { + "packages": { + "chalk>ansi-styles": true, + "chalk>supports-color": true + } + }, + "chalk>ansi-styles": { + "packages": { + "chalk>ansi-styles>color-convert": true + } + }, + "chalk>ansi-styles>color-convert": { + "packages": { + "jest-canvas-mock>moo-color>color-name": true + } + }, "classnames": { "globals": { "classNames": "write", @@ -3485,13 +3580,13 @@ }, "debounce-stream>duplexer": { "packages": { - "browserify>stream-browserify": true + "stream-browserify": true } }, "debounce-stream>through": { "packages": { "browserify>process": true, - "browserify>stream-browserify": true + "stream-browserify": true } }, "depcheck>@vue/compiler-sfc>postcss>nanoid": { @@ -3582,10 +3677,10 @@ "bn.js": true, "browserify>buffer": true, "browserify>crypto-browserify": true, - "browserify>events": true, "eth-lattice-keyring>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk": true, - "eth-lattice-keyring>rlp": true + "eth-lattice-keyring>rlp": true, + "webpack>events": true } }, "eth-lattice-keyring>@ethereumjs/tx": { @@ -3673,7 +3768,7 @@ "@ethereumjs/common>crc-32": true, "@ethereumjs/tx>@ethereumjs/util": true, "browserify>buffer": true, - "browserify>events": true + "webpack>events": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": { @@ -3693,7 +3788,7 @@ "@ethereumjs/common>crc-32": true, "@ethereumjs/tx>@ethereumjs/util": true, "browserify>buffer": true, - "browserify>events": true + "webpack>events": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": { @@ -3838,13 +3933,21 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethereum-cryptography": true, "eth-sig-util>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, "koa>content-disposition>safe-buffer": true } }, + "eth-sig-util>ethereumjs-util>ethereum-cryptography": { + "packages": { + "browserify>buffer": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "mocha>serialize-javascript>randombytes": true + } + }, "eth-sig-util>ethereumjs-util>ethjs-util": { "packages": { "browserify>buffer": true, @@ -3885,11 +3988,19 @@ "browserify>assert": true, "browserify>buffer": true, "eth-sig-util>ethereumjs-util>ethjs-util": true, + "ethereumjs-abi>ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true } }, + "ethereumjs-abi>ethereumjs-util>ethereum-cryptography": { + "packages": { + "browserify>buffer": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "mocha>serialize-javascript>randombytes": true + } + }, "ethereumjs-util": { "packages": { "bn.js": true, @@ -3912,10 +4023,10 @@ }, "ethereumjs-util>create-hash>cipher-base": { "packages": { - "browserify>stream-browserify": true, "browserify>string_decoder": true, "koa>content-disposition>safe-buffer": true, - "pumpify>inherits": true + "pumpify>inherits": true, + "stream-browserify": true } }, "ethereumjs-util>create-hash>md5.js": { @@ -3936,11 +4047,11 @@ "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "ethereumjs-util>create-hash>ripemd160": { @@ -3952,14 +4063,9 @@ }, "ethereumjs-util>ethereum-cryptography": { "packages": { - "browserify>assert": true, "browserify>buffer": true, - "browserify>crypto-browserify>create-hmac": true, - "ethereumjs-util>ethereum-cryptography>bs58check": true, - "ethereumjs-util>ethereum-cryptography>hash.js": true, "ethereumjs-util>ethereum-cryptography>keccak": true, "ethereumjs-util>ethereum-cryptography>secp256k1": true, - "koa>content-disposition>safe-buffer": true, "mocha>serialize-javascript>randombytes": true } }, @@ -4006,11 +4112,11 @@ "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "ethereumjs-util>ethereum-cryptography>scrypt-js": { @@ -4052,10 +4158,10 @@ "bn.js": true, "browserify>buffer": true, "ethjs-contract": true, - "ethjs-query": true, "ethjs>ethjs-abi": true, "ethjs>ethjs-filter": true, "ethjs>ethjs-provider-http": true, + "ethjs>ethjs-query": true, "ethjs>ethjs-unit": true, "ethjs>ethjs-util": true, "ethjs>js-sha3": true, @@ -4064,47 +4170,21 @@ }, "ethjs-contract": { "packages": { + "ethjs-contract>babel-runtime": true, "ethjs-contract>ethjs-abi": true, "ethjs-contract>ethjs-util": true, - "ethjs-query>babel-runtime": true, "ethjs>ethjs-filter": true, "ethjs>js-sha3": true, "promise-to-callback": true } }, - "ethjs-contract>ethjs-abi": { - "packages": { - "bn.js": true, - "browserify>buffer": 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 - }, - "packages": { - "ethjs-query>ethjs-format": true, - "ethjs-query>ethjs-rpc": true, - "promise-to-callback": true - } - }, - "ethjs-query>babel-runtime": { + "ethjs-contract>babel-runtime": { "packages": { - "@babel/runtime": true, - "@babel/runtime>regenerator-runtime": true, - "ethjs-query>babel-runtime>core-js": true + "ethjs-contract>babel-runtime>core-js": true, + "ethjs-contract>babel-runtime>regenerator-runtime": true } }, - "ethjs-query>babel-runtime>core-js": { + "ethjs-contract>babel-runtime>core-js": { "globals": { "PromiseRejectionEvent": true, "__e": "write", @@ -4114,24 +4194,29 @@ "setTimeout": true } }, - "ethjs-query>ethjs-format": { + "ethjs-contract>babel-runtime>regenerator-runtime": { + "globals": { + "regeneratorRuntime": "write" + } + }, + "ethjs-contract>ethjs-abi": { "packages": { - "ethjs-query>ethjs-format>ethjs-schema": true, - "ethjs-query>ethjs-format>ethjs-util": true, - "ethjs>ethjs-util>strip-hex-prefix": true, + "bn.js": true, + "browserify>buffer": true, + "ethjs>js-sha3": true, "ethjs>number-to-bn": true } }, - "ethjs-query>ethjs-format>ethjs-util": { + "ethjs-contract>ethjs-util": { "packages": { "browserify>buffer": true, "ethjs>ethjs-util>is-hex-prefixed": true, "ethjs>ethjs-util>strip-hex-prefix": true } }, - "ethjs-query>ethjs-rpc": { + "ethjs-query>babel-runtime": { "packages": { - "promise-to-callback": true + "@babel/runtime": true } }, "ethjs>ethjs-abi": { @@ -4158,6 +4243,16 @@ "XMLHttpRequest": true } }, + "ethjs>ethjs-query": { + "globals": { + "console": true + }, + "packages": { + "@metamask/ethjs-query>ethjs-format": true, + "@metamask/ethjs-query>ethjs-rpc": true, + "promise-to-callback": true + } + }, "ethjs>ethjs-unit": { "packages": { "bn.js": true, @@ -4190,7 +4285,7 @@ "extension-port-stream": { "packages": { "browserify>buffer": true, - "browserify>stream-browserify": true + "stream-browserify": true } }, "fast-json-patch": { @@ -4239,6 +4334,11 @@ "browserify>buffer": true } }, + "koa>is-generator-function": { + "packages": { + "koa>is-generator-function>has-tostringtag": true + } + }, "koa>is-generator-function>has-tostringtag": { "packages": { "string.prototype.matchall>has-symbols": true @@ -4310,11 +4410,11 @@ "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "mocha>serialize-javascript>randombytes": { @@ -4364,7 +4464,7 @@ "packages": { "await-semaphore": true, "browserify>assert": true, - "ethjs-query": true + "ethjs>ethjs-query": true } }, "obj-multiplex": { @@ -4908,7 +5008,6 @@ "readable-stream": { "packages": { "browserify>browser-resolve": true, - "browserify>events": true, "browserify>process": true, "browserify>timers-browserify": true, "pumpify>inherits": true, @@ -4917,7 +5016,8 @@ "readable-stream>process-nextick-args": true, "readable-stream>safe-buffer": true, "readable-stream>string_decoder": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "readable-stream>core-util-is": { @@ -4974,12 +5074,40 @@ "sinon>nise>path-to-regexp>isarray": true } }, + "stream-browserify": { + "packages": { + "pumpify>inherits": true, + "stream-browserify>readable-stream": true, + "webpack>events": true + } + }, + "stream-browserify>readable-stream": { + "packages": { + "browserify>browser-resolve": true, + "browserify>buffer": true, + "browserify>process": true, + "browserify>string_decoder": true, + "pumpify>inherits": true, + "readable-stream>util-deprecate": true, + "webpack>events": true + } + }, "string.prototype.matchall>call-bind": { "packages": { "browserify>has>function-bind": true, "string.prototype.matchall>get-intrinsic": true } }, + "string.prototype.matchall>es-abstract>gopd": { + "packages": { + "string.prototype.matchall>get-intrinsic": true + } + }, + "string.prototype.matchall>es-abstract>is-callable": { + "globals": { + "document": true + } + }, "string.prototype.matchall>es-abstract>is-regex": { "packages": { "koa>is-generator-function>has-tostringtag": true, @@ -5006,6 +5134,13 @@ "string.prototype.matchall>regexp.prototype.flags>functions-have-names": true } }, + "string.prototype.matchall>side-channel": { + "packages": { + "brfs>static-module>object-inspect": true, + "string.prototype.matchall>call-bind": true, + "string.prototype.matchall>get-intrinsic": true + } + }, "superstruct": { "globals": { "console.warn": true, diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index 62a2de0bf326..3edaafb89fe0 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -5,11 +5,6 @@ "regeneratorRuntime": "write" } }, - "@babel/runtime>regenerator-runtime": { - "globals": { - "regeneratorRuntime": "write" - } - }, "@download/blockies": { "globals": { "document.createElement": true @@ -131,7 +126,7 @@ "@ethereumjs/common>crc-32": true, "@ethereumjs/tx>@ethereumjs/util": true, "browserify>buffer": true, - "browserify>events": true + "webpack>events": true } }, "@ethereumjs/common>crc-32": { @@ -161,27 +156,11 @@ }, "packages": { "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography": true, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, + "@ethereumjs/tx>ethereum-cryptography": true, "browserify>buffer": true, - "browserify>events": true, - "browserify>insert-module-globals>is-buffer": true - } - }, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography>@noble/hashes": true, - "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true - } - }, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true + "browserify>insert-module-globals>is-buffer": true, + "webpack>events": true } }, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": { @@ -208,6 +187,7 @@ "crypto": true }, "packages": { + "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true, "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true } }, @@ -517,9 +497,9 @@ "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring": true, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": true, "browserify>buffer": true, - "browserify>events": true, "ethereumjs-util>rlp": true, - "uuid": true + "uuid": true, + "webpack>events": true } }, "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring": { @@ -542,7 +522,7 @@ "packages": { "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2": true, "@metamask/safe-event-emitter": true, - "browserify>stream-browserify": true + "stream-browserify": true } }, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2": { @@ -749,8 +729,8 @@ "@metamask-institutional/sdk>@metamask-institutional/types": true, "@metamask/obs-store": true, "browserify>crypto-browserify": true, - "browserify>events": true, - "gulp-sass>lodash.clonedeep": true + "gulp-sass>lodash.clonedeep": true, + "webpack>events": true } }, "@metamask-institutional/custody-keyring>@metamask-institutional/configuration-client": { @@ -795,7 +775,7 @@ "@metamask-institutional/sdk>bignumber.js": true, "@metamask-institutional/sdk>jsonwebtoken": true, "browserify>crypto-browserify": true, - "browserify>events": true + "webpack>events": true } }, "@metamask-institutional/sdk>bignumber.js": { @@ -820,9 +800,9 @@ "@metamask-institutional/sdk>jsonwebtoken>jws>jwa": true, "browserify>buffer": true, "browserify>process": true, - "browserify>stream-browserify": true, "browserify>util": true, - "koa>content-disposition>safe-buffer": true + "koa>content-disposition>safe-buffer": true, + "stream-browserify": true } }, "@metamask-institutional/sdk>jsonwebtoken>jws>jwa": { @@ -855,8 +835,8 @@ "@metamask-institutional/sdk": true, "@metamask-institutional/transaction-update>@metamask-institutional/websocket-client": true, "@metamask/obs-store": true, - "browserify>events": true, - "ethereumjs-util": true + "ethereumjs-util": true, + "webpack>events": true } }, "@metamask-institutional/transaction-update>@metamask-institutional/websocket-client": { @@ -867,7 +847,7 @@ "setTimeout": true }, "packages": { - "browserify>events": true + "webpack>events": true } }, "@metamask/address-book-controller": { @@ -920,12 +900,12 @@ "@metamask/controller-utils": true, "@metamask/metamask-eth-abis": true, "@metamask/utils": true, - "browserify>events": true, "eth-json-rpc-filters>async-mutex": true, "eth-query": true, "ethereumjs-util": true, "single-call-balance-checker-abi": true, - "uuid": true + "uuid": true, + "webpack>events": true } }, "@metamask/assets-controllers>@metamask/abi-utils": { @@ -1062,25 +1042,24 @@ "setTimeout": true }, "packages": { - "@metamask/eth-json-rpc-middleware>@metamask/utils": true, + "@metamask/eth-json-rpc-middleware>@metamask/eth-sig-util": 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, + "@metamask/utils": true, "eth-rpc-errors": true, "json-rpc-engine": true } }, - "@metamask/eth-json-rpc-middleware>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, + "@metamask/eth-json-rpc-middleware>@metamask/eth-sig-util": { "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "bn.js": true, "browserify>buffer": true, - "nock>debug": true, - "semver": true, - "superstruct": true + "eth-sig-util>ethereumjs-util>ethjs-util": true, + "eth-sig-util>tweetnacl": true, + "eth-sig-util>tweetnacl-util": true } }, "@metamask/eth-json-rpc-middleware>clone": { @@ -1089,13 +1068,17 @@ } }, "@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-sig-util": true, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring": true, - "@metamask/eth-keyring-controller>obs-store": true, - "browserify>events": true + "@metamask/eth-keyring-controller>@metamask/utils": true, + "@metamask/obs-store": true, + "webpack>events": true } }, "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring": { @@ -1105,7 +1088,7 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true, "@metamask/scure-bip39": true, "browserify>buffer": true } @@ -1150,7 +1133,7 @@ "@metamask/eth-keyring-controller>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, + "@ethereumjs/tx>ethereum-cryptography": true, "bn.js": true, "browserify>buffer": true, "eth-sig-util>ethereumjs-util>ethjs-util": true, @@ -1158,29 +1141,14 @@ "eth-sig-util>tweetnacl-util": true } }, - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true - } - }, - "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring>ethereum-cryptography": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true, "browserify>buffer": true, - "browserify>events": true, - "mocha>serialize-javascript>randombytes": true + "mocha>serialize-javascript>randombytes": true, + "webpack>events": true } }, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring>ethereum-cryptography": { @@ -1198,10 +1166,17 @@ "crypto": true } }, - "@metamask/eth-keyring-controller>obs-store": { + "@metamask/eth-keyring-controller>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, "packages": { - "@metamask/eth-token-tracker>safe-event-emitter": true, - "watchify>xtend": true + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true } }, "@metamask/eth-ledger-bridge-keyring": { @@ -1218,8 +1193,8 @@ "@metamask/eth-ledger-bridge-keyring>eth-sig-util": true, "@metamask/eth-ledger-bridge-keyring>hdkey": true, "browserify>buffer": true, - "browserify>events": true, - "ethereumjs-util": true + "ethereumjs-util": true, + "webpack>events": true } }, "@metamask/eth-ledger-bridge-keyring>eth-sig-util": { @@ -1233,17 +1208,25 @@ }, "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util": { "packages": { + "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethereum-cryptography": true, "@metamask/ppom-validator>elliptic": 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, "koa>content-disposition>safe-buffer": true } }, + "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethereum-cryptography": { + "packages": { + "browserify>buffer": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "mocha>serialize-javascript>randombytes": true + } + }, "@metamask/eth-ledger-bridge-keyring>hdkey": { "packages": { "@metamask/eth-ledger-bridge-keyring>hdkey>secp256k1": true, @@ -1263,32 +1246,6 @@ "koa>content-disposition>safe-buffer": true } }, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": { - "packages": { - "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/eth-snap-keyring>@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/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true - } - }, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "@metamask/eth-token-tracker": { "globals": { "console.warn": true @@ -1301,25 +1258,19 @@ "@metamask/eth-token-tracker>human-standard-token-abi": true, "@metamask/eth-token-tracker>safe-event-emitter": true, "ethjs-contract": true, - "ethjs-query": true + "ethjs>ethjs-query": true } }, "@metamask/eth-token-tracker>deep-equal": { "packages": { - "@metamask/eth-token-tracker>deep-equal>is-arguments": true, "@metamask/eth-token-tracker>deep-equal>is-date-object": true, "@ngraveio/bc-ur>assert>object-is": true, + "browserify>util>is-arguments": true, "globalthis>define-properties>object-keys": true, "string.prototype.matchall>es-abstract>is-regex": true, "string.prototype.matchall>regexp.prototype.flags": true } }, - "@metamask/eth-token-tracker>deep-equal>is-arguments": { - "packages": { - "koa>is-generator-function>has-tostringtag": true, - "string.prototype.matchall>call-bind": true - } - }, "@metamask/eth-token-tracker>deep-equal>is-date-object": { "packages": { "koa>is-generator-function>has-tostringtag": true @@ -1368,7 +1319,7 @@ "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-contract>babel-runtime": true, "ethjs>ethjs-filter": true, "ethjs>js-sha3": true, "promise-to-callback": true @@ -1387,9 +1338,9 @@ "console": true }, "packages": { - "ethjs-query>babel-runtime": true, - "ethjs-query>ethjs-format": true, - "ethjs-query>ethjs-rpc": true, + "@metamask/ethjs-query>ethjs-format": true, + "@metamask/ethjs-query>ethjs-rpc": true, + "ethjs-contract>babel-runtime": true, "promise-to-callback": true } }, @@ -1421,7 +1372,18 @@ "@metamask/eth-trezor-keyring>@trezor/connect-web": true, "@metamask/eth-trezor-keyring>hdkey": true, "browserify>buffer": true, - "browserify>events": true + "webpack>events": true + } + }, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": { + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@ethereumjs/tx>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/eth-trezor-keyring>@metamask/utils": { @@ -1438,7 +1400,7 @@ }, "@metamask/eth-trezor-keyring>@trezor/connect-plugin-ethereum": { "packages": { - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web": { @@ -1463,8 +1425,8 @@ "packages": { "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect": true, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/utils": true, - "browserify>events": true, - "mockttp>graphql-tag>tslib": true + "mockttp>graphql-tag>tslib": true, + "webpack>events": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect": { @@ -1495,8 +1457,8 @@ "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect>@trezor/transport>protobufjs": true, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/utils": true, "browserify>buffer": true, - "browserify>events": true, - "lavamoat>json-stable-stringify": true + "lavamoat>json-stable-stringify": true, + "webpack>events": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web>@trezor/connect>@trezor/transport>bytebuffer": { @@ -1597,6 +1559,36 @@ "URL": true } }, + "@metamask/ethjs-query": { + "globals": { + "console": true + }, + "packages": { + "@metamask/ethjs-query>ethjs-format": true, + "@metamask/ethjs-query>ethjs-rpc": true, + "promise-to-callback": true + } + }, + "@metamask/ethjs-query>ethjs-format": { + "packages": { + "@metamask/ethjs-query>ethjs-format>ethjs-schema": true, + "@metamask/ethjs-query>ethjs-format>ethjs-util": true, + "ethjs>ethjs-util>strip-hex-prefix": true, + "ethjs>number-to-bn": true + } + }, + "@metamask/ethjs-query>ethjs-format>ethjs-util": { + "packages": { + "browserify>buffer": true, + "ethjs>ethjs-util>is-hex-prefixed": true, + "ethjs>ethjs-util>strip-hex-prefix": true + } + }, + "@metamask/ethjs-query>ethjs-rpc": { + "packages": { + "promise-to-callback": true + } + }, "@metamask/gas-fee-controller": { "globals": { "clearInterval": true, @@ -1644,6 +1636,29 @@ "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": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, "@metamask/key-tree>@noble/ed25519": { "globals": { "crypto": true @@ -1675,53 +1690,13 @@ "@metamask/keyring-controller": { "packages": { "@metamask/base-controller": true, - "@metamask/keyring-controller>@metamask/eth-keyring-controller": true, + "@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, @@ -1737,29 +1712,48 @@ }, "@metamask/keyring-controller>ethereumjs-wallet": { "packages": { + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": true, "@truffle/codec>utf8": true, "browserify>buffer": true, "browserify>crypto-browserify": true, "eth-lattice-keyring>gridplus-sdk>aes-js": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>ethereum-cryptography>bs58check": true, "ethereumjs-util>ethereum-cryptography>scrypt-js": true, "mocha>serialize-javascript>randombytes": true, "uuid": true } }, + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": { + "packages": { + "browserify>assert": true, + "browserify>buffer": true, + "browserify>crypto-browserify>create-hmac": true, + "ethereumjs-util>ethereum-cryptography>bs58check": true, + "ethereumjs-util>ethereum-cryptography>hash.js": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "koa>content-disposition>safe-buffer": true, + "mocha>serialize-javascript>randombytes": true + } + }, "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": { "packages": { + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, "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/logging-controller": { + "packages": { + "@metamask/base-controller": true, + "uuid": true + } + }, "@metamask/logo": { "globals": { "addEventListener": true, @@ -1777,39 +1771,87 @@ "@metamask/message-manager": { "packages": { "@metamask/base-controller": true, - "@metamask/controller-utils": true, + "@metamask/message-manager>@metamask/controller-utils": true, "@metamask/message-manager>@metamask/eth-sig-util": true, "@metamask/message-manager>jsonschema": true, "browserify>buffer": true, - "browserify>events": true, "ethereumjs-util": true, - "uuid": true + "uuid": true, + "webpack>events": true + } + }, + "@metamask/message-manager>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "@metamask/message-manager>@metamask/utils": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true, + "ethereumjs-util": true, + "ethjs>ethjs-unit": 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, + "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/abi-utils": true, + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/utils": 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": { + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/abi-utils": { + "packages": { + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/abi-utils>@metamask/utils": true, + "superstruct": true + } + }, + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/abi-utils>@metamask/utils": { "globals": { "TextDecoder": true, - "crypto": true + "TextEncoder": true }, "packages": { - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true } }, - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { + "@metamask/message-manager>@metamask/eth-sig-util>@metamask/utils": { "globals": { - "TextEncoder": true, - "crypto": true + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, + "@metamask/message-manager>@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/message-manager>jsonschema": { @@ -1817,6 +1859,29 @@ "browserify>url": true } }, + "@metamask/name-controller": { + "globals": { + "fetch": true + }, + "packages": { + "@metamask/base-controller": true, + "@metamask/name-controller>@metamask/utils": true, + "eth-json-rpc-filters>async-mutex": true + } + }, + "@metamask/name-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/network-controller": { "globals": { "URL": true, @@ -1901,7 +1966,7 @@ "setTimeout": true }, "packages": { - "browserify>events": true + "webpack>events": true } }, "@metamask/notification-controller": { @@ -1920,7 +1985,7 @@ "packages": { "@metamask/obs-store>through2": true, "@metamask/safe-event-emitter": true, - "browserify>stream-browserify": true + "stream-browserify": true } }, "@metamask/obs-store>through2": { @@ -1942,88 +2007,42 @@ "@metamask/permission-controller>nanoid": true, "deep-freeze-strict": true, "eth-rpc-errors": true, - "immer": true, - "json-rpc-engine": true - } - }, - "@metamask/permission-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/permission-controller>nanoid": { - "globals": { - "crypto.getRandomValues": true - } - }, - "@metamask/phishing-controller": { - "globals": { - "fetch": true - }, - "packages": { - "@metamask/base-controller": true, - "@metamask/controller-utils": true, - "@metamask/phishing-warning>eth-phishing-detect": true, - "punycode": true - } - }, - "@metamask/phishing-warning>eth-phishing-detect": { - "packages": { - "eslint>optionator>fast-levenshtein": true - } - }, - "@metamask/post-message-stream": { - "globals": { - "MessageEvent.prototype": true, - "WorkerGlobalScope": true, - "addEventListener": true, - "browser": true, - "chrome": true, - "location.origin": true, - "postMessage": true, - "removeEventListener": true - }, - "packages": { - "@metamask/post-message-stream>readable-stream": true, - "@metamask/utils": true - } - }, - "@metamask/post-message-stream>readable-stream": { - "packages": { - "@metamask/post-message-stream>readable-stream>process-nextick-args": true, - "@metamask/post-message-stream>readable-stream>safe-buffer": true, - "@metamask/post-message-stream>readable-stream>string_decoder": true, - "browserify>browser-resolve": true, - "browserify>events": true, - "browserify>process": true, - "browserify>timers-browserify": true, - "pumpify>inherits": true, - "readable-stream>core-util-is": true, - "readable-stream>isarray": true, - "readable-stream>util-deprecate": true + "immer": true, + "json-rpc-engine": true } }, - "@metamask/post-message-stream>readable-stream>process-nextick-args": { + "@metamask/permission-controller>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, "packages": { - "browserify>process": true + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, + "@metamask/permission-controller>nanoid": { + "globals": { + "crypto.getRandomValues": true } }, - "@metamask/post-message-stream>readable-stream>safe-buffer": { + "@metamask/phishing-controller": { + "globals": { + "fetch": true + }, "packages": { - "browserify>buffer": true + "@metamask/base-controller": true, + "@metamask/controller-utils": true, + "@metamask/phishing-warning>eth-phishing-detect": true, + "punycode": true } }, - "@metamask/post-message-stream>readable-stream>string_decoder": { + "@metamask/phishing-warning>eth-phishing-detect": { "packages": { - "@metamask/post-message-stream>readable-stream>safe-buffer": true + "eslint>optionator>fast-levenshtein": true } }, "@metamask/ppom-validator>elliptic": { @@ -2074,12 +2093,10 @@ }, "@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, "@metamask/snaps-utils": true, "eth-rpc-errors": true, @@ -2091,16 +2108,6 @@ "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, @@ -2124,7 +2131,7 @@ "setTimeout": true }, "packages": { - "browserify>events": true + "webpack>events": true } }, "@metamask/scure-bip39": { @@ -2156,10 +2163,10 @@ "@metamask/controller-utils": true, "@metamask/message-manager": true, "browserify>buffer": true, - "browserify>events": true, "eth-rpc-errors": true, "ethereumjs-util": true, - "lodash": true + "lodash": true, + "webpack>events": true } }, "@metamask/smart-transactions-controller": { @@ -2206,9 +2213,9 @@ "packages": { "@metamask/base-controller": true, "@metamask/permission-controller": true, - "@metamask/post-message-stream": true, "@metamask/providers>@metamask/object-multiplex": true, "@metamask/rpc-methods": true, + "@metamask/snaps-controllers>@metamask/post-message-stream": true, "@metamask/snaps-controllers>@metamask/utils": true, "@metamask/snaps-controllers>@xstate/fsm": true, "@metamask/snaps-controllers>concat-stream": true, @@ -2221,7 +2228,7 @@ "eth-rpc-errors": true, "json-rpc-engine": true, "json-rpc-middleware-stream": true, - "pump": true + "stream-browserify": true } }, "@metamask/snaps-controllers-flask>nanoid": { @@ -2229,6 +2236,34 @@ "crypto.getRandomValues": true } }, + "@metamask/snaps-controllers>@metamask/post-message-stream": { + "globals": { + "MessageEvent.prototype": true, + "WorkerGlobalScope": true, + "addEventListener": true, + "browser": true, + "chrome": true, + "location.origin": true, + "postMessage": true, + "removeEventListener": true + }, + "packages": { + "@metamask/snaps-controllers>@metamask/post-message-stream>@metamask/utils": true, + "@metamask/snaps-controllers>concat-stream>readable-stream": true + } + }, + "@metamask/snaps-controllers>@metamask/post-message-stream>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, "@metamask/snaps-controllers>@metamask/utils": { "globals": { "TextDecoder": true, @@ -2255,11 +2290,11 @@ "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "@metamask/snaps-controllers>gunzip-maybe": { @@ -2354,11 +2389,11 @@ "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "@metamask/snaps-controllers>tar-stream": { @@ -2383,11 +2418,11 @@ "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "@metamask/snaps-ui": { @@ -2420,28 +2455,23 @@ "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, + "@metamask/snaps-utils>is-svg": true, "@metamask/snaps-utils>rfdc": true, "@metamask/snaps-utils>validate-npm-package-name": true, + "browserify>buffer": true, + "browserify>path-browserify": true, + "browserify>process": true, + "chalk": true, "semver": true, "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/snaps-registry": { "packages": { "@metamask/key-tree>@noble/secp256k1": true, @@ -2481,6 +2511,20 @@ "luxon": true } }, + "@metamask/snaps-utils>is-svg": { + "packages": { + "@metamask/snaps-utils>is-svg>fast-xml-parser": true + } + }, + "@metamask/snaps-utils>is-svg>fast-xml-parser": { + "globals": { + "entityName": true, + "val": true + }, + "packages": { + "@metamask/snaps-utils>is-svg>fast-xml-parser>strnum": true + } + }, "@metamask/snaps-utils>rfdc": { "packages": { "browserify>buffer": true @@ -2729,6 +2773,11 @@ "browserify>process": true } }, + "@storybook/addon-knobs>qs": { + "packages": { + "string.prototype.matchall>side-channel": true + } + }, "@truffle/codec": { "packages": { "@truffle/codec>@truffle/abi-utils": true, @@ -2904,9 +2953,9 @@ "@truffle/codec>cbor>nofilter": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, - "browserify>stream-browserify": true, "browserify>url": true, - "browserify>util": true + "browserify>util": true, + "stream-browserify": true } }, "@truffle/codec>cbor>bignumber.js": { @@ -2918,8 +2967,8 @@ "@truffle/codec>cbor>nofilter": { "packages": { "browserify>buffer": true, - "browserify>stream-browserify": true, - "browserify>util": true + "browserify>util": true, + "stream-browserify": true } }, "@truffle/codec>web3-utils": { @@ -3250,6 +3299,15 @@ "define": true } }, + "brfs>static-module>object-inspect": { + "globals": { + "HTMLElement": true, + "WeakRef": true + }, + "packages": { + "browserify>browser-resolve": true + } + }, "browserify>assert": { "globals": { "Buffer": true @@ -3282,8 +3340,8 @@ "browserify>browserify-zlib>pako": true, "browserify>buffer": true, "browserify>process": true, - "browserify>stream-browserify": true, - "browserify>util": true + "browserify>util": true, + "stream-browserify": true } }, "browserify>buffer": { @@ -3344,9 +3402,9 @@ "browserify>crypto-browserify>create-hmac": true, "browserify>crypto-browserify>public-encrypt>browserify-rsa": true, "browserify>crypto-browserify>public-encrypt>parse-asn1": true, - "browserify>stream-browserify": true, "ethereumjs-util>create-hash": true, - "pumpify>inherits": true + "pumpify>inherits": true, + "stream-browserify": true } }, "browserify>crypto-browserify>create-ecdh": { @@ -3442,11 +3500,6 @@ "mocha>serialize-javascript>randombytes": true } }, - "browserify>events": { - "globals": { - "console": true - } - }, "browserify>has": { "packages": { "browserify>has>function-bind": true @@ -3480,13 +3533,6 @@ "define": true } }, - "browserify>stream-browserify": { - "packages": { - "browserify>events": true, - "pumpify>inherits": true, - "readable-stream": true - } - }, "browserify>stream-http": { "globals": { "AbortController": true, @@ -3515,11 +3561,11 @@ "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "browserify>string_decoder": { @@ -3540,20 +3586,53 @@ }, "browserify>url": { "packages": { - "browserify>punycode": true, - "browserify>querystring-es3": true + "@storybook/addon-knobs>qs": true, + "browserify>punycode": true } }, "browserify>util": { "globals": { "console.error": true, "console.log": true, - "console.trace": true, - "process": true + "console.trace": true }, "packages": { "browserify>process": true, - "browserify>util>inherits": true + "browserify>util>is-arguments": true, + "browserify>util>is-typed-array": true, + "browserify>util>which-typed-array": true, + "koa>is-generator-function": true, + "pumpify>inherits": true + } + }, + "browserify>util>is-arguments": { + "packages": { + "koa>is-generator-function>has-tostringtag": true, + "string.prototype.matchall>call-bind": true + } + }, + "browserify>util>is-typed-array": { + "packages": { + "browserify>util>is-typed-array>for-each": true, + "koa>is-generator-function>has-tostringtag": true, + "string.prototype.matchall>call-bind": true, + "string.prototype.matchall>es-abstract>available-typed-arrays": true, + "string.prototype.matchall>es-abstract>gopd": true + } + }, + "browserify>util>is-typed-array>for-each": { + "packages": { + "string.prototype.matchall>es-abstract>is-callable": true + } + }, + "browserify>util>which-typed-array": { + "packages": { + "browserify>util>is-typed-array": true, + "browserify>util>is-typed-array>for-each": true, + "koa>is-generator-function>has-tostringtag": true, + "string.prototype.matchall>call-bind": true, + "string.prototype.matchall>es-abstract>available-typed-arrays": true, + "string.prototype.matchall>es-abstract>gopd": true } }, "browserify>vm-browserify": { @@ -3563,6 +3642,22 @@ "document.createElement": true } }, + "chalk": { + "packages": { + "chalk>ansi-styles": true, + "chalk>supports-color": true + } + }, + "chalk>ansi-styles": { + "packages": { + "chalk>ansi-styles>color-convert": true + } + }, + "chalk>ansi-styles>color-convert": { + "packages": { + "jest-canvas-mock>moo-color>color-name": true + } + }, "classnames": { "globals": { "classNames": "write", @@ -3625,13 +3720,13 @@ }, "debounce-stream>duplexer": { "packages": { - "browserify>stream-browserify": true + "stream-browserify": true } }, "debounce-stream>through": { "packages": { "browserify>process": true, - "browserify>stream-browserify": true + "stream-browserify": true } }, "depcheck>@vue/compiler-sfc>postcss>nanoid": { @@ -3722,10 +3817,10 @@ "bn.js": true, "browserify>buffer": true, "browserify>crypto-browserify": true, - "browserify>events": true, "eth-lattice-keyring>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk": true, - "eth-lattice-keyring>rlp": true + "eth-lattice-keyring>rlp": true, + "webpack>events": true } }, "eth-lattice-keyring>@ethereumjs/tx": { @@ -3813,7 +3908,7 @@ "@ethereumjs/common>crc-32": true, "@ethereumjs/tx>@ethereumjs/util": true, "browserify>buffer": true, - "browserify>events": true + "webpack>events": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": { @@ -3833,7 +3928,7 @@ "@ethereumjs/common>crc-32": true, "@ethereumjs/tx>@ethereumjs/util": true, "browserify>buffer": true, - "browserify>events": true + "webpack>events": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": { @@ -3978,13 +4073,21 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, + "eth-sig-util>ethereumjs-util>ethereum-cryptography": true, "eth-sig-util>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, "koa>content-disposition>safe-buffer": true } }, + "eth-sig-util>ethereumjs-util>ethereum-cryptography": { + "packages": { + "browserify>buffer": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "mocha>serialize-javascript>randombytes": true + } + }, "eth-sig-util>ethereumjs-util>ethjs-util": { "packages": { "browserify>buffer": true, @@ -4025,11 +4128,19 @@ "browserify>assert": true, "browserify>buffer": true, "eth-sig-util>ethereumjs-util>ethjs-util": true, + "ethereumjs-abi>ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true } }, + "ethereumjs-abi>ethereumjs-util>ethereum-cryptography": { + "packages": { + "browserify>buffer": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "mocha>serialize-javascript>randombytes": true + } + }, "ethereumjs-util": { "packages": { "bn.js": true, @@ -4052,10 +4163,10 @@ }, "ethereumjs-util>create-hash>cipher-base": { "packages": { - "browserify>stream-browserify": true, "browserify>string_decoder": true, "koa>content-disposition>safe-buffer": true, - "pumpify>inherits": true + "pumpify>inherits": true, + "stream-browserify": true } }, "ethereumjs-util>create-hash>md5.js": { @@ -4076,11 +4187,11 @@ "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "ethereumjs-util>create-hash>ripemd160": { @@ -4092,14 +4203,9 @@ }, "ethereumjs-util>ethereum-cryptography": { "packages": { - "browserify>assert": true, "browserify>buffer": true, - "browserify>crypto-browserify>create-hmac": true, - "ethereumjs-util>ethereum-cryptography>bs58check": true, - "ethereumjs-util>ethereum-cryptography>hash.js": true, "ethereumjs-util>ethereum-cryptography>keccak": true, "ethereumjs-util>ethereum-cryptography>secp256k1": true, - "koa>content-disposition>safe-buffer": true, "mocha>serialize-javascript>randombytes": true } }, @@ -4146,11 +4252,11 @@ "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "ethereumjs-util>ethereum-cryptography>scrypt-js": { @@ -4192,10 +4298,10 @@ "bn.js": true, "browserify>buffer": true, "ethjs-contract": true, - "ethjs-query": true, "ethjs>ethjs-abi": true, "ethjs>ethjs-filter": true, "ethjs>ethjs-provider-http": true, + "ethjs>ethjs-query": true, "ethjs>ethjs-unit": true, "ethjs>ethjs-util": true, "ethjs>js-sha3": true, @@ -4204,47 +4310,21 @@ }, "ethjs-contract": { "packages": { + "ethjs-contract>babel-runtime": true, "ethjs-contract>ethjs-abi": true, "ethjs-contract>ethjs-util": true, - "ethjs-query>babel-runtime": true, "ethjs>ethjs-filter": true, "ethjs>js-sha3": true, "promise-to-callback": true } }, - "ethjs-contract>ethjs-abi": { - "packages": { - "bn.js": true, - "browserify>buffer": 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 - }, - "packages": { - "ethjs-query>ethjs-format": true, - "ethjs-query>ethjs-rpc": true, - "promise-to-callback": true - } - }, - "ethjs-query>babel-runtime": { + "ethjs-contract>babel-runtime": { "packages": { - "@babel/runtime": true, - "@babel/runtime>regenerator-runtime": true, - "ethjs-query>babel-runtime>core-js": true + "ethjs-contract>babel-runtime>core-js": true, + "ethjs-contract>babel-runtime>regenerator-runtime": true } }, - "ethjs-query>babel-runtime>core-js": { + "ethjs-contract>babel-runtime>core-js": { "globals": { "PromiseRejectionEvent": true, "__e": "write", @@ -4254,24 +4334,29 @@ "setTimeout": true } }, - "ethjs-query>ethjs-format": { + "ethjs-contract>babel-runtime>regenerator-runtime": { + "globals": { + "regeneratorRuntime": "write" + } + }, + "ethjs-contract>ethjs-abi": { "packages": { - "ethjs-query>ethjs-format>ethjs-schema": true, - "ethjs-query>ethjs-format>ethjs-util": true, - "ethjs>ethjs-util>strip-hex-prefix": true, + "bn.js": true, + "browserify>buffer": true, + "ethjs>js-sha3": true, "ethjs>number-to-bn": true } }, - "ethjs-query>ethjs-format>ethjs-util": { + "ethjs-contract>ethjs-util": { "packages": { "browserify>buffer": true, "ethjs>ethjs-util>is-hex-prefixed": true, "ethjs>ethjs-util>strip-hex-prefix": true } }, - "ethjs-query>ethjs-rpc": { + "ethjs-query>babel-runtime": { "packages": { - "promise-to-callback": true + "@babel/runtime": true } }, "ethjs>ethjs-abi": { @@ -4298,6 +4383,16 @@ "XMLHttpRequest": true } }, + "ethjs>ethjs-query": { + "globals": { + "console": true + }, + "packages": { + "@metamask/ethjs-query>ethjs-format": true, + "@metamask/ethjs-query>ethjs-rpc": true, + "promise-to-callback": true + } + }, "ethjs>ethjs-unit": { "packages": { "bn.js": true, @@ -4330,7 +4425,7 @@ "extension-port-stream": { "packages": { "browserify>buffer": true, - "browserify>stream-browserify": true + "stream-browserify": true } }, "fast-json-patch": { @@ -4379,6 +4474,11 @@ "browserify>buffer": true } }, + "koa>is-generator-function": { + "packages": { + "koa>is-generator-function>has-tostringtag": true + } + }, "koa>is-generator-function>has-tostringtag": { "packages": { "string.prototype.matchall>has-symbols": true @@ -4450,11 +4550,11 @@ "packages": { "browserify>browser-resolve": true, "browserify>buffer": true, - "browserify>events": true, "browserify>process": true, "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "mocha>serialize-javascript>randombytes": { @@ -4504,7 +4604,7 @@ "packages": { "await-semaphore": true, "browserify>assert": true, - "ethjs-query": true + "ethjs>ethjs-query": true } }, "obj-multiplex": { @@ -5048,7 +5148,6 @@ "readable-stream": { "packages": { "browserify>browser-resolve": true, - "browserify>events": true, "browserify>process": true, "browserify>timers-browserify": true, "pumpify>inherits": true, @@ -5057,7 +5156,8 @@ "readable-stream>process-nextick-args": true, "readable-stream>safe-buffer": true, "readable-stream>string_decoder": true, - "readable-stream>util-deprecate": true + "readable-stream>util-deprecate": true, + "webpack>events": true } }, "readable-stream>core-util-is": { @@ -5114,12 +5214,40 @@ "sinon>nise>path-to-regexp>isarray": true } }, + "stream-browserify": { + "packages": { + "pumpify>inherits": true, + "stream-browserify>readable-stream": true, + "webpack>events": true + } + }, + "stream-browserify>readable-stream": { + "packages": { + "browserify>browser-resolve": true, + "browserify>buffer": true, + "browserify>process": true, + "browserify>string_decoder": true, + "pumpify>inherits": true, + "readable-stream>util-deprecate": true, + "webpack>events": true + } + }, "string.prototype.matchall>call-bind": { "packages": { "browserify>has>function-bind": true, "string.prototype.matchall>get-intrinsic": true } }, + "string.prototype.matchall>es-abstract>gopd": { + "packages": { + "string.prototype.matchall>get-intrinsic": true + } + }, + "string.prototype.matchall>es-abstract>is-callable": { + "globals": { + "document": true + } + }, "string.prototype.matchall>es-abstract>is-regex": { "packages": { "koa>is-generator-function>has-tostringtag": true, @@ -5146,6 +5274,13 @@ "string.prototype.matchall>regexp.prototype.flags>functions-have-names": true } }, + "string.prototype.matchall>side-channel": { + "packages": { + "brfs>static-module>object-inspect": true, + "string.prototype.matchall>call-bind": true, + "string.prototype.matchall>get-intrinsic": true + } + }, "superstruct": { "globals": { "console.warn": true, diff --git a/lavamoat/build-system/policy.json b/lavamoat/build-system/policy.json index daa7b4e8717b..f6fcc3efe20f 100644 --- a/lavamoat/build-system/policy.json +++ b/lavamoat/build-system/policy.json @@ -6,9 +6,46 @@ "process.emitWarning": true }, "packages": { + "@babel/code-frame>chalk": true, "lavamoat>@babel/highlight": true } }, + "@babel/code-frame>chalk": { + "globals": { + "process.env.TERM": true, + "process.platform": true + }, + "packages": { + "@babel/code-frame>chalk>ansi-styles": true, + "@babel/code-frame>chalk>escape-string-regexp": true, + "@babel/code-frame>chalk>supports-color": true + } + }, + "@babel/code-frame>chalk>ansi-styles": { + "packages": { + "@metamask/jazzicon>color>color-convert": true + } + }, + "@babel/code-frame>chalk>supports-color": { + "builtin": { + "os.release": true + }, + "globals": { + "process.env": true, + "process.platform": true, + "process.stderr": true, + "process.stdout": true, + "process.versions.node.split": true + }, + "packages": { + "@babel/code-frame>chalk>supports-color>has-flag": true + } + }, + "@babel/code-frame>chalk>supports-color>has-flag": { + "globals": { + "process.argv": true + } + }, "@babel/core": { "builtin": { "assert": true, @@ -40,6 +77,7 @@ "@babel/core>@babel/parser": true, "@babel/core>@babel/template": true, "@babel/core>@babel/types": true, + "@babel/core>convert-source-map": true, "@babel/core>gensync": true, "@babel/core>semver": true, "@babel/plugin-proposal-class-properties": true, @@ -52,8 +90,7 @@ "@babel/preset-typescript": true, "depcheck>@babel/traverse": true, "depcheck>json5": true, - "nock>debug": true, - "nyc>convert-source-map": true + "nock>debug": true } }, "@babel/core>@ampproject/remapping": { @@ -67,7 +104,8 @@ }, "@babel/core>@babel/generator": { "globals": { - "console.error": true + "console.error": true, + "console.warn": true }, "packages": { "@babel/core>@babel/generator>jsesc": true, @@ -112,11 +150,9 @@ "path.extname": true }, "packages": { + "@babel/core": true, "@babel/core>@babel/helper-module-transforms>@babel/helper-module-imports": true, "@babel/core>@babel/helper-module-transforms>@babel/helper-simple-access": true, - "@babel/core>@babel/template": true, - "@babel/core>@babel/types": true, - "depcheck>@babel/traverse": true, "depcheck>@babel/traverse>@babel/helper-environment-visitor": true, "depcheck>@babel/traverse>@babel/helper-split-export-declaration": true, "lavamoat>@babel/highlight>@babel/helper-validator-identifier": true @@ -160,6 +196,14 @@ "lavamoat>@babel/highlight>@babel/helper-validator-identifier": true } }, + "@babel/core>convert-source-map": { + "globals": { + "Buffer": true, + "atob": true, + "btoa": true, + "value": true + } + }, "@babel/core>semver": { "globals": { "console": true, @@ -180,13 +224,18 @@ "packages": { "@babel/core": true, "@babel/core>@babel/parser": true, + "@babel/eslint-parser>@nicolo-ribaudo/eslint-scope-5-internals": true, "@babel/eslint-parser>eslint-scope": true, "@babel/eslint-parser>eslint-visitor-keys": true, "@babel/eslint-parser>semver": true, "@babel/parser": true, "depcheck>@babel/parser": true, "eslint": true, - "lavamoat>lavamoat-tofu>@babel/parser": true, + "lavamoat>lavamoat-tofu>@babel/parser": true + } + }, + "@babel/eslint-parser>@nicolo-ribaudo/eslint-scope-5-internals": { + "packages": { "webpack>eslint-scope": true } }, @@ -217,27 +266,13 @@ "@babel/preset-env>@babel/helper-validator-option": true, "@babel/preset-env>@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": true, "@babel/preset-env>@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": true, - "@babel/preset-env>@babel/plugin-proposal-async-generator-functions": true, - "@babel/preset-env>@babel/plugin-proposal-class-properties": true, - "@babel/preset-env>@babel/plugin-proposal-class-static-block": true, - "@babel/preset-env>@babel/plugin-proposal-dynamic-import": true, - "@babel/preset-env>@babel/plugin-proposal-export-namespace-from": true, - "@babel/preset-env>@babel/plugin-proposal-json-strings": true, - "@babel/preset-env>@babel/plugin-proposal-logical-assignment-operators": true, - "@babel/preset-env>@babel/plugin-proposal-nullish-coalescing-operator": true, - "@babel/preset-env>@babel/plugin-proposal-numeric-separator": true, - "@babel/preset-env>@babel/plugin-proposal-object-rest-spread": true, - "@babel/preset-env>@babel/plugin-proposal-optional-catch-binding": true, - "@babel/preset-env>@babel/plugin-proposal-optional-chaining": true, - "@babel/preset-env>@babel/plugin-proposal-private-methods": true, - "@babel/preset-env>@babel/plugin-proposal-private-property-in-object": true, - "@babel/preset-env>@babel/plugin-proposal-unicode-property-regex": true, "@babel/preset-env>@babel/plugin-syntax-async-generators": true, "@babel/preset-env>@babel/plugin-syntax-class-properties": true, "@babel/preset-env>@babel/plugin-syntax-class-static-block": true, "@babel/preset-env>@babel/plugin-syntax-dynamic-import": true, "@babel/preset-env>@babel/plugin-syntax-export-namespace-from": true, "@babel/preset-env>@babel/plugin-syntax-import-assertions": true, + "@babel/preset-env>@babel/plugin-syntax-import-attributes": true, "@babel/preset-env>@babel/plugin-syntax-import-meta": true, "@babel/preset-env>@babel/plugin-syntax-json-strings": true, "@babel/preset-env>@babel/plugin-syntax-logical-assignment-operators": true, @@ -248,19 +283,27 @@ "@babel/preset-env>@babel/plugin-syntax-optional-chaining": true, "@babel/preset-env>@babel/plugin-syntax-private-property-in-object": true, "@babel/preset-env>@babel/plugin-syntax-top-level-await": true, + "@babel/preset-env>@babel/plugin-syntax-unicode-sets-regex": true, "@babel/preset-env>@babel/plugin-transform-arrow-functions": true, + "@babel/preset-env>@babel/plugin-transform-async-generator-functions": true, "@babel/preset-env>@babel/plugin-transform-async-to-generator": true, "@babel/preset-env>@babel/plugin-transform-block-scoped-functions": true, "@babel/preset-env>@babel/plugin-transform-block-scoping": true, + "@babel/preset-env>@babel/plugin-transform-class-properties": true, + "@babel/preset-env>@babel/plugin-transform-class-static-block": true, "@babel/preset-env>@babel/plugin-transform-classes": true, "@babel/preset-env>@babel/plugin-transform-computed-properties": true, "@babel/preset-env>@babel/plugin-transform-destructuring": true, "@babel/preset-env>@babel/plugin-transform-dotall-regex": true, "@babel/preset-env>@babel/plugin-transform-duplicate-keys": true, + "@babel/preset-env>@babel/plugin-transform-dynamic-import": true, "@babel/preset-env>@babel/plugin-transform-exponentiation-operator": true, + "@babel/preset-env>@babel/plugin-transform-export-namespace-from": true, "@babel/preset-env>@babel/plugin-transform-for-of": true, "@babel/preset-env>@babel/plugin-transform-function-name": true, + "@babel/preset-env>@babel/plugin-transform-json-strings": true, "@babel/preset-env>@babel/plugin-transform-literals": true, + "@babel/preset-env>@babel/plugin-transform-logical-assignment-operators": true, "@babel/preset-env>@babel/plugin-transform-member-expression-literals": true, "@babel/preset-env>@babel/plugin-transform-modules-amd": true, "@babel/preset-env>@babel/plugin-transform-modules-commonjs": true, @@ -268,8 +311,15 @@ "@babel/preset-env>@babel/plugin-transform-modules-umd": true, "@babel/preset-env>@babel/plugin-transform-named-capturing-groups-regex": true, "@babel/preset-env>@babel/plugin-transform-new-target": true, + "@babel/preset-env>@babel/plugin-transform-nullish-coalescing-operator": true, + "@babel/preset-env>@babel/plugin-transform-numeric-separator": true, + "@babel/preset-env>@babel/plugin-transform-object-rest-spread": true, "@babel/preset-env>@babel/plugin-transform-object-super": true, + "@babel/preset-env>@babel/plugin-transform-optional-catch-binding": true, + "@babel/preset-env>@babel/plugin-transform-optional-chaining": true, "@babel/preset-env>@babel/plugin-transform-parameters": true, + "@babel/preset-env>@babel/plugin-transform-private-methods": true, + "@babel/preset-env>@babel/plugin-transform-private-property-in-object": true, "@babel/preset-env>@babel/plugin-transform-property-literals": true, "@babel/preset-env>@babel/plugin-transform-regenerator": true, "@babel/preset-env>@babel/plugin-transform-reserved-words": true, @@ -279,7 +329,9 @@ "@babel/preset-env>@babel/plugin-transform-template-literals": true, "@babel/preset-env>@babel/plugin-transform-typeof-symbol": true, "@babel/preset-env>@babel/plugin-transform-unicode-escapes": true, + "@babel/preset-env>@babel/plugin-transform-unicode-property-regex": true, "@babel/preset-env>@babel/plugin-transform-unicode-regex": true, + "@babel/preset-env>@babel/plugin-transform-unicode-sets-regex": true, "@babel/preset-env>@babel/preset-modules": true, "@babel/preset-env>babel-plugin-polyfill-corejs2": true, "@babel/preset-env>babel-plugin-polyfill-corejs3": true, @@ -297,138 +349,10 @@ "packages": { "@babel/core": true, "@babel/preset-env>@babel/helper-plugin-utils": true, - "@babel/preset-env>@babel/plugin-proposal-optional-chaining": true, + "@babel/preset-env>@babel/plugin-transform-optional-chaining": true, "@babel/preset-env>@babel/plugin-transform-spread>@babel/helper-skip-transparent-expression-wrappers": true } }, - "@babel/preset-env>@babel/plugin-proposal-async-generator-functions": { - "packages": { - "@babel/core": true, - "@babel/preset-env>@babel/helper-plugin-utils": true, - "@babel/preset-env>@babel/plugin-syntax-async-generators": true, - "@babel/preset-env>@babel/plugin-transform-async-to-generator>@babel/helper-remap-async-to-generator": true, - "depcheck>@babel/traverse>@babel/helper-environment-visitor": true - } - }, - "@babel/preset-env>@babel/plugin-proposal-class-properties": { - "packages": { - "@babel/preset-env>@babel/helper-plugin-utils": true, - "@babel/preset-env>@babel/plugin-proposal-private-methods>@babel/helper-create-class-features-plugin": true - } - }, - "@babel/preset-env>@babel/plugin-proposal-class-static-block": { - "packages": { - "@babel/preset-env>@babel/helper-plugin-utils": true, - "@babel/preset-env>@babel/plugin-proposal-private-methods>@babel/helper-create-class-features-plugin": true, - "@babel/preset-env>@babel/plugin-syntax-class-static-block": true - } - }, - "@babel/preset-env>@babel/plugin-proposal-dynamic-import": { - "packages": { - "@babel/preset-env>@babel/helper-plugin-utils": true, - "@babel/preset-env>@babel/plugin-syntax-dynamic-import": true - } - }, - "@babel/preset-env>@babel/plugin-proposal-export-namespace-from": { - "packages": { - "@babel/core": true, - "@babel/preset-env>@babel/helper-plugin-utils": true, - "@babel/preset-env>@babel/plugin-syntax-export-namespace-from": true - } - }, - "@babel/preset-env>@babel/plugin-proposal-json-strings": { - "packages": { - "@babel/preset-env>@babel/helper-plugin-utils": true, - "@babel/preset-env>@babel/plugin-syntax-json-strings": true - } - }, - "@babel/preset-env>@babel/plugin-proposal-logical-assignment-operators": { - "packages": { - "@babel/core": true, - "@babel/preset-env>@babel/helper-plugin-utils": true, - "@babel/preset-env>@babel/plugin-syntax-logical-assignment-operators": true - } - }, - "@babel/preset-env>@babel/plugin-proposal-nullish-coalescing-operator": { - "packages": { - "@babel/core": true, - "@babel/preset-env>@babel/helper-plugin-utils": true, - "@babel/preset-env>@babel/plugin-syntax-nullish-coalescing-operator": true - } - }, - "@babel/preset-env>@babel/plugin-proposal-numeric-separator": { - "packages": { - "@babel/preset-env>@babel/helper-plugin-utils": true, - "@babel/preset-env>@babel/plugin-syntax-numeric-separator": true - } - }, - "@babel/preset-env>@babel/plugin-proposal-object-rest-spread": { - "packages": { - "@babel/core": true, - "@babel/core>@babel/helper-compilation-targets": true, - "@babel/preset-env>@babel/compat-data": true, - "@babel/preset-env>@babel/helper-plugin-utils": true, - "@babel/preset-env>@babel/plugin-syntax-object-rest-spread": true, - "@babel/preset-env>@babel/plugin-transform-parameters": true - } - }, - "@babel/preset-env>@babel/plugin-proposal-optional-catch-binding": { - "packages": { - "@babel/preset-env>@babel/helper-plugin-utils": true, - "@babel/preset-env>@babel/plugin-syntax-optional-catch-binding": true - } - }, - "@babel/preset-env>@babel/plugin-proposal-optional-chaining": { - "packages": { - "@babel/core": true, - "@babel/preset-env>@babel/helper-plugin-utils": true, - "@babel/preset-env>@babel/plugin-syntax-optional-chaining": true, - "@babel/preset-env>@babel/plugin-transform-spread>@babel/helper-skip-transparent-expression-wrappers": true - } - }, - "@babel/preset-env>@babel/plugin-proposal-private-methods": { - "packages": { - "@babel/preset-env>@babel/helper-plugin-utils": true, - "@babel/preset-env>@babel/plugin-proposal-private-methods>@babel/helper-create-class-features-plugin": true - } - }, - "@babel/preset-env>@babel/plugin-proposal-private-methods>@babel/helper-create-class-features-plugin": { - "globals": { - "console.warn": true - }, - "packages": { - "@babel/core": true, - "@babel/preset-env>@babel/plugin-proposal-private-methods>@babel/helper-create-class-features-plugin>semver": true, - "@babel/preset-env>@babel/plugin-transform-classes>@babel/helper-annotate-as-pure": true, - "@babel/preset-env>@babel/plugin-transform-classes>@babel/helper-optimise-call-expression": true, - "@babel/preset-env>@babel/plugin-transform-classes>@babel/helper-replace-supers": true, - "@babel/preset-env>@babel/plugin-transform-classes>@babel/helper-replace-supers>@babel/helper-member-expression-to-functions": true, - "@babel/preset-env>@babel/plugin-transform-spread>@babel/helper-skip-transparent-expression-wrappers": true, - "depcheck>@babel/traverse>@babel/helper-environment-visitor": true, - "depcheck>@babel/traverse>@babel/helper-function-name": true, - "depcheck>@babel/traverse>@babel/helper-split-export-declaration": true - } - }, - "@babel/preset-env>@babel/plugin-proposal-private-methods>@babel/helper-create-class-features-plugin>semver": { - "globals": { - "console": true, - "process": true - } - }, - "@babel/preset-env>@babel/plugin-proposal-private-property-in-object": { - "packages": { - "@babel/preset-env>@babel/helper-plugin-utils": true, - "@babel/preset-env>@babel/plugin-proposal-private-methods>@babel/helper-create-class-features-plugin": true, - "@babel/preset-env>@babel/plugin-syntax-private-property-in-object": true, - "@babel/preset-env>@babel/plugin-transform-classes>@babel/helper-annotate-as-pure": true - } - }, - "@babel/preset-env>@babel/plugin-proposal-unicode-property-regex": { - "packages": { - "@babel/preset-env>@babel/helper-plugin-utils": true, - "@babel/preset-env>@babel/plugin-transform-dotall-regex>@babel/helper-create-regexp-features-plugin": true - } - }, "@babel/preset-env>@babel/plugin-syntax-async-generators": { "packages": { "@babel/preset-env>@babel/helper-plugin-utils": true @@ -459,6 +383,11 @@ "@babel/preset-env>@babel/helper-plugin-utils": true } }, + "@babel/preset-env>@babel/plugin-syntax-import-attributes": { + "packages": { + "@babel/preset-env>@babel/helper-plugin-utils": true + } + }, "@babel/preset-env>@babel/plugin-syntax-import-meta": { "packages": { "@babel/preset-env>@babel/helper-plugin-utils": true @@ -509,11 +438,26 @@ "@babel/preset-env>@babel/helper-plugin-utils": true } }, + "@babel/preset-env>@babel/plugin-syntax-unicode-sets-regex": { + "packages": { + "@babel/preset-env>@babel/helper-plugin-utils": true, + "@babel/preset-env>@babel/plugin-transform-dotall-regex>@babel/helper-create-regexp-features-plugin": true + } + }, "@babel/preset-env>@babel/plugin-transform-arrow-functions": { "packages": { "@babel/preset-env>@babel/helper-plugin-utils": true } }, + "@babel/preset-env>@babel/plugin-transform-async-generator-functions": { + "packages": { + "@babel/core": true, + "@babel/preset-env>@babel/helper-plugin-utils": true, + "@babel/preset-env>@babel/plugin-syntax-async-generators": true, + "@babel/preset-env>@babel/plugin-transform-async-to-generator>@babel/helper-remap-async-to-generator": true, + "depcheck>@babel/traverse>@babel/helper-environment-visitor": true + } + }, "@babel/preset-env>@babel/plugin-transform-async-to-generator": { "packages": { "@babel/core": true, @@ -525,7 +469,6 @@ "@babel/preset-env>@babel/plugin-transform-async-to-generator>@babel/helper-remap-async-to-generator": { "packages": { "@babel/core": true, - "@babel/core>@babel/types": true, "@babel/preset-env>@babel/plugin-transform-async-to-generator>@babel/helper-remap-async-to-generator>@babel/helper-wrap-function": true, "@babel/preset-env>@babel/plugin-transform-classes>@babel/helper-annotate-as-pure": true, "depcheck>@babel/traverse>@babel/helper-environment-visitor": true @@ -550,6 +493,19 @@ "@babel/preset-env>@babel/helper-plugin-utils": true } }, + "@babel/preset-env>@babel/plugin-transform-class-properties": { + "packages": { + "@babel/preset-env>@babel/helper-plugin-utils": true, + "@babel/preset-env>@babel/plugin-transform-private-methods>@babel/helper-create-class-features-plugin": true + } + }, + "@babel/preset-env>@babel/plugin-transform-class-static-block": { + "packages": { + "@babel/preset-env>@babel/helper-plugin-utils": true, + "@babel/preset-env>@babel/plugin-syntax-class-static-block": true, + "@babel/preset-env>@babel/plugin-transform-private-methods>@babel/helper-create-class-features-plugin": true + } + }, "@babel/preset-env>@babel/plugin-transform-classes": { "packages": { "@babel/core": true, @@ -576,11 +532,9 @@ }, "@babel/preset-env>@babel/plugin-transform-classes>@babel/helper-replace-supers": { "packages": { - "@babel/core>@babel/template": true, - "@babel/core>@babel/types": true, + "@babel/core": true, "@babel/preset-env>@babel/plugin-transform-classes>@babel/helper-optimise-call-expression": true, "@babel/preset-env>@babel/plugin-transform-classes>@babel/helper-replace-supers>@babel/helper-member-expression-to-functions": true, - "depcheck>@babel/traverse": true, "depcheck>@babel/traverse>@babel/helper-environment-visitor": true } }, @@ -612,7 +566,8 @@ "packages": { "@babel/core": true, "@babel/preset-env>@babel/plugin-transform-classes>@babel/helper-annotate-as-pure": true, - "@babel/preset-env>@babel/plugin-transform-dotall-regex>@babel/helper-create-regexp-features-plugin>regexpu-core": true + "@babel/preset-env>@babel/plugin-transform-dotall-regex>@babel/helper-create-regexp-features-plugin>regexpu-core": true, + "@babel/preset-env>@babel/plugin-transform-dotall-regex>@babel/helper-create-regexp-features-plugin>semver": true } }, "@babel/preset-env>@babel/plugin-transform-dotall-regex>@babel/helper-create-regexp-features-plugin>regexpu-core": { @@ -620,19 +575,19 @@ "characterClassItem.kind": true }, "packages": { + "@babel/preset-env>@babel/plugin-transform-dotall-regex>@babel/helper-create-regexp-features-plugin>regexpu-core>@babel/regjsgen": true, "@babel/preset-env>@babel/plugin-transform-dotall-regex>@babel/helper-create-regexp-features-plugin>regexpu-core>regenerate": true, - "@babel/preset-env>@babel/plugin-transform-dotall-regex>@babel/helper-create-regexp-features-plugin>regexpu-core>regjsgen": true, "@babel/preset-env>@babel/plugin-transform-dotall-regex>@babel/helper-create-regexp-features-plugin>regexpu-core>regjsparser": true, "@babel/preset-env>@babel/plugin-transform-dotall-regex>@babel/helper-create-regexp-features-plugin>regexpu-core>unicode-match-property-ecmascript": true, "@babel/preset-env>@babel/plugin-transform-dotall-regex>@babel/helper-create-regexp-features-plugin>regexpu-core>unicode-match-property-value-ecmascript": true } }, - "@babel/preset-env>@babel/plugin-transform-dotall-regex>@babel/helper-create-regexp-features-plugin>regexpu-core>regenerate": { + "@babel/preset-env>@babel/plugin-transform-dotall-regex>@babel/helper-create-regexp-features-plugin>regexpu-core>@babel/regjsgen": { "globals": { "define": true } }, - "@babel/preset-env>@babel/plugin-transform-dotall-regex>@babel/helper-create-regexp-features-plugin>regexpu-core>regjsgen": { + "@babel/preset-env>@babel/plugin-transform-dotall-regex>@babel/helper-create-regexp-features-plugin>regexpu-core>regenerate": { "globals": { "define": true } @@ -648,12 +603,24 @@ "@babel/preset-env>@babel/plugin-transform-dotall-regex>@babel/helper-create-regexp-features-plugin>regexpu-core>unicode-match-property-ecmascript>unicode-property-aliases-ecmascript": true } }, + "@babel/preset-env>@babel/plugin-transform-dotall-regex>@babel/helper-create-regexp-features-plugin>semver": { + "globals": { + "console": true, + "process": true + } + }, "@babel/preset-env>@babel/plugin-transform-duplicate-keys": { "packages": { "@babel/core": true, "@babel/preset-env>@babel/helper-plugin-utils": true } }, + "@babel/preset-env>@babel/plugin-transform-dynamic-import": { + "packages": { + "@babel/preset-env>@babel/helper-plugin-utils": true, + "@babel/preset-env>@babel/plugin-syntax-dynamic-import": true + } + }, "@babel/preset-env>@babel/plugin-transform-exponentiation-operator": { "packages": { "@babel/core": true, @@ -663,13 +630,14 @@ }, "@babel/preset-env>@babel/plugin-transform-exponentiation-operator>@babel/helper-builder-binary-assignment-operator-visitor": { "packages": { - "@babel/core>@babel/types": true, - "@babel/preset-env>@babel/plugin-transform-exponentiation-operator>@babel/helper-builder-binary-assignment-operator-visitor>@babel/helper-explode-assignable-expression": true + "@babel/core>@babel/types": true } }, - "@babel/preset-env>@babel/plugin-transform-exponentiation-operator>@babel/helper-builder-binary-assignment-operator-visitor>@babel/helper-explode-assignable-expression": { + "@babel/preset-env>@babel/plugin-transform-export-namespace-from": { "packages": { - "@babel/core>@babel/types": true + "@babel/core": true, + "@babel/preset-env>@babel/helper-plugin-utils": true, + "@babel/preset-env>@babel/plugin-syntax-export-namespace-from": true } }, "@babel/preset-env>@babel/plugin-transform-for-of": { @@ -685,11 +653,24 @@ "depcheck>@babel/traverse>@babel/helper-function-name": true } }, + "@babel/preset-env>@babel/plugin-transform-json-strings": { + "packages": { + "@babel/preset-env>@babel/helper-plugin-utils": true, + "@babel/preset-env>@babel/plugin-syntax-json-strings": true + } + }, "@babel/preset-env>@babel/plugin-transform-literals": { "packages": { "@babel/preset-env>@babel/helper-plugin-utils": true } }, + "@babel/preset-env>@babel/plugin-transform-logical-assignment-operators": { + "packages": { + "@babel/core": true, + "@babel/preset-env>@babel/helper-plugin-utils": true, + "@babel/preset-env>@babel/plugin-syntax-logical-assignment-operators": true + } + }, "@babel/preset-env>@babel/plugin-transform-member-expression-literals": { "packages": { "@babel/core": true, @@ -746,6 +727,29 @@ "@babel/preset-env>@babel/helper-plugin-utils": true } }, + "@babel/preset-env>@babel/plugin-transform-nullish-coalescing-operator": { + "packages": { + "@babel/core": true, + "@babel/preset-env>@babel/helper-plugin-utils": true, + "@babel/preset-env>@babel/plugin-syntax-nullish-coalescing-operator": true + } + }, + "@babel/preset-env>@babel/plugin-transform-numeric-separator": { + "packages": { + "@babel/preset-env>@babel/helper-plugin-utils": true, + "@babel/preset-env>@babel/plugin-syntax-numeric-separator": true + } + }, + "@babel/preset-env>@babel/plugin-transform-object-rest-spread": { + "packages": { + "@babel/core": true, + "@babel/core>@babel/helper-compilation-targets": true, + "@babel/preset-env>@babel/compat-data": true, + "@babel/preset-env>@babel/helper-plugin-utils": true, + "@babel/preset-env>@babel/plugin-syntax-object-rest-spread": true, + "@babel/preset-env>@babel/plugin-transform-parameters": true + } + }, "@babel/preset-env>@babel/plugin-transform-object-super": { "packages": { "@babel/core": true, @@ -753,10 +757,61 @@ "@babel/preset-env>@babel/plugin-transform-classes>@babel/helper-replace-supers": true } }, - "@babel/preset-env>@babel/plugin-transform-parameters": { + "@babel/preset-env>@babel/plugin-transform-optional-catch-binding": { + "packages": { + "@babel/preset-env>@babel/helper-plugin-utils": true, + "@babel/preset-env>@babel/plugin-syntax-optional-catch-binding": true + } + }, + "@babel/preset-env>@babel/plugin-transform-optional-chaining": { + "packages": { + "@babel/core": true, + "@babel/preset-env>@babel/helper-plugin-utils": true, + "@babel/preset-env>@babel/plugin-syntax-optional-chaining": true, + "@babel/preset-env>@babel/plugin-transform-spread>@babel/helper-skip-transparent-expression-wrappers": true + } + }, + "@babel/preset-env>@babel/plugin-transform-parameters": { + "packages": { + "@babel/core": true, + "@babel/preset-env>@babel/helper-plugin-utils": true + } + }, + "@babel/preset-env>@babel/plugin-transform-private-methods": { + "packages": { + "@babel/preset-env>@babel/helper-plugin-utils": true, + "@babel/preset-env>@babel/plugin-transform-private-methods>@babel/helper-create-class-features-plugin": true + } + }, + "@babel/preset-env>@babel/plugin-transform-private-methods>@babel/helper-create-class-features-plugin": { + "globals": { + "console.warn": true + }, + "packages": { + "@babel/core": true, + "@babel/preset-env>@babel/plugin-transform-classes>@babel/helper-annotate-as-pure": true, + "@babel/preset-env>@babel/plugin-transform-classes>@babel/helper-optimise-call-expression": true, + "@babel/preset-env>@babel/plugin-transform-classes>@babel/helper-replace-supers": true, + "@babel/preset-env>@babel/plugin-transform-classes>@babel/helper-replace-supers>@babel/helper-member-expression-to-functions": true, + "@babel/preset-env>@babel/plugin-transform-private-methods>@babel/helper-create-class-features-plugin>semver": true, + "@babel/preset-env>@babel/plugin-transform-spread>@babel/helper-skip-transparent-expression-wrappers": true, + "depcheck>@babel/traverse>@babel/helper-environment-visitor": true, + "depcheck>@babel/traverse>@babel/helper-function-name": true, + "depcheck>@babel/traverse>@babel/helper-split-export-declaration": true + } + }, + "@babel/preset-env>@babel/plugin-transform-private-methods>@babel/helper-create-class-features-plugin>semver": { + "globals": { + "console": true, + "process": true + } + }, + "@babel/preset-env>@babel/plugin-transform-private-property-in-object": { "packages": { - "@babel/core": true, - "@babel/preset-env>@babel/helper-plugin-utils": true + "@babel/preset-env>@babel/helper-plugin-utils": true, + "@babel/preset-env>@babel/plugin-syntax-private-property-in-object": true, + "@babel/preset-env>@babel/plugin-transform-classes>@babel/helper-annotate-as-pure": true, + "@babel/preset-env>@babel/plugin-transform-private-methods>@babel/helper-create-class-features-plugin": true } }, "@babel/preset-env>@babel/plugin-transform-property-literals": { @@ -828,18 +883,30 @@ "@babel/preset-env>@babel/helper-plugin-utils": true } }, + "@babel/preset-env>@babel/plugin-transform-unicode-property-regex": { + "packages": { + "@babel/preset-env>@babel/helper-plugin-utils": true, + "@babel/preset-env>@babel/plugin-transform-dotall-regex>@babel/helper-create-regexp-features-plugin": true + } + }, "@babel/preset-env>@babel/plugin-transform-unicode-regex": { "packages": { "@babel/preset-env>@babel/helper-plugin-utils": true, "@babel/preset-env>@babel/plugin-transform-dotall-regex>@babel/helper-create-regexp-features-plugin": true } }, + "@babel/preset-env>@babel/plugin-transform-unicode-sets-regex": { + "packages": { + "@babel/preset-env>@babel/helper-plugin-utils": true, + "@babel/preset-env>@babel/plugin-transform-dotall-regex>@babel/helper-create-regexp-features-plugin": true + } + }, "@babel/preset-env>babel-plugin-polyfill-corejs2": { "packages": { "@babel/core": true, "@babel/preset-env>@babel/compat-data": 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>semver": true } }, "@babel/preset-env>babel-plugin-polyfill-corejs2>@babel/helper-define-polyfill-provider": { @@ -867,12 +934,6 @@ "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, @@ -957,8 +1018,8 @@ "packages": { "@babel/core": true, "@babel/preset-env>@babel/helper-plugin-utils": true, - "@babel/preset-env>@babel/plugin-proposal-private-methods>@babel/helper-create-class-features-plugin": true, "@babel/preset-env>@babel/plugin-transform-classes>@babel/helper-annotate-as-pure": true, + "@babel/preset-env>@babel/plugin-transform-private-methods>@babel/helper-create-class-features-plugin": true, "@babel/preset-typescript>@babel/plugin-transform-typescript>@babel/plugin-syntax-typescript": true } }, @@ -1166,39 +1227,6 @@ "define": true } }, - "@storybook/test-runner>glob": { - "builtin": { - "assert": true, - "events.EventEmitter": true, - "fs": true, - "path.isAbsolute": true, - "path.join": true, - "path.resolve": true, - "util": true - }, - "globals": { - "console.error": true, - "process.cwd": true, - "process.nextTick": true, - "process.platform": true - }, - "packages": { - "@storybook/test-runner>glob>minimatch": true, - "nyc>glob>fs.realpath": true, - "nyc>glob>inflight": true, - "pump>once": true, - "pumpify>inherits": true - } - }, - "@storybook/test-runner>glob>minimatch": { - "globals": { - "console.error": true, - "process": true - }, - "packages": { - "addons-linter>glob>minimatch>brace-expansion": true - } - }, "@typescript-eslint/eslint-plugin": { "packages": { "@typescript-eslint/eslint-plugin>@typescript-eslint/type-utils": true, @@ -1302,89 +1330,6 @@ "typescript": true } }, - "addons-linter>glob>minimatch>brace-expansion": { - "packages": { - "stylelint>balanced-match": true - } - }, - "babel-plugin-module-resolver": { - "builtin": { - "fs": true, - "path": true - }, - "globals": { - "console.warn": true, - "process.cwd": true, - "process.env.NODE_ENV": true - }, - "packages": { - "@storybook/test-runner>glob": true, - "babel-plugin-module-resolver>find-babel-config": true, - "babel-plugin-module-resolver>pkg-up": true, - "babel-plugin-module-resolver>reselect": true, - "brfs>resolve": true - } - }, - "babel-plugin-module-resolver>find-babel-config": { - "builtin": { - "fs.readFile": true, - "fs.readFileSync": true, - "path.dirname": true, - "path.isAbsolute": true, - "path.join": true - }, - "globals": { - "process.cwd": true - }, - "packages": { - "depcheck>json5": true, - "nyc>find-up>path-exists": true - } - }, - "babel-plugin-module-resolver>pkg-up": { - "packages": { - "babel-plugin-module-resolver>pkg-up>find-up": true - } - }, - "babel-plugin-module-resolver>pkg-up>find-up": { - "builtin": { - "path.dirname": true, - "path.join": true, - "path.parse": true, - "path.resolve": true - }, - "packages": { - "babel-plugin-module-resolver>pkg-up>find-up>locate-path": true - } - }, - "babel-plugin-module-resolver>pkg-up>find-up>locate-path": { - "builtin": { - "path.resolve": true - }, - "globals": { - "process.cwd": true - }, - "packages": { - "babel-plugin-module-resolver>pkg-up>find-up>locate-path>p-locate": true, - "babel-plugin-module-resolver>pkg-up>find-up>locate-path>path-exists": true - } - }, - "babel-plugin-module-resolver>pkg-up>find-up>locate-path>p-locate": { - "packages": { - "babel-plugin-module-resolver>pkg-up>find-up>locate-path>p-locate>p-limit": true - } - }, - "babel-plugin-module-resolver>pkg-up>find-up>locate-path>p-locate>p-limit": { - "packages": { - "nyc>find-up>locate-path>p-locate>p-limit>p-try": true - } - }, - "babel-plugin-module-resolver>pkg-up>find-up>locate-path>path-exists": { - "builtin": { - "fs.access": true, - "fs.accessSync": true - } - }, "babelify": { "builtin": { "path.extname": true, @@ -1693,7 +1638,7 @@ "browserify>insert-module-globals": true, "browserify>module-deps": true, "browserify>read-only-stream": true, - "browserify>shasum": true, + "browserify>shasum-object": true, "browserify>syntax-error": true, "browserify>through2": true, "labeled-stream-splicer": true, @@ -1785,7 +1730,7 @@ "browserify>deps-sort": { "packages": { "browserify>deps-sort>through2": true, - "watchify>browserify>shasum-object": true + "browserify>shasum-object": true } }, "browserify>deps-sort>through2": { @@ -1933,18 +1878,15 @@ "readable-stream": true } }, - "browserify>shasum": { + "browserify>shasum-object": { "builtin": { - "buffer.Buffer.isBuffer": true, "crypto.createHash": true }, + "globals": { + "Buffer.isBuffer": true + }, "packages": { - "browserify>shasum>json-stable-stringify": true - } - }, - "browserify>shasum>json-stable-stringify": { - "packages": { - "lavamoat>json-stable-stringify>jsonify": true + "eth-rpc-errors>fast-safe-stringify": true } }, "browserify>string_decoder": { @@ -2254,31 +2196,7 @@ "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 + "nyc>glob": true } }, "depcheck>@babel/traverse": { @@ -2505,33 +2423,9 @@ "packages": { "brfs>resolve": true, "del>is-glob": true, - "eslint-import-resolver-typescript>glob": true, "eslint-plugin-import>tsconfig-paths": true, - "nock>debug": true - } - }, - "eslint-import-resolver-typescript>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 + "nock>debug": true, + "nyc>glob": true } }, "eslint-plugin-import": { @@ -5885,40 +5779,16 @@ "packages": { "eslint>glob-parent": true, "gulp>glob-watcher>is-negated-glob": true, - "gulp>vinyl-fs>glob-stream>glob": true, "gulp>vinyl-fs>glob-stream>ordered-read-streams": true, "gulp>vinyl-fs>glob-stream>pumpify": true, "gulp>vinyl-fs>glob-stream>to-absolute-glob": true, "gulp>vinyl-fs>glob-stream>unique-stream": true, + "nyc>glob": true, "react-markdown>unified>extend": true, "readable-stream": true, "vinyl>remove-trailing-separator": true } }, - "gulp>vinyl-fs>glob-stream>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 - } - }, "gulp>vinyl-fs>glob-stream>ordered-read-streams": { "builtin": { "util.inherits": true @@ -6566,6 +6436,30 @@ "util.promisify": true } }, + "nyc>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>glob>fs.realpath": { "builtin": { "fs.lstat": true, @@ -8100,31 +7994,7 @@ "setTimeout": true }, "packages": { - "stylelint>file-entry-cache>flat-cache>rimraf>glob": true - } - }, - "stylelint>file-entry-cache>flat-cache>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>glob": true } }, "stylelint>file-entry-cache>flat-cache>write": { @@ -8862,17 +8732,6 @@ "watchify>xtend": true } }, - "watchify>browserify>shasum-object": { - "builtin": { - "crypto.createHash": true - }, - "globals": { - "Buffer.isBuffer": true - }, - "packages": { - "eth-rpc-errors>fast-safe-stringify": true - } - }, "webpack>browserslist": { "builtin": { "fs.existsSync": true, diff --git a/package.json b/package.json index 99a52e23d433..77df13a53975 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metamask-crx", - "version": "11.2.0", + "version": "11.3.0", "private": true, "repository": { "type": "git", @@ -16,13 +16,15 @@ "build": "yarn lavamoat:build", "build:dev": "node development/build/index.js", "start:test": "SEGMENT_HOST='https://api.segment.io' SEGMENT_WRITE_KEY='FAKE' SENTRY_DSN_DEV=https://fake@sentry.io/0000000 PORTFOLIO_URL=http://127.0.0.1:8080 yarn build:dev testDev", + "start:test:flask": "SEGMENT_HOST='https://api.segment.io' SEGMENT_WRITE_KEY='FAKE' SENTRY_DSN_DEV=https://fake@sentry.io/0000000 PORTFOLIO_URL=http://127.0.0.1:8080 BLOCKAID_FILE_CDN=storage.googleapis.com/ppom-mock-cdn yarn build:dev testDev --build-type flask --apply-lavamoat=false --snow=false", "start:test:mv3": "ENABLE_MV3=true SEGMENT_HOST='https://api.segment.io' SEGMENT_WRITE_KEY='FAKE' SENTRY_DSN_DEV=https://fake@sentry.io/0000000 PORTFOLIO_URL=http://127.0.0.1:8080 yarn build:dev testDev", "benchmark:chrome": "SELENIUM_BROWSER=chrome ts-node test/e2e/benchmark.js", "mv3:stats:chrome": "SELENIUM_BROWSER=chrome ENABLE_MV3=true ts-node test/e2e/mv3-perf-stats/index.js", "user-actions-benchmark:chrome": "SELENIUM_BROWSER=chrome ts-node test/e2e/user-actions-benchmark.js", "benchmark:firefox": "SELENIUM_BROWSER=firefox ts-node test/e2e/benchmark.js", "build:test": "SEGMENT_HOST='https://api.segment.io' SEGMENT_WRITE_KEY='FAKE' SENTRY_DSN_DEV=https://fake@sentry.io/0000000 PORTFOLIO_URL=http://127.0.0.1:8080 yarn build test", - "build:test:flask": "yarn build test --build-type flask", + "build:test:flask": "BLOCKAID_FILE_CDN=storage.googleapis.com/ppom-mock-cdn yarn build test --build-type flask", + "build:test:mmi": "yarn build test --build-type mmi", "build:test:mv3": "ENABLE_MV3=true SEGMENT_HOST='https://api.segment.io' SEGMENT_WRITE_KEY='FAKE' SENTRY_DSN_DEV=https://fake@sentry.io/0000000 PORTFOLIO_URL=http://127.0.0.1:8080 yarn build test", "build:test:dev:mv3": "ENABLE_MV3=true SEGMENT_HOST='https://api.segment.io' SEGMENT_WRITE_KEY='FAKE' SENTRY_DSN_DEV=https://fake@sentry.io/0000000 PORTFOLIO_URL=http://127.0.0.1:8080 yarn build:dev testDev --apply-lavamoat=false", "test": "yarn lint && yarn test:unit && yarn test:unit:jest", @@ -36,6 +38,7 @@ "test:unit:global": "mocha test/unit-global/*.test.js", "test:unit:mocha": "node ./test/run-unit-tests.js --mocha", "test:e2e:chrome": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js", + "test:e2e:chrome:mmi": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js --mmi", "test:e2e:chrome:snaps": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js --snaps", "test:e2e:chrome:mv3": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js --mv3", "test:e2e:chrome:rpc": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js --rpc", @@ -104,8 +107,8 @@ }, "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", + "@babel/core": "patch:@babel/core@npm%3A7.23.2#~/.yarn/patches/@babel-core-npm-7.23.2-b93f586907.patch", + "@babel/runtime": "patch:@babel/runtime@npm%3A7.23.2#~/.yarn/patches/@babel-runtime-npm-7.23.2-d013d6cf7e.patch", "@metamask/approval-controller": "^3.4.0", "@types/react": "^16.9.53", "analytics-node/axios": "^0.21.2", @@ -119,7 +122,6 @@ "ast-types": "^0.14.2", "x-default-browser": "^0.5.2", "web3-provider-engine/eth-json-rpc-filters": "^6.0.0", - "typescript@~4.4.0": "patch:typescript@npm:4.4.4#.yarn/patches/typescript-npm-4.4.4-3fedcc07a3.patch", "acorn@^7.0.0": "patch:acorn@npm:7.4.1#.yarn/patches/acorn-npm-7.4.1-f450b4646c.patch", "acorn@^7.4.1": "patch:acorn@npm:7.4.1#.yarn/patches/acorn-npm-7.4.1-f450b4646c.patch", "acorn@^7.1.1": "patch:acorn@npm:7.4.1#.yarn/patches/acorn-npm-7.4.1-f450b4646c.patch", @@ -202,20 +204,19 @@ "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", "lavamoat-core@npm:^14.4.1": "patch:lavamoat-core@npm%3A14.4.1#~/.yarn/patches/lavamoat-core-npm-14.4.1-c4e8bbb016.patch", - "@metamask/keyring-controller@^7.2.0": "patch:@metamask/keyring-controller@npm%3A7.2.0#~/.yarn/patches/@metamask-keyring-controller-npm-7.2.0-fcc0c7893b.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", + "@metamask/signature-controller@^6.0.0": "patch:@metamask/signature-controller@npm%3A6.0.0#~/.yarn/patches/@metamask-signature-controller-npm-6.0.0-90e8e479a9.patch", "semver@7.3.7": "^7.5.4", "semver@7.3.8": "^7.5.4" }, "dependencies": { - "@babel/runtime": "^7.18.9", - "@blockaid/ppom_release": "^1.2.6", + "@babel/runtime": "^7.23.2", + "@blockaid/ppom_release": "^1.2.8", "@download/blockies": "^1.0.3", "@ensdomains/content-hash": "^2.5.6", "@ethereumjs/common": "^3.1.1", "@ethereumjs/tx": "^4.1.1", "@ethersproject/abi": "^5.6.4", - "@ethersproject/bignumber": "^5.6.2", + "@ethersproject/bignumber": "^5.7.0", "@ethersproject/contracts": "^5.7.0", "@ethersproject/hdnode": "^5.6.2", "@ethersproject/providers": "^5.7.2", @@ -230,7 +231,7 @@ "@metamask-institutional/institutional-features": "^1.2.6", "@metamask-institutional/portfolio-dashboard": "^1.4.0", "@metamask-institutional/rpc-allowlist": "^1.0.0", - "@metamask-institutional/sdk": "^0.1.19", + "@metamask-institutional/sdk": "^0.1.18", "@metamask-institutional/transaction-update": "^0.1.29", "@metamask/address-book-controller": "^3.0.0", "@metamask/announcement-controller": "^4.0.0", @@ -243,20 +244,23 @@ "@metamask/design-tokens": "^1.12.0", "@metamask/desktop": "^0.3.0", "@metamask/eth-json-rpc-middleware": "^11.0.0", - "@metamask/eth-keyring-controller": "^10.0.1", + "@metamask/eth-keyring-controller": "^13.0.1", "@metamask/eth-ledger-bridge-keyring": "^0.15.0", - "@metamask/eth-snap-keyring": "^0.1.4", + "@metamask/eth-snap-keyring": "0.3.1", "@metamask/eth-token-tracker": "^4.0.0", "@metamask/eth-trezor-keyring": "^1.1.0", "@metamask/etherscan-link": "^2.2.0", + "@metamask/ethjs-query": "^0.5.0", "@metamask/gas-fee-controller": "^6.0.1", "@metamask/jazzicon": "^2.0.0", "@metamask/key-tree": "^9.0.0", - "@metamask/keyring-controller": "^7.2.0", + "@metamask/keyring-controller": "^8.0.1", + "@metamask/logging-controller": "^1.0.1", "@metamask/logo": "^3.1.1", "@metamask/message-manager": "^7.3.0", "@metamask/metamask-eth-abis": "^3.0.0", - "@metamask/network-controller": "^12.1.1", + "@metamask/name-controller": "^3.0.0", + "@metamask/network-controller": "^12.2.0", "@metamask/notification-controller": "^3.0.0", "@metamask/obs-store": "^8.1.0", "@metamask/permission-controller": "^4.0.0", @@ -265,20 +269,16 @@ "@metamask/ppom-validator": "^0.5.0", "@metamask/providers": "^11.1.0", "@metamask/rate-limit-controller": "^3.0.0", - "@metamask/rpc-methods": "^1.0.2", - "@metamask/rpc-methods-flask": "npm:@metamask/rpc-methods@0.38.2-flask.1", + "@metamask/rpc-methods": "^2.0.0", "@metamask/safe-event-emitter": "^2.0.0", "@metamask/scure-bip39": "^2.0.3", "@metamask/selected-network-controller": "^1.0.0", - "@metamask/signature-controller": "^5.3.0", + "@metamask/signature-controller": "^6.0.0", "@metamask/slip44": "^3.0.0", "@metamask/smart-transactions-controller": "^4.0.0", - "@metamask/snaps-controllers": "^1.0.2", - "@metamask/snaps-controllers-flask": "npm:@metamask/snaps-controllers@0.38.3-flask.1", - "@metamask/snaps-ui": "^1.0.2", - "@metamask/snaps-ui-flask": "npm:@metamask/snaps-ui@0.37.4-flask.1", - "@metamask/snaps-utils": "^1.0.2", - "@metamask/snaps-utils-flask": "npm:@metamask/snaps-utils@0.38.3-flask.1", + "@metamask/snaps-controllers": "^2.0.1", + "@metamask/snaps-ui": "^2.0.0", + "@metamask/snaps-utils": "^2.0.1", "@metamask/subject-metadata-controller": "^2.0.0", "@metamask/utils": "^5.0.0", "@ngraveio/bc-ur": "^1.1.6", @@ -317,7 +317,6 @@ "ethereumjs-util": "^7.0.10", "ethjs": "^0.4.0", "ethjs-contract": "^0.2.3", - "ethjs-query": "^0.3.4", "extension-port-stream": "^2.1.1", "fast-json-patch": "^3.1.1", "fuse.js": "^3.2.0", @@ -372,15 +371,14 @@ "devDependencies": { "@actions/core": "^1.10.0", "@actions/github": "^5.1.1", - "@babel/code-frame": "^7.12.13", - "@babel/core": "^7.21.5", - "@babel/eslint-parser": "^7.13.14", - "@babel/eslint-plugin": "^7.12.1", - "@babel/preset-env": "^7.5.5", - "@babel/preset-react": "^7.0.0", - "@babel/preset-typescript": "^7.16.7", - "@babel/register": "^7.5.5", - "@ethersproject/bignumber": "^5.7.0", + "@babel/code-frame": "^7.22.13", + "@babel/core": "^7.23.2", + "@babel/eslint-parser": "^7.22.15", + "@babel/eslint-plugin": "^7.22.10", + "@babel/preset-env": "^7.23.2", + "@babel/preset-react": "^7.22.15", + "@babel/preset-typescript": "^7.23.2", + "@babel/register": "^7.22.15", "@lavamoat/allow-scripts": "^2.3.1", "@lavamoat/lavapack": "^5.2.4", "@metamask/auto-changelog": "^2.1.0", @@ -393,21 +391,21 @@ "@metamask/phishing-warning": "^2.1.0", "@metamask/test-dapp": "^7.1.0", "@sentry/cli": "^2.19.4", - "@storybook/addon-a11y": "^7.0.11", - "@storybook/addon-actions": "^7.0.11", - "@storybook/addon-essentials": "^7.0.11", + "@storybook/addon-a11y": "^7.4.6", + "@storybook/addon-actions": "^7.4.6", + "@storybook/addon-essentials": "^7.4.6", "@storybook/addon-knobs": "^7.0.2", - "@storybook/addon-mdx-gfm": "^7.0.11", - "@storybook/addons": "^7.0.11", - "@storybook/api": "^7.0.11", - "@storybook/client-api": "^7.0.11", - "@storybook/components": "^7.0.11", - "@storybook/core-events": "^7.0.11", - "@storybook/react": "^7.0.11", - "@storybook/react-webpack5": "^7.0.11", + "@storybook/addon-mdx-gfm": "^7.4.6", + "@storybook/addons": "^7.4.6", + "@storybook/api": "^7.4.6", + "@storybook/client-api": "^7.4.6", + "@storybook/components": "^7.4.6", + "@storybook/core-events": "^7.4.6", + "@storybook/react": "^7.4.6", + "@storybook/react-webpack5": "^7.4.6", "@storybook/storybook-deployer": "^2.8.16", "@storybook/test-runner": "^0.10.0", - "@storybook/theming": "^7.0.11", + "@storybook/theming": "^7.4.6", "@testing-library/jest-dom": "^5.11.10", "@testing-library/react": "^10.4.8", "@testing-library/react-hooks": "^8.0.1", @@ -441,12 +439,11 @@ "@typescript-eslint/parser": "^5.30.7", "@whitespace/storybook-addon-html": "^5.1.6", "addons-linter": "^5.2.0", - "babel-plugin-module-resolver": "^5.0.0", "babelify": "^10.0.0", "bify-module-groups": "^2.0.0", "brfs": "^2.0.2", "browser-util-inspect": "^0.2.0", - "browserify": "^16.5.1", + "browserify": "^17.0.0", "chalk": "^4.1.2", "chokidar": "^3.5.3", "chromedriver": "^116.0.0", @@ -473,7 +470,7 @@ "eslint-plugin-prettier": "^4.2.1", "eslint-plugin-react": "^7.23.1", "eslint-plugin-react-hooks": "^4.2.0", - "eslint-plugin-storybook": "^0.6.12", + "eslint-plugin-storybook": "^0.6.15", "fake-indexeddb": "^4.0.1", "fancy-log": "^1.3.3", "fast-glob": "^3.2.2", @@ -539,8 +536,8 @@ "source-map": "^0.7.2", "source-map-explorer": "^2.4.2", "squirrelly": "^9.0.0", - "storybook": "^7.0.11", - "storybook-dark-mode": "^3.0.0", + "storybook": "^7.4.6", + "storybook-dark-mode": "^3.0.1", "stream-browserify": "^3.0.0", "string.prototype.matchall": "^4.0.2", "style-loader": "^0.21.0", @@ -550,7 +547,7 @@ "through2": "^4.0.2", "ts-node": "^10.5.0", "ttest": "^2.1.1", - "typescript": "~4.4.0", + "typescript": "~4.5.0", "vinyl": "^2.2.1", "vinyl-buffer": "^1.0.1", "vinyl-source-stream": "^2.0.0", @@ -595,7 +592,6 @@ "eth-trezor-keyring>trezor-connect>@trezor/utxo-lib>blake-hash": false, "eth-trezor-keyring>trezor-connect>@trezor/utxo-lib>tiny-secp256k1": false, "ethereumjs-util>ethereum-cryptography>keccak": false, - "ethjs-query>babel-runtime>core-js": false, "ganache>@trufflesuite/bigint-buffer": false, "ganache>bufferutil": false, "ganache>keccak": false, @@ -630,7 +626,9 @@ "@metamask/eth-trezor-keyring>hdkey>secp256k1": false, "@storybook/addon-knobs>core-js": false, "@storybook/manager-webpack5>core-js": false, - "@storybook/react-webpack5>@storybook/preset-react-webpack>@pmmmwh/react-refresh-webpack-plugin>core-js-pure": false + "@storybook/react-webpack5>@storybook/preset-react-webpack>@pmmmwh/react-refresh-webpack-plugin>core-js-pure": false, + "ethjs-contract>babel-runtime>core-js": false, + "ts-node>@swc/core": false } }, "packageManager": "yarn@4.0.0-rc.48" diff --git a/shared/constants/app.ts b/shared/constants/app.ts index 04cf708ba52d..47bb37e4b5ae 100644 --- a/shared/constants/app.ts +++ b/shared/constants/app.ts @@ -77,6 +77,13 @@ export const SNAP_DIALOG_TYPES = { }; ///: END:ONLY_INCLUDE_IN +///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) +export const SNAP_MANAGE_ACCOUNTS_CONFIRMATION_TYPES = { + confirmAccountCreation: 'snap_manageAccounts:confirmAccountCreation', + confirmAccountRemoval: 'snap_manageAccounts:confirmAccountRemoval', +}; +///: END:ONLY_INCLUDE_IN + /** * Custom messages to send and be received by the extension */ diff --git a/shared/constants/bridge.ts b/shared/constants/bridge.ts index cba071bfbc04..4bab94d5a4c6 100644 --- a/shared/constants/bridge.ts +++ b/shared/constants/bridge.ts @@ -4,6 +4,7 @@ export const ALLOWED_BRIDGE_CHAIN_IDS = [ CHAIN_IDS.MAINNET, CHAIN_IDS.BSC, CHAIN_IDS.POLYGON, + CHAIN_IDS.ZKSYNC_ERA, CHAIN_IDS.AVALANCHE, CHAIN_IDS.OPTIMISM, CHAIN_IDS.ARBITRUM, @@ -16,6 +17,8 @@ export const ALLOWED_BRIDGE_TOKEN_ADDRESSES = { '0x6b175474e89094c44da98b954eedeac495271d0f', '0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0', '0x8965349fb649a33a30cbfda057d8ec2c48abe2a2', + '0xae78736cd615f374d3085123a210448e74fc6393', + '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', ], [CHAIN_IDS.BSC]: [ '0x55d398326f99059ff775485246999027b3197955', @@ -23,14 +26,22 @@ export const ALLOWED_BRIDGE_TOKEN_ADDRESSES = { '0x1af3f329e8be154074d8769d1ffa4ee058b1dbc3', '0x2170ed0880ac9a755fd29b2688956bd959f933f8', '0xcc42724c6683b7e57334c4e856f4c9965ed682bd', - '0x1ce0c2827e2ef14d5c4f29a091d735a204794041', + '0x7130d2a12b9bcbfae4f2634d864a1ee1ce3ead9c', ], [CHAIN_IDS.POLYGON]: [ '0xc2132d05d31c914a87c6611c10748aeb04b58e8f', '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', '0x8f3cf7ad23cd3cadbd9735aff958023239c6a063', '0x7ceb23fd6bc0add59e62ac25578270cff1b9f619', - '0x2c89bbc92bd86f8075d1decc58c7f4e0107f286b', + '0x1bfd67037b42cf73acf2047067bd4f2c47d9bfd6', + ], + [CHAIN_IDS.ZKSYNC_ERA]: [ + '0x5aea5775959fbc2557cc8789bc1bf90a239d9a91', + '0xbbeb516fb02a01611cbbe0453fe3c580d7281011', + '0x493257fd37edb34451f62edf8d2a0c418852ba4c', + '0x3355df6d4c9c3035724fd0e3914de96a5a83aaf4', + '0x4bef76b6b7f2823c6c1f4fcfeacd85c24548ad7e', + '0x32fd44bb869620c0ef993754c8a00be67c464806', ], [CHAIN_IDS.AVALANCHE]: [ '0xc7198437980c041c805a1edcba50c1ce5db95118', @@ -39,15 +50,21 @@ export const ALLOWED_BRIDGE_TOKEN_ADDRESSES = { '0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e', '0xd586e7f844cea2f87f50152665bcbc2c279d8d70', '0x49d5c2bdffac6ce2bfdb6640f4f80f226bc10bab', + '0x50b7545627a5162f82a992c33b87adc75187b218', ], [CHAIN_IDS.OPTIMISM]: [ '0x94b008aa00579c1307b0ef2c499ad98a8ce58e58', '0x7f5c764cbc14f9669b88837ca1490cca17c31607', '0xda10009cbd5d07dd0cecc66161fc93d7c9000da1', + '0x9bcef72be871e61ed4fbbc7630889bee758eb81d', + '0x68f180fcce6836688e9084f035309e29bf0a2095', ], [CHAIN_IDS.ARBITRUM]: [ '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', '0xda10009cbd5d07dd0cecc66161fc93d7c9000da1', + '0xec70dcb4a1efa46b8f2d97c310c9c4790ba5ffa8', + '0x2f2a2543b76a4166549f7aab2e75bef0aefc5b0f', + '0xaf88d065e77c8cc2239327c5edb3a432268e5831', ], }; diff --git a/shared/constants/labels.ts b/shared/constants/labels.ts index ab03c4eb0a5d..dc2ee63a7c95 100644 --- a/shared/constants/labels.ts +++ b/shared/constants/labels.ts @@ -3,8 +3,8 @@ export const TRUNCATED_NAME_CHAR_LIMIT = 11; // The number of characters to slice from the beginning of an address for truncated format: // `${TRUNCATED_ADDRESS_START_CHARS}...${TRUNCATED_ADDRESS_END_CHARS}` -export const TRUNCATED_ADDRESS_START_CHARS = 5; +export const TRUNCATED_ADDRESS_START_CHARS = 7; // The number of characters to slice from the end of an address for truncated format: // `${TRUNCATED_ADDRESS_START_CHARS}...${TRUNCATED_ADDRESS_END_CHARS}` -export const TRUNCATED_ADDRESS_END_CHARS = 4; +export const TRUNCATED_ADDRESS_END_CHARS = 5; diff --git a/shared/constants/metametrics.ts b/shared/constants/metametrics.ts index ab43e4a546be..e9b26f6c6712 100644 --- a/shared/constants/metametrics.ts +++ b/shared/constants/metametrics.ts @@ -455,6 +455,9 @@ export enum MetaMetricsUserTrait { */ MmiIsCustodian = 'mmi_is_custodian', ///: END:ONLY_INCLUDE_IN + ///: BEGIN:ONLY_INCLUDE_IN(petnames) + PetnameAddressCount = 'petname_addresses_count', + ///: END:ONLY_INCLUDE_IN } /** @@ -525,7 +528,6 @@ export enum MetaMetricsEventName { NavSendButtonClicked = 'Send Button Clicked', NavSwapButtonClicked = 'Swap Button Clicked', NftAdded = 'NFT Added', - OnboardingWelcome = 'App Installed', OnboardingWalletCreationStarted = 'Wallet Setup Selected', OnboardingWalletImportStarted = 'Wallet Import Started', OnboardingWalletCreationAttempted = 'Wallet Password Created', @@ -546,6 +548,11 @@ export enum MetaMetricsEventName { PermissionsApproved = 'Permissions Approved', PermissionsRejected = 'Permissions Rejected', PermissionsRequested = 'Permissions Requested', + PetnameCreated = 'Petname Created', + PetnameDeleted = 'Petname Deleted', + PetnameDisplayed = 'Petname Displayed', + PetnameModalOpened = 'Petname Modal Opened', + PetnameUpdated = 'Petname Updated', PhishingPageDisplayed = 'Phishing Page Displayed', PortfolioLinkClicked = 'Portfolio Link Clicked', ProviderMethodCalled = 'Provider Method Called', @@ -632,6 +639,9 @@ export enum MetaMetricsEventName { SnapUpdated = 'Snap Updated', SnapExportUsed = 'Snap Export Used', ///: END:ONLY_INCLUDE_IN + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) + AddSnapAccountEnabled = 'Add Snap Account Enabled', + ///: END:ONLY_INCLUDE_IN } export enum MetaMetricsEventAccountType { @@ -663,18 +673,19 @@ export enum MetaMetricsEventCategory { Navigation = 'Navigation', Network = 'Network', Onboarding = 'Onboarding', + Petnames = 'Petnames', Phishing = 'Phishing', Retention = 'Retention', ServiceWorkers = 'service_workers', Settings = 'Settings', Snaps = 'Snaps', Swaps = 'Swaps', + Tokens = 'Tokens', Transactions = 'Transactions', Wallet = 'Wallet', ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) MMI = 'Institutional', ///: END:ONLY_INCLUDE_IN - Tokens = 'Tokens', } export enum MetaMetricsEventLinkType { diff --git a/shared/constants/permissions.test.js b/shared/constants/permissions.test.js index 0bc4e9cc37db..7ea0bb47eb5d 100644 --- a/shared/constants/permissions.test.js +++ b/shared/constants/permissions.test.js @@ -3,7 +3,6 @@ import { restrictedMethodPermissionBuilders } from '@metamask/rpc-methods'; import { EndowmentPermissions, ExcludedSnapEndowments, - ExcludedSnapPermissions, RestrictedMethods, } from './permissions'; @@ -13,8 +12,8 @@ describe('EndowmentPermissions', () => { // test, so we re-add them here. expect(Object.keys(EndowmentPermissions).sort()).toStrictEqual( [ - 'endowment:long-running', 'endowment:lifecycle-hooks', + 'endowment:name-lookup', ...Object.keys(endowmentPermissionBuilders).filter( (targetName) => !Object.keys(ExcludedSnapEndowments).includes(targetName), @@ -24,46 +23,14 @@ describe('EndowmentPermissions', () => { }); }); -const FlaskOnlyPermissions = ['snap_manageAccounts', 'snap_getLocale']; - +// This test is flawed because it doesn't take fencing into consideration +// TODO: Figure out a better way to test this describe('RestrictedMethods', () => { it('has the expected permission keys', () => { - // this is done because we there is a difference between flask and stable permissions - // the code fence in `shared/constants/snaps/permissions.ts` is not supported in jest - const mainBuildRestrictedMethodPermissions = Object.keys(RestrictedMethods) - .filter((key) => !FlaskOnlyPermissions.includes(key)) - .sort(); - - expect(mainBuildRestrictedMethodPermissions).toStrictEqual( - [ - 'eth_accounts', - ...Object.keys(restrictedMethodPermissionBuilders).filter( - (targetName) => - !Object.keys(ExcludedSnapPermissions).includes(targetName), - ), - ].sort(), - ); - }); -}); - -// Kept here because code fences are not supported in jest. -// rpc methods flask has more restricted endowment permission builders -jest.mock('@metamask/rpc-methods', () => - jest.requireActual('@metamask/rpc-methods-flask'), -); - -describe('Flask Restricted Methods', () => { - it('has the expected flask permission keys', () => { - const flaskExcludedSnapPermissions = Object.keys( - ExcludedSnapPermissions, - ).filter((key) => !FlaskOnlyPermissions.includes(key)); - expect(Object.keys(RestrictedMethods).sort()).toStrictEqual( [ 'eth_accounts', - ...Object.keys(restrictedMethodPermissionBuilders).filter( - (targetName) => !flaskExcludedSnapPermissions.includes(targetName), - ), + ...Object.keys(restrictedMethodPermissionBuilders), ].sort(), ); }); diff --git a/shared/constants/snaps/permissions.ts b/shared/constants/snaps/permissions.ts index d5e1b16c6d4f..26d1f8ee9417 100644 --- a/shared/constants/snaps/permissions.ts +++ b/shared/constants/snaps/permissions.ts @@ -6,8 +6,8 @@ export const EndowmentPermissions = Object.freeze({ 'endowment:rpc': 'endowment:rpc', 'endowment:webassembly': 'endowment:webassembly', ///: BEGIN:ONLY_INCLUDE_IN(build-flask) - 'endowment:long-running': 'endowment:long-running', 'endowment:lifecycle-hooks': 'endowment:lifecycle-hooks', + 'endowment:name-lookup': 'endowment:name-lookup', ///: END:ONLY_INCLUDE_IN } as const); @@ -28,10 +28,10 @@ export const ExcludedSnapEndowments = Object.freeze({ ///: BEGIN:ONLY_INCLUDE_IN(build-main) 'endowment:keyring': 'This endowment is still in development therefore not available.', - 'endowment:long-running': - 'endowment:long-running is deprecated. For more information please see https://github.com/MetaMask/snaps/issues/945.', 'endowment:lifecycle-hooks': 'This endowment is experimental and therefore not available.', + 'endowment:name-lookup': + 'This permission is still in development and therefore not available.', ///: END:ONLY_INCLUDE_IN }); diff --git a/shared/constants/transaction.ts b/shared/constants/transaction.ts index 8a5ac8f98eb6..bd80d34bb3cc 100644 --- a/shared/constants/transaction.ts +++ b/shared/constants/transaction.ts @@ -331,7 +331,7 @@ export interface TransactionMeta { blockNumber?: string; chainId: string; /** An internally unique tx identifier. */ - id: number; + id: string; /** Time the transaction was first suggested, in unix epoch time (ms). */ time: number; /** A string representing a name of transaction contract method. */ @@ -400,6 +400,10 @@ export interface TransactionMeta { submittedTime?: number; /** The error encountered during the transaction */ txErr?: TxError; + /** + * Whether the transaction is verified on the blockchain. + */ + verifiedOnBlockchain?: boolean; } /** @@ -441,6 +445,14 @@ export enum TransactionMetaMetricsEvent { submitted = 'Transaction Submitted', } +export enum AnonymousTransactionMetaMetricsEvent { + added = 'Transaction Added Anon', + approved = 'Transaction Approved Anon', + finalized = 'Transaction Finalized Anon', + rejected = 'Transaction Rejected Anon', + submitted = 'Transaction Submitted Anon', +} + /** * The types of assets that a user can send * diff --git a/shared/modules/conversion.utils.test.js b/shared/modules/conversion.utils.test.js index c3f2b6a92bad..6e6c4811420d 100644 --- a/shared/modules/conversion.utils.test.js +++ b/shared/modules/conversion.utils.test.js @@ -3,6 +3,7 @@ import { decWEIToDecETH, getValueFromWeiHex, getWeiHexFromDecimalValue, + sumDecimals, } from './conversion.utils'; describe('conversion utils', () => { @@ -18,6 +19,23 @@ describe('conversion utils', () => { }); }); + describe('sumDecimals', () => { + it('properly sums one value', () => { + const sum = sumDecimals('0.01').toString(10); + + expect('0.01').toStrictEqual(sum); + }); + + it('properly sums an array of decimals', () => { + const sum = sumDecimals( + '0.01', + ...['0.10', '1.00', '10.00', '100.00', '1000.00'], + ).toString(10); + + expect('1111.11').toStrictEqual(sum); + }); + }); + describe('getWeiHexFromDecimalValue', () => { it('should correctly convert 0 in ETH', () => { const weiValue = getWeiHexFromDecimalValue({ diff --git a/shared/modules/conversion.utils.ts b/shared/modules/conversion.utils.ts index e2466bcabb1a..0f3a35dde774 100644 --- a/shared/modules/conversion.utils.ts +++ b/shared/modules/conversion.utils.ts @@ -156,6 +156,16 @@ export function sumHexes(first: string, ...args: string[]) { return total.toPrefixedHexString(); } +export function sumDecimals(first: string, ...args: string[]) { + const firstValue = new Numeric(first, 10); + const total = args.reduce( + (acc, hexAmount) => acc.add(new Numeric(hexAmount, 10)), + firstValue, + ); + + return total; +} + export function hexWEIToDecGWEI(value: number | string | BigNumber | BN) { return new Numeric(value, 16, EtherDenomination.WEI) .toBase(10) diff --git a/shared/modules/transaction.utils.test.js b/shared/modules/transaction.utils.test.js index 242d100077a8..a5801df4f6df 100644 --- a/shared/modules/transaction.utils.test.js +++ b/shared/modules/transaction.utils.test.js @@ -1,4 +1,4 @@ -import EthQuery from 'ethjs-query'; +import EthQuery from '@metamask/ethjs-query'; import { createTestProviderTools } from '../../test/stub/provider'; import { TransactionType } from '../constants/transaction'; import { diff --git a/shared/notifications/index.js b/shared/notifications/index.js index eef336bc7501..961b5a559c8c 100644 --- a/shared/notifications/index.js +++ b/shared/notifications/index.js @@ -6,6 +6,7 @@ */ export const NOTIFICATION_DROP_LEDGER_FIREFOX = 25; export const NOTIFICATION_OPEN_BETA_SNAPS = 26; +export const NOTIFICATION_BUY_SELL_BUTTON = 27; export const UI_NOTIFICATIONS = { 1: { @@ -134,7 +135,7 @@ export const UI_NOTIFICATIONS = { id: 23, date: null, image: { - src: 'images/blockaid-security-provider.png', + src: 'images/blockaid-security-provider.svg', width: '100%', }, }, @@ -156,6 +157,14 @@ export const UI_NOTIFICATIONS = { width: '100%', }, }, + [NOTIFICATION_BUY_SELL_BUTTON]: { + id: Number(NOTIFICATION_BUY_SELL_BUTTON), + date: null, + image: { + src: 'images/sell_button_whatsnew.png', + width: '100%', + }, + }, }; export const getTranslatedUINotifications = (t, locale) => { @@ -419,5 +428,16 @@ export const getTranslatedUINotifications = (t, locale) => { ) : '', }, + [NOTIFICATION_BUY_SELL_BUTTON]: { + ...UI_NOTIFICATIONS[NOTIFICATION_BUY_SELL_BUTTON], + title: t('notificationsBuySellTitle'), + description: t('notificationsBuySellDescription'), + actionText: t('notificationsBuySellActionText'), + date: UI_NOTIFICATIONS[NOTIFICATION_BUY_SELL_BUTTON].date + ? new Intl.DateTimeFormat(formattedLocale).format( + new Date(UI_NOTIFICATIONS[NOTIFICATION_BUY_SELL_BUTTON].date), + ) + : '', + }, }; }; diff --git a/test/data/mock-send-state.json b/test/data/mock-send-state.json index 8b4cbf16a709..14d4967d70f9 100644 --- a/test/data/mock-send-state.json +++ b/test/data/mock-send-state.json @@ -11,6 +11,7 @@ }, "appState": { "networkDropdownOpen": false, + "importNftsModal": { "open": false }, "gasIsLoading": false, "isLoading": false, "modal": { diff --git a/test/data/mock-state.json b/test/data/mock-state.json index 33a4db866132..6c2064108972 100644 --- a/test/data/mock-state.json +++ b/test/data/mock-state.json @@ -4,6 +4,7 @@ }, "appState": { "networkDropdownOpen": false, + "importNftsModal": { "open": false }, "gasIsLoading": false, "isLoading": false, "modal": { @@ -19,6 +20,14 @@ "warning": null, "customTokenAmount": "10" }, + "confirmTransaction": { + "txData": { + "txParams": { + "gas": "0x153e2", + "value": "0x0" + } + } + }, "history": { "mostRecentOverviewPage": "/mostRecentOverviewPage" }, @@ -151,6 +160,10 @@ { "type": "Snap Keyring", "accounts": ["0xb552685e3d2790efd64a175b00d51f02cdafee5d"] + }, + { + "type": "Custody test", + "accounts": ["0xca8f1F0245530118D0cf14a06b01Daf8f76Cf281"] } ], "identities": { @@ -169,6 +182,10 @@ "0xeb9e64b93097bc15f01f13eae97015c57ab64823": { "name": "Test Account 3", "address": "0xeb9e64b93097bc15f01f13eae97015c57ab64823" + }, + "0xca8f1F0245530118D0cf14a06b01Daf8f76Cf281": { + "name": "Custody test", + "address": "0xca8f1F0245530118D0cf14a06b01Daf8f76Cf281" } }, "selectedNetworkClientId": "goerli", @@ -1379,6 +1396,7 @@ } ], "desktopEnabled": false, + "addSnapAccountEnabled": false, "pendingApprovals": { "testApprovalId": { "id": "testApprovalId", diff --git a/test/e2e/accounts/test-create-snap-account.spec.js b/test/e2e/accounts/test-create-snap-account.spec.js new file mode 100644 index 000000000000..1cd8e2d00656 --- /dev/null +++ b/test/e2e/accounts/test-create-snap-account.spec.js @@ -0,0 +1,262 @@ +const { + withFixtures, + defaultGanacheOptions, + unlockWallet, + WINDOW_TITLES, + switchToNotificationWindow, +} = require('../helpers'); +const FixtureBuilder = require('../fixture-builder'); +const { TEST_SNAPS_SIMPLE_KEYRING_WEBSITE_URL } = require('./utils'); + +describe('Create Snap Account', function () { + it('create Snap account popup contains correct Snap name and snapId', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions: defaultGanacheOptions, + failOnConsoleError: false, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + + await unlockWallet(driver); + + // navigate to test Snaps page and connect + await driver.openNewPage(TEST_SNAPS_SIMPLE_KEYRING_WEBSITE_URL); + await driver.clickElement('#connectButton'); + + // switch to metamask extension and click connect to start installing the snap + await switchToNotificationWindow(driver); + await driver.clickElement({ + text: 'Connect', + tag: 'button', + }); + + // scroll to the bottom of the page + await driver.clickElementSafe('[data-testid="snap-install-scroll"]'); + + // click the install button to install the snap + await driver.waitForSelector({ text: 'Install' }); + await driver.clickElement({ + text: 'Install', + tag: 'button', + }); + await driver.waitForSelector({ text: 'OK' }); + await driver.clickElement({ + text: 'OK', + tag: 'button', + }); + + // move back to the Snap window to test the create account flow + await driver.switchToWindowWithTitle( + WINDOW_TITLES.SnapSimpleKeyringDapp, + ); + + // check the dapp connection status + await driver.waitForSelector({ + css: '#snapConnected', + text: 'Connected', + }); + + // create new account on dapp + await driver.clickElement({ + text: 'Create account', + tag: 'div', + }); + + await driver.clickElement({ + text: 'Create Account', + tag: 'button', + }); + + await switchToNotificationWindow(driver); + + await driver.findElement({ + css: '[data-testid="confirmation-submit-button"]', + text: 'Create', + }); + + await driver.findElement({ + css: '[data-testid="confirmation-cancel-button"]', + text: 'Cancel', + }); + + await driver.findElement({ + css: '[data-testid="create-snap-account-content-description"]', + text: 'MetaMask Simple Snap Keyring wants to add a new Snap account to your wallet', + }); + + await driver.findElement({ + css: '[data-testid="create-snap-account-content-title"]', + text: 'Create Snap account', + }); + }, + ); + }); + + it('create Snap account confirmation flow ends in approval success', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions: defaultGanacheOptions, + failOnConsoleError: false, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + + await unlockWallet(driver); + + // navigate to test Snaps page and connect + await driver.openNewPage(TEST_SNAPS_SIMPLE_KEYRING_WEBSITE_URL); + await driver.clickElement('#connectButton'); + + // switch to metamask extension and click connect to start installing the snap + await switchToNotificationWindow(driver); + await driver.clickElement({ + text: 'Connect', + tag: 'button', + }); + + // scroll to the bottom of the page + await driver.clickElementSafe('[data-testid="snap-install-scroll"]'); + + // click the install button to install the snap + await driver.waitForSelector({ text: 'Install' }); + await driver.clickElement({ + text: 'Install', + tag: 'button', + }); + await driver.waitForSelector({ text: 'OK' }); + await driver.clickElement({ + text: 'OK', + tag: 'button', + }); + + // move back to the Snap window to test the create account flow + await driver.switchToWindowWithTitle( + WINDOW_TITLES.SnapSimpleKeyringDapp, + ); + + // check the dapp connection status + await driver.waitForSelector({ + css: '#snapConnected', + text: 'Connected', + }); + + // create new account on dapp + await driver.clickElement({ + text: 'Create account', + tag: 'div', + }); + + await driver.clickElement({ + text: 'Create Account', + tag: 'button', + }); + + await switchToNotificationWindow(driver); + + await driver.clickElement('[data-testid="confirmation-submit-button"]'); + + await driver.findElement({ + tag: 'div', + text: 'Your account is ready!', + }); + + // click the okay button + await driver.clickElement('[data-testid="confirmation-submit-button"]'); + + // switch back to the test dapp/Snap window + await driver.switchToWindowWithTitle( + WINDOW_TITLES.SnapSimpleKeyringDapp, + ); + + await driver.findElement({ + tag: 'p', + text: 'Successful request', + }); + }, + ); + }); + + it('create Snap account confirmation cancelation results in error in Snap', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions: defaultGanacheOptions, + failOnConsoleError: false, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + + await unlockWallet(driver); + // navigate to test Snaps page and connect + await driver.openNewPage(TEST_SNAPS_SIMPLE_KEYRING_WEBSITE_URL); + await driver.clickElement('#connectButton'); + + // switch to metamask extension and click connect to start installing the snap + await switchToNotificationWindow(driver); + await driver.clickElement({ + text: 'Connect', + tag: 'button', + }); + + // scroll to the bottom of the page + await driver.clickElementSafe('[data-testid="snap-install-scroll"]'); + + // click the install button to install the snap + await driver.waitForSelector({ text: 'Install' }); + await driver.clickElement({ + text: 'Install', + tag: 'button', + }); + await driver.waitForSelector({ text: 'OK' }); + await driver.clickElement({ + text: 'OK', + tag: 'button', + }); + + // move back to the Snap window to test the create account flow + await driver.switchToWindowWithTitle( + WINDOW_TITLES.SnapSimpleKeyringDapp, + ); + + // check the dapp connection status + await driver.waitForSelector({ + css: '#snapConnected', + text: 'Connected', + }); + + // create new account on dapp + await driver.clickElement({ + text: 'Create account', + tag: 'div', + }); + + await driver.clickElement({ + text: 'Create Account', + tag: 'button', + }); + + // switch to metamask extension + await switchToNotificationWindow(driver); + + // cancel account creation + await driver.clickElement('[data-testid="confirmation-cancel-button"]'); + + // switch back to the test dapp/Snap window + await driver.switchToWindowWithTitle( + WINDOW_TITLES.SnapSimpleKeyringDapp, + ); + + await driver.findElement({ + tag: 'p', + text: 'Error request', + }); + }, + ); + }); +}); diff --git a/test/e2e/accounts/test-remove-accounts-snap.spec.js b/test/e2e/accounts/test-remove-accounts-snap.spec.js new file mode 100644 index 000000000000..850eca6a1f72 --- /dev/null +++ b/test/e2e/accounts/test-remove-accounts-snap.spec.js @@ -0,0 +1,127 @@ +const { strict: assert } = require('assert'); +const { + withFixtures, + defaultGanacheOptions, + unlockWallet, + WINDOW_TITLES, + switchToNotificationWindow, +} = require('../helpers'); +const FixtureBuilder = require('../fixture-builder'); +const { TEST_SNAPS_SIMPLE_KEYRING_WEBSITE_URL } = require('./utils'); + +describe('Remove Account Snap', function () { + it('disable a snap and remove it', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions: defaultGanacheOptions, + failOnConsoleError: false, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + + await unlockWallet(driver); + + // Navigate to test Snaps page and connect. + await driver.openNewPage(TEST_SNAPS_SIMPLE_KEYRING_WEBSITE_URL); + + // Connect the dapp. + await driver.clickElement('#connectButton'); + await switchToNotificationWindow(driver); + await driver.clickElement({ + text: 'Connect', + tag: 'button', + }); + + // Scroll to the bottom of the page. + await driver.clickElementSafe('[data-testid="snap-install-scroll"]'); + + // Click the install button to install the snap. + await driver.waitForSelector({ text: 'Install' }); + await driver.clickElement({ + text: 'Install', + tag: 'button', + }); + await driver.waitForSelector({ text: 'OK' }); + await driver.clickElement({ + text: 'OK', + tag: 'button', + }); + + // Move back to the snap window to test the create account flow. + await driver.switchToWindowWithTitle( + WINDOW_TITLES.SnapSimpleKeyringDapp, + ); + + // Check the dapp connection status. + await driver.waitForSelector({ + css: '#snapConnected', + text: 'Connected', + }); + + // Create new account on dapp. + await driver.clickElement({ + text: 'Create account', + tag: 'div', + }); + await driver.clickElement({ + text: 'Create Account', + tag: 'button', + }); + await switchToNotificationWindow(driver); + await driver.clickElement('[data-testid="confirmation-submit-button"]'); + await driver.findElement({ + tag: 'div', + text: 'Your account is ready!', + }); + + // Click the OK button. + await driver.clickElement('[data-testid="confirmation-submit-button"]'); + + // Switch back to the test dapp window. + await driver.switchToWindowWithTitle( + WINDOW_TITLES.SnapSimpleKeyringDapp, + ); + + await driver.findElement({ + tag: 'p', + text: 'Successful request', + }); + + // Navigate to settings. + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); + await driver.clickElement( + '[data-testid="account-options-menu-button"]', + ); + await driver.clickElement({ text: 'Settings', tag: 'div' }); + await driver.clickElement({ text: 'Snaps', tag: 'div' }); + await driver.clickElement({ + text: 'MetaMask Simple Snap Keyring', + tag: 'p', + }); + + // Disable the snap. + await driver.clickElement('.toggle-button > div'); + + // Remove the snap. + await driver.clickElement({ + text: 'Remove MetaMask Simple Snap Keyring', + tag: 'p', + }); + await driver.clickElement('#popoverRemoveSnapButton'); + + // Assert that the snap was removed. + const removeResult = await driver.findElement( + '.snap-list-tab__container--no-snaps_inner', + ); + assert.equal( + await removeResult.getText(), + "You don't have any snaps installed.", + ); + }, + ); + }); +}); diff --git a/test/e2e/accounts/test-snap-accounts.spec.js b/test/e2e/accounts/test-snap-accounts.spec.js new file mode 100644 index 000000000000..91adb3e6ba99 --- /dev/null +++ b/test/e2e/accounts/test-snap-accounts.spec.js @@ -0,0 +1,464 @@ +const util = require('ethereumjs-util'); +const FixtureBuilder = require('../fixture-builder'); +const { + clickSignOnSignatureConfirmation, + convertETHToHexGwei, + openDapp, + PRIVATE_KEY, + PRIVATE_KEY_TWO, + sendTransaction, + switchToNotificationWindow, + switchToOrOpenDapp, + unlockWallet, + validateContractDetails, + WINDOW_TITLES, + withFixtures, +} = require('../helpers'); +const Driver = require('../webdriver/driver'); // eslint-disable-line no-unused-vars -- this is imported for JSDoc +const { TEST_SNAPS_SIMPLE_KEYRING_WEBSITE_URL } = require('./utils'); + +describe('Test Snap Account', function () { + const ganacheOptions = { + accounts: [ + { + secretKey: PRIVATE_KEY, + balance: convertETHToHexGwei(25), + }, + { + secretKey: PRIVATE_KEY_TWO, + balance: convertETHToHexGwei(25), + }, + ], + }; + + const accountSnapFixtures = (title) => { + return { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp(false) + .build(), + ganacheOptions, + failOnConsoleError: false, + title, + }; + }; + + // convert PRIVATE_KEY to public key + const PUBLIC_KEY = util + .privateToAddress(Buffer.from(PRIVATE_KEY.slice(2), 'hex')) + .toString('hex'); + + it('can create a new Snap account', async function () { + await withFixtures( + accountSnapFixtures(this.test.title), + async ({ driver }) => { + await installSnapSimpleKeyring(driver, false); + + await makeNewAccountAndSwitch(driver); + }, + ); + }); + + it('can import a private key and transfer 1 ETH (sync flow)', async function () { + await withFixtures( + accountSnapFixtures(this.test.title), + async ({ driver }) => { + await importPrivateKeyAndTransfer1ETH(driver, 'sync'); + }, + ); + }); + + it('can import a private key and transfer 1 ETH (async flow approve)', async function () { + await withFixtures( + accountSnapFixtures(this.test.title), + async ({ driver }) => { + await importPrivateKeyAndTransfer1ETH(driver, 'approve'); + }, + ); + }); + + it('can import a private key and transfer 1 ETH (async flow reject)', async function () { + await withFixtures( + accountSnapFixtures(this.test.title), + async ({ driver }) => { + await importPrivateKeyAndTransfer1ETH(driver, 'reject'); + }, + ); + }); + + // run the full matrix of sign types and sync/async approve/async reject flows + // (in Jest we could do this with test.each, but that does not exist here) + [ + ['#personalSign', 'sync'], + ['#personalSign', 'approve'], + ['#personalSign', 'reject'], + ['#signTypedData', 'sync'], + ['#signTypedData', 'approve'], + ['#signTypedData', 'reject'], + ['#signTypedDataV3', 'sync'], + ['#signTypedDataV3', 'approve'], + ['#signTypedDataV3', 'reject'], + ['#signTypedDataV4', 'sync'], + ['#signTypedDataV4', 'approve'], + ['#signTypedDataV4', 'reject'], + ['#signPermit', 'sync'], + ['#signPermit', 'approve'], + ['#signPermit', 'reject'], + ].forEach(([locatorID, flowType]) => { + // generate title of the test from the locatorID and flowType + let title = `can ${locatorID} (${ + flowType === 'sync' ? 'sync' : 'async' + } flow`; + + title += flowType === 'sync' ? ')' : ` ${flowType})`; + + it(title, async function () { + await withFixtures( + accountSnapFixtures(this.test.title), + async ({ driver }) => { + const isAsyncFlow = flowType !== 'sync'; + + await installSnapSimpleKeyring(driver, isAsyncFlow); + + const newPublicKey = await makeNewAccountAndSwitch(driver); + + await openDapp(driver); + + await signData(driver, locatorID, newPublicKey, flowType); + }, + ); + }); + }); + + it('can connect to the Test Dapp, then #signTypedDataV3, disconnect then connect, then #signTypedDataV4 (async flow approve)', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder().build(), + ganacheOptions, + failOnConsoleError: false, + title: this.test.title, + }, + async ({ driver }) => { + const flowType = 'approve'; + const isAsyncFlow = flowType !== 'sync'; + + await installSnapSimpleKeyring(driver, isAsyncFlow); + + const newPublicKey = await makeNewAccountAndSwitch(driver); + + // open the Test Dapp and connect Account 2 to it + await connectAccountToTestDapp(driver); + + // do #signTypedDataV3 + await signData(driver, '#signTypedDataV3', newPublicKey, flowType); + + // disconnect from the Test Dapp + await disconnectFromTestDapp(driver); + + // reconnect Account 2 to the Test Dapp + await connectAccountToTestDapp(driver); + + // do #signTypedDataV4 + await signData(driver, '#signTypedDataV4', newPublicKey, flowType); + }, + ); + }); + + /** + * @param {Driver} driver + * @param {string} flowType + */ + async function importPrivateKeyAndTransfer1ETH(driver, flowType) { + const isAsyncFlow = flowType !== 'sync'; + + await installSnapSimpleKeyring(driver, isAsyncFlow); + await importKeyAndSwitch(driver); + + // send 1 ETH from Account 2 to Account 1 + await sendTransaction(driver, PUBLIC_KEY, 1, isAsyncFlow); + + if (isAsyncFlow) { + await approveOrRejectRequest(driver, flowType); + } + + if (flowType === 'sync' || flowType === 'approve') { + // click on Accounts + await driver.clickElement('[data-testid="account-menu-icon"]'); + + // ensure one account has 26 ETH and the other has 24 ETH + await driver.findElement('[title="26 ETH"]'); + await driver.findElement('[title="24 ETH"]'); + } else if (flowType === 'reject') { + // ensure the transaction was rejected by the Snap + await driver.findElement( + '[data-original-title="Request rejected by user or snap."]', + ); + } + } + + /** + * @param {Driver} driver + * @param {string} locatorID + * @param {string} newPublicKey + * @param {string} flowType + */ + async function signData(driver, locatorID, newPublicKey, flowType) { + const isAsyncFlow = flowType !== 'sync'; + + await switchToOrOpenDapp(driver); + + await driver.clickElement(locatorID); + await switchToNotificationWindow(driver, 4); + + // these two don't have a contract details page + if (locatorID !== '#personalSign' && locatorID !== '#signTypedData') { + await validateContractDetails(driver); + } + + await clickSignOnSignatureConfirmation(driver, 3); + + if (isAsyncFlow) { + await approveOrRejectRequest(driver, flowType); + } + + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + + if (flowType === 'sync' || flowType === 'approve') { + await driver.clickElement(`${locatorID}Verify`); + + const resultLocator = + locatorID === '#personalSign' + ? '#personalSignVerifyECRecoverResult' // the verify span IDs are different with Personal Sign + : `${locatorID}VerifyResult`; + + await driver.findElement({ + css: resultLocator, + text: newPublicKey.toLowerCase(), + }); + } else if (flowType === 'reject') { + // ensure the transaction was rejected by the Snap + await driver.findElement({ + text: 'Error: Request rejected by user or snap.', + }); + } + } + + /** + * @param {Driver} driver + * @param {boolean} isAsyncFlow + */ + async function installSnapSimpleKeyring(driver, isAsyncFlow) { + driver.navigate(); + + await unlockWallet(driver); + + // navigate to test Snaps page and connect + await driver.openNewPage(TEST_SNAPS_SIMPLE_KEYRING_WEBSITE_URL); + const connectButton = await driver.findElement('#connectButton'); + await driver.scrollToElement(connectButton); + await connectButton.click(); + + await switchToNotificationWindow(driver); + await driver.clickElement({ + text: 'Connect', + tag: 'button', + }); + + await driver.clickElementSafe('[data-testid="snap-install-scroll"]', 1000); + + await driver.waitForSelector({ text: 'Install' }); + + await driver.clickElement({ + text: 'Install', + tag: 'button', + }); + + await driver.waitForSelector({ text: 'OK' }); + + await driver.clickElement({ + text: 'OK', + tag: 'button', + }); + + await driver.switchToWindowWithTitle('SSK - Simple Snap Keyring'); + + await driver.waitForSelector({ + text: 'Connected', + tag: 'span', + }); + + if (isAsyncFlow) { + await toggleAsyncFlow(driver); + } + } + + /** + * @param {Driver} driver + */ + async function toggleAsyncFlow(driver) { + await driver.switchToWindowWithTitle('SSK - Simple Snap Keyring'); + + // click the parent of #use-sync-flow-toggle (trying to click the element itself gives "ElementNotInteractableError: could not be scrolled into view") + await driver.clickElement({ + xpath: '//input[@id="use-sync-flow-toggle"]/..', + }); + } + + /** + * @param {Driver} driver + */ + async function importKeyAndSwitch(driver) { + await driver.clickElement({ + text: 'Import account', + tag: 'div', + }); + + await driver.fill('#import-account-private-key', PRIVATE_KEY_TWO); + + await driver.clickElement({ + text: 'Import Account', + tag: 'button', + }); + + // Click "Create" on the Snap's confirmation popup + await switchToNotificationWindow(driver, 3); + await driver.clickElement('[data-testid="confirmation-submit-button"]'); + await driver.clickElement('[data-testid="confirmation-submit-button"]'); + await driver.switchToWindowWithTitle('SSK - Simple Snap Keyring'); + + await switchToAccount2(driver); + } + + /** + * @param {Driver} driver + */ + async function makeNewAccountAndSwitch(driver) { + await driver.clickElement({ + text: 'Create account', + tag: 'div', + }); + + await driver.clickElement({ + text: 'Create Account', + tag: 'button', + }); + + // Click "Create" on the Snap's confirmation popup + await switchToNotificationWindow(driver, 3); + await driver.clickElement('[data-testid="confirmation-submit-button"]'); + await driver.clickElement('[data-testid="confirmation-submit-button"]'); + await driver.switchToWindowWithTitle('SSK - Simple Snap Keyring'); + + const newPublicKey = await ( + await driver.findElement({ + text: '0x', + tag: 'p', + }) + ).getText(); + + await switchToAccount2(driver); + + return newPublicKey; + } + + /** + * @param {Driver} driver + */ + async function switchToAccount2(driver) { + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); + + // click on Accounts + await driver.clickElement('[data-testid="account-menu-icon"]'); + + const label = await driver.findElement({ css: '.mm-tag', text: 'Snaps' }); + + label.click(); + + await driver.waitForElementNotPresent('.mm-tag'); + } + + /** + * @param {Driver} driver + */ + async function connectAccountToTestDapp(driver) { + await switchToOrOpenDapp(driver); + await driver.clickElement('#connectButton'); + await switchToNotificationWindow(driver, 4); + await driver.clickElement('[data-testid="page-container-footer-next"]'); + await driver.clickElement('[data-testid="page-container-footer-next"]'); + } + + /** + * @param {Driver} driver + */ + async function disconnectFromTestDapp(driver) { + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); + await driver.clickElement('[data-testid="account-options-menu-button"]'); + await driver.clickElement('[data-testid="global-menu-connected-sites"]'); + await driver.clickElement({ text: 'Disconnect', tag: 'a' }); + await driver.clickElement({ text: 'Disconnect', tag: 'button' }); + } + + /** + * @param {Driver} driver + * @param {string} flowType + */ + async function approveOrRejectRequest(driver, flowType) { + await driver.switchToWindowWithTitle('SSK - Simple Snap Keyring'); + + await driver.clickElementUsingMouseMove({ + text: 'List requests', + tag: 'div', + }); + + await driver.clickElement({ + text: 'List Requests', + tag: 'button', + }); + + // get the JSON from the screen + const requestJSON = await ( + await driver.findElement({ + text: '"scope": "",', + tag: 'div', + }) + ).getText(); + + const requestID = JSON.parse(requestJSON)[0].id; + + if (flowType === 'approve') { + await driver.clickElementUsingMouseMove({ + text: 'Approve request', + tag: 'div', + }); + + await driver.fill('#approve-request-request-id', requestID); + + await driver.clickElement({ + text: 'Approve Request', + tag: 'button', + }); + } else if (flowType === 'reject') { + await driver.clickElementUsingMouseMove({ + text: 'Reject request', + tag: 'div', + }); + + await driver.fill('#reject-request-request-id', requestID); + + await driver.clickElement({ + text: 'Reject Request', + tag: 'button', + }); + } + + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); + } +}); diff --git a/test/e2e/accounts/utils.ts b/test/e2e/accounts/utils.ts new file mode 100644 index 000000000000..3aab19654db4 --- /dev/null +++ b/test/e2e/accounts/utils.ts @@ -0,0 +1,2 @@ +export const TEST_SNAPS_SIMPLE_KEYRING_WEBSITE_URL = + 'https://metamask.github.io/snap-simple-keyring/0.2.3/'; diff --git a/test/e2e/fixture-builder.js b/test/e2e/fixture-builder.js index 61db5bfc3e2e..7f59264e6e84 100644 --- a/test/e2e/fixture-builder.js +++ b/test/e2e/fixture-builder.js @@ -259,7 +259,6 @@ function defaultFixture() { name: 'Account 1', }, }, - infuraBlocked: false, ipfsGateway: 'dweb.link', knownMethodData: {}, ledgerTransportType: 'webhid', @@ -382,8 +381,7 @@ function onboardingFixture() { featureFlags: {}, forgottenPassword: false, identities: {}, - infuraBlocked: false, - ipfsGateway: 'dweb.link', + ipfsGateway: 'dweb.linkssssss', knownMethodData: {}, ledgerTransportType: 'webhid', lostIdentities: {}, @@ -479,6 +477,13 @@ class FixtureBuilder { return this; } + withKeyringControllerAdditionalAccountVault() { + return this.withKeyringController({ + vault: + '{"data":"n1LbLX7D4CdnFjYkyvn8Vfv0VQ0spMTdzCP+bsrZX2cQXiz+GXb9AKaIjbcR0EHuQ5/VulkrpbZFDSYJ5VlZ5VRVVUngckHCNgzw73Jo3D+fVrmwEn6HhBbA+STHRMdjf3eEL/eiS5HbkQ0zutoj8KU/nMPfTz6iuV+WGa0hcOKZa+mqYkSzeYuqVCnWYspjF9hKE5NKnl5Vrnvu3/eFi6PiDeaUbIfs0ccttopnTdQya5e3KB23tu0ORa48EJawK0JeKurLlFfNNNqq+tg3HRgxUyiVp6mCns8GBdsd9Wx3HP00qIJa4OAFV2TtDvSSuek1XAWlIqjKegZbnXosB0t3IABhqWnSozXRFvsHe8oHVZP++B/2pJPzz5kkAgK9Ya/quy/7ok/GN5qw0n9Q6cCexfm9hGC3MI53ClEg08yq2w/eVKMDeEdES6IqidpRxOanIAsrcDjPIw6yP7tXqzo7d4A/50GyBb5MJYeTD7r9bV5/5VWcHtILDyGt4CROgM9/U/wdKduNJy5Igfhh0nvA0399Ber9jvWmtmQxiWAxAgrcf9Xi0SZXWewH/ZEnAOkIOmTVX9hpAGkbDqIvK1Zt2bIK5X/At2KiZ5DqAFet9AiyLZTPR5YQ2KaB8AarEjUthTa7EcDSpAPsr9jLPZwlKuMZO2I29xZHx4ht4ozlcqU+zMF8JBojtP73cRQKc0Chqm8xY9I9K6jANdZn9lT+q20RDgwJAfkp+UUSTTqUgZ3ruej2FyY9F+GWuOZJY1zPN0KG7j7uPXaP5Gqq","iv":"XxlC9CCaul7U0F6JRNyH9A==","salt":"gQOYCUFPAPVJITl0gxIs8TdgNQNl2ltzu4OAHajj+tM="}', + }); + } + withKeyringControllerImportedAccountVault() { return this.withKeyringController({ vault: @@ -582,7 +587,7 @@ class FixtureBuilder { return this; } - withPermissionControllerConnectedToTestDapp() { + withPermissionControllerConnectedToTestDapp(restrictReturnedAccounts = true) { return this.withPermissionController({ subjects: { [DAPP_URL]: { @@ -592,10 +597,13 @@ class FixtureBuilder { id: 'ZaqPEWxyhNCJYACFw93jE', parentCapability: 'eth_accounts', invoker: DAPP_URL, - caveats: [ + caveats: restrictReturnedAccounts && [ { type: 'restrictReturnedAccounts', - value: ['0x5cfe73b6021e818b776b421b1c4db2474086a7e1'], + value: [ + '0x5cfe73b6021e818b776b421b1c4db2474086a7e1', + '0x09781764c08de8ca82e156bbf156a3ca217c7950', + ], }, ], date: 1664388714636, @@ -651,6 +659,23 @@ class FixtureBuilder { return this; } + withPreferencesControllerAdditionalAccountIdentities() { + return this.withPreferencesController({ + identites: { + '0x5cfe73b6021e818b776b421b1c4db2474086a7e1': { + address: '0x5cfe73b6021e818b776b421b1c4db2474086a7e1', + lastSelected: 1665507600000, + name: 'Account 1', + }, + '0x09781764c08de8ca82e156bbf156a3ca217c7950': { + address: '0x09781764c08de8ca82e156bbf156a3ca217c7950', + lastSelected: 1665507500000, + name: 'Account 2', + }, + }, + }); + } + withPreferencesControllerImportedAccountIdentities() { return this.withPreferencesController({ identities: { @@ -753,7 +778,7 @@ class FixtureBuilder { withTransactionControllerMultipleTransactions() { return this.withTransactionController({ transactions: { - 7911313280012623: { + '7087d1d7-f0e8-4c0f-a903-6d9daa392baf': { chainId: CHAIN_IDS.LOCALHOST, dappSuggestedGasFees: { gas: '0x5208', @@ -768,7 +793,7 @@ class FixtureBuilder { maxFeePerGas: '0x59682f0c', maxPriorityFeePerGas: '0x59682f00', }, - id: 7911313280012623, + id: '7087d1d7-f0e8-4c0f-a903-6d9daa392baf', loadingDefaults: true, metamaskNetworkId: '1337', origin: 'https://metamask.github.io', @@ -794,7 +819,7 @@ class FixtureBuilder { }, ], ], - id: 7911313280012623, + id: '7087d1d7-f0e8-4c0f-a903-6d9daa392baf', loadingDefaults: false, metamaskNetworkId: '1337', origin: 'https://metamask.github.io', @@ -810,7 +835,7 @@ class FixtureBuilder { }, type: 'simpleSend', }, - 7911313280012624: { + '6eab4240-3762-4581-abc5-cd91eab6964e': { chainId: CHAIN_IDS.LOCALHOST, dappSuggestedGasFees: { gas: '0x5208', @@ -825,7 +850,7 @@ class FixtureBuilder { maxFeePerGas: '0x59682f0c', maxPriorityFeePerGas: '0x59682f00', }, - id: 7911313280012624, + id: '6eab4240-3762-4581-abc5-cd91eab6964e', loadingDefaults: true, metamaskNetworkId: '1337', origin: 'https://metamask.github.io', @@ -851,7 +876,7 @@ class FixtureBuilder { }, ], ], - id: 7911313280012624, + id: '6eab4240-3762-4581-abc5-cd91eab6964e', loadingDefaults: false, metamaskNetworkId: '1337', origin: 'https://metamask.github.io', @@ -867,7 +892,7 @@ class FixtureBuilder { }, type: 'simpleSend', }, - 7911313280012625: { + 'c15eee26-11d6-4914-a70e-36ef9a3bcacb': { chainId: CHAIN_IDS.LOCALHOST, dappSuggestedGasFees: { gas: '0x5208', @@ -882,7 +907,7 @@ class FixtureBuilder { maxFeePerGas: '0x59682f0c', maxPriorityFeePerGas: '0x59682f00', }, - id: 7911313280012625, + id: 'c15eee26-11d6-4914-a70e-36ef9a3bcacb', loadingDefaults: true, metamaskNetworkId: '1337', origin: 'https://metamask.github.io', @@ -908,7 +933,7 @@ class FixtureBuilder { }, ], ], - id: 7911313280012625, + id: 'c15eee26-11d6-4914-a70e-36ef9a3bcacb', loadingDefaults: false, metamaskNetworkId: '1337', origin: 'https://metamask.github.io', @@ -924,7 +949,7 @@ class FixtureBuilder { }, type: 'simpleSend', }, - 7911313280012626: { + 'dfa9e5ad-d069-46b1-976e-a23734971d87': { chainId: CHAIN_IDS.LOCALHOST, dappSuggestedGasFees: { gas: '0x5208', @@ -939,7 +964,7 @@ class FixtureBuilder { maxFeePerGas: '0x59682f0c', maxPriorityFeePerGas: '0x59682f00', }, - id: 7911313280012626, + id: 'dfa9e5ad-d069-46b1-976e-a23734971d87', loadingDefaults: true, metamaskNetworkId: '1337', origin: 'https://metamask.github.io', @@ -965,7 +990,7 @@ class FixtureBuilder { }, ], ], - id: 7911313280012626, + id: 'dfa9e5ad-d069-46b1-976e-a23734971d87', loadingDefaults: false, metamaskNetworkId: '1337', origin: 'https://metamask.github.io', @@ -988,12 +1013,12 @@ class FixtureBuilder { withTransactionControllerTypeOneTransaction() { return this.withTransactionController({ transactions: { - 4046084157914634: { + '13a01e77-a368-4bb9-aba9-e7435580e3b9': { chainId: CHAIN_IDS.LOCALHOST, history: [ { chainId: CHAIN_IDS.LOCALHOST, - id: 4046084157914634, + id: '13a01e77-a368-4bb9-aba9-e7435580e3b9', loadingDefaults: true, metamaskNetworkId: '1337', origin: 'metamask', @@ -1018,13 +1043,13 @@ class FixtureBuilder { }, ], ], - id: 4046084157914634, + id: '13a01e77-a368-4bb9-aba9-e7435580e3b9', loadingDefaults: false, metamaskNetworkId: '1337', origin: 'metamask', primaryTransaction: { chainId: CHAIN_IDS.LOCALHOST, - id: 4046084157914634, + id: '13a01e77-a368-4bb9-aba9-e7435580e3b9', loadingDefaults: true, metamaskNetworkId: '1337', origin: 'metamask', @@ -1057,12 +1082,12 @@ class FixtureBuilder { withTransactionControllerTypeTwoTransaction() { return this.withTransactionController({ transactions: { - 4046084157914634: { + '13a01e77-a368-4bb9-aba9-e7435580e3b9': { chainId: CHAIN_IDS.LOCALHOST, history: [ { chainId: CHAIN_IDS.LOCALHOST, - id: 4046084157914634, + id: '13a01e77-a368-4bb9-aba9-e7435580e3b9', loadingDefaults: true, metamaskNetworkId: '1337', origin: 'metamask', @@ -1089,13 +1114,13 @@ class FixtureBuilder { }, ], ], - id: 4046084157914634, + id: '13a01e77-a368-4bb9-aba9-e7435580e3b9', loadingDefaults: false, metamaskNetworkId: '1337', origin: 'metamask', primaryTransaction: { chainId: CHAIN_IDS.LOCALHOST, - id: 4046084157914634, + id: '13a01e77-a368-4bb9-aba9-e7435580e3b9', loadingDefaults: true, metamaskNetworkId: '1337', origin: 'metamask', @@ -1132,12 +1157,12 @@ class FixtureBuilder { withTransactionControllerApprovedTransaction() { return this.withTransactionController({ transactions: { - 4046084157914634: { + '13a01e77-a368-4bb9-aba9-e7435580e3b9': { chainId: CHAIN_IDS.LOCALHOST, history: [ { chainId: CHAIN_IDS.LOCALHOST, - id: 4046084157914634, + id: '13a01e77-a368-4bb9-aba9-e7435580e3b9', loadingDefaults: true, metamaskNetworkId: '1337', origin: 'metamask', @@ -1173,13 +1198,13 @@ class FixtureBuilder { }, ], ], - id: 4046084157914634, + id: '13a01e77-a368-4bb9-aba9-e7435580e3b9', loadingDefaults: false, metamaskNetworkId: '1337', origin: 'metamask', primaryTransaction: { chainId: CHAIN_IDS.LOCALHOST, - id: 4046084157914634, + id: '13a01e77-a368-4bb9-aba9-e7435580e3b9', loadingDefaults: true, metamaskNetworkId: '1337', origin: 'metamask', @@ -1216,12 +1241,12 @@ class FixtureBuilder { withTransactionControllerCompletedTransaction() { return this.withTransactionController({ transactions: { - 5748272735958801: { + '0c9342ce-ef3f-4cab-9425-8e57144256a6': { chainId: CHAIN_IDS.LOCALHOST, history: [ { chainId: CHAIN_IDS.LOCALHOST, - id: 5748272735958801, + id: '0c9342ce-ef3f-4cab-9425-8e57144256a6', loadingDefaults: true, metamaskNetworkId: '1337', origin: 'metamask', @@ -1333,7 +1358,7 @@ class FixtureBuilder { }, ], ], - id: 5748272735958801, + id: '0c9342ce-ef3f-4cab-9425-8e57144256a6', loadingDefaults: false, metamaskNetworkId: '5', origin: 'metamask', @@ -1367,11 +1392,11 @@ class FixtureBuilder { withTransactionControllerIncomingTransaction() { return this.withTransactionController({ transactions: { - 5748272735958807: { + '8a13fd36-fdad-48ae-8b6a-c8991026d550': { blockNumber: '1', chainId: CHAIN_IDS.LOCALHOST, hash: '0xf1af8286e4fa47578c2aec5f08c108290643df978ebc766d72d88476eee90bab', - id: 5748272735958807, + id: '8a13fd36-fdad-48ae-8b6a-c8991026d550', metamaskNetworkId: '1337', status: 'confirmed', time: 1671635520000, @@ -1405,6 +1430,20 @@ class FixtureBuilder { }); } + withNameController(data) { + merge( + this.fixture.data.NameController + ? this.fixture.data.NameController + : (this.fixture.data.NameController = {}), + data, + ); + return this; + } + + withNoNames() { + return this.withNameController({ names: {} }); + } + build() { this.fixture.meta = { version: 74, diff --git a/test/e2e/flask/petnames.spec.js b/test/e2e/flask/petnames.spec.js new file mode 100644 index 000000000000..7f1a3ebc4979 --- /dev/null +++ b/test/e2e/flask/petnames.spec.js @@ -0,0 +1,255 @@ +const { withFixtures, openDapp, convertToHexValue } = require('../helpers'); +const FixtureBuilder = require('../fixture-builder'); +const { TEST_SNAPS_WEBSITE_URL } = require('../snaps/enums'); + +const SIGNATURE_TYPE = { + TYPED_V3: 'v3', + TYPED_V4: 'v4', +}; + +const ganacheOptions = { + accounts: [ + { + secretKey: + '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', + balance: convertToHexValue(25000000000000000000), + }, + ], +}; + +async function login(driver) { + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); +} + +async function openTestSnaps(driver) { + const handle = await driver.openNewPage(TEST_SNAPS_WEBSITE_URL); + await driver.delay(1000); + return handle; +} + +async function installNameLookupSnap(driver) { + // Click Connect Button + const connectButton = await driver.findElement( + '[data-testid="name-lookup"] button', + ); + await driver.scrollToElement(connectButton); + await driver.delay(1000); + await connectButton.click(); + await driver.delay(1000); + + // Confirm Connect Modal + focusNotification(driver); + await driver.clickElement({ + text: 'Connect', + tag: 'button', + }); + + // Confirm Install Modal + await driver.waitForSelector({ text: 'Install' }); + await driver.clickElement({ + text: 'Install', + tag: 'button', + }); + + // Success Modal + await driver.waitForSelector({ text: 'OK' }); + await driver.clickElement({ + text: 'OK', + tag: 'button', + }); +} + +async function createSignatureRequest(driver, type) { + const buttonId = + type === SIGNATURE_TYPE.TYPED_V3 ? '#signTypedDataV3' : '#signTypedDataV4'; + + await driver.clickElement(buttonId); + await driver.delay(3000); +} + +async function rejectSignatureRequest(driver) { + await driver.clickElement({ text: 'Reject', tag: 'button' }); + await driver.delay(3000); +} + +async function focusNotification(driver) { + const windowHandles = await driver.getAllWindowHandles(); + await driver.switchToWindowWithTitle('MetaMask Notification', windowHandles); + await driver.delay(3000); +} + +async function focusTestDapp(driver) { + const windowHandles = await driver.getAllWindowHandles(); + await driver.switchToWindowWithTitle('E2E Test Dapp', windowHandles); + await driver.delay(3000); +} + +async function showThirdPartyDetails(driver) { + await driver.clickElement( + '.signature-request-content__verify-contract-details', + ); +} + +async function closeThirdPartyDetails(driver) { + await driver.clickElement({ text: 'Got it', tag: 'button' }); +} + +async function expectName(driver, expectedValue, isSaved) { + const containerClass = isSaved ? 'name__saved' : 'name__missing'; + const valueClass = isSaved ? 'name__name' : 'name__value'; + + await driver.findElement({ + css: `.${containerClass} .${valueClass}`, + text: expectedValue, + }); +} + +async function clickName(driver, value) { + await driver.clickElement({ + css: `.name`, + text: value, + }); +} + +async function saveName(driver, value, name, proposedName) { + await clickName(driver, value); + await driver.clickElement('.form-combo-field'); + + if (proposedName) { + await driver.clickElement({ + css: '.form-combo-field__option-primary', + text: proposedName, + }); + } + + if (name) { + const input = await driver.findElement('.form-combo-field input'); + await input.fill(name); + await input.press(driver.Key.ENTER); + } + + await driver.clickElement({ text: 'Save', tag: 'button' }); +} + +async function expectProposedNames(driver, value, options) { + await clickName(driver, value); + await driver.clickElement('.form-combo-field'); + + for (const option of options) { + await driver.findElement({ + css: '.form-combo-field__option-primary', + text: option[0], + }); + + await driver.findElement({ + css: '.form-combo-field__option-secondary', + text: option[1], + }); + } +} + +describe('Petnames', function () { + it('can save names for addresses in type 3 signatures', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .withNoNames() + .build(), + ganacheOptions, + title: this.test.title, + }, + async ({ driver }) => { + await login(driver); + await openDapp(driver); + await createSignatureRequest(driver, SIGNATURE_TYPE.TYPED_V3); + await focusNotification(driver); + await expectName(driver, '0xCD2a3...DD826', false); + await expectName(driver, '0xbBbBB...bBBbB', false); + await saveName(driver, '0xCD2a3...DD826', undefined, 'test.lens'); + await saveName(driver, '0xbBbBB...bBBbB', undefined, 'test2.lens'); + await showThirdPartyDetails(driver); + await expectName(driver, '0xCcCCc...ccccC', false); + await saveName(driver, '0xCcCCc...ccccC', 'Custom Name'); + await closeThirdPartyDetails(driver); + await rejectSignatureRequest(driver); + await focusTestDapp(driver); + await createSignatureRequest(driver, SIGNATURE_TYPE.TYPED_V3); + await focusNotification(driver); + await expectName(driver, 'test.lens', true); + await expectName(driver, 'test2.lens', true); + await showThirdPartyDetails(driver); + await expectName(driver, 'Custom Name', true); + }, + ); + }); + + it('can save names for addresses in type 4 signatures', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .withNoNames() + .build(), + ganacheOptions, + title: this.test.title, + }, + async ({ driver }) => { + await login(driver); + await openDapp(driver); + await createSignatureRequest(driver, SIGNATURE_TYPE.TYPED_V4); + await focusNotification(driver); + await expectName(driver, '0xCD2a3...DD826', false); + await expectName(driver, '0xDeaDb...DbeeF', false); + await expectName(driver, '0xbBbBB...bBBbB', false); + await expectName(driver, '0xB0Bda...bEa57', false); + await expectName(driver, '0xB0B0b...00000', false); + await saveName(driver, '0xCD2a3...DD826', undefined, 'test.lens'); + await saveName(driver, '0xB0Bda...bEa57', undefined, 'Test Token 2'); + await showThirdPartyDetails(driver); + await expectName(driver, '0xCcCCc...ccccC', false); + await saveName(driver, '0xCcCCc...ccccC', 'Custom Name'); + await closeThirdPartyDetails(driver); + await rejectSignatureRequest(driver); + await focusTestDapp(driver); + await createSignatureRequest(driver, SIGNATURE_TYPE.TYPED_V4); + await focusNotification(driver); + await expectName(driver, 'test.lens', true); + await expectName(driver, 'Test Token 2', true); + await showThirdPartyDetails(driver); + await expectName(driver, 'Custom Name', true); + }, + ); + }); + + it('can propose names using installed snaps', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .withNoNames() + .build(), + ganacheOptions, + title: this.test.title, + }, + async ({ driver }) => { + await login(driver); + await openDapp(driver); + await openTestSnaps(driver); + await installNameLookupSnap(driver); + await focusTestDapp(driver); + await createSignatureRequest(driver, SIGNATURE_TYPE.TYPED_V4); + await focusNotification(driver); + await expectProposedNames(driver, '0xCD2a3...DD826', [ + ['test.lens', 'Lens Protocol'], + ['example.domain - 0xcd2 / 0x539', 'Name Lookup Example Snap'], + ]); + }, + ); + }); +}); diff --git a/test/e2e/flask/ppom-toggle-settings.spec.js b/test/e2e/flask/ppom-toggle-settings.spec.js new file mode 100644 index 000000000000..f3a19631aca6 --- /dev/null +++ b/test/e2e/flask/ppom-toggle-settings.spec.js @@ -0,0 +1,87 @@ +const { strict: assert } = require('assert'); +const { + withFixtures, + unlockWallet, + openDapp, + defaultGanacheOptions, + getWindowHandles, +} = require('../helpers'); +const FixtureBuilder = require('../fixture-builder'); + +const mainnetProviderConfig = { + providerConfig: { + chainId: '0x1', + nickname: '', + rpcUrl: '', + type: 'mainnet', + }, +}; + +describe('PPOM Settings', function () { + it('should not show the PPOM warning when toggle is off', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withNetworkController(mainnetProviderConfig) + .withPermissionControllerConnectedToTestDapp() + .build(), + ganacheOptions: defaultGanacheOptions, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + await unlockWallet(driver); + + await openDapp(driver); + await driver.clickElement('#maliciousPermit'); + const windowHandles = await getWindowHandles(driver, 3); + await driver.switchToWindow(windowHandles.popup); + + const blockaidResponseTitle = + '[data-testid="security-provider-banner-alert"]'; + const exists = await driver.isElementPresent(blockaidResponseTitle); + assert.equal(exists, false, 'This is a deceptive request'); + }, + ); + }); + + it('should show the PPOM warning when the toggle is on', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withNetworkController(mainnetProviderConfig) + .withPermissionControllerConnectedToTestDapp() + .build(), + ganacheOptions: defaultGanacheOptions, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + await unlockWallet(driver); + + await driver.clickElement( + '[data-testid="account-options-menu-button"]', + ); + + await driver.clickElement({ text: 'Settings', tag: 'div' }); + await driver.clickElement({ text: 'Experimental', tag: 'div' }); + + await driver.clickElement( + '[data-testid="settings-toggle-security-alert-blockaid"] .toggle-button > div', + ); + + await openDapp(driver); + await driver.clickElement('#maliciousPermit'); + const windowHandles = await getWindowHandles(driver, 3); + await driver.switchToWindow(windowHandles.popup); + + const blockaidResponseTitle = + '[data-testid="security-provider-banner-alert"]'; + const exists = await driver.isElementPresent(blockaidResponseTitle); + assert.equal(exists, true, 'This is a deceptive request'); + }, + ); + }); +}); diff --git a/test/e2e/helpers.js b/test/e2e/helpers.js index 194bdaaf4971..50d21aad2e08 100644 --- a/test/e2e/helpers.js +++ b/test/e2e/helpers.js @@ -134,7 +134,7 @@ async function withFixtures(options, testSuite) { console.log( `[driver] Called '${prop}' with arguments ${JSON.stringify( args, - )}`, + ).slice(0, 200)}`, // limit the length of the log entry to 200 characters ); return originalProperty.bind(target)(...args); }; @@ -208,6 +208,15 @@ async function withFixtures(options, testSuite) { } } +const WINDOW_TITLES = Object.freeze({ + ExtensionInFullScreenView: 'MetaMask', + TestDApp: 'E2E Test Dapp', + Notification: 'MetaMask Notification', + ServiceWorkerSettings: 'Inspect with Chrome Developer Tools', + InstalledExtensions: 'Extensions', + SnapSimpleKeyringDapp: 'SSK - Simple Snap Keyring', +}); + /** * @param {*} driver - selinium driver * @param {*} handlesCount - total count of windows that should be loaded @@ -222,7 +231,7 @@ const getWindowHandles = async (driver, handlesCount) => { const extension = windowHandles[0]; const dapp = await driver.switchToWindowWithTitle( - 'E2E Test Dapp', + WINDOW_TITLES.TestDApp, windowHandles, ); const popup = windowHandles.find( @@ -513,9 +522,24 @@ const openDapp = async (driver, contract = null, dappURL = DAPP_URL) => { : await driver.openNewPage(dappURL); }; +const switchToOrOpenDapp = async ( + driver, + contract = null, + dappURL = DAPP_URL, +) => { + try { + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + } catch { + await openDapp(driver, contract, dappURL); + } +}; + const PRIVATE_KEY = '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC'; +const PRIVATE_KEY_TWO = + '0xa444f52ea41e3a39586d7069cb8e8233e9f6b9dea9cbb700cce69ae860661cc8'; + const convertETHToHexGwei = (eth) => convertToHexValue(eth * 10 ** 18); const defaultGanacheOptions = { @@ -524,15 +548,26 @@ const defaultGanacheOptions = { const SERVICE_WORKER_URL = 'chrome://inspect/#service-workers'; -const sendTransaction = async (driver, recipientAddress, quantity) => { +const sendTransaction = async ( + driver, + recipientAddress, + quantity, + isAsyncFlow = false, +) => { await driver.clickElement('[data-testid="eth-overview-send"]'); await driver.fill('[data-testid="ens-input"]', recipientAddress); await driver.fill('.unit-input__input', quantity); await driver.clickElement('[data-testid="page-container-footer-next"]'); await driver.clickElement('[data-testid="page-container-footer-next"]'); - await driver.clickElement('[data-testid="home__activity-tab"]'); - await driver.waitForElementNotPresent('.transaction-list-item--unconfirmed'); - await driver.findElement('.transaction-list-item'); + + // the default is to do this block, but if we're testing an async flow, it would get stuck here + if (!isAsyncFlow) { + await driver.clickElement('[data-testid="home__activity-tab"]'); + await driver.waitForElementNotPresent( + '.transaction-list-item--unconfirmed', + ); + await driver.findElement('.transaction-list-item'); + } }; const findAnotherAccountFromAccountList = async ( @@ -574,14 +609,13 @@ const locateAccountBalanceDOM = async (driver, ganacheServer) => { text: `${balance} ETH`, }); }; -const DEFAULT_PRIVATE_KEY = - '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC'; + const WALLET_PASSWORD = 'correct horse battery staple'; const DEFAULT_GANACHE_OPTIONS = { accounts: [ { - secretKey: DEFAULT_PRIVATE_KEY, + secretKey: PRIVATE_KEY, balance: convertETHToHexGwei(25), }, ], @@ -597,13 +631,6 @@ async function waitForAccountRendered(driver) { '[data-testid="eth-overview__primary-currency"]', ); } -const WINDOW_TITLES = Object.freeze({ - ExtensionInFullScreenView: 'MetaMask', - TestDApp: 'E2E Test Dapp', - Notification: 'MetaMask Notification', - ServiceWorkerSettings: 'Inspect with Chrome Developer Tools', - InstalledExtensions: 'Extensions', -}); const unlockWallet = async (driver) => { await driver.fill('#password', 'correct horse battery staple'); @@ -670,17 +697,54 @@ async function terminateServiceWorker(driver) { await driver.closeWindowHandle(serviceWorkerTab); } +/** + * This method handles clicking the sign button on signature confrimation + * screen. + * + * @param {WebDriver} driver + * @param numHandles + */ +async function clickSignOnSignatureConfirmation(driver, numHandles = 2) { + await driver.clickElement({ text: 'Sign', tag: 'button' }); + await driver.waitUntilXWindowHandles(numHandles); + await driver.getAllWindowHandles(); +} + +/** + * Some signing methods have extra security that requires the user to click a + * button to validate that they have verified the details. This method handles + * performing the necessary steps to click that button. + * + * @param {WebDriver} driver + */ +async function validateContractDetails(driver) { + const verifyContractDetailsButton = await driver.findElement( + '.signature-request-content__verify-contract-details', + ); + + verifyContractDetailsButton.click(); + await driver.clickElement({ text: 'Got it', tag: 'button' }); + + // Approve signing typed data + await driver.clickElement('[data-testid="signature-request-scroll-button"]'); + await driver.delay(regularDelayMs); +} + /** * This method assumes the extension is open, the dapp is open and waits for a * third window handle to open (the notification window). Once it does it * switches to the new window. * * @param {WebDriver} driver + * @param numHandles */ -async function switchToNotificationWindow(driver) { - await driver.waitUntilXWindowHandles(3); +async function switchToNotificationWindow(driver, numHandles = 3) { + await driver.waitUntilXWindowHandles(numHandles); const windowHandles = await driver.getAllWindowHandles(); - await driver.switchToWindowWithTitle('MetaMask Notification', windowHandles); + await driver.switchToWindowWithTitle( + WINDOW_TITLES.Notification, + windowHandles, + ); } /** @@ -696,6 +760,7 @@ async function switchToNotificationWindow(driver) { async function getEventPayloads(driver, mockedEndpoints, hasRequest = true) { await driver.wait(async () => { let isPending = true; + for (const mockedEndpoint of mockedEndpoints) { isPending = await mockedEndpoint.isPending(); } @@ -748,6 +813,7 @@ module.exports = { TEST_SEED_PHRASE, TEST_SEED_PHRASE_TWO, PRIVATE_KEY, + PRIVATE_KEY_TWO, getWindowHandles, convertToHexValue, tinyDelayMs, @@ -767,6 +833,7 @@ module.exports = { importWrongSRPOnboardingFlow, testSRPDropdownIterations, openDapp, + switchToOrOpenDapp, defaultGanacheOptions, sendTransaction, findAnotherAccountFromAccountList, @@ -784,6 +851,8 @@ module.exports = { generateRandNumBetween, sleepSeconds, terminateServiceWorker, + clickSignOnSignatureConfirmation, + validateContractDetails, switchToNotificationWindow, getEventPayloads, onboardingBeginCreateNewWallet, diff --git a/test/e2e/json-rpc/eth_accounts.spec.js b/test/e2e/json-rpc/eth_accounts.spec.js new file mode 100644 index 000000000000..ecc15a5d0d24 --- /dev/null +++ b/test/e2e/json-rpc/eth_accounts.spec.js @@ -0,0 +1,42 @@ +const { strict: assert } = require('assert'); +const { withFixtures, defaultGanacheOptions } = require('../helpers'); +const FixtureBuilder = require('../fixture-builder'); + +describe('eth_accounts', function () { + it('executes a eth_accounts json rpc call', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withKeyringControllerAdditionalAccountVault() + .withPreferencesControllerAdditionalAccountIdentities() + .withPermissionControllerConnectedToTestDapp() + .build(), + ganacheOptions: defaultGanacheOptions, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + // eth_accounts + await driver.openNewPage(`http://127.0.0.1:8080`); + + const accountsRequest = JSON.stringify({ + jsonrpc: '2.0', + method: 'eth_accounts', + }); + + const accounts = await driver.executeScript( + `return window.ethereum.request(${accountsRequest})`, + ); + + assert.deepStrictEqual(accounts, [ + '0x5cfe73b6021e818b776b421b1c4db2474086a7e1', + '0x09781764c08de8ca82e156bbf156a3ca217c7950', + ]); + }, + ); + }); +}); diff --git a/test/e2e/json-rpc/eth_estimateGas.spec.js b/test/e2e/json-rpc/eth_estimateGas.spec.js new file mode 100644 index 000000000000..6a875094e3de --- /dev/null +++ b/test/e2e/json-rpc/eth_estimateGas.spec.js @@ -0,0 +1,43 @@ +const { strict: assert } = require('assert'); +const { withFixtures, defaultGanacheOptions } = require('../helpers'); +const FixtureBuilder = require('../fixture-builder'); + +describe('eth_estimateGas', function () { + it('executes a estimate gas json rpc call', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + ganacheOptions: defaultGanacheOptions, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + // eth_estimateGas + await driver.openNewPage(`http://127.0.0.1:8080`); + + const estimateGas = JSON.stringify({ + jsonrpc: '2.0', + method: 'eth_estimateGas', + params: [ + { + to: '0x5cfe73b6021e818b776b421b1c4db2474086a7e1', + from: '0x5cfe73b6021e818b776b421b1c4db2474086a7e1', + }, + ], + }); + + const estimateGasRequest = await driver.executeScript( + `return window.ethereum.request(${estimateGas})`, + ); + + assert.strictEqual(estimateGasRequest, '0x5208'); + }, + ); + }); +}); diff --git a/test/e2e/json-rpc/eth_gasPrice.spec.js b/test/e2e/json-rpc/eth_gasPrice.spec.js new file mode 100644 index 000000000000..28053cef442d --- /dev/null +++ b/test/e2e/json-rpc/eth_gasPrice.spec.js @@ -0,0 +1,37 @@ +const { strict: assert } = require('assert'); +const { withFixtures, defaultGanacheOptions } = require('../helpers'); +const FixtureBuilder = require('../fixture-builder'); + +describe('eth_gasPrice', function () { + it('executes gas price json rpc call', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + ganacheOptions: defaultGanacheOptions, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + // eth_gasPrice + await driver.openNewPage(`http://127.0.0.1:8080`); + + const gasPriceRequest = JSON.stringify({ + jsonrpc: '2.0', + method: 'eth_gasPrice', + }); + + const gasPrice = await driver.executeScript( + `return window.ethereum.request(${gasPriceRequest})`, + ); + + assert.strictEqual(gasPrice, '0x77359400'); // 2000000000 + }, + ); + }); +}); diff --git a/test/e2e/json-rpc/eth_newBlockFilter.spec.js b/test/e2e/json-rpc/eth_newBlockFilter.spec.js new file mode 100644 index 000000000000..6784eae8d9a1 --- /dev/null +++ b/test/e2e/json-rpc/eth_newBlockFilter.spec.js @@ -0,0 +1,82 @@ +const { strict: assert } = require('assert'); +const { withFixtures, defaultGanacheOptions } = require('../helpers'); +const FixtureBuilder = require('../fixture-builder'); + +describe('eth_newBlockFilter', function () { + const ganacheOptions = { + blockTime: 0.1, + ...defaultGanacheOptions, + }; + it('executes a new block filter call', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + ganacheOptions, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + // eth_newBlockFilter + await driver.openNewPage(`http://127.0.0.1:8080`); + + const newBlockfilterRequest = JSON.stringify({ + jsonrpc: '2.0', + method: 'eth_newBlockFilter', + }); + + const newBlockFilter = await driver.executeScript( + `return window.ethereum.request(${newBlockfilterRequest})`, + ); + + assert.strictEqual(newBlockFilter, '0x01'); + + // eth_getFilterChanges + const getFilterChangesRequest = JSON.stringify({ + jsonrpc: '2.0', + method: 'eth_getFilterChanges', + params: ['0x01'], + }); + + await driver.delay(1000); + + const filterChanges = await driver.executeScript( + `return window.ethereum.request(${getFilterChangesRequest})`, + ); + + const blockByHashRequest = JSON.stringify({ + jsonrpc: '2.0', + method: 'eth_getBlockByNumber', + params: ['latest', false], + }); + + const blockByHash = await driver.executeScript( + `return window.ethereum.request(${blockByHashRequest})`, + ); + + assert.strictEqual( + filterChanges[filterChanges.length - 1], + blockByHash.hash, + ); + + // eth_uninstallFilter + const uninstallFilterRequest = JSON.stringify({ + jsonrpc: '2.0', + method: 'eth_uninstallFilter', + params: ['0x01'], + }); + + const uninstallFilter = await driver.executeScript( + `return window.ethereum.request(${uninstallFilterRequest})`, + ); + + assert.strictEqual(uninstallFilter, true); + }, + ); + }); +}); diff --git a/test/e2e/metrics/permissions-approved.spec.js b/test/e2e/metrics/permissions-approved.spec.js index 1a7b7cc71f70..9bca8354b92c 100644 --- a/test/e2e/metrics/permissions-approved.spec.js +++ b/test/e2e/metrics/permissions-approved.spec.js @@ -45,7 +45,7 @@ async function mockSegment(mockServer) { } describe('Permissions Approved Event', function () { - it('Successfully tracked when connecting to dapp', async function () { + it('Successfully tracked when connecting to dapp @no-mmi', async function () { await withFixtures( { dapp: true, diff --git a/test/e2e/metrics/signature-approved.spec.js b/test/e2e/metrics/signature-approved.spec.js index 989656832184..e45900e4264d 100644 --- a/test/e2e/metrics/signature-approved.spec.js +++ b/test/e2e/metrics/signature-approved.spec.js @@ -7,6 +7,8 @@ const { openDapp, unlockWallet, getEventPayloads, + clickSignOnSignatureConfirmation, + validateContractDetails, } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); @@ -45,39 +47,7 @@ async function mockSegment(mockServer) { ]; } -/** - * Some signing methods have extra security that requires the user to click a - * button to validate that they have verified the details. This method handles - * performing the necessary steps to click that button. - * - * @param {WebDriver} driver - */ -async function validateContractDetails(driver) { - const verifyContractDetailsButton = await driver.findElement( - '.signature-request-content__verify-contract-details', - ); - - verifyContractDetailsButton.click(); - await driver.clickElement({ text: 'Got it', tag: 'button' }); - - // Approve signing typed data - await driver.clickElement('[data-testid="signature-request-scroll-button"]'); - await driver.delay(regularDelayMs); -} - -/** - * This method handles clicking the sign button on signature confrimation - * screen. - * - * @param {WebDriver} driver - */ -async function clickSignOnSignatureConfirmation(driver) { - await driver.clickElement({ text: 'Sign', tag: 'button' }); - await driver.waitUntilXWindowHandles(2); - await driver.getAllWindowHandles(); -} - -describe('Signature Approved Event', function () { +describe('Signature Approved Event @no-mmi', function () { it('Successfully tracked for signTypedData_v4', async function () { await withFixtures( { diff --git a/test/e2e/metrics/swaps.spec.js b/test/e2e/metrics/swaps.spec.js index ba7e7db5270c..1f49b5899737 100644 --- a/test/e2e/metrics/swaps.spec.js +++ b/test/e2e/metrics/swaps.spec.js @@ -99,7 +99,7 @@ async function mockSegmentAndMetaswapRequests(mockServer) { ]; } -describe('Swap Eth for another Token', function () { +describe('Swap Eth for another Token @no-mmi', function () { it('Completes a Swap between ETH and DAI after changing initial rate', async function () { const { initialBalanceInHex } = genRandInitBal(); diff --git a/test/e2e/metrics/transaction-finalized.spec.js b/test/e2e/metrics/transaction-finalized.spec.js index 1fbfeba0dd55..b72bb0598de7 100644 --- a/test/e2e/metrics/transaction-finalized.spec.js +++ b/test/e2e/metrics/transaction-finalized.spec.js @@ -47,7 +47,7 @@ async function mockSegment(mockServer) { batch: [ { type: 'track', - event: 'Transaction Submitted', + event: 'Transaction Submitted Anon', }, ], }) @@ -78,7 +78,7 @@ async function mockSegment(mockServer) { batch: [ { type: 'track', - event: 'Transaction Finalized', + event: 'Transaction Finalized Anon', }, ], }) @@ -134,7 +134,7 @@ const eventHasZeroAddressAnonymousId = (payload) => payload.anonymousId === '0x0000000000000000'; describe('Transaction Finalized Event', function () { - it('Successfully tracked when sending a transaction', async function () { + it('Successfully tracked when sending a transaction @no-mmi', async function () { await withFixtures( { fixtures: new FixtureBuilder() @@ -214,6 +214,8 @@ describe('Transaction Finalized Event', function () { }), ]; + await driver.delay(10000); + const transactionFinalizedWithSensitivePropertiesAssertions = [ messageIdStartsWithTransactionSubmitted, messageIdEndsWithZeros, diff --git a/test/e2e/metrics/unlock-wallet.spec.js b/test/e2e/metrics/unlock-wallet.spec.js index b980b0bb7ae4..5c6afc76d8d2 100644 --- a/test/e2e/metrics/unlock-wallet.spec.js +++ b/test/e2e/metrics/unlock-wallet.spec.js @@ -2,6 +2,7 @@ const { strict: assert } = require('assert'); const { withFixtures, unlockWallet, + waitForAccountRendered, defaultGanacheOptions, } = require('../helpers'); const FixtureBuilder = require('../fixture-builder'); @@ -35,6 +36,7 @@ describe('Unlock wallet', function () { async ({ driver, mockedEndpoint }) => { await driver.navigate(); await unlockWallet(driver); + await waitForAccountRendered(driver); await driver.wait(async () => { const isPending = await mockedEndpoint.isPending(); return isPending === false; diff --git a/test/e2e/metrics/wallet-created.spec.js b/test/e2e/metrics/wallet-created.spec.js index c1c573e00e47..17152df356fa 100644 --- a/test/e2e/metrics/wallet-created.spec.js +++ b/test/e2e/metrics/wallet-created.spec.js @@ -49,7 +49,7 @@ async function mockSegment(mockServer) { } describe('Wallet Created Events', function () { - it('are sent when onboarding user who chooses to opt in metrics', async function () { + it('are sent when onboarding user who chooses to opt in metrics @no-mmi', async function () { await withFixtures( { fixtures: new FixtureBuilder({ onboarding: true }) diff --git a/test/e2e/mock-e2e.js b/test/e2e/mock-e2e.js index 997c040c290a..91a32c5c5fdb 100644 --- a/test/e2e/mock-e2e.js +++ b/test/e2e/mock-e2e.js @@ -388,7 +388,61 @@ async function setupMocking(server, testSpecificMock, { chainId }) { }; }); + await mockLensNameProvider(server); + await mockTokenNameProvider(server, chainId); + return mockedEndpoint; } +async function mockLensNameProvider(server) { + const handlesByAddress = { + '0xcd2a3d9f938e13cd947ec05abc7fe734df8dd826': 'test.lens', + '0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb': 'test2.lens', + '0xcccccccccccccccccccccccccccccccccccccccc': 'test3.lens', + }; + + await server.forPost('https://api.lens.dev').thenCallback((request) => { + const address = request.body?.json?.variables?.address; + const handle = handlesByAddress[address]; + + return { + statusCode: 200, + json: { + data: { + profiles: { + items: [ + { + handle, + }, + ], + }, + }, + }, + }; + }); +} + +async function mockTokenNameProvider(server) { + const namesByAddress = { + '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef': 'Test Token', + '0xb0bdabea57b0bdabea57b0bdabea57b0bdabea57': 'Test Token 2', + }; + + for (const address of Object.keys(namesByAddress)) { + const name = namesByAddress[address]; + + await server + .forGet(/https:\/\/token-api\.metaswap\.codefi\.network\/token\/.*/gu) + .withQuery({ address }) + .thenCallback(() => { + return { + statusCode: 200, + json: { + name, + }, + }; + }); + } +} + module.exports = { setupMocking }; diff --git a/test/e2e/nft/erc1155-interaction.spec.js b/test/e2e/nft/erc1155-interaction.spec.js index c6cb2020c78b..948458ef7c8e 100644 --- a/test/e2e/nft/erc1155-interaction.spec.js +++ b/test/e2e/nft/erc1155-interaction.spec.js @@ -132,7 +132,7 @@ describe('ERC1155 NFTs testdapp interaction', function () { ); }); - it('should enable approval for a third party address to manage all ERC1155 token', async function () { + it('should enable approval for a third party address to manage all ERC1155 token @no-mmi', async function () { const expectedMessageTitle = 'Allow access to and transfer all of your NFTs from this collection?'; const expectedDescription = @@ -222,7 +222,7 @@ describe('ERC1155 NFTs testdapp interaction', function () { ); }); - it('should revoke approval for a third party address to manage all ERC1155 token', async function () { + it('should revoke approval for a third party address to manage all ERC1155 token @no-mmi', async function () { const expectedMessageTitle = 'Revoke permission to access and transfer all of your NFTs from this collection?'; const expectedDescription = diff --git a/test/e2e/nft/erc721-interaction.spec.js b/test/e2e/nft/erc721-interaction.spec.js index bbfd544e76cf..9d169e6ebce2 100644 --- a/test/e2e/nft/erc721-interaction.spec.js +++ b/test/e2e/nft/erc721-interaction.spec.js @@ -15,7 +15,7 @@ describe('ERC721 NFTs testdapp interaction', function () { ], }; - it('should prompt users to add their NFTs to their wallet (one by one)', async function () { + it('should prompt users to add their NFTs to their wallet (one by one) @no-mmi', async function () { await withFixtures( { dapp: true, @@ -359,7 +359,7 @@ describe('ERC721 NFTs testdapp interaction', function () { ); }); - it('should enable approval for a third party address to manage all ERC721 NFTs', async function () { + it('should enable approval for a third party address to manage all ERC721 NFTs @no-mmi', async function () { await withFixtures( { dapp: true, @@ -430,7 +430,7 @@ describe('ERC721 NFTs testdapp interaction', function () { ); }); - it('should disable approval for a third party address to manage all ERC721 NFTs', async function () { + it('should disable approval for a third party address to manage all ERC721 NFTs @no-mmi', async function () { await withFixtures( { dapp: true, diff --git a/test/e2e/nft/view-erc1155-details.spec.js b/test/e2e/nft/view-erc1155-details.spec.js index 99133de7f65b..b782a82b3088 100644 --- a/test/e2e/nft/view-erc1155-details.spec.js +++ b/test/e2e/nft/view-erc1155-details.spec.js @@ -58,7 +58,7 @@ describe('View ERC1155 NFT details', function () { const nftContract = await driver.findElement( '.nft-details__contract-wrapper', ); - assert.equal(await nftContract.getText(), '0x581...5947'); + assert.equal(await nftContract.getText(), '0x581c3...45947'); }, ); }); diff --git a/test/e2e/nft/view-nft-details.spec.js b/test/e2e/nft/view-nft-details.spec.js index 2648085ddb0f..fa80ba7ad1f8 100644 --- a/test/e2e/nft/view-nft-details.spec.js +++ b/test/e2e/nft/view-nft-details.spec.js @@ -57,7 +57,7 @@ describe('View NFT details', function () { const nftContract = await driver.findElement( '.nft-details__contract-wrapper', ); - assert.equal(await nftContract.getText(), '0x581...5947'); + assert.equal(await nftContract.getText(), '0x581c3...45947'); }, ); }); diff --git a/test/e2e/restore/MetaMaskUserData.json b/test/e2e/restore/MetaMaskUserData.json index 5215b9620011..250b3cb3e852 100644 --- a/test/e2e/restore/MetaMaskUserData.json +++ b/test/e2e/restore/MetaMaskUserData.json @@ -27,7 +27,6 @@ "ticker": "ETH" } ], - "infuraBlocked": false, "ipfsGateway": "dweb.link", "knownMethodData": {}, "ledgerTransportType": "webhid", diff --git a/test/e2e/run-all.js b/test/e2e/run-all.js index 811f6b8fb94c..c5383103d6b2 100644 --- a/test/e2e/run-all.js +++ b/test/e2e/run-all.js @@ -53,6 +53,10 @@ async function main() { 'Run tests in debug mode, logging each driver interaction', type: 'boolean', }) + .option('mmi', { + description: `Run only mmi related tests`, + type: 'boolean', + }) .option('snaps', { description: `run snaps e2e tests`, type: 'boolean', @@ -89,6 +93,7 @@ async function main() { browser, debug, retries, + mmi, snaps, mv3, rpc, @@ -99,20 +104,11 @@ async function main() { let testPaths; if (snaps) { - const testDir = path.join(__dirname, 'snaps'); - testPaths = await getTestPathsForTestDir(testDir); - - if (buildType && buildType !== 'flask') { - // These tests should only be ran on Flask for now - const filteredTests = [ - 'test-snap-manageAccount.spec.js', - 'test-snap-rpc.spec.js', - 'test-snap-lifecycle.spec.js', - ]; - testPaths = testPaths.filter((p) => - filteredTests.every((filteredTest) => !p.endsWith(filteredTest)), - ); - } + testPaths = [ + ...(await getTestPathsForTestDir(path.join(__dirname, 'snaps'))), + ...(await getTestPathsForTestDir(path.join(__dirname, 'accounts'))), + ...(await getTestPathsForTestDir(path.join(__dirname, 'flask'))), + ]; } else if (rpc) { const testDir = path.join(__dirname, 'json-rpc'); testPaths = await getTestPathsForTestDir(testDir); @@ -133,6 +129,24 @@ async function main() { } } + // These tests should only be run on Flask for now. + if (buildType !== 'flask') { + const filteredTests = [ + 'settings-add-snap-account-toggle.spec.js', + 'test-snap-accounts.spec.js', + 'test-create-snap-account.spec.js', + 'test-remove-accounts-snap.spec.js', + 'test-snap-lifecycle.spec.js', + 'test-snap-get-locale.spec.js', + 'ppom-blockaid-alert.spec.js', + 'ppom-toggle-settings.spec.js', + 'petnames.spec.js', + ]; + testPaths = testPaths.filter((p) => + filteredTests.every((filteredTest) => !p.endsWith(filteredTest)), + ); + } + const runE2eTestPath = path.join(__dirname, 'run-e2e-test.js'); const args = [runE2eTestPath]; @@ -148,6 +162,9 @@ async function main() { if (updateSnapshot) { args.push('--update-snapshot'); } + if (mmi) { + args.push('--mmi'); + } // For running E2Es in parallel in CI const currentChunkIndex = process.env.CIRCLE_NODE_INDEX ?? 0; diff --git a/test/e2e/run-e2e-test.js b/test/e2e/run-e2e-test.js index a7b8f8602c8c..ca8ee6966ccd 100644 --- a/test/e2e/run-e2e-test.js +++ b/test/e2e/run-e2e-test.js @@ -25,6 +25,10 @@ async function main() { 'Run tests in debug mode, logging each driver interaction', type: 'boolean', }) + .option('mmi', { + description: 'Run only mmi related tests', + type: 'boolean', + }) .option('retries', { default: 0, description: @@ -60,6 +64,7 @@ async function main() { const { browser, debug, + mmi, e2eTestPath, retries, retryUntilFailure, @@ -117,6 +122,13 @@ async function main() { const configFile = path.join(__dirname, '.mocharc.js'); const extraArgs = process.env.E2E_ARGS?.split(' ') || []; + // If mmi flag is passed + if (mmi) { + // Tests that contains `@no-mmi` will be grep (-g) and inverted (-i) + // meaning that all tests with @no-mmi in the title will be ignored + extraArgs.push('-g', '@no-mmi', '-i'); + } + const dir = 'test/test-results/e2e'; fs.mkdir(dir, { recursive: true }); diff --git a/test/e2e/snaps/enums.js b/test/e2e/snaps/enums.js index 6ec77de3087e..6ff9ce39fbf5 100644 --- a/test/e2e/snaps/enums.js +++ b/test/e2e/snaps/enums.js @@ -1,6 +1,3 @@ module.exports = { - TEST_SNAPS_WEBSITE_URL: - 'https://metamask.github.io/snaps/test-snaps/0.38.0-flask.1/', - TEST_SNAPS_SIMPLE_KEYRING_WEBSITE_URL: - 'https://metamask.github.io/snap-simple-keyring/0.1.4/', + TEST_SNAPS_WEBSITE_URL: 'https://metamask.github.io/snaps/test-snaps/1.1.0/', }; diff --git a/test/e2e/snaps/ppom-blockaid-alert.spec.js b/test/e2e/snaps/ppom-blockaid-alert.spec.js new file mode 100644 index 000000000000..a9fb855acb24 --- /dev/null +++ b/test/e2e/snaps/ppom-blockaid-alert.spec.js @@ -0,0 +1,265 @@ +const { strict: assert } = require('assert'); +const FixtureBuilder = require('../fixture-builder'); +const { + defaultGanacheOptions, + getWindowHandles, + openDapp, + unlockWallet, + withFixtures, +} = require('../helpers'); + +const { + CHAIN_IDS, + NETWORK_TYPES, +} = require('../../../shared/constants/network'); + +const bannerAlertSelector = '[data-testid="security-provider-banner-alert"]'; +const selectedAddress = '0x5cfe73b6021e818b776b421b1c4db2474086a7e1'; + +const mainnetProviderConfig = { + providerConfig: { + chainId: CHAIN_IDS.MAINNET, + nickname: '', + rpcUrl: '', + type: NETWORK_TYPES.MAINNET, + }, +}; + +async function mockInfura(mockServer) { + await mockServer + .forPost() + .withJsonBodyIncluding({ method: 'eth_estimateGas' }) + .thenCallback((req) => { + return { + statusCode: 200, + json: { + jsonrpc: '2.0', + id: req.body.json.id, + result: '0x5cec', + }, + }; + }); + await mockServer + .forPost() + .withJsonBodyIncluding({ method: 'eth_getBalance' }) + .thenCallback((req) => { + return { + statusCode: 200, + json: { + jsonrpc: '2.0', + id: req.body.json.id, + result: '0x55DE6A779BBAC0000', + }, + }; + }); + await mockServer + .forPost() + .withJsonBodyIncluding({ method: 'eth_getTransactionCount' }) + .thenCallback((req) => { + return { + statusCode: 200, + json: { + jsonrpc: '2.0', + id: req.body.json.id, + result: '0x115e89f', + }, + }; + }); + await mockServer + .forPost() + .withJsonBodyIncluding({ method: 'eth_blockNumber' }) + .thenCallback((req) => { + return { + statusCode: 200, + json: { + jsonrpc: '2.0', + id: req.body.json.id, + result: '0x1', + // result: '0x115e89f', + }, + }; + }); + await mockServer + .forPost() + .withJsonBodyIncluding({ method: 'eth_gasPrice' }) + .thenCallback((req) => { + return { + statusCode: 200, + json: { + jsonrpc: '2.0', + id: req.body.json.id, + result: '0x09184e72a000', + }, + }; + }); +} + +/** + * Tests various Blockaid PPOM security alerts. Data for the E2E test requests and responses are provided here: + * + * @see {@link https://wobbly-nutmeg-8a5.notion.site/MM-E2E-Testing-1e51b617f79240a49cd3271565c6e12d} + */ +describe('Confirmation Security Alert - Blockaid', function () { + it('should not show security alerts for benign requests', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withNetworkController(mainnetProviderConfig) + .withPermissionControllerConnectedToTestDapp() + .withPreferencesController({ + securityAlertsEnabled: true, + }) + .build(), + defaultGanacheOptions, + testSpecificMock: mockInfura, + title: this.test.title, + }, + + async ({ driver }) => { + await driver.navigate(); + await unlockWallet(driver); + await openDapp(driver); + + const testBenignConfigs = [ + { + logExpectedDetail: 'Benign 1', + method: 'eth_sendTransaction', + params: [ + { + from: selectedAddress, + data: '0x095ea7b3000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', + to: '0x6b175474e89094c44da98b954eedeac495271d0f', + value: '0x0', + }, + ], + }, + { + logExpectedDetail: 'blur', + method: 'eth_signTypedData_v4', + params: [ + selectedAddress, + '{"types":{"Order":[{"name":"trader","type":"address"},{"name":"side","type":"uint8"},{"name":"matchingPolicy","type":"address"},{"name":"collection","type":"address"},{"name":"tokenId","type":"uint256"},{"name":"amount","type":"uint256"},{"name":"paymentToken","type":"address"},{"name":"price","type":"uint256"},{"name":"listingTime","type":"uint256"},{"name":"expirationTime","type":"uint256"},{"name":"fees","type":"Fee[]"},{"name":"salt","type":"uint256"},{"name":"extraParams","type":"bytes"},{"name":"nonce","type":"uint256"}],"Fee":[{"name":"rate","type":"uint16"},{"name":"recipient","type":"address"}],"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}]},"domain":{"name":"Blur Exchange","version":"1.0","chainId":"1","verifyingContract":"0x000000000000ad05ccc4f10045630fb830b95127"},"primaryType":"Order","message":{"trader":"0xd854343f41b2138b686f2d3ba38402a9f7fb4337","side":"1","matchingPolicy":"0x0000000000dab4a563819e8fd93dba3b25bc3495","collection":"0xc4a5025c4563ad0acc09d92c2506e6744dad58eb","tokenId":"30420","amount":"1","paymentToken":"0x0000000000000000000000000000000000000000","price":"1000000000000000000","listingTime":"1679418212","expirationTime":"1680023012","salt":"154790208154270131670189427454206980105","extraParams":"0x01","nonce":"0"}}', + ], + }, + { + logExpectedDetail: 'seaport', + method: 'eth_signTypedData_v4', + params: [ + selectedAddress, + '{"types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"OrderComponents":[{"name":"offerer","type":"address"},{"name":"zone","type":"address"},{"name":"offer","type":"OfferItem[]"},{"name":"consideration","type":"ConsiderationItem[]"},{"name":"orderType","type":"uint8"},{"name":"startTime","type":"uint256"},{"name":"endTime","type":"uint256"},{"name":"zoneHash","type":"bytes32"},{"name":"salt","type":"uint256"},{"name":"conduitKey","type":"bytes32"},{"name":"counter","type":"uint256"}],"OfferItem":[{"name":"itemType","type":"uint8"},{"name":"token","type":"address"},{"name":"identifierOrCriteria","type":"uint256"},{"name":"startAmount","type":"uint256"},{"name":"endAmount","type":"uint256"}],"ConsiderationItem":[{"name":"itemType","type":"uint8"},{"name":"token","type":"address"},{"name":"identifierOrCriteria","type":"uint256"},{"name":"startAmount","type":"uint256"},{"name":"endAmount","type":"uint256"},{"name":"recipient","type":"address"}]},"primaryType":"OrderComponents","domain":{"name":"Seaport","version":"1.4","chainId":"1","verifyingContract":"0x00000000000001ad428e4906aE43D8F9852d0dD6"},"message":{"offerer":"0xCaFca5eDFb361E8A39a735233f23DAf86CBeD5FC","offer":[{"itemType":"1","token":"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2","identifierOrCriteria":"0","startAmount":"2500000000000000","endAmount":"2500000000000000"}],"consideration":[{"itemType":"2","token":"0xaA7200ee500dE2dcde75E996De83CBD73BCa9705","identifierOrCriteria":"11909","startAmount":"1","endAmount":"1","recipient":"0xCaFca5eDFb361E8A39a735233f23DAf86CBeD5FC"},{"itemType":"1","token":"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2","identifierOrCriteria":"0","startAmount":"62500000000000","endAmount":"62500000000000","recipient":"0x0000a26b00c1F0DF003000390027140000fAa719"},{"itemType":"1","token":"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2","identifierOrCriteria":"0","startAmount":"12500000000000","endAmount":"12500000000000","recipient":"0x8324BdEF2F30E08E368f2Fa2F14143cDCA77423D"}],"startTime":"1681835413","endTime":"1682094598","orderType":"0","zone":"0x004C00500000aD104D7DBd00e3ae0A5C00560C00","zoneHash":"0x0000000000000000000000000000000000000000000000000000000000000000","salt":"24446860302761739304752683030156737591518664810215442929812618382526293324216","conduitKey":"0x0000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000","totalOriginalConsiderationItems":"3","counter":"0"}}', + ], + }, + ]; + + for (const config of testBenignConfigs) { + const { logExpectedDetail, method, params } = config; + + // Send JSON-RPC request + const request = JSON.stringify({ + jsonrpc: '2.0', + method, + params, + }); + await driver.executeScript( + `window.transactionHash = window.ethereum.request(${request})`, + ); + + // Wait for confirmation pop-up + await driver.waitUntilXWindowHandles(3); + const windowHandles = await getWindowHandles(driver, 3); + await driver.switchToWindowWithTitle('MetaMask Notification'); + + const isPresent = await driver.isElementPresent(bannerAlertSelector); + assert.equal( + isPresent, + false, + `Banner alert unexpectedly found. \nExpected detail: ${logExpectedDetail}`, + ); + + // Wait for confirmation pop-up to close + await driver.clickElement({ text: 'Reject', tag: 'button' }); + await driver.switchToWindow(windowHandles.dapp); + } + }, + ); + }); + + /** + * Disclaimer: this test may be missing checks for some reason types. e.g. blur, domain, and failed + */ + it('should show security alerts for malicious requests', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withNetworkController(mainnetProviderConfig) + .withPermissionControllerConnectedToTestDapp() + .withPreferencesController({ + securityAlertsEnabled: true, + }) + .build(), + defaultGanacheOptions, + testSpecificMock: mockInfura, + title: this.test.title, + }, + + async ({ driver }) => { + await driver.navigate(); + await unlockWallet(driver); + await openDapp(driver); + + const expectedTitle = 'This is a deceptive request'; + + const testMaliciousConfigs = [ + { + btnSelector: '#maliciousPermit', + expectedDescription: + 'If you approve this request, a third party known for scams might take all your assets.', + expectedReason: 'permit_farming', + }, + { + btnSelector: '#maliciousSeaport', + expectedDescription: + 'If you approve this request, someone can steal your assets listed on OpenSea.', + expectedReason: 'seaport_farming', + }, + { + btnSelector: '#maliciousTradeOrder', + expectedDescription: + 'If you approve this request, you might lose your assets.', + expectedReason: 'trade_order_farming', + }, + ]; + + for (const config of testMaliciousConfigs) { + const { expectedDescription, expectedReason, btnSelector } = config; + + // Click TestDapp button to send JSON-RPC request + await driver.clickElement(btnSelector); + + // Wait for confirmation pop-up + await driver.waitUntilXWindowHandles(3); + const windowHandles = await getWindowHandles(driver, 3); + await driver.switchToWindowWithTitle('MetaMask Notification'); + + const bannerAlert = await driver.findElement(bannerAlertSelector); + const bannerAlertText = await bannerAlert.getText(); + + assert( + bannerAlertText.includes(expectedTitle), + `Expected banner alert title: ${expectedTitle} \nExpected reason: ${expectedReason}\n`, + ); + assert( + bannerAlertText.includes(expectedDescription), + `Expected banner alert description: ${expectedDescription} \nExpected reason: ${expectedReason}\n`, + ); + + // Wait for confirmation pop-up to close + await driver.clickElement({ text: 'Reject', tag: 'button' }); + await driver.switchToWindow(windowHandles.dapp); + } + }, + ); + }); +}); diff --git a/test/e2e/snaps/test-snap-get-locale.spec.js b/test/e2e/snaps/test-snap-get-locale.spec.js new file mode 100644 index 000000000000..bf270935762d --- /dev/null +++ b/test/e2e/snaps/test-snap-get-locale.spec.js @@ -0,0 +1,173 @@ +const { strict: assert } = require('assert'); +const { withFixtures } = require('../helpers'); +const FixtureBuilder = require('../fixture-builder'); +const { TEST_SNAPS_WEBSITE_URL } = require('./enums'); + +describe('Test Snap Get Locale', function () { + it('test snap_getLocale functionality', async function () { + const ganacheOptions = { + accounts: [ + { + secretKey: + '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', + balance: 25000000000000000000, + }, + ], + }; + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions, + failOnConsoleError: false, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + + // enter pw into extension + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + // 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('#connectgetlocale'); + await driver.scrollToElement(dialogButton); + await driver.delay(1000); + await driver.clickElement('#connectgetlocale'); + await driver.delay(1000); + + // switch to metamask extension and click connect + let windowHandles = await driver.waitUntilXWindowHandles( + 3, + 1000, + 10000, + ); + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + await driver.clickElement({ + text: 'Connect', + tag: 'button', + }); + + await driver.waitForSelector({ text: 'Install' }); + + await driver.clickElementSafe('[data-testid="snap-install-scroll"]'); + + await driver.clickElement({ + text: 'Install', + tag: 'button', + }); + + await driver.waitForSelector({ text: 'OK' }); + + await driver.clickElement({ + text: 'OK', + tag: 'button', + }); + + // switch to test snaps tab + await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + + // wait for npm installation success + await driver.waitForSelector({ + css: '#connectgetlocale', + text: 'Reconnect to Get Locale Snap', + }); + + // click on alert dialog + await driver.clickElement('#sendGetLocaleHelloButton'); + 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(), + 'Hello https://metamask.github.io!\nThis is a dialog!', + ); + + // click ok button + await driver.clickElement({ + text: 'OK', + tag: 'button', + }); + + // switch back to test snaps tab + windowHandles = await driver.waitUntilXWindowHandles(2, 1000, 10000); + await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + + // check for result correctness + await driver.waitForSelector({ + css: '#getLocaleResult', + text: 'null', + }); + + // try switching language to dansk + // + // switch to the original MM tab + const extensionPage = windowHandles[0]; + await driver.switchToWindow(extensionPage); + await driver.delay(1000); + + // click on the global action menu + await driver.clickElement( + '[data-testid="account-options-menu-button"]', + ); + + // try to click on the notification item + await driver.clickElement({ text: 'Settings', tag: 'div' }); + await driver.delay(1000); + + // try to click on the snaps item + await driver.clickElement({ + text: 'General', + tag: 'div', + }); + await driver.delay(1000); + + // try to click on locale-select + await driver.clickElement('[data-testid="locale-select"]'); + + // try to select dansk from the list + await driver.clickElement({ text: 'Dansk', tag: 'option' }); + + // switch back to test snaps tab + windowHandles = await driver.waitUntilXWindowHandles(2, 1000, 10000); + await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + + // click on alert dialog + await driver.clickElement('#sendGetLocaleHelloButton'); + 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 for dansk result + const result2 = await driver.findElement('.snap-ui-renderer__panel'); + await driver.scrollToElement(result2); + await driver.delay(500); + assert.equal( + await result2.getText(), + 'Hej https://metamask.github.io!\nDette er en dialog!', + ); + }, + ); + }); +}); diff --git a/test/e2e/snaps/test-snap-manageAccount.spec.js b/test/e2e/snaps/test-snap-manageAccount.spec.js deleted file mode 100644 index 44ca13dbc3f6..000000000000 --- a/test/e2e/snaps/test-snap-manageAccount.spec.js +++ /dev/null @@ -1,109 +0,0 @@ -const { strict: assert } = require('assert'); -const { withFixtures } = require('../helpers'); -const FixtureBuilder = require('../fixture-builder'); -const { TEST_SNAPS_SIMPLE_KEYRING_WEBSITE_URL } = require('./enums'); - -describe('Test Snap Account', function () { - it('can create a new snap account', async function () { - const ganacheOptions = { - accounts: [ - { - secretKey: - '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', - balance: 25000000000000000000, - }, - ], - }; - await withFixtures( - { - fixtures: new FixtureBuilder().build(), - ganacheOptions, - failOnConsoleError: false, - title: this.test.title, - }, - async ({ driver }) => { - await driver.navigate(); - - // enter pw into extension - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); - - // navigate to test snaps page and connect - await driver.openNewPage(TEST_SNAPS_SIMPLE_KEYRING_WEBSITE_URL); - await driver.delay(1000); - const connectButton = await driver.findElement('#connectButton'); - await driver.scrollToElement(connectButton); - await driver.delay(1000); - await driver.clickElement('#connectButton'); - await driver.delay(500); - - // switch to metamask extension and click connect - const windowHandles = await driver.waitUntilXWindowHandles( - 3, - 1000, - 10000, - ); - await driver.switchToWindowWithTitle( - 'MetaMask Notification', - windowHandles, - ); - await driver.clickElement({ - text: 'Connect', - tag: 'button', - }); - - await driver.clickElementSafe('[data-testid="snap-install-scroll"]'); - - await driver.waitForSelector({ text: 'Install' }); - - await driver.clickElement({ - text: 'Install', - tag: 'button', - }); - - await driver.waitForSelector({ text: 'OK' }); - - await driver.clickElement({ - text: 'OK', - tag: 'button', - }); - - await driver.switchToWindowWithTitle( - 'SSK - Snap Simple Keyring', - windowHandles, - ); - - // check the dapp connection status - await driver.waitForSelector({ - css: '#snapConnected', - text: 'Connected', - }); - - // create new account on dapp - await driver.clickElement({ - text: 'Create Account', - tag: 'div', - }); - - // create name for account - await driver.fill("[placeholder='Name']", 'snap account'); - - await driver.clickElement({ - text: 'Execute', - tag: 'button', - }); - - await driver.delay(1000); - - // switch to metamask extension - await driver.switchToWindowWithTitle('MetaMask', windowHandles); - - // click on accounts - await driver.clickElement('[data-testid="account-menu-icon"]'); - - const label = await driver.findElement('.mm-tag'); - assert.strictEqual(await label.getText(), 'Snaps'); - }, - ); - }); -}); diff --git a/test/e2e/swaps/swap-eth.spec.js b/test/e2e/swaps/swap-eth.spec.js index 380ce2965987..d6693368ed39 100644 --- a/test/e2e/swaps/swap-eth.spec.js +++ b/test/e2e/swaps/swap-eth.spec.js @@ -9,7 +9,7 @@ const { changeExchangeRate, } = require('./shared'); -describe('Swap Eth for another Token', function () { +describe('Swap Eth for another Token @no-mmi', function () { it('Completes second Swaps while first swap is processing', async function () { withFixturesOptions.ganacheOptions.blockTime = 10; diff --git a/test/e2e/swaps/swaps-notifications.spec.js b/test/e2e/swaps/swaps-notifications.spec.js index 2a5a4b9bb25c..4aa0508696af 100644 --- a/test/e2e/swaps/swaps-notifications.spec.js +++ b/test/e2e/swaps/swaps-notifications.spec.js @@ -8,7 +8,7 @@ const { checkNotification, } = require('./shared'); -describe('Swaps - notifications', function () { +describe('Swaps - notifications @no-mmi', function () { async function mockTradesApiPriceSlippageError(mockServer) { await mockServer .forGet('https://swap.metaswap.codefi.network/networks/1/trades') diff --git a/test/e2e/tests/account-details.spec.js b/test/e2e/tests/account-details.spec.js index eeee82694f54..b6601fb51b5c 100644 --- a/test/e2e/tests/account-details.spec.js +++ b/test/e2e/tests/account-details.spec.js @@ -105,6 +105,9 @@ describe('Show account details', function () { // Create and focus on different account await driver.clickElement('[data-testid="account-menu-icon"]'); + await driver.clickElement( + '[data-testid="multichain-account-menu-popover-action-button"]', + ); await driver.clickElement( '[data-testid="multichain-account-menu-popover-add-account"]', ); @@ -153,6 +156,9 @@ describe('Show account details', function () { // Create and focus on different account await driver.clickElement('[data-testid="account-menu-icon"]'); + await driver.clickElement( + '[data-testid="multichain-account-menu-popover-action-button"]', + ); await driver.clickElement( '[data-testid="multichain-account-menu-popover-add-account"]', ); diff --git a/test/e2e/tests/add-account.spec.js b/test/e2e/tests/add-account.spec.js index 93b0696b33df..5b2551b86294 100644 --- a/test/e2e/tests/add-account.spec.js +++ b/test/e2e/tests/add-account.spec.js @@ -41,6 +41,9 @@ describe('Add account', function () { await unlockWallet(driver); await driver.clickElement('[data-testid="account-menu-icon"]'); + await driver.clickElement( + '[data-testid="multichain-account-menu-popover-action-button"]', + ); await driver.clickElement( '[data-testid="multichain-account-menu-popover-add-account"]', ); @@ -55,7 +58,7 @@ describe('Add account', function () { ); }); - it('should not affect public address when using secret recovery phrase to recover account with non-zero balance', async function () { + it('should not affect public address when using secret recovery phrase to recover account with non-zero balance @no-mmi', async function () { await withFixtures( { fixtures: new FixtureBuilder({ onboarding: true }).build(), @@ -82,6 +85,9 @@ describe('Add account', function () { // Create 2nd account await driver.clickElement('[data-testid="account-menu-icon"]'); + await driver.clickElement( + '[data-testid="multichain-account-menu-popover-action-button"]', + ); await driver.clickElement( '[data-testid="multichain-account-menu-popover-add-account"]', ); @@ -161,7 +167,7 @@ describe('Add account', function () { ); }); - it('should be possible to remove an account imported with a private key, but should not be possible to remove an account generated from the SRP imported in onboarding', async function () { + it('should be possible to remove an account imported with a private key, but should not be possible to remove an account generated from the SRP imported in onboarding @no-mmi', async function () { const testPrivateKey = '14abe6f4aab7f9f626fe981c864d0adeb5685f289ac9270c27b8fd790b4235d6'; @@ -176,7 +182,9 @@ describe('Add account', function () { await unlockWallet(driver); await driver.clickElement('[data-testid="account-menu-icon"]'); - + await driver.clickElement( + '[data-testid="multichain-account-menu-popover-action-button"]', + ); await driver.clickElement( '[data-testid="multichain-account-menu-popover-add-account"]', ); @@ -191,7 +199,6 @@ describe('Add account', function () { }); await driver.clickElement('[data-testid="account-menu-icon"]'); - const menuItems = await driver.findElements( '.multichain-account-list-item', ); @@ -207,6 +214,9 @@ describe('Add account', function () { // Create 3rd account with private key await driver.clickElement('.mm-text-field'); + await driver.clickElement( + '[data-testid="multichain-account-menu-popover-action-button"]', + ); await driver.clickElement({ text: 'Import account', tag: 'button' }); await driver.fill('#private-key-box', testPrivateKey); diff --git a/test/e2e/tests/add-custom-network.spec.js b/test/e2e/tests/add-custom-network.spec.js index d094324ea347..82233d09b34b 100644 --- a/test/e2e/tests/add-custom-network.spec.js +++ b/test/e2e/tests/add-custom-network.spec.js @@ -1,12 +1,66 @@ const { strict: assert } = require('assert'); +const { toHex } = require('@metamask/controller-utils'); const FixtureBuilder = require('../fixture-builder'); const { convertToHexValue, withFixtures, openDapp, regularDelayMs, + unlockWallet, } = require('../helpers'); +const TEST_CHAIN_ID = toHex(100); + +const MOCK_CHAINLIST_RESPONSE = [ + { + name: 'Ethereum Mainnet', + chain: 'ETH', + icon: 'ethereum', + rpc: [ + 'https://mainnet.infura.io/v3/', + 'wss://mainnet.infura.io/ws/v3/ { - await driver.navigate(); - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); - - await openDapp(driver); - await driver.executeScript(` + describe('JSON-RPC API', function () { + it('should show warning when adding chainId 0x1(ethereum) and be followed by an wrong chainId error', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + ganacheOptions, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + await unlockWallet(driver); + + await openDapp(driver); + await driver.executeScript(` var params = [{ chainId: "0x1", chainName: "Fake Ethereum Network", @@ -56,68 +110,69 @@ describe('Custom network', function () { params }) `); - const windowHandles = await driver.waitUntilXWindowHandles(3); - - await driver.switchToWindowWithTitle( - 'MetaMask Notification', - windowHandles, - ); - - await driver.clickElement({ - tag: 'button', - text: 'Approve', - }); - - const warningTxt = - 'You are adding a new RPC provider for Ethereum Mainnet'; - - await driver.findElement({ - tag: 'h4', - text: warningTxt, - }); - - await driver.clickElement({ - tag: 'button', - text: 'Approve', - }); - - const errMsg = - 'Chain ID returned by the custom network does not match the submitted chain ID.'; - await driver.findElement({ - tag: 'span', - text: errMsg, - }); - - const approveBtn = await driver.findElement({ - tag: 'button', - text: 'Approve', - }); - - assert.equal(await approveBtn.isEnabled(), false); - await driver.clickElement({ - tag: 'button', - text: 'Cancel', - }); - }, - ); - }); - it('don’t add bad rpc custom network', async function () { - await withFixtures( - { - dapp: true, - fixtures: new FixtureBuilder() - .withPermissionControllerConnectedToTestDapp() - .build(), - title: this.test.title, - }, - async ({ driver }) => { - await driver.navigate(); - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); - - await openDapp(driver); - await driver.executeScript(` + const windowHandles = await driver.waitUntilXWindowHandles(3); + + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + + await driver.clickElement({ + tag: 'button', + text: 'Approve', + }); + + const warningTxt = + 'You are adding a new RPC provider for Ethereum Mainnet'; + + await driver.findElement({ + tag: 'h4', + text: warningTxt, + }); + + await driver.clickElement({ + tag: 'button', + text: 'Approve', + }); + + const errMsg = + 'Chain ID returned by the custom network does not match the submitted chain ID.'; + await driver.findElement({ + tag: 'span', + text: errMsg, + }); + + const approveBtn = await driver.findElement({ + tag: 'button', + text: 'Approve', + }); + + assert.equal(await approveBtn.isEnabled(), false); + await driver.clickElement({ + tag: 'button', + text: 'Cancel', + }); + }, + ); + }); + + it("don't add bad rpc custom network", async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .withPreferencesController({ useSafeChainsListValidation: true }) + .build(), + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + await unlockWallet(driver); + + await openDapp(driver); + await driver.executeScript(` var params = [{ chainId: "0x123", chainName: "Antani", @@ -134,62 +189,152 @@ describe('Custom network', function () { params }) `); - const windowHandles = await driver.waitUntilXWindowHandles(3); - - await driver.switchToWindowWithTitle( - 'MetaMask Notification', - windowHandles, - ); - - const errMsg1 = 'verify the network details'; - await driver.findElement({ - tag: 'a', - text: errMsg1, - }); - - await driver.clickElement({ - tag: 'button', - text: 'Approve', - }); - - const errMsg2 = - 'Chain ID returned by the custom network does not match the submitted chain ID.'; - await driver.findElement({ - tag: 'span', - text: errMsg2, - }); - - const approveBtn = await driver.findElement({ - tag: 'button', - text: 'Approve', - }); - - assert.equal(await approveBtn.isEnabled(), false); - await driver.clickElement({ - tag: 'button', - text: 'Cancel', - }); - }, - ); - }); - - it('don’t add unreachable custom network', async function () { - await withFixtures( - { - dapp: true, - fixtures: new FixtureBuilder() - .withPermissionControllerConnectedToTestDapp() - .build(), - ganacheOptions, - title: this.test.title, - }, - async ({ driver }) => { - await driver.navigate(); - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); - - await openDapp(driver); - await driver.executeScript(` + const windowHandles = await driver.waitUntilXWindowHandles(3); + + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + + const warningMsg1 = + 'According to our record the network name may not correctly match this chain ID.'; + await driver.findElement({ + tag: 'span', + text: warningMsg1, + }); + + const errorMsg1 = + 'The submitted currency symbol does not match what we expect for this chain ID.'; + await driver.findElement({ + tag: 'span', + text: errorMsg1, + }); + + const errorMsg2 = + 'According to our records the submitted RPC URL value does not match a known provider for this chain ID.'; + await driver.findElement({ + tag: 'span', + text: errorMsg2, + }); + + const errMsg1 = 'verify the network details'; + await driver.findElement({ + tag: 'a', + text: errMsg1, + }); + + await driver.clickElement({ + tag: 'button', + text: 'Approve', + }); + + const errMsg2 = + 'Chain ID returned by the custom network does not match the submitted chain ID.'; + await driver.findElement({ + tag: 'span', + text: errMsg2, + }); + + const approveBtn = await driver.findElement({ + tag: 'button', + text: 'Approve', + }); + + assert.equal(await approveBtn.isEnabled(), false); + await driver.clickElement({ + tag: 'button', + text: 'Cancel', + }); + }, + ); + }); + + it("don't validate bad rpc custom network when toggle is off", async function () { + async function mockRPCURLAndChainId(mockServer) { + return [ + await mockServer + .forPost('https://responsive-rpc.url/') + .thenCallback(() => ({ + statusCode: 200, + json: { + id: '1694444405781', + jsonrpc: '2.0', + result: TEST_CHAIN_ID, + }, + })), + ]; + } + + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .withPreferencesController({ useSafeChainsListValidation: false }) + .build(), + title: this.test.title, + testSpecificMock: mockRPCURLAndChainId, + }, + async ({ driver }) => { + await driver.navigate(); + await unlockWallet(driver); + + await openDapp(driver); + await driver.executeScript(` + var params = [{ + chainId: "${TEST_CHAIN_ID}", + chainName: "Antani", + nativeCurrency: { + name: "", + symbol: "ANTANI", + decimals: 18 + }, + rpcUrls: ["https://responsive-rpc.url/"], + blockExplorerUrls: [ "http://localhost:8080/api/customRPC" ] + }] + window.ethereum.request({ + method: 'wallet_addEthereumChain', + params + }) + `); + const windowHandles = await driver.waitUntilXWindowHandles(3); + + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + + await driver.clickElement({ + tag: 'button', + text: 'Approve', + }); + + const switchNetworkBtn = await driver.findElement({ + tag: 'button', + text: 'Switch network', + }); + + await switchNetworkBtn.click(); + }, + ); + }); + + it("don't add unreachable custom network", async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + ganacheOptions, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + await unlockWallet(driver); + + await openDapp(driver); + await driver.executeScript(` var params = [{ chainId: "0x123", chainName: "Antani", @@ -206,215 +351,473 @@ describe('Custom network', function () { params }) `); - const windowHandles = await driver.waitUntilXWindowHandles(3); - - await driver.switchToWindowWithTitle( - 'MetaMask Notification', - windowHandles, - ); - await driver.clickElement({ - tag: 'button', - text: 'Approve', - }); - - await driver.findElement({ - tag: 'span', - text: 'Error while connecting to the custom network.', - }); - - const approveBtn = await driver.findElement({ - tag: 'button', - text: 'Approve', - }); - - assert.equal(await approveBtn.isEnabled(), false); - await driver.clickElement({ - tag: 'button', - text: 'Cancel', - }); - }, - ); - }); - - it('add custom network and switch the network', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder().build(), - ganacheOptions, - title: this.test.title, - }, - async ({ driver }) => { - await driver.navigate(); - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); - - // Avoid a stale element error - await driver.delay(regularDelayMs); - - await driver.clickElement('[data-testid="network-display"]'); - - await driver.clickElement({ tag: 'button', text: 'Add network' }); - await driver.clickElement({ - tag: 'button', - text: 'Add', - }); - - // verify network details - const title = await driver.findElement({ - tag: 'h6', - text: 'Arbitrum One', - }); - - assert.equal( - await title.getText(), - 'Arbitrum One', - 'Title of popup should be selected network', - ); - - const [networkName, networkUrl, chainIdElement, currencySymbol] = - await driver.findElements('.definition-list dd'); - - assert.equal( - await networkName.getText(), - networkNAME, - 'Network name is not correctly displayed', - ); - assert.equal( - await networkUrl.getText(), - networkURL, - 'Network Url is not correctly displayed', - ); - assert.equal( - await chainIdElement.getText(), - chainID.toString(), - 'Chain Id is not correctly displayed', - ); - assert.equal( - await currencySymbol.getText(), - currencySYMBOL, - 'Currency symbol is not correctly displayed', - ); - - await driver.clickElement({ tag: 'a', text: 'View all details' }); - - const networkDetailsLabels = await driver.findElements('dd'); - assert.equal( - await networkDetailsLabels[8].getText(), - blockExplorerURL, - 'Block Explorer URL is not correct', - ); - - await driver.clickElement({ tag: 'button', text: 'Close' }); - await driver.clickElement({ tag: 'button', text: 'Approve' }); - await driver.clickElement({ - tag: 'h6', - text: 'Switch to Arbitrum One', - }); - // verify network switched - const networkDisplayed = await driver.findElement({ - tag: 'p', - text: 'Arbitrum One', - }); - assert.equal( - await networkDisplayed.getText(), - 'Arbitrum One', - 'You have not switched to Arbitrum Network', - ); - }, - ); - }); - - it('add custom network and not switch the network', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder().build(), - ganacheOptions, - title: this.test.title, - }, - async ({ driver }) => { - await driver.navigate(); - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); - - // Avoid a stale element error - await driver.delay(regularDelayMs); - - await driver.clickElement('[data-testid="network-display"]'); - await driver.clickElement({ tag: 'button', text: 'Add network' }); - - // had to put all Add elements in list since list is changing and networks are not always in same order - await driver.clickElement({ - tag: 'button', - text: 'Add', - }); - - await driver.clickElement({ tag: 'button', text: 'Approve' }); - - await driver.clickElement({ - tag: 'h6', - text: 'Dismiss', - }); - - // verify if added network is in list of networks - const networkDisplay = await driver.findElement( - '[data-testid="network-display"]', - ); - await networkDisplay.click(); - - const arbitrumNetwork = await driver.findElements({ - text: 'Arbitrum One', - tag: 'button', - }); - assert.ok(arbitrumNetwork.length, 1); - }, - ); + const windowHandles = await driver.waitUntilXWindowHandles(3); + + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + await driver.clickElement({ + tag: 'button', + text: 'Approve', + }); + + await driver.findElement({ + tag: 'span', + text: 'Error while connecting to the custom network.', + }); + + const approveBtn = await driver.findElement({ + tag: 'button', + text: 'Approve', + }); + + assert.equal(await approveBtn.isEnabled(), false); + await driver.clickElement({ + tag: 'button', + text: 'Cancel', + }); + }, + ); + }); }); - it('Delete the Arbitrum network', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder() - .withNetworkController({ - networkConfigurations: { - networkConfigurationId: { - rpcUrl: networkURL, - chainId: chainID, - nickname: networkNAME, - ticker: currencySYMBOL, - rpcPrefs: {}, + describe('Popular Networks List', function () { + it('add custom network and switch the network', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + await unlockWallet(driver); + + // Avoid a stale element error + await driver.delay(regularDelayMs); + + await driver.clickElement('[data-testid="network-display"]'); + + await driver.clickElement({ tag: 'button', text: 'Add network' }); + await driver.clickElement({ + tag: 'button', + text: 'Add', + }); + + // verify network details + const title = await driver.findElement({ + tag: 'h6', + text: 'Arbitrum One', + }); + + assert.equal( + await title.getText(), + 'Arbitrum One', + 'Title of popup should be selected network', + ); + + const [networkName, networkUrl, chainIdElement, currencySymbol] = + await driver.findElements('.definition-list dd'); + + assert.equal( + await networkName.getText(), + networkNAME, + 'Network name is not correctly displayed', + ); + assert.equal( + await networkUrl.getText(), + networkURL, + 'Network Url is not correctly displayed', + ); + assert.equal( + await chainIdElement.getText(), + chainID.toString(), + 'Chain Id is not correctly displayed', + ); + assert.equal( + await currencySymbol.getText(), + currencySYMBOL, + 'Currency symbol is not correctly displayed', + ); + + await driver.clickElement({ tag: 'a', text: 'View all details' }); + + const networkDetailsLabels = await driver.findElements('dd'); + assert.equal( + await networkDetailsLabels[8].getText(), + blockExplorerURL, + 'Block Explorer URL is not correct', + ); + + await driver.clickElement({ tag: 'button', text: 'Close' }); + await driver.clickElement({ tag: 'button', text: 'Approve' }); + await driver.clickElement({ + tag: 'h6', + text: 'Switch to Arbitrum One', + }); + // verify network switched + const networkDisplayed = await driver.findElement({ + tag: 'p', + text: 'Arbitrum One', + }); + assert.equal( + await networkDisplayed.getText(), + 'Arbitrum One', + 'You have not switched to Arbitrum Network', + ); + }, + ); + }); + + it('add custom network and not switch the network', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + await unlockWallet(driver); + + // Avoid a stale element error + await driver.delay(regularDelayMs); + + await driver.clickElement('[data-testid="network-display"]'); + await driver.clickElement({ tag: 'button', text: 'Add network' }); + + // had to put all Add elements in list since list is changing and networks are not always in same order + await driver.clickElement({ + tag: 'button', + text: 'Add', + }); + + await driver.clickElement({ tag: 'button', text: 'Approve' }); + + await driver.clickElement({ + tag: 'h6', + text: 'Dismiss', + }); + + // verify if added network is in list of networks + const networkDisplay = await driver.findElement( + '[data-testid="network-display"]', + ); + await networkDisplay.click(); + + const arbitrumNetwork = await driver.findElements({ + text: 'Arbitrum One', + tag: 'button', + }); + assert.ok(arbitrumNetwork.length, 1); + }, + ); + }); + + it('delete the Arbitrum network', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder() + .withNetworkController({ + networkConfigurations: { + networkConfigurationId: { + rpcUrl: networkURL, + chainId: chainID, + nickname: networkNAME, + ticker: currencySYMBOL, + rpcPrefs: {}, + }, }, - }, - }) - .build(), - ganacheOptions, - title: this.test.title, - }, - async ({ driver }) => { - await driver.navigate(); - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); - - await driver.clickElement( - '[data-testid="account-options-menu-button"]', - ); - await driver.clickElement({ text: 'Settings', tag: 'div' }); - await driver.clickElement({ text: 'Networks', tag: 'div' }); - - const arbitrumNetwork = await driver.clickElement({ - text: 'Arbitrum One', - tag: 'div', - }); - - // Click first Delete button - await driver.clickElement('button.btn-danger'); - - // Click modal Delete button - await driver.clickElement('button.btn-danger-primary'); - - // Checks if Arbitrum is deleted - const existNetwork = await driver.isElementPresent(arbitrumNetwork); - assert.equal(existNetwork, false, 'Network is not deleted'); - }, - ); + }) + .build(), + ganacheOptions, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + await unlockWallet(driver); + + await driver.clickElement( + '[data-testid="account-options-menu-button"]', + ); + await driver.clickElement({ text: 'Settings', tag: 'div' }); + await driver.clickElement({ text: 'Networks', tag: 'div' }); + + const arbitrumNetwork = await driver.clickElement({ + text: 'Arbitrum One', + tag: 'div', + }); + + // Click first Delete button + await driver.clickElement('button.btn-danger'); + + // Click modal Delete button + await driver.clickElement('button.btn-danger-primary'); + + // Checks if Arbitrum is deleted + const existNetwork = await driver.isElementPresent(arbitrumNetwork); + assert.equal(existNetwork, false, 'Network is not deleted'); + }, + ); + }); + + it("when the network details validation toggle is turned on, validate user inserted details against data from 'chainid.network'", async function () { + async function mockRPCURLAndChainId(mockServer) { + return [ + await mockServer + .forPost('https://unresponsive-rpc.url/') + // 502 Error communicating with upstream server + .thenCallback(() => ({ statusCode: 502 })), + + await mockServer + .forGet('https://chainid.network/chains.json') + .thenCallback(() => ({ + statusCode: 200, + json: MOCK_CHAINLIST_RESPONSE, + })), + ]; + } + + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions, + title: this.test.title, + testSpecificMock: mockRPCURLAndChainId, + }, + async ({ driver }) => { + await driver.navigate(); + + await unlockWallet(driver); + + await checkThatSafeChainsListValidationToggleIsOn(driver); + + await failCandidateNetworkValidation(driver); + }, + ); + }); + + it("when the network details validation toggle is turned off, don't validate user inserted details", async function () { + async function mockRPCURLAndChainId(mockServer) { + return [ + await mockServer + .forPost('https://responsive-rpc.url/') + .thenCallback(() => ({ + statusCode: 200, + json: { + id: '1694444405781', + jsonrpc: '2.0', + result: TEST_CHAIN_ID, + }, + })), + + await mockServer + .forGet('https://chainid.network/chains.json') + .thenCallback(() => ({ + // even with an error, the test passes + statusCode: 400, + })), + ]; + } + + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions, + title: this.test.title, + testSpecificMock: mockRPCURLAndChainId, + }, + async ({ driver }) => { + await driver.navigate(); + + await unlockWallet(driver); + + await toggleOffSafeChainsListValidation(driver); + + await candidateNetworkIsNotValidated(driver); + }, + ); + }); }); }); + +async function checkThatSafeChainsListValidationToggleIsOn(driver) { + const accountOptionsMenuSelector = + '[data-testid="account-options-menu-button"]'; + await driver.waitForSelector(accountOptionsMenuSelector); + await driver.clickElement(accountOptionsMenuSelector); + + const globalMenuSettingsSelector = '[data-testid="global-menu-settings"]'; + await driver.waitForSelector(globalMenuSettingsSelector); + await driver.clickElement(globalMenuSettingsSelector); + + const securityAndPrivacyTabRawLocator = { + text: 'Security & privacy', + tag: 'div', + }; + await driver.clickElement(securityAndPrivacyTabRawLocator); + + const useSafeChainsListValidationToggleSelector = + '[data-testid="useSafeChainsListValidation"]'; + const useSafeChainsListValidationToggleElement = await driver.waitForSelector( + useSafeChainsListValidationToggleSelector, + ); + const useSafeChainsListValidationToggleState = + await useSafeChainsListValidationToggleElement.getText(); + + assert.equal( + useSafeChainsListValidationToggleState, + 'ON', + 'Safe chains list validation toggle is off', + ); + + // return to the home screen + const appHeaderSelector = '[data-testid="app-header-logo"]'; + await driver.waitForSelector(appHeaderSelector); + await driver.clickElement(appHeaderSelector); +} + +async function failCandidateNetworkValidation(driver) { + const networkMenuSelector = '[data-testid="network-display"]'; + await driver.waitForSelector(networkMenuSelector); + await driver.clickElement(networkMenuSelector); + + await driver.clickElement({ text: 'Add network', tag: 'button' }); + + const addNetworkManuallyButtonSelector = + '[data-testid="add-network-manually"]'; + await driver.waitForSelector(addNetworkManuallyButtonSelector); + + await driver.clickElement(`${addNetworkManuallyButtonSelector} > h6`); + + const [ + , + // first element is the search input that we don't need to fill + networkNameInputEl, + newRPCURLInputEl, + chainIDInputEl, + currencySymbolInputEl, + blockExplorerURLInputEl, + ] = await driver.findElements('input'); + + await networkNameInputEl.fill('cheapETH'); + await newRPCURLInputEl.fill('https://unresponsive-rpc.url'); + await chainIDInputEl.fill(toHex(777)); + await currencySymbolInputEl.fill('cTH'); + await blockExplorerURLInputEl.fill('https://block-explorer.url'); + + const chainIdValidationMessageRawLocator = { + text: 'Could not fetch chain ID. Is your RPC URL correct?', + tag: 'h6', + }; + await driver.waitForSelector(chainIdValidationMessageRawLocator); + + const tickerSymbolValidationMessageRawLocator = { + text: 'Ticker symbol verification data is currently unavailable, make sure that the symbol you have entered is correct. It will impact the conversion rates that you see for this network', + tag: 'h6', + }; + await driver.waitForSelector(tickerSymbolValidationMessageRawLocator); + + const saveButtonRawLocator = { + text: 'Save', + tag: 'button', + }; + const saveButtonEl = await driver.findElement(saveButtonRawLocator); + assert.equal(await saveButtonEl.isEnabled(), false); +} + +async function toggleOffSafeChainsListValidation(driver) { + const accountOptionsMenuSelector = + '[data-testid="account-options-menu-button"]'; + await driver.waitForSelector(accountOptionsMenuSelector); + await driver.clickElement(accountOptionsMenuSelector); + + const globalMenuSettingsSelector = '[data-testid="global-menu-settings"]'; + await driver.waitForSelector(globalMenuSettingsSelector); + await driver.clickElement(globalMenuSettingsSelector); + + const securityAndPrivacyTabRawLocator = { + text: 'Security & privacy', + tag: 'div', + }; + await driver.clickElement(securityAndPrivacyTabRawLocator); + + const useSafeChainsListValidationLabelSelector = + '[data-testid="useSafeChainsListValidation"]'; + const useSafeChainsListValidationToggleSelector = + '[data-testid="useSafeChainsListValidation"] .toggle-button > div'; + + let useSafeChainsListValidationLabelElement = await driver.waitForSelector( + useSafeChainsListValidationLabelSelector, + ); + + let useSafeChainsListValidationToggleState = + await useSafeChainsListValidationLabelElement.getText(); + + assert.equal( + useSafeChainsListValidationToggleState, + 'ON', + 'Safe chains list validation toggle is OFF by default', + ); + + await driver.clickElement(useSafeChainsListValidationToggleSelector); + + await driver.delay(regularDelayMs); + + useSafeChainsListValidationLabelElement = await driver.waitForSelector( + useSafeChainsListValidationLabelSelector, + ); + + useSafeChainsListValidationToggleState = + await useSafeChainsListValidationLabelElement.getText(); + + assert.equal( + useSafeChainsListValidationToggleState, + 'OFF', + 'Safe chains list validation toggle is ON', + ); + + driver.delay(regularDelayMs); + + // return to the home screen + const appHeaderSelector = '[data-testid="app-header-logo"]'; + await driver.waitForSelector(appHeaderSelector); + await driver.clickElement(appHeaderSelector); +} + +async function candidateNetworkIsNotValidated(driver) { + const networkMenuSelector = '[data-testid="network-display"]'; + await driver.waitForSelector(networkMenuSelector); + await driver.clickElement(networkMenuSelector); + + await driver.clickElement({ text: 'Add network', tag: 'button' }); + + const addNetworkManuallyButtonSelector = + '[data-testid="add-network-manually"]'; + await driver.waitForSelector(addNetworkManuallyButtonSelector); + await driver.clickElement(`${addNetworkManuallyButtonSelector} > h6`); + + const [ + , + // first element is the search input that we don't need to fill + networkNameInputEl, + newRPCURLInputEl, + chainIDInputEl, + currencySymbolInputEl, + blockExplorerURLInputEl, + ] = await driver.findElements('input'); + + await networkNameInputEl.fill('cheapETH'); + await newRPCURLInputEl.fill('https://responsive-rpc.url/'); + await chainIDInputEl.fill(TEST_CHAIN_ID); + await currencySymbolInputEl.fill('cTH'); + await blockExplorerURLInputEl.fill('https://block-explorer.url'); + + const saveButtonRawLocator = { + text: 'Save', + tag: 'button', + }; + const saveButtonEl = await driver.findElement(saveButtonRawLocator); + assert.equal(await saveButtonEl.isEnabled(), true); +} diff --git a/test/e2e/tests/chain-interactions.spec.js b/test/e2e/tests/chain-interactions.spec.js index efb83f35eb34..3ed9be54fdb4 100644 --- a/test/e2e/tests/chain-interactions.spec.js +++ b/test/e2e/tests/chain-interactions.spec.js @@ -15,7 +15,7 @@ describe('Chain Interactions', function () { ], concurrent: { port, chainId }, }; - it('should add the Ganache test chain and not switch the network', async function () { + it('should add the Ganache test chain and not switch the network @no-mmi', async function () { await withFixtures( { dapp: true, diff --git a/test/e2e/tests/custom-token-add-approve.spec.js b/test/e2e/tests/custom-token-add-approve.spec.js index f5f58e5d8ebb..03aaecac7b1f 100644 --- a/test/e2e/tests/custom-token-add-approve.spec.js +++ b/test/e2e/tests/custom-token-add-approve.spec.js @@ -81,7 +81,7 @@ describe('Create token, approve token and approve token without gas', function ( ); }); - it('approves an already created token and displays the token approval data', async function () { + it('approves an already created token and displays the token approval data @no-mmi', async function () { await withFixtures( { dapp: true, @@ -199,7 +199,7 @@ describe('Create token, approve token and approve token without gas', function ( ); }); - it('set custom spending cap, customizes gas, edit spending cap and checks transaction in transaction list', async function () { + it('set custom spending cap, customizes gas, edit spending cap and checks transaction in transaction list @no-mmi', async function () { await withFixtures( { dapp: true, @@ -341,7 +341,7 @@ describe('Create token, approve token and approve token without gas', function ( ); }); - it('set maximum spending cap, submits the transaction and finds the transaction in the transactions list', async function () { + it('set maximum spending cap, submits the transaction and finds the transaction in the transactions list @no-mmi', async function () { await withFixtures( { dapp: true, @@ -425,7 +425,7 @@ describe('Create token, approve token and approve token without gas', function ( ); }); - it('approves token without gas, set site suggested spending cap, submits the transaction and finds the transaction in the transactions list', async function () { + it('approves token without gas, set site suggested spending cap, submits the transaction and finds the transaction in the transactions list @no-mmi', async function () { await withFixtures( { dapp: true, diff --git a/test/e2e/tests/edit-gas-fee.spec.js b/test/e2e/tests/edit-gas-fee.spec.js index 965ffaec7054..38a71361359f 100644 --- a/test/e2e/tests/edit-gas-fee.spec.js +++ b/test/e2e/tests/edit-gas-fee.spec.js @@ -8,7 +8,7 @@ const { const FixtureBuilder = require('../fixture-builder'); describe('Editing Confirm Transaction', function () { - it('allows selecting high, medium, low gas estimates on edit gas fee popover', async function () { + it('allows selecting high, medium, low gas estimates on edit gas fee popover @no-mmi', async function () { const ganacheOptions = { hardfork: 'london', accounts: [ @@ -179,7 +179,7 @@ describe('Editing Confirm Transaction', function () { ); }); - it('should use dapp suggested estimates for transaction coming from dapp', async function () { + it('should use dapp suggested estimates for transaction coming from dapp @no-mmi', async function () { const ganacheOptions = { hardfork: 'london', accounts: [ diff --git a/test/e2e/tests/errors.spec.js b/test/e2e/tests/errors.spec.js index 9c4927a7838e..245a26cbd925 100644 --- a/test/e2e/tests/errors.spec.js +++ b/test/e2e/tests/errors.spec.js @@ -273,7 +273,7 @@ describe('Sentry errors', function () { }); }); - describe('before initialization, after opting into metrics', function () { + describe('before initialization, after opting into metrics @no-mmi', function () { it('should send error events in background', async function () { await withFixtures( { @@ -589,7 +589,7 @@ describe('Sentry errors', function () { }); }); - describe('after initialization, after opting into metrics', function () { + describe('after initialization, after opting into metrics @no-mmi', function () { it('should send error events in background', async function () { await withFixtures( { @@ -784,7 +784,7 @@ describe('Sentry errors', function () { }); }); - it('should have no policy gaps for UI controller state', async function () { + it('should have no policy gaps for UI controller state @no-mmi', async function () { await withFixtures( { fixtures: new FixtureBuilder().build(), @@ -808,7 +808,7 @@ describe('Sentry errors', function () { ); }); - it('should not have extra properties in UI state mask', async function () { + it('should not have extra properties in UI state mask @no-mmi', async function () { const expectedMissingState = { currentPopupId: false, // Initialized as undefined // Part of transaction controller store, but missing from the initial diff --git a/test/e2e/tests/import-flow.spec.js b/test/e2e/tests/import-flow.spec.js index 3991350a6407..e92c8ffc2542 100644 --- a/test/e2e/tests/import-flow.spec.js +++ b/test/e2e/tests/import-flow.spec.js @@ -56,7 +56,7 @@ describe('Import flow', function () { const address = await driver.findElement( '.multichain-address-copy-button', ); - assert.equal(await address.getText(), '0x0Cc...afD3'); + assert.equal(await address.getText(), '0x0Cc52...7afD3'); await driver.clickElement('.mm-modal button[aria-label="Close"]'); @@ -83,7 +83,10 @@ describe('Import flow', function () { // choose Create account from the account menu await driver.clickElement('[data-testid="account-menu-icon"]'); - await driver.clickElement({ text: 'Add account', tag: 'button' }); + await driver.clickElement( + '[data-testid="multichain-account-menu-popover-action-button"]', + ); + await driver.clickElement({ text: 'Add a new account', tag: 'button' }); // set account name await driver.fill('[placeholder="Account 2"]', '2nd account'); @@ -196,6 +199,9 @@ describe('Import flow', function () { await driver.press('#password', driver.Key.ENTER); await driver.clickElement('[data-testid="account-menu-icon"]'); + await driver.clickElement( + '[data-testid="multichain-account-menu-popover-action-button"]', + ); await driver.clickElement({ text: 'Import account', tag: 'button' }); // Imports Account 4 with private key @@ -222,6 +228,9 @@ describe('Import flow', function () { }); // Imports Account 5 with private key + await driver.clickElement( + '[data-testid="multichain-account-menu-popover-action-button"]', + ); await driver.clickElement({ text: 'Import account', tag: 'button' }); await driver.findClickableElement('#private-key-box'); await driver.fill('#private-key-box', testPrivateKey2); @@ -277,6 +286,9 @@ describe('Import flow', function () { // Imports an account with JSON file await driver.clickElement('[data-testid="account-menu-icon"]'); + await driver.clickElement( + '[data-testid="multichain-account-menu-popover-action-button"]', + ); await driver.clickElement({ text: 'Import account', tag: 'button' }); await driver.clickElement('.dropdown__select'); @@ -340,6 +352,9 @@ describe('Import flow', function () { // choose Import Account from the account menu await driver.clickElement('[data-testid="account-menu-icon"]'); + await driver.clickElement( + '[data-testid="multichain-account-menu-popover-action-button"]', + ); await driver.clickElement({ text: 'Import account', tag: 'button' }); // enter private key @@ -373,6 +388,9 @@ describe('Import flow', function () { // choose Connect hardware wallet from the account menu await driver.clickElement('[data-testid="account-menu-icon"]'); + await driver.clickElement( + '[data-testid="multichain-account-menu-popover-action-button"]', + ); await driver.clickElement({ text: 'Add hardware wallet', tag: 'button', diff --git a/test/e2e/tests/incremental-security.spec.js b/test/e2e/tests/incremental-security.spec.js index e96b49c195e8..961dcc904959 100644 --- a/test/e2e/tests/incremental-security.spec.js +++ b/test/e2e/tests/incremental-security.spec.js @@ -17,7 +17,7 @@ describe('Incremental Security', function () { }, ], }; - it('Back up Secret Recovery Phrase from backup reminder', async function () { + it('Back up Secret Recovery Phrase from backup reminder @no-mmi', async function () { await withFixtures( { dapp: true, diff --git a/test/e2e/tests/multiple-transactions.spec.js b/test/e2e/tests/multiple-transactions.spec.js index b213f3dcacfb..a4c9a505b91e 100644 --- a/test/e2e/tests/multiple-transactions.spec.js +++ b/test/e2e/tests/multiple-transactions.spec.js @@ -70,6 +70,9 @@ describe('Multiple transactions', function () { await driver.switchToWindow(extensionTab); await driver.delay(regularDelayMs); await driver.clickElement('[data-testid="home__activity-tab"]'); + await driver.waitForSelector( + '.transaction-list__completed-transactions .activity-list-item:nth-of-type(2)', + ); const confirmedTxes = await driver.findElements( '.transaction-list__completed-transactions .activity-list-item', diff --git a/test/e2e/tests/portfolio-site.spec.js b/test/e2e/tests/portfolio-site.spec.js index 93e0d0877518..b708460e0a13 100644 --- a/test/e2e/tests/portfolio-site.spec.js +++ b/test/e2e/tests/portfolio-site.spec.js @@ -12,7 +12,7 @@ describe('Portfolio site', function () { }, ], }; - it('should link to the portfolio site', async function () { + it('should link to the portfolio site @no-mmi', async function () { await withFixtures( { dapp: true, diff --git a/test/e2e/tests/send-eth.spec.js b/test/e2e/tests/send-eth.spec.js index b0c4838c62ce..320102bc57e1 100644 --- a/test/e2e/tests/send-eth.spec.js +++ b/test/e2e/tests/send-eth.spec.js @@ -399,7 +399,7 @@ describe('Send ETH from inside MetaMask to a Multisig Address', function () { ], }; - it('finds the transaction in the transactions list', async function () { + it('finds the transaction in the transactions list @no-mmi', async function () { await withFixtures( { fixtures: new FixtureBuilder().build(), diff --git a/test/e2e/tests/settings-add-snap-account-toggle.spec.js b/test/e2e/tests/settings-add-snap-account-toggle.spec.js new file mode 100644 index 000000000000..54a32f5d1662 --- /dev/null +++ b/test/e2e/tests/settings-add-snap-account-toggle.spec.js @@ -0,0 +1,52 @@ +const { strict: assert } = require('assert'); +const { withFixtures } = require('../helpers'); +const FixtureBuilder = require('../fixture-builder'); + +describe('Add snap account experimental settings', function () { + it('switch "Enable Add snap account" to on', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + title: this.test.title, + failOnConsoleError: false, + }, + async ({ driver }) => { + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + // Make sure the "Add snap account" button is not visible. + await driver.clickElement('[data-testid="account-menu-icon"]'); + await driver.assertElementNotPresent({ + text: 'Add snap account', + tag: 'button', + }); + await driver.clickElement('.mm-box button[aria-label="Close"]'); + + // Navigate to experimental settings. + await driver.clickElement( + '[data-testid="account-options-menu-button"]', + ); + await driver.clickElement({ text: 'Settings', tag: 'div' }); + await driver.clickElement({ text: 'Experimental', tag: 'div' }); + + // Switch "Enable Add snap account" to on. + const toggle = await driver.findElement( + '[data-testid="add-snap-account-toggle"]', + ); + await driver.scrollToElement(toggle); + await driver.clickElement('[data-testid="add-snap-account-toggle"]'); + + // Make sure the "Add snap account" button is visible. + await driver.clickElement('[data-testid="account-menu-icon"]'); + assert.equal( + await driver.isElementPresentAndVisible({ + text: 'Add snap account', + tag: 'button', + }), + true, + ); + }, + ); + }); +}); diff --git a/test/e2e/tests/signature-request.spec.js b/test/e2e/tests/signature-request.spec.js index 375f643be807..bbe628d9a831 100644 --- a/test/e2e/tests/signature-request.spec.js +++ b/test/e2e/tests/signature-request.spec.js @@ -124,7 +124,7 @@ describe('Sign Typed Data Signature Request', function () { }); testData.forEach((data) => { - it(`can queue multiple Signature Requests of ${data.type} and confirm`, async function () { + it(`can queue multiple Signature Requests of ${data.type} and confirm @no-mmi`, async function () { await withFixtures( { dapp: true, diff --git a/test/e2e/tests/simple-send.spec.js b/test/e2e/tests/simple-send.spec.js index e8c582a2c7c7..3e692ed0e599 100644 --- a/test/e2e/tests/simple-send.spec.js +++ b/test/e2e/tests/simple-send.spec.js @@ -7,7 +7,7 @@ const { const FixtureBuilder = require('../fixture-builder'); describe('Simple send', function () { - it('can send a simple transaction from one account to another', async function () { + it('can send a simple transaction from one account to another @no-mmi', async function () { const ganacheOptions = { accounts: [ { diff --git a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json index f5a380e7413c..5aa7a4426840 100644 --- a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json +++ b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json @@ -28,12 +28,12 @@ "showBetaHeader": false, "showProductTour": true, "trezorModel": null, + "hadAdvancedGasFeesSetPriorToMigration92_3": false, "nftsDropdownState": {}, "termsOfUseLastAgreed": "number", "qrHardware": {}, "usedNetworks": { "0x1": true, "0x5": true, "0x539": true }, "snapsInstallPrivacyWarningShown": true, - "hadAdvancedGasFeesSetPriorToMigration92_3": false, "serviceWorkerLastActiveTime": 0 }, "ApprovalController": { @@ -68,9 +68,10 @@ }, "KeyringController": { "isUnlocked": false, - "keyringTypes": "object", - "keyrings": "object" + "keyrings": "object", + "vault": "string" }, + "LoggingController": { "logs": "object" }, "MetaMetricsController": { "participateInMetaMetrics": true, "metaMetricsId": "fake-metrics-id", @@ -124,6 +125,7 @@ "dismissSeedBackUpReminder": true, "disabledRpcMethodPreferences": { "eth_sign": false }, "useMultiAccountBalanceChecker": true, + "useSafeChainsListValidation": "boolean", "useTokenDetection": false, "useNftDetection": false, "use4ByteResolution": true, @@ -145,7 +147,6 @@ }, "ipfsGateway": "string", "useAddressBarEnsResolution": true, - "infuraBlocked": false, "ledgerTransportType": "webhid", "snapRegistryList": "object", "transactionSecurityCheckEnabled": false, @@ -153,10 +154,7 @@ "isLineaMainnetReleased": true, "selectedAddress": "string" }, - "SelectedNetworkController": { - "domains": {}, - "perDomainNetwork": "boolean" - }, + "SelectedNetworkController": { "domains": {}, "perDomainNetwork": "boolean" }, "SignatureController": { "unapprovedMsgs": "object", "unapprovedPersonalMsgs": "object", @@ -221,7 +219,5 @@ "allIgnoredTokens": {}, "allDetectedTokens": {} }, - "TxController": { - "transactions": "object" - } + "TxController": { "transactions": "object" } } diff --git a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json index 28486f27ec15..b3fa6f2ba7e7 100644 --- a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json +++ b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json @@ -13,6 +13,7 @@ "isAccountMenuOpen": false, "isNetworkMenuOpen": false, "identities": "object", + "transactions": "object", "networkConfigurations": "object", "addressBook": "object", "contractExchangeRates": "object", @@ -50,12 +51,12 @@ "showBetaHeader": false, "showProductTour": true, "trezorModel": null, + "hadAdvancedGasFeesSetPriorToMigration92_3": false, "nftsDropdownState": {}, "termsOfUseLastAgreed": "number", "qrHardware": {}, "usedNetworks": { "0x1": true, "0x5": true, "0x539": true }, "snapsInstallPrivacyWarningShown": true, - "hadAdvancedGasFeesSetPriorToMigration92_3": false, "serviceWorkerLastActiveTime": 0, "currentAppVersion": "string", "previousAppVersion": "", @@ -79,13 +80,13 @@ } }, "cachedBalances": "object", - "keyringTypes": "object", "keyrings": "object", "useNonceField": false, "usePhishDetect": true, "dismissSeedBackUpReminder": true, "disabledRpcMethodPreferences": { "eth_sign": false }, "useMultiAccountBalanceChecker": true, + "useSafeChainsListValidation": true, "useTokenDetection": false, "useNftDetection": false, "useCurrencyRateCheck": true, @@ -96,7 +97,6 @@ "forgottenPassword": false, "ipfsGateway": "string", "useAddressBarEnsResolution": true, - "infuraBlocked": false, "ledgerTransportType": "webhid", "snapRegistryList": "object", "transactionSecurityCheckEnabled": false, @@ -146,6 +146,7 @@ "ignoredNfts": "object", "domains": {}, "perDomainNetwork": "boolean", + "logs": "object", "snapErrors": "object", "snaps": "object", "snapStates": "object", @@ -154,7 +155,6 @@ "lastUpdated": "object", "notifications": "object", "accounts": "object", - "transactions": "object", "unapprovedDecryptMsgs": "object", "unapprovedDecryptMsgCount": 0, "unapprovedEncryptionPublicKeyMsgs": "object", diff --git a/test/e2e/tests/state-snapshots/errors-before-init-opt-in-background-state.json b/test/e2e/tests/state-snapshots/errors-before-init-opt-in-background-state.json index 98f21ebd506a..75bd62d27908 100644 --- a/test/e2e/tests/state-snapshots/errors-before-init-opt-in-background-state.json +++ b/test/e2e/tests/state-snapshots/errors-before-init-opt-in-background-state.json @@ -80,7 +80,6 @@ "featureFlags": {}, "forgottenPassword": false, "identities": "object", - "infuraBlocked": false, "ipfsGateway": "string", "knownMethodData": "object", "ledgerTransportType": "webhid", diff --git a/test/e2e/tests/state-snapshots/errors-before-init-opt-in-ui-state.json b/test/e2e/tests/state-snapshots/errors-before-init-opt-in-ui-state.json index bf25106ca50b..5fa13c429985 100644 --- a/test/e2e/tests/state-snapshots/errors-before-init-opt-in-ui-state.json +++ b/test/e2e/tests/state-snapshots/errors-before-init-opt-in-ui-state.json @@ -80,7 +80,6 @@ "featureFlags": {}, "forgottenPassword": false, "identities": "object", - "infuraBlocked": false, "ipfsGateway": "string", "knownMethodData": "object", "ledgerTransportType": "webhid", diff --git a/test/e2e/tests/terms-of-use.spec.js b/test/e2e/tests/terms-of-use.spec.js index f224cb55a251..a8be7b5f1cb1 100644 --- a/test/e2e/tests/terms-of-use.spec.js +++ b/test/e2e/tests/terms-of-use.spec.js @@ -12,7 +12,7 @@ describe('Terms of use', function () { }, ], }; - it('accepts the updated terms of use', async function () { + it('accepts the updated terms of use @no-mmi', async function () { const firstOfJan = 1672574400; await withFixtures( { diff --git a/test/e2e/user-actions-benchmark.js b/test/e2e/user-actions-benchmark.js index 07843ecdf32f..3c2d71045a68 100644 --- a/test/e2e/user-actions-benchmark.js +++ b/test/e2e/user-actions-benchmark.js @@ -34,6 +34,9 @@ async function loadNewAccount() { await driver.press('#password', driver.Key.ENTER); await driver.clickElement('[data-testid="account-menu-icon"]'); + await driver.clickElement( + '[data-testid="multichain-account-menu-popover-action-button"]', + ); const timestampBeforeAction = new Date(); await driver.clickElement( '[data-testid="multichain-account-menu-popover-add-account"]', diff --git a/test/e2e/webdriver/driver.js b/test/e2e/webdriver/driver.js index d6592c44fec6..5dfaf22258b8 100644 --- a/test/e2e/webdriver/driver.js +++ b/test/e2e/webdriver/driver.js @@ -36,6 +36,13 @@ function wrapElementWithAPI(element, driver) { throw new Error(`Provided state: '${state}' is not supported`); } }; + + element.nestedFindElement = async (rawLocator) => { + const locator = driver.buildLocator(rawLocator); + const newElement = await element.findElement(locator); + return wrapElementWithAPI(newElement, driver); + }; + return element; } @@ -249,10 +256,14 @@ class Driver { await element.click(); } + /** + * 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. + * + * @param rawLocator + */ 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(); @@ -261,6 +272,21 @@ class Driver { } } + /** + * Can fix instances where a normal click produces ElementClickInterceptedError + * + * @param rawLocator + */ + async clickElementUsingMouseMove(rawLocator) { + const element = await this.findClickableElement(rawLocator); + await this.scrollToElement(element); + await this.driver + .actions() + .move({ origin: element, x: 1, y: 1 }) + .click() + .perform(); + } + async clickPoint(rawLocator, x, y) { const element = await this.findElement(rawLocator); await this.driver @@ -343,7 +369,13 @@ class Driver { // Navigation async navigate(page = Driver.PAGES.HOME) { - return await this.driver.get(`${this.extensionUrl}/${page}.html`); + const response = await this.driver.get(`${this.extensionUrl}/${page}.html`); + // Wait for asyncronous JavaScript to load + await this.driver.wait( + until.elementLocated(this.buildLocator('.metamask-loaded')), + 10 * 1000, + ); + return response; } async getCurrentUrl() { diff --git a/test/jest/mock-store.js b/test/jest/mock-store.js index 4ceaded9cee0..96697f354f23 100644 --- a/test/jest/mock-store.js +++ b/test/jest/mock-store.js @@ -260,7 +260,6 @@ export const createSwapsMockStore = () => { }, selectedAddress: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', currentLocale: 'en', - keyringTypes: [KeyringType.imported, KeyringType.hdKeyTree], keyrings: [ { type: KeyringType.hdKeyTree, diff --git a/test/jest/setup.js b/test/jest/setup.js index 94feffdfff4b..5f713c1e0ad7 100644 --- a/test/jest/setup.js +++ b/test/jest/setup.js @@ -11,6 +11,10 @@ jest.mock('webextension-polyfill', () => { }; }); +jest.mock('../../ui/hooks/usePetnamesEnabled', () => ({ + usePetnamesEnabled: () => false, +})); + const UNRESOLVED = Symbol('timedOut'); // Store this in case it gets stubbed later diff --git a/test/scenarios/3. transactions/cancel transaction.csv b/test/scenarios/3. transactions/cancel transaction.csv index 852cd56f947a..031edc14b130 100644 --- a/test/scenarios/3. transactions/cancel transaction.csv +++ b/test/scenarios/3. transactions/cancel transaction.csv @@ -19,7 +19,6 @@ The total amount is shown.", The recipient's hexadecimal address is shown in the activity list item. The amount is shown in the activity list item.", 11,Cancel the transaction.,,"The transaction appears in the activity list. -The recipient's hexadecimal address is shown in the activity list item. The amount is shown in the activity list item.", 12,Wait for the transaction to complete.,,Another activity item appears.,Two activity items; Send and Receive. 13,Open the Send activity list item.,,"The updated gas fees are shown in the item details. @@ -27,4 +26,4 @@ The transaction status, recipient's address, nonce, amount, gas and total are sh 14,Expand the Activity log.,,"The created, submitted, cancel attempt and cancelled activity is shown in the activity log.", 15,Proceed to view the transaction on the block explorer.,,The block explorer opens in a new tab., 16,Open the Receive activity list item.,,"The transaction status, recipient's address, nonce, amount, gas and total are shown in the item details.", -17,Proceed to view the transaction on the block explorer.,,The block explorer opens in a new tab., \ No newline at end of file +17,Proceed to view the transaction on the block explorer.,,The block explorer opens in a new tab., diff --git a/test/scenarios/3. transactions/send erc20 token origin MM.csv b/test/scenarios/3. transactions/send erc20 token origin MM.csv index b7d6ad181222..05b0f9fb637a 100644 --- a/test/scenarios/3. transactions/send erc20 token origin MM.csv +++ b/test/scenarios/3. transactions/send erc20 token origin MM.csv @@ -30,8 +30,7 @@ The specified token is shown. The estimated gas details are shown. The total amount is shown.", 17,Confirm the transaction.,,"The transaction appears in the activity list. -The recipient's hexadecimal address is shown in the activity list item. The amount is shown in the activity list item.", 18,Open the activity list item.,,"The transaction status, recipient's address, nonce, amount, gas and total are shown in the item details.", 19,Expand the Activity log.,,"The created, submitted and confirmed activity is shown in the activity log.", -20,Proceed to view the transaction on the block explorer.,,The block explorer opens in a new tab., \ No newline at end of file +20,Proceed to view the transaction on the block explorer.,,The block explorer opens in a new tab., diff --git a/test/scenarios/3. transactions/send erc721 token origin MM.csv b/test/scenarios/3. transactions/send erc721 token origin MM.csv index af4bc2d6739c..8a988375cbaa 100644 --- a/test/scenarios/3. transactions/send erc721 token origin MM.csv +++ b/test/scenarios/3. transactions/send erc721 token origin MM.csv @@ -30,8 +30,7 @@ The specified NFT token id is shown. The estimated gas details are shown. The total amount is shown.", 18,Confirm the transaction.,,"The transaction appears in the activity list. -The recipient's hexadecimal address is shown in the activity list item. The amount is shown in the activity list item.", 19,Open the activity list item.,,"The transaction status, recipient's address, nonce, amount, gas and total are shown in the item details.", 20,Expand the Activity log.,,"The created, submitted and confirmed activity is shown in the activity log.", -21,Proceed to view the transaction on the block explorer.,,The block explorer opens in a new tab., \ No newline at end of file +21,Proceed to view the transaction on the block explorer.,,The block explorer opens in a new tab., diff --git a/test/scenarios/3. transactions/send native token origin MM.csv b/test/scenarios/3. transactions/send native token origin MM.csv index 11968d1d757e..8bf34a45033a 100644 --- a/test/scenarios/3. transactions/send native token origin MM.csv +++ b/test/scenarios/3. transactions/send native token origin MM.csv @@ -14,7 +14,8 @@ The specified amount is shown. The estimated gas details are shown. The total amount is shown.", 8,Confirm the transaction.,,"The transaction appears in the activity list. +The recipient's hexadecimal address is shown in the activity list item. The amount is shown in the activity list item.", 9,Open the activity list item.,,"The transaction status, recipient's address, nonce, amount, gas and total are shown in the item details.", 10,Expand the Activity log.,,"The created, submitted and confirmed activity is shown in the activity log.", -11,Proceed to view the transaction on the block explorer.,,The block explorer opens in a new tab., +11,Proceed to view the transaction on the block explorer.,,The block explorer opens in a new tab., \ No newline at end of file diff --git a/test/scenarios/3. transactions/speed up transaction.csv b/test/scenarios/3. transactions/speed up transaction.csv index 5e89b3a52641..14c87989aed3 100644 --- a/test/scenarios/3. transactions/speed up transaction.csv +++ b/test/scenarios/3. transactions/speed up transaction.csv @@ -16,7 +16,6 @@ The total amount is shown.", 8,Proceed to edit the transaction gas fees.,e.g. 0.1.,, 9,Reduce the the Max base fee and Priority fee.,e.g. Max base fee 0.00001 and Priority fee 0.00001.,, 10,Confirm the transaction.,,"The transaction appears in the activity list. -The recipient's hexadecimal address is shown in the activity list item. The amount is shown in the activity list item.", 11,Speed up the transaction.,,"The transaction appears in the activity list. The recipient's hexadecimal address is shown in the activity list item. @@ -24,4 +23,4 @@ The amount is shown in the activity list item.", 12,Open the activity list item.,,"The updated gas fees are shown in the item details. The transaction status, recipient's address, nonce, amount, gas and total are shown in the item details.", 13,Expand the Activity log.,,"The created, submitted, resubmitted and confirmed activity is shown in the activity log.", -14,Proceed to view the transaction on the block explorer.,,The block explorer opens in a new tab., \ No newline at end of file +14,Proceed to view the transaction on the block explorer.,,The block explorer opens in a new tab., diff --git a/types/eth-keyring-controller.d.ts b/types/eth-keyring-controller.d.ts deleted file mode 100644 index ee7525bf394d..000000000000 --- a/types/eth-keyring-controller.d.ts +++ /dev/null @@ -1,17 +0,0 @@ -declare module '@metamask/eth-keyring-controller' { - export class KeyringController { - signMessage: (...any) => any; - - signPersonalMessage: (...any) => any; - - signTypedMessage: (...any) => any; - - getKeyringForAccount: (address: string) => Promise<{ - type: string; - }>; - - getEncryptionPublicKey: (address: string) => Promise; - - decryptMessage: (...any) => any; - } -} diff --git a/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.scss b/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.scss index e9b958789754..7ba24fd41ceb 100644 --- a/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.scss +++ b/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.scss @@ -1,6 +1,6 @@ .unconnected-account-alert { &__content { - border-radius: 0; + border-radius: 0 !important; // To override the box border radius because of popover } &__footer { diff --git a/ui/components/app/app-components.scss b/ui/components/app/app-components.scss index c4dc26714527..c5c610d5dc51 100644 --- a/ui/components/app/app-components.scss +++ b/ui/components/app/app-components.scss @@ -95,6 +95,8 @@ @import 'network-account-balance-header/index'; @import 'approve-content-card/index'; @import 'transaction-alerts/transaction-alerts'; +@import 'name/index'; +@import 'name/name-details/index'; ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) @import '../institutional/interactive-replacement-token-notification/index'; @import '../institutional/confirm-remove-jwt-modal/index'; diff --git a/ui/components/app/asset-list/__snapshots__/asset-list.test.js.snap b/ui/components/app/asset-list/__snapshots__/asset-list.test.js.snap new file mode 100644 index 000000000000..7a741c600582 --- /dev/null +++ b/ui/components/app/asset-list/__snapshots__/asset-list.test.js.snap @@ -0,0 +1,339 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AssetList token fiat value calculations calculates the correct fiat account total 1`] = ` + +`; diff --git a/ui/components/app/asset-list/asset-list.buy-receive.test.js b/ui/components/app/asset-list/asset-list.buy-receive.test.js new file mode 100644 index 000000000000..949f747cf660 --- /dev/null +++ b/ui/components/app/asset-list/asset-list.buy-receive.test.js @@ -0,0 +1,64 @@ +import React from 'react'; +import { renderWithProvider } from '../../../../test/jest'; +import configureStore from '../../../store/store'; +import mockState from '../../../../test/data/mock-state.json'; +import { CHAIN_IDS } from '../../../../shared/constants/network'; +import AssetList from './asset-list'; + +// Specific to just the ETH FIAT conversion +const ETH_BALANCE = '0x041173b2c0e57d'; // 0.0011 ETH ($1.83) + +const render = ( + selectedAddress = mockState.metamask.selectedAddress, + balance = ETH_BALANCE, + chainId = CHAIN_IDS.MAINNET, +) => { + const state = { + ...mockState, + metamask: { + ...mockState.metamask, + providerConfig: { chainId }, + cachedBalances: { + [CHAIN_IDS.MAINNET]: { + [selectedAddress]: balance, + }, + }, + selectedAddress, + }, + }; + const store = configureStore(state); + return renderWithProvider( + undefined} />, + store, + ); +}; + +describe('AssetList Buy/Receive', () => { + it('shows Buy and Receive when the account is empty', () => { + process.env.MULTICHAIN = 1; + const { queryByText } = render( + '0xc42edfcc21ed14dda456aa0756c153f7985d8813', + '0x0', + ); + expect(queryByText('Buy')).toBeInTheDocument(); + expect(queryByText('Receive')).toBeInTheDocument(); + }); + + it('shows only Receive when chainId is not buyable', () => { + process.env.MULTICHAIN = 1; + const { queryByText } = render( + '0xc42edfcc21ed14dda456aa0756c153f7985d8813', + '0x0', + '0x8675309', // Custom chain ID that isn't buyable + ); + expect(queryByText('Buy')).not.toBeInTheDocument(); + expect(queryByText('Receive')).toBeInTheDocument(); + }); + + it('shows neither when the account has a balance', () => { + process.env.MULTICHAIN = 1; + const { queryByText } = render(); + expect(queryByText('Buy')).not.toBeInTheDocument(); + expect(queryByText('Receive')).not.toBeInTheDocument(); + }); +}); diff --git a/ui/components/app/asset-list/asset-list.js b/ui/components/app/asset-list/asset-list.js index 0cb8e636ced3..259579e380cc 100644 --- a/ui/components/app/asset-list/asset-list.js +++ b/ui/components/app/asset-list/asset-list.js @@ -1,6 +1,7 @@ import React, { useContext, useState } from 'react'; import PropTypes from 'prop-types'; -import { useSelector } from 'react-redux'; +import { shallowEqual, useSelector } from 'react-redux'; +import { isEqual } from 'lodash'; import TokenList from '../token-list'; import { PRIMARY, SECONDARY } from '../../../helpers/constants/common'; import { useUserPreferencedCurrency } from '../../../hooks/useUserPreferencedCurrency'; @@ -10,8 +11,19 @@ import { getNativeCurrencyImage, getDetectedTokensInCurrentNetwork, getIstokenDetectionInactiveOnNonMainnetSupportedNetwork, + getShouldHideZeroBalanceTokens, + getTokenExchangeRates, + getCurrentCurrency, + getIsBuyableChain, + getCurrentChainId, + getSwapsDefaultToken, + getSelectedAddress, } from '../../../selectors'; -import { getNativeCurrency } from '../../../ducks/metamask/metamask'; +import { + getConversionRate, + getNativeCurrency, + getTokens, +} from '../../../ducks/metamask/metamask'; import { useCurrencyDisplay } from '../../../hooks/useCurrencyDisplay'; import Box from '../../ui/box/box'; import { MetaMetricsContext } from '../../../contexts/metametrics'; @@ -25,17 +37,34 @@ import { TokenListItem, ImportTokenLink, BalanceOverview, + AssetListConversionButton, } from '../../multichain'; +import { isEqualCaseInsensitive } from '../../../../shared/modules/string-utils'; +import { getTokenFiatAmount } from '../../../helpers/utils/token-util'; +import { formatCurrency } from '../../../helpers/utils/confirm-tx.util'; +import { + getValueFromWeiHex, + sumDecimals, +} from '../../../../shared/modules/conversion.utils'; +import { useTokenTracker } from '../../../hooks/useTokenTracker'; + +import useRamps from '../../../hooks/experiences/useRamps'; +import { Display } from '../../../helpers/constants/design-system'; + +import { ReceiveModal } from '../../multichain/receive-modal'; + const AssetList = ({ onClickAsset }) => { const [showDetectedTokens, setShowDetectedTokens] = useState(false); - const selectedAccountBalance = useSelector(getSelectedAccountCachedBalance); const nativeCurrency = useSelector(getNativeCurrency); const showFiat = useSelector(getShouldShowFiat); const trackEvent = useContext(MetaMetricsContext); const balance = useSelector(getSelectedAccountCachedBalance); const balanceIsLoading = !balance; + const selectedAddress = useSelector(getSelectedAddress); + + const [showReceiveModal, setShowReceiveModal] = useState(false); const { currency: primaryCurrency, @@ -66,39 +95,158 @@ const AssetList = ({ onClickAsset }) => { getIstokenDetectionInactiveOnNonMainnetSupportedNetwork, ); + const contractExchangeRates = useSelector( + getTokenExchangeRates, + shallowEqual, + ); + const conversionRate = useSelector(getConversionRate); + const currentCurrency = useSelector(getCurrentCurrency); + + const nativeFiat = getValueFromWeiHex({ + value: balance, + toCurrency: currentCurrency, + conversionRate, + numberOfDecimals: 2, + }); + + const shouldHideZeroBalanceTokens = useSelector( + getShouldHideZeroBalanceTokens, + ); + // use `isEqual` comparison function because the token array is serialized + // from the background so it has a new reference with each background update, + // even if the tokens haven't changed + const tokens = useSelector(getTokens, isEqual); + const { loading, tokensWithBalances } = useTokenTracker( + tokens, + true, + shouldHideZeroBalanceTokens, + ); + + // An array of string balances (ex: ["1.90", "22290.01", ...]) + const dollarBalances = tokensWithBalances.map((token) => { + const contractExchangeTokenKey = Object.keys(contractExchangeRates).find( + (key) => isEqualCaseInsensitive(key, token.address), + ); + const tokenExchangeRate = + (contractExchangeTokenKey && + contractExchangeRates[contractExchangeTokenKey]) ?? + 0; + + const fiat = getTokenFiatAmount( + tokenExchangeRate, + conversionRate, + currentCurrency, + token.string, + token.symbol, + false, + false, + ); + + return fiat; + }); + + // Total native and token fiat balance as a string (ex: "8.90") + const totalFiatBalance = sumDecimals(nativeFiat, ...dollarBalances).toString( + 10, + ); + + // Fiat balance formatted in user's desired currency (ex: "$8.90") + const formattedTotalFiatBalance = formatCurrency( + totalFiatBalance, + currentCurrency, + ); + + const balanceIsZero = Number(totalFiatBalance) === 0; + const isBuyableChain = useSelector(getIsBuyableChain); + const shouldShowBuy = isBuyableChain && balanceIsZero; + const shouldShowReceive = balanceIsZero; + const { openBuyCryptoInPdapp } = useRamps(); + const chainId = useSelector(getCurrentChainId); + const defaultSwapsToken = useSelector(getSwapsDefaultToken); + return ( <> - {process.env.MULTICHAIN ? : null} - onClickAsset(nativeCurrency)} - title={nativeCurrency} - primary={ - primaryCurrencyProperties.value ?? secondaryCurrencyProperties.value - } - tokenSymbol={primaryCurrencyProperties.suffix} - secondary={showFiat ? secondaryCurrencyDisplay : undefined} - tokenImage={balanceIsLoading ? null : primaryTokenImage} - /> - { - onClickAsset(tokenAddress); - trackEvent({ - event: MetaMetricsEventName.TokenScreenOpened, - category: MetaMetricsEventCategory.Navigation, - properties: { - token_symbol: primaryCurrencyProperties.suffix, - location: 'Home', - }, - }); - }} - /> - {detectedTokens.length > 0 && - !isTokenDetectionInactiveOnNonMainnetSupportedNetwork ? ( - setShowDetectedTokens(true)} - margin={4} + {process.env.MULTICHAIN ? ( + ) : null} + {detectedTokens.length > 0 && + !isTokenDetectionInactiveOnNonMainnetSupportedNetwork && ( + setShowDetectedTokens(true)} + margin={4} + /> + )} + {process.env.MULTICHAIN && (shouldShowBuy || shouldShowReceive) ? ( + + {shouldShowBuy ? ( + { + openBuyCryptoInPdapp(); + trackEvent({ + event: MetaMetricsEventName.NavBuyButtonClicked, + category: MetaMetricsEventCategory.Navigation, + properties: { + location: 'Home', + text: 'Buy', + chain_id: chainId, + token_symbol: defaultSwapsToken, + }, + }); + }} + /> + ) : null} + {shouldShowReceive ? ( + setShowReceiveModal(true)} + /> + ) : null} + {showReceiveModal ? ( + setShowReceiveModal(false)} + /> + ) : null} + + ) : ( + <> + onClickAsset(nativeCurrency)} + title={nativeCurrency} + primary={ + primaryCurrencyProperties.value ?? + secondaryCurrencyProperties.value + } + tokenSymbol={primaryCurrencyProperties.suffix} + secondary={showFiat ? secondaryCurrencyDisplay : undefined} + tokenImage={balanceIsLoading ? null : primaryTokenImage} + /> + { + onClickAsset(tokenAddress); + trackEvent({ + event: MetaMetricsEventName.TokenScreenOpened, + category: MetaMetricsEventCategory.Navigation, + properties: { + token_symbol: primaryCurrencyProperties.suffix, + location: 'Home', + }, + }); + }} + /> + + )} 0 ? 0 : 4}> diff --git a/ui/components/app/asset-list/asset-list.test.js b/ui/components/app/asset-list/asset-list.test.js index b3925d6b63f3..9ba19e0cf8f1 100644 --- a/ui/components/app/asset-list/asset-list.test.js +++ b/ui/components/app/asset-list/asset-list.test.js @@ -3,15 +3,81 @@ import { screen } from '@testing-library/react'; import { renderWithProvider } from '../../../../test/jest'; import configureStore from '../../../store/store'; import mockState from '../../../../test/data/mock-state.json'; +import { CHAIN_IDS } from '../../../../shared/constants/network'; import AssetList from './asset-list'; -const render = () => { - const store = configureStore({ +// Specific to just the ETH FIAT conversion +const CONVERSION_RATE = 1597.32; +const ETH_BALANCE = '0x041173b2c0e57d'; // 0.0011 ETH ($1.83) + +const USDC_BALANCE = '199.4875'; // @ $1 +const LINK_BALANCE = '122.0005'; // @ $6.75 +const WBTC_BALANCE = '2.38'; // @ $26,601.51 + +const USDC_CONTRACT = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'; +const LINK_CONTRACT = '0x514910771AF9Ca656af840dff83E8264EcF986CA'; +const WBTC_CONTRACT = '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599'; + +jest.mock('../../../hooks/useTokenTracker', () => { + return { + useTokenTracker: () => ({ + loading: false, + tokensWithBalances: [ + { + address: USDC_CONTRACT, + decimals: 6, + symbol: 'USDC', + string: USDC_BALANCE, // $199.36 + }, + { + address: LINK_CONTRACT, + aggregators: [], + decimals: 18, + symbol: 'LINK', + string: LINK_BALANCE, // $824.78 + }, + { + address: WBTC_CONTRACT, + aggregators: [], + decimals: 8, + symbol: 'WBTC', + string: WBTC_BALANCE, // $63,381.02 + }, + ], + error: null, + }), + }; +}); + +const render = ( + selectedAddress = mockState.metamask.selectedAddress, + balance = ETH_BALANCE, + chainId = CHAIN_IDS.MAINNET, +) => { + const state = { + ...mockState, metamask: { ...mockState.metamask, + providerConfig: { chainId }, + conversionRate: CONVERSION_RATE, + cachedBalances: { + [CHAIN_IDS.MAINNET]: { + [selectedAddress]: balance, + }, + }, + contractExchangeRates: { + [USDC_CONTRACT]: 0.00062566, + [LINK_CONTRACT]: 0.00423239, + [WBTC_CONTRACT]: 16.66575, + }, + selectedAddress, }, - }); - return renderWithProvider(, store); + }; + const store = configureStore(state); + return renderWithProvider( + undefined} />, + store, + ); }; describe('AssetList', () => { @@ -19,4 +85,14 @@ describe('AssetList', () => { render(); expect(screen.getByText('Refresh list')).toBeInTheDocument(); }); + + describe('token fiat value calculations', () => { + it('calculates the correct fiat account total', () => { + process.env.MULTICHAIN = 1; + const { container } = render(); + expect(container).toMatchSnapshot(); + expect(screen.getByText('$63,356.88 USD')).toBeInTheDocument(); + jest.resetModules(); + }); + }); }); diff --git a/ui/components/app/confirm-page-container/confirm-page-container-container.test.js b/ui/components/app/confirm-page-container/confirm-page-container-container.test.js index 6432fad41027..a6afdcfc6368 100644 --- a/ui/components/app/confirm-page-container/confirm-page-container-container.test.js +++ b/ui/components/app/confirm-page-container/confirm-page-container-container.test.js @@ -319,6 +319,8 @@ describe('Confirm Page Container Container Test', () => { }; mockState.metamask.addressBook = addressBook; + mockState.confirmTransaction.txData.txParams.to = + '0x7a1A4Ad9cc746a70ee58568466f7996dD0aCE4E8'; const store = configureMockStore()(mockState); diff --git a/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.test.js b/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.test.js index f81301c195ec..5261d935c185 100644 --- a/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.test.js +++ b/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.test.js @@ -7,6 +7,7 @@ import { INSUFFICIENT_FUNDS_ERROR_KEY, TRANSACTION_ERROR_KEY, } from '../../../../helpers/constants/error-keys'; +import { shortenAddress } from '../../../../helpers/utils/util'; import ConfirmPageContainerContent from './confirm-page-container-content.component'; describe('Confirm Page Container Content', () => { @@ -25,6 +26,17 @@ describe('Confirm Page Container Content', () => { }, }, }, + identities: {}, + tokenList: {}, + }, + confirmTransaction: { + txData: { + txParams: { + gas: '0x153e2', + value: '0x0', + to: '0x0BC30598F0F386371eB3d2195AcAA14C7566534b', + }, + }, }, }; @@ -106,7 +118,7 @@ describe('Confirm Page Container Content', () => { expect(props.onCancel).toHaveBeenCalledTimes(1); }); - it('render contract address name from addressBook in title for contract', async () => { + it('render contract address in the content component', async () => { props.disabled = false; props.toAddress = '0x06195827297c7A80a443b6894d3BDB8824b43896'; props.transactionType = TransactionType.contractInteraction; @@ -114,8 +126,11 @@ describe('Confirm Page Container Content', () => { , store, ); + const expectedAddress = shortenAddress( + mockStore.confirmTransaction.txData.txParams.to, + ); - expect(queryByText('Address Book Account 1')).toBeInTheDocument(); + expect(queryByText(`${expectedAddress}`)).toBeInTheDocument(); }); it('render simple title without address name for simple send', async () => { diff --git a/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/confirm-page-container-summary.component.js b/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/confirm-page-container-summary.component.js index 46a3f068f42e..2421f11ee39b 100644 --- a/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/confirm-page-container-summary.component.js +++ b/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/confirm-page-container-summary.component.js @@ -9,7 +9,7 @@ import { TransactionType } from '../../../../../../shared/constants/transaction' import { toChecksumHexAddress } from '../../../../../../shared/modules/hexstring-utils'; import { useI18nContext } from '../../../../../hooks/useI18nContext'; import useAddressDetails from '../../../../../hooks/useAddressDetails'; -import { getIpfsGateway } from '../../../../../selectors'; +import { getIpfsGateway, txDataSelector } from '../../../../../selectors'; import Identicon from '../../../../ui/identicon'; import InfoTooltip from '../../../../ui/info-tooltip'; @@ -25,7 +25,6 @@ const ConfirmPageContainerSummary = (props) => { subtitleComponent, className, tokenAddress, - toAddress, nonce, origin, image, @@ -36,6 +35,10 @@ const ConfirmPageContainerSummary = (props) => { const t = useI18nContext(); const ipfsGateway = useSelector(getIpfsGateway); + const txData = useSelector(txDataSelector); + const { txParams = {} } = txData; + const { to: txParamsToAddress } = txParams; + const contractInitiatedTransactionType = [ TransactionType.contractInteraction, TransactionType.tokenMethodTransfer, @@ -48,14 +51,15 @@ const ConfirmPageContainerSummary = (props) => { if (isContractTypeTransaction) { // If the transaction is TOKEN_METHOD_TRANSFER or TOKEN_METHOD_TRANSFER_FROM // the contract address is passed down as tokenAddress, if it is anyother - // type of contract interaction it is passed as toAddress + // type of contract interaction it is "to" from txParams + contractAddress = transactionType === TransactionType.tokenMethodTransfer || transactionType === TransactionType.tokenMethodTransferFrom || transactionType === TransactionType.tokenMethodSafeTransferFrom || transactionType === TransactionType.tokenMethodSetApprovalForAll ? tokenAddress - : toAddress; + : txParamsToAddress; } const { toName, isTrusted } = useAddressDetails(contractAddress); @@ -146,7 +150,6 @@ ConfirmPageContainerSummary.propTypes = { subtitleComponent: PropTypes.node, className: PropTypes.string, tokenAddress: PropTypes.string, - toAddress: PropTypes.string, nonce: PropTypes.string, origin: PropTypes.string.isRequired, transactionType: PropTypes.string, diff --git a/ui/components/app/connected-accounts-list/connected-accounts-list-item/connected-accounts-list-item.component.js b/ui/components/app/connected-accounts-list/connected-accounts-list-item/connected-accounts-list-item.component.js index 4ec24a7b48b0..5590edee8755 100644 --- a/ui/components/app/connected-accounts-list/connected-accounts-list-item/connected-accounts-list-item.component.js +++ b/ui/components/app/connected-accounts-list/connected-accounts-list-item/connected-accounts-list-item.component.js @@ -1,54 +1,114 @@ +import React from 'react'; import classnames from 'classnames'; import PropTypes from 'prop-types'; -import React, { PureComponent } from 'react'; -import Identicon from '../../../ui/identicon'; +import { useSelector } from 'react-redux'; +import { shortenAddress } from '../../../../helpers/utils/util'; -export default class ConnectedAccountsListItem extends PureComponent { - static contextTypes = { - t: PropTypes.func.isRequired, - }; +import { + AvatarAccount, + AvatarAccountSize, + AvatarAccountVariant, + Box, + Text, +} from '../../../component-library'; +import { getUseBlockie } from '../../../../selectors'; +import { + AlignItems, + BackgroundColor, + Display, + FlexDirection, + JustifyContent, + TextColor, + TextVariant, +} from '../../../../helpers/constants/design-system'; - static propTypes = { - address: PropTypes.string.isRequired, - className: PropTypes.string, - name: PropTypes.node.isRequired, - status: PropTypes.string, - action: PropTypes.node, - options: PropTypes.node, - }; - - static defaultProps = { - className: null, - options: null, - action: null, - }; - - render() { - const { address, className, name, status, action, options } = this.props; - - return ( -
-
- -
-

- {name} -

+export default function ConnectedAccountsListItem({ + address, + className = null, + name, + status, + action = null, + options = null, + backgroundColor, +}) { + const useBlockie = useSelector(getUseBlockie); + const containerbackgroundColor = + backgroundColor ?? BackgroundColor.backgroundDefault; + return ( + + + + + + + {name} + + {shortenAddress(address)} {status ? ( -

-    + {status} -

+ ) : null} +
+ {action} -
-
- {options} -
- ); - } + + + + {options} + + ); } +ConnectedAccountsListItem.propTypes = { + /** + * Address for Avatar + */ + address: PropTypes.string.isRequired, + /** + * An additional className to apply + */ + className: PropTypes.string, + /** + * Name of the account + */ + name: PropTypes.node.isRequired, + /** + * Status showing connected, not connected and active state + */ + status: PropTypes.string, + /** + * Action for account + */ + action: PropTypes.node, + /** + * Render Options button with actions + */ + options: PropTypes.node, + /** + * ContainerbackgroundColor showing highlighted state when not connected + */ + backgroundColor: PropTypes.string, +}; diff --git a/ui/components/app/connected-accounts-list/connected-accounts-list.component.js b/ui/components/app/connected-accounts-list/connected-accounts-list.component.js index 11563efc82d5..a1f0bbba2124 100644 --- a/ui/components/app/connected-accounts-list/connected-accounts-list.component.js +++ b/ui/components/app/connected-accounts-list/connected-accounts-list.component.js @@ -1,6 +1,15 @@ import PropTypes from 'prop-types'; import React, { PureComponent } from 'react'; -import { IconName } from '../../component-library'; +import { + BackgroundColor, + TextVariant, +} from '../../../helpers/constants/design-system'; +import { + ButtonLink, + ButtonLinkSize, + IconName, + Text, +} from '../../component-library'; import { MenuItem } from '../../ui/menu'; import ConnectedAccountsListItem from './connected-accounts-list-item'; import ConnectedAccountsListOptions from './connected-accounts-list-options'; @@ -80,16 +89,20 @@ export default class ConnectedAccountsList extends PureComponent { return ( connectAccount(accountToConnect.address)} - > - {t('connect')} - + + connectAccount(accountToConnect.address)} + size={ButtonLinkSize.Inherit} + > + {t('connect')} + + } /> ); @@ -116,12 +129,15 @@ export default class ConnectedAccountsList extends PureComponent { const { t } = this.context; return ( - this.switchAccount(address)} - > - {t('switchToThisAccount')} - + + this.switchAccount(address)} + size={ButtonLinkSize.Inherit} + > + {t('switchToThisAccount')} + + ); } @@ -139,7 +155,7 @@ export default class ConnectedAccountsList extends PureComponent { { const t = useI18nContext(); @@ -29,47 +44,60 @@ const ConnectedAccountsPermissions = ({ permissions }) => { ); return ( -
-

+ - {t('permissions')} -

+ + {expanded ? ( + + + {t('authorizedPermissions')}: + +
    + {permissionLabels.map(({ label }, idx) => ( +
  • + +
  • + ))} +
+
+ ) : null} + ); }; diff --git a/ui/components/app/connected-accounts-permissions/index.scss b/ui/components/app/connected-accounts-permissions/index.scss index 6e9ff8dc7c5b..9bf85e0780cb 100644 --- a/ui/components/app/connected-accounts-permissions/index.scss +++ b/ui/components/app/connected-accounts-permissions/index.scss @@ -1,37 +1,4 @@ .connected-accounts-permissions { - @include H7; - - display: flex; - flex-direction: column; - color: var(--color-text-alternative); - - strong { - font-weight: bold; - } - - p + p { - padding-top: 8px; - } - - &__header { - @include H6; - - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; - cursor: pointer; - color: var(--color-text-default); - - button { - font-size: $font-size-paragraph; - background: none; - padding: 0; - margin-left: 8px; - color: var(--color-icon-default); - } - } - &__list { padding-block: 8px; height: 100%; diff --git a/ui/components/app/connected-sites-list/connected-snaps.js b/ui/components/app/connected-sites-list/connected-snaps.js new file mode 100644 index 000000000000..30e6fcfb48ad --- /dev/null +++ b/ui/components/app/connected-sites-list/connected-snaps.js @@ -0,0 +1,140 @@ +import React, { useState } from 'react'; +import PropTypes from 'prop-types'; +import { useHistory } from 'react-router-dom'; +import { WALLET_SNAP_PERMISSION_KEY } from '@metamask/snaps-utils'; +import { useDispatch, useSelector } from 'react-redux'; +import { SnapCaveatType } from '@metamask/rpc-methods'; +import { Box, IconName, IconSize, Text } from '../../component-library'; +import { useI18nContext } from '../../../hooks/useI18nContext'; +import { MenuItem } from '../../ui/menu'; +import { SNAPS_VIEW_ROUTE } from '../../../helpers/constants/routes'; +import SnapAvatar from '../snaps/snap-avatar'; +import { + AlignItems, + BlockSize, + Display, + FlexDirection, + JustifyContent, + TextVariant, +} from '../../../helpers/constants/design-system'; +import ConnectedAccountsListOptions from '../connected-accounts-list/connected-accounts-list-options'; +import { + getOriginOfCurrentTab, + getPermissionSubjects, +} from '../../../selectors'; +import { removePermissionsFor, updateCaveat } from '../../../store/actions'; + +export default function ConnectedSnaps({ connectedSubjects }) { + const [showOptions, setShowOptions] = useState(); + const t = useI18nContext(); + const history = useHistory(); + const dispatch = useDispatch(); + const subjects = useSelector(getPermissionSubjects); + const connectedOrigin = useSelector(getOriginOfCurrentTab); + + const onDisconnect = (snapId) => { + const caveatValue = + subjects[connectedOrigin].permissions[WALLET_SNAP_PERMISSION_KEY] + .caveats[0].value; + const newCaveatValue = { ...caveatValue }; + delete newCaveatValue[snapId]; + if (Object.keys(newCaveatValue).length > 0) { + dispatch( + updateCaveat( + connectedOrigin, + WALLET_SNAP_PERMISSION_KEY, + SnapCaveatType.SnapIds, + newCaveatValue, + ), + ); + } else { + dispatch( + removePermissionsFor({ + [connectedOrigin]: [WALLET_SNAP_PERMISSION_KEY], + }), + ); + } + }; + + const renderListItemOptions = (snapId) => { + return ( + setShowOptions()} + onShowOptions={() => setShowOptions(snapId)} + show={showOptions === snapId} + > + { + e.preventDefault(); + onDisconnect(snapId); + }} + > + {t('disconnect')} + + + history.push(`${SNAPS_VIEW_ROUTE}/${encodeURIComponent(snapId)}`) + } + > + {t('snapsSettings')} + + + ); + }; + + return ( + + {connectedSubjects.map((subject) => ( + + + + + {subject.name} + + + {renderListItemOptions(subject.origin)} + + ))} + + ); +} + +ConnectedSnaps.propTypes = { + /** + * Shape of ConnectedSnaps + */ + connectedSubjects: PropTypes.arrayOf( + PropTypes.shape({ + /** + * It should have a name for Snap + */ + name: PropTypes.string, + /** + * Origin of connected subject, in case of snaps it's snapId + */ + origin: PropTypes.string, + }), + ).isRequired, +}; diff --git a/ui/components/app/connected-sites-list/index.scss b/ui/components/app/connected-sites-list/index.scss index 7df824c5f9ad..01129de154c3 100644 --- a/ui/components/app/connected-sites-list/index.scss +++ b/ui/components/app/connected-sites-list/index.scss @@ -11,7 +11,6 @@ flex-direction: row; justify-content: space-between; align-items: center; - border-top: 1px solid var(--color-border-muted); padding: 16px 24px; & &-link-button { diff --git a/ui/components/app/connected-status-indicator/connected-status-indicator.js b/ui/components/app/connected-status-indicator/connected-status-indicator.js index c1a4eae402f0..991420145af9 100644 --- a/ui/components/app/connected-status-indicator/connected-status-indicator.js +++ b/ui/components/app/connected-status-indicator/connected-status-indicator.js @@ -2,9 +2,11 @@ import React from 'react'; import PropTypes from 'prop-types'; import { useSelector } from 'react-redux'; import { findKey } from 'lodash'; +import { WALLET_SNAP_PERMISSION_KEY } from '@metamask/snaps-utils'; import { STATUS_CONNECTED, STATUS_CONNECTED_TO_ANOTHER_ACCOUNT, + STATUS_CONNECTED_TO_SNAP, STATUS_NOT_CONNECTED, } from '../../../helpers/constants/connected-sites'; import { @@ -15,6 +17,7 @@ import { useI18nContext } from '../../../hooks/useI18nContext'; import { getAddressConnectedSubjectMap, getOriginOfCurrentTab, + getPermissionsForActiveTab, getSelectedAddress, } from '../../../selectors'; import { ConnectedSiteMenu } from '../../multichain'; @@ -23,6 +26,13 @@ export default function ConnectedStatusIndicator({ onClick }) { const t = useI18nContext(); const selectedAddress = useSelector(getSelectedAddress); + + const permissionsForActiveTab = useSelector(getPermissionsForActiveTab); + + const activeWalletSnap = permissionsForActiveTab + .map((permission) => permission.key) + .includes(WALLET_SNAP_PERMISSION_KEY); + const addressConnectedSubjectMap = useSelector(getAddressConnectedSubjectMap); const originOfCurrentTab = useSelector(getOriginOfCurrentTab); @@ -35,6 +45,8 @@ export default function ConnectedStatusIndicator({ onClick }) { status = STATUS_CONNECTED; } else if (findKey(addressConnectedSubjectMap, originOfCurrentTab)) { status = STATUS_CONNECTED_TO_ANOTHER_ACCOUNT; + } else if (activeWalletSnap) { + status = STATUS_CONNECTED_TO_SNAP; } else { status = STATUS_NOT_CONNECTED; } @@ -42,7 +54,10 @@ export default function ConnectedStatusIndicator({ onClick }) { let globalMenuColor = Color.iconAlternative; if (status === STATUS_CONNECTED) { globalMenuColor = Color.successDefault; - } else if (status === STATUS_CONNECTED_TO_ANOTHER_ACCOUNT) { + } else if ( + status === STATUS_CONNECTED_TO_ANOTHER_ACCOUNT || + status === STATUS_CONNECTED_TO_SNAP + ) { globalMenuColor = BackgroundColor.backgroundDefault; } diff --git a/ui/components/app/detected-token/detected-token-address/detected-token-address.test.js b/ui/components/app/detected-token/detected-token-address/detected-token-address.test.js index de3fc18d6cfc..cf7c0bade7b6 100644 --- a/ui/components/app/detected-token/detected-token-address/detected-token-address.test.js +++ b/ui/components/app/detected-token/detected-token-address/detected-token-address.test.js @@ -14,6 +14,6 @@ describe('DetectedTokenAddress', () => { renderWithProvider(, store); expect(screen.getByText('Token address:')).toBeInTheDocument(); - expect(screen.getByText('0xc01...2a6f')).toBeInTheDocument(); + expect(screen.getByText('0xc011a...f2a6f')).toBeInTheDocument(); }); }); diff --git a/ui/components/app/detected-token/detected-token-details/detected-token-details.test.js b/ui/components/app/detected-token/detected-token-details/detected-token-details.test.js index f767d560fb2e..1c15944445fb 100644 --- a/ui/components/app/detected-token/detected-token-details/detected-token-details.test.js +++ b/ui/components/app/detected-token/detected-token-details/detected-token-details.test.js @@ -80,7 +80,7 @@ describe('DetectedTokenDetails', () => { expect(screen.getByText('0 SNX')).toBeInTheDocument(); expect(screen.getByText('$0')).toBeInTheDocument(); expect(screen.getByText('Token address:')).toBeInTheDocument(); - expect(screen.getByText('0xc01...2a6f')).toBeInTheDocument(); + expect(screen.getByText('0xc011a...f2a6f')).toBeInTheDocument(); expect(screen.getByText('From token lists:')).toBeInTheDocument(); expect(screen.getByText('Aave, Bancor')).toBeInTheDocument(); expect(screen.getByText('+ 10 more')).toBeInTheDocument(); diff --git a/ui/components/app/detected-token/detected-token.test.js b/ui/components/app/detected-token/detected-token.test.js index 34358ffbbd1b..b6cf8ad0ed21 100644 --- a/ui/components/app/detected-token/detected-token.test.js +++ b/ui/components/app/detected-token/detected-token.test.js @@ -19,9 +19,9 @@ describe('DetectedToken', () => { expect(screen.getByText('0 FSW')).toBeInTheDocument(); expect(screen.getAllByText('$0')).toHaveLength(3); expect(screen.getAllByText('Token address:')).toHaveLength(3); - expect(screen.getByText('0x514...86CA')).toBeInTheDocument(); - expect(screen.getByText('0xc00...6888')).toBeInTheDocument(); - expect(screen.getByText('0xfff...26DB')).toBeInTheDocument(); + expect(screen.getByText('0x51491...986CA')).toBeInTheDocument(); + expect(screen.getByText('0xc00e9...26888')).toBeInTheDocument(); + expect(screen.getByText('0xfffff...126DB')).toBeInTheDocument(); expect(screen.getAllByText('From token lists:')).toHaveLength(3); expect(screen.getByText('Aave, Bancor')).toBeInTheDocument(); expect(screen.getByText('+ 9 more')).toBeInTheDocument(); diff --git a/ui/components/app/incoming-trasaction-toggle/__snapshots__/incoming-transaction-toggle.test.js.snap b/ui/components/app/incoming-trasaction-toggle/__snapshots__/incoming-transaction-toggle.test.js.snap index fafe28db8982..0113330cccdd 100644 --- a/ui/components/app/incoming-trasaction-toggle/__snapshots__/incoming-transaction-toggle.test.js.snap +++ b/ui/components/app/incoming-trasaction-toggle/__snapshots__/incoming-transaction-toggle.test.js.snap @@ -6,7 +6,7 @@ exports[`IncomingTransactionToggle should render existing incoming transaction p class="mm-box mm-incoming-transaction-toggle" >

Show incoming transactions

@@ -15,61 +15,6 @@ exports[`IncomingTransactionToggle should render existing incoming transaction p > This relies on different third-party APIs for each network, which expose your Ethereum address and your IP address.

-
-

- Enable for all networks -

-