1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-21 09:27:02 +01:00

Merge branch 'develop' of github.com:MetaMask/metamask-extension into minimal

This commit is contained in:
Matthias Kretschmann 2023-09-02 17:01:22 +01:00
commit 6ceb9f7654
Signed by: m
GPG Key ID: 606EEEF3C479A91F
218 changed files with 4447 additions and 2168 deletions

View File

@ -1,5 +1,5 @@
diff --git a/dist/KeyringController.d.ts b/dist/KeyringController.d.ts
index 82de83a7bb1ad14bb23f3b6274e0c4d5bb773382..86a09b3f604f6feb26e2c7edbdcb0abebd4bae20 100644
index ccfd5ca9accf782b0a612ab1666501898cf2abb9..f772552156491b308f2aa29a734a5138237d951e 100644
--- a/dist/KeyringController.d.ts
+++ b/dist/KeyringController.d.ts
@@ -1,10 +1,11 @@
@ -28,7 +28,7 @@ index 82de83a7bb1ad14bb23f3b6274e0c4d5bb773382..86a09b3f604f6feb26e2c7edbdcb0abe
* Adds a new account to the default (first) HD seed phrase keyring.
*
diff --git a/dist/KeyringController.js b/dist/KeyringController.js
index 54d39d266425b45ed1008cecb16e78cf831c75d7..0ddded415bf71716c27ed3bf7bd1c5a79b11be13 100644
index 9e241ba3b5445a053e3b20ee70a579118b7b2934..eb1f7bce9d3607017b39e087db227e8a7dadd849 100644
--- a/dist/KeyringController.js
+++ b/dist/KeyringController.js
@@ -153,6 +153,12 @@ class KeyringController extends base_controller_1.BaseControllerV2 {

View File

@ -6,6 +6,70 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [10.35.1]
### Changed
- Store default gas settings by network ([#20576](https://github.com/MetaMask/metamask-extension/pull/20576), [#20632](https://github.com/MetaMask/metamask-extension/pull/20632))
- Add more diagnostic information upon failure ([#20595](https://github.com/MetaMask/metamask-extension/pull/20595))
### Fixed
- Fix bug resulting in custom network configuration being lost upon restart ([#20586](https://github.com/MetaMask/metamask-extension/pull/20586))
- Fix UI crash when balances are missing ([#20385](https://github.com/MetaMask/metamask-extension/pull/20385))
- Fix infinite rerender on network change while signature request is pending ([#20473](https://github.com/MetaMask/metamask-extension/pull/20473))
- Fix Dapp link on NFT import screen ([#19799](https://github.com/MetaMask/metamask-extension/pull/19799))
- Fix 'View on Opensea' link for main and testnet NFTs ([#19797](https://github.com/MetaMask/metamask-extension/pull/19797))
- Ensure chainId comparison in switchEthereumChain handler is case insensitive ([#20149](https://github.com/MetaMask/metamask-extension/pull/20149))
- Enforce user preferences in incoming transactions controller ([#19982](https://github.com/MetaMask/metamask-extension/pull/19982))
## [10.35.0]
### Added
- Add the ability to customize tx nonce on ERC20 approval screens ([#17945](https://github.com/MetaMask/metamask-extension/pull/17945))
- Improved gas estimates on Base network ([#20097](https://github.com/MetaMask/metamask-extension/pull/20097))
### Changed
- Update the "Spending Cap Request" screen (also known as the "ERC 20 approval" or "token allowance" screen) ([#19666](https://github.com/MetaMask/metamask-extension/pull/19666))
- Populate the "Custom Spending Cap" input with the dapp suggesed value
- Show "Use Site Suggestion" button when user changes input
- Update copy
- Add a "Learn more" link
- Update icons and text of Activity Screen, and categorize transactions by dates ([#19557](https://github.com/MetaMask/metamask-extension/pull/19557))
- Change the "Import NFTs" UI from a full screen page to a modal ([#19806](https://github.com/MetaMask/metamask-extension/pull/19806))
- Add loading indicator when clicking Refresh list on tokens screen ([#19952](https://github.com/MetaMask/metamask-extension/pull/19952))
- Bolden "Done" text for priv key export button ([#20059](https://github.com/MetaMask/metamask-extension/pull/20059))
- Added background color of test network icons in the network menu ([#20032](https://github.com/MetaMask/metamask-extension/pull/20032))
- Ensure "Show test networks" is toggled on if current network is a test network ([#20048](https://github.com/MetaMask/metamask-extension/pull/20048))
- Disable the "Show test networks" toggle when the currently selected network is a test network ([#19951](https://github.com/MetaMask/metamask-extension/pull/19951))
- Increase size of nft detection text ([#20053](https://github.com/MetaMask/metamask-extension/pull/20053))
- Add underline to most link texts on hover ([#19992](https://github.com/MetaMask/metamask-extension/pull/19992))
- Move MetaMask fee and quote list to new line for swap review quote ([#20030](https://github.com/MetaMask/metamask-extension/pull/20030))
- Change the "Import NFTs" UI from a full screen page to a modal ([#19806](https://github.com/MetaMask/metamask-extension/pull/19806))
- Change "Hardware wallet" link text to "Add Hardware wallet" ([#20026](https://github.com/MetaMask/metamask-extension/pull/20026))
- Remove the portfolio icon from the screen (because it is now it the three dot menu) ([#19988](https://github.com/MetaMask/metamask-extension/pull/19988))
- Use System Theme colors for tooltip ([#19954](https://github.com/MetaMask/metamask-extension/pull/19954))
- Separate the test networks from other networks in the "Select a network" popup ([#19812](https://github.com/MetaMask/metamask-extension/pull/19812))
- Update "three dot" menu on token screen ([#19765](https://github.com/MetaMask/metamask-extension/pull/19765))
- Make the token's three-dot menu smaller
- Move it next to the breadcrumbs
- Remove the "Account Details" option from the token detail menu
- Update BNB Chain name from "BNB Smart Chain" to "BNB Chain" ([#19836](https://github.com/MetaMask/metamask-extension/pull/19836))
- [FLASK] Allow Snaps to use `eth_accounts` as a revokable permission ([#19306](https://github.com/MetaMask/metamask-extension/pull/19306))
### Fixed
- Fix "Hold to reveal SRP" button on mobile browsers ([#19847](https://github.com/MetaMask/metamask-extension/pull/19847))
- Correctly show network name and selection when chainIds collide ([#19947](https://github.com/MetaMask/metamask-extension/pull/19947))
- Fix misaligned icons in 'Connected sites' modal ([#19944](https://github.com/MetaMask/metamask-extension/pull/19944))
- Show the icon of the correct network in the "badge" associated with token icon's in the assets list ([#19964](https://github.com/MetaMask/metamask-extension/pull/19964))
- Stop showing "product tour" steps when on the Swaps screen ([#19938](https://github.com/MetaMask/metamask-extension/pull/19938))
- Fixing auto scrolling to settings when searching within Advanced and Security settings ([#19771](https://github.com/MetaMask/metamask-extension/pull/19771))
- Fixed connected sites icon's background color ([#19891](https://github.com/MetaMask/metamask-extension/pull/19891))
- Fix to ensure "Account Details" is displayed when that option is selected from each accounts three-dot menu within the Account Menu ([#19857](https://github.com/MetaMask/metamask-extension/pull/19857))
- Render correct image in the asset dropdown while sending an NFT ([#19787](https://github.com/MetaMask/metamask-extension/pull/19787))
- Removed grey line from connected sites modal if there are no connected sites ([#20036](https://github.com/MetaMask/metamask-extension/pull/20036))
- [FLASK] Fix overflow on snaps connect screen ([#19995](https://github.com/MetaMask/metamask-extension/pull/19995))
- [FLASK] Fix Snaps UI divider ([#19919](https://github.com/MetaMask/metamask-extension/pull/19919))
- [FLASK] Fix fetch for snap registry ([#19866](https://github.com/MetaMask/metamask-extension/pull/19866))
- [FLASK] Fix Snaps UI divider ([#19919](https://github.com/MetaMask/metamask-extension/pull/19919))
## [10.34.5]
### Changed
- Improve error diagnostic information
@ -3896,7 +3960,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Uncategorized
- Added the ability to restore accounts from seed words.
[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.34.5...HEAD
[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.35.1...HEAD
[10.35.1]: https://github.com/MetaMask/metamask-extension/compare/v10.35.0...v10.35.1
[10.35.0]: https://github.com/MetaMask/metamask-extension/compare/v10.34.5...v10.35.0
[10.34.5]: https://github.com/MetaMask/metamask-extension/compare/v10.34.4...v10.34.5
[10.34.4]: https://github.com/MetaMask/metamask-extension/compare/v10.34.3...v10.34.4
[10.34.3]: https://github.com/MetaMask/metamask-extension/compare/v10.34.2...v10.34.3

View File

@ -296,12 +296,6 @@
"advancedConfiguration": {
"message": "Erweiterte Einstellungen"
},
"advancedGasFeeDefaultOptIn": {
"message": "Speichern Sie diese $1 als Standard für \"Erweitert\""
},
"advancedGasFeeDefaultOptOut": {
"message": "Immer diese Werte und erweiterte Einstellung als Standard verwenden."
},
"advancedGasFeeModalTitle": {
"message": "Erweiterte Gasgebühr"
},
@ -2336,9 +2330,6 @@
"more": {
"message": "mehr"
},
"moreComingSoon": {
"message": "Mehr Anbieter in Kürze"
},
"multipleSnapConnectionWarning": {
"message": "$1 möchte sich mit $2 Snaps verbinden. Fahren Sie nur fort, wenn Sie dieser Webseite vertrauen.",
"description": "$1 is the dapp and $2 is the number of snaps it wants to connect to."
@ -2495,9 +2486,6 @@
"newTokensImportedTitle": {
"message": "Token importiert"
},
"newValues": {
"message": "neue Werte"
},
"next": {
"message": "Weiter"
},
@ -2767,12 +2755,6 @@
"notifications23ActionText": {
"message": "Sicherheitswarnungen aktivieren"
},
"notifications23DescriptionOne": {
"message": "Fallen Sie nicht bekannten Betrügereien zum Opfer und schützen Sie gleichzeitig Ihre Privatsphäre mit Sicherheitswarnungen von Blockaid."
},
"notifications23DescriptionThree": {
"message": "Wir haben für Sie diese Funktion aktiviert, wenn Sie die Sicherheitswarnungen von OpenSea erhalten haben."
},
"notifications23DescriptionTwo": {
"message": "Vor der Bestätigung von Anfragen lassen Sie stets die nötige Sorgfalt walten."
},
@ -3658,19 +3640,9 @@
"securityAlerts": {
"message": "Sicherheitswarnung"
},
"securityAlertsDescription1": {
"message": "Diese Funktion warnt Sie vor schädlichen Aktivitäten, indem sie Ihre Transaktionen und Signaturanfragen lokal überprüft. Ihre Daten werden dazu nicht an Dritte weitergegeben, die diesen Dienst anbieten. Denken Sie immer an Ihre eigene Sorgfaltspflicht, bevor Sie Anfragen genehmigen, denn es gibt keine Garantie dafür, dass diese Funktion alle schädlichen Aktivitäten auch tatsächlich erkennt."
},
"securityAlertsDescription2": {
"message": "Achten Sie darauf, Ihrer eigenen Sorgfaltspflicht nachzukommen, bevor Sie eine Anfrage bestätigen. Es gibt keine Garantie dafür, dass alle E-Mail-Aktivitäten von dieser Funktion erkannt werden."
},
"securityAndPrivacy": {
"message": "Sicherheit & Datenschutz"
},
"securityProviderAdviceBy": {
"message": "Sicherheitstipp von $1",
"description": "The security provider that is providing data"
},
"seeDetails": {
"message": "Details anzeigen"
},
@ -3764,9 +3736,6 @@
"selectPathHelp": {
"message": "Wenn Sie Ihre bestehenden Ledger-Konten nachfolgend nicht sehen, versuchen Sie, die Pfade zu \"Legacy (MEW / MyCrypto)\" zu ändern"
},
"selectProvider": {
"message": "Anbieter auswählen:"
},
"selectType": {
"message": "Typ auswählen"
},

View File

@ -296,12 +296,6 @@
"advancedConfiguration": {
"message": "Προηγμένη ρύθμιση παραμέτρων"
},
"advancedGasFeeDefaultOptIn": {
"message": "Αποθηκεύστε αυτά τα $1 ως προεπιλογή μου για το \"Προηγμένο\""
},
"advancedGasFeeDefaultOptOut": {
"message": "Να χρησιμοποιούνται πάντα αυτές τις τιμές και η ρύθμιση για προχωρημένους."
},
"advancedGasFeeModalTitle": {
"message": "Προηγμένη χρέωση τελών συναλλαγής"
},
@ -2336,9 +2330,6 @@
"more": {
"message": "περισσότερα"
},
"moreComingSoon": {
"message": "Προσεχώς περισσότεροι πάροχοι"
},
"multipleSnapConnectionWarning": {
"message": "Το $1 θέλει να συνδεθεί με το snap $2. Προχωρήστε μόνο αν εμπιστεύεστε αυτόν τον ιστότοπο.",
"description": "$1 is the dapp and $2 is the number of snaps it wants to connect to."
@ -2495,9 +2486,6 @@
"newTokensImportedTitle": {
"message": "Τα token εισήχθησαν"
},
"newValues": {
"message": "νέες τιμές"
},
"next": {
"message": "Επόμενο"
},
@ -2767,12 +2755,6 @@
"notifications23ActionText": {
"message": "Ενεργοποίηση ειδοποιήσεων ασφαλείας"
},
"notifications23DescriptionOne": {
"message": "Αποφύγετε τις γνωστές απάτες, διατηρώντας παράλληλα το απόρρητό σας με τις ειδοποιήσεις ασφαλείας της Blockaid."
},
"notifications23DescriptionThree": {
"message": "Εάν ενεργοποιήσατε τις ειδοποιήσεις ασφαλείας από το OpenSea, σας μεταφέραμε σε αυτή τη λειτουργία."
},
"notifications23DescriptionTwo": {
"message": "Κάνετε πάντα τον δικό σας επιμελή έλεγχο προτού εγκρίνετε τα αιτήματα."
},
@ -3658,19 +3640,9 @@
"securityAlerts": {
"message": "Ειδοποιήσεις ασφαλείας"
},
"securityAlertsDescription1": {
"message": "Αυτή η λειτουργία σας προειδοποιεί για κακόβουλη δραστηριότητα, καθώς εξετάζει τοπικά τις συναλλαγές και τα αιτήματα υπογραφής σας. Τα δεδομένα σας δεν κοινοποιούνται στους τρίτους που παρέχουν αυτή την υπηρεσία. Πάντα να προβαίνετε σε δικό σας επιμελή έλεγχο προτού εγκρίνετε οποιαδήποτε αιτήματα. Δεν υπάρχει καμία εγγύηση ότι αυτή η λειτουργία θα εντοπίσει όλες τις κακόβουλες δραστηριότητες."
},
"securityAlertsDescription2": {
"message": "Φροντίστε πάντα να κάνετε τον δικό σας επιμελή έλεγχο προτού εγκρίνετε οποιαδήποτε αιτήματα. Δεν υπάρχει καμία εγγύηση ότι όλες οι κακόβουλες δραστηριότητες θα ανιχνεύονται από αυτή τη λειτουργία."
},
"securityAndPrivacy": {
"message": "Ασφάλεια και Απόρρητο"
},
"securityProviderAdviceBy": {
"message": "Συμβουλές ασφαλείας από $1",
"description": "The security provider that is providing data"
},
"seeDetails": {
"message": "Δείτε λεπτομέρειες"
},
@ -3764,9 +3736,6 @@
"selectPathHelp": {
"message": "Εάν δεν βλέπετε τους αναμενόμενους λογαριασμούς, προσπαθήστε να αλλάξετε το μονοπάτι HD."
},
"selectProvider": {
"message": "Επιλέξτε παρόχους:"
},
"selectType": {
"message": "Επιλέξτε Τύπο"
},

View File

@ -300,10 +300,8 @@
"message": "Advanced configuration"
},
"advancedGasFeeDefaultOptIn": {
"message": "Save these $1 as my default for \"Advanced\""
},
"advancedGasFeeDefaultOptOut": {
"message": "Always use these values and advanced setting as default."
"message": "Save these values as my default for the $1 network.",
"description": "$1 is the current network name."
},
"advancedGasFeeModalTitle": {
"message": "Advanced gas fee"
@ -598,6 +596,12 @@
"bridge": {
"message": "Bridge"
},
"bridgeDescription": {
"message": "Transfer tokens from different networks"
},
"bridgeDisabled": {
"message": "Bridge is not available in this network"
},
"browserNotSupported": {
"message": "Your browser is not supported..."
},
@ -617,6 +621,12 @@
"message": "Buy $1",
"description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase"
},
"buyDescription": {
"message": "Hold up your crypto and earn potential profits"
},
"buyDisabled": {
"message": "Buy is not available in this network"
},
"buyMoreAsset": {
"message": "Buy more $1",
"description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase"
@ -1149,6 +1159,9 @@
"message": "Description from $1",
"description": "$1 represents the name of the snap"
},
"desktopApp": {
"message": "Desktop App"
},
"desktopConnectionCriticalErrorDescription": {
"message": "This error could be intermittent, so try restarting the extension or disable MetaMask Desktop."
},
@ -2342,9 +2355,6 @@
"more": {
"message": "more"
},
"moreComingSoon": {
"message": "More providers coming soon"
},
"multipleSnapConnectionWarning": {
"message": "$1 wants to connect with $2 snaps. Only proceed if you trust this website.",
"description": "$1 is the dapp and $2 is the number of snaps it wants to connect to."
@ -2501,9 +2511,6 @@
"newTokensImportedTitle": {
"message": "Token imported"
},
"newValues": {
"message": "new values"
},
"next": {
"message": "Next"
},
@ -2774,10 +2781,7 @@
"message": "Enable security alerts"
},
"notifications23DescriptionOne": {
"message": "Steer clear of known scams while still preserving your privacy with security alerts powered by Blockaid."
},
"notifications23DescriptionThree": {
"message": "If you enabled security alerts from OpenSea, we've moved you over to this feature."
"message": "Steer clear of known scams while still preserving your privacy with security alerts powered by Blockaid on Ethereum Mainnet."
},
"notifications23DescriptionTwo": {
"message": "Always do your own due diligence before approving requests."
@ -2785,6 +2789,15 @@
"notifications23Title": {
"message": "Stay safe with security alerts"
},
"notifications24ActionText": {
"message": "Got it"
},
"notifications24Description": {
"message": "Advanced gas fee settings are now remembered based on the network you're using. This means you can set specific advanced gas fees for each network and avoid overpaying for gas or stuck transactions."
},
"notifications24Title": {
"message": "Advanced gas fees by network"
},
"notifications3ActionText": {
"message": "Read more",
"description": "The 'call to action' on the button, or link, of the 'Stay secure' notification. Upon clicking, users will be taken to a page about security on the metamask support website."
@ -2866,6 +2879,14 @@
"notifications9Title": {
"message": "👓 We are making transactions easier to read."
},
"notificationsDropLedgerFirefoxDescription": {
"message": "Firefox no longer supports U2F, so Ledger won't work with MetaMask on Firefox. Try MetaMask on Google Chrome instead.",
"description": "Description of a notification in the 'See What's New' popup. Describes that ledger will not longer be supported for firefox users and they should use MetaMask on chrome for ledger support instead."
},
"notificationsDropLedgerFirefoxTitle": {
"message": "Dropping Ledger Support for Firefox",
"description": "Title for a notification in the 'See What's New' popup. Tells firefox users that ledger support is being dropped."
},
"notificationsEmptyText": {
"message": "This is where you can find notifications from your installed snaps."
},
@ -3664,17 +3685,14 @@
"securityAlerts": {
"message": "Security alerts"
},
"securityAlertsDescription1": {
"message": "This feature alerts you to malicious activity by locally reviewing your transactions and signature requests. Your data isn't shared with the third parties providing this service. Always do your own due diligence before approving any requests. There's no guarantee that this feature will detect all malicious activity."
},
"securityAlertsDescription2": {
"message": "Always be sure to do your own due diligence before approving any requests. There's no guarantee all mailcious activity will be detected by this feature."
"securityAlertsDescription": {
"message": "This feature alerts you to malicious activity on Ethereum Mainnet by actively reviewing transaction and signature requests while preserving your privacy. Your data isn't shared with the third party providing this service. Always do your own due diligence before approving any requests. There's no guarantee that this feature will detect all malicious activity."
},
"securityAndPrivacy": {
"message": "Security & privacy"
},
"securityProviderAdviceBy": {
"message": "Security advice by $1",
"securityProviderPoweredBy": {
"message": "Powered by $1",
"description": "The security provider that is providing data"
},
"seeDetails": {
@ -3758,6 +3776,9 @@
"selectAnAccountHelp": {
"message": "Select the custodian accounts to use in MetaMask Institutional."
},
"selectAnAction": {
"message": "Select an action"
},
"selectHdPath": {
"message": "Select HD path"
},
@ -3770,9 +3791,6 @@
"selectPathHelp": {
"message": "If you don't see the accounts you expect, try switching the HD path."
},
"selectProvider": {
"message": "Select providers:"
},
"selectType": {
"message": "Select Type"
},
@ -3785,6 +3803,9 @@
"sendBugReport": {
"message": "Send us a bug report."
},
"sendDescription": {
"message": "Send crypto to any account"
},
"sendSpecifiedTokens": {
"message": "Send $1",
"description": "Symbol of the specified token"
@ -4231,6 +4252,9 @@
"stake": {
"message": "Stake"
},
"stakeDescription": {
"message": "Hold up your crypto and earn potential profits"
},
"stateLogError": {
"message": "Error in retrieving state logs."
},
@ -4422,9 +4446,15 @@
"swapDecentralizedExchange": {
"message": "Decentralized exchange"
},
"swapDescription": {
"message": "Swap and trade your tokens"
},
"swapDirectContract": {
"message": "Direct contract"
},
"swapDisabled": {
"message": "Swap is not available in this network"
},
"swapEditLimit": {
"message": "Edit limit"
},
@ -4699,6 +4729,9 @@
"message": "We were unable to retrieve your $1 balance",
"description": "This message communicates to the user that their balance of a given token is currently unavailable. $1 will be replaced by a token symbol"
},
"swapTokenNotAvailable": {
"message": "Token is not available to swap in this region"
},
"swapTokenToToken": {
"message": "Swap $1 to $2",
"description": "Used in the transaction display list to describe a swap. $1 and $2 are the symbols of tokens in involved in a swap."

View File

@ -296,12 +296,6 @@
"advancedConfiguration": {
"message": "Configuración avanzada"
},
"advancedGasFeeDefaultOptIn": {
"message": "Guarda estos 1$ como mi valor predeterminado para \"Avanzado\""
},
"advancedGasFeeDefaultOptOut": {
"message": "Usar siempre estos valores y la configuración avanzada como valores predeterminados."
},
"advancedGasFeeModalTitle": {
"message": "Tarifa de gas avanzada"
},
@ -2336,9 +2330,6 @@
"more": {
"message": "más"
},
"moreComingSoon": {
"message": "Muy pronto más proveedores"
},
"multipleSnapConnectionWarning": {
"message": "$1 quiere conectarse con $2 complementos. Continúe solo si confía en este sitio web.",
"description": "$1 is the dapp and $2 is the number of snaps it wants to connect to."
@ -2495,9 +2486,6 @@
"newTokensImportedTitle": {
"message": "Token importado"
},
"newValues": {
"message": "nuevos valores"
},
"next": {
"message": "Siguiente"
},
@ -2767,12 +2755,6 @@
"notifications23ActionText": {
"message": "Habilitar alertas de seguridad"
},
"notifications23DescriptionOne": {
"message": "Aléjese de las estafas conocidas mientras conserva su privacidad con las alertas de seguridad impulsadas por Blockaid."
},
"notifications23DescriptionThree": {
"message": "Si habilitó las alertas de seguridad de OpenSea, lo trasladamos a esta función."
},
"notifications23DescriptionTwo": {
"message": "Siempre asegúrese de hacer su propia diligencia debida antes de aprobar cualquier solicitud."
},
@ -3658,19 +3640,9 @@
"securityAlerts": {
"message": "Alertas de seguridad"
},
"securityAlertsDescription1": {
"message": "Esta función lo alerta sobre actividades maliciosas al revisar localmente sus transacciones y solicitudes de firma. Sus datos no se comparten con los terceros que brindan este servicio. Siempre haga su propia diligencia debida antes de aprobar cualquier solicitud. No hay garantía de que esta característica detecte todas la actividades maliciosas."
},
"securityAlertsDescription2": {
"message": "Siempre asegúrese de hacer su propia diligencia debida antes de aprobar cualquier solicitud. No hay garantía de que esta característica detecte toda la actividad maliciosa."
},
"securityAndPrivacy": {
"message": "Seguridad y privacidad"
},
"securityProviderAdviceBy": {
"message": "Asesoramiento de seguridad por $1",
"description": "The security provider that is providing data"
},
"seeDetails": {
"message": "Ver detalles"
},
@ -3764,9 +3736,6 @@
"selectPathHelp": {
"message": "Si no ve sus cuentas existentes en Ledger a continuación, intente cambiar de ruta de acceso a \"Legacy (MEW / MyCrypto)\""
},
"selectProvider": {
"message": "Seleccionar proveedores:"
},
"selectType": {
"message": "Seleccionar tipo"
},

View File

@ -145,12 +145,6 @@
"advancedBaseGasFeeToolTip": {
"message": "Cuando su transacción se incluya en el bloque, se reembolsará cualquier diferencia entre su tarifa base máxima y la tarifa base real. El importe total se calcula como tarifa base máxima (en GWEI) * límite de gas."
},
"advancedGasFeeDefaultOptIn": {
"message": "Guarda estos 1$ como mi valor predeterminado para \"Avanzado\""
},
"advancedGasFeeDefaultOptOut": {
"message": "Usar siempre estos valores y la configuración avanzada como valores predeterminados."
},
"advancedGasFeeModalTitle": {
"message": "Tarifa de gas avanzada"
},
@ -1410,9 +1404,6 @@
"newPassword": {
"message": "Contraseña nueva (mín. de 8 caracteres)"
},
"newValues": {
"message": "nuevos valores"
},
"next": {
"message": "Siguiente"
},

View File

@ -296,12 +296,6 @@
"advancedConfiguration": {
"message": "Configuration avancée"
},
"advancedGasFeeDefaultOptIn": {
"message": "Enregistrer ces $1 comme valeur par défaut pour «Avancé»"
},
"advancedGasFeeDefaultOptOut": {
"message": "Toujours utiliser par défaut ces valeurs et les paramètres avancés."
},
"advancedGasFeeModalTitle": {
"message": "Frais de carburant avancés"
},
@ -415,7 +409,7 @@
"message": "Tant que vous naurez pas révoqué cette autorisation, lautre partie pourra accéder à votre portefeuille et transférer sans préavis les NFT suivants."
},
"approveTokenDescriptionWithoutSymbol": {
"message": "Tant que vous naurez pas révoqué cette autorisation, lautre partie pourra accéder à votre portefeuille et transférer sans préavis les NFT via $1$.",
"message": "Tant que vous naurez pas révoqué cette autorisation, lautre partie pourra accéder à votre portefeuille et transférer sans préavis les NFT via $1.",
"description": "$1 is a link to contract on the block explorer when we're not able to retrieve a erc721 or erc1155 name"
},
"approveTokenTitle": {
@ -2336,9 +2330,6 @@
"more": {
"message": "plus"
},
"moreComingSoon": {
"message": "Dautres fournisseurs seront bientôt disponibles"
},
"multipleSnapConnectionWarning": {
"message": "$1 veut se connecter avec $2 snaps. Ne procédez que si vous avez confiance dans ce site web.",
"description": "$1 is the dapp and $2 is the number of snaps it wants to connect to."
@ -2495,9 +2486,6 @@
"newTokensImportedTitle": {
"message": "Jeton importé"
},
"newValues": {
"message": "nouvelles valeurs"
},
"next": {
"message": "Suivant"
},
@ -2767,12 +2755,6 @@
"notifications23ActionText": {
"message": "Activer les alertes de sécurité"
},
"notifications23DescriptionOne": {
"message": "Évitez les escroqueries et protégez vos donnés personnelles grâce aux alertes de sécurité fournies par Blockaid."
},
"notifications23DescriptionThree": {
"message": "Les utilisateurs qui ont déjà activé les alertes de sécurité OpenSea recevront désormais des alertes de sécurité de ce nouveau fournisseur."
},
"notifications23DescriptionTwo": {
"message": "Vous devez faire preuve de diligence raisonnable avant dapprouver toute demande."
},
@ -3658,19 +3640,9 @@
"securityAlerts": {
"message": "Alertes de sécurité"
},
"securityAlertsDescription1": {
"message": "Cette fonctionnalité vous avertit de toute activité malveillante en examinant localement vos transactions et vos demandes de signature. Vos données ne sont pas partagées avec les tiers qui fournissent ce service. Vous devez faire preuve de diligence raisonnable avant dapprouver toute demande. Rien ne garantit que toutes les activités malveillantes seront détectées par cette fonctionnalité."
},
"securityAlertsDescription2": {
"message": "Vous devez faire preuve de diligence raisonnable avant dapprouver toute demande. Rien ne garantit que toutes les activités malveillantes seront détectées par cette fonctionnalité."
},
"securityAndPrivacy": {
"message": "Sécurité et confidentialité"
},
"securityProviderAdviceBy": {
"message": "Conseils de sécurité fournis par $1",
"description": "The security provider that is providing data"
},
"seeDetails": {
"message": "Voir les détails"
},
@ -3764,9 +3736,6 @@
"selectPathHelp": {
"message": "Si vos comptes napparaissent pas ci-dessous, essayez de sélectionner le chemin HD."
},
"selectProvider": {
"message": "Sélectionner les fournisseurs :"
},
"selectType": {
"message": "Sélectionner le type"
},

View File

@ -296,12 +296,6 @@
"advancedConfiguration": {
"message": "उन्नत कंफिगुरेशन"
},
"advancedGasFeeDefaultOptIn": {
"message": "इन $1 को \"एडवांस\" के लिए मेरे डिफॉल्ट के रूप में सहेजें"
},
"advancedGasFeeDefaultOptOut": {
"message": "हमेशा इन मूल्यों और एडवांस सेटिंग को डिफॉल्ट के रूप में उपयोग करें।"
},
"advancedGasFeeModalTitle": {
"message": "एडवांस गैस शुल्क"
},
@ -2336,9 +2330,6 @@
"more": {
"message": "अधिक"
},
"moreComingSoon": {
"message": "जल्द ही और प्रोवाइडर उपलब्ध होंगे"
},
"multipleSnapConnectionWarning": {
"message": "$1 चाहता है कि $2 स्नैप्स के साथ जुड़े। तभी आगे बढ़ें अगर आप इस वेबसाइट पर भरोसा करते हैं।",
"description": "$1 is the dapp and $2 is the number of snaps it wants to connect to."
@ -2495,9 +2486,6 @@
"newTokensImportedTitle": {
"message": "टोकन इम्पोर्ट हो गया"
},
"newValues": {
"message": "नए मान"
},
"next": {
"message": "अगला"
},
@ -2767,12 +2755,6 @@
"notifications23ActionText": {
"message": "सुरक्षा अलर्ट सक्षम करें"
},
"notifications23DescriptionOne": {
"message": "Blockaid द्वारा संचालित सुरक्षा अलर्ट के साथ अपनी गोपनीयता बनाए रखते हुए ज्ञात घोटालों से दूर रहें।"
},
"notifications23DescriptionThree": {
"message": "यदि आपने OpenSea से सुरक्षा अलर्ट सक्षम किया है, तो हमने आपको इस फीचर पर ला दिया है।"
},
"notifications23DescriptionTwo": {
"message": "अनुरोध को स्वीकार करने से पहले हमेशा अपनी खुद की सावधानी बरतें।"
},
@ -3658,19 +3640,9 @@
"securityAlerts": {
"message": "सुरक्षा चेतावनी"
},
"securityAlertsDescription1": {
"message": "यह फीचर स्थानीय रूप से आपके लेनदेन और हस्ताक्षर अनुरोधों की समीक्षा करके आपको दुर्भावनापूर्ण गतिविधि के प्रति सचेत करती है। आपका डेटा यह सेवा प्रदान करने वाले तृतीय पक्षों के साथ साझा नहीं किया जाता है। किसी भी अनुरोध को मंजूरी देने से पहले हमेशा जांच करें। इस बात की कोई गारंटी नहीं है कि यह फीचर सभी दुर्भावनापूर्ण गतिविधियों का पता लगा लेगी।"
},
"securityAlertsDescription2": {
"message": "किसी भी अनुरोध को मंज़ूरी देने से पहले हमेशा पूरी जांच-पड़ताल ज़रूर करें। इस बात की कोई गारंटी नहीं है कि इस सुविधा के माध्यम से बुरी नीयत से की गई सभी गतिविधि का पता लगाया जा सकेगा।"
},
"securityAndPrivacy": {
"message": "सुरक्षा और गोपनीयता"
},
"securityProviderAdviceBy": {
"message": "$1 की ओर से सुरक्षा सलाह",
"description": "The security provider that is providing data"
},
"seeDetails": {
"message": "ब्यौरा देखें"
},
@ -3764,9 +3736,6 @@
"selectPathHelp": {
"message": "यदि आपको अपेक्षित खाते दिखाई नहीं देते हैं, तो HD पथ बदलने का प्रयास करें।"
},
"selectProvider": {
"message": "प्रदाताओं का चयन करें:"
},
"selectType": {
"message": "प्रकार का चयन करें"
},

View File

@ -296,12 +296,6 @@
"advancedConfiguration": {
"message": "Konfigurasi lanjutan"
},
"advancedGasFeeDefaultOptIn": {
"message": "Simpan $1 ini sebagai default saya untuk \"Lanjutan\""
},
"advancedGasFeeDefaultOptOut": {
"message": "Selalu gunakan nilai ini dan pengaturan lanjutan sebagai default."
},
"advancedGasFeeModalTitle": {
"message": "Biaya gas lanjutan"
},
@ -2336,9 +2330,6 @@
"more": {
"message": "selengkapnya"
},
"moreComingSoon": {
"message": "Penyedia lainnya akan segera hadir"
},
"multipleSnapConnectionWarning": {
"message": "$1 ingin terhubung dengan $2 snap. Hanya lanjutkan jika Anda memercayai situs web ini.",
"description": "$1 is the dapp and $2 is the number of snaps it wants to connect to."
@ -2495,9 +2486,6 @@
"newTokensImportedTitle": {
"message": "Token diimpor"
},
"newValues": {
"message": "nilai baru"
},
"next": {
"message": "Berikutnya"
},
@ -2767,12 +2755,6 @@
"notifications23ActionText": {
"message": "Aktifkan peringatan keamanan"
},
"notifications23DescriptionOne": {
"message": "Hindari penipuan yang terdeteksi sambil tetap menjaga privasi Anda dengan peringatan keamanan yang didukung oleh Blockaid."
},
"notifications23DescriptionThree": {
"message": "Jika Anda mengaktifkan peringatan keamanan dari OpenSea, kami telah memindahkan Anda ke fitur ini."
},
"notifications23DescriptionTwo": {
"message": "Selalu lakukan uji tuntas sendiri sebelum menyetujui permintaan."
},
@ -3658,19 +3640,9 @@
"securityAlerts": {
"message": "Peringatan keamanan"
},
"securityAlertsDescription1": {
"message": "Fitur ini memberi tahu Anda seputar aktivitas berbahaya dengan meninjau transaksi dan permintaan tanda tangan Anda secara lokal. Data Anda tidak dibagikan kepada pihak ketiga yang menyediakan layanan ini. Selalu lakukan uji tuntas sendiri sebelum menyetujui permintaan apa pun. Tidak ada jaminan bahwa fitur ini akan mendeteksi semua aktivitas berbahaya."
},
"securityAlertsDescription2": {
"message": "Pastikan untuk selalu melakukan uji tuntas sebelum menyetujui permintaan apa pun. Tidak ada jaminan semua aktivitas berbahaya akan terdeteksi oleh fitur ini."
},
"securityAndPrivacy": {
"message": "Keamanan & privasi"
},
"securityProviderAdviceBy": {
"message": "Saran keamanan dari $1",
"description": "The security provider that is providing data"
},
"seeDetails": {
"message": "Lihat detailnya"
},
@ -3764,9 +3736,6 @@
"selectPathHelp": {
"message": "Jika Anda tidak menemukan akun yang diharapkan, coba alihkan jalur HD."
},
"selectProvider": {
"message": "Pilih penyedia:"
},
"selectType": {
"message": "Pilih Jenis"
},

View File

@ -210,12 +210,6 @@
"advancedBaseGasFeeToolTip": {
"message": "Quando la tua transazione viene inclusa nel blocco, ogni differenza tra la tua offerta massima di gas e il gas effettivamente utilizzato viene restituita a te. Il totale viene calcolato come offerta massima di gas (in GEWI) * limite di gas."
},
"advancedGasFeeDefaultOptIn": {
"message": "Salva queste $1 come mie preferite per \"Avanzate\""
},
"advancedGasFeeDefaultOptOut": {
"message": "Utilizzare sempre questi valori e l'impostazione avanzata come predefiniti."
},
"advancedGasFeeModalTitle": {
"message": "Tariffa gas avanzata"
},

View File

@ -296,12 +296,6 @@
"advancedConfiguration": {
"message": "詳細設定"
},
"advancedGasFeeDefaultOptIn": {
"message": "これらの$1を「高度な設定」のデフォルトとして保存"
},
"advancedGasFeeDefaultOptOut": {
"message": "常にこれらの値と高度な設定をデフォルトとして使用します。"
},
"advancedGasFeeModalTitle": {
"message": "高度なガス代"
},
@ -2336,9 +2330,6 @@
"more": {
"message": "他"
},
"moreComingSoon": {
"message": "他のプロバイダーも近日追加予定"
},
"multipleSnapConnectionWarning": {
"message": "$1 が $2 個のスナップとの接続を要求しています。この Web サイトが信頼できる場合にのみ続行してください。",
"description": "$1 is the dapp and $2 is the number of snaps it wants to connect to."
@ -2495,9 +2486,6 @@
"newTokensImportedTitle": {
"message": "トークンがインポートされました"
},
"newValues": {
"message": "新しい値"
},
"next": {
"message": "次へ"
},
@ -2767,12 +2755,6 @@
"notifications23ActionText": {
"message": "セキュリティアラートを有効にする"
},
"notifications23DescriptionOne": {
"message": "Blockaid によるセキュリティアラートを使用して、プライバシーを守りつつ既知の詐欺を回避しましょう。"
},
"notifications23DescriptionThree": {
"message": "OpenSea のセキュリティアラートを有効にしていた場合、この機能に移行されました。"
},
"notifications23DescriptionTwo": {
"message": "要求を承認する前に、必ず独自のデューデリジェンスを行ってください。"
},
@ -3658,19 +3640,9 @@
"securityAlerts": {
"message": "、セキュリティアラート"
},
"securityAlertsDescription1": {
"message": "この機能は、トランザクションと署名要求をローカルで確認することで、悪質な行為に対する警告を発します。ユーザーのデータはこのサービスを提供するサードパーティと共有されません。要求を承認する前には、必ず独自のデューデリジェンスを行ってください。この機能がすべての悪質な行為を検出するという保証はありません。"
},
"securityAlertsDescription2": {
"message": "要求を承認する前に、常に独自のデューデリジェンスを行うようにしてください。この機能によりすべての悪質な行為の検出が保証されているわけではありません。"
},
"securityAndPrivacy": {
"message": "セキュリティとプライバシー"
},
"securityProviderAdviceBy": {
"message": "$1 によるセキュリティアドバイス",
"description": "The security provider that is providing data"
},
"seeDetails": {
"message": "詳細を表示"
},
@ -3764,9 +3736,6 @@
"selectPathHelp": {
"message": "アカウントが見当たらない場合は、HDパスを切り替えてみてください。"
},
"selectProvider": {
"message": "プロバイダーを選択してください:"
},
"selectType": {
"message": "種類を選択"
},

View File

@ -296,12 +296,6 @@
"advancedConfiguration": {
"message": "고급 옵션"
},
"advancedGasFeeDefaultOptIn": {
"message": "이 $1 옵션을 \"고급\"의 기본값으로 저장합니다"
},
"advancedGasFeeDefaultOptOut": {
"message": "항상 이 값과 고급 설정을 기본값으로 사용합니다."
},
"advancedGasFeeModalTitle": {
"message": "고급 가스 요금"
},
@ -2336,9 +2330,6 @@
"more": {
"message": "그 외"
},
"moreComingSoon": {
"message": "더 많은 공급업체가 곧 추가됩니다"
},
"multipleSnapConnectionWarning": {
"message": "$1에서 $2개의 스냅 연결을 원합니다. 해당 웹사이트를 신뢰할 수 있는 경우에만 진행하세요.",
"description": "$1 is the dapp and $2 is the number of snaps it wants to connect to."
@ -2495,9 +2486,6 @@
"newTokensImportedTitle": {
"message": "불러온 토큰"
},
"newValues": {
"message": "새로운 가치"
},
"next": {
"message": "다음"
},
@ -2767,12 +2755,6 @@
"notifications23ActionText": {
"message": "보안 알림 활성화"
},
"notifications23DescriptionOne": {
"message": "Blockaid가 제공하는 보안 알림을 통해 개인정보를 보호하면서 알려진 사기를 피하세요."
},
"notifications23DescriptionThree": {
"message": "OpenSea에서 보안 알림을 활성화하면, 이 기능으로 이동합니다."
},
"notifications23DescriptionTwo": {
"message": "요청을 승인하기 전에 항상 직접 실사하세요."
},
@ -3658,19 +3640,9 @@
"securityAlerts": {
"message": "보안 알림"
},
"securityAlertsDescription1": {
"message": "이 기능은 거래 및 서명 요청을 로컬에서 검토하여 악의적인 활동이 있는 경우 경고합니다. 사용자 데이터는 이 서비스를 제공하는 제3자와 공유되지 않습니다. 요청을 승인하기 전에 항상 직접 실사하세요. 이 기능이 모든 악성 활동 탐지를 보장하지는 않습니다."
},
"securityAlertsDescription2": {
"message": "요청을 승인하기 전에 항상 직접 확인하세요. 이 기능을 통해 모든 악의적인 활동이 감지된다는 보장이 없습니다."
},
"securityAndPrivacy": {
"message": "보안 및 프라이버시"
},
"securityProviderAdviceBy": {
"message": "$1의 보안 권고",
"description": "The security provider that is providing data"
},
"seeDetails": {
"message": "세부 정보 보기"
},
@ -3764,9 +3736,6 @@
"selectPathHelp": {
"message": "아래에 기존 Ledger 계정이 표시되지 않는다면 경로를 \"Legacy (MEW / MyCrypto)\"로 변경해 보세요."
},
"selectProvider": {
"message": "공급업체 선택"
},
"selectType": {
"message": "유형 선택"
},

View File

@ -296,12 +296,6 @@
"advancedConfiguration": {
"message": "Configurações avançadas"
},
"advancedGasFeeDefaultOptIn": {
"message": "Salvar estes $1 como meu padrão para \"Avançado\""
},
"advancedGasFeeDefaultOptOut": {
"message": "Sempre utilizar esses valores e a configuração avançada por padrão."
},
"advancedGasFeeModalTitle": {
"message": "Taxa de gás avançada"
},
@ -2336,9 +2330,6 @@
"more": {
"message": "mais"
},
"moreComingSoon": {
"message": "Mais provedores em breve"
},
"multipleSnapConnectionWarning": {
"message": "$1 deseja conectar-se a $2 snaps. Prossiga apenas se você confia no site.",
"description": "$1 is the dapp and $2 is the number of snaps it wants to connect to."
@ -2495,9 +2486,6 @@
"newTokensImportedTitle": {
"message": "Token importado"
},
"newValues": {
"message": "novos valores"
},
"next": {
"message": "Próximo"
},
@ -2764,15 +2752,6 @@
"notifications22Title": {
"message": "Procurando os dados da sua conta ou o URL do explorador de blocos?"
},
"notifications23ActionText": {
"message": "Ativar alertas de segurança"
},
"notifications23DescriptionOne": {
"message": "Fique longe de golpes conhecidos enquanto preserva sua privacidade com alertas de segurança com tecnologia da Blockaid."
},
"notifications23DescriptionThree": {
"message": "Se você ativou os alertas de segurança da OpenSea, fizemos sua transição para esse recurso."
},
"notifications23DescriptionTwo": {
"message": "Sempre faça sua própria devida diligência antes de aprovar solicitações."
},
@ -3658,19 +3637,9 @@
"securityAlerts": {
"message": "Alertas de segurança"
},
"securityAlertsDescription1": {
"message": "Esse recurso alerta sobre atividades mal-intencionadas ao analisar localmente suas transações e solicitações de assinatura. Seus dados não são compartilhados com os terceiros prestadores do serviço. Sempre faça sua própria devida diligência antes de aprovar qualquer solicitação. Não há garantia de que esse recurso detectará toda e qualquer atividade mal-intencionada."
},
"securityAlertsDescription2": {
"message": "Sempre se certifique de fazer a devida diligência por conta própria antes de aprovar eventuais solicitações. Não há garantia de que toda e qualquer atividade mal-intencionada será detectada por esse recurso."
},
"securityAndPrivacy": {
"message": "Segurança e privacidade"
},
"securityProviderAdviceBy": {
"message": "Conselhos de segurança de $1",
"description": "The security provider that is providing data"
},
"seeDetails": {
"message": "Ver detalhes"
},
@ -3764,9 +3733,6 @@
"selectPathHelp": {
"message": "Se você não vir as contas esperadas, tente trocar o caminho do HD."
},
"selectProvider": {
"message": "Selecione os provedores:"
},
"selectType": {
"message": "Selecionar Tipo"
},

View File

@ -145,12 +145,6 @@
"advancedBaseGasFeeToolTip": {
"message": "Quando a sua transação for incluída no bloco, qualquer diferença entre a sua taxa de base máxima e a taxa de base real será reembolsada. O cálculo do valor total é feito da seguinte forma: taxa de base máxima (em GWEI) * limite de gás."
},
"advancedGasFeeDefaultOptIn": {
"message": "Salvar estes $1 como meu padrão para \"Avançado\""
},
"advancedGasFeeDefaultOptOut": {
"message": "Sempre utilizar esses valores e a configuração avançada por padrão."
},
"advancedGasFeeModalTitle": {
"message": "Taxa de gás avançada"
},
@ -1410,9 +1404,6 @@
"newPassword": {
"message": "Nova senha (no mínimo 8 caracteres)"
},
"newValues": {
"message": "novos valores"
},
"next": {
"message": "Seguinte"
},

View File

@ -296,12 +296,6 @@
"advancedConfiguration": {
"message": "Расширенная конфигурация"
},
"advancedGasFeeDefaultOptIn": {
"message": "Сохранить этот $1 в качестве моего значения по умолчанию для «Дополнительной» настройки"
},
"advancedGasFeeDefaultOptOut": {
"message": "Всегда использовать эти значения и дополнительную настройку по умолчанию."
},
"advancedGasFeeModalTitle": {
"message": "Дополнительная плата за газ"
},
@ -2336,9 +2330,6 @@
"more": {
"message": "больше"
},
"moreComingSoon": {
"message": "Скоро появятся другие поставщики"
},
"multipleSnapConnectionWarning": {
"message": "$1 хочет подключиться с помощью привязок $2. Продолжайте, только если вы доверяете этому веб-сайту.",
"description": "$1 is the dapp and $2 is the number of snaps it wants to connect to."
@ -2495,9 +2486,6 @@
"newTokensImportedTitle": {
"message": "Токен импортирован"
},
"newValues": {
"message": "новые значения"
},
"next": {
"message": "Далее"
},
@ -2767,12 +2755,6 @@
"notifications23ActionText": {
"message": "Включить оповещения безопасности"
},
"notifications23DescriptionOne": {
"message": "Избегайте известных мошенников, сохраняя при этом свою конфиденциальность с помощью оповещений безопасности Blockaid."
},
"notifications23DescriptionThree": {
"message": "Если вы включили оповещения безопасности от OpenSea, мы активировали для вас эту функцию."
},
"notifications23DescriptionTwo": {
"message": "Всегда проводите собственную комплексную проверку перед утверждением запросов."
},
@ -3658,19 +3640,9 @@
"securityAlerts": {
"message": "Оповещения безопасности"
},
"securityAlertsDescription1": {
"message": "Эта функция предупреждает вас о вредоносных действиях, локально просматривая ваши транзакции и запросы подписания. Ваши данные не передаются третьим сторонам, предоставляющим эту услугу. Всегда проводите комплексную проверку, прежде чем одобрять какие-либо запросы. Нет гарантии, что эта функция обнаружит все вредоносные действия."
},
"securityAlertsDescription2": {
"message": "Всегда обязательно проводите собственную комплексную проверку, прежде чем одобрять какие-либо запросы. Нет никакой гарантии, что эта функция обнаружит все вредоносные действия."
},
"securityAndPrivacy": {
"message": "Безопасность и конфиденциальность"
},
"securityProviderAdviceBy": {
"message": "Совет по безопасности от $1",
"description": "The security provider that is providing data"
},
"seeDetails": {
"message": "См. подробности"
},
@ -3764,9 +3736,6 @@
"selectPathHelp": {
"message": "Если вы не видите ожидаемые счета, попробуйте переключиться на путь HD."
},
"selectProvider": {
"message": "Выберите поставщиков:"
},
"selectType": {
"message": "Выбрать тип"
},

View File

@ -296,12 +296,6 @@
"advancedConfiguration": {
"message": "Advanced na pagsasaayos"
},
"advancedGasFeeDefaultOptIn": {
"message": "I-save itong mga $1bilang aking default para sa \"Advanced\""
},
"advancedGasFeeDefaultOptOut": {
"message": "Laging gamitin ang mga value na ito at advanced setting bilang default."
},
"advancedGasFeeModalTitle": {
"message": "Advanced na gas fee"
},
@ -2336,9 +2330,6 @@
"more": {
"message": "higit pa"
},
"moreComingSoon": {
"message": "Parating na ang mas maraming provider"
},
"multipleSnapConnectionWarning": {
"message": "Gustong kumonekta ng $1 sa $2 (na) snap. Magpatuloy lang kung pinagkakatiwalaan mo ang website na ito.",
"description": "$1 is the dapp and $2 is the number of snaps it wants to connect to."
@ -2495,9 +2486,6 @@
"newTokensImportedTitle": {
"message": "Na-import ang token"
},
"newValues": {
"message": "bagong value"
},
"next": {
"message": "Susunod"
},
@ -2767,12 +2755,6 @@
"notifications23ActionText": {
"message": "Pinapagana ang mga alerto sa seguridad"
},
"notifications23DescriptionOne": {
"message": "Iniiwasan ang mga kilalang scam habang pinapanatili pa rin ang pagpapanatili ng iyong privacy gamit ang mga alerto ng seguridad na pinatatakbo ng Blockaid."
},
"notifications23DescriptionThree": {
"message": "Kung pinagana mo ang mga alerto ng seguridad mula sa OpenSea, inilipat ka namin sa feature na ito."
},
"notifications23DescriptionTwo": {
"message": "Palaging gumawa ng sarili mong pagsusuri bago aprubahan ang mga kahilingan."
},
@ -3658,19 +3640,9 @@
"securityAlerts": {
"message": "Mga alerto sa seguridad"
},
"securityAlertsDescription1": {
"message": "Ang feature na ito ay nagbibigay ng alerto sa iyo sa malisyosong aktibidad sa pamamagitan ng lokal na pagsusuri sa iyong mga transaksyon at kahilingan sa pagpirma. Ang iyong data ay hindi ibinabahagi sa mga third party na nagbibigay ng serbisyong ito. Palaging gumawa ng sarili mong pagsusuri bago aprubahan ang anumang mga kahilingan. Walang garantiya na made-detect ng feature na ito ang lahat ng malisyosong aktibidad."
},
"securityAlertsDescription2": {
"message": "Laging tiyakin na isasagawa ang sariling pagsusuri bago pahintulutan ang anumang kahilingan. Walang garantiya na ang lahat ng malisyosong aktibidad ay matutuklasan ng feature na ito."
},
"securityAndPrivacy": {
"message": "Seguridad at Pagkapribado"
},
"securityProviderAdviceBy": {
"message": "Abiso sa seguridad ng $1",
"description": "The security provider that is providing data"
},
"seeDetails": {
"message": "Tingnan ang mga detalye"
},
@ -3764,9 +3736,6 @@
"selectPathHelp": {
"message": "Kung hindi mo makita ang mga account na inaasahan mo, subukang ilipat sa HD path."
},
"selectProvider": {
"message": "Pumili ng mga provider:"
},
"selectType": {
"message": "Pumili ng Uri"
},

View File

@ -296,12 +296,6 @@
"advancedConfiguration": {
"message": "Gelişmiş yapılandırma"
},
"advancedGasFeeDefaultOptIn": {
"message": "\"Gelişmiş\" için şunları varsayılanım olarak kaydet: $1"
},
"advancedGasFeeDefaultOptOut": {
"message": "Varsayılan olarak her zaman bu değerleri ve gelişmiş ayarı kullan."
},
"advancedGasFeeModalTitle": {
"message": "Gelişmiş gaz ücreti"
},
@ -2336,9 +2330,6 @@
"more": {
"message": "daha fazla"
},
"moreComingSoon": {
"message": "Daha fazla sağlayıcı çok yakında"
},
"multipleSnapConnectionWarning": {
"message": "$1, $2 snap'lerine bağlanmak istiyor. Bu web sitesine güveniyorsanız ilerleyin.",
"description": "$1 is the dapp and $2 is the number of snaps it wants to connect to."
@ -2495,9 +2486,6 @@
"newTokensImportedTitle": {
"message": "Token içe aktarıldı"
},
"newValues": {
"message": "yeni değerler"
},
"next": {
"message": "Sonraki"
},
@ -2767,12 +2755,6 @@
"notifications23ActionText": {
"message": "Güvenlik uyarılarını etkinleştir"
},
"notifications23DescriptionOne": {
"message": "Blockaid tarafından desteklenen güvenlik uyarıları ile gizliliğinizi korumaya devam ederken bilinen dolandırıcılıklardan uzak durun."
},
"notifications23DescriptionThree": {
"message": "OpenSea'den güvenlik uyarılarını etkinleştirdiyseniz sizi bu özelliğe taşıdık."
},
"notifications23DescriptionTwo": {
"message": "Talepleri onaylamadan önce her zaman kendiniz gerekli özeni gösterin."
},
@ -3658,19 +3640,9 @@
"securityAlerts": {
"message": "Güvenlik uyarıları"
},
"securityAlertsDescription1": {
"message": "Bu özellik, işlemlerinizi ve imza taleplerinizi yerel olarak inceleyerek sizi kötü amaçlı aktivitelere karşı uyarır. Verileriniz bu hizmeti sunan üçüncü taraflarla paylaşılmaz. Herhangi bir talebi onaylamadan önce gerekli özeni her zaman kendiniz gösterin. Bu özelliğin tüm kötü amaçlı aktiviteleri algılayacağına dair herhangi bir garanti söz konusu değildir."
},
"securityAlertsDescription2": {
"message": "Talepleri onaylamadan önce her zaman gerekli özeni gösterdiğinizden emin olun. Tüm kötü niyetli aktivitelerin bu özellik tarafından algılanacağına dair herhangi bir garanti sunulmamaktadır."
},
"securityAndPrivacy": {
"message": "Güvenlik ve gizlilik"
},
"securityProviderAdviceBy": {
"message": "$1 güvenlik önerisi",
"description": "The security provider that is providing data"
},
"seeDetails": {
"message": "Ayrıntılara bakın"
},
@ -3764,9 +3736,6 @@
"selectPathHelp": {
"message": "Beklediğiniz hesapları görmüyorsanız HD yoluna geçmeyi deneyin."
},
"selectProvider": {
"message": "Sağlayıcıları seç:"
},
"selectType": {
"message": "Tür Seç"
},

View File

@ -296,12 +296,6 @@
"advancedConfiguration": {
"message": "Cấu hình nâng cao"
},
"advancedGasFeeDefaultOptIn": {
"message": "Lưu $1 này làm mặc định của tôi cho \"Nâng cao\""
},
"advancedGasFeeDefaultOptOut": {
"message": "Luôn sử dụng các giá trị và thiết lập nâng cao này làm mặc định."
},
"advancedGasFeeModalTitle": {
"message": "Phí gas nâng cao"
},
@ -2336,9 +2330,6 @@
"more": {
"message": "thêm"
},
"moreComingSoon": {
"message": "Sắp có thêm nhiều nhà cung cấp khác"
},
"multipleSnapConnectionWarning": {
"message": "$1 muốn kết nối với $2 snap. Chỉ tiến hành nếu bạn tin tưởng trang web này.",
"description": "$1 is the dapp and $2 is the number of snaps it wants to connect to."
@ -2495,9 +2486,6 @@
"newTokensImportedTitle": {
"message": "Đã nhập token"
},
"newValues": {
"message": "giá trị mới"
},
"next": {
"message": "Tiếp theo"
},
@ -2767,12 +2755,6 @@
"notifications23ActionText": {
"message": "Bật cảnh báo bảo mật"
},
"notifications23DescriptionOne": {
"message": "Tránh xa các hành vi gian lận đã biết trong khi vẫn bảo vệ quyền riêng tư của bạn với các cảnh báo bảo mật do Blockaid cung cấp."
},
"notifications23DescriptionThree": {
"message": "Nếu bạn đã bật cảnh báo bảo mật từ OpenSea, chúng tôi đã chuyển bạn sang tính năng này."
},
"notifications23DescriptionTwo": {
"message": "Luôn tự thẩm định trước khi phê duyệt các yêu cầu."
},
@ -3658,19 +3640,9 @@
"securityAlerts": {
"message": "Cảnh báo bảo mật"
},
"securityAlertsDescription1": {
"message": "Tính năng này sẽ cảnh báo cho bạn khi có hoạt động độc hại bằng cách xem xét cục bộ các giao dịch và yêu cầu chữ ký của bạn. Dữ liệu của bạn không được chia sẻ với các bên thứ ba cung cấp dịch vụ này. Luôn tự thẩm định trước khi phê duyệt bất kỳ yêu cầu nào. Không có gì đảm bảo rằng tính năng này sẽ phát hiện được tất cả các hoạt động độc hại."
},
"securityAlertsDescription2": {
"message": "Nhớ luôn tự thẩm định trước khi phê duyệt bất kỳ yêu cầu nào. Không có gì đảm bảo tính năng này sẽ phát hiện được tất cả các hành vi độc hại."
},
"securityAndPrivacy": {
"message": "Bảo mật và quyền riêng tư"
},
"securityProviderAdviceBy": {
"message": "Lời khuyên bảo mật bởi $1",
"description": "The security provider that is providing data"
},
"seeDetails": {
"message": "Xem chi tiết"
},
@ -3764,9 +3736,6 @@
"selectPathHelp": {
"message": "Nếu bạn không thấy các tài khoản như mong đợi, hãy chuyển sang đường dẫn HD."
},
"selectProvider": {
"message": "Chọn nhà cung cấp:"
},
"selectType": {
"message": "Chọn loại"
},

View File

@ -296,12 +296,6 @@
"advancedConfiguration": {
"message": "高级配置"
},
"advancedGasFeeDefaultOptIn": {
"message": "将这些 $1 保存为“高级”默认值"
},
"advancedGasFeeDefaultOptOut": {
"message": "始终使用这些值和高级设置作为默认值。"
},
"advancedGasFeeModalTitle": {
"message": "高级燃料费"
},
@ -2336,9 +2330,6 @@
"more": {
"message": "更多"
},
"moreComingSoon": {
"message": "即将有更多提供商加入"
},
"multipleSnapConnectionWarning": {
"message": "$1想连接$2个snap。只有在您信任此网站的情况下才能继续。",
"description": "$1 is the dapp and $2 is the number of snaps it wants to connect to."
@ -2495,9 +2486,6 @@
"newTokensImportedTitle": {
"message": "已导入代币"
},
"newValues": {
"message": "新的值"
},
"next": {
"message": "下一步"
},
@ -2767,12 +2755,6 @@
"notifications23ActionText": {
"message": "启用安全警报"
},
"notifications23DescriptionOne": {
"message": "通过由 Blockaid 提供支持的安全警报,避开已知的诈骗,同时仍会保护您的隐私。"
},
"notifications23DescriptionThree": {
"message": "如果您从 OpenSea 启用了安全警报,则我们已将您转移到此功能。"
},
"notifications23DescriptionTwo": {
"message": "在批准请求之前,请务必自行作出审慎调查。"
},
@ -3658,19 +3640,9 @@
"securityAlerts": {
"message": "安全警告"
},
"securityAlertsDescription1": {
"message": "此功能通过在本地检查您的交易和签名请求来向您发出恶意活动警报。您的数据不会与提供此服务的第三方共享。在批准任何请求之前,请务必自行作出审慎调查。无法保证此功能可以检测到所有恶意活动。"
},
"securityAlertsDescription2": {
"message": "在批准任何请求之前,请务必自行谨慎调查。无法保证此功能可以检测到所有恶意活动。"
},
"securityAndPrivacy": {
"message": "安全和隐私"
},
"securityProviderAdviceBy": {
"message": "$1的安全建议",
"description": "The security provider that is providing data"
},
"seeDetails": {
"message": "查看详情"
},
@ -3764,9 +3736,6 @@
"selectPathHelp": {
"message": "如果您没有看到您期望的账户,请尝试切换 HD 路径。"
},
"selectProvider": {
"message": "选择提供程序:"
},
"selectType": {
"message": "选择类型"
},

View File

@ -360,7 +360,7 @@ async function loadPhishingWarningPage() {
} catch (error) {
if (error instanceof PhishingWarningPageTimeoutError) {
console.warn(
'Phishing warning page timeout; page not guaraneteed to work offline.',
'Phishing warning page timeout; page not guaranteed to work offline.',
);
} else {
console.error('Failed to initialize phishing warning page', error);

View File

@ -49,6 +49,10 @@ export default class AppStateController extends EventEmitter {
showProductTour: true,
trezorModel: null,
currentPopupId: undefined,
// This key is only used for checking if the user had set advancedGasFee
// prior to Migration 92.3 where we split out the setting to support
// multiple networks.
hadAdvancedGasFeesSetPriorToMigration92_3: false,
...initState,
qrHardware: {},
nftsDropdownState: {},

View File

@ -226,6 +226,7 @@ describe('DetectTokensController', function () {
onInfuraIsBlocked: sinon.stub(),
onInfuraIsUnblocked: sinon.stub(),
networkConfigurations: {},
onAccountRemoved: sinon.stub(),
});
preferences.setAddresses([
'0x7e57e2',

View File

@ -641,9 +641,10 @@ export default class MMIController extends EventEmitter {
async setAccountAndNetwork(origin, address, chainId) {
await this.appStateController.getUnlockPromise(true);
const addressToLowerCase = address.toLowerCase();
const selectedAddress = this.preferencesController.getSelectedAddress();
if (selectedAddress.toLowerCase() !== address.toLowerCase()) {
this.preferencesController.setSelectedAddress(address);
if (selectedAddress.toLowerCase() !== addressToLowerCase) {
this.preferencesController.setSelectedAddress(addressToLowerCase);
}
const selectedChainId = parseInt(
this.networkController.state.providerConfig.chainId,
@ -667,7 +668,7 @@ export default class MMIController extends EventEmitter {
getPermissionBackgroundApiMethods(
this.permissionController,
).addPermittedAccount(origin, address);
).addPermittedAccount(origin, addressToLowerCase);
return true;
}

View File

@ -52,6 +52,7 @@ describe('MMIController', function () {
initState: {},
onInfuraIsBlocked: jest.fn(),
onInfuraIsUnblocked: jest.fn(),
onAccountRemoved: jest.fn(),
provider: {},
networkConfigurations: {},
}),

View File

@ -66,7 +66,7 @@ export default class PreferencesController {
///: BEGIN:ONLY_INCLUDE_IN(blockaid)
securityAlertsEnabled: false,
///: END:ONLY_INCLUDE_IN
advancedGasFee: null,
advancedGasFee: {},
// WARNING: Do not use feature flags for security-sensitive things.
// Feature flag toggling is available in the global namespace
@ -117,6 +117,9 @@ export default class PreferencesController {
this._subscribeToInfuraAvailability();
// subscribe to account removal
opts.onAccountRemoved((address) => this.removeAddress(address));
global.setPreference = (key, value) => {
return this.setFeatureFlag(key, value);
};
@ -240,10 +243,18 @@ export default class PreferencesController {
/**
* Setter for the `advancedGasFee` property
*
* @param {object} val - holds the maxBaseFee and PriorityFee that the user set as default advanced settings.
* @param {object} options
* @param {string} options.chainId - The chainId the advancedGasFees should be set on
* @param {object} options.gasFeePreferences - The advancedGasFee options to set
*/
setAdvancedGasFee(val) {
this.store.updateState({ advancedGasFee: val });
setAdvancedGasFee({ chainId, gasFeePreferences }) {
const { advancedGasFee } = this.store.getState();
this.store.updateState({
advancedGasFee: {
...advancedGasFee,
[chainId]: gasFeePreferences,
},
});
}
/**

View File

@ -42,6 +42,7 @@ describe('preferences controller', () => {
tokenListController,
onInfuraIsBlocked: jest.fn(),
onInfuraIsUnblocked: jest.fn(),
onAccountRemoved: jest.fn(),
networkConfigurations: NETWORK_CONFIGURATION_DATA,
});
});
@ -109,6 +110,65 @@ describe('preferences controller', () => {
});
});
describe('onAccountRemoved', () => {
it('should remove an address from state', () => {
const testAddress = '0xda22le';
let accountRemovedListener;
const onAccountRemoved = (callback) => {
accountRemovedListener = callback;
};
preferencesController = new PreferencesController({
initLangCode: 'en_US',
tokenListController,
onInfuraIsBlocked: jest.fn(),
onInfuraIsUnblocked: jest.fn(),
initState: {
identities: {
[testAddress]: {
name: 'Account 1',
address: testAddress,
},
},
},
onAccountRemoved,
networkConfigurations: NETWORK_CONFIGURATION_DATA,
});
accountRemovedListener(testAddress);
expect(
preferencesController.store.getState().identities['0xda22le'],
).toStrictEqual(undefined);
});
it('should throw an error if address not found', () => {
const testAddress = '0xda22le';
let accountRemovedListener;
const onAccountRemoved = (callback) => {
accountRemovedListener = callback;
};
preferencesController = new PreferencesController({
initLangCode: 'en_US',
tokenListController,
onInfuraIsBlocked: jest.fn(),
onInfuraIsUnblocked: jest.fn(),
initState: {
identities: {
'0x7e57e2': {
name: 'Account 1',
address: '0x7e57e2',
},
},
},
onAccountRemoved,
networkConfigurations: NETWORK_CONFIGURATION_DATA,
});
expect(() => {
accountRemovedListener(testAddress);
}).toThrow(`${testAddress} can't be deleted cause it was not found`);
});
});
describe('removeAddress', () => {
it('should remove an address from state', () => {
preferencesController.setAddresses(['0xda22le', '0x7e57e2']);
@ -228,14 +288,14 @@ describe('preferences controller', () => {
});
});
describe('setUse4ByteResolution', function () {
it('should default to true', function () {
describe('setUse4ByteResolution', () => {
it('should default to true', () => {
expect(
preferencesController.store.getState().use4ByteResolution,
).toStrictEqual(true);
});
it('should set the use4ByteResolution property in state', function () {
it('should set the use4ByteResolution property in state', () => {
preferencesController.setUse4ByteResolution(false);
expect(
preferencesController.store.getState().use4ByteResolution,
@ -259,22 +319,27 @@ describe('preferences controller', () => {
});
describe('setAdvancedGasFee', () => {
it('should default to null', () => {
it('should default to an empty object', () => {
expect(
preferencesController.store.getState().advancedGasFee,
).toStrictEqual(null);
).toStrictEqual({});
});
it('should set the setAdvancedGasFee property in state', () => {
preferencesController.setAdvancedGasFee({
maxBaseFee: '1.5',
priorityFee: '2',
chainId: CHAIN_IDS.GOERLI,
gasFeePreferences: {
maxBaseFee: '1.5',
priorityFee: '2',
},
});
expect(
preferencesController.store.getState().advancedGasFee.maxBaseFee,
preferencesController.store.getState().advancedGasFee[CHAIN_IDS.GOERLI]
.maxBaseFee,
).toStrictEqual('1.5');
expect(
preferencesController.store.getState().advancedGasFee.priorityFee,
preferencesController.store.getState().advancedGasFee[CHAIN_IDS.GOERLI]
.priorityFee,
).toStrictEqual('2');
});
});

View File

@ -1,10 +1,11 @@
import { Web3Provider } from '@ethersproject/providers';
import { Contract } from '@ethersproject/contracts';
import log from 'loglevel';
import BigNumber from 'bignumber.js';
import { ObservableStore } from '@metamask/obs-store';
import { mapValues, cloneDeep } from 'lodash';
import abi from 'human-standard-token-abi';
import { captureException } from '@sentry/browser';
import {
decGWEIToHexWEI,
sumHexes,
@ -18,6 +19,11 @@ import {
} from '../../../shared/constants/swaps';
import { GasEstimateTypes } from '../../../shared/constants/gas';
import { CHAIN_IDS, NetworkStatus } from '../../../shared/constants/network';
import {
MetaMetricsEventCategory,
MetaMetricsEventName,
MetaMetricsEventErrorType,
} from '../../../shared/constants/metametrics';
import {
FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME,
FALLBACK_SMART_TRANSACTIONS_DEADLINE,
@ -115,6 +121,7 @@ export default class SwapsController {
getCurrentChainId,
getEIP1559GasFeeEstimates,
onNetworkStateChange,
trackMetaMetricsEvent,
},
state,
) {
@ -140,6 +147,7 @@ export default class SwapsController {
this.getBufferedGasLimit = getBufferedGasLimit;
this.getTokenRatesState = getTokenRatesState;
this.trackMetaMetricsEvent = trackMetaMetricsEvent;
this.pollCount = 0;
this.getProviderConfig = getProviderConfig;
@ -362,6 +370,7 @@ export default class SwapsController {
} else if (!isPolledRequest) {
const { gasLimit: approvalGas } = await this.timedoutGasReturn(
firstQuote.approvalNeeded,
firstQuote.aggregator,
);
newQuotes = mapValues(newQuotes, (quote) => ({
@ -463,6 +472,7 @@ export default class SwapsController {
Object.values(quotes).map(async (quote) => {
const { gasLimit, simulationFails } = await this.timedoutGasReturn(
quote.trade,
quote.aggregator,
);
return [gasLimit, simulationFails, quote.aggregator];
}),
@ -492,13 +502,24 @@ export default class SwapsController {
return newQuotes;
}
timedoutGasReturn(tradeTxParams) {
timedoutGasReturn(tradeTxParams, aggregator = '') {
return new Promise((resolve) => {
let gasTimedOut = false;
const gasTimeout = setTimeout(() => {
gasTimedOut = true;
resolve({ gasLimit: null, simulationFails: true });
this.trackMetaMetricsEvent({
event: MetaMetricsEventName.QuoteError,
category: MetaMetricsEventCategory.Swaps,
properties: {
error_type: MetaMetricsEventErrorType.GasTimeout,
aggregator,
},
});
resolve({
gasLimit: null,
simulationFails: true,
});
}, SECOND * 5);
// Remove gas from params that will be passed to the `estimateGas` call
@ -519,7 +540,11 @@ export default class SwapsController {
}
})
.catch((e) => {
log.error(e);
captureException(e, {
extra: {
aggregator,
},
});
if (!gasTimedOut) {
clearTimeout(gasTimeout);
resolve({ gasLimit: null, simulationFails: true });
@ -534,7 +559,10 @@ export default class SwapsController {
const quoteToUpdate = { ...swapsState.quotes[initialAggId] };
const { gasLimit: newGasEstimate, simulationFails } =
await this.timedoutGasReturn(quoteToUpdate.trade);
await this.timedoutGasReturn(
quoteToUpdate.trade,
quoteToUpdate.aggregator,
);
if (newGasEstimate && !simulationFails) {
const gasEstimateWithRefund = calculateGasEstimateWithRefund(

View File

@ -860,7 +860,10 @@ describe('SwapsController', function () {
// Mocked quotes approvalNeeded is null, so it will only be called with the gas
assert.strictEqual(
timedoutGasReturnStub.calledOnceWithExactly(MOCK_APPROVAL_NEEDED),
timedoutGasReturnStub.calledOnceWithExactly(
MOCK_APPROVAL_NEEDED,
TEST_AGG_ID_APPROVAL,
),
true,
);
});

View File

@ -1938,9 +1938,13 @@ export default class TransactionController extends EventEmitter {
*/
this.getTransactions = (opts) => this.txStateManager.getTransactions(opts);
/** @returns {object} the saved default values for advancedGasFee */
/**
* @returns {object} the saved default values for advancedGasFee
*/
this.getAdvancedGasFee = () =>
this.preferencesStore.getState().advancedGasFee;
this.preferencesStore.getState().advancedGasFee[
this._getCurrentChainId()
];
}
// called once on startup

View File

@ -73,6 +73,7 @@ describe('Transaction Controller', function () {
fromAccount,
fragmentExists,
networkStatusStore,
preferencesStore,
getCurrentChainId,
messengerMock,
resultCallbacksMock,
@ -97,6 +98,7 @@ describe('Transaction Controller', function () {
}).provider;
networkStatusStore = new ObservableStore(currentNetworkStatus);
preferencesStore = new ObservableStore({ advancedGasFee: {} });
fromAccount = getTestAccounts()[0];
const blockTrackerStub = new EventEmitter();
@ -155,6 +157,7 @@ describe('Transaction Controller', function () {
getAccountType: () => 'MetaMask',
getDeviceModel: () => 'N/A',
securityProviderRequest: () => undefined,
preferencesStore,
messenger: messengerMock,
});

View File

@ -56,6 +56,7 @@ export default class AccountTracker {
* @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
* @param {Function} opts.getNetworkIdentifier - A function that returns the current network
* @param {Function} opts.onAccountRemoved - Allows subscribing to keyring controller accountRemoved event
*/
constructor(opts = {}) {
const initState = {
@ -83,6 +84,9 @@ export default class AccountTracker {
this.preferencesController = opts.preferencesController;
this.onboardingController = opts.onboardingController;
// subscribe to account removal
opts.onAccountRemoved((address) => this.removeAccount([address]));
this.onboardingController.store.subscribe(
previousValueComparator(async (prevState, currState) => {
const { completedOnboarding: prevCompletedOnboarding } = prevState;

View File

@ -70,6 +70,7 @@ describe('Account Tracker', () => {
getState: noop,
},
},
onAccountRemoved: jest.fn(),
});
});
@ -140,6 +141,38 @@ describe('Account Tracker', () => {
});
});
describe('onAccountRemoved', () => {
it('should remove an account from state', () => {
let accountRemovedListener;
const onAccountRemoved = (callback) => {
accountRemovedListener = callback;
};
accountTracker = new AccountTracker({
provider,
blockTracker: blockTrackerStub,
preferencesController: {
store: {
getState: () => ({
useMultiAccountBalanceChecker,
}),
subscribe: noop,
},
},
onboardingController: {
store: {
subscribe: noop,
getState: noop,
},
},
onAccountRemoved,
});
accountRemovedListener(VALID_ADDRESS);
expect(
accountTracker.store.getState().accounts[VALID_ADDRESS],
).toStrictEqual(undefined);
});
});
describe('_updateAccountsViaBalanceChecker', () => {
it('should update the passed address account balance, and set other balances to null, if useMultiAccountBalanceChecker is false', async () => {
useMultiAccountBalanceChecker = true;

View File

@ -51,7 +51,12 @@ export default class NotificationManager extends EventEmitter {
const lastFocused = await this.platform.getLastFocusedWindow();
// Position window in top right corner of lastFocused window.
top = lastFocused.top;
left = lastFocused.left + (lastFocused.width - NOTIFICATION_WIDTH);
// - this is to make sure no error is triggered from polyfill
// error eg: Invalid value for bounds. Bounds must be at least 50% within visible screen space.
left = Math.max(
lastFocused.left + (lastFocused.width - NOTIFICATION_WIDTH),
0,
);
} catch (_) {
// The following properties are more than likely 0, due to being
// opened from the background chrome process for the extension that

View File

@ -35,6 +35,7 @@ jest.mock('webextension-polyfill', () => {
getAll: jest.fn(),
create: jest.fn(),
update: jest.fn(),
getLastFocused: jest.fn(),
},
};
});
@ -68,4 +69,28 @@ describe('Notification Manager', () => {
expect(setCurrentPopupIdSpy).toHaveBeenCalledTimes(1);
expect(setCurrentPopupIdSpy).toHaveBeenCalledWith(newPopupWindow.id);
});
it('should not pass negative left value for extension window created from last focused window', async () => {
const newPopupWindow = generateMockWindow();
setCurrentPopupIdSpy = jest.fn();
const createSpy = jest.fn().mockReturnValue(newPopupWindow);
browser.windows.getAll.mockReturnValue([]);
browser.windows.create = createSpy;
browser.windows.getLastFocused.mockReturnValue({
top: 0,
left: 0,
width: 120, // make sure this is smalled than NOTIFICATION_WIDTH
});
currentPopupId = undefined;
await notificationManager.showPopup(setCurrentPopupIdSpy, currentPopupId);
expect(createSpy).toHaveBeenCalledTimes(1);
expect(createSpy).toHaveBeenCalledWith({
height: 620,
left: 0, // this is critical, means error related to polyfill is not triggered
top: 0,
type: 'popup',
url: 'notification.html',
width: 360,
});
});
});

View File

@ -1,4 +1,4 @@
import { PPOM } from '@blockaid/ppom';
import { PPOM } from '@blockaid/ppom_release';
import { PPOMController } from '@metamask/ppom-validator';
import {

View File

@ -1,56 +0,0 @@
import { KeyringController } from '@metamask/eth-keyring-controller';
import log from 'loglevel';
import { KeyringType } from '../../../shared/constants/keyring';
const seedPhraseVerifier = {
/**
* Verifies if the seed words can restore the accounts.
*
* Key notes:
* - The seed words can recreate the primary keyring and the accounts belonging to it.
* - The created accounts in the primary keyring are always the same.
* - The keyring always creates the accounts in the same sequence.
*
* @param {Array} createdAccounts - The accounts to restore
* @param {Buffer} seedPhrase - The seed words to verify, encoded as a Buffer
* @returns {Promise<void>}
*/
async verifyAccounts(createdAccounts, seedPhrase) {
if (!createdAccounts || createdAccounts.length < 1) {
throw new Error('No created accounts defined.');
}
const keyringController = new KeyringController({});
const keyringBuilder = keyringController.getKeyringBuilderForType(
KeyringType.hdKeyTree,
);
const keyring = keyringBuilder();
const opts = {
mnemonic: seedPhrase,
numberOfAccounts: createdAccounts.length,
};
await keyring.deserialize(opts);
const restoredAccounts = await keyring.getAccounts();
log.debug(`Created accounts: ${JSON.stringify(createdAccounts)}`);
log.debug(`Restored accounts: ${JSON.stringify(restoredAccounts)}`);
if (restoredAccounts.length !== createdAccounts.length) {
// this should not happen...
throw new Error('Wrong number of accounts');
}
for (let i = 0; i < restoredAccounts.length; i++) {
if (
restoredAccounts[i].toLowerCase() !== createdAccounts[i].toLowerCase()
) {
throw new Error(
`Not identical accounts! Original: ${createdAccounts[i]}, Restored: ${restoredAccounts[i]}`,
);
}
}
},
};
export default seedPhraseVerifier;

View File

@ -1,121 +0,0 @@
/**
* @jest-environment node
* https://github.com/facebook/jest/issues/7780
*/
import { cloneDeep } from 'lodash';
import { KeyringController } from '@metamask/eth-keyring-controller';
import firstTimeState from '../first-time-state';
import mockEncryptor from '../../../test/lib/mock-encryptor';
import { KeyringType } from '../../../shared/constants/keyring';
import seedPhraseVerifier from './seed-phrase-verifier';
describe('SeedPhraseVerifier', () => {
describe('verifyAccounts', () => {
const password = 'passw0rd1';
const { hdKeyTree } = KeyringType;
let keyringController;
let primaryKeyring;
beforeEach(async () => {
keyringController = new KeyringController({
initState: cloneDeep(firstTimeState),
encryptor: mockEncryptor,
});
expect.any(keyringController);
await keyringController.createNewVaultAndKeychain(password);
primaryKeyring = keyringController.getKeyringsByType(hdKeyTree)[0];
});
it('should be able to verify created account with seed words', async () => {
const createdAccounts = await primaryKeyring.getAccounts();
expect(createdAccounts).toHaveLength(1);
const serialized = await primaryKeyring.serialize();
const seedWords = serialized.mnemonic;
expect(seedWords).not.toHaveLength(0);
await seedPhraseVerifier.verifyAccounts(createdAccounts, seedWords);
});
it('should be able to verify created account (upper case) with seed words', async () => {
const createdAccounts = await primaryKeyring.getAccounts();
expect(createdAccounts).toHaveLength(1);
const upperCaseAccounts = [createdAccounts[0].toUpperCase()];
const serialized = await primaryKeyring.serialize();
const seedWords = serialized.mnemonic;
expect(seedWords).not.toHaveLength(0);
await seedPhraseVerifier.verifyAccounts(upperCaseAccounts, seedWords);
});
it('should be able to verify created account (lower case) with seed words', async () => {
const createdAccounts = await primaryKeyring.getAccounts();
expect(createdAccounts).toHaveLength(1);
const lowerCaseAccounts = [createdAccounts[0].toLowerCase()];
const serialized = await primaryKeyring.serialize();
const seedWords = serialized.mnemonic;
expect(seedWords).not.toHaveLength(0);
await seedPhraseVerifier.verifyAccounts(lowerCaseAccounts, seedWords);
});
it('should return error with good but different seed words', async () => {
const createdAccounts = await primaryKeyring.getAccounts();
expect(createdAccounts).toHaveLength(1);
await primaryKeyring.serialize();
const seedWords =
'debris dizzy just program just float decrease vacant alarm reduce speak stadium';
await expect(async () => {
await seedPhraseVerifier.verifyAccounts(createdAccounts, seedWords);
}).rejects.toThrow('Not identical accounts!');
});
it('should return error with undefined existing accounts', async () => {
const createdAccounts = await primaryKeyring.getAccounts();
expect(createdAccounts).toHaveLength(1);
await primaryKeyring.serialize();
const seedWords =
'debris dizzy just program just float decrease vacant alarm reduce speak stadium';
await expect(async () => {
await seedPhraseVerifier.verifyAccounts(undefined, seedWords);
}).rejects.toThrow('No created accounts defined.');
});
it('should return error with empty accounts array', async () => {
const createdAccounts = await primaryKeyring.getAccounts();
expect(createdAccounts).toHaveLength(1);
await primaryKeyring.serialize();
const seedWords =
'debris dizzy just program just float decrease vacant alarm reduce speak stadium';
await expect(async () => {
await seedPhraseVerifier.verifyAccounts([], seedWords);
}).rejects.toThrow('No created accounts defined.');
});
it('should be able to verify more than one created account with seed words', async () => {
await keyringController.addNewAccount(primaryKeyring);
await keyringController.addNewAccount(primaryKeyring);
const createdAccounts = await primaryKeyring.getAccounts();
expect(createdAccounts).toHaveLength(3);
const serialized = await primaryKeyring.serialize();
const seedWords = serialized.mnemonic;
expect(seedWords).not.toHaveLength(0);
await seedPhraseVerifier.verifyAccounts(createdAccounts, seedWords);
});
});
});

View File

@ -1,6 +1,7 @@
import * as Sentry from '@sentry/browser';
import { Dedupe, ExtraErrorData } from '@sentry/integrations';
import { AllProperties } from '../../../shared/modules/object.utils';
import { FilterEvents } from './sentry-filter-events';
import extractEthjsErrorMessage from './extractEthjsErrorMessage';
@ -28,72 +29,269 @@ export const ERROR_URL_ALLOWLIST = {
// debugging, and they do not contain any identifiable information.
export const SENTRY_BACKGROUND_STATE = {
AccountTracker: {
accounts: false,
currentBlockGasLimit: true,
},
AddressBookController: {
addressBook: false,
},
AlertController: {
alertEnabledness: true,
unconnectedAccountAlertShownOrigins: false,
web3ShimUsageOrigins: false,
},
AnnouncementController: {
announcements: false,
},
AppMetadataController: {
currentAppVersion: true,
currentMigrationVersion: true,
previousAppVersion: true,
previousMigrationVersion: true,
currentMigrationVersion: true,
},
ApprovalController: {
approvalFlows: false,
pendingApprovals: false,
pendingApprovalCount: false,
},
AppStateController: {
browserEnvironment: true,
connectedStatusPopoverHasBeenShown: true,
currentPopupId: false,
defaultHomeActiveTabName: true,
fullScreenGasPollTokens: true,
hadAdvancedGasFeesSetPriorToMigration92_3: true,
nftsDetectionNoticeDismissed: true,
nftsDropdownState: true,
notificationGasPollTokens: true,
outdatedBrowserWarningLastShown: true,
popupGasPollTokens: true,
qrHardware: true,
recoveryPhraseReminderHasBeenShown: true,
recoveryPhraseReminderLastShown: true,
serviceWorkerLastActiveTime: true,
showBetaHeader: true,
showProductTour: true,
showTestnetMessageInDropdown: true,
snapsInstallPrivacyWarningShown: true,
termsOfUseLastAgreed: true,
timeoutMinutes: true,
trezorModel: true,
usedNetworks: true,
},
CachedBalancesController: {
cachedBalances: false,
},
CronjobController: {
jobs: false,
},
CurrencyController: {
conversionDate: true,
conversionRate: true,
currentCurrency: true,
nativeCurrency: true,
pendingCurrentCurrency: true,
pendingNativeCurrency: true,
usdConversionRate: true,
},
DecryptMessageController: {
unapprovedDecryptMsgs: false,
unapprovedDecryptMsgCount: true,
},
DesktopController: {
desktopEnabled: true,
},
EncryptionPublicKeyController: {
unapprovedEncryptionPublicKeyMsgs: false,
unapprovedEncryptionPublicKeyMsgCount: true,
},
EnsController: {
ensResolutionsByAddress: false,
},
GasFeeController: {
estimatedGasFeeTimeBounds: true,
gasEstimateType: true,
gasFeeEstimates: true,
},
KeyringController: {
isUnlocked: true,
keyrings: false,
keyringTypes: false,
},
MetaMetricsController: {
eventsBeforeMetricsOptIn: false,
fragments: false,
metaMetricsId: true,
participateInMetaMetrics: true,
previousUserTraits: false,
segmentApiCalls: false,
traits: false,
},
NetworkController: {
networkConfigurations: false,
networkId: true,
networkStatus: true,
networksMetadata: true,
providerConfig: {
chainId: true,
id: true,
nickname: true,
rpcPrefs: false,
rpcUrl: false,
ticker: true,
type: true,
},
selectedNetworkClientId: false,
},
NftController: {
allNftContracts: false,
allNfts: false,
ignoredNfts: false,
},
NotificationController: {
notifications: false,
},
OnboardingController: {
completedOnboarding: true,
firstTimeFlowType: true,
onboardingTabs: false,
seedPhraseBackedUp: true,
},
PermissionController: {
subjects: false,
},
PermissionLogController: {
permissionActivityLog: false,
permissionHistory: false,
},
PhishingController: {},
PreferencesController: {
advancedGasFee: true,
currentLocale: true,
disabledRpcMethodPreferences: true,
dismissSeedBackUpReminder: true,
featureFlags: true,
forgottenPassword: true,
ipfsGateway: true,
preferences: true,
identities: false,
incomingTransactionsPreferences: true,
infuraBlocked: true,
ipfsGateway: false,
isLineaMainnetReleased: true,
knownMethodData: false,
ledgerTransportType: true,
lostIdentities: false,
openSeaEnabled: true,
preferences: {
autoLockTimeLimit: true,
hideZeroBalanceTokens: true,
showFiatInTestnets: true,
showTestNetworks: true,
useNativeCurrencyAsPrimaryCurrency: true,
},
selectedAddress: false,
snapRegistryList: false,
theme: true,
transactionSecurityCheckEnabled: true,
use4ByteResolution: true,
useAddressBarEnsResolution: true,
useBlockie: true,
useCurrencyRateCheck: true,
useMultiAccountBalanceChecker: true,
useNftDetection: true,
useNonceField: true,
usePhishDetect: true,
useTokenDetection: true,
},
SignatureController: {
unapprovedMsgCount: true,
unapprovedMsgs: false,
unapprovedPersonalMsgCount: true,
unapprovedPersonalMsgs: false,
unapprovedTypedMessages: false,
unapprovedTypedMessagesCount: true,
},
SmartTransactionsController: {
smartTransactionsState: {
fees: {
approvalTxFees: true,
tradeTxFees: true,
},
liveness: true,
smartTransactions: false,
userOptIn: true,
},
},
SnapController: {
snapErrors: false,
snapStates: false,
snaps: false,
},
SnapsRegistry: {
database: false,
lastUpdated: false,
},
SubjectMetadataController: {
subjectMetadata: false,
},
SwapsController: {
swapsState: {
approveTxId: false,
customApproveTxData: false,
customGasPrice: true,
customMaxFeePerGas: true,
customMaxGas: true,
customMaxPriorityFeePerGas: true,
errorKey: true,
fetchParams: true,
quotes: false,
quotesLastFetched: true,
quotesPollingLimitEnabled: true,
routeState: true,
saveFetchedQuotes: true,
selectedAggId: true,
swapsFeatureFlags: true,
swapsFeatureIsLive: true,
swapsQuotePrefetchingRefreshTime: true,
swapsQuoteRefreshTime: true,
swapsStxBatchStatusRefreshTime: true,
swapsStxGetTransactionsRefreshTime: true,
swapsStxMaxFeeMultiplier: true,
swapsUserFeeLevel: true,
tokens: false,
topAggId: false,
tradeTxId: false,
},
},
TokenListController: {
preventPollingOnNetworkRestart: true,
tokenList: false,
tokensChainsCache: {
[AllProperties]: false,
},
},
TokenRatesController: {
contractExchangeRates: false,
},
TokensController: {
allDetectedTokens: {
[AllProperties]: false,
},
allIgnoredTokens: {
[AllProperties]: false,
},
allTokens: {
[AllProperties]: false,
},
detectedTokens: false,
ignoredTokens: false,
tokens: false,
},
TransactionController: {
currentNetworkTxList: false,
transactions: false,
lastFetchedBlockNumbers: false,
},
TxController: {
currentNetworkTxList: false,
transactions: false,
unapprovedTxs: false,
},
};
const flattenedBackgroundStateMask = Object.values(
@ -118,7 +316,9 @@ export const SENTRY_UI_STATE = {
// These properties are in the `metamask` slice but not in the background state
customNonceValue: true,
isAccountMenuOpen: true,
isNetworkMenuOpen: true,
nextNonce: true,
pendingTokens: false,
welcomeScreenSeen: true,
},
unconnectedAccount: true,

View File

@ -194,7 +194,6 @@ import DecryptMessageController from './controllers/decrypt-message';
import TransactionController from './controllers/transactions';
import DetectTokensController from './controllers/detect-tokens';
import SwapsController from './controllers/swaps';
import seedPhraseVerifier from './lib/seed-phrase-verifier';
import MetaMetricsController from './controllers/metametrics';
import { segment } from './lib/segment';
import createMetaRPCHandler from './lib/createMetaRPCHandler';
@ -413,6 +412,10 @@ export default class MetamaskController extends EventEmitter {
networkControllerMessenger,
'NetworkController:infuraIsUnblocked',
),
onAccountRemoved: this.controllerMessenger.subscribe.bind(
this.controllerMessenger,
'KeyringController:accountRemoved',
),
tokenListController: this.tokenListController,
provider: this.provider,
networkConfigurations: this.networkController.state.networkConfigurations,
@ -758,6 +761,10 @@ export default class MetamaskController extends EventEmitter {
initState.AccountTracker?.accounts
? { accounts: initState.AccountTracker.accounts }
: { accounts: {} },
onAccountRemoved: this.controllerMessenger.subscribe.bind(
this.controllerMessenger,
'KeyringController:accountRemoved',
),
});
// start and stop polling for balances based on activeControllerConnections
@ -1360,8 +1367,8 @@ export default class MetamaskController extends EventEmitter {
],
}),
getEncryptionPublicKey:
this.keyringController.getEncryptionPublicKey.bind(
this.keyringController,
this.coreKeyringController.getEncryptionPublicKey.bind(
this.coreKeyringController,
),
getAccountKeyringType:
this.coreKeyringController.getAccountKeyringType.bind(
@ -1445,6 +1452,9 @@ export default class MetamaskController extends EventEmitter {
this.gasFeeController.fetchGasFeeEstimates.bind(
this.gasFeeController,
),
trackMetaMetricsEvent: this.metaMetricsController.trackEvent.bind(
this.metaMetricsController,
),
},
initState.SwapsController,
);
@ -1845,14 +1855,16 @@ export default class MetamaskController extends EventEmitter {
/**
* Tracks snaps export usage. Note: This function is throttled to 1 call per 60 seconds.
*
* @param {string} snapId - The ID of the snap the handler is being triggered on.
* @param {string} handler - The handler to trigger on the snap for the request.
*/
_trackSnapExportUsage = throttle(
(handler) =>
(snapId, handler) =>
this.metaMetricsController.trackEvent({
event: MetaMetricsEventName.SnapExportUsed,
category: MetaMetricsEventCategory.Snaps,
properties: {
snap_id: snapId,
export: handler,
},
}),
@ -1870,7 +1882,7 @@ export default class MetamaskController extends EventEmitter {
* @returns The result of the JSON-RPC request.
*/
handleSnapRequest(args) {
this._trackSnapExportUsage(args.handler);
this._trackSnapExportUsage(args.snapId, args.handler);
return this.controllerMessenger.call('SnapController:handleRequest', args);
}
@ -2092,6 +2104,15 @@ export default class MetamaskController extends EventEmitter {
}, []);
this.dismissNotifications(notificationIds);
this.metaMetricsController.trackEvent({
event: MetaMetricsEventName.SnapUninstalled,
category: MetaMetricsEventCategory.Snaps,
properties: {
snap_id: truncatedSnap.id,
version: truncatedSnap.version,
},
});
},
);
@ -3009,6 +3030,20 @@ export default class MetamaskController extends EventEmitter {
return new Uint8Array(new Uint16Array(indices).buffer);
}
/**
* Converts a BIP-39 mnemonic stored as indices of words in the English wordlist to a buffer of Unicode code points.
*
* @param {Uint8Array} wordlistIndices - Indices to specific words in the BIP-39 English wordlist.
* @returns {Buffer} The BIP-39 mnemonic formed from the words in the English wordlist, encoded as a list of Unicode code points.
*/
_convertEnglishWordlistIndicesToCodepoints(wordlistIndices) {
return Buffer.from(
Array.from(new Uint16Array(wordlistIndices.buffer))
.map((i) => wordlist[i])
.join(' '),
);
}
/**
* Get an account balance from the AccountTracker or request it directly from the network.
*
@ -3449,28 +3484,9 @@ export default class MetamaskController extends EventEmitter {
* encoded as an array of UTF-8 bytes.
*/
async verifySeedPhrase() {
const [primaryKeyring] = this.coreKeyringController.getKeyringsByType(
KeyringType.hdKeyTree,
return this._convertEnglishWordlistIndicesToCodepoints(
await this.coreKeyringController.verifySeedPhrase(),
);
if (!primaryKeyring) {
throw new Error('MetamaskController - No HD Key Tree found');
}
const serialized = await primaryKeyring.serialize();
const seedPhraseAsBuffer = Buffer.from(serialized.mnemonic);
const accounts = await primaryKeyring.getAccounts();
if (accounts.length < 1) {
throw new Error('MetamaskController - No accounts found');
}
try {
await seedPhraseVerifier.verifyAccounts(accounts, seedPhraseAsBuffer);
return Array.from(seedPhraseAsBuffer.values());
} catch (err) {
log.error(err.message);
throw err;
}
}
/**
@ -3545,10 +3561,6 @@ export default class MetamaskController extends EventEmitter {
async removeAccount(address) {
// Remove all associated permissions
this.removeAllAccountPermissions(address);
// Remove account from the preferences controller
this.preferencesController.removeAddress(address);
// Remove account from the account tracker controller
this.accountTracker.removeAccount([address]);
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
this.custodyController.removeAccount(address);

View File

@ -871,10 +871,7 @@ describe('MetaMaskController', function () {
try {
await metamaskController.verifySeedPhrase();
} catch (error) {
assert.equal(
error.message,
'MetamaskController - No HD Key Tree found',
);
assert.equal(error.message, 'No HD keyring found.');
}
});
@ -947,8 +944,6 @@ describe('MetaMaskController', function () {
getAccounts: sinon.stub().returns(Promise.resolve([])),
destroy: sinon.stub(),
};
sinon.stub(metamaskController.preferencesController, 'removeAddress');
sinon.stub(metamaskController.accountTracker, 'removeAccount');
sinon.stub(metamaskController.keyringController, 'removeAccount');
sinon.stub(metamaskController, 'removeAllAccountPermissions');
sinon
@ -963,28 +958,12 @@ describe('MetaMaskController', function () {
afterEach(function () {
metamaskController.keyringController.removeAccount.restore();
metamaskController.accountTracker.removeAccount.restore();
metamaskController.preferencesController.removeAddress.restore();
metamaskController.removeAllAccountPermissions.restore();
mockKeyring.getAccounts.resetHistory();
mockKeyring.destroy.resetHistory();
});
it('should call preferencesController.removeAddress', async function () {
assert(
metamaskController.preferencesController.removeAddress.calledWith(
addressToRemove,
),
);
});
it('should call accountTracker.removeAccount', async function () {
assert(
metamaskController.accountTracker.removeAccount.calledWith([
addressToRemove,
]),
);
});
it('should call keyringController.removeAccount', async function () {
assert(
metamaskController.keyringController.removeAccount.calledWith(

View File

@ -0,0 +1,99 @@
import { NetworkType, toHex } from '@metamask/controller-utils';
import { NetworkStatus } from '@metamask/network-controller';
import { cloneDeep } from 'lodash';
import { version as currentStateVersion, migrate } from './092.2';
const TEST_NETWORK_CONTROLLER_STATE = {
networkId: 'network-id',
networkStatus: NetworkStatus.Available,
providerConfig: {
type: NetworkType.rpc,
chainId: toHex(42),
nickname: 'Funky Town Chain',
ticker: 'ETH',
id: 'test-network-client-id',
},
networkDetails: { EIPS: {} },
networkConfigurations: {
'network-configuration-id-1': {
chainId: toHex(42),
nickname: 'Localhost 8545',
rpcPrefs: {},
rpcUrl: 'http://localhost:8545',
ticker: 'ETH',
},
},
};
const anyPreviousStateVersion = 91;
describe('migration #96', () => {
afterEach(() => {
jest.resetAllMocks();
});
it('should update the state version number in the appropriate metadata field', async () => {
const originalVersionedState = {
meta: { version: anyPreviousStateVersion },
data: {},
};
const newStorage = await migrate(cloneDeep(originalVersionedState));
expect(newStorage.meta).toStrictEqual({ version: currentStateVersion });
});
it('should return state unaltered if there is no network controller state', async () => {
const originalMetaMaskState = {
anotherController: 'another-controller-state',
};
const originalVersionedState = {
meta: { version: anyPreviousStateVersion },
data: originalMetaMaskState,
};
const updatedVersionedState = await migrate(
cloneDeep(originalVersionedState),
);
expect(updatedVersionedState.data).toStrictEqual(originalMetaMaskState);
});
it('should return unaltered state if there are no obsolete network controller state properties', async () => {
const originalMetaMaskState = {
anotherController: 'another-controller-state',
NetworkController: TEST_NETWORK_CONTROLLER_STATE,
};
const originalVersionedState = {
meta: { version: anyPreviousStateVersion },
data: originalMetaMaskState,
};
const updatedVersionedState = await migrate(
cloneDeep(originalVersionedState),
);
expect(updatedVersionedState.data).toStrictEqual(originalMetaMaskState);
});
it('should return updated state without obsolete network controller state properties', async () => {
const originalMetaMaskState = {
anotherController: 'another-controller-state',
NetworkController: {
...TEST_NETWORK_CONTROLLER_STATE,
someSortOfRogueObsoleteStateProperty: 'exists',
},
};
const originalVersionedState = {
meta: { version: anyPreviousStateVersion },
data: originalMetaMaskState,
};
const updatedVersionedState = await migrate(
cloneDeep(originalVersionedState),
);
expect(updatedVersionedState.data).not.toStrictEqual(originalMetaMaskState);
expect(updatedVersionedState.data).toStrictEqual({
anotherController: 'another-controller-state',
NetworkController: TEST_NETWORK_CONTROLLER_STATE,
});
});
});

View File

@ -0,0 +1,75 @@
import { hasProperty } from '@metamask/utils';
import { captureException } from '@sentry/browser';
import { cloneDeep, isObject, pick } from 'lodash';
type MetaMaskState = Record<string, unknown>;
type VersionedState = {
meta: { version: number };
data: MetaMaskState;
};
export const version = 92.2;
/**
* This migration removes obsolete NetworkController state properties.
*
* @param originalVersionedState - Versioned MetaMask extension state, exactly what we persist to dist.
* @param originalVersionedState.meta - State metadata.
* @param originalVersionedState.meta.version - The current state version.
* @param originalVersionedState.data - The persisted MetaMask state, keyed by controller.
* @returns Updated versioned of MetaMask extension state.
*/
export async function migrate(
originalVersionedState: VersionedState,
): Promise<VersionedState> {
const updatedVersionedState = cloneDeep(originalVersionedState);
updatedVersionedState.meta.version = version;
updatedVersionedState.data = transformState(updatedVersionedState.data);
return updatedVersionedState;
}
function transformState(originalState: MetaMaskState): MetaMaskState {
const updatedState =
filterOutObsoleteNetworkControllerStateProperties(originalState);
return updatedState;
}
function filterOutObsoleteNetworkControllerStateProperties(
state: MetaMaskState,
): MetaMaskState {
// https://github.com/MetaMask/core/blob/%40metamask/network-controller%4010.3.1/packages/network-controller/src/NetworkController.ts#L336-L342
const CURRENT_NETWORK_CONTROLLER_STATE_PROPS = [
'networkId',
'networkStatus',
'providerConfig',
'networkDetails',
'networkConfigurations',
];
if (
!hasProperty(state, 'NetworkController') ||
!isObject(state.NetworkController)
) {
captureException(
`Migration ${version}: Invalid NetworkController state: ${typeof state.NetworkController}`,
);
return state;
}
const networkControllerState = state.NetworkController;
// delete network state properties that are not currently in use
const updatedNetworkController = pick(
networkControllerState,
CURRENT_NETWORK_CONTROLLER_STATE_PROPS,
);
return {
...state,
NetworkController: updatedNetworkController,
};
}

View File

@ -0,0 +1,184 @@
import { migrate } from './092.3';
const PREFERENCES_CONTROLLER_MOCK = {
useBlockie: false,
useNonceField: false,
usePhishDetect: true,
dismissSeedBackUpReminder: false,
disabledRpcMethodPreferences: {
eth_sign: false,
},
useMultiAccountBalanceChecker: true,
useTokenDetection: false,
useNftDetection: false,
use4ByteResolution: true,
useCurrencyRateCheck: true,
openSeaEnabled: false,
advancedGasFee: null,
featureFlags: {
showIncomingTransactions: true,
},
knownMethodData: {},
currentLocale: 'EN',
identities: {},
lostIdentities: {},
forgottenPassword: false,
preferences: {
autoLockTimeLimit: undefined,
showFiatInTestnets: false,
showTestNetworks: false,
useNativeCurrencyAsPrimaryCurrency: true,
hideZeroBalanceTokens: false,
},
// ENS decentralized website resolution
ipfsGateway: '',
useAddressBarEnsResolution: true,
infuraBlocked: null,
ledgerTransportType: 'U2F',
snapRegistryList: {},
transactionSecurityCheckEnabled: false,
theme: 'OS',
isLineaMainnetReleased: false,
};
describe('migration #92.3', () => {
it('updates the version metadata', async () => {
const oldStorage = {
meta: { version: 92.2 },
data: {},
};
const newStorage = await migrate(oldStorage);
expect(newStorage.meta).toStrictEqual({ version: 92.3 });
});
it('does nothing if no PreferencesController state', async () => {
const oldData = {
some: 'data',
};
const oldStorage = {
meta: { version: 92.2 },
data: oldData,
};
const newStorage = await migrate(oldStorage);
expect(newStorage.data).toStrictEqual(oldData);
});
it('does nothing if no AppStateController state', async () => {
const oldData = {
some: 'data',
};
const oldStorage = {
meta: { version: 92.2 },
data: oldData,
};
const newStorage = await migrate(oldStorage);
expect(newStorage.data).toStrictEqual(oldData);
});
it('changes advancedGasFee from null to an empty object, and sets hadAdvancedGasFeesSetPriorToMigration92_3 to false', async () => {
const oldData = {
some: 'data',
PreferencesController: {
...PREFERENCES_CONTROLLER_MOCK,
},
AppStateController: {},
};
const oldStorage = {
meta: { version: 92.2 },
data: oldData,
};
const newStorage = await migrate(oldStorage);
expect(newStorage.data).toStrictEqual({
some: oldData.some,
PreferencesController: {
...PREFERENCES_CONTROLLER_MOCK,
advancedGasFee: {},
},
AppStateController: {
hadAdvancedGasFeesSetPriorToMigration92_3: false,
},
});
});
it('changes advancedGasFee from an object of values to an empty object and sets hadAdvancedGasFeesSetPriorToMigration92_3 to true', async () => {
const oldData = {
some: 'data',
PreferencesController: {
...PREFERENCES_CONTROLLER_MOCK,
advancedGasFee: {
priorityFee: '0x1',
maxBaseFee: '0x1',
},
},
AppStateController: {},
};
const oldStorage = {
meta: { version: 92.2 },
data: oldData,
};
const newStorage = await migrate(oldStorage);
expect(newStorage.data).toStrictEqual({
some: oldData.some,
PreferencesController: {
...PREFERENCES_CONTROLLER_MOCK,
advancedGasFee: {},
},
AppStateController: {
hadAdvancedGasFeesSetPriorToMigration92_3: true,
},
});
});
it('does not erase advancedGasFee if it does not contain the expected data prior to this migration', async () => {
const oldData = {
some: 'data',
PreferencesController: {
...PREFERENCES_CONTROLLER_MOCK,
advancedGasFee: {
'0x5': {
priorityFee: '0x1',
maxBaseFee: '0x1',
},
},
},
AppStateController: {},
};
const oldStorage = {
meta: { version: 92.2 },
data: oldData,
};
const newStorage = await migrate(oldStorage);
expect(newStorage.data).toStrictEqual({
some: oldData.some,
PreferencesController: {
...PREFERENCES_CONTROLLER_MOCK,
advancedGasFee: {
'0x5': {
priorityFee: '0x1',
maxBaseFee: '0x1',
},
},
},
AppStateController: {
hadAdvancedGasFeesSetPriorToMigration92_3: false,
},
});
});
});

View File

@ -0,0 +1,98 @@
import { hasProperty, isNullOrUndefined, isObject } from '@metamask/utils';
import { cloneDeep } from 'lodash';
import log from 'loglevel';
type VersionedData = {
meta: { version: number };
data: Record<string, unknown>;
};
export const version = 92.3;
/**
* This migration does the following:
*
* - Deletes currently stored advancedGasFee in preferences controller,
* replacing the default with an empty object
* - Sets hadAdvancedGasFeesSetPriorToMigration92_3 flag on AppStateController
* to indicate if the user had previously had advancedGasFee set in their
* preferences. This will be used to display a whats new entry to inform users
* that we wiped these settings and made them apply per network.
*
* @param originalVersionedData - Versioned MetaMask extension state, exactly what we persist to dist.
* @param originalVersionedData.meta - State metadata.
* @param originalVersionedData.meta.version - The current state version.
* @param originalVersionedData.data - The persisted MetaMask state, keyed by controller.
* @returns Updated versioned MetaMask extension state.
*/
export async function migrate(
originalVersionedData: VersionedData,
): Promise<VersionedData> {
const versionedData = cloneDeep(originalVersionedData);
versionedData.meta.version = version;
migrateData(versionedData.data);
return versionedData;
}
function migrateData(state: Record<string, unknown>): void {
changeShapeAndRemoveOldAdvancedGasFeePreference(state);
}
function changeShapeAndRemoveOldAdvancedGasFeePreference(
state: Record<string, unknown>,
) {
if (isNullOrUndefined(state.PreferencesController)) {
log.warn(
`Migration #${version}: preferences controller null or undefined, skipping migration`,
);
return;
}
if (
hasProperty(state, 'AppStateController') &&
isObject(state.AppStateController) &&
hasProperty(state, 'PreferencesController') &&
isObject(state.PreferencesController)
) {
const possibleOriginalValue = state.PreferencesController?.advancedGasFee;
// Will be false if the keys set on the object are anything other than the
// maxBaseFee or priorityFee. Essentially if the object is already keyed
// by chainId it won't show as hadFeesSet.
const hadFeesSet =
isObject(possibleOriginalValue) &&
hasFeePreferenceKeys(possibleOriginalValue);
state.AppStateController.hadAdvancedGasFeesSetPriorToMigration92_3 =
hadFeesSet;
if (
state.PreferencesController.advancedGasFee === null ||
(isObject(state.PreferencesController.advancedGasFee) &&
hasFeePreferenceKeys(state.PreferencesController.advancedGasFee))
) {
state.PreferencesController.advancedGasFee = {};
}
} else if (isObject(state.AppStateController) === false) {
global.sentry?.captureException?.(
new Error(
`typeof state.AppStateController is ${typeof state.AppStateController}`,
),
);
} else if (isObject(state.PreferencesController) === false) {
global.sentry?.captureException?.(
new Error(
`typeof state.PreferencesController is ${typeof state.PreferencesController}`,
),
);
}
}
function hasFeePreferenceKeys(objectToCheck: Record<string, unknown>): boolean {
const keys = Object.keys(objectToCheck);
if (keys.includes('maxBaseFee') || keys.includes('priorityFee')) {
return true;
}
return false;
}

View File

@ -97,6 +97,8 @@ import * as m090 from './090';
import * as m091 from './091';
import * as m092 from './092';
import * as m092point1 from './092.1';
import * as m092point2 from './092.2';
import * as m092point3 from './092.3';
import * as m093 from './093';
import * as m094 from './094';
import * as m095 from './095';
@ -195,6 +197,8 @@ const migrations = [
m091,
m092,
m092point1,
m092point2,
m092point3,
m093,
m094,
m095,

View File

@ -25,7 +25,7 @@ buildTypes:
- SEGMENT_WRITE_KEY_REF: SEGMENT_PROD_WRITE_KEY
- ALLOW_LOCAL_SNAPS: false
- REQUIRE_SNAPS_ALLOWLIST: true
- IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.consensys.io/1.0.1/index.html
- IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.consensys.io/1.0.2/index.html
# Main build uses the default browser manifest
manifestOverrides: false

View File

@ -204,7 +204,7 @@ function getCopyTargets(
if (activeFeatures.includes('blockaid')) {
allCopyTargets.push({
src: getPathInsideNodeModules('@blockaid/ppom', '/'),
src: getPathInsideNodeModules('@blockaid/ppom_release', '/'),
pattern: '*.wasm',
dest: '',
});

View File

@ -31,7 +31,7 @@ function upload_sourcemaps {
local release="${1}"; shift
local dist_directory="${1}"; shift
sentry-cli releases files "${release}" upload-sourcemaps "${dist_directory}"/chrome/*.js "${dist_directory}"/sourcemaps/ --rewrite --url-prefix 'metamask'
sentry-cli releases files "${release}" upload-sourcemaps "${dist_directory}"/chrome/*.js "${dist_directory}"/sourcemaps/ --rewrite --url-prefix '/metamask'
}
function main {

View File

@ -1,6 +1,6 @@
{
"name": "metamask-crx",
"version": "10.34.5",
"version": "10.35.1",
"private": true,
"repository": {
"type": "git",
@ -201,12 +201,12 @@
"request@^2.88.2": "patch:request@npm%3A2.88.2#./.yarn/patches/request-npm-2.88.2-f4a57c72c4.patch",
"request@^2.85.0": "patch:request@npm%3A2.88.2#./.yarn/patches/request-npm-2.88.2-f4a57c72c4.patch",
"lavamoat-core@^14.2.0": "patch:lavamoat-core@npm%3A14.2.0#./.yarn/patches/lavamoat-core-npm-14.2.0-c453f4f755.patch",
"@metamask/keyring-controller@^7.0.0": "patch:@metamask/keyring-controller@npm%3A7.0.0#./.yarn/patches/@metamask-keyring-controller-npm-7.0.0-962008b200.patch",
"@metamask/keyring-controller@^7.2.0": "patch:@metamask/keyring-controller@npm%3A7.2.0#~/.yarn/patches/@metamask-keyring-controller-npm-7.2.0-fcc0c7893b.patch",
"@metamask/signature-controller@^5.3.0": "patch:@metamask/signature-controller@npm%3A5.3.0#./.yarn/patches/@metamask-signature-controller-npm-5.3.0-225628460b.patch"
},
"dependencies": {
"@babel/runtime": "^7.18.9",
"@blockaid/ppom": "^1.1.1",
"@blockaid/ppom_release": "^1.2.6",
"@download/blockies": "^1.0.3",
"@ensdomains/content-hash": "^2.5.6",
"@ethereumjs/common": "^3.1.1",
@ -249,7 +249,7 @@
"@metamask/gas-fee-controller": "^6.0.1",
"@metamask/jazzicon": "^2.0.0",
"@metamask/key-tree": "^9.0.0",
"@metamask/keyring-controller": "^7.0.0",
"@metamask/keyring-controller": "^7.2.0",
"@metamask/logo": "^3.1.1",
"@metamask/message-manager": "^7.3.0",
"@metamask/metamask-eth-abis": "^3.0.0",
@ -258,22 +258,22 @@
"@metamask/obs-store": "^8.1.0",
"@metamask/permission-controller": "^4.0.0",
"@metamask/phishing-controller": "^6.0.0",
"@metamask/post-message-stream": "^6.0.0",
"@metamask/post-message-stream": "^6.2.0",
"@metamask/ppom-validator": "^0.3.0",
"@metamask/providers": "^11.1.0",
"@metamask/rate-limit-controller": "^3.0.0",
"@metamask/rpc-methods": "^1.0.1",
"@metamask/rpc-methods": "^1.0.2",
"@metamask/rpc-methods-flask": "npm:@metamask/rpc-methods@0.37.2-flask.1",
"@metamask/safe-event-emitter": "^2.0.0",
"@metamask/scure-bip39": "^2.0.3",
"@metamask/signature-controller": "^5.3.0",
"@metamask/slip44": "^3.0.0",
"@metamask/smart-transactions-controller": "^4.0.0",
"@metamask/snaps-controllers": "^1.0.1",
"@metamask/snaps-controllers": "^1.0.2",
"@metamask/snaps-controllers-flask": "npm:@metamask/snaps-controllers@0.38.0-flask.1",
"@metamask/snaps-ui": "^1.0.1",
"@metamask/snaps-ui": "^1.0.2",
"@metamask/snaps-ui-flask": "npm:@metamask/snaps-ui@0.37.3-flask.1",
"@metamask/snaps-utils": "^1.0.1",
"@metamask/snaps-utils": "^1.0.2",
"@metamask/snaps-utils-flask": "npm:@metamask/snaps-utils@0.38.0-flask.1",
"@metamask/subject-metadata-controller": "^2.0.0",
"@metamask/utils": "^5.0.0",
@ -314,7 +314,7 @@
"ethjs": "^0.4.0",
"ethjs-contract": "^0.2.3",
"ethjs-query": "^0.3.4",
"extension-port-stream": "^2.0.0",
"extension-port-stream": "^2.1.1",
"fast-json-patch": "^3.1.1",
"fuse.js": "^3.2.0",
"globalthis": "^1.0.1",
@ -387,7 +387,7 @@
"@metamask/eslint-config-typescript": "^9.0.1",
"@metamask/forwarder": "^1.1.0",
"@metamask/phishing-warning": "^2.1.0",
"@metamask/test-dapp": "^7.0.1",
"@metamask/test-dapp": "^7.1.0",
"@sentry/cli": "^2.19.4",
"@storybook/addon-a11y": "^7.0.11",
"@storybook/addon-actions": "^7.0.11",

View File

@ -550,6 +550,7 @@ export enum MetaMetricsEventName {
PortfolioLinkClicked = 'Portfolio Link Clicked',
ProviderMethodCalled = 'Provider Method Called',
PublicAddressCopied = 'Public Address Copied',
QuoteError = 'Quote Error',
ServiceWorkerRestarted = 'Service Worker Restarted',
SignatureApproved = 'Signature Approved',
SignatureFailed = 'Signature Failed',
@ -627,6 +628,7 @@ export enum MetaMetricsEventName {
SwapError = 'Swap Error',
///: BEGIN:ONLY_INCLUDE_IN(snaps)
SnapInstalled = 'Snap Installed',
SnapUninstalled = 'Snap Uninstalled',
SnapUpdated = 'Snap Updated',
SnapExportUsed = 'Snap Export Used',
///: END:ONLY_INCLUDE_IN
@ -689,6 +691,7 @@ export enum MetaMetricsEventKeyType {
export enum MetaMetricsEventErrorType {
InsufficientGas = 'insufficient_gas',
GasTimeout = 'gas_timeout',
}
export enum MetaMetricsNetworkEventSource {

View File

@ -564,6 +564,7 @@ export const BUYABLE_CHAINS_MAP: {
| typeof CHAIN_IDS.MOONBEAM_TESTNET
| typeof CHAIN_IDS.LINEA_GOERLI
| typeof CHAIN_IDS.GOERLI
| typeof CHAIN_IDS.SEPOLIA
| typeof CHAIN_IDS.GNOSIS
>]: BuyableChainSettings;
} = {
@ -571,10 +572,6 @@ export const BUYABLE_CHAINS_MAP: {
nativeCurrency: CURRENCY_SYMBOLS.ETH,
network: BUYABLE_CHAIN_ETHEREUM_NETWORK_NAME,
},
[CHAIN_IDS.SEPOLIA]: {
nativeCurrency: TEST_NETWORK_TICKER_MAP[NETWORK_TYPES.SEPOLIA],
network: BUYABLE_CHAIN_ETHEREUM_NETWORK_NAME,
},
[CHAIN_IDS.BSC]: {
nativeCurrency: CURRENCY_SYMBOLS.BNB,
network: 'bsc',

View File

@ -140,8 +140,7 @@ export const MMI_SWAPS_URL = 'https://metamask-institutional.io/swap';
export const SWAPS_API_V2_BASE_URL = 'https://swap.metaswap.codefi.network';
export const SWAPS_DEV_API_V2_BASE_URL = 'https://swap.dev-api.cx.metamask.io';
export const GAS_API_BASE_URL = 'https://gas-api.metaswap.codefi.network';
export const GAS_DEV_API_BASE_URL =
'https://gas-api.metaswap-dev.codefi.network';
export const GAS_DEV_API_BASE_URL = 'https://gas.dev-api.cx.metamask.io';
const BSC_DEFAULT_BLOCK_EXPLORER_URL = 'https://bscscan.com/';
const MAINNET_DEFAULT_BLOCK_EXPLORER_URL = 'https://etherscan.io/';

View File

@ -155,7 +155,7 @@ export const getBaseApi = function (type, chainId) {
case 'trade':
return `${baseUrl}/trades?`;
case 'tokens':
return `${baseUrl}/tokens`;
return `${baseUrl}/tokens?includeBlockedTokens=true`;
case 'token':
return `${baseUrl}/token`;
case 'topAssets':

View File

@ -1,25 +1,43 @@
/**
* Return a "masked" copy of the given object.
* This symbol matches all object properties when used in a mask
*/
export const AllProperties = Symbol('*');
/**
* Return a "masked" copy of the given object. The returned object includes
* only the properties present in the mask.
*
* The returned object includes only the properties present in the mask. The
* mask is an object that mirrors the structure of the given object, except
* the only values are `true` or a sub-mask. `true` implies the property
* should be included, and a sub-mask implies the property should be further
* masked according to that sub-mask.
* The mask is an object that mirrors the structure of the given object, except
* the only values are `true`, `false, a sub-mask, or the 'AllProperties"
* symbol. `true` implies the property should be included, and `false` will
* exclude it. A sub-mask implies the property should be further masked
* according to that sub-mask. The "AllProperties" symbol is used for objects
* with dynamic keys, and applies a rule (either `true`, `false`, or a
* sub-mask`) to every property in that object.
*
* If a property is not found in the last, its type is included instead.
* If a property is excluded, its type is included instead.
*
* @param {object} object - The object to mask
* @param {Object<object | boolean>} mask - The mask to apply to the object
*/
export function maskObject(object, mask) {
let maskAllProperties = false;
if (Object.keys(mask).includes(AllProperties)) {
if (Object.keys(mask).length > 1) {
throw new Error('AllProperties mask key does not support sibling keys');
}
maskAllProperties = true;
}
return Object.keys(object).reduce((state, key) => {
if (mask[key] === true) {
const maskKey = maskAllProperties ? mask[AllProperties] : mask[key];
if (maskKey === true) {
state[key] = object[key];
} else if (mask[key]) {
state[key] = maskObject(object[key], mask[key]);
} else {
} else if (maskKey && typeof maskKey === 'object') {
state[key] = maskObject(object[key], maskKey);
} else if (maskKey === undefined || maskKey === false) {
state[key] = typeof object[key];
} else {
throw new Error(`Unsupported mask entry: ${maskKey}`);
}
return state;
}, {});

View File

@ -1,4 +1,11 @@
// Messages and descriptions for these locale keys are in app/_locales/en/messages.json
/**
* I'm trying something new here, where notifications get names that are translated
* into numbers in only one place. This should make merge conflicts easier.
*/
export const NOTIFICATION_DROP_LEDGER_FIREFOX = 25;
export const UI_NOTIFICATIONS = {
1: {
id: 1,
@ -131,6 +138,15 @@ export const UI_NOTIFICATIONS = {
},
},
///: END:ONLY_INCLUDE_IN
24: {
id: 24,
date: null,
},
// This syntax is unusual, but very helpful here. It's equivalent to `UI_NOTIFICATIONS[NOTIFICATION_DROP_LEDGER_FIREFOX] =`
[NOTIFICATION_DROP_LEDGER_FIREFOX]: {
id: Number(NOTIFICATION_DROP_LEDGER_FIREFOX),
date: null,
},
};
export const getTranslatedUINotifications = (t, locale) => {
@ -348,7 +364,6 @@ export const getTranslatedUINotifications = (t, locale) => {
description: [
t('notifications23DescriptionOne'),
t('notifications23DescriptionTwo'),
t('notifications23DescriptionThree'),
],
actionText: t('notifications23ActionText'),
date: UI_NOTIFICATIONS[23].date
@ -358,5 +373,27 @@ export const getTranslatedUINotifications = (t, locale) => {
: '',
},
///: END:ONLY_INCLUDE_IN
24: {
...UI_NOTIFICATIONS[24],
title: t('notifications24Title'),
description: t('notifications24Description'),
actionText: t('notifications24ActionText'),
date: UI_NOTIFICATIONS[24].date
? new Intl.DateTimeFormat(formattedLocale).format(
new Date(UI_NOTIFICATIONS[24].date),
)
: '',
},
// This syntax is unusual, but very helpful here. It's equivalent to `unnamedObject[NOTIFICATION_DROP_LEDGER_FIREFOX] =`
[NOTIFICATION_DROP_LEDGER_FIREFOX]: {
...UI_NOTIFICATIONS[NOTIFICATION_DROP_LEDGER_FIREFOX],
title: t('notificationsDropLedgerFirefoxTitle'),
description: [t('notificationsDropLedgerFirefoxDescription')],
date: UI_NOTIFICATIONS[NOTIFICATION_DROP_LEDGER_FIREFOX].date
? new Intl.DateTimeFormat(formattedLocale).format(
new Date(UI_NOTIFICATIONS[NOTIFICATION_DROP_LEDGER_FIREFOX].date),
)
: '',
},
};
};

View File

@ -111,6 +111,7 @@
"networkId": "5",
"providerConfig": {
"type": "rpc",
"nickname": "goerli",
"chainId": "0x5",
"ticker": "ETH",
"id": "chain5"
@ -349,8 +350,10 @@
"useNftDetection": true,
"openSeaEnabled": true,
"advancedGasFee": {
"maxBaseFee": "75",
"priorityFee": "2"
"0x5": {
"maxBaseFee": "75",
"priorityFee": "2"
}
},
"nftsDropdownState": {
"0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc": {

View File

@ -72,9 +72,12 @@ describe('ERC721 NFTs testdapp interaction', function () {
assert.equal(await nftsMintStatus.isDisplayed(), true);
// watch 3 of the nfts
await driver.clickElement({ text: 'Watch NFT 1', tag: 'button' });
await driver.clickElement({ text: 'Watch NFT 2', tag: 'button' });
await driver.clickElement({ text: 'Watch NFT 3', tag: 'button' });
await driver.fill('#watchNFTInput', '1');
await driver.clickElement({ text: 'Watch NFT', tag: 'button' });
await driver.fill('#watchNFTInput', '2');
await driver.clickElement({ text: 'Watch NFT', tag: 'button' });
await driver.fill('#watchNFTInput', '3');
await driver.clickElement({ text: 'Watch NFT', tag: 'button' });
await driver.waitUntilXWindowHandles(3);
windowHandles = await driver.getAllWindowHandles();
@ -83,6 +86,12 @@ describe('ERC721 NFTs testdapp interaction', function () {
windowHandles,
);
// avoid race condition
await driver.waitForSelector({
css: '.confirm-add-suggested-nft__nft-tokenId',
text: '#3',
});
// confirm watchNFT
await driver.waitForSelector({
css: '.mm-text--heading-lg',
@ -98,9 +107,12 @@ describe('ERC721 NFTs testdapp interaction', function () {
assert.equal(nftsListItemsFirstCheck.length, 3);
await driver.switchToWindowWithTitle('E2E Test Dapp', windowHandles);
await driver.clickElement({ text: 'Watch NFT 4', tag: 'button' });
await driver.clickElement({ text: 'Watch NFT 5', tag: 'button' });
await driver.clickElement({ text: 'Watch NFT 6', tag: 'button' });
await driver.fill('#watchNFTInput', '4');
await driver.clickElement({ text: 'Watch NFT', tag: 'button' });
await driver.fill('#watchNFTInput', '5');
await driver.clickElement({ text: 'Watch NFT', tag: 'button' });
await driver.fill('#watchNFTInput', '6');
await driver.clickElement({ text: 'Watch NFT', tag: 'button' });
await driver.waitUntilXWindowHandles(3);
windowHandles = await driver.getAllWindowHandles();

View File

@ -4,8 +4,24 @@ const { strict: assert } = require('assert');
const { get, has, set, unset } = require('lodash');
const { Browser } = require('selenium-webdriver');
const { format } = require('prettier');
const { convertToHexValue, withFixtures } = require('../helpers');
const { isObject } = require('@metamask/utils');
const { SENTRY_UI_STATE } = require('../../../app/scripts/lib/setupSentry');
const FixtureBuilder = require('../fixture-builder');
const { convertToHexValue, withFixtures } = require('../helpers');
/**
* Derive a UI state field from a background state field.
*
* @param {string} backgroundField - The path of a background field.
* @returns {string} The path for the corresponding UI field.
*/
function backgroundToUiField(backgroundField) {
// The controller name is lost in the UI due to state flattening
const [, ...rest] = backgroundField.split('.');
const flattenedBackgroundField = rest.join('.');
// Controller state is under the 'metamask' slice in the UI
return `metamask.${flattenedBackgroundField}`;
}
const maskedBackgroundFields = [
'CurrencyController.conversionDate', // This is a timestamp that changes each run
@ -13,14 +29,13 @@ const maskedBackgroundFields = [
// part of the release process
'AppMetadataController.currentAppVersion',
'AppMetadataController.currentMigrationVersion',
'AppStateController.browserEnvironment.browser',
'AppStateController.browserEnvironment.os',
'AppStateController.outdatedBrowserWarningLastShown',
'AppStateController.recoveryPhraseReminderLastShown',
'AppStateController.termsOfUseLastAgreed',
];
const maskedUiFields = [
'metamask.conversionDate', // This is a timestamp that changes each run
// App metadata is masked so that we don't have to update the snapshot as
// part of the release process
'metamask.currentAppVersion',
'metamask.currentMigrationVersion',
];
const maskedUiFields = maskedBackgroundFields.map(backgroundToUiField);
const removedBackgroundFields = [
// This property is timing-dependent
@ -30,13 +45,7 @@ const removedBackgroundFields = [
'AppStateController.timeoutMinutes',
];
const removedUiFields = [
// This property is timing-dependent
'metamask.currentBlockGasLimit',
// These properties are set to undefined, causing inconsistencies between Chrome and Firefox
'metamask.currentPopupId',
'metamask.timeoutMinutes',
];
const removedUiFields = removedBackgroundFields.map(backgroundToUiField);
/**
* Transform background state to make it consistent between test runs.
@ -115,6 +124,38 @@ async function matchesSnapshot({
}
}
/**
* Get an object consisting of all properties in the complete
* object that are missing from the given object.
*
* @param {object} complete - The complete object to compare to.
* @param {object} object - The object to test for missing properties.
*/
function getMissingProperties(complete, object) {
const missing = {};
for (const [key, value] of Object.entries(complete)) {
if (key in object) {
if (isObject(value) && isObject(object[key])) {
const missingNestedProperties = getMissingProperties(
value,
object[key],
);
if (Object.keys(missingNestedProperties).length > 0) {
missing[key] = missingNestedProperties;
} else {
// no missing nested properties
}
} else {
// Skip non-object values, they are considered as present
// even if they represent masked data structures
}
} else {
missing[key] = value;
}
}
return missing;
}
describe('Sentry errors', function () {
const migrationError =
process.env.SELENIUM_BROWSER === Browser.CHROME
@ -320,7 +361,10 @@ describe('Sentry errors', function () {
'Invalid version state',
);
await matchesSnapshot({
data: transformBackgroundState(appState.persistedState),
data: {
...appState.persistedState,
data: transformBackgroundState(appState.persistedState.data),
},
snapshot: 'errors-before-init-opt-in-background-state',
});
},
@ -468,7 +512,10 @@ describe('Sentry errors', function () {
'Invalid version state',
);
await matchesSnapshot({
data: transformBackgroundState(appState.persistedState),
data: {
...appState.persistedState,
data: transformBackgroundState(appState.persistedState.data),
},
snapshot: 'errors-before-init-opt-in-ui-state',
});
},
@ -736,4 +783,80 @@ describe('Sentry errors', function () {
);
});
});
it('should have no policy gaps for UI controller state', async function () {
await withFixtures(
{
fixtures: new FixtureBuilder().build(),
ganacheOptions,
title: this.test.title,
},
async ({ driver }) => {
await driver.navigate();
await driver.findElement('#password');
const fullUiState = await driver.executeScript(() =>
window.stateHooks?.getCleanAppState?.(),
);
const missingState = getMissingProperties(
fullUiState.metamask,
SENTRY_UI_STATE.metamask,
);
assert.deepEqual(missingState, {});
},
);
});
it('should not have extra properties in UI state mask', async function () {
const expectedMissingState = {
currentPopupId: false, // Initialized as undefined
// Part of transaction controller store, but missing from the initial
// state
lastFetchedBlockNumbers: false,
preferences: {
autoLockTimeLimit: true, // Initialized as undefined
},
smartTransactionsState: {
fees: {
approvalTxFees: true, // Initialized as undefined
tradeTxFees: true, // Initialized as undefined
},
userOptIn: true, // Initialized as undefined
},
swapsState: {
// This can get wiped out during initialization due to a bug in
// the "resetState" method
swapsFeatureFlags: true,
},
// This can get erased due to a bug in the app state controller's
// preferences state change handler
timeoutMinutes: true,
};
await withFixtures(
{
fixtures: new FixtureBuilder().build(),
ganacheOptions,
title: this.test.title,
},
async ({ driver }) => {
await driver.navigate();
await driver.findElement('#password');
const fullUiState = await driver.executeScript(() =>
window.stateHooks?.getCleanAppState?.(),
);
const extraMaskProperties = getMissingProperties(
SENTRY_UI_STATE.metamask,
fullUiState.metamask,
);
const unexpectedExtraMaskProperties = getMissingProperties(
extraMaskProperties,
expectedMissingState,
);
assert.deepEqual(unexpectedExtraMaskProperties, {});
},
);
});
});

View File

@ -1,12 +1,12 @@
{
"AccountTracker": { "accounts": "object" },
"AddressBookController": "object",
"AddressBookController": { "addressBook": "object" },
"AlertController": {
"alertEnabledness": { "unconnectedAccount": true, "web3ShimUsage": true },
"unconnectedAccountAlertShownOrigins": "object",
"web3ShimUsageOrigins": "object"
},
"AnnouncementController": "object",
"AnnouncementController": { "announcements": "object" },
"AppMetadataController": {
"currentAppVersion": "string",
"previousAppVersion": "",
@ -16,36 +16,41 @@
"AppStateController": {
"connectedStatusPopoverHasBeenShown": true,
"defaultHomeActiveTabName": null,
"browserEnvironment": "object",
"popupGasPollTokens": "object",
"notificationGasPollTokens": "object",
"fullScreenGasPollTokens": "object",
"recoveryPhraseReminderHasBeenShown": "boolean",
"browserEnvironment": { "os": "string", "browser": "string" },
"popupGasPollTokens": [],
"notificationGasPollTokens": [],
"fullScreenGasPollTokens": [],
"recoveryPhraseReminderHasBeenShown": true,
"recoveryPhraseReminderLastShown": "number",
"outdatedBrowserWarningLastShown": "number",
"nftsDetectionNoticeDismissed": "boolean",
"showTestnetMessageInDropdown": "boolean",
"showBetaHeader": "boolean",
"showProductTour": "boolean",
"trezorModel": "object",
"nftsDropdownState": "object",
"nftsDetectionNoticeDismissed": false,
"showTestnetMessageInDropdown": true,
"showBetaHeader": false,
"showProductTour": true,
"trezorModel": null,
"nftsDropdownState": {},
"termsOfUseLastAgreed": "number",
"qrHardware": "object",
"usedNetworks": "object",
"snapsInstallPrivacyWarningShown": "boolean",
"serviceWorkerLastActiveTime": "number"
"qrHardware": {},
"usedNetworks": { "0x1": true, "0x5": true, "0x539": true },
"snapsInstallPrivacyWarningShown": true,
"hadAdvancedGasFeesSetPriorToMigration92_3": false,
"serviceWorkerLastActiveTime": 0
},
"ApprovalController": "object",
"CachedBalancesController": "object",
"CronjobController": "object",
"ApprovalController": {
"pendingApprovals": "object",
"pendingApprovalCount": "number",
"approvalFlows": "object"
},
"CachedBalancesController": { "cachedBalances": "object" },
"CronjobController": { "jobs": "object" },
"CurrencyController": {
"conversionDate": "number",
"conversionRate": 1700,
"nativeCurrency": "ETH",
"currentCurrency": "usd",
"pendingCurrentCurrency": "object",
"pendingNativeCurrency": "object",
"usdConversionRate": "number"
"pendingCurrentCurrency": null,
"pendingNativeCurrency": null,
"usdConversionRate": 1700
},
"DecryptMessageController": {
"unapprovedDecryptMsgs": "object",
@ -55,8 +60,12 @@
"unapprovedEncryptionPublicKeyMsgs": "object",
"unapprovedEncryptionPublicKeyMsgCount": 0
},
"EnsController": "object",
"GasFeeController": "object",
"EnsController": { "ensResolutionsByAddress": "object" },
"GasFeeController": {
"gasFeeEstimates": {},
"estimatedGasFeeTimeBounds": {},
"gasEstimateType": "none"
},
"KeyringController": {
"isUnlocked": false,
"keyringTypes": "object",
@ -75,42 +84,54 @@
"selectedNetworkClientId": "string",
"networkId": "1337",
"providerConfig": {
"chainId": "string",
"chainId": "0x539",
"nickname": "Localhost 8545",
"rpcPrefs": "object",
"rpcUrl": "string",
"ticker": "ETH",
"type": "rpc",
"id": "string"
"id": "networkConfigurationId"
},
"networksMetadata": {
"networkConfigurationId": {
"EIPS": { "1559": false },
"status": "available"
}
},
"networksMetadata": "object",
"networkConfigurations": "object"
},
"NftController": "object",
"NotificationController": "object",
"NftController": {
"allNftContracts": "object",
"allNfts": "object",
"ignoredNfts": "object"
},
"NotificationController": { "notifications": "object" },
"OnboardingController": {
"seedPhraseBackedUp": true,
"firstTimeFlowType": "import",
"completedOnboarding": true,
"onboardingTabs": "object"
},
"PermissionController": "object",
"PermissionLogController": "object",
"PermissionController": { "subjects": "object" },
"PermissionLogController": {
"permissionHistory": "object",
"permissionActivityLog": "object"
},
"PreferencesController": {
"useBlockie": false,
"useNonceField": false,
"usePhishDetect": true,
"dismissSeedBackUpReminder": "boolean",
"disabledRpcMethodPreferences": "object",
"useMultiAccountBalanceChecker": "boolean",
"useTokenDetection": "boolean",
"useNftDetection": "boolean",
"use4ByteResolution": "boolean",
"useCurrencyRateCheck": "boolean",
"openSeaEnabled": "boolean",
"advancedGasFee": "object",
"dismissSeedBackUpReminder": true,
"disabledRpcMethodPreferences": { "eth_sign": false },
"useMultiAccountBalanceChecker": true,
"useTokenDetection": false,
"useNftDetection": false,
"use4ByteResolution": true,
"useCurrencyRateCheck": true,
"openSeaEnabled": false,
"advancedGasFee": {},
"featureFlags": {},
"incomingTransactionsPreferences": "object",
"incomingTransactionsPreferences": {},
"knownMethodData": "object",
"currentLocale": "en",
"identities": "object",
@ -122,14 +143,14 @@
"showTestNetworks": false,
"useNativeCurrencyAsPrimaryCurrency": true
},
"ipfsGateway": "dweb.link",
"useAddressBarEnsResolution": "boolean",
"infuraBlocked": "boolean",
"ledgerTransportType": "string",
"ipfsGateway": "string",
"useAddressBarEnsResolution": true,
"infuraBlocked": false,
"ledgerTransportType": "webhid",
"snapRegistryList": "object",
"transactionSecurityCheckEnabled": "boolean",
"theme": "string",
"isLineaMainnetReleased": "boolean",
"transactionSecurityCheckEnabled": false,
"theme": "light",
"isLineaMainnetReleased": true,
"selectedAddress": "string"
},
"SignatureController": {
@ -140,13 +161,65 @@
"unapprovedPersonalMsgCount": 0,
"unapprovedTypedMessagesCount": 0
},
"SmartTransactionsController": "object",
"SnapController": "object",
"SnapsRegistry": "object",
"SubjectMetadataController": "object",
"SwapsController": "object",
"TokenListController": "object",
"TokenRatesController": "object",
"TokensController": "object",
"TxController": "object"
"SmartTransactionsController": {
"smartTransactionsState": {
"fees": {},
"liveness": true,
"smartTransactions": "object"
}
},
"SnapController": {
"snapErrors": "object",
"snaps": "object",
"snapStates": "object"
},
"SnapsRegistry": { "database": "object", "lastUpdated": "object" },
"SubjectMetadataController": { "subjectMetadata": "object" },
"SwapsController": {
"swapsState": {
"quotes": "object",
"quotesPollingLimitEnabled": false,
"fetchParams": null,
"tokens": "object",
"tradeTxId": "object",
"approveTxId": "object",
"quotesLastFetched": null,
"customMaxGas": "",
"customGasPrice": null,
"customMaxFeePerGas": null,
"customMaxPriorityFeePerGas": null,
"swapsUserFeeLevel": "",
"selectedAggId": null,
"customApproveTxData": "string",
"errorKey": "",
"topAggId": "object",
"routeState": "",
"swapsFeatureIsLive": true,
"saveFetchedQuotes": false,
"swapsQuoteRefreshTime": 60000,
"swapsQuotePrefetchingRefreshTime": 60000,
"swapsStxBatchStatusRefreshTime": 10000,
"swapsStxGetTransactionsRefreshTime": 10000,
"swapsStxMaxFeeMultiplier": 2
}
},
"TokenListController": {
"tokenList": "object",
"tokensChainsCache": {},
"preventPollingOnNetworkRestart": true
},
"TokenRatesController": { "contractExchangeRates": "object" },
"TokensController": {
"tokens": "object",
"ignoredTokens": "object",
"detectedTokens": "object",
"allTokens": {},
"allIgnoredTokens": {},
"allDetectedTokens": {}
},
"TxController": {
"unapprovedTxs": "object",
"currentNetworkTxList": "object",
"transactions": "object"
}
}

View File

@ -11,7 +11,7 @@
"isInitialized": true,
"isUnlocked": false,
"isAccountMenuOpen": false,
"isNetworkMenuOpen": "boolean",
"isNetworkMenuOpen": false,
"identities": "object",
"unapprovedTxs": "object",
"networkConfigurations": "object",
@ -21,7 +21,6 @@
"customNonceValue": "",
"useBlockie": false,
"featureFlags": {},
"incomingTransactionsPreferences": "object",
"welcomeScreenSeen": false,
"currentLocale": "en",
"preferences": {
@ -33,31 +32,32 @@
"firstTimeFlowType": "import",
"completedOnboarding": true,
"knownMethodData": "object",
"use4ByteResolution": "boolean",
"use4ByteResolution": true,
"participateInMetaMetrics": true,
"nextNonce": null,
"conversionRate": 1300,
"nativeCurrency": "ETH",
"connectedStatusPopoverHasBeenShown": true,
"defaultHomeActiveTabName": null,
"browserEnvironment": "object",
"popupGasPollTokens": "object",
"notificationGasPollTokens": "object",
"fullScreenGasPollTokens": "object",
"recoveryPhraseReminderHasBeenShown": "boolean",
"browserEnvironment": { "os": "string", "browser": "string" },
"popupGasPollTokens": [],
"notificationGasPollTokens": [],
"fullScreenGasPollTokens": [],
"recoveryPhraseReminderHasBeenShown": true,
"recoveryPhraseReminderLastShown": "number",
"outdatedBrowserWarningLastShown": "number",
"nftsDetectionNoticeDismissed": "boolean",
"showTestnetMessageInDropdown": "boolean",
"showBetaHeader": "boolean",
"showProductTour": "boolean",
"trezorModel": "object",
"nftsDropdownState": "object",
"nftsDetectionNoticeDismissed": false,
"showTestnetMessageInDropdown": true,
"showBetaHeader": false,
"showProductTour": true,
"trezorModel": null,
"nftsDropdownState": {},
"termsOfUseLastAgreed": "number",
"qrHardware": "object",
"usedNetworks": "object",
"snapsInstallPrivacyWarningShown": "boolean",
"serviceWorkerLastActiveTime": "number",
"qrHardware": {},
"usedNetworks": { "0x1": true, "0x5": true, "0x539": true },
"snapsInstallPrivacyWarningShown": true,
"hadAdvancedGasFeesSetPriorToMigration92_3": false,
"serviceWorkerLastActiveTime": 0,
"currentAppVersion": "string",
"previousAppVersion": "",
"previousMigrationVersion": 0,
@ -65,51 +65,56 @@
"selectedNetworkClientId": "string",
"networkId": "1337",
"providerConfig": {
"chainId": "string",
"chainId": "0x539",
"nickname": "Localhost 8545",
"rpcPrefs": "object",
"rpcUrl": "string",
"ticker": "ETH",
"type": "rpc",
"id": "string"
"id": "networkConfigurationId"
},
"networksMetadata": {
"networkConfigurationId": {
"EIPS": { "1559": false },
"status": "available"
}
},
"networksMetadata": "object",
"cachedBalances": "object",
"keyringTypes": "object",
"keyrings": "object",
"useNonceField": false,
"usePhishDetect": true,
"dismissSeedBackUpReminder": "boolean",
"disabledRpcMethodPreferences": "object",
"useMultiAccountBalanceChecker": "boolean",
"useTokenDetection": "boolean",
"useNftDetection": "boolean",
"useCurrencyRateCheck": "boolean",
"openSeaEnabled": "boolean",
"advancedGasFee": "object",
"dismissSeedBackUpReminder": true,
"disabledRpcMethodPreferences": { "eth_sign": false },
"useMultiAccountBalanceChecker": true,
"useTokenDetection": false,
"useNftDetection": false,
"useCurrencyRateCheck": true,
"openSeaEnabled": false,
"advancedGasFee": {},
"incomingTransactionsPreferences": {},
"lostIdentities": "object",
"forgottenPassword": false,
"ipfsGateway": "dweb.link",
"useAddressBarEnsResolution": "boolean",
"infuraBlocked": "boolean",
"ledgerTransportType": "string",
"ipfsGateway": "string",
"useAddressBarEnsResolution": true,
"infuraBlocked": false,
"ledgerTransportType": "webhid",
"snapRegistryList": "object",
"transactionSecurityCheckEnabled": "boolean",
"theme": "string",
"isLineaMainnetReleased": "boolean",
"transactionSecurityCheckEnabled": false,
"theme": "light",
"isLineaMainnetReleased": true,
"selectedAddress": "string",
"metaMetricsId": "fake-metrics-id",
"eventsBeforeMetricsOptIn": "object",
"traits": "object",
"transactions": "object",
"fragments": "object",
"segmentApiCalls": "object",
"previousUserTraits": "object",
"conversionDate": "number",
"currentCurrency": "usd",
"pendingCurrentCurrency": "object",
"pendingNativeCurrency": "object",
"usdConversionRate": "number",
"pendingCurrentCurrency": null,
"pendingNativeCurrency": null,
"usdConversionRate": 1300,
"alertEnabledness": { "unconnectedAccount": true, "web3ShimUsage": true },
"unconnectedAccountAlertShownOrigins": "object",
"web3ShimUsageOrigins": "object",
@ -120,19 +125,23 @@
"permissionActivityLog": "object",
"subjectMetadata": "object",
"announcements": "object",
"gasFeeEstimates": "object",
"estimatedGasFeeTimeBounds": "object",
"gasEstimateType": "string",
"gasFeeEstimates": {},
"estimatedGasFeeTimeBounds": {},
"gasEstimateType": "none",
"tokenList": "object",
"tokensChainsCache": "object",
"preventPollingOnNetworkRestart": "boolean",
"tokensChainsCache": {},
"preventPollingOnNetworkRestart": true,
"tokens": "object",
"ignoredTokens": "object",
"detectedTokens": "object",
"allTokens": "object",
"allIgnoredTokens": "object",
"allDetectedTokens": "object",
"smartTransactionsState": "object",
"allTokens": {},
"allIgnoredTokens": {},
"allDetectedTokens": {},
"smartTransactionsState": {
"fees": {},
"liveness": true,
"smartTransactions": "object"
},
"allNftContracts": "object",
"allNfts": "object",
"ignoredNfts": "object",
@ -145,6 +154,7 @@
"notifications": "object",
"accounts": "object",
"currentNetworkTxList": "object",
"transactions": "object",
"unapprovedDecryptMsgs": "object",
"unapprovedDecryptMsgCount": 0,
"unapprovedEncryptionPublicKeyMsgs": "object",
@ -155,7 +165,32 @@
"unapprovedMsgCount": 0,
"unapprovedPersonalMsgCount": 0,
"unapprovedTypedMessagesCount": 0,
"swapsState": "object",
"swapsState": {
"quotes": "object",
"quotesPollingLimitEnabled": false,
"fetchParams": null,
"tokens": "object",
"tradeTxId": "object",
"approveTxId": "object",
"quotesLastFetched": null,
"customMaxGas": "",
"customGasPrice": null,
"customMaxFeePerGas": null,
"customMaxPriorityFeePerGas": null,
"swapsUserFeeLevel": "",
"selectedAggId": null,
"customApproveTxData": "string",
"errorKey": "",
"topAggId": "object",
"routeState": "",
"swapsFeatureIsLive": true,
"saveFetchedQuotes": false,
"swapsQuoteRefreshTime": 60000,
"swapsQuotePrefetchingRefreshTime": 60000,
"swapsStxBatchStatusRefreshTime": 10000,
"swapsStxGetTransactionsRefreshTime": 10000,
"swapsStxMaxFeeMultiplier": 2
},
"ensResolutionsByAddress": "object",
"pendingApprovals": "object",
"pendingApprovalCount": "number",

View File

@ -5,33 +5,42 @@
"unconnectedAccountAlertShownOrigins": "object",
"web3ShimUsageOrigins": "object"
},
"AnnouncementController": "object",
"AnnouncementController": { "announcements": "object" },
"AppStateController": {
"browserEnvironment": "object",
"nftsDropdownState": "object",
"browserEnvironment": {},
"nftsDropdownState": {},
"connectedStatusPopoverHasBeenShown": true,
"termsOfUseLastAgreed": "number",
"defaultHomeActiveTabName": null,
"fullScreenGasPollTokens": "object",
"notificationGasPollTokens": "object",
"popupGasPollTokens": "object",
"qrHardware": "object",
"recoveryPhraseReminderHasBeenShown": "boolean",
"fullScreenGasPollTokens": [],
"notificationGasPollTokens": [],
"popupGasPollTokens": [],
"qrHardware": {},
"recoveryPhraseReminderHasBeenShown": true,
"recoveryPhraseReminderLastShown": "number",
"showTestnetMessageInDropdown": "boolean",
"trezorModel": "object",
"usedNetworks": "object",
"snapsInstallPrivacyWarningShown": "boolean"
"showTestnetMessageInDropdown": true,
"trezorModel": null,
"usedNetworks": {
"0x1": true,
"0xe708": true,
"0x5": true,
"0x539": true
},
"snapsInstallPrivacyWarningShown": true
},
"CachedBalancesController": "object",
"CachedBalancesController": { "cachedBalances": "object" },
"CurrencyController": {
"conversionDate": 1665507600,
"conversionDate": "number",
"conversionRate": 1300,
"currentCurrency": "usd",
"nativeCurrency": "ETH",
"usdConversionRate": "number"
"usdConversionRate": 1300
},
"GasFeeController": {
"estimatedGasFeeTimeBounds": {},
"gasEstimateType": "none",
"gasFeeEstimates": {}
},
"GasFeeController": "object",
"KeyringController": { "vault": "string" },
"MetaMetricsController": {
"eventsBeforeMetricsOptIn": "object",
@ -43,15 +52,17 @@
"NetworkController": {
"networkId": "1337",
"selectedNetworkClientId": "string",
"networksMetadata": "object",
"networksMetadata": {
"networkConfigurationId": { "EIPS": {}, "status": "available" }
},
"providerConfig": {
"chainId": "string",
"chainId": "0x539",
"nickname": "Localhost 8545",
"rpcPrefs": "object",
"rpcUrl": "string",
"ticker": "ETH",
"type": "rpc",
"id": "string"
"id": "networkConfigurationId"
},
"networkConfigurations": "object"
},
@ -61,20 +72,20 @@
"onboardingTabs": "object",
"seedPhraseBackedUp": true
},
"PermissionController": "object",
"PermissionController": { "subjects": "object" },
"PreferencesController": {
"advancedGasFee": "object",
"advancedGasFee": null,
"currentLocale": "en",
"dismissSeedBackUpReminder": "boolean",
"dismissSeedBackUpReminder": true,
"featureFlags": {},
"forgottenPassword": false,
"identities": "object",
"infuraBlocked": "boolean",
"ipfsGateway": "dweb.link",
"infuraBlocked": false,
"ipfsGateway": "string",
"knownMethodData": "object",
"ledgerTransportType": "string",
"ledgerTransportType": "webhid",
"lostIdentities": "object",
"openSeaEnabled": "boolean",
"openSeaEnabled": false,
"preferences": {
"hideZeroBalanceTokens": false,
"showFiatInTestnets": false,
@ -82,19 +93,32 @@
"useNativeCurrencyAsPrimaryCurrency": true
},
"selectedAddress": "string",
"theme": "string",
"theme": "light",
"useBlockie": false,
"useNftDetection": "boolean",
"useNftDetection": false,
"useNonceField": false,
"usePhishDetect": true,
"useTokenDetection": "boolean",
"useCurrencyRateCheck": "boolean",
"useMultiAccountBalanceChecker": "boolean"
"useTokenDetection": false,
"useCurrencyRateCheck": true,
"useMultiAccountBalanceChecker": true
},
"SmartTransactionsController": "object",
"SubjectMetadataController": "object",
"TokensController": "object",
"TransactionController": "object",
"SmartTransactionsController": {
"smartTransactionsState": {
"fees": {},
"liveness": true,
"smartTransactions": "object"
}
},
"SubjectMetadataController": { "subjectMetadata": "object" },
"TokensController": {
"allDetectedTokens": {},
"allIgnoredTokens": {},
"allTokens": {},
"detectedTokens": "object",
"ignoredTokens": "object",
"tokens": "object"
},
"TransactionController": { "transactions": "object" },
"config": "object",
"firstTimeInfo": "object"
}

View File

@ -5,33 +5,42 @@
"unconnectedAccountAlertShownOrigins": "object",
"web3ShimUsageOrigins": "object"
},
"AnnouncementController": "object",
"AnnouncementController": { "announcements": "object" },
"AppStateController": {
"browserEnvironment": "object",
"nftsDropdownState": "object",
"browserEnvironment": {},
"nftsDropdownState": {},
"connectedStatusPopoverHasBeenShown": true,
"termsOfUseLastAgreed": "number",
"defaultHomeActiveTabName": null,
"fullScreenGasPollTokens": "object",
"notificationGasPollTokens": "object",
"popupGasPollTokens": "object",
"qrHardware": "object",
"recoveryPhraseReminderHasBeenShown": "boolean",
"fullScreenGasPollTokens": [],
"notificationGasPollTokens": [],
"popupGasPollTokens": [],
"qrHardware": {},
"recoveryPhraseReminderHasBeenShown": true,
"recoveryPhraseReminderLastShown": "number",
"showTestnetMessageInDropdown": "boolean",
"trezorModel": "object",
"usedNetworks": "object",
"snapsInstallPrivacyWarningShown": "boolean"
"showTestnetMessageInDropdown": true,
"trezorModel": null,
"usedNetworks": {
"0x1": true,
"0xe708": true,
"0x5": true,
"0x539": true
},
"snapsInstallPrivacyWarningShown": true
},
"CachedBalancesController": "object",
"CachedBalancesController": { "cachedBalances": "object" },
"CurrencyController": {
"conversionDate": 1665507600,
"conversionDate": "number",
"conversionRate": 1300,
"currentCurrency": "usd",
"nativeCurrency": "ETH",
"usdConversionRate": "number"
"usdConversionRate": 1300
},
"GasFeeController": {
"estimatedGasFeeTimeBounds": {},
"gasEstimateType": "none",
"gasFeeEstimates": {}
},
"GasFeeController": "object",
"KeyringController": { "vault": "string" },
"MetaMetricsController": {
"eventsBeforeMetricsOptIn": "object",
@ -43,15 +52,17 @@
"NetworkController": {
"networkId": "1337",
"selectedNetworkClientId": "string",
"networksMetadata": "object",
"networksMetadata": {
"networkConfigurationId": { "EIPS": {}, "status": "available" }
},
"providerConfig": {
"chainId": "string",
"chainId": "0x539",
"nickname": "Localhost 8545",
"rpcPrefs": "object",
"rpcUrl": "string",
"ticker": "ETH",
"type": "rpc",
"id": "string"
"id": "networkConfigurationId"
},
"networkConfigurations": "object"
},
@ -61,20 +72,20 @@
"onboardingTabs": "object",
"seedPhraseBackedUp": true
},
"PermissionController": "object",
"PermissionController": { "subjects": "object" },
"PreferencesController": {
"advancedGasFee": "object",
"advancedGasFee": null,
"currentLocale": "en",
"dismissSeedBackUpReminder": "boolean",
"dismissSeedBackUpReminder": true,
"featureFlags": {},
"forgottenPassword": false,
"identities": "object",
"infuraBlocked": "boolean",
"ipfsGateway": "dweb.link",
"infuraBlocked": false,
"ipfsGateway": "string",
"knownMethodData": "object",
"ledgerTransportType": "string",
"ledgerTransportType": "webhid",
"lostIdentities": "object",
"openSeaEnabled": "boolean",
"openSeaEnabled": false,
"preferences": {
"hideZeroBalanceTokens": false,
"showFiatInTestnets": false,
@ -82,19 +93,32 @@
"useNativeCurrencyAsPrimaryCurrency": true
},
"selectedAddress": "string",
"theme": "string",
"theme": "light",
"useBlockie": false,
"useNftDetection": "boolean",
"useNftDetection": false,
"useNonceField": false,
"usePhishDetect": true,
"useTokenDetection": "boolean",
"useCurrencyRateCheck": "boolean",
"useMultiAccountBalanceChecker": "boolean"
"useTokenDetection": false,
"useCurrencyRateCheck": true,
"useMultiAccountBalanceChecker": true
},
"SmartTransactionsController": "object",
"SubjectMetadataController": "object",
"TokensController": "object",
"TransactionController": "object",
"SmartTransactionsController": {
"smartTransactionsState": {
"fees": {},
"liveness": true,
"smartTransactions": "object"
}
},
"SubjectMetadataController": { "subjectMetadata": "object" },
"TokensController": {
"allDetectedTokens": {},
"allIgnoredTokens": {},
"allTokens": {},
"detectedTokens": "object",
"ignoredTokens": "object",
"tokens": "object"
},
"TransactionController": { "transactions": "object" },
"config": "object",
"firstTimeInfo": "object"
},

View File

@ -1,6 +1,7 @@
import React, { useEffect, useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { capitalize } from 'lodash';
import { useTransactionEventFragment } from '../../../../hooks/useTransactionEventFragment';
import { EditGasModes } from '../../../../../shared/constants/gas';
@ -8,7 +9,11 @@ import {
Display,
FlexDirection,
} from '../../../../helpers/constants/design-system';
import { getAdvancedGasFeeValues } from '../../../../selectors';
import {
getAdvancedGasFeeValues,
getCurrentChainId,
getNetworkIdentifier,
} from '../../../../selectors';
import { setAdvancedGasFee } from '../../../../store/actions';
import { useGasFeeContext } from '../../../../contexts/gasFee';
import { useAdvancedGasFeePopoverContext } from '../context';
@ -21,6 +26,9 @@ const AdvancedGasFeeDefaults = () => {
const { gasErrors, maxBaseFee, maxPriorityFeePerGas } =
useAdvancedGasFeePopoverContext();
const advancedGasFeeValues = useSelector(getAdvancedGasFeeValues);
// This will need to use a different chainId in multinetwork
const chainId = useSelector(getCurrentChainId);
const networkIdentifier = useSelector(getNetworkIdentifier);
const { updateTransactionEventFragment } = useTransactionEventFragment();
const { editGasMode } = useGasFeeContext();
const [isDefaultSettingsSelected, setDefaultSettingsSelected] = useState(
@ -39,7 +47,7 @@ const AdvancedGasFeeDefaults = () => {
const handleUpdateDefaultSettings = () => {
if (isDefaultSettingsSelected) {
dispatch(setAdvancedGasFee(null));
dispatch(setAdvancedGasFee({ chainId, gasFeePreferences: undefined }));
setDefaultSettingsSelected(false);
updateTransactionEventFragment({
properties: {
@ -50,8 +58,11 @@ const AdvancedGasFeeDefaults = () => {
} else {
dispatch(
setAdvancedGasFee({
maxBaseFee,
priorityFee: maxPriorityFeePerGas,
chainId,
gasFeePreferences: {
maxBaseFee,
priorityFee: maxPriorityFeePerGas,
},
}),
);
updateTransactionEventFragment({
@ -82,13 +93,7 @@ const AdvancedGasFeeDefaults = () => {
isChecked={isDefaultSettingsSelected}
onChange={handleUpdateDefaultSettings}
isDisabled={gasErrors.maxFeePerGas || gasErrors.maxPriorityFeePerGas}
label={
isDefaultSettingsSelected
? t('advancedGasFeeDefaultOptOut')
: t('advancedGasFeeDefaultOptIn', [
<strong key="default-value-change">{t('newValues')}</strong>,
])
}
label={t('advancedGasFeeDefaultOptIn', [capitalize(networkIdentifier)])}
/>
</Box>
);

View File

@ -15,8 +15,11 @@ import { GasFeeContextProvider } from '../../../../contexts/gasFee';
import configureStore from '../../../../store/store';
import AdvancedGasFeeInputs from '../advanced-gas-fee-inputs';
import { CHAIN_IDS } from '../../../../../shared/constants/network';
import AdvancedGasFeeDefaults from './advanced-gas-fee-defaults';
const TEXT_SELECTOR = 'Save these values as my default for the Goerli network.';
jest.mock('../../../../store/actions', () => ({
disconnectGasFeeEstimatePoller: jest.fn(),
getGasFeeEstimatesAndStartPolling: jest
@ -62,68 +65,58 @@ const render = (defaultGasParams, contextParams) => {
};
describe('AdvancedGasFeeDefaults', () => {
it('should renders correct message when the default is not set', () => {
render({ advancedGasFee: null });
expect(screen.queryByText('new values')).toBeInTheDocument();
render({ advancedGasFee: {} });
expect(screen.queryByText(TEXT_SELECTOR)).toBeInTheDocument();
});
it('should renders correct message when the default values are set', () => {
render({
advancedGasFee: { maxBaseFee: 50, priorityFee: 2 },
advancedGasFee: {
[CHAIN_IDS.GOERLI]: { maxBaseFee: 50, priorityFee: 2 },
},
});
expect(
screen.queryByText(
'Always use these values and advanced setting as default.',
),
).toBeInTheDocument();
expect(screen.queryByText(TEXT_SELECTOR)).toBeInTheDocument();
});
it('should renders correct message when the default values are set and the maxBaseFee values are updated', () => {
render({
advancedGasFee: { maxBaseFee: 50, priorityFee: 2 },
advancedGasFee: {
[CHAIN_IDS.GOERLI]: { maxBaseFee: 50, priorityFee: 2 },
},
});
expect(document.getElementsByTagName('input')[2]).toBeChecked();
expect(
screen.queryByText(
'Always use these values and advanced setting as default.',
),
).toBeInTheDocument();
expect(screen.queryByText(TEXT_SELECTOR)).toBeInTheDocument();
fireEvent.change(document.getElementsByTagName('input')[0], {
target: { value: 75 },
});
expect(document.getElementsByTagName('input')[0]).toHaveValue(75);
expect(screen.queryByText('new values')).toBeInTheDocument();
expect(
screen.queryByText('Save these as my default for "Advanced"'),
).toBeInTheDocument();
expect(screen.queryByText(TEXT_SELECTOR)).toBeInTheDocument();
expect(screen.queryByText(TEXT_SELECTOR)).toBeInTheDocument();
});
it('should renders correct message when the default values are set and the priorityFee values are updated', () => {
render({
advancedGasFee: { maxBaseFee: 50, priorityFee: 2 },
advancedGasFee: {
[CHAIN_IDS.GOERLI]: { maxBaseFee: 50, priorityFee: 2 },
},
});
expect(document.getElementsByTagName('input')[2]).toBeChecked();
expect(
screen.queryByText(
'Always use these values and advanced setting as default.',
),
).toBeInTheDocument();
expect(screen.queryByText(TEXT_SELECTOR)).toBeInTheDocument();
fireEvent.change(document.getElementsByTagName('input')[1], {
target: { value: 5 },
});
expect(document.getElementsByTagName('input')[1]).toHaveValue(5);
expect(screen.queryByText('new values')).toBeInTheDocument();
expect(
screen.queryByText('Save these as my default for "Advanced"'),
).toBeInTheDocument();
expect(screen.queryByText(TEXT_SELECTOR)).toBeInTheDocument();
expect(screen.queryByText(TEXT_SELECTOR)).toBeInTheDocument();
});
it('should call action setAdvancedGasFee when checkbox or label text is clicked', () => {
render({
advancedGasFee: { maxBaseFee: 50, priorityFee: 2 },
advancedGasFee: {
[CHAIN_IDS.GOERLI]: { maxBaseFee: 50, priorityFee: 2 },
},
});
const mock = jest
.spyOn(Actions, 'setAdvancedGasFee')
.mockReturnValue({ type: 'test' });
const checkboxLabel = screen.queryByText(
'Always use these values and advanced setting as default.',
);
const checkboxLabel = screen.queryByText(TEXT_SELECTOR);
fireEvent.click(checkboxLabel);
expect(mock).toHaveBeenCalledTimes(1);
const checkbox = document.querySelector('input[type=checkbox]');

View File

@ -13,6 +13,7 @@ import configureStore from '../../../../../store/store';
import { AdvancedGasFeePopoverContextProvider } from '../../context';
import AdvancedGasFeeGasLimit from '../../advanced-gas-fee-gas-limit';
import { CHAIN_IDS } from '../../../../../../shared/constants/network';
import PriorityfeeInput from './priority-fee-input';
jest.mock('../../../../../store/actions', () => ({
@ -34,7 +35,7 @@ const render = (txProps, contextProps) => {
balance: '0x1F4',
},
},
advancedGasFee: { priorityFee: 100 },
advancedGasFee: { [CHAIN_IDS.GOERLI]: { priorityFee: 100 } },
featureFlags: { advancedInlineGas: true },
gasFeeEstimates:
mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates,

View File

@ -19,6 +19,7 @@ import {
DetectedTokensBanner,
TokenListItem,
ImportTokenLink,
BalanceOverview,
} from '../../multichain';
const AssetList = ({ onClickAsset }) => {
@ -61,6 +62,7 @@ const AssetList = ({ onClickAsset }) => {
return (
<>
{process.env.MULTICHAIN ? <BalanceOverview /> : null}
<TokenListItem
onClick={() => onClickAsset(nativeCurrency)}
title={nativeCurrency}

View File

@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
BUTTON_VARIANT,
ButtonVariant,
Button,
Box,
Modal,
@ -72,7 +72,7 @@ export default function ConfigureSnapPopup({
{t('configureSnapPopupLink')}
</Text>
<Button
variant={BUTTON_VARIANT.LINK}
variant={ButtonVariant.Link}
marginBottom={8}
onClick={() => {
global.platform.openTab({

View File

@ -14,12 +14,6 @@ import { PageContainerFooter } from '../../../ui/page-container';
import { INSUFFICIENT_FUNDS_ERROR_KEY } from '../../../../helpers/constants/error-keys';
import { Severity } from '../../../../helpers/constants/design-system';
import { isSuspiciousResponse } from '../../../../../shared/modules/security-provider.utils';
///: BEGIN:ONLY_INCLUDE_IN(blockaid)
import BlockaidBannerAlert from '../../security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert';
///: END:ONLY_INCLUDE_IN
import SecurityProviderBannerMessage from '../../security-provider-banner-message/security-provider-banner-message';
import { ConfirmPageContainerSummary, ConfirmPageContainerWarning } from '.';
export default class ConfirmPageContainerContent extends Component {
@ -67,7 +61,6 @@ export default class ConfirmPageContainerContent extends Component {
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
openBuyCryptoInPdapp: PropTypes.func,
///: END:ONLY_INCLUDE_IN
txData: PropTypes.object,
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
noteComponent: PropTypes.node,
///: END:ONLY_INCLUDE_IN
@ -209,7 +202,6 @@ export default class ConfirmPageContainerContent extends Component {
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
openBuyCryptoInPdapp,
///: END:ONLY_INCLUDE_IN
txData,
} = this.props;
const { t } = this.context;
@ -227,18 +219,6 @@ export default class ConfirmPageContainerContent extends Component {
{ethGasPriceWarning && (
<ConfirmPageContainerWarning warning={ethGasPriceWarning} />
)}
{
///: BEGIN:ONLY_INCLUDE_IN(blockaid)
<BlockaidBannerAlert
securityAlertResponse={txData?.securityAlertResponse}
/>
///: END:ONLY_INCLUDE_IN
}
{isSuspiciousResponse(txData?.securityProviderResponse) && (
<SecurityProviderBannerMessage
securityProviderResponse={txData.securityProviderResponse}
/>
)}
<ConfirmPageContainerSummary
className={classnames({
'confirm-page-container-summary--border':

View File

@ -1,7 +1,6 @@
import { fireEvent } from '@testing-library/react';
import React from 'react';
import configureMockStore from 'redux-mock-store';
import { SECURITY_PROVIDER_MESSAGE_SEVERITY } from '../../../../../shared/constants/security-provider';
import { TransactionType } from '../../../../../shared/constants/transaction';
import { renderWithProvider } from '../../../../../test/lib/render-helpers';
import {
@ -51,13 +50,6 @@ describe('Confirm Page Container Content', () => {
disabled: true,
origin: 'http://localhost:4200',
hideTitle: false,
txData: {
securityProviderResponse: {
flagAsDangerous: '?',
reason: 'Some reason...',
reason_header: 'Some reason header...',
},
},
};
});
@ -138,40 +130,6 @@ describe('Confirm Page Container Content', () => {
expect(queryByText('Address Book Account 1')).not.toBeInTheDocument();
});
it('should render SecurityProviderBannerMessage component properly', () => {
const { queryByText } = renderWithProvider(
<ConfirmPageContainerContent {...props} />,
store,
);
expect(queryByText('Request not verified')).toBeInTheDocument();
expect(
queryByText(
'Because of an error, this request was not verified by the security provider. Proceed with caution.',
),
).toBeInTheDocument();
expect(queryByText('OpenSea')).toBeInTheDocument();
});
it('should not render SecurityProviderBannerMessage component when flagAsDangerous is not malicious', () => {
props.txData.securityProviderResponse = {
flagAsDangerous: SECURITY_PROVIDER_MESSAGE_SEVERITY.NOT_MALICIOUS,
};
const { queryByText } = renderWithProvider(
<ConfirmPageContainerContent {...props} />,
store,
);
expect(queryByText('Request not verified')).toBeNull();
expect(
queryByText(
'Because of an error, this request was not verified by the security provider. Proceed with caution.',
),
).toBeNull();
expect(queryByText('OpenSea')).toBeNull();
});
it('should show insufficient funds error for EIP-1559 network', () => {
const { getByRole } = renderWithProvider(
<ConfirmPageContainerContent
@ -197,26 +155,4 @@ describe('Confirm Page Container Content', () => {
);
expect(getByRole('button', { name: 'Buy' })).toBeInTheDocument();
});
it('should display security alert if present', () => {
const { getByText } = renderWithProvider(
<ConfirmPageContainerContent
{...props}
txData={{
securityAlertResponse: {
resultType: 'Malicious',
reason: 'blur_farming',
description:
'A SetApprovalForAll request was made on {contract}. We found the operator {operator} to be malicious',
args: {
contract: '0xa7206d878c5c3871826dfdb42191c49b1d11f466',
operator: '0x92a3b9773b1763efa556f55ccbeb20441962d9b2',
},
},
}}
/>,
store,
);
expect(getByText('This is a deceptive request')).toBeInTheDocument();
});
});

View File

@ -3,6 +3,15 @@ import PropTypes from 'prop-types';
import { Icon, IconName } from '../../../../component-library';
import { IconColor } from '../../../../../helpers/constants/design-system';
/**
* @deprecated The `<ConfirmPageContainerWarning />` component has been deprecated in favor of the new `<BannerAlert>` component from the component-library.
* Please update your code to use the new `<BannerAlert>` component instead, which can be found at ui/components/component-library/banner-alert/banner-alert.js.
* You can find documentation for the new `BannerAlert` component in the MetaMask Storybook:
* {@link https://metamask.github.io/metamask-storybook/?path=/docs/components-componentlibrary-banneralert--docs}
* If you would like to help with the replacement of the old `ConfirmPageContainerWarning` component, please submit a pull request against this GitHub issue:
* {@link https://github.com/MetaMask/metamask-extension/issues/20466}
*/
const ConfirmPageContainerWarning = (props) => {
return (
<div className="confirm-page-container-warning">

View File

@ -1,8 +1,10 @@
import React from 'react';
import { BannerAlert } from '../../../../component-library';
import { Severity } from '../../../../../helpers/constants/design-system';
import ConfirmPageContainerWarning from '.';
export default {
title: 'Components/UI/ConfirmPageContainerWarning', // title should follow the folder structure location of the component. Don't use spaces.
title: 'Components/UI/ConfirmPageContainerWarning(Deprecated)', // title should follow the folder structure location of the component. Don't use spaces.
argTypes: {
warning: {
@ -14,6 +16,21 @@ export default {
},
};
export const DefaultStory = (args) => <ConfirmPageContainerWarning {...args} />;
export const DefaultStory = (args) => (
<>
<BannerAlert
severity={Severity.Warning}
title="Deprecated"
description="The <ConfirmPageContainerWarning> component has been deprecated in favor of the new <BannerAlert> component from the component-library.
If you would like to help with the replacement of the old ConfirmPageContainerWarning component, please submit a pull request to metamask-extension"
actionButtonLabel="See details"
actionButtonProps={{
href: 'https://github.com/MetaMask/metamask-extension/issues/20466',
}}
marginBottom={4}
/>
<ConfirmPageContainerWarning {...args} />
</>
);
DefaultStory.storyName = 'Default';

View File

@ -2,8 +2,6 @@ import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { useSelector } from 'react-redux';
import CheckBox from '../../../ui/check-box';
import {
Display,
TextColor,
@ -12,7 +10,7 @@ import {
import { useTokenTracker } from '../../../../hooks/useTokenTracker';
import { useTokenFiatAmount } from '../../../../hooks/useTokenFiatAmount';
import { getUseCurrencyRateCheck } from '../../../../selectors';
import { Box, Text } from '../../../component-library';
import { Box, Checkbox, Text } from '../../../component-library';
const DetectedTokenValues = ({
token,
@ -54,12 +52,15 @@ const DetectedTokenValues = ({
color={TextColor.textAlternative}
>
{useCurrencyRateCheck
? formattedFiatBalance || '$0' // since formattedFiatBalance will be when teh conversion rate is not obtained, should be replace the `$0` with `N/A`
? formattedFiatBalance || '$0' // since formattedFiatBalance will be when the conversion rate is not obtained, should replace the `$0` with `N/A`
: formattedFiatBalance}
</Text>
</Box>
<Box className="detected-token-values__checkbox">
<CheckBox checked={tokenSelection} onClick={handleCheckBoxSelection} />
<Checkbox
isChecked={tokenSelection}
onClick={handleCheckBoxSelection}
/>
</Box>
</Box>
);

View File

@ -61,9 +61,13 @@ const render = ({ txProps, contextProps } = {}) => {
balance: '0x1F4',
},
},
identities: {
'0xAddress': {},
},
selectedAddress: '0xAddress',
featureFlags: { advancedInlineGas: true },
gasFeeEstimates: MOCK_FEE_ESTIMATE,
advancedGasFee: {},
},
});

View File

@ -10,6 +10,7 @@ import { ETH } from '../../../../helpers/constants/common';
import configureStore from '../../../../store/store';
import { GasFeeContextProvider } from '../../../../contexts/gasFee';
import { CHAIN_IDS } from '../../../../../shared/constants/network';
import EditGasItem from './edit-gas-item';
jest.mock('../../../../store/actions', () => ({
@ -59,7 +60,9 @@ const renderComponent = ({
const store = configureStore({
metamask: {
nativeCurrency: ETH,
providerConfig: {},
providerConfig: {
chainId: CHAIN_IDS.GOERLI,
},
cachedBalances: {},
accounts: {
'0xAddress': {
@ -67,13 +70,18 @@ const renderComponent = ({
balance: '0x176e5b6f173ebe66',
},
},
identities: {
'0xAddress': {},
},
selectedAddress: '0xAddress',
featureFlags: { advancedInlineGas: true },
gasEstimateType: 'fee-market',
gasFeeEstimates: MOCK_FEE_ESTIMATE,
advancedGasFee: {
maxBaseFee: '100',
priorityFee: '2',
[CHAIN_IDS.GOERLI]: {
maxBaseFee: '100',
priorityFee: '2',
},
},
},
});

View File

@ -41,6 +41,9 @@ const renderComponent = (componentProps) => {
balance: '0x176e5b6f173ebe66',
},
},
identities: {
'0xAddress': {},
},
selectedAddress: '0xAddress',
featureFlags: { advancedInlineGas: true },
},

View File

@ -28,6 +28,9 @@ const render = () => {
balance: '0x176e5b6f173ebe66',
},
},
identities: {
'0xAddress': {},
},
selectedAddress: '0xAddress',
},
});

View File

@ -7,8 +7,8 @@ import {
import ZENDESK_URLS from '../../../../helpers/constants/zendesk-url';
import { useI18nContext } from '../../../../hooks/useI18nContext';
import {
BUTTON_SIZES,
BUTTON_VARIANT,
ButtonSize,
ButtonVariant,
Box,
Button,
Modal,
@ -88,11 +88,10 @@ export default function HoldToRevealModal({
</Text>,
<Button
key="hold-to-reveal-5"
variant={BUTTON_VARIANT.LINK}
size={BUTTON_SIZES.INHERIT}
variant={ButtonVariant.Link}
size={ButtonSize.Inherit}
href={ZENDESK_URLS.NON_CUSTODIAL_WALLET}
target="_blank"
rel="noopener noreferrer"
externalLink
>
{t('holdToRevealContent5')}
</Button>,

View File

@ -20,6 +20,15 @@ import { Icon, IconName, IconSize } from '../../component-library';
import { getProviderConfig } from '../../../ducks/metamask/metamask';
import { getNetworkLabelKey } from '../../../helpers/utils/i18n-helper';
/**
* @deprecated The `<NetworkDisplay />` component has been deprecated in favor of the new `<PickerNetwork>` component from the component-library.
* Please update your code to use the new `<PickerNetwork>` component instead, which can be found at ui/components/component-library/picker-network/picker-network.tsx.
* You can find documentation for the new `PickerNetwork` component in the MetaMask Storybook:
* {@link https://metamask.github.io/metamask-storybook/?path=/docs/components-componentlibrary-pickernetwork--docs}
* If you would like to help with the replacement of the old `NetworkDisplay` component, please submit a pull request against this GitHub issue:
* {@link https://github.com/MetaMask/metamask-extension/issues/20485}
*/
export default function NetworkDisplay({
disabled,
labelProps,

View File

@ -4,8 +4,9 @@ import {
BUILT_IN_NETWORKS,
NETWORK_TYPES,
} from '../../../../shared/constants/network';
import { Size } from '../../../helpers/constants/design-system';
import { Severity, Size } from '../../../helpers/constants/design-system';
import { BannerAlert } from '../../component-library/banner-alert';
import NetworkDisplay from '.';
export default {
@ -38,13 +39,26 @@ export default {
};
export const DefaultStory = (args) => (
<NetworkDisplay
{...args}
targetNetwork={{
type: args.targetNetwork,
nickname: args.targetNetwork,
}}
/>
<>
<BannerAlert
severity={Severity.Warning}
title="Deprecated"
description="The <NetworkDisplay> component has been deprecated in favor of the new <PickerNetwork> component from the component-library.
Please update your code to use the new <PickerNetwork> component instead, which can be found at ui/components/component-library/picker-network/picker-network.tsx."
actionButtonLabel="See details"
actionButtonProps={{
href: 'https://github.com/MetaMask/metamask-extension/issues/20485',
}}
marginBottom={4}
/>
<NetworkDisplay
{...args}
targetNetwork={{
type: args.targetNetwork,
nickname: args.targetNetwork,
}}
/>
</>
);
DefaultStory.storyName = 'Default';

View File

@ -13,6 +13,7 @@ import {
} from '../../../helpers/constants/design-system';
import {
AvatarIcon,
AvatarIconSize,
Icon,
IconName,
IconSize,
@ -77,7 +78,7 @@ const PermissionCell = ({
{typeof permissionIcon === 'string' ? (
<AvatarIcon
iconName={permissionIcon}
size={IconSize.Md}
size={AvatarIconSize.Md}
iconProps={{
size: IconSize.Sm,
}}

View File

@ -3,7 +3,7 @@
exports[`Security Provider Banner Alert should match snapshot 1`] = `
<div>
<div
class="mm-box mm-banner-base mm-banner-alert mm-banner-alert--severity-danger mm-box--margin-4 mm-box--padding-3 mm-box--padding-left-2 mm-box--display-flex mm-box--gap-2 mm-box--background-color-error-muted mm-box--rounded-sm"
class="mm-box mm-banner-base mm-banner-alert mm-banner-alert--severity-danger mm-box--padding-3 mm-box--padding-left-2 mm-box--display-flex mm-box--gap-2 mm-box--background-color-error-muted mm-box--rounded-sm"
>
<span
class="mm-box mm-icon mm-icon--size-lg mm-box--display-inline-block mm-box--color-error-default"
@ -64,7 +64,7 @@ exports[`Security Provider Banner Alert should match snapshot 1`] = `
class="mm-box disclosure__summary--icon mm-icon mm-icon--size-sm mm-box--margin-inline-end-1 mm-box--display-inline-block mm-box--color-primary-default"
style="mask-image: url('./images/icons/security-tick.svg');"
/>
[securityProviderAdviceBy]
[securityProviderPoweredBy]
</p>
</div>
</div>

View File

@ -2,7 +2,7 @@
exports[`Blockaid Banner Alert should render 'danger' UI when securityAlertResponse.result_type is 'Malicious 1`] = `
<div
class="mm-box mm-banner-base mm-banner-alert mm-banner-alert--severity-danger mm-box--margin-4 mm-box--padding-3 mm-box--padding-left-2 mm-box--display-flex mm-box--gap-2 mm-box--background-color-error-muted mm-box--rounded-sm"
class="mm-box mm-banner-base mm-banner-alert mm-banner-alert--severity-danger mm-box--padding-3 mm-box--padding-left-2 mm-box--display-flex mm-box--gap-2 mm-box--background-color-error-muted mm-box--rounded-sm"
>
<span
class="mm-box mm-icon mm-icon--size-lg mm-box--display-inline-block mm-box--color-error-default"
@ -28,7 +28,7 @@ exports[`Blockaid Banner Alert should render 'danger' UI when securityAlertRespo
/>
<span>
Security advice by
Powered by
<a
class="mm-box mm-text mm-button-base mm-button-link mm-button-link--size-inherit mm-text--body-md-medium mm-box--padding-0 mm-box--padding-right-0 mm-box--padding-left-0 mm-box--display-inline-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-primary-default mm-box--background-color-transparent"
href="https://blockaid.io/"
@ -47,7 +47,7 @@ exports[`Blockaid Banner Alert should render 'danger' UI when securityAlertRespo
exports[`Blockaid Banner Alert should render 'warning' UI when securityAlertResponse.result_type is 'Failed 1`] = `
<div
class="mm-box mm-banner-base mm-banner-alert mm-banner-alert--severity-warning mm-box--margin-4 mm-box--padding-3 mm-box--padding-left-2 mm-box--display-flex mm-box--gap-2 mm-box--background-color-warning-muted mm-box--rounded-sm"
class="mm-box mm-banner-base mm-banner-alert mm-banner-alert--severity-warning mm-box--padding-3 mm-box--padding-left-2 mm-box--display-flex mm-box--gap-2 mm-box--background-color-warning-muted mm-box--rounded-sm"
>
<span
class="mm-box mm-icon mm-icon--size-lg mm-box--display-inline-block mm-box--color-warning-default"
@ -70,7 +70,7 @@ exports[`Blockaid Banner Alert should render 'warning' UI when securityAlertResp
exports[`Blockaid Banner Alert should render 'warning' UI when securityAlertResponse.result_type is 'Warning 1`] = `
<div
class="mm-box mm-banner-base mm-banner-alert mm-banner-alert--severity-warning mm-box--margin-4 mm-box--padding-3 mm-box--padding-left-2 mm-box--display-flex mm-box--gap-2 mm-box--background-color-warning-muted mm-box--rounded-sm"
class="mm-box mm-banner-base mm-banner-alert mm-banner-alert--severity-warning mm-box--padding-3 mm-box--padding-left-2 mm-box--display-flex mm-box--gap-2 mm-box--background-color-warning-muted mm-box--rounded-sm"
>
<span
class="mm-box mm-icon mm-icon--size-lg mm-box--display-inline-block mm-box--color-warning-default"
@ -96,7 +96,7 @@ exports[`Blockaid Banner Alert should render 'warning' UI when securityAlertResp
/>
<span>
Security advice by
Powered by
<a
class="mm-box mm-text mm-button-base mm-button-link mm-button-link--size-inherit mm-text--body-md-medium mm-box--padding-0 mm-box--padding-right-0 mm-box--padding-left-0 mm-box--display-inline-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-primary-default mm-box--background-color-transparent"
href="https://blockaid.io/"
@ -116,7 +116,7 @@ exports[`Blockaid Banner Alert should render 'warning' UI when securityAlertResp
exports[`Blockaid Banner Alert should render details when provided 1`] = `
<div>
<div
class="mm-box mm-banner-base mm-banner-alert mm-banner-alert--severity-warning mm-box--margin-4 mm-box--padding-3 mm-box--padding-left-2 mm-box--display-flex mm-box--gap-2 mm-box--background-color-warning-muted mm-box--rounded-sm"
class="mm-box mm-banner-base mm-banner-alert mm-banner-alert--severity-warning mm-box--padding-3 mm-box--padding-left-2 mm-box--display-flex mm-box--gap-2 mm-box--background-color-warning-muted mm-box--rounded-sm"
>
<span
class="mm-box mm-icon mm-icon--size-lg mm-box--display-inline-block mm-box--color-warning-default"
@ -180,7 +180,7 @@ exports[`Blockaid Banner Alert should render details when provided 1`] = `
/>
<span>
Security advice by
Powered by
<a
class="mm-box mm-text mm-button-base mm-button-link mm-button-link--size-inherit mm-text--body-md-medium mm-box--padding-0 mm-box--padding-right-0 mm-box--padding-left-0 mm-box--display-inline-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-primary-default mm-box--background-color-transparent"
href="https://blockaid.io/"

View File

@ -44,7 +44,7 @@ const REASON_TO_TITLE_TKEY = Object.freeze({
[BlockaidReason.rawSignatureFarming]: 'blockaidTitleSuspicious',
});
function BlockaidBannerAlert({ securityAlertResponse }) {
function BlockaidBannerAlert({ securityAlertResponse, ...props }) {
const t = useContext(I18nContext);
if (!securityAlertResponse) {
@ -63,13 +63,13 @@ function BlockaidBannerAlert({ securityAlertResponse }) {
const description = t(REASON_TO_DESCRIPTION_TKEY[reason] || 'other');
const details = Boolean(features?.length) && (
const details = features?.length ? (
<Text as="ul">
{features.map((feature, i) => (
<li key={`blockaid-detail-${i}`}> {feature}</li>
))}
</Text>
);
) : null;
const isFailedResultType = resultType === BlockaidResultType.Failed;
@ -87,6 +87,7 @@ function BlockaidBannerAlert({ securityAlertResponse }) {
provider={isFailedResultType ? null : SecurityProvider.Blockaid}
severity={severity}
title={title}
{...props}
/>
);
}

View File

@ -33,11 +33,12 @@ function SecurityProviderBannerAlert({
provider,
severity,
title,
...props
}) {
const t = useContext(I18nContext);
return (
<BannerAlert title={title} severity={severity} margin={4}>
<BannerAlert title={title} severity={severity} {...props}>
<Text marginTop={2}>{description}</Text>
{details && (
@ -61,7 +62,7 @@ function SecurityProviderBannerAlert({
size={IconSize.Sm}
marginInlineEnd={1}
/>
{t('securityProviderAdviceBy', [
{t('securityProviderPoweredBy', [
<ButtonLink
key={`security-provider-button-link-${provider}`}
size={Size.inherit}

View File

@ -47,6 +47,7 @@ export default function SecurityProviderBannerMessage({
return (
<BannerAlert
className="security-provider-banner-message"
marginTop={4}
marginRight={4}
marginLeft={4}

View File

@ -61,7 +61,7 @@ exports[`SignatureRequestHeader should match snapshot 1`] = `
<span
class="icon-with-fallback__fallback"
>
U
G
</span>
</div>
</div>
@ -71,7 +71,7 @@ exports[`SignatureRequestHeader should match snapshot 1`] = `
<h6
class="mm-box mm-text mm-text--body-sm mm-box--color-text-alternative"
>
Unknown private network
goerli
</h6>
<h6
class="mm-box mm-text mm-text--body-sm mm-text--font-weight-bold mm-box--color-text-default"

View File

@ -137,7 +137,7 @@ exports[`SignatureRequestOriginal should match snapshot 1`] = `
<span
class="icon-with-fallback__fallback"
>
U
G
</span>
</div>
</div>
@ -147,7 +147,7 @@ exports[`SignatureRequestOriginal should match snapshot 1`] = `
<h6
class="mm-box mm-text mm-text--body-sm mm-box--color-text-alternative"
>
Unknown private network
goerli
</h6>
<h6
class="mm-box mm-text mm-text--body-sm mm-text--font-weight-bold mm-box--color-text-default"

View File

@ -157,6 +157,7 @@ export default class SignatureRequestOriginal extends Component {
///: BEGIN:ONLY_INCLUDE_IN(blockaid)
<BlockaidBannerAlert
securityAlertResponse={txData?.securityAlertResponse}
margin={4}
/>
///: END:ONLY_INCLUDE_IN
}

View File

@ -134,7 +134,7 @@ exports[`SignatureRequestSIWE (Sign in with Ethereum) should match snapshot 1`]
<span
class="icon-with-fallback__fallback"
>
U
G
</span>
</div>
</div>
@ -144,7 +144,7 @@ exports[`SignatureRequestSIWE (Sign in with Ethereum) should match snapshot 1`]
<h6
class="mm-box mm-text mm-text--body-sm mm-box--color-text-alternative"
>
Unknown private network
goerli
</h6>
<h6
class="mm-box mm-text mm-text--body-sm mm-text--font-weight-bold mm-box--color-text-default"

View File

@ -130,16 +130,12 @@ export default function SignatureRequestSIWE({ txData }) {
<ConfirmPageContainerNavigation />
</div>
<SignatureRequestHeader txData={txData} />
<Header
fromAccount={fromAccount}
domain={origin}
isSIWEDomainValid={isSIWEDomainValid}
subjectMetadata={targetSubjectMetadata}
/>
{
///: BEGIN:ONLY_INCLUDE_IN(blockaid)
<BlockaidBannerAlert
securityAlertResponse={txData?.securityAlertResponse}
margin={4}
/>
///: END:ONLY_INCLUDE_IN
}
@ -148,6 +144,13 @@ export default function SignatureRequestSIWE({ txData }) {
securityProviderResponse={txData.securityProviderResponse}
/>
)}
<Header
fromAccount={fromAccount}
domain={origin}
isSIWEDomainValid={isSIWEDomainValid}
subjectMetadata={targetSubjectMetadata}
/>
<Message data={formatMessageParams(parsedMessage, t)} />
{!isMatchingAddress && (
<BannerAlert

View File

@ -89,7 +89,7 @@ exports[`SignatureRequestHeader renders correctly with fromAccount 1`] = `
<span
class="box box--margin-top-1 box--margin-bottom-1 box--flex-direction-row typography chip__label typography--h7 typography--weight-normal typography--style-normal typography--color-text-alternative"
>
Private network
goerli
</span>
</div>
</div>
@ -127,7 +127,7 @@ exports[`SignatureRequestHeader renders correctly without fromAccount 1`] = `
<span
class="box box--margin-top-1 box--margin-bottom-1 box--flex-direction-row typography chip__label typography--h7 typography--weight-normal typography--style-normal typography--color-text-alternative"
>
Private network
goerli
</span>
</div>
</div>

View File

@ -247,6 +247,9 @@ const SignatureRequest = ({ txData }) => {
///: BEGIN:ONLY_INCLUDE_IN(blockaid)
<BlockaidBannerAlert
securityAlertResponse={txData?.securityAlertResponse}
marginLeft={4}
marginRight={4}
marginBottom={4}
/>
///: END:ONLY_INCLUDE_IN
}

View File

@ -16,7 +16,7 @@ import {
import {
AvatarIcon,
IconSize,
AvatarIconSize,
Text,
Box,
BannerAlert,
@ -35,10 +35,7 @@ const InstallError = ({ title, error, description, iconName }) => {
{iconName && (
<AvatarIcon
iconName={iconName}
size={IconSize.Xl}
iconProps={{
size: IconSize.Xl,
}}
size={AvatarIconSize.Xl}
color={IconColor.errorDefault}
backgroundColor={BackgroundColor.errorMuted}
marginBottom={4}

View File

@ -50,7 +50,6 @@ const SnapAvatar = ({
borderColor={BackgroundColor.backgroundDefault}
borderWidth={borderWidth}
iconProps={{
size: badgeSize,
color: IconColor.infoInverse,
}}
/>

View File

@ -10,12 +10,13 @@ import {
IconColor,
TextVariant,
TextColor,
Display,
} from '../../../../helpers/constants/design-system';
import Box from '../../../ui/box';
import {
AvatarIcon,
AvatarIconSize,
Box,
IconName,
IconSize,
Text,
} from '../../../component-library';
import {
@ -42,19 +43,19 @@ export const SnapDelineator = ({
>
<Box
className="snap-delineator__header"
display={Display.Flex}
alignItems={AlignItems.center}
padding={1}
>
<AvatarIcon
iconName={IconName.Snaps}
size={IconSize.Sm}
size={AvatarIconSize.Sm}
backgroundColor={
isError ? IconColor.errorDefault : IconColor.infoDefault
}
borderColor={BackgroundColor.backgroundDefault}
borderWidth={2}
iconProps={{
size: IconSize.Sm,
color: IconColor.infoInverse,
}}
/>

View File

@ -10,14 +10,18 @@ import {
IconColor,
TextVariant,
TextAlign,
Size,
JustifyContent,
FontWeight,
} from '../../../../helpers/constants/design-system';
import Popover from '../../../ui/popover';
import Button from '../../../ui/button';
import { AvatarIcon, IconName, Text } from '../../../component-library';
import Box from '../../../ui/box/box';
import {
AvatarIcon,
AvatarIconSize,
Box,
IconName,
Text,
} from '../../../component-library';
/**
* a very simple reducer using produce from Immer to keep checkboxes state manipulation
@ -87,7 +91,7 @@ export default function SnapInstallWarning({
iconName={IconName.Danger}
backgroundColor={BackgroundColor.warningMuted}
color={IconColor.warningDefault}
size={Size.XL}
size={AvatarIconSize.Xl}
/>
</Box>
<Text

View File

@ -1,24 +1,24 @@
import React from 'react';
import PropTypes from 'prop-types';
import { useI18nContext } from '../../../../hooks/useI18nContext';
import Box from '../../../ui/box/box';
import Popover from '../../../ui/popover';
import {
AvatarIcon,
AvatarIconSize,
Box,
Button,
BUTTON_SIZES,
BUTTON_VARIANT,
ButtonLink,
ButtonLinkSize,
IconName,
IconSize,
Text,
} from '../../../component-library';
import {
AlignItems,
BackgroundColor,
BLOCK_SIZES,
DISPLAY,
BlockSize,
Display,
FontWeight,
IconColor,
JustifyContent,
@ -43,7 +43,7 @@ export default function SnapPrivacyWarning({ onAccepted, onCanceled }) {
<Box
marginTop={4}
className="snap-privacy-warning__header__info-icon"
display={DISPLAY.FLEX}
display={Display.Flex}
justifyContent={JustifyContent.center}
alignItems={AlignItems.center}
>
@ -51,14 +51,14 @@ export default function SnapPrivacyWarning({ onAccepted, onCanceled }) {
iconName={IconName.Info}
color={IconColor.infoDefault}
backgroundColor={BackgroundColor.primaryMuted}
size={IconSize.Md}
size={AvatarIconSize.Md}
/>
</Box>
<Box
className="snap-privacy-warning__header__title"
marginTop={4}
marginBottom={4}
display={DISPLAY.FLEX}
display={Display.Flex}
justifyContent={JustifyContent.center}
alignItems={AlignItems.center}
>
@ -119,12 +119,12 @@ export default function SnapPrivacyWarning({ onAccepted, onCanceled }) {
<Box
className="snap-privacy-warning__footer"
marginTop={6}
display={DISPLAY.FLEX}
display={Display.Flex}
>
<Button
variant={BUTTON_VARIANT.SECONDARY}
size={BUTTON_SIZES.LG}
width={BLOCK_SIZES.FULL}
width={BlockSize.Full}
className="snap-privacy-warning__cancel-button"
onClick={onCanceled}
marginRight={2}
@ -134,7 +134,7 @@ export default function SnapPrivacyWarning({ onAccepted, onCanceled }) {
<Button
variant={BUTTON_VARIANT.PRIMARY}
size={BUTTON_SIZES.LG}
width={BLOCK_SIZES.FULL}
width={BlockSize.Full}
className="snap-privacy-warning__ok-button"
onClick={onAccepted}
marginLeft={2}

View File

@ -60,8 +60,7 @@ export default function QuizContent({
key={idx}
size={btn.size}
onClick={btn.onClick}
label={btn.label}
variant={btn.variant}
variant={btn.variant as any}
width={BlockSize.Full}
data-testid={btn['data-testid']}
>

View File

@ -18,8 +18,8 @@ import { REVEAL_SEED_ROUTE } from '../../../../helpers/constants/routes';
import ZENDESK_URLS from '../../../../helpers/constants/zendesk-url';
import { useI18nContext } from '../../../../hooks/useI18nContext';
import {
BUTTON_SIZES,
BUTTON_VARIANT,
ButtonSize,
ButtonVariant,
Icon,
IconName,
IconSize,
@ -81,14 +81,14 @@ export default function SRPQuiz(props: any) {
{
label: t('srpSecurityQuizGetStarted'),
onClick: () => setStage(QuizStage.questionOne),
variant: BUTTON_VARIANT.PRIMARY,
size: BUTTON_SIZES.LG,
variant: ButtonVariant.Primary,
size: ButtonSize.Lg,
'data-testid': 'srp-quiz-get-started',
},
{
label: t('learnMoreUpperCase'),
onClick: openSupportArticle,
variant: BUTTON_VARIANT.LINK,
variant: ButtonVariant.Link,
'data-testid': 'srp-quiz-learn-more',
},
]}
@ -105,21 +105,21 @@ export default function SRPQuiz(props: any) {
{
label: t('srpSecurityQuizQuestionOneWrongAnswer'),
onClick: () => setStage(QuizStage.wrongAnswerQuestionOne),
variant: BUTTON_VARIANT.SECONDARY,
size: BUTTON_SIZES.LG,
variant: ButtonVariant.Secondary,
size: ButtonSize.Lg,
'data-testid': 'srp-quiz-wrong-answer',
},
{
label: t('srpSecurityQuizQuestionOneRightAnswer'),
onClick: () => setStage(QuizStage.rightAnswerQuestionOne),
variant: BUTTON_VARIANT.SECONDARY,
size: BUTTON_SIZES.LG,
variant: ButtonVariant.Secondary,
size: ButtonSize.Lg,
'data-testid': 'srp-quiz-right-answer',
},
{
label: t('learnMoreUpperCase'),
onClick: openSupportArticle,
variant: BUTTON_VARIANT.LINK,
variant: ButtonVariant.Link,
},
]}
/>
@ -137,14 +137,14 @@ export default function SRPQuiz(props: any) {
{
label: t('continue'),
onClick: () => setStage(QuizStage.questionTwo),
variant: BUTTON_VARIANT.PRIMARY,
size: BUTTON_SIZES.LG,
variant: ButtonVariant.Primary,
size: ButtonSize.Lg,
'data-testid': 'srp-quiz-continue',
},
{
label: t('learnMoreUpperCase'),
onClick: openSupportArticle,
variant: BUTTON_VARIANT.LINK,
variant: ButtonVariant.Link,
},
]}
/>
@ -162,14 +162,14 @@ export default function SRPQuiz(props: any) {
{
label: t('tryAgain'),
onClick: () => setStage(QuizStage.questionOne),
variant: BUTTON_VARIANT.PRIMARY,
size: BUTTON_SIZES.LG,
variant: ButtonVariant.Primary,
size: ButtonSize.Lg,
'data-testid': 'srp-quiz-try-again',
},
{
label: t('learnMoreUpperCase'),
onClick: openSupportArticle,
variant: BUTTON_VARIANT.LINK,
variant: ButtonVariant.Link,
},
]}
/>
@ -185,21 +185,21 @@ export default function SRPQuiz(props: any) {
{
label: t('srpSecurityQuizQuestionTwoRightAnswer'),
onClick: () => setStage(QuizStage.rightAnswerQuestionTwo),
variant: BUTTON_VARIANT.SECONDARY,
size: BUTTON_SIZES.LG,
variant: ButtonVariant.Secondary,
size: ButtonSize.Lg,
'data-testid': 'srp-quiz-right-answer',
},
{
label: t('srpSecurityQuizQuestionTwoWrongAnswer'),
onClick: () => setStage(QuizStage.wrongAnswerQuestionTwo),
variant: BUTTON_VARIANT.SECONDARY,
size: BUTTON_SIZES.LG,
variant: ButtonVariant.Secondary,
size: ButtonSize.Lg,
'data-testid': 'srp-quiz-wrong-answer',
},
{
label: t('learnMoreUpperCase'),
onClick: openSupportArticle,
variant: BUTTON_VARIANT.LINK,
variant: ButtonVariant.Link,
},
]}
/>
@ -217,14 +217,14 @@ export default function SRPQuiz(props: any) {
{
label: t('continue'),
onClick: () => history.push(REVEAL_SEED_ROUTE),
variant: BUTTON_VARIANT.PRIMARY,
size: BUTTON_SIZES.LG,
variant: ButtonVariant.Primary,
size: ButtonSize.Lg,
'data-testid': 'srp-quiz-continue',
},
{
label: t('learnMoreUpperCase'),
onClick: openSupportArticle,
variant: BUTTON_VARIANT.LINK,
variant: ButtonVariant.Link,
},
]}
/>
@ -242,14 +242,14 @@ export default function SRPQuiz(props: any) {
{
label: t('tryAgain'),
onClick: () => setStage(QuizStage.questionTwo),
variant: BUTTON_VARIANT.PRIMARY,
size: BUTTON_SIZES.LG,
variant: ButtonVariant.Primary,
size: ButtonSize.Lg,
'data-testid': 'srp-quiz-try-again',
},
{
label: t('learnMoreUpperCase'),
onClick: openSupportArticle,
variant: BUTTON_VARIANT.LINK,
variant: ButtonVariant.Link,
},
]}
/>

Some files were not shown because too many files have changed in this diff Show More