diff --git a/.circleci/config.yml b/.circleci/config.yml index 091dbdf6189e..5ab0af8fb0cc 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -45,6 +45,14 @@ rc_branch_only: &rc_branch_only only: - /^Version-v(\d+)[.](\d+)[.](\d+)/ +develop_master_rc_only: &develop_master_rc_only + filters: + branches: + only: + - develop + - master + - /^Version-v(\d+)[.](\d+)[.](\d+)/ + aliases: # Shallow Git Clone - &shallow-git-clone @@ -143,12 +151,14 @@ workflows: requires: - prep-deps - prep-build-confirmation-redesign-test-mv2: + <<: *develop_master_rc_only requires: - prep-deps - prep-build-test-flask: requires: - prep-deps - prep-build-test-flask-mv2: + <<: *develop_master_rc_only requires: - prep-deps - prep-build-test-mmi: @@ -184,11 +194,15 @@ workflows: requires: - prep-build-test-mv2 - test-e2e-firefox-confirmation-redesign: + <<: *develop_master_rc_only requires: - prep-build-confirmation-redesign-test-mv2 - test-e2e-chrome-rpc: requires: - prep-build-test + - test-api-specs: + requires: + - prep-build-test - test-e2e-chrome-multiple-providers: requires: - prep-build-test @@ -196,6 +210,7 @@ workflows: requires: - prep-build-test-flask - test-e2e-firefox-flask: + <<: *develop_master_rc_only requires: - prep-build-test-flask-mv2 - test-e2e-chrome-mmi: @@ -221,7 +236,7 @@ workflows: - test-unit-jest-development: requires: - prep-deps - - upload-and-validate-coverage: + - upload-coverage: requires: - test-unit-jest-main - test-unit-jest-development @@ -271,7 +286,7 @@ workflows: - test-unit-jest-main - test-unit-jest-development - test-unit-global - - upload-and-validate-coverage + - upload-coverage - validate-source-maps - validate-source-maps-beta - validate-source-maps-flask @@ -1036,6 +1051,38 @@ jobs: name: depcheck command: yarn depcheck + test-api-specs: + executor: node-browsers-medium-plus + steps: + - run: *shallow-git-clone + - run: sudo corepack enable + - attach_workspace: + at: . + - run: + name: Move test build to dist + command: mv ./dist-test ./dist + - run: + name: Move test zips to builds + command: mv ./builds-test ./builds + - gh/install + - run: + name: test:api-specs + command: | + timeout 20m yarn test:api-specs --retries 2 + no_output_timeout: 5m + - run: + name: Comment on PR + command: | + if [ -f html-report/index.html ]; then + gh pr comment "${CIRCLE_PR_NUMBER}" --body ":x: API Spec Test Failed. View the report [here](https://output.circle-artifacts.com/output/job/${CIRCLE_WORKFLOW_JOB_ID}/artifacts/${CIRCLE_NODE_INDEX}/html-report/index.html)." + else + echo "API Spec Report not found!" + fi + when: on_fail + - store_artifacts: + path: html-report + destination: html-report + test-e2e-chrome: executor: node-browsers-medium-plus parallelism: 20 @@ -1630,7 +1677,7 @@ jobs: - store_test_results: path: test/test-results/junit.xml - upload-and-validate-coverage: + upload-coverage: executor: node-browsers-small steps: - run: *shallow-git-clone @@ -1638,9 +1685,6 @@ jobs: - attach_workspace: at: . - codecov/upload - - run: - name: test:coverage:validate - command: yarn test:coverage:validate - persist_to_workspace: root: . paths: diff --git a/.depcheckrc.yml b/.depcheckrc.yml index f2f9b37fd563..e4169c5436f0 100644 --- a/.depcheckrc.yml +++ b/.depcheckrc.yml @@ -39,8 +39,6 @@ ignores: - 'wait-on' - 'tsx' # used in .devcontainer - 'prettier-eslint' # used by the Prettier ESLint VSCode extension - # development tool - - 'nyc' # storybook - '@storybook/cli' - '@storybook/core' diff --git a/.eslintrc.js b/.eslintrc.js index 2fa4b8cf9846..9f7fed5928ed 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -46,9 +46,7 @@ module.exports = { 'development/**/*.js', 'test/e2e/**/*.js', 'test/helpers/*.js', - 'test/lib/wait-until-called.js', 'test/run-unit-tests.js', - 'test/merge-coverage.js', ], extends: [ path.resolve(__dirname, '.eslintrc.base.js'), @@ -94,8 +92,6 @@ module.exports = { 'test/stub/**/*.js', 'test/unit-global/**/*.js', ], - // TODO: Convert these files to modern JS - excludedFiles: ['test/lib/wait-until-called.js'], extends: [ path.resolve(__dirname, '.eslintrc.base.js'), path.resolve(__dirname, '.eslintrc.node.js'), @@ -261,30 +257,7 @@ module.exports = { * Mocha library. */ { - files: [ - '**/*.test.js', - 'test/lib/wait-until-called.js', - 'test/e2e/**/*.spec.js', - ], - excludedFiles: [ - 'app/scripts/controllers/app-state.test.js', - 'app/scripts/controllers/mmi-controller.test.js', - 'app/scripts/metamask-controller.actions.test.js', - 'app/scripts/detect-multiple-instances.test.js', - 'app/scripts/controllers/swaps.test.js', - 'app/scripts/controllers/metametrics.test.js', - 'app/scripts/controllers/permissions/**/*.test.js', - 'app/scripts/controllers/preferences.test.js', - 'app/scripts/lib/**/*.test.js', - 'app/scripts/metamask-controller.test.js', - 'app/scripts/migrations/*.test.js', - 'app/scripts/platforms/*.test.js', - 'development/**/*.test.js', - 'shared/**/*.test.js', - 'ui/**/*.test.js', - 'ui/__mocks__/*.js', - 'test/e2e/helpers.test.js', - ], + files: ['test/e2e/**/*.spec.js', 'test/unit-global/*.test.js'], extends: ['@metamask/eslint-config-mocha'], rules: { // In Mocha tests, it is common to use `this` to store values or do @@ -297,7 +270,9 @@ module.exports = { * Jest tests * * These are files that make use of globals and syntax introduced by the - * Jest library. The files in this section should match the Mocha excludedFiles section. + * Jest library. + * TODO: This list of files is incomplete, and should be replaced with globs that match the + * Jest config. */ { files: [ @@ -391,7 +366,6 @@ module.exports = { 'test/e2e/benchmark.js', 'test/helpers/setup-helper.js', 'test/run-unit-tests.js', - 'test/merge-coverage.js', ], rules: { 'node/no-process-exit': 'off', diff --git a/.gitignore b/.gitignore index d182260bfa8d..4f2d481b8807 100644 --- a/.gitignore +++ b/.gitignore @@ -75,3 +75,7 @@ lavamoat/**/policy-debug.json # Attributions licenseInfos.json + +# API Spec tests +html-report/ + diff --git a/.mocharc.js b/.mocharc.js index 890fca78e6b9..ff6200513b96 100644 --- a/.mocharc.js +++ b/.mocharc.js @@ -1,23 +1,6 @@ module.exports = { // TODO: Remove the `exit` setting, it can hide broken tests. exit: true, - ignore: [ - './app/scripts/lib/**/*.test.js', - './app/scripts/migrations/*.test.js', - './app/scripts/platforms/*.test.js', - './app/scripts/controllers/app-state.test.js', - './app/scripts/controllers/permissions/**/*.test.js', - './app/scripts/controllers/mmi-controller.test.ts', - './app/scripts/metamask-controller.actions.test.js', - './app/scripts/detect-multiple-instances.test.js', - './app/scripts/controllers/swaps.test.js', - './app/scripts/controllers/metametrics.test.js', - './app/scripts/controllers/preferences.test.js', - './app/scripts/constants/error-utils.test.js', - './app/scripts/metamask-controller.test.js', - './development/fitness-functions/**/*.test.ts', - './test/e2e/helpers.test.js', - ], recursive: true, require: ['test/env.js', 'test/setup.js'], }; diff --git a/.yarn/patches/@metamask-keyring-controller-npm-15.0.0-fa070ce311.patch b/.yarn/patches/@metamask-keyring-controller-npm-15.0.0-fa070ce311.patch deleted file mode 100644 index 27d866a74888..000000000000 --- a/.yarn/patches/@metamask-keyring-controller-npm-15.0.0-fa070ce311.patch +++ /dev/null @@ -1,120 +0,0 @@ -diff --git a/dist/chunk-52QZQQKP.mjs b/dist/chunk-52QZQQKP.mjs -index 934f432c8013a6af5303726e1495bed2335fa078..8de2560fe81dfc3dbfef83dd0079482306c425d9 100644 ---- a/dist/chunk-52QZQQKP.mjs -+++ b/dist/chunk-52QZQQKP.mjs -@@ -2,7 +2,8 @@ import { - __privateAdd, - __privateGet, - __privateMethod, -- __privateSet -+ __privateSet, -+ KeyringControllerError - } from "./chunk-NAAWD7HX.mjs"; - - // src/KeyringController.ts -@@ -582,6 +583,18 @@ var KeyringController = class extends BaseController { - }) - ); - serializedKeyrings.push(...__privateGet(this, _unsupportedKeyrings)); -+ /** -+ * ============================== PATCH INFORMATION ============================== -+ * The HD keyring is the default keyring for all wallets if this keyring is missing -+ * for some reason we should avoid saving the keyrings -+ * -+ * The upstream fix is here: https://github.com/MetaMask/core/pull/4168 -+ * -+ * This patch can be found on the core branch `extension-keyring-controller-v13-patch` -+ */ -+ if (!serializedKeyrings.some((keyring) => keyring.type === KeyringTypes.hd)) { -+ throw new Error(KeyringControllerError.NoHdKeyring); -+ } - let vault; - let newEncryptionKey; - if (__privateGet(this, _cacheEncryptionKey)) { -@@ -1087,9 +1100,16 @@ getKeyringBuilderForType_fn = function(type) { - }; - _addQRKeyring = new WeakSet(); - addQRKeyring_fn = async function() { -- const qrKeyring = await __privateMethod(this, _newKeyring, newKeyring_fn).call(this, "QR Hardware Wallet Device" /* qr */, { -- accounts: [] -- }); -+ /** -+ * Patch for @metamask/keyring-controller v13.0.0 -+ * Below code change will fix the issue 23804, The intial code added a empty accounts as argument when creating a new QR keyring. -+ * cause the new Keystone MetamaskKeyring default properties all are undefined during deserialise() process. -+ * Please refer to PR 23903 for detail. -+ * -+ * This patch can be found on the core branch `extension-keyring-controller-v13-patch` -+ */ -+ // @ts-expect-error See patch note -+ const qrKeyring = await __privateMethod(this, _newKeyring, newKeyring_fn).call(this, "QR Hardware Wallet Device"); - const accounts = await qrKeyring.getAccounts(); - await __privateMethod(this, _checkForDuplicate, checkForDuplicate_fn).call(this, "QR Hardware Wallet Device" /* qr */, accounts); - __privateGet(this, _keyrings).push(qrKeyring); -diff --git a/dist/chunk-CHLPTPMZ.js b/dist/chunk-CHLPTPMZ.js -index bef1a8e9dd5efe426f8aaaba1fe4501b124f7e87..7b48c000e54708da2a689e2d6cb1b61a279f1205 100644 ---- a/dist/chunk-CHLPTPMZ.js -+++ b/dist/chunk-CHLPTPMZ.js -@@ -50,6 +50,7 @@ var KeyringControllerError = /* @__PURE__ */ ((KeyringControllerError2) => { - KeyringControllerError2["ExpiredCredentials"] = "KeyringController - Encryption key and salt provided are expired"; - KeyringControllerError2["NoKeyringBuilder"] = "KeyringController - No keyringBuilder found for keyring"; - KeyringControllerError2["DataType"] = "KeyringController - Incorrect data type provided"; -+ KeyringControllerError2["NoHdKeyring"] = "KeyringController - No HD Keyring found"; - return KeyringControllerError2; - })(KeyringControllerError || {}); - -diff --git a/dist/chunk-GXM4O6HW.js b/dist/chunk-GXM4O6HW.js -index f7539e2e6354f418cbb095cc1a2cda01a5bdeae6..978f4426536c594568ecc56f1c27881db4bfa861 100644 ---- a/dist/chunk-GXM4O6HW.js -+++ b/dist/chunk-GXM4O6HW.js -@@ -582,6 +582,18 @@ var KeyringController = class extends _basecontroller.BaseController { - }) - ); - serializedKeyrings.push(..._chunkCHLPTPMZjs.__privateGet.call(void 0, this, _unsupportedKeyrings)); -+ /** -+ * ============================== PATCH INFORMATION ============================== -+ * The HD keyring is the default keyring for all wallets if this keyring is missing -+ * for some reason we should avoid saving the keyrings -+ * -+ * The upstream fix is here: https://github.com/MetaMask/core/pull/4168 -+ * -+ * This patch can be found on the core branch `extension-keyring-controller-v13-patch` -+ */ -+ if (!serializedKeyrings.some((keyring) => keyring.type === KeyringTypes.hd)) { -+ throw new Error(_chunkCHLPTPMZjs.KeyringControllerError.NoHdKeyring); -+ } - let vault; - let newEncryptionKey; - if (_chunkCHLPTPMZjs.__privateGet.call(void 0, this, _cacheEncryptionKey)) { -@@ -1087,9 +1099,16 @@ getKeyringBuilderForType_fn = function(type) { - }; - _addQRKeyring = new WeakSet(); - addQRKeyring_fn = async function() { -- const qrKeyring = await _chunkCHLPTPMZjs.__privateMethod.call(void 0, this, _newKeyring, newKeyring_fn).call(this, "QR Hardware Wallet Device" /* qr */, { -- accounts: [] -- }); -+ /** -+ * Patch for @metamask/keyring-controller v13.0.0 -+ * Below code change will fix the issue 23804, The intial code added a empty accounts as argument when creating a new QR keyring. -+ * cause the new Keystone MetamaskKeyring default properties all are undefined during deserialise() process. -+ * Please refer to PR 23903 for detail. -+ * -+ * This patch can be found on the core branch `extension-keyring-controller-v13-patch` -+ */ -+ // @ts-expect-error See patch note -+ const qrKeyring = await _chunkCHLPTPMZjs.__privateMethod.call(void 0, this, _newKeyring, newKeyring_fn).call(this, "QR Hardware Wallet Device"); - const accounts = await qrKeyring.getAccounts(); - await _chunkCHLPTPMZjs.__privateMethod.call(void 0, this, _checkForDuplicate, checkForDuplicate_fn).call(this, "QR Hardware Wallet Device" /* qr */, accounts); - _chunkCHLPTPMZjs.__privateGet.call(void 0, this, _keyrings).push(qrKeyring); -diff --git a/dist/chunk-NAAWD7HX.mjs b/dist/chunk-NAAWD7HX.mjs -index b5de23aabec9d502e8e6423480ffaaff26257bfc..a0c027a7c13828883ec5c05cbb7eab92c41f0dc3 100644 ---- a/dist/chunk-NAAWD7HX.mjs -+++ b/dist/chunk-NAAWD7HX.mjs -@@ -50,6 +50,7 @@ var KeyringControllerError = /* @__PURE__ */ ((KeyringControllerError2) => { - KeyringControllerError2["ExpiredCredentials"] = "KeyringController - Encryption key and salt provided are expired"; - KeyringControllerError2["NoKeyringBuilder"] = "KeyringController - No keyringBuilder found for keyring"; - KeyringControllerError2["DataType"] = "KeyringController - Incorrect data type provided"; -+ KeyringControllerError2["NoHdKeyring"] = "KeyringController - No HD Keyring found"; - return KeyringControllerError2; - })(KeyringControllerError || {}); - diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index 32affca2e5d6..731a805b1f2a 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -3209,24 +3209,12 @@ "onboardingMetametricsAgree": { "message": "Ich stimme zu" }, - "onboardingMetametricsAllowOptOutLegacy": { - "message": "Erlaubt Ihnen immer die Abmeldung über Einstellungen" - }, - "onboardingMetametricsDataTermsLegacy": { - "message": "Diese Daten werden gesammelt und sind daher im Rahmen der Datenschutz-Grundverordnung (EU) 2016/679 anonym." - }, "onboardingMetametricsDescription": { "message": "Wir würden gerne grundlegende Nutzungs- und Diagnosedaten sammeln, um MetaMask zu verbessern. Sie sollten wissen, dass wir die Daten, die Sie uns hier zur Verfügung stellen, niemals verkaufen." }, "onboardingMetametricsDescription2": { "message": "Wenn wir Metriken sammeln, wird es immer wie folgt sein ..." }, - "onboardingMetametricsDescription2Legacy": { - "message": "MetaMask wird ..." - }, - "onboardingMetametricsDescriptionLegacy": { - "message": "MetaMask möchte Nutzungsdaten sammeln, um ein besseres Verständnis zu erhalten, wie unsere Nutzer mit MetaMask interagieren. Diese Daten werden verwendet, um Dienste anzubieten, was auf Ihrer Nutzung basierte Dienstverbesserungen einschließt." - }, "onboardingMetametricsDisagree": { "message": "Nein, danke!" }, @@ -3234,19 +3222,9 @@ "message": "Wir werden Sie informieren, wenn wir beschließen, diese Daten für andere Zwecke zu verwenden. Für weitere Informationen können Sie unsere $1 einsehen. Vergessen Sie nicht, dass Sie jederzeit zu Einstellungen gehen und sich abmelden können.", "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, - "onboardingMetametricsInfuraTermsLegacy": { - "message": "*Wenn Sie Infura als Standard-RPC-Anbieter in MetaMask vewenden, speichert Infura Ihre IP-Adresse und Ihre Etherum-Wallet-Adresse, wenn Sie eine Transaktion senden. Wir speichern diese Daten in keinster Weise in unserem System, um sie miteinander in Verbindung zu bringen. Für weitere Informationen darüber, wie MetaMask und Infura in Hinischt auf Datenspeicherung zusammenarbeiten, sehen Sie sich bitte unser Update $1 an. Für mehr Informationen bezüglich unseren allgemeinen Datenschutzpraktiken, sehen Sie sich bitte unsere $2 an.", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" - }, "onboardingMetametricsInfuraTermsPolicy": { "message": "Datenschutzrichtlinie" }, - "onboardingMetametricsInfuraTermsPolicyLegacy": { - "message": "Datenschutzerklärung hier" - }, - "onboardingMetametricsInfuraTermsPolicyLinkLegacy": { - "message": "hier" - }, "onboardingMetametricsModalTitle": { "message": "Benutzerdefiniertes Netzwerk hinzufügen" }, @@ -3264,17 +3242,6 @@ "onboardingMetametricsNeverCollectIPEmphasis": { "message": "Allgemein:" }, - "onboardingMetametricsNeverCollectIPLegacy": { - "message": "$1 speichert Ihre vollständige IP-Adresse*", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverCollectLegacy": { - "message": "$1 speichert Daten, die wir nicht benötigen, um die Dienstleistung zur Verfügung zu stellen (wie zum Beispiel Schlüssel, Adresse, Transaktions-Hashs oder Guthaben)", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverEmphasisLegacy": { - "message": "Nie" - }, "onboardingMetametricsNeverSellData": { "message": "$1 Sie können jederzeit über die Einstellungen entscheiden, ob Sie Ihre Nutzungsdaten freigeben oder löschen möchten.", "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" @@ -3282,13 +3249,6 @@ "onboardingMetametricsNeverSellDataEmphasis": { "message": "Optional:" }, - "onboardingMetametricsNeverSellDataLegacy": { - "message": "$1 Daten verkaufen. Niemals!", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsSendAnonymizeLegacy": { - "message": "Anonymisierte Ereignisse für Klicks und Seitenaufrufe senden" - }, "onboardingMetametricsTitle": { "message": "Helfen Sie uns, MetaMask zu verbessern." }, diff --git a/app/_locales/el/messages.json b/app/_locales/el/messages.json index 57366b6653de..cfbe0bd874dd 100644 --- a/app/_locales/el/messages.json +++ b/app/_locales/el/messages.json @@ -3209,24 +3209,12 @@ "onboardingMetametricsAgree": { "message": "Συμφωνώ" }, - "onboardingMetametricsAllowOptOutLegacy": { - "message": "Σας επιτρέπεται πάντα να εξαιρεθείτε μέσω των Ρυθμίσεων" - }, - "onboardingMetametricsDataTermsLegacy": { - "message": "Τα δεδομένα αυτά είναι συγκεντρωτικά και συνεπώς ανώνυμα για τους σκοπούς του Γενικού Κανονισμού για την Προστασία Δεδομένων (ΕΕ) 2016/679." - }, "onboardingMetametricsDescription": { "message": "Θέλουμε να συλλέξουμε βασικά δεδομένα χρήσης και διάγνωσης για να βελτιώσουμε το MetaMask. Λάβετε υπόψη ότι δεν πουλάμε ποτέ τα δεδομένα που μας παρέχετε εδώ." }, "onboardingMetametricsDescription2": { "message": "Όταν συγκεντρώνουμε μετρήσεις, θα είναι πάντα..." }, - "onboardingMetametricsDescription2Legacy": { - "message": "Το MetaMask θα..." - }, - "onboardingMetametricsDescriptionLegacy": { - "message": "Το MetaMask θα ήθελε να συλλέγει δεδομένα χρήσης για να κατανοήσει καλύτερα τον τρόπο με τον οποίο οι χρήστες μας αλληλεπιδρούν με το MetaMask. Τα δεδομένα αυτά θα χρησιμοποιηθούν για την παροχή της υπηρεσίας, η οποία περιλαμβάνει τη βελτίωση της υπηρεσίας με βάση τη χρήση σας." - }, "onboardingMetametricsDisagree": { "message": "Όχι, ευχαριστώ" }, @@ -3234,19 +3222,9 @@ "message": "Θα σας ενημερώσουμε εάν αποφασίσουμε να χρησιμοποιήσουμε αυτά τα δεδομένα για άλλους σκοπούς. Για περισσότερες πληροφορίες, μπορείτε να ανατρέξετε στην $1. Να θυμάστε ότι μπορείτε να μεταβείτε στις ρυθμίσεις και να εξαιρεθείτε ανά πάσα στιγμή.", "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, - "onboardingMetametricsInfuraTermsLegacy": { - "message": "* Όταν χρησιμοποιείτε την Infura ως τον προεπιλεγμένο πάροχο RPC στο MetaMask, η Infura θα συλλέγει τη διεύθυνση IP σας και τη διεύθυνση του πορτοφολιού σας στο Ethereum όταν αποστέλλετε μια συναλλαγή. Δεν αποθηκεύουμε αυτές τις πληροφορίες με τρόπο που να επιτρέπει στα συστήματά μας να συσχετίζουν αυτά τα δύο δεδομένα. Για περισσότερες πληροφορίες σχετικά με τον τρόπο με τον οποίο αλληλεπιδρούν το MetaMask και η Infura από την πλευρά της συλλογής δεδομένων, δείτε την ενημέρωσή μας $1. Για περισσότερες πληροφορίες σχετικά με τις πρακτικές απορρήτου μας γενικά, δείτε την ενημέρωσή μας $2.", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" - }, "onboardingMetametricsInfuraTermsPolicy": { "message": "Πολιτική Απορρήτου" }, - "onboardingMetametricsInfuraTermsPolicyLegacy": { - "message": "Πολιτική Απορρήτου εδώ" - }, - "onboardingMetametricsInfuraTermsPolicyLinkLegacy": { - "message": "εδώ" - }, "onboardingMetametricsModalTitle": { "message": "Προσθήκη προσαρμοσμένου δικτύου" }, @@ -3264,17 +3242,6 @@ "onboardingMetametricsNeverCollectIPEmphasis": { "message": "Γενικές:" }, - "onboardingMetametricsNeverCollectIPLegacy": { - "message": "To $1 συλλέγει την πλήρη διεύθυνση IP σας*", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverCollectLegacy": { - "message": "To $1 συλλέγει πληροφορίες που δεν χρειαζόμαστε για την παροχή της υπηρεσίας (όπως κλειδιά, διευθύνσεις, αναλύσεις συναλλαγών ή υπόλοιπα)", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverEmphasisLegacy": { - "message": "Ποτέ" - }, "onboardingMetametricsNeverSellData": { "message": "$1 εσείς αποφασίζετε αν θέλετε να κοινοποιήσετε ή να διαγράψετε τα δεδομένα χρήσης σας μέσω των ρυθμίσεων ανά πάσα στιγμή.", "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" @@ -3282,13 +3249,6 @@ "onboardingMetametricsNeverSellDataEmphasis": { "message": "Προαιρετικές:" }, - "onboardingMetametricsNeverSellDataLegacy": { - "message": "To $1 πουλάει δεδομένα. Ποτέ!", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsSendAnonymizeLegacy": { - "message": "Αποστολή ανώνυμων συμβάντων κλικ και προβολής ιστοσελίδων" - }, "onboardingMetametricsTitle": { "message": "Βοηθήστε μας να βελτιώσουμε το MetaMask" }, diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 814a31bdca50..a7573e179ef3 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -3438,24 +3438,12 @@ "onboardingMetametricsAgree": { "message": "I agree" }, - "onboardingMetametricsAllowOptOutLegacy": { - "message": "Always allow you to opt-out via Settings" - }, - "onboardingMetametricsDataTermsLegacy": { - "message": "This data is aggregated and is therefore anonymous for the purposes of General Data Protection Regulation (EU) 2016/679." - }, "onboardingMetametricsDescription": { "message": "We’d like to gather basic usage and diagnostics data to improve MetaMask. Know that we never sell the data you provide here." }, "onboardingMetametricsDescription2": { "message": "When we gather metrics, it will always be..." }, - "onboardingMetametricsDescription2Legacy": { - "message": "MetaMask will..." - }, - "onboardingMetametricsDescriptionLegacy": { - "message": "MetaMask would like to gather usage data to better understand how our users interact with MetaMask. This data will be used to provide the service, which includes improving the service based on your use." - }, "onboardingMetametricsDisagree": { "message": "No thanks" }, @@ -3463,19 +3451,9 @@ "message": "We’ll let you know if we decide to use this data for other purposes. You can review our $1 for more information. Remember, you can go to settings and opt out at any time.", "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, - "onboardingMetametricsInfuraTermsLegacy": { - "message": "* When you use Infura as your default RPC provider in MetaMask, Infura will collect your IP address and your Ethereum wallet address when you send a transaction. We don’t store this information in a way that allows our systems to associate those two pieces of data. For more information on how MetaMask and Infura interact from a data collection perspective, see our update $1. For more information on our privacy practices in general, see our $2.", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" - }, "onboardingMetametricsInfuraTermsPolicy": { "message": "Privacy Policy" }, - "onboardingMetametricsInfuraTermsPolicyLegacy": { - "message": "Privacy Policy here" - }, - "onboardingMetametricsInfuraTermsPolicyLinkLegacy": { - "message": "here" - }, "onboardingMetametricsModalTitle": { "message": "Add custom network" }, @@ -3493,17 +3471,6 @@ "onboardingMetametricsNeverCollectIPEmphasis": { "message": "General:" }, - "onboardingMetametricsNeverCollectIPLegacy": { - "message": "$1 collect your full IP address*", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverCollectLegacy": { - "message": "$1 collect information we don’t need to provide the service (such as keys, addresses, transaction hashes, or balances)", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverEmphasisLegacy": { - "message": "Never" - }, "onboardingMetametricsNeverSellData": { "message": "$1 you decide if you want to share or delete your usage data via settings any time.", "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" @@ -3511,13 +3478,6 @@ "onboardingMetametricsNeverSellDataEmphasis": { "message": "Optional:" }, - "onboardingMetametricsNeverSellDataLegacy": { - "message": "$1 sell data. Ever!", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsSendAnonymizeLegacy": { - "message": "Send anonymized click and pageview events" - }, "onboardingMetametricsTitle": { "message": "Help us improve MetaMask" }, diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index 02f7754a725b..f49efdbc7218 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -3206,24 +3206,12 @@ "onboardingMetametricsAgree": { "message": "Acepto" }, - "onboardingMetametricsAllowOptOutLegacy": { - "message": "Siempre le permitirá excluirse a través de la Configuración" - }, - "onboardingMetametricsDataTermsLegacy": { - "message": "Estos datos se agrupan y, por lo tanto, son anónimos a los efectos del Reglamento general de protección de datos (UE) 2016/679." - }, "onboardingMetametricsDescription": { "message": "Nos gustaría recopilar datos básicos de uso y diagnóstico para mejorar MetaMask. Tenga presente que nunca venderemos los datos que nos proporcione aquí." }, "onboardingMetametricsDescription2": { "message": "Al recopilar métricas, siempre será..." }, - "onboardingMetametricsDescription2Legacy": { - "message": "MetaMask..." - }, - "onboardingMetametricsDescriptionLegacy": { - "message": "MetaMask quisiera recopilar datos de uso para comprender mejor cómo nuestros usuarios interactúan con MetaMask. Estos datos se utilizarán para proporcionar el servicio, lo que incluye mejorarlo en función de su uso." - }, "onboardingMetametricsDisagree": { "message": "No, gracias" }, @@ -3231,19 +3219,9 @@ "message": "Le informaremos si decidimos usar estos datos para otros fines. Puede consultar $1 para obtener más información. Recuerde que puede acceder a la configuración y excluirse en cualquier momento.", "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, - "onboardingMetametricsInfuraTermsLegacy": { - "message": "*Al utilizar Infura como su proveedor de RPC predeterminado en MetaMask, Infura recopilará su dirección IP y la dirección de su monedero de Ethereum cuando envíe una transacción. No almacenamos esta información de una manera que permita qie nuestros sistemas asocien esos dos datos. Para obtener más información sobre cómo interactúan MetaMask e Infura desde la perspectiva de la recopilación de datos, consulte nuestra actualización $1. Para obtener más información sobre nuestras prácticas de privacidad en general, consulte nuestra $2.", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" - }, "onboardingMetametricsInfuraTermsPolicy": { "message": "Política de privacidad" }, - "onboardingMetametricsInfuraTermsPolicyLegacy": { - "message": "Política de privacidad aquí" - }, - "onboardingMetametricsInfuraTermsPolicyLinkLegacy": { - "message": "aquí" - }, "onboardingMetametricsModalTitle": { "message": "Agregar red personalizada" }, @@ -3261,17 +3239,6 @@ "onboardingMetametricsNeverCollectIPEmphasis": { "message": "Generales:" }, - "onboardingMetametricsNeverCollectIPLegacy": { - "message": "$1 recopilará su dirección IP completa*", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverCollectLegacy": { - "message": "$1 recopilará información que no necesitamos para brindar el servicio (como claves, direcciones, hashes de transacciones o saldos)", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverEmphasisLegacy": { - "message": "Nunca" - }, "onboardingMetametricsNeverSellData": { "message": "$1 usted decide si desea compartir o eliminar sus datos de uso a través de la configuración en cualquier momento.", "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" @@ -3279,13 +3246,6 @@ "onboardingMetametricsNeverSellDataEmphasis": { "message": "Opcionales:" }, - "onboardingMetametricsNeverSellDataLegacy": { - "message": "$1 venderá datos. ¡Jamás!", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsSendAnonymizeLegacy": { - "message": "Enviará eventos de vistas de página y clics anónimos" - }, "onboardingMetametricsTitle": { "message": "Ayúdenos a mejorar MetaMask" }, diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index 0f6beff29ece..c44d687aeaf6 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -3209,24 +3209,12 @@ "onboardingMetametricsAgree": { "message": "J’accepte" }, - "onboardingMetametricsAllowOptOutLegacy": { - "message": "Vous pourrez toujours vous désinscrire depuis les Paramètres" - }, - "onboardingMetametricsDataTermsLegacy": { - "message": "Conformément au règlement général sur la protection des données (UE) 2016/679, ces données sont agrégées pour préserver l’anonymat des utilisateurs." - }, "onboardingMetametricsDescription": { "message": "Nous aimerions recueillir des données d’utilisation et de diagnostic de base afin d’améliorer MetaMask. Sachez que nous ne vendons jamais les données que vous nous fournissez ici." }, "onboardingMetametricsDescription2": { "message": "Lorsque nous recueillons des données, elles sont toujours…" }, - "onboardingMetametricsDescription2Legacy": { - "message": "MetaMask..." - }, - "onboardingMetametricsDescriptionLegacy": { - "message": "MetaMask souhaite recueillir des données d’utilisation afin de mieux comprendre comment les utilisateurs interagissent avec MetaMask. Ces données seront utilisées pour améliorer les services que nous proposons ainsi que l’expérience utilisateur." - }, "onboardingMetametricsDisagree": { "message": "Non merci" }, @@ -3234,19 +3222,9 @@ "message": "Nous vous informerons si nous décidons d’utiliser ces données à d’autres fins. Pour plus d’informations, vous pouvez consulter notre $1. N’oubliez pas que vous pouvez aller dans les paramètres et vous désinscrire à tout moment.", "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, - "onboardingMetametricsInfuraTermsLegacy": { - "message": "* Sachez que lorsque vous définissez Infura comme fournisseur de RPC par défaut dans MetaMask, votre adresse IP et l’adresse de votre portefeuille Ethereum seront communiquées à Infura pour valider les transactions. Ces données sont stockées séparément sur nos systèmes pour préserver l’anonymat des utilisateurs. Pour plus d’informations sur la façon dont MetaMask et Infura collectent les données, consultez nos dernières mises à jour $1. Pour plus d’informations, consultez notre $2.", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" - }, "onboardingMetametricsInfuraTermsPolicy": { "message": "Politique de confidentialité" }, - "onboardingMetametricsInfuraTermsPolicyLegacy": { - "message": "Politique de confidentialité ici" - }, - "onboardingMetametricsInfuraTermsPolicyLinkLegacy": { - "message": "ici" - }, "onboardingMetametricsModalTitle": { "message": "Ajouter un réseau personnalisé" }, @@ -3264,17 +3242,6 @@ "onboardingMetametricsNeverCollectIPEmphasis": { "message": "Général :" }, - "onboardingMetametricsNeverCollectIPLegacy": { - "message": "Nous ne collectons $1 l’intégralité de votre adresse IP*", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverCollectLegacy": { - "message": "Nous ne collectons $1 d’informations dont nous n’avons pas besoin pour fournir nos services (comme les clés, les adresses, les hachages de transactions ou les soldes)", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverEmphasisLegacy": { - "message": "Jamais" - }, "onboardingMetametricsNeverSellData": { "message": "$1 vous pouvez décider à tout moment de partager ou de supprimer vos données d’utilisation dans les paramètres.", "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" @@ -3282,13 +3249,6 @@ "onboardingMetametricsNeverSellDataEmphasis": { "message": "Facultatif :" }, - "onboardingMetametricsNeverSellDataLegacy": { - "message": "Nous ne vendons $1 vos données !", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsSendAnonymizeLegacy": { - "message": "Envoyer des données anonymisées sur les clics effectués et les pages vues" - }, "onboardingMetametricsTitle": { "message": "Aidez-nous à améliorer MetaMask" }, diff --git a/app/_locales/hi/messages.json b/app/_locales/hi/messages.json index fcc67f89f409..7ebd3e958736 100644 --- a/app/_locales/hi/messages.json +++ b/app/_locales/hi/messages.json @@ -3206,24 +3206,12 @@ "onboardingMetametricsAgree": { "message": "मैं सहमत हूं" }, - "onboardingMetametricsAllowOptOutLegacy": { - "message": "सेटिंग के माध्यम से आपको हमेशा ऑप्ट-आउट करने की अनुमति देता है" - }, - "onboardingMetametricsDataTermsLegacy": { - "message": "यह डेटा एग्रीगेट किया गया है और इसलिए सामान्य डेटा संरक्षण विनियम (EU) 2016/679 के उद्देश्यों के लिए अज्ञात है।" - }, "onboardingMetametricsDescription": { "message": "हम MetaMask को बेहतर बनाने के लिए बुनियादी यूसेज और डाएगोनोस्टिक्स डेटा कलेक्ट करना चाहेंगे। जान लें कि हम आपके द्वारा यहां उपलब्ध कराया गया डेटा कभी नहीं बेचते हैं।" }, "onboardingMetametricsDescription2": { "message": "जब हम मेट्रिक्स इकट्ठा करते हैं, तो यह हमेशा... रहेगा" }, - "onboardingMetametricsDescription2Legacy": { - "message": "MetaMask करेगा..." - }, - "onboardingMetametricsDescriptionLegacy": { - "message": "MetaMask यह समझने के लिए इस्तेमाल डेटा एकत्र करना चाहता है कि हमारे यूज़र MetaMask से कैसे इंटरैक्ट करते हैं। इस डेटा का इस्तेमाल सर्विस प्रदान करने के लिए किया जाएगा, जिसमें आपके इस्तेमाल के आधार पर सर्विस में सुधार करना शामिल है।" - }, "onboardingMetametricsDisagree": { "message": "जी नहीं, धन्यवाद" }, @@ -3231,19 +3219,9 @@ "message": "यदि हम इस डेटा का उपयोग अन्य उद्देश्यों के लिए करने का निर्णय लेते हैं तो हम आपको बताएंगे। अधिक जानकारी के लिए आप हमारे $1 की समीक्षा कर सकते हैं। याद रखें, आप किसी भी समय सेटिंग्स में जाकर ऑप्ट आउट कर सकते हैं।", "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, - "onboardingMetametricsInfuraTermsLegacy": { - "message": "* जब आप MetaMask में अपने डिफॉल्ट RPC प्रोवाइडर के रूप में Infura का इस्तेमाल करते हैं, तो जब आप ट्रांसेक्शन भेजते हैं तो Infura आपका IP एड्रेस और आपके Ethereum वॉलेट का एड्रेस एकत्र कर लेगा। हम इस जानकारी को इस तरह से स्टोर नहीं करते हैं जिससे हमारे सिस्टम डेटा के उन दो टुकड़ों को जोड़ सकें। डेटा कलेक्शन के नज़रिए से MetaMask और Infura कैसे इंटरैक्ट करते हैं, इस बारे में अधिक जानकारी के लिए, हमारा अपडेट $1 देखें। सामान्य तौर पर हमारी गोपनीयता की कार्यप्रणाली के बारे में अधिक जानकारी के लिए, हमारा $2 देखें।", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" - }, "onboardingMetametricsInfuraTermsPolicy": { "message": "गोपनीयता नीति" }, - "onboardingMetametricsInfuraTermsPolicyLegacy": { - "message": "यहां गोपनीयता नीति" - }, - "onboardingMetametricsInfuraTermsPolicyLinkLegacy": { - "message": "यहां" - }, "onboardingMetametricsModalTitle": { "message": "कस्टम नेटवर्क जोड़ें" }, @@ -3261,17 +3239,6 @@ "onboardingMetametricsNeverCollectIPEmphasis": { "message": "सामान्य:" }, - "onboardingMetametricsNeverCollectIPLegacy": { - "message": "$1 आपका पूरा IP एड्रेस एकत्र करते हैं*", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverCollectLegacy": { - "message": "$1 ऐसी जानकारी एकत्र करते हैं जिसे हमें सर्विस प्रदान करने की आवश्यकता नहीं है (जैसे keys, एड्रेस, ट्रांसेक्शन हैशेज़ या बैलेंस)", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverEmphasisLegacy": { - "message": "कभी नहीं" - }, "onboardingMetametricsNeverSellData": { "message": "$1 आप तय करते हैं कि आप किसी भी समय सेटिंग्स के माध्यम से अपना यूसेज डेटा शेयर करना चाहते हैं या हटाना चाहते हैं।", "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" @@ -3279,13 +3246,6 @@ "onboardingMetametricsNeverSellDataEmphasis": { "message": "वैकल्पिक:" }, - "onboardingMetametricsNeverSellDataLegacy": { - "message": "$1 डेटा बेचते हैं। कभी!", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsSendAnonymizeLegacy": { - "message": "अज्ञात क्लिक और पेजव्यू इवेंट भेजें" - }, "onboardingMetametricsTitle": { "message": "MetaMask को बेहतर बनाने में हमारी मदद करें" }, diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json index 1bb94a0d3e04..45bc8912c676 100644 --- a/app/_locales/id/messages.json +++ b/app/_locales/id/messages.json @@ -3209,24 +3209,12 @@ "onboardingMetametricsAgree": { "message": "Saya setuju" }, - "onboardingMetametricsAllowOptOutLegacy": { - "message": "Selalu izinkan Anda untuk keluar melalui Pengaturan" - }, - "onboardingMetametricsDataTermsLegacy": { - "message": "Data ini dikumpulkan sehingga bersifat anonim untuk tujuan Peraturan Perlindungan Data Umum (UE) 2016/679." - }, "onboardingMetametricsDescription": { "message": "Kami ingin mengumpulkan data penggunaan dasar dan diagnostik untuk meningkatkan MetaMask. Pahami bahwa kami tidak pernah menjual data yang Anda berikan di sini." }, "onboardingMetametricsDescription2": { "message": "Saat kami mengumpulkan metrik, maka akan selalu..." }, - "onboardingMetametricsDescription2Legacy": { - "message": "MetaMask akan..." - }, - "onboardingMetametricsDescriptionLegacy": { - "message": "MetaMask ingin mengumpulkan data penggunaan untuk lebih memahami cara pengguna kami berinteraksi dengan MetaMask. Data ini akan digunakan untuk menyediakan layanan, termasuk meningkatkan layanan berdasarkan penggunaan Anda." - }, "onboardingMetametricsDisagree": { "message": "Tidak, terima kasih" }, @@ -3234,19 +3222,9 @@ "message": "Kami akan memberitahukan keputusan untuk menggunakan data ini dengan tujuan lain. Anda dapat meninjau $1 kami untuk informasi selengkapnya. Ingat, Anda dapat membuka pengaturan dan memilih keluar setiap saat.", "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, - "onboardingMetametricsInfuraTermsLegacy": { - "message": "* Saat Anda menggunakan Infura sebagai penyedia RPC awal di MetaMask, Infura akan mengumpulkan alamat IP dan alamat dompet Ethereum Anda saat mengirim transaksi. Kami tidak menyimpan informasi ini dengan cara yang memungkinkan sistem kami menghubungkan kedua bagian data tersebut. Untuk informasi lebih lanjut seputar cara MetaMask dan Infura berinteraksi dari perspektif pengumpulan data, lihat pembaruan $1. Untuk informasi lebih lanjut seputar praktik privasi kami secara umum, lihat $2 kami.", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" - }, "onboardingMetametricsInfuraTermsPolicy": { "message": "Kebijakan Privasi" }, - "onboardingMetametricsInfuraTermsPolicyLegacy": { - "message": "Kebijakan Privasi di sini" - }, - "onboardingMetametricsInfuraTermsPolicyLinkLegacy": { - "message": "di sini" - }, "onboardingMetametricsModalTitle": { "message": "Tambahkan jaringan khusus" }, @@ -3264,17 +3242,6 @@ "onboardingMetametricsNeverCollectIPEmphasis": { "message": "Umum:" }, - "onboardingMetametricsNeverCollectIPLegacy": { - "message": "$1 mengumpulkan alamat IP lengkap Anda*", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverCollectLegacy": { - "message": "$1 mengumpulkan informasi yang tidak kami perlukan untuk menyediakan layanan (seperti kunci, alamat, hash transaksi, atau saldo)", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverEmphasisLegacy": { - "message": "Jangan" - }, "onboardingMetametricsNeverSellData": { "message": "$1 memutuskan jika Anda ingin membagikan atau menghapus data penggunaan melalui pengaturan setiap saat.", "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" @@ -3282,13 +3249,6 @@ "onboardingMetametricsNeverSellDataEmphasis": { "message": "Opsional:" }, - "onboardingMetametricsNeverSellDataLegacy": { - "message": "$1 menjual data. Jangan pernah!", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsSendAnonymizeLegacy": { - "message": "Kirim klik anonim dan acara tampilan laman" - }, "onboardingMetametricsTitle": { "message": "Bantu kami meningkatkan MetaMask" }, diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index a5226fd27192..4ca1b2faaf7f 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -3206,24 +3206,12 @@ "onboardingMetametricsAgree": { "message": "同意します" }, - "onboardingMetametricsAllowOptOutLegacy": { - "message": "いつでも設定からオプトアウトできるようにします" - }, - "onboardingMetametricsDataTermsLegacy": { - "message": "一般データ保護規則 (EU) 2016/679 の目的に従い、このデータは集約され匿名化されます。" - }, "onboardingMetametricsDescription": { "message": "MetaMaskの改善を目的に、基本的な使用状況および診断データを収集したいと思います。ここで提供されるデータが販売されることはありません。" }, "onboardingMetametricsDescription2": { "message": "指標を収集する際、常に次の条件が適用されます..." }, - "onboardingMetametricsDescription2Legacy": { - "message": "MetaMaskは..." - }, - "onboardingMetametricsDescriptionLegacy": { - "message": "MetaMaskは、ユーザーによるMetaMaskの使用状況をより詳細に把握するため、使用データを収集したいと考えています。このデータは、使用状況に基づくサービスの改善を含め、サービスの提供を目的に使用されます。" - }, "onboardingMetametricsDisagree": { "message": "結構です" }, @@ -3231,19 +3219,9 @@ "message": "このデータを他の目的に使用する際は、お知らせします。詳細は当社の$1をご覧ください。設定でいつでもオプトアウトできます。", "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, - "onboardingMetametricsInfuraTermsLegacy": { - "message": "* MetaMaskでInfuraをデフォルトのRPCプロバイダーとして使用する場合、Infuraはトランザクションの送信時にユーザーのIPアドレスおよびイーサリアムウォレットアドレスを収集します。当社がこれらの情報を、システムによりこれら2つのデータが関連付けられる形で保管することはありません。データ収集の観点から見たMetaMaskとInfuraとのやり取りに関する詳細は、当社の最新の$1をご覧ください。当社のプライバシー慣行全般に関する詳細は、$2をご覧ください。", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" - }, "onboardingMetametricsInfuraTermsPolicy": { "message": "プライバシー ポリシー" }, - "onboardingMetametricsInfuraTermsPolicyLegacy": { - "message": "こちらのプライバシーポリシー" - }, - "onboardingMetametricsInfuraTermsPolicyLinkLegacy": { - "message": "こちら" - }, "onboardingMetametricsModalTitle": { "message": "カスタムネットワークを追加" }, @@ -3261,17 +3239,6 @@ "onboardingMetametricsNeverCollectIPEmphasis": { "message": "一般:" }, - "onboardingMetametricsNeverCollectIPLegacy": { - "message": "ユーザーの完全なIPアドレスを収集することは、$1*", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverCollectLegacy": { - "message": "サービスの提供に不要な情報 (キー、アドレス、トランザクションハッシュ、残高) を収集することは、$1", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverEmphasisLegacy": { - "message": "一切ありません" - }, "onboardingMetametricsNeverSellData": { "message": "$1 使用状況データを共有するか削除するかは、設定でいつでも指定できます。", "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" @@ -3279,13 +3246,6 @@ "onboardingMetametricsNeverSellDataEmphasis": { "message": "任意:" }, - "onboardingMetametricsNeverSellDataLegacy": { - "message": "データを販売することは$1。絶対です!", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsSendAnonymizeLegacy": { - "message": "匿名のクリックおよびページ閲覧イベントを送信" - }, "onboardingMetametricsTitle": { "message": "MetaMaskの改善にご協力ください" }, diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index d9ccf970cbd6..af94a9026392 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -3206,24 +3206,12 @@ "onboardingMetametricsAgree": { "message": "동의함" }, - "onboardingMetametricsAllowOptOutLegacy": { - "message": "언제든 설정을 통해 옵트아웃할 수 있습니다." - }, - "onboardingMetametricsDataTermsLegacy": { - "message": "이 데이터는 집계 처리된 정보이며 일반 데이터 보호 규정 (EU) 2016/679의 목적에 따라 익명으로 관리됩니다." - }, "onboardingMetametricsDescription": { "message": "MetaMask를 개선하기 위해 기본적인 사용 및 진단 데이터를 수집하고자 합니다. MetaMask는 제공받은 데이터를 절대 판매하지 않습니다." }, "onboardingMetametricsDescription2": { "message": "메트릭을 수집할 때는 항상..." }, - "onboardingMetametricsDescription2Legacy": { - "message": "MetaMask에서는..." - }, - "onboardingMetametricsDescriptionLegacy": { - "message": "MetaMask는 사용자가 MetaMask를 어떻게 사용하는지 이해하기 위해 기본적인 사용 데이터를 수집하고자 합니다. 이 데이터는 사용자 경험을 통한 서비스 개선에 사용됩니다." - }, "onboardingMetametricsDisagree": { "message": "괜찮습니다" }, @@ -3231,19 +3219,9 @@ "message": "이 데이터를 다른 목적으로 사용하기로 결정하면 알려드리겠습니다. 자세한 내용은 $1을(를) 참고하세요. 언제든지 설정으로 이동하여 해제할 수 있습니다.", "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, - "onboardingMetametricsInfuraTermsLegacy": { - "message": "* MetaMask에서 Infura를 기본 RPC 공급업체로 이용하는 경우, 트랜잭션 전송 시 Infura가 IP 주소와 이더리움 지갑 주소 정보를 수집합니다. MetaMask는 해당 두 정보를 연계할 수 있는 방식으로 정보를 저장하지 않습니다. 데이터 수집 관점에서 MetaMask와 Infura가 인터렉션하는 방법에 대한 자세한 내용은 $1 업데이트를 참조하세요. 일반적인 개인정보 처리방침에 대한 자세한 내용은 $2에서 확인하세요.", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" - }, "onboardingMetametricsInfuraTermsPolicy": { "message": "개인정보 처리방침" }, - "onboardingMetametricsInfuraTermsPolicyLegacy": { - "message": "개인정보 처리방침" - }, - "onboardingMetametricsInfuraTermsPolicyLinkLegacy": { - "message": "여기" - }, "onboardingMetametricsModalTitle": { "message": "맞춤 네트워크 추가" }, @@ -3261,17 +3239,6 @@ "onboardingMetametricsNeverCollectIPEmphasis": { "message": "일반:" }, - "onboardingMetametricsNeverCollectIPLegacy": { - "message": "$1에서는 사용자의 IP 주소 전체를 수집합니다.", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverCollectLegacy": { - "message": "$1에서는 서비스 제공에 필요하지 않은 정보(예: 키, 주소, 트랜잭션 해시 또는 잔액)를 수집합니다.", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverEmphasisLegacy": { - "message": "절대로" - }, "onboardingMetametricsNeverSellData": { "message": "$1 언제든지 설정을 통해 사용 데이터를 공유할지 삭제할지 결정할 수 있습니다.", "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" @@ -3279,13 +3246,6 @@ "onboardingMetametricsNeverSellDataEmphasis": { "message": "선택 사항:" }, - "onboardingMetametricsNeverSellDataLegacy": { - "message": "$1에서는 데이터를 판매합니다. 항상요!", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsSendAnonymizeLegacy": { - "message": "익명 클릭 및 페이지뷰 이벤트 보내기" - }, "onboardingMetametricsTitle": { "message": "MetaMask 개선에 도움을 주세요" }, diff --git a/app/_locales/pt/messages.json b/app/_locales/pt/messages.json index 971129f0e027..fe80de66b981 100644 --- a/app/_locales/pt/messages.json +++ b/app/_locales/pt/messages.json @@ -3209,24 +3209,12 @@ "onboardingMetametricsAgree": { "message": "Concordo" }, - "onboardingMetametricsAllowOptOutLegacy": { - "message": "Permite que você cancele a inscrição a qualquer momento nas Configurações" - }, - "onboardingMetametricsDataTermsLegacy": { - "message": "Esses dados são agregados e, portanto, anônimos para os fins do Regulamento Geral sobre a Proteção de Dados (UE) de 2016/679." - }, "onboardingMetametricsDescription": { "message": "Gostaríamos de coletar dados básicos de uso para melhorar a MetaMask. Saiba que nunca vendemos os dados que você fornece aqui." }, "onboardingMetametricsDescription2": { "message": "Quando coletamos as métricas, elas sempre são..." }, - "onboardingMetametricsDescription2Legacy": { - "message": "A MetaMask..." - }, - "onboardingMetametricsDescriptionLegacy": { - "message": "A MetaMask gostaria de reunir dados de uso para entender melhor como nossos usuários interagem com a MetaMask. Esses dados serão usados para prestar o serviço, o que inclui melhorá-lo com base em seu uso." - }, "onboardingMetametricsDisagree": { "message": "Não, obrigado" }, @@ -3234,19 +3222,9 @@ "message": "Informaremos a você se decidirmos usar esses dados para outras finalidades. Você pode analisar nossa $1 para obter mais informações. Lembre-se: você pode acessar as configurações e revogar a permissão a qualquer momento.", "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, - "onboardingMetametricsInfuraTermsLegacy": { - "message": "* Quando você usa a Infura como seu provedor RPC padrão na MetaMask, a Infura coleta seu endereço IP e da carteira de Ethereum quando você envia uma transação. Não armazenamos essas informações de forma que permita aos nossos sistemas cruzarem os dois fragmentos de dados. Para obter mais informações sobre como a MetaMask e a Infura interagem da perspectiva da coleta de dados, veja nossa atualização $1. Para obter mais informações sobre nossas práticas de privacidade em geral, veja nossa $2.", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" - }, "onboardingMetametricsInfuraTermsPolicy": { "message": "Política de Privacidade" }, - "onboardingMetametricsInfuraTermsPolicyLegacy": { - "message": "Política de Privacidade aqui" - }, - "onboardingMetametricsInfuraTermsPolicyLinkLegacy": { - "message": "aqui" - }, "onboardingMetametricsModalTitle": { "message": "Adicionar rede personalizada" }, @@ -3264,17 +3242,6 @@ "onboardingMetametricsNeverCollectIPEmphasis": { "message": "Gerais:" }, - "onboardingMetametricsNeverCollectIPLegacy": { - "message": "$1 coletará seu endereço IP completo*", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverCollectLegacy": { - "message": "$1 coletará informações de que não precisamos para prestar o serviço (tais como chaves, endereços, hashes de transações ou saldos)", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverEmphasisLegacy": { - "message": "Nunca" - }, "onboardingMetametricsNeverSellData": { "message": "$1 você decide se quer compartilhar ou excluir seus dados de uso nas configurações, a qualquer momento.", "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" @@ -3282,13 +3249,6 @@ "onboardingMetametricsNeverSellDataEmphasis": { "message": "Opcionais:" }, - "onboardingMetametricsNeverSellDataLegacy": { - "message": "$1 venderá dados. Jamais!", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsSendAnonymizeLegacy": { - "message": "Enviará eventos de cliques e visualizações de páginas anonimizados" - }, "onboardingMetametricsTitle": { "message": "Ajude-nos a melhorar a MetaMask" }, diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index 2ebd1f371e74..3106cf4540f4 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -3209,24 +3209,12 @@ "onboardingMetametricsAgree": { "message": "Я согласен(-на)" }, - "onboardingMetametricsAllowOptOutLegacy": { - "message": "Всегда разрешать вам отказываться в Настройках" - }, - "onboardingMetametricsDataTermsLegacy": { - "message": "Эти данные агрегированы и, следовательно, являются анонимными для целей Общего регламента по защите данных (ЕС) 2016/679." - }, "onboardingMetametricsDescription": { "message": "Мы хотели бы собрать базовые данные об использовании и диагностике для улучшения MetaMask. Помните, что мы никогда не продаем данные, которые вы здесь предоставляете." }, "onboardingMetametricsDescription2": { "message": "Когда мы собираем показатели, они всегда будут..." }, - "onboardingMetametricsDescription2Legacy": { - "message": "MetaMask..." - }, - "onboardingMetametricsDescriptionLegacy": { - "message": "MetaMask хотел бы собрать данные об использовании, чтобы лучше понять, как наши пользователи взаимодействуют с MetaMask. Эти данные будут использоваться для предоставления обслуживания, в том числе его улучшения услуги на основе вашего использования." - }, "onboardingMetametricsDisagree": { "message": "Нет, спасибо" }, @@ -3234,19 +3222,9 @@ "message": "Мы сообщим вам, если решим использовать эти данные для других целей. Вы можете ознакомиться с нашей $1 для получения дополнительной информации. Помните, что вы можете перейти в настройки и отказаться в любой момент.", "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, - "onboardingMetametricsInfuraTermsLegacy": { - "message": "* Когда вы используете Infura в качестве поставщика RPC по умолчанию в MetaMask, Infura будет собирать ваш IP-адрес и адрес вашего кошелька Ethereum при отправке транзакции. Мы не храним эту информацию таким образом, чтобы наши системы могли связать эти две части данных. Для получения дополнительной информации о том, как MetaMask и Infura взаимодействуют с точки зрения сбора данных, см. нашу обновленную $1. Для получения дополнительной информации о нашей политике конфиденциальности в целом см. нашу $2.", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" - }, "onboardingMetametricsInfuraTermsPolicy": { "message": "Политикой конфиденциальности" }, - "onboardingMetametricsInfuraTermsPolicyLegacy": { - "message": "Политику конфиденциальности здесь" - }, - "onboardingMetametricsInfuraTermsPolicyLinkLegacy": { - "message": "здесь" - }, "onboardingMetametricsModalTitle": { "message": "Добавить пользовательскую сеть" }, @@ -3264,17 +3242,6 @@ "onboardingMetametricsNeverCollectIPEmphasis": { "message": "Общедоступными:" }, - "onboardingMetametricsNeverCollectIPLegacy": { - "message": "$1 не сохраняет ваш полный IP-адрес*", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverCollectLegacy": { - "message": "$1 не будет собирать информацию, которая нам не нужна для предоставления услуги (например, ключи, адреса, хэши транзакций или остатки)", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverEmphasisLegacy": { - "message": "Никогда" - }, "onboardingMetametricsNeverSellData": { "message": "$1 вы в любое время решаете, хотите ли вы поделиться своими данными об использовании или удалить их в настройках.", "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" @@ -3282,13 +3249,6 @@ "onboardingMetametricsNeverSellDataEmphasis": { "message": "Необязательными:" }, - "onboardingMetametricsNeverSellDataLegacy": { - "message": "$1 не продает данные. Никогда!", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsSendAnonymizeLegacy": { - "message": "Отправлять анонимизированные события кликов и просмотров страниц" - }, "onboardingMetametricsTitle": { "message": "Помогите нам улучшить MetaMask" }, diff --git a/app/_locales/tl/messages.json b/app/_locales/tl/messages.json index c9f382c3644d..4a570071faa5 100644 --- a/app/_locales/tl/messages.json +++ b/app/_locales/tl/messages.json @@ -3206,24 +3206,12 @@ "onboardingMetametricsAgree": { "message": "Sumasang-ayon ako" }, - "onboardingMetametricsAllowOptOutLegacy": { - "message": "Palagi kang pinapayagan na mag-opt out sa pamamagitan ng Mga Setting" - }, - "onboardingMetametricsDataTermsLegacy": { - "message": "Ang datos na ito ay pinagsama-sama at samakatuwid ay hindi nagpapakilala para sa mga layunin ng General Data Protection Regulation (EU) 2016/679." - }, "onboardingMetametricsDescription": { "message": "Nais naming mangalap ng data para sa batayang paggamit upang mapahusay ang MetaMask. Dapat mong malaman na hindi namin ibebenta ang data na iyong ibibigay rito." }, "onboardingMetametricsDescription2": { "message": "Kapag kami ay nangangalap ng metrics, ito ay palaging..." }, - "onboardingMetametricsDescription2Legacy": { - "message": "Ang MetaMask ay..." - }, - "onboardingMetametricsDescriptionLegacy": { - "message": "Nais ng MetaMask na mangalap ng datos ng paggamit upang mas maunawaan kung paano nakikipag-ugnayan ang aming mga user sa MetaMask. Gagamitin ang datos na ito upang ibigay ang serbisyo, na kinabibilangan ng pagpapabuti ng serbisyo batay sa iyong paggamit." - }, "onboardingMetametricsDisagree": { "message": "Salamat nalang" }, @@ -3231,19 +3219,9 @@ "message": "Ipapaalam namin sa iyo kung magdesisyon kaming gamitin ang data na ito para sa ibang layunin. Maaari mong suriin ang aming $1 para sa karagdagang impormasyon. Tandaan, maaari kang magpunta sa mga setting at mag-opt out anumang oras.", "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, - "onboardingMetametricsInfuraTermsLegacy": { - "message": "* Kapag ginamit mo ang Infura bilang iyong default na provider ng RPC sa MetaMask, kukunin ng Infura ang iyong IP address at ang iyong Ethereum wallet address kapag nagpadala ka ng transaksyon. Hindi namin iniimbak ang impormasyong ito sa paraan na nagpapahintulot sa aming mga system na iugnay ang dalawang piraso ng data na iyon. Para sa higit pang impormasyon kung paano nakikipag-ugnayan ang MetaMask at Infura mula sa pananaw ng pagkolekta ng data, tingnan ang aming update na $1. Para sa higit pang impormasyon sa aming mga kasanayan sa pagkapribado sa pangkalahatan, tingnan ang aming $2.", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" - }, "onboardingMetametricsInfuraTermsPolicy": { "message": "Patakaran sa Pagkapribado" }, - "onboardingMetametricsInfuraTermsPolicyLegacy": { - "message": "Patakaran sa Pagkapribado dito" - }, - "onboardingMetametricsInfuraTermsPolicyLinkLegacy": { - "message": "dito" - }, "onboardingMetametricsModalTitle": { "message": "Magdagdag ng custom na network" }, @@ -3261,17 +3239,6 @@ "onboardingMetametricsNeverCollectIPEmphasis": { "message": "Pangkalahatan:" }, - "onboardingMetametricsNeverCollectIPLegacy": { - "message": "Kinokolekta ng $1 ang iyong buong IP address*", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverCollectLegacy": { - "message": "Kinokolekta ng $1 ang impormasyon na hindi namin kailangan para ibigay ang serbisyo (tulad ng mga key, address, hash ng transaksyon, o balanse)", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverEmphasisLegacy": { - "message": "Hindi kailanman" - }, "onboardingMetametricsNeverSellData": { "message": "$1 ikaw ang magdedesisyon kung nais mong ibahagi o burahin ang iyong data sa paggamit sa pamamagitan ng mga setting anumang oras.", "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" @@ -3279,13 +3246,6 @@ "onboardingMetametricsNeverSellDataEmphasis": { "message": "Opsyonal:" }, - "onboardingMetametricsNeverSellDataLegacy": { - "message": "Ang $1 ay nagbebenta ng datos. Kailanman!", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsSendAnonymizeLegacy": { - "message": "Magpapadala ng mga anonymous na kaganapang pag-click at pagtingin sa page" - }, "onboardingMetametricsTitle": { "message": "Tulungan kaming mapahusay ang MetaMask" }, diff --git a/app/_locales/tr/messages.json b/app/_locales/tr/messages.json index 1dbad4ab24e5..51aafd650946 100644 --- a/app/_locales/tr/messages.json +++ b/app/_locales/tr/messages.json @@ -3209,24 +3209,12 @@ "onboardingMetametricsAgree": { "message": "Kabul ediyorum" }, - "onboardingMetametricsAllowOptOutLegacy": { - "message": "Her zaman Ayarlar kısmından vazgeçebilmenize izin verir" - }, - "onboardingMetametricsDataTermsLegacy": { - "message": "Bu veriler toplanmıştır ve bu nedenle 2016/679 sayılı Genel Veri Koruma Tüzüğü (AB) maksadıyla isimsizdir." - }, "onboardingMetametricsDescription": { "message": "MetaMask'i iyileştirmek için temel kullanım ve tanılama verilerini toplamak istiyoruz. Burada sunduğunuz verileri asla satmadığımızı bilmenizi isteriz." }, "onboardingMetametricsDescription2": { "message": "Ölçümleri toplarken bu her zaman aşağıdaki gibi olacaktır..." }, - "onboardingMetametricsDescription2Legacy": { - "message": "MetaMask..." - }, - "onboardingMetametricsDescriptionLegacy": { - "message": "MetaMask kullanıcılarımızn MetaMask ile nasıl etkileşimde bulunduklarını daha iyi anlamak amacıyla kullanım verilerini toplamak ister. Bu veriler, hizmeti kullanımınıza göre geliştirmek de dahil olmak üzere hizmeti sunmak için kullanılacaktır." - }, "onboardingMetametricsDisagree": { "message": "Hayır, istemiyorum" }, @@ -3234,19 +3222,9 @@ "message": "Bu verileri başka amaçlar için kullanmaya karar vermemiz durumunda sizi bilgilendireceğiz. Daha fazla bilgi için $1 bölümümüzü inceleyebilirsiniz. Unutmayın, dilediğiniz zaman ayarlar kısmına giderek vazgeçebilirsiniz.", "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, - "onboardingMetametricsInfuraTermsLegacy": { - "message": "* MetaMask'te varsayılan RPC sağlayıcınız olarak Infura'yı kullandığınızda, siz bir işlem gönderdiğinizde Infura tarafından IP adresiniz ve Ethereum cüzdan adresiniz toplanır. Bu bilgileri sistemlerimizin bu iki veri parçasını ilişkilendirebilmesini sağlayan şekilde saklamayız. MetaMask ve Infura'nın veri toplama açısından nasıl etkileşimde bulundukları hakkında daha fazla bilgi için lütfen güncel $1 bölümümüze bakın. Genel olarak gizlilik uygulamalarımız hakkında daha fazla bilgi için $2 bölümümüze bakın.", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" - }, "onboardingMetametricsInfuraTermsPolicy": { "message": "Gizlilik Politikası" }, - "onboardingMetametricsInfuraTermsPolicyLegacy": { - "message": "buradan Gizlilik Politikası" - }, - "onboardingMetametricsInfuraTermsPolicyLinkLegacy": { - "message": "burada" - }, "onboardingMetametricsModalTitle": { "message": "Özel ağ ekle" }, @@ -3264,17 +3242,6 @@ "onboardingMetametricsNeverCollectIPEmphasis": { "message": "Genel:" }, - "onboardingMetametricsNeverCollectIPLegacy": { - "message": "$1 tam IP adresinizi toplar*", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverCollectLegacy": { - "message": "$1 ihtiyacımız olmayan bilgileri (anahtarlar, adresler, işlem hash değerleri veya bakiyeler gibi) hizmeti sunmak için toplar", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverEmphasisLegacy": { - "message": "Hiçbir Zaman" - }, "onboardingMetametricsNeverSellData": { "message": "$1 kullanım verilerinizi paylaşmak veya silmek isteyip istemediğinize ayarlar kısmından dilediğiniz zaman siz karar verirsiniz.", "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" @@ -3282,13 +3249,6 @@ "onboardingMetametricsNeverSellDataEmphasis": { "message": "İsteğe bağlı:" }, - "onboardingMetametricsNeverSellDataLegacy": { - "message": "$1 verileri satmaz. Asla!", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsSendAnonymizeLegacy": { - "message": "İsimsiz tıklama ve sayfa görüntüleme etkinlikleri gönder" - }, "onboardingMetametricsTitle": { "message": "MetaMask'i iyileştirmemize yardımcı olun" }, diff --git a/app/_locales/vi/messages.json b/app/_locales/vi/messages.json index bbbcffe561d6..6f2cba66d83b 100644 --- a/app/_locales/vi/messages.json +++ b/app/_locales/vi/messages.json @@ -3206,24 +3206,12 @@ "onboardingMetametricsAgree": { "message": "Tôi đồng ý" }, - "onboardingMetametricsAllowOptOutLegacy": { - "message": "Luôn cho phép bạn chọn không tham gia thông qua phần Cài đặt" - }, - "onboardingMetametricsDataTermsLegacy": { - "message": "Do đó, dữ liệu này được tổng hợp và ẩn danh theo các mục đích của Quy định bảo vệ dữ liệu chung (EU) 2016/679." - }, "onboardingMetametricsDescription": { "message": "Chúng tôi muốn thu thập dữ liệu sử dụng và chẩn đoán cơ bản để cải tiến MetaMask. Xin lưu ý, chúng tôi không bao giờ bán dữ liệu mà bạn cung cấp ở đây." }, "onboardingMetametricsDescription2": { "message": "Khi thu thập số liệu, chúng tôi sẽ luôn cam kết điều này..." }, - "onboardingMetametricsDescription2Legacy": { - "message": "MetaMask sẽ..." - }, - "onboardingMetametricsDescriptionLegacy": { - "message": "MetaMask muốn thu thập dữ liệu sử dụng để hiểu rõ hơn cách người dùng tương tác với MetaMask. Dữ liệu này sẽ được sử dụng để cung cấp dịch vụ, bao gồm cả cải thiện dịch vụ dựa trên quá trình sử dụng của bạn." - }, "onboardingMetametricsDisagree": { "message": "Không, cảm ơn" }, @@ -3231,19 +3219,9 @@ "message": "Chúng tôi sẽ thông báo cho bạn nếu chúng tôi quyết định sử dụng dữ liệu này cho các mục đích khác. Bạn có thể xem lại $1 của chúng tôi để biết thêm thông tin. Lưu ý, bạn có thể truy cập cài đặt và chọn không tham gia bất kỳ lúc nào.", "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, - "onboardingMetametricsInfuraTermsLegacy": { - "message": "* Khi bạn sử dụng Infura làm nhà cung cấp RPC mặc định trong MetaMask, Infura sẽ thu thập địa chỉ IP và địa chỉ ví Ethereum của bạn khi bạn gửi giao dịch. Chúng tôi không lưu trữ thông tin này để cho phép hệ thống của chúng tôi liên kết hai loại dữ liệu đó. Để biết thêm thông tin về cách MetaMask và Infura tương tác trong việc thu thập dữ liệu, hãy xem bản cập nhật $1 của chúng tôi. Để biết thêm thông tin về các phương pháp bảo vệ quyền riêng tư của chúng tôi nói chung, hãy xem $2.", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" - }, "onboardingMetametricsInfuraTermsPolicy": { "message": "Chính sách quyền riêng tư" }, - "onboardingMetametricsInfuraTermsPolicyLegacy": { - "message": "Chính sách quyền riêng tư tại đây" - }, - "onboardingMetametricsInfuraTermsPolicyLinkLegacy": { - "message": "tại đây" - }, "onboardingMetametricsModalTitle": { "message": "Thêm mạng tùy chỉnh" }, @@ -3261,17 +3239,6 @@ "onboardingMetametricsNeverCollectIPEmphasis": { "message": "Chung:" }, - "onboardingMetametricsNeverCollectIPLegacy": { - "message": "$1 thu thập địa chỉ IP đầy đủ của bạn*", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverCollectLegacy": { - "message": "$1 thu thập các thông tin mà chúng tôi không cần để cung cấp dịch vụ (chẳng hạn như khóa, địa chỉ, mã băm giao dịch hoặc số dư)", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverEmphasisLegacy": { - "message": "Không bao giờ" - }, "onboardingMetametricsNeverSellData": { "message": "$1 bạn có thể chọn chia sẻ hoặc xóa dữ liệu sử dụng của mình trong phần cài đặt bất kỳ lúc nào.", "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" @@ -3279,13 +3246,6 @@ "onboardingMetametricsNeverSellDataEmphasis": { "message": "Không bắt buộc:" }, - "onboardingMetametricsNeverSellDataLegacy": { - "message": "$1 không bao giờ bán dữ liệu!", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsSendAnonymizeLegacy": { - "message": "Gửi các sự kiện nhấp chuột & lượt xem trang ẩn danh" - }, "onboardingMetametricsTitle": { "message": "Giúp chúng tôi cải thiện MetaMask" }, diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index 2b73be877bbe..ca5b01c48545 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -3206,24 +3206,12 @@ "onboardingMetametricsAgree": { "message": "我同意" }, - "onboardingMetametricsAllowOptOutLegacy": { - "message": "始终允许您通过设置选择退出" - }, - "onboardingMetametricsDataTermsLegacy": { - "message": "此数据是汇总数据,因而可以保持匿名,以遵守《通用数据保护条例》(欧盟)2016/679。" - }, "onboardingMetametricsDescription": { "message": "我们希望收集基本的使用和诊断数据,以改进 MetaMask。请注意,我们绝不会出卖您在此处提供的数据。" }, "onboardingMetametricsDescription2": { "message": "当我们收集指标时,总是..." }, - "onboardingMetametricsDescription2Legacy": { - "message": "MetaMask 将会......" - }, - "onboardingMetametricsDescriptionLegacy": { - "message": "MetaMask 希望收集使用数据,以更好地了解我们的用户如何与 MetaMask 交互。这些数据将用于提供服务,包括根据您的使用情况改进服务。" - }, "onboardingMetametricsDisagree": { "message": "不,谢谢" }, @@ -3231,19 +3219,9 @@ "message": "如果我们决定将这些数据用于其他目的,我们会通知您。您可以查看我们的 $1 以了解更多信息。请记住,您可以随时转到设置并选择退出。", "description": "$1 represents `onboardingMetametricsInfuraTermsPolicy`" }, - "onboardingMetametricsInfuraTermsLegacy": { - "message": "* 如您在 MetaMask中 使用 Infura 作为默认的 RPC 提供商,Infura 将在您发送交易时收集您的 IP 地址和以太坊钱包地址。我们不会以允许系统将这两项数据关联起来的方式存储这些信息。如需从数据收集角度进一步了解 MetaMask 和 Infura 如何进行交互,请参阅我们的更新版 $1。如需进一步了解我们的一般隐私准则,请参阅我们的 $2。", - "description": "$1 represents `onboardingMetametricsInfuraTermsPolicyLink`, $2 represents `onboardingMetametricsInfuraTermsPolicy`" - }, "onboardingMetametricsInfuraTermsPolicy": { "message": "隐私政策" }, - "onboardingMetametricsInfuraTermsPolicyLegacy": { - "message": "隐私政策在此处" - }, - "onboardingMetametricsInfuraTermsPolicyLinkLegacy": { - "message": "此处" - }, "onboardingMetametricsModalTitle": { "message": "添加自定义网络" }, @@ -3261,17 +3239,6 @@ "onboardingMetametricsNeverCollectIPEmphasis": { "message": "通用:" }, - "onboardingMetametricsNeverCollectIPLegacy": { - "message": "$1收集您的完整 IP 地址*", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverCollectLegacy": { - "message": "$1 收集我们不需要提供服务的信息(如私钥、地址、交易散列或余额)", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsNeverEmphasisLegacy": { - "message": "永远不会发生" - }, "onboardingMetametricsNeverSellData": { "message": "$1 您可以随时决定是否通过设置共享或删除您的使用数据。", "description": "$1 represents `onboardingMetametricsNeverSellDataEmphasis`" @@ -3279,13 +3246,6 @@ "onboardingMetametricsNeverSellDataEmphasis": { "message": "可选:" }, - "onboardingMetametricsNeverSellDataLegacy": { - "message": "$1 出售数据。永远不会!", - "description": "$1 represents `onboardingMetametricsNeverEmphasis`" - }, - "onboardingMetametricsSendAnonymizeLegacy": { - "message": "发送匿名的点击和页面浏览事件" - }, "onboardingMetametricsTitle": { "message": "请帮助我们改进 MetaMask" }, diff --git a/app/scripts/lib/keyring-snaps-permissions.test.ts b/app/scripts/lib/snap-keyring/keyring-snaps-permissions.test.ts similarity index 100% rename from app/scripts/lib/keyring-snaps-permissions.test.ts rename to app/scripts/lib/snap-keyring/keyring-snaps-permissions.test.ts diff --git a/app/scripts/lib/keyring-snaps-permissions.ts b/app/scripts/lib/snap-keyring/keyring-snaps-permissions.ts similarity index 100% rename from app/scripts/lib/keyring-snaps-permissions.ts rename to app/scripts/lib/snap-keyring/keyring-snaps-permissions.ts diff --git a/app/scripts/lib/snap-keyring/utils/isBlockedUrl.ts b/app/scripts/lib/snap-keyring/utils/isBlockedUrl.ts index f196faff0b96..50bc4bfa08eb 100644 --- a/app/scripts/lib/snap-keyring/utils/isBlockedUrl.ts +++ b/app/scripts/lib/snap-keyring/utils/isBlockedUrl.ts @@ -1,5 +1,5 @@ import { PhishingController } from '@metamask/phishing-controller'; -import { isProtocolAllowed } from '../../keyring-snaps-permissions'; +import { isProtocolAllowed } from '../keyring-snaps-permissions'; /** * Checks whether a given URL is blocked due to not using HTTPS or being diff --git a/app/scripts/metamask-controller.actions.test.js b/app/scripts/metamask-controller.actions.test.js index a5a49ac94e35..33fa8c9baa8a 100644 --- a/app/scripts/metamask-controller.actions.test.js +++ b/app/scripts/metamask-controller.actions.test.js @@ -164,57 +164,41 @@ describe('MetaMaskController', function () { }); describe('#importAccountWithStrategy', function () { - it('two sequential calls with same strategy give same result', async function () { - let keyringControllerState1; - let keyringControllerState2; + it('throws an error when importing the same account twice', async function () { const importPrivkey = '4cfd3e90fc78b0f86bf7524722150bb8da9c60cd532564d7ff43f5716514f553'; - await metamaskController.createNewVaultAndKeychain('test@123'); - await Promise.all([ + + await metamaskController.importAccountWithStrategy('privateKey', [ + importPrivkey, + ]); + + await expect( metamaskController.importAccountWithStrategy('privateKey', [ importPrivkey, ]), - Promise.resolve(1).then(() => { - keyringControllerState1 = JSON.stringify( - metamaskController.keyringController.state, - ); - metamaskController.importAccountWithStrategy('privateKey', [ - importPrivkey, - ]); - }), - Promise.resolve(2).then(() => { - keyringControllerState2 = JSON.stringify( - metamaskController.keyringController.state, - ); - }), - ]); - expect(keyringControllerState1).toStrictEqual(keyringControllerState2); + ).rejects.toThrow( + 'KeyringController - The account you are trying to import is a duplicate', + ); }); }); describe('#createNewVaultAndRestore', function () { it('two successive calls with same inputs give same result', async function () { - const result1 = await metamaskController.createNewVaultAndRestore( - 'test@123', - TEST_SEED, - ); - const result2 = await metamaskController.createNewVaultAndRestore( - 'test@123', - TEST_SEED, - ); + await metamaskController.createNewVaultAndRestore('test@123', TEST_SEED); + const result1 = metamaskController.keyringController.state; + await metamaskController.createNewVaultAndRestore('test@123', TEST_SEED); + const result2 = metamaskController.keyringController.state; expect(result1).toStrictEqual(result2); }); }); describe('#createNewVaultAndKeychain', function () { it('two successive calls with same inputs give same result', async function () { - const result1 = await metamaskController.createNewVaultAndKeychain( - 'test@123', - ); - const result2 = await metamaskController.createNewVaultAndKeychain( - 'test@123', - ); + await metamaskController.createNewVaultAndKeychain('test@123'); + const result1 = metamaskController.keyringController.state; + await metamaskController.createNewVaultAndKeychain('test@123'); + const result2 = metamaskController.keyringController.state; expect(result1).not.toStrictEqual(undefined); expect(result1).toStrictEqual(result2); }); @@ -222,9 +206,13 @@ describe('MetaMaskController', function () { describe('#setLocked', function () { it('should lock the wallet', async function () { - const { isUnlocked, keyrings } = await metamaskController.setLocked(); - expect(isUnlocked).toStrictEqual(false); - expect(keyrings).toStrictEqual([]); + await metamaskController.setLocked(); + expect( + metamaskController.keyringController.state.isUnlocked, + ).toStrictEqual(false); + expect(metamaskController.keyringController.state.keyrings).toStrictEqual( + [], + ); }); }); diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 14d264fd67f7..205a06c9dd06 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -248,7 +248,7 @@ import { ///: END:ONLY_INCLUDE_IF import { submitSmartTransactionHook } from './lib/transaction/smart-transactions'; ///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps) -import { keyringSnapPermissionsBuilder } from './lib/keyring-snaps-permissions'; +import { keyringSnapPermissionsBuilder } from './lib/snap-keyring/keyring-snaps-permissions'; ///: END:ONLY_INCLUDE_IF import { SnapsNameProvider } from './lib/SnapsNameProvider'; @@ -4046,7 +4046,7 @@ export default class MetamaskController extends EventEmitter { } // create new vault - const vault = await this.keyringController.createNewVaultAndRestore( + await this.keyringController.createNewVaultAndRestore( password, this._convertMnemonicToWordlistIndices(seedPhraseAsBuffer), ); @@ -4060,8 +4060,6 @@ export default class MetamaskController extends EventEmitter { // Ledger Keyring GitHub downtime this.setLedgerTransportPreference(); } - - return vault; } finally { releaseLock(); } @@ -4101,8 +4099,7 @@ export default class MetamaskController extends EventEmitter { } // This account has assets, so check the next one - ({ addedAccountAddress: address } = - await this.keyringController.addNewAccount(count)); + address = await this.keyringController.addNewAccount(count); } } @@ -4492,36 +4489,28 @@ 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.addNewAccountForKeyring( - keyring, + const unlockedAccount = + await this.keyringController.addNewAccountForKeyring(keyring); + const label = this.getAccountLabel( + deviceName === HardwareDeviceNames.qr ? keyring.getName() : deviceName, + index, + hdPathDescription, ); - const newAccounts = await this.keyringController.getAccounts(); - newAccounts.forEach((address) => { - if (!oldAccounts.includes(address)) { - const label = this.getAccountLabel( - deviceName === HardwareDeviceNames.qr - ? keyring.getName() - : deviceName, - index, - hdPathDescription, - ); - // Set the account label to Trezor 1 / Ledger 1 / QR Hardware 1, etc - this.preferencesController.setAccountLabel(address, label); - // Select the account - this.preferencesController.setSelectedAddress(address); + // Set the account label to Trezor 1 / Ledger 1 / QR Hardware 1, etc + this.preferencesController.setAccountLabel(unlockedAccount, label); + // Select the account + this.preferencesController.setSelectedAddress(unlockedAccount); - // It is expected that the account also exist in the accounts-controller - // in other case, an error shall be thrown - const account = this.accountsController.getAccountByAddress(address); - this.accountsController.setAccountName(account.id, label); - } - }); + // It is expected that the account also exist in the accounts-controller + // in other case, an error shall be thrown + const account = + this.accountsController.getAccountByAddress(unlockedAccount); + this.accountsController.setAccountName(account.id, label); const accounts = this.accountsController.listAccounts(); const { identities } = this.preferencesController.store.getState(); - return { ...keyState, identities, accounts }; + return { unlockedAccount, identities, accounts }; } // @@ -4537,7 +4526,7 @@ export default class MetamaskController extends EventEmitter { async addNewAccount(accountCount) { const oldAccounts = await this.keyringController.getAccounts(); - const { addedAccountAddress } = await this.keyringController.addNewAccount( + const addedAccountAddress = await this.keyringController.addNewAccount( accountCount, ); @@ -4709,7 +4698,7 @@ export default class MetamaskController extends EventEmitter { * @param {any} args - The data required by that strategy to import an account. */ async importAccountWithStrategy(strategy, args) { - const { importedAccountAddress } = + const importedAccountAddress = await this.keyringController.importAccountWithStrategy(strategy, args); // set new account as selected this.preferencesController.setSelectedAddress(importedAccountAddress); diff --git a/app/scripts/metamask-controller.test.js b/app/scripts/metamask-controller.test.js index 3012b7a68c8e..74da2709882f 100644 --- a/app/scripts/metamask-controller.test.js +++ b/app/scripts/metamask-controller.test.js @@ -27,6 +27,8 @@ import { RatesController, TokenListController, } from '@metamask/assets-controllers'; +import { TrezorKeyring } from '@metamask/eth-trezor-keyring'; +import { LedgerKeyring } from '@metamask/eth-ledger-bridge-keyring'; import { NETWORK_TYPES } from '../../shared/constants/network'; import { createTestProviderTools } from '../../test/stub/provider'; import { HardwareDeviceNames } from '../../shared/constants/hardware-wallets'; @@ -127,6 +129,64 @@ jest.mock( }, ); +const KNOWN_PUBLIC_KEY = + '02065bc80d3d12b3688e4ad5ab1e9eda6adf24aec2518bfc21b87c99d4c5077ab0'; + +const KNOWN_PUBLIC_KEY_ADDRESSES = [ + { + address: '0x0e122670701207DB7c6d7ba9aE07868a4572dB3f', + balance: null, + index: 0, + }, + { + address: '0x2ae19DAd8b2569F7Bb4606D951Cc9495631e818E', + balance: null, + index: 1, + }, + { + address: '0x0051140bAaDC3E9AC92A4a90D18Bb6760c87e7ac', + balance: null, + index: 2, + }, + { + address: '0x9DBCF67CC721dBd8Df28D7A0CbA0fa9b0aFc6472', + balance: null, + index: 3, + }, + { + address: '0x828B2c51c5C1bB0c57fCD2C108857212c95903DE', + balance: null, + index: 4, + }, +]; + +const buildMockKeyringBridge = (publicKeyPayload) => + jest.fn(() => ({ + init: jest.fn(), + dispose: jest.fn(), + updateTransportMethod: jest.fn(), + getPublicKey: jest.fn(async () => publicKeyPayload), + })); + +jest.mock('@metamask/eth-trezor-keyring', () => ({ + ...jest.requireActual('@metamask/eth-trezor-keyring'), + TrezorConnectBridge: buildMockKeyringBridge({ + success: true, + payload: { + publicKey: KNOWN_PUBLIC_KEY, + chainCode: '0x1', + }, + }), +})); + +jest.mock('@metamask/eth-ledger-bridge-keyring', () => ({ + ...jest.requireActual('@metamask/eth-ledger-bridge-keyring'), + LedgerIframeBridge: buildMockKeyringBridge({ + publicKey: KNOWN_PUBLIC_KEY, + chainCode: '0x1', + }), +})); + const mockIsManifestV3 = jest.fn().mockReturnValue(false); jest.mock('../../shared/modules/mv3.utils', () => ({ get isManifestV3() { @@ -754,257 +814,290 @@ describe('MetaMaskController', () => { }); }); - describe('connectHardware', () => { - it('should throw if it receives an unknown device name', async () => { - const result = metamaskController.connectHardware( - 'Some random device name', - 0, - `m/44/0'/0'`, - ); - - await expect(result).rejects.toThrow( - 'MetamaskController:getKeyringForDevice - Unknown device', - ); + describe('hardware keyrings', () => { + beforeEach(async () => { + await metamaskController.createNewVaultAndKeychain('test@123'); }); - it('should add the Trezor Hardware keyring', async () => { - jest.spyOn(metamaskController.keyringController, 'addNewKeyring'); - await metamaskController - .connectHardware(HardwareDeviceNames.trezor, 0) - .catch(() => null); - const keyrings = - await metamaskController.keyringController.getKeyringsByType( - KeyringType.trezor, + describe('connectHardware', () => { + it('should throw if it receives an unknown device name', async () => { + const result = metamaskController.connectHardware( + 'Some random device name', + 0, + `m/44/0'/0'`, ); - expect( - metamaskController.keyringController.addNewKeyring, - ).toHaveBeenCalledWith(KeyringType.trezor); - expect(keyrings).toHaveLength(1); - }); - it('should add the Ledger Hardware keyring', async () => { - jest.spyOn(metamaskController.keyringController, 'addNewKeyring'); - await metamaskController - .connectHardware(HardwareDeviceNames.ledger, 0) - .catch(() => null); - const keyrings = - await metamaskController.keyringController.getKeyringsByType( - KeyringType.ledger, + await expect(result).rejects.toThrow( + 'MetamaskController:getKeyringForDevice - Unknown device', ); - expect( - metamaskController.keyringController.addNewKeyring, - ).toHaveBeenCalledWith(KeyringType.ledger); - expect(keyrings).toHaveLength(1); - }); - }); + }); - describe('getPrimaryKeyringMnemonic', () => { - it('should return a mnemonic as a Uint8Array', () => { - const mockMnemonic = - 'above mercy benefit hospital call oval domain student sphere interest argue shock'; - const mnemonicIndices = mockMnemonic - .split(' ') - .map((word) => englishWordlist.indexOf(word)); - const uint8ArrayMnemonic = new Uint8Array( - new Uint16Array(mnemonicIndices).buffer, - ); + it('should add the Trezor Hardware keyring and return the first page of accounts', async () => { + jest.spyOn(metamaskController.keyringController, 'addNewKeyring'); - const mockHDKeyring = { - type: 'HD Key Tree', - mnemonic: uint8ArrayMnemonic, - }; - jest - .spyOn(metamaskController.keyringController, 'getKeyringsByType') - .mockReturnValue([mockHDKeyring]); + const firstPage = await metamaskController.connectHardware( + HardwareDeviceNames.trezor, + 0, + ); - const recoveredMnemonic = - metamaskController.getPrimaryKeyringMnemonic(); + expect( + metamaskController.keyringController.addNewKeyring, + ).toHaveBeenCalledWith(KeyringType.trezor); + expect( + metamaskController.keyringController.state.keyrings[1].type, + ).toBe(TrezorKeyring.type); + expect(firstPage).toStrictEqual(KNOWN_PUBLIC_KEY_ADDRESSES); + }); - expect(recoveredMnemonic).toStrictEqual(uint8ArrayMnemonic); - }); - }); + it('should add the Ledger Hardware keyring and return the first page of accounts', async () => { + jest.spyOn(metamaskController.keyringController, 'addNewKeyring'); - describe('checkHardwareStatus', () => { - it('should throw if it receives an unknown device name', async () => { - const result = metamaskController.checkHardwareStatus( - 'Some random device name', - `m/44/0'/0'`, - ); - await expect(result).rejects.toThrow( - 'MetamaskController:getKeyringForDevice - Unknown device', - ); - }); + const firstPage = await metamaskController.connectHardware( + HardwareDeviceNames.ledger, + 0, + ); - it('should be locked by default', async () => { - await metamaskController - .connectHardware(HardwareDeviceNames.trezor, 0) - .catch(() => null); - const status = await metamaskController.checkHardwareStatus( - HardwareDeviceNames.trezor, - ); - expect(status).toStrictEqual(false); + expect( + metamaskController.keyringController.addNewKeyring, + ).toHaveBeenCalledWith(KeyringType.ledger); + expect( + metamaskController.keyringController.state.keyrings[1].type, + ).toBe(LedgerKeyring.type); + expect(firstPage).toStrictEqual(KNOWN_PUBLIC_KEY_ADDRESSES); + }); }); - }); - describe('forgetDevice', () => { - it('should throw if it receives an unknown device name', async () => { - const result = metamaskController.forgetDevice( - 'Some random device name', - ); - await expect(result).rejects.toThrow( - 'MetamaskController:getKeyringForDevice - Unknown device', - ); - }); + describe('checkHardwareStatus', () => { + it('should throw if it receives an unknown device name', async () => { + const result = metamaskController.checkHardwareStatus( + 'Some random device name', + `m/44/0'/0'`, + ); + await expect(result).rejects.toThrow( + 'MetamaskController:getKeyringForDevice - Unknown device', + ); + }); - it('should remove the identities when the device is forgotten', async () => { - jest.spyOn(window, 'open').mockReturnValue(); + [HardwareDeviceNames.trezor, HardwareDeviceNames.ledger].forEach( + (device) => { + describe(`using ${device}`, () => { + it('should be unlocked by default', async () => { + await metamaskController.connectHardware(device, 0); - const localMetaMaskController = new MetaMaskController({ - showUserConfirmation: noop, - encryptor: mockEncryptor, - initState: { - ...cloneDeep(firstTimeState), - KeyringController: { - keyrings: [{ type: KeyringType.trezor, accounts: ['0x123'] }], - isUnlocked: true, - }, - PreferencesController: { - identities: { - '0x123': { name: 'Trezor 1', address: '0x123' }, - }, - selectedAddress: '0x123', - }, - }, - initLangCode: 'en_US', - platform: { - showTransactionNotification: () => undefined, - getVersion: () => 'foo', + const status = await metamaskController.checkHardwareStatus( + device, + ); + + expect(status).toStrictEqual(true); + }); + }); }, - browser: browserPolyfillMock, - infuraProjectId: 'foo', - isFirstMetaMaskControllerSetup: true, + ); + }); + + describe('forgetDevice', () => { + it('should throw if it receives an unknown device name', async () => { + const result = metamaskController.forgetDevice( + 'Some random device name', + ); + await expect(result).rejects.toThrow( + 'MetamaskController:getKeyringForDevice - Unknown device', + ); }); - await localMetaMaskController.keyringController.createNewVaultAndKeychain( - 'password', - ); + it('should remove the identities when the device is forgotten', async () => { + await metamaskController.connectHardware( + HardwareDeviceNames.trezor, + 0, + ); + await metamaskController.unlockHardwareWalletAccount( + 0, + HardwareDeviceNames.trezor, + ); + const hardwareKeyringAccount = + metamaskController.keyringController.state.keyrings[1].accounts[0]; - await localMetaMaskController.keyringController.addNewKeyring( - 'Trezor Hardware', - { - accounts: ['0x123'], - }, - ); + await metamaskController.forgetDevice(HardwareDeviceNames.trezor); - await localMetaMaskController.forgetDevice(HardwareDeviceNames.trezor); - const { identities: updatedIdentities } = - localMetaMaskController.preferencesController.store.getState(); - expect(updatedIdentities['0x123']).toBeUndefined(); - }); + expect( + Object.keys( + metamaskController.preferencesController.store.getState() + .identities, + ), + ).not.toContain(hardwareKeyringAccount); + expect( + metamaskController.accountsController + .listAccounts() + .some((account) => account.address === hardwareKeyringAccount), + ).toStrictEqual(false); + }); - it('should wipe all the keyring info', async () => { - await metamaskController - .connectHardware(HardwareDeviceNames.trezor, 0) - .catch(() => null); - await metamaskController.forgetDevice(HardwareDeviceNames.trezor); - const keyrings = - await metamaskController.keyringController.getKeyringsByType( - KeyringType.trezor, + it('should wipe all the keyring info', async () => { + await metamaskController.connectHardware( + HardwareDeviceNames.trezor, + 0, ); - expect(keyrings[0].accounts).toStrictEqual([]); - expect(keyrings[0].page).toStrictEqual(0); - expect(keyrings[0].isUnlocked()).toStrictEqual(false); + await metamaskController.forgetDevice(HardwareDeviceNames.trezor); + const keyrings = + await metamaskController.keyringController.getKeyringsByType( + KeyringType.trezor, + ); + + expect(keyrings[0].accounts).toStrictEqual([]); + expect(keyrings[0].page).toStrictEqual(0); + expect(keyrings[0].isUnlocked()).toStrictEqual(false); + }); }); - }); - describe('unlockHardwareWalletAccount', () => { - const accountToUnlock = 10; - beforeEach(async () => { - await metamaskController.keyringController.createNewVaultAndRestore( - 'password', - TEST_SEED, - ); - jest.spyOn(window, 'open').mockReturnValue(); - jest - .spyOn( - metamaskController.keyringController, - 'addNewAccountForKeyring', - ) - .mockReturnValue('0x123'); + describe('unlockHardwareWalletAccount', () => { + const accountToUnlock = 0; - jest - .spyOn(metamaskController.keyringController, 'getAccounts') - .mockResolvedValueOnce(['0x1']) - .mockResolvedValueOnce(['0x2']) - .mockResolvedValueOnce(['0x3']); - jest - .spyOn(metamaskController.preferencesController, 'setSelectedAddress') - .mockReturnValue(); - jest - .spyOn(metamaskController.preferencesController, 'setAccountLabel') - .mockReturnValue(); + [HardwareDeviceNames.trezor, HardwareDeviceNames.ledger].forEach( + (device) => { + describe(`using ${device}`, () => { + beforeEach(async () => { + await metamaskController.connectHardware(device, 0); + }); - jest - .spyOn(metamaskController.accountsController, 'getAccountByAddress') - .mockReturnValue({ - account: { - id: '2d47e693-26c2-47cb-b374-6151199bbe3f', - }, - }); - jest - .spyOn(metamaskController.accountsController, 'setAccountName') - .mockReturnValue(); + it('should return the unlocked account', async () => { + const { unlockedAccount } = + await metamaskController.unlockHardwareWalletAccount( + accountToUnlock, + device, + ); + + expect(unlockedAccount).toBe( + KNOWN_PUBLIC_KEY_ADDRESSES[ + accountToUnlock + ].address.toLowerCase(), + ); + }); - await metamaskController.unlockHardwareWalletAccount( - accountToUnlock, - HardwareDeviceNames.trezor, - `m/44'/1'/0'/0`, - ); - }); + it('should add the unlocked account to KeyringController', async () => { + await metamaskController.unlockHardwareWalletAccount( + accountToUnlock, + device, + ); - it('should set unlockedAccount in the keyring', async () => { - const keyrings = - await metamaskController.keyringController.getKeyringsByType( - KeyringType.trezor, - ); - expect(keyrings[0].unlockedAccount).toStrictEqual(accountToUnlock); - }); + expect( + metamaskController.keyringController.state.keyrings[1] + .accounts, + ).toStrictEqual([ + KNOWN_PUBLIC_KEY_ADDRESSES[ + accountToUnlock + ].address.toLowerCase(), + ]); + }); - it('should call keyringController.addNewAccount', async () => { - expect( - metamaskController.keyringController.addNewAccountForKeyring, - ).toHaveBeenCalledTimes(1); - }); + it('should call keyringController.addNewAccountForKeyring', async () => { + jest.spyOn( + metamaskController.keyringController, + 'addNewAccountForKeyring', + ); - it('should call keyringController.getAccounts', async () => { - expect( - metamaskController.keyringController.getAccounts, - ).toHaveBeenCalledTimes(3); - }); + await metamaskController.unlockHardwareWalletAccount( + accountToUnlock, + device, + ); - it('should call preferencesController.setSelectedAddress', async () => { - expect( - metamaskController.preferencesController.setSelectedAddress, - ).toHaveBeenCalledTimes(1); - }); + expect( + metamaskController.keyringController.addNewAccountForKeyring, + ).toHaveBeenCalledTimes(1); + }); - it('should call preferencesController.setAccountLabel', async () => { - expect( - metamaskController.preferencesController.setAccountLabel, - ).toHaveBeenCalledTimes(1); - }); + it('should call preferencesController.setSelectedAddress', async () => { + jest.spyOn( + metamaskController.preferencesController, + 'setSelectedAddress', + ); - it('should call accountsController.getAccountByAddress', async () => { - expect( - metamaskController.accountsController.getAccountByAddress, - ).toHaveBeenCalledTimes(1); + await metamaskController.unlockHardwareWalletAccount( + accountToUnlock, + device, + ); + + expect( + metamaskController.preferencesController.setSelectedAddress, + ).toHaveBeenCalledTimes(1); + }); + + it('should call preferencesController.setAccountLabel', async () => { + jest.spyOn( + metamaskController.preferencesController, + 'setAccountLabel', + ); + + await metamaskController.unlockHardwareWalletAccount( + accountToUnlock, + device, + ); + + expect( + metamaskController.preferencesController.setAccountLabel, + ).toHaveBeenCalledTimes(1); + }); + + it('should call accountsController.getAccountByAddress', async () => { + jest.spyOn( + metamaskController.accountsController, + 'getAccountByAddress', + ); + + await metamaskController.unlockHardwareWalletAccount( + accountToUnlock, + device, + ); + + expect( + metamaskController.accountsController.getAccountByAddress, + ).toHaveBeenCalledTimes(1); + }); + + it('should call accountsController.setAccountName', async () => { + jest.spyOn( + metamaskController.accountsController, + 'setAccountName', + ); + + await metamaskController.unlockHardwareWalletAccount( + accountToUnlock, + device, + ); + + expect( + metamaskController.accountsController.setAccountName, + ).toHaveBeenCalledTimes(1); + }); + }); + }, + ); }); + }); - it('should call accountsController.setAccountName', async () => { - expect( - metamaskController.accountsController.setAccountName, - ).toHaveBeenCalledTimes(1); + describe('getPrimaryKeyringMnemonic', () => { + it('should return a mnemonic as a Uint8Array', () => { + const mockMnemonic = + 'above mercy benefit hospital call oval domain student sphere interest argue shock'; + const mnemonicIndices = mockMnemonic + .split(' ') + .map((word) => englishWordlist.indexOf(word)); + const uint8ArrayMnemonic = new Uint8Array( + new Uint16Array(mnemonicIndices).buffer, + ); + + const mockHDKeyring = { + type: 'HD Key Tree', + mnemonic: uint8ArrayMnemonic, + }; + jest + .spyOn(metamaskController.keyringController, 'getKeyringsByType') + .mockReturnValue([mockHDKeyring]); + + const recoveredMnemonic = + metamaskController.getPrimaryKeyringMnemonic(); + + expect(recoveredMnemonic).toStrictEqual(uint8ArrayMnemonic); }); }); diff --git a/app/scripts/skip-onboarding.js b/app/scripts/skip-onboarding.js index 86b07aae66e5..39c3b0b61865 100644 --- a/app/scripts/skip-onboarding.js +++ b/app/scripts/skip-onboarding.js @@ -100,13 +100,13 @@ async function generateVaultAndAccount(encodedSeedPhrase, password) { return new Uint8Array(new Uint16Array(indices).buffer); }; - const res = await krCtrl.createNewVaultAndRestore( + await krCtrl.createNewVaultAndRestore( password, _convertMnemonicToWordlistIndices(seedPhraseAsBuffer), ); const { vault } = krCtrl.state; - const account = res.keyrings[0].accounts[0]; + const account = krCtrl.state.keyrings[0].accounts[0]; return { vault, account }; } diff --git a/coverage-targets.js b/coverage-targets.js deleted file mode 100644 index 631a8b6e737d..000000000000 --- a/coverage-targets.js +++ /dev/null @@ -1,20 +0,0 @@ -// Codecov uses a yaml file for its configuration and it targets line coverage. -// To keep our policy in place we have thile file separate from our -// codecov.yml file that specifies coverage targets for each project in the -// codecov.yml file. These targets are read by the test/merge-coverage.js -// script, and the paths from the codecov.yml file are used to figure out which -// subset of files to check against these targets. -module.exports = { - global: { - lines: 70.85, - branches: 59.07, - statements: 70.3, - functions: 63.52, - }, - transforms: { - branches: 100, - functions: 100, - lines: 100, - statements: 100, - }, -}; diff --git a/development/ts-migration-dashboard/files-to-convert.json b/development/ts-migration-dashboard/files-to-convert.json index df0feeb26e47..ed5615e8c9d0 100644 --- a/development/ts-migration-dashboard/files-to-convert.json +++ b/development/ts-migration-dashboard/files-to-convert.json @@ -316,7 +316,6 @@ "test/lib/mock-encryptor.js", "test/lib/render-helpers.js", "test/lib/tick.js", - "test/lib/wait-until-called.js", "test/mocks/permissions.js", "test/stub/provider.js", "test/stub/tx-meta-stub.js", diff --git a/jest.config.js b/jest.config.js index 1d6f86938950..f52466a9d183 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,26 +1,8 @@ module.exports = { collectCoverageFrom: [ - '/app/scripts/constants/error-utils.js', - '/app/scripts/controllers/app-metadata.ts', - '/app/scripts/controllers/permissions/**/*.js', - '/app/scripts/controllers/sign.ts', - '/app/scripts/controllers/decrypt-message.ts', - '/app/scripts/controllers/encryption-public-key.ts', - '/app/scripts/controllers/transactions/etherscan.ts', - '/app/scripts/controllers/transactions/EtherscanRemoteTransactionSource.ts', - '/app/scripts/controllers/transactions/IncomingTransactionHelper.ts', - '/app/scripts/controllers/preferences.js', - '/app/scripts/flask/**/*.js', - '/app/scripts/lib/**/*.(js|ts)', - '/app/scripts/metamask-controller.js', - '/app/scripts/migrations/*.js', - '/app/scripts/migrations/*.ts', - '!/app/scripts/migrations/*.test.(js|ts)', - '/app/scripts/platforms/*.js', + '/app/scripts/**/*.(js|ts|tsx)', '/shared/**/*.(js|ts|tsx)', '/ui/**/*.(js|ts|tsx)', - '/development/fitness-functions/**/*.test.(js|ts|tsx)', - '/test/e2e/helpers.test.js', ], coverageDirectory: './coverage', coveragePathIgnorePatterns: ['.stories.*', '.snap'], @@ -41,35 +23,8 @@ module.exports = { setupFiles: ['/test/setup.js', '/test/env.js'], setupFilesAfterEnv: ['/test/jest/setup.js'], testMatch: [ - '/app/scripts/constants/error-utils.test.js', - '/app/scripts/controllers/app-metadata.test.ts', - '/app/scripts/controllers/app-state.test.js', - '/app/scripts/controllers/encryption-public-key.test.ts', - '/app/scripts/controllers/transactions/etherscan.test.ts', - '/app/scripts/controllers/transactions/EtherscanRemoteTransactionSource.test.ts', - '/app/scripts/controllers/transactions/IncomingTransactionHelper.test.ts', - '/app/scripts/controllers/onboarding.test.ts', - '/app/scripts/controllers/mmi-controller.test.ts', - '/app/scripts/controllers/permissions/**/*.test.js', - '/app/scripts/controllers/preferences.test.js', - '/app/scripts/controllers/sign.test.ts', - '/app/scripts/controllers/decrypt-message.test.ts', - '/app/scripts/controllers/authentication/**/*.test.ts', - '/app/scripts/controllers/push-platform-notifications/**/*.test.ts', - '/app/scripts/controllers/user-storage/**/*.test.ts', - '/app/scripts/controllers/metamask-notifications/**/*.test.ts', - '/app/scripts/metamask-controller.actions.test.js', - '/app/scripts/detect-multiple-instances.test.js', - '/app/scripts/controllers/swaps.test.js', - '/app/scripts/controllers/metametrics.test.js', - '/app/scripts/flask/**/*.test.js', - '/app/scripts/lib/**/*.test.(js|ts)', - '/app/scripts/lib/createRPCMethodTrackingMiddleware.test.js', - '/app/scripts/metamask-controller.test.js', - '/app/scripts/migrations/*.test.(js|ts)', - '/app/scripts/platforms/*.test.js', - '/app/scripts/translate.test.ts', - '/shared/**/*.test.(js|ts)', + '/app/scripts/**/*.test.(js|ts|tsx)', + '/shared/**/*.test.(js|ts|tsx)', '/ui/**/*.test.(js|ts|tsx)', '/development/fitness-functions/**/*.test.(js|ts|tsx)', '/test/e2e/helpers.test.js', diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 6834eba9dc46..17fca01f238b 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -526,8 +526,8 @@ "@keystonehq/bc-ur-registry-eth": true, "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring": true, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": true, - "@keystonehq/metamask-airgapped-keyring>rlp": true, "browserify>buffer": true, + "ethereumjs-util>rlp": true, "uuid": true, "webpack>events": true } @@ -537,12 +537,17 @@ "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/util": true, "@keystonehq/bc-ur-registry-eth": true, + "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring>rlp": true, "@metamask/eth-trezor-keyring>hdkey": true, "browserify>buffer": true, - "eth-lattice-keyring>rlp": true, "uuid": true } }, + "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring>rlp": { + "globals": { + "TextEncoder": true + } + }, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": { "packages": { "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>@metamask/safe-event-emitter": true, @@ -591,12 +596,6 @@ "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": true } }, - "@keystonehq/metamask-airgapped-keyring>rlp": { - "packages": { - "bn.js": true, - "browserify>buffer": true - } - }, "@lavamoat/lavadome-react": { "globals": { "Document.prototype": true, @@ -1630,6 +1629,7 @@ "@metamask/keyring-controller>@metamask/eth-simple-keyring": true, "@metamask/keyring-controller>async-mutex": true, "@metamask/keyring-controller>ethereumjs-wallet": true, + "@metamask/name-controller>async-mutex": true, "@metamask/utils": true } }, @@ -1694,18 +1694,12 @@ "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": { "packages": { "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, - "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util>rlp": true, "bn.js": true, "browserify>assert": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, - "ethereumjs-util>create-hash": true - } - }, - "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util>rlp": { - "packages": { - "bn.js": true, - "browserify>buffer": true + "ethereumjs-util>create-hash": true, + "ethereumjs-util>rlp": true } }, "@metamask/logging-controller": { @@ -3907,9 +3901,9 @@ "eth-lattice-keyring>gridplus-sdk>bitwise": true, "eth-lattice-keyring>gridplus-sdk>borc": true, "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": true, + "eth-lattice-keyring>gridplus-sdk>rlp": true, "eth-lattice-keyring>gridplus-sdk>secp256k1": true, "eth-lattice-keyring>gridplus-sdk>uuid": true, - "eth-lattice-keyring>rlp": true, "ethereumjs-util>ethereum-cryptography>bs58check": true, "ethereumjs-util>ethereum-cryptography>hash.js": true, "lodash": true @@ -4008,6 +4002,11 @@ "ganache>abstract-level>buffer": true } }, + "eth-lattice-keyring>gridplus-sdk>rlp": { + "globals": { + "TextEncoder": true + } + }, "eth-lattice-keyring>gridplus-sdk>secp256k1": { "packages": { "@metamask/ppom-validator>elliptic": true diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index 6834eba9dc46..17fca01f238b 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -526,8 +526,8 @@ "@keystonehq/bc-ur-registry-eth": true, "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring": true, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": true, - "@keystonehq/metamask-airgapped-keyring>rlp": true, "browserify>buffer": true, + "ethereumjs-util>rlp": true, "uuid": true, "webpack>events": true } @@ -537,12 +537,17 @@ "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/util": true, "@keystonehq/bc-ur-registry-eth": true, + "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring>rlp": true, "@metamask/eth-trezor-keyring>hdkey": true, "browserify>buffer": true, - "eth-lattice-keyring>rlp": true, "uuid": true } }, + "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring>rlp": { + "globals": { + "TextEncoder": true + } + }, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": { "packages": { "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>@metamask/safe-event-emitter": true, @@ -591,12 +596,6 @@ "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": true } }, - "@keystonehq/metamask-airgapped-keyring>rlp": { - "packages": { - "bn.js": true, - "browserify>buffer": true - } - }, "@lavamoat/lavadome-react": { "globals": { "Document.prototype": true, @@ -1630,6 +1629,7 @@ "@metamask/keyring-controller>@metamask/eth-simple-keyring": true, "@metamask/keyring-controller>async-mutex": true, "@metamask/keyring-controller>ethereumjs-wallet": true, + "@metamask/name-controller>async-mutex": true, "@metamask/utils": true } }, @@ -1694,18 +1694,12 @@ "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": { "packages": { "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, - "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util>rlp": true, "bn.js": true, "browserify>assert": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, - "ethereumjs-util>create-hash": true - } - }, - "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util>rlp": { - "packages": { - "bn.js": true, - "browserify>buffer": true + "ethereumjs-util>create-hash": true, + "ethereumjs-util>rlp": true } }, "@metamask/logging-controller": { @@ -3907,9 +3901,9 @@ "eth-lattice-keyring>gridplus-sdk>bitwise": true, "eth-lattice-keyring>gridplus-sdk>borc": true, "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": true, + "eth-lattice-keyring>gridplus-sdk>rlp": true, "eth-lattice-keyring>gridplus-sdk>secp256k1": true, "eth-lattice-keyring>gridplus-sdk>uuid": true, - "eth-lattice-keyring>rlp": true, "ethereumjs-util>ethereum-cryptography>bs58check": true, "ethereumjs-util>ethereum-cryptography>hash.js": true, "lodash": true @@ -4008,6 +4002,11 @@ "ganache>abstract-level>buffer": true } }, + "eth-lattice-keyring>gridplus-sdk>rlp": { + "globals": { + "TextEncoder": true + } + }, "eth-lattice-keyring>gridplus-sdk>secp256k1": { "packages": { "@metamask/ppom-validator>elliptic": true diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 6834eba9dc46..17fca01f238b 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -526,8 +526,8 @@ "@keystonehq/bc-ur-registry-eth": true, "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring": true, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": true, - "@keystonehq/metamask-airgapped-keyring>rlp": true, "browserify>buffer": true, + "ethereumjs-util>rlp": true, "uuid": true, "webpack>events": true } @@ -537,12 +537,17 @@ "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/util": true, "@keystonehq/bc-ur-registry-eth": true, + "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring>rlp": true, "@metamask/eth-trezor-keyring>hdkey": true, "browserify>buffer": true, - "eth-lattice-keyring>rlp": true, "uuid": true } }, + "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring>rlp": { + "globals": { + "TextEncoder": true + } + }, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": { "packages": { "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>@metamask/safe-event-emitter": true, @@ -591,12 +596,6 @@ "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": true } }, - "@keystonehq/metamask-airgapped-keyring>rlp": { - "packages": { - "bn.js": true, - "browserify>buffer": true - } - }, "@lavamoat/lavadome-react": { "globals": { "Document.prototype": true, @@ -1630,6 +1629,7 @@ "@metamask/keyring-controller>@metamask/eth-simple-keyring": true, "@metamask/keyring-controller>async-mutex": true, "@metamask/keyring-controller>ethereumjs-wallet": true, + "@metamask/name-controller>async-mutex": true, "@metamask/utils": true } }, @@ -1694,18 +1694,12 @@ "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": { "packages": { "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, - "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util>rlp": true, "bn.js": true, "browserify>assert": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, - "ethereumjs-util>create-hash": true - } - }, - "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util>rlp": { - "packages": { - "bn.js": true, - "browserify>buffer": true + "ethereumjs-util>create-hash": true, + "ethereumjs-util>rlp": true } }, "@metamask/logging-controller": { @@ -3907,9 +3901,9 @@ "eth-lattice-keyring>gridplus-sdk>bitwise": true, "eth-lattice-keyring>gridplus-sdk>borc": true, "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": true, + "eth-lattice-keyring>gridplus-sdk>rlp": true, "eth-lattice-keyring>gridplus-sdk>secp256k1": true, "eth-lattice-keyring>gridplus-sdk>uuid": true, - "eth-lattice-keyring>rlp": true, "ethereumjs-util>ethereum-cryptography>bs58check": true, "ethereumjs-util>ethereum-cryptography>hash.js": true, "lodash": true @@ -4008,6 +4002,11 @@ "ganache>abstract-level>buffer": true } }, + "eth-lattice-keyring>gridplus-sdk>rlp": { + "globals": { + "TextEncoder": true + } + }, "eth-lattice-keyring>gridplus-sdk>secp256k1": { "packages": { "@metamask/ppom-validator>elliptic": true diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index c479a4f75381..c32af3459439 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -526,8 +526,8 @@ "@keystonehq/bc-ur-registry-eth": true, "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring": true, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": true, - "@keystonehq/metamask-airgapped-keyring>rlp": true, "browserify>buffer": true, + "ethereumjs-util>rlp": true, "uuid": true, "webpack>events": true } @@ -537,12 +537,17 @@ "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/util": true, "@keystonehq/bc-ur-registry-eth": true, + "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring>rlp": true, "@metamask/eth-trezor-keyring>hdkey": true, "browserify>buffer": true, - "eth-lattice-keyring>rlp": true, "uuid": true } }, + "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring>rlp": { + "globals": { + "TextEncoder": true + } + }, "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": { "packages": { "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>@metamask/safe-event-emitter": true, @@ -591,12 +596,6 @@ "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": true } }, - "@keystonehq/metamask-airgapped-keyring>rlp": { - "packages": { - "bn.js": true, - "browserify>buffer": true - } - }, "@lavamoat/lavadome-react": { "globals": { "Document.prototype": true, @@ -790,56 +789,8 @@ "@metamask-institutional/custody-controller": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask-institutional/custody-controller>@metamask/obs-store": true, - "@metamask-institutional/custody-keyring": true - } - }, - "@metamask-institutional/custody-controller>@metamask/obs-store": { - "packages": { - "@metamask-institutional/custody-controller>@metamask/obs-store>@metamask/safe-event-emitter": true, - "@metamask-institutional/custody-controller>@metamask/obs-store>through2": true, - "stream-browserify": true - } - }, - "@metamask-institutional/custody-controller>@metamask/obs-store>@metamask/safe-event-emitter": { - "globals": { - "setTimeout": true - }, - "packages": { - "webpack>events": true - } - }, - "@metamask-institutional/custody-controller>@metamask/obs-store>through2": { - "packages": { - "@metamask-institutional/custody-controller>@metamask/obs-store>through2>readable-stream": true, - "browserify>process": true, - "browserify>util": true, - "watchify>xtend": true - } - }, - "@metamask-institutional/custody-controller>@metamask/obs-store>through2>readable-stream": { - "packages": { - "@metamask-institutional/custody-controller>@metamask/obs-store>through2>readable-stream>isarray": true, - "@metamask-institutional/custody-controller>@metamask/obs-store>through2>readable-stream>safe-buffer": true, - "@metamask-institutional/custody-controller>@metamask/obs-store>through2>readable-stream>string_decoder": true, - "browserify>browser-resolve": true, - "browserify>process": true, - "browserify>timers-browserify": true, - "pumpify>inherits": true, - "readable-stream-2>core-util-is": true, - "readable-stream-2>process-nextick-args": true, - "readable-stream>util-deprecate": true, - "webpack>events": true - } - }, - "@metamask-institutional/custody-controller>@metamask/obs-store>through2>readable-stream>safe-buffer": { - "packages": { - "browserify>buffer": true - } - }, - "@metamask-institutional/custody-controller>@metamask/obs-store>through2>readable-stream>string_decoder": { - "packages": { - "@metamask-institutional/custody-controller>@metamask/obs-store>through2>readable-stream>safe-buffer": true + "@metamask-institutional/custody-keyring": true, + "@metamask/obs-store": true } }, "@metamask-institutional/custody-keyring": { @@ -851,9 +802,9 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask-institutional/custody-keyring>@metamask-institutional/configuration-client": true, - "@metamask-institutional/custody-keyring>@metamask/obs-store": true, "@metamask-institutional/sdk": true, "@metamask-institutional/sdk>@metamask-institutional/types": true, + "@metamask/obs-store": true, "browserify>crypto-browserify": true, "gulp-sass>lodash.clonedeep": true, "webpack>events": true @@ -865,54 +816,6 @@ "fetch": true } }, - "@metamask-institutional/custody-keyring>@metamask/obs-store": { - "packages": { - "@metamask-institutional/custody-keyring>@metamask/obs-store>@metamask/safe-event-emitter": true, - "@metamask-institutional/custody-keyring>@metamask/obs-store>through2": true, - "stream-browserify": true - } - }, - "@metamask-institutional/custody-keyring>@metamask/obs-store>@metamask/safe-event-emitter": { - "globals": { - "setTimeout": true - }, - "packages": { - "webpack>events": true - } - }, - "@metamask-institutional/custody-keyring>@metamask/obs-store>through2": { - "packages": { - "@metamask-institutional/custody-keyring>@metamask/obs-store>through2>readable-stream": true, - "browserify>process": true, - "browserify>util": true, - "watchify>xtend": true - } - }, - "@metamask-institutional/custody-keyring>@metamask/obs-store>through2>readable-stream": { - "packages": { - "@metamask-institutional/custody-keyring>@metamask/obs-store>through2>readable-stream>isarray": true, - "@metamask-institutional/custody-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": true, - "@metamask-institutional/custody-keyring>@metamask/obs-store>through2>readable-stream>string_decoder": true, - "browserify>browser-resolve": true, - "browserify>process": true, - "browserify>timers-browserify": true, - "pumpify>inherits": true, - "readable-stream-2>core-util-is": true, - "readable-stream-2>process-nextick-args": true, - "readable-stream>util-deprecate": true, - "webpack>events": true - } - }, - "@metamask-institutional/custody-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": { - "packages": { - "browserify>buffer": true - } - }, - "@metamask-institutional/custody-keyring>@metamask/obs-store>through2>readable-stream>string_decoder": { - "packages": { - "@metamask-institutional/custody-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": true - } - }, "@metamask-institutional/extension": { "globals": { "console.log": true @@ -927,55 +830,7 @@ "@metamask-institutional/institutional-features": { "packages": { "@metamask-institutional/custody-keyring": true, - "@metamask-institutional/institutional-features>@metamask/obs-store": true - } - }, - "@metamask-institutional/institutional-features>@metamask/obs-store": { - "packages": { - "@metamask-institutional/institutional-features>@metamask/obs-store>@metamask/safe-event-emitter": true, - "@metamask-institutional/institutional-features>@metamask/obs-store>through2": true, - "stream-browserify": true - } - }, - "@metamask-institutional/institutional-features>@metamask/obs-store>@metamask/safe-event-emitter": { - "globals": { - "setTimeout": true - }, - "packages": { - "webpack>events": true - } - }, - "@metamask-institutional/institutional-features>@metamask/obs-store>through2": { - "packages": { - "@metamask-institutional/institutional-features>@metamask/obs-store>through2>readable-stream": true, - "browserify>process": true, - "browserify>util": true, - "watchify>xtend": true - } - }, - "@metamask-institutional/institutional-features>@metamask/obs-store>through2>readable-stream": { - "packages": { - "@metamask-institutional/institutional-features>@metamask/obs-store>through2>readable-stream>isarray": true, - "@metamask-institutional/institutional-features>@metamask/obs-store>through2>readable-stream>safe-buffer": true, - "@metamask-institutional/institutional-features>@metamask/obs-store>through2>readable-stream>string_decoder": true, - "browserify>browser-resolve": true, - "browserify>process": true, - "browserify>timers-browserify": true, - "pumpify>inherits": true, - "readable-stream-2>core-util-is": true, - "readable-stream-2>process-nextick-args": true, - "readable-stream>util-deprecate": true, - "webpack>events": true - } - }, - "@metamask-institutional/institutional-features>@metamask/obs-store>through2>readable-stream>safe-buffer": { - "packages": { - "browserify>buffer": true - } - }, - "@metamask-institutional/institutional-features>@metamask/obs-store>through2>readable-stream>string_decoder": { - "packages": { - "@metamask-institutional/institutional-features>@metamask/obs-store>through2>readable-stream>safe-buffer": true + "@metamask/obs-store": true } }, "@metamask-institutional/rpc-allowlist": { @@ -989,7 +844,6 @@ "console.debug": true, "console.error": true, "console.log": true, - "console.warn": true, "fetch": true }, "packages": { @@ -1009,7 +863,7 @@ "@ethereumjs/tx>@ethereumjs/util": true, "@metamask-institutional/sdk": true, "@metamask-institutional/transaction-update>@metamask-institutional/websocket-client": true, - "@metamask-institutional/transaction-update>@metamask/obs-store": true, + "@metamask/obs-store": true, "webpack>events": true } }, @@ -1024,54 +878,6 @@ "webpack>events": true } }, - "@metamask-institutional/transaction-update>@metamask/obs-store": { - "packages": { - "@metamask-institutional/transaction-update>@metamask/obs-store>@metamask/safe-event-emitter": true, - "@metamask-institutional/transaction-update>@metamask/obs-store>through2": true, - "stream-browserify": true - } - }, - "@metamask-institutional/transaction-update>@metamask/obs-store>@metamask/safe-event-emitter": { - "globals": { - "setTimeout": true - }, - "packages": { - "webpack>events": true - } - }, - "@metamask-institutional/transaction-update>@metamask/obs-store>through2": { - "packages": { - "@metamask-institutional/transaction-update>@metamask/obs-store>through2>readable-stream": true, - "browserify>process": true, - "browserify>util": true, - "watchify>xtend": true - } - }, - "@metamask-institutional/transaction-update>@metamask/obs-store>through2>readable-stream": { - "packages": { - "@metamask-institutional/transaction-update>@metamask/obs-store>through2>readable-stream>isarray": true, - "@metamask-institutional/transaction-update>@metamask/obs-store>through2>readable-stream>safe-buffer": true, - "@metamask-institutional/transaction-update>@metamask/obs-store>through2>readable-stream>string_decoder": true, - "browserify>browser-resolve": true, - "browserify>process": true, - "browserify>timers-browserify": true, - "pumpify>inherits": true, - "readable-stream-2>core-util-is": true, - "readable-stream-2>process-nextick-args": true, - "readable-stream>util-deprecate": true, - "webpack>events": true - } - }, - "@metamask-institutional/transaction-update>@metamask/obs-store>through2>readable-stream>safe-buffer": { - "packages": { - "browserify>buffer": true - } - }, - "@metamask-institutional/transaction-update>@metamask/obs-store>through2>readable-stream>string_decoder": { - "packages": { - "@metamask-institutional/transaction-update>@metamask/obs-store>through2>readable-stream>safe-buffer": true - } - }, "@metamask/abi-utils": { "packages": { "@metamask/utils": true, @@ -1915,6 +1721,7 @@ "@metamask/keyring-controller>@metamask/eth-simple-keyring": true, "@metamask/keyring-controller>async-mutex": true, "@metamask/keyring-controller>ethereumjs-wallet": true, + "@metamask/name-controller>async-mutex": true, "@metamask/utils": true } }, @@ -1979,18 +1786,12 @@ "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": { "packages": { "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, - "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util>rlp": true, "bn.js": true, "browserify>assert": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, - "ethereumjs-util>create-hash": true - } - }, - "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util>rlp": { - "packages": { - "bn.js": true, - "browserify>buffer": true + "ethereumjs-util>create-hash": true, + "ethereumjs-util>rlp": true } }, "@metamask/logging-controller": { @@ -4192,9 +3993,9 @@ "eth-lattice-keyring>gridplus-sdk>bitwise": true, "eth-lattice-keyring>gridplus-sdk>borc": true, "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": true, + "eth-lattice-keyring>gridplus-sdk>rlp": true, "eth-lattice-keyring>gridplus-sdk>secp256k1": true, "eth-lattice-keyring>gridplus-sdk>uuid": true, - "eth-lattice-keyring>rlp": true, "ethereumjs-util>ethereum-cryptography>bs58check": true, "ethereumjs-util>ethereum-cryptography>hash.js": true, "lodash": true @@ -4293,6 +4094,11 @@ "ganache>abstract-level>buffer": true } }, + "eth-lattice-keyring>gridplus-sdk>rlp": { + "globals": { + "TextEncoder": true + } + }, "eth-lattice-keyring>gridplus-sdk>secp256k1": { "packages": { "@metamask/ppom-validator>elliptic": true diff --git a/lavamoat/build-system/policy.json b/lavamoat/build-system/policy.json index 635158958f06..02078b5d39fc 100644 --- a/lavamoat/build-system/policy.json +++ b/lavamoat/build-system/policy.json @@ -1161,7 +1161,7 @@ "@lavamoat/lavapack>combine-source-map>inline-source-map": true, "@lavamoat/lavapack>combine-source-map>lodash.memoize": true, "@lavamoat/lavapack>combine-source-map>source-map": true, - "nyc>convert-source-map": true + "gulp-sourcemaps>convert-source-map": true } }, "@lavamoat/lavapack>combine-source-map>inline-source-map": { @@ -1670,6 +1670,30 @@ "browserify>duplexer2>readable-stream>safe-buffer": true } }, + "browserify>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": { + "@metamask/object-multiplex>once": true, + "eslint>minimatch": true, + "gulp-watch>path-is-absolute": true, + "mocha>glob>fs.realpath": true, + "mocha>glob>inflight": true, + "pumpify>inherits": true + } + }, "browserify>has": { "packages": { "browserify>has>function-bind": true @@ -2313,7 +2337,7 @@ "setTimeout": true }, "packages": { - "nyc>glob": true + "browserify>glob": true } }, "depcheck>@babel/traverse": { @@ -2552,11 +2576,11 @@ "process.cwd": true }, "packages": { + "browserify>glob": true, "del>is-glob": true, "depcheck>resolve": true, "eslint-plugin-import>tsconfig-paths": true, - "nock>debug": true, - "nyc>glob": true + "nock>debug": true } }, "eslint-plugin-import": { @@ -3910,13 +3934,13 @@ "gulp-sourcemaps>@gulp-sourcemaps/identity-map": true, "gulp-sourcemaps>@gulp-sourcemaps/map-sources": true, "gulp-sourcemaps>acorn": true, + "gulp-sourcemaps>convert-source-map": true, "gulp-sourcemaps>css": true, "gulp-sourcemaps>debug-fabulous": true, "gulp-sourcemaps>detect-newline": true, "gulp-sourcemaps>source-map": true, "gulp-sourcemaps>strip-bom-string": true, - "gulp-sourcemaps>through2": true, - "nyc>convert-source-map": true + "gulp-sourcemaps>through2": true } }, "gulp-sourcemaps>@gulp-sourcemaps/identity-map": { @@ -4033,6 +4057,15 @@ "define": true } }, + "gulp-sourcemaps>convert-source-map": { + "builtin": { + "fs.readFileSync": true, + "path.join": true + }, + "globals": { + "Buffer.from": true + } + }, "gulp-sourcemaps>css": { "builtin": { "fs.readFileSync": true, @@ -5719,7 +5752,7 @@ "gulp>gulp-cli>matchdep>micromatch>fragment-cache": true, "gulp>gulp-cli>matchdep>micromatch>nanomatch>define-property": true, "gulp>gulp-cli>matchdep>micromatch>regex-not": true, - "nyc>spawn-wrap>is-windows": true + "gulp>gulp-cli>replace-homedir>is-absolute>is-windows": true } }, "gulp>gulp-cli>matchdep>micromatch>nanomatch>define-property": { @@ -5737,7 +5770,7 @@ "gulp>gulp-cli>replace-homedir>is-absolute": { "packages": { "gulp>gulp-cli>replace-homedir>is-absolute>is-relative": true, - "nyc>spawn-wrap>is-windows": true + "gulp>gulp-cli>replace-homedir>is-absolute>is-windows": true } }, "gulp>gulp-cli>replace-homedir>is-absolute>is-relative": { @@ -5750,6 +5783,13 @@ "gulp>gulp-cli>replace-homedir>is-absolute>is-relative>is-unc-path>unc-path-regex": true } }, + "gulp>gulp-cli>replace-homedir>is-absolute>is-windows": { + "globals": { + "define": true, + "isWindows": "write", + "process": true + } + }, "gulp>undertaker": { "builtin": { "assert": true, @@ -5970,6 +6010,7 @@ "process.nextTick": true }, "packages": { + "browserify>glob": true, "eslint>glob-parent": true, "gulp>glob-watcher>is-negated-glob": true, "gulp>vinyl-fs>glob-stream>ordered-read-streams": true, @@ -5977,7 +6018,6 @@ "gulp>vinyl-fs>glob-stream>readable-stream": 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, "vinyl>remove-trailing-separator": true } @@ -6464,11 +6504,11 @@ }, "packages": { "del>graceful-fs": true, + "gulp-sourcemaps>convert-source-map": true, "gulp>vinyl-fs>remove-bom-buffer": true, "gulp>vinyl-fs>vinyl-sourcemap>append-buffer": true, "gulp>vinyl-fs>vinyl-sourcemap>normalize-path": true, "gulp>vinyl-fs>vinyl-sourcemap>now-and-later": true, - "nyc>convert-source-map": true, "vinyl": true } }, @@ -6769,7 +6809,7 @@ }, "packages": { "mocha>find-up>locate-path": true, - "nyc>find-up>path-exists": true + "mocha>find-up>path-exists": true } }, "mocha>find-up>locate-path": { @@ -6793,6 +6833,47 @@ "@storybook/test-runner>jest-circus>p-limit": true } }, + "mocha>find-up>path-exists": { + "builtin": { + "fs.access": true, + "fs.accessSync": true, + "util.promisify": true + } + }, + "mocha>glob>fs.realpath": { + "builtin": { + "fs.lstat": true, + "fs.lstatSync": true, + "fs.readlink": true, + "fs.readlinkSync": true, + "fs.realpath": true, + "fs.realpathSync": true, + "fs.stat": true, + "fs.statSync": true, + "path.normalize": true, + "path.resolve": true + }, + "globals": { + "console.error": true, + "console.trace": true, + "process.env.NODE_DEBUG": true, + "process.nextTick": true, + "process.noDeprecation": true, + "process.platform": true, + "process.throwDeprecation": true, + "process.traceDeprecation": true, + "process.version": true + } + }, + "mocha>glob>inflight": { + "globals": { + "process.nextTick": true + }, + "packages": { + "@metamask/object-multiplex>once": true, + "@metamask/object-multiplex>once>wrappy": true + } + }, "mocha>log-symbols": { "packages": { "chalk": true, @@ -6855,105 +6936,6 @@ "node-sass": { "native": true }, - "nyc>convert-source-map": { - "builtin": { - "fs.readFileSync": true, - "path.join": true - }, - "globals": { - "Buffer.from": true - } - }, - "nyc>find-up>path-exists": { - "builtin": { - "fs.access": true, - "fs.accessSync": true, - "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": { - "@metamask/object-multiplex>once": true, - "eslint>minimatch": true, - "gulp-watch>path-is-absolute": true, - "nyc>glob>fs.realpath": true, - "nyc>glob>inflight": true, - "pumpify>inherits": true - } - }, - "nyc>glob>fs.realpath": { - "builtin": { - "fs.lstat": true, - "fs.lstatSync": true, - "fs.readlink": true, - "fs.readlinkSync": true, - "fs.realpath": true, - "fs.realpathSync": true, - "fs.stat": true, - "fs.statSync": true, - "path.normalize": true, - "path.resolve": true - }, - "globals": { - "console.error": true, - "console.trace": true, - "process.env.NODE_DEBUG": true, - "process.nextTick": true, - "process.noDeprecation": true, - "process.platform": true, - "process.throwDeprecation": true, - "process.traceDeprecation": true, - "process.version": true - } - }, - "nyc>glob>inflight": { - "globals": { - "process.nextTick": true - }, - "packages": { - "@metamask/object-multiplex>once": true, - "@metamask/object-multiplex>once>wrappy": true - } - }, - "nyc>resolve-from": { - "builtin": { - "fs.realpathSync": true, - "module._nodeModulePaths": true, - "module._resolveFilename": true, - "path.join": true, - "path.resolve": true - } - }, - "nyc>signal-exit": { - "builtin": { - "assert.equal": true, - "events": true - }, - "globals": { - "process": true - } - }, - "nyc>spawn-wrap>is-windows": { - "globals": { - "define": true, - "isWindows": "write", - "process": true - } - }, "nyc>yargs>set-blocking": { "globals": { "process.stderr": true, @@ -8291,7 +8273,6 @@ "lodash": true, "mocha>log-symbols": true, "nock>debug": true, - "nyc>resolve-from": true, "stylelint>@stylelint/postcss-css-in-js": true, "stylelint>@stylelint/postcss-markdown": true, "stylelint>autoprefixer": true, @@ -8319,6 +8300,7 @@ "stylelint>postcss-selector-parser": true, "stylelint>postcss-syntax": true, "stylelint>postcss-value-parser": true, + "stylelint>resolve-from": true, "stylelint>specificity": true, "stylelint>style-search": true, "stylelint>sugarss": true, @@ -8519,7 +8501,7 @@ "setTimeout": true }, "packages": { - "nyc>glob": true + "browserify>glob": true } }, "stylelint>file-entry-cache>flat-cache>write": { @@ -8821,6 +8803,15 @@ "process.platform": true } }, + "stylelint>resolve-from": { + "builtin": { + "fs.realpathSync": true, + "module._nodeModulePaths": true, + "module._resolveFilename": true, + "path.join": true, + "path.resolve": true + } + }, "stylelint>specificity": { "globals": { "define": true @@ -8932,11 +8923,20 @@ }, "packages": { "eslint>imurmurhash": true, - "nyc>signal-exit": true, "stylelint>write-file-atomic>is-typedarray": true, + "stylelint>write-file-atomic>signal-exit": true, "stylelint>write-file-atomic>typedarray-to-buffer": true } }, + "stylelint>write-file-atomic>signal-exit": { + "builtin": { + "assert.equal": true, + "events": true + }, + "globals": { + "process": true + } + }, "stylelint>write-file-atomic>typedarray-to-buffer": { "globals": { "Buffer.from": true diff --git a/nyc.config.js b/nyc.config.js deleted file mode 100644 index 408ea27b427b..000000000000 --- a/nyc.config.js +++ /dev/null @@ -1,17 +0,0 @@ -// nyc is our coverage reporter for mocha, and currently is collecting -// coverage for .yarn folder. all of these are default excludes except the -// .yarn/** entry. This entire file should be removable once we complete the -// migration from mocha to jest in the app folder. -module.exports = { - exclude: [ - 'coverage/**', - 'packages/*/test/**', - 'test/**', - 'test{,-*}.js', - '**/*{.,-}test.js', - '**/__tests__/**', - '**/node_modules/**', - '**/babel.config.js', - '.yarn/**', - ], -}; diff --git a/package.json b/package.json index 049a59abceed..b95a8584f4a1 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "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:flask": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js --build-type flask", + "test:api-specs": "SELENIUM_BROWSER=chrome ts-node test/e2e/run-openrpc-api-test-coverage.ts", "test:e2e:mmi:ci": "yarn playwright test", "test:e2e:mmi:all": "yarn playwright test --project=mmi && yarn test:e2e:mmi:visual", "test:e2e:mmi:regular": "yarn playwright test --project=mmi", @@ -59,8 +60,7 @@ "test:e2e:single": "node test/e2e/run-e2e-test.js", "test:coverage:jest": "node ./test/run-unit-tests.js --jestGlobal --coverage", "test:coverage:jest:dev": "node ./test/run-unit-tests.js --jestDev --coverage", - "test:coverage:validate": "node ./test/merge-coverage.js", - "test:coverage": "node ./test/run-unit-tests.js --jestGlobal --jestDev --coverage && yarn test:coverage:validate", + "test:coverage": "node ./test/run-unit-tests.js --jestGlobal --jestDev --coverage", "test:coverage:html": "yarn test:coverage --html", "ganache:start": "./development/run-ganache.sh", "sentry:publish": "node ./development/sentry-publish.js", @@ -243,9 +243,6 @@ "@babel/runtime@npm:^7.18.3": "patch:@babel/runtime@npm%3A7.24.0#~/.yarn/patches/@babel-runtime-npm-7.24.0-7eb1dd11a2.patch", "@babel/runtime@npm:^7.8.3": "patch:@babel/runtime@npm%3A7.24.0#~/.yarn/patches/@babel-runtime-npm-7.24.0-7eb1dd11a2.patch", "@babel/runtime@npm:^7.8.4": "patch:@babel/runtime@npm%3A7.24.0#~/.yarn/patches/@babel-runtime-npm-7.24.0-7eb1dd11a2.patch", - "@metamask/keyring-controller@npm:^13.0.0": "patch:@metamask/keyring-controller@npm%3A15.0.0#~/.yarn/patches/@metamask-keyring-controller-npm-15.0.0-fa070ce311.patch", - "@metamask/keyring-controller@npm:^12.2.0": "patch:@metamask/keyring-controller@npm%3A15.0.0#~/.yarn/patches/@metamask-keyring-controller-npm-15.0.0-fa070ce311.patch", - "@metamask/keyring-controller@npm:^14.0.1": "patch:@metamask/keyring-controller@npm%3A15.0.0#~/.yarn/patches/@metamask-keyring-controller-npm-15.0.0-fa070ce311.patch", "@spruceid/siwe-parser@npm:1.1.3": "patch:@spruceid/siwe-parser@npm%3A2.1.0#~/.yarn/patches/@spruceid-siwe-parser-npm-2.1.0-060b7ede7a.patch", "@spruceid/siwe-parser@npm:2.1.0": "patch:@spruceid/siwe-parser@npm%3A2.1.0#~/.yarn/patches/@spruceid-siwe-parser-npm-2.1.0-060b7ede7a.patch", "@trezor/connect-web@npm:^9.2.2": "patch:@trezor/connect-web@npm%3A9.2.2#~/.yarn/patches/@trezor-connect-web-npm-9.2.2-a4de8e45fc.patch", @@ -278,14 +275,14 @@ "@lavamoat/lavadome-react": "0.0.17", "@lavamoat/snow": "^2.0.1", "@material-ui/core": "^4.11.0", - "@metamask-institutional/custody-controller": "^0.2.27", - "@metamask-institutional/custody-keyring": "^2.0.0", - "@metamask-institutional/extension": "^0.3.24", - "@metamask-institutional/institutional-features": "^1.3.2", + "@metamask-institutional/custody-controller": "^0.2.30", + "@metamask-institutional/custody-keyring": "^2.0.3", + "@metamask-institutional/extension": "^0.3.27", + "@metamask-institutional/institutional-features": "^1.3.5", "@metamask-institutional/portfolio-dashboard": "^1.4.1", "@metamask-institutional/rpc-allowlist": "^1.0.3", - "@metamask-institutional/sdk": "^0.1.27", - "@metamask-institutional/transaction-update": "^0.2.2", + "@metamask-institutional/sdk": "^0.1.30", + "@metamask-institutional/transaction-update": "^0.2.5", "@metamask/abi-utils": "^2.0.2", "@metamask/accounts-controller": "^16.0.0", "@metamask/address-book-controller": "^4.0.1", @@ -313,7 +310,7 @@ "@metamask/gas-fee-controller": "patch:@metamask/gas-fee-controller@npm%3A15.1.2#~/.yarn/patches/@metamask-gas-fee-controller-npm-15.1.2-db4d2976aa.patch", "@metamask/jazzicon": "^2.0.0", "@metamask/keyring-api": "^8.0.0", - "@metamask/keyring-controller": "patch:@metamask/keyring-controller@npm%3A15.0.0#~/.yarn/patches/@metamask-keyring-controller-npm-15.0.0-fa070ce311.patch", + "@metamask/keyring-controller": "^16.1.0", "@metamask/logging-controller": "^3.0.1", "@metamask/logo": "^3.1.2", "@metamask/message-manager": "^7.3.0", @@ -336,7 +333,7 @@ "@metamask/safe-event-emitter": "^3.1.1", "@metamask/scure-bip39": "^2.0.3", "@metamask/selected-network-controller": "^15.0.2", - "@metamask/signature-controller": "^14.0.1", + "@metamask/signature-controller": "^16.0.0", "@metamask/smart-transactions-controller": "^10.1.2", "@metamask/snaps-controllers": "^9.0.0", "@metamask/snaps-execution-environments": "^6.4.0", @@ -448,6 +445,7 @@ "@lavamoat/lavadome-core": "0.0.10", "@lavamoat/lavapack": "^6.1.0", "@lgbot/madge": "^6.2.0", + "@metamask/api-specs": "^0.9.3", "@metamask/auto-changelog": "^2.1.0", "@metamask/build-utils": "^1.0.0", "@metamask/eslint-config": "^9.0.0", @@ -461,6 +459,10 @@ "@metamask/test-bundler": "^1.0.0", "@metamask/test-dapp": "^8.4.0", "@octokit/core": "^3.6.0", + "@open-rpc/meta-schema": "^1.14.6", + "@open-rpc/mock-server": "^1.7.5", + "@open-rpc/schema-utils-js": "^1.16.2", + "@open-rpc/test-coverage": "^2.2.2", "@playwright/test": "^1.39.0", "@sentry/cli": "^2.19.4", "@storybook/addon-a11y": "^7.6.19", @@ -573,9 +575,6 @@ "history": "^5.0.0", "husky": "^8.0.3", "ini": "^3.0.0", - "istanbul-lib-coverage": "^3.2.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-reports": "^3.1.5", "jest": "^29.7.0", "jest-canvas-mock": "^2.3.1", "jest-environment-jsdom": "^29.7.0", @@ -591,7 +590,6 @@ "mockttp": "^3.10.1", "nock": "patch:nock@npm%3A13.5.4#~/.yarn/patches/nock-npm-13.5.4-2c4f77b249.patch", "node-fetch": "^2.6.1", - "nyc": "^15.1.0", "postcss": "^8.4.32", "postcss-rtlcss": "^4.0.9", "prettier": "^2.7.1", diff --git a/shared/constants/metametrics.ts b/shared/constants/metametrics.ts index a5065ea2dadd..82c6a557be4f 100644 --- a/shared/constants/metametrics.ts +++ b/shared/constants/metametrics.ts @@ -580,6 +580,7 @@ export enum MetaMetricsEventName { OnboardingWalletAdvancedSettingsWithAuthenticating = 'Settings Updated with Authenticating', OnboardingWalletAdvancedSettingsWithoutAuthenticating = 'Settings Updated without Authenticating', OnboardingWalletAdvancedSettingsTurnOffProfileSyncing = 'Turn Off Profile Syncing', + OnboardingWalletAdvancedSettingsTurnOnProfileSyncing = 'Turn On Profile Syncing', OnboardingWalletImportAttempted = 'Wallet Import Attempted', OnboardingWalletVideoPlay = 'SRP Intro Video Played', OnboardingTwitterClick = 'External Link Clicked', diff --git a/shared/constants/network.ts b/shared/constants/network.ts index 62fe072bf0c0..452f0584ffaa 100644 --- a/shared/constants/network.ts +++ b/shared/constants/network.ts @@ -1116,3 +1116,10 @@ export const TEST_NETWORKS = [ LINEA_GOERLI_DISPLAY_NAME, LINEA_SEPOLIA_DISPLAY_NAME, ]; + +export const TEST_NETWORK_IDS = [ + CHAIN_IDS.GOERLI, + CHAIN_IDS.SEPOLIA, + CHAIN_IDS.LINEA_GOERLI, + CHAIN_IDS.LINEA_SEPOLIA, +]; diff --git a/shared/lib/swaps-utils.js b/shared/lib/swaps-utils.js index f27f4c9e8a8f..62c71ecbaadb 100644 --- a/shared/lib/swaps-utils.js +++ b/shared/lib/swaps-utils.js @@ -18,6 +18,8 @@ import { addHexPrefix } from '../../app/scripts/lib/util'; import { decimalToHex } from '../modules/conversion.utils'; import fetchWithCache from './fetch-with-cache'; +const FALLBACK_GAS_MULTIPLIER = 1.5; + const TEST_CHAIN_IDS = [CHAIN_IDS.GOERLI, CHAIN_IDS.LOCALHOST]; const clientIdHeader = { 'X-Client-Id': SWAPS_CLIENT_ID }; @@ -325,3 +327,37 @@ export async function fetchTradesInfo( return newQuotes; } + +/** + * Given a gas estimate, gas multiplier, max gas, and custom max gas, returns the max gas limit + * to use for a transaction. + * + * @param {string} gasEstimate - The gas estimate for the transaction. + * @param {number} gasMultiplier - The gas multiplier to use. + * @param {number} maxGas - The max gas limit to use. + * @param {string} customMaxGas - The custom max gas limit to use. + * @returns {string} The max gas limit to use for the transaction. + */ + +export function calculateMaxGasLimit( + gasEstimate, + gasMultiplier = FALLBACK_GAS_MULTIPLIER, + maxGas, + customMaxGas, +) { + const gasLimitForMax = new BigNumber(gasEstimate || 0, 16) + .round(0) + .toString(16); + + const usedGasLimitWithMultiplier = new BigNumber(gasLimitForMax, 16) + .times(gasMultiplier, 10) + .round(0) + .toString(16); + + const nonCustomMaxGasLimit = gasEstimate + ? usedGasLimitWithMultiplier + : `0x${decimalToHex(maxGas || 0)}`; + const maxGasLimit = customMaxGas || nonCustomMaxGasLimit; + + return maxGasLimit; +} diff --git a/shared/lib/swaps-utils.test.js b/shared/lib/swaps-utils.test.js index 5db5fb23085b..4cbc0927e1f3 100644 --- a/shared/lib/swaps-utils.test.js +++ b/shared/lib/swaps-utils.test.js @@ -10,7 +10,11 @@ import { TOKENS, MOCK_TRADE_RESPONSE_2, } from '../../ui/pages/swaps/swaps-util-test-constants'; -import { fetchTradesInfo, shouldEnableDirectWrapping } from './swaps-utils'; +import { + fetchTradesInfo, + shouldEnableDirectWrapping, + calculateMaxGasLimit, +} from './swaps-utils'; jest.mock('./storage-helpers', () => ({ getStorageItem: jest.fn(), @@ -224,4 +228,46 @@ describe('Swaps Utils', () => { expect(shouldEnableDirectWrapping(CHAIN_IDS.MAINNET)).toBe(false); }); }); + + describe('calculateMaxGasLimit', () => { + const gasEstimate = '0x37b15'; + const maxGas = 273740; + let expectedMaxGas = '42d4c'; + let gasMultiplier = 1.2; + let customMaxGas = ''; + + it('should return the max gas limit', () => { + const result = calculateMaxGasLimit( + gasEstimate, + gasMultiplier, + maxGas, + customMaxGas, + ); + expect(result).toStrictEqual(expectedMaxGas); + }); + + it('should return the custom max gas limit', () => { + customMaxGas = '46d4c'; + const result = calculateMaxGasLimit( + gasEstimate, + gasMultiplier, + maxGas, + customMaxGas, + ); + expect(result).toStrictEqual(customMaxGas); + }); + + it('should return the max gas limit with a gas multiplier of 4.5', () => { + gasMultiplier = 4.5; + expectedMaxGas = 'fa9df'; + customMaxGas = ''; + const result = calculateMaxGasLimit( + gasEstimate, + gasMultiplier, + maxGas, + customMaxGas, + ); + expect(result).toStrictEqual(expectedMaxGas); + }); + }); }); diff --git a/test/e2e/api-specs/ConfirmationRejectionRule.ts b/test/e2e/api-specs/ConfirmationRejectionRule.ts new file mode 100644 index 000000000000..9a8348357a69 --- /dev/null +++ b/test/e2e/api-specs/ConfirmationRejectionRule.ts @@ -0,0 +1,224 @@ +import Rule from '@open-rpc/test-coverage/build/rules/rule'; +import { Call } from '@open-rpc/test-coverage/build/coverage'; +import { + ContentDescriptorObject, + ExampleObject, + ExamplePairingObject, + MethodObject, +} from '@open-rpc/meta-schema'; +import paramsToObj from '@open-rpc/test-coverage/build/utils/params-to-obj'; +import { Driver } from '../webdriver/driver'; +import { WINDOW_TITLES, switchToOrOpenDapp } from '../helpers'; +import { addToQueue } from './helpers'; + +type ConfirmationsRejectRuleOptions = { + driver: Driver; + only: string[]; +}; +// this rule makes sure that all confirmation requests are rejected. +// it also validates that the JSON-RPC response is an error with +// error code 4001 (user rejected request) +export class ConfirmationsRejectRule implements Rule { + private driver: Driver; + + private only: string[]; + + private rejectButtonInsteadOfCancel: string[]; + + private requiresEthAccountsPermission: string[]; + + constructor(options: ConfirmationsRejectRuleOptions) { + this.driver = options.driver; + this.only = options.only; + this.rejectButtonInsteadOfCancel = [ + 'personal_sign', + 'eth_signTypedData_v4', + ]; + this.requiresEthAccountsPermission = [ + 'personal_sign', + 'eth_signTypedData_v4', + 'eth_getEncryptionPublicKey', + ]; + } + + getTitle() { + return 'Confirmations Rejection Rule'; + } + + async beforeRequest(_: unknown, call: Call) { + await new Promise((resolve, reject) => { + addToQueue({ + name: 'beforeRequest', + resolve, + reject, + task: async () => { + try { + if (this.requiresEthAccountsPermission.includes(call.methodName)) { + const requestPermissionsRequest = JSON.stringify({ + jsonrpc: '2.0', + method: 'wallet_requestPermissions', + params: [{ eth_accounts: {} }], + }); + + await this.driver.executeScript( + `window.ethereum.request(${requestPermissionsRequest})`, + ); + const screenshot = await this.driver.driver.takeScreenshot(); + call.attachments = call.attachments || []; + call.attachments.push({ + type: 'image', + data: `data:image/png;base64,${screenshot}`, + }); + + await this.driver.waitUntilXWindowHandles(3); + await this.driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + + await this.driver.findClickableElements({ + text: 'Next', + tag: 'button', + }); + + const screenshotTwo = await this.driver.driver.takeScreenshot(); + call.attachments.push({ + type: 'image', + data: `data:image/png;base64,${screenshotTwo}`, + }); + + await this.driver.clickElement({ + text: 'Next', + tag: 'button', + }); + + await this.driver.clickElement({ + text: 'Confirm', + tag: 'button', + }); + + await switchToOrOpenDapp(this.driver); + } + } catch (e) { + console.log(e); + } + }, + }); + }); + } + + async afterRequest(_: unknown, call: Call) { + await new Promise((resolve, reject) => { + addToQueue({ + name: 'afterRequest', + resolve, + reject, + task: async () => { + try { + await this.driver.waitUntilXWindowHandles(3); + await this.driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + + let text = 'Cancel'; + if (this.rejectButtonInsteadOfCancel.includes(call.methodName)) { + await this.driver.findClickableElements({ + text: 'Reject', + tag: 'button', + }); + text = 'Reject'; + } else { + await this.driver.findClickableElements({ + text: 'Cancel', + tag: 'button', + }); + } + const screenshot = await this.driver.driver.takeScreenshot(); + call.attachments = call.attachments || []; + call.attachments.push({ + type: 'image', + data: `data:image/png;base64,${screenshot}`, + }); + await this.driver.clickElement({ text, tag: 'button' }); + // make sure to switch back to the dapp or else the next test will fail on the wrong window + await switchToOrOpenDapp(this.driver); + } catch (e) { + console.log(e); + } + }, + }); + }); + } + + // get all the confirmation calls to make and expect to pass + getCalls(_: unknown, method: MethodObject) { + const calls: Call[] = []; + const isMethodAllowed = this.only ? this.only.includes(method.name) : true; + if (isMethodAllowed) { + if (method.examples) { + // pull the first example + const e = method.examples[0]; + const ex = e as ExamplePairingObject; + + if (!ex.result) { + return calls; + } + const p = ex.params.map((_e) => (_e as ExampleObject).value); + const params = + method.paramStructure === 'by-name' + ? paramsToObj(p, method.params as ContentDescriptorObject[]) + : p; + calls.push({ + title: `${this.getTitle()} - with example ${ex.name}`, + methodName: method.name, + params, + url: '', + resultSchema: (method.result as ContentDescriptorObject).schema, + expectedResult: (ex.result as ExampleObject).value, + }); + } else { + // naively call the method with no params + calls.push({ + title: `${method.name} > confirmation rejection`, + methodName: method.name, + params: [], + url: '', + resultSchema: (method.result as ContentDescriptorObject).schema, + }); + } + } + return calls; + } + + async afterResponse(_: unknown, call: Call) { + await new Promise((resolve, reject) => { + addToQueue({ + name: 'afterResponse', + resolve, + reject, + task: async () => { + try { + if (this.requiresEthAccountsPermission.includes(call.methodName)) { + const revokePermissionsRequest = JSON.stringify({ + jsonrpc: '2.0', + method: 'wallet_revokePermissions', + params: [{ eth_accounts: {} }], + }); + + await this.driver.executeScript( + `window.ethereum.request(${revokePermissionsRequest})`, + ); + } + } catch (e) { + console.log(e); + } + }, + }); + }); + } + + validateCall(call: Call) { + if (call.error) { + call.valid = call.error.code === 4001; + if (!call.valid) { + call.reason = `Expected error code 4001, got ${call.error.code}`; + } + } + return call; + } +} diff --git a/test/e2e/api-specs/helpers.ts b/test/e2e/api-specs/helpers.ts new file mode 100644 index 000000000000..d4f4d3be22c5 --- /dev/null +++ b/test/e2e/api-specs/helpers.ts @@ -0,0 +1,135 @@ +import { v4 as uuid } from 'uuid'; +import { ErrorObject } from '@open-rpc/meta-schema'; +import { Driver } from '../webdriver/driver'; + +// eslint-disable-next-line @typescript-eslint/no-shadow, @typescript-eslint/no-explicit-any +declare let window: any; + +type QueueItem = { + task: () => Promise; + resolve: (value: unknown) => void; + reject: (reason?: unknown) => void; + name: string; +}; + +export const taskQueue: QueueItem[] = []; +let isProcessing = false; + +export const processQueue = async () => { + if (isProcessing || taskQueue.length === 0) { + return; + } + + isProcessing = true; + const item = taskQueue.shift(); + if (!item) { + return; + } + const { task, resolve, reject }: QueueItem | undefined = item; + try { + const result = await task(); + resolve(result); + } catch (error) { + reject(error); + } finally { + isProcessing = false; + await processQueue(); + } +}; + +export const addToQueue = ({ task, resolve, reject, name }: QueueItem) => { + taskQueue.push({ task, resolve, reject, name }); + return processQueue(); +}; + +export const pollForResult = async ( + driver: Driver, + generatedKey: string, +): Promise => { + let result; + // eslint-disable-next-line no-loop-func + await new Promise((resolve, reject) => { + addToQueue({ + name: 'pollResult', + resolve, + reject, + task: async () => { + result = await driver.executeScript( + `return window['${generatedKey}'];`, + ); + + while (result === null) { + // Continue polling if result is not set + await driver.delay(500); + result = await driver.executeScript( + `return window['${generatedKey}'];`, + ); + } + + // clear the result + await driver.executeScript(`delete window['${generatedKey}'];`); + + return result; + }, + }); + }); + if (result !== undefined) { + return result; + } + return pollForResult(driver, generatedKey); +}; + +export const createDriverTransport = (driver: Driver) => { + return async ( + _: string, + method: string, + params: unknown[] | Record, + ) => { + const generatedKey = uuid(); + return new Promise((resolve, reject) => { + const execute = async () => { + await addToQueue({ + name: 'transport', + resolve, + reject, + task: async () => { + // don't wait for executeScript to finish window.ethereum promise + // we need this because if we wait for the promise to resolve it + // will hang in selenium since it can only do one thing at a time. + // the workaround is to put the response on window.asyncResult and poll for it. + driver.executeScript( + ([m, p, g]: [ + string, + unknown[] | Record, + string, + ]) => { + window[g] = null; + window.ethereum + .request({ method: m, params: p }) + .then((r: unknown) => { + window[g] = { result: r }; + }) + .catch((e: ErrorObject) => { + window[g] = { + error: { + code: e.code, + message: e.message, + data: e.data, + }, + }; + }); + }, + method, + params, + generatedKey, + ); + }, + }); + }; + return execute(); + }).then(async () => { + const response = await pollForResult(driver, generatedKey); + return response; + }); + }; +}; diff --git a/test/e2e/helpers.js b/test/e2e/helpers.js index f3ab5f59d3c0..41951f973aa9 100644 --- a/test/e2e/helpers.js +++ b/test/e2e/helpers.js @@ -44,6 +44,7 @@ async function withFixtures(options, testSuite) { title, ignoredConsoleErrors = [], dappPath = undefined, + disableGanache, dappPaths, testSpecificMock = function () { // do nothing. @@ -54,7 +55,10 @@ async function withFixtures(options, testSuite) { } = options; const fixtureServer = new FixtureServer(); - const ganacheServer = new Ganache(); + let ganacheServer; + if (!disableGanache) { + ganacheServer = new Ganache(); + } const bundlerServer = new Bundler(); const https = await mockttp.generateCACertificate(); const mockServer = mockttp.getLocal({ https, cors: true }); @@ -67,10 +71,12 @@ async function withFixtures(options, testSuite) { let driver; let failed = false; try { - await ganacheServer.start(ganacheOptions); + if (!disableGanache) { + await ganacheServer.start(ganacheOptions); + } let contractRegistry; - if (smartContract) { + if (smartContract && !disableGanache) { const ganacheSeeder = new GanacheSeeder(ganacheServer.getProvider()); const contracts = smartContract instanceof Array ? smartContract : [smartContract]; @@ -97,7 +103,7 @@ async function withFixtures(options, testSuite) { }); } - if (useBundler) { + if (!disableGanache && useBundler) { await initBundler(bundlerServer, ganacheServer, usePaymaster); } @@ -263,7 +269,9 @@ async function withFixtures(options, testSuite) { } finally { if (!failed || process.env.E2E_LEAVE_RUNNING !== 'true') { await fixtureServer.stop(); - await ganacheServer.quit(); + if (ganacheServer) { + await ganacheServer.quit(); + } if (ganacheOptions?.concurrent) { secondaryGanacheServer.forEach(async (server) => { diff --git a/test/e2e/mmi/specs/visual.spec.ts-snapshots/custodian-connection-info-mmi-visual-linux.png b/test/e2e/mmi/specs/visual.spec.ts-snapshots/custodian-connection-info-mmi-visual-linux.png index a722d3cc1bc7..8b628e6b61cc 100644 Binary files a/test/e2e/mmi/specs/visual.spec.ts-snapshots/custodian-connection-info-mmi-visual-linux.png and b/test/e2e/mmi/specs/visual.spec.ts-snapshots/custodian-connection-info-mmi-visual-linux.png differ diff --git a/test/e2e/run-openrpc-api-test-coverage.ts b/test/e2e/run-openrpc-api-test-coverage.ts new file mode 100644 index 000000000000..f192f6088954 --- /dev/null +++ b/test/e2e/run-openrpc-api-test-coverage.ts @@ -0,0 +1,410 @@ +import testCoverage from '@open-rpc/test-coverage'; +import { parseOpenRPCDocument } from '@open-rpc/schema-utils-js'; +import HtmlReporter from '@open-rpc/test-coverage/build/reporters/html-reporter'; +import ExamplesRule from '@open-rpc/test-coverage/build/rules/examples-rule'; +import JsonSchemaFakerRule from '@open-rpc/test-coverage/build/rules/json-schema-faker-rule'; + +import { + ExampleObject, + ExamplePairingObject, + MethodObject, +} from '@open-rpc/meta-schema'; +import openrpcDocument from '@metamask/api-specs'; +import { ConfirmationsRejectRule } from './api-specs/ConfirmationRejectionRule'; + +import { Driver, PAGES } from './webdriver/driver'; + +import { createDriverTransport } from './api-specs/helpers'; + +import FixtureBuilder from './fixture-builder'; +import { + withFixtures, + openDapp, + unlockWallet, + DAPP_URL, + ACCOUNT_1, +} from './helpers'; + +// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires +const mockServer = require('@open-rpc/mock-server/build/index').default; + +async function main() { + const port = 8545; + const chainId = 1337; + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder().build(), + disableGanache: true, + title: 'api-specs coverage', + }, + async ({ driver }: { driver: Driver }) => { + await unlockWallet(driver); + + // Navigate to extension home screen + await driver.navigate(PAGES.HOME); + + // Open Dapp + await openDapp(driver, undefined, DAPP_URL); + + const transport = createDriverTransport(driver); + + const transaction = + openrpcDocument.components?.schemas?.TransactionInfo?.allOf?.[0]; + + if (transaction) { + delete transaction.unevaluatedProperties; + } + + const chainIdMethod = openrpcDocument.methods.find( + (m) => (m as MethodObject).name === 'eth_chainId', + ); + (chainIdMethod as MethodObject).examples = [ + { + name: 'chainIdExample', + description: 'Example of a chainId request', + params: [], + result: { + name: 'chainIdResult', + value: `0x${chainId.toString(16)}`, + }, + }, + ]; + + const getBalanceMethod = openrpcDocument.methods.find( + (m) => (m as MethodObject).name === 'eth_getBalance', + ); + + (getBalanceMethod as MethodObject).examples = [ + { + name: 'getBalanceExample', + description: 'Example of a getBalance request', + params: [ + { + name: 'address', + value: ACCOUNT_1, + }, + { + name: 'tag', + value: 'latest', + }, + ], + result: { + name: 'getBalanceResult', + value: '0x1a8819e0c9bab700', // can we get this from a variable too + }, + }, + ]; + + const blockNumber = openrpcDocument.methods.find( + (m) => (m as MethodObject).name === 'eth_blockNumber', + ); + + (blockNumber as MethodObject).examples = [ + { + name: 'blockNumberExample', + description: 'Example of a blockNumber request', + params: [], + result: { + name: 'blockNumberResult', + value: '0x1', + }, + }, + ]; + + const personalSign = openrpcDocument.methods.find( + (m) => (m as MethodObject).name === 'personal_sign', + ); + + (personalSign as MethodObject).examples = [ + { + name: 'personalSignExample', + description: 'Example of a personalSign request', + params: [ + { + name: 'data', + value: '0xdeadbeef', + }, + { + name: 'address', + value: ACCOUNT_1, + }, + ], + result: { + name: 'personalSignResult', + value: '0x1a8819e0c9bab700', + }, + }, + ]; + + const switchEthereumChain = openrpcDocument.methods.find( + (m) => (m as MethodObject).name === 'wallet_switchEthereumChain', + ); + (switchEthereumChain as MethodObject).examples = [ + { + name: 'wallet_switchEthereumChain', + description: + 'Example of a wallet_switchEthereumChain request to sepolia', + params: [ + { + name: 'SwitchEthereumChainParameter', + value: { + chainId: '0xaa36a7', + }, + }, + ], + result: { + name: 'wallet_switchEthereumChain', + value: null, + }, + }, + ]; + + const signTypedData4 = openrpcDocument.methods.find( + (m) => (m as MethodObject).name === 'eth_signTypedData_v4', + ); + + const signTypedData4Example = (signTypedData4 as MethodObject) + .examples?.[0] as ExamplePairingObject; + + // just update address for signTypedData + (signTypedData4Example.params[0] as ExampleObject).value = ACCOUNT_1; + + // update chainId for signTypedData + ( + signTypedData4Example.params[1] as ExampleObject + ).value.domain.chainId = 1337; + + // net_version missing from execution-apis. see here: https://github.com/ethereum/execution-apis/issues/540 + const netVersion: MethodObject = { + name: 'net_version', + summary: 'Returns the current network ID.', + params: [], + result: { + description: 'Returns the current network ID.', + name: 'net_version', + schema: { + type: 'string', + }, + }, + description: 'Returns the current network ID.', + examples: [ + { + name: 'net_version', + description: 'Example of a net_version request', + params: [], + result: { + name: 'net_version', + description: 'The current network ID', + value: '0x1', + }, + }, + ], + }; + // add net_version + (openrpcDocument.methods as MethodObject[]).push( + netVersion as unknown as MethodObject, + ); + + const getEncryptionPublicKey = openrpcDocument.methods.find( + (m) => (m as MethodObject).name === 'eth_getEncryptionPublicKey', + ); + + (getEncryptionPublicKey as MethodObject).examples = [ + { + name: 'getEncryptionPublicKeyExample', + description: 'Example of a getEncryptionPublicKey request', + params: [ + { + name: 'address', + value: ACCOUNT_1, + }, + ], + result: { + name: 'getEncryptionPublicKeyResult', + value: '0x1a8819e0c9bab700', + }, + }, + ]; + + const getTransactionCount = openrpcDocument.methods.find( + (m) => (m as MethodObject).name === 'eth_getTransactionCount', + ); + (getTransactionCount as MethodObject).examples = [ + { + name: 'getTransactionCountExampleEarliest', + description: 'Example of a pending getTransactionCount request', + params: [ + { + name: 'address', + value: ACCOUNT_1, + }, + { + name: 'tag', + value: 'earliest', + }, + ], + result: { + name: 'getTransactionCountResult', + value: '0x0', + }, + }, + { + name: 'getTransactionCountExampleFinalized', + description: 'Example of a pending getTransactionCount request', + params: [ + { + name: 'address', + value: ACCOUNT_1, + }, + { + name: 'tag', + value: 'finalized', + }, + ], + result: { + name: 'getTransactionCountResult', + value: '0x0', + }, + }, + { + name: 'getTransactionCountExampleSafe', + description: 'Example of a pending getTransactionCount request', + params: [ + { + name: 'address', + value: ACCOUNT_1, + }, + { + name: 'tag', + value: 'safe', + }, + ], + result: { + name: 'getTransactionCountResult', + value: '0x0', + }, + }, + { + name: 'getTransactionCountExample', + description: 'Example of a getTransactionCount request', + params: [ + { + name: 'address', + value: ACCOUNT_1, + }, + { + name: 'tag', + value: 'latest', + }, + ], + result: { + name: 'getTransactionCountResult', + value: '0x0', + }, + }, + // returns a number right now. see here: https://github.com/MetaMask/metamask-extension/pull/14822 + // { + // name: 'getTransactionCountExamplePending', + // description: 'Example of a pending getTransactionCount request', + // params: [ + // { + // name: 'address', + // value: ACCOUNT_1, + // }, + // { + // name: 'tag', + // value: 'pending', + // }, + // ], + // result: { + // name: 'getTransactionCountResult', + // value: '0x0', + // }, + // }, + ]; + + const server = mockServer(port, openrpcDocument); + server.start(); + + // TODO: move these to a "Confirmation" tag in api-specs + const methodsWithConfirmations = [ + 'wallet_requestPermissions', + 'eth_requestAccounts', + 'wallet_watchAsset', + 'personal_sign', // requires permissions for eth_accounts + 'wallet_addEthereumChain', + 'eth_signTypedData_v4', // requires permissions for eth_accounts + 'wallet_switchEthereumChain', + + // commented out because its not returning 4001 error. + // see here https://github.com/MetaMask/metamask-extension/issues/24227 + // 'eth_getEncryptionPublicKey', // requires permissions for eth_accounts + ]; + const filteredMethods = openrpcDocument.methods + .filter((_m: unknown) => { + const m = _m as MethodObject; + return ( + m.name.includes('snap') || + m.name.includes('Snap') || + m.name.toLowerCase().includes('account') || + m.name.includes('crypt') || + m.name.includes('blob') || + m.name.includes('sendTransaction') || + m.name.startsWith('wallet_scanQRCode') || + methodsWithConfirmations.includes(m.name) || + // filters are currently 0 prefixed for odd length on + // extension which doesn't pass spec + // see here: https://github.com/MetaMask/eth-json-rpc-filters/issues/152 + m.name.includes('filter') || + m.name.includes('Filter') + ); + }) + .map((m) => (m as MethodObject).name); + + const testCoverageResults = await testCoverage({ + openrpcDocument: (await parseOpenRPCDocument( + openrpcDocument as never, + )) as never, + transport, + reporters: [ + 'console-streaming', + new HtmlReporter({ autoOpen: !process.env.CI }), + ], + skip: [ + 'eth_coinbase', + // these 2 methods below are not supported by MetaMask extension yet and + // don't get passed through. See here: https://github.com/MetaMask/metamask-extension/issues/24225 + 'eth_getBlockReceipts', + 'eth_maxPriorityFeePerGas', + ], + rules: [ + new JsonSchemaFakerRule({ + only: [], + skip: filteredMethods, + numCalls: 2, + }), + new ExamplesRule({ + only: [], + skip: filteredMethods, + }), + new ConfirmationsRejectRule({ + driver, + only: methodsWithConfirmations, + }), + ], + }); + + await driver.quit(); + + // if any of the tests failed, exit with a non-zero code + if (testCoverageResults.every((r) => r.valid)) { + process.exit(0); + } else { + process.exit(1); + } + }, + ); +} + +main(); diff --git a/test/e2e/tests/confirmations/signatures/permit.spec.ts b/test/e2e/tests/confirmations/signatures/permit.spec.ts index 5afe288f869b..8320fd748f63 100644 --- a/test/e2e/tests/confirmations/signatures/permit.spec.ts +++ b/test/e2e/tests/confirmations/signatures/permit.spec.ts @@ -85,7 +85,7 @@ async function assertInfoValues(driver: Driver) { }); const value = driver.findElement({ text: '3000' }); const nonce = driver.findElement({ text: '0' }); - const deadline = driver.findElement({ text: '50000000000' }); + const deadline = driver.findElement({ text: '02 August 1971, 16:53' }); assert.ok(await origin, 'origin'); assert.ok(await contractPetName, 'contractPetName'); diff --git a/test/e2e/tests/request-queuing/chain-id-check.spec.js b/test/e2e/tests/request-queuing/chain-id-check.spec.js deleted file mode 100644 index 780254295796..000000000000 --- a/test/e2e/tests/request-queuing/chain-id-check.spec.js +++ /dev/null @@ -1,103 +0,0 @@ -const { strict: assert } = require('assert'); -const FixtureBuilder = require('../../fixture-builder'); -const { - withFixtures, - openDapp, - unlockWallet, - DAPP_URL, - regularDelayMs, - WINDOW_TITLES, - defaultGanacheOptions, - switchToNotificationWindow, -} = require('../../helpers'); -const { PAGES } = require('../../webdriver/driver'); - -describe('Request Queuing', function () { - it('should keep chain id the same with request queuing and switching mm network with a connected site.', async function () { - const port = 8546; - const chainId = 1338; - await withFixtures( - { - dapp: true, - fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() - .withPreferencesControllerUseRequestQueueEnabled() - .withSelectedNetworkControllerPerDomain() - .build(), - ganacheOptions: { - ...defaultGanacheOptions, - concurrent: [ - { - port, - chainId, - ganacheOptions2: defaultGanacheOptions, - }, - ], - }, - title: this.test.fullTitle(), - }, - async ({ driver }) => { - await unlockWallet(driver); - - // Navigate to extension home screen - await driver.navigate(PAGES.HOME); - - // Open Dapp One - await openDapp(driver, undefined, DAPP_URL); - - // Connect to dapp - await driver.findClickableElement({ text: 'Connect', tag: 'button' }); - await driver.clickElement('#connectButton'); - - await driver.delay(regularDelayMs); - - await switchToNotificationWindow(driver); - - await driver.clickElement({ - text: 'Next', - tag: 'button', - css: '[data-testid="page-container-footer-next"]', - }); - - await driver.clickElement({ - text: 'Confirm', - tag: 'button', - css: '[data-testid="page-container-footer-next"]', - }); - - await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); - - const request = JSON.stringify({ - method: 'eth_chainId', - }); - - const firstChainIdCall = await driver.executeScript( - `return window.ethereum.request(${request})`, - ); - - assert.equal(firstChainIdCall, '0x539'); // 1337 - - await driver.switchToWindowWithTitle( - WINDOW_TITLES.ExtensionInFullScreenView, - ); - - // Network Selector - await driver.clickElement('[data-testid="network-display"]'); - - // Switch to second network - await driver.clickElement({ - text: 'Localhost 8546', - css: 'p', - }); - - await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); - - const secondChainIdCall = await driver.executeScript( - `return window.ethereum.request(${request})`, - ); - - assert.equal(secondChainIdCall, '0x539'); // 1337 - }, - ); - }); -}); diff --git a/test/e2e/tests/request-queuing/chainid-check.spec.js b/test/e2e/tests/request-queuing/chainid-check.spec.js index 664cb1117d3c..850051d39c6a 100644 --- a/test/e2e/tests/request-queuing/chainid-check.spec.js +++ b/test/e2e/tests/request-queuing/chainid-check.spec.js @@ -12,123 +12,315 @@ const { } = require('../../helpers'); const { PAGES } = require('../../webdriver/driver'); -describe('Request-queue chainId proxy sync', function () { - it('should preserve per dapp network selections after connecting without refresh calls @no-mmi', async function () { - const port = 8546; - const chainId = 1338; - await withFixtures( - { - dapp: true, - fixtures: new FixtureBuilder() - .withNetworkControllerDoubleGanache() - .withPreferencesControllerUseRequestQueueEnabled() - .withSelectedNetworkControllerPerDomain() - .build(), - ganacheOptions: { - ...defaultGanacheOptions, - concurrent: [ - { - port, - chainId, - ganacheOptions2: defaultGanacheOptions, - }, - ], +describe('Request Queueing chainId proxy sync', function () { + describe('request queue is on', function () { + it('should preserve per dapp network selections after connecting and switching without refresh calls @no-mmi', async function () { + const port = 8546; + const chainId = 1338; + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withNetworkControllerDoubleGanache() + .withPreferencesControllerUseRequestQueueEnabled() + .withSelectedNetworkControllerPerDomain() + .build(), + ganacheOptions: { + ...defaultGanacheOptions, + concurrent: [ + { + port, + chainId, + ganacheOptions2: defaultGanacheOptions, + }, + ], + }, + title: this.test.fullTitle(), }, - title: this.test.fullTitle(), - }, - async ({ driver }) => { - await unlockWallet(driver); + async ({ driver }) => { + await unlockWallet(driver); - // Navigate to extension home screen - await driver.navigate(PAGES.HOME); + // Navigate to extension home screen + await driver.navigate(PAGES.HOME); - // Open Dapp One - await openDapp(driver, undefined, DAPP_URL); + // Open Dapp One + await openDapp(driver, undefined, DAPP_URL); - await driver.delay(regularDelayMs); + await driver.delay(regularDelayMs); - const chainIdRequest = JSON.stringify({ - method: 'eth_chainId', - }); + const chainIdRequest = JSON.stringify({ + method: 'eth_chainId', + }); - const chainIdCheckBeforeConnect = await driver.executeScript( - `return window.ethereum.request(${chainIdRequest})`, - ); + const chainIdBeforeConnect = await driver.executeScript( + `return window.ethereum.request(${chainIdRequest})`, + ); - assert.equal(chainIdCheckBeforeConnect, '0x539'); // 1337 + assert.equal(chainIdBeforeConnect, '0x539'); // 1337 - await driver.switchToWindowWithTitle( - WINDOW_TITLES.ExtensionInFullScreenView, - ); + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); - // Network Selector - await driver.clickElement('[data-testid="network-display"]'); + // Network Selector + await driver.clickElement('[data-testid="network-display"]'); - // Switch to second network - await driver.clickElement({ - text: 'Ethereum Mainnet', - css: 'p', - }); + // Switch to second network + await driver.clickElement({ + text: 'Ethereum Mainnet', + css: 'p', + }); - await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); - const secondChainIdCheckBeforeConnect = await driver.executeScript( - `return window.ethereum.request(${chainIdRequest})`, - ); + const chainIdBeforeConnectAfterManualSwitch = + await driver.executeScript( + `return window.ethereum.request(${chainIdRequest})`, + ); - // before connecting the chainId should change with the wallet - assert.equal(secondChainIdCheckBeforeConnect, '0x1'); + // before connecting the chainId should change with the wallet + assert.equal(chainIdBeforeConnectAfterManualSwitch, '0x1'); - // Connect to dapp - await driver.findClickableElement({ text: 'Connect', tag: 'button' }); - await driver.clickElement('#connectButton'); + // Connect to dapp + await driver.findClickableElement({ text: 'Connect', tag: 'button' }); + await driver.clickElement('#connectButton'); - await driver.delay(regularDelayMs); + await driver.delay(regularDelayMs); - await switchToNotificationWindow(driver); + await switchToNotificationWindow(driver); - await driver.clickElement({ - text: 'Next', - tag: 'button', - css: '[data-testid="page-container-footer-next"]', - }); + await driver.clickElement({ + text: 'Next', + tag: 'button', + css: '[data-testid="page-container-footer-next"]', + }); - await driver.clickElement({ - text: 'Confirm', - tag: 'button', - css: '[data-testid="page-container-footer-next"]', - }); + await driver.clickElement({ + text: 'Confirm', + tag: 'button', + css: '[data-testid="page-container-footer-next"]', + }); - await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); - const firstChainIdCallAfterConnect = await driver.executeScript( - `return window.ethereum.request(${chainIdRequest})`, - ); + const chainIdAfterConnect = await driver.executeScript( + `return window.ethereum.request(${chainIdRequest})`, + ); - assert.equal(firstChainIdCallAfterConnect, '0x1'); + // should still be on the same chainId as the wallet after connecting + assert.equal(chainIdAfterConnect, '0x1'); - await driver.switchToWindowWithTitle( - WINDOW_TITLES.ExtensionInFullScreenView, - ); + const switchEthereumChainRequest = JSON.stringify({ + jsonrpc: '2.0', + method: 'wallet_switchEthereumChain', + params: [{ chainId: '0x539' }], + }); - // Network Selector - await driver.clickElement('[data-testid="network-display"]'); + await driver.executeScript( + `window.ethereum.request(${switchEthereumChainRequest})`, + ); - // Switch to second network - await driver.clickElement({ - text: 'Localhost 8546', - css: 'p', - }); + await switchToNotificationWindow(driver); + await driver.findClickableElements({ + text: 'Switch network', + tag: 'button', + }); - await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + await driver.clickElement({ text: 'Switch network', tag: 'button' }); - const secondChainIdCall = await driver.executeScript( - `return window.ethereum.request(${chainIdRequest})`, - ); - // after connecting the dapp should now have its own selected network - // independent from the globally selected and therefore should not have changed - assert.equal(secondChainIdCall, '0x1'); - }, - ); + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + + const chainIdAfterDappSwitch = await driver.executeScript( + `return window.ethereum.request(${chainIdRequest})`, + ); + + // should be on the new chainId that was requested + assert.equal(chainIdAfterDappSwitch, '0x539'); // 1337 + + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); + + // Network Selector + await driver.clickElement('[data-testid="network-display"]'); + + // Switch network + await driver.clickElement({ + text: 'Localhost 8546', + css: 'p', + }); + + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + + const chainIdAfterManualSwitch = await driver.executeScript( + `return window.ethereum.request(${chainIdRequest})`, + ); + // after connecting the dapp should now have its own selected network + // independent from the globally selected and therefore should not have changed when + // the globally selected network was manually changed via the wallet UI + assert.equal(chainIdAfterManualSwitch, '0x539'); // 1337 + }, + ); + }); + }); + + describe('request queue is off', function () { + it('should always follow the globally selected network after connecting and switching without refresh calls @no-mmi', async function () { + const port = 8546; + const chainId = 1338; + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withNetworkControllerDoubleGanache() + .build(), + ganacheOptions: { + ...defaultGanacheOptions, + concurrent: [ + { + port, + chainId, + ganacheOptions2: defaultGanacheOptions, + }, + ], + }, + title: this.test.fullTitle(), + }, + async ({ driver }) => { + 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="experimental-setting-toggle-request-queue"]', + ); + + // Navigate to extension home screen + await driver.navigate(PAGES.HOME); + + // Open Dapp One + await openDapp(driver, undefined, DAPP_URL); + + await driver.delay(regularDelayMs); + + const chainIdRequest = JSON.stringify({ + method: 'eth_chainId', + }); + + const chainIdBeforeConnect = await driver.executeScript( + `return window.ethereum.request(${chainIdRequest})`, + ); + + assert.equal(chainIdBeforeConnect, '0x539'); // 1337 + + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); + + // Network Selector + await driver.clickElement('[data-testid="network-display"]'); + + // Switch to second network + await driver.clickElement({ + text: 'Ethereum Mainnet', + css: 'p', + }); + + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + + const chainIdBeforeConnectAfterManualSwitch = + await driver.executeScript( + `return window.ethereum.request(${chainIdRequest})`, + ); + + // before connecting the chainId should change with the wallet + assert.equal(chainIdBeforeConnectAfterManualSwitch, '0x1'); + + // Connect to dapp + await driver.findClickableElement({ text: 'Connect', tag: 'button' }); + await driver.clickElement('#connectButton'); + + await driver.delay(regularDelayMs); + + await switchToNotificationWindow(driver); + + await driver.clickElement({ + text: 'Next', + tag: 'button', + css: '[data-testid="page-container-footer-next"]', + }); + + await driver.clickElement({ + text: 'Confirm', + tag: 'button', + css: '[data-testid="page-container-footer-next"]', + }); + + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + + const chainIdAfterConnect = await driver.executeScript( + `return window.ethereum.request(${chainIdRequest})`, + ); + + // should still be on the same chainId as the wallet after connecting + assert.equal(chainIdAfterConnect, '0x1'); + + const switchEthereumChainRequest = JSON.stringify({ + jsonrpc: '2.0', + method: 'wallet_switchEthereumChain', + params: [{ chainId: '0x539' }], + }); + + await driver.executeScript( + `window.ethereum.request(${switchEthereumChainRequest})`, + ); + + await switchToNotificationWindow(driver); + await driver.findClickableElements({ + text: 'Switch network', + tag: 'button', + }); + + await driver.clickElement({ text: 'Switch network', tag: 'button' }); + + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + + const chainIdAfterDappSwitch = await driver.executeScript( + `return window.ethereum.request(${chainIdRequest})`, + ); + + // should be on the new chainId that was requested + assert.equal(chainIdAfterDappSwitch, '0x539'); // 1337 + + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); + + // TODO: check that the wallet network has changed too + + // Network Selector + await driver.clickElement('[data-testid="network-display"]'); + + // Switch network + await driver.clickElement({ + text: 'Ethereum Mainnet', + css: 'p', + }); + + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + + const chainIdAfterManualSwitch = await driver.executeScript( + `return window.ethereum.request(${chainIdRequest})`, + ); + // after connecting the dapp should still be following the + // globally selected network and therefore should have changed when + // the globally selected network was manually changed via the wallet UI + assert.equal(chainIdAfterManualSwitch, '0x1'); + }, + ); + }); }); }); diff --git a/test/e2e/tests/request-queuing/dapp1-switch-dapp2-send.spec.js b/test/e2e/tests/request-queuing/dapp1-switch-dapp2-send.spec.js index 02f496f68235..6cab2f88d96b 100644 --- a/test/e2e/tests/request-queuing/dapp1-switch-dapp2-send.spec.js +++ b/test/e2e/tests/request-queuing/dapp1-switch-dapp2-send.spec.js @@ -12,7 +12,7 @@ const { } = require('../../helpers'); describe('Request Queuing Dapp 1, Switch Tx -> Dapp 2 Send Tx', function () { - it('should queue send tx after switch network confirmation.', async function () { + it('should queue send tx after switch network confirmation and transaction should target the correct network after switch is confirmed', async function () { const port = 8546; const chainId = 1338; await withFixtures( @@ -165,4 +165,158 @@ describe('Request Queuing Dapp 1, Switch Tx -> Dapp 2 Send Tx', function () { }, ); }); + + it('should queue send tx after switch network confirmation and transaction should target the correct network after switch is cancelled.', async function () { + const port = 8546; + const chainId = 1338; + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withNetworkControllerTripleGanache() + .withPreferencesControllerUseRequestQueueEnabled() + .withSelectedNetworkControllerPerDomain() + .build(), + dappOptions: { numberOfDapps: 2 }, + ganacheOptions: { + ...defaultGanacheOptions, + concurrent: [ + { + port, + chainId, + ganacheOptions2: defaultGanacheOptions, + }, + { + port: 7777, + chainId: 1000, + ganacheOptions2: defaultGanacheOptions, + }, + ], + }, + title: this.test.fullTitle(), + }, + async ({ driver }) => { + await unlockWallet(driver); + + // Open Dapp One + await openDapp(driver, undefined, DAPP_URL); + + // Connect to dapp + await driver.findClickableElement({ text: 'Connect', tag: 'button' }); + await driver.clickElement('#connectButton'); + + await driver.delay(regularDelayMs); + + await switchToNotificationWindow(driver); + + await driver.clickElement({ + text: 'Next', + tag: 'button', + css: '[data-testid="page-container-footer-next"]', + }); + + await driver.clickElement({ + text: 'Confirm', + tag: 'button', + css: '[data-testid="page-container-footer-next"]', + }); + + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); + + // Network Selector + await driver.clickElement('[data-testid="network-display"]'); + + // Switch to second network + await driver.clickElement({ + text: 'Localhost 8546', + css: 'p', + }); + + // Wait for the first dapp's connect confirmation to disappear + await driver.waitUntilXWindowHandles(2); + + // TODO: Request Queuing bug when opening both dapps at the same time will have them stuck on the same network, with will be incorrect for one of them. + // Open Dapp Two + await openDapp(driver, undefined, DAPP_ONE_URL); + + // Connect to dapp 2 + await driver.findClickableElement({ text: 'Connect', tag: 'button' }); + await driver.clickElement('#connectButton'); + + await driver.delay(regularDelayMs); + + await switchToNotificationWindow(driver, 4); + + await driver.clickElement({ + text: 'Next', + tag: 'button', + css: '[data-testid="page-container-footer-next"]', + }); + + await driver.clickElement({ + text: 'Confirm', + tag: 'button', + css: '[data-testid="page-container-footer-next"]', + }); + + await driver.switchToWindowWithUrl(DAPP_URL); + + // switchEthereumChain request + const switchEthereumChainRequest = JSON.stringify({ + jsonrpc: '2.0', + method: 'wallet_switchEthereumChain', + params: [{ chainId: '0x3e8' }], + }); + + // Initiate switchEthereumChain on Dapp Two + await driver.executeScript( + `window.ethereum.request(${switchEthereumChainRequest})`, + ); + + await driver.switchToWindowWithUrl(DAPP_ONE_URL); + + await driver.clickElement('#sendButton'); + + await switchToNotificationWindow(driver, 4); + await driver.findClickableElements({ + text: 'Cancel', + tag: 'button', + }); + + await driver.clickElement({ text: 'Cancel', tag: 'button' }); + + // Wait for switch confirmation to close then tx confirmation to show. + await driver.waitUntilXWindowHandles(3); + + await switchToNotificationWindow(driver, 4); + + // Check correct network on the send confirmation. + await driver.findElement({ + css: '[data-testid="network-display"]', + text: 'Localhost 8546', + }); + + await driver.clickElement({ text: 'Confirm', tag: 'button' }); + + // Switch back to the extension + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); + + await driver.clickElement( + '[data-testid="account-overview__activity-tab"]', + ); + + // Check for transaction + await driver.wait(async () => { + const confirmedTxes = await driver.findElements( + '.transaction-list__completed-transactions .activity-list-item', + ); + return confirmedTxes.length === 1; + }, 10000); + }, + ); + }); }); diff --git a/test/e2e/tests/tokens/increase-token-allowance.spec.js b/test/e2e/tests/tokens/increase-token-allowance.spec.js index 4fb092906558..52a7d9454e38 100644 --- a/test/e2e/tests/tokens/increase-token-allowance.spec.js +++ b/test/e2e/tests/tokens/increase-token-allowance.spec.js @@ -232,6 +232,8 @@ describe('Increase Token Allowance', function () { }); await driver.delay(2000); + // Windows: MetaMask, Test Dapp and Dialog + await driver.waitUntilXWindowHandles(3); await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); let spendingCapElement = await driver.findElement( '[data-testid="custom-spending-cap-input"]', @@ -297,6 +299,8 @@ describe('Increase Token Allowance', function () { } async function confirmTransferFromTokensSuccess(driver) { + // Windows: MetaMask, Test Dapp and Dialog + await driver.waitUntilXWindowHandles(3, 1000, 10000); await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); await driver.waitForSelector({ text: '1.5 TST', tag: 'h1' }); await driver.clickElement({ text: 'Confirm', tag: 'button' }); diff --git a/test/lib/wait-until-called.js b/test/lib/wait-until-called.js deleted file mode 100644 index c59e51aa4c69..000000000000 --- a/test/lib/wait-until-called.js +++ /dev/null @@ -1,66 +0,0 @@ -const DEFAULT_TIMEOUT = 10000; - -/** - * A function that wraps a sinon stub and returns an asynchronous function - * that resolves if the stubbed function was called enough times, or throws - * if the timeout is exceeded. - * - * The stub that has been passed in will be setup to call the wrapped function - * directly. - * - * WARNING: Any existing `callsFake` behavior will be overwritten. - * - * @param {import('sinon').stub} stub - A sinon stub of a function - * @param {unknown} [wrappedThis] - The object the stubbed function was called - * on, if any (i.e. the `this` value) - * @param {object} [options] - Optional configuration - * @param {number} [options.callCount] - The number of calls to wait for. - * @param {number|null} [options.timeout] - The timeout, in milliseconds. Pass - * in `null` to disable the timeout. - * @returns {Function} An asynchronous function that resolves when the stub is - * called enough times, or throws if the timeout is reached. - */ -function waitUntilCalled( - stub, - wrappedThis = null, - { callCount = 1, timeout = DEFAULT_TIMEOUT } = {}, -) { - let numCalls = 0; - let resolve; - let timeoutHandle; - const stubHasBeenCalled = new Promise((_resolve) => { - resolve = _resolve; - if (timeout !== null) { - timeoutHandle = setTimeout( - () => resolve(new Error('Timeout exceeded')), - timeout, - ); - } - }); - stub.callsFake((...args) => { - try { - if (stub.wrappedMethod) { - stub.wrappedMethod.call(wrappedThis, ...args); - } - } finally { - if (numCalls < callCount) { - numCalls += 1; - if (numCalls === callCount) { - if (timeoutHandle) { - clearTimeout(timeoutHandle); - } - resolve(); - } - } - } - }); - - return async () => { - const error = await stubHasBeenCalled; - if (error) { - throw error; - } - }; -} - -module.exports = waitUntilCalled; diff --git a/test/merge-coverage.js b/test/merge-coverage.js deleted file mode 100644 index 1a6617a4e90b..000000000000 --- a/test/merge-coverage.js +++ /dev/null @@ -1,268 +0,0 @@ -const fs = require('fs'); -const path = require('path'); -const libCoverage = require('istanbul-lib-coverage'); -const libReport = require('istanbul-lib-report'); -const reports = require('istanbul-reports'); -const glob = require('fast-glob'); -const yargs = require('yargs/yargs'); -const { hideBin } = require('yargs/helpers'); -// Temporarily commented out as we can't rely on the commented yaml file -// Can be restored when the codecov checks are restored -// const yaml = require('yaml'); -const codecovTargets = require('../coverage-targets'); - -// Temporarily commented out as we can't rely on the commented yaml file -// Can be restored when the codecov checks are restored. In the meantime -// the important parts of the yaml file are copied below in normal js object -// format. -// const codecovConfig = yaml.parse(fs.readFileSync('codecov.yml', 'utf8')); - -const codecovConfig = { - coverage: { - status: { - global: {}, - project: { - transforms: { - paths: ['development/build/transforms/**/*.js'], - }, - }, - }, - }, -}; - -const COVERAGE_DIR = './coverage/'; - -const COVERAGE_THRESHOLD_FOR_BUMP = 1; - -/** - * Load .json file at path and parse it into a javascript object - * - * @param {string} filePath - path to the file to load - * @returns {object} the JavaScript object parsed from the file - */ -function loadData(filePath) { - const json = fs.readFileSync(filePath); - return JSON.parse(json); -} - -/** - * Loads an array of json coverage files and merges them into a final coverage - * report. - * - * @param {string[]} files - array of strings that are paths to files - * @returns {libCoverage.CoverageMap} CoverageMap - */ -function mergeCoverageMaps(files) { - const coverageMap = libCoverage.createCoverageMap({}); - - files.forEach((covergeFinalFile) => { - coverageMap.merge(loadData(covergeFinalFile)); - }); - - return coverageMap; -} - -/** - * Given a target directory and a coverageMap generates a finalized coverage - * summary report and saves it to the directory. - * - * @param {string} dir - target directory - * @param {libCoverage.CoverageMap} coverageMap - CoverageMap to report on - * @param reportType - * @param reportOptions - */ -function generateSummaryReport(dir, coverageMap, reportType, reportOptions) { - const context = libReport.createContext({ - dir, - coverageMap, - }); - - reports.create(reportType, reportOptions ?? {}).execute(context); -} - -/** - * Generates a multiline string with coverage data - * - * @param {CoverageTarget} target - Target coverage threshold - * @param {import('istanbul-lib-coverage').CoverageSummaryData} actual - - * istanbul coverage summary detailing actual summary - * @returns {string} multiline report of coverage - */ -function generateConsoleReport(target, actual) { - const { lines, branches, functions, statements } = actual.data; - const breakdown = - `Lines: ${lines.covered}/${lines.total} (${lines.pct}%). Target: ${target.lines}%\n` + - `Branches: ${branches.covered}/${branches.total} (${branches.pct}%). Target: ${target.branches}%\n` + - `Statements: ${statements.covered}/${statements.total} (${statements.pct}%). Target: ${target.statements}%\n` + - `Functions: ${functions.covered}/${functions.total} (${functions.pct}%). Target: ${target.functions}%`; - return breakdown; -} - -/** - * @typedef {object} CoverageTarget - * @property {number} lines - percentage of lines that must be covered - * @property {number} statements - percentage of statements that must be covered - * @property {number} branches - percentage of branches that must be covered - * @property {number} functions - percentage of functions that must be covered - */ - -/** - * Checks if the coverage meets target - * - * @param {CoverageTarget} target - * @param {import('istanbul-lib-coverage').CoverageSummaryData} actual - * @returns {boolean} - */ -function isCoverageInsufficient(target, actual) { - const lineCoverageNotMet = actual.lines.pct < target.lines; - const branchCoverageNotMet = actual.branches.pct < target.branches; - const functionCoverageNotMet = actual.functions.pct < target.functions; - const statementCoverageNotMet = actual.statements.pct < target.statements; - return ( - lineCoverageNotMet || - branchCoverageNotMet || - functionCoverageNotMet || - statementCoverageNotMet - ); -} - -/** - * Checks if the coverage should be bumped up - * - * @param {CoverageTarget} target - * @param {import('istanbul-lib-coverage').CoverageSummaryData} actual - * @returns {boolean} - */ -function shouldCoverageBeBumped(target, actual) { - const lineCoverageNeedsBumped = - actual.lines.pct > target.lines + COVERAGE_THRESHOLD_FOR_BUMP; - const branchCoverageNeedsBumped = - actual.branches.pct > target.branches + COVERAGE_THRESHOLD_FOR_BUMP; - const functionCoverageNeedsBumped = - actual.functions.pct > target.functions + COVERAGE_THRESHOLD_FOR_BUMP; - const statementCoverageNeedsBumped = - actual.statements.pct > target.statements + COVERAGE_THRESHOLD_FOR_BUMP; - return ( - lineCoverageNeedsBumped || - branchCoverageNeedsBumped || - functionCoverageNeedsBumped || - statementCoverageNeedsBumped - ); -} - -/** - * Creates and returns a combined coverage summary report of every file in the - * provided array. - * - * @param {string[]} files - array of files generated by fast-glob - * @param {libCoverage.CoverageMap} coverageMap - * @returns {import('istanbul-lib-coverage').CoverageSummaryData} - */ -function getFileCoverage(files, coverageMap) { - const subCoverageMap = libCoverage.createCoverageMap({}); - - files.forEach((file) => { - try { - subCoverageMap.merge( - coverageMap.fileCoverageFor(`${process.cwd()}/${file}`), - ); - } catch { - // If the coverage doesn't exist, it means that it was excluded from - // coverage or had no coverage to report, which is fine. Glob is a lot - // wider of a net then what the test file runners match against. - } - }); - - const summary = subCoverageMap.getCoverageSummary(); - return summary; -} - -/** - * Checks coverage and reports to console - * Throws an error if coverage isn't met - * - * @param {string} name - The target's name from coverageThresholds in jest - * config - * @param {CoverageTarget} target - the target coverage threshold - * @param {import('istanbul-lib-coverage').CoverageSummaryData} actual - - * istanbul coverage summary representing actual coverage - */ -function checkCoverage(name, target, actual) { - const breakdown = generateConsoleReport(target, actual); - if (isCoverageInsufficient(target, actual)) { - const errorMsg = `Coverage thresholds for ${name} NOT met\n${breakdown}`; - throw new Error(errorMsg); - } else if (shouldCoverageBeBumped(target, actual)) { - const errorMsg = `Coverage EXCEEDS threshold for ${name} and must be bumped\n${breakdown}`; - throw new Error(errorMsg); - } - console.log(`Coverage thresholds for ${name} met\n${breakdown}\n\n`); -} - -/** - * Primary script function - */ -async function start() { - const { - argv: { html }, - } = yargs(hideBin(process.argv)).usage( - '$0 [options]', - 'Run unit tests on the application code.', - (yargsInstance) => - yargsInstance - .option('html', { - alias: ['h'], - default: false, - description: 'Generate HTML report', - type: 'boolean', - }) - .strict(), - ); - // First get all of the files matching the pattern coverage-final-${n}.json - // from the coverage directory - const files = fs.readdirSync(COVERAGE_DIR); - const filePaths = files - .filter( - (file) => - path.basename(file).startsWith('coverage-final') && - path.extname(file) === '.json', - ) - .map((file) => path.join(COVERAGE_DIR, file)); - - // Next, generate a coverageMap - const coverageMap = mergeCoverageMaps(filePaths, true); - - // Persist this to file, which may eventually be used in more steps - generateSummaryReport(COVERAGE_DIR, coverageMap, 'json-summary'); - if (html) { - generateSummaryReport(COVERAGE_DIR, coverageMap, 'html'); - } - - // Use the keys in coverageThreshold in jest config to determine targets - const coverageTargets = Object.keys(codecovConfig.coverage.status.project); - - // Check coverage totals for each target - coverageTargets.forEach((target) => { - const summary = - target === 'global' - ? coverageMap.getCoverageSummary() - : getFileCoverage( - glob.sync([ - ...codecovConfig.coverage.status.project[target].paths, - // checking test file coverage is redundant. - '!**/*.test.js', - '!**/__mocks__/**/*.js', - '!**/*.stories.*', - ]), - coverageMap, - ); - // Check and validate the coverage - checkCoverage(target, codecovTargets[target], summary); - }); -} - -start().catch((error) => { - // Report the errored coverage check - console.error(error); - process.exit(1); -}); diff --git a/test/run-unit-tests.js b/test/run-unit-tests.js index a58a858c09c8..645bcfc02e1b 100644 --- a/test/run-unit-tests.js +++ b/test/run-unit-tests.js @@ -64,45 +64,14 @@ async function runJest( } } -/** - * Run mocha tests on the app directory. Mocha tests do not yet support - * parallelism / test-splitting. - * - * @param {boolean} coverage - Use nyc to collect coverage - */ -async function runMocha({ coverage }) { - const options = ['mocha', './app/**/*.test.js']; - // If coverage is true, then we need to run nyc as the first command - // and mocha after, so we use unshift to add three options to the beginning - // of the options array. - if (coverage) { - options.unshift('nyc', '--reporter=json', 'yarn'); - } - await runInShell('yarn', options); - if (coverage) { - // Once done we rename the coverage file so that it is unique among test - // runners - await runCommand('mv', [ - './coverage/coverage-final.json', - `./coverage/coverage-final-mocha.json`, - ]); - } -} - async function start() { const { - argv: { mocha, jestGlobal, jestDev, coverage, fakeParallelism, maxWorkers }, + argv: { jestGlobal, jestDev, coverage, fakeParallelism, maxWorkers }, } = yargs(hideBin(process.argv)).usage( '$0 [options]', 'Run unit tests on the application code.', (yargsInstance) => yargsInstance - .option('mocha', { - alias: ['m'], - default: false, - description: 'Run Mocha tests', - type: 'boolean', - }) .option('jestDev', { alias: ['d'], default: false, @@ -156,8 +125,6 @@ async function start() { throw new Error( 'Do not try to run both jest test configs with fakeParallelism, bad things could happen.', ); - } else if (mocha) { - throw new Error('Test splitting is not supported for mocha yet.'); } else { const processes = []; for (let x = 0; x < fakeParallelism; x++) { @@ -179,9 +146,6 @@ async function start() { totalShards: maxProcesses, maxWorkers, }; - if (mocha) { - await runMocha(options); - } if (jestDev) { await runJest({ target: 'dev', ...options }); } diff --git a/ui/components/app/confirm/info/row/date.stories.tsx b/ui/components/app/confirm/info/row/date.stories.tsx new file mode 100644 index 000000000000..971ba7624f3e --- /dev/null +++ b/ui/components/app/confirm/info/row/date.stories.tsx @@ -0,0 +1,26 @@ +import React from 'react'; + +import { ConfirmInfoRow } from './row'; +import { ConfirmInfoRowDate } from './date'; + +const ConfirmInfoRowDateStory = { + title: 'Components/App/Confirm/InfoRowDate', + component: ConfirmInfoRowDate, + + decorators: [ + (story) => {story()}, + ], + + argTypes: { + url: { + control: 'date', + }, + }, +}; + +export const DefaultStory = ({ date }) => ; +DefaultStory.args = { + date: 1633019124000, +}; + +export default ConfirmInfoRowDateStory; diff --git a/ui/components/app/confirm/info/row/date.test.tsx b/ui/components/app/confirm/info/row/date.test.tsx new file mode 100644 index 000000000000..eda8510e4e7c --- /dev/null +++ b/ui/components/app/confirm/info/row/date.test.tsx @@ -0,0 +1,11 @@ +import React from 'react'; +import { render } from '@testing-library/react'; + +import { ConfirmInfoRowDate } from './date'; + +describe('ConfirmInfoRowDate', () => { + it('should match snapshot', () => { + const { getByText } = render(); + expect(getByText('30 September 2021, 16:25')).toBeInTheDocument(); + }); +}); diff --git a/ui/components/app/confirm/info/row/date.tsx b/ui/components/app/confirm/info/row/date.tsx new file mode 100644 index 000000000000..47fa8e4ea56a --- /dev/null +++ b/ui/components/app/confirm/info/row/date.tsx @@ -0,0 +1,27 @@ +import React from 'react'; + +import { + AlignItems, + Display, + FlexWrap, + TextColor, +} from '../../../../../helpers/constants/design-system'; +import { formatUTCDate } from '../../../../../helpers/utils/util'; +import { Box, Text } from '../../../../component-library'; + +export type ConfirmInfoRowDateProps = { + date: number; +}; + +export const ConfirmInfoRowDate = ({ date }: ConfirmInfoRowDateProps) => ( + + + {formatUTCDate(date)} + + +); diff --git a/ui/components/app/confirm/info/row/index.ts b/ui/components/app/confirm/info/row/index.ts index ef2102b280a1..0fc08d5887bb 100644 --- a/ui/components/app/confirm/info/row/index.ts +++ b/ui/components/app/confirm/info/row/index.ts @@ -1,4 +1,5 @@ export * from './address'; +export * from './date'; export * from './divider'; export * from './row'; export * from './text'; diff --git a/ui/components/multichain/asset-picker-amount/asset-picker/__snapshots__/asset-picker.test.tsx.snap b/ui/components/multichain/asset-picker-amount/asset-picker/__snapshots__/asset-picker.test.tsx.snap index 4b62e6ebe220..9eedf3168b8b 100644 --- a/ui/components/multichain/asset-picker-amount/asset-picker/__snapshots__/asset-picker.test.tsx.snap +++ b/ui/components/multichain/asset-picker-amount/asset-picker/__snapshots__/asset-picker.test.tsx.snap @@ -13,18 +13,31 @@ exports[`AssetPicker matches snapshot 1`] = ` class="mm-box mm-box--display-flex mm-box--gap-3 mm-box--align-items-center" >
- - undefined logo +
+ + NATIVE TICKER logo +
+
+
+ ? +
+
- ? +
+ s +
+
+
+ ? +
+
{/* This is the Modal that ask to choose token to send */} @@ -155,13 +165,32 @@ export function AssetPicker({ title={isDisabled ? t('swapTokenNotAvailable') : undefined} > - + + } + marginRight={3} + > + + + {formattedSymbol} diff --git a/ui/components/ui/token-input/token-input.stories.tsx b/ui/components/ui/token-input/token-input.stories.tsx new file mode 100644 index 000000000000..67c83bcbc5bf --- /dev/null +++ b/ui/components/ui/token-input/token-input.stories.tsx @@ -0,0 +1,53 @@ +import React from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; +import TokenInput from './token-input.component'; + +const meta: Meta = { + title: 'Components/UI/TokenInput', + component: TokenInput, + argTypes: { + dataTestId: { control: 'text' }, + currentCurrency: { control: 'text' }, + onChange: { action: 'changed' }, + value: { control: 'text' }, + showFiat: { control: 'boolean' }, + hideConversion: { control: 'boolean' }, + token: { + control: 'object', + defaultValue: { + address: '0x0', + decimals: 18, + symbol: 'ETH', + }, + }, + tokenExchangeRates: { control: 'object' }, + nativeCurrency: { control: 'text' }, + tokens: { control: 'array' }, + }, + args: { + dataTestId: 'token-input', + currentCurrency: 'USD', + value: '0x0', + showFiat: true, + hideConversion: false, + token: { + address: '0x0', + decimals: 18, + symbol: 'ETH', + }, + tokenExchangeRates: {}, + nativeCurrency: 'ETH', + tokens: [ + { + address: '0x0', + decimals: 18, + symbol: 'ETH', + }, + ], + }, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/ui/ducks/swaps/swaps.js b/ui/ducks/swaps/swaps.js index 56a7273e8d5b..59fadda433d5 100644 --- a/ui/ducks/swaps/swaps.js +++ b/ui/ducks/swaps/swaps.js @@ -94,6 +94,7 @@ import { } from '../../../shared/lib/transactions-controller-utils'; import { EtherDenomination } from '../../../shared/constants/common'; import { Numeric } from '../../../shared/modules/Numeric'; +import { calculateMaxGasLimit } from '../../../shared/lib/swaps-utils'; export const GAS_PRICES_LOADING_STATES = { INITIAL: 'INITIAL', @@ -102,8 +103,6 @@ export const GAS_PRICES_LOADING_STATES = { COMPLETED: 'COMPLETED', }; -export const FALLBACK_GAS_MULTIPLIER = 1.5; - const initialState = { aggregatorMetadata: null, approveTxId: null, @@ -1106,20 +1105,16 @@ export const signAndSendTransactions = ( const usedQuote = getUsedQuote(state); const usedTradeTxParams = usedQuote.trade; - const estimatedGasLimit = new BigNumber( - usedQuote?.gasEstimate || 0, - 16, - ).toString(16); - - const maxGasLimit = - customSwapsGas || - (usedQuote?.gasEstimate - ? `0x${estimatedGasLimit}` - : `0x${decimalToHex( - new BigNumber(usedQuote?.maxGas) - .mul(usedQuote?.gasMultiplier || FALLBACK_GAS_MULTIPLIER) - .toString() || 0, - )}`); + const estimatedGasLimit = new BigNumber(usedQuote?.gasEstimate || 0, 16) + .round(0) + .toString(16); + + const maxGasLimit = calculateMaxGasLimit( + usedQuote?.gasEstimate, + usedQuote?.gasMultiplier, + usedQuote?.maxGas, + customSwapsGas, + ); const usedGasPrice = getUsedSwapsGasPrice(state); usedTradeTxParams.gas = maxGasLimit; diff --git a/ui/helpers/utils/util.js b/ui/helpers/utils/util.js index 909c7c2c2d8a..114e7cb4c369 100644 --- a/ui/helpers/utils/util.js +++ b/ui/helpers/utils/util.js @@ -43,6 +43,16 @@ export function formatDate(date, format = "M/d/y 'at' T") { return DateTime.fromMillis(date).toFormat(format); } +export const formatUTCDate = (dateInMillis) => { + if (!dateInMillis) { + return dateInMillis; + } + + return DateTime.fromMillis(dateInMillis) + .setZone('utc') + .toFormat('dd LLLL yyyy, HH:mm'); +}; + export function formatDateWithYearContext( date, formatThisYear = 'MMM d', diff --git a/ui/helpers/utils/util.test.js b/ui/helpers/utils/util.test.js index fdcfe4e48972..76811f432f81 100644 --- a/ui/helpers/utils/util.test.js +++ b/ui/helpers/utils/util.test.js @@ -1043,6 +1043,18 @@ describe('util', () => { }); }); + describe('formatUTCDate', () => { + it('formats passed date string', () => { + expect(util.formatUTCDate(1633019124000)).toStrictEqual( + '30 September 2021, 16:25', + ); + }); + + it('returns empty string if empty string is passed', () => { + expect(util.formatUTCDate('')).toStrictEqual(''); + }); + }); + describe('shortenAddress', () => { it('should return the same address if it is shorter than TRUNCATED_NAME_CHAR_LIMIT', () => { expect(util.shortenAddress('0x123')).toStrictEqual('0x123'); diff --git a/ui/hooks/useHideFiatForTestnet.test.ts b/ui/hooks/useHideFiatForTestnet.test.ts new file mode 100644 index 000000000000..cdc4905c74c4 --- /dev/null +++ b/ui/hooks/useHideFiatForTestnet.test.ts @@ -0,0 +1,69 @@ +import { renderHook } from '@testing-library/react-hooks'; +import { getShowFiatInTestnets, getCurrentChainId } from '../selectors'; +import { TEST_NETWORK_IDS, CHAIN_IDS } from '../../shared/constants/network'; +import { useHideFiatForTestnet } from './useHideFiatForTestnet'; + +jest.mock('react-redux', () => ({ + useSelector: jest.fn().mockImplementation((selector) => selector()), +})); + +jest.mock('../selectors', () => ({ + getShowFiatInTestnets: jest.fn(), + getCurrentChainId: jest.fn(), +})); + +describe('useHideFiatForTestnet', () => { + const mockGetShowFiatInTestnets = jest.mocked(getShowFiatInTestnets); + const mockGetCurrentChainId = jest.mocked(getCurrentChainId); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('utilizes the specified chain id', () => { + mockGetShowFiatInTestnets.mockReturnValue(false); + mockGetCurrentChainId.mockReturnValue(TEST_NETWORK_IDS[0]); + + const { result } = renderHook(() => + useHideFiatForTestnet(CHAIN_IDS.MAINNET), + ); + + expect(result.current).toBe(false); + }); + + it('returns true if current network is a testnet and showFiatInTestnets is false', () => { + mockGetShowFiatInTestnets.mockReturnValue(false); + mockGetCurrentChainId.mockReturnValue(TEST_NETWORK_IDS[0]); + + const { result } = renderHook(() => useHideFiatForTestnet()); + + expect(result.current).toBe(true); + }); + + it('returns false if current network is a testnet and showFiatInTestnets is true', () => { + mockGetShowFiatInTestnets.mockReturnValue(true); + mockGetCurrentChainId.mockReturnValue(TEST_NETWORK_IDS[0]); + + const { result } = renderHook(() => useHideFiatForTestnet()); + + expect(result.current).toBe(false); + }); + + it('returns false if current network is not a testnet', () => { + mockGetShowFiatInTestnets.mockReturnValue(false); + mockGetCurrentChainId.mockReturnValue('1'); + + const { result } = renderHook(() => useHideFiatForTestnet()); + + expect(result.current).toBe(false); + }); + + it('returns false if current network is not a testnet but showFiatInTestnets is true', () => { + mockGetShowFiatInTestnets.mockReturnValue(true); + mockGetCurrentChainId.mockReturnValue('1'); + + const { result } = renderHook(() => useHideFiatForTestnet()); + + expect(result.current).toBe(false); + }); +}); diff --git a/ui/hooks/useHideFiatForTestnet.ts b/ui/hooks/useHideFiatForTestnet.ts new file mode 100644 index 000000000000..b01b20513550 --- /dev/null +++ b/ui/hooks/useHideFiatForTestnet.ts @@ -0,0 +1,17 @@ +import { useSelector } from 'react-redux'; +import type { Hex } from '@metamask/utils'; +import { getShowFiatInTestnets, getCurrentChainId } from '../selectors'; +import { TEST_NETWORK_IDS } from '../../shared/constants/network'; + +/** + * Returns true if the fiat value should be hidden for testnet networks. + * + * @param providedChainId + * @returns boolean + */ +export const useHideFiatForTestnet = (providedChainId?: Hex): boolean => { + const showFiatInTestnets = useSelector(getShowFiatInTestnets); + const currentChainId = useSelector(getCurrentChainId); + const chainId = providedChainId ?? currentChainId; + return TEST_NETWORK_IDS.includes(chainId) && !showFiatInTestnets; +}; diff --git a/ui/hooks/useMultichainSelector.test.ts b/ui/hooks/useMultichainSelector.test.ts new file mode 100644 index 000000000000..e4469a9f05db --- /dev/null +++ b/ui/hooks/useMultichainSelector.test.ts @@ -0,0 +1,76 @@ +import { InternalAccount } from '@metamask/keyring-api'; +import { createMockInternalAccount } from '../../test/jest/mocks'; +import { renderHookWithProvider } from '../../test/lib/render-helpers'; +import { getSelectedNetworkClientId } from '../selectors'; +import { MultichainState, getMultichainIsEvm } from '../selectors/multichain'; +import { useMultichainSelector } from './useMultichainSelector'; + +const mockAccount = createMockInternalAccount(); +const mockNetworkId = '0x1'; + +const mockState = { + metamask: { + selectedNetworkClientId: mockNetworkId, + completedOnboarding: true, + internalAccounts: { + accounts: { + [mockAccount.id]: mockAccount, + }, + selectedAccount: mockAccount.id, + }, + }, +}; + +const renderUseMultichainHook = ( + selector: (state: MultichainState, account?: InternalAccount) => unknown, + account?: InternalAccount, + state?: MultichainState, +) => { + return renderHookWithProvider( + () => useMultichainSelector(selector, account ?? mockAccount), + state ?? mockState, + ); +}; + +describe('useMultichainSelector', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + it('calls useSelector with the correct selector and account', () => { + const mockSelector = jest.fn(); + renderUseMultichainHook(mockSelector, mockAccount); + + expect(mockSelector.mock.calls[0][0]).toMatchObject(mockState); + expect(mockSelector).toHaveBeenCalledWith( + expect.anything(), // already checked above + mockAccount, + ); + }); + + it('calls useSelector with the correct selector and undefined account', () => { + const mockSelector = jest.fn(); + renderUseMultichainHook(mockSelector); + + expect(mockSelector.mock.calls[0][0]).toMatchObject(mockState); + expect(mockSelector).toHaveBeenCalledWith( + expect.anything(), // already checked above + mockAccount, + ); + }); + + it('uses selectedAccount if account is not provided', () => { + const { result } = renderUseMultichainHook(getMultichainIsEvm, null); + + expect(result.current).toBe(true); + }); + + it('is compatible with selectors that do not require an account', () => { + const { result } = renderUseMultichainHook( + getSelectedNetworkClientId, + mockAccount, + ); + + expect(result.current).toBe(mockNetworkId); + }); +}); diff --git a/ui/hooks/useMultichainSelector.ts b/ui/hooks/useMultichainSelector.ts new file mode 100644 index 000000000000..326ac79bf9cd --- /dev/null +++ b/ui/hooks/useMultichainSelector.ts @@ -0,0 +1,16 @@ +import { useSelector, DefaultRootState } from 'react-redux'; +import { InternalAccount } from '@metamask/keyring-api'; +import { getSelectedInternalAccount } from '../selectors'; + +export function useMultichainSelector< + TState = DefaultRootState, + TSelected = unknown, +>( + selector: (state: TState, account?: InternalAccount) => TSelected, + account?: InternalAccount, +) { + return useSelector((state: TState) => { + // We either pass an account or fallback to the currently selected one + return selector(state, account || getSelectedInternalAccount(state)); + }); +} diff --git a/ui/pages/confirmations/components/confirm/info/personal-sign/siwe-sign/siwe-sign.tsx b/ui/pages/confirmations/components/confirm/info/personal-sign/siwe-sign/siwe-sign.tsx index 8c1260c3ede5..94389b253450 100644 --- a/ui/pages/confirmations/components/confirm/info/personal-sign/siwe-sign/siwe-sign.tsx +++ b/ui/pages/confirmations/components/confirm/info/personal-sign/siwe-sign/siwe-sign.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { DateTime } from 'luxon'; import { useSelector } from 'react-redux'; import { toHex } from '@metamask/controller-utils'; @@ -9,9 +10,9 @@ import { SignatureRequestType } from '../../../../../types/confirm'; import { ConfirmInfoRow, ConfirmInfoRowAddress, + ConfirmInfoRowDate, ConfirmInfoRowText, } from '../../../../../../../components/app/confirm/info/row'; -import { formatDate } from '../../../../../utils/date'; const SIWESignInfo: React.FC = () => { const t = useI18nContext(); @@ -64,7 +65,9 @@ const SIWESignInfo: React.FC = () => { - + {requestId && ( diff --git a/ui/pages/confirmations/components/confirm/info/typed-sign/__snapshots__/typed-sign.test.tsx.snap b/ui/pages/confirmations/components/confirm/info/typed-sign/__snapshots__/typed-sign.test.tsx.snap index cf3c57f86829..328fe4209390 100644 --- a/ui/pages/confirmations/components/confirm/info/typed-sign/__snapshots__/typed-sign.test.tsx.snap +++ b/ui/pages/confirmations/components/confirm/info/typed-sign/__snapshots__/typed-sign.test.tsx.snap @@ -1,5 +1,466 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`TypedSignInfo correctly renders permit sign type 1`] = ` +
+
+
+
+

+ Spender +

+
+
+
+ +

+ 0x5B38D...eddC4 +

+
+
+
+
+
+
+

+ Request from +

+
+
+ +
+
+
+
+

+ metamask.github.io +

+
+
+
+
+

+ Interacting with +

+
+
+
+ +

+ 0xCcCCc...ccccC +

+
+
+
+
+
+
+
+

+ Message +

+
+
+
+
+

+ Primary type: +

+
+
+

+ Permit +

+
+
+
+
+
+
+

+ Owner: +

+
+
+
+ +

+ 0x935E7...05477 +

+
+
+
+
+
+

+ Spender: +

+
+
+
+ +

+ 0x5B38D...eddC4 +

+
+
+
+
+
+

+ Value: +

+
+
+

+ 3000 +

+
+
+
+
+

+ Nonce: +

+
+
+

+ 0 +

+
+
+
+
+

+ Deadline: +

+
+
+

+ 02 August 1971, 16:53 +

+
+
+
+
+
+
+
+
+`; + exports[`TypedSignInfo does not render if required data is not present in the transaction 1`] = `
`; exports[`TypedSignInfo renders origin for typed sign data request 1`] = ` diff --git a/ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign.test.tsx b/ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign.test.tsx index 4d64d3a38f28..332b3f79a6ff 100644 --- a/ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign.test.tsx +++ b/ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign.test.tsx @@ -80,7 +80,7 @@ describe('TypedSignInfo', () => { expect(getByText('Estimated changes')).toBeDefined(); }); - it('displays "Spender" for permit signature type', () => { + it('correctly renders permit sign type', () => { const state = { ...mockState, confirm: { @@ -88,7 +88,7 @@ describe('TypedSignInfo', () => { }, }; const mockStore = configureMockStore([])(state); - const { getByText } = renderWithProvider(, mockStore); - expect(getByText('Spender')).toBeDefined(); + const { container } = renderWithProvider(, mockStore); + expect(container).toMatchSnapshot(); }); }); diff --git a/ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign.tsx b/ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign.tsx index f6efca236f3a..019dd138f401 100644 --- a/ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign.tsx +++ b/ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign.tsx @@ -63,6 +63,7 @@ const TypedSignInfo: React.FC = () => { diff --git a/ui/pages/confirmations/components/confirm/row/dataTree.tsx b/ui/pages/confirmations/components/confirm/row/dataTree.tsx index c72fc6113292..307b608488d9 100644 --- a/ui/pages/confirmations/components/confirm/row/dataTree.tsx +++ b/ui/pages/confirmations/components/confirm/row/dataTree.tsx @@ -8,6 +8,7 @@ import { BlockSize } from '../../../../../helpers/constants/design-system'; import { ConfirmInfoRow, ConfirmInfoRowAddress, + ConfirmInfoRowDate, ConfirmInfoRowText, } from '../../../../../components/app/confirm/info/row'; @@ -20,32 +21,50 @@ export type TreeData = { export const DataTree = ({ data, + isPermit = false, }: { data: Record | TreeData[]; + isPermit?: boolean; }) => ( - {Object.entries(data).map(([label, { value, type }], i) => { - return ( - - { - // eslint-disable-next-line @typescript-eslint/no-use-before-define - - } - - ); - })} + {Object.entries(data).map(([label, { value, type }], i) => ( + + { + // eslint-disable-next-line @typescript-eslint/no-use-before-define + + } + + ))} ); -const DataField = ({ value, type }: { value: ValueType; type: string }) => { +const DataField = ({ + label, + isPermit, + type, + value, +}: { + label: string; + isPermit: boolean; + type: string; + value: ValueType; +}) => { if (typeof value === 'object' && value !== null) { - return ; + return ; + } + if (isPermit && label === 'deadline') { + return ; } if ( type === 'address' && diff --git a/ui/pages/confirmations/components/confirm/row/typed-sign-data/typedSignData.tsx b/ui/pages/confirmations/components/confirm/row/typed-sign-data/typedSignData.tsx index 3b3d1db72ca4..9b3934cef651 100644 --- a/ui/pages/confirmations/components/confirm/row/typed-sign-data/typedSignData.tsx +++ b/ui/pages/confirmations/components/confirm/row/typed-sign-data/typedSignData.tsx @@ -11,7 +11,13 @@ import { import { DataTree } from '../dataTree'; import { parseSanitizeTypedDataMessage } from '../../../../utils'; -export const ConfirmInfoRowTypedSignData = ({ data }: { data: string }) => { +export const ConfirmInfoRowTypedSignData = ({ + data, + isPermit, +}: { + data: string; + isPermit?: boolean; +}) => { const t = useI18nContext(); if (!data) { @@ -29,7 +35,7 @@ export const ConfirmInfoRowTypedSignData = ({ data }: { data: string }) => { - + ); diff --git a/ui/pages/confirmations/components/simulation-details/fiat-display.test.tsx b/ui/pages/confirmations/components/simulation-details/fiat-display.test.tsx index 5716e22e5747..0eee6aee8990 100644 --- a/ui/pages/confirmations/components/simulation-details/fiat-display.test.tsx +++ b/ui/pages/confirmations/components/simulation-details/fiat-display.test.tsx @@ -1,47 +1,104 @@ import React from 'react'; import { screen } from '@testing-library/react'; import configureStore from 'redux-mock-store'; +import { merge } from 'lodash'; import { useFiatFormatter } from '../../../../hooks/useFiatFormatter'; import { renderWithProvider } from '../../../../../test/lib/render-helpers'; import mockState from '../../../../../test/data/mock-state.json'; +import { CHAIN_IDS } from '../../../../../shared/constants/network'; import { IndividualFiatDisplay, TotalFiatDisplay } from './fiat-display'; import { FIAT_UNAVAILABLE } from './types'; -const store = configureStore()(mockState); +const mockStateWithTestnet = merge({}, mockState, { + metamask: { + providerConfig: { + chainId: CHAIN_IDS.SEPOLIA, + }, + }, +}); -jest.mock('../../../../hooks/useFiatFormatter'); -(useFiatFormatter as jest.Mock).mockReturnValue((value: number) => `$${value}`); - -describe('IndividualFiatDisplay', () => { - // @ts-expect-error This is missing from the Mocha type definitions - it.each([ - [FIAT_UNAVAILABLE, 'Not Available'], - [100, '$100'], - [-100, '$100'], - ])( - 'when fiatAmount is %s it renders %s', - (fiatAmount: number | null, expected: string) => { - renderWithProvider( - , - store, - ); - expect(screen.getByText(expected)).toBeInTheDocument(); +const mockStateWithShowingFiatOnTestnets = merge({}, mockStateWithTestnet, { + metamask: { + preferences: { + showFiatInTestnets: true, }, - ); + }, }); +const mockStoreWithShowingFiatOnTestnets = configureStore()( + mockStateWithShowingFiatOnTestnets, +); -describe('TotalFiatDisplay', () => { - // @ts-expect-error This is missing from the Mocha type definitions - it.each([ - [[FIAT_UNAVAILABLE, FIAT_UNAVAILABLE], 'Not Available'], - [[], 'Not Available'], - [[100, 200, FIAT_UNAVAILABLE, 300], 'Total = $600'], - [[-100, -200, FIAT_UNAVAILABLE, -300], 'Total = $600'], - ])( - 'when fiatAmounts is %s it renders %s', - (fiatAmounts: (number | null)[], expected: string) => { - renderWithProvider(, store); - expect(screen.getByText(expected)).toBeInTheDocument(); +const mockStateWithHidingFiatOnTestnets = merge({}, mockStateWithTestnet, { + metamask: { + preferences: { + showFiatInTestnets: false, }, - ); + }, +}); +const mockStoreWithHidingFiatOnTestnets = configureStore()( + mockStateWithHidingFiatOnTestnets, +); + +jest.mock('../../../../hooks/useFiatFormatter'); + +describe('FiatDisplay', () => { + const mockUseFiatFormatter = jest.mocked(useFiatFormatter); + + beforeEach(() => { + jest.resetAllMocks(); + mockUseFiatFormatter.mockReturnValue((value: number) => `$${value}`); + }); + + describe('IndividualFiatDisplay', () => { + // @ts-expect-error This is missing from the Mocha type definitions + it.each([ + [FIAT_UNAVAILABLE, 'Not Available'], + [100, '$100'], + [-100, '$100'], + ])( + 'when fiatAmount is %s it renders %s', + (fiatAmount: number | null, expected: string) => { + renderWithProvider( + , + mockStoreWithShowingFiatOnTestnets, + ); + expect(screen.getByText(expected)).toBeInTheDocument(); + }, + ); + + it('does not render anything if user opted out to show fiat values on testnet', () => { + const { queryByText } = renderWithProvider( + , + mockStoreWithHidingFiatOnTestnets, + ); + expect(queryByText('100')).toBe(null); + }); + }); + + describe('TotalFiatDisplay', () => { + // @ts-expect-error This is missing from the Mocha type definitions + it.each([ + [[FIAT_UNAVAILABLE, FIAT_UNAVAILABLE], 'Not Available'], + [[], 'Not Available'], + [[100, 200, FIAT_UNAVAILABLE, 300], 'Total = $600'], + [[-100, -200, FIAT_UNAVAILABLE, -300], 'Total = $600'], + ])( + 'when fiatAmounts is %s it renders %s', + (fiatAmounts: (number | null)[], expected: string) => { + renderWithProvider( + , + mockStoreWithShowingFiatOnTestnets, + ); + expect(screen.getByText(expected)).toBeInTheDocument(); + }, + ); + + it('does not render anything if user opted out to show fiat values on testnet', () => { + const { queryByText } = renderWithProvider( + , + mockStoreWithHidingFiatOnTestnets, + ); + expect(queryByText('600')).toBe(null); + }); + }); }); diff --git a/ui/pages/confirmations/components/simulation-details/fiat-display.tsx b/ui/pages/confirmations/components/simulation-details/fiat-display.tsx index 6286141441af..5143cd5ed06b 100644 --- a/ui/pages/confirmations/components/simulation-details/fiat-display.tsx +++ b/ui/pages/confirmations/components/simulation-details/fiat-display.tsx @@ -8,6 +8,7 @@ import { useI18nContext } from '../../../../hooks/useI18nContext'; import { Text } from '../../../../components/component-library'; import { SizeNumber } from '../../../../components/component-library/box/box.types'; import { useFiatFormatter } from '../../../../hooks/useFiatFormatter'; +import { useHideFiatForTestnet } from '../../../../hooks/useHideFiatForTestnet'; import { FIAT_UNAVAILABLE, FiatAmount } from './types'; const textStyle = { @@ -37,7 +38,13 @@ export function calculateTotalFiat(fiatAmounts: FiatAmount[]): number { export const IndividualFiatDisplay: React.FC<{ fiatAmount: FiatAmount }> = ({ fiatAmount, }) => { + const hideFiatForTestnet = useHideFiatForTestnet(); const fiatFormatter = useFiatFormatter(); + + if (hideFiatForTestnet) { + return null; + } + if (fiatAmount === FIAT_UNAVAILABLE) { return ; } @@ -55,10 +62,15 @@ export const IndividualFiatDisplay: React.FC<{ fiatAmount: FiatAmount }> = ({ export const TotalFiatDisplay: React.FC<{ fiatAmounts: FiatAmount[]; }> = ({ fiatAmounts }) => { + const hideFiatForTestnet = useHideFiatForTestnet(); const t = useI18nContext(); const fiatFormatter = useFiatFormatter(); const totalFiat = calculateTotalFiat(fiatAmounts); + if (hideFiatForTestnet) { + return null; + } + return totalFiat === 0 ? ( ) : ( diff --git a/ui/pages/create-account/connect-hardware/select-hardware.js b/ui/pages/create-account/connect-hardware/select-hardware.js index 24ea2bcbebdb..8f2e3b8569e3 100644 --- a/ui/pages/create-account/connect-hardware/select-hardware.js +++ b/ui/pages/create-account/connect-hardware/select-hardware.js @@ -56,7 +56,16 @@ export default class SelectHardware extends Component { connect = async () => { if (this.state.selectedDevice) { - if (this.state.selectedDevice === 'trezor') { + // Not all browsers have usb support. In particular, Firefox does + // not support usb. More information on that can be found here: + // https://mozilla.github.io/standards-positions/#webusb + // + // The below `&& window.navigator.usb` condition ensures that we + // only attempt to connect Trezor via usb if we are in a browser + // that supports usb. If not, the connection of the hardware wallet + // to the browser will be handled by the Trezor connect screen. In + // the case of Firefox, this will depend on the Trezor bridge software + if (this.state.selectedDevice === 'trezor' && window.navigator.usb) { this.setState({ trezorRequestDevicePending: true }); try { await window.navigator.usb.requestDevice({ diff --git a/ui/pages/onboarding-flow/metametrics/__snapshots__/metametrics.test.js.snap b/ui/pages/onboarding-flow/metametrics/__snapshots__/metametrics.test.js.snap index c68e7759e419..516b27b2a38b 100644 --- a/ui/pages/onboarding-flow/metametrics/__snapshots__/metametrics.test.js.snap +++ b/ui/pages/onboarding-flow/metametrics/__snapshots__/metametrics.test.js.snap @@ -146,7 +146,7 @@ exports[`Onboarding Metametrics Component should match snapshot after new policy

- MetaMask would like to gather usage data to better understand how our users interact with MetaMask. This data will be used to provide the service, which includes improving the service based on your use. + We’d like to gather basic usage and diagnostics data to improve MetaMask. Know that we never sell the data you provide here.

- MetaMask will... + When we gather metrics, it will always be...

    -
  • - - Always allow you to opt-out via Settings -
  • -
  • - - Send anonymized click and pageview events -
  • @@ -192,9 +178,9 @@ exports[`Onboarding Metametrics Component should match snapshot after new policy - Never + Private: - collect information we don’t need to provide the service (such as keys, addresses, transaction hashes, or balances) + clicks and views on the app are stored, but other details (like your public address) are not.
    @@ -204,8 +190,8 @@ exports[`Onboarding Metametrics Component should match snapshot after new policy class="box box--flex-direction-row" > @@ -213,9 +199,9 @@ exports[`Onboarding Metametrics Component should match snapshot after new policy - Never + General: - collect your full IP address* + we temporarily use your IP address to detect a general location (like your country or region), but it's never stored.

@@ -225,8 +211,8 @@ exports[`Onboarding Metametrics Component should match snapshot after new policy class="box box--flex-direction-row" > @@ -234,42 +220,47 @@ exports[`Onboarding Metametrics Component should match snapshot after new policy - Never + Optional: - sell data. Ever! + you decide if you want to share or delete your usage data via settings any time.
-
- This data is aggregated and is therefore anonymous for the purposes of General Data Protection Regulation (EU) 2016/679. -
+ + + + + We’ll use this data to learn how you interact with our marketing communications. We may share relevant news (like product features). + +
- * When you use Infura as your default RPC provider in MetaMask, Infura will collect your IP address and your Ethereum wallet address when you send a transaction. We don’t store this information in a way that allows our systems to associate those two pieces of data. For more information on how MetaMask and Infura interact from a data collection perspective, see our update - - here - - . For more information on our privacy practices in general, see our + We’ll let you know if we decide to use this data for other purposes. You can review our - Privacy Policy here + Privacy Policy - . + for more information. Remember, you can go to settings and opt out at any time.
diff --git a/ui/pages/onboarding-flow/metametrics/metametrics.js b/ui/pages/onboarding-flow/metametrics/metametrics.js index f874c99ca5e0..8fe4246ca332 100644 --- a/ui/pages/onboarding-flow/metametrics/metametrics.js +++ b/ui/pages/onboarding-flow/metametrics/metametrics.js @@ -35,7 +35,6 @@ import { IconName, IconSize, } from '../../../components/component-library'; -import { PRIVACY_POLICY_DATE } from '../../../helpers/constants/privacy-policy'; import Box from '../../../components/ui/box/box'; import { FirstTimeFlowType } from '../../../../shared/constants/onboarding'; @@ -45,9 +44,6 @@ export default function OnboardingMetametrics() { const dispatch = useDispatch(); const history = useHistory(); - const newPrivacyPolicyDate = new Date(PRIVACY_POLICY_DATE); - const currentDate = new Date(Date.now()); - const nextRoute = useSelector(getFirstTimeFlowTypeRouteAfterMetaMetricsOptIn); const firstTimeFlowType = useSelector(getFirstTimeFlowType); @@ -108,298 +104,135 @@ export default function OnboardingMetametrics() { history.push(nextRoute); }; - const renderLegacyOnboarding = () => { - return ( -
+ - - {t('onboardingMetametricsTitle')} - - - {t('onboardingMetametricsDescriptionLegacy')} - - - {t('onboardingMetametricsDescription2Legacy')} - -
    -
  • + {t('onboardingMetametricsTitle')} + + + {t('onboardingMetametricsDescription')} + + + {t('onboardingMetametricsDescription2')} + +
      +
    • + - {t('onboardingMetametricsAllowOptOutLegacy')} -
    • -
    • + {t('onboardingMetametricsNeverCollect', [ + + {t('onboardingMetametricsNeverCollectEmphasis')} + , + ])} + +
    • +
    • + - {t('onboardingMetametricsSendAnonymizeLegacy')} -
    • -
    • - - - {t('onboardingMetametricsNeverCollectLegacy', [ - - {t('onboardingMetametricsNeverEmphasisLegacy')} - , - ])} - -
    • -
    • - - - {t('onboardingMetametricsNeverCollectIPLegacy', [ - - {t('onboardingMetametricsNeverEmphasisLegacy')} - , - ])} - -
    • -
    • - - - {t('onboardingMetametricsNeverSellDataLegacy', [ - - {t('onboardingMetametricsNeverEmphasisLegacy')} - , - ])} - {' '} -
    • -
    - - {t('onboardingMetametricsDataTermsLegacy')} - - - {t('onboardingMetametricsInfuraTermsLegacy', [ - - {t('onboardingMetametricsInfuraTermsPolicyLinkLegacy')} - , - - {t('onboardingMetametricsInfuraTermsPolicyLegacy')} - , - ])} - - -
    - - -
    -
- ); - }; - - const renderOnboarding = () => { - return ( -
+ {t('onboardingMetametricsNeverCollectIPEmphasis')} + , + ])} + + +
  • + + + {t('onboardingMetametricsNeverSellData', [ + + {t('onboardingMetametricsNeverSellDataEmphasis')} + , + ])} + {' '} +
  • + + + dispatch(setDataCollectionForMarketing(!dataCollectionForMarketing)) + } + label={t('onboardingMetametricsUseDataCheckbox')} + paddingBottom={3} + /> + - - {t('onboardingMetametricsTitle')} - - - {t('onboardingMetametricsDescription')} - - + {t('onboardingMetametricsInfuraTermsPolicy')} + , + ])} + + +
    + - -
    + {t('onboardingMetametricsDisagree')} +
    - ); - }; - - return currentDate >= newPrivacyPolicyDate - ? renderOnboarding() - : renderLegacyOnboarding(); +
    + ); } diff --git a/ui/pages/onboarding-flow/metametrics/metametrics.test.js b/ui/pages/onboarding-flow/metametrics/metametrics.test.js index 487987a0f5f5..5318d0ca1821 100644 --- a/ui/pages/onboarding-flow/metametrics/metametrics.test.js +++ b/ui/pages/onboarding-flow/metametrics/metametrics.test.js @@ -140,13 +140,4 @@ describe('Onboarding Metametrics Component', () => { ); expect(queryByTestId('onboarding-metametrics')).toBeInTheDocument(); }); - - it('should render the Legacy Onboarding component when the current date is before the new privacy policy date', () => { - jest.useFakeTimers().setSystemTime(new Date('2020-01-01')); - const { queryByTestId } = renderWithProvider( - , - mockStore, - ); - expect(queryByTestId('onboarding-legacy-metametrics')).toBeInTheDocument(); - }); }); diff --git a/ui/pages/onboarding-flow/privacy-settings/privacy-settings.js b/ui/pages/onboarding-flow/privacy-settings/privacy-settings.js index 98b42d5e4d22..ea15950451c5 100644 --- a/ui/pages/onboarding-flow/privacy-settings/privacy-settings.js +++ b/ui/pages/onboarding-flow/privacy-settings/privacy-settings.js @@ -253,6 +253,14 @@ export default function PrivacySettings() { ); } else { profileSyncingProps.setIsProfileSyncingEnabled(true); + trackEvent({ + category: MetaMetricsEventCategory.Onboarding, + event: + MetaMetricsEventName.OnboardingWalletAdvancedSettingsTurnOnProfileSyncing, + properties: { + participateInMetaMetrics, + }, + }); } }; diff --git a/ui/pages/onboarding-flow/recovery-phrase/__snapshots__/review-recovery-phrase.test.js.snap b/ui/pages/onboarding-flow/recovery-phrase/__snapshots__/review-recovery-phrase.test.js.snap index e95f2e73c43b..5e8cc1914b3d 100644 --- a/ui/pages/onboarding-flow/recovery-phrase/__snapshots__/review-recovery-phrase.test.js.snap +++ b/ui/pages/onboarding-flow/recovery-phrase/__snapshots__/review-recovery-phrase.test.js.snap @@ -275,11 +275,11 @@ exports[`Review Recovery Phrase Component should match snapshot 1`] = ` class="far fa-eye" color="white" /> -
    Make sure nobody is looking -
    +

    - {t('makeSureNoOneWatching')} - + )}
    diff --git a/ui/pages/settings/experimental-tab/experimental-tab.component.js b/ui/pages/settings/experimental-tab/experimental-tab.component.js index 948d062dad5b..fd84fe7a1369 100644 --- a/ui/pages/settings/experimental-tab/experimental-tab.component.js +++ b/ui/pages/settings/experimental-tab/experimental-tab.component.js @@ -216,7 +216,6 @@ export default class ExperimentalTab extends PureComponent {
    {t('toggleRequestQueueField')} @@ -225,7 +224,10 @@ export default class ExperimentalTab extends PureComponent {
    -
    +
    { }, ); - it('returns false if none account is selected', () => { + it('returns false if no account is selected', () => { const state = MOCK_STATE; state.metamask.internalAccounts.selectedAccount = ''; diff --git a/ui/selectors/multichain.test.ts b/ui/selectors/multichain.test.ts index d811f57798c3..fd87387a22e3 100644 --- a/ui/selectors/multichain.test.ts +++ b/ui/selectors/multichain.test.ts @@ -1,3 +1,4 @@ +import { Cryptocurrency } from '@metamask/assets-controllers'; import { getNativeCurrency } from '../ducks/metamask/metamask'; import { MULTICHAIN_PROVIDER_CONFIGS, @@ -12,6 +13,7 @@ import { import { CHAIN_IDS } from '../../shared/constants/network'; import { AccountsState } from './accounts'; import { + MultichainState, getMultichainCurrentChainId, getMultichainCurrentCurrency, getMultichainDefaultToken, @@ -25,15 +27,16 @@ import { } from './multichain'; import { getCurrentCurrency, getCurrentNetwork, getShouldShowFiat } from '.'; -type TestState = AccountsState & { - metamask: { - preferences: { showFiatInTestnets: boolean }; - providerConfig: { type: string; ticker: string; chainId: string }; - currentCurrency: string; - currencyRates: Record; - completedOnboarding: boolean; +type TestState = MultichainState & + AccountsState & { + metamask: { + preferences: { showFiatInTestnets: boolean }; + providerConfig: { type: string; ticker: string; chainId: string }; + currentCurrency: string; + currencyRates: Record; + completedOnboarding: boolean; + }; }; -}; function getEvmState(): TestState { return { @@ -57,6 +60,22 @@ function getEvmState(): TestState { selectedAccount: MOCK_ACCOUNT_EOA.id, accounts: MOCK_ACCOUNTS, }, + balances: { + [MOCK_ACCOUNT_BIP122_P2WPKH.id]: { + 'bip122:000000000019d6689c085ae165831e93/slip44:0': { + amount: '1.00000000', + unit: 'BTC', + }, + }, + }, + fiatCurrency: 'usd', + cryptocurrencies: [Cryptocurrency.Btc], + rates: { + btc: { + conversionDate: 0, + conversionRate: '100000', + }, + }, }, }; } diff --git a/ui/selectors/multichain.ts b/ui/selectors/multichain.ts index 3e9070b1a3ab..62c607397073 100644 --- a/ui/selectors/multichain.ts +++ b/ui/selectors/multichain.ts @@ -1,5 +1,6 @@ -import { isEvmAccountType } from '@metamask/keyring-api'; +import { InternalAccount, isEvmAccountType } from '@metamask/keyring-api'; import { ProviderConfig } from '@metamask/network-controller'; +import type { RatesControllerState } from '@metamask/assets-controllers'; import { CaipChainId, KnownCaipNamespace, @@ -16,6 +17,7 @@ import { getNativeCurrency, getProviderConfig, } from '../ducks/metamask/metamask'; +import { BalancesControllerState } from '../../app/scripts/lib/accounts/BalancesController'; import { AccountsState } from './accounts'; import { getAllNetworks, @@ -28,12 +30,16 @@ import { getShouldShowFiat, } from '.'; -export type MultichainState = AccountsState & { - metamask: { - // TODO: Use states from new {Rates,Balances,Chain}Controller - }; +export type RatesState = { + metamask: RatesControllerState; +}; + +export type BalancesState = { + metamask: BalancesControllerState; }; +export type MultichainState = AccountsState & RatesState & BalancesState; + export type MultichainNetwork = { nickname: string; isEvmNetwork: boolean; @@ -50,8 +56,9 @@ export function getMultichainNetworkProviders( export function getMultichainNetwork( state: MultichainState, + account?: InternalAccount, ): MultichainNetwork { - const isEvm = getMultichainIsEvm(state); + const isEvm = getMultichainIsEvm(state, account); // EVM networks const evmNetworks: ProviderConfig[] = getAllNetworks(state); @@ -80,7 +87,7 @@ export function getMultichainNetwork( // this as a CAIP-2 namespace and apply our filter with it // For non-EVM, we know we have a selected account, since the logic `isEvm` is based // on having a non-EVM account being selected! - const selectedAccount = getSelectedInternalAccount(state); + const selectedAccount = account ?? getSelectedInternalAccount(state); const nonEvmNetworks = getMultichainNetworkProviders(state); const nonEvmNetwork = nonEvmNetworks.find((provider) => { const { namespace } = parseCaipChainId(provider.chainId); @@ -108,11 +115,14 @@ export function getMultichainNetwork( // a popup (for ethereum related stuffs) is being shown (and uses this function), then the native // currency will be BTC.. -export function getMultichainIsEvm(state: MultichainState) { +export function getMultichainIsEvm( + state: MultichainState, + account?: InternalAccount, +) { const isOnboarded = getCompletedOnboarding(state); // Selected account is not available during onboarding (this is used in // the AppHeader) - const selectedAccount = getMaybeSelectedInternalAccount(state); + const selectedAccount = account ?? getMaybeSelectedInternalAccount(state); // There are no selected account during onboarding. we default to the original EVM behavior. return ( @@ -128,20 +138,27 @@ export function getMultichainIsEvm(state: MultichainState) { * it returns a network, but it actually returns a provider configuration specific to a multichain setup. * * @param state - The redux state. + * @param account - The multichain account. * @returns The current multichain provider configuration. */ -export function getMultichainProviderConfig(state: MultichainState) { - return getMultichainNetwork(state).network; +export function getMultichainProviderConfig( + state: MultichainState, + account?: InternalAccount, +) { + return getMultichainNetwork(state, account).network; } export function getMultichainCurrentNetwork(state: MultichainState) { return getMultichainProviderConfig(state); } -export function getMultichainNativeCurrency(state: MultichainState) { - return getMultichainIsEvm(state) +export function getMultichainNativeCurrency( + state: MultichainState, + account?: InternalAccount, +) { + return getMultichainIsEvm(state, account) ? getNativeCurrency(state) - : getMultichainProviderConfig(state).ticker; + : getMultichainProviderConfig(state, account).ticker; } export function getMultichainCurrentCurrency(state: MultichainState) { @@ -159,19 +176,33 @@ export function getMultichainCurrentCurrency(state: MultichainState) { : getMultichainProviderConfig(state).ticker; } -export function getMultichainCurrencyImage(state: MultichainState) { - if (getMultichainIsEvm(state)) { +export function getMultichainCurrencyImage( + state: MultichainState, + account?: InternalAccount, +) { + if (getMultichainIsEvm(state, account)) { return getNativeCurrencyImage(state); } const provider = getMultichainProviderConfig( state, + account, ) as MultichainProviderConfig; return provider.rpcPrefs?.imageUrl; } -export function getMultichainShouldShowFiat(state: MultichainState) { - return getMultichainIsEvm(state) +export function getMultichainNativeCurrencyImage( + state: MultichainState, + account?: InternalAccount, +) { + return getMultichainCurrencyImage(state, account); +} + +export function getMultichainShouldShowFiat( + state: MultichainState, + account?: InternalAccount, +) { + return getMultichainIsEvm(state, account) ? getShouldShowFiat(state) : // For now we force this for non-EVM true; @@ -199,3 +230,11 @@ export function getMultichainIsMainnet(state: MultichainState) { // update this for other non-EVM networks later! chainId === MultichainNetworks.BITCOIN; } + +export function getMultichainBalances(state: MultichainState) { + return state.metamask.balances; +} + +export const getMultichainCoinRates = (state: MultichainState) => { + return state.metamask.rates; +}; diff --git a/ui/store/actions.ts b/ui/store/actions.ts index d5356de53f49..5b417a9a5e98 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -201,20 +201,15 @@ export function createNewVaultAndRestore( Buffer.from(seedPhrase, 'utf8').values(), ); - // TODO: Add types for vault - // TODO: Replace `any` with type - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let vault: any; return new Promise((resolve, reject) => { callBackgroundMethod( 'createNewVaultAndRestore', [password, encodedSeedPhrase], - (err, _vault) => { + (err) => { if (err) { reject(err); return; } - vault = _vault; resolve(); }, ); @@ -223,7 +218,6 @@ export function createNewVaultAndRestore( .then(() => { dispatch(showAccountsPage()); dispatch(hideLoadingIndication()); - return vault; }) .catch((err) => { dispatch(displayWarning(err.message)); diff --git a/yarn.lock b/yarn.lock index 052f24b7aaf0..dfc472553001 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1609,7 +1609,7 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.24.1, @babel/runtime@npm:^7.24.5": +"@babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.24.1, @babel/runtime@npm:^7.24.5": version: 7.24.6 resolution: "@babel/runtime@npm:7.24.6" dependencies: @@ -3569,6 +3569,20 @@ __metadata: languageName: node linkType: hard +"@floating-ui/react@npm:^0.26.9": + version: 0.26.12 + resolution: "@floating-ui/react@npm:0.26.12" + dependencies: + "@floating-ui/react-dom": "npm:^2.0.0" + "@floating-ui/utils": "npm:^0.2.0" + tabbable: "npm:^6.0.0" + peerDependencies: + react: ">=16.8.0" + react-dom: ">=16.8.0" + checksum: 10/da77f6b99ed0c8d5169f0ed287304615bef7c66b7a0011e4425e843016f6450a928bc27310a861fb14f8a1e58ef11fbdd92550583440f11af5d1a905968453a6 + languageName: node + linkType: hard + "@floating-ui/utils@npm:^0.1.3": version: 0.1.6 resolution: "@floating-ui/utils@npm:0.1.6" @@ -3576,6 +3590,13 @@ __metadata: languageName: node linkType: hard +"@floating-ui/utils@npm:^0.2.0": + version: 0.2.1 + resolution: "@floating-ui/utils@npm:0.2.1" + checksum: 10/33c9ab346e7b05c5a1e6a95bc902aafcfc2c9d513a147e2491468843bd5607531b06d0b9aa56aa491cbf22a6c2495c18ccfc4c0344baec54a689a7bb8e4898d6 + languageName: node + linkType: hard + "@fluent/syntax@npm:0.19.0": version: 0.19.0 resolution: "@fluent/syntax@npm:0.19.0" @@ -4119,6 +4140,87 @@ __metadata: languageName: node linkType: hard +"@json-schema-spec/json-pointer@npm:^0.1.2": + version: 0.1.2 + resolution: "@json-schema-spec/json-pointer@npm:0.1.2" + checksum: 10/2a691ffc11f1a266ca4d0c9e2c99791679d580f343ef69746fad623d1abcf4953adde987890e41f906767d7729604c0182341e9012388b73a44d5b21fb296453 + languageName: node + linkType: hard + +"@json-schema-tools/dereferencer@npm:1.5.1": + version: 1.5.1 + resolution: "@json-schema-tools/dereferencer@npm:1.5.1" + dependencies: + "@json-schema-tools/reference-resolver": "npm:^1.2.1" + "@json-schema-tools/traverse": "npm:^1.7.5" + fast-safe-stringify: "npm:^2.0.7" + checksum: 10/1852b6249916014ea0554c993d15fe2a32bfbbfe160d0effc720d41a5252c7cdbd7c37f77f2728c085d9024b3cd077bb7f7e774b8fb88ac1eb3359e069177b02 + languageName: node + linkType: hard + +"@json-schema-tools/dereferencer@npm:1.5.4": + version: 1.5.4 + resolution: "@json-schema-tools/dereferencer@npm:1.5.4" + dependencies: + "@json-schema-tools/reference-resolver": "npm:^1.2.4" + "@json-schema-tools/traverse": "npm:^1.7.8" + fast-safe-stringify: "npm:^2.0.7" + checksum: 10/2dc01d1d9208cc63af81b680dcd0e46716fe60123c38fc37051041fc2d704ce5f71554fdfbd0cb96845ff2f44c6108ac16d710fcf7cd51ffbe08812b1bee8779 + languageName: node + linkType: hard + +"@json-schema-tools/dereferencer@npm:1.5.5": + version: 1.5.5 + resolution: "@json-schema-tools/dereferencer@npm:1.5.5" + dependencies: + "@json-schema-tools/reference-resolver": "npm:^1.2.4" + "@json-schema-tools/traverse": "npm:^1.7.8" + fast-safe-stringify: "npm:^2.0.7" + checksum: 10/25d2ebb2741d5deee21570c39cb09e49911ac58712dc18741772de684f5c4f74f7c322f038e2e9b9091c2c2687a46dd08f3945f629faa7434296ada8ec9cc8d2 + languageName: node + linkType: hard + +"@json-schema-tools/meta-schema@npm:1.6.19": + version: 1.6.19 + resolution: "@json-schema-tools/meta-schema@npm:1.6.19" + checksum: 10/29e4fec73dc4ada7b451f6eab1251827158e619ae559c3c5b33c15d90b311812b08b933a9498261ebd7f7e88ce726786a611170e817b7167987db1e26955ddcb + languageName: node + linkType: hard + +"@json-schema-tools/meta-schema@npm:^1.6.10": + version: 1.7.4 + resolution: "@json-schema-tools/meta-schema@npm:1.7.4" + checksum: 10/6a688260eaac550d372325a39e7d4f44db7904a3fcaa3d3e0bf318b259007326592b53e511025ff35010ba0e0314dba338fd169338c5ea090328663f3e7cbd46 + languageName: node + linkType: hard + +"@json-schema-tools/reference-resolver@npm:1.2.4": + version: 1.2.4 + resolution: "@json-schema-tools/reference-resolver@npm:1.2.4" + dependencies: + "@json-schema-spec/json-pointer": "npm:^0.1.2" + isomorphic-fetch: "npm:^3.0.0" + checksum: 10/1ad98d011e5aad72000112215615715593a0a244ca82dbf6008cc93bfcd14ef99a0796ab4e808faee083dc13182dc9ab2d01ca5db4f44ca880f45de2f5ea2437 + languageName: node + linkType: hard + +"@json-schema-tools/reference-resolver@npm:^1.2.1, @json-schema-tools/reference-resolver@npm:^1.2.4": + version: 1.2.5 + resolution: "@json-schema-tools/reference-resolver@npm:1.2.5" + dependencies: + "@json-schema-spec/json-pointer": "npm:^0.1.2" + isomorphic-fetch: "npm:^3.0.0" + checksum: 10/0f48098ea6df853a56fc7c758974eee4c5b7e3979123f49f52929c82a1eb263c7d0154efc6671325920d670494b05cae4d4625c6204023b4b1fed6e5f93ccb96 + languageName: node + linkType: hard + +"@json-schema-tools/traverse@npm:^1.7.5, @json-schema-tools/traverse@npm:^1.7.8": + version: 1.10.3 + resolution: "@json-schema-tools/traverse@npm:1.10.3" + checksum: 10/690623740d223ea373d8e561dad5c70bf86461bcedc5fc45da01c87bcdf3284bbdbad3006d4a423f8d82e4b2d4580e45f92c0b272f006024fb597d7f01876215 + languageName: node + linkType: hard + "@juggle/resize-observer@npm:^3.3.1": version: 3.4.0 resolution: "@juggle/resize-observer@npm:3.4.0" @@ -4358,6 +4460,33 @@ __metadata: languageName: node linkType: hard +"@mantine/core@npm:^7.8.0": + version: 7.8.0 + resolution: "@mantine/core@npm:7.8.0" + dependencies: + "@floating-ui/react": "npm:^0.26.9" + clsx: "npm:2.1.0" + react-number-format: "npm:^5.3.1" + react-remove-scroll: "npm:^2.5.7" + react-textarea-autosize: "npm:8.5.3" + type-fest: "npm:^4.12.0" + peerDependencies: + "@mantine/hooks": 7.8.0 + react: ^18.2.0 + react-dom: ^18.2.0 + checksum: 10/9d3ba53cd41a7b725579dec3723ee92444b45c51a0ed7a283caad047c1a9d3d4c8edf2cf143c4abf8959f3ade62cc7cdcb552fe1f4bfc1ef0f6a6d6136ce958f + languageName: node + linkType: hard + +"@mantine/hooks@npm:^7.8.0": + version: 7.8.0 + resolution: "@mantine/hooks@npm:7.8.0" + peerDependencies: + react: ^18.2.0 + checksum: 10/723d963995076574842ed3296a9acc63fd4a279d265a80edfe7f32c0359f70821e86dc5da5c37c13ce4ce8edfcbbf2c0c32a3024c60a7167172034cf6ddac220 + languageName: node + linkType: hard + "@material-ui/core@npm:^4.11.0": version: 4.11.0 resolution: "@material-ui/core@npm:4.11.0" @@ -4487,60 +4616,60 @@ __metadata: languageName: node linkType: hard -"@metamask-institutional/custody-controller@npm:^0.2.27": - version: 0.2.27 - resolution: "@metamask-institutional/custody-controller@npm:0.2.27" +"@metamask-institutional/custody-controller@npm:^0.2.30": + version: 0.2.30 + resolution: "@metamask-institutional/custody-controller@npm:0.2.30" dependencies: "@ethereumjs/util": "npm:^8.0.5" - "@metamask-institutional/custody-keyring": "npm:^2.0.0" - "@metamask-institutional/sdk": "npm:^0.1.27" + "@metamask-institutional/custody-keyring": "npm:^2.0.3" + "@metamask-institutional/sdk": "npm:^0.1.30" "@metamask-institutional/types": "npm:^1.1.0" - "@metamask/obs-store": "npm:^8.0.0" - checksum: 10/b834477c4551fdbd56143742038f1b101cb72b1655380a63d6d84416af949b259109a22967d3233009d737400f656c91ba100dcb61522eb14e6715564f07e404 + "@metamask/obs-store": "npm:^9.0.0" + checksum: 10/3d5ad6675d09f67bff924461b2d72f6c406a8cf86523119bcc8dea0f473501b8644f2dafd3babfcc4d2a0cbeb44d32b1a15dad701b481daac34c5eb4e5bcdd4b languageName: node linkType: hard -"@metamask-institutional/custody-keyring@npm:^2.0.0": - version: 2.0.0 - resolution: "@metamask-institutional/custody-keyring@npm:2.0.0" +"@metamask-institutional/custody-keyring@npm:^2.0.3": + version: 2.0.3 + resolution: "@metamask-institutional/custody-keyring@npm:2.0.3" dependencies: "@ethereumjs/tx": "npm:^4.1.1" "@ethereumjs/util": "npm:^8.0.5" "@metamask-institutional/configuration-client": "npm:^2.0.1" - "@metamask-institutional/sdk": "npm:^0.1.27" + "@metamask-institutional/sdk": "npm:^0.1.30" "@metamask-institutional/types": "npm:^1.1.0" - "@metamask/obs-store": "npm:^8.0.0" + "@metamask/obs-store": "npm:^9.0.0" crypto: "npm:^1.0.1" lodash.clonedeep: "npm:^4.5.0" - checksum: 10/14563443d157d97554ab4456c69ecba52aacde9659bcdc5b20724a3cf7c626c3ef624446823ceafbf3aa25307e89f0dc09636e8db49f49f48d5d7c6b37f52bf9 + checksum: 10/987beeeed67fb92a436eb1318f48ec2cc0ceb1ae944b7f5b2e492dcdc28a4298c5a8d25a520022ac52f87a411f7341961100be47a9626fbb1674aed349d98737 languageName: node linkType: hard -"@metamask-institutional/extension@npm:^0.3.24": - version: 0.3.24 - resolution: "@metamask-institutional/extension@npm:0.3.24" +"@metamask-institutional/extension@npm:^0.3.27": + version: 0.3.27 + resolution: "@metamask-institutional/extension@npm:0.3.27" dependencies: "@ethereumjs/util": "npm:^8.0.5" - "@metamask-institutional/custody-controller": "npm:^0.2.27" - "@metamask-institutional/custody-keyring": "npm:^2.0.0" + "@metamask-institutional/custody-controller": "npm:^0.2.30" + "@metamask-institutional/custody-keyring": "npm:^2.0.3" "@metamask-institutional/portfolio-dashboard": "npm:^1.4.1" - "@metamask-institutional/sdk": "npm:^0.1.27" - "@metamask-institutional/transaction-update": "npm:^0.2.2" + "@metamask-institutional/sdk": "npm:^0.1.30" + "@metamask-institutional/transaction-update": "npm:^0.2.5" "@metamask-institutional/types": "npm:^1.1.0" jest-create-mock-instance: "npm:^2.0.0" jest-fetch-mock: "npm:3.0.3" lodash.clonedeep: "npm:^4.5.0" - checksum: 10/7ec773d3f98b61d4d6b877e39eec239aca3cb5accaa2211728ddbad32fb6dba5f1c2e7ac7e90e1606bf94995f78dd323cb64a06fa587fd435b7e1592515f73ab + checksum: 10/dc9eefe8045607cd415b9db4a8df833c9a523e9d06a3a0e49e4c6e85063924db1f117725a91c926f19ce26d0701fc175ea4ad38fb13a8a3b092434bcd7fd7882 languageName: node linkType: hard -"@metamask-institutional/institutional-features@npm:^1.3.2": - version: 1.3.2 - resolution: "@metamask-institutional/institutional-features@npm:1.3.2" +"@metamask-institutional/institutional-features@npm:^1.3.5": + version: 1.3.5 + resolution: "@metamask-institutional/institutional-features@npm:1.3.5" dependencies: - "@metamask-institutional/custody-keyring": "npm:^2.0.0" - "@metamask/obs-store": "npm:^8.0.0" - checksum: 10/be5e8722c1180cf7127ee4c7cab0b26a60cb56e7bf0147836b496496bc6ada4de3e0265b97118ba4229ae6a847188097ed7175d51d689c5898e381fe54707aa9 + "@metamask-institutional/custody-keyring": "npm:^2.0.3" + "@metamask/obs-store": "npm:^9.0.0" + checksum: 10/1a154dbbfc71c9fee43d755d901423e3ea17ad149679225481fdc2d73ae95960e1805a792dbe660dd778703614ea5fd7390314bd7099c8ede510db1d23bc08ab languageName: node linkType: hard @@ -4558,9 +4687,9 @@ __metadata: languageName: node linkType: hard -"@metamask-institutional/sdk@npm:^0.1.27": - version: 0.1.27 - resolution: "@metamask-institutional/sdk@npm:0.1.27" +"@metamask-institutional/sdk@npm:^0.1.30": + version: 0.1.30 + resolution: "@metamask-institutional/sdk@npm:0.1.30" dependencies: "@metamask-institutional/simplecache": "npm:^1.1.0" "@metamask-institutional/types": "npm:^1.1.0" @@ -4568,7 +4697,7 @@ __metadata: "@types/node": "npm:^20.11.17" bignumber.js: "npm:^9.1.1" jsonwebtoken: "npm:^9.0.0" - checksum: 10/9de0d737cab194c8f16a63f92bade1265667f2042c4449bdde60240afb09cdfb71c2b583fbd629a9c72c43530b8d6816def91601aa517c8b47b0b2d473095397 + checksum: 10/3f36925fa9399a0ea06e2a64ea89accfb34f0a17581ab69652b4f325a948db10e88faebcca4f7c2d9f5f1f1c7f98bd8f970b7a489218dfd1be8cebc669a2f67e languageName: node linkType: hard @@ -4579,17 +4708,17 @@ __metadata: languageName: node linkType: hard -"@metamask-institutional/transaction-update@npm:^0.2.2": - version: 0.2.2 - resolution: "@metamask-institutional/transaction-update@npm:0.2.2" +"@metamask-institutional/transaction-update@npm:^0.2.5": + version: 0.2.5 + resolution: "@metamask-institutional/transaction-update@npm:0.2.5" dependencies: "@ethereumjs/util": "npm:^8.0.5" - "@metamask-institutional/custody-keyring": "npm:^2.0.0" - "@metamask-institutional/sdk": "npm:^0.1.27" + "@metamask-institutional/custody-keyring": "npm:^2.0.3" + "@metamask-institutional/sdk": "npm:^0.1.30" "@metamask-institutional/types": "npm:^1.1.0" - "@metamask-institutional/websocket-client": "npm:^0.2.2" - "@metamask/obs-store": "npm:^8.0.0" - checksum: 10/31c62a2d207e8e3c2469b870eecb18ff2db450eda8b28c2d428a69cc9eee8a477142f74abebad50c62a6e0f1132dafa8db6b8bf95f43677a401a54b4d3cd5fd0 + "@metamask-institutional/websocket-client": "npm:^0.2.5" + "@metamask/obs-store": "npm:^9.0.0" + checksum: 10/9dbcf7c38a03becf61ab013f78df225da1f6de12976f328e7809c0edda5ab9e1aeee2b4d5b9430c15d5dc9f7040fa703c560c58073d601110895388c1c15d7a8 languageName: node linkType: hard @@ -4600,15 +4729,15 @@ __metadata: languageName: node linkType: hard -"@metamask-institutional/websocket-client@npm:^0.2.2": - version: 0.2.2 - resolution: "@metamask-institutional/websocket-client@npm:0.2.2" +"@metamask-institutional/websocket-client@npm:^0.2.5": + version: 0.2.5 + resolution: "@metamask-institutional/websocket-client@npm:0.2.5" dependencies: - "@metamask-institutional/custody-keyring": "npm:^2.0.0" - "@metamask-institutional/sdk": "npm:^0.1.27" + "@metamask-institutional/custody-keyring": "npm:^2.0.3" + "@metamask-institutional/sdk": "npm:^0.1.30" "@metamask-institutional/types": "npm:^1.1.0" mock-socket: "npm:^9.2.1" - checksum: 10/652ffded926f5064e543e15e01992ec37a588783bc711a6f74404c1984ac5406fa83ab19187f00ae9b81a182cb46be08b0be388f583d68d6b45500969b5b2f46 + checksum: 10/4743ccbb3a92a5b7ddccfd9f72741910bb93cc769023c8b9ee7944bb82f79938e45b10af5f7754b2898dc218c0e3874cb38aa628f96685fc69d956900723755d languageName: node linkType: hard @@ -4686,7 +4815,14 @@ __metadata: languageName: node linkType: hard -"@metamask/approval-controller@npm:^6.0.1, @metamask/approval-controller@npm:^6.0.2": +"@metamask/api-specs@npm:^0.9.3": + version: 0.9.3 + resolution: "@metamask/api-specs@npm:0.9.3" + checksum: 10/803852ba43a0fbabb43aeba2ca63e43d22a99d35710700aa04c92cc85184c93024b052b2ee43831762341848de42d172c99485fa7b659249e75255ff8d29d0b2 + languageName: node + linkType: hard + +"@metamask/approval-controller@npm:^6.0.2": version: 6.0.2 resolution: "@metamask/approval-controller@npm:6.0.2" dependencies: @@ -5481,22 +5617,7 @@ __metadata: languageName: node linkType: hard -"@metamask/keyring-api@npm:^5.1.0": - version: 5.1.0 - resolution: "@metamask/keyring-api@npm:5.1.0" - dependencies: - "@metamask/snaps-sdk": "npm:^3.1.1" - "@metamask/utils": "npm:^8.3.0" - "@types/uuid": "npm:^9.0.1" - superstruct: "npm:^1.0.3" - uuid: "npm:^9.0.0" - peerDependencies: - "@metamask/providers": ">=15 <17" - checksum: 10/f1c7ddfabd1d2ef45f8b05d1a1b3c71ce3bb4d8111e53d00acc71f68a18473c0e5f90583644c72ee85e52021857d9f9de3fc9aaec9819209b849408539909eca - languageName: node - linkType: hard - -"@metamask/keyring-api@npm:^6.0.0, @metamask/keyring-api@npm:^6.1.1": +"@metamask/keyring-api@npm:^6.1.1": version: 6.4.0 resolution: "@metamask/keyring-api@npm:6.4.0" dependencies: @@ -5528,45 +5649,24 @@ __metadata: languageName: node linkType: hard -"@metamask/keyring-controller@npm:15.0.0": - version: 15.0.0 - resolution: "@metamask/keyring-controller@npm:15.0.0" +"@metamask/keyring-controller@npm:^16.0.0, @metamask/keyring-controller@npm:^16.1.0": + version: 16.1.0 + resolution: "@metamask/keyring-controller@npm:16.1.0" dependencies: "@ethereumjs/util": "npm:^8.1.0" - "@keystonehq/metamask-airgapped-keyring": "npm:^0.13.1" - "@metamask/base-controller": "npm:^5.0.1" - "@metamask/browser-passworder": "npm:^4.3.0" - "@metamask/eth-hd-keyring": "npm:^7.0.1" - "@metamask/eth-sig-util": "npm:^7.0.1" - "@metamask/eth-simple-keyring": "npm:^6.0.1" - "@metamask/keyring-api": "npm:^5.1.0" - "@metamask/message-manager": "npm:^8.0.1" - "@metamask/utils": "npm:^8.3.0" - async-mutex: "npm:^0.2.6" - ethereumjs-wallet: "npm:^1.0.1" - immer: "npm:^9.0.6" - checksum: 10/ae6c378ba68ee8e37fbf273a68f1ce0e5439e3f8c9b38a338fb9f9bd0fd6b12f9927e9c5f33a2ead87dd76e7665a71073187d744e7b810aecf24e2964b6af7a7 - languageName: node - linkType: hard - -"@metamask/keyring-controller@npm:^16.0.0": - version: 16.0.0 - resolution: "@metamask/keyring-controller@npm:16.0.0" - dependencies: - "@ethereumjs/util": "npm:^8.1.0" - "@keystonehq/metamask-airgapped-keyring": "npm:^0.13.1" + "@keystonehq/metamask-airgapped-keyring": "npm:^0.14.1" "@metamask/base-controller": "npm:^5.0.2" "@metamask/browser-passworder": "npm:^4.3.0" "@metamask/eth-hd-keyring": "npm:^7.0.1" "@metamask/eth-sig-util": "npm:^7.0.1" "@metamask/eth-simple-keyring": "npm:^6.0.1" - "@metamask/keyring-api": "npm:^6.0.0" - "@metamask/message-manager": "npm:^8.0.2" + "@metamask/keyring-api": "npm:^6.1.1" + "@metamask/message-manager": "npm:^9.0.0" "@metamask/utils": "npm:^8.3.0" - async-mutex: "npm:^0.2.6" + async-mutex: "npm:^0.5.0" ethereumjs-wallet: "npm:^1.0.1" immer: "npm:^9.0.6" - checksum: 10/33c10f4c61acfa0f8de7a3d90c2dfc63be1d137866653254e3d5f68dbf4ee886415e2ab620009e5b82c2a112bfab6d09653f5ad16adeccecd87b89f1f1fa0b7c + checksum: 10/62ee509d236808048013d171cb700900729aac448809b12c3647d71465c467015dbd00318500f2ec58fded4a45a106a2415fc3a6ab123a956c1aa9189a8132e0 languageName: node linkType: hard @@ -5591,27 +5691,6 @@ __metadata: languageName: node linkType: hard -"@metamask/keyring-controller@patch:@metamask/keyring-controller@npm%3A15.0.0#~/.yarn/patches/@metamask-keyring-controller-npm-15.0.0-fa070ce311.patch": - version: 15.0.0 - resolution: "@metamask/keyring-controller@patch:@metamask/keyring-controller@npm%3A15.0.0#~/.yarn/patches/@metamask-keyring-controller-npm-15.0.0-fa070ce311.patch::version=15.0.0&hash=3f5b2f" - dependencies: - "@ethereumjs/util": "npm:^8.1.0" - "@keystonehq/metamask-airgapped-keyring": "npm:^0.13.1" - "@metamask/base-controller": "npm:^5.0.1" - "@metamask/browser-passworder": "npm:^4.3.0" - "@metamask/eth-hd-keyring": "npm:^7.0.1" - "@metamask/eth-sig-util": "npm:^7.0.1" - "@metamask/eth-simple-keyring": "npm:^6.0.1" - "@metamask/keyring-api": "npm:^5.1.0" - "@metamask/message-manager": "npm:^8.0.1" - "@metamask/utils": "npm:^8.3.0" - async-mutex: "npm:^0.2.6" - ethereumjs-wallet: "npm:^1.0.1" - immer: "npm:^9.0.6" - checksum: 10/76116ea6ba8b85e1d3117f4ceebc31d27e591402d77afa9451f661e629b7c3a697d8fdf3b2a7ec536abf3d30d98fe92d2404c5356a2e8656c9886c38589b04f3 - languageName: node - linkType: hard - "@metamask/logging-controller@npm:^3.0.1": version: 3.0.1 resolution: "@metamask/logging-controller@npm:3.0.1" @@ -5663,7 +5742,7 @@ __metadata: languageName: node linkType: hard -"@metamask/message-manager@npm:^8.0.1, @metamask/message-manager@npm:^8.0.2": +"@metamask/message-manager@npm:^8.0.2": version: 8.0.2 resolution: "@metamask/message-manager@npm:8.0.2" dependencies: @@ -5678,6 +5757,21 @@ __metadata: languageName: node linkType: hard +"@metamask/message-manager@npm:^9.0.0": + version: 9.0.0 + resolution: "@metamask/message-manager@npm:9.0.0" + dependencies: + "@metamask/base-controller": "npm:^5.0.2" + "@metamask/controller-utils": "npm:^10.0.0" + "@metamask/eth-sig-util": "npm:^7.0.1" + "@metamask/utils": "npm:^8.3.0" + "@types/uuid": "npm:^8.3.0" + jsonschema: "npm:^1.2.4" + uuid: "npm:^8.3.2" + checksum: 10/9b30deada10c64bf92594c3d9e372aa3f6e4cf5c95ab7681901d61b2651451d2aac10cd25390b1cca8fa08db764396758781d760edf3de190930d02acfcbb0c6 + languageName: node + linkType: hard + "@metamask/message-signing-snap@npm:^0.3.3": version: 0.3.3 resolution: "@metamask/message-signing-snap@npm:0.3.3" @@ -5822,16 +5916,6 @@ __metadata: languageName: node linkType: hard -"@metamask/obs-store@npm:^8.0.0": - version: 8.1.0 - resolution: "@metamask/obs-store@npm:8.1.0" - dependencies: - "@metamask/safe-event-emitter": "npm:^2.0.0" - through2: "npm:^2.0.3" - checksum: 10/92356067fa3517526d656f2f0bdfbc4d39f65e27fb30d84240cfc9c1aa9cd5d743498952df18ed8efbb8887b6cc1bc1fab37bde3fb0fc059539e0dfcc67ff86f - languageName: node - linkType: hard - "@metamask/obs-store@npm:^9.0.0": version: 9.0.0 resolution: "@metamask/obs-store@npm:9.0.0" @@ -5862,11 +5946,11 @@ __metadata: linkType: hard "@metamask/permission-controller@npm:^9.0.2": - version: 9.1.1 - resolution: "@metamask/permission-controller@npm:9.1.1" + version: 9.1.0 + resolution: "@metamask/permission-controller@npm:9.1.0" dependencies: "@metamask/base-controller": "npm:^5.0.2" - "@metamask/controller-utils": "npm:^10.0.0" + "@metamask/controller-utils": "npm:^9.1.0" "@metamask/json-rpc-engine": "npm:^8.0.2" "@metamask/rpc-errors": "npm:^6.2.1" "@metamask/utils": "npm:^8.3.0" @@ -5876,7 +5960,7 @@ __metadata: nanoid: "npm:^3.1.31" peerDependencies: "@metamask/approval-controller": ^6.0.0 - checksum: 10/15b276863c8917779e6fa3aaa7df1cdc4e2342eb0f9a1cf75c84688bdc6ac63772315f8a2dbed68a3fa882e1d23dc61990d7c2308972f40c8241700b21f11677 + checksum: 10/bfae4c16cbe5b180b00ef029c3fa8d7f770247dfad4c0afc11822f4b0bd36373d6f749ac5507f23cf5dbd848096fa86ad2546be190c665c419cae58fcf0d7f00 languageName: node linkType: hard @@ -6136,24 +6220,24 @@ __metadata: languageName: node linkType: hard -"@metamask/signature-controller@npm:^14.0.1": - version: 14.0.1 - resolution: "@metamask/signature-controller@npm:14.0.1" +"@metamask/signature-controller@npm:^16.0.0": + version: 16.0.0 + resolution: "@metamask/signature-controller@npm:16.0.0" dependencies: - "@metamask/approval-controller": "npm:^6.0.1" - "@metamask/base-controller": "npm:^5.0.1" - "@metamask/controller-utils": "npm:^9.0.1" - "@metamask/keyring-controller": "npm:^14.0.1" + "@metamask/approval-controller": "npm:^6.0.2" + "@metamask/base-controller": "npm:^5.0.2" + "@metamask/controller-utils": "npm:^9.1.0" + "@metamask/keyring-controller": "npm:^16.0.0" "@metamask/logging-controller": "npm:^3.0.1" - "@metamask/message-manager": "npm:^8.0.1" + "@metamask/message-manager": "npm:^8.0.2" "@metamask/rpc-errors": "npm:^6.2.1" "@metamask/utils": "npm:^8.3.0" lodash: "npm:^4.17.21" peerDependencies: "@metamask/approval-controller": ^6.0.0 - "@metamask/keyring-controller": ^14.0.0 + "@metamask/keyring-controller": ^16.0.0 "@metamask/logging-controller": ^3.0.0 - checksum: 10/46fe7351048176d3e70adac9a9ca661d29240d7398dba7874083b8e67b99aa941c8636e84f263af5a992d526251c66bcc347af8437880fb3a434c1c22e8b595f + checksum: 10/410118733fa2fb95668beb2a0236a46330428cc1c0474a62b502762cd836ffbd380ba0397deecd32e046ef835d776727b33a88ddf4ca87630bba668a3e816f23 languageName: node linkType: hard @@ -6818,6 +6902,147 @@ __metadata: languageName: node linkType: hard +"@open-rpc/examples@npm:^1.6.1": + version: 1.7.0 + resolution: "@open-rpc/examples@npm:1.7.0" + checksum: 10/b1c9730965051971f049a8728434e7ec2cd1c45546861dfd207fa3c915aae12db9ada5242d78c86ed8ea3d6c3f8c49dbac3a28155a9af1cfee0344817847b73e + languageName: node + linkType: hard + +"@open-rpc/html-reporter-react@npm:^0.0.4": + version: 0.0.4 + resolution: "@open-rpc/html-reporter-react@npm:0.0.4" + dependencies: + "@mantine/core": "npm:^7.8.0" + "@mantine/hooks": "npm:^7.8.0" + "@tabler/icons-react": "npm:^3.2.0" + react: "npm:^18.2.0" + react-dom: "npm:^18.2.0" + react18-json-view: "npm:^0.2.8" + wouter: "npm:^3.1.2" + checksum: 10/4576f7217405eae19c832b1f76450734f05b38ef586560baa391e12e2ba36477cbebb84ea456d17eabe12b77d5e43269cbbe8201fe384e92ec815947d787d05f + languageName: node + linkType: hard + +"@open-rpc/meta-schema@npm:1.14.2": + version: 1.14.2 + resolution: "@open-rpc/meta-schema@npm:1.14.2" + checksum: 10/8689d447b7a7e9a01cb3479b086565cd16b29fbc04a7c867294264d03d2ada6d6b291e22f520742608509135d09d6b1efb6bf929e5a82943b298594d7e3e9650 + languageName: node + linkType: hard + +"@open-rpc/meta-schema@npm:^1.14.6": + version: 1.14.6 + resolution: "@open-rpc/meta-schema@npm:1.14.6" + checksum: 10/7cb672ea42c143c3fcb177ad04b935d56c38cb28fc7ede0a0bb50293e0e49dee81046c2d43bc57c8bbf9efbbb76356d60b4a8e408a03ecc8fa5952ef3e342316 + languageName: node + linkType: hard + +"@open-rpc/mock-server@npm:^1.7.5": + version: 1.7.5 + resolution: "@open-rpc/mock-server@npm:1.7.5" + dependencies: + "@open-rpc/examples": "npm:^1.6.1" + "@open-rpc/schema-utils-js": "npm:1.16.1" + "@open-rpc/server-js": "npm:1.9.3" + commander: "npm:^6.1.0" + lodash: "npm:^4.17.19" + bin: + open-rpc-mock-server: build/cli.js + checksum: 10/f80d3d51b4aeca498c38eca21cbe85e1840c4d5709d3d71781eac54c2ad79cd2c18da81c92c561baefd00f822d9d1f9c198c0e9e3cb2ffa9e2587f93ee0f28a3 + languageName: node + linkType: hard + +"@open-rpc/schema-utils-js@npm:1.15.0": + version: 1.15.0 + resolution: "@open-rpc/schema-utils-js@npm:1.15.0" + dependencies: + "@json-schema-tools/dereferencer": "npm:1.5.1" + "@json-schema-tools/meta-schema": "npm:^1.6.10" + "@json-schema-tools/reference-resolver": "npm:^1.2.1" + "@open-rpc/meta-schema": "npm:1.14.2" + ajv: "npm:^6.10.0" + detect-node: "npm:^2.0.4" + fast-safe-stringify: "npm:^2.0.7" + fs-extra: "npm:^9.0.0" + is-url: "npm:^1.2.4" + isomorphic-fetch: "npm:^3.0.0" + checksum: 10/88a9d27cdf77af13890f763c2aef660c15cc6a274268ae92b626ed7dab1cb4d1bf1bfc8470c49ef97c4cf40fb8e53aa4c95c27d17de5dfdbbffa0847bf79e3a9 + languageName: node + linkType: hard + +"@open-rpc/schema-utils-js@npm:1.16.1": + version: 1.16.1 + resolution: "@open-rpc/schema-utils-js@npm:1.16.1" + dependencies: + "@json-schema-tools/dereferencer": "npm:1.5.4" + "@json-schema-tools/meta-schema": "npm:1.6.19" + "@json-schema-tools/reference-resolver": "npm:1.2.4" + "@open-rpc/meta-schema": "npm:1.14.2" + ajv: "npm:^6.10.0" + detect-node: "npm:^2.0.4" + fast-safe-stringify: "npm:^2.0.7" + fs-extra: "npm:^9.0.0" + is-url: "npm:^1.2.4" + isomorphic-fetch: "npm:^3.0.0" + checksum: 10/090f77ea88cb6b292631e6635659127eff0b975e8985f67d2e7d5364c3e0ea847f202fede814b3ef6fd6b4257adc20673ce0aa76b4e914d06cb758c8330e388d + languageName: node + linkType: hard + +"@open-rpc/schema-utils-js@npm:^1.16.2": + version: 1.16.2 + resolution: "@open-rpc/schema-utils-js@npm:1.16.2" + dependencies: + "@json-schema-tools/dereferencer": "npm:1.5.5" + "@json-schema-tools/meta-schema": "npm:1.6.19" + "@json-schema-tools/reference-resolver": "npm:1.2.4" + "@open-rpc/meta-schema": "npm:1.14.2" + ajv: "npm:^6.10.0" + detect-node: "npm:^2.0.4" + fast-safe-stringify: "npm:^2.0.7" + fs-extra: "npm:^10.1.0" + is-url: "npm:^1.2.4" + isomorphic-fetch: "npm:^3.0.0" + checksum: 10/4ba6b8c5606e3910f1b54f8b1519c4f4c78b7d2dfda023ef709ff59d9294f6cb46bf88093aa6159823173f5ba9183ee2b4e4dee8988fac7d5a7eb806b9cdae4a + languageName: node + linkType: hard + +"@open-rpc/server-js@npm:1.9.3": + version: 1.9.3 + resolution: "@open-rpc/server-js@npm:1.9.3" + dependencies: + "@open-rpc/schema-utils-js": "npm:1.15.0" + body-parser: "npm:^1.19.0" + connect: "npm:^3.7.0" + cors: "npm:^2.8.5" + json-schema-faker: "npm:^0.5.0-rcv.26" + lodash: "npm:^4.17.19" + node-ipc: "npm:9.1.1" + ws: "npm:^8.0.0" + checksum: 10/27005f6a782f99892989a5e6df8d7d5ce00aa83f09f009d5826a19fe3d8c2d65ea51613a0d10ae4f798774279c4b5dd204aa5cf57eb657d7c74c9bb3a317d77e + languageName: node + linkType: hard + +"@open-rpc/test-coverage@npm:^2.2.2": + version: 2.2.2 + resolution: "@open-rpc/test-coverage@npm:2.2.2" + dependencies: + "@open-rpc/html-reporter-react": "npm:^0.0.4" + "@open-rpc/schema-utils-js": "npm:^1.16.2" + "@types/isomorphic-fetch": "npm:0.0.35" + "@types/lodash": "npm:^4.14.162" + ajv: "npm:^7.0.0" + colors: "npm:^1.3.3" + commander: "npm:^8.0.0" + isomorphic-fetch: "npm:^3.0.0" + json-schema-faker: "npm:^0.5.0-rcv.29" + lodash: "npm:^4.17.20" + bin: + open-rpc-test-coverage: bin/cli.js + checksum: 10/fc764031d8395dca73187684143f07cd2f6be854bedbd943b086e46f94e5c4207942bf87f1d4ac66f4220f209d6d4a7d50b0eb70d4586e2d07a4e086f0e344b1 + languageName: node + linkType: hard + "@pkgjs/parseargs@npm:^0.11.0": version: 0.11.0 resolution: "@pkgjs/parseargs@npm:0.11.0" @@ -9028,6 +9253,24 @@ __metadata: languageName: node linkType: hard +"@tabler/icons-react@npm:^3.2.0": + version: 3.2.0 + resolution: "@tabler/icons-react@npm:3.2.0" + dependencies: + "@tabler/icons": "npm:3.2.0" + peerDependencies: + react: ">= 16" + checksum: 10/743349a5c7d8cff1d55a101147c2fedc19dc844d0ec9f3de367383382ee314c444166cf137aca0154a7eaf8bcb4f3398a89bda9eb72a04f8c3e6ceb8dc582492 + languageName: node + linkType: hard + +"@tabler/icons@npm:3.2.0": + version: 3.2.0 + resolution: "@tabler/icons@npm:3.2.0" + checksum: 10/4fe4de5ad3cdb54d7c711523dc6e1fc43605bca3fcfc777277da1713184ed5f9034010435c09a5bf928d6774cd643297483394a183aead42eb8f8a6626b70bcc + languageName: node + linkType: hard + "@testing-library/dom@npm:^7.17.1": version: 7.22.2 resolution: "@testing-library/dom@npm:7.22.2" @@ -9916,6 +10159,13 @@ __metadata: languageName: node linkType: hard +"@types/isomorphic-fetch@npm:0.0.35": + version: 0.0.35 + resolution: "@types/isomorphic-fetch@npm:0.0.35" + checksum: 10/cff2d6eb7cf69dc77b88183f029b18007847a86f2b5f02a59f1c7444771d97443b8e010fec24860c0454a363bcb81afeeaacf7094a31ef337115f920285ac7cf + languageName: node + linkType: hard + "@types/istanbul-lib-coverage@npm:*, @types/istanbul-lib-coverage@npm:^2.0.0, @types/istanbul-lib-coverage@npm:^2.0.1": version: 2.0.3 resolution: "@types/istanbul-lib-coverage@npm:2.0.3" @@ -10013,10 +10263,10 @@ __metadata: languageName: node linkType: hard -"@types/lodash@npm:^4.14.136, @types/lodash@npm:^4.14.167": - version: 4.14.184 - resolution: "@types/lodash@npm:4.14.184" - checksum: 10/8906648e102cae18719e4ba53f49b44b1d0dec8bd8082c5aa0c9ec1012b3a6e9ac268fde226ea5ee9e9cf124ce8a564d06dedb1d317fd78f74a0c8b4a5e2d793 +"@types/lodash@npm:^4.14.136, @types/lodash@npm:^4.14.162, @types/lodash@npm:^4.14.167": + version: 4.17.0 + resolution: "@types/lodash@npm:4.17.0" + checksum: 10/2053203292b5af99352d108656ceb15d39da5922fc3fb8186e1552d65c82d6e545372cc97f36c95873aa7186404d59d9305e9d49254d4ae55e77df1e27ab7b5d languageName: node linkType: hard @@ -10617,14 +10867,14 @@ __metadata: linkType: hard "@typescript-eslint/eslint-plugin@npm:^7.10.0": - version: 7.10.0 - resolution: "@typescript-eslint/eslint-plugin@npm:7.10.0" + version: 7.11.0 + resolution: "@typescript-eslint/eslint-plugin@npm:7.11.0" dependencies: "@eslint-community/regexpp": "npm:^4.10.0" - "@typescript-eslint/scope-manager": "npm:7.10.0" - "@typescript-eslint/type-utils": "npm:7.10.0" - "@typescript-eslint/utils": "npm:7.10.0" - "@typescript-eslint/visitor-keys": "npm:7.10.0" + "@typescript-eslint/scope-manager": "npm:7.11.0" + "@typescript-eslint/type-utils": "npm:7.11.0" + "@typescript-eslint/utils": "npm:7.11.0" + "@typescript-eslint/visitor-keys": "npm:7.11.0" graphemer: "npm:^1.4.0" ignore: "npm:^5.3.1" natural-compare: "npm:^1.4.0" @@ -10635,7 +10885,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10/dfe505cdf718dd29e8637b902e4c544c6b7d246d2051fd1936090423eb3dadfe2bd757de51e565e6fd80e74cf1918e191c26fee6df515100484ec3efd9b8d111 + checksum: 10/be95ed0bbd5b34c47239677ea39d531bcd8a18717a67d70a297bed5b0050b256159856bb9c1e894ac550d011c24bb5b4abf8056c5d70d0d5895f0cc1accd14ea languageName: node linkType: hard @@ -10658,20 +10908,20 @@ __metadata: linkType: hard "@typescript-eslint/parser@npm:^7.10.0": - version: 7.10.0 - resolution: "@typescript-eslint/parser@npm:7.10.0" + version: 7.11.0 + resolution: "@typescript-eslint/parser@npm:7.11.0" dependencies: - "@typescript-eslint/scope-manager": "npm:7.10.0" - "@typescript-eslint/types": "npm:7.10.0" - "@typescript-eslint/typescript-estree": "npm:7.10.0" - "@typescript-eslint/visitor-keys": "npm:7.10.0" + "@typescript-eslint/scope-manager": "npm:7.11.0" + "@typescript-eslint/types": "npm:7.11.0" + "@typescript-eslint/typescript-estree": "npm:7.11.0" + "@typescript-eslint/visitor-keys": "npm:7.11.0" debug: "npm:^4.3.4" peerDependencies: eslint: ^8.56.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/1fa71049b2debf2f7f5366fb433e3d4c8e1591c2061a15fa8797d14623a2b6984340a59e7717acc013ce8c6a2ed32c5c0e811fe948b5936d41c2a5a09b61d130 + checksum: 10/0a32417aec62d7de04427323ab3fc8159f9f02429b24f739d8748e8b54fc65b0e3dbae8e4779c4b795f0d8e5f98a4d83a43b37ea0f50ebda51546cdcecf73caa languageName: node linkType: hard @@ -10695,22 +10945,22 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:7.10.0": - version: 7.10.0 - resolution: "@typescript-eslint/scope-manager@npm:7.10.0" +"@typescript-eslint/scope-manager@npm:7.11.0": + version: 7.11.0 + resolution: "@typescript-eslint/scope-manager@npm:7.11.0" dependencies: - "@typescript-eslint/types": "npm:7.10.0" - "@typescript-eslint/visitor-keys": "npm:7.10.0" - checksum: 10/838a7a9573577d830b2f65801ce045abe6fad08ac7e04bac4cc9b2e5b7cbac07e645de9c79b9485f4cc361fe25da5319025aa0336fad618023fff62e4e980638 + "@typescript-eslint/types": "npm:7.11.0" + "@typescript-eslint/visitor-keys": "npm:7.11.0" + checksum: 10/79eff310405c6657ff092641e3ad51c6698c6708b915ecef945ebdd1737bd48e1458c5575836619f42dec06143ec0e3a826f3e551af590d297367da3d08f329e languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:7.10.0": - version: 7.10.0 - resolution: "@typescript-eslint/type-utils@npm:7.10.0" +"@typescript-eslint/type-utils@npm:7.11.0": + version: 7.11.0 + resolution: "@typescript-eslint/type-utils@npm:7.11.0" dependencies: - "@typescript-eslint/typescript-estree": "npm:7.10.0" - "@typescript-eslint/utils": "npm:7.10.0" + "@typescript-eslint/typescript-estree": "npm:7.11.0" + "@typescript-eslint/utils": "npm:7.11.0" debug: "npm:^4.3.4" ts-api-utils: "npm:^1.3.0" peerDependencies: @@ -10718,7 +10968,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10/e62db9ffbfbccce60258108f7ed025005e04df18da897ff1b30049e3c10a47150e94c2fb5ac0ab9711ebb60517521213dcccbea6d08125107a87a67088a79042 + checksum: 10/ab6ebeff68a60fc40d0ace88e03d6b4242b8f8fe2fa300db161780d58777b57f69fa077cd482e1b673316559459bd20b8cc89a7f9f30e644bfed8293f77f0e4b languageName: node linkType: hard @@ -10743,10 +10993,10 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/types@npm:7.10.0": - version: 7.10.0 - resolution: "@typescript-eslint/types@npm:7.10.0" - checksum: 10/76075a7b87ddfff8e7e4aebf3d225e67bf79ead12a7709999d4d5c31611d9c0813ca69a9298f320efb018fe493ce3763c964a0e670a4c953d8eff000f10672c0 +"@typescript-eslint/types@npm:7.11.0": + version: 7.11.0 + resolution: "@typescript-eslint/types@npm:7.11.0" + checksum: 10/c6a0b47ef43649a59c9d51edfc61e367b55e519376209806b1c98385a8385b529e852c7a57e081fb15ef6a5dc0fc8e90bd5a508399f5ac2137f4d462e89cdc30 languageName: node linkType: hard @@ -10787,12 +11037,12 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:7.10.0": - version: 7.10.0 - resolution: "@typescript-eslint/typescript-estree@npm:7.10.0" +"@typescript-eslint/typescript-estree@npm:7.11.0": + version: 7.11.0 + resolution: "@typescript-eslint/typescript-estree@npm:7.11.0" dependencies: - "@typescript-eslint/types": "npm:7.10.0" - "@typescript-eslint/visitor-keys": "npm:7.10.0" + "@typescript-eslint/types": "npm:7.11.0" + "@typescript-eslint/visitor-keys": "npm:7.11.0" debug: "npm:^4.3.4" globby: "npm:^11.1.0" is-glob: "npm:^4.0.3" @@ -10802,7 +11052,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10/d11d0c45749c9bd4a187b6dfdf5600e36ba8c87667cd2020d9158667c47c32ec0bcb1ef3b7eee5577b667def5f7f33d8131092a0f221b3d3e8105078800f923f + checksum: 10/b98b101e42d3b91003510a5c5a83f4350b6c1cf699bf2e409717660579ffa71682bc280c4f40166265c03f9546ed4faedc3723e143f1ab0ed7f5990cc3dff0ae languageName: node linkType: hard @@ -10824,17 +11074,17 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/utils@npm:7.10.0": - version: 7.10.0 - resolution: "@typescript-eslint/utils@npm:7.10.0" +"@typescript-eslint/utils@npm:7.11.0": + version: 7.11.0 + resolution: "@typescript-eslint/utils@npm:7.11.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.4.0" - "@typescript-eslint/scope-manager": "npm:7.10.0" - "@typescript-eslint/types": "npm:7.10.0" - "@typescript-eslint/typescript-estree": "npm:7.10.0" + "@typescript-eslint/scope-manager": "npm:7.11.0" + "@typescript-eslint/types": "npm:7.11.0" + "@typescript-eslint/typescript-estree": "npm:7.11.0" peerDependencies: eslint: ^8.56.0 - checksum: 10/62327b585295f9c3aa2508aefac639d562b6f7f270a229aa3a2af8dbd055f4a4d230a8facae75a8a53bb8222b0041162072d259add56b541f8bdfda8da36ea5f + checksum: 10/fbef14e166a70ccc4527c0731e0338acefa28218d1a018aa3f5b6b1ad9d75c56278d5f20bda97cf77da13e0a67c4f3e579c5b2f1c2e24d676960927921b55851 languageName: node linkType: hard @@ -10886,13 +11136,13 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:7.10.0": - version: 7.10.0 - resolution: "@typescript-eslint/visitor-keys@npm:7.10.0" +"@typescript-eslint/visitor-keys@npm:7.11.0": + version: 7.11.0 + resolution: "@typescript-eslint/visitor-keys@npm:7.11.0" dependencies: - "@typescript-eslint/types": "npm:7.10.0" + "@typescript-eslint/types": "npm:7.11.0" eslint-visitor-keys: "npm:^3.4.3" - checksum: 10/44b555a075bdff38e3e13c454ceaac50aa2546635e81f907d1ea84822c8887487d1d6bb4ff690f627da9585dc19ad07e228847c162c30bb06c46fb119899d8cc + checksum: 10/1f2cf1214638e9e78e052393c9e24295196ec4781b05951659a3997e33f8699a760ea3705c17d770e10eda2067435199e0136ab09e5fac63869e22f2da184d89 languageName: node linkType: hard @@ -11646,7 +11896,7 @@ __metadata: languageName: node linkType: hard -"ajv@npm:^6.1.0, ajv@npm:^6.10.2, ajv@npm:^6.12.4, ajv@npm:^6.12.5": +"ajv@npm:^6.1.0, ajv@npm:^6.10.0, ajv@npm:^6.10.2, ajv@npm:^6.12.4, ajv@npm:^6.12.5": version: 6.12.6 resolution: "ajv@npm:6.12.6" dependencies: @@ -11658,6 +11908,18 @@ __metadata: languageName: node linkType: hard +"ajv@npm:^7.0.0": + version: 7.2.4 + resolution: "ajv@npm:7.2.4" + dependencies: + fast-deep-equal: "npm:^3.1.1" + json-schema-traverse: "npm:^1.0.0" + require-from-string: "npm:^2.0.2" + uri-js: "npm:^4.2.2" + checksum: 10/ed241a8986f80777713a7ffde37cdea8d112631623bbc7f0d867689bcb7af41f24a7ea2750c4dd8be681bf7fea314e05c8b4521a86bfb5882acd2432fc5335df + languageName: node + linkType: hard + "ansi-align@npm:^2.0.0": version: 2.0.0 resolution: "ansi-align@npm:2.0.0" @@ -12347,6 +12609,13 @@ __metadata: languageName: node linkType: hard +"at-least-node@npm:^1.0.0": + version: 1.0.0 + resolution: "at-least-node@npm:1.0.0" + checksum: 10/463e2f8e43384f1afb54bc68485c436d7622acec08b6fad269b421cb1d29cebb5af751426793d0961ed243146fe4dc983402f6d5a51b720b277818dbf6f2e49e + languageName: node + linkType: hard + "atob@npm:^2.1.2": version: 2.1.2 resolution: "atob@npm:2.1.2" @@ -12960,7 +13229,7 @@ __metadata: languageName: node linkType: hard -"body-parser@npm:1.20.2, body-parser@npm:^1.15.2, body-parser@npm:^1.20.0": +"body-parser@npm:1.20.2, body-parser@npm:^1.15.2, body-parser@npm:^1.19.0, body-parser@npm:^1.20.0": version: 1.20.2 resolution: "body-parser@npm:1.20.2" dependencies: @@ -13684,6 +13953,13 @@ __metadata: languageName: node linkType: hard +"call-me-maybe@npm:^1.0.1": + version: 1.0.2 + resolution: "call-me-maybe@npm:1.0.2" + checksum: 10/3d375b6f810a82c751157b199daba60452876186c19ac653e81bfc5fc10d1e2ba7aedb8622367c3a8aca6879f0e6a29435a1193b35edb8f7fd8267a67ea32373 + languageName: node + linkType: hard + "callsites@npm:^3.0.0, callsites@npm:^3.1.0": version: 3.1.0 resolution: "callsites@npm:3.1.0" @@ -14303,6 +14579,13 @@ __metadata: languageName: node linkType: hard +"clsx@npm:2.1.0": + version: 2.1.0 + resolution: "clsx@npm:2.1.0" + checksum: 10/2e0ce7c3b6803d74fc8147c408f88e79245583202ac14abd9691e2aebb9f312de44270b79154320d10bb7804a9197869635d1291741084826cff20820f31542b + languageName: node + linkType: hard + "clsx@npm:^1.0.4": version: 1.1.1 resolution: "clsx@npm:1.1.1" @@ -14441,6 +14724,13 @@ __metadata: languageName: node linkType: hard +"colors@npm:^1.3.3": + version: 1.4.0 + resolution: "colors@npm:1.4.0" + checksum: 10/90b2d5465159813a3983ea72ca8cff75f784824ad70f2cc2b32c233e95bcfbcda101ebc6d6766bc50f57263792629bfb4f1f8a4dfbd1d240f229fc7f69b785fc + languageName: node + linkType: hard + "columnify@npm:1.6.0": version: 1.6.0 resolution: "columnify@npm:1.6.0" @@ -14514,7 +14804,7 @@ __metadata: languageName: node linkType: hard -"commander@npm:^6.2.1": +"commander@npm:^6.1.0, commander@npm:^6.2.1": version: 6.2.1 resolution: "commander@npm:6.2.1" checksum: 10/25b88c2efd0380c84f7844b39cf18510da7bfc5013692d68cdc65f764a1c34e6c8a36ea6d72b6620e3710a930cf8fab2695bdec2bf7107a0f4fa30a3ef3b7d0e @@ -14528,7 +14818,7 @@ __metadata: languageName: node linkType: hard -"commander@npm:^8.3.0": +"commander@npm:^8.0.0, commander@npm:^8.3.0": version: 8.3.0 resolution: "commander@npm:8.3.0" checksum: 10/6b7b5d334483ce24bd73c5dac2eab901a7dbb25fd983ea24a1eeac6e7166bb1967f641546e8abf1920afbde86a45fbfe5812fbc69d0dc451bb45ca416a12a3a3 @@ -16465,6 +16755,13 @@ __metadata: languageName: node linkType: hard +"easy-stack@npm:^1.0.0": + version: 1.0.1 + resolution: "easy-stack@npm:1.0.1" + checksum: 10/4b0d0f619db5a6c5a7aa4b8110b30f1adb956a42f3b77b5c2d6b5bbefe2f414643c2835624fd3eab9e6fe50cc76b1523dc8225c68db229af35200e644bcdd738 + languageName: node + linkType: hard + "ecdsa-sig-formatter@npm:1.0.11": version: 1.0.11 resolution: "ecdsa-sig-formatter@npm:1.0.11" @@ -17882,6 +18179,13 @@ __metadata: languageName: node linkType: hard +"event-pubsub@npm:4.3.0": + version: 4.3.0 + resolution: "event-pubsub@npm:4.3.0" + checksum: 10/8a1af789f85050c263eb102d5bd724065bbdc60e3be693fa90efe21d407c0eeb242a79139207a9488289f9f97458e369bfde3294328f21d49addb202439ced20 + languageName: node + linkType: hard + "event-stream@npm:^3.3.4": version: 3.3.4 resolution: "event-stream@npm:3.3.4" @@ -18989,6 +19293,13 @@ __metadata: languageName: node linkType: hard +"format-util@npm:^1.0.3": + version: 1.0.5 + resolution: "format-util@npm:1.0.5" + checksum: 10/0c8622e54ad899ca184ff0b4999e9ff9567965051bade140911209d60554c2ea4d43075763c1cf574d2f740966afe46469c9284357919505cdddf1a0b65ff85c + languageName: node + linkType: hard + "format@npm:^0.2.0": version: 0.2.2 resolution: "format@npm:0.2.2" @@ -19065,7 +19376,7 @@ __metadata: languageName: node linkType: hard -"fs-extra@npm:^10.0.0": +"fs-extra@npm:^10.0.0, fs-extra@npm:^10.1.0": version: 10.1.0 resolution: "fs-extra@npm:10.1.0" dependencies: @@ -19087,6 +19398,18 @@ __metadata: languageName: node linkType: hard +"fs-extra@npm:^9.0.0": + version: 9.1.0 + resolution: "fs-extra@npm:9.1.0" + dependencies: + at-least-node: "npm:^1.0.0" + graceful-fs: "npm:^4.2.0" + jsonfile: "npm:^6.0.1" + universalify: "npm:^2.0.0" + checksum: 10/08600da1b49552ed23dfac598c8fc909c66776dd130fea54fbcad22e330f7fcc13488bb995f6bc9ce5651aa35b65702faf616fe76370ee56f1aade55da982dca + languageName: node + linkType: hard + "fs-minipass@npm:^1.2.7": version: 1.2.7 resolution: "fs-minipass@npm:1.2.7" @@ -22087,6 +22410,16 @@ __metadata: languageName: node linkType: hard +"isomorphic-fetch@npm:^3.0.0": + version: 3.0.0 + resolution: "isomorphic-fetch@npm:3.0.0" + dependencies: + node-fetch: "npm:^2.6.1" + whatwg-fetch: "npm:^3.4.1" + checksum: 10/568fe0307528c63405c44dd3873b7b6c96c0d19ff795cb15846e728b6823bdbc68cc8c97ac23324509661316f12f551e43dac2929bc7030b8bc4d6aa1158b857 + languageName: node + linkType: hard + "isomorphic-ws@npm:^4.0.1": version: 4.0.1 resolution: "isomorphic-ws@npm:4.0.1" @@ -22187,7 +22520,7 @@ __metadata: languageName: node linkType: hard -"istanbul-reports@npm:^3.0.2, istanbul-reports@npm:^3.1.3, istanbul-reports@npm:^3.1.5": +"istanbul-reports@npm:^3.0.2, istanbul-reports@npm:^3.1.3": version: 3.1.5 resolution: "istanbul-reports@npm:3.1.5" dependencies: @@ -22872,6 +23205,22 @@ __metadata: languageName: node linkType: hard +"js-message@npm:1.0.5": + version: 1.0.5 + resolution: "js-message@npm:1.0.5" + checksum: 10/885d0de9e00bb72a4a8a1c12839192ece6872306ae54e82a71092f44b5a74512cb3507e79415499f53f007cded1060577d33a25a9648973cb93b10d57ef1c479 + languageName: node + linkType: hard + +"js-queue@npm:2.0.0": + version: 2.0.0 + resolution: "js-queue@npm:2.0.0" + dependencies: + easy-stack: "npm:^1.0.0" + checksum: 10/cc9e530267ca6991fd47d24af901816f745ee2b744c8eeff6dc199568f8dc4a53385c129b201fbc8cc6fab60e81e16fe7e1dae7fc0d0f508f81ee29f61f891b2 + languageName: node + linkType: hard + "js-sha3@npm:^0.9.2": version: 0.9.3 resolution: "js-sha3@npm:0.9.3" @@ -22897,7 +23246,7 @@ __metadata: languageName: node linkType: hard -"js-yaml@npm:^3.10.0, js-yaml@npm:^3.13.1, js-yaml@npm:^3.14.0": +"js-yaml@npm:^3.10.0, js-yaml@npm:^3.12.1, js-yaml@npm:^3.13.1, js-yaml@npm:^3.14.0": version: 3.14.1 resolution: "js-yaml@npm:3.14.1" dependencies: @@ -23168,6 +23517,29 @@ __metadata: languageName: node linkType: hard +"json-schema-faker@npm:^0.5.0-rcv.26, json-schema-faker@npm:^0.5.0-rcv.29": + version: 0.5.6 + resolution: "json-schema-faker@npm:0.5.6" + dependencies: + json-schema-ref-parser: "npm:^6.1.0" + jsonpath-plus: "npm:^7.2.0" + bin: + jsf: bin/gen.cjs + checksum: 10/cd7b44eb712d4975d0e87c38f38c4500168502e546505e5bc8cd6d33950d991114fe83c810247d5b91bdbe686174d5e8850de39322b4aadaf854202a4bbbffdc + languageName: node + linkType: hard + +"json-schema-ref-parser@npm:^6.1.0": + version: 6.1.0 + resolution: "json-schema-ref-parser@npm:6.1.0" + dependencies: + call-me-maybe: "npm:^1.0.1" + js-yaml: "npm:^3.12.1" + ono: "npm:^4.0.11" + checksum: 10/f36dbb0d9780bf57d68846658bc0e8ac8a17c9095b41a836819a0cfd8550dbdee4b043a0bb535cbce3c683f1ee39b791c208dce15b143e58e34c8abcc747cb89 + languageName: node + linkType: hard + "json-schema-traverse@npm:^0.4.1": version: 0.4.1 resolution: "json-schema-traverse@npm:0.4.1" @@ -23292,6 +23664,13 @@ __metadata: languageName: node linkType: hard +"jsonpath-plus@npm:^7.2.0": + version: 7.2.0 + resolution: "jsonpath-plus@npm:7.2.0" + checksum: 10/f602445b1aa2d55abc2875859fd948f942980ef6400ca2a0362c7a6aa6f912467865262f4d092e04a16889fa74f0dbf6fd67b9dc9583485a5059be6e0a62c6c2 + languageName: node + linkType: hard + "jsonschema@npm:1.2.2": version: 1.2.2 resolution: "jsonschema@npm:1.2.2" @@ -24967,18 +25346,19 @@ __metadata: "@lavamoat/snow": "npm:^2.0.1" "@lgbot/madge": "npm:^6.2.0" "@material-ui/core": "npm:^4.11.0" - "@metamask-institutional/custody-controller": "npm:^0.2.27" - "@metamask-institutional/custody-keyring": "npm:^2.0.0" - "@metamask-institutional/extension": "npm:^0.3.24" - "@metamask-institutional/institutional-features": "npm:^1.3.2" + "@metamask-institutional/custody-controller": "npm:^0.2.30" + "@metamask-institutional/custody-keyring": "npm:^2.0.3" + "@metamask-institutional/extension": "npm:^0.3.27" + "@metamask-institutional/institutional-features": "npm:^1.3.5" "@metamask-institutional/portfolio-dashboard": "npm:^1.4.1" "@metamask-institutional/rpc-allowlist": "npm:^1.0.3" - "@metamask-institutional/sdk": "npm:^0.1.27" - "@metamask-institutional/transaction-update": "npm:^0.2.2" + "@metamask-institutional/sdk": "npm:^0.1.30" + "@metamask-institutional/transaction-update": "npm:^0.2.5" "@metamask/abi-utils": "npm:^2.0.2" "@metamask/accounts-controller": "npm:^16.0.0" "@metamask/address-book-controller": "npm:^4.0.1" "@metamask/announcement-controller": "npm:^6.1.0" + "@metamask/api-specs": "npm:^0.9.3" "@metamask/approval-controller": "npm:^7.0.0" "@metamask/assets-controllers": "npm:^33.0.0" "@metamask/auto-changelog": "npm:^2.1.0" @@ -25011,7 +25391,7 @@ __metadata: "@metamask/gas-fee-controller": "patch:@metamask/gas-fee-controller@npm%3A15.1.2#~/.yarn/patches/@metamask-gas-fee-controller-npm-15.1.2-db4d2976aa.patch" "@metamask/jazzicon": "npm:^2.0.0" "@metamask/keyring-api": "npm:^8.0.0" - "@metamask/keyring-controller": "patch:@metamask/keyring-controller@npm%3A15.0.0#~/.yarn/patches/@metamask-keyring-controller-npm-15.0.0-fa070ce311.patch" + "@metamask/keyring-controller": "npm:^16.1.0" "@metamask/logging-controller": "npm:^3.0.1" "@metamask/logo": "npm:^3.1.2" "@metamask/message-manager": "npm:^7.3.0" @@ -25035,7 +25415,7 @@ __metadata: "@metamask/safe-event-emitter": "npm:^3.1.1" "@metamask/scure-bip39": "npm:^2.0.3" "@metamask/selected-network-controller": "npm:^15.0.2" - "@metamask/signature-controller": "npm:^14.0.1" + "@metamask/signature-controller": "npm:^16.0.0" "@metamask/smart-transactions-controller": "npm:^10.1.2" "@metamask/snaps-controllers": "npm:^9.0.0" "@metamask/snaps-execution-environments": "npm:^6.4.0" @@ -25051,6 +25431,10 @@ __metadata: "@noble/ciphers": "npm:^0.5.2" "@noble/hashes": "npm:^1.3.3" "@octokit/core": "npm:^3.6.0" + "@open-rpc/meta-schema": "npm:^1.14.6" + "@open-rpc/mock-server": "npm:^1.7.5" + "@open-rpc/schema-utils-js": "npm:^1.16.2" + "@open-rpc/test-coverage": "npm:^2.2.2" "@playwright/test": "npm:^1.39.0" "@popperjs/core": "npm:^2.4.0" "@reduxjs/toolkit": "patch:@reduxjs/toolkit@npm%3A1.9.7#~/.yarn/patches/@reduxjs-toolkit-npm-1.9.7-b14925495c.patch" @@ -25201,9 +25585,6 @@ __metadata: immer: "npm:^9.0.6" ini: "npm:^3.0.0" is-retry-allowed: "npm:^2.2.0" - istanbul-lib-coverage: "npm:^3.2.0" - istanbul-lib-report: "npm:^3.0.0" - istanbul-reports: "npm:^3.1.5" jest: "npm:^29.7.0" jest-canvas-mock: "npm:^2.3.1" jest-environment-jsdom: "npm:^29.7.0" @@ -25228,7 +25609,6 @@ __metadata: nanoid: "npm:^2.1.6" nock: "patch:nock@npm%3A13.5.4#~/.yarn/patches/nock-npm-13.5.4-2c4f77b249.patch" node-fetch: "npm:^2.6.1" - nyc: "npm:^15.1.0" pify: "npm:^5.0.0" postcss: "npm:^8.4.32" postcss-rtlcss: "npm:^4.0.9" @@ -26003,6 +26383,13 @@ __metadata: languageName: node linkType: hard +"mitt@npm:^3.0.1": + version: 3.0.1 + resolution: "mitt@npm:3.0.1" + checksum: 10/287c70d8e73ffc25624261a4989c783768aed95ecb60900f051d180cf83e311e3e59865bfd6e9d029cdb149dc20ba2f128a805e9429c5c4ce33b1416c65bbd14 + languageName: node + linkType: hard + "mixin-deep@npm:^1.2.0": version: 1.3.2 resolution: "mixin-deep@npm:1.3.2" @@ -26649,6 +27036,17 @@ __metadata: languageName: node linkType: hard +"node-ipc@npm:9.1.1": + version: 9.1.1 + resolution: "node-ipc@npm:9.1.1" + dependencies: + event-pubsub: "npm:4.3.0" + js-message: "npm:1.0.5" + js-queue: "npm:2.0.0" + checksum: 10/c83afe366a1c35dbe15f3ca8715e4ac85834e3f87a614ba2a06c1ec3a4a3a379b8ebf8f0d5222cdec18df94553e8c7d09ce96829d3d107d6b989d8b42f795593 + languageName: node + linkType: hard + "node-pre-gyp@npm:^0.12.0": version: 0.12.0 resolution: "node-pre-gyp@npm:0.12.0" @@ -27197,6 +27595,15 @@ __metadata: languageName: node linkType: hard +"ono@npm:^4.0.11": + version: 4.0.11 + resolution: "ono@npm:4.0.11" + dependencies: + format-util: "npm:^1.0.3" + checksum: 10/f7ba5f597ae62f9b02bb0c00de3af786ebfb02459223e81d39f714a9404fade2065b830102a1d25c4fa216f17a407d6b721add197c710f8afce9e851cfb12984 + languageName: node + linkType: hard + "open@npm:8.4.2, open@npm:^8.0.4, open@npm:^8.4.0": version: 8.4.2 resolution: "open@npm:8.4.2" @@ -29298,6 +29705,18 @@ __metadata: languageName: node linkType: hard +"react-dom@npm:^18.2.0": + version: 18.2.0 + resolution: "react-dom@npm:18.2.0" + dependencies: + loose-envify: "npm:^1.1.0" + scheduler: "npm:^0.23.0" + peerDependencies: + react: ^18.2.0 + checksum: 10/ca5e7762ec8c17a472a3605b6f111895c9f87ac7d43a610ab7024f68cd833d08eda0625ce02ec7178cc1f3c957cf0b9273cdc17aa2cd02da87544331c43b1d21 + languageName: node + linkType: hard + "react-easy-swipe@npm:^0.0.21": version: 0.0.21 resolution: "react-easy-swipe@npm:0.0.21" @@ -29451,6 +29870,18 @@ __metadata: languageName: node linkType: hard +"react-number-format@npm:^5.3.1": + version: 5.3.4 + resolution: "react-number-format@npm:5.3.4" + dependencies: + prop-types: "npm:^15.7.2" + peerDependencies: + react: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + react-dom: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + checksum: 10/c5bc021f20ecb5c3dca8da93c89ce583d92b60bfabcfbcfeb59a9fb29ec17d756b559d6a00ff9a185e6c3c5c3f3839afd4ddc1244ad8fbea20342baf74a8bd43 + languageName: node + linkType: hard + "react-popper@npm:^2.2.3": version: 2.2.4 resolution: "react-popper@npm:2.2.4" @@ -29492,9 +29923,9 @@ __metadata: languageName: node linkType: hard -"react-remove-scroll-bar@npm:^2.3.3": - version: 2.3.4 - resolution: "react-remove-scroll-bar@npm:2.3.4" +"react-remove-scroll-bar@npm:^2.3.3, react-remove-scroll-bar@npm:^2.3.6": + version: 2.3.6 + resolution: "react-remove-scroll-bar@npm:2.3.6" dependencies: react-style-singleton: "npm:^2.2.1" tslib: "npm:^2.0.0" @@ -29504,7 +29935,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10/ac028b3ed12e66972cab8656747736729b219dff5a600178d1650300a2a750ace37f7ec82146147d37b092b19874f45cf7a45edceff68ac1f59607a828ca089f + checksum: 10/5ab8eda61d5b10825447d11e9c824486c929351a471457c22452caa19b6898e18c3af6a46c3fa68010c713baed1eb9956106d068b4a1058bdcf97a1a9bbed734 languageName: node linkType: hard @@ -29527,6 +29958,25 @@ __metadata: languageName: node linkType: hard +"react-remove-scroll@npm:^2.5.7": + version: 2.5.10 + resolution: "react-remove-scroll@npm:2.5.10" + dependencies: + react-remove-scroll-bar: "npm:^2.3.6" + react-style-singleton: "npm:^2.2.1" + tslib: "npm:^2.1.0" + use-callback-ref: "npm:^1.3.0" + use-sidecar: "npm:^1.1.2" + peerDependencies: + "@types/react": ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10/15f606482a614a92f8f65692cf27a1c1621d77a63c36f53a7bc4f2243799f2b04770083b313c4b3c2ed76f47d4046f52e86f95280ad5599389818fb882de7d6b + languageName: node + linkType: hard + "react-responsive-carousel@npm:^3.2.21": version: 3.2.21 resolution: "react-responsive-carousel@npm:3.2.21" @@ -29638,6 +30088,19 @@ __metadata: languageName: node linkType: hard +"react-textarea-autosize@npm:8.5.3": + version: 8.5.3 + resolution: "react-textarea-autosize@npm:8.5.3" + dependencies: + "@babel/runtime": "npm:^7.20.13" + use-composed-ref: "npm:^1.3.0" + use-latest: "npm:^1.2.1" + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: 10/4ade4329374f77414f55074826617e388d884b6c9401e0877b63d7f3715db07041431bb757265fb971c4ef15f3fde70ff6a05a5abb09ad3ff89334e1ff5c39ea + languageName: node + linkType: hard + "react-tippy@npm:^1.2.2": version: 1.2.2 resolution: "react-tippy@npm:1.2.2" @@ -29690,6 +30153,15 @@ __metadata: languageName: node linkType: hard +"react18-json-view@npm:^0.2.8": + version: 0.2.8 + resolution: "react18-json-view@npm:0.2.8" + peerDependencies: + react: ">=16.8.0" + checksum: 10/40c57c74713472e2e9cdfde6dee4bf5fb5e56a052772754f666a25405b0a7491a8eb26a7d7d55d727d5ffb04c638b2f47fa8ba9534edf87df621e7bd5dc26d61 + languageName: node + linkType: hard + "react@npm:^16.12.0": version: 16.14.0 resolution: "react@npm:16.14.0" @@ -29701,6 +30173,15 @@ __metadata: languageName: node linkType: hard +"react@npm:^18.2.0": + version: 18.2.0 + resolution: "react@npm:18.2.0" + dependencies: + loose-envify: "npm:^1.1.0" + checksum: 10/b9214a9bd79e99d08de55f8bef2b7fc8c39630be97c4e29d7be173d14a9a10670b5325e94485f74cd8bff4966ef3c78ee53c79a7b0b9b70cba20aa8973acc694 + languageName: node + linkType: hard + "read-cmd-shim@npm:^4.0.0": version: 4.0.0 resolution: "read-cmd-shim@npm:4.0.0" @@ -30076,6 +30557,13 @@ __metadata: languageName: node linkType: hard +"regexparam@npm:^3.0.0": + version: 3.0.0 + resolution: "regexparam@npm:3.0.0" + checksum: 10/80574803cb9f31d1ec7b10ce1db5be629868794ce331c7098fd9725c4c0891347c2fedc18b17de17bda2441da6ef30218b1ad2d481a4081e33ef773de04f9082 + languageName: node + linkType: hard + "regexpp@npm:^3.0.0": version: 3.2.0 resolution: "regexpp@npm:3.2.0" @@ -31279,6 +31767,15 @@ __metadata: languageName: node linkType: hard +"scheduler@npm:^0.23.0": + version: 0.23.0 + resolution: "scheduler@npm:0.23.0" + dependencies: + loose-envify: "npm:^1.1.0" + checksum: 10/0c4557aa37bafca44ff21dc0ea7c92e2dbcb298bc62eae92b29a39b029134f02fb23917d6ebc8b1fa536b4184934314c20d8864d156a9f6357f3398aaf7bfda8 + languageName: node + linkType: hard + "schema-utils@npm:^0.4.5": version: 0.4.5 resolution: "schema-utils@npm:0.4.5" @@ -33067,6 +33564,13 @@ __metadata: languageName: node linkType: hard +"tabbable@npm:^6.0.0": + version: 6.2.0 + resolution: "tabbable@npm:6.2.0" + checksum: 10/980fa73476026e99dcacfc0d6e000d41d42c8e670faf4682496d30c625495e412c4369694f2a15cf1e5252d22de3c396f2b62edbe8d60b5dadc40d09e3f2dde3 + languageName: node + linkType: hard + "table@npm:^5.4.6": version: 5.4.6 resolution: "table@npm:5.4.6" @@ -33907,10 +34411,10 @@ __metadata: languageName: node linkType: hard -"type-fest@npm:^4.0.0": - version: 4.15.0 - resolution: "type-fest@npm:4.15.0" - checksum: 10/8f897551877daa0df7bb17a21b6acd8a21ac5a0bdb14dbfd353b16013fed99f23c6d9c12a2c7685c8dededb4739ec8bfb120a914330f8b11a478a89758a11acc +"type-fest@npm:^4.0.0, type-fest@npm:^4.12.0": + version: 4.18.1 + resolution: "type-fest@npm:4.18.1" + checksum: 10/ff76e19cb969854161fea2de854073f346e159f5efff05906ece93cbde8a7161b9374121aca53782b44f754152cbacc70264c90ca1acc81ca917723acce5054f languageName: node linkType: hard @@ -34579,7 +35083,16 @@ __metadata: languageName: node linkType: hard -"use-isomorphic-layout-effect@npm:^1.1.2": +"use-composed-ref@npm:^1.3.0": + version: 1.3.0 + resolution: "use-composed-ref@npm:1.3.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: 10/f771cbadfdc91e03b7ab9eb32d0fc0cc647755711801bf507e891ad38c4bbc5f02b2509acadf9c965ec9c5f2f642fd33bdfdfb17b0873c4ad0a9b1f5e5e724bf + languageName: node + linkType: hard + +"use-isomorphic-layout-effect@npm:^1.1.1, use-isomorphic-layout-effect@npm:^1.1.2": version: 1.1.2 resolution: "use-isomorphic-layout-effect@npm:1.1.2" peerDependencies: @@ -34591,6 +35104,20 @@ __metadata: languageName: node linkType: hard +"use-latest@npm:^1.2.1": + version: 1.2.1 + resolution: "use-latest@npm:1.2.1" + dependencies: + use-isomorphic-layout-effect: "npm:^1.1.1" + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10/b0cbdd91f32e9a7fb4cd9d54934bef55dd6dbe90e2853506405e7c2ca78ca61dd34a6241f7138110a5013da02366138708f23f417c63524ad27aa43afa4196d6 + languageName: node + linkType: hard + "use-memo-one@npm:^1.1.1": version: 1.1.3 resolution: "use-memo-one@npm:1.1.3" @@ -34628,6 +35155,15 @@ __metadata: languageName: node linkType: hard +"use-sync-external-store@npm:^1.0.0": + version: 1.2.0 + resolution: "use-sync-external-store@npm:1.2.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: 10/a676216affc203876bd47981103f201f28c2731361bb186367e12d287a7566763213a8816910c6eb88265eccd4c230426eb783d64c373c4a180905be8820ed8e + languageName: node + linkType: hard + "use@npm:^3.1.0": version: 3.1.0 resolution: "use@npm:3.1.0" @@ -35429,6 +35965,13 @@ __metadata: languageName: node linkType: hard +"whatwg-fetch@npm:^3.4.1": + version: 3.6.20 + resolution: "whatwg-fetch@npm:3.6.20" + checksum: 10/2b4ed92acd6a7ad4f626a6cb18b14ec982bbcaf1093e6fe903b131a9c6decd14d7f9c9ca3532663c2759d1bdf01d004c77a0adfb2716a5105465c20755a8c57c + languageName: node + linkType: hard + "whatwg-mimetype@npm:^2.3.0": version: 2.3.0 resolution: "whatwg-mimetype@npm:2.3.0" @@ -35601,6 +36144,19 @@ __metadata: languageName: node linkType: hard +"wouter@npm:^3.1.2": + version: 3.1.2 + resolution: "wouter@npm:3.1.2" + dependencies: + mitt: "npm:^3.0.1" + regexparam: "npm:^3.0.0" + use-sync-external-store: "npm:^1.0.0" + peerDependencies: + react: ">=16.8.0" + checksum: 10/66e8dd68eeb06f13aa4008282fe049fbeaec3dfff97c577eb5a838e27af56e88f68dc9b1516c39016e9474c3a801ea1dadcb9df73a2324dcef57ffd53daa200c + languageName: node + linkType: hard + "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0, wrap-ansi@npm:^7.0.0": version: 7.0.0 resolution: "wrap-ansi@npm:7.0.0" @@ -35703,7 +36259,7 @@ __metadata: languageName: node linkType: hard -"ws@npm:*, ws@npm:>=8.14.2, ws@npm:^8.11.0, ws@npm:^8.16.0, ws@npm:^8.17.1, ws@npm:^8.2.3, ws@npm:^8.5.0, ws@npm:^8.8.0": +"ws@npm:*, ws@npm:>=8.14.2, ws@npm:^8.0.0, ws@npm:^8.11.0, ws@npm:^8.16.0, ws@npm:^8.17.1, ws@npm:^8.2.3, ws@npm:^8.5.0, ws@npm:^8.8.0": version: 8.17.1 resolution: "ws@npm:8.17.1" peerDependencies: