From 31d5c1cf223c4fc8d4afb8a2c325397983180e38 Mon Sep 17 00:00:00 2001 From: MetaMask Bot <37885440+metamaskbot@users.noreply.github.com> Date: Wed, 24 Aug 2022 08:57:47 -1000 Subject: [PATCH] Version v10.18.4 RC (#15643) * Version v10.18.4 * Fix default currency symbol for `wallet_addEthereumChain` + improve warnings for data that doesn't match our validation expectations (#15201) * set more appropriate default for ticker symbol when wallet_addEthereumChain is called * throw error to dapp when site suggests network with same chainId but different ticker symbol from already added network, instead of showing error and disabled notification to user * Fix Provider Tracking Metrics (#15082) * fix filetype audit (#15334) * Remove decentralized 4byte function signature registry since it contains incorrect signatures and we can't algorithmically check for best option when 4byte.directory is down (#15300) * remove decentralized 4byte function signature registry since it is griefed and we can't algorithmically check for best option when 4byte is down * add migration * remove nock of on chain registry call in getMethodDataAsync test * remove audit exclusion (#15346) * Updates `eth-lattice-keyring` to v0.10.0 (#15261) This is mainly associated with an update in GridPlus SDK and enables better strategies for fetching calldata decoder data. `eth-lattice-keyring` changes: GridPlus/eth-lattice-keyring@v0.7.3...v0.10.0 `gridplus-sdk` changes (which includes a codebase rewrite): GridPlus/gridplus-sdk@v1.2.3...v2.2.2 * Fix 'block link explorer on custom networks' (#13870) * Created a logic for the 'Add a block explorer URL' Removed unused message Message logic rollback Modified history push operation WIP: Pushing before rebasing Applied requested changes Removed unintenionally added code * Lint fix * Metrics fixed * Stop injecting provider on docs.google.com (#15459) * Fix setting of gasPrice when on non-eip 1559 networks (#15628) * Fix setting of gasPrice when on non-eip 1559 networks * Fix unit tests * Fix logic * Update ui/ducks/send/send.test.js Co-authored-by: Mark Stacey Co-authored-by: Mark Stacey * [GridPlus] Bumps `eth-lattice-keyring` to v0.11.0 (#15490) * [GridPlus] Bumps `gridplus-sdk` to v2.2.4 (#15561) * remove exclusions for mismatched object jsdoc type casing (#15351) * Improve `tokenId` parsing and clean up `useAssetDetails` hook (#15304) * Fix state creation in setupSentryGetStateGlobal (#15635) * filter breadcrumbs for improved clarity while debugging sentry errors (#15639) * Update v10.18.4 changelog (#15645) * Auto generated changelog * Update 10.18.4 changelog * Run lavamoat:auto * Call metrics event for wallet type selection at the right time (#15591) * Fix Sentry in LavaMoat contexts (#15672) Our Sentry setup relies upon application state, but it wasn't able to access it in LavaMoat builds because it's running in a separate Compartment. A patch has been introduced to the LavaMoat runtime to allow the root Compartment to mutate the `rootGlobals` object, which is accessible from outside the compartment as well. This lets us expose application state to our Sentry integration. * Fix Sentry deduplication of events that were never sent (#15677) The Sentry `Dedupe` integration has been filtering out our events, even when they were never sent due to our `beforeSend` handler. It was wrongly identifying them as duplicates because it has no knowledge of `beforeSend` or whether they were actually sent or not. To resolve this, the filtering we were doing in `beforeSend` has been moved to a Sentry integration. This integration is installed ahead of the `Dedupe` integration, so `Dedupe` should never find out about any events that we filter out, and thus will never consider them as sent when they were not. * Replace `lavamoat-runtime.js` patch (#15682) A patch made in #15672 was found to be unnecessary. Instead of setting a `rootGlobals` object upon construction of the root compartment, we are now creating a `sentryHooks` object in the initial top-level compartment. I hadn't realized at the time that the root compartment would inherit all properties of the initial compartment `globalThis`. This accomplishes the same goals as #15672 except without needing a patch. * Update v10.18.4 changelog * Fix lint issues * Update yarn.lock * Update `depcheck` to latest version (#15690) `depcheck` has been updated to the latest version. This version pins `@babel/parser` to v7.16.4 because of unresolved bugs in v7.16.5 that result in `depcheck` failing to parse TypeScript files correctly. We had a Yarn resolution in place to ensure `@babel/parser@7.16.4` was being used already. That resolution is no longer needed so it has been removed. This should resove the issue the dev team has been seeing lately where `yarn` and `yarn-deduplicate` disagree about the state the lockfile should be in. * Update yarn.lock * Update LavaMoat policy * deduplicate * Update LavaMoat build policy Co-authored-by: MetaMask Bot Co-authored-by: Alex Donesky Co-authored-by: Brad Decker Co-authored-by: Alex Miller Co-authored-by: Filip Sekulic Co-authored-by: Erik Marks <25517051+rekmarks@users.noreply.github.com> Co-authored-by: Dan J Miller Co-authored-by: Mark Stacey Co-authored-by: seaona <54408225+seaona@users.noreply.github.com> Co-authored-by: seaona Co-authored-by: PeterYinusa --- .iyarc | 2 +- CHANGELOG.md | 18 +- app/_locales/de/messages.json | 8 - app/_locales/el/messages.json | 8 - app/_locales/en/messages.json | 26 +- app/_locales/es/messages.json | 8 - app/_locales/es_419/messages.json | 8 - app/_locales/fr/messages.json | 8 - app/_locales/hi/messages.json | 8 - app/_locales/id/messages.json | 8 - app/_locales/ja/messages.json | 8 - app/_locales/ko/messages.json | 8 - app/_locales/ph/messages.json | 8 - app/_locales/pt/messages.json | 8 - app/_locales/pt_BR/messages.json | 8 - app/_locales/ru/messages.json | 8 - app/_locales/tl/messages.json | 8 - app/_locales/tr/messages.json | 8 - app/_locales/vi/messages.json | 8 - app/_locales/zh/messages.json | 8 - app/_locales/zh_CN/messages.json | 8 - app/scripts/background.js | 36 +- app/scripts/contentscript.js | 13 +- app/scripts/controllers/alert.js | 8 +- app/scripts/controllers/app-state.js | 2 +- app/scripts/controllers/cached-balances.js | 8 +- app/scripts/controllers/detect-tokens.js | 10 +- .../controllers/incoming-transactions.js | 2 +- .../controllers/incoming-transactions.test.js | 2 +- app/scripts/controllers/metametrics.js | 18 +- app/scripts/controllers/network/network.js | 7 +- app/scripts/controllers/onboarding.js | 4 +- .../controllers/permissions/permission-log.js | 24 +- .../permissions/permission-log.test.js | 6 +- .../controllers/permissions/specifications.js | 2 +- app/scripts/controllers/preferences.js | 18 +- app/scripts/controllers/swaps.js | 4 +- app/scripts/controllers/transactions/index.js | 42 +- .../lib/tx-state-history-helpers.js | 10 +- .../controllers/transactions/lib/util.js | 18 +- .../transactions/pending-tx-tracker.js | 16 +- .../controllers/transactions/tx-gas-utils.js | 10 +- .../transactions/tx-state-manager.js | 6 +- app/scripts/first-time-state.js | 6 +- app/scripts/lib/ComposableObservableStore.js | 8 +- app/scripts/lib/account-tracker.js | 16 +- app/scripts/lib/buy-url.js | 2 +- .../lib/createRPCMethodTrackingMiddleware.js | 228 +++++++--- .../createRPCMethodTrackingMiddleware.test.js | 217 +++++++++ app/scripts/lib/decrypt-message-manager.js | 22 +- .../lib/encryption-public-key-manager.js | 22 +- app/scripts/lib/getObjStructure.js | 8 +- app/scripts/lib/local-store.js | 8 +- app/scripts/lib/message-manager.js | 22 +- app/scripts/lib/migrator/index.js | 6 +- app/scripts/lib/network-store.js | 2 +- app/scripts/lib/personal-message-manager.js | 22 +- .../handlers/add-ethereum-chain.js | 40 +- .../handlers/get-provider-state.js | 4 +- .../handlers/log-web3-shim-usage.js | 2 +- .../handlers/watch-asset.js | 6 +- app/scripts/lib/sentry-filter-events.ts | 73 +++ app/scripts/lib/setupSentry.js | 38 +- app/scripts/lib/typed-message-manager.js | 26 +- app/scripts/lib/util.js | 2 +- app/scripts/lockdown-more.js | 2 +- app/scripts/metamask-controller.js | 103 +++-- app/scripts/migrations/048.js | 2 +- app/scripts/migrations/073.js | 30 ++ app/scripts/migrations/073.test.js | 427 ++++++++++++++++++ app/scripts/migrations/index.js | 2 + app/scripts/sentry-install.js | 5 +- development/build/manifest.js | 2 +- development/build/utils.js | 2 +- development/lib/retry.js | 2 +- jest.config.js | 8 + lavamoat/browserify/beta/policy.json | 158 ++----- lavamoat/browserify/flask/policy.json | 158 ++----- lavamoat/browserify/main/policy.json | 158 ++----- lavamoat/build-system/policy.json | 14 +- package.json | 8 +- shared/constants/app.js | 5 + shared/constants/gas.js | 2 +- shared/constants/metametrics.js | 39 +- shared/constants/tokens.js | 2 +- shared/constants/transaction.js | 26 +- shared/modules/conversion.utils.js | 4 +- shared/modules/hexstring-utils.js | 2 +- shared/modules/object.utils.js | 4 +- shared/modules/transaction.utils.js | 4 +- test/e2e/webdriver/driver.js | 4 +- test/e2e/webdriver/firefox.js | 2 +- test/lib/wait-until-called.js | 2 +- test/mocks/permissions.js | 30 +- .../app/menu-bar/account-options-menu.js | 56 ++- .../account-details-modal.component.js | 59 ++- .../account-details-modal.container.js | 19 +- .../account-details-modal.test.js | 29 +- .../transaction-activity-log.util.js | 2 +- ...transaction-list-item-details.component.js | 42 +- ...action-list-item-details.component.test.js | 44 ++ ...transaction-list-item-details.container.js | 14 +- .../transaction-list-item.stories.js | 2 +- .../error-message/error-message.component.js | 4 +- .../nickname-popover.component.js | 41 +- ui/ducks/metamask/metamask.js | 8 +- ui/ducks/send/send.js | 73 +-- ui/ducks/send/send.test.js | 4 + ui/helpers/utils/i18n-helper.js | 2 +- ui/helpers/utils/permission.js | 2 +- ui/helpers/utils/token-util.js | 97 ++-- ui/helpers/utils/transactions.util.js | 26 +- ui/helpers/utils/transactions.util.test.js | 8 - ui/helpers/utils/util.js | 2 +- ui/hooks/gasFeeInput/useGasEstimates.js | 2 +- ui/hooks/gasFeeInput/useGasFeeErrors.js | 6 +- ui/hooks/gasFeeInput/useGasFeeInputs.js | 2 +- ui/hooks/gasFeeInput/useGasPriceInput.js | 2 +- ui/hooks/gasFeeInput/useMaxFeePerGasInput.js | 2 +- .../useMaxPriorityFeePerGasInput.js | 2 +- ui/hooks/useAssetDetails.js | 70 +-- ui/hooks/useAssetDetails.test.js | 60 ++- ui/hooks/useCurrencyDisplay.js | 4 +- ui/hooks/useEthFiatAmount.js | 2 +- ui/hooks/useEventFragment.js | 2 +- ui/hooks/useGasFeeErrors.js | 6 +- ui/hooks/useMethodData.js | 2 +- ui/hooks/useOriginMetadata.js | 2 +- ui/hooks/useShouldShowSpeedUp.js | 2 +- ui/hooks/useSwappedTokenValue.js | 2 +- ui/hooks/useTokenData.js | 2 +- ui/hooks/useTokenDisplayValue.js | 2 +- ui/hooks/useTokenFiatAmount.js | 2 +- ui/hooks/useTransactionDisplayData.js | 13 +- ui/hooks/useUserPreferencedCurrency.js | 4 +- ui/index.js | 2 +- ui/pages/asset/components/asset-options.js | 35 +- ui/pages/asset/components/native-asset.js | 4 +- ui/pages/asset/components/token-asset.js | 5 +- ui/pages/confirmation/confirmation.js | 2 +- .../templates/add-ethereum-chain.js | 95 ++-- ui/pages/confirmation/templates/index.js | 10 +- .../metametrics-opt-in.component.js | 37 +- .../select-action/select-action.component.js | 37 ++ .../select-action/select-action.container.js | 1 + .../networks-form/networks-form.js | 1 + .../settings/networks-tab/networks-tab.js | 4 +- ui/selectors/permissions.js | 20 +- ui/selectors/selectors.js | 71 ++- ui/selectors/transactions.js | 12 +- ui/store/actions.js | 4 +- yarn.lock | 134 ++++-- 152 files changed, 2304 insertions(+), 1338 deletions(-) create mode 100644 app/scripts/lib/createRPCMethodTrackingMiddleware.test.js create mode 100644 app/scripts/lib/sentry-filter-events.ts create mode 100644 app/scripts/migrations/073.js create mode 100644 app/scripts/migrations/073.test.js diff --git a/.iyarc b/.iyarc index bbd5d06c1..0d2a2e59f 100644 --- a/.iyarc +++ b/.iyarc @@ -2,4 +2,4 @@ GHSA-93q8-gq69-wqmw GHSA-257v-vj4p-3w2h GHSA-wm7h-9275-46v2 -GHSA-pfrx-2q88-qq97 +GHSA-pfrx-2q88-qq97 \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index aef71c924..9fd2689d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [10.18.4] +### Changed +- Update `eth-lattice-keyring` to v0.10.0 which itself updates `gridplus-sdk` ([#15261](https://github.com/MetaMask/metamask-extension/pull/15261)) + - `eth-lattice-keyring` changes: ([GridPlus/eth-lattice-keyring@v0.7.3...v0.10.0])(https://github.com/GridPlus/eth-lattice-keyring/compare/v0.7.3...v0.10.0) + - `gridplus-sdk` changes: ([GridPlus/gridplus-sdk@v1.2.3...v2.2.4])(https://github.com/GridPlus/gridplus-sdk/compare/v1.2.3...v2.2.4) +- Update `eth-lattice-keyring` to v0.11.0 ([#15490](https://github.com/MetaMask/metamask-extension/pull/15490)). See changes [GridPlus/eth-lattice-keyring@v0.10.0...v0.11.0](https://github.com/GridPlus/eth-lattice-keyring/compare/v0.10.0...v0.11.0) +- Improve ERC721 Send screen by parsing the `tokenId` and refactor `useAssetDetails` hook to avoid unnecessary network calls ([#15304](https://github.com/MetaMask/metamask-extension/pull/15304)) + +### Fixed +- Fix GDrive incompatibility with the Extension by stop injecting provider on docs.google.com ([#15459](https://github.com/MetaMask/metamask-extension/pull/15459)) +- Fix default currency symbol for `wallet_addEthereumChain` + improve warnings for data that doesn't match our validation expectations ([#15201](https://github.com/MetaMask/metamask-extension/pull/15201)) +- Fix block explorer link on custom networks for the cases when link is invalid or left empty ([#13870](https://github.com/MetaMask/metamask-extension/pull/13870)) +- Fix signature parsing errors re-surfaced due to 4byte function signature directory being down, by removing the directory([#15300](https://github.com/MetaMask/metamask-extension/pull/15300)) +- Fix intermitent failure when performing a Send tx in non-EIP-1559 networks (like Optimism) by setting the `gasPrice` ([#15628](https://github.com/MetaMask/metamask-extension/pull/15628)) + ## [10.18.3] ### Fixed - Prevent confirm screen from showing method name from contract registry for transactions created within MetaMask ([#15472](https://github.com/MetaMask/metamask-extension/pull/15472)) @@ -3107,7 +3122,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Uncategorized - Added the ability to restore accounts from seed words. -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.18.3...HEAD +[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.18.4...HEAD +[10.18.4]: https://github.com/MetaMask/metamask-extension/compare/v10.18.3...v10.18.4 [10.18.3]: https://github.com/MetaMask/metamask-extension/compare/v10.18.2...v10.18.3 [10.18.2]: https://github.com/MetaMask/metamask-extension/compare/v10.18.1...v10.18.2 [10.18.1]: https://github.com/MetaMask/metamask-extension/compare/v10.18.0...v10.18.1 diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index 7dd71c5cd..7951a4640 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -1888,10 +1888,6 @@ "metametricsTitle": { "message": "6M+ Benutzern beitreten um MetaMask zu verbessern" }, - "mismatchedChain": { - "message": "Die Netzwerkdetails für diese Ketten-ID stimmen nicht mit unseren Aufzeichnungen überein. Wir empfehlen Ihnen $1, bevor Sie fortfahren.", - "description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key" - }, "mismatchedChainLinkText": { "message": "die Netzwerkdetails überprüfen", "description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key." @@ -3874,10 +3870,6 @@ "message": "Dieses benutzerdefinierte Netzwerk ist nicht erkannt. Wir empfehlen, dass Sie $1 bevor Sie fortfahren", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." }, - "unrecognizedChainLinkText": { - "message": "die Netzwerkdetails überprüfen", - "description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key." - }, "unsendableAsset": { "message": "Verwenden von Sammelbaren (ERC-721) Token wird derzeit nicht unterstützt", "description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending" diff --git a/app/_locales/el/messages.json b/app/_locales/el/messages.json index 3ddbb409e..649655d5e 100644 --- a/app/_locales/el/messages.json +++ b/app/_locales/el/messages.json @@ -1888,10 +1888,6 @@ "metametricsTitle": { "message": "Συμμετάσχετε σε 6εκ+ χρήστες για να βελτιώσετε το MetaMask" }, - "mismatchedChain": { - "message": "Οι λεπτομέρειες δικτύου για αυτό το αναγνωριστικό αλυσίδας δεν ταιριάζουν με τις εγγραφές μας. Σας συνιστούμε να $1 πριν συνεχίσετε.", - "description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key" - }, "mismatchedChainLinkText": { "message": "επαληθεύστε τα στοιχεία δικτύου", "description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key." @@ -3874,10 +3870,6 @@ "message": "Αυτό το προσαρμοσμένο δίκτυο δεν αναγνωρίζεται. Σας συνιστούμε να $1 πριν προχωρήσετε", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." }, - "unrecognizedChainLinkText": { - "message": "επαληθεύστε τα στοιχεία δικτύου", - "description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key." - }, "unsendableAsset": { "message": "Η αποστολή συλλεκτικών (ERC-721) δεν υποστηρίζεται προς το παρόν", "description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending" diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 4e3a7ec46..a3ef3b742 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -121,6 +121,9 @@ "addAlias": { "message": "Add alias" }, + "addBlockExplorer": { + "message": "Add a block explorer" + }, "addContact": { "message": "Add contact" }, @@ -1909,14 +1912,23 @@ "metametricsTitle": { "message": "Join 6M+ users to improve MetaMask" }, - "mismatchedChain": { - "message": "The network details for this chain ID do not match our records. We recommend that you $1 before proceeding.", - "description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key" - }, "mismatchedChainLinkText": { "message": "verify the network details", "description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key." }, + "mismatchedChainRecommendation": { + "message": "We recommend that you $1 before proceeding.", + "description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key. The link will open to instructions for users to validate custom network details." + }, + "mismatchedNetworkName": { + "message": "According to our record the network name may not correctly match this chain ID." + }, + "mismatchedNetworkSymbol": { + "message": "The submitted currency symbol does not match what we expect for this chain ID." + }, + "mismatchedRpcUrl": { + "message": "According to our records the submitted RPC URL value does not match a known provider for this chain ID." + }, "missingNFT": { "message": "Don't see your NFT?" }, @@ -3933,13 +3945,9 @@ "message": "The decentralized web awaits" }, "unrecognizedChain": { - "message": "This custom network is not recognized. We recommend that you $1 before proceeding", + "message": "This custom network is not recognized", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." }, - "unrecognizedChainLinkText": { - "message": "verify the network details", - "description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key." - }, "unsendableAsset": { "message": "Sending collectible (ERC-721) tokens is not currently supported", "description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending" diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index 785728f1e..ffe4d6aeb 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -1888,10 +1888,6 @@ "metametricsTitle": { "message": "Únase a más de 6 millones de usuarios para mejorar MetaMask" }, - "mismatchedChain": { - "message": "Los detalles de la red de este identificador de cadena no coinciden con nuestros registros. Antes de continuar, le recomendamos que $1.", - "description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key" - }, "mismatchedChainLinkText": { "message": "verifique los detalles de la red", "description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key." @@ -3874,10 +3870,6 @@ "message": "No se reconoce esta red personalizada. Antes de continuar, le recomendamos que $1", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." }, - "unrecognizedChainLinkText": { - "message": "verifique los detalles de la red", - "description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key." - }, "unsendableAsset": { "message": "El envío de tokens coleccionables (ERC-721) no se admite actualmente", "description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending" diff --git a/app/_locales/es_419/messages.json b/app/_locales/es_419/messages.json index 32b5cbe35..f92e60f3d 100644 --- a/app/_locales/es_419/messages.json +++ b/app/_locales/es_419/messages.json @@ -1643,10 +1643,6 @@ "metametricsTitle": { "message": "Únase a más de 6 millones de usuarios para mejorar MetaMask" }, - "mismatchedChain": { - "message": "Los detalles de la red de este ID de cadena no coinciden con nuestros registros. Antes de continuar, le recomendamos que $1.", - "description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key" - }, "mismatchedChainLinkText": { "message": "verifique los detalles de la red", "description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key." @@ -3215,10 +3211,6 @@ "message": "No se reconoce esta red personalizada. Antes de continuar, le recomendamos que $1", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." }, - "unrecognizedChainLinkText": { - "message": "verifique los detalles de la red", - "description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key." - }, "unsendableAsset": { "message": "El envío de tokens coleccionables (ERC-721) no se admite actualmente", "description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending" diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index 5e9bb0b99..9d2367dae 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -1888,10 +1888,6 @@ "metametricsTitle": { "message": "Rejoignez plus de 6 M d’utilisateurs pour améliorer MetaMask" }, - "mismatchedChain": { - "message": "Les détails du réseau pour cet ID de chaîne ne correspondent pas à nos registres. Nous vous recommandons de $1 avant de poursuivre.", - "description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key" - }, "mismatchedChainLinkText": { "message": "vérifier les détails du réseau", "description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key." @@ -3874,10 +3870,6 @@ "message": "Ce réseau personnalisé n’est pas reconnu. Nous vous recommandons de $1 avant de continuer", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." }, - "unrecognizedChainLinkText": { - "message": "vérifier les détails du réseau", - "description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key." - }, "unsendableAsset": { "message": "L’envoi de jetons collectibles (ERC-721) n’est pas pris en charge actuellement", "description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending" diff --git a/app/_locales/hi/messages.json b/app/_locales/hi/messages.json index b3b6cafec..2d643f1aa 100644 --- a/app/_locales/hi/messages.json +++ b/app/_locales/hi/messages.json @@ -1888,10 +1888,6 @@ "metametricsTitle": { "message": "MetaMask को बेहतर बनाने के लिए 6M+ उपयोगकर्ताओं से जुड़ें" }, - "mismatchedChain": { - "message": "इस चेन ID के लिए नेटवर्क विवरण हमारे रिकॉर्ड से मेल नहीं खाता। हम अनुशंसा करते हैं कि आप आगे बढ़ने से पहले $1।", - "description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key" - }, "mismatchedChainLinkText": { "message": "नेटवर्क विवरण सत्यापित करें", "description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key." @@ -3874,10 +3870,6 @@ "message": "यह कस्टम नेटवर्क पहचाना नहीं गया है। हम अनुशंसा करते हैं कि आप आगे बढ़ने से पहले $1", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." }, - "unrecognizedChainLinkText": { - "message": "नेटवर्क विवरण सत्यापित करें", - "description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key." - }, "unsendableAsset": { "message": "वर्तमान में संग्रहणीय (ERC-721) टोकन भेजना समर्थित नहीं है", "description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending" diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json index f30dc5943..83c6ea82d 100644 --- a/app/_locales/id/messages.json +++ b/app/_locales/id/messages.json @@ -1888,10 +1888,6 @@ "metametricsTitle": { "message": "Bergabunglah bersama 6 Jt+ pengguna untuk meningkatkan MetaMask" }, - "mismatchedChain": { - "message": "Detail jaringan untuk ID rantai ini tidak cocok dengan catatan kami. Kami menyarankan agar Anda $1 sebelum melanjutkan.", - "description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key" - }, "mismatchedChainLinkText": { "message": "memverifikasi detail jaringan", "description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key." @@ -3874,10 +3870,6 @@ "message": "Jaringan kustom ini tidak dikenali. Kami menyarankan agar Anda $1 sebelum melanjutkan", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." }, - "unrecognizedChainLinkText": { - "message": "memverifikasi detail jaringan", - "description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key." - }, "unsendableAsset": { "message": "Tidak mendukung pengiriman token koleksi (ERC-721) untuk saat ini", "description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending" diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index 33386655d..bf140ebfd 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -1888,10 +1888,6 @@ "metametricsTitle": { "message": "6百万人以上のユーザーと共に、MetaMaskの改善にご協力ください" }, - "mismatchedChain": { - "message": "このチェーンIDのネットワーク詳細が、レコードと一致しません。続行する前に$1をお勧めします。", - "description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key" - }, "mismatchedChainLinkText": { "message": "ネットワークの詳細の確認", "description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key." @@ -3874,10 +3870,6 @@ "message": "このカスタムネットワークは認識されません。続行する前に$1をお勧めします", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." }, - "unrecognizedChainLinkText": { - "message": "ネットワークの詳細の確認", - "description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key." - }, "unsendableAsset": { "message": "コレクティブル (ERC-721) トークンの送信は現在サポートされていません", "description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending" diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index a0ad41425..8a5ba0a7b 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -1888,10 +1888,6 @@ "metametricsTitle": { "message": "6백만 명 이상의 사용자와 함께 MetaMask 기능 향상에 동참하세요." }, - "mismatchedChain": { - "message": "이 체인 ID의 네트워크 세부 정보가 기록과 일치하지 않습니다. 진행하기 전에 $1을(를) 권장합니다.", - "description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key" - }, "mismatchedChainLinkText": { "message": "네트워크 세부 정보 검증", "description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key." @@ -3874,10 +3870,6 @@ "message": "이 맞춤형 네트워크는 인식되지 않습니다. 진행하기 전에 $1을(를) 권장합니다.", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." }, - "unrecognizedChainLinkText": { - "message": "네트워크 세부 정보 검증", - "description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key." - }, "unsendableAsset": { "message": "수집 가능한(ERC-721) 토큰 전송은 현재 지원되지 않습니다.", "description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending" diff --git a/app/_locales/ph/messages.json b/app/_locales/ph/messages.json index a137aed83..9d64198d3 100644 --- a/app/_locales/ph/messages.json +++ b/app/_locales/ph/messages.json @@ -1039,10 +1039,6 @@ "metametricsOptInDescription": { "message": "Gustong kunin ng MetaMask ang data ng paggamit para mas maunawaan kung paano ginagamit ng mga user namin ang extension. Gagamitin ang data na ito para patuloy na mapahusay ang kakayahang magamit at karanasan ng user sa paggamit ng produkto namin at Ethereum ecosystem." }, - "mismatchedChain": { - "message": "Ang mga detalye ng network para sa chain ID na ito ay hindi tumutugma sa aming mga record. Inirerekomenda naming $1 ka bago magpatuloy.", - "description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key" - }, "mismatchedChainLinkText": { "message": "i-verify ang mga detalye ng network", "description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key." @@ -2161,10 +2157,6 @@ "message": "Hindi kinikilala ang custom na network na ito. Inirerekomenda naming $1 ka bago magpatuloy", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." }, - "unrecognizedChainLinkText": { - "message": "i-verify ang mga detalye ng network", - "description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key." - }, "updatedWithDate": { "message": "Na-update noong $1" }, diff --git a/app/_locales/pt/messages.json b/app/_locales/pt/messages.json index 3fbbd87ca..b8b40ee7a 100644 --- a/app/_locales/pt/messages.json +++ b/app/_locales/pt/messages.json @@ -1888,10 +1888,6 @@ "metametricsTitle": { "message": "Junte-se a mais de 6 milhões de usuários para melhorar a MetaMask" }, - "mismatchedChain": { - "message": "Os detalhes da rede para esse ID da cadeia não correspondem aos dos nossos registros. Recomendamos que você $1 antes de continuar.", - "description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key" - }, "mismatchedChainLinkText": { "message": "verifique os detalhes da rede", "description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key." @@ -3874,10 +3870,6 @@ "message": "Essa rede personalizada não foi reconhecida. Recomendamos que você $1 antes de continuar", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." }, - "unrecognizedChainLinkText": { - "message": "verifique os detalhes da rede", - "description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key." - }, "unsendableAsset": { "message": "O envio de tokens colecionáveis (ERC-721) não é suportado no momento", "description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending" diff --git a/app/_locales/pt_BR/messages.json b/app/_locales/pt_BR/messages.json index be4c7f7c0..35a8c9b30 100644 --- a/app/_locales/pt_BR/messages.json +++ b/app/_locales/pt_BR/messages.json @@ -1627,10 +1627,6 @@ "metametricsTitle": { "message": "Junte-se a mais de 6 milhões de usuários para melhorar a MetaMask" }, - "mismatchedChain": { - "message": "Os detalhes da rede para esse ID da cadeia não correspondem aos dos nossos registros. Recomendamos que você $1 antes de continuar.", - "description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key" - }, "mismatchedChainLinkText": { "message": "verifique os detalhes da rede", "description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key." @@ -3199,10 +3195,6 @@ "message": "Essa rede personalizada não foi reconhecida. Recomendamos que você $1 antes de continuar", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." }, - "unrecognizedChainLinkText": { - "message": "verifique os detalhes da rede", - "description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key." - }, "unsendableAsset": { "message": "O envio de tokens colecionáveis (ERC-721) não é suportado no momento", "description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending" diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index aa8be8ffd..16fa10c05 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -1888,10 +1888,6 @@ "metametricsTitle": { "message": "Присоединяйтесь к более чем 6 млн пользователей, чтобы улучшить MetaMask" }, - "mismatchedChain": { - "message": "Сведения о сети для этого ID цепочки не совпадают с указанными в записях. Мы рекомендуем $1 до того, как продолжить.", - "description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key" - }, "mismatchedChainLinkText": { "message": "проверить сведения о сети", "description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key." @@ -3874,10 +3870,6 @@ "message": "Эта пользовательская сеть не распознана. Мы рекомендуем $1, прежде чем продолжить", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." }, - "unrecognizedChainLinkText": { - "message": "проверить сведения о сети", - "description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key." - }, "unsendableAsset": { "message": "Отправка коллекционных активов (ERC-721) сейчас не поддерживается", "description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending" diff --git a/app/_locales/tl/messages.json b/app/_locales/tl/messages.json index 4b8404a21..5ed22eaba 100644 --- a/app/_locales/tl/messages.json +++ b/app/_locales/tl/messages.json @@ -1888,10 +1888,6 @@ "metametricsTitle": { "message": "Sumali sa 6M+ user upang mapabuti ang MetaMask" }, - "mismatchedChain": { - "message": "Ang mga detalye ng network para sa chain ID na ito ay hindi tumutugma sa aming mga talaan. Inirerekomenda namin na $1 ka bago magpatuloy.", - "description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key" - }, "mismatchedChainLinkText": { "message": "i-verify ang mga detalye ng network", "description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key." @@ -3874,10 +3870,6 @@ "message": "Hindi nakikilala ang custom network na ito. Nirerekomenda namin na ikaw ay $1 bago magpatuloy", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." }, - "unrecognizedChainLinkText": { - "message": "i-verify ang mga detalye ng network", - "description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key." - }, "unsendableAsset": { "message": "Ang pagpapadala ng collectible (ERC-721) token ay kasalukuyang hindi magagamit", "description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending" diff --git a/app/_locales/tr/messages.json b/app/_locales/tr/messages.json index 1a0468bf7..05719bd53 100644 --- a/app/_locales/tr/messages.json +++ b/app/_locales/tr/messages.json @@ -1888,10 +1888,6 @@ "metametricsTitle": { "message": "MetaMask'i geliştirmek için 6 milyondan fazla kullanıcıya katılın" }, - "mismatchedChain": { - "message": "Bu zincir kimliği için ağ ayrıntıları kayıtlarımızla uyumlu değil. Devam etmeden önce şunu yapmanızı öneriyoruz: $1.", - "description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key" - }, "mismatchedChainLinkText": { "message": "ağ bilgilerini doğrula", "description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key." @@ -3874,10 +3870,6 @@ "message": "Bu özel ağ tanınmadı. Devam etmeden önce $1 öneririz", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." }, - "unrecognizedChainLinkText": { - "message": "ağ bilgilerini doğrula", - "description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key." - }, "unsendableAsset": { "message": "Toplanabilir (ERC-721) tokenlerin gönderilmesi şu anda desteklenmiyor", "description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending" diff --git a/app/_locales/vi/messages.json b/app/_locales/vi/messages.json index 1b7b5534a..a38862ed5 100644 --- a/app/_locales/vi/messages.json +++ b/app/_locales/vi/messages.json @@ -1888,10 +1888,6 @@ "metametricsTitle": { "message": "Tham gia cùng hơn 6 Triệu người dùng để cải thiện MetaMask" }, - "mismatchedChain": { - "message": "Thông tin về mạng cho mã chuỗi này không khớp với hồ sơ của chúng tôi. Bạn nên $1 trước khi tiếp tục.", - "description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key" - }, "mismatchedChainLinkText": { "message": "xác minh thông tin về mạng", "description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key." @@ -3874,10 +3870,6 @@ "message": "Không nhận ra mạng tùy chỉnh này. Bạn nên $1 trước khi tiếp tục", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." }, - "unrecognizedChainLinkText": { - "message": "xác minh thông tin về mạng", - "description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key." - }, "unsendableAsset": { "message": "Hiện không hỗ trợ gửi token sưu tập (ERC-721)", "description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending" diff --git a/app/_locales/zh/messages.json b/app/_locales/zh/messages.json index f1c97fe44..66984cbd4 100644 --- a/app/_locales/zh/messages.json +++ b/app/_locales/zh/messages.json @@ -1888,10 +1888,6 @@ "metametricsTitle": { "message": "和600多万用户一起改进 MetaMask" }, - "mismatchedChain": { - "message": "此链 ID 的网络信息与我们的记录不符。我们建议您在继续操作之前 $1。", - "description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key" - }, "mismatchedChainLinkText": { "message": "验证网络信息", "description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key." @@ -3874,10 +3870,6 @@ "message": "这个自定义网络无法识别。我们建议您在继续操作之前 $1", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." }, - "unrecognizedChainLinkText": { - "message": "验证网络信息", - "description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key." - }, "unsendableAsset": { "message": "当前不支持发送可收藏的 (ERC-721) 代币", "description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending" diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index 1252d6a14..64633eb4b 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -1597,10 +1597,6 @@ "metametricsTitle": { "message": "加入 6M+ 用户来改进MetaMask" }, - "mismatchedChain": { - "message": "此链路的网络详细信息与我们的记录不匹配。我们建议您在继续操作之前$1。", - "description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key" - }, "mismatchedChainLinkText": { "message": "验证网络详细信息", "description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key." @@ -3157,10 +3153,6 @@ "message": "这个自定义网络无法识别。我们建议您在继续操作之前$1", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." }, - "unrecognizedChainLinkText": { - "message": "验证网络详细信息", - "description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key." - }, "unsendableAsset": { "message": "当前不支持发送可收藏的 (ERC-721) 代币", "description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending" diff --git a/app/scripts/background.js b/app/scripts/background.js index 0246c5d73..e0caed345 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -114,33 +114,33 @@ if (isManifestV3()) { * @property {boolean} isInitialized - Whether the first vault has been created. * @property {boolean} isUnlocked - Whether the vault is currently decrypted and accounts are available for selection. * @property {boolean} isAccountMenuOpen - Represents whether the main account selection UI is currently displayed. - * @property {Object} identities - An object matching lower-case hex addresses to Identity objects with "address" and "name" (nickname) keys. - * @property {Object} unapprovedTxs - An object mapping transaction hashes to unapproved transactions. + * @property {object} identities - An object matching lower-case hex addresses to Identity objects with "address" and "name" (nickname) keys. + * @property {object} unapprovedTxs - An object mapping transaction hashes to unapproved transactions. * @property {Array} frequentRpcList - A list of frequently used RPCs, including custom user-provided ones. * @property {Array} addressBook - A list of previously sent to addresses. - * @property {Object} contractExchangeRates - Info about current token prices. + * @property {object} contractExchangeRates - Info about current token prices. * @property {Array} tokens - Tokens held by the current user, including their balances. - * @property {Object} send - TODO: Document + * @property {object} send - TODO: Document * @property {boolean} useBlockie - Indicates preferred user identicon format. True for blockie, false for Jazzicon. - * @property {Object} featureFlags - An object for optional feature flags. + * @property {object} featureFlags - An object for optional feature flags. * @property {boolean} welcomeScreen - True if welcome screen should be shown. * @property {string} currentLocale - A locale string matching the user's preferred display language. - * @property {Object} provider - The current selected network provider. + * @property {object} provider - The current selected network provider. * @property {string} provider.rpcUrl - The address for the RPC API, if using an RPC API. * @property {string} provider.type - An identifier for the type of network selected, allows MetaMask to use custom provider strategies for known networks. * @property {string} network - A stringified number of the current network ID. - * @property {Object} accounts - An object mapping lower-case hex addresses to objects with "balance" and "address" keys, both storing hex string values. + * @property {object} accounts - An object mapping lower-case hex addresses to objects with "balance" and "address" keys, both storing hex string values. * @property {hex} currentBlockGasLimit - The most recently seen block gas limit, in a lower case hex prefixed string. * @property {TransactionMeta[]} currentNetworkTxList - An array of transactions associated with the currently selected network. - * @property {Object} unapprovedMsgs - An object of messages pending approval, mapping a unique ID to the options. + * @property {object} unapprovedMsgs - An object of messages pending approval, mapping a unique ID to the options. * @property {number} unapprovedMsgCount - The number of messages in unapprovedMsgs. - * @property {Object} unapprovedPersonalMsgs - An object of messages pending approval, mapping a unique ID to the options. + * @property {object} unapprovedPersonalMsgs - An object of messages pending approval, mapping a unique ID to the options. * @property {number} unapprovedPersonalMsgCount - The number of messages in unapprovedPersonalMsgs. - * @property {Object} unapprovedEncryptionPublicKeyMsgs - An object of messages pending approval, mapping a unique ID to the options. + * @property {object} unapprovedEncryptionPublicKeyMsgs - An object of messages pending approval, mapping a unique ID to the options. * @property {number} unapprovedEncryptionPublicKeyMsgCount - The number of messages in EncryptionPublicKeyMsgs. - * @property {Object} unapprovedDecryptMsgs - An object of messages pending approval, mapping a unique ID to the options. + * @property {object} unapprovedDecryptMsgs - An object of messages pending approval, mapping a unique ID to the options. * @property {number} unapprovedDecryptMsgCount - The number of messages in unapprovedDecryptMsgs. - * @property {Object} unapprovedTypedMsgs - An object of messages pending approval, mapping a unique ID to the options. + * @property {object} unapprovedTypedMsgs - An object of messages pending approval, mapping a unique ID to the options. * @property {number} unapprovedTypedMsgCount - The number of messages in unapprovedTypedMsgs. * @property {number} pendingApprovalCount - The number of pending request in the approval controller. * @property {string[]} keyringTypes - An array of unique keyring identifying strings, representing available strategies for creating accounts. @@ -304,7 +304,7 @@ async function loadStateFromPersistence() { * Streams emitted state updates to platform-specific storage strategy. * Creates platform listeners for new Dapps/Contexts, and sets up their data connections to the controller. * - * @param {Object} initState - The initial state to start the controller with, matches the state that is emitted from the controller. + * @param {object} initState - The initial state to start the controller with, matches the state that is emitted from the controller. * @param {string} initLangCode - The region code for the language preferred by the current user. * @param {string} remoteSourcePort - remote application port connecting to extension. * @returns {Promise} After setup is complete. @@ -356,12 +356,12 @@ function setupController(initState, initLangCode, remoteSourcePort) { }, ); - setupSentryGetStateGlobal(controller.store); + setupSentryGetStateGlobal(controller); /** * Assigns the given state to the versioned object (with metadata), and returns that. * - * @param {Object} state - The state object as emitted by the MetaMaskController. + * @param {object} state - The state object as emitted by the MetaMaskController. * @returns {VersionedData} The state object wrapped in an object that includes a metadata key. */ function versionifyData(state) { @@ -762,13 +762,13 @@ browser.runtime.onInstalled.addListener(({ reason }) => { }); function setupSentryGetStateGlobal(store) { - global.getSentryState = function () { + global.sentryHooks.getSentryState = function () { const fullState = store.getState(); - const debugState = maskObject(fullState, SENTRY_STATE); + const debugState = maskObject({ metamask: fullState }, SENTRY_STATE); return { browser: window.navigator.userAgent, store: debugState, - version: global.platform.getVersion(), + version: platform.getVersion(), }; }; } diff --git a/app/scripts/contentscript.js b/app/scripts/contentscript.js index 9cc350d6d..5250a010e 100644 --- a/app/scripts/contentscript.js +++ b/app/scripts/contentscript.js @@ -330,16 +330,17 @@ function documentElementCheck() { */ function blockedDomainCheck() { const blockedDomains = [ - 'uscourts.gov', - 'dropbox.com', - 'webbyawards.com', - 'cdn.shopify.com/s/javascripts/tricorder/xtld-read-only-frame.html', 'adyen.com', - 'gravityforms.com', - 'harbourair.com', 'ani.gamer.com.tw', 'blueskybooking.com', + 'cdn.shopify.com/s/javascripts/tricorder/xtld-read-only-frame.html', + 'docs.google.com', + 'dropbox.com', + 'gravityforms.com', + 'harbourair.com', 'sharefile.com', + 'uscourts.gov', + 'webbyawards.com', ]; const currentUrl = window.location.href; let currentRegex; diff --git a/app/scripts/controllers/alert.js b/app/scripts/controllers/alert.js index b4b95d440..15e5ea155 100644 --- a/app/scripts/controllers/alert.js +++ b/app/scripts/controllers/alert.js @@ -5,16 +5,16 @@ import { } from '../../../shared/constants/alerts'; /** - * @typedef {Object} AlertControllerInitState - * @property {Object} alertEnabledness - A map of alerts IDs to booleans, where + * @typedef {object} AlertControllerInitState + * @property {object} alertEnabledness - A map of alerts IDs to booleans, where * `true` indicates that the alert is enabled and shown, and `false` the opposite. - * @property {Object} unconnectedAccountAlertShownOrigins - A map of origin + * @property {object} unconnectedAccountAlertShownOrigins - A map of origin * strings to booleans indicating whether the "switch to connected" alert has * been shown (`true`) or otherwise (`false`). */ /** - * @typedef {Object} AlertControllerOptions + * @typedef {object} AlertControllerOptions * @property {AlertControllerInitState} initState - The initial controller state */ diff --git a/app/scripts/controllers/app-state.js b/app/scripts/controllers/app-state.js index 6ca948aa0..5bf237e31 100644 --- a/app/scripts/controllers/app-state.js +++ b/app/scripts/controllers/app-state.js @@ -5,7 +5,7 @@ import { MINUTE } from '../../../shared/constants/time'; export default class AppStateController extends EventEmitter { /** - * @param {Object} opts + * @param {object} opts */ constructor(opts = {}) { const { diff --git a/app/scripts/controllers/cached-balances.js b/app/scripts/controllers/cached-balances.js index 228e906fa..fcccbe70d 100644 --- a/app/scripts/controllers/cached-balances.js +++ b/app/scripts/controllers/cached-balances.js @@ -1,10 +1,10 @@ import { ObservableStore } from '@metamask/obs-store'; /** - * @typedef {Object} CachedBalancesOptions - * @property {Object} accountTracker An {@code AccountTracker} reference + * @typedef {object} CachedBalancesOptions + * @property {object} accountTracker An {@code AccountTracker} reference * @property {Function} getCurrentChainId A function to get the current chain id - * @property {Object} initState The initial controller state + * @property {object} initState The initial controller state */ /** @@ -33,7 +33,7 @@ export default class CachedBalancesController { * Updates the cachedBalances property for the current chain. Cached balances will be updated to those in the passed accounts * if balances in the passed accounts are truthy. * - * @param {Object} obj - The the recently updated accounts object for the current chain + * @param {object} obj - The the recently updated accounts object for the current chain * @param obj.accounts * @returns {Promise} */ diff --git a/app/scripts/controllers/detect-tokens.js b/app/scripts/controllers/detect-tokens.js index d9cfe9b14..697887c2f 100644 --- a/app/scripts/controllers/detect-tokens.js +++ b/app/scripts/controllers/detect-tokens.js @@ -21,7 +21,7 @@ export default class DetectTokensController { /** * Creates a DetectTokensController * - * @param {Object} [config] - Options to configure controller + * @param {object} [config] - Options to configure controller * @param config.interval * @param config.preferences * @param config.network @@ -250,7 +250,7 @@ export default class DetectTokensController { } /** - * @type {Object} + * @type {object} */ set network(network) { if (!network) { @@ -263,7 +263,7 @@ export default class DetectTokensController { /** * In setter when isUnlocked is updated to true, detectNewTokens and restart polling * - * @type {Object} + * @type {object} */ set keyringMemStore(keyringMemStore) { if (!keyringMemStore) { @@ -281,7 +281,7 @@ export default class DetectTokensController { } /** - * @type {Object} + * @type {object} */ set tokenList(tokenList) { if (!tokenList) { @@ -293,7 +293,7 @@ export default class DetectTokensController { /** * Internal isActive state * - * @type {Object} + * @type {object} */ get isActive() { return this.isOpen && this.isUnlocked; diff --git a/app/scripts/controllers/incoming-transactions.js b/app/scripts/controllers/incoming-transactions.js index c56509314..8b07f4a1f 100644 --- a/app/scripts/controllers/incoming-transactions.js +++ b/app/scripts/controllers/incoming-transactions.js @@ -31,7 +31,7 @@ const fetchWithTimeout = getFetchWithTimeout(SECOND * 30); * * Note that this is not an exhaustive type definiton; only the properties we use are defined * - * @typedef {Object} EtherscanTransaction + * @typedef {object} EtherscanTransaction * @property {string} blockNumber - The number of the block this transaction was found in, in decimal * @property {string} from - The hex-prefixed address of the sender * @property {string} gas - The gas limit, in decimal GWEI diff --git a/app/scripts/controllers/incoming-transactions.test.js b/app/scripts/controllers/incoming-transactions.test.js index 525bf1fdf..fd5f9d9cf 100644 --- a/app/scripts/controllers/incoming-transactions.test.js +++ b/app/scripts/controllers/incoming-transactions.test.js @@ -104,7 +104,7 @@ function getMockBlockTracker() { * Returns a transaction object matching the expected format returned * by the Etherscan API * - * @param {Object} [params] - options bag + * @param {object} [params] - options bag * @param {string} [params.toAddress] - The hex-prefixed address of the recipient * @param {number} [params.blockNumber] - The block number for the transaction * @param {boolean} [params.useEIP1559] - Use EIP-1559 gas fields diff --git a/app/scripts/controllers/metametrics.js b/app/scripts/controllers/metametrics.js index 7e1b6c6ec..67c879c94 100644 --- a/app/scripts/controllers/metametrics.js +++ b/app/scripts/controllers/metametrics.js @@ -44,7 +44,7 @@ const exceptionsToFilter = { */ /** - * @typedef {Object} MetaMetricsControllerState + * @typedef {object} MetaMetricsControllerState * @property {string} [metaMetricsId] - The user's metaMetricsId that will be * attached to all non-anonymized event payloads * @property {boolean} [participateInMetaMetrics] - The user's preference for @@ -57,9 +57,9 @@ const exceptionsToFilter = { export default class MetaMetricsController { /** * @param {object} options - * @param {Object} options.segment - an instance of analytics-node for tracking + * @param {object} options.segment - an instance of analytics-node for tracking * events that conform to the new MetaMetrics tracking plan. - * @param {Object} options.preferencesStore - The preferences controller store, used + * @param {object} options.preferencesStore - The preferences controller store, used * to access and subscribe to preferences that will be attached to events * @param {Function} options.onNetworkDidChange - Used to attach a listener to the * networkDidChange event emitted by the networkController @@ -295,7 +295,7 @@ export default class MetaMetricsController { * Calls this._identify with validated metaMetricsId and user traits if user is participating * in the MetaMetrics analytics program * - * @param {Object} userTraits + * @param {object} userTraits */ identify(userTraits) { const { metaMetricsId, participateInMetaMetrics } = this.state; @@ -604,8 +604,8 @@ export default class MetaMetricsController { * Returns a new object of all valid user traits. For dates, we transform them into ISO-8601 timestamp strings. * * @see {@link https://segment.com/docs/connections/spec/common/#timestamps} - * @param {Object} userTraits - * @returns {Object} + * @param {object} userTraits + * @returns {object} */ _buildValidTraits(userTraits) { return Object.entries(userTraits).reduce((validTraits, [key, value]) => { @@ -626,7 +626,7 @@ export default class MetaMetricsController { * Returns an array of all of the collectibles/NFTs the user * possesses across all networks and accounts. * - * @param {Object} allCollectibles + * @param {object} allCollectibles * @returns {[]} */ _getAllNFTsFlattened = memoize((allCollectibles = {}) => { @@ -639,7 +639,7 @@ export default class MetaMetricsController { * Returns the number of unique collectible/NFT addresses the user * possesses across all networks and accounts. * - * @param {Object} allCollectibles + * @param {object} allCollectibles * @returns {number} */ _getAllUniqueNFTAddressesLength(allCollectibles = {}) { @@ -668,7 +668,7 @@ export default class MetaMetricsController { * * @see {@link https://segment.com/docs/connections/sources/catalog/libraries/server/node/#identify} * @private - * @param {Object} userTraits + * @param {object} userTraits */ _identify(userTraits) { const { metaMetricsId } = this.state; diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index cb572773a..9cdad5aed 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -142,7 +142,7 @@ export default class NetworkController extends EventEmitter { /** * Method to return the latest block for the current network * - * @returns {Object} Block header + * @returns {object} Block header */ getLatestBlock() { return new Promise((resolve, reject) => { @@ -272,6 +272,11 @@ export default class NetworkController extends EventEmitter { return NETWORK_TYPE_TO_ID_MAP[type]?.chainId || configChainId; } + getCurrentRpcUrl() { + const { rpcUrl } = this.getProviderConfig(); + return rpcUrl; + } + setRpcTarget(rpcUrl, chainId, ticker = 'ETH', nickname = '', rpcPrefs) { assert.ok( isPrefixedFormattedHexString(chainId), diff --git a/app/scripts/controllers/onboarding.js b/app/scripts/controllers/onboarding.js index 812ba7e44..ad8ef8b8c 100644 --- a/app/scripts/controllers/onboarding.js +++ b/app/scripts/controllers/onboarding.js @@ -2,13 +2,13 @@ import { ObservableStore } from '@metamask/obs-store'; import log from 'loglevel'; /** - * @typedef {Object} InitState + * @typedef {object} InitState * @property {boolean} seedPhraseBackedUp Indicates whether the user has completed the seed phrase backup challenge * @property {boolean} completedOnboarding Indicates whether the user has completed the onboarding flow */ /** - * @typedef {Object} OnboardingOptions + * @typedef {object} OnboardingOptions * @property {InitState} initState The initial controller state */ diff --git a/app/scripts/controllers/permissions/permission-log.js b/app/scripts/controllers/permissions/permission-log.js index 70e8d1c9f..60b34b6c3 100644 --- a/app/scripts/controllers/permissions/permission-log.js +++ b/app/scripts/controllers/permissions/permission-log.js @@ -27,7 +27,7 @@ export class PermissionLogController { /** * Get the restricted method activity log. * - * @returns {Array} The activity log. + * @returns {Array} The activity log. */ getActivityLog() { return this.store.getState().permissionActivityLog; @@ -36,7 +36,7 @@ export class PermissionLogController { /** * Update the restricted method activity log. * - * @param {Array} logs - The new activity log array. + * @param {Array} logs - The new activity log array. */ updateActivityLog(logs) { this.store.updateState({ permissionActivityLog: logs }); @@ -45,7 +45,7 @@ export class PermissionLogController { /** * Get the permission history log. * - * @returns {Object} The permissions history log. + * @returns {object} The permissions history log. */ getHistory() { return this.store.getState().permissionHistory; @@ -54,7 +54,7 @@ export class PermissionLogController { /** * Update the permission history log. * - * @param {Object} history - The new permissions history log object. + * @param {object} history - The new permissions history log object. */ updateHistory(history) { this.store.updateState({ permissionHistory: history }); @@ -146,7 +146,7 @@ export class PermissionLogController { /** * Creates and commits an activity log entry, without response data. * - * @param {Object} request - The request object. + * @param {object} request - The request object. * @param {boolean} isInternal - Whether the request is internal. */ logRequest(request, isInternal) { @@ -169,8 +169,8 @@ export class PermissionLogController { * Adds response data to an existing activity log entry. * Entry assumed already committed (i.e., in the log). * - * @param {Object} entry - The entry to add a response to. - * @param {Object} response - The response object. + * @param {object} entry - The entry to add a response to. + * @param {object} response - The response object. * @param {number} time - Output from Date.now() */ logResponse(entry, response, time) { @@ -190,7 +190,7 @@ export class PermissionLogController { * Commit a new entry to the activity log. * Removes the oldest entry from the log if it exceeds the log limit. * - * @param {Object} entry - The activity log entry. + * @param {object} entry - The activity log entry. */ commitNewActivity(entry) { const logs = this.getActivityLog(); @@ -277,7 +277,7 @@ export class PermissionLogController { * with the same key (permission name). * * @param {string} origin - The requesting origin. - * @param {Object} newEntries - The new entries to commit. + * @param {object} newEntries - The new entries to commit. */ commitNewHistory(origin, newEntries) { // a simple merge updates most permissions @@ -318,7 +318,7 @@ export class PermissionLogController { /** * Get all requested methods from a permissions request. * - * @param {Object} request - The request object. + * @param {object} request - The request object. * @returns {Array} The names of the requested permissions. */ getRequestedMethods(request) { @@ -337,7 +337,7 @@ export class PermissionLogController { * Get the permitted accounts from an eth_accounts permissions object. * Returns an empty array if the permission is not eth_accounts. * - * @param {Object} perm - The permissions object. + * @param {object} perm - The permissions object. * @returns {Array} The permitted accounts. */ getAccountsFromPermission(perm) { @@ -367,7 +367,7 @@ export class PermissionLogController { * * @param {Array} accounts - An array of addresses. * @param {number} time - A time, e.g. Date.now(). - * @returns {Object} A string:number map of addresses to time. + * @returns {object} A string:number map of addresses to time. */ function getAccountToTimeMap(accounts, time) { return accounts.reduce((acc, account) => ({ ...acc, [account]: time }), {}); diff --git a/app/scripts/controllers/permissions/permission-log.test.js b/app/scripts/controllers/permissions/permission-log.test.js index 4ed46b84c..a8d58f692 100644 --- a/app/scripts/controllers/permissions/permission-log.test.js +++ b/app/scripts/controllers/permissions/permission-log.test.js @@ -639,9 +639,9 @@ describe('PermissionLogController', () => { * Validates an activity log entry with respect to a request, response, and * relevant metadata. * - * @param {Object} entry - The activity log entry to validate. - * @param {Object} req - The request that generated the entry. - * @param {Object} [res] - The response for the request, if any. + * @param {object} entry - The activity log entry to validate. + * @param {object} req - The request that generated the entry. + * @param {object} [res] - The response for the request, if any. * @param {'restricted'|'internal'} methodType - The method log controller method type of the request. * @param {boolean} success - Whether the request succeeded or not. */ diff --git a/app/scripts/controllers/permissions/specifications.js b/app/scripts/controllers/permissions/specifications.js index bab176db2..ac52af06c 100644 --- a/app/scripts/controllers/permissions/specifications.js +++ b/app/scripts/controllers/permissions/specifications.js @@ -31,7 +31,7 @@ const CaveatFactories = Object.freeze({ /** * A PreferencesController identity object. * - * @typedef {Object} Identity + * @typedef {object} Identity * @property {string} address - The address of the identity. * @property {string} name - The name of the identity. * @property {number} [lastSelected] - Unix timestamp of when the identity was diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 9b9c16d11..c1a1d2c7b 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -14,17 +14,17 @@ import { NETWORK_EVENTS } from './network'; export default class PreferencesController { /** * - * @typedef {Object} PreferencesController - * @param {Object} opts - Overrides the defaults for the initial state of this.store - * @property {Object} store The stored object containing a users preferences, stored in local storage + * @typedef {object} PreferencesController + * @param {object} opts - Overrides the defaults for the initial state of this.store + * @property {object} store The stored object containing a users preferences, stored in local storage * @property {Array} store.frequentRpcList A list of custom rpcs to provide the user * @property {boolean} store.useBlockie The users preference for blockie identicons within the UI * @property {boolean} store.useNonceField The users preference for nonce field within the UI - * @property {Object} store.featureFlags A key-boolean map, where keys refer to features and booleans to whether the + * @property {object} store.featureFlags A key-boolean map, where keys refer to features and booleans to whether the * user wishes to see that feature. * * Feature flags can be set by the global function `setPreference(feature, enabled)`, and so should not expose any sensitive behavior. - * @property {Object} store.knownMethodData Contains all data methods known by the user + * @property {object} store.knownMethodData Contains all data methods known by the user * @property {string} store.currentLocale The preferred language locale key * @property {string} store.selectedAddress A hex string that matches the currently selected address in the app */ @@ -376,12 +376,12 @@ export default class PreferencesController { /** * updates custom RPC details * - * @param {Object} newRpcDetails - Options bag. + * @param {object} newRpcDetails - Options bag. * @param {string} newRpcDetails.rpcUrl - The RPC url to add to frequentRpcList. * @param {string} newRpcDetails.chainId - The chainId of the selected network. * @param {string} [newRpcDetails.ticker] - Optional ticker symbol of the selected network. * @param {string} [newRpcDetails.nickname] - Optional nickname of the selected network. - * @param {Object} [newRpcDetails.rpcPrefs] - Optional RPC preferences, such as the block explorer URL + * @param {object} [newRpcDetails.rpcPrefs] - Optional RPC preferences, such as the block explorer URL */ async updateRpc(newRpcDetails) { const rpcList = this.getFrequentRpcListDetail(); @@ -456,7 +456,7 @@ export default class PreferencesController { * @param {string} chainId - The chainId of the selected network. * @param {string} [ticker] - Ticker symbol of the selected network. * @param {string} [nickname] - Nickname of the selected network. - * @param {Object} [rpcPrefs] - Optional RPC preferences, such as the block explorer URL + * @param {object} [rpcPrefs] - Optional RPC preferences, such as the block explorer URL */ addToFrequentRpcList( rpcUrl, @@ -550,7 +550,7 @@ export default class PreferencesController { /** * A getter for the `preferences` property * - * @returns {Object} A key-boolean map of user-selected preferences. + * @returns {object} A key-boolean map of user-selected preferences. */ getPreferences() { return this.store.getState().preferences; diff --git a/app/scripts/controllers/swaps.js b/app/scripts/controllers/swaps.js index f19da6ff1..01ccf0b38 100644 --- a/app/scripts/controllers/swaps.js +++ b/app/scripts/controllers/swaps.js @@ -883,7 +883,7 @@ export default class SwapsController { * Calculates the median overallValueOfQuote of a sample of quotes. * * @param {Array} _quotes - A sample of quote objects with overallValueOfQuote, ethFee, metaMaskFeeInEth, and ethValueOfTokens properties - * @returns {Object} An object with the ethValueOfTokens, ethFee, and metaMaskFeeInEth of the quote with the median overallValueOfQuote + * @returns {object} An object with the ethValueOfTokens, ethFee, and metaMaskFeeInEth of the quote with the median overallValueOfQuote */ function getMedianEthValueQuote(_quotes) { if (!Array.isArray(_quotes) || _quotes.length === 0) { @@ -960,7 +960,7 @@ function getMedianEthValueQuote(_quotes) { * * @param {Array} quotes - A sample of quote objects with overallValueOfQuote, ethFee, metaMaskFeeInEth and * ethValueOfTokens properties - * @returns {Object} An object with the arithmetic mean each of the ethFee, metaMaskFeeInEth and ethValueOfTokens of + * @returns {object} An object with the arithmetic mean each of the ethFee, metaMaskFeeInEth and ethValueOfTokens of * the passed quote objects */ function meansOfQuotesFeesAndValue(quotes) { diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index 854088f67..a616ce357 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -85,7 +85,7 @@ const VALID_UNAPPROVED_TRANSACTION_TYPES = [ const METRICS_STATUS_FAILED = 'failed on-chain'; /** - * @typedef {Object} CustomGasSettings + * @typedef {object} CustomGasSettings * @property {string} [gas] - The gas limit to use for the transaction * @property {string} [gasPrice] - The gasPrice to use for a legacy transaction * @property {string} [maxFeePerGas] - The maximum amount to pay per gas on a @@ -109,16 +109,16 @@ const METRICS_STATUS_FAILED = 'failed on-chain'; * - nonceTracker * calculating nonces * - * @param {Object} opts - * @param {Object} opts.initState - initial transaction list default is an empty array - * @param {Object} opts.networkStore - an observable store for network number - * @param {Object} opts.blockTracker - An instance of eth-blocktracker - * @param {Object} opts.provider - A network provider. + * @param {object} opts + * @param {object} opts.initState - initial transaction list default is an empty array + * @param {object} opts.networkStore - an observable store for network number + * @param {object} opts.blockTracker - An instance of eth-blocktracker + * @param {object} opts.provider - A network provider. * @param {Function} opts.signTransaction - function the signs an @ethereumjs/tx - * @param {Object} opts.getPermittedAccounts - get accounts that an origin has permissions for + * @param {object} opts.getPermittedAccounts - get accounts that an origin has permissions for * @param {Function} opts.signTransaction - ethTx signer that returns a rawTx * @param {number} [opts.txHistoryLimit] - number *optional* for limiting how many transactions are in state - * @param {Object} opts.preferencesStore + * @param {object} opts.preferencesStore */ export default class TransactionController extends EventEmitter { @@ -313,8 +313,8 @@ export default class TransactionController extends EventEmitter { * Add a new unapproved transaction to the pipeline * * @returns {Promise} the hash of the transaction after being submitted to the network - * @param {Object} txParams - txParams for the transaction - * @param {Object} opts - with the key origin to put the origin on the txMeta + * @param {object} txParams - txParams for the transaction + * @param {object} opts - with the key origin to put the origin on the txMeta */ async newUnapprovedTransaction(txParams, opts = {}) { log.debug( @@ -802,7 +802,7 @@ export default class TransactionController extends EventEmitter { /** * Adds the tx gas defaults: gas && gasPrice * - * @param {Object} txMeta - the txMeta object + * @param {object} txMeta - the txMeta object * @param getCodeResponse * @returns {Promise} resolves with txMeta */ @@ -945,7 +945,7 @@ export default class TransactionController extends EventEmitter { /** * Gets default gas fees, or returns `undefined` if gas fees are already set * - * @param {Object} txMeta - The txMeta object + * @param {object} txMeta - The txMeta object * @param eip1559Compatibility * @returns {Promise} The default gas price */ @@ -1005,8 +1005,8 @@ export default class TransactionController extends EventEmitter { /** * Gets default gas limit, or debug information about why gas estimate failed. * - * @param {Object} txMeta - The txMeta object - * @returns {Promise} Object containing the default gas limit, or the simulation failure object + * @param {object} txMeta - The txMeta object + * @returns {Promise} Object containing the default gas limit, or the simulation failure object */ async _getDefaultGasLimit(txMeta) { const chainId = this._getCurrentChainId(); @@ -1217,7 +1217,7 @@ export default class TransactionController extends EventEmitter { /** * updates the txMeta in the txStateManager * - * @param {Object} txMeta - the updated txMeta + * @param {object} txMeta - the updated txMeta */ async updateTransaction(txMeta) { this.txStateManager.updateTransaction( @@ -1229,7 +1229,7 @@ export default class TransactionController extends EventEmitter { /** * updates and approves the transaction * - * @param {Object} txMeta + * @param {object} txMeta */ async updateAndApproveTransaction(txMeta) { this.txStateManager.updateTransaction( @@ -1676,7 +1676,7 @@ export default class TransactionController extends EventEmitter { // /** maps methods for convenience*/ _mapMethods() { - /** @returns {Object} the state in transaction controller */ + /** @returns {object} the state in transaction controller */ this.getState = () => this.memStore.getState(); /** @returns {string|number} the network number stored in networkStore */ @@ -2106,8 +2106,8 @@ export default class TransactionController extends EventEmitter { * @param {TransactionMeta} txMeta - Transaction meta object * @param {TransactionMetaMetricsEventString} event - The event type that * triggered fragment creation - * @param {Object} properties - properties to include in the fragment - * @param {Object} [sensitiveProperties] - sensitive properties to include in + * @param {object} properties - properties to include in the fragment + * @param {object} [sensitiveProperties] - sensitive properties to include in * the fragment */ _createTransactionEventFragment( @@ -2220,9 +2220,9 @@ export default class TransactionController extends EventEmitter { * object and uses them to create and send metrics for various transaction * events. * - * @param {Object} txMeta - the txMeta object + * @param {object} txMeta - the txMeta object * @param {TransactionMetaMetricsEventString} event - the name of the transaction event - * @param {Object} extraParams - optional props and values to include in sensitiveProperties + * @param {object} extraParams - optional props and values to include in sensitiveProperties */ async _trackTransactionMetricsEvent(txMeta, event, extraParams = {}) { if (!txMeta) { diff --git a/app/scripts/controllers/transactions/lib/tx-state-history-helpers.js b/app/scripts/controllers/transactions/lib/tx-state-history-helpers.js index cb0673c7a..a6252f5a9 100644 --- a/app/scripts/controllers/transactions/lib/tx-state-history-helpers.js +++ b/app/scripts/controllers/transactions/lib/tx-state-history-helpers.js @@ -28,8 +28,8 @@ export function migrateFromSnapshotsToDiffs(longHistory) { * value * with the first entry having the note and a timestamp when the change took place * - * @param {Object} previousState - the previous state of the object - * @param {Object} newState - the update object + * @param {object} previousState - the previous state of the object + * @param {object} newState - the update object * @param {string} [note] - a optional note for the state change * @returns {Array} */ @@ -49,7 +49,7 @@ export function generateHistoryEntry(previousState, newState, note) { * Recovers previous txMeta state obj * * @param _shortHistory - * @returns {Object} + * @returns {object} */ export function replayHistory(_shortHistory) { const shortHistory = cloneDeep(_shortHistory); @@ -61,8 +61,8 @@ export function replayHistory(_shortHistory) { /** * Snapshot {@code txMeta} * - * @param {Object} txMeta - the tx metadata object - * @returns {Object} a deep clone without history + * @param {object} txMeta - the tx metadata object + * @returns {object} a deep clone without history */ export function snapshotFromTxMeta(txMeta) { const shallow = { ...txMeta }; diff --git a/app/scripts/controllers/transactions/lib/util.js b/app/scripts/controllers/transactions/lib/util.js index 9a19ca573..328703138 100644 --- a/app/scripts/controllers/transactions/lib/util.js +++ b/app/scripts/controllers/transactions/lib/util.js @@ -32,10 +32,10 @@ export function normalizeAndValidateTxParams(txParams, lowerCase = true) { /** * Normalizes the given txParams * - * @param {Object} txParams - The transaction params + * @param {object} txParams - The transaction params * @param {boolean} [lowerCase] - Whether to lowercase the 'to' address. * Default: true - * @returns {Object} the normalized tx params + * @returns {object} the normalized tx params */ export function normalizeTxParams(txParams, lowerCase = true) { // apply only keys in the normalizers @@ -52,7 +52,7 @@ export function normalizeTxParams(txParams, lowerCase = true) { * Given two fields, ensure that the second field is not included in txParams, * and if it is throw an invalidParams error. * - * @param {Object} txParams - the transaction parameters object + * @param {object} txParams - the transaction parameters object * @param {string} fieldBeingValidated - the current field being validated * @param {string} mutuallyExclusiveField - the field to ensure is not provided * @throws {ethErrors.rpc.invalidParams} Throws if mutuallyExclusiveField is @@ -74,7 +74,7 @@ function ensureMutuallyExclusiveFieldsNotProvided( * Ensures that the provided value for field is a string, throws an * invalidParams error if field is not a string. * - * @param {Object} txParams - the transaction parameters object + * @param {object} txParams - the transaction parameters object * @param {string} field - the current field being validated * @throws {ethErrors.rpc.invalidParams} Throws if field is not a string */ @@ -91,7 +91,7 @@ function ensureFieldIsString(txParams, field) { * given field, if it is provided. If types do not match throws an * invalidParams error. * - * @param {Object} txParams - the transaction parameters object + * @param {object} txParams - the transaction parameters object * @param {'gasPrice' | 'maxFeePerGas' | 'maxPriorityFeePerGas'} field - the * current field being validated * @throws {ethErrors.rpc.invalidParams} Throws if type does not match the @@ -126,7 +126,7 @@ function ensureProperTransactionEnvelopeTypeProvided(txParams, field) { /** * Validates the given tx parameters * - * @param {Object} txParams - the tx params + * @param {object} txParams - the tx params * @param {boolean} eip1559Compatibility - whether or not the current network supports EIP-1559 transactions * @throws {Error} if the tx params contains invalid fields */ @@ -227,7 +227,7 @@ export function validateTxParams(txParams, eip1559Compatibility = true) { /** * Validates the {@code from} field in the given tx params * - * @param {Object} txParams + * @param {object} txParams * @throws {Error} if the from address isn't valid */ export function validateFrom(txParams) { @@ -244,8 +244,8 @@ export function validateFrom(txParams) { /** * Validates the {@code to} field in the given tx params * - * @param {Object} txParams - the tx params - * @returns {Object} the tx params + * @param {object} txParams - the tx params + * @returns {object} the tx params * @throws {Error} if the recipient is invalid OR there isn't tx data */ export function validateRecipient(txParams) { diff --git a/app/scripts/controllers/transactions/pending-tx-tracker.js b/app/scripts/controllers/transactions/pending-tx-tracker.js index 2bd547189..7fbaca8ce 100644 --- a/app/scripts/controllers/transactions/pending-tx-tracker.js +++ b/app/scripts/controllers/transactions/pending-tx-tracker.js @@ -29,14 +29,14 @@ export default class PendingTransactionTracker extends EventEmitter { droppedBlocksBufferByHash = new Map(); /** - * @param {Object} config - Configuration. + * @param {object} config - Configuration. * @param {Function} config.approveTransaction - Approves a transaction. * @param {Function} config.confirmTransaction - Set a transaction as confirmed. * @param {Function} config.getCompletedTransactions - Returns completed transactions. * @param {Function} config.getPendingTransactions - Returns an array of pending transactions, - * @param {Object} config.nonceTracker - see nonce tracker - * @param {Object} config.provider - A network provider. - * @param {Object} config.query - An EthQuery instance. + * @param {object} config.nonceTracker - see nonce tracker + * @param {object} config.provider - A network provider. + * @param {object} config.query - An EthQuery instance. * @param {Function} config.publishTransaction - Publishes a raw transaction, */ constructor(config) { @@ -119,7 +119,7 @@ export default class PendingTransactionTracker extends EventEmitter { * * Will only attempt to retry the given tx every {@code 2**(txMeta.retryCount)} blocks. * - * @param {Object} txMeta - the transaction metadata + * @param {object} txMeta - the transaction metadata * @param {string} latestBlockNumber - the latest block number in hex * @returns {Promise} the tx hash if retried * @fires tx:block-update @@ -160,7 +160,7 @@ export default class PendingTransactionTracker extends EventEmitter { /** * Query the network to see if the given {@code txMeta} has been included in a block * - * @param {Object} txMeta - the transaction metadata + * @param {object} txMeta - the transaction metadata * @returns {Promise} * @fires tx:confirmed * @fires tx:dropped @@ -232,7 +232,7 @@ export default class PendingTransactionTracker extends EventEmitter { /** * Checks whether the nonce in the given {@code txMeta} is behind the network nonce * - * @param {Object} txMeta - the transaction metadata + * @param {object} txMeta - the transaction metadata * @returns {Promise} * @private */ @@ -265,7 +265,7 @@ export default class PendingTransactionTracker extends EventEmitter { /** * Checks whether the nonce in the given {@code txMeta} is correct against the local set of transactions * - * @param {Object} txMeta - the transaction metadata + * @param {object} txMeta - the transaction metadata * @returns {Promise} * @private */ diff --git a/app/scripts/controllers/transactions/tx-gas-utils.js b/app/scripts/controllers/transactions/tx-gas-utils.js index a4b73a31c..350cb1eaa 100644 --- a/app/scripts/controllers/transactions/tx-gas-utils.js +++ b/app/scripts/controllers/transactions/tx-gas-utils.js @@ -8,10 +8,10 @@ import { hexToBn, BnMultiplyByFraction, bnToHex } from '../../lib/util'; * Result of gas analysis, including either a gas estimate for a successful analysis, or * debug information for a failed analysis. * - * @typedef {Object} GasAnalysisResult + * @typedef {object} GasAnalysisResult * @property {string} blockGasLimit - The gas limit of the block used for the analysis * @property {string} estimatedGasHex - The estimated gas, in hexadecimal - * @property {Object} simulationFails - Debug information about why an analysis failed + * @property {object} simulationFails - Debug information about why an analysis failed */ /** @@ -19,7 +19,7 @@ import { hexToBn, BnMultiplyByFraction, bnToHex } from '../../lib/util'; * its passed ethquery * and used to do things like calculate gas of a tx. * - * @param {Object} provider - A network provider. + * @param {object} provider - A network provider. */ export default class TxGasUtil { @@ -28,7 +28,7 @@ export default class TxGasUtil { } /** - * @param {Object} txMeta - the txMeta object + * @param {object} txMeta - the txMeta object * @returns {GasAnalysisResult} The result of the gas analysis */ async analyzeGasUsage(txMeta) { @@ -56,7 +56,7 @@ export default class TxGasUtil { /** * Estimates the tx's gas usage * - * @param {Object} txMeta - the txMeta object + * @param {object} txMeta - the txMeta object * @returns {string} the estimated gas limit as a hex string */ async estimateTxGas(txMeta) { diff --git a/app/scripts/controllers/transactions/tx-state-manager.js b/app/scripts/controllers/transactions/tx-state-manager.js index c924c9b66..dc1c66e01 100644 --- a/app/scripts/controllers/transactions/tx-state-manager.js +++ b/app/scripts/controllers/transactions/tx-state-manager.js @@ -39,7 +39,7 @@ export const ERROR_SUBMITTING = */ /** - * @typedef {Object} TransactionState + * @typedef {object} TransactionState * @property {Record} transactions - TransactionMeta * keyed by the transaction's id. */ @@ -49,7 +49,7 @@ export const ERROR_SUBMITTING = * storing the transaction. It also has some convenience methods for finding * subsets of transactions. * - * @param {Object} opts + * @param {object} opts * @param {TransactionState} [opts.initState={ transactions: {} }] - initial * transactions list keyed by id * @param {number} [opts.txHistoryLimit] - limit for how many finished @@ -300,7 +300,7 @@ export default class TransactionStateManager extends EventEmitter { /** * updates the txMeta in the list and adds a history entry * - * @param {Object} txMeta - the txMeta to update + * @param {object} txMeta - the txMeta to update * @param {string} [note] - a note about the update for history */ updateTransaction(txMeta, note) { diff --git a/app/scripts/first-time-state.js b/app/scripts/first-time-state.js index 857921889..b5f906862 100644 --- a/app/scripts/first-time-state.js +++ b/app/scripts/first-time-state.js @@ -1,7 +1,7 @@ /** - * @typedef {Object} FirstTimeState - * @property {Object} config Initial configuration parameters - * @property {Object} NetworkController Network controller state + * @typedef {object} FirstTimeState + * @property {object} config Initial configuration parameters + * @property {object} NetworkController Network controller state */ /** diff --git a/app/scripts/lib/ComposableObservableStore.js b/app/scripts/lib/ComposableObservableStore.js index 75b86be92..6d156ab29 100644 --- a/app/scripts/lib/ComposableObservableStore.js +++ b/app/scripts/lib/ComposableObservableStore.js @@ -23,12 +23,12 @@ export default class ComposableObservableStore extends ObservableStore { /** * Create a new store * - * @param {Object} options - * @param {Object} [options.config] - Map of internal state keys to child stores + * @param {object} options + * @param {object} [options.config] - Map of internal state keys to child stores * @param {ControllerMessenger} options.controllerMessenger - The controller * messenger, used for subscribing to events from BaseControllerV2-based * controllers. - * @param {Object} [options.state] - The initial store state + * @param {object} [options.state] - The initial store state * @param {boolean} [options.persist] - Whether or not to apply the persistence for v2 controllers */ constructor({ config, controllerMessenger, state, persist }) { @@ -79,7 +79,7 @@ export default class ComposableObservableStore extends ObservableStore { * Merges all child store state into a single object rather than * returning an object keyed by child store class name * - * @returns {Object} Object containing merged child store state + * @returns {object} Object containing merged child store state */ getFlatState() { if (!this.config) { diff --git a/app/scripts/lib/account-tracker.js b/app/scripts/lib/account-tracker.js index 7abe349a3..d8c90588c 100644 --- a/app/scripts/lib/account-tracker.js +++ b/app/scripts/lib/account-tracker.js @@ -35,21 +35,21 @@ import { bnToHex } from './util'; * * It also tracks transaction hashes, and checks their inclusion status on each new block. * - * @typedef {Object} AccountTracker - * @property {Object} store The stored object containing all accounts to track, as well as the current block's gas limit. - * @property {Object} store.accounts The accounts currently stored in this AccountTracker + * @typedef {object} AccountTracker + * @property {object} store The stored object containing all accounts to track, as well as the current block's gas limit. + * @property {object} store.accounts The accounts currently stored in this AccountTracker * @property {string} store.currentBlockGasLimit A hex string indicating the gas limit of the current block - * @property {Object} _provider A provider needed to create the EthQuery instance used within this AccountTracker. + * @property {object} _provider A provider needed to create the EthQuery instance used within this AccountTracker. * @property {EthQuery} _query An EthQuery instance used to access account information from the blockchain * @property {BlockTracker} _blockTracker A BlockTracker instance. Needed to ensure that accounts and their info updates * when a new block is created. - * @property {Object} _currentBlockNumber Reference to a property on the _blockTracker: the number (i.e. an id) of the the current block + * @property {object} _currentBlockNumber Reference to a property on the _blockTracker: the number (i.e. an id) of the the current block */ export default class AccountTracker { /** - * @param {Object} opts - Options for initializing the controller - * @param {Object} opts.provider - An EIP-1193 provider instance that uses the current global network - * @param {Object} opts.blockTracker - A block tracker, which emits events for each new block + * @param {object} opts - Options for initializing the controller + * @param {object} opts.provider - An EIP-1193 provider instance that uses the current global network + * @param {object} opts.blockTracker - A block tracker, which emits events for each new block * @param {Function} opts.getCurrentChainId - A function that returns the `chainId` for the current global network */ constructor(opts = {}) { diff --git a/app/scripts/lib/buy-url.js b/app/scripts/lib/buy-url.js index eed5ff82d..7cd885a66 100644 --- a/app/scripts/lib/buy-url.js +++ b/app/scripts/lib/buy-url.js @@ -141,7 +141,7 @@ const createCoinbasePayUrl = (walletAddress, chainId) => { /** * Gives the caller a url at which the user can acquire eth, depending on the network they are in * - * @param {Object} opts - Options required to determine the correct url + * @param {object} opts - Options required to determine the correct url * @param {string} opts.chainId - The chainId for which to return a url * @param {string} opts.address - The address the bought ETH should be sent to. Only relevant if chainId === '0x1'. * @param opts.service diff --git a/app/scripts/lib/createRPCMethodTrackingMiddleware.js b/app/scripts/lib/createRPCMethodTrackingMiddleware.js index 89141357f..3362e29ad 100644 --- a/app/scripts/lib/createRPCMethodTrackingMiddleware.js +++ b/app/scripts/lib/createRPCMethodTrackingMiddleware.js @@ -1,19 +1,91 @@ +import { MESSAGE_TYPE, ORIGIN_METAMASK } from '../../../shared/constants/app'; import { EVENT, EVENT_NAMES } from '../../../shared/constants/metametrics'; import { SECOND } from '../../../shared/constants/time'; -const USER_PROMPTED_EVENT_NAME_MAP = { - eth_signTypedData_v4: EVENT_NAMES.SIGNATURE_REQUESTED, - eth_signTypedData_v3: EVENT_NAMES.SIGNATURE_REQUESTED, - eth_signTypedData: EVENT_NAMES.SIGNATURE_REQUESTED, - eth_personal_sign: EVENT_NAMES.SIGNATURE_REQUESTED, - eth_sign: EVENT_NAMES.SIGNATURE_REQUESTED, - eth_getEncryptionPublicKey: EVENT_NAMES.ENCRYPTION_PUBLIC_KEY_REQUESTED, - eth_decrypt: EVENT_NAMES.DECRYPTION_REQUESTED, - wallet_requestPermissions: EVENT_NAMES.PERMISSIONS_REQUESTED, - eth_requestAccounts: EVENT_NAMES.PERMISSIONS_REQUESTED, +/** + * These types determine how the method tracking middleware handles incoming + * requests based on the method name. There are three options right now but + * the types could be expanded to cover other options in the future. + */ +const RATE_LIMIT_TYPES = { + RATE_LIMITED: 'rate_limited', + BLOCKED: 'blocked', + NON_RATE_LIMITED: 'non_rate_limited', }; -const samplingTimeouts = {}; +/** + * This object maps a method name to a RATE_LIMIT_TYPE. If not in this map the + * default is 'RATE_LIMITED' + */ +const RATE_LIMIT_MAP = { + [MESSAGE_TYPE.ETH_SIGN]: RATE_LIMIT_TYPES.NON_RATE_LIMITED, + [MESSAGE_TYPE.ETH_SIGN_TYPED_DATA]: RATE_LIMIT_TYPES.NON_RATE_LIMITED, + [MESSAGE_TYPE.ETH_SIGN_TYPED_DATA_V3]: RATE_LIMIT_TYPES.NON_RATE_LIMITED, + [MESSAGE_TYPE.ETH_SIGN_TYPED_DATA_V4]: RATE_LIMIT_TYPES.NON_RATE_LIMITED, + [MESSAGE_TYPE.PERSONAL_SIGN]: RATE_LIMIT_TYPES.NON_RATE_LIMITED, + [MESSAGE_TYPE.ETH_DECRYPT]: RATE_LIMIT_TYPES.NON_RATE_LIMITED, + [MESSAGE_TYPE.ETH_GET_ENCRYPTION_PUBLIC_KEY]: + RATE_LIMIT_TYPES.NON_RATE_LIMITED, + [MESSAGE_TYPE.ETH_REQUEST_ACCOUNTS]: RATE_LIMIT_TYPES.RATE_LIMITED, + [MESSAGE_TYPE.WALLET_REQUEST_PERMISSIONS]: RATE_LIMIT_TYPES.RATE_LIMITED, + [MESSAGE_TYPE.SEND_METADATA]: RATE_LIMIT_TYPES.BLOCKED, + [MESSAGE_TYPE.GET_PROVIDER_STATE]: RATE_LIMIT_TYPES.BLOCKED, +}; + +/** + * For events with user interaction (approve / reject | cancel) this map will + * return an object with APPROVED, REJECTED and REQUESTED keys that map to the + * appropriate event names. + */ +const EVENT_NAME_MAP = { + [MESSAGE_TYPE.ETH_SIGN]: { + APPROVED: EVENT_NAMES.SIGNATURE_APPROVED, + REJECTED: EVENT_NAMES.SIGNATURE_REJECTED, + REQUESTED: EVENT_NAMES.SIGNATURE_REQUESTED, + }, + [MESSAGE_TYPE.ETH_SIGN_TYPED_DATA]: { + APPROVED: EVENT_NAMES.SIGNATURE_APPROVED, + REJECTED: EVENT_NAMES.SIGNATURE_REJECTED, + REQUESTED: EVENT_NAMES.SIGNATURE_REQUESTED, + }, + [MESSAGE_TYPE.ETH_SIGN_TYPED_DATA_V3]: { + APPROVED: EVENT_NAMES.SIGNATURE_APPROVED, + REJECTED: EVENT_NAMES.SIGNATURE_REJECTED, + REQUESTED: EVENT_NAMES.SIGNATURE_REQUESTED, + }, + [MESSAGE_TYPE.ETH_SIGN_TYPED_DATA_V4]: { + APPROVED: EVENT_NAMES.SIGNATURE_APPROVED, + REJECTED: EVENT_NAMES.SIGNATURE_REJECTED, + REQUESTED: EVENT_NAMES.SIGNATURE_REQUESTED, + }, + [MESSAGE_TYPE.PERSONAL_SIGN]: { + APPROVED: EVENT_NAMES.SIGNATURE_APPROVED, + REJECTED: EVENT_NAMES.SIGNATURE_REJECTED, + REQUESTED: EVENT_NAMES.SIGNATURE_REQUESTED, + }, + [MESSAGE_TYPE.ETH_DECRYPT]: { + APPROVED: EVENT_NAMES.DECRYPTION_APPROVED, + REJECTED: EVENT_NAMES.DECRYPTION_REJECTED, + REQUESTED: EVENT_NAMES.DECRYPTION_REQUESTED, + }, + [MESSAGE_TYPE.ETH_GET_ENCRYPTION_PUBLIC_KEY]: { + APPROVED: EVENT_NAMES.ENCRYPTION_PUBLIC_KEY_APPROVED, + REJECTED: EVENT_NAMES.ENCRYPTION_PUBLIC_KEY_REJECTED, + REQUESTED: EVENT_NAMES.ENCRYPTION_PUBLIC_KEY_REQUESTED, + }, + [MESSAGE_TYPE.ETH_REQUEST_ACCOUNTS]: { + APPROVED: EVENT_NAMES.PERMISSIONS_APPROVED, + REJECTED: EVENT_NAMES.PERMISSIONS_REJECTED, + REQUESTED: EVENT_NAMES.PERMISSIONS_REQUESTED, + }, + [MESSAGE_TYPE.WALLET_REQUEST_PERMISSIONS]: { + APPROVED: EVENT_NAMES.PERMISSIONS_APPROVED, + REJECTED: EVENT_NAMES.PERMISSIONS_REJECTED, + REQUESTED: EVENT_NAMES.PERMISSIONS_REQUESTED, + }, +}; + +const rateLimitTimeouts = {}; /** * Returns a middleware that tracks inpage_provider usage using sampling for @@ -21,65 +93,113 @@ const samplingTimeouts = {}; * signature requests * * @param {object} opts - options for the rpc method tracking middleware - * @param {Function} opts.trackEvent - trackEvent method from MetaMetricsController - * @param {Function} opts.getMetricsState - get the state of MetaMetricsController + * @param {Function} opts.trackEvent - trackEvent method from + * MetaMetricsController + * @param {Function} opts.getMetricsState - get the state of + * MetaMetricsController + * @param {number} [opts.rateLimitSeconds] - number of seconds to wait before + * allowing another set of events to be tracked. * @returns {Function} */ export default function createRPCMethodTrackingMiddleware({ trackEvent, getMetricsState, + rateLimitSeconds = 60, }) { return function rpcMethodTrackingMiddleware( /** @type {any} */ req, /** @type {any} */ res, /** @type {Function} */ next, ) { - const startTime = Date.now(); - const { origin } = req; + const { origin, method } = req; + + // Determine what type of rate limit to apply based on method + const rateLimitType = + RATE_LIMIT_MAP[method] ?? RATE_LIMIT_TYPES.RATE_LIMITED; + + // If the rateLimitType is RATE_LIMITED check the rateLimitTimeouts + const rateLimited = + rateLimitType === RATE_LIMIT_TYPES.RATE_LIMITED && + typeof rateLimitTimeouts[method] !== 'undefined'; + + // Get the participateInMetaMetrics state to determine if we should track + // anything. This is extra redundancy because this value is checked in + // the metametrics controller's trackEvent method as well. + const userParticipatingInMetaMetrics = + getMetricsState().participateInMetaMetrics === true; + + // Get the event type, each of which has APPROVED, REJECTED and REQUESTED + // keys for the various events in the flow. + const eventType = EVENT_NAME_MAP[method]; + + // Boolean variable that reduces code duplication and increases legibility + const shouldTrackEvent = + // Don't track if the request came from our own UI or background + origin !== ORIGIN_METAMASK && + // Don't track if this is a blocked method + rateLimitType !== RATE_LIMIT_TYPES.BLOCKED && + // Don't track if the rate limit has been hit + rateLimited === false && + // Don't track if the user isn't participating in metametrics + userParticipatingInMetaMetrics === true; + + if (shouldTrackEvent) { + // We track an initial "requested" event as soon as the dapp calls the + // provider method. For the events not special cased this is the only + // event that will be fired and the event name will be + // 'Provider Method Called'. + const event = eventType + ? eventType.REQUESTED + : EVENT_NAMES.PROVIDER_METHOD_CALLED; + + const properties = {}; + + if (event === EVENT_NAMES.SIGNATURE_REQUESTED) { + properties.signature_type = method; + } else { + properties.method = method; + } + + trackEvent({ + event, + category: EVENT.CATEGORIES.INPAGE_PROVIDER, + referrer: { + url: origin, + }, + properties, + }); + + rateLimitTimeouts[method] = setTimeout(() => { + delete rateLimitTimeouts[method]; + }, SECOND * rateLimitSeconds); + } next((callback) => { - const endTime = Date.now(); - if (!getMetricsState().participateInMetaMetrics) { + if (shouldTrackEvent === false || typeof eventType === 'undefined') { return callback(); } - if (USER_PROMPTED_EVENT_NAME_MAP[req.method]) { - const userRejected = res.error?.code === 4001; - trackEvent({ - event: USER_PROMPTED_EVENT_NAME_MAP[req.method], - category: EVENT.CATEGORIES.INPAGE_PROVIDER, - referrer: { - url: origin, - }, - properties: { - method: req.method, - status: userRejected ? 'rejected' : 'approved', - error_code: res.error?.code, - error_message: res.error?.message, - has_result: typeof res.result !== 'undefined', - duration: endTime - startTime, - }, - }); - } else if (typeof samplingTimeouts[req.method] === 'undefined') { - trackEvent({ - event: 'Provider Method Called', - category: EVENT.CATEGORIES.INPAGE_PROVIDER, - referrer: { - url: origin, - }, - properties: { - method: req.method, - error_code: res.error?.code, - error_message: res.error?.message, - has_result: typeof res.result !== 'undefined', - duration: endTime - startTime, - }, - }); - // Only record one call to this method every ten seconds to avoid - // overloading network requests. - samplingTimeouts[req.method] = setTimeout(() => { - delete samplingTimeouts[req.method]; - }, SECOND * 10); + + // An error code of 4001 means the user rejected the request, which we + // can use here to determine which event to track. + const event = + res.error?.code === 4001 ? eventType.REJECTED : eventType.APPROVED; + + const properties = {}; + + if (eventType.REQUESTED === EVENT_NAMES.SIGNATURE_REQUESTED) { + properties.signature_type = method; + } else { + properties.method = method; } + + trackEvent({ + event, + category: EVENT.CATEGORIES.INPAGE_PROVIDER, + referrer: { + url: origin, + }, + properties, + }); return callback(); }); }; diff --git a/app/scripts/lib/createRPCMethodTrackingMiddleware.test.js b/app/scripts/lib/createRPCMethodTrackingMiddleware.test.js new file mode 100644 index 000000000..ffa953fa0 --- /dev/null +++ b/app/scripts/lib/createRPCMethodTrackingMiddleware.test.js @@ -0,0 +1,217 @@ +import { MESSAGE_TYPE } from '../../../shared/constants/app'; +import { EVENT_NAMES } from '../../../shared/constants/metametrics'; +import { SECOND } from '../../../shared/constants/time'; +import createRPCMethodTrackingMiddleware from './createRPCMethodTrackingMiddleware'; + +const trackEvent = jest.fn(); +const metricsState = { participateInMetaMetrics: null }; +const getMetricsState = () => metricsState; + +const handler = createRPCMethodTrackingMiddleware({ + trackEvent, + getMetricsState, + rateLimitSeconds: 1, +}); + +function getNext(timeout = 500) { + let deferred; + const promise = new Promise((resolve) => { + deferred = { + resolve, + }; + }); + const cb = () => deferred.resolve(); + let triggerNext; + setTimeout(() => { + deferred.resolve(); + }, timeout); + return { + executeMiddlewareStack: async () => { + if (triggerNext) { + triggerNext(() => cb()); + } + return await deferred.resolve(); + }, + promise, + next: (postReqHandler) => { + triggerNext = postReqHandler; + }, + }; +} + +const waitForSeconds = async (seconds) => + await new Promise((resolve) => setTimeout(resolve, SECOND * seconds)); + +describe('createRPCMethodTrackingMiddleware', () => { + afterEach(() => { + jest.resetAllMocks(); + metricsState.participateInMetaMetrics = null; + }); + + describe('before participateInMetaMetrics is set', () => { + it('should not track an event for a signature request', async () => { + const req = { + method: MESSAGE_TYPE.ETH_SIGN, + origin: 'some.dapp', + }; + + const res = { + error: null, + }; + const { executeMiddlewareStack, next } = getNext(); + handler(req, res, next); + await executeMiddlewareStack(); + expect(trackEvent).not.toHaveBeenCalled(); + }); + }); + + describe('participateInMetaMetrics is set to false', () => { + beforeEach(() => { + metricsState.participateInMetaMetrics = false; + }); + + it('should not track an event for a signature request', async () => { + const req = { + method: MESSAGE_TYPE.ETH_SIGN, + origin: 'some.dapp', + }; + + const res = { + error: null, + }; + const { executeMiddlewareStack, next } = getNext(); + handler(req, res, next); + await executeMiddlewareStack(); + expect(trackEvent).not.toHaveBeenCalled(); + }); + }); + + describe('participateInMetaMetrics is set to true', () => { + beforeEach(() => { + metricsState.participateInMetaMetrics = true; + }); + + it(`should immediately track a ${EVENT_NAMES.SIGNATURE_REQUESTED} event`, () => { + const req = { + method: MESSAGE_TYPE.ETH_SIGN, + origin: 'some.dapp', + }; + + const res = { + error: null, + }; + const { next } = getNext(); + handler(req, res, next); + expect(trackEvent).toHaveBeenCalledTimes(1); + expect(trackEvent.mock.calls[0][0]).toMatchObject({ + category: 'inpage_provider', + event: EVENT_NAMES.SIGNATURE_REQUESTED, + properties: { signature_type: MESSAGE_TYPE.ETH_SIGN }, + referrer: { url: 'some.dapp' }, + }); + }); + + it(`should track a ${EVENT_NAMES.SIGNATURE_APPROVED} event if the user approves`, async () => { + const req = { + method: MESSAGE_TYPE.ETH_SIGN_TYPED_DATA_V4, + origin: 'some.dapp', + }; + + const res = { + error: null, + }; + const { next, executeMiddlewareStack } = getNext(); + handler(req, res, next); + await executeMiddlewareStack(); + expect(trackEvent).toHaveBeenCalledTimes(2); + expect(trackEvent.mock.calls[1][0]).toMatchObject({ + category: 'inpage_provider', + event: EVENT_NAMES.SIGNATURE_APPROVED, + properties: { signature_type: MESSAGE_TYPE.ETH_SIGN_TYPED_DATA_V4 }, + referrer: { url: 'some.dapp' }, + }); + }); + + it(`should track a ${EVENT_NAMES.SIGNATURE_REJECTED} event if the user approves`, async () => { + const req = { + method: MESSAGE_TYPE.PERSONAL_SIGN, + origin: 'some.dapp', + }; + + const res = { + error: { code: 4001 }, + }; + const { next, executeMiddlewareStack } = getNext(); + handler(req, res, next); + await executeMiddlewareStack(); + expect(trackEvent).toHaveBeenCalledTimes(2); + expect(trackEvent.mock.calls[1][0]).toMatchObject({ + category: 'inpage_provider', + event: EVENT_NAMES.SIGNATURE_REJECTED, + properties: { signature_type: MESSAGE_TYPE.PERSONAL_SIGN }, + referrer: { url: 'some.dapp' }, + }); + }); + + it(`should track a ${EVENT_NAMES.PERMISSIONS_APPROVED} event if the user approves`, async () => { + const req = { + method: MESSAGE_TYPE.ETH_REQUEST_ACCOUNTS, + origin: 'some.dapp', + }; + + const res = {}; + const { next, executeMiddlewareStack } = getNext(); + handler(req, res, next); + await executeMiddlewareStack(); + expect(trackEvent).toHaveBeenCalledTimes(2); + expect(trackEvent.mock.calls[1][0]).toMatchObject({ + category: 'inpage_provider', + event: EVENT_NAMES.PERMISSIONS_APPROVED, + properties: { method: MESSAGE_TYPE.ETH_REQUEST_ACCOUNTS }, + referrer: { url: 'some.dapp' }, + }); + }); + + it(`should never track blocked methods such as ${MESSAGE_TYPE.GET_PROVIDER_STATE}`, () => { + const req = { + method: MESSAGE_TYPE.GET_PROVIDER_STATE, + origin: 'www.notadapp.com', + }; + + const res = { + error: null, + }; + const { next, executeMiddlewareStack } = getNext(); + handler(req, res, next); + expect(trackEvent).not.toHaveBeenCalled(); + executeMiddlewareStack(); + }); + + it(`should only track events when not rate limited`, async () => { + const req = { + method: 'eth_chainId', + origin: 'some.dapp', + }; + + const res = { + error: null, + }; + + let callCount = 0; + + while (callCount < 3) { + callCount += 1; + const { next, executeMiddlewareStack } = getNext(); + handler(req, res, next); + await executeMiddlewareStack(); + if (callCount !== 3) { + await waitForSeconds(0.6); + } + } + + expect(trackEvent).toHaveBeenCalledTimes(2); + expect(trackEvent.mock.calls[0][0].properties.method).toBe('eth_chainId'); + expect(trackEvent.mock.calls[1][0].properties.method).toBe('eth_chainId'); + }); + }); +}); diff --git a/app/scripts/lib/decrypt-message-manager.js b/app/scripts/lib/decrypt-message-manager.js index f90336dda..020a2b247 100644 --- a/app/scripts/lib/decrypt-message-manager.js +++ b/app/scripts/lib/decrypt-message-manager.js @@ -15,11 +15,11 @@ const hexRe = /^[0-9A-Fa-f]+$/gu; * Represents, and contains data about, an 'eth_decrypt' type decryption request. These are created when a * decryption for an eth_decrypt call is requested. * - * @typedef {Object} DecryptMessage + * @typedef {object} DecryptMessage * @property {number} id An id to track and identify the message object - * @property {Object} msgParams The parameters to pass to the decryptMessage method once the decryption request is + * @property {object} msgParams The parameters to pass to the decryptMessage method once the decryption request is * approved. - * @property {Object} msgParams.metamaskId Added to msgParams for tracking and identification within MetaMask. + * @property {object} msgParams.metamaskId Added to msgParams for tracking and identification within MetaMask. * @property {string} msgParams.data A hex string conversion of the raw buffer data of the decryption request * @property {number} time The epoch time at which the this message was created * @property {string} status Indicates whether the decryption request is 'unapproved', 'approved', 'decrypted' or 'rejected' @@ -56,7 +56,7 @@ export default class DecryptMessageManager extends EventEmitter { /** * A getter for the 'unapproved' DecryptMessages in this.messages * - * @returns {Object} An index of DecryptMessage ids to DecryptMessages, for all 'unapproved' DecryptMessages in + * @returns {object} An index of DecryptMessage ids to DecryptMessages, for all 'unapproved' DecryptMessages in * this.messages */ getUnapprovedMsgs() { @@ -73,8 +73,8 @@ export default class DecryptMessageManager extends EventEmitter { * the new DecryptMessage to this.messages, and to save the unapproved DecryptMessages from that list to * this.memStore. * - * @param {Object} msgParams - The params for the eth_decrypt call to be made after the message is approved. - * @param {Object} [req] - The original request object possibly containing the origin + * @param {object} msgParams - The params for the eth_decrypt call to be made after the message is approved. + * @param {object} [req] - The original request object possibly containing the origin * @returns {Promise} The raw decrypted message contents */ addUnapprovedMessageAsync(msgParams, req) { @@ -117,8 +117,8 @@ export default class DecryptMessageManager extends EventEmitter { * the new DecryptMessage to this.messages, and to save the unapproved DecryptMessages from that list to * this.memStore. * - * @param {Object} msgParams - The params for the eth_decryptMsg call to be made after the message is approved. - * @param {Object} [req] - The original request object possibly containing the origin + * @param {object} msgParams - The params for the eth_decryptMsg call to be made after the message is approved. + * @param {object} [req] - The original request object possibly containing the origin * @returns {number} The id of the newly created DecryptMessage. */ addUnapprovedMessage(msgParams, req) { @@ -175,8 +175,8 @@ export default class DecryptMessageManager extends EventEmitter { * Approves a DecryptMessage. Sets the message status via a call to this.setMsgStatusApproved, and returns a promise * with the message params modified for proper decryption. * - * @param {Object} msgParams - The msgParams to be used when eth_decryptMsg is called, plus data added by MetaMask. - * @param {Object} msgParams.metamaskId - Added to msgParams for tracking and identification within MetaMask. + * @param {object} msgParams - The msgParams to be used when eth_decryptMsg is called, plus data added by MetaMask. + * @param {object} msgParams.metamaskId - Added to msgParams for tracking and identification within MetaMask. * @returns {Promise} Promises the msgParams object with metamaskId removed. */ approveMessage(msgParams) { @@ -210,7 +210,7 @@ export default class DecryptMessageManager extends EventEmitter { /** * Removes the metamaskId property from passed msgParams and returns a promise which resolves the updated msgParams * - * @param {Object} msgParams - The msgParams to modify + * @param {object} msgParams - The msgParams to modify * @returns {Promise} Promises the msgParams with the metamaskId property removed */ prepMsgForDecryption(msgParams) { diff --git a/app/scripts/lib/encryption-public-key-manager.js b/app/scripts/lib/encryption-public-key-manager.js index c84d1cb9c..5f2b74993 100644 --- a/app/scripts/lib/encryption-public-key-manager.js +++ b/app/scripts/lib/encryption-public-key-manager.js @@ -11,11 +11,11 @@ import createId from '../../../shared/modules/random-id'; * Represents, and contains data about, an 'eth_getEncryptionPublicKey' type request. These are created when * an eth_getEncryptionPublicKey call is requested. * - * @typedef {Object} EncryptionPublicKey + * @typedef {object} EncryptionPublicKey * @property {number} id An id to track and identify the message object - * @property {Object} msgParams The parameters to pass to the encryptionPublicKey method once the request is + * @property {object} msgParams The parameters to pass to the encryptionPublicKey method once the request is * approved. - * @property {Object} msgParams.metamaskId Added to msgParams for tracking and identification within MetaMask. + * @property {object} msgParams.metamaskId Added to msgParams for tracking and identification within MetaMask. * @property {string} msgParams.data A hex string conversion of the raw buffer data of the request * @property {number} time The epoch time at which the this message was created * @property {string} status Indicates whether the request is 'unapproved', 'approved', 'received' or 'rejected' @@ -52,7 +52,7 @@ export default class EncryptionPublicKeyManager extends EventEmitter { /** * A getter for the 'unapproved' EncryptionPublicKeys in this.messages * - * @returns {Object} An index of EncryptionPublicKey ids to EncryptionPublicKeys, for all 'unapproved' EncryptionPublicKeys in + * @returns {object} An index of EncryptionPublicKey ids to EncryptionPublicKeys, for all 'unapproved' EncryptionPublicKeys in * this.messages */ getUnapprovedMsgs() { @@ -69,8 +69,8 @@ export default class EncryptionPublicKeyManager extends EventEmitter { * the new EncryptionPublicKey to this.messages, and to save the unapproved EncryptionPublicKeys from that list to * this.memStore. * - * @param {Object} address - The param for the eth_getEncryptionPublicKey call to be made after the message is approved. - * @param {Object} [req] - The original request object possibly containing the origin + * @param {object} address - The param for the eth_getEncryptionPublicKey call to be made after the message is approved. + * @param {object} [req] - The original request object possibly containing the origin * @returns {Promise} The raw public key contents */ addUnapprovedMessageAsync(address, req) { @@ -110,8 +110,8 @@ export default class EncryptionPublicKeyManager extends EventEmitter { * the new EncryptionPublicKey to this.messages, and to save the unapproved EncryptionPublicKeys from that list to * this.memStore. * - * @param {Object} address - The param for the eth_getEncryptionPublicKey call to be made after the message is approved. - * @param {Object} [req] - The original request object possibly containing the origin + * @param {object} address - The param for the eth_getEncryptionPublicKey call to be made after the message is approved. + * @param {object} [req] - The original request object possibly containing the origin * @returns {number} The id of the newly created EncryptionPublicKey. */ addUnapprovedMessage(address, req) { @@ -164,8 +164,8 @@ export default class EncryptionPublicKeyManager extends EventEmitter { * Approves a EncryptionPublicKey. Sets the message status via a call to this.setMsgStatusApproved, and returns a promise * with any the message params modified for proper providing. * - * @param {Object} msgParams - The msgParams to be used when eth_getEncryptionPublicKey is called, plus data added by MetaMask. - * @param {Object} msgParams.metamaskId - Added to msgParams for tracking and identification within MetaMask. + * @param {object} msgParams - The msgParams to be used when eth_getEncryptionPublicKey is called, plus data added by MetaMask. + * @param {object} msgParams.metamaskId - Added to msgParams for tracking and identification within MetaMask. * @returns {Promise} Promises the msgParams object with metamaskId removed. */ approveMessage(msgParams) { @@ -199,7 +199,7 @@ export default class EncryptionPublicKeyManager extends EventEmitter { /** * Removes the metamaskId property from passed msgParams and returns a promise which resolves the updated msgParams * - * @param {Object} msgParams - The msgParams to modify + * @param {object} msgParams - The msgParams to modify * @returns {Promise} Promises the msgParams with the metamaskId property removed */ prepMsgForEncryptionPublicKey(msgParams) { diff --git a/app/scripts/lib/getObjStructure.js b/app/scripts/lib/getObjStructure.js index 7e703ccd6..97a4bdd75 100644 --- a/app/scripts/lib/getObjStructure.js +++ b/app/scripts/lib/getObjStructure.js @@ -16,8 +16,8 @@ import { cloneDeep } from 'lodash'; * Creates an object that represents the structure of the given object. It replaces all values with the result of their * type. * - * @param {Object} obj - The object for which a 'structure' will be returned. Usually a plain object and not a class. - * @returns {Object} The "mapped" version of a deep clone of the passed object, with each non-object property value + * @param {object} obj - The object for which a 'structure' will be returned. Usually a plain object and not a class. + * @returns {object} The "mapped" version of a deep clone of the passed object, with each non-object property value * replaced with the javascript type of that value. */ export default function getObjStructure(obj) { @@ -31,9 +31,9 @@ export default function getObjStructure(obj) { * Modifies all the properties and deeply nested of a passed object. Iterates recursively over all nested objects and * their properties, and covers the entire depth of the object. At each property value which is not an object is modified. * - * @param {Object} target - The object to modify + * @param {object} target - The object to modify * @param {Function} visit - The modifier to apply to each non-object property value - * @returns {Object} The modified object + * @returns {object} The modified object */ function deepMap(target = {}, visit) { Object.entries(target).forEach(([key, value]) => { diff --git a/app/scripts/lib/local-store.js b/app/scripts/lib/local-store.js index 889e36d55..069853e12 100644 --- a/app/scripts/lib/local-store.js +++ b/app/scripts/lib/local-store.js @@ -34,7 +34,7 @@ export default class ExtensionStore { /** * Sets the key in local state * - * @param {Object} state - The state to set + * @param {object} state - The state to set * @returns {Promise} */ async set(state) { @@ -45,7 +45,7 @@ export default class ExtensionStore { * Returns all of the keys currently saved * * @private - * @returns {Object} the key-value map from local storage + * @returns {object} the key-value map from local storage */ _get() { const { local } = browser.storage; @@ -64,7 +64,7 @@ export default class ExtensionStore { /** * Sets the key in local state * - * @param {Object} obj - The key to set + * @param {object} obj - The key to set * @returns {Promise} * @private */ @@ -86,7 +86,7 @@ export default class ExtensionStore { /** * Returns whether or not the given object contains no keys * - * @param {Object} obj - The object to check + * @param {object} obj - The object to check * @returns {boolean} */ function isEmpty(obj) { diff --git a/app/scripts/lib/message-manager.js b/app/scripts/lib/message-manager.js index ad176ef9f..6f80bb75b 100644 --- a/app/scripts/lib/message-manager.js +++ b/app/scripts/lib/message-manager.js @@ -12,10 +12,10 @@ import { EVENT } from '../../../shared/constants/metametrics'; * an eth_sign call is requested. * * @see {@link https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign} - * @typedef {Object} Message + * @typedef {object} Message * @property {number} id An id to track and identify the message object - * @property {Object} msgParams The parameters to pass to the eth_sign method once the signature request is approved. - * @property {Object} msgParams.metamaskId Added to msgParams for tracking and identification within MetaMask. + * @property {object} msgParams The parameters to pass to the eth_sign method once the signature request is approved. + * @property {object} msgParams.metamaskId Added to msgParams for tracking and identification within MetaMask. * @property {string} msgParams.data A hex string conversion of the raw buffer data of the signature request * @property {number} time The epoch time at which the this message was created * @property {string} status Indicates whether the signature request is 'unapproved', 'approved', 'signed' or 'rejected' @@ -52,7 +52,7 @@ export default class MessageManager extends EventEmitter { /** * A getter for the 'unapproved' Messages in this.messages * - * @returns {Object} An index of Message ids to Messages, for all 'unapproved' Messages in this.messages + * @returns {object} An index of Message ids to Messages, for all 'unapproved' Messages in this.messages */ getUnapprovedMsgs() { return this.messages @@ -67,8 +67,8 @@ export default class MessageManager extends EventEmitter { * Creates a new Message with an 'unapproved' status using the passed msgParams. this.addMsg is called to add the * new Message to this.messages, and to save the unapproved Messages from that list to this.memStore. * - * @param {Object} msgParams - The params for the eth_sign call to be made after the message is approved. - * @param {Object} [req] - The original request object possibly containing the origin + * @param {object} msgParams - The params for the eth_sign call to be made after the message is approved. + * @param {object} [req] - The original request object possibly containing the origin * @returns {promise} after signature has been */ async addUnapprovedMessageAsync(msgParams, req) { @@ -106,8 +106,8 @@ export default class MessageManager extends EventEmitter { * Creates a new Message with an 'unapproved' status using the passed msgParams. this.addMsg is called to add the * new Message to this.messages, and to save the unapproved Messages from that list to this.memStore. * - * @param {Object} msgParams - The params for the eth_sign call to be made after the message is approved. - * @param {Object} [req] - The original request object where the origin may be specified + * @param {object} msgParams - The params for the eth_sign call to be made after the message is approved. + * @param {object} [req] - The original request object where the origin may be specified * @returns {number} The id of the newly created message. */ addUnapprovedMessage(msgParams, req) { @@ -158,8 +158,8 @@ export default class MessageManager extends EventEmitter { * Approves a Message. Sets the message status via a call to this.setMsgStatusApproved, and returns a promise with * any the message params modified for proper signing. * - * @param {Object} msgParams - The msgParams to be used when eth_sign is called, plus data added by MetaMask. - * @param {Object} msgParams.metamaskId - Added to msgParams for tracking and identification within MetaMask. + * @param {object} msgParams - The msgParams to be used when eth_sign is called, plus data added by MetaMask. + * @param {object} msgParams.metamaskId - Added to msgParams for tracking and identification within MetaMask. * @returns {Promise} Promises the msgParams object with metamaskId removed. */ approveMessage(msgParams) { @@ -193,7 +193,7 @@ export default class MessageManager extends EventEmitter { /** * Removes the metamaskId property from passed msgParams and returns a promise which resolves the updated msgParams * - * @param {Object} msgParams - The msgParams to modify + * @param {object} msgParams - The msgParams to modify * @returns {Promise} Promises the msgParams with the metamaskId property removed */ prepMsgForSigning(msgParams) { diff --git a/app/scripts/lib/migrator/index.js b/app/scripts/lib/migrator/index.js index c2b46b027..ca2abb8ea 100644 --- a/app/scripts/lib/migrator/index.js +++ b/app/scripts/lib/migrator/index.js @@ -1,13 +1,13 @@ import EventEmitter from 'events'; /** - * @typedef {Object} Migration + * @typedef {object} Migration * @property {number} version - The migration version * @property {Function} migrate - Returns a promise of the migrated data */ /** - * @typedef {Object} MigratorOptions + * @typedef {object} MigratorOptions * @property {Array} [migrations] - The list of migrations to apply * @property {number} [defaultVersion] - The version to use in the initial state */ @@ -82,7 +82,7 @@ export default class Migrator extends EventEmitter { /** * Returns the initial state for the migrator * - * @param {Object} [data] - The data for the initial state + * @param {object} [data] - The data for the initial state * @returns {{meta: {version: number}, data: any}} */ generateInitialState(data) { diff --git a/app/scripts/lib/network-store.js b/app/scripts/lib/network-store.js index ca5f4c843..75f7796a0 100644 --- a/app/scripts/lib/network-store.js +++ b/app/scripts/lib/network-store.js @@ -54,7 +54,7 @@ export default class ReadOnlyNetworkStore { /** * Set state * - * @param {Object} state - The state to set + * @param {object} state - The state to set * @returns {Promise} */ async set(state) { diff --git a/app/scripts/lib/personal-message-manager.js b/app/scripts/lib/personal-message-manager.js index 9058887db..00017bc37 100644 --- a/app/scripts/lib/personal-message-manager.js +++ b/app/scripts/lib/personal-message-manager.js @@ -16,11 +16,11 @@ const hexRe = /^[0-9A-Fa-f]+$/gu; * signature for an personal_sign call is requested. * * @see {@link https://web3js.readthedocs.io/en/1.0/web3-eth-personal.html#sign} - * @typedef {Object} PersonalMessage + * @typedef {object} PersonalMessage * @property {number} id An id to track and identify the message object - * @property {Object} msgParams The parameters to pass to the personal_sign method once the signature request is + * @property {object} msgParams The parameters to pass to the personal_sign method once the signature request is * approved. - * @property {Object} msgParams.metamaskId Added to msgParams for tracking and identification within MetaMask. + * @property {object} msgParams.metamaskId Added to msgParams for tracking and identification within MetaMask. * @property {string} msgParams.data A hex string conversion of the raw buffer data of the signature request * @property {number} time The epoch time at which the this message was created * @property {string} status Indicates whether the signature request is 'unapproved', 'approved', 'signed' or 'rejected' @@ -57,7 +57,7 @@ export default class PersonalMessageManager extends EventEmitter { /** * A getter for the 'unapproved' PersonalMessages in this.messages * - * @returns {Object} An index of PersonalMessage ids to PersonalMessages, for all 'unapproved' PersonalMessages in + * @returns {object} An index of PersonalMessage ids to PersonalMessages, for all 'unapproved' PersonalMessages in * this.messages */ getUnapprovedMsgs() { @@ -74,8 +74,8 @@ export default class PersonalMessageManager extends EventEmitter { * the new PersonalMessage to this.messages, and to save the unapproved PersonalMessages from that list to * this.memStore. * - * @param {Object} msgParams - The params for the eth_sign call to be made after the message is approved. - * @param {Object} [req] - The original request object possibly containing the origin + * @param {object} msgParams - The params for the eth_sign call to be made after the message is approved. + * @param {object} [req] - The original request object possibly containing the origin * @returns {promise} When the message has been signed or rejected */ addUnapprovedMessageAsync(msgParams, req) { @@ -120,8 +120,8 @@ export default class PersonalMessageManager extends EventEmitter { * the new PersonalMessage to this.messages, and to save the unapproved PersonalMessages from that list to * this.memStore. * - * @param {Object} msgParams - The params for the eth_sign call to be made after the message is approved. - * @param {Object} [req] - The original request object possibly containing the origin + * @param {object} msgParams - The params for the eth_sign call to be made after the message is approved. + * @param {object} [req] - The original request object possibly containing the origin * @returns {number} The id of the newly created PersonalMessage. */ addUnapprovedMessage(msgParams, req) { @@ -178,8 +178,8 @@ export default class PersonalMessageManager extends EventEmitter { * Approves a PersonalMessage. Sets the message status via a call to this.setMsgStatusApproved, and returns a promise * with any the message params modified for proper signing. * - * @param {Object} msgParams - The msgParams to be used when eth_sign is called, plus data added by MetaMask. - * @param {Object} msgParams.metamaskId - Added to msgParams for tracking and identification within MetaMask. + * @param {object} msgParams - The msgParams to be used when eth_sign is called, plus data added by MetaMask. + * @param {object} msgParams.metamaskId - Added to msgParams for tracking and identification within MetaMask. * @returns {Promise} Promises the msgParams object with metamaskId removed. */ approveMessage(msgParams) { @@ -213,7 +213,7 @@ export default class PersonalMessageManager extends EventEmitter { /** * Removes the metamaskId property from passed msgParams and returns a promise which resolves the updated msgParams * - * @param {Object} msgParams - The msgParams to modify + * @param {object} msgParams - The msgParams to modify * @returns {Promise} Promises the msgParams with the metamaskId property removed */ prepMsgForSigning(msgParams) { diff --git a/app/scripts/lib/rpc-method-middleware/handlers/add-ethereum-chain.js b/app/scripts/lib/rpc-method-middleware/handlers/add-ethereum-chain.js index 04d66a3ad..223743a92 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/add-ethereum-chain.js +++ b/app/scripts/lib/rpc-method-middleware/handlers/add-ethereum-chain.js @@ -1,7 +1,10 @@ import { ethErrors, errorCodes } from 'eth-rpc-errors'; import validUrl from 'valid-url'; import { omit } from 'lodash'; -import { MESSAGE_TYPE } from '../../../../../shared/constants/app'; +import { + MESSAGE_TYPE, + UNKNOWN_TICKER_SYMBOL, +} from '../../../../../shared/constants/app'; import { EVENT } from '../../../../../shared/constants/metametrics'; import { isPrefixedFormattedHexString, @@ -16,6 +19,7 @@ const addEthereumChain = { hookNames: { addCustomRpc: true, getCurrentChainId: true, + getCurrentRpcUrl: true, findCustomRpcBy: true, updateRpcTarget: true, requestUserApproval: true, @@ -32,6 +36,7 @@ async function addEthereumChainHandler( { addCustomRpc, getCurrentChainId, + getCurrentRpcUrl, findCustomRpcBy, updateRpcTarget, requestUserApproval, @@ -145,15 +150,21 @@ async function addEthereumChainHandler( const existingNetwork = findCustomRpcBy({ chainId: _chainId }); - if (existingNetwork) { + // if the request is to add a network that is already added and configured + // with the same RPC gateway we shouldn't try to add it again. + if (existingNetwork && existingNetwork.rpcUrl === firstValidRPCUrl) { // If the network already exists, the request is considered successful res.result = null; const currentChainId = getCurrentChainId(); - if (currentChainId === _chainId) { + const currentRpcUrl = getCurrentRpcUrl(); + + // If the current chainId and rpcUrl matches that of the incoming request + // We don't need to proceed further. + if (currentChainId === _chainId && currentRpcUrl === firstValidRPCUrl) { return end(); } - + // If this network is already added with but is not the currently selected network // Ask the user to switch the network try { await updateRpcTarget( @@ -236,15 +247,32 @@ async function addEthereumChainHandler( ); } } - const ticker = nativeCurrency?.symbol || 'ETH'; - if (typeof ticker !== 'string' || ticker.length < 2 || ticker.length > 6) { + const ticker = nativeCurrency?.symbol || UNKNOWN_TICKER_SYMBOL; + + if ( + ticker !== UNKNOWN_TICKER_SYMBOL && + (typeof ticker !== 'string' || ticker.length < 2 || ticker.length > 6) + ) { return end( ethErrors.rpc.invalidParams({ message: `Expected 2-6 character string 'nativeCurrency.symbol'. Received:\n${ticker}`, }), ); } + // if the chainId is the same as an existing network but the ticker is different we want to block this action + // as it is potentially malicious and confusing + if ( + existingNetwork && + existingNetwork.chainId === _chainId && + existingNetwork.ticker !== ticker + ) { + return end( + ethErrors.rpc.invalidParams({ + message: `nativeCurrency.symbol does not match currency symbol for a network the user already has added with the same chainId. Received:\n${ticker}`, + }), + ); + } try { await addCustomRpc( diff --git a/app/scripts/lib/rpc-method-middleware/handlers/get-provider-state.js b/app/scripts/lib/rpc-method-middleware/handlers/get-provider-state.js index afc09666a..70dbb7b16 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/get-provider-state.js +++ b/app/scripts/lib/rpc-method-middleware/handlers/get-provider-state.js @@ -16,14 +16,14 @@ const getProviderState = { export default getProviderState; /** - * @typedef {Object} ProviderStateHandlerResult + * @typedef {object} ProviderStateHandlerResult * @property {string} chainId - The current chain ID. * @property {boolean} isUnlocked - Whether the extension is unlocked or not. * @property {string} networkVersion - The current network ID. */ /** - * @typedef {Object} ProviderStateHandlerOptions + * @typedef {object} ProviderStateHandlerOptions * @property {() => ProviderStateHandlerResult} getProviderState - A function that * gets the current provider state. */ diff --git a/app/scripts/lib/rpc-method-middleware/handlers/log-web3-shim-usage.js b/app/scripts/lib/rpc-method-middleware/handlers/log-web3-shim-usage.js index c89feaf50..b829e16fa 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/log-web3-shim-usage.js +++ b/app/scripts/lib/rpc-method-middleware/handlers/log-web3-shim-usage.js @@ -20,7 +20,7 @@ const logWeb3ShimUsage = { export default logWeb3ShimUsage; /** - * @typedef {Object} LogWeb3ShimUsageOptions + * @typedef {object} LogWeb3ShimUsageOptions * @property {Function} sendMetrics - A function that registers a metrics event. * @property {Function} getWeb3ShimUsageState - A function that gets web3 shim * usage state for the given origin. diff --git a/app/scripts/lib/rpc-method-middleware/handlers/watch-asset.js b/app/scripts/lib/rpc-method-middleware/handlers/watch-asset.js index 6a9502670..6935ef96c 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/watch-asset.js +++ b/app/scripts/lib/rpc-method-middleware/handlers/watch-asset.js @@ -11,14 +11,14 @@ const watchAsset = { export default watchAsset; /** - * @typedef {Object} WatchAssetOptions + * @typedef {object} WatchAssetOptions * @property {Function} handleWatchAssetRequest - The wallet_watchAsset method implementation. */ /** - * @typedef {Object} WatchAssetParam + * @typedef {object} WatchAssetParam * @property {string} type - The type of the asset to watch. - * @property {Object} options - Watch options for the asset. + * @property {object} options - Watch options for the asset. */ /** diff --git a/app/scripts/lib/sentry-filter-events.ts b/app/scripts/lib/sentry-filter-events.ts new file mode 100644 index 000000000..050f0bcd2 --- /dev/null +++ b/app/scripts/lib/sentry-filter-events.ts @@ -0,0 +1,73 @@ +import { + Event as SentryEvent, + EventProcessor, + Hub, + Integration, +} from '@sentry/types'; +import { logger } from '@sentry/utils'; + +/** + * Filter events when MetaMetrics is disabled. + */ +export class FilterEvents implements Integration { + /** + * Property that holds the integration name. + */ + public static id = 'FilterEvents'; + + /** + * Another property that holds the integration name. + * + * I don't know why this exists, but the other Sentry integrations have it. + */ + public name: string = FilterEvents.id; + + /** + * A function that returns whether MetaMetrics is enabled. This should also + * return `false` if state has not yet been initialzed. + * + * @returns `true` if MetaMask's state has been initialized, and MetaMetrics + * is enabled, `false` otherwise. + */ + private getMetaMetricsEnabled: () => boolean; + + /** + * @param options - Constructor options. + * @param options.getMetaMetricsEnabled - A function that returns whether + * MetaMetrics is enabled. This should also return `false` if state has not + * yet been initialzed. + */ + constructor({ + getMetaMetricsEnabled, + }: { + getMetaMetricsEnabled: () => boolean; + }) { + this.getMetaMetricsEnabled = getMetaMetricsEnabled; + } + + /** + * Setup the integration. + * + * @param addGlobalEventProcessor - A function that allows adding a global + * event processor. + * @param getCurrentHub - A function that returns the current Sentry hub. + */ + public setupOnce( + addGlobalEventProcessor: (callback: EventProcessor) => void, + getCurrentHub: () => Hub, + ): void { + addGlobalEventProcessor((currentEvent: SentryEvent) => { + // Sentry integrations use the Sentry hub to get "this" references, for + // reasons I don't fully understand. + // eslint-disable-next-line consistent-this + const self = getCurrentHub().getIntegration(FilterEvents); + if (self) { + if (!self.getMetaMetricsEnabled()) { + logger.warn(`Event dropped due to MetaMetrics setting.`); + return null; + } + } + return currentEvent; + }); + } +} diff --git a/app/scripts/lib/setupSentry.js b/app/scripts/lib/setupSentry.js index 196389439..09d588454 100644 --- a/app/scripts/lib/setupSentry.js +++ b/app/scripts/lib/setupSentry.js @@ -2,6 +2,7 @@ import * as Sentry from '@sentry/browser'; import { Dedupe, ExtraErrorData } from '@sentry/integrations'; import { BuildType } from '../../../shared/constants/app'; +import { FilterEvents } from './sentry-filter-events'; import extractEthjsErrorMessage from './extractEthjsErrorMessage'; /* eslint-disable prefer-destructuring */ @@ -97,22 +98,51 @@ export default function setupSentry({ release, getState }) { sentryTarget = SENTRY_DSN_DEV; } + /** + * A function that returns whether MetaMetrics is enabled. This should also + * return `false` if state has not yet been initialzed. + * + * @returns `true` if MetaMask's state has been initialized, and MetaMetrics + * is enabled, `false` otherwise. + */ + function getMetaMetricsEnabled() { + if (getState) { + const appState = getState(); + if (!appState?.store?.metamask?.participateInMetaMetrics) { + return false; + } + } else { + return false; + } + return true; + } + Sentry.init({ dsn: sentryTarget, debug: METAMASK_DEBUG, environment, - integrations: [new Dedupe(), new ExtraErrorData()], + integrations: [ + new FilterEvents({ getMetaMetricsEnabled }), + new Dedupe(), + new ExtraErrorData(), + ], release, - beforeSend: (report) => { + beforeSend: (report) => rewriteReport(report), + beforeBreadcrumb(breadcrumb) { if (getState) { const appState = getState(); - if (!appState?.store?.metamask?.participateInMetaMetrics) { + if ( + Object.values(appState).length && + (!appState?.store?.metamask?.participateInMetaMetrics || + !appState?.store?.metamask?.completedOnboarding || + breadcrumb?.category === 'ui.input') + ) { return null; } } else { return null; } - return rewriteReport(report); + return breadcrumb; }, }); diff --git a/app/scripts/lib/typed-message-manager.js b/app/scripts/lib/typed-message-manager.js index 6b2c99719..8d5562c47 100644 --- a/app/scripts/lib/typed-message-manager.js +++ b/app/scripts/lib/typed-message-manager.js @@ -15,12 +15,12 @@ import { isValidHexAddress } from '../../../shared/modules/hexstring-utils'; * Represents, and contains data about, an 'eth_signTypedData' type signature request. These are created when a * signature for an eth_signTypedData call is requested. * - * @typedef {Object} TypedMessage + * @typedef {object} TypedMessage * @property {number} id An id to track and identify the message object - * @property {Object} msgParams The parameters to pass to the eth_signTypedData method once the signature request is + * @property {object} msgParams The parameters to pass to the eth_signTypedData method once the signature request is * approved. - * @property {Object} msgParams.metamaskId Added to msgParams for tracking and identification within MetaMask. - * @property {Object} msgParams.from The address that is making the signature request. + * @property {object} msgParams.metamaskId Added to msgParams for tracking and identification within MetaMask. + * @property {object} msgParams.from The address that is making the signature request. * @property {string} msgParams.data A hex string conversion of the raw buffer data of the signature request * @property {number} time The epoch time at which the this message was created * @property {string} status Indicates whether the signature request is 'unapproved', 'approved', 'signed', 'rejected', or 'errored' @@ -59,7 +59,7 @@ export default class TypedMessageManager extends EventEmitter { /** * A getter for the 'unapproved' TypedMessages in this.messages * - * @returns {Object} An index of TypedMessage ids to TypedMessages, for all 'unapproved' TypedMessages in + * @returns {object} An index of TypedMessage ids to TypedMessages, for all 'unapproved' TypedMessages in * this.messages */ getUnapprovedMsgs() { @@ -76,8 +76,8 @@ export default class TypedMessageManager extends EventEmitter { * the new TypedMessage to this.messages, and to save the unapproved TypedMessages from that list to * this.memStore. Before any of this is done, msgParams are validated * - * @param {Object} msgParams - The params for the eth_sign call to be made after the message is approved. - * @param {Object} [req] - The original request object possibly containing the origin + * @param {object} msgParams - The params for the eth_sign call to be made after the message is approved. + * @param {object} [req] - The original request object possibly containing the origin * @param version * @returns {promise} When the message has been signed or rejected */ @@ -116,8 +116,8 @@ export default class TypedMessageManager extends EventEmitter { * the new TypedMessage to this.messages, and to save the unapproved TypedMessages from that list to * this.memStore. Before any of this is done, msgParams are validated * - * @param {Object} msgParams - The params for the eth_sign call to be made after the message is approved. - * @param {Object} [req] - The original request object possibly containing the origin + * @param {object} msgParams - The params for the eth_sign call to be made after the message is approved. + * @param {object} [req] - The original request object possibly containing the origin * @param version * @returns {number} The id of the newly created TypedMessage. */ @@ -152,7 +152,7 @@ export default class TypedMessageManager extends EventEmitter { /** * Helper method for this.addUnapprovedMessage. Validates that the passed params have the required properties. * - * @param {Object} params - The params to validate + * @param {object} params - The params to validate */ validateParams(params) { assert.ok( @@ -249,8 +249,8 @@ export default class TypedMessageManager extends EventEmitter { * Approves a TypedMessage. Sets the message status via a call to this.setMsgStatusApproved, and returns a promise * with any the message params modified for proper signing. * - * @param {Object} msgParams - The msgParams to be used when eth_sign is called, plus data added by MetaMask. - * @param {Object} msgParams.metamaskId - Added to msgParams for tracking and identification within MetaMask. + * @param {object} msgParams - The msgParams to be used when eth_sign is called, plus data added by MetaMask. + * @param {object} msgParams.metamaskId - Added to msgParams for tracking and identification within MetaMask. * @returns {Promise} Promises the msgParams object with metamaskId removed. */ approveMessage(msgParams) { @@ -284,7 +284,7 @@ export default class TypedMessageManager extends EventEmitter { /** * Removes the metamaskId property from passed msgParams and returns a promise which resolves the updated msgParams * - * @param {Object} msgParams - The msgParams to modify + * @param {object} msgParams - The msgParams to modify * @returns {Promise} Promises the msgParams with the metamaskId property removed */ prepMsgForSigning(msgParams) { diff --git a/app/scripts/lib/util.js b/app/scripts/lib/util.js index b7fdf0521..edb1aca70 100644 --- a/app/scripts/lib/util.js +++ b/app/scripts/lib/util.js @@ -76,7 +76,7 @@ const getPlatform = () => { * Converts a hex string to a BN object * * @param {string} inputHex - A number represented as a hex string - * @returns {Object} A BN object + * @returns {object} A BN object */ function hexToBn(inputHex) { return new BN(stripHexPrefix(inputHex), 16); diff --git a/app/scripts/lockdown-more.js b/app/scripts/lockdown-more.js index a1f413eed..b2773d401 100644 --- a/app/scripts/lockdown-more.js +++ b/app/scripts/lockdown-more.js @@ -74,7 +74,7 @@ try { * We want to make globals non-writable, and we can't set the `writable` * property and accessor properties at the same time. * - * @param {Object} descriptor - The propertyName descriptor to check. + * @param {object} descriptor - The propertyName descriptor to check. * @returns {boolean} Whether the propertyName descriptor has any accessors. */ function hasAccessor(descriptor) { diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index d01d277e7..d7159d2f2 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -88,7 +88,10 @@ import { import { EVENT } from '../../shared/constants/metametrics'; import { hexToDecimal } from '../../ui/helpers/utils/conversions.util'; -import { getTokenValueParam } from '../../ui/helpers/utils/token-util'; +import { + getTokenIdParam, + getTokenValueParam, +} from '../../ui/helpers/utils/token-util'; import { isEqualCaseInsensitive } from '../../shared/modules/string-utils'; import { parseStandardTokenTransactionData } from '../../shared/modules/transaction.utils'; import { @@ -160,7 +163,7 @@ const PHISHING_SAFELIST = 'metamask-phishing-safelist'; export default class MetamaskController extends EventEmitter { /** - * @param {Object} opts + * @param {object} opts */ constructor(opts) { super(); @@ -859,7 +862,12 @@ export default class MetamaskController extends EventEmitter { } = txMeta.txParams; const { chainId } = txMeta; const transactionData = parseStandardTokenTransactionData(data); - const tokenAmountOrTokenId = getTokenValueParam(transactionData); + // Sometimes the tokenId value is parsed as "_value" param. Not seeing this often any more, but still occasionally: + // i.e. call approve() on BAYC contract - https://etherscan.io/token/0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d#writeContract, and tokenId shows up as _value, + // not sure why since it doesn't match the ERC721 ABI spec we use to parse these transactions - https://github.com/MetaMask/metamask-eth-abis/blob/d0474308a288f9252597b7c93a3a8deaad19e1b2/src/abis/abiERC721.ts#L62. + const transactionDataTokenId = + getTokenIdParam(transactionData) ?? + getTokenValueParam(transactionData); const { allCollectibles } = this.collectiblesController.state; // check if its a known collectible @@ -868,7 +876,7 @@ export default class MetamaskController extends EventEmitter { ].find( ({ address, tokenId }) => isEqualCaseInsensitive(address, contractAddress) && - tokenId === tokenAmountOrTokenId, + tokenId === transactionDataTokenId, ); // if it is we check and update ownership status. @@ -1410,9 +1418,9 @@ export default class MetamaskController extends EventEmitter { /** * Gets network state relevant for external providers. * - * @param {Object} [memState] - The MetaMask memState. If not provided, + * @param {object} [memState] - The MetaMask memState. If not provided, * this function will retrieve the most recent state. - * @returns {Object} An object with relevant network state properties. + * @returns {object} An object with relevant network state properties. */ getProviderNetworkState(memState) { const { network } = memState || this.getState(); @@ -1429,7 +1437,7 @@ export default class MetamaskController extends EventEmitter { /** * The metamask-state of the various controllers, made available to the UI * - * @returns {Object} status + * @returns {object} status */ getState() { const { vault } = this.keyringController.store.getState(); @@ -1446,7 +1454,7 @@ export default class MetamaskController extends EventEmitter { * These functions are the interface for the UI. * The API object can be transmitted over a stream via JSON-RPC. * - * @returns {Object} Object containing API functions. + * @returns {object} Object containing API functions. */ getApi() { const { @@ -2005,7 +2013,7 @@ export default class MetamaskController extends EventEmitter { * For example, a mnemonic phrase can generate many accounts, and is a keyring. * * @param {string} password - * @returns {Object} vault + * @returns {object} vault */ async createNewVaultAndKeychain(password) { const releaseLock = await this.createVaultMutex.acquire(); @@ -2178,7 +2186,7 @@ export default class MetamaskController extends EventEmitter { * Collects all the information that we want to share * with the mobile client for syncing purposes * - * @returns {Promise} Parts of the state that we want to syncx + * @returns {Promise} Parts of the state that we want to syncx */ async fetchInfoToSync() { // Preferences @@ -2754,8 +2762,8 @@ export default class MetamaskController extends EventEmitter { * this wrapper needs to exist so we can provide a reference to * "newUnapprovedTransaction" before "txController" is instantiated * - * @param {Object} txParams - The transaction parameters. - * @param {Object} [req] - The original request, containing the origin. + * @param {object} txParams - The transaction parameters. + * @param {object} [req] - The original request, containing the origin. */ async newUnapprovedTransaction(txParams, req) { return await this.txController.newUnapprovedTransaction(txParams, req); @@ -2769,8 +2777,8 @@ export default class MetamaskController extends EventEmitter { * path, since this data can be a transaction, or can leak private key * information. * - * @param {Object} msgParams - The params passed to eth_sign. - * @param {Object} [req] - The original request, containing the origin. + * @param {object} msgParams - The params passed to eth_sign. + * @param {object} [req] - The original request, containing the origin. */ async newUnsignedMessage(msgParams, req) { const data = normalizeMsgData(msgParams.data); @@ -2819,8 +2827,8 @@ export default class MetamaskController extends EventEmitter { /** * Signifies user intent to complete an eth_sign method. * - * @param {Object} msgParams - The params passed to eth_call. - * @returns {Promise} Full state update. + * @param {object} msgParams - The params passed to eth_call. + * @returns {Promise} Full state update. */ async signMessage(msgParams) { log.info('MetaMaskController - signMessage'); @@ -2861,8 +2869,8 @@ export default class MetamaskController extends EventEmitter { * * We currently define our eth_sign and personal_sign mostly for legacy Dapps. * - * @param {Object} msgParams - The params of the message to sign & return to the Dapp. - * @param {Object} [req] - The original request, containing the origin. + * @param {object} msgParams - The params of the message to sign & return to the Dapp. + * @param {object} [req] - The original request, containing the origin. */ async newUnsignedPersonalMessage(msgParams, req) { const promise = this.personalMessageManager.addUnapprovedMessageAsync( @@ -2878,8 +2886,8 @@ export default class MetamaskController extends EventEmitter { * Signifies a user's approval to sign a personal_sign message in queue. * Triggers signing, and the callback function from newUnsignedPersonalMessage. * - * @param {Object} msgParams - The params of the message to sign & return to the Dapp. - * @returns {Promise} A full state update. + * @param {object} msgParams - The params of the message to sign & return to the Dapp. + * @returns {Promise} A full state update. */ async signPersonalMessage(msgParams) { log.info('MetaMaskController - signPersonalMessage'); @@ -2920,8 +2928,8 @@ export default class MetamaskController extends EventEmitter { /** * Called when a dapp uses the eth_decrypt method. * - * @param {Object} msgParams - The params of the message to sign & return to the Dapp. - * @param {Object} req - (optional) the original request, containing the origin + * @param {object} msgParams - The params of the message to sign & return to the Dapp. + * @param {object} req - (optional) the original request, containing the origin * Passed back to the requesting Dapp. */ async newRequestDecryptMessage(msgParams, req) { @@ -2937,8 +2945,8 @@ export default class MetamaskController extends EventEmitter { /** * Only decrypt message and don't touch transaction state * - * @param {Object} msgParams - The params of the message to decrypt. - * @returns {Promise} A full state update. + * @param {object} msgParams - The params of the message to decrypt. + * @returns {Promise} A full state update. */ async decryptMessageInline(msgParams) { log.info('MetaMaskController - decryptMessageInline'); @@ -2963,8 +2971,8 @@ export default class MetamaskController extends EventEmitter { * Signifies a user's approval to decrypt a message in queue. * Triggers decrypt, and the callback function from newUnsignedDecryptMessage. * - * @param {Object} msgParams - The params of the message to decrypt & return to the Dapp. - * @returns {Promise} A full state update. + * @param {object} msgParams - The params of the message to decrypt & return to the Dapp. + * @returns {Promise} A full state update. */ async decryptMessage(msgParams) { log.info('MetaMaskController - decryptMessage'); @@ -3009,8 +3017,8 @@ export default class MetamaskController extends EventEmitter { /** * Called when a dapp uses the eth_getEncryptionPublicKey method. * - * @param {Object} msgParams - The params of the message to sign & return to the Dapp. - * @param {Object} req - (optional) the original request, containing the origin + * @param {object} msgParams - The params of the message to sign & return to the Dapp. + * @param {object} req - (optional) the original request, containing the origin * Passed back to the requesting Dapp. */ async newRequestEncryptionPublicKey(msgParams, req) { @@ -3064,8 +3072,8 @@ export default class MetamaskController extends EventEmitter { * Signifies a user's approval to receiving encryption public key in queue. * Triggers receiving, and the callback function from newUnsignedEncryptionPublicKey. * - * @param {Object} msgParams - The params of the message to receive & return to the Dapp. - * @returns {Promise} A full state update. + * @param {object} msgParams - The params of the message to receive & return to the Dapp. + * @returns {Promise} A full state update. */ async encryptionPublicKey(msgParams) { log.info('MetaMaskController - encryptionPublicKey'); @@ -3111,8 +3119,8 @@ export default class MetamaskController extends EventEmitter { /** * Called when a dapp uses the eth_signTypedData method, per EIP 712. * - * @param {Object} msgParams - The params passed to eth_signTypedData. - * @param {Object} [req] - The original request, containing the origin. + * @param {object} msgParams - The params passed to eth_signTypedData. + * @param {object} [req] - The original request, containing the origin. * @param version */ newUnsignedTypedMessage(msgParams, req, version) { @@ -3130,8 +3138,8 @@ export default class MetamaskController extends EventEmitter { * The method for a user approving a call to eth_signTypedData, per EIP 712. * Triggers the callback in newUnsignedTypedMessage. * - * @param {Object} msgParams - The params passed to eth_signTypedData. - * @returns {Object} Full state update. + * @param {object} msgParams - The params passed to eth_signTypedData. + * @returns {object} Full state update. */ async signTypedMessage(msgParams) { log.info('MetaMaskController - eth_signTypedData'); @@ -3196,7 +3204,7 @@ export default class MetamaskController extends EventEmitter { * ).CustomGasSettings} [customGasSettings] - overrides to use for gas params * instead of allowing this method to generate them * @param newTxMetaProps - * @returns {Object} MetaMask state + * @returns {object} MetaMask state */ async createCancelTransaction( originalTxId, @@ -3223,7 +3231,7 @@ export default class MetamaskController extends EventEmitter { * ).CustomGasSettings} [customGasSettings] - overrides to use for gas params * instead of allowing this method to generate them * @param newTxMetaProps - * @returns {Object} MetaMask state + * @returns {object} MetaMask state */ async createSpeedUpTransaction( originalTxId, @@ -3282,14 +3290,14 @@ export default class MetamaskController extends EventEmitter { * A runtime.MessageSender object, as provided by the browser: * * @see https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/MessageSender - * @typedef {Object} MessageSender + * @typedef {object} MessageSender * @property {string} - The URL of the page or frame hosting the script that sent the message. */ /** * A Snap sender object. * - * @typedef {Object} SnapSender + * @typedef {object} SnapSender * @property {string} snapId - The ID of the snap. */ @@ -3519,7 +3527,7 @@ export default class MetamaskController extends EventEmitter { /** * A method for creating a provider that is safely restricted for the requesting subject. * - * @param {Object} options - Provider engine options + * @param {object} options - Provider engine options * @param {string} options.origin - The origin of the sender * @param {MessageSender | SnapSender} options.sender - The sender object. * @param {string} options.subjectType - The type of the sender subject. @@ -3642,6 +3650,9 @@ export default class MetamaskController extends EventEmitter { getCurrentChainId: this.networkController.getCurrentChainId.bind( this.networkController, ), + getCurrentRpcUrl: this.networkController.getCurrentRpcUrl.bind( + this.networkController, + ), setProviderType: this.networkController.setProviderType.bind( this.networkController, ), @@ -3740,8 +3751,8 @@ export default class MetamaskController extends EventEmitter { * can be deleted later. * * @param {string} origin - The connection's origin string. - * @param {Object} options - Data associated with the connection - * @param {Object} options.engine - The connection's JSON Rpc Engine + * @param {object} options - Data associated with the connection + * @param {object} options.engine - The connection's JSON Rpc Engine * @returns {string} The connection's id (so that it can be deleted later) */ addConnection(origin, { engine }) { @@ -3856,7 +3867,7 @@ export default class MetamaskController extends EventEmitter { /** * Handle a KeyringController update * - * @param {Object} state - the KC state + * @param {object} state - the KC state * @returns {Promise} * @private */ @@ -4042,7 +4053,7 @@ export default class MetamaskController extends EventEmitter { * @param {string} chainId - The chainId of the selected network. * @param {string} ticker - The ticker symbol of the selected network. * @param {string} [nickname] - Nickname of the selected network. - * @param {Object} [rpcPrefs] - RPC preferences. + * @param {object} [rpcPrefs] - RPC preferences. * @param {string} [rpcPrefs.blockExplorerUrl] - URL of block explorer for the chain. * @returns {Promise} The RPC Target URL confirmed. */ @@ -4132,8 +4143,8 @@ export default class MetamaskController extends EventEmitter { * Returns the first RPC info object that matches at least one field of the * provided search criteria. Returns null if no match is found * - * @param {Object} rpcInfo - The RPC endpoint properties and values to check. - * @returns {Object} rpcInfo found in the frequentRpcList + * @param {object} rpcInfo - The RPC endpoint properties and values to check. + * @returns {object} rpcInfo found in the frequentRpcList */ findCustomRpcBy(rpcInfo) { const frequentRpcListDetail = this.preferencesController.getFrequentRpcListDetail(); @@ -4178,7 +4189,7 @@ export default class MetamaskController extends EventEmitter { /** * A method for initializing storage the first time. * - * @param {Object} initState - The default state to initialize with. + * @param {object} initState - The default state to initialize with. * @private */ recordFirstTimeInfo(initState) { diff --git a/app/scripts/migrations/048.js b/app/scripts/migrations/048.js index e46d2f833..e8a94edd6 100644 --- a/app/scripts/migrations/048.js +++ b/app/scripts/migrations/048.js @@ -198,7 +198,7 @@ function updateChainIds(networkEntries, chainId) { * * @param localhostTokens * @param rpcTokens - * @returns {Array} + * @returns {Array} */ function mergeTokenArrays(localhostTokens, rpcTokens) { const localhostTokensMap = tokenArrayToMap(localhostTokens); diff --git a/app/scripts/migrations/073.js b/app/scripts/migrations/073.js new file mode 100644 index 000000000..85c4927fa --- /dev/null +++ b/app/scripts/migrations/073.js @@ -0,0 +1,30 @@ +import { cloneDeep } from 'lodash'; + +const version = 73; + +/** + * Should empty the `knownMethodData` object in PreferencesController + */ +export default { + version, + async migrate(originalVersionedData) { + const versionedData = cloneDeep(originalVersionedData); + versionedData.meta.version = version; + const state = versionedData.data; + const newState = transformState(state); + versionedData.data = newState; + return versionedData; + }, +}; + +function transformState(state) { + const PreferencesController = state?.PreferencesController || {}; + + return { + ...state, + PreferencesController: { + ...PreferencesController, + knownMethodData: {}, + }, + }; +} diff --git a/app/scripts/migrations/073.test.js b/app/scripts/migrations/073.test.js new file mode 100644 index 000000000..2b6214f62 --- /dev/null +++ b/app/scripts/migrations/073.test.js @@ -0,0 +1,427 @@ +import migration73 from './073'; + +describe('migration #73', () => { + it('should update the version metadata', async () => { + const oldStorage = { + meta: { + version: 72, + }, + data: {}, + }; + + const newStorage = await migration73.migrate(oldStorage); + expect(newStorage.meta).toStrictEqual({ + version: 73, + }); + }); + + it('should empty knownMethodData object in PreferencesController', async () => { + const oldStorage = { + meta: { + version: 72, + }, + data: { + PreferencesController: { + knownMethodData: { + '0x095ea7b3': { + name: 'Approve', + params: [ + { + type: 'address', + }, + { + type: 'uint256', + }, + ], + }, + '0x1249c58b': { + name: 'Mint', + params: [], + }, + '0x1688f0b9': { + name: 'Create Proxy With Nonce', + params: [ + { + type: 'address', + }, + { + type: 'bytes', + }, + { + type: 'uint256', + }, + ], + }, + '0x18cbafe5': { + name: 'Swap Exact Tokens For E T H', + params: [ + { + type: 'uint256', + }, + { + type: 'uint256', + }, + { + type: 'address[]', + }, + { + type: 'address', + }, + { + type: 'uint256', + }, + ], + }, + '0x23b872dd': { + name: 'Transfer From', + params: [ + { + type: 'address', + }, + { + type: 'address', + }, + { + type: 'uint256', + }, + ], + }, + '0x2e1a7d4d': { + name: 'Withdraw', + params: [ + { + type: 'uint256', + }, + ], + }, + '0x2e7ba6ef': { + name: 'Claim', + params: [ + { + type: 'uint256', + }, + { + type: 'address', + }, + { + type: 'uint256', + }, + { + type: 'bytes32[]', + }, + ], + }, + '0x2eb2c2d6': { + name: 'Safe Batch Transfer From', + params: [ + { + type: 'address', + }, + { + type: 'address', + }, + { + type: 'uint256[]', + }, + { + type: 'uint256[]', + }, + { + type: 'bytes', + }, + ], + }, + '0x3671f8cf': {}, + '0x41441d3b': { + name: 'Enter Staking', + params: [ + { + type: 'uint256', + }, + ], + }, + '0x441a3e70': { + name: 'Withdraw', + params: [ + { + type: 'uint256', + }, + { + type: 'uint256', + }, + ], + }, + '0x6f652e1a': { + name: 'Create Order', + params: [ + { + type: 'address', + }, + { + type: 'uint256', + }, + { + type: 'uint256', + }, + { + type: 'uint256', + }, + ], + }, + '0x8dbdbe6d': { + name: 'Deposit', + params: [ + { + type: 'uint256', + }, + { + type: 'uint256', + }, + { + type: 'address', + }, + ], + }, + '0x8ed955b9': { + name: 'Harvest All', + params: [], + }, + '0xa22cb465': { + name: 'Set Approval For All', + params: [ + { + type: 'address', + }, + { + type: 'bool', + }, + ], + }, + '0xa9059cbb': { + name: 'Transfer', + params: [ + { + type: 'address', + }, + { + type: 'uint256', + }, + ], + }, + '0xab834bab': { + name: 'Atomic Match_', + params: [ + { + type: 'address[14]', + }, + { + type: 'uint256[18]', + }, + { + type: 'uint8[8]', + }, + { + type: 'bytes', + }, + { + type: 'bytes', + }, + { + type: 'bytes', + }, + { + type: 'bytes', + }, + { + type: 'bytes', + }, + { + type: 'bytes', + }, + { + type: 'uint8[2]', + }, + { + type: 'bytes32[5]', + }, + ], + }, + '0xd0e30db0': { + name: 'Deposit', + params: [], + }, + '0xddd81f82': { + name: 'Register Proxy', + params: [], + }, + '0xded9382a': { + name: 'Remove Liquidity E T H With Permit', + params: [ + { + type: 'address', + }, + { + type: 'uint256', + }, + { + type: 'uint256', + }, + { + type: 'uint256', + }, + { + type: 'address', + }, + { + type: 'uint256', + }, + { + type: 'bool', + }, + { + type: 'uint8', + }, + { + type: 'bytes32', + }, + { + type: 'bytes32', + }, + ], + }, + '0xe2bbb158': { + name: 'Deposit', + params: [ + { + type: 'uint256', + }, + { + type: 'uint256', + }, + ], + }, + '0xf305d719': { + name: 'Add Liquidity E T H', + params: [ + { + type: 'address', + }, + { + type: 'uint256', + }, + { + type: 'uint256', + }, + { + type: 'uint256', + }, + { + type: 'address', + }, + { + type: 'uint256', + }, + ], + }, + }, + }, + }, + }; + + const newStorage = await migration73.migrate(oldStorage); + expect(newStorage).toStrictEqual({ + meta: { + version: 73, + }, + data: { + PreferencesController: { + knownMethodData: {}, + }, + }, + }); + }); + + it('should preserve other PreferencesController state', async () => { + const oldStorage = { + meta: { + version: 72, + }, + data: { + PreferencesController: { + currentLocale: 'en', + dismissSeedBackUpReminder: false, + ipfsGateway: 'dweb.link', + knownMethodData: { + '0xd0e30db0': { + name: 'Deposit', + params: [], + }, + '0xddd81f82': { + name: 'Register Proxy', + params: [], + }, + }, + openSeaEnabled: false, + useTokenDetection: false, + }, + }, + }; + + const newStorage = await migration73.migrate(oldStorage); + expect(newStorage).toStrictEqual({ + meta: { + version: 73, + }, + data: { + PreferencesController: { + currentLocale: 'en', + dismissSeedBackUpReminder: false, + ipfsGateway: 'dweb.link', + knownMethodData: {}, + openSeaEnabled: false, + useTokenDetection: false, + }, + }, + }); + }); + + it('should not change state in controllers other than PreferencesController', async () => { + const oldStorage = { + meta: { + version: 71, + }, + data: { + PreferencesController: { + knownMethodData: { + '0xd0e30db0': { + name: 'Deposit', + params: [], + }, + '0xddd81f82': { + name: 'Register Proxy', + params: [], + }, + }, + }, + data: { + FooController: { a: 'b' }, + }, + }, + }; + + const newStorage = await migration73.migrate(oldStorage); + expect(newStorage).toStrictEqual({ + meta: { + version: 73, + }, + data: { + PreferencesController: { + knownMethodData: {}, + }, + data: { + FooController: { a: 'b' }, + }, + }, + }); + }); +}); diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js index b2a52040d..f8a6db814 100644 --- a/app/scripts/migrations/index.js +++ b/app/scripts/migrations/index.js @@ -76,6 +76,7 @@ import m069 from './069'; import m070 from './070'; import m071 from './071'; import m072 from './072'; +import m073 from './073'; const migrations = [ m002, @@ -149,6 +150,7 @@ const migrations = [ m070, m071, m072, + m073, ]; export default migrations; diff --git a/app/scripts/sentry-install.js b/app/scripts/sentry-install.js index d959997e0..1f0b87bd5 100644 --- a/app/scripts/sentry-install.js +++ b/app/scripts/sentry-install.js @@ -1,7 +1,10 @@ import setupSentry from './lib/setupSentry'; +// The root compartment will populate this with hooks +global.sentryHooks = {}; + // setup sentry error reporting global.sentry = setupSentry({ release: process.env.METAMASK_VERSION, - getState: () => global.getSentryState?.() || {}, + getState: () => global.sentryHooks?.getSentryState?.() || {}, }); diff --git a/development/build/manifest.js b/development/build/manifest.js index fb6a4092b..58817372e 100644 --- a/development/build/manifest.js +++ b/development/build/manifest.js @@ -132,7 +132,7 @@ async function writeJson(obj, file) { * * @param {BuildType} buildType - The build type. * @param {string} platform - The platform (i.e. the browser). - * @returns {Object} The build modificantions for the given build type and platform. + * @returns {object} The build modificantions for the given build type and platform. */ async function getBuildModifications(buildType, platform) { if (!Object.values(BuildType).includes(buildType)) { diff --git a/development/build/utils.js b/development/build/utils.js index bd427d6bb..9ca4f5c17 100644 --- a/development/build/utils.js +++ b/development/build/utils.js @@ -10,7 +10,7 @@ const { BuildType } = require('../lib/build-type'); * * @param {string[]} platforms - A list of browsers to generate versions for. * @param {string} version - The current version. - * @returns {Object} An object with the browser as the key and the browser-specific version object + * @returns {object} An object with the browser as the key and the browser-specific version object * as the value. For example, the version `9.6.0-beta.1` would return the object * `{ firefox: { version: '9.6.0.beta1' }, chrome: { version: '9.6.0.1', version_name: '9.6.0-beta.1' } }`. */ diff --git a/development/lib/retry.js b/development/lib/retry.js index 225a11525..204795142 100644 --- a/development/lib/retry.js +++ b/development/lib/retry.js @@ -3,7 +3,7 @@ * of retries is exceeded, whichever comes first (with an optional delay in * between retries). * - * @param {Object} args - A set of arguments and options. + * @param {object} args - A set of arguments and options. * @param {number} args.retries - The maximum number of times to re-run the * function on failure. * @param {number} args.delay - The amount of time (in milliseconds) to wait in diff --git a/jest.config.js b/jest.config.js index 38a48471f..ad12bb85b 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,6 +1,7 @@ module.exports = { collectCoverageFrom: [ '/app/scripts/controllers/permissions/**/*.js', + '/app/scripts/lib/createRPCMethodTrackingMiddleware.js', '/shared/**/*.js', '/ui/**/*.js', ], @@ -20,6 +21,12 @@ module.exports = { lines: 100, statements: 100, }, + './app/scripts/lib/createRPCMethodTrackingMiddleware.js': { + branches: 95.65, + functions: 100, + lines: 100, + statements: 100, + }, }, // TODO: enable resetMocks // resetMocks: true, @@ -34,6 +41,7 @@ module.exports = { '/app/scripts/platforms/*.test.js', 'app/scripts/controllers/network/**/*.test.js', '/app/scripts/controllers/permissions/**/*.test.js', + '/app/scripts/lib/createRPCMethodTrackingMiddleware.test.js', ], testTimeout: 2500, transform: { diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 7b6c8c22c..2ed8c9610 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -4010,9 +4010,9 @@ }, "packages": { "@sentry/browser>@sentry/core": true, - "@sentry/browser>@sentry/types": true, - "@sentry/browser>@sentry/utils": true, - "@sentry/browser>tslib": true + "@sentry/types": true, + "@sentry/utils": true, + "@sentry/utils>tslib": true } }, "@sentry/browser>@sentry/core": { @@ -4023,9 +4023,9 @@ "packages": { "@sentry/browser>@sentry/core>@sentry/hub": true, "@sentry/browser>@sentry/core>@sentry/minimal": true, - "@sentry/browser>@sentry/types": true, - "@sentry/browser>@sentry/utils": true, - "@sentry/browser>tslib": true + "@sentry/types": true, + "@sentry/utils": true, + "@sentry/utils>tslib": true } }, "@sentry/browser>@sentry/core>@sentry/hub": { @@ -4034,18 +4034,32 @@ "setInterval": true }, "packages": { - "@sentry/browser>@sentry/types": true, - "@sentry/browser>@sentry/utils": true, - "@sentry/browser>tslib": true + "@sentry/types": true, + "@sentry/utils": true, + "@sentry/utils>tslib": true } }, "@sentry/browser>@sentry/core>@sentry/minimal": { "packages": { "@sentry/browser>@sentry/core>@sentry/hub": true, - "@sentry/browser>tslib": true + "@sentry/utils>tslib": true } }, - "@sentry/browser>@sentry/utils": { + "@sentry/integrations": { + "globals": { + "clearTimeout": true, + "console.error": true, + "console.log": true, + "setTimeout": true + }, + "packages": { + "@sentry/types": true, + "@sentry/utils": true, + "@sentry/utils>tslib": true, + "localforage": true + } + }, + "@sentry/utils": { "globals": { "CustomEvent": true, "DOMError": true, @@ -4063,29 +4077,15 @@ "setTimeout": true }, "packages": { - "@sentry/browser>tslib": true, + "@sentry/utils>tslib": true, "browserify>process": true } }, - "@sentry/browser>tslib": { + "@sentry/utils>tslib": { "globals": { "define": true } }, - "@sentry/integrations": { - "globals": { - "clearTimeout": true, - "console.error": true, - "console.log": true, - "setTimeout": true - }, - "packages": { - "@sentry/browser>@sentry/types": true, - "@sentry/browser>@sentry/utils": true, - "@sentry/browser>tslib": true, - "localforage": true - } - }, "@storybook/api>regenerator-runtime": { "globals": { "regeneratorRuntime": "write" @@ -5187,7 +5187,6 @@ "addEventListener": true, "browser": true, "clearInterval": true, - "console.warn": true, "fetch": true, "open": true, "setInterval": true, @@ -5216,40 +5215,31 @@ }, "eth-lattice-keyring>gridplus-sdk": { "globals": { - "console.warn": true, + "ActiveXObject": true, + "AggregateError": true, + "Buffer": true, + "DO_NOT_EXPORT_CRC": true, + "FinalizationRegistry": true, + "HTMLElement": true, + "TextEncoder": true, + "URL": true, + "URLSearchParams": true, + "WeakRef": true, + "XMLHttpRequest": true, + "btoa": true, + "clearTimeout": true, + "console": true, + "crypto": true, + "define": true, + "document": true, + "intToBuffer": true, + "location": true, + "msCrypto": true, "setTimeout": true }, "packages": { - "3box>ethers>elliptic": true, - "@ethereumjs/common": true, - "@ethereumjs/common>crc-32": true, - "@ethereumjs/tx": true, - "bn.js": true, "browserify>buffer": true, - "eth-lattice-keyring>gridplus-sdk>bech32": true, - "eth-lattice-keyring>gridplus-sdk>bignumber.js": true, - "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, - "ethereumjs-wallet>aes-js": true, - "ethereumjs-wallet>bs58check": true, - "ethers>@ethersproject/keccak256>js-sha3": true, - "ethers>@ethersproject/sha2>hash.js": true, - "lodash": true, - "pubnub>superagent": true - } - }, - "eth-lattice-keyring>gridplus-sdk>bignumber.js": { - "globals": { - "crypto": true, - "define": true - } - }, - "eth-lattice-keyring>gridplus-sdk>bitwise": { - "packages": { - "browserify>buffer": true + "browserify>process": true } }, "eth-lattice-keyring>gridplus-sdk>borc": { @@ -5269,43 +5259,6 @@ "define": true } }, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": { - "globals": { - "intToBuffer": true - }, - "packages": { - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>bn.js": true, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>buffer": true, - "ethers>@ethersproject/keccak256>js-sha3": true - } - }, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>buffer": { - "globals": { - "console": true - }, - "packages": { - "base64-js": true, - "browserify>buffer>ieee754": true - } - }, - "eth-lattice-keyring>gridplus-sdk>rlp": { - "globals": { - "TextEncoder": true - } - }, - "eth-lattice-keyring>gridplus-sdk>secp256k1": { - "packages": { - "3box>ethers>elliptic": true - } - }, "eth-lattice-keyring>rlp": { "globals": { "TextEncoder": true @@ -6499,21 +6452,6 @@ "browserify>buffer": true } }, - "pubnub>superagent": { - "globals": { - "ActiveXObject": true, - "XMLHttpRequest": true, - "btoa": true, - "clearTimeout": true, - "console.error": true, - "console.trace": true, - "console.warn": true, - "setTimeout": true - }, - "packages": { - "pubnub>superagent>component-emitter": true - } - }, "pump": { "packages": { "browserify>browser-resolve": true, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index 7b6c8c22c..2ed8c9610 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -4010,9 +4010,9 @@ }, "packages": { "@sentry/browser>@sentry/core": true, - "@sentry/browser>@sentry/types": true, - "@sentry/browser>@sentry/utils": true, - "@sentry/browser>tslib": true + "@sentry/types": true, + "@sentry/utils": true, + "@sentry/utils>tslib": true } }, "@sentry/browser>@sentry/core": { @@ -4023,9 +4023,9 @@ "packages": { "@sentry/browser>@sentry/core>@sentry/hub": true, "@sentry/browser>@sentry/core>@sentry/minimal": true, - "@sentry/browser>@sentry/types": true, - "@sentry/browser>@sentry/utils": true, - "@sentry/browser>tslib": true + "@sentry/types": true, + "@sentry/utils": true, + "@sentry/utils>tslib": true } }, "@sentry/browser>@sentry/core>@sentry/hub": { @@ -4034,18 +4034,32 @@ "setInterval": true }, "packages": { - "@sentry/browser>@sentry/types": true, - "@sentry/browser>@sentry/utils": true, - "@sentry/browser>tslib": true + "@sentry/types": true, + "@sentry/utils": true, + "@sentry/utils>tslib": true } }, "@sentry/browser>@sentry/core>@sentry/minimal": { "packages": { "@sentry/browser>@sentry/core>@sentry/hub": true, - "@sentry/browser>tslib": true + "@sentry/utils>tslib": true } }, - "@sentry/browser>@sentry/utils": { + "@sentry/integrations": { + "globals": { + "clearTimeout": true, + "console.error": true, + "console.log": true, + "setTimeout": true + }, + "packages": { + "@sentry/types": true, + "@sentry/utils": true, + "@sentry/utils>tslib": true, + "localforage": true + } + }, + "@sentry/utils": { "globals": { "CustomEvent": true, "DOMError": true, @@ -4063,29 +4077,15 @@ "setTimeout": true }, "packages": { - "@sentry/browser>tslib": true, + "@sentry/utils>tslib": true, "browserify>process": true } }, - "@sentry/browser>tslib": { + "@sentry/utils>tslib": { "globals": { "define": true } }, - "@sentry/integrations": { - "globals": { - "clearTimeout": true, - "console.error": true, - "console.log": true, - "setTimeout": true - }, - "packages": { - "@sentry/browser>@sentry/types": true, - "@sentry/browser>@sentry/utils": true, - "@sentry/browser>tslib": true, - "localforage": true - } - }, "@storybook/api>regenerator-runtime": { "globals": { "regeneratorRuntime": "write" @@ -5187,7 +5187,6 @@ "addEventListener": true, "browser": true, "clearInterval": true, - "console.warn": true, "fetch": true, "open": true, "setInterval": true, @@ -5216,40 +5215,31 @@ }, "eth-lattice-keyring>gridplus-sdk": { "globals": { - "console.warn": true, + "ActiveXObject": true, + "AggregateError": true, + "Buffer": true, + "DO_NOT_EXPORT_CRC": true, + "FinalizationRegistry": true, + "HTMLElement": true, + "TextEncoder": true, + "URL": true, + "URLSearchParams": true, + "WeakRef": true, + "XMLHttpRequest": true, + "btoa": true, + "clearTimeout": true, + "console": true, + "crypto": true, + "define": true, + "document": true, + "intToBuffer": true, + "location": true, + "msCrypto": true, "setTimeout": true }, "packages": { - "3box>ethers>elliptic": true, - "@ethereumjs/common": true, - "@ethereumjs/common>crc-32": true, - "@ethereumjs/tx": true, - "bn.js": true, "browserify>buffer": true, - "eth-lattice-keyring>gridplus-sdk>bech32": true, - "eth-lattice-keyring>gridplus-sdk>bignumber.js": true, - "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, - "ethereumjs-wallet>aes-js": true, - "ethereumjs-wallet>bs58check": true, - "ethers>@ethersproject/keccak256>js-sha3": true, - "ethers>@ethersproject/sha2>hash.js": true, - "lodash": true, - "pubnub>superagent": true - } - }, - "eth-lattice-keyring>gridplus-sdk>bignumber.js": { - "globals": { - "crypto": true, - "define": true - } - }, - "eth-lattice-keyring>gridplus-sdk>bitwise": { - "packages": { - "browserify>buffer": true + "browserify>process": true } }, "eth-lattice-keyring>gridplus-sdk>borc": { @@ -5269,43 +5259,6 @@ "define": true } }, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": { - "globals": { - "intToBuffer": true - }, - "packages": { - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>bn.js": true, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>buffer": true, - "ethers>@ethersproject/keccak256>js-sha3": true - } - }, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>buffer": { - "globals": { - "console": true - }, - "packages": { - "base64-js": true, - "browserify>buffer>ieee754": true - } - }, - "eth-lattice-keyring>gridplus-sdk>rlp": { - "globals": { - "TextEncoder": true - } - }, - "eth-lattice-keyring>gridplus-sdk>secp256k1": { - "packages": { - "3box>ethers>elliptic": true - } - }, "eth-lattice-keyring>rlp": { "globals": { "TextEncoder": true @@ -6499,21 +6452,6 @@ "browserify>buffer": true } }, - "pubnub>superagent": { - "globals": { - "ActiveXObject": true, - "XMLHttpRequest": true, - "btoa": true, - "clearTimeout": true, - "console.error": true, - "console.trace": true, - "console.warn": true, - "setTimeout": true - }, - "packages": { - "pubnub>superagent>component-emitter": true - } - }, "pump": { "packages": { "browserify>browser-resolve": true, diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 7b6c8c22c..2ed8c9610 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -4010,9 +4010,9 @@ }, "packages": { "@sentry/browser>@sentry/core": true, - "@sentry/browser>@sentry/types": true, - "@sentry/browser>@sentry/utils": true, - "@sentry/browser>tslib": true + "@sentry/types": true, + "@sentry/utils": true, + "@sentry/utils>tslib": true } }, "@sentry/browser>@sentry/core": { @@ -4023,9 +4023,9 @@ "packages": { "@sentry/browser>@sentry/core>@sentry/hub": true, "@sentry/browser>@sentry/core>@sentry/minimal": true, - "@sentry/browser>@sentry/types": true, - "@sentry/browser>@sentry/utils": true, - "@sentry/browser>tslib": true + "@sentry/types": true, + "@sentry/utils": true, + "@sentry/utils>tslib": true } }, "@sentry/browser>@sentry/core>@sentry/hub": { @@ -4034,18 +4034,32 @@ "setInterval": true }, "packages": { - "@sentry/browser>@sentry/types": true, - "@sentry/browser>@sentry/utils": true, - "@sentry/browser>tslib": true + "@sentry/types": true, + "@sentry/utils": true, + "@sentry/utils>tslib": true } }, "@sentry/browser>@sentry/core>@sentry/minimal": { "packages": { "@sentry/browser>@sentry/core>@sentry/hub": true, - "@sentry/browser>tslib": true + "@sentry/utils>tslib": true } }, - "@sentry/browser>@sentry/utils": { + "@sentry/integrations": { + "globals": { + "clearTimeout": true, + "console.error": true, + "console.log": true, + "setTimeout": true + }, + "packages": { + "@sentry/types": true, + "@sentry/utils": true, + "@sentry/utils>tslib": true, + "localforage": true + } + }, + "@sentry/utils": { "globals": { "CustomEvent": true, "DOMError": true, @@ -4063,29 +4077,15 @@ "setTimeout": true }, "packages": { - "@sentry/browser>tslib": true, + "@sentry/utils>tslib": true, "browserify>process": true } }, - "@sentry/browser>tslib": { + "@sentry/utils>tslib": { "globals": { "define": true } }, - "@sentry/integrations": { - "globals": { - "clearTimeout": true, - "console.error": true, - "console.log": true, - "setTimeout": true - }, - "packages": { - "@sentry/browser>@sentry/types": true, - "@sentry/browser>@sentry/utils": true, - "@sentry/browser>tslib": true, - "localforage": true - } - }, "@storybook/api>regenerator-runtime": { "globals": { "regeneratorRuntime": "write" @@ -5187,7 +5187,6 @@ "addEventListener": true, "browser": true, "clearInterval": true, - "console.warn": true, "fetch": true, "open": true, "setInterval": true, @@ -5216,40 +5215,31 @@ }, "eth-lattice-keyring>gridplus-sdk": { "globals": { - "console.warn": true, + "ActiveXObject": true, + "AggregateError": true, + "Buffer": true, + "DO_NOT_EXPORT_CRC": true, + "FinalizationRegistry": true, + "HTMLElement": true, + "TextEncoder": true, + "URL": true, + "URLSearchParams": true, + "WeakRef": true, + "XMLHttpRequest": true, + "btoa": true, + "clearTimeout": true, + "console": true, + "crypto": true, + "define": true, + "document": true, + "intToBuffer": true, + "location": true, + "msCrypto": true, "setTimeout": true }, "packages": { - "3box>ethers>elliptic": true, - "@ethereumjs/common": true, - "@ethereumjs/common>crc-32": true, - "@ethereumjs/tx": true, - "bn.js": true, "browserify>buffer": true, - "eth-lattice-keyring>gridplus-sdk>bech32": true, - "eth-lattice-keyring>gridplus-sdk>bignumber.js": true, - "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, - "ethereumjs-wallet>aes-js": true, - "ethereumjs-wallet>bs58check": true, - "ethers>@ethersproject/keccak256>js-sha3": true, - "ethers>@ethersproject/sha2>hash.js": true, - "lodash": true, - "pubnub>superagent": true - } - }, - "eth-lattice-keyring>gridplus-sdk>bignumber.js": { - "globals": { - "crypto": true, - "define": true - } - }, - "eth-lattice-keyring>gridplus-sdk>bitwise": { - "packages": { - "browserify>buffer": true + "browserify>process": true } }, "eth-lattice-keyring>gridplus-sdk>borc": { @@ -5269,43 +5259,6 @@ "define": true } }, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": { - "globals": { - "intToBuffer": true - }, - "packages": { - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>bn.js": true, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>buffer": true, - "ethers>@ethersproject/keccak256>js-sha3": true - } - }, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>bn.js": { - "globals": { - "Buffer": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser>buffer": { - "globals": { - "console": true - }, - "packages": { - "base64-js": true, - "browserify>buffer>ieee754": true - } - }, - "eth-lattice-keyring>gridplus-sdk>rlp": { - "globals": { - "TextEncoder": true - } - }, - "eth-lattice-keyring>gridplus-sdk>secp256k1": { - "packages": { - "3box>ethers>elliptic": true - } - }, "eth-lattice-keyring>rlp": { "globals": { "TextEncoder": true @@ -6499,21 +6452,6 @@ "browserify>buffer": true } }, - "pubnub>superagent": { - "globals": { - "ActiveXObject": true, - "XMLHttpRequest": true, - "btoa": true, - "clearTimeout": true, - "console.error": true, - "console.trace": true, - "console.warn": true, - "setTimeout": true - }, - "packages": { - "pubnub>superagent>component-emitter": true - } - }, "pump": { "packages": { "browserify>browser-resolve": true, diff --git a/lavamoat/build-system/policy.json b/lavamoat/build-system/policy.json index 8096a980d..f633b23af 100644 --- a/lavamoat/build-system/policy.json +++ b/lavamoat/build-system/policy.json @@ -38,6 +38,7 @@ "@babel/core>@babel/helper-compilation-targets": true, "@babel/core>@babel/helper-module-transforms": true, "@babel/core>@babel/helpers": true, + "@babel/core>@babel/parser": true, "@babel/core>@babel/template": true, "@babel/core>@babel/types": true, "@babel/core>gensync": true, @@ -51,7 +52,6 @@ "@babel/preset-env": true, "@babel/preset-react": true, "@babel/preset-typescript": true, - "depcheck>@babel/parser": true, "depcheck>@babel/traverse": true, "depcheck>json5": true, "eslint>debug": true, @@ -132,8 +132,8 @@ "@babel/core>@babel/template": { "packages": { "@babel/code-frame": true, - "@babel/core>@babel/types": true, - "depcheck>@babel/parser": true + "@babel/core>@babel/parser": true, + "@babel/core>@babel/types": true } }, "@babel/core>@babel/types": { @@ -1005,7 +1005,7 @@ "@metamask/jazzicon>color>color-convert>color-name": true } }, - "@sentry/browser>tslib": { + "@sentry/utils>tslib": { "globals": { "define": true } @@ -1088,7 +1088,7 @@ }, "@typescript-eslint/eslint-plugin>tsutils": { "packages": { - "@sentry/browser>tslib": true, + "@sentry/utils>tslib": true, "typescript": true } }, @@ -1846,8 +1846,8 @@ "packages": { "@babel/code-frame": true, "@babel/core>@babel/generator": true, + "@babel/core>@babel/parser": true, "@babel/core>@babel/types": true, - "depcheck>@babel/parser": true, "depcheck>@babel/traverse>@babel/helper-environment-visitor": true, "depcheck>@babel/traverse>@babel/helper-function-name": true, "depcheck>@babel/traverse>@babel/helper-hoist-variables": true, @@ -5552,7 +5552,7 @@ "console.log": true }, "packages": { - "depcheck>@babel/parser": true, + "@babel/core>@babel/parser": true, "depcheck>@babel/traverse": true } }, diff --git a/package.json b/package.json index a749aee57..534b2a971 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metamask-crx", - "version": "10.18.3", + "version": "10.18.4", "private": true, "repository": { "type": "git", @@ -136,6 +136,8 @@ "@reduxjs/toolkit": "^1.6.2", "@sentry/browser": "^6.0.0", "@sentry/integrations": "^6.0.0", + "@sentry/types": "^6.0.1", + "@sentry/utils": "^6.0.1", "@truffle/codec": "^0.11.18", "@truffle/decoder": "^5.1.0", "@zxing/browser": "^0.0.10", @@ -158,7 +160,7 @@ "eth-json-rpc-infura": "^5.1.0", "eth-json-rpc-middleware": "^8.0.0", "eth-keyring-controller": "^7.0.2", - "eth-lattice-keyring": "^0.7.3", + "eth-lattice-keyring": "^0.11.0", "eth-method-registry": "^2.0.0", "eth-query": "^2.1.2", "eth-rpc-errors": "^4.0.2", @@ -289,7 +291,7 @@ "css-loader": "^2.1.1", "css-to-xpath": "^0.1.0", "del": "^3.0.0", - "depcheck": "^1.4.2", + "depcheck": "^1.4.3", "dependency-tree": "^8.1.1", "duplexify": "^4.1.1", "enzyme": "^3.10.0", diff --git a/shared/constants/app.js b/shared/constants/app.js index 0d1aecc06..bc27e0df1 100644 --- a/shared/constants/app.js +++ b/shared/constants/app.js @@ -39,11 +39,14 @@ export const MESSAGE_TYPE = { ETH_REQUEST_ACCOUNTS: 'eth_requestAccounts', ETH_SIGN: 'eth_sign', ETH_SIGN_TYPED_DATA: 'eth_signTypedData', + ETH_SIGN_TYPED_DATA_V3: 'eth_signTypedData_v3', + ETH_SIGN_TYPED_DATA_V4: 'eth_signTypedData_v4', GET_PROVIDER_STATE: 'metamask_getProviderState', LOG_WEB3_SHIM_USAGE: 'metamask_logWeb3ShimUsage', PERSONAL_SIGN: 'personal_sign', SEND_METADATA: 'metamask_sendDomainMetadata', SWITCH_ETHEREUM_CHAIN: 'wallet_switchEthereumChain', + WALLET_REQUEST_PERMISSIONS: 'wallet_requestPermissions', WATCH_ASSET: 'wallet_watchAsset', WATCH_ASSET_LEGACY: 'metamask_watchAsset', ///: BEGIN:ONLY_INCLUDE_IN(flask) @@ -92,3 +95,5 @@ export const FIREFOX_BUILD_IDS = [ METAMASK_PROD_FIREFOX_ID, METAMASK_FLASK_FIREFOX_ID, ]; + +export const UNKNOWN_TICKER_SYMBOL = 'UNKNOWN'; diff --git a/shared/constants/gas.js b/shared/constants/gas.js index 0092e9ae0..8954aa7cf 100644 --- a/shared/constants/gas.js +++ b/shared/constants/gas.js @@ -11,7 +11,7 @@ export const GAS_LIMITS = { }; /** - * @typedef {Object} GasEstimateTypes + * @typedef {object} GasEstimateTypes * @property {'fee-market'} FEE_MARKET - A gas estimate for a fee market * transaction generated by our gas estimation API. * @property {'legacy'} LEGACY - A gas estimate for a legacy Transaction diff --git a/shared/constants/metametrics.js b/shared/constants/metametrics.js index 1751c2a55..16c0a2eb7 100644 --- a/shared/constants/metametrics.js +++ b/shared/constants/metametrics.js @@ -9,7 +9,7 @@ * event was triggered. Also included as full details of the current page in * page events. * - * @typedef {Object} MetaMetricsPageObject + * @typedef {object} MetaMetricsPageObject * @property {string} [path] - the path of the current page (e.g /home) * @property {string} [title] - the title of the current page (e.g 'home') * @property {string} [url] - the fully qualified url of the current page @@ -18,7 +18,7 @@ /** * For metamask, this is the dapp that triggered an interaction * - * @typedef {Object} MetaMetricsReferrerObject + * @typedef {object} MetaMetricsReferrerObject * @property {string} [url] - the origin of the dapp issuing the * notification */ @@ -31,8 +31,8 @@ * function, but still provides the consumer a way to override these values if * necessary. * - * @typedef {Object} MetaMetricsContext - * @property {Object} app - Application metadata. + * @typedef {object} MetaMetricsContext + * @property {object} app - Application metadata. * @property {string} app.name - the name of the application tracking the event * @property {string} app.version - the version of the application * @property {string} userAgent - the useragent string of the user @@ -43,7 +43,7 @@ */ /** - * @typedef {Object} MetaMetricsEventPayload + * @typedef {object} MetaMetricsEventPayload * @property {string} event - event name to track * @property {string} category - category to associate event to * @property {string} [environmentType] - The type of environment this event @@ -66,7 +66,7 @@ */ /** - * @typedef {Object} MetaMetricsEventOptions + * @typedef {object} MetaMetricsEventOptions * @property {boolean} [isOptIn] - happened during opt in/out workflow * @property {boolean} [flushImmediately] - When true will automatically flush * the segment queue after tracking the event. Recommended if the result of @@ -83,7 +83,7 @@ */ /** - * @typedef {Object} MetaMetricsEventFragment + * @typedef {object} MetaMetricsEventFragment * @property {string} successEvent - The event name to fire when the fragment * is closed in an affirmative action. * @property {string} [failureEvent] - The event name to fire when the fragment @@ -125,19 +125,19 @@ /** * Represents the shape of data sent to the segment.track method. * - * @typedef {Object} SegmentEventPayload + * @typedef {object} SegmentEventPayload * @property {string} [userId] - The metametrics id for the user * @property {string} [anonymousId] - An anonymousId that is used to track * sensitive data while preserving anonymity. * @property {string} event - name of the event to track - * @property {Object} properties - properties to attach to the event + * @property {object} properties - properties to attach to the event * @property {MetaMetricsContext} context - the context the event occurred in */ /** - * @typedef {Object} MetaMetricsPagePayload + * @typedef {object} MetaMetricsPagePayload * @property {string} name - The name of the page that was viewed - * @property {Object} [params] - The variadic parts of the page url + * @property {object} [params] - The variadic parts of the page url * example (route: `/asset/:asset`, path: `/asset/ETH`) * params: { asset: 'ETH' } * @property {EnvironmentType} environmentType - the environment type that the @@ -148,14 +148,14 @@ */ /** - * @typedef {Object} MetaMetricsPageOptions + * @typedef {object} MetaMetricsPageOptions * @property {boolean} [isOptInPath] - is the current path one of the pages in * the onboarding workflow? If true and participateInMetaMetrics is null track * the page view */ /** - * @typedef {Object} Traits + * @typedef {object} Traits * @property {'address_book_entries'} ADDRESS_BOOK_ENTRIES - When the user * adds or modifies addresses in address book the address_book_entries trait * is identified. @@ -207,7 +207,7 @@ export const TRAITS = { }; /** - * @typedef {Object} MetaMetricsTraits + * @typedef {object} MetaMetricsTraits * @property {number} [address_book_entries] - The number of entries in the * user's address book. * @property {'ledgerLive' | 'webhid' | 'u2f'} [ledger_connection_type] - the @@ -252,7 +252,7 @@ export const METAMETRICS_BACKGROUND_PAGE_OBJECT = { }; /** - * @typedef {Object} SegmentInterface + * @typedef {object} SegmentInterface * @property {SegmentEventPayload[]} queue - A queue of events to be sent when * the flushAt limit has been reached, or flushInterval occurs * @property {() => void} flush - Immediately flush the queue, resetting it to @@ -276,9 +276,18 @@ export const REJECT_NOTFICIATION_CLOSE_SIG = */ export const EVENT_NAMES = { + ENCRYPTION_PUBLIC_KEY_APPROVED: 'Encryption Public Key Approved', + ENCRYPTION_PUBLIC_KEY_REJECTED: 'Encryption Public Key Rejected', ENCRYPTION_PUBLIC_KEY_REQUESTED: 'Encryption Public Key Requested', + DECRYPTION_APPROVED: 'Decryption Approved', + DECRYPTION_REJECTED: 'Decryption Rejected', DECRYPTION_REQUESTED: 'Decryption Requested', + PERMISSIONS_APPROVED: 'Permissions Approved', + PERMISSIONS_REJECTED: 'Permissions Rejected', PERMISSIONS_REQUESTED: 'Permissions Requested', + PROVIDER_METHOD_CALLED: 'Provider Method Called', + SIGNATURE_APPROVED: 'Signature Approved', + SIGNATURE_REJECTED: 'Signature Rejected', SIGNATURE_REQUESTED: 'Signature Requested', TOKEN_ADDED: 'Token Added', TOKEN_DETECTED: 'Token Detected', diff --git a/shared/constants/tokens.js b/shared/constants/tokens.js index 2a878f3df..86a960a13 100644 --- a/shared/constants/tokens.js +++ b/shared/constants/tokens.js @@ -10,7 +10,7 @@ export const LISTED_CONTRACT_ADDRESSES = Object.keys( ).map((address) => address.toLowerCase()); /** - * @typedef {Object} TokenDetails + * @typedef {object} TokenDetails * @property {string} address - The address of the selected 'TOKEN' or * 'COLLECTIBLE' contract. * @property {string} [symbol] - The symbol of the token. diff --git a/shared/constants/transaction.js b/shared/constants/transaction.js index d2a54ae35..7e6e2ed8b 100644 --- a/shared/constants/transaction.js +++ b/shared/constants/transaction.js @@ -3,7 +3,7 @@ import { MESSAGE_TYPE } from './app'; /** * Transaction Type is a MetaMask construct used internally * - * @typedef {Object} TransactionTypes + * @typedef {object} TransactionTypes * @property {'transfer'} TOKEN_METHOD_TRANSFER - A token transaction where the user * is sending tokens that they own to another address * @property {'transferfrom'} TOKEN_METHOD_TRANSFER_FROM - A token transaction @@ -77,7 +77,7 @@ export const TRANSACTION_TYPES = { * transaction params that were hitherto the only transaction type sent on * Ethereum. * - * @typedef {Object} TransactionEnvelopeTypes + * @typedef {object} TransactionEnvelopeTypes * @property {'0x0'} LEGACY - A legacy transaction, the very first type. * @property {'0x1'} ACCESS_LIST - EIP-2930 defined the access list transaction * type that allowed for specifying the state that a transaction would act @@ -103,7 +103,7 @@ export const TRANSACTION_ENVELOPE_TYPES = { * Transaction Status is a mix of Ethereum and MetaMask terminology, used internally * for transaction processing. * - * @typedef {Object} TransactionStatuses + * @typedef {object} TransactionStatuses * @property {'unapproved'} UNAPPROVED - A new transaction that the user has not * approved or rejected * @property {'approved'} APPROVED - The user has approved the transaction in the @@ -155,7 +155,7 @@ export const IN_PROGRESS_TRANSACTION_STATUSES = [ * Transaction Group Status is a MetaMask construct to track the status of groups * of transactions. * - * @typedef {Object} TransactionGroupStatuses + * @typedef {object} TransactionGroupStatuses * @property {'cancelled'} CANCELLED - A cancel type transaction in the group was * confirmed * @property {'pending'} PENDING - The primaryTransaction of the group has a status @@ -174,7 +174,7 @@ export const TRANSACTION_GROUP_STATUSES = { /** * Statuses that are specific to Smart Transactions. * - * @typedef {Object} SmartTransactionStatuses + * @typedef {object} SmartTransactionStatuses * @property {'cancelled'} CANCELLED - It can be cancelled for various reasons. * @property {'pending'} PENDING - Smart transaction is being processed. * @property {'success'} SUCCESS - Smart transaction was successfully mined. @@ -193,7 +193,7 @@ export const SMART_TRANSACTION_STATUSES = { * Transaction Group Category is a MetaMask construct to categorize the intent * of a group of transactions for purposes of displaying in the UI * - * @typedef {Object} TransactionGroupCategories + * @typedef {object} TransactionGroupCategories * @property {'send'} SEND - Transaction group representing ether being sent from * the user. * @property {'receive'} RECEIVE - Transaction group representing a deposit/incoming @@ -226,7 +226,7 @@ export const TRANSACTION_GROUP_CATEGORIES = { }; /** - * @typedef {Object} TxParams + * @typedef {object} TxParams * @property {string} from - The address the transaction is sent from * @property {string} to - The address the transaction is sent to * @property {string} value - The amount of wei, in hexadecimal, to send @@ -237,7 +237,7 @@ export const TRANSACTION_GROUP_CATEGORIES = { */ /** - * @typedef {Object} TxError + * @typedef {object} TxError * @property {string} message - The message from the encountered error. * @property {any} rpc - The "value" of the error. * @property {string} [stack] - the stack trace from the error, if available. @@ -246,7 +246,7 @@ export const TRANSACTION_GROUP_CATEGORIES = { /** * An object representing a transaction, in whatever state it is in. * - * @typedef {Object} TransactionMeta + * @typedef {object} TransactionMeta * @property {string} [blockNumber] - The block number this transaction was * included in. Currently only present on incoming transactions! * @property {number} id - An internally unique tx identifier. @@ -261,7 +261,7 @@ export const TRANSACTION_GROUP_CATEGORIES = { * @property {boolean} loadingDefaults - TODO: Document * @property {TxParams} txParams - The transaction params as passed to the * network provider. - * @property {Object[]} history - A history of mutations to this + * @property {object[]} history - A history of mutations to this * TransactionMeta object. * @property {string} origin - A string representing the interface that * suggested the transaction. @@ -269,7 +269,7 @@ export const TRANSACTION_GROUP_CATEGORIES = { * gas estimation on the transaction metadata. * @property {boolean} userEditedGasLimit - A boolean representing when the * user manually edited the gas limit. - * @property {Object} nonceDetails - A metadata object containing information + * @property {object} nonceDetails - A metadata object containing information * used to derive the suggested nonce, useful for debugging nonce issues. * @property {string} rawTx - A hex string of the final signed transaction, * ready to submit to the network. @@ -283,7 +283,7 @@ export const TRANSACTION_GROUP_CATEGORIES = { /** * Defines the possible types * - * @typedef {Object} TransactionMetaMetricsEvents + * @typedef {object} TransactionMetaMetricsEvents * @property {'Transaction Added'} ADDED - All transactions, except incoming * ones, are added to the controller state in an unapproved status. When this * happens we fire the Transaction Added event to show that the transaction @@ -327,7 +327,7 @@ export const TRANSACTION_EVENTS = { }; /** - * @typedef {Object} AssetTypes + * @typedef {object} AssetTypes * @property {'NATIVE'} NATIVE - The native asset for the current network, such * as ETH * @property {'TOKEN'} TOKEN - An ERC20 token. diff --git a/shared/modules/conversion.utils.js b/shared/modules/conversion.utils.js index eb6e73aee..b973f8436 100644 --- a/shared/modules/conversion.utils.js +++ b/shared/modules/conversion.utils.js @@ -6,7 +6,7 @@ * currency. It should return a single value. * * @param {(number | string | BN)} value - The value to convert. - * @param {Object} [options] - Options to specify details of the conversion + * @param {object} [options] - Options to specify details of the conversion * @param {string} [options.fromCurrency = 'ETH' | 'USD'] - The currency of the passed value * @param {string} [options.toCurrency = 'ETH' | 'USD'] - The desired currency of the result * @param {string} [options.fromNumericBase = 'hex' | 'dec' | 'BN'] - The numeric basic of the passed value. @@ -73,7 +73,7 @@ const isValidBase = (base) => { /** * Utility method to convert a value between denominations, formats and currencies. * - * @param {Object} input + * @param {object} input * @param {string | BigNumber} input.value * @param {NumericBase} input.fromNumericBase * @param {EthDenomination} [input.fromDenomination] diff --git a/shared/modules/hexstring-utils.js b/shared/modules/hexstring-utils.js index 63132f106..0e13b8377 100644 --- a/shared/modules/hexstring-utils.js +++ b/shared/modules/hexstring-utils.js @@ -23,7 +23,7 @@ export function isBurnAddress(address) { * provided this method will validate it has the proper checksum formatting. * * @param {string} possibleAddress - Input parameter to check against - * @param {Object} [options] - options bag + * @param {object} [options] - options bag * @param {boolean} [options.allowNonPrefixed] - If true will first ensure '0x' * is prepended to the string * @param {boolean} [options.mixedCaseUseChecksum] - If true will treat mixed diff --git a/shared/modules/object.utils.js b/shared/modules/object.utils.js index ea2af06c4..bce38cb9b 100644 --- a/shared/modules/object.utils.js +++ b/shared/modules/object.utils.js @@ -7,8 +7,8 @@ * should be included, and a sub-mask implies the property should be further * masked according to that sub-mask. * - * @param {Object} object - The object to mask - * @param {Object} mask - The mask to apply to the object + * @param {object} object - The object to mask + * @param {object} mask - The mask to apply to the object */ export function maskObject(object, mask) { return Object.keys(object).reduce((state, key) => { diff --git a/shared/modules/transaction.utils.js b/shared/modules/transaction.utils.js index 688548b8e..9b04e6648 100644 --- a/shared/modules/transaction.utils.js +++ b/shared/modules/transaction.utils.js @@ -12,7 +12,7 @@ import { isEqualCaseInsensitive } from './string-utils'; */ /** - * @typedef {Object} InferTransactionTypeResult + * @typedef {object} InferTransactionTypeResult * @property {InferrableTransactionTypes} type - The type of transaction * @property {string} getCodeResponse - The contract code, in hex format if * it exists. '0x0' or '0x' are also indicators of non-existent contract @@ -135,7 +135,7 @@ export function parseStandardTokenTransactionData(data) { * represent specific events that we control from the extension and are added manually * at transaction creation. * - * @param {Object} txParams - Parameters for the transaction + * @param {object} txParams - Parameters for the transaction * @param {EthQuery} query - EthQuery instance * @returns {InferTransactionTypeResult} */ diff --git a/test/e2e/webdriver/driver.js b/test/e2e/webdriver/driver.js index 73c029bfe..76a47cf8d 100644 --- a/test/e2e/webdriver/driver.js +++ b/test/e2e/webdriver/driver.js @@ -7,9 +7,9 @@ const cssToXPath = require('css-to-xpath'); * Temporary workaround to patch selenium's element handle API with methods * that match the playwright API for Elements * - * @param {Object} element - Selenium Element + * @param {object} element - Selenium Element * @param driver - * @returns {Object} modified Selenium Element + * @returns {object} modified Selenium Element */ function wrapElementWithAPI(element, driver) { element.press = (key) => element.sendKeys(key); diff --git a/test/e2e/webdriver/firefox.js b/test/e2e/webdriver/firefox.js index 3e3dd84cd..776792e10 100644 --- a/test/e2e/webdriver/firefox.js +++ b/test/e2e/webdriver/firefox.js @@ -29,7 +29,7 @@ class FirefoxDriver { /** * Builds a {@link FirefoxDriver} instance * - * @param {Object} options - the options for the build + * @param {object} options - the options for the build * @param options.responsive * @param options.port * @param options.type diff --git a/test/lib/wait-until-called.js b/test/lib/wait-until-called.js index 94a87f0f4..c59e51aa4 100644 --- a/test/lib/wait-until-called.js +++ b/test/lib/wait-until-called.js @@ -13,7 +13,7 @@ const DEFAULT_TIMEOUT = 10000; * @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 {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. diff --git a/test/mocks/permissions.js b/test/mocks/permissions.js index e17655b5f..6d9fac475 100644 --- a/test/mocks/permissions.js +++ b/test/mocks/permissions.js @@ -49,7 +49,7 @@ const CAVEATS = { * Gets a correctly formatted eth_accounts restrictReturnedAccounts caveat. * * @param {Array} accounts - The accounts for the caveat - * @returns {Object} An eth_accounts restrictReturnedAccounts caveats + * @returns {object} An eth_accounts restrictReturnedAccounts caveats */ eth_accounts: (accounts) => { return [ @@ -71,21 +71,21 @@ const PERMS = { */ requests: { /** - * @returns {Object} A permissions request object with eth_accounts + * @returns {object} A permissions request object with eth_accounts */ eth_accounts: () => { return { eth_accounts: {} }; }, /** - * @returns {Object} A permissions request object with test_method + * @returns {object} A permissions request object with test_method */ test_method: () => { return { test_method: {} }; }, /** - * @returns {Object} A permissions request object with does_not_exist + * @returns {object} A permissions request object with does_not_exist */ does_not_exist: () => { return { does_not_exist: {} }; @@ -100,7 +100,7 @@ const PERMS = { granted: { /** * @param {Array} accounts - The accounts for the eth_accounts permission caveat - * @returns {Object} A granted permissions object with eth_accounts and its caveat + * @returns {object} A granted permissions object with eth_accounts and its caveat */ eth_accounts: (accounts) => { return { @@ -110,7 +110,7 @@ const PERMS = { }, /** - * @returns {Object} A granted permissions object with test_method + * @returns {object} A granted permissions object with test_method */ test_method: () => { return { @@ -138,7 +138,7 @@ export const getters = deepFreeze({ * @param {string} method - The request method * @param {Array} params - The request parameters * @param {string} [id] - The request id - * @returns {Object} An RPC request object + * @returns {object} An RPC request object */ custom: (origin, method, params = [], id) => { const req = { @@ -156,7 +156,7 @@ export const getters = deepFreeze({ * Gets an eth_accounts RPC request object. * * @param {string} origin - The origin of the request - * @returns {Object} An RPC request object + * @returns {object} An RPC request object */ eth_accounts: (origin) => { return { @@ -171,7 +171,7 @@ export const getters = deepFreeze({ * * @param {string} origin - The origin of the request * @param {boolean} param - The request param - * @returns {Object} An RPC request object + * @returns {object} An RPC request object */ test_method: (origin, param = false) => { return { @@ -185,7 +185,7 @@ export const getters = deepFreeze({ * Gets an eth_requestAccounts RPC request object. * * @param {string} origin - The origin of the request - * @returns {Object} An RPC request object + * @returns {object} An RPC request object */ eth_requestAccounts: (origin) => { return { @@ -201,7 +201,7 @@ export const getters = deepFreeze({ * * @param {string} origin - The origin of the request * @param {string} permissionName - The name of the permission to request - * @returns {Object} An RPC request object + * @returns {object} An RPC request object */ requestPermission: (origin, permissionName) => { return { @@ -216,8 +216,8 @@ export const getters = deepFreeze({ * for multiple permissions. * * @param {string} origin - The origin of the request - * @param {Object} permissions - A permission request object - * @returns {Object} An RPC request object + * @param {object} permissions - A permission request object + * @returns {object} An RPC request object */ requestPermissions: (origin, permissions = {}) => { return { @@ -231,9 +231,9 @@ export const getters = deepFreeze({ * Gets a metamask_sendDomainMetadata RPC request object. * * @param {string} origin - The origin of the request - * @param {Object} name - The subjectMetadata name + * @param {object} name - The subjectMetadata name * @param {Array} [args] - Any other data for the request's subjectMetadata - * @returns {Object} An RPC request object + * @returns {object} An RPC request object */ metamask_sendDomainMetadata: (origin, name, ...args) => { return { diff --git a/ui/components/app/menu-bar/account-options-menu.js b/ui/components/app/menu-bar/account-options-menu.js index f712631b4..2d8a22826 100644 --- a/ui/components/app/menu-bar/account-options-menu.js +++ b/ui/components/app/menu-bar/account-options-menu.js @@ -5,10 +5,14 @@ import { useDispatch, useSelector } from 'react-redux'; import { getAccountLink } from '@metamask/etherscan-link'; import { showModal } from '../../../store/actions'; -import { CONNECTED_ROUTE } from '../../../helpers/constants/routes'; +import { + CONNECTED_ROUTE, + NETWORKS_ROUTE, +} from '../../../helpers/constants/routes'; import { getURLHostName } from '../../../helpers/utils/util'; import { Menu, MenuItem } from '../../ui/menu'; import { + getBlockExplorerLinkText, getCurrentChainId, getCurrentKeyring, getRpcPrefsForCurrentProvider, @@ -34,9 +38,30 @@ export default function AccountOptionsMenu({ anchorElement, onClose }) { const { blockExplorerUrl } = rpcPrefs; const blockExplorerUrlSubTitle = getURLHostName(blockExplorerUrl); const trackEvent = useContext(MetaMetricsContext); + const blockExplorerLinkText = useSelector(getBlockExplorerLinkText); const isRemovable = keyring.type !== 'HD Key Tree'; + const routeToAddBlockExplorerUrl = () => { + history.push(`${NETWORKS_ROUTE}#blockExplorerUrl`); + }; + + const openBlockExplorer = () => { + trackEvent({ + event: 'Clicked Block Explorer Link', + category: EVENT.CATEGORIES.NAVIGATION, + properties: { + link_type: 'Account Tracker', + action: 'Account Options', + block_explorer_domain: getURLHostName(addressLink), + }, + }); + global.platform.openTab({ + url: addressLink, + }); + onClose(); + }; + return ( { - trackEvent({ - event: 'Clicked Block Explorer Link', - category: EVENT.CATEGORIES.NAVIGATION, - properties: { - link_type: 'Account Tracker', - action: 'Account Options', - block_explorer_domain: getURLHostName(addressLink), - }, - }); - global.platform.openTab({ - url: addressLink, - }); - onClose(); - }} + onClick={ + blockExplorerLinkText.firstPart === 'addBlockExplorer' + ? routeToAddBlockExplorerUrl + : openBlockExplorer + } subtitle={ blockExplorerUrlSubTitle ? ( @@ -68,9 +83,12 @@ export default function AccountOptionsMenu({ anchorElement, onClose }) { } iconClassName="fas fa-external-link-alt" > - {rpcPrefs.blockExplorerUrl - ? t('viewinExplorer', [t('blockExplorerAccountAction')]) - : t('viewOnEtherscan', [t('blockExplorerAccountAction')])} + {t( + blockExplorerLinkText.firstPart, + blockExplorerLinkText.secondPart === '' + ? null + : [t(blockExplorerLinkText.secondPart)], + )} {getEnvironmentType() === ENVIRONMENT_TYPE_FULLSCREEN ? null : ( { + hideModal(); + history.push(`${NETWORKS_ROUTE}#blockExplorerUrl`); + }; + + const openBlockExplorer = () => { + const accountLink = getAccountLink(address, chainId, rpcPrefs); + this.context.trackEvent({ + category: EVENT.CATEGORIES.NAVIGATION, + event: 'Clicked Block Explorer Link', + properties: { + link_type: 'Account Tracker', + action: 'Account Details Modal', + block_explorer_domain: getURLHostName(accountLink), + }, + }); + global.platform.openTab({ + url: accountLink, + }); + }; + return ( { - const accountLink = getAccountLink(address, chainId, rpcPrefs); - this.context.trackEvent({ - category: EVENT.CATEGORIES.NAVIGATION, - event: 'Clicked Block Explorer Link', - properties: { - link_type: 'Account Tracker', - action: 'Account Details Modal', - block_explorer_domain: getURLHostName(accountLink), - }, - }); - global.platform.openTab({ - url: accountLink, - }); - }} + onClick={ + blockExplorerLinkText.firstPart === 'addBlockExplorer' + ? routeToAddBlockExplorerUrl + : openBlockExplorer + } > - {rpcPrefs.blockExplorerUrl - ? this.context.t('blockExplorerView', [ - getURLHostName(rpcPrefs.blockExplorerUrl), - ]) - : this.context.t('etherscanViewOn')} + {this.context.t( + blockExplorerLinkText.firstPart, + blockExplorerLinkText.secondPart === '' + ? null + : [blockExplorerLinkText.secondPart], + )} {exportPrivateKeyFeatureEnabled ? ( diff --git a/ui/components/app/modals/account-details-modal/account-details-modal.container.js b/ui/components/app/modals/account-details-modal/account-details-modal.container.js index 0241c4d2a..f5270b1b9 100644 --- a/ui/components/app/modals/account-details-modal/account-details-modal.container.js +++ b/ui/components/app/modals/account-details-modal/account-details-modal.container.js @@ -1,10 +1,17 @@ import { connect } from 'react-redux'; -import { showModal, setAccountLabel } from '../../../../store/actions'; +import { compose } from 'redux'; +import { withRouter } from 'react-router-dom'; +import { + showModal, + setAccountLabel, + hideModal, +} from '../../../../store/actions'; import { getSelectedIdentity, getRpcPrefsForCurrentProvider, getCurrentChainId, getMetaMaskAccountsOrdered, + getBlockExplorerLinkText, } from '../../../../selectors'; import AccountDetailsModal from './account-details-modal.component'; @@ -15,6 +22,7 @@ const mapStateToProps = (state) => { keyrings: state.metamask.keyrings, rpcPrefs: getRpcPrefsForCurrentProvider(state), accounts: getMetaMaskAccountsOrdered(state), + blockExplorerLinkText: getBlockExplorerLinkText(state, true), }; }; @@ -24,10 +32,13 @@ const mapDispatchToProps = (dispatch) => { dispatch(showModal({ name: 'EXPORT_PRIVATE_KEY' })), setAccountLabel: (address, label) => dispatch(setAccountLabel(address, label)), + hideModal: () => { + dispatch(hideModal()); + }, }; }; -export default connect( - mapStateToProps, - mapDispatchToProps, +export default compose( + withRouter, + connect(mapStateToProps, mapDispatchToProps), )(AccountDetailsModal); diff --git a/ui/components/app/modals/account-details-modal/account-details-modal.test.js b/ui/components/app/modals/account-details-modal/account-details-modal.test.js index 8b61394d8..a2a810769 100644 --- a/ui/components/app/modals/account-details-modal/account-details-modal.test.js +++ b/ui/components/app/modals/account-details-modal/account-details-modal.test.js @@ -30,14 +30,16 @@ describe('Account Details Modal', () => { name: 'Account 1', }, }, - accounts: [ - { - address: '0xAddress', - lastSelected: 1637764711510, - name: 'Account 1', - balance: '0x543a5fb6caccf599', - }, - ], + accounts: { + address: '0xAddress', + lastSelected: 1637764711510, + name: 'Account 1', + balance: '0x543a5fb6caccf599', + }, + blockExplorerLinkText: { + firstPart: 'addBlockExplorer', + secondPart: '', + }, }; beforeEach(() => { @@ -58,6 +60,12 @@ describe('Account Details Modal', () => { }); it('opens new tab when view block explorer is clicked', () => { + wrapper.setProps({ + blockExplorerLinkText: { + firstPart: 'viewOnEtherscan', + secondPart: 'blockExplorerAccountAction', + }, + }); const modalButton = wrapper.find('.account-details-modal__button'); const etherscanLink = modalButton.first(); @@ -75,7 +83,10 @@ describe('Account Details Modal', () => { it('sets blockexplorerview text when block explorer url in rpcPrefs exists', () => { const blockExplorerUrl = 'https://block.explorer'; - wrapper.setProps({ rpcPrefs: { blockExplorerUrl } }); + wrapper.setProps({ + rpcPrefs: { blockExplorerUrl }, + blockExplorerLinkText: { firstPart: 'blockExplorerView' }, + }); const modalButton = wrapper.find('.account-details-modal__button'); const blockExplorerLink = modalButton.first().shallow(); diff --git a/ui/components/app/transaction-activity-log/transaction-activity-log.util.js b/ui/components/app/transaction-activity-log/transaction-activity-log.util.js index b0b0caeea..f9aec2343 100644 --- a/ui/components/app/transaction-activity-log/transaction-activity-log.util.js +++ b/ui/components/app/transaction-activity-log/transaction-activity-log.util.js @@ -44,7 +44,7 @@ const statusHash = { /** * @name getActivities - * @param {Object} transaction - txMeta object + * @param {object} transaction - txMeta object * @param {boolean} isFirstTransaction - True if the transaction is the first created transaction * in the list of transactions with the same nonce. If so, we use this transaction to create the * transactionCreated activity. diff --git a/ui/components/app/transaction-list-item-details/transaction-list-item-details.component.js b/ui/components/app/transaction-list-item-details/transaction-list-item-details.component.js index f65c82f63..92592a5b0 100644 --- a/ui/components/app/transaction-list-item-details/transaction-list-item-details.component.js +++ b/ui/components/app/transaction-list-item-details/transaction-list-item-details.component.js @@ -16,6 +16,7 @@ import { EVENT } from '../../../../shared/constants/metametrics'; import { TRANSACTION_TYPES } from '../../../../shared/constants/transaction'; import { getURLHostName } from '../../../helpers/utils/util'; import TransactionDecoding from '../transaction-decoding'; +import { NETWORKS_ROUTE } from '../../../helpers/constants/routes'; export default class TransactionListItemDetails extends PureComponent { static contextTypes = { @@ -46,6 +47,9 @@ export default class TransactionListItemDetails extends PureComponent { senderNickname: PropTypes.string.isRequired, recipientNickname: PropTypes.string, transactionStatus: PropTypes.func, + isCustomNetwork: PropTypes.bool, + history: PropTypes.object, + blockExplorerLinkText: PropTypes.object, }; state = { @@ -56,26 +60,33 @@ export default class TransactionListItemDetails extends PureComponent { const { transactionGroup: { primaryTransaction }, rpcPrefs, + isCustomNetwork, + history, + onClose, } = this.props; const blockExplorerLink = getBlockExplorerLink( primaryTransaction, rpcPrefs, ); - this.context.trackEvent({ - category: EVENT.CATEGORIES.TRANSACTIONS, - event: 'Clicked Block Explorer Link', - properties: { - link_type: 'Transaction Block Explorer', - action: 'Transaction Details', - block_explorer_domain: getURLHostName(blockExplorerLink), - legacy_event: true, - }, - }); + if (!rpcPrefs.blockExplorerUrl && isCustomNetwork) { + onClose(); + history.push(`${NETWORKS_ROUTE}#blockExplorerUrl`); + } else { + this.context.trackEvent({ + category: EVENT.CATEGORIES.TRANSACTIONS, + event: 'Clicked Block Explorer Link', + properties: { + link_type: 'Transaction Block Explorer', + action: 'Transaction Details', + block_explorer_domain: getURLHostName(blockExplorerLink), + }, + }); - global.platform.openTab({ - url: blockExplorerLink, - }); + global.platform.openTab({ + url: blockExplorerLink, + }); + } }; handleCancel = (event) => { @@ -136,6 +147,7 @@ export default class TransactionListItemDetails extends PureComponent { recipientNickname, showCancel, transactionStatus: TransactionStatus, + blockExplorerLinkText, } = this.props; const { primaryTransaction: transaction, @@ -191,7 +203,9 @@ export default class TransactionListItemDetails extends PureComponent { onClick={this.handleBlockExplorerClick} disabled={!hash} > - {t('viewOnBlockExplorer')} + {blockExplorerLinkText.firstPart === 'addBlockExplorer' + ? t('addBlockExplorer') + : t('viewOnBlockExplorer')}
diff --git a/ui/components/app/transaction-list-item-details/transaction-list-item-details.component.test.js b/ui/components/app/transaction-list-item-details/transaction-list-item-details.component.test.js index 18417627c..eef1225c3 100644 --- a/ui/components/app/transaction-list-item-details/transaction-list-item-details.component.test.js +++ b/ui/components/app/transaction-list-item-details/transaction-list-item-details.component.test.js @@ -31,6 +31,15 @@ describe('TransactionListItemDetails Component', () => { initialTransaction: transaction, }; + const rpcPrefs = { + blockExplorerUrl: 'https://customblockexplorer.com/', + }; + + const blockExplorerLinkText = { + firstPart: 'addBlockExplorer', + secondPart: '', + }; + const wrapper = shallow( undefined} @@ -42,6 +51,8 @@ describe('TransactionListItemDetails Component', () => { senderNickname="sender-nickname" recipientNickname="recipient-nickname" transactionStatus={TransactionStatus} + rpcPrefs={rpcPrefs} + blockExplorerLinkText={blockExplorerLinkText} />, { context: { t: (str1, str2) => (str2 ? str1 + str2 : str1) } }, ); @@ -77,6 +88,15 @@ describe('TransactionListItemDetails Component', () => { hasCancelled: false, }; + const rpcPrefs = { + blockExplorerUrl: 'https://customblockexplorer.com/', + }; + + const blockExplorerLinkText = { + firstPart: 'addBlockExplorer', + secondPart: '', + }; + const wrapper = shallow( undefined} @@ -89,6 +109,8 @@ describe('TransactionListItemDetails Component', () => { senderNickname="sender-nickname" recipientNickname="recipient-nickname" transactionStatus={TransactionStatus} + rpcPrefs={rpcPrefs} + blockExplorerLinkText={blockExplorerLinkText} />, { context: { t: (str1, str2) => (str2 ? str1 + str2 : str1) } }, ); @@ -120,6 +142,15 @@ describe('TransactionListItemDetails Component', () => { initialTransaction: transaction, }; + const rpcPrefs = { + blockExplorerUrl: 'https://customblockexplorer.com/', + }; + + const blockExplorerLinkText = { + firstPart: 'addBlockExplorer', + secondPart: '', + }; + const wrapper = shallow( undefined} @@ -131,6 +162,8 @@ describe('TransactionListItemDetails Component', () => { senderNickname="sender-nickname" recipientNickname="recipient-nickname" transactionStatus={TransactionStatus} + rpcPrefs={rpcPrefs} + blockExplorerLinkText={blockExplorerLinkText} />, { context: { t: (str1, str2) => (str2 ? str1 + str2 : str1) } }, ); @@ -165,6 +198,15 @@ describe('TransactionListItemDetails Component', () => { initialTransaction: transaction, }; + const rpcPrefs = { + blockExplorerUrl: 'https://customblockexplorer.com/', + }; + + const blockExplorerLinkText = { + firstPart: 'addBlockExplorer', + secondPart: '', + }; + const wrapper = shallow( undefined} @@ -176,6 +218,8 @@ describe('TransactionListItemDetails Component', () => { senderNickname="sender-nickname" recipientNickname="recipient-nickname" transactionStatus={TransactionStatus} + rpcPrefs={rpcPrefs} + blockExplorerLinkText={blockExplorerLinkText} />, { context: { t: (str1, str2) => (str2 ? str1 + str2 : str1) } }, ); diff --git a/ui/components/app/transaction-list-item-details/transaction-list-item-details.container.js b/ui/components/app/transaction-list-item-details/transaction-list-item-details.container.js index dc3775fb2..61731c092 100644 --- a/ui/components/app/transaction-list-item-details/transaction-list-item-details.container.js +++ b/ui/components/app/transaction-list-item-details/transaction-list-item-details.container.js @@ -1,7 +1,11 @@ import { connect } from 'react-redux'; +import { compose } from 'redux'; +import { withRouter } from 'react-router-dom'; import { tryReverseResolveAddress } from '../../../store/actions'; import { getAddressBook, + getBlockExplorerLinkText, + getIsCustomNetwork, getRpcPrefsForCurrentProvider, getEnsResolutionByAddress, } from '../../../selectors'; @@ -25,11 +29,15 @@ const mapStateToProps = (state, ownProps) => { }; const rpcPrefs = getRpcPrefsForCurrentProvider(state); + const isCustomNetwork = getIsCustomNetwork(state); + return { rpcPrefs, recipientEns, senderNickname: getNickName(senderAddress), recipientNickname: recipientAddress ? getNickName(recipientAddress) : null, + isCustomNetwork, + blockExplorerLinkText: getBlockExplorerLinkText(state), }; }; @@ -41,7 +49,7 @@ const mapDispatchToProps = (dispatch) => { }; }; -export default connect( - mapStateToProps, - mapDispatchToProps, +export default compose( + withRouter, + connect(mapStateToProps, mapDispatchToProps), )(TransactionListItemDetails); diff --git a/ui/components/app/transaction-list-item/transaction-list-item.stories.js b/ui/components/app/transaction-list-item/transaction-list-item.stories.js index 0d030310a..f02558a73 100644 --- a/ui/components/app/transaction-list-item/transaction-list-item.stories.js +++ b/ui/components/app/transaction-list-item/transaction-list-item.stories.js @@ -11,7 +11,7 @@ import TransactionListItem from '.'; */ /** - * @param {Object} args + * @param {object} args * @returns {TransactionGroup} */ const getMockTransactionGroup = (args) => { diff --git a/ui/components/ui/error-message/error-message.component.js b/ui/components/ui/error-message/error-message.component.js index db8ce1da4..fc0bd86eb 100644 --- a/ui/components/ui/error-message/error-message.component.js +++ b/ui/components/ui/error-message/error-message.component.js @@ -4,10 +4,10 @@ import PropTypes from 'prop-types'; /** * @deprecated - Please use ActionableMessage type danger * @see ActionableMessage - * @param {Object} props + * @param {object} props * @param {string} props.errorMessage * @param {string} props.errorKey - * @param {Object} context + * @param {object} context */ const ErrorMessage = (props, context) => { const { errorMessage, errorKey } = props; diff --git a/ui/components/ui/nickname-popover/nickname-popover.component.js b/ui/components/ui/nickname-popover/nickname-popover.component.js index d0f8a194f..03ebb0fa3 100644 --- a/ui/components/ui/nickname-popover/nickname-popover.component.js +++ b/ui/components/ui/nickname-popover/nickname-popover.component.js @@ -1,6 +1,7 @@ import React, { useCallback, useContext } from 'react'; import { useSelector } from 'react-redux'; import PropTypes from 'prop-types'; +import { useHistory } from 'react-router-dom'; import { I18nContext } from '../../../contexts/i18n'; import Tooltip from '../tooltip'; import Popover from '../popover'; @@ -9,7 +10,13 @@ import Identicon from '../identicon/identicon.component'; import { shortenAddress } from '../../../helpers/utils/util'; import CopyIcon from '../icon/copy-icon.component'; import { useCopyToClipboard } from '../../../hooks/useCopyToClipboard'; -import { getUseTokenDetection, getTokenList } from '../../../selectors'; +import { + getUseTokenDetection, + getTokenList, + getBlockExplorerLinkText, +} from '../../../selectors'; + +import { NETWORKS_ROUTE } from '../../../helpers/constants/routes'; const NicknamePopover = ({ address, @@ -19,6 +26,7 @@ const NicknamePopover = ({ explorerLink, }) => { const t = useContext(I18nContext); + const history = useHistory(); const onAddClick = useCallback(() => { onAdd(); @@ -27,6 +35,17 @@ const NicknamePopover = ({ const [copied, handleCopy] = useCopyToClipboard(); const useTokenDetection = useSelector(getUseTokenDetection); const tokenList = useSelector(getTokenList); + const blockExplorerLinkText = useSelector(getBlockExplorerLinkText); + + const routeToAddBlockExplorerUrl = () => { + history.push(`${NETWORKS_ROUTE}#blockExplorerUrl`); + }; + + const openBlockExplorer = () => { + global.platform.openTab({ + url: explorerLink, + }); + }; return (
@@ -66,16 +85,22 @@ const NicknamePopover = ({
{ const environmentType = getEnvironmentType(); const isFullScreen = environmentType === ENVIRONMENT_TYPE_FULLSCREEN; const shouldRenderNetworkForm = - isFullScreen || Boolean(pathname.match(NETWORKS_FORM_ROUTE)); + isFullScreen || + Boolean(pathname.match(NETWORKS_FORM_ROUTE)) || + window.location.hash.split('#')[2] === 'blockExplorerUrl'; const frequentRpcListDetail = useSelector(getFrequentRpcListDetail); const provider = useSelector(getProvider); diff --git a/ui/selectors/permissions.js b/ui/selectors/permissions.js index be0543ef5..dbca0a404 100644 --- a/ui/selectors/permissions.js +++ b/ui/selectors/permissions.js @@ -12,8 +12,8 @@ import { /** * Get the permission subjects object. * - * @param {Object} state - The current state. - * @returns {Object} The permissions subjects object. + * @param {object} state - The current state. + * @returns {object} The permissions subjects object. */ export function getPermissionSubjects(state) { return state.metamask.subjects || {}; @@ -23,7 +23,7 @@ export function getPermissionSubjects(state) { * Selects the permitted accounts from the eth_accounts permission given state * and an origin. * - * @param {Object} state - The current state. + * @param {object} state - The current state. * @param {string} origin - The origin/subject to get the permitted accounts for. * @returns {Array} An empty array or an array of accounts. */ @@ -37,7 +37,7 @@ export function getPermittedAccounts(state, origin) { * Selects the permitted accounts from the eth_accounts permission for the * origin of the current tab. * - * @param {Object} state - The current state. + * @param {object} state - The current state. * @returns {Array} An empty array or an array of accounts. */ export function getPermittedAccountsForCurrentTab(state) { @@ -47,8 +47,8 @@ export function getPermittedAccountsForCurrentTab(state) { /** * Returns a map of permitted accounts by origin for all origins. * - * @param {Object} state - The current state. - * @returns {Object} Permitted accounts by origin. + * @param {object} state - The current state. + * @returns {object} Permitted accounts by origin. */ export function getPermittedAccountsByOrigin(state) { const subjects = getPermissionSubjects(state); @@ -68,8 +68,8 @@ export function getPermittedAccountsByOrigin(state) { * - name * - icon * - * @param {Object} state - The current state. - * @returns {Array} An array of connected subject objects. + * @param {object} state - The current state. + * @returns {Array} An array of connected subject objects. */ export function getConnectedSubjectsForSelectedAddress(state) { const { selectedAddress } = state.metamask; @@ -124,8 +124,8 @@ export function getSubjectsWithPermission(state, permissionName) { * - iconUrl * - name * - * @param {Object} state - The current state. - * @returns {Object} A mapping of addresses to a mapping of origins to + * @param {object} state - The current state. + * @returns {object} A mapping of addresses to a mapping of origins to * connected subject info. */ export function getAddressConnectedSubjectMap(state) { diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index 4a7bb6a17..46f2a70a7 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -18,6 +18,7 @@ import { BSC_DISPLAY_NAME, POLYGON_DISPLAY_NAME, AVALANCHE_DISPLAY_NAME, + CHAIN_ID_TO_RPC_URL_MAP, } from '../../shared/constants/network'; import { KEYRING_TYPES, @@ -41,7 +42,11 @@ import { ALLOWED_DEV_SWAPS_CHAIN_IDS, } from '../../shared/constants/swaps'; -import { shortenAddress, getAccountByAddress } from '../helpers/utils/util'; +import { + shortenAddress, + getAccountByAddress, + getURLHostName, +} from '../helpers/utils/util'; import { getValueFromWeiHex, hexToDecimal, @@ -76,7 +81,7 @@ import { SNAPS_VIEW_ROUTE } from '../helpers/constants/routes'; * This will be used for all cases where this state key is accessed only for that * purpose. * - * @param {Object} state - redux state object + * @param {object} state - redux state object */ export function isNetworkLoading(state) { return state.metamask.network === 'loading'; @@ -199,7 +204,7 @@ export function checkNetworkOrAccountNotSupports1559(state) { /** * Checks if the current wallet is a hardware wallet. * - * @param {Object} state + * @param {object} state * @returns {boolean} */ export function isHardwareWallet(state) { @@ -210,7 +215,7 @@ export function isHardwareWallet(state) { /** * Get a HW wallet type, e.g. "Ledger Hardware" * - * @param {Object} state + * @param {object} state * @returns {string | undefined} */ export function getHardwareWalletType(state) { @@ -242,7 +247,7 @@ export function getAccountType(state) { * metadata that predates the switch to using chainId. * * @deprecated - use getCurrentChainId instead - * @param {Object} state - redux state object + * @param {object} state - redux state object */ export function deprecatedGetCurrentNetworkId(state) { return state.metamask.network; @@ -639,7 +644,7 @@ export function getWeb3ShimUsageStateForOrigin(state, origin) { } /** - * @typedef {Object} SwapsEthToken + * @typedef {object} SwapsEthToken * @property {string} symbol - The symbol for ETH, namely "ETH" * @property {string} name - The name of the ETH currency, "Ether" * @property {string} address - A substitute address for the metaswap-api to @@ -756,7 +761,7 @@ export const getSnapsRouteObjects = createSelector(getSnaps, (snaps) => { }); /** - * @typedef {Object} Notification + * @typedef {object} Notification * @property {string} id - A unique identifier for the notification * @property {string} origin - A string identifing the snap origin * @property {EpochTimeStamp} createdDate - A date in epochTimeStramps, identifying when the notification was first committed @@ -771,7 +776,7 @@ export const getSnapsRouteObjects = createSelector(getSnaps, (snaps) => { * * The returned notifications are sorted by date. * - * @param {Object} state - the redux state object + * @param {object} state - the redux state object * @returns {Notification[]} An array of notifications that can be shown to the user */ @@ -803,8 +808,8 @@ export const getUnreadNotificationsCount = createSelector( /** * Get an object of announcement IDs and if they are allowed or not. * - * @param {Object} state - * @returns {Object} + * @param {object} state + * @returns {object} */ function getAllowedAnnouncementIds(state) { const currentKeyring = getCurrentKeyring(state); @@ -830,7 +835,7 @@ function getAllowedAnnouncementIds(state) { } /** - * @typedef {Object} Announcement + * @typedef {object} Announcement * @property {number} id - A unique identifier for the announcement * @property {string} date - A date in YYYY-MM-DD format, identifying when the notification was first committed */ @@ -843,7 +848,7 @@ function getAllowedAnnouncementIds(state) { * * The returned announcements are sorted by date. * - * @param {Object} state - the redux state object + * @param {object} state - the redux state object * @returns {Announcement[]} An array of announcements that can be shown to the user */ @@ -916,7 +921,7 @@ export function getTheme(state) { * To retrieve the tokenList produced by TokenListcontroller * * @param {*} state - * @returns {Object} + * @returns {object} */ export function getTokenList(state) { return state.metamask.tokenList; @@ -1072,3 +1077,43 @@ export function getNewTokensImported(state) { export function getIsCustomNetworkListEnabled(state) { return state.metamask.customNetworkListEnabled; } + +export function getIsCustomNetwork(state) { + const chainId = getCurrentChainId(state); + + return !CHAIN_ID_TO_RPC_URL_MAP[chainId]; +} + +export function getBlockExplorerLinkText( + state, + accountDetailsModalComponent = false, +) { + const isCustomNetwork = getIsCustomNetwork(state); + const rpcPrefs = getRpcPrefsForCurrentProvider(state); + + let blockExplorerLinkText = { + firstPart: 'addBlockExplorer', + secondPart: '', + }; + + if (rpcPrefs.blockExplorerUrl) { + blockExplorerLinkText = accountDetailsModalComponent + ? { + firstPart: 'blockExplorerView', + secondPart: getURLHostName(rpcPrefs.blockExplorerUrl), + } + : { + firstPart: 'viewinExplorer', + secondPart: 'blockExplorerAccountAction', + }; + } else if (isCustomNetwork === false) { + blockExplorerLinkText = accountDetailsModalComponent + ? { firstPart: 'etherscanViewOn', secondPart: '' } + : { + firstPart: 'viewOnEtherscan', + secondPart: 'blockExplorerAccountAction', + }; + } + + return blockExplorerLinkText; +} diff --git a/ui/selectors/transactions.js b/ui/selectors/transactions.js index 15e05d2f8..a80147451 100644 --- a/ui/selectors/transactions.js +++ b/ui/selectors/transactions.js @@ -150,8 +150,8 @@ const insertOrderedNonce = (nonces, nonceToInsert) => { * @private * @description Inserts (mutates) a transaction object into an array of ordered transactions, sorted * in ascending order by time. - * @param {Object[]} transactions - Array of transaction objects. - * @param {Object} transaction - Transaction object to be inserted into the array of transactions. + * @param {object[]} transactions - Array of transaction objects. + * @param {object} transaction - Transaction object to be inserted into the array of transactions. */ const insertTransactionByTime = (transactions, transaction) => { const { time } = transaction; @@ -173,11 +173,11 @@ const insertTransactionByTime = (transactions, transaction) => { /** * Contains transactions and properties associated with those transactions of the same nonce. * - * @typedef {Object} transactionGroup + * @typedef {object} transactionGroup * @property {string} nonce - The nonce that the transactions within this transactionGroup share. - * @property {Object[]} transactions - An array of transaction (txMeta) objects. - * @property {Object} initialTransaction - The transaction (txMeta) with the lowest "time". - * @property {Object} primaryTransaction - Either the latest transaction or the confirmed + * @property {object[]} transactions - An array of transaction (txMeta) objects. + * @property {object} initialTransaction - The transaction (txMeta) with the lowest "time". + * @property {object} primaryTransaction - Either the latest transaction or the confirmed * transaction. * @property {boolean} hasRetried - True if a transaction in the group was a retry transaction. * @property {boolean} hasCancelled - True if a transaction in the group was a cancel transaction. diff --git a/ui/store/actions.js b/ui/store/actions.js index 012b04536..a9a0e0fc4 100644 --- a/ui/store/actions.js +++ b/ui/store/actions.js @@ -100,7 +100,7 @@ export function tryUnlockMetamask(password) { * * @param {string} password - The password. * @param {string} seedPhrase - The seed phrase. - * @returns {Object} The updated state of the keyring controller. + * @returns {object} The updated state of the keyring controller. */ export function createNewVaultAndRestore(password, seedPhrase) { return (dispatch) => { @@ -2981,7 +2981,7 @@ export function requestAccountsPermissionWithId(origin) { /** * Approves the permissions request. * - * @param {Object} request - The permissions request to approve. + * @param {object} request - The permissions request to approve. */ export function approvePermissionsRequest(request) { return (dispatch) => { diff --git a/yarn.lock b/yarn.lock index 59206be9f..51f17898a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -403,10 +403,15 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.10.1", "@babel/parser@^7.12.0", "@babel/parser@^7.12.11", "@babel/parser@^7.12.5", "@babel/parser@^7.12.7", "@babel/parser@^7.13.9", "@babel/parser@^7.15.8", "@babel/parser@^7.16.7", "@babel/parser@^7.17.0": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.0.tgz#f0ac33eddbe214e4105363bb17c3341c5ffcc43c" - integrity sha512-VKXSCQx5D8S04ej+Dqsr1CzYvvWgf20jIw2D+YhQCrIlr2UZGaDds23Y0xg75/skOxpLCRpUZvk/1EAVkGoDOw== +"@babel/parser@7.16.4": + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.4.tgz#d5f92f57cf2c74ffe9b37981c0e72fee7311372e" + integrity sha512-6V0qdPUaiVHH3RtZeLIsc+6pDhbYzHR8ogA8w+f+Wc77DuXto19g2QUwveINoS34Uw+W8/hQDGJCx+i4n7xcng== + +"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.10.1", "@babel/parser@^7.12.0", "@babel/parser@^7.12.11", "@babel/parser@^7.12.7", "@babel/parser@^7.13.9", "@babel/parser@^7.15.8", "@babel/parser@^7.16.7", "@babel/parser@^7.17.0": + version "7.18.13" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.13.tgz#5b2dd21cae4a2c5145f1fbd8ca103f9313d3b7e4" + integrity sha512-dgXcIfMuQ0kgzLB2b9tRZs7TTFFaGM2AbtA4fJgUUYukzGH4jwsS7hzQHEGs67jdehpm22vkgKwvbU+aEflgwg== "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.15.4": version "7.15.4" @@ -3447,12 +3452,12 @@ "@sentry/types" "6.13.3" tslib "^1.9.3" -"@sentry/types@6.13.3": +"@sentry/types@6.13.3", "@sentry/types@^6.0.1": version "6.13.3" resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.13.3.tgz#63ad5b6735b0dfd90b3a256a9f8e77b93f0f66b2" integrity sha512-Vrz5CdhaTRSvCQjSyIFIaV9PodjAVFkzJkTRxyY7P77RcegMsRSsG1yzlvCtA99zG9+e6MfoJOgbOCwuZids5A== -"@sentry/utils@6.13.3": +"@sentry/utils@6.13.3", "@sentry/utils@^6.0.1": version "6.13.3" resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.13.3.tgz#188754d40afe693c3fcae410f9322531588a9926" integrity sha512-zYFuFH3MaYtBZTeJ4Yajg7pDf0pM3MWs3+9k5my9Fd+eqNcl7dYQYJbT9gyC0HXK1QI4CAMNNlHNl4YXhF91ag== @@ -8455,7 +8460,7 @@ component-emitter@1.2.1: resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= -component-emitter@^1.2.0, component-emitter@^1.2.1, component-emitter@~1.3.0: +component-emitter@^1.2.0, component-emitter@^1.2.1, component-emitter@^1.3.0, component-emitter@~1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== @@ -8684,10 +8689,10 @@ cookie@~0.4.1: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== -cookiejar@^2.1.0, cookiejar@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" - integrity sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA== +cookiejar@^2.1.0, cookiejar@^2.1.1, cookiejar@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.3.tgz#fc7a6216e408e74414b90230050842dacda75acc" + integrity sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ== cookies@~0.8.0: version "0.8.0" @@ -9283,10 +9288,10 @@ debug@3.X, debug@^3.0.0, debug@^3.1.0, debug@^3.1.1, debug@^3.2.6: dependencies: ms "^2.1.1" -debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0, debug@^4.3.1, debug@^4.3.2, debug@~4.3.1: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== +debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@~4.3.1: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: ms "2.1.2" @@ -9565,12 +9570,12 @@ delimit-stream@0.1.0: resolved "https://registry.yarnpkg.com/delimit-stream/-/delimit-stream-0.1.0.tgz#9b8319477c0e5f8aeb3ce357ae305fc25ea1cd2b" integrity sha1-m4MZR3wOX4rrPONXrjBfwl6hzSs= -depcheck@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/depcheck/-/depcheck-1.4.2.tgz#dedeb8729b8fdf990e2bc45a869d99cfb4460097" - integrity sha512-oYaBLRbF5NMkYxc5rltnqtuPAn25Lx5xPBIJXy5oUVBgrEDDtotCoYUfFH8lvcmSWzgk1Ts9H+f4Rk0oWL51LQ== +depcheck@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/depcheck/-/depcheck-1.4.3.tgz#faa4c143921f3fe25d5a7a633f9864327c250843" + integrity sha512-vy8xe1tlLFu7t4jFyoirMmOR7x7N601ubU9Gkifyr9z8rjBFtEdWHDBMqXyk6OkK+94NXutzddVXJuo0JlUQKQ== dependencies: - "@babel/parser" "^7.12.5" + "@babel/parser" "7.16.4" "@babel/traverse" "^7.12.5" "@vue/compiler-sfc" "^3.0.5" camelcase "^6.2.0" @@ -9782,10 +9787,10 @@ detective@^5.2.0: defined "^1.0.0" minimist "^1.1.1" -dezalgo@^1.0.0: +dezalgo@1.0.3, dezalgo@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" - integrity sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY= + integrity sha512-K7i4zNfT2kgQz3GylDw40ot9GAE47sFZ9EXHFSPP6zONLgH6kWXE0KWJchkbQJLBkRazq4APwZ4OwiFFlT95OQ== dependencies: asap "^2.0.0" wrappy "1" @@ -11145,16 +11150,16 @@ eth-keyring-controller@^7.0.2: eth-simple-keyring "^4.2.0" obs-store "^4.0.3" -eth-lattice-keyring@^0.7.3: - version "0.7.3" - resolved "https://registry.yarnpkg.com/eth-lattice-keyring/-/eth-lattice-keyring-0.7.3.tgz#fe27b1ff3f81535506be5804801da1bfdc379cbe" - integrity sha512-DVyk316MUU0e/871eO/EFGPnMLT4sRwgft1iZ9dhY5dUcrcjs0G+Vza9/HPvKu7jJm3FPLcL2T3DJUlF4+XmZQ== +eth-lattice-keyring@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/eth-lattice-keyring/-/eth-lattice-keyring-0.11.0.tgz#7df63dc55d168f2a104ef469db78687fc181cb66" + integrity sha512-eFVP4uTvnNYLI3KbpPxqVv/AY9swbCH4ZfqDMsYEZ+vg1UQjnsXAxy4iIUuKR+cF4e8kCKK6hFtALEGxuilcJA== dependencies: "@ethereumjs/common" "2.4.0" "@ethereumjs/tx" "3.3.0" bn.js "^5.2.0" ethereumjs-util "^7.0.10" - gridplus-sdk "^1.2.3" + gridplus-sdk "^2.2.0" rlp "^3.0.0" secp256k1 "4.0.2" @@ -12141,7 +12146,7 @@ fast-redact@^3.0.0: resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.1.1.tgz#790fcff8f808c2e12fabbfb2be5cb2deda448fa0" integrity sha512-odVmjC8x8jNeMZ3C+rPMESzXVSEU8tSWSHv9HFxP2mm89G/1WwqhrerJDQm9Zus8X6aoRgQDThKqptdNA6bt+A== -fast-safe-stringify@^2.0.6, fast-safe-stringify@^2.0.7: +fast-safe-stringify@^2.0.6, fast-safe-stringify@^2.0.7, fast-safe-stringify@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== @@ -12666,6 +12671,16 @@ formidable@^1.2.0: resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.1.tgz#70fb7ca0290ee6ff961090415f4b3df3d2082659" integrity sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg== +formidable@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/formidable/-/formidable-2.0.1.tgz#4310bc7965d185536f9565184dee74fbb75557ff" + integrity sha512-rjTMNbp2BpfQShhFbR3Ruk3qk2y9jKpvMW78nJgx8QKtxjDVrwbZG+wvDOmVbifHyOUOQJXxqEy6r0faRrPzTQ== + dependencies: + dezalgo "1.0.3" + hexoid "1.0.0" + once "1.4.0" + qs "6.9.3" + forwarded@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" @@ -13450,10 +13465,10 @@ graphql-subscriptions@^1.1.0: resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.8.0.tgz#33410e96b012fa3bdb1091cc99a94769db212b38" integrity sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw== -gridplus-sdk@^1.2.3: - version "1.2.4" - resolved "https://registry.yarnpkg.com/gridplus-sdk/-/gridplus-sdk-1.2.4.tgz#3bfd73a65b5af0a23bbc0164e8537981d35dd8db" - integrity sha512-S4Yg48GG+eAuXxO0I5yWnM8w7VFgvLuP0aS7f6L+h+et1FUF3yNIR2sBuFnijcuGVcMy+jqvA66r8iSttBQfQw== +gridplus-sdk@^2.2.0: + version "2.2.4" + resolved "https://registry.yarnpkg.com/gridplus-sdk/-/gridplus-sdk-2.2.4.tgz#1d05fcb460b1670cc4b051796f93cbea1fbce2f4" + integrity sha512-zjG5w5t3mLwBwMPHmfg6AlfaHoV5hKHQE7tFM7IEYnxQYwQG0MSgFghIZFNcp2R0SnG3A8coFhLoSaX/+9SdPA== dependencies: "@ethereumjs/common" "2.4.0" "@ethereumjs/tx" "3.3.0" @@ -13471,7 +13486,7 @@ gridplus-sdk@^1.2.3: js-sha3 "^0.8.0" rlp "^3.0.0" secp256k1 "4.0.2" - superagent "^3.8.3" + superagent "^7.1.3" growl@1.10.5: version "1.10.5" @@ -13942,6 +13957,11 @@ heap@~0.2.6: resolved "https://registry.yarnpkg.com/heap/-/heap-0.2.6.tgz#087e1f10b046932fc8594dd9e6d378afc9d1e5ac" integrity sha1-CH4fELBGky/IWU3Z5tN4r8nR5aw= +hexoid@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hexoid/-/hexoid-1.0.0.tgz#ad10c6573fb907de23d9ec63a711267d9dc9bc18" + integrity sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g== + hi-base32@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/hi-base32/-/hi-base32-0.5.0.tgz#61329f76a31f31008533f1c36f2473e259d64571" @@ -18648,10 +18668,10 @@ mersenne-twister@^1.0.1, mersenne-twister@^1.1.0: resolved "https://registry.yarnpkg.com/mersenne-twister/-/mersenne-twister-1.1.0.tgz#f916618ee43d7179efcf641bec4531eb9670978a" integrity sha1-+RZhjuQ9cXnvz2Qb7EUx65Zwl4o= -methods@^1.1.1, methods@~1.1.2: +methods@^1.1.1, methods@^1.1.2, methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== microevent.ts@~0.1.1: version "0.1.1" @@ -18746,10 +18766,10 @@ mime@1.6.0, mime@^1.4.1: resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== -mime@^2.4.4: - version "2.5.2" - resolved "https://registry.yarnpkg.com/mime/-/mime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe" - integrity sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg== +mime@2.6.0, mime@^2.4.4: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" + integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== mimic-fn@^2.1.0: version "2.1.0" @@ -20169,7 +20189,7 @@ on-headers@~1.0.2: resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== -once@^1.3.0, once@^1.3.1, once@^1.3.2, once@^1.3.3, once@^1.4.0: +once@1.4.0, once@^1.3.0, once@^1.3.1, once@^1.3.2, once@^1.3.3, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= @@ -22333,15 +22353,20 @@ qs@6.7.0: resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== +qs@6.9.3: + version "6.9.3" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.3.tgz#bfadcd296c2d549f1dffa560619132c977f5008e" + integrity sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw== + qs@6.9.6: version "6.9.6" resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.6.tgz#26ed3c8243a431b2924aca84cc90471f35d5a0ee" integrity sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ== -qs@^6.10.0, qs@^6.4.0, qs@^6.5.1, qs@^6.5.2: - version "6.10.1" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.1.tgz#4931482fa8d647a5aab799c5271d2133b981fb6a" - integrity sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg== +qs@^6.10.0, qs@^6.10.3, qs@^6.4.0, qs@^6.5.1, qs@^6.5.2: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== dependencies: side-channel "^1.0.4" @@ -24233,7 +24258,7 @@ semver@7.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== -semver@7.3.7, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5: +semver@7.3.7, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7: version "7.3.7" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== @@ -25592,7 +25617,7 @@ superagent-proxy@^2.0.0, superagent-proxy@^3.0.0: debug "^4.3.2" proxy-agent "^5.0.0" -superagent@^3.8.1, superagent@^3.8.3: +superagent@^3.8.1: version "3.8.3" resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.3.tgz#460ea0dbdb7d5b11bc4f78deba565f86a178e128" integrity sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA== @@ -25608,6 +25633,23 @@ superagent@^3.8.1, superagent@^3.8.3: qs "^6.5.1" readable-stream "^2.3.5" +superagent@^7.1.3: + version "7.1.6" + resolved "https://registry.yarnpkg.com/superagent/-/superagent-7.1.6.tgz#64f303ed4e4aba1e9da319f134107a54cacdc9c6" + integrity sha512-gZkVCQR1gy/oUXr+kxJMLDjla434KmSOKbx5iGD30Ql+AkJQ/YlPKECJy2nhqOsHLjGHzoDTXNSjhnvWhzKk7g== + dependencies: + component-emitter "^1.3.0" + cookiejar "^2.1.3" + debug "^4.3.4" + fast-safe-stringify "^2.1.1" + form-data "^4.0.0" + formidable "^2.0.1" + methods "^1.1.2" + mime "2.6.0" + qs "^6.10.3" + readable-stream "^3.6.0" + semver "^7.3.7" + superstruct@^0.6.0, superstruct@~0.6.0, superstruct@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.6.1.tgz#148fc3d627bb59fcfe24aa1bd2a1b8c51b1db072"