diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index a0240346af64..77958f69da2d 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -10,6 +10,7 @@ on: - opened - reopened - synchronize + merge_group: jobs: test-unit: diff --git a/.storybook/test-data.js b/.storybook/test-data.js index 72a9bc3b78aa..de94b69f857e 100644 --- a/.storybook/test-data.js +++ b/.storybook/test-data.js @@ -676,7 +676,7 @@ const state = { welcomeScreenSeen: false, currentLocale: 'en', preferences: { - useNativeCurrencyAsPrimaryCurrency: true, + showNativeTokenAsMainBalance: true, }, incomingTransactionsPreferences: { [CHAIN_IDS.MAINNET]: true, diff --git a/CHANGELOG.md b/CHANGELOG.md index 199b83700dde..9dd79055e0c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [12.3.1] +### Fixed +- Fix duplicate network validation ([#27463](https://github.com/MetaMask/metamask-extension/pull/27463)) +- Fix notification metrics ([#27435](https://github.com/MetaMask/metamask-extension/pull/27435)) +- Fix transaction metrics ([#27457](https://github.com/MetaMask/metamask-extension/pull/27457)) + ## [12.3.0] ### Added - Added the ability to name accounts during the snap account creation flow ([#25191](https://github.com/MetaMask/metamask-extension/pull/25191)) @@ -5106,7 +5112,8 @@ Update styles and spacing on the critical error page ([#20350](https://github.c - Added the ability to restore accounts from seed words. -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v12.3.0...HEAD +[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v12.3.1...HEAD +[12.3.1]: https://github.com/MetaMask/metamask-extension/compare/v12.3.0...v12.3.1 [12.3.0]: https://github.com/MetaMask/metamask-extension/compare/v12.2.4...v12.3.0 [12.2.4]: https://github.com/MetaMask/metamask-extension/compare/v12.2.3...v12.2.4 [12.2.3]: https://github.com/MetaMask/metamask-extension/compare/v12.2.2...v12.2.3 diff --git a/app/_locales/am/messages.json b/app/_locales/am/messages.json index 4ce44a388ac1..f118bc17df41 100644 --- a/app/_locales/am/messages.json +++ b/app/_locales/am/messages.json @@ -235,10 +235,6 @@ "fast": { "message": "ፈጣን" }, - "fiat": { - "message": "ፊያት", - "description": "Exchange type" - }, "fileImportFail": { "message": "ፋይል ማስመጣት እየሰራ አይደለም? እዚህ ላይ ጠቅ ያድርጉ!", "description": "Helps user import their account from a JSON file" @@ -493,12 +489,6 @@ "prev": { "message": "የቀደመ" }, - "primaryCurrencySetting": { - "message": "ተቀዳሚ የገንዘብ ዓይነት" - }, - "primaryCurrencySettingDescription": { - "message": "ዋጋዎች በራሳቸው የሰንሰለት ገንዘብ ዓይነት (ለምሳሌ ETH) በቅድሚያ እንዲታዪ ይምረጡ። ዋጋዎች በተመረጠ የፊያት ገንዘብ ዓይነት እንዲታዩ ደግሞ ፊያትን ይምረጡ።" - }, "privacyMsg": { "message": "የግለኝነት መጠበቂያ ህግ" }, @@ -750,9 +740,6 @@ "unlockMessage": { "message": "ያልተማከለ ድር ይጠባበቃል" }, - "updatedWithDate": { - "message": "የዘመነ $1" - }, "urlErrorMsg": { "message": "URIs አግባብነት ያለው የ HTTP/HTTPS ቅድመ ቅጥያ ይፈልጋል።" }, diff --git a/app/_locales/ar/messages.json b/app/_locales/ar/messages.json index 6cb79c56b136..d9717df6b190 100644 --- a/app/_locales/ar/messages.json +++ b/app/_locales/ar/messages.json @@ -505,12 +505,6 @@ "prev": { "message": "السابق" }, - "primaryCurrencySetting": { - "message": "العملة الأساسية" - }, - "primaryCurrencySettingDescription": { - "message": "حدد خيار \"المحلية\" لتحديد أولويات عرض القيم بالعملة المحلية للسلسلة (مثلاً ETH). حدد Fiat لتحديد أولويات عرض القيم بعملات fiat المحددة الخاصة بك." - }, "privacyMsg": { "message": "سياسة الخصوصية" }, @@ -762,9 +756,6 @@ "unlockMessage": { "message": "شبكة الويب اللامركزية بانتظارك" }, - "updatedWithDate": { - "message": "تم تحديث $1" - }, "urlErrorMsg": { "message": "تتطلب الروابط بادئة HTTP/HTTPS مناسبة." }, diff --git a/app/_locales/bg/messages.json b/app/_locales/bg/messages.json index 1fa7a14393d4..749b1561dafe 100644 --- a/app/_locales/bg/messages.json +++ b/app/_locales/bg/messages.json @@ -504,12 +504,6 @@ "prev": { "message": "Предишен" }, - "primaryCurrencySetting": { - "message": "Основна валута" - }, - "primaryCurrencySettingDescription": { - "message": "Изберете местна, за да приоритизирате показването на стойности в основната валута на веригата (например ETH). Изберете Fiat, за да поставите приоритет на показването на стойности в избраната от вас fiat валута." - }, "privacyMsg": { "message": "Политика за поверителност" }, @@ -761,9 +755,6 @@ "unlockMessage": { "message": "Децентрализираната мрежа очаква" }, - "updatedWithDate": { - "message": "Актуализирано $1 " - }, "urlErrorMsg": { "message": "URI изискват съответния HTTP / HTTPS префикс." }, diff --git a/app/_locales/bn/messages.json b/app/_locales/bn/messages.json index a9cc5aa0d845..15acaa2e6765 100644 --- a/app/_locales/bn/messages.json +++ b/app/_locales/bn/messages.json @@ -241,10 +241,6 @@ "fast": { "message": "দ্রুত" }, - "fiat": { - "message": "ফিয়াট", - "description": "Exchange type" - }, "fileImportFail": { "message": "ফাইল আমদানি কাজ করছে না? এখানে ক্লিক করুন!", "description": "Helps user import their account from a JSON file" @@ -502,12 +498,6 @@ "prev": { "message": "পূর্ববর্তী" }, - "primaryCurrencySetting": { - "message": "প্রাথমিক মুদ্রা" - }, - "primaryCurrencySettingDescription": { - "message": "চেনটিতে (যেমন ETH) দেশীয় মুদ্রায় মানগুলি প্রদর্শনকে অগ্রাধিকার দিতে দেশীয় নির্বাচন করুন। আপনার নির্দেশিত মুদ্রায় মানগুলির প্রদর্শনকে অগ্রাধিকার দিতে নির্দেশিত নির্বাচন করুন।" - }, "privacyMsg": { "message": "সম্মত হয়েছেন" }, @@ -759,9 +749,6 @@ "unlockMessage": { "message": "ছড়িয়ে ছিটিয়ে থাকা ওয়েব অপেক্ষা করছে" }, - "updatedWithDate": { - "message": "আপডেট করা $1" - }, "urlErrorMsg": { "message": "URI গুলির যথাযথ HTTP/HTTPS প্রেফিক্সের প্রয়োজন।" }, diff --git a/app/_locales/ca/messages.json b/app/_locales/ca/messages.json index 92f2b2771ff9..fc9e2afb41e6 100644 --- a/app/_locales/ca/messages.json +++ b/app/_locales/ca/messages.json @@ -489,12 +489,6 @@ "personalAddressDetected": { "message": "Adreça personal detectada. Introduir l'adreça del contracte de fitxa." }, - "primaryCurrencySetting": { - "message": "Divisa principal" - }, - "primaryCurrencySettingDescription": { - "message": "Selecciona Natiu per a prioritzar la mostra de valors en la divisa nadiua de la cadena (p. ex. ETH). Selecciona Fiat per prioritzar la mostra de valors en la divisa fiduciària seleccionada." - }, "privacyMsg": { "message": "Política de privadesa" }, @@ -740,9 +734,6 @@ "unlockMessage": { "message": "La web descentralitzada està esperant" }, - "updatedWithDate": { - "message": "Actualitzat $1" - }, "urlErrorMsg": { "message": "Els URIs requereixen el prefix HTTP/HTTPS apropiat." }, diff --git a/app/_locales/cs/messages.json b/app/_locales/cs/messages.json index 6e3bfa315303..4113f8c5cc42 100644 --- a/app/_locales/cs/messages.json +++ b/app/_locales/cs/messages.json @@ -105,10 +105,6 @@ "failed": { "message": "Neúspěšné" }, - "fiat": { - "message": "FIAT", - "description": "Exchange type" - }, "fileImportFail": { "message": "Import souboru nefunguje? Klikněte sem!", "description": "Helps user import their account from a JSON file" diff --git a/app/_locales/da/messages.json b/app/_locales/da/messages.json index 12eba292e0a4..37e4663523cf 100644 --- a/app/_locales/da/messages.json +++ b/app/_locales/da/messages.json @@ -489,12 +489,6 @@ "prev": { "message": "Forrige" }, - "primaryCurrencySetting": { - "message": "Primær Valuta" - }, - "primaryCurrencySettingDescription": { - "message": "Vælg lokal for fortrinsvis at vise værdier i kædens (f.eks. ETH) lokale valuta. Vælg Fiat for fortrinsvis at vise værdier i din valgte fiat valuta." - }, "privacyMsg": { "message": "Privatlivspolitik" }, @@ -734,9 +728,6 @@ "unlockMessage": { "message": "Det decentraliserede internet venter" }, - "updatedWithDate": { - "message": "Opdaterede $1" - }, "urlErrorMsg": { "message": "Links kræver det rette HTTP/HTTPS-præfix." }, diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index 5d5f0e30923f..3ff80228ef4f 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -1873,10 +1873,6 @@ "feeDetails": { "message": "Details zur Gebühr" }, - "fiat": { - "message": "FIAT", - "description": "Exchange type" - }, "fileImportFail": { "message": "Dateiimport fehlgeschlagen? Bitte hier klicken!", "description": "Helps user import their account from a JSON file" @@ -3092,9 +3088,6 @@ "noConnectedAccountTitle": { "message": "MetaMask ist nicht mit dieser Website verbunden" }, - "noConversionDateAvailable": { - "message": "Kein Umrechnungskursdaten verfügbar" - }, "noConversionRateAvailable": { "message": "Kein Umrechnungskurs verfügbar" }, @@ -3915,12 +3908,6 @@ "priceUnavailable": { "message": "Preis nicht verfügbar" }, - "primaryCurrencySetting": { - "message": "Hauptwährung" - }, - "primaryCurrencySettingDescription": { - "message": "Wählen Sie 'Nativ', um dem Anzeigen von Werten in der nativen Währung der Chain (z. B. ETH) Vorrang zu geben. Wählen Sie 'Fiat', um dem Anzeigen von Werten in Ihrer gewählten Fiat-Währung Vorrang zu geben." - }, "primaryType": { "message": "Primärer Typ" }, @@ -6085,9 +6072,6 @@ "updateRequest": { "message": "Aktualisierungsanfrage" }, - "updatedWithDate": { - "message": "$1 aktualisiert" - }, "uploadDropFile": { "message": "Legen Sie Ihre Datei hier ab" }, diff --git a/app/_locales/el/messages.json b/app/_locales/el/messages.json index 340670a11bc9..c348e7bb6cbf 100644 --- a/app/_locales/el/messages.json +++ b/app/_locales/el/messages.json @@ -1873,10 +1873,6 @@ "feeDetails": { "message": "Λεπτομέρειες χρεώσεων" }, - "fiat": { - "message": "Εντολή", - "description": "Exchange type" - }, "fileImportFail": { "message": "Η εισαγωγή αρχείων δεν λειτουργεί; Κάντε κλικ εδώ!", "description": "Helps user import their account from a JSON file" @@ -3092,9 +3088,6 @@ "noConnectedAccountTitle": { "message": "Το MetaMask δεν συνδέεται με αυτόν τον ιστότοπο" }, - "noConversionDateAvailable": { - "message": "Δεν υπάρχει διαθέσιμη ημερομηνία μετατροπής νομίσματος" - }, "noConversionRateAvailable": { "message": "Δεν υπάρχει διαθέσιμη ισοτιμία μετατροπής" }, @@ -3915,12 +3908,6 @@ "priceUnavailable": { "message": "μη διαθέσιμη τιμή" }, - "primaryCurrencySetting": { - "message": "Κύριο νόμισμα" - }, - "primaryCurrencySettingDescription": { - "message": "Επιλέξτε εγχώριο για να δώσετε προτεραιότητα στην εμφάνιση των τιμών στο νόμισμα της αλυσίδας (π.χ. ETH). Επιλέξτε Παραστατικό για να δώσετε προτεραιότητα στην εμφάνιση τιμών στο επιλεγμένο παραστατικό νόμισμα." - }, "primaryType": { "message": "Βασικός τύπος" }, @@ -6085,9 +6072,6 @@ "updateRequest": { "message": "Αίτημα ενημέρωσης" }, - "updatedWithDate": { - "message": "Ενημερώθηκε $1" - }, "uploadDropFile": { "message": "Αφήστε το αρχείο σας εδώ" }, diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index b880d92ad468..1ddcd1c05a6b 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -402,6 +402,10 @@ "advancedPriorityFeeToolTip": { "message": "Priority fee (aka “miner tip”) goes directly to miners and incentivizes them to prioritize your transaction." }, + "aggregatedBalancePopover": { + "message": "This reflects the value of all tokens you own on a given network. If you prefer seeing this value in ETH or other currencies, go to $1.", + "description": "$1 represents the settings page" + }, "agreeTermsOfUse": { "message": "I agree to MetaMask's $1", "description": "$1 is the `terms` link" @@ -1347,7 +1351,7 @@ "message": "CryptoCompare" }, "currencyConversion": { - "message": "Currency conversion" + "message": "Currency" }, "currencyRateCheckToggle": { "message": "Show balance and token price checker" @@ -2032,10 +2036,6 @@ "feeDetails": { "message": "Fee details" }, - "fiat": { - "message": "Fiat", - "description": "Exchange type" - }, "fileImportFail": { "message": "File import not working? Click here!", "description": "Helps user import their account from a JSON file" @@ -2121,6 +2121,9 @@ "message": "This gas fee has been suggested by $1. Overriding this may cause a problem with your transaction. Please reach out to $1 if you have questions.", "description": "$1 represents the Dapp's origin" }, + "gasFee": { + "message": "Gas fee" + }, "gasIsETH": { "message": "Gas is $1 " }, @@ -2435,6 +2438,9 @@ "inYourSettings": { "message": "in your Settings" }, + "included": { + "message": "included" + }, "infuraBlockedNotification": { "message": "MetaMask is unable to connect to the blockchain host. Review possible reasons $1.", "description": "$1 is a clickable link with with text defined by the 'here' key" @@ -3296,9 +3302,6 @@ "noConnectedAccountTitle": { "message": "MetaMask isn’t connected to this site" }, - "noConversionDateAvailable": { - "message": "No currency conversion date available" - }, "noConversionRateAvailable": { "message": "No conversion rate available" }, @@ -4139,12 +4142,6 @@ "priceUnavailable": { "message": "price unavailable" }, - "primaryCurrencySetting": { - "message": "Primary currency" - }, - "primaryCurrencySettingDescription": { - "message": "Select native to prioritize displaying values in the native currency of the chain (e.g. ETH). Select Fiat to prioritize displaying values in your selected fiat currency." - }, "primaryType": { "message": "Primary type" }, @@ -4879,6 +4876,9 @@ "showMore": { "message": "Show more" }, + "showNativeTokenAsMainBalance": { + "message": "Show native token as main balance" + }, "showNft": { "message": "Show NFT" }, @@ -5668,12 +5668,22 @@ "message": "Gas fees are paid to crypto miners who process transactions on the $1 network. MetaMask does not profit from gas fees.", "description": "$1 is the selected network, e.g. Ethereum or BSC" }, + "swapGasIncludedTooltipExplanation": { + "message": "This quote incorporates gas fees by adjusting the token amount sent or received. You may receive ETH in a separate transaction on your activity list." + }, + "swapGasIncludedTooltipExplanationLinkText": { + "message": "Learn more about gas fees" + }, "swapHighSlippage": { "message": "High slippage" }, "swapHighSlippageWarning": { "message": "Slippage amount is very high." }, + "swapIncludesGasAndMetaMaskFee": { + "message": "Includes gas and a $1% MetaMask fee", + "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number." + }, "swapIncludesMMFee": { "message": "Includes a $1% MetaMask fee.", "description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number." @@ -6404,9 +6414,6 @@ "updatedRpcForNetworks": { "message": "Network RPCs Updated" }, - "updatedWithDate": { - "message": "Updated $1" - }, "uploadDropFile": { "message": "Drop your file here" }, @@ -6663,6 +6670,9 @@ "yourBalance": { "message": "Your balance" }, + "yourBalanceIsAggregated": { + "message": "Your balance is aggregated" + }, "yourNFTmayBeAtRisk": { "message": "Your NFT may be at risk" }, diff --git a/app/_locales/en_GB/messages.json b/app/_locales/en_GB/messages.json index 80a17b1c5e22..71599915880e 100644 --- a/app/_locales/en_GB/messages.json +++ b/app/_locales/en_GB/messages.json @@ -1934,10 +1934,6 @@ "feeDetails": { "message": "Fee details" }, - "fiat": { - "message": "Fiat", - "description": "Exchange type" - }, "fileImportFail": { "message": "File import not working? Click here!", "description": "Helps user import their account from a JSON file" @@ -3166,9 +3162,6 @@ "noConnectedAccountTitle": { "message": "MetaMask isn’t connected to this site" }, - "noConversionDateAvailable": { - "message": "No currency conversion date available" - }, "noConversionRateAvailable": { "message": "No conversion rate available" }, @@ -4007,12 +4000,6 @@ "priceUnavailable": { "message": "price unavailable" }, - "primaryCurrencySetting": { - "message": "Primary currency" - }, - "primaryCurrencySettingDescription": { - "message": "Select native to prioritize displaying values in the native currency of the chain (e.g. ETH). Select Fiat to prioritize displaying values in your selected fiat currency." - }, "primaryType": { "message": "Primary type" }, @@ -6225,9 +6212,6 @@ "updateRequest": { "message": "Update request" }, - "updatedWithDate": { - "message": "Updated $1" - }, "uploadDropFile": { "message": "Drop your file here" }, diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index 599168440ee5..05015a3de622 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -1870,10 +1870,6 @@ "feeDetails": { "message": "Detalles de la tarifa" }, - "fiat": { - "message": "Fiduciaria", - "description": "Exchange type" - }, "fileImportFail": { "message": "¿No funciona la importación del archivo? Haga clic aquí.", "description": "Helps user import their account from a JSON file" @@ -3089,9 +3085,6 @@ "noConnectedAccountTitle": { "message": "MetaMask no está conectado a este sitio" }, - "noConversionDateAvailable": { - "message": "No hay fecha de conversión de moneda disponible" - }, "noConversionRateAvailable": { "message": "No hay tasa de conversión disponible" }, @@ -3912,12 +3905,6 @@ "priceUnavailable": { "message": "precio no disponible" }, - "primaryCurrencySetting": { - "message": "Moneda principal" - }, - "primaryCurrencySettingDescription": { - "message": "Seleccione Nativa para dar prioridad a mostrar los valores en la moneda nativa de la cadena (p. ej., ETH). Seleccione Fiduciaria para dar prioridad a mostrar los valores en la moneda fiduciaria seleccionada." - }, "primaryType": { "message": "Tipo principal" }, @@ -6082,9 +6069,6 @@ "updateRequest": { "message": "Solicitud de actualización" }, - "updatedWithDate": { - "message": "$1 actualizado" - }, "uploadDropFile": { "message": "Ingrese su archivo aquí" }, diff --git a/app/_locales/es_419/messages.json b/app/_locales/es_419/messages.json index 1b8bc945343b..0bba1bd69551 100644 --- a/app/_locales/es_419/messages.json +++ b/app/_locales/es_419/messages.json @@ -782,10 +782,6 @@ "feeAssociatedRequest": { "message": "Esta solicitud tiene asociada una tarifa." }, - "fiat": { - "message": "Fiduciaria", - "description": "Exchange type" - }, "fileImportFail": { "message": "¿No funciona la importación del archivo? ¡Haga clic aquí!", "description": "Helps user import their account from a JSON file" @@ -1321,9 +1317,6 @@ "noAccountsFound": { "message": "No se encuentran cuentas para la consulta de búsqueda determinada" }, - "noConversionDateAvailable": { - "message": "No hay fecha de conversión de moneda disponible" - }, "noConversionRateAvailable": { "message": "No hay tasa de conversión disponible" }, @@ -1489,12 +1482,6 @@ "prev": { "message": "Ant." }, - "primaryCurrencySetting": { - "message": "Moneda principal" - }, - "primaryCurrencySettingDescription": { - "message": "Seleccione Nativa para dar prioridad a mostrar los valores en la moneda nativa de la cadena (p. ej., ETH). Seleccione Fiduciaria para dar prioridad a mostrar los valores en la moneda fiduciaria seleccionada." - }, "priorityFee": { "message": "Tarifa de prioridad" }, @@ -2405,9 +2392,6 @@ "message": "El envío de tokens coleccionables (ERC-721) no se admite actualmente", "description": "This is an error message we show the user if they attempt to send an NFT asset type, for which currently don't support sending" }, - "updatedWithDate": { - "message": "$1 actualizado" - }, "urlErrorMsg": { "message": "Las direcciones URL requieren el prefijo HTTP/HTTPS adecuado." }, diff --git a/app/_locales/et/messages.json b/app/_locales/et/messages.json index acebcc9091da..38125572b8ec 100644 --- a/app/_locales/et/messages.json +++ b/app/_locales/et/messages.json @@ -498,12 +498,6 @@ "prev": { "message": "Eelm" }, - "primaryCurrencySetting": { - "message": "Põhivaluuta" - }, - "primaryCurrencySettingDescription": { - "message": "Valige omavääring, et prioriseerida vääringu kuvamist ahela omavääringus (nt ETH). Valige Fiat, et prioriseerida vääringu kuvamist valitud fiat-vääringus." - }, "privacyMsg": { "message": "privaatsuspoliitika" }, @@ -755,9 +749,6 @@ "unlockMessage": { "message": "Detsentraliseeritud veeb ootab" }, - "updatedWithDate": { - "message": "Värskendatud $1" - }, "urlErrorMsg": { "message": "URI-d nõuavad sobivat HTTP/HTTPS-i prefiksit." }, diff --git a/app/_locales/fa/messages.json b/app/_locales/fa/messages.json index c9c1bafdc7bf..c1a4deb11ce4 100644 --- a/app/_locales/fa/messages.json +++ b/app/_locales/fa/messages.json @@ -244,10 +244,6 @@ "fast": { "message": "سریع" }, - "fiat": { - "message": "حکم قانونی", - "description": "Exchange type" - }, "fileImportFail": { "message": "وارد کردن فایل کار نمیکند؟ اینجا کلیک نمایید!", "description": "Helps user import their account from a JSON file" @@ -508,12 +504,6 @@ "prev": { "message": "قبلی" }, - "primaryCurrencySetting": { - "message": "واحد پول اصلی" - }, - "primaryCurrencySettingDescription": { - "message": "برای اولویت دهی نمایش قیمت ها در واحد پولی اصلی زنجیره (مثلًا ETH)، اصلی را انتخاب کنید. برای اولویت دهی نمایش قیمت ها در فیات واحد پولی شما، فیات را انتخاب کنید." - }, "privacyMsg": { "message": "خط‌مشی رازداری" }, @@ -765,9 +755,6 @@ "unlockMessage": { "message": "وب غیر متمرکز شده انتظار میکشد" }, - "updatedWithDate": { - "message": "بروزرسانی شد 1$1" - }, "urlErrorMsg": { "message": "URl ها نیازمند پیشوند مناسب HTTP/HTTPS اند." }, diff --git a/app/_locales/fi/messages.json b/app/_locales/fi/messages.json index 1c9cdb7c7a43..89e274dd4466 100644 --- a/app/_locales/fi/messages.json +++ b/app/_locales/fi/messages.json @@ -244,10 +244,6 @@ "fast": { "message": "Nopea" }, - "fiat": { - "message": "Kiinteä", - "description": "Exchange type" - }, "fileImportFail": { "message": "Eikö tiedoston tuominen onnistu? Klikkaa tästä!", "description": "Helps user import their account from a JSON file" @@ -505,12 +501,6 @@ "prev": { "message": "Aiemp." }, - "primaryCurrencySetting": { - "message": "Ensisijainen valuutta" - }, - "primaryCurrencySettingDescription": { - "message": "Valitse natiivivaihtoehto näyttääksesi arvot ensisijaisesti ketjun natiivivaluutalla (esim. ETH). Valitse oletusmääräys asettaaksesi valitsemasi oletusvaluutan ensisijaiseksi." - }, "privacyMsg": { "message": "Tietosuojakäytäntö" }, @@ -762,9 +752,6 @@ "unlockMessage": { "message": "Hajautettu verkko odottaa" }, - "updatedWithDate": { - "message": "$1 päivitetty" - }, "urlErrorMsg": { "message": "URI:t vaativat asianmukaisen HTTP/HTTPS-etuliitteen." }, diff --git a/app/_locales/fil/messages.json b/app/_locales/fil/messages.json index e08c88bd7ffa..498c1878fd10 100644 --- a/app/_locales/fil/messages.json +++ b/app/_locales/fil/messages.json @@ -436,12 +436,6 @@ "prev": { "message": "Nakaraan" }, - "primaryCurrencySetting": { - "message": "Pangunahing Currency" - }, - "primaryCurrencySettingDescription": { - "message": "Piliin ang native para bigyang priyoridad ang pagpapakita ng mga halaga sa native currency ng chain (hal. ETH). Piliin ang Fiat para bigyang priyoridad ang pagpapakita ng mga halaga sa napili mong fiat currency." - }, "privacyMsg": { "message": "Patakaran sa Privacy" }, @@ -677,9 +671,6 @@ "unlockMessage": { "message": "Naghihintay ang decentralized web" }, - "updatedWithDate": { - "message": "Na-update ang $1" - }, "urlErrorMsg": { "message": "Kinakailangan ng mga URI ang naaangkop na HTTP/HTTPS prefix." }, diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index 84124b8f1fff..8301ad348b07 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -1873,10 +1873,6 @@ "feeDetails": { "message": "Détails des frais" }, - "fiat": { - "message": "FIAT", - "description": "Exchange type" - }, "fileImportFail": { "message": "L’importation de fichier ne fonctionne pas ? Cliquez ici !", "description": "Helps user import their account from a JSON file" @@ -3092,9 +3088,6 @@ "noConnectedAccountTitle": { "message": "MetaMask n’est pas connecté à ce site" }, - "noConversionDateAvailable": { - "message": "Aucune date de conversion des devises n’est disponible" - }, "noConversionRateAvailable": { "message": "Aucun taux de conversion disponible" }, @@ -3915,12 +3908,6 @@ "priceUnavailable": { "message": "prix non disponible" }, - "primaryCurrencySetting": { - "message": "Devise principale" - }, - "primaryCurrencySettingDescription": { - "message": "Sélectionnez « natif » pour donner la priorité à l’affichage des valeurs dans la devise native de la chaîne (par ex. ETH). Sélectionnez « fiduciaire » pour donner la priorité à l’affichage des valeurs dans la devise de votre choix." - }, "primaryType": { "message": "Type principal" }, @@ -6085,9 +6072,6 @@ "updateRequest": { "message": "Demande de mise à jour" }, - "updatedWithDate": { - "message": "Mis à jour $1" - }, "uploadDropFile": { "message": "Déposez votre fichier ici" }, diff --git a/app/_locales/he/messages.json b/app/_locales/he/messages.json index 9d118e31c098..413bf21d586b 100644 --- a/app/_locales/he/messages.json +++ b/app/_locales/he/messages.json @@ -244,10 +244,6 @@ "fast": { "message": "מהיר" }, - "fiat": { - "message": "פיאט", - "description": "Exchange type" - }, "fileImportFail": { "message": "ייבוא הקובץ לא עובד? לחצ/י כאן!", "description": "Helps user import their account from a JSON file" @@ -505,12 +501,6 @@ "prev": { "message": "הקודם" }, - "primaryCurrencySetting": { - "message": "מטבע ראשי" - }, - "primaryCurrencySettingDescription": { - "message": "בחר/י 'מקומי' כדי לתעדף הצגת ערכים במטבע המקומי של הצ'יין (למשל ETH). בחר/י פיאט כדי לתעדף הצגת ערכים במטבע הפיאט שבחרת." - }, "privacyMsg": { "message": "מדיניות הפרטיות" }, @@ -762,9 +752,6 @@ "unlockMessage": { "message": "הרשת המבוזרת מחכה" }, - "updatedWithDate": { - "message": "עודכן $1" - }, "urlErrorMsg": { "message": "כתובות URI דורשות את קידומת HTTP/HTTPS המתאימה." }, diff --git a/app/_locales/hi/messages.json b/app/_locales/hi/messages.json index fd957c6925df..0a5423979efa 100644 --- a/app/_locales/hi/messages.json +++ b/app/_locales/hi/messages.json @@ -1873,10 +1873,6 @@ "feeDetails": { "message": "फ़ीस का ब्यौरा" }, - "fiat": { - "message": "फिएट", - "description": "Exchange type" - }, "fileImportFail": { "message": "फाइल इम्पोर्ट काम नहीं कर रहा है? यहां क्लिक करें!", "description": "Helps user import their account from a JSON file" @@ -3092,9 +3088,6 @@ "noConnectedAccountTitle": { "message": "MetaMask इस साइट से कनेक्टेड नहीं है।" }, - "noConversionDateAvailable": { - "message": "कोई करेंसी कन्वर्शन तारीख उपलब्ध नहीं है" - }, "noConversionRateAvailable": { "message": "कोई भी कन्वर्शन दर उपलब्ध नहीं है" }, @@ -3915,12 +3908,6 @@ "priceUnavailable": { "message": "प्राइस अनुपलब्ध है" }, - "primaryCurrencySetting": { - "message": "प्राथमिक मुद्रा" - }, - "primaryCurrencySettingDescription": { - "message": "चेन की ओरिजिनल करेंसी (जैसे ETH) में प्रदर्शित वैल्यूज़ को प्राथमिकता देने के लिए ओरिजिनल को चुनें। अपनी चुना गया फिएट करेंसी में प्रदर्शित वैल्यूज़ को प्राथमिकता देने के लिए फिएट को चुनें।" - }, "primaryType": { "message": "प्राइमरी टाइप" }, @@ -6085,9 +6072,6 @@ "updateRequest": { "message": "अपडेट का अनुरोध" }, - "updatedWithDate": { - "message": "अपडेट किया गया $1" - }, "uploadDropFile": { "message": "अपनी फ़ाइल यहां छोड़ें" }, diff --git a/app/_locales/hn/messages.json b/app/_locales/hn/messages.json index 8e9091f911db..a4e2e37bde22 100644 --- a/app/_locales/hn/messages.json +++ b/app/_locales/hn/messages.json @@ -87,10 +87,6 @@ "failed": { "message": "विफल" }, - "fiat": { - "message": "FIAT एक्सचेंज टाइप", - "description": "Exchange type" - }, "fileImportFail": { "message": "फ़ाइल आयात काम नहीं कर रहा है? यहां क्लिक करें!", "description": "Helps user import their account from a JSON file" diff --git a/app/_locales/hr/messages.json b/app/_locales/hr/messages.json index 4463408d9435..7f9334f49f5c 100644 --- a/app/_locales/hr/messages.json +++ b/app/_locales/hr/messages.json @@ -501,12 +501,6 @@ "prev": { "message": "Prethodno" }, - "primaryCurrencySetting": { - "message": "Glavna valuta" - }, - "primaryCurrencySettingDescription": { - "message": "Odaberite da se prvo prikazuju valute u osnovnoj valuti bloka (npr. ETH). Odaberite mogućnost Fiat za prikazivanje valuta u odabranoj valuti Fiat." - }, "privacyMsg": { "message": "Pravilnik o zaštiti privatnosti" }, @@ -755,9 +749,6 @@ "unlockMessage": { "message": "Decentralizirani internet čeka" }, - "updatedWithDate": { - "message": "Ažurirano $1" - }, "urlErrorMsg": { "message": "URI-jevima se zahtijeva prikladan prefiks HTTP/HTTPS." }, diff --git a/app/_locales/ht/messages.json b/app/_locales/ht/messages.json index 700f6debed18..7309b04dbd05 100644 --- a/app/_locales/ht/messages.json +++ b/app/_locales/ht/messages.json @@ -153,10 +153,6 @@ "failed": { "message": "Tonbe" }, - "fiat": { - "message": "FIAT", - "description": "Exchange type" - }, "fileImportFail": { "message": "Enpòte dosye ki pa travay? Klike la a!", "description": "Helps user import their account from a JSON file" @@ -357,12 +353,6 @@ "prev": { "message": "Avan" }, - "primaryCurrencySetting": { - "message": "Lajan ou itilize pi plis la" - }, - "primaryCurrencySettingDescription": { - "message": "Chwazi ETH pou bay priyorite montre valè nan ETH. Chwazi Fiat priyorite montre valè nan lajan ou chwazi a." - }, "privacyMsg": { "message": "Règleman sou enfòmasyon prive" }, @@ -548,9 +538,6 @@ "unlockMessage": { "message": "Entènèt desantralize a ap tann" }, - "updatedWithDate": { - "message": "Mete ajou $1" - }, "urlErrorMsg": { "message": "URIs mande pou apwopriye prefiks HTTP / HTTPS a." }, diff --git a/app/_locales/hu/messages.json b/app/_locales/hu/messages.json index 4786cfb9703d..7b2b429ae5ed 100644 --- a/app/_locales/hu/messages.json +++ b/app/_locales/hu/messages.json @@ -501,12 +501,6 @@ "prev": { "message": "Előző" }, - "primaryCurrencySetting": { - "message": "Elsődleges pénznem" - }, - "primaryCurrencySettingDescription": { - "message": "Válaszd a helyit, hogy az értékek elsősorban a helyi pénznemben jelenjenek meg (pl. ETH). Válaszd a Fiatot, hogy az értékek elsősorban a választott fiat pénznemben jelenjenek meg." - }, "privacyMsg": { "message": "Adatvédelmi szabályzat" }, @@ -755,9 +749,6 @@ "unlockMessage": { "message": "A decentralizált hálózat csak önre vár" }, - "updatedWithDate": { - "message": "$1 frissítve" - }, "urlErrorMsg": { "message": "Az URI-hez szükség van a megfelelő HTTP/HTTPS előtagra." }, diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json index a9a34d9b9a4e..054150ae5b7a 100644 --- a/app/_locales/id/messages.json +++ b/app/_locales/id/messages.json @@ -1873,10 +1873,6 @@ "feeDetails": { "message": "Detail biaya" }, - "fiat": { - "message": "Fiat", - "description": "Exchange type" - }, "fileImportFail": { "message": "Impor file tidak bekerja? Klik di sini!", "description": "Helps user import their account from a JSON file" @@ -3092,9 +3088,6 @@ "noConnectedAccountTitle": { "message": "MetaMask tidak terhubung ke situs ini" }, - "noConversionDateAvailable": { - "message": "Tanggal konversi mata uang tidak tersedia" - }, "noConversionRateAvailable": { "message": "Nilai konversi tidak tersedia" }, @@ -3915,12 +3908,6 @@ "priceUnavailable": { "message": "harga tidak tersedia" }, - "primaryCurrencySetting": { - "message": "Mata uang primer" - }, - "primaryCurrencySettingDescription": { - "message": "Pilih asal untuk memprioritaskan nilai yang ditampilkan dalam mata uang asal chain (contoh, ETH). Pilih Fiat untuk memprioritaskan nilai yang ditampilkan dalam mata uang fiat yang Anda pilih." - }, "primaryType": { "message": "Tipe primer" }, @@ -6085,9 +6072,6 @@ "updateRequest": { "message": "Permintaan pembaruan" }, - "updatedWithDate": { - "message": "Diperbarui $1" - }, "uploadDropFile": { "message": "Letakkan fail di sini" }, diff --git a/app/_locales/it/messages.json b/app/_locales/it/messages.json index 7c413941da92..71b07590d6d1 100644 --- a/app/_locales/it/messages.json +++ b/app/_locales/it/messages.json @@ -808,10 +808,6 @@ "feeAssociatedRequest": { "message": "Una tassa è associata a questa richiesta." }, - "fiat": { - "message": "FIAT", - "description": "Exchange type" - }, "fileImportFail": { "message": "Importazione file non funziona? Clicca qui!", "description": "Helps user import their account from a JSON file" @@ -1165,12 +1161,6 @@ "prev": { "message": "Precedente" }, - "primaryCurrencySetting": { - "message": "Moneta Primaria" - }, - "primaryCurrencySettingDescription": { - "message": "Seleziona ETH per privilegiare la visualizzazione dei valori nella moneta nativa della blockhain. Seleziona Fiat per privilegiare la visualizzazione dei valori nella moneta selezionata." - }, "privacyMsg": { "message": "Politica sulla Privacy" }, @@ -1698,9 +1688,6 @@ "unlockMessage": { "message": "Il web decentralizzato ti attende" }, - "updatedWithDate": { - "message": "Aggiornata $1" - }, "urlErrorMsg": { "message": "Gli URI richiedono un prefisso HTTP/HTTPS." }, diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index f491ac9aa280..74f281b7f873 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -1873,10 +1873,6 @@ "feeDetails": { "message": "手数料の詳細" }, - "fiat": { - "message": "法定通貨", - "description": "Exchange type" - }, "fileImportFail": { "message": "ファイルのインポートが機能していない場合、ここをクリックしてください!", "description": "Helps user import their account from a JSON file" @@ -3092,9 +3088,6 @@ "noConnectedAccountTitle": { "message": "MetaMaskはこのサイトに接続されていません" }, - "noConversionDateAvailable": { - "message": "通貨換算日がありません" - }, "noConversionRateAvailable": { "message": "利用可能な換算レートがありません" }, @@ -3915,12 +3908,6 @@ "priceUnavailable": { "message": "価格が利用できません" }, - "primaryCurrencySetting": { - "message": "プライマリ通貨" - }, - "primaryCurrencySettingDescription": { - "message": "チェーンのネイティブ通貨 (ETHなど) による値の表示を優先するには、「ネイティブ」を選択します。選択した法定通貨による値の表示を優先するには、「法定通貨」を選択します。" - }, "primaryType": { "message": "基本型" }, @@ -6085,9 +6072,6 @@ "updateRequest": { "message": "更新リクエスト" }, - "updatedWithDate": { - "message": "$1が更新されました" - }, "uploadDropFile": { "message": "ここにファイルをドロップします" }, diff --git a/app/_locales/kn/messages.json b/app/_locales/kn/messages.json index 6471b738b5b9..120651f0b759 100644 --- a/app/_locales/kn/messages.json +++ b/app/_locales/kn/messages.json @@ -244,10 +244,6 @@ "fast": { "message": "ವೇಗ" }, - "fiat": { - "message": "ಫಿಯೆಟ್", - "description": "Exchange type" - }, "fileImportFail": { "message": "ಫೈಲ್ ಆಮದು ಮಾಡುವಿಕೆ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತಿಲ್ಲವೇ? ಇಲ್ಲಿ ಕ್ಲಿಕ್ ಮಾಡಿ!", "description": "Helps user import their account from a JSON file" @@ -508,12 +504,6 @@ "prev": { "message": "ಹಿಂದಿನ" }, - "primaryCurrencySetting": { - "message": "ಪ್ರಾಥಮಿಕ ಕರೆನ್ಸಿ" - }, - "primaryCurrencySettingDescription": { - "message": "ಸರಪಳಿಯ ಸ್ಥಳೀಯ ಕರೆನ್ಸಿಯಲ್ಲಿ ಮೌಲ್ಯಗಳನ್ನು ಪ್ರದರ್ಶಿಸಲು ಆದ್ಯತೆ ನೀಡಲು ಸ್ಥಳೀಯವನ್ನು ಆಯ್ಕೆಮಾಡಿ (ಉದಾ. ETH). ನಿಮ್ಮ ಆಯ್ಕೆಮಾಡಿದ ಫಿಯೆಟ್ ಕರೆನ್ಸಿಯಲ್ಲಿ ಮೌಲ್ಯಗಳನ್ನು ಪ್ರದರ್ಶಿಸಲು ಆದ್ಯತೆ ನೀಡಲು ಫಿಯೆಟ್ ಆಯ್ಕೆಮಾಡಿ." - }, "privacyMsg": { "message": "ಗೌಪ್ಯತೆ ನೀತಿ" }, @@ -765,9 +755,6 @@ "unlockMessage": { "message": "ವಿಕೇಂದ್ರೀಕೃತ ವೆಬ್ ನಿರೀಕ್ಷಿಸುತ್ತಿದೆ" }, - "updatedWithDate": { - "message": "$1 ನವೀಕರಿಸಲಾಗಿದೆ" - }, "urlErrorMsg": { "message": "URI ಗಳಿಗೆ ಸೂಕ್ತವಾದ HTTP/HTTPS ಪೂರ್ವಪ್ರತ್ಯಯದ ಅಗತ್ಯವಿದೆ." }, diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index 615db337e09e..ce11ea4bebf4 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -1873,10 +1873,6 @@ "feeDetails": { "message": "수수료 세부 정보" }, - "fiat": { - "message": "명목", - "description": "Exchange type" - }, "fileImportFail": { "message": "파일 가져오기가 작동하지 않나요? 여기를 클릭하세요.", "description": "Helps user import their account from a JSON file" @@ -3092,9 +3088,6 @@ "noConnectedAccountTitle": { "message": "MetaMask가 이 사이트와 연결되어 있지 않습니다" }, - "noConversionDateAvailable": { - "message": "사용 가능한 통화 변환 날짜 없음" - }, "noConversionRateAvailable": { "message": "사용 가능한 환율 없음" }, @@ -3915,12 +3908,6 @@ "priceUnavailable": { "message": "가격 사용 불가" }, - "primaryCurrencySetting": { - "message": "기본 통화" - }, - "primaryCurrencySettingDescription": { - "message": "체인의 고유 통화(예: ETH)로 값을 우선 표시하려면 고유를 선택합니다. 선택한 명목 통화로 값을 우선 표시하려면 명목을 선택합니다." - }, "primaryType": { "message": "기본 유형" }, @@ -6085,9 +6072,6 @@ "updateRequest": { "message": "업데이트 요청" }, - "updatedWithDate": { - "message": "$1에 업데이트됨" - }, "uploadDropFile": { "message": "여기에 파일을 드롭" }, diff --git a/app/_locales/lt/messages.json b/app/_locales/lt/messages.json index 0668166eb8fe..fe825ae6b798 100644 --- a/app/_locales/lt/messages.json +++ b/app/_locales/lt/messages.json @@ -244,10 +244,6 @@ "fast": { "message": "Greitas" }, - "fiat": { - "message": "Standartinė valiuta", - "description": "Exchange type" - }, "fileImportFail": { "message": "Failo importavimas neveikia? Spustelėkite čia!", "description": "Helps user import their account from a JSON file" @@ -508,12 +504,6 @@ "prev": { "message": "Peržiūra" }, - "primaryCurrencySetting": { - "message": "Pagrindinė valiuta" - }, - "primaryCurrencySettingDescription": { - "message": "Rinkitės vietinę, kad vertės pirmiausia būtų rodomos vietine grandinės valiuta (pvz., ETH). Rinkitės standartinę, kad vertės pirmiausia būtų rodomos jūsų pasirinkta standartine valiuta." - }, "privacyMsg": { "message": "Privatumo politika" }, @@ -765,9 +755,6 @@ "unlockMessage": { "message": "Laukiančios decentralizuotos svetainės" }, - "updatedWithDate": { - "message": "Atnaujinta $1" - }, "urlErrorMsg": { "message": "URI reikia atitinkamo HTTP/HTTPS priešdėlio." }, diff --git a/app/_locales/lv/messages.json b/app/_locales/lv/messages.json index 3939c9145c12..697af7849327 100644 --- a/app/_locales/lv/messages.json +++ b/app/_locales/lv/messages.json @@ -504,12 +504,6 @@ "prev": { "message": "Iepr." }, - "primaryCurrencySetting": { - "message": "Primārā valūta" - }, - "primaryCurrencySettingDescription": { - "message": "Atlasīt vietējo, lai piešķirtu attēlotajām vērtībām prioritātes ķēdes vietējā vērtībā (piemēram, ETH). Atlasiet Fiat, lai piešķirtu augstāku prioritāti vērtībām jūsu atlasītajā fiat valūtā." - }, "privacyMsg": { "message": "Privātuma politika" }, @@ -761,9 +755,6 @@ "unlockMessage": { "message": "Decentralizētais tīkls jau gaida" }, - "updatedWithDate": { - "message": "Atjaunināts $1" - }, "urlErrorMsg": { "message": "URI jāsākas ar atbilstošo HTTP/HTTPS priedēkli." }, diff --git a/app/_locales/ms/messages.json b/app/_locales/ms/messages.json index cfad6a22d73d..dc42e639ff2a 100644 --- a/app/_locales/ms/messages.json +++ b/app/_locales/ms/messages.json @@ -488,12 +488,6 @@ "prev": { "message": "Sebelumnya" }, - "primaryCurrencySetting": { - "message": "Mata Wang Utama" - }, - "primaryCurrencySettingDescription": { - "message": "Pilih natif untuk mengutamakan nilai paparan dalam mata wang natif rantaian (cth. ETH). Pilih Fiat untuk mengutamakan nilai paparan dalam mata wang fiat yang anda pilih." - }, "privacyMsg": { "message": "Dasar Privasi" }, @@ -742,9 +736,6 @@ "unlockMessage": { "message": "Web ternyahpusat menanti" }, - "updatedWithDate": { - "message": "Dikemaskini $1" - }, "urlErrorMsg": { "message": "URI memerlukan awalan HTTP/HTTPS yang sesuai." }, diff --git a/app/_locales/nl/messages.json b/app/_locales/nl/messages.json index 946976a7a93e..cbebb9a14563 100644 --- a/app/_locales/nl/messages.json +++ b/app/_locales/nl/messages.json @@ -84,10 +84,6 @@ "failed": { "message": "mislukt" }, - "fiat": { - "message": "FIAT", - "description": "Exchange type" - }, "fileImportFail": { "message": "Bestandsimport werkt niet? Klik hier!", "description": "Helps user import their account from a JSON file" diff --git a/app/_locales/no/messages.json b/app/_locales/no/messages.json index 0d1fa5173a9f..45a101fc83a5 100644 --- a/app/_locales/no/messages.json +++ b/app/_locales/no/messages.json @@ -492,12 +492,6 @@ "prev": { "message": "Tidligere" }, - "primaryCurrencySetting": { - "message": "Hovedvaluta " - }, - "primaryCurrencySettingDescription": { - "message": "Velg nasjonal for å prioritere å vise verdier i nasjonal valuta i kjeden (f.eks. ETH). Velg Fiat for å prioritere visning av verdier i den valgte fiat-valutaen." - }, "privacyMsg": { "message": "Personvernerklæring" }, @@ -740,9 +734,6 @@ "unlockMessage": { "message": "Det desentraliserte internett venter deg" }, - "updatedWithDate": { - "message": "Oppdatert $1" - }, "urlErrorMsg": { "message": "URI-er krever det aktuelle HTTP/HTTPS-prefikset." }, diff --git a/app/_locales/ph/messages.json b/app/_locales/ph/messages.json index df15e05a0bb6..454facde8524 100644 --- a/app/_locales/ph/messages.json +++ b/app/_locales/ph/messages.json @@ -513,10 +513,6 @@ "feeAssociatedRequest": { "message": "May nauugnay na bayarin para sa request na ito." }, - "fiat": { - "message": "Fiat", - "description": "Exchange type" - }, "fileImportFail": { "message": "Hindi gumagana ang pag-import ng file? Mag-click dito!", "description": "Helps user import their account from a JSON file" @@ -955,12 +951,6 @@ "prev": { "message": "Nakaraan" }, - "primaryCurrencySetting": { - "message": "Pangunahing Currency" - }, - "primaryCurrencySettingDescription": { - "message": "Piliin ang native para maisapriyoridad ang pagpapakita ng mga value sa native na currency ng chain (hal. ETH). Piliin ang Fiat para maisapriyoridad ang pagpapakita ng mga value sa napili mong fiat currency." - }, "privacyMsg": { "message": "Patakaran sa Pagkapribado" }, @@ -1655,9 +1645,6 @@ "message": "Hindi kinikilala ang custom na network na ito. Inirerekomenda naming $1 ka bago magpatuloy", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." }, - "updatedWithDate": { - "message": "Na-update noong $1" - }, "urlErrorMsg": { "message": "Kinakailangan ng mga URL ang naaangkop na HTTP/HTTPS prefix." }, diff --git a/app/_locales/pl/messages.json b/app/_locales/pl/messages.json index cb82388a8634..d22673fa9f1f 100644 --- a/app/_locales/pl/messages.json +++ b/app/_locales/pl/messages.json @@ -244,10 +244,6 @@ "fast": { "message": "Szybko" }, - "fiat": { - "message": "FIAT", - "description": "Exchange type" - }, "fileImportFail": { "message": "Importowanie pliku nie działa? Kliknij tutaj!", "description": "Helps user import their account from a JSON file" @@ -502,12 +498,6 @@ "prev": { "message": "Poprzednie" }, - "primaryCurrencySetting": { - "message": "Waluta podstawowa" - }, - "primaryCurrencySettingDescription": { - "message": "Wybierz walutę natywną, aby preferować wyświetlanie wartości w walucie natywnej łańcucha (np. ETH). Wybierz walutę fiat, aby preferować wyświetlanie wartości w wybranej przez siebie walucie fiat." - }, "privacyMsg": { "message": "Polityka prywatności" }, @@ -753,9 +743,6 @@ "unlockMessage": { "message": "Zdecentralizowana sieć oczekuje" }, - "updatedWithDate": { - "message": "Zaktualizowano $1" - }, "urlErrorMsg": { "message": "URI wymaga prawidłowego prefiksu HTTP/HTTPS." }, diff --git a/app/_locales/pt/messages.json b/app/_locales/pt/messages.json index d5039ee7e604..770d517c8b25 100644 --- a/app/_locales/pt/messages.json +++ b/app/_locales/pt/messages.json @@ -1873,10 +1873,6 @@ "feeDetails": { "message": "Detalhes da taxa" }, - "fiat": { - "message": "Fiduciária", - "description": "Exchange type" - }, "fileImportFail": { "message": "A importação de arquivo não está funcionando? Clique aqui!", "description": "Helps user import their account from a JSON file" @@ -3092,9 +3088,6 @@ "noConnectedAccountTitle": { "message": "A MetaMask não está conectada a este site" }, - "noConversionDateAvailable": { - "message": "Não há uma data de conversão de moeda disponível" - }, "noConversionRateAvailable": { "message": "Não há uma taxa de conversão disponível" }, @@ -3915,12 +3908,6 @@ "priceUnavailable": { "message": "preço não disponível" }, - "primaryCurrencySetting": { - "message": "Moeda principal" - }, - "primaryCurrencySettingDescription": { - "message": "Selecione Nativa para priorizar a exibição de valores na moeda nativa da cadeia (por ex., ETH). Selecione Fiduciária para priorizar a exibição de valores na moeda fiduciária selecionada." - }, "primaryType": { "message": "Tipo primário" }, @@ -6085,9 +6072,6 @@ "updateRequest": { "message": "Solicitação de atualização" }, - "updatedWithDate": { - "message": "Atualizado em $1" - }, "uploadDropFile": { "message": "Solte seu arquivo aqui" }, diff --git a/app/_locales/pt_BR/messages.json b/app/_locales/pt_BR/messages.json index 4c4b17d74f6e..0f6efb88d348 100644 --- a/app/_locales/pt_BR/messages.json +++ b/app/_locales/pt_BR/messages.json @@ -782,10 +782,6 @@ "feeAssociatedRequest": { "message": "Há uma taxa associada a essa solicitação." }, - "fiat": { - "message": "Fiduciária", - "description": "Exchange type" - }, "fileImportFail": { "message": "A importação de arquivo não está funcionando? Clique aqui!", "description": "Helps user import their account from a JSON file" @@ -1321,9 +1317,6 @@ "noAccountsFound": { "message": "Nenhuma conta encontrada para a busca efetuada" }, - "noConversionDateAvailable": { - "message": "Não há uma data de conversão de moeda disponível" - }, "noConversionRateAvailable": { "message": "Não há uma taxa de conversão disponível" }, @@ -1493,12 +1486,6 @@ "prev": { "message": "Anterior" }, - "primaryCurrencySetting": { - "message": "Moeda principal" - }, - "primaryCurrencySettingDescription": { - "message": "Selecione Nativa para priorizar a exibição de valores na moeda nativa da cadeia (por ex., ETH). Selecione Fiduciária para priorizar a exibição de valores na moeda fiduciária selecionada." - }, "priorityFee": { "message": "Taxa de prioridade" }, @@ -2409,9 +2396,6 @@ "message": "O envio de tokens colecionáveis (ERC-721) não é suportado no momento", "description": "This is an error message we show the user if they attempt to send an NFT asset type, for which currently don't support sending" }, - "updatedWithDate": { - "message": "Atualizado em $1" - }, "urlErrorMsg": { "message": "Os URLs precisam do prefixo HTTP/HTTPS adequado." }, diff --git a/app/_locales/ro/messages.json b/app/_locales/ro/messages.json index aad720151da6..912accba29be 100644 --- a/app/_locales/ro/messages.json +++ b/app/_locales/ro/messages.json @@ -495,12 +495,6 @@ "prev": { "message": "Ant" }, - "primaryCurrencySetting": { - "message": "Moneda principală" - }, - "primaryCurrencySettingDescription": { - "message": "Selectați nativ pentru a prioritiza valorile afișate în moneda nativă a lanțului (ex. ETH). Selectați Fiat pentru a prioritiza valorile afișate în moneda selectată fiat." - }, "privacyMsg": { "message": "Politica de Confidențialitate" }, @@ -746,9 +740,6 @@ "unlockMessage": { "message": "Web-ul descentralizat așteaptă" }, - "updatedWithDate": { - "message": "Actualizat $1" - }, "urlErrorMsg": { "message": "URL necesită prefixul potrivit HTTP/HTTPS." }, diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index 794cd777afd1..6ce21329f244 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -1873,10 +1873,6 @@ "feeDetails": { "message": "Сведения о комиссии" }, - "fiat": { - "message": "Фиатная", - "description": "Exchange type" - }, "fileImportFail": { "message": "Импорт файлов не работает? Нажмите здесь!", "description": "Helps user import their account from a JSON file" @@ -3092,9 +3088,6 @@ "noConnectedAccountTitle": { "message": "MetaMask не подключен к этому сайту" }, - "noConversionDateAvailable": { - "message": "Дата обмена валюты недоступна" - }, "noConversionRateAvailable": { "message": "Нет доступного обменного курса" }, @@ -3915,12 +3908,6 @@ "priceUnavailable": { "message": "цена недоступна" }, - "primaryCurrencySetting": { - "message": "Основная валюта" - }, - "primaryCurrencySettingDescription": { - "message": "Выберите «собственная», чтобы установить приоритет отображения значений в собственной валюте блокчейна (например, ETH). Выберите «Фиатная», чтобы установить приоритет отображения значений в выбранной фиатной валюте." - }, "primaryType": { "message": "Основной тип" }, @@ -6085,9 +6072,6 @@ "updateRequest": { "message": "Запрос обновления" }, - "updatedWithDate": { - "message": "Обновлено $1" - }, "uploadDropFile": { "message": "Переместите свой файл сюда" }, diff --git a/app/_locales/sk/messages.json b/app/_locales/sk/messages.json index 564e7cb12d94..829435f28ff7 100644 --- a/app/_locales/sk/messages.json +++ b/app/_locales/sk/messages.json @@ -238,10 +238,6 @@ "fast": { "message": "Rýchle" }, - "fiat": { - "message": "FIAT", - "description": "Exchange type" - }, "fileImportFail": { "message": "Import souboru nefunguje? Klikněte sem!", "description": "Helps user import their account from a JSON file" @@ -480,12 +476,6 @@ "prev": { "message": "Predchádzajúce" }, - "primaryCurrencySetting": { - "message": "Primárna mena" - }, - "primaryCurrencySettingDescription": { - "message": "Vyberte natívne, ak chcete priorizovať zobrazovanie hodnôt v natívnej mene reťazca (napr. ETH). Ak chcete priorizovať zobrazovanie hodnôt vo svojej vybranej mene fiat, zvoľte možnosť Fiat." - }, "privacyMsg": { "message": "Zásady ochrany osobních údajů" }, @@ -731,9 +721,6 @@ "unlockMessage": { "message": "Decentralizovaný web čaká" }, - "updatedWithDate": { - "message": "Aktualizované $1" - }, "urlErrorMsg": { "message": "URI vyžadují korektní HTTP/HTTPS prefix." }, diff --git a/app/_locales/sl/messages.json b/app/_locales/sl/messages.json index 8d43d184c427..cb82e0358212 100644 --- a/app/_locales/sl/messages.json +++ b/app/_locales/sl/messages.json @@ -244,10 +244,6 @@ "fast": { "message": "Hiter" }, - "fiat": { - "message": "Klasične", - "description": "Exchange type" - }, "fileImportFail": { "message": "Uvoz z datoteko ne deluje? Kliknite tukaj!", "description": "Helps user import their account from a JSON file" @@ -496,12 +492,6 @@ "prev": { "message": "Prej" }, - "primaryCurrencySetting": { - "message": "Glavna valuta" - }, - "primaryCurrencySettingDescription": { - "message": "Izberite Native za prikaz vrednosti v privzeti valuti verige (npr. ETH). Izberite Klasične za prikaz vrednosti v izbrani klasični valuti." - }, "privacyMsg": { "message": "Zasebnost" }, @@ -753,9 +743,6 @@ "unlockMessage": { "message": "Decentralizirana spletna denarnica" }, - "updatedWithDate": { - "message": "Posodobljeno $1" - }, "urlErrorMsg": { "message": "URI zahtevajo ustrezno HTTP/HTTPS predpono." }, diff --git a/app/_locales/sr/messages.json b/app/_locales/sr/messages.json index d3f5e27c6235..e15ae23086b3 100644 --- a/app/_locales/sr/messages.json +++ b/app/_locales/sr/messages.json @@ -241,10 +241,6 @@ "fast": { "message": "Брзо" }, - "fiat": { - "message": "Dekret", - "description": "Exchange type" - }, "fileImportFail": { "message": "Uvoz datoteke ne radi? Kliknite ovde!", "description": "Helps user import their account from a JSON file" @@ -499,12 +495,6 @@ "prev": { "message": "Prethodno" }, - "primaryCurrencySetting": { - "message": "Primarna valuta" - }, - "primaryCurrencySettingDescription": { - "message": "Izaberite primarnu da biste postavili prioritete u prikazivanju vrednosti u primarnoj valuti lanca (npr. ETH). Izaberite Fiat da biste postavili prioritete u prikazivanju vrednosti u vašoj izabranoj fiat valuti." - }, "privacyMsg": { "message": "Smernice za privatnost" }, @@ -753,9 +743,6 @@ "unlockMessage": { "message": "Decentralizovani veb čeka" }, - "updatedWithDate": { - "message": "Ažuriran $1" - }, "urlErrorMsg": { "message": "URI-ovi zahtevaju odgovarajući prefiks HTTP / HTTPS." }, diff --git a/app/_locales/sv/messages.json b/app/_locales/sv/messages.json index a98db5bea015..163cdebc426e 100644 --- a/app/_locales/sv/messages.json +++ b/app/_locales/sv/messages.json @@ -492,12 +492,6 @@ "prev": { "message": "Föregående" }, - "primaryCurrencySetting": { - "message": "Primär valuta" - }, - "primaryCurrencySettingDescription": { - "message": "Välj native för att prioritera visning av värden i den ursprungliga valutan i kedjan (t.ex. ETH). Välj Fiat för att prioritera visning av värden i din valda fiatvaluta." - }, "privacyMsg": { "message": "Integritetspolicy" }, @@ -740,9 +734,6 @@ "unlockMessage": { "message": "Den decentraliserade webben väntar" }, - "updatedWithDate": { - "message": "Uppdaterat $1" - }, "urlErrorMsg": { "message": "URI:er kräver lämpligt HTTP/HTTPS-prefix." }, diff --git a/app/_locales/sw/messages.json b/app/_locales/sw/messages.json index d8ad6258e8ba..c1535d76cdd8 100644 --- a/app/_locales/sw/messages.json +++ b/app/_locales/sw/messages.json @@ -486,12 +486,6 @@ "prev": { "message": "Hakiki" }, - "primaryCurrencySetting": { - "message": "Sarafu ya Msingi" - }, - "primaryCurrencySettingDescription": { - "message": "Chagua mzawa ili kuweka kipaumbele kuonyesha thamani kwenye sarafu mzawa ya mnyororo (k.m ETH). Chagua Fiat ili uwelke kipaumbale kuonyesha thamani kwenye sarafu yako ya fiat uliyoichagua." - }, "privacyMsg": { "message": "Sera ya Faragha" }, @@ -743,9 +737,6 @@ "unlockMessage": { "message": "Wavuti uliotenganishwa unasubiri" }, - "updatedWithDate": { - "message": "Imesasishwa $1" - }, "urlErrorMsg": { "message": "URI huhitaji kiambishi sahihi cha HTTP/HTTPS." }, diff --git a/app/_locales/ta/messages.json b/app/_locales/ta/messages.json index 8e38061bebb2..d5d1929a2dc4 100644 --- a/app/_locales/ta/messages.json +++ b/app/_locales/ta/messages.json @@ -129,10 +129,6 @@ "fast": { "message": "வேகமான" }, - "fiat": { - "message": "FIAT", - "description": "Exchange type" - }, "fileImportFail": { "message": "கோப்பு இறக்குமதி வேலை செய்யவில்லையா? இங்கே கிளிக் செய்யவும்!", "description": "Helps user import their account from a JSON file" diff --git a/app/_locales/th/messages.json b/app/_locales/th/messages.json index c3b4a8a6e3fa..e6c074fe1264 100644 --- a/app/_locales/th/messages.json +++ b/app/_locales/th/messages.json @@ -120,10 +120,6 @@ "fast": { "message": "เร็ว" }, - "fiat": { - "message": "เงินตรา", - "description": "Exchange type" - }, "fileImportFail": { "message": "นำเข้าไฟล์ไม่สำเหร็จ กดที่นี่!", "description": "Helps user import their account from a JSON file" @@ -371,9 +367,6 @@ "unlock": { "message": "ปลดล็อก" }, - "updatedWithDate": { - "message": "อัปเดต $1 แล้ว" - }, "urlErrorMsg": { "message": "URI ต้องมีคำนำหน้าเป็น HTTP หรือ HTTPS" }, diff --git a/app/_locales/tl/messages.json b/app/_locales/tl/messages.json index 958fa1345041..57b62731724d 100644 --- a/app/_locales/tl/messages.json +++ b/app/_locales/tl/messages.json @@ -1873,10 +1873,6 @@ "feeDetails": { "message": "Mga detalye ng singil" }, - "fiat": { - "message": "Fiat", - "description": "Exchange type" - }, "fileImportFail": { "message": "Hindi gumagana ang pag-import ng file? Mag-click dito!", "description": "Helps user import their account from a JSON file" @@ -3092,9 +3088,6 @@ "noConnectedAccountTitle": { "message": "Ang MetaMask ay hindi nakakonekta sa site na ito" }, - "noConversionDateAvailable": { - "message": "Walang available na petsa sa pagpapapalit ng currency" - }, "noConversionRateAvailable": { "message": "Hindi available ang rate ng palitan" }, @@ -3915,12 +3908,6 @@ "priceUnavailable": { "message": "hindi available ang presyo" }, - "primaryCurrencySetting": { - "message": "Pangunahing Currency" - }, - "primaryCurrencySettingDescription": { - "message": "Piliin ang native para maisapriyoridad ang pagpapakita ng mga value sa native na currency ng chain (hal. ETH). Piliin ang Fiat para maisapriyoridad ang pagpapakita ng mga value sa napili mong fiat na salapi." - }, "primaryType": { "message": "Pangunahing uri" }, @@ -6085,9 +6072,6 @@ "updateRequest": { "message": "Hiling sa pag-update" }, - "updatedWithDate": { - "message": "Na-update noong $1" - }, "uploadDropFile": { "message": "I-drop ang file mo rito" }, diff --git a/app/_locales/tr/messages.json b/app/_locales/tr/messages.json index 3fbbc1bc51ff..9f8e90a386e3 100644 --- a/app/_locales/tr/messages.json +++ b/app/_locales/tr/messages.json @@ -1873,10 +1873,6 @@ "feeDetails": { "message": "Ücret bilgileri" }, - "fiat": { - "message": "Fiat Para", - "description": "Exchange type" - }, "fileImportFail": { "message": "Dosya içe aktarma çalışmıyor mu? Buraya tıklayın!", "description": "Helps user import their account from a JSON file" @@ -3092,9 +3088,6 @@ "noConnectedAccountTitle": { "message": "MetaMask bu siteye bağlı değil" }, - "noConversionDateAvailable": { - "message": "Para birimi dönüşüm tarihi mevcut değil" - }, "noConversionRateAvailable": { "message": "Dönüşüm oranı mevcut değil" }, @@ -3915,12 +3908,6 @@ "priceUnavailable": { "message": "fiyat mevcut değil" }, - "primaryCurrencySetting": { - "message": "Öncelikli para birimi" - }, - "primaryCurrencySettingDescription": { - "message": "Değerlerin zincirin yerli para biriminde (ör. ETH) görüntülenmesini önceliklendirmek için yerli seçimi yapın. Seçtiğiniz fiat parada değerlerin gösterilmesini önceliklendirmek için Fiat Para seçin." - }, "primaryType": { "message": "Öncelikli tür" }, @@ -6085,9 +6072,6 @@ "updateRequest": { "message": "Talebi güncelle" }, - "updatedWithDate": { - "message": "$1 güncellendi" - }, "uploadDropFile": { "message": "Dosyanızı buraya sürükleyin" }, diff --git a/app/_locales/uk/messages.json b/app/_locales/uk/messages.json index 37bab506a87d..b0c011690910 100644 --- a/app/_locales/uk/messages.json +++ b/app/_locales/uk/messages.json @@ -244,10 +244,6 @@ "fast": { "message": "Швидка" }, - "fiat": { - "message": "Вказівка", - "description": "Exchange type" - }, "fileImportFail": { "message": "Не працює імпорт файлу? Натисніть тут!", "description": "Helps user import their account from a JSON file" @@ -508,12 +504,6 @@ "prev": { "message": "Попередній" }, - "primaryCurrencySetting": { - "message": "Первісна валюта" - }, - "primaryCurrencySettingDescription": { - "message": "Оберіть \"рідна\", щоб пріоритезувати показ сум у рідних валютах мережі (напр.ETH). \nОберіть \"фіатна\", щоб пріоритезувати показ сум у ваших обраних фіатних валютах." - }, "privacyMsg": { "message": "Політика конфіденційності" }, @@ -765,9 +755,6 @@ "unlockMessage": { "message": "Децентралізована мережа очікує" }, - "updatedWithDate": { - "message": "Оновлено $1" - }, "urlErrorMsg": { "message": "URIs вимагають відповідного префікса HTTP/HTTPS." }, diff --git a/app/_locales/vi/messages.json b/app/_locales/vi/messages.json index 52e7a3a18792..273089bb4343 100644 --- a/app/_locales/vi/messages.json +++ b/app/_locales/vi/messages.json @@ -1873,10 +1873,6 @@ "feeDetails": { "message": "Chi tiết phí" }, - "fiat": { - "message": "Pháp định", - "description": "Exchange type" - }, "fileImportFail": { "message": "Tính năng nhập tập tin không hoạt động? Nhấp vào đây!", "description": "Helps user import their account from a JSON file" @@ -3092,9 +3088,6 @@ "noConnectedAccountTitle": { "message": "MetaMask không được kết nối với trang web này" }, - "noConversionDateAvailable": { - "message": "Hiện không có ngày quy đổi tiền tệ nào" - }, "noConversionRateAvailable": { "message": "Không có sẵn tỷ lệ quy đổi nào" }, @@ -3915,12 +3908,6 @@ "priceUnavailable": { "message": "giá không khả dụng" }, - "primaryCurrencySetting": { - "message": "Tiền tệ chính" - }, - "primaryCurrencySettingDescription": { - "message": "Chọn Gốc để ưu tiên hiển thị giá trị bằng đơn vị tiền tệ gốc của chuỗi (ví dụ: ETH). Chọn Pháp định để ưu tiên hiển thị giá trị bằng đơn vị tiền pháp định mà bạn chọn." - }, "primaryType": { "message": "Loại chính" }, @@ -6085,9 +6072,6 @@ "updateRequest": { "message": "Yêu cầu cập nhật" }, - "updatedWithDate": { - "message": "Đã cập nhật $1" - }, "uploadDropFile": { "message": "Thả tập tin của bạn vào đây" }, diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index 302eb5648224..6a8f8d9f4df6 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -1873,10 +1873,6 @@ "feeDetails": { "message": "费用详情" }, - "fiat": { - "message": "法币", - "description": "Exchange type" - }, "fileImportFail": { "message": "文件导入失败?点击这里!", "description": "Helps user import their account from a JSON file" @@ -3092,9 +3088,6 @@ "noConnectedAccountTitle": { "message": "MetaMask 未连接到此站点" }, - "noConversionDateAvailable": { - "message": "没有可用的货币转换日期" - }, "noConversionRateAvailable": { "message": "无可用汇率" }, @@ -3915,12 +3908,6 @@ "priceUnavailable": { "message": "价格不可用" }, - "primaryCurrencySetting": { - "message": "主要货币" - }, - "primaryCurrencySettingDescription": { - "message": "选择原生以优先显示链的原生货币(例如 ETH)的值。选择法币以优先显示以您所选法币显示的值。" - }, "primaryType": { "message": "主要类型" }, @@ -6085,9 +6072,6 @@ "updateRequest": { "message": "更新请求" }, - "updatedWithDate": { - "message": "已于 $1 更新" - }, "uploadDropFile": { "message": "将您的文件放在此处" }, diff --git a/app/_locales/zh_TW/messages.json b/app/_locales/zh_TW/messages.json index 0924d284b529..dee06a7aef16 100644 --- a/app/_locales/zh_TW/messages.json +++ b/app/_locales/zh_TW/messages.json @@ -512,10 +512,6 @@ "feeAssociatedRequest": { "message": "這個請求會附帶一筆手續費。" }, - "fiat": { - "message": "法定貨幣", - "description": "Exchange type" - }, "fileImportFail": { "message": "檔案匯入失敗?點擊這裡!", "description": "Helps user import their account from a JSON file" @@ -944,12 +940,6 @@ "prev": { "message": "前一頁" }, - "primaryCurrencySetting": { - "message": "主要貨幣" - }, - "primaryCurrencySettingDescription": { - "message": "選擇原生來優先使用鏈上原生貨幣 (例如 ETH) 顯示金額。選擇法定貨幣來優先使用您選擇的法定貨幣顯示金額。" - }, "privacyMsg": { "message": "隱私政策" }, @@ -1380,9 +1370,6 @@ "message": "無法辨識這個自訂網路。我們建議您先$1再繼續。", "description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details." }, - "updatedWithDate": { - "message": "更新時間 $1" - }, "urlErrorMsg": { "message": "URL 需要以適當的 HTTP/HTTPS 作為開頭" }, diff --git a/app/scripts/constants/sentry-state.ts b/app/scripts/constants/sentry-state.ts index 33bf9bac0f22..9763d152eb39 100644 --- a/app/scripts/constants/sentry-state.ts +++ b/app/scripts/constants/sentry-state.ts @@ -226,7 +226,7 @@ export const SENTRY_BACKGROUND_STATE = { showFiatInTestnets: true, showTestNetworks: true, smartTransactionsOptInStatus: true, - useNativeCurrencyAsPrimaryCurrency: true, + showNativeTokenAsMainBalance: true, petnamesEnabled: true, showConfirmationAdvancedDetails: true, }, diff --git a/app/scripts/controllers/metametrics.js b/app/scripts/controllers/metametrics.js index bfe7f79d1ac4..ef1dbe02789a 100644 --- a/app/scripts/controllers/metametrics.js +++ b/app/scripts/controllers/metametrics.js @@ -846,8 +846,8 @@ export default class MetaMetricsController { [MetaMetricsUserTrait.Theme]: metamaskState.theme || 'default', [MetaMetricsUserTrait.TokenDetectionEnabled]: metamaskState.useTokenDetection, - [MetaMetricsUserTrait.UseNativeCurrencyAsPrimaryCurrency]: - metamaskState.useNativeCurrencyAsPrimaryCurrency, + [MetaMetricsUserTrait.ShowNativeTokenAsMainBalance]: + metamaskState.showNativeTokenAsMainBalance, [MetaMetricsUserTrait.CurrentCurrency]: metamaskState.currentCurrency, ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) [MetaMetricsUserTrait.MmiExtensionId]: this.extension?.runtime?.id, diff --git a/app/scripts/controllers/metametrics.test.js b/app/scripts/controllers/metametrics.test.js index 2113efd1715b..3d4845e056d0 100644 --- a/app/scripts/controllers/metametrics.test.js +++ b/app/scripts/controllers/metametrics.test.js @@ -1088,7 +1088,7 @@ describe('MetaMetricsController', function () { securityAlertsEnabled: true, theme: 'default', useTokenDetection: true, - useNativeCurrencyAsPrimaryCurrency: true, + showNativeTokenAsMainBalance: true, security_providers: [], names: { [NameType.ETHEREUM_ADDRESS]: { @@ -1143,7 +1143,7 @@ describe('MetaMetricsController', function () { [MetaMetricsUserTrait.ThreeBoxEnabled]: false, [MetaMetricsUserTrait.Theme]: 'default', [MetaMetricsUserTrait.TokenDetectionEnabled]: true, - [MetaMetricsUserTrait.UseNativeCurrencyAsPrimaryCurrency]: true, + [MetaMetricsUserTrait.ShowNativeTokenAsMainBalance]: true, [MetaMetricsUserTrait.SecurityProviders]: ['blockaid'], ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) [MetaMetricsUserTrait.MmiExtensionId]: 'testid', @@ -1181,7 +1181,7 @@ describe('MetaMetricsController', function () { useNftDetection: false, theme: 'default', useTokenDetection: true, - useNativeCurrencyAsPrimaryCurrency: true, + showNativeTokenAsMainBalance: true, }); const updatedTraits = metaMetricsController._buildUserTraitsObject({ @@ -1208,7 +1208,7 @@ describe('MetaMetricsController', function () { useNftDetection: false, theme: 'default', useTokenDetection: true, - useNativeCurrencyAsPrimaryCurrency: false, + showNativeTokenAsMainBalance: false, }); expect(updatedTraits).toStrictEqual({ @@ -1216,7 +1216,7 @@ describe('MetaMetricsController', function () { [MetaMetricsUserTrait.NumberOfAccounts]: 3, [MetaMetricsUserTrait.NumberOfTokens]: 1, [MetaMetricsUserTrait.OpenseaApiEnabled]: false, - [MetaMetricsUserTrait.UseNativeCurrencyAsPrimaryCurrency]: false, + [MetaMetricsUserTrait.ShowNativeTokenAsMainBalance]: false, }); }); @@ -1245,7 +1245,7 @@ describe('MetaMetricsController', function () { useNftDetection: true, theme: 'default', useTokenDetection: true, - useNativeCurrencyAsPrimaryCurrency: true, + showNativeTokenAsMainBalance: true, }); const updatedTraits = metaMetricsController._buildUserTraitsObject({ @@ -1267,7 +1267,7 @@ describe('MetaMetricsController', function () { useNftDetection: true, theme: 'default', useTokenDetection: true, - useNativeCurrencyAsPrimaryCurrency: true, + showNativeTokenAsMainBalance: true, }); expect(updatedTraits).toStrictEqual(null); }); diff --git a/app/scripts/controllers/preferences-controller.ts b/app/scripts/controllers/preferences-controller.ts index ab6c3e959215..a158ac0024d4 100644 --- a/app/scripts/controllers/preferences-controller.ts +++ b/app/scripts/controllers/preferences-controller.ts @@ -96,6 +96,7 @@ export type Preferences = { showFiatInTestnets: boolean; showTestNetworks: boolean; smartTransactionsOptInStatus: boolean | null; + showNativeTokenAsMainBalance: boolean; useNativeCurrencyAsPrimaryCurrency: boolean; hideZeroBalanceTokens: boolean; petnamesEnabled: boolean; @@ -105,6 +106,7 @@ export type Preferences = { showMultiRpcModal: boolean; isRedesignedConfirmationsDeveloperEnabled: boolean; showConfirmationAdvancedDetails: boolean; + shouldShowAggregatedBalancePopover: boolean; }; export type PreferencesControllerState = { @@ -122,7 +124,9 @@ export type PreferencesControllerState = { useRequestQueue: boolean; openSeaEnabled: boolean; securityAlertsEnabled: boolean; + ///: BEGIN:ONLY_INCLUDE_IF(build-flask) watchEthereumAccountEnabled: boolean; + ///: END:ONLY_INCLUDE_IF bitcoinSupportEnabled: boolean; bitcoinTestnetSupportEnabled: boolean; addSnapAccountEnabled: boolean; @@ -223,6 +227,7 @@ export default class PreferencesController { showFiatInTestnets: false, showTestNetworks: false, smartTransactionsOptInStatus: null, // null means we will show the Smart Transactions opt-in modal to a user if they are eligible + showNativeTokenAsMainBalance: false, useNativeCurrencyAsPrimaryCurrency: true, hideZeroBalanceTokens: false, petnamesEnabled: true, @@ -232,6 +237,7 @@ export default class PreferencesController { showMultiRpcModal: false, isRedesignedConfirmationsDeveloperEnabled: false, showConfirmationAdvancedDetails: false, + shouldShowAggregatedBalancePopover: true, // by default user should see popover; }, // ENS decentralized website resolution ipfsGateway: IPFS_DEFAULT_GATEWAY_URL, @@ -425,6 +431,7 @@ export default class PreferencesController { } ///: END:ONLY_INCLUDE_IF + ///: BEGIN:ONLY_INCLUDE_IF(build-flask) /** * Setter for the `watchEthereumAccountEnabled` property. * @@ -436,6 +443,7 @@ export default class PreferencesController { watchEthereumAccountEnabled, }); } + ///: END:ONLY_INCLUDE_IF /** * Setter for the `bitcoinSupportEnabled` property. diff --git a/app/scripts/controllers/swaps/swaps.test.ts b/app/scripts/controllers/swaps/swaps.test.ts index 3fa4f1ff9409..4ed1b545f170 100644 --- a/app/scripts/controllers/swaps/swaps.test.ts +++ b/app/scripts/controllers/swaps/swaps.test.ts @@ -26,6 +26,7 @@ const MOCK_FETCH_PARAMS: FetchTradesInfoParams = { fromAddress: '0x7F18BB4Dd92CF2404C54CBa1A9BE4A1153bdb078', exchangeList: 'zeroExV1', balanceError: false, + enableGasIncludedQuotes: false, }; const TEST_AGG_ID_1 = 'TEST_AGG_1'; @@ -1164,6 +1165,7 @@ describe('SwapsController', function () { fromAddress: '', exchangeList: 'zeroExV1', balanceError: false, + enableGasIncludedQuotes: false, metaData: {} as FetchTradesInfoParamsMetadata, }; const swapsFeatureIsLive = false; diff --git a/app/scripts/controllers/swaps/swaps.types.ts b/app/scripts/controllers/swaps/swaps.types.ts index 44e4d4939742..ca059723277a 100644 --- a/app/scripts/controllers/swaps/swaps.types.ts +++ b/app/scripts/controllers/swaps/swaps.types.ts @@ -308,6 +308,7 @@ export type FetchTradesInfoParams = { fromAddress: string; exchangeList: string; balanceError: boolean; + enableGasIncludedQuotes: boolean; }; export type FetchTradesInfoParamsMetadata = { diff --git a/app/scripts/lib/rpc-method-middleware/handlers/get-provider-state.js b/app/scripts/lib/rpc-method-middleware/handlers/get-provider-state.js deleted file mode 100644 index 70dbb7b16cfa..000000000000 --- a/app/scripts/lib/rpc-method-middleware/handlers/get-provider-state.js +++ /dev/null @@ -1,49 +0,0 @@ -import { MESSAGE_TYPE } from '../../../../../shared/constants/app'; - -/** - * This RPC method gets background state relevant to the provider. - * The background sends RPC notifications on state changes, but the provider - * first requests state on initialization. - */ - -const getProviderState = { - methodNames: [MESSAGE_TYPE.GET_PROVIDER_STATE], - implementation: getProviderStateHandler, - hookNames: { - getProviderState: true, - }, -}; -export default getProviderState; - -/** - * @typedef {object} ProviderStateHandlerResult - * @property {string} chainId - The current chain ID. - * @property {boolean} isUnlocked - Whether the extension is unlocked or not. - * @property {string} networkVersion - The current network ID. - */ - -/** - * @typedef {object} ProviderStateHandlerOptions - * @property {() => ProviderStateHandlerResult} getProviderState - A function that - * gets the current provider state. - */ - -/** - * @param {import('json-rpc-engine').JsonRpcRequest<[]>} req - The JSON-RPC request object. - * @param {import('json-rpc-engine').JsonRpcResponse} res - The JSON-RPC response object. - * @param {Function} _next - The json-rpc-engine 'next' callback. - * @param {Function} end - The json-rpc-engine 'end' callback. - * @param {ProviderStateHandlerOptions} options - */ -async function getProviderStateHandler( - req, - res, - _next, - end, - { getProviderState: _getProviderState }, -) { - res.result = { - ...(await _getProviderState(req.origin)), - }; - return end(); -} diff --git a/app/scripts/lib/rpc-method-middleware/handlers/get-provider-state.test.ts b/app/scripts/lib/rpc-method-middleware/handlers/get-provider-state.test.ts new file mode 100644 index 000000000000..f3d76a09f5fc --- /dev/null +++ b/app/scripts/lib/rpc-method-middleware/handlers/get-provider-state.test.ts @@ -0,0 +1,56 @@ +import { PendingJsonRpcResponse } from '@metamask/utils'; +import { JsonRpcEngineEndCallback } from 'json-rpc-engine'; +import getProviderState, { + GetProviderState, + ProviderStateHandlerResult, +} from './get-provider-state'; +import { HandlerRequestType } from './types'; + +describe('getProviderState', () => { + let mockEnd: JsonRpcEngineEndCallback; + let mockGetProviderState: GetProviderState; + + beforeEach(() => { + mockEnd = jest.fn(); + mockGetProviderState = jest.fn().mockResolvedValue({ + chainId: '0x539', + isUnlocked: true, + networkVersion: '', + accounts: [], + }); + }); + + it('should call getProviderState when the handler is invoked', async () => { + const req: HandlerRequestType = { + origin: 'testOrigin', + params: [], + id: '22', + jsonrpc: '2.0', + method: 'metamask_getProviderState', + }; + + const res: PendingJsonRpcResponse = { + id: '22', + jsonrpc: '2.0', + result: { + chainId: '0x539', + isUnlocked: true, + networkVersion: '', + accounts: [], + }, + }; + + await getProviderState.implementation(req, res, jest.fn(), mockEnd, { + getProviderState: mockGetProviderState, + }); + + expect(mockGetProviderState).toHaveBeenCalledWith(req.origin); + expect(res.result).toStrictEqual({ + chainId: '0x539', + isUnlocked: true, + networkVersion: '', + accounts: [], + }); + expect(mockEnd).toHaveBeenCalled(); + }); +}); diff --git a/app/scripts/lib/rpc-method-middleware/handlers/get-provider-state.ts b/app/scripts/lib/rpc-method-middleware/handlers/get-provider-state.ts new file mode 100644 index 000000000000..530b48b25164 --- /dev/null +++ b/app/scripts/lib/rpc-method-middleware/handlers/get-provider-state.ts @@ -0,0 +1,81 @@ +import type { + JsonRpcEngineNextCallback, + JsonRpcEngineEndCallback, +} from 'json-rpc-engine'; +import type { + PendingJsonRpcResponse, + JsonRpcParams, + Hex, +} from '@metamask/utils'; +import { OriginString } from '@metamask/permission-controller'; +import { MESSAGE_TYPE } from '../../../../../shared/constants/app'; +import { + HandlerWrapper, + HandlerRequestType as ProviderStateHandlerRequest, +} from './types'; + +/** + * @property chainId - The current chain ID. + * @property isUnlocked - Whether the extension is unlocked or not. + * @property networkVersion - The current network ID. + * @property accounts - List of permitted accounts for the specified origin. + */ +export type ProviderStateHandlerResult = { + chainId: Hex; + isUnlocked: boolean; + networkVersion: string; + accounts: string[]; +}; + +export type GetProviderState = ( + origin: OriginString, +) => Promise; + +type GetProviderStateConstraint = + { + implementation: ( + _req: ProviderStateHandlerRequest, + res: PendingJsonRpcResponse, + _next: JsonRpcEngineNextCallback, + end: JsonRpcEngineEndCallback, + { _getProviderState }: Record, + ) => Promise; + } & HandlerWrapper; + +/** + * This RPC method gets background state relevant to the provider. + * The background sends RPC notifications on state changes, but the provider + * first requests state on initialization. + */ +const getProviderState = { + methodNames: [MESSAGE_TYPE.GET_PROVIDER_STATE], + implementation: getProviderStateHandler, + hookNames: { + getProviderState: true, + }, +} satisfies GetProviderStateConstraint; + +export default getProviderState; + +/** + * @param req - The JSON-RPC request object. + * @param res - The JSON-RPC response object. + * @param _next - The json-rpc-engine 'next' callback. + * @param end - The json-rpc-engine 'end' callback. + * @param options + * @param options.getProviderState - An async function that gets the current provider state. + */ +async function getProviderStateHandler< + Params extends JsonRpcParams = JsonRpcParams, +>( + req: ProviderStateHandlerRequest, + res: PendingJsonRpcResponse, + _next: JsonRpcEngineNextCallback, + end: JsonRpcEngineEndCallback, + { getProviderState: _getProviderState }: Record, +): Promise { + res.result = { + ...(await _getProviderState(req.origin)), + }; + return end(); +} diff --git a/app/scripts/lib/rpc-method-middleware/handlers/types.ts b/app/scripts/lib/rpc-method-middleware/handlers/types.ts index 5b7a2a7494d4..46ceef442ec2 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/types.ts +++ b/app/scripts/lib/rpc-method-middleware/handlers/types.ts @@ -1,6 +1,13 @@ +import { OriginString } from '@metamask/permission-controller'; +import { JsonRpcParams, JsonRpcRequest } from '@metamask/utils'; import { MessageType } from '../../../../../shared/constants/app'; export type HandlerWrapper = { methodNames: [MessageType] | MessageType[]; hookNames: Record; }; + +export type HandlerRequestType = + Required> & { + origin: OriginString; + }; diff --git a/app/scripts/lib/snap-keyring/account-watcher-snap.ts b/app/scripts/lib/snap-keyring/account-watcher-snap.ts index 3775dcd28405..48ace4e595af 100644 --- a/app/scripts/lib/snap-keyring/account-watcher-snap.ts +++ b/app/scripts/lib/snap-keyring/account-watcher-snap.ts @@ -1,3 +1,4 @@ +// BEGIN:ONLY_INCLUDE_IF(build-flask) import { SnapId } from '@metamask/snaps-sdk'; import AccountWatcherSnap from '@metamask/account-watcher/dist/preinstalled-snap.json'; @@ -6,3 +7,4 @@ export const ACCOUNT_WATCHER_SNAP_ID: SnapId = export const ACCOUNT_WATCHER_NAME: string = AccountWatcherSnap.manifest.proposedName; +// END:ONLY_INCLUDE_IF diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index c03b8802e22f..63fd6a1610f5 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -3275,10 +3275,12 @@ export default class MetamaskController extends EventEmitter { preferencesController, ), ///: END:ONLY_INCLUDE_IF + ///: BEGIN:ONLY_INCLUDE_IF(build-flask) setWatchEthereumAccountEnabled: preferencesController.setWatchEthereumAccountEnabled.bind( preferencesController, ), + ///: END:ONLY_INCLUDE_IF setBitcoinSupportEnabled: preferencesController.setBitcoinSupportEnabled.bind( preferencesController, diff --git a/app/scripts/migrations/128.test.ts b/app/scripts/migrations/128.test.ts new file mode 100644 index 000000000000..f2658bfc6bd9 --- /dev/null +++ b/app/scripts/migrations/128.test.ts @@ -0,0 +1,39 @@ +import { migrate, version } from './128'; + +const oldVersion = 127; + +describe(`migration #${version}`, () => { + it('updates the version metadata', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: {}, + }; + + const newStorage = await migrate(oldStorage); + + expect(newStorage.meta).toStrictEqual({ version }); + }); + + it('Removes useNativeCurrencyAsPrimaryCurrency from the PreferencesController.preferences state', async () => { + const oldState = { + PreferencesController: { + preferences: { + hideZeroBalanceTokens: false, + showTestNetworks: true, + useNativeCurrencyAsPrimaryCurrency: true, + }, + }, + }; + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: oldState, + }); + + delete ( + oldState.PreferencesController.preferences as { + useNativeCurrencyAsPrimaryCurrency?: boolean; + } + ).useNativeCurrencyAsPrimaryCurrency; + expect(transformedState.data).toStrictEqual(oldState); + }); +}); diff --git a/app/scripts/migrations/128.ts b/app/scripts/migrations/128.ts new file mode 100644 index 000000000000..89f14606af7f --- /dev/null +++ b/app/scripts/migrations/128.ts @@ -0,0 +1,42 @@ +import { hasProperty, isObject } from '@metamask/utils'; +import { cloneDeep } from 'lodash'; + +type VersionedData = { + meta: { version: number }; + data: Record; +}; + +export const version = 128; + +/** + * This migration removes `useNativeCurrencyAsPrimaryCurrency` from preferences in PreferencesController. + * + * @param originalVersionedData - Versioned MetaMask extension state, exactly what we persist to dist. + * @param originalVersionedData.meta - State metadata. + * @param originalVersionedData.meta.version - The current state version. + * @param originalVersionedData.data - The persisted MetaMask state, keyed by controller. + * @returns Updated versioned MetaMask extension state. + */ +export async function migrate( + originalVersionedData: VersionedData, +): Promise { + const versionedData = cloneDeep(originalVersionedData); + versionedData.meta.version = version; + transformState(versionedData.data); + return versionedData; +} + +function transformState( + state: Record, +): Record { + if ( + hasProperty(state, 'PreferencesController') && + isObject(state.PreferencesController) && + isObject(state.PreferencesController.preferences) + ) { + delete state.PreferencesController.preferences + .useNativeCurrencyAsPrimaryCurrency; + } + + return state; +} diff --git a/app/scripts/migrations/129.test.ts b/app/scripts/migrations/129.test.ts new file mode 100644 index 000000000000..740add0e7e4e --- /dev/null +++ b/app/scripts/migrations/129.test.ts @@ -0,0 +1,60 @@ +import { migrate, version } from './129'; + +const oldVersion = 128; + +describe(`migration #${version}`, () => { + it('updates the version metadata', async () => { + const oldStorage = { + meta: { version: oldVersion }, + data: {}, + }; + + const newStorage = await migrate(oldStorage); + + expect(newStorage.meta).toStrictEqual({ version }); + }); + + it('Adds shouldShowAggregatedBalancePopover to the PreferencesController.preferences state when its undefined', async () => { + const oldState = { + PreferencesController: { + preferences: { + hideZeroBalanceTokens: false, + showTestNetworks: true, + }, + }, + }; + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: oldState, + }); + + expect(transformedState.data).toStrictEqual({ + ...oldState, + PreferencesController: { + ...oldState.PreferencesController, + preferences: { + ...oldState.PreferencesController.preferences, + shouldShowAggregatedBalancePopover: true, + }, + }, + }); + }); + + it('Does not add shouldShowAggregatedBalancePopover to the PreferencesController.preferences state when its defined', async () => { + const oldState = { + PreferencesController: { + preferences: { + hideZeroBalanceTokens: false, + showTestNetworks: true, + shouldShowAggregatedBalancePopover: false, + }, + }, + }; + const transformedState = await migrate({ + meta: { version: oldVersion }, + data: oldState, + }); + + expect(transformedState.data).toStrictEqual(oldState); + }); +}); diff --git a/app/scripts/migrations/129.ts b/app/scripts/migrations/129.ts new file mode 100644 index 000000000000..b4323798a006 --- /dev/null +++ b/app/scripts/migrations/129.ts @@ -0,0 +1,47 @@ +import { hasProperty, isObject } from '@metamask/utils'; +import { cloneDeep } from 'lodash'; + +type VersionedData = { + meta: { version: number }; + data: Record; +}; + +export const version = 129; + +/** + * This migration adds `shouldShowAggregatedBalancePopover` to preferences in PreferencesController and set it to true when its undefined. + * + * @param originalVersionedData - Versioned MetaMask extension state, exactly what we persist to dist. + * @param originalVersionedData.meta - State metadata. + * @param originalVersionedData.meta.version - The current state version. + * @param originalVersionedData.data - The persisted MetaMask state, keyed by controller. + * @returns Updated versioned MetaMask extension state. + */ +export async function migrate( + originalVersionedData: VersionedData, +): Promise { + const versionedData = cloneDeep(originalVersionedData); + versionedData.meta.version = version; + transformState(versionedData.data); + return versionedData; +} + +function transformState( + state: Record, +): Record { + if ( + hasProperty(state, 'PreferencesController') && + isObject(state.PreferencesController) && + isObject(state.PreferencesController.preferences) + ) { + if ( + state.PreferencesController.preferences + .shouldShowAggregatedBalancePopover === undefined + ) { + state.PreferencesController.preferences.shouldShowAggregatedBalancePopover = + true; + } + } + + return state; +} diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js index 80407ecf232e..296ff8077613 100644 --- a/app/scripts/migrations/index.js +++ b/app/scripts/migrations/index.js @@ -147,6 +147,8 @@ const migrations = [ require('./125.1'), require('./126'), require('./127'), + require('./128'), + require('./129'), ]; export default migrations; diff --git a/app/scripts/snaps/preinstalled-snaps.ts b/app/scripts/snaps/preinstalled-snaps.ts index 81755e98da2b..f46681ddab57 100644 --- a/app/scripts/snaps/preinstalled-snaps.ts +++ b/app/scripts/snaps/preinstalled-snaps.ts @@ -1,8 +1,8 @@ import type { PreinstalledSnap } from '@metamask/snaps-controllers'; import MessageSigningSnap from '@metamask/message-signing-snap/dist/preinstalled-snap.json'; import EnsResolverSnap from '@metamask/ens-resolver-snap/dist/preinstalled-snap.json'; -import AccountWatcherSnap from '@metamask/account-watcher/dist/preinstalled-snap.json'; ///: BEGIN:ONLY_INCLUDE_IF(build-flask) +import AccountWatcherSnap from '@metamask/account-watcher/dist/preinstalled-snap.json'; import BitcoinWalletSnap from '@metamask/bitcoin-wallet-snap/dist/preinstalled-snap.json'; import PreinstalledExampleSnap from '@metamask/preinstalled-example-snap/dist/preinstalled-snap.json'; ///: END:ONLY_INCLUDE_IF @@ -11,8 +11,8 @@ import PreinstalledExampleSnap from '@metamask/preinstalled-example-snap/dist/pr const PREINSTALLED_SNAPS = Object.freeze([ MessageSigningSnap as PreinstalledSnap, EnsResolverSnap as PreinstalledSnap, - AccountWatcherSnap as PreinstalledSnap, ///: BEGIN:ONLY_INCLUDE_IF(build-flask) + AccountWatcherSnap as PreinstalledSnap, BitcoinWalletSnap as unknown as PreinstalledSnap, PreinstalledExampleSnap as unknown as PreinstalledSnap, ///: END:ONLY_INCLUDE_IF diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 95835b028ee9..380e38cd7a63 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -2039,12 +2039,10 @@ "URL": true, "URLSearchParams": true, "addEventListener": true, - "clearInterval": true, "console.error": true, "dispatchEvent": true, "fetch": true, "removeEventListener": true, - "setInterval": true, "setTimeout": true }, "packages": { @@ -4511,6 +4509,14 @@ "define": true } }, + "history": { + "globals": { + "console": true, + "define": true, + "document.defaultView": true, + "document.querySelector": true + } + }, "https-browserify": { "packages": { "browserify>url": true, @@ -5088,37 +5094,59 @@ "react-router-dom>tiny-warning": true } }, - "react-router-dom>history": { + "react-router-dom-v5-compat": { "globals": { + "FormData": true, + "URL": true, + "URLSearchParams": true, + "__reactRouterVersion": "write", "addEventListener": true, "confirm": true, + "define": true, "document": true, - "history": true, - "location": true, - "navigator.userAgent": true, - "removeEventListener": true + "history.scrollRestoration": true, + "location.href": true, + "removeEventListener": true, + "scrollTo": true, + "scrollY": true, + "sessionStorage.getItem": true, + "sessionStorage.setItem": true, + "setTimeout": true }, "packages": { - "react-router-dom>history>resolve-pathname": true, - "react-router-dom>history>value-equal": true, - "react-router-dom>tiny-invariant": true, - "react-router-dom>tiny-warning": true + "history": true, + "react": true, + "react-dom": true, + "react-router-dom": true, + "react-router-dom-v5-compat>@remix-run/router": true, + "react-router-dom-v5-compat>react-router": true } }, - "react-router-dom>react-router": { + "react-router-dom-v5-compat>@remix-run/router": { + "globals": { + "AbortController": true, + "DOMException": true, + "FormData": true, + "Headers": true, + "Request": true, + "Response": true, + "URL": true, + "URLSearchParams": true, + "console": true, + "document.defaultView": true + } + }, + "react-router-dom-v5-compat>react-router": { + "globals": { + "console.error": true, + "define": true + }, "packages": { - "prop-types": true, - "prop-types>react-is": true, "react": true, - "react-redux>hoist-non-react-statics": true, - "react-router-dom>react-router>history": true, - "react-router-dom>react-router>mini-create-react-context": true, - "react-router-dom>tiny-invariant": true, - "react-router-dom>tiny-warning": true, - "serve-handler>path-to-regexp": true + "react-router-dom-v5-compat>@remix-run/router": true } }, - "react-router-dom>react-router>history": { + "react-router-dom>history": { "globals": { "addEventListener": true, "confirm": true, @@ -5135,13 +5163,16 @@ "react-router-dom>tiny-warning": true } }, - "react-router-dom>react-router>mini-create-react-context": { + "react-router-dom>react-router": { "packages": { - "@babel/runtime": true, "prop-types": true, + "prop-types>react-is": true, "react": true, - "react-router-dom>react-router>mini-create-react-context>gud": true, - "react-router-dom>tiny-warning": true + "react-redux>hoist-non-react-statics": true, + "react-router-dom>history": true, + "react-router-dom>tiny-invariant": true, + "react-router-dom>tiny-warning": true, + "serve-handler>path-to-regexp": true } }, "react-router-dom>tiny-warning": { diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index 95835b028ee9..380e38cd7a63 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -2039,12 +2039,10 @@ "URL": true, "URLSearchParams": true, "addEventListener": true, - "clearInterval": true, "console.error": true, "dispatchEvent": true, "fetch": true, "removeEventListener": true, - "setInterval": true, "setTimeout": true }, "packages": { @@ -4511,6 +4509,14 @@ "define": true } }, + "history": { + "globals": { + "console": true, + "define": true, + "document.defaultView": true, + "document.querySelector": true + } + }, "https-browserify": { "packages": { "browserify>url": true, @@ -5088,37 +5094,59 @@ "react-router-dom>tiny-warning": true } }, - "react-router-dom>history": { + "react-router-dom-v5-compat": { "globals": { + "FormData": true, + "URL": true, + "URLSearchParams": true, + "__reactRouterVersion": "write", "addEventListener": true, "confirm": true, + "define": true, "document": true, - "history": true, - "location": true, - "navigator.userAgent": true, - "removeEventListener": true + "history.scrollRestoration": true, + "location.href": true, + "removeEventListener": true, + "scrollTo": true, + "scrollY": true, + "sessionStorage.getItem": true, + "sessionStorage.setItem": true, + "setTimeout": true }, "packages": { - "react-router-dom>history>resolve-pathname": true, - "react-router-dom>history>value-equal": true, - "react-router-dom>tiny-invariant": true, - "react-router-dom>tiny-warning": true + "history": true, + "react": true, + "react-dom": true, + "react-router-dom": true, + "react-router-dom-v5-compat>@remix-run/router": true, + "react-router-dom-v5-compat>react-router": true } }, - "react-router-dom>react-router": { + "react-router-dom-v5-compat>@remix-run/router": { + "globals": { + "AbortController": true, + "DOMException": true, + "FormData": true, + "Headers": true, + "Request": true, + "Response": true, + "URL": true, + "URLSearchParams": true, + "console": true, + "document.defaultView": true + } + }, + "react-router-dom-v5-compat>react-router": { + "globals": { + "console.error": true, + "define": true + }, "packages": { - "prop-types": true, - "prop-types>react-is": true, "react": true, - "react-redux>hoist-non-react-statics": true, - "react-router-dom>react-router>history": true, - "react-router-dom>react-router>mini-create-react-context": true, - "react-router-dom>tiny-invariant": true, - "react-router-dom>tiny-warning": true, - "serve-handler>path-to-regexp": true + "react-router-dom-v5-compat>@remix-run/router": true } }, - "react-router-dom>react-router>history": { + "react-router-dom>history": { "globals": { "addEventListener": true, "confirm": true, @@ -5135,13 +5163,16 @@ "react-router-dom>tiny-warning": true } }, - "react-router-dom>react-router>mini-create-react-context": { + "react-router-dom>react-router": { "packages": { - "@babel/runtime": true, "prop-types": true, + "prop-types>react-is": true, "react": true, - "react-router-dom>react-router>mini-create-react-context>gud": true, - "react-router-dom>tiny-warning": true + "react-redux>hoist-non-react-statics": true, + "react-router-dom>history": true, + "react-router-dom>tiny-invariant": true, + "react-router-dom>tiny-warning": true, + "serve-handler>path-to-regexp": true } }, "react-router-dom>tiny-warning": { diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 95835b028ee9..380e38cd7a63 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -2039,12 +2039,10 @@ "URL": true, "URLSearchParams": true, "addEventListener": true, - "clearInterval": true, "console.error": true, "dispatchEvent": true, "fetch": true, "removeEventListener": true, - "setInterval": true, "setTimeout": true }, "packages": { @@ -4511,6 +4509,14 @@ "define": true } }, + "history": { + "globals": { + "console": true, + "define": true, + "document.defaultView": true, + "document.querySelector": true + } + }, "https-browserify": { "packages": { "browserify>url": true, @@ -5088,37 +5094,59 @@ "react-router-dom>tiny-warning": true } }, - "react-router-dom>history": { + "react-router-dom-v5-compat": { "globals": { + "FormData": true, + "URL": true, + "URLSearchParams": true, + "__reactRouterVersion": "write", "addEventListener": true, "confirm": true, + "define": true, "document": true, - "history": true, - "location": true, - "navigator.userAgent": true, - "removeEventListener": true + "history.scrollRestoration": true, + "location.href": true, + "removeEventListener": true, + "scrollTo": true, + "scrollY": true, + "sessionStorage.getItem": true, + "sessionStorage.setItem": true, + "setTimeout": true }, "packages": { - "react-router-dom>history>resolve-pathname": true, - "react-router-dom>history>value-equal": true, - "react-router-dom>tiny-invariant": true, - "react-router-dom>tiny-warning": true + "history": true, + "react": true, + "react-dom": true, + "react-router-dom": true, + "react-router-dom-v5-compat>@remix-run/router": true, + "react-router-dom-v5-compat>react-router": true } }, - "react-router-dom>react-router": { + "react-router-dom-v5-compat>@remix-run/router": { + "globals": { + "AbortController": true, + "DOMException": true, + "FormData": true, + "Headers": true, + "Request": true, + "Response": true, + "URL": true, + "URLSearchParams": true, + "console": true, + "document.defaultView": true + } + }, + "react-router-dom-v5-compat>react-router": { + "globals": { + "console.error": true, + "define": true + }, "packages": { - "prop-types": true, - "prop-types>react-is": true, "react": true, - "react-redux>hoist-non-react-statics": true, - "react-router-dom>react-router>history": true, - "react-router-dom>react-router>mini-create-react-context": true, - "react-router-dom>tiny-invariant": true, - "react-router-dom>tiny-warning": true, - "serve-handler>path-to-regexp": true + "react-router-dom-v5-compat>@remix-run/router": true } }, - "react-router-dom>react-router>history": { + "react-router-dom>history": { "globals": { "addEventListener": true, "confirm": true, @@ -5135,13 +5163,16 @@ "react-router-dom>tiny-warning": true } }, - "react-router-dom>react-router>mini-create-react-context": { + "react-router-dom>react-router": { "packages": { - "@babel/runtime": true, "prop-types": true, + "prop-types>react-is": true, "react": true, - "react-router-dom>react-router>mini-create-react-context>gud": true, - "react-router-dom>tiny-warning": true + "react-redux>hoist-non-react-statics": true, + "react-router-dom>history": true, + "react-router-dom>tiny-invariant": true, + "react-router-dom>tiny-warning": true, + "serve-handler>path-to-regexp": true } }, "react-router-dom>tiny-warning": { diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index 8c60013092de..576041b08cfb 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -2131,12 +2131,10 @@ "URL": true, "URLSearchParams": true, "addEventListener": true, - "clearInterval": true, "console.error": true, "dispatchEvent": true, "fetch": true, "removeEventListener": true, - "setInterval": true, "setTimeout": true }, "packages": { @@ -4603,6 +4601,14 @@ "define": true } }, + "history": { + "globals": { + "console": true, + "define": true, + "document.defaultView": true, + "document.querySelector": true + } + }, "https-browserify": { "packages": { "browserify>url": true, @@ -5156,37 +5162,59 @@ "react-router-dom>tiny-warning": true } }, - "react-router-dom>history": { + "react-router-dom-v5-compat": { "globals": { + "FormData": true, + "URL": true, + "URLSearchParams": true, + "__reactRouterVersion": "write", "addEventListener": true, "confirm": true, + "define": true, "document": true, - "history": true, - "location": true, - "navigator.userAgent": true, - "removeEventListener": true + "history.scrollRestoration": true, + "location.href": true, + "removeEventListener": true, + "scrollTo": true, + "scrollY": true, + "sessionStorage.getItem": true, + "sessionStorage.setItem": true, + "setTimeout": true }, "packages": { - "react-router-dom>history>resolve-pathname": true, - "react-router-dom>history>value-equal": true, - "react-router-dom>tiny-invariant": true, - "react-router-dom>tiny-warning": true + "history": true, + "react": true, + "react-dom": true, + "react-router-dom": true, + "react-router-dom-v5-compat>@remix-run/router": true, + "react-router-dom-v5-compat>react-router": true } }, - "react-router-dom>react-router": { + "react-router-dom-v5-compat>@remix-run/router": { + "globals": { + "AbortController": true, + "DOMException": true, + "FormData": true, + "Headers": true, + "Request": true, + "Response": true, + "URL": true, + "URLSearchParams": true, + "console": true, + "document.defaultView": true + } + }, + "react-router-dom-v5-compat>react-router": { + "globals": { + "console.error": true, + "define": true + }, "packages": { - "prop-types": true, - "prop-types>react-is": true, "react": true, - "react-redux>hoist-non-react-statics": true, - "react-router-dom>react-router>history": true, - "react-router-dom>react-router>mini-create-react-context": true, - "react-router-dom>tiny-invariant": true, - "react-router-dom>tiny-warning": true, - "serve-handler>path-to-regexp": true + "react-router-dom-v5-compat>@remix-run/router": true } }, - "react-router-dom>react-router>history": { + "react-router-dom>history": { "globals": { "addEventListener": true, "confirm": true, @@ -5203,13 +5231,16 @@ "react-router-dom>tiny-warning": true } }, - "react-router-dom>react-router>mini-create-react-context": { + "react-router-dom>react-router": { "packages": { - "@babel/runtime": true, "prop-types": true, + "prop-types>react-is": true, "react": true, - "react-router-dom>react-router>mini-create-react-context>gud": true, - "react-router-dom>tiny-warning": true + "react-redux>hoist-non-react-statics": true, + "react-router-dom>history": true, + "react-router-dom>tiny-invariant": true, + "react-router-dom>tiny-warning": true, + "serve-handler>path-to-regexp": true } }, "react-router-dom>tiny-warning": { diff --git a/package.json b/package.json index 86b0718ff463..6f378c0ee6a7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metamask-crx", - "version": "12.3.0", + "version": "12.3.1", "private": true, "repository": { "type": "git", @@ -344,7 +344,7 @@ "@metamask/post-message-stream": "^8.0.0", "@metamask/ppom-validator": "0.34.0", "@metamask/preinstalled-example-snap": "^0.1.0", - "@metamask/profile-sync-controller": "^0.9.3", + "@metamask/profile-sync-controller": "^0.9.4", "@metamask/providers": "^14.0.2", "@metamask/queued-request-controller": "^2.0.0", "@metamask/rate-limit-controller": "^6.0.0", @@ -397,6 +397,7 @@ "fast-json-patch": "^3.1.1", "fuse.js": "^3.2.0", "he": "^1.2.0", + "history": "^5.3.0", "human-standard-token-abi": "^2.0.0", "immer": "^9.0.6", "is-retry-allowed": "^2.2.0", @@ -426,7 +427,8 @@ "react-popper": "^2.2.3", "react-redux": "^7.2.9", "react-responsive-carousel": "^3.2.21", - "react-router-dom": "^5.1.2", + "react-router-dom": "^5.3.4", + "react-router-dom-v5-compat": "^6.26.2", "react-simple-file-input": "^2.0.0", "react-tippy": "^1.2.2", "react-toggle-button": "^2.2.0", @@ -603,7 +605,6 @@ "gulp-stylelint": "^13.0.0", "gulp-watch": "^5.0.1", "gulp-zip": "^5.1.0", - "history": "^5.0.0", "html-bundler-webpack-plugin": "^3.17.3", "https-browserify": "^1.0.0", "husky": "^8.0.3", diff --git a/shared/constants/metametrics.ts b/shared/constants/metametrics.ts index d9287da93a12..2eef3b55028c 100644 --- a/shared/constants/metametrics.ts +++ b/shared/constants/metametrics.ts @@ -446,9 +446,9 @@ export enum MetaMetricsUserTrait { */ TokenDetectionEnabled = 'token_detection_enabled', /** - * Identified when the user enables native currency. + * Identified when show native token as main balance is toggled. */ - UseNativeCurrencyAsPrimaryCurrency = 'use_native_currency_as_primary_currency', + ShowNativeTokenAsMainBalance = 'show_native_token_as_main_balance', /** * Identified when the security provider feature is enabled. */ @@ -632,12 +632,14 @@ export enum MetaMetricsEventName { TokenHidden = 'Token Hidden', TokenImportCanceled = 'Token Import Canceled', TokenImportClicked = 'Token Import Clicked', - UseNativeCurrencyAsPrimaryCurrency = 'Use Native Currency as Primary Currency', + ShowNativeTokenAsMainBalance = 'Show native token as main balance', WalletSetupStarted = 'Wallet Setup Selected', WalletSetupCanceled = 'Wallet Setup Canceled', WalletSetupFailed = 'Wallet Setup Failed', WalletCreated = 'Wallet Created', + // BEGIN:ONLY_INCLUDE_IF(build-flask) WatchEthereumAccountsToggled = 'Watch Ethereum Accounts Toggled', + // END:ONLY_INCLUDE_IF ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) DeeplinkClicked = 'Deeplink Clicked', ConnectCustodialAccountClicked = 'Connect Custodial Account Clicked', diff --git a/shared/lib/swaps-utils.js b/shared/lib/swaps-utils.js index d80d70902810..c51a3ac1198e 100644 --- a/shared/lib/swaps-utils.js +++ b/shared/lib/swaps-utils.js @@ -265,6 +265,7 @@ export async function fetchTradesInfo( value, fromAddress, exchangeList, + enableGasIncludedQuotes, }, { chainId }, ) { @@ -275,6 +276,7 @@ export async function fetchTradesInfo( slippage, timeout: SECOND * 10, walletAddress: fromAddress, + enableGasIncludedQuotes, }; if (exchangeList) { diff --git a/shared/lib/swaps-utils.test.js b/shared/lib/swaps-utils.test.js index 06080a8f55e7..891c1c5fb961 100644 --- a/shared/lib/swaps-utils.test.js +++ b/shared/lib/swaps-utils.test.js @@ -87,6 +87,7 @@ describe('Swaps Utils', () => { sourceDecimals: TOKENS[0].decimals, sourceTokenInfo: { ...TOKENS[0] }, destinationTokenInfo: { ...TOKENS[1] }, + enableGasIncludedQuotes: false, }, { chainId: CHAIN_IDS.MAINNET }, ); diff --git a/shared/modules/currency-display.utils.test.ts b/shared/modules/currency-display.utils.test.ts deleted file mode 100644 index b2fdbc456593..000000000000 --- a/shared/modules/currency-display.utils.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { - showPrimaryCurrency, - showSecondaryCurrency, -} from './currency-display.utils'; - -describe('showPrimaryCurrency', () => { - it('should return true when useNativeCurrencyAsPrimaryCurrency is true', () => { - const result = showPrimaryCurrency(true, true); - expect(result).toBe(true); - }); - - it('should return true when isOriginalNativeSymbol is true', () => { - const result = showPrimaryCurrency(true, false); - expect(result).toBe(true); - }); - - it('should return false when useNativeCurrencyAsPrimaryCurrency and isOriginalNativeSymbol are false', () => { - const result = showPrimaryCurrency(false, false); - expect(result).toBe(false); - }); -}); - -describe('showSecondaryCurrency', () => { - it('should return true when useNativeCurrencyAsPrimaryCurrency is false', () => { - const result = showSecondaryCurrency(true, false); - expect(result).toBe(true); - }); - - it('should return true when isOriginalNativeSymbol is true', () => { - const result = showSecondaryCurrency(true, true); - expect(result).toBe(true); - }); - - it('should return false when useNativeCurrencyAsPrimaryCurrency is true and isOriginalNativeSymbol is false', () => { - const result = showSecondaryCurrency(false, true); - expect(result).toBe(false); - }); -}); diff --git a/shared/modules/currency-display.utils.ts b/shared/modules/currency-display.utils.ts deleted file mode 100644 index 3f50a2364e6d..000000000000 --- a/shared/modules/currency-display.utils.ts +++ /dev/null @@ -1,31 +0,0 @@ -export const showPrimaryCurrency = ( - isOriginalNativeSymbol: boolean, - useNativeCurrencyAsPrimaryCurrency: boolean, -): boolean => { - // crypto is the primary currency in this case , so we have to display it always - if (useNativeCurrencyAsPrimaryCurrency) { - return true; - } - // if the primary currency corresponds to a fiat value, check that the symbol is correct. - if (isOriginalNativeSymbol) { - return true; - } - - return false; -}; - -export const showSecondaryCurrency = ( - isOriginalNativeSymbol: boolean, - useNativeCurrencyAsPrimaryCurrency: boolean, -): boolean => { - // crypto is the secondary currency in this case , so we have to display it always - if (!useNativeCurrencyAsPrimaryCurrency) { - return true; - } - // if the secondary currency corresponds to a fiat value, check that the symbol is correct. - if (isOriginalNativeSymbol) { - return true; - } - - return false; -}; diff --git a/shared/modules/metametrics.test.ts b/shared/modules/metametrics.test.ts index 93d423fb3d2d..9d6d17bc8040 100644 --- a/shared/modules/metametrics.test.ts +++ b/shared/modules/metametrics.test.ts @@ -72,6 +72,9 @@ const createTransactionMeta = () => { }, hash: txHash, error: null, + swapMetaData: { + gas_included: true, + }, }; }; @@ -107,6 +110,7 @@ describe('getSmartTransactionMetricsProperties', () => { ); expect(result).toStrictEqual({ + gas_included: true, is_smart_transaction: true, smart_transaction_duplicated: true, smart_transaction_proxied: true, @@ -132,7 +136,7 @@ describe('getSmartTransactionMetricsProperties', () => { }); }); - it('returns "is_smart_transaction: true" only if it is a smart transaction, but does not have statusMetadata', () => { + it('returns "is_smart_transaction" and "gas_included" params only if it is a smart transaction, but does not have statusMetadata', () => { const transactionMetricsRequest = createTransactionMetricsRequest({ getIsSmartTransaction: () => true, getSmartTransactionByMinedTxHash: () => { @@ -152,6 +156,7 @@ describe('getSmartTransactionMetricsProperties', () => { expect(result).toStrictEqual({ is_smart_transaction: true, + gas_included: true, }); }); }); diff --git a/shared/modules/metametrics.ts b/shared/modules/metametrics.ts index c60c7a0e44cd..b689891da1fb 100644 --- a/shared/modules/metametrics.ts +++ b/shared/modules/metametrics.ts @@ -5,6 +5,7 @@ import { TransactionMetricsRequest } from '../../app/scripts/lib/transaction/met type SmartTransactionMetricsProperties = { is_smart_transaction: boolean; + gas_included: boolean; smart_transaction_duplicated?: boolean; smart_transaction_timed_out?: boolean; smart_transaction_proxied?: boolean; @@ -21,6 +22,7 @@ export const getSmartTransactionMetricsProperties = ( if (!isSmartTransaction) { return properties; } + properties.gas_included = transactionMeta.swapMetaData?.gas_included; const smartTransaction = transactionMetricsRequest.getSmartTransactionByMinedTxHash( transactionMeta.hash, diff --git a/test/data/mock-send-state.json b/test/data/mock-send-state.json index 6629d8c6ac67..96cd95cfbd84 100644 --- a/test/data/mock-send-state.json +++ b/test/data/mock-send-state.json @@ -131,8 +131,7 @@ "preferences": { "hideZeroBalanceTokens": false, "showFiatInTestnets": false, - "showTestNetworks": true, - "useNativeCurrencyAsPrimaryCurrency": true + "showTestNetworks": true }, "seedPhraseBackedUp": null, "ensResolutionsByAddress": {}, diff --git a/test/data/mock-state.json b/test/data/mock-state.json index 4b6a2f506215..c2d18bcb76dc 100644 --- a/test/data/mock-state.json +++ b/test/data/mock-state.json @@ -367,12 +367,12 @@ "preferences": { "hideZeroBalanceTokens": false, "isRedesignedConfirmationsDeveloperEnabled": false, + "petnamesEnabled": false, "showExtensionInFullSizeView": false, "showFiatInTestnets": false, + "showNativeTokenAsMainBalance": true, "showTestNetworks": true, - "smartTransactionsOptInStatus": false, - "useNativeCurrencyAsPrimaryCurrency": true, - "petnamesEnabled": false + "smartTransactionsOptInStatus": false }, "ensResolutionsByAddress": {}, "isAccountMenuOpen": false, diff --git a/test/e2e/default-fixture.js b/test/e2e/default-fixture.js index 470e260ff959..4605e0bb0295 100644 --- a/test/e2e/default-fixture.js +++ b/test/e2e/default-fixture.js @@ -206,11 +206,12 @@ function defaultFixture(inputChainId = CHAIN_IDS.LOCALHOST) { showFiatInTestnets: false, showTestNetworks: false, smartTransactionsOptInStatus: false, - useNativeCurrencyAsPrimaryCurrency: true, + showNativeTokenAsMainBalance: true, petnamesEnabled: true, showMultiRpcModal: false, isRedesignedConfirmationsDeveloperEnabled: false, showConfirmationAdvancedDetails: false, + shouldShowAggregatedBalancePopover: true, }, selectedAddress: '0x5cfe73b6021e818b776b421b1c4db2474086a7e1', theme: 'light', diff --git a/test/e2e/fixture-builder.js b/test/e2e/fixture-builder.js index cc30c261d22d..edce958fab11 100644 --- a/test/e2e/fixture-builder.js +++ b/test/e2e/fixture-builder.js @@ -72,11 +72,12 @@ function onboardingFixture() { showFiatInTestnets: false, showTestNetworks: false, smartTransactionsOptInStatus: false, - useNativeCurrencyAsPrimaryCurrency: true, + showNativeTokenAsMainBalance: true, petnamesEnabled: true, showMultiRpcModal: false, isRedesignedConfirmationsDeveloperEnabled: false, showConfirmationAdvancedDetails: false, + shouldShowAggregatedBalancePopover: true, }, useExternalServices: true, theme: 'light', @@ -186,6 +187,14 @@ class FixtureBuilder { }); } + withShowFiatTestnetEnabled() { + return this.withPreferencesController({ + preferences: { + showFiatInTestnets: true, + }, + }); + } + withConversionRateEnabled() { return this.withPreferencesController({ useCurrencyRateCheck: true, @@ -594,6 +603,14 @@ class FixtureBuilder { }); } + withPreferencesControllerShowNativeTokenAsMainBalanceDisabled() { + return this.withPreferencesController({ + preferences: { + showNativeTokenAsMainBalance: false, + }, + }); + } + withPreferencesControllerTxSimulationsDisabled() { return this.withPreferencesController({ useTransactionSimulations: false, diff --git a/test/e2e/accounts/create-watch-account.spec.ts b/test/e2e/flask/create-watch-account.spec.ts similarity index 100% rename from test/e2e/accounts/create-watch-account.spec.ts rename to test/e2e/flask/create-watch-account.spec.ts diff --git a/test/e2e/page-objects/pages/header-navbar.ts b/test/e2e/page-objects/pages/header-navbar.ts index 742b37a5c48f..eb47cee791d9 100644 --- a/test/e2e/page-objects/pages/header-navbar.ts +++ b/test/e2e/page-objects/pages/header-navbar.ts @@ -9,6 +9,8 @@ class HeaderNavbar { private lockMetaMaskButton: string; + private mmiPortfolioButton: string; + private settingsButton: string; constructor(driver: Driver) { @@ -16,11 +18,16 @@ class HeaderNavbar { this.accountMenuButton = '[data-testid="account-menu-icon"]'; this.accountOptionMenu = '[data-testid="account-options-menu-button"]'; this.lockMetaMaskButton = '[data-testid="global-menu-lock"]'; + this.mmiPortfolioButton = '[data-testid="global-menu-mmi-portfolio"]'; this.settingsButton = '[data-testid="global-menu-settings"]'; } async lockMetaMask(): Promise { await this.driver.clickElement(this.accountOptionMenu); + // fix race condition with mmi build + if (process.env.MMI) { + await this.driver.waitForSelector(this.mmiPortfolioButton); + } await this.driver.clickElement(this.lockMetaMaskButton); } @@ -31,6 +38,10 @@ class HeaderNavbar { async openSettingsPage(): Promise { console.log('Open settings page'); await this.driver.clickElement(this.accountOptionMenu); + // fix race condition with mmi build + if (process.env.MMI) { + await this.driver.waitForSelector(this.mmiPortfolioButton); + } await this.driver.clickElement(this.settingsButton); } diff --git a/test/e2e/restore/MetaMaskUserData.json b/test/e2e/restore/MetaMaskUserData.json index 0f400e8a34e7..846acc8164cd 100644 --- a/test/e2e/restore/MetaMaskUserData.json +++ b/test/e2e/restore/MetaMaskUserData.json @@ -36,8 +36,7 @@ "showExtensionInFullSizeView": false, "showFiatInTestnets": false, "showTestNetworks": false, - "smartTransactionsOptInStatus": false, - "useNativeCurrencyAsPrimaryCurrency": true + "smartTransactionsOptInStatus": false }, "theme": "light", "useBlockie": false, diff --git a/test/e2e/tests/dapp-interactions/encrypt-decrypt.spec.js b/test/e2e/tests/dapp-interactions/encrypt-decrypt.spec.js index 2f595138d0cf..fbf11b16cd40 100644 --- a/test/e2e/tests/dapp-interactions/encrypt-decrypt.spec.js +++ b/test/e2e/tests/dapp-interactions/encrypt-decrypt.spec.js @@ -195,7 +195,9 @@ describe('Encrypt Decrypt', function () { ); }); - it('should show balance correctly as Fiat', async function () { + it('should show balance correctly in native tokens', async function () { + // In component ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.container.js, after removing useNativeCurrencyAsPrimaryCurrency; + // We will display native balance in the confirm-encryption-public-key.component.js await withFixtures( { dapp: true, @@ -203,7 +205,7 @@ describe('Encrypt Decrypt', function () { .withPermissionControllerConnectedToTestDapp() .withPreferencesController({ preferences: { - useNativeCurrencyAsPrimaryCurrency: false, + showNativeTokenAsMainBalance: false, }, }) .build(), @@ -231,7 +233,7 @@ describe('Encrypt Decrypt', function () { const accountBalanceLabel = await driver.findElement( '.request-encryption-public-key__balance-value', ); - assert.equal(await accountBalanceLabel.getText(), '$42,500.00 USD'); + assert.equal(await accountBalanceLabel.getText(), '25 ETH'); }, ); }); diff --git a/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-background-state.json b/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-background-state.json index c133de6128ca..a4c6ebe05c6d 100644 --- a/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-background-state.json +++ b/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-background-state.json @@ -211,12 +211,13 @@ "showFiatInTestnets": false, "showTestNetworks": false, "smartTransactionsOptInStatus": false, - "useNativeCurrencyAsPrimaryCurrency": true, + "showNativeTokenAsMainBalance": true, "petnamesEnabled": true, "isRedesignedConfirmationsDeveloperEnabled": "boolean", "redesignedConfirmationsEnabled": true, "redesignedTransactionsEnabled": "boolean", - "showMultiRpcModal": "boolean" + "showMultiRpcModal": "boolean", + "shouldShowAggregatedBalancePopover": "boolean" }, "ipfsGateway": "string", "isIpfsGatewayEnabled": "boolean", diff --git a/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-ui-state.json b/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-ui-state.json index dfee54fbd6cb..4ae178caa4a7 100644 --- a/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-ui-state.json +++ b/test/e2e/tests/metrics/state-snapshots/errors-after-init-opt-in-ui-state.json @@ -32,12 +32,13 @@ "showFiatInTestnets": false, "showTestNetworks": false, "smartTransactionsOptInStatus": false, - "useNativeCurrencyAsPrimaryCurrency": true, + "showNativeTokenAsMainBalance": true, "petnamesEnabled": true, "isRedesignedConfirmationsDeveloperEnabled": "boolean", "redesignedConfirmationsEnabled": true, "redesignedTransactionsEnabled": "boolean", - "showMultiRpcModal": "boolean" + "showMultiRpcModal": "boolean", + "shouldShowAggregatedBalancePopover": "boolean" }, "firstTimeFlowType": "import", "completedOnboarding": true, diff --git a/test/e2e/tests/metrics/state-snapshots/errors-before-init-opt-in-background-state.json b/test/e2e/tests/metrics/state-snapshots/errors-before-init-opt-in-background-state.json index b6354922add0..f21b237a1c46 100644 --- a/test/e2e/tests/metrics/state-snapshots/errors-before-init-opt-in-background-state.json +++ b/test/e2e/tests/metrics/state-snapshots/errors-before-init-opt-in-background-state.json @@ -112,11 +112,12 @@ "showFiatInTestnets": false, "showTestNetworks": false, "smartTransactionsOptInStatus": false, - "useNativeCurrencyAsPrimaryCurrency": true, + "showNativeTokenAsMainBalance": true, "petnamesEnabled": true, "showConfirmationAdvancedDetails": false, "isRedesignedConfirmationsDeveloperEnabled": "boolean", - "showMultiRpcModal": "boolean" + "showMultiRpcModal": "boolean", + "shouldShowAggregatedBalancePopover": "boolean" }, "selectedAddress": "string", "theme": "light", diff --git a/test/e2e/tests/metrics/state-snapshots/errors-before-init-opt-in-ui-state.json b/test/e2e/tests/metrics/state-snapshots/errors-before-init-opt-in-ui-state.json index 51910b2057a7..833584fd8c6d 100644 --- a/test/e2e/tests/metrics/state-snapshots/errors-before-init-opt-in-ui-state.json +++ b/test/e2e/tests/metrics/state-snapshots/errors-before-init-opt-in-ui-state.json @@ -112,11 +112,12 @@ "showFiatInTestnets": false, "showTestNetworks": false, "smartTransactionsOptInStatus": false, - "useNativeCurrencyAsPrimaryCurrency": true, + "showNativeTokenAsMainBalance": true, "petnamesEnabled": true, "showConfirmationAdvancedDetails": false, "isRedesignedConfirmationsDeveloperEnabled": "boolean", - "showMultiRpcModal": "boolean" + "showMultiRpcModal": "boolean", + "shouldShowAggregatedBalancePopover": "boolean" }, "selectedAddress": "string", "theme": "light", diff --git a/test/e2e/tests/settings/4byte-directory.spec.js b/test/e2e/tests/settings/4byte-directory.spec.js index 2874118c3a28..483ff1e0149a 100644 --- a/test/e2e/tests/settings/4byte-directory.spec.js +++ b/test/e2e/tests/settings/4byte-directory.spec.js @@ -1,12 +1,10 @@ -const { strict: assert } = require('assert'); const FixtureBuilder = require('../../fixture-builder'); const { - withFixtures, + logInWithBalanceValidation, openDapp, - unlockWallet, openMenuSafe, - largeDelayMs, - veryLargeDelayMs, + unlockWallet, + withFixtures, WINDOW_TITLES, } = require('../../helpers'); const { SMART_CONTRACTS } = require('../../seeder/smart-contracts'); @@ -27,27 +25,23 @@ describe('4byte setting', function () { const contractAddress = await contractRegistry.getContractAddress( smartContract, ); - await unlockWallet(driver); + await logInWithBalanceValidation(driver); // deploy contract await openDapp(driver, contractAddress); // wait for deployed contract, calls and confirms a contract method where ETH is sent - await driver.delay(largeDelayMs); await driver.clickElement('#depositButton'); - await driver.waitForSelector({ - css: 'span', - text: 'Deposit initiated', - }); - - await driver.waitUntilXWindowHandles(3); await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); - const actionElement = await driver.waitForSelector({ - css: '.confirm-page-container-summary__action__name', + await driver.waitForSelector({ + tag: 'span', text: 'Deposit', }); - assert.equal(await actionElement.getText(), 'DEPOSIT'); + await driver.assertElementNotPresent({ + tag: 'span', + text: 'Contract interaction', + }); }, ); }); @@ -83,28 +77,18 @@ describe('4byte setting', function () { await openDapp(driver, contractAddress); // wait for deployed contract, calls and confirms a contract method where ETH is sent - await driver.findClickableElement('#depositButton'); await driver.clickElement('#depositButton'); - await driver.waitForSelector({ - css: 'span', - text: 'Deposit initiated', - }); - - await driver.waitUntilXWindowHandles(3); await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); - const contractInteraction = 'Contract interaction'; - const actionElement = await driver.waitForSelector({ - css: '.confirm-page-container-summary__action__name', - text: contractInteraction, + + await driver.assertElementNotPresent({ + tag: 'span', + text: 'Deposit', + }); + await driver.waitForSelector({ + tag: 'span', + text: 'Contract interaction', }); - // We add a delay here to wait for any potential UI changes - await driver.delay(veryLargeDelayMs); - // css text-transform: uppercase is applied to the text - assert.equal( - await actionElement.getText(), - contractInteraction.toUpperCase(), - ); }, ); }); diff --git a/test/e2e/tests/settings/account-token-list.spec.js b/test/e2e/tests/settings/account-token-list.spec.js index 0fae71ae1d85..9e4822d0dbbc 100644 --- a/test/e2e/tests/settings/account-token-list.spec.js +++ b/test/e2e/tests/settings/account-token-list.spec.js @@ -3,6 +3,7 @@ const { withFixtures, defaultGanacheOptions, logInWithBalanceValidation, + unlockWallet, } = require('../../helpers'); const FixtureBuilder = require('../../fixture-builder'); @@ -41,26 +42,18 @@ describe('Settings', function () { it('Should match the value of token list item and account list item for fiat conversion', async function () { await withFixtures( { - fixtures: new FixtureBuilder().withConversionRateEnabled().build(), + fixtures: new FixtureBuilder() + .withConversionRateEnabled() + .withShowFiatTestnetEnabled() + .withPreferencesControllerShowNativeTokenAsMainBalanceDisabled() + .build(), ganacheOptions: defaultGanacheOptions, title: this.test.fullTitle(), }, - async ({ driver, ganacheServer }) => { - await logInWithBalanceValidation(driver, ganacheServer); - - await driver.clickElement( - '[data-testid="account-options-menu-button"]', - ); - await driver.clickElement({ text: 'Settings', tag: 'div' }); - await driver.clickElement({ - text: 'General', - tag: 'div', - }); - await driver.clickElement({ text: 'Fiat', tag: 'label' }); + async ({ driver }) => { + await unlockWallet(driver); - await driver.clickElement( - '.settings-page__header__title-container__close-button', - ); + await driver.clickElement('[data-testid="popover-close"]'); await driver.clickElement( '[data-testid="account-overview__asset-tab"]', ); @@ -70,7 +63,6 @@ describe('Settings', function () { ); await driver.delay(1000); assert.equal(await tokenListAmount.getText(), '$42,500.00\nUSD'); - await driver.clickElement('[data-testid="account-menu-icon"]'); const accountTokenValue = await driver.waitForSelector( '.multichain-account-list-item .multichain-account-list-item__asset', diff --git a/test/e2e/tests/settings/address-book.spec.js b/test/e2e/tests/settings/address-book.spec.js index c784ce3daa3b..e81bd7c544aa 100644 --- a/test/e2e/tests/settings/address-book.spec.js +++ b/test/e2e/tests/settings/address-book.spec.js @@ -5,6 +5,7 @@ const { withFixtures, logInWithBalanceValidation, openActionMenuAndStartSendFlow, + openMenuSafe, unlockWallet, } = require('../../helpers'); const { shortenAddress } = require('../../../../ui/helpers/utils/util'); @@ -92,10 +93,8 @@ describe('Address Book', function () { }, async ({ driver }) => { await unlockWallet(driver); + await openMenuSafe(driver); - await driver.clickElement( - '[data-testid="account-options-menu-button"]', - ); await driver.clickElement({ text: 'Settings', tag: 'div' }); await driver.clickElement({ text: 'Contacts', tag: 'div' }); await driver.clickElement({ @@ -159,9 +158,8 @@ describe('Address Book', function () { async ({ driver }) => { await unlockWallet(driver); - await driver.clickElement( - '[data-testid="account-options-menu-button"]', - ); + await openMenuSafe(driver); + await driver.clickElement({ text: 'Settings', tag: 'div' }); await driver.clickElement({ text: 'Contacts', tag: 'div' }); diff --git a/test/e2e/tests/settings/auto-lock.spec.js b/test/e2e/tests/settings/auto-lock.spec.js index bded29fa5f39..7d7a159d4a1b 100644 --- a/test/e2e/tests/settings/auto-lock.spec.js +++ b/test/e2e/tests/settings/auto-lock.spec.js @@ -1,8 +1,9 @@ const { strict: assert } = require('assert'); const { defaultGanacheOptions, - withFixtures, + openMenuSafe, unlockWallet, + withFixtures, } = require('../../helpers'); const FixtureBuilder = require('../../fixture-builder'); @@ -17,9 +18,7 @@ describe('Auto-Lock Timer', function () { async ({ driver }) => { await unlockWallet(driver); // Set Auto Lock Timer - await driver.clickElement( - '[data-testid="account-options-menu-button"]', - ); + await openMenuSafe(driver); await driver.clickElement({ text: 'Settings', tag: 'div' }); await driver.clickElement({ text: 'Advanced', tag: 'div' }); const sixSecsInMins = '0.1'; diff --git a/test/e2e/tests/settings/backup-restore.spec.js b/test/e2e/tests/settings/backup-restore.spec.js index 02a36b638884..41186e70cd23 100644 --- a/test/e2e/tests/settings/backup-restore.spec.js +++ b/test/e2e/tests/settings/backup-restore.spec.js @@ -2,10 +2,11 @@ const { strict: assert } = require('assert'); const { promises: fs } = require('fs'); const { - defaultGanacheOptions, - withFixtures, createDownloadFolder, + defaultGanacheOptions, + openMenuSafe, unlockWallet, + withFixtures, } = require('../../helpers'); const FixtureBuilder = require('../../fixture-builder'); @@ -31,10 +32,10 @@ const getBackupJson = async () => { try { const backup = `${downloadsFolder}/${userDataFileName}`; - await fs.access(backup); const contents = await fs.readFile(backup); return JSON.parse(contents.toString()); } catch (e) { + console.log('Error reading the backup file', e); return null; } }; @@ -56,9 +57,8 @@ describe('Backup and Restore', function () { await unlockWallet(driver); // Download user settings - await driver.clickElement( - '[data-testid="account-options-menu-button"]', - ); + await openMenuSafe(driver); + await driver.clickElement({ text: 'Settings', tag: 'div' }); await driver.clickElement({ text: 'Advanced', tag: 'div' }); await driver.clickElement('[data-testid="export-data-button"]'); diff --git a/test/e2e/tests/settings/change-language.spec.ts b/test/e2e/tests/settings/change-language.spec.ts index aafb36059c9b..1bd9915a33da 100644 --- a/test/e2e/tests/settings/change-language.spec.ts +++ b/test/e2e/tests/settings/change-language.spec.ts @@ -16,8 +16,8 @@ const selectors = { ethOverviewSend: '[data-testid="eth-overview-send"]', ensInput: '[data-testid="ens-input"]', nftsTab: '[data-testid="account-overview__nfts-tab"]', - labelSpanish: { tag: 'span', text: 'Idioma actual' }, - currentLanguageLabel: { tag: 'span', text: 'Current language' }, + labelSpanish: { tag: 'p', text: 'Idioma actual' }, + currentLanguageLabel: { tag: 'p', text: 'Current language' }, advanceText: { text: 'Avanceret', tag: 'div' }, waterText: '[placeholder="Søg"]', headerTextDansk: { text: 'Indstillinger', tag: 'h3' }, diff --git a/test/e2e/tests/settings/clear-activity.spec.js b/test/e2e/tests/settings/clear-activity.spec.js index 34a23aecb173..781363bf42d3 100644 --- a/test/e2e/tests/settings/clear-activity.spec.js +++ b/test/e2e/tests/settings/clear-activity.spec.js @@ -1,8 +1,9 @@ const { strict: assert } = require('assert'); const { defaultGanacheOptions, - withFixtures, + openMenuSafe, unlockWallet, + withFixtures, } = require('../../helpers'); const FixtureBuilder = require('../../fixture-builder'); @@ -38,9 +39,8 @@ describe('Clear account activity', function () { }); // Clear activity and nonce data - await driver.clickElement( - '[data-testid="account-options-menu-button"]', - ); + await openMenuSafe(driver); + await driver.clickElement({ text: 'Settings', tag: 'div' }); await driver.clickElement({ text: 'Advanced', tag: 'div' }); await driver.clickElement({ diff --git a/test/e2e/tests/settings/ipfs-ens-resolution.spec.js b/test/e2e/tests/settings/ipfs-ens-resolution.spec.js index e706a3f41e31..450ec649d809 100644 --- a/test/e2e/tests/settings/ipfs-ens-resolution.spec.js +++ b/test/e2e/tests/settings/ipfs-ens-resolution.spec.js @@ -1,4 +1,9 @@ -const { withFixtures, tinyDelayMs, unlockWallet } = require('../../helpers'); +const { + openMenuSafe, + tinyDelayMs, + unlockWallet, + withFixtures, +} = require('../../helpers'); const FixtureBuilder = require('../../fixture-builder'); describe('Settings', function () { @@ -64,9 +69,8 @@ describe('Settings', function () { await unlockWallet(driver); // goes to the settings screen - await driver.clickElement( - '[data-testid="account-options-menu-button"]', - ); + await openMenuSafe(driver); + await driver.clickElement({ text: 'Settings', tag: 'div' }); await driver.clickElement({ text: 'Security & privacy', tag: 'div' }); diff --git a/test/e2e/tests/settings/ipfs-toggle.spec.js b/test/e2e/tests/settings/ipfs-toggle.spec.js index 045c51496853..cd078b587d54 100644 --- a/test/e2e/tests/settings/ipfs-toggle.spec.js +++ b/test/e2e/tests/settings/ipfs-toggle.spec.js @@ -1,8 +1,9 @@ const { strict: assert } = require('assert'); const { - withFixtures, defaultGanacheOptions, + openMenuSafe, unlockWallet, + withFixtures, } = require('../../helpers'); const FixtureBuilder = require('../../fixture-builder'); const { SMART_CONTRACTS } = require('../../seeder/smart-contracts'); @@ -20,10 +21,8 @@ describe('Settings', function () { }, async ({ driver }) => { await unlockWallet(driver); + await openMenuSafe(driver); - await driver.clickElement( - '[data-testid="account-options-menu-button"]', - ); await driver.clickElement({ text: 'Settings', tag: 'div' }); await driver.clickElement({ text: 'Security & privacy', tag: 'div' }); diff --git a/test/e2e/tests/settings/localization.spec.js b/test/e2e/tests/settings/localization.spec.js index 707cc120e578..57dbfd5f68cf 100644 --- a/test/e2e/tests/settings/localization.spec.js +++ b/test/e2e/tests/settings/localization.spec.js @@ -17,6 +17,7 @@ describe('Localization', function () { .withPreferencesController({ preferences: { showFiatInTestnets: true, + showNativeTokenAsMainBalance: false, }, }) .build(), @@ -26,15 +27,13 @@ describe('Localization', function () { async ({ driver }) => { await unlockWallet(driver); - const secondaryBalance = await driver.findElement( - '[data-testid="eth-overview__secondary-currency"]', + // After the removal of displaying secondary currency in coin-overview.tsx, we will test localization on main balance with showNativeTokenAsMainBalance = false + const primaryBalance = await driver.findElement( + '[data-testid="eth-overview__primary-currency"]', ); - const secondaryBalanceText = await secondaryBalance.getText(); - const [fiatAmount, fiatUnit] = secondaryBalanceText - .trim() - .split(/\s+/u); - assert.ok(fiatAmount.startsWith('₱')); - assert.equal(fiatUnit, 'PHP'); + const balanceText = await primaryBalance.getText(); + assert.ok(balanceText.startsWith('₱')); + assert.ok(balanceText.endsWith('PHP')); }, ); }); diff --git a/test/e2e/tests/settings/settings-general.spec.js b/test/e2e/tests/settings/settings-general.spec.js index dafe32ba9bea..5e75c857a7f8 100644 --- a/test/e2e/tests/settings/settings-general.spec.js +++ b/test/e2e/tests/settings/settings-general.spec.js @@ -1,8 +1,9 @@ const { strict: assert } = require('assert'); const { defaultGanacheOptions, - withFixtures, + openMenuSafe, unlockWallet, + withFixtures, } = require('../../helpers'); const FixtureBuilder = require('../../fixture-builder'); @@ -18,9 +19,8 @@ describe('Settings', function () { await unlockWallet(driver); // goes to the settings screen - await driver.clickElement( - '[data-testid="account-options-menu-button"]', - ); + await openMenuSafe(driver); + await driver.clickElement({ text: 'Settings', tag: 'div' }); // finds the jazzicon toggle turned on diff --git a/test/e2e/tests/settings/settings-search.spec.js b/test/e2e/tests/settings/settings-search.spec.js index 7a9207dcbf9f..fb67fbffd23b 100644 --- a/test/e2e/tests/settings/settings-search.spec.js +++ b/test/e2e/tests/settings/settings-search.spec.js @@ -9,7 +9,7 @@ const FixtureBuilder = require('../../fixture-builder'); describe('Settings Search', function () { const settingsSearch = { - general: 'Primary currency', + general: 'Show native token as main balance', advanced: 'State logs', contacts: 'Contacts', security: 'Reveal Secret', diff --git a/test/e2e/tests/settings/show-native-as-main-balance.spec.ts b/test/e2e/tests/settings/show-native-as-main-balance.spec.ts new file mode 100644 index 000000000000..d81e590cc5db --- /dev/null +++ b/test/e2e/tests/settings/show-native-as-main-balance.spec.ts @@ -0,0 +1,240 @@ +import { strict as assert } from 'assert'; +import { expect } from '@playwright/test'; +import { + withFixtures, + defaultGanacheOptions, + logInWithBalanceValidation, + unlockWallet, + getEventPayloads, +} from '../../helpers'; +import { MockedEndpoint, Mockttp } from '../../mock-e2e'; +import { Driver } from '../../webdriver/driver'; + +import FixtureBuilder from '../../fixture-builder'; + +async function mockSegment(mockServer: Mockttp) { + return [ + await mockServer + .forPost('https://api.segment.io/v1/batch') + .withJsonBodyIncluding({ + batch: [{ type: 'track', event: 'Show native token as main balance' }], + }) + .thenCallback(() => { + return { + statusCode: 200, + }; + }), + ]; +} + +describe('Settings: Show native token as main balance', function () { + it('Should show balance in crypto when toggle is on', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().withConversionRateDisabled().build(), + ganacheOptions: defaultGanacheOptions, + title: this.test?.fullTitle(), + }, + async ({ + driver, + ganacheServer, + }: { + driver: Driver; + ganacheServer: unknown; + }) => { + await logInWithBalanceValidation(driver, ganacheServer); + + await driver.clickElement( + '[data-testid="account-overview__asset-tab"]', + ); + const tokenValue = '25 ETH'; + const tokenListAmount = await driver.findElement( + '[data-testid="multichain-token-list-item-value"]', + ); + await driver.waitForNonEmptyElement(tokenListAmount); + assert.equal(await tokenListAmount.getText(), tokenValue); + }, + ); + }); + + it('Should show balance in fiat when toggle is OFF', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder() + .withConversionRateEnabled() + .withPreferencesControllerShowNativeTokenAsMainBalanceDisabled() + .build(), + ganacheOptions: defaultGanacheOptions, + title: this.test?.fullTitle(), + }, + async ({ driver }: { driver: Driver }) => { + await unlockWallet(driver); + + await driver.clickElement( + '[data-testid="account-options-menu-button"]', + ); + await driver.clickElement({ text: 'Settings', tag: 'div' }); + + await driver.clickElement({ + text: 'Advanced', + tag: 'div', + }); + await driver.clickElement('.show-fiat-on-testnets-toggle'); + + await driver.delay(1000); + + await driver.clickElement( + '.settings-page__header__title-container__close-button', + ); + // close popover + await driver.clickElement('[data-testid="popover-close"]'); + + await driver.clickElement( + '[data-testid="account-overview__asset-tab"]', + ); + + const tokenListAmount = await driver.findElement( + '.eth-overview__primary-container', + ); + assert.equal(await tokenListAmount.getText(), '$42,500.00\nUSD'); + }, + ); + }); + + it('Should not show popover twice', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder() + .withConversionRateEnabled() + .withPreferencesControllerShowNativeTokenAsMainBalanceDisabled() + .build(), + ganacheOptions: defaultGanacheOptions, + title: this.test?.fullTitle(), + }, + async ({ driver }: { driver: Driver }) => { + await unlockWallet(driver); + + await driver.clickElement( + '[data-testid="account-options-menu-button"]', + ); + await driver.clickElement({ text: 'Settings', tag: 'div' }); + + await driver.clickElement({ + text: 'Advanced', + tag: 'div', + }); + await driver.clickElement('.show-fiat-on-testnets-toggle'); + + await driver.delay(1000); + + await driver.clickElement( + '.settings-page__header__title-container__close-button', + ); + // close popover for the first time + await driver.clickElement('[data-testid="popover-close"]'); + // go to setting and back to home page and make sure popover is not shown again + await driver.clickElement( + '[data-testid="account-options-menu-button"]', + ); + await driver.clickElement({ text: 'Settings', tag: 'div' }); + // close setting + await driver.clickElement( + '.settings-page__header__title-container__close-button', + ); + // assert popover does not exist + await driver.assertElementNotPresent('[data-testid="popover-close"]'); + }, + ); + }); + + it('Should Successfully track the event when toggle is turned off', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder() + .withMetaMetricsController({ + metaMetricsId: 'fake-metrics-fd20', + participateInMetaMetrics: true, + }) + .build(), + defaultGanacheOptions, + title: this.test?.fullTitle(), + testSpecificMock: mockSegment, + }, + async ({ + driver, + mockedEndpoint: mockedEndpoints, + }: { + driver: Driver; + mockedEndpoint: MockedEndpoint[]; + }) => { + await unlockWallet(driver); + + await driver.clickElement( + '[data-testid="account-options-menu-button"]', + ); + + await driver.clickElement({ text: 'Settings', tag: 'div' }); + await driver.clickElement({ + text: 'General', + tag: 'div', + }); + await driver.clickElement('.show-native-token-as-main-balance'); + + const events = await getEventPayloads(driver, mockedEndpoints); + expect(events[0].properties).toMatchObject({ + show_native_token_as_main_balance: false, + category: 'Settings', + locale: 'en', + chain_id: '0x539', + environment_type: 'fullscreen', + }); + }, + ); + }); + + it('Should Successfully track the event when toggle is turned on', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder() + .withMetaMetricsController({ + metaMetricsId: 'fake-metrics-fd20', + participateInMetaMetrics: true, + }) + .withPreferencesControllerShowNativeTokenAsMainBalanceDisabled() + .build(), + defaultGanacheOptions, + title: this.test?.fullTitle(), + testSpecificMock: mockSegment, + }, + async ({ + driver, + mockedEndpoint: mockedEndpoints, + }: { + driver: Driver; + mockedEndpoint: MockedEndpoint[]; + }) => { + await unlockWallet(driver); + + await driver.clickElement( + '[data-testid="account-options-menu-button"]', + ); + + await driver.clickElement({ text: 'Settings', tag: 'div' }); + await driver.clickElement({ + text: 'General', + tag: 'div', + }); + await driver.clickElement('.show-native-token-as-main-balance'); + + const events = await getEventPayloads(driver, mockedEndpoints); + expect(events[0].properties).toMatchObject({ + show_native_token_as_main_balance: true, + category: 'Settings', + locale: 'en', + chain_id: '0x539', + environment_type: 'fullscreen', + }); + }, + ); + }); +}); diff --git a/test/e2e/tests/settings/state-logs.spec.js b/test/e2e/tests/settings/state-logs.spec.js index 07e9b4744900..3b9e568ee6bc 100644 --- a/test/e2e/tests/settings/state-logs.spec.js +++ b/test/e2e/tests/settings/state-logs.spec.js @@ -1,10 +1,11 @@ const { strict: assert } = require('assert'); const { promises: fs } = require('fs'); const { - defaultGanacheOptions, - withFixtures, createDownloadFolder, + defaultGanacheOptions, + openMenuSafe, unlockWallet, + withFixtures, } = require('../../helpers'); const FixtureBuilder = require('../../fixture-builder'); @@ -38,9 +39,8 @@ describe('State logs', function () { await unlockWallet(driver); // Download state logs - await driver.clickElement( - '[data-testid="account-options-menu-button"]', - ); + await openMenuSafe(driver); + await driver.clickElement({ text: 'Settings', tag: 'div' }); await driver.clickElement({ text: 'Advanced', tag: 'div' }); await driver.clickElement({ diff --git a/test/e2e/tests/tokens/nft/auto-detect-nft.spec.js b/test/e2e/tests/tokens/nft/auto-detect-nft.spec.js index 36b09723444b..ccd15ce0f71b 100644 --- a/test/e2e/tests/tokens/nft/auto-detect-nft.spec.js +++ b/test/e2e/tests/tokens/nft/auto-detect-nft.spec.js @@ -1,8 +1,9 @@ const { strict: assert } = require('assert'); const { - withFixtures, defaultGanacheOptions, + openMenuSafe, unlockWallet, + withFixtures, } = require('../../../helpers'); const FixtureBuilder = require('../../../fixture-builder'); const { setupAutoDetectMocking } = require('./mocks'); @@ -25,9 +26,8 @@ describe('NFT detection', function () { await unlockWallet(driver); // go to settings - await driver.clickElement( - '[data-testid="account-options-menu-button"]', - ); + await openMenuSafe(driver); + await driver.clickElement({ text: 'Settings', tag: 'div' }); await driver.clickElement({ text: 'Security & privacy', tag: 'div' }); await driver.clickElement( diff --git a/test/e2e/tests/transaction/send-eth.spec.js b/test/e2e/tests/transaction/send-eth.spec.js index 36872115dcbe..5cbcb8309a18 100644 --- a/test/e2e/tests/transaction/send-eth.spec.js +++ b/test/e2e/tests/transaction/send-eth.spec.js @@ -189,7 +189,9 @@ describe('Send ETH', function () { const balance = await driver.findElement( '[data-testid="eth-overview__primary-currency"]', ); + assert.ok(/^[\d.]+\sETH$/u.test(await balance.getText())); + await driver.clickElement( '[data-testid="account-overview__activity-tab"]', ); diff --git a/test/integration/confirmations/transactions/contract-deployment.test.tsx b/test/integration/confirmations/transactions/contract-deployment.test.tsx new file mode 100644 index 000000000000..ecef04f30861 --- /dev/null +++ b/test/integration/confirmations/transactions/contract-deployment.test.tsx @@ -0,0 +1,408 @@ +import { ApprovalType } from '@metamask/controller-utils'; +import { TransactionType } from '@metamask/transaction-controller'; +import { + act, + fireEvent, + screen, + waitFor, + within, +} from '@testing-library/react'; +import nock from 'nock'; +import { + MetaMetricsEventCategory, + MetaMetricsEventLocation, + MetaMetricsEventName, +} from '../../../../shared/constants/metametrics'; +import * as backgroundConnection from '../../../../ui/store/background-connection'; +import { tEn } from '../../../lib/i18n-helpers'; +import { integrationTestRender } from '../../../lib/render-helpers'; +import mockMetaMaskState from '../../data/integration-init-state.json'; +import { createMockImplementation, mock4byte } from '../../helpers'; +import { getUnapprovedContractDeploymentTransaction } from './transactionDataHelpers'; + +jest.mock('../../../../ui/store/background-connection', () => ({ + ...jest.requireActual('../../../../ui/store/background-connection'), + submitRequestToBackground: jest.fn(), + callBackgroundMethod: jest.fn(), +})); + +const mockedBackgroundConnection = jest.mocked(backgroundConnection); + +const backgroundConnectionMocked = { + onNotification: jest.fn(), +}; +export const pendingTransactionId = '48a75190-45ca-11ef-9001-f3886ec2397c'; +export const pendingTransactionTime = new Date().getTime(); + +const getMetaMaskStateWithUnapprovedContractDeployment = ({ + accountAddress, + showConfirmationAdvancedDetails = false, +}: { + accountAddress: string; + showConfirmationAdvancedDetails?: boolean; +}) => { + return { + ...mockMetaMaskState, + preferences: { + ...mockMetaMaskState.preferences, + redesignedConfirmationsEnabled: true, + showConfirmationAdvancedDetails, + }, + nextNonce: '8', + currencyRates: { + SepoliaETH: { + conversionDate: 1721392020.645, + conversionRate: 3404.13, + usdConversionRate: 3404.13, + }, + ETH: { + conversionDate: 1721393858.083, + conversionRate: 3414.67, + usdConversionRate: 3414.67, + }, + }, + currentCurrency: 'usd', + pendingApprovals: { + [pendingTransactionId]: { + id: pendingTransactionId, + origin: 'local:http://localhost:8086/', + time: pendingTransactionTime, + type: ApprovalType.Transaction, + requestData: { + txId: pendingTransactionId, + }, + requestState: null, + expectsResult: false, + }, + }, + pendingApprovalCount: 1, + knownMethodData: { + '0xd0e30db0': { + name: 'Deposit', + params: [ + { + type: 'uint256', + }, + ], + }, + }, + transactions: [ + getUnapprovedContractDeploymentTransaction( + accountAddress, + pendingTransactionId, + pendingTransactionTime, + ), + ], + }; +}; + +const advancedDetailsMockedRequests = { + getGasFeeTimeEstimate: { + lowerTimeBound: new Date().getTime(), + upperTimeBound: new Date().getTime(), + }, + getNextNonce: '9', + decodeTransactionData: { + data: [ + { + name: 'Deposit', + params: [ + { + name: 'numberOfTokens', + type: 'uint256', + value: 1, + }, + ], + }, + ], + source: 'Sourcify', + }, +}; + +const setupSubmitRequestToBackgroundMocks = ( + mockRequests?: Record, +) => { + mockedBackgroundConnection.submitRequestToBackground.mockImplementation( + createMockImplementation({ + ...advancedDetailsMockedRequests, + ...(mockRequests ?? {}), + }), + ); +}; + +describe('Contract Deployment Confirmation', () => { + beforeEach(() => { + jest.resetAllMocks(); + setupSubmitRequestToBackgroundMocks(); + const DEPOSIT_HEX_SIG = '0xd0e30db0'; + mock4byte(DEPOSIT_HEX_SIG); + }); + + afterEach(() => { + nock.cleanAll(); + }); + + it('displays the header account modal with correct data', async () => { + const account = + mockMetaMaskState.internalAccounts.accounts[ + mockMetaMaskState.internalAccounts + .selectedAccount as keyof typeof mockMetaMaskState.internalAccounts.accounts + ]; + + const accountName = account.metadata.name; + const mockedMetaMaskState = + getMetaMaskStateWithUnapprovedContractDeployment({ + accountAddress: account.address, + }); + + await act(async () => { + await integrationTestRender({ + preloadedState: mockedMetaMaskState, + backgroundConnection: backgroundConnectionMocked, + }); + }); + + expect(screen.getByTestId('header-account-name')).toHaveTextContent( + accountName, + ); + expect(screen.getByTestId('header-network-display-name')).toHaveTextContent( + 'Sepolia', + ); + + fireEvent.click(screen.getByTestId('header-info__account-details-button')); + + expect( + await screen.findByTestId( + 'confirmation-account-details-modal__account-name', + ), + ).toHaveTextContent(accountName); + expect(screen.getByTestId('address-copy-button-text')).toHaveTextContent( + '0x0DCD5...3E7bc', + ); + expect( + screen.getByTestId('confirmation-account-details-modal__account-balance'), + ).toHaveTextContent('1.582717SepoliaETH'); + + let confirmAccountDetailsModalMetricsEvent; + + await waitFor(() => { + confirmAccountDetailsModalMetricsEvent = + mockedBackgroundConnection.submitRequestToBackground.mock.calls?.find( + (call) => + call[0] === 'trackMetaMetricsEvent' && + call[1]?.[0].category === MetaMetricsEventCategory.Confirmations, + ); + + expect(confirmAccountDetailsModalMetricsEvent?.[0]).toBe( + 'trackMetaMetricsEvent', + ); + }); + + expect(confirmAccountDetailsModalMetricsEvent?.[1]).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + category: MetaMetricsEventCategory.Confirmations, + event: MetaMetricsEventName.AccountDetailsOpened, + properties: { + action: 'Confirm Screen', + location: MetaMetricsEventLocation.Transaction, + transaction_type: TransactionType.deployContract, + }, + }), + ]), + ); + + fireEvent.click( + screen.getByTestId('confirmation-account-details-modal__close-button'), + ); + + await waitFor(() => { + expect( + screen.queryByTestId( + 'confirmation-account-details-modal__account-name', + ), + ).not.toBeInTheDocument(); + }); + }); + + it('displays the transaction details section', async () => { + const account = + mockMetaMaskState.internalAccounts.accounts[ + mockMetaMaskState.internalAccounts + .selectedAccount as keyof typeof mockMetaMaskState.internalAccounts.accounts + ]; + + const mockedMetaMaskState = + getMetaMaskStateWithUnapprovedContractDeployment({ + accountAddress: account.address, + }); + + await act(async () => { + await integrationTestRender({ + preloadedState: mockedMetaMaskState, + backgroundConnection: backgroundConnectionMocked, + }); + }); + + expect( + screen.getByText(tEn('confirmTitleDeployContract') as string), + ).toBeInTheDocument(); + + const simulationSection = screen.getByTestId('simulation-details-layout'); + expect(simulationSection).toBeInTheDocument(); + expect(simulationSection).toHaveTextContent( + tEn('simulationDetailsTitle') as string, + ); + const simulationDetailsRow = await screen.findByTestId( + 'simulation-rows-incoming', + ); + expect(simulationSection).toContainElement(simulationDetailsRow); + expect(simulationDetailsRow).toHaveTextContent( + tEn('simulationDetailsIncomingHeading') as string, + ); + expect(simulationDetailsRow).toContainElement( + screen.getByTestId('simulation-details-amount-pill'), + ); + + const transactionDetailsSection = screen.getByTestId( + 'transaction-details-section', + ); + expect(transactionDetailsSection).toBeInTheDocument(); + expect(transactionDetailsSection).toHaveTextContent( + tEn('requestFrom') as string, + ); + expect(transactionDetailsSection).toHaveTextContent( + tEn('interactingWith') as string, + ); + + const gasFeesSection = screen.getByTestId('gas-fee-section'); + expect(gasFeesSection).toBeInTheDocument(); + + const editGasFeesRow = + within(gasFeesSection).getByTestId('edit-gas-fees-row'); + expect(editGasFeesRow).toHaveTextContent(tEn('networkFee') as string); + + const firstGasField = within(editGasFeesRow).getByTestId('first-gas-field'); + expect(firstGasField).toHaveTextContent('0.0001 ETH'); + const editGasFeeNativeCurrency = + within(editGasFeesRow).getByTestId('native-currency'); + expect(editGasFeeNativeCurrency).toHaveTextContent('$0.47'); + expect(editGasFeesRow).toContainElement( + screen.getByTestId('edit-gas-fee-icon'), + ); + + const gasFeeSpeed = within(gasFeesSection).getByTestId( + 'gas-fee-details-speed', + ); + expect(gasFeeSpeed).toHaveTextContent(tEn('speed') as string); + + const gasTimingTime = within(gasFeeSpeed).getByTestId('gas-timing-time'); + expect(gasTimingTime).toHaveTextContent('~0 sec'); + }); + + it('sets the preference showConfirmationAdvancedDetails to true when advanced details button is clicked', async () => { + mockedBackgroundConnection.callBackgroundMethod.mockImplementation( + createMockImplementation({ setPreference: {} }), + ); + + const account = + mockMetaMaskState.internalAccounts.accounts[ + mockMetaMaskState.internalAccounts + .selectedAccount as keyof typeof mockMetaMaskState.internalAccounts.accounts + ]; + + const mockedMetaMaskState = + getMetaMaskStateWithUnapprovedContractDeployment({ + accountAddress: account.address, + showConfirmationAdvancedDetails: false, + }); + + await act(async () => { + await integrationTestRender({ + preloadedState: mockedMetaMaskState, + backgroundConnection: backgroundConnectionMocked, + }); + }); + + fireEvent.click(screen.getByTestId('header-advanced-details-button')); + + await waitFor(() => { + expect( + mockedBackgroundConnection.callBackgroundMethod, + ).toHaveBeenCalledWith( + 'setPreference', + ['showConfirmationAdvancedDetails', true], + expect.anything(), + ); + }); + }); + + it('displays the advanced transaction details section', async () => { + mockedBackgroundConnection.callBackgroundMethod.mockImplementation( + createMockImplementation({ setPreference: {} }), + ); + + const account = + mockMetaMaskState.internalAccounts.accounts[ + mockMetaMaskState.internalAccounts + .selectedAccount as keyof typeof mockMetaMaskState.internalAccounts.accounts + ]; + + const mockedMetaMaskState = + getMetaMaskStateWithUnapprovedContractDeployment({ + accountAddress: account.address, + showConfirmationAdvancedDetails: true, + }); + + await act(async () => { + await integrationTestRender({ + preloadedState: mockedMetaMaskState, + backgroundConnection: backgroundConnectionMocked, + }); + }); + + await waitFor(() => { + expect( + mockedBackgroundConnection.submitRequestToBackground, + ).toHaveBeenCalledWith('getNextNonce', expect.anything()); + }); + + const gasFeesSection = screen.getByTestId('gas-fee-section'); + const maxFee = screen.getByTestId('gas-fee-details-max-fee'); + expect(gasFeesSection).toContainElement(maxFee); + expect(maxFee).toHaveTextContent(tEn('maxFee') as string); + expect(maxFee).toHaveTextContent('0.0023 ETH'); + expect(maxFee).toHaveTextContent('$7.72'); + + const nonceSection = screen.getByTestId('advanced-details-nonce-section'); + expect(nonceSection).toBeInTheDocument(); + expect(nonceSection).toHaveTextContent( + tEn('advancedDetailsNonceDesc') as string, + ); + expect(nonceSection).toContainElement( + screen.getByTestId('advanced-details-displayed-nonce'), + ); + expect( + screen.getByTestId('advanced-details-displayed-nonce'), + ).toHaveTextContent('9'); + + const dataSection = screen.getByTestId('advanced-details-data-section'); + expect(dataSection).toBeInTheDocument(); + + const dataSectionFunction = screen.getByTestId( + 'advanced-details-data-function', + ); + expect(dataSection).toContainElement(dataSectionFunction); + expect(dataSectionFunction).toHaveTextContent( + tEn('transactionDataFunction') as string, + ); + expect(dataSectionFunction).toHaveTextContent('Deposit'); + + const transactionDataParams = screen.getByTestId( + 'advanced-details-data-param-0', + ); + expect(dataSection).toContainElement(transactionDataParams); + expect(transactionDataParams).toHaveTextContent('Number Of Tokens'); + expect(transactionDataParams).toHaveTextContent('1'); + }); +}); diff --git a/test/integration/confirmations/transactions/contract-interaction.test.tsx b/test/integration/confirmations/transactions/contract-interaction.test.tsx index cd5953db50b8..1102cb21c67d 100644 --- a/test/integration/confirmations/transactions/contract-interaction.test.tsx +++ b/test/integration/confirmations/transactions/contract-interaction.test.tsx @@ -1,25 +1,26 @@ +import { ApprovalType } from '@metamask/controller-utils'; +import { TransactionType } from '@metamask/transaction-controller'; import { + act, fireEvent, + screen, waitFor, within, - screen, - act, } from '@testing-library/react'; -import { ApprovalType } from '@metamask/controller-utils'; import nock from 'nock'; -import { TransactionType } from '@metamask/transaction-controller'; -import mockMetaMaskState from '../../data/integration-init-state.json'; -import { integrationTestRender } from '../../../lib/render-helpers'; -import * as backgroundConnection from '../../../../ui/store/background-connection'; import { MetaMetricsEventCategory, - MetaMetricsEventName, MetaMetricsEventLocation, + MetaMetricsEventName, } from '../../../../shared/constants/metametrics'; +import * as backgroundConnection from '../../../../ui/store/background-connection'; +import { tEn } from '../../../lib/i18n-helpers'; +import { integrationTestRender } from '../../../lib/render-helpers'; +import mockMetaMaskState from '../../data/integration-init-state.json'; import { createMockImplementation, mock4byte } from '../../helpers'; import { getMaliciousUnapprovedTransaction, - getUnapprovedTransaction, + getUnapprovedContractInteractionTransaction, } from './transactionDataHelpers'; jest.mock('../../../../ui/store/background-connection', () => ({ @@ -89,7 +90,7 @@ const getMetaMaskStateWithUnapprovedContractInteraction = ({ }, }, transactions: [ - getUnapprovedTransaction( + getUnapprovedContractInteractionTransaction( accountAddress, pendingTransactionId, pendingTransactionTime, @@ -261,18 +262,21 @@ describe('Contract Interaction Confirmation', () => { }); }); - expect(screen.getByText('Transaction request')).toBeInTheDocument(); + expect( + screen.getByText(tEn('confirmTitleTransaction') as string), + ).toBeInTheDocument(); const simulationSection = screen.getByTestId('simulation-details-layout'); expect(simulationSection).toBeInTheDocument(); - expect(simulationSection).toHaveTextContent('Estimated changes'); + expect(simulationSection).toHaveTextContent( + tEn('simulationDetailsTitle') as string, + ); const simulationDetailsRow = await screen.findByTestId( 'simulation-rows-incoming', ); expect(simulationSection).toContainElement(simulationDetailsRow); - expect(simulationDetailsRow).toHaveTextContent('You receive'); - expect(simulationDetailsRow).toContainElement( - screen.getByTestId('simulation-details-asset-pill'), + expect(simulationDetailsRow).toHaveTextContent( + tEn('simulationDetailsIncomingHeading') as string, ); expect(simulationDetailsRow).toContainElement( screen.getByTestId('simulation-details-amount-pill'), @@ -282,15 +286,19 @@ describe('Contract Interaction Confirmation', () => { 'transaction-details-section', ); expect(transactionDetailsSection).toBeInTheDocument(); - expect(transactionDetailsSection).toHaveTextContent('Request from'); - expect(transactionDetailsSection).toHaveTextContent('Interacting with'); + expect(transactionDetailsSection).toHaveTextContent( + tEn('requestFrom') as string, + ); + expect(transactionDetailsSection).toHaveTextContent( + tEn('interactingWith') as string, + ); const gasFeesSection = screen.getByTestId('gas-fee-section'); expect(gasFeesSection).toBeInTheDocument(); const editGasFeesRow = within(gasFeesSection).getByTestId('edit-gas-fees-row'); - expect(editGasFeesRow).toHaveTextContent('Network fee'); + expect(editGasFeesRow).toHaveTextContent(tEn('networkFee') as string); const firstGasField = within(editGasFeesRow).getByTestId('first-gas-field'); expect(firstGasField).toHaveTextContent('0.0001 ETH'); @@ -304,7 +312,7 @@ describe('Contract Interaction Confirmation', () => { const gasFeeSpeed = within(gasFeesSection).getByTestId( 'gas-fee-details-speed', ); - expect(gasFeeSpeed).toHaveTextContent('Speed'); + expect(gasFeeSpeed).toHaveTextContent(tEn('speed') as string); const gasTimingTime = within(gasFeeSpeed).getByTestId('gas-timing-time'); expect(gasTimingTime).toHaveTextContent('~0 sec'); @@ -393,13 +401,15 @@ describe('Contract Interaction Confirmation', () => { const gasFeesSection = screen.getByTestId('gas-fee-section'); const maxFee = screen.getByTestId('gas-fee-details-max-fee'); expect(gasFeesSection).toContainElement(maxFee); - expect(maxFee).toHaveTextContent('Max fee'); + expect(maxFee).toHaveTextContent(tEn('maxFee') as string); expect(maxFee).toHaveTextContent('0.0023 ETH'); expect(maxFee).toHaveTextContent('$7.72'); const nonceSection = screen.getByTestId('advanced-details-nonce-section'); expect(nonceSection).toBeInTheDocument(); - expect(nonceSection).toHaveTextContent('Nonce'); + expect(nonceSection).toHaveTextContent( + tEn('advancedDetailsNonceDesc') as string, + ); expect(nonceSection).toContainElement( screen.getByTestId('advanced-details-displayed-nonce'), ); @@ -414,7 +424,9 @@ describe('Contract Interaction Confirmation', () => { 'advanced-details-data-function', ); expect(dataSection).toContainElement(dataSectionFunction); - expect(dataSectionFunction).toHaveTextContent('Function'); + expect(dataSectionFunction).toHaveTextContent( + tEn('transactionDataFunction') as string, + ); expect(dataSectionFunction).toHaveTextContent('mintNFTs'); const transactionDataParams = screen.getByTestId( @@ -444,9 +456,8 @@ describe('Contract Interaction Confirmation', () => { }); }); - const headingText = 'This is a deceptive request'; - const bodyText = - 'If you approve this request, a third party known for scams will take all your assets.'; + const headingText = tEn('blockaidTitleDeceptive') as string; + const bodyText = tEn('blockaidDescriptionTransferFarming') as string; expect(screen.getByText(headingText)).toBeInTheDocument(); expect(screen.getByText(bodyText)).toBeInTheDocument(); }); diff --git a/test/integration/confirmations/transactions/erc20-approve.test.tsx b/test/integration/confirmations/transactions/erc20-approve.test.tsx index b6ab98774cb4..a2404ba75b09 100644 --- a/test/integration/confirmations/transactions/erc20-approve.test.tsx +++ b/test/integration/confirmations/transactions/erc20-approve.test.tsx @@ -2,12 +2,13 @@ import { ApprovalType } from '@metamask/controller-utils'; import { act, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import nock from 'nock'; +import { TokenStandard } from '../../../../shared/constants/transaction'; import * as backgroundConnection from '../../../../ui/store/background-connection'; +import { tEn } from '../../../lib/i18n-helpers'; import { integrationTestRender } from '../../../lib/render-helpers'; +import { createTestProviderTools } from '../../../stub/provider'; import mockMetaMaskState from '../../data/integration-init-state.json'; import { createMockImplementation, mock4byte } from '../../helpers'; -import { TokenStandard } from '../../../../shared/constants/transaction'; -import { createTestProviderTools } from '../../../stub/provider'; import { getUnapprovedApproveTransaction } from './transactionDataHelpers'; jest.mock('../../../../ui/store/background-connection', () => ({ @@ -161,9 +162,13 @@ describe('ERC20 Approve Confirmation', () => { }); }); - expect(screen.getByText('Spending cap request')).toBeInTheDocument(); expect( - screen.getByText('This site wants permission to withdraw your tokens'), + screen.getByText(tEn('confirmTitlePermitTokens') as string), + ).toBeInTheDocument(); + expect( + screen.getByText( + tEn('confirmTitleDescERC20ApproveTransaction') as string, + ), ).toBeInTheDocument(); }); @@ -184,9 +189,9 @@ describe('ERC20 Approve Confirmation', () => { expect(simulationSection).toBeInTheDocument(); expect(simulationSection).toHaveTextContent( - "You're giving someone else permission to spend this amount from your account.", + tEn('simulationDetailsERC20ApproveDesc') as string, ); - expect(simulationSection).toHaveTextContent('Spending cap'); + expect(simulationSection).toHaveTextContent(tEn('spendingCap') as string); const spendingCapValue = screen.getByTestId('simulation-token-value'); expect(simulationSection).toContainElement(spendingCapValue); expect(spendingCapValue).toHaveTextContent('1'); @@ -213,7 +218,7 @@ describe('ERC20 Approve Confirmation', () => { ); expect(approveDetails).toContainElement(approveDetailsSpender); - expect(approveDetailsSpender).toHaveTextContent('Spender'); + expect(approveDetailsSpender).toHaveTextContent(tEn('spender') as string); expect(approveDetailsSpender).toHaveTextContent('0x2e0D7...5d09B'); const spenderTooltip = screen.getByTestId( 'confirmation__approve-spender-tooltip', @@ -222,7 +227,7 @@ describe('ERC20 Approve Confirmation', () => { await testUser.hover(spenderTooltip); const spenderTooltipContent = await screen.findByText( - 'This is the address that will be able to spend your tokens on your behalf.', + tEn('spenderTooltipERC20ApproveDesc') as string, ); expect(spenderTooltipContent).toBeInTheDocument(); @@ -243,7 +248,7 @@ describe('ERC20 Approve Confirmation', () => { ); await testUser.hover(approveDetailsRequestFromTooltip); const requestFromTooltipContent = await screen.findByText( - 'This is the site asking for your confirmation.', + tEn('requestFromTransactionDescription') as string, ); expect(requestFromTooltipContent).toBeInTheDocument(); }); @@ -266,13 +271,15 @@ describe('ERC20 Approve Confirmation', () => { ); expect(spendingCapSection).toBeInTheDocument(); - expect(spendingCapSection).toHaveTextContent('Account balance'); + expect(spendingCapSection).toHaveTextContent( + tEn('accountBalance') as string, + ); expect(spendingCapSection).toHaveTextContent('0'); const spendingCapGroup = screen.getByTestId( 'confirmation__approve-spending-cap-group', ); expect(spendingCapSection).toContainElement(spendingCapGroup); - expect(spendingCapGroup).toHaveTextContent('Spending cap'); + expect(spendingCapGroup).toHaveTextContent(tEn('spendingCap') as string); expect(spendingCapGroup).toHaveTextContent('1'); const spendingCapGroupTooltip = screen.getByTestId( @@ -281,7 +288,7 @@ describe('ERC20 Approve Confirmation', () => { expect(spendingCapGroup).toContainElement(spendingCapGroupTooltip); await testUser.hover(spendingCapGroupTooltip); const requestFromTooltipContent = await screen.findByText( - 'This is the amount of tokens the spender will be able to access on your behalf.', + tEn('spendingCapTooltipDesc') as string, ); expect(requestFromTooltipContent).toBeInTheDocument(); }); @@ -308,7 +315,9 @@ describe('ERC20 Approve Confirmation', () => { 'transaction-details-recipient-row', ); expect(approveDetails).toContainElement(approveDetailsRecipient); - expect(approveDetailsRecipient).toHaveTextContent('Interacting with'); + expect(approveDetailsRecipient).toHaveTextContent( + tEn('interactingWith') as string, + ); expect(approveDetailsRecipient).toHaveTextContent('0x07614...3ad68'); const approveDetailsRecipientTooltip = screen.getByTestId( @@ -319,7 +328,7 @@ describe('ERC20 Approve Confirmation', () => { ); await testUser.hover(approveDetailsRecipientTooltip); const recipientTooltipContent = await screen.findByText( - "This is the contract you're interacting with. Protect yourself from scammers by verifying the details.", + tEn('interactingWithTransactionDescription') as string, ); expect(recipientTooltipContent).toBeInTheDocument(); @@ -327,7 +336,7 @@ describe('ERC20 Approve Confirmation', () => { 'transaction-details-method-data-row', ); expect(approveDetails).toContainElement(approveMethodData); - expect(approveMethodData).toHaveTextContent('Method'); + expect(approveMethodData).toHaveTextContent(tEn('methodData') as string); expect(approveMethodData).toHaveTextContent('Approve'); const approveMethodDataTooltip = screen.getByTestId( 'transaction-details-method-data-row-tooltip', @@ -335,7 +344,7 @@ describe('ERC20 Approve Confirmation', () => { expect(approveMethodData).toContainElement(approveMethodDataTooltip); await testUser.hover(approveMethodDataTooltip); const approveMethodDataTooltipContent = await screen.findByText( - 'Function executed based on decoded input data.', + tEn('methodDataTransactionDesc') as string, ); expect(approveMethodDataTooltipContent).toBeInTheDocument(); @@ -351,7 +360,9 @@ describe('ERC20 Approve Confirmation', () => { 'advanced-details-data-function', ); expect(dataSection).toContainElement(dataSectionFunction); - expect(dataSectionFunction).toHaveTextContent('Function'); + expect(dataSectionFunction).toHaveTextContent( + tEn('transactionDataFunction') as string, + ); expect(dataSectionFunction).toHaveTextContent('Approve'); const approveDataParams1 = screen.getByTestId( diff --git a/test/integration/confirmations/transactions/erc721-approve.test.tsx b/test/integration/confirmations/transactions/erc721-approve.test.tsx index 8a836dbd7568..c3948d150b1d 100644 --- a/test/integration/confirmations/transactions/erc721-approve.test.tsx +++ b/test/integration/confirmations/transactions/erc721-approve.test.tsx @@ -1,12 +1,14 @@ import { ApprovalType } from '@metamask/controller-utils'; -import { act, screen, waitFor } from '@testing-library/react'; +import { act, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import nock from 'nock'; +import { TokenStandard } from '../../../../shared/constants/transaction'; import * as backgroundConnection from '../../../../ui/store/background-connection'; +import { tEn } from '../../../lib/i18n-helpers'; import { integrationTestRender } from '../../../lib/render-helpers'; +import { createTestProviderTools } from '../../../stub/provider'; import mockMetaMaskState from '../../data/integration-init-state.json'; import { createMockImplementation, mock4byte } from '../../helpers'; -import { TokenStandard } from '../../../../shared/constants/transaction'; -import { createTestProviderTools } from '../../../stub/provider'; import { getUnapprovedApproveTransaction } from './transactionDataHelpers'; jest.mock('../../../../ui/store/background-connection', () => ({ @@ -23,14 +25,21 @@ const backgroundConnectionMocked = { export const pendingTransactionId = '48a75190-45ca-11ef-9001-f3886ec2397c'; export const pendingTransactionTime = new Date().getTime(); -const getMetaMaskStateWithUnapprovedApproveTransaction = ( - accountAddress: string, -) => { +const getMetaMaskStateWithUnapprovedApproveTransaction = (opts?: { + showAdvanceDetails: boolean; +}) => { + const account = + mockMetaMaskState.internalAccounts.accounts[ + mockMetaMaskState.internalAccounts + .selectedAccount as keyof typeof mockMetaMaskState.internalAccounts.accounts + ]; + return { ...mockMetaMaskState, preferences: { ...mockMetaMaskState.preferences, redesignedConfirmationsEnabled: true, + showConfirmationAdvancedDetails: opts?.showAdvanceDetails ?? false, }, pendingApprovals: { [pendingTransactionId]: { @@ -61,7 +70,7 @@ const getMetaMaskStateWithUnapprovedApproveTransaction = ( }, transactions: [ getUnapprovedApproveTransaction( - accountAddress, + account.address, pendingTransactionId, pendingTransactionTime, ), @@ -78,7 +87,7 @@ const advancedDetailsMockedRequests = { decodeTransactionData: { data: [ { - name: 'approve', + name: 'Approve', params: [ { type: 'address', @@ -129,7 +138,8 @@ describe('ERC721 Approve Confirmation', () => { }, }); const APPROVE_NFT_HEX_SIG = '0x095ea7b3'; - mock4byte(APPROVE_NFT_HEX_SIG); + const APPROVE_NFT_TEXT_SIG = 'approve(address,uint256)'; + mock4byte(APPROVE_NFT_HEX_SIG, APPROVE_NFT_TEXT_SIG); }); afterEach(() => { @@ -141,15 +151,28 @@ describe('ERC721 Approve Confirmation', () => { delete (global as any).ethereumProvider; }); - it('displays approve details with correct data', async () => { - const account = - mockMetaMaskState.internalAccounts.accounts[ - mockMetaMaskState.internalAccounts - .selectedAccount as keyof typeof mockMetaMaskState.internalAccounts.accounts - ]; + it('displays spending cap request title', async () => { + const mockedMetaMaskState = + getMetaMaskStateWithUnapprovedApproveTransaction(); + await act(async () => { + await integrationTestRender({ + preloadedState: mockedMetaMaskState, + backgroundConnection: backgroundConnectionMocked, + }); + }); + + expect( + screen.getByText(tEn('confirmTitleApproveTransaction') as string), + ).toBeInTheDocument(); + expect( + screen.getByText(tEn('confirmTitleDescApproveTransaction') as string), + ).toBeInTheDocument(); + }); + + it('displays approve simulation section', async () => { const mockedMetaMaskState = - getMetaMaskStateWithUnapprovedApproveTransaction(account.address); + getMetaMaskStateWithUnapprovedApproveTransaction(); await act(async () => { await integrationTestRender({ @@ -158,12 +181,163 @@ describe('ERC721 Approve Confirmation', () => { }); }); - await waitFor(() => { - expect(screen.getByText('Allowance request')).toBeInTheDocument(); + const simulationSection = screen.getByTestId( + 'confirmation__simulation_section', + ); + expect(simulationSection).toBeInTheDocument(); + + expect(simulationSection).toHaveTextContent( + tEn('simulationDetailsApproveDesc') as string, + ); + expect(simulationSection).toHaveTextContent( + tEn('simulationApproveHeading') as string, + ); + const spendingCapValue = screen.getByTestId('simulation-token-value'); + expect(simulationSection).toContainElement(spendingCapValue); + expect(spendingCapValue).toHaveTextContent('1'); + expect(simulationSection).toHaveTextContent('0x07614...3ad68'); + }); + + it('displays approve details with correct data', async () => { + const testUser = userEvent.setup(); + + const mockedMetaMaskState = + getMetaMaskStateWithUnapprovedApproveTransaction(); + + await act(async () => { + await integrationTestRender({ + preloadedState: mockedMetaMaskState, + backgroundConnection: backgroundConnectionMocked, + }); }); - await waitFor(() => { - expect(screen.getByText('Request from')).toBeInTheDocument(); + const approveDetails = screen.getByTestId('confirmation__approve-details'); + expect(approveDetails).toBeInTheDocument(); + const approveDetailsSpender = screen.getByTestId( + 'confirmation__approve-spender', + ); + + expect(approveDetails).toContainElement(approveDetailsSpender); + expect(approveDetailsSpender).toHaveTextContent(tEn('spender') as string); + expect(approveDetailsSpender).toHaveTextContent('0x2e0D7...5d09B'); + const spenderTooltip = screen.getByTestId( + 'confirmation__approve-spender-tooltip', + ); + expect(approveDetailsSpender).toContainElement(spenderTooltip); + await testUser.hover(spenderTooltip); + const spenderTooltipContent = await screen.findByText( + tEn('spenderTooltipDesc') as string, + ); + expect(spenderTooltipContent).toBeInTheDocument(); + + const approveDetailsRequestFrom = screen.getByTestId( + 'transaction-details-origin-row', + ); + expect(approveDetails).toContainElement(approveDetailsRequestFrom); + expect(approveDetailsRequestFrom).toHaveTextContent( + tEn('requestFrom') as string, + ); + expect(approveDetailsRequestFrom).toHaveTextContent( + 'http://localhost:8086/', + ); + + const approveDetailsRequestFromTooltip = screen.getByTestId( + 'transaction-details-origin-row-tooltip', + ); + expect(approveDetailsRequestFrom).toContainElement( + approveDetailsRequestFromTooltip, + ); + await testUser.hover(approveDetailsRequestFromTooltip); + const requestFromTooltipContent = await screen.findByText( + tEn('requestFromTransactionDescription') as string, + ); + expect(requestFromTooltipContent).toBeInTheDocument(); + }); + + it('displays the advanced transaction details section', async () => { + const testUser = userEvent.setup(); + + const mockedMetaMaskState = + getMetaMaskStateWithUnapprovedApproveTransaction({ + showAdvanceDetails: true, + }); + + await act(async () => { + await integrationTestRender({ + preloadedState: mockedMetaMaskState, + backgroundConnection: backgroundConnectionMocked, + }); }); + + const approveDetails = screen.getByTestId('confirmation__approve-details'); + expect(approveDetails).toBeInTheDocument(); + + const approveDetailsRecipient = screen.getByTestId( + 'transaction-details-recipient-row', + ); + expect(approveDetails).toContainElement(approveDetailsRecipient); + expect(approveDetailsRecipient).toHaveTextContent( + tEn('interactingWith') as string, + ); + expect(approveDetailsRecipient).toHaveTextContent('0x07614...3ad68'); + + const approveDetailsRecipientTooltip = screen.getByTestId( + 'transaction-details-recipient-row-tooltip', + ); + expect(approveDetailsRecipient).toContainElement( + approveDetailsRecipientTooltip, + ); + await testUser.hover(approveDetailsRecipientTooltip); + const recipientTooltipContent = await screen.findByText( + tEn('interactingWithTransactionDescription') as string, + ); + expect(recipientTooltipContent).toBeInTheDocument(); + + const approveMethodData = await screen.findByTestId( + 'transaction-details-method-data-row', + ); + expect(approveDetails).toContainElement(approveMethodData); + expect(approveMethodData).toHaveTextContent(tEn('methodData') as string); + expect(approveMethodData).toHaveTextContent('Approve'); + const approveMethodDataTooltip = screen.getByTestId( + 'transaction-details-method-data-row-tooltip', + ); + expect(approveMethodData).toContainElement(approveMethodDataTooltip); + await testUser.hover(approveMethodDataTooltip); + const approveMethodDataTooltipContent = await screen.findByText( + tEn('methodDataTransactionDesc') as string, + ); + expect(approveMethodDataTooltipContent).toBeInTheDocument(); + + const approveDetailsNonce = screen.getByTestId( + 'advanced-details-nonce-section', + ); + expect(approveDetailsNonce).toBeInTheDocument(); + + const dataSection = screen.getByTestId('advanced-details-data-section'); + expect(dataSection).toBeInTheDocument(); + + const dataSectionFunction = screen.getByTestId( + 'advanced-details-data-function', + ); + expect(dataSection).toContainElement(dataSectionFunction); + expect(dataSectionFunction).toHaveTextContent( + tEn('transactionDataFunction') as string, + ); + expect(dataSectionFunction).toHaveTextContent('Approve'); + + const approveDataParams1 = screen.getByTestId( + 'advanced-details-data-param-0', + ); + expect(dataSection).toContainElement(approveDataParams1); + expect(approveDataParams1).toHaveTextContent('Param #1'); + expect(approveDataParams1).toHaveTextContent('0x2e0D7...5d09B'); + + const approveDataParams2 = screen.getByTestId( + 'advanced-details-data-param-1', + ); + expect(dataSection).toContainElement(approveDataParams2); + expect(approveDataParams2).toHaveTextContent('Param #2'); + expect(approveDataParams2).toHaveTextContent('1'); }); }); diff --git a/test/integration/confirmations/transactions/increase-allowance.test.tsx b/test/integration/confirmations/transactions/increase-allowance.test.tsx new file mode 100644 index 000000000000..c288a5cc4e6d --- /dev/null +++ b/test/integration/confirmations/transactions/increase-allowance.test.tsx @@ -0,0 +1,384 @@ +import { ApprovalType } from '@metamask/controller-utils'; +import { act, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import nock from 'nock'; +import { TokenStandard } from '../../../../shared/constants/transaction'; +import * as backgroundConnection from '../../../../ui/store/background-connection'; +import { tEn } from '../../../lib/i18n-helpers'; +import { integrationTestRender } from '../../../lib/render-helpers'; +import { createTestProviderTools } from '../../../stub/provider'; +import mockMetaMaskState from '../../data/integration-init-state.json'; +import { createMockImplementation, mock4byte } from '../../helpers'; +import { getUnapprovedIncreaseAllowanceTransaction } from './transactionDataHelpers'; + +jest.mock('../../../../ui/store/background-connection', () => ({ + ...jest.requireActual('../../../../ui/store/background-connection'), + submitRequestToBackground: jest.fn(), + callBackgroundMethod: jest.fn(), +})); + +const mockedBackgroundConnection = jest.mocked(backgroundConnection); + +const backgroundConnectionMocked = { + onNotification: jest.fn(), +}; +export const pendingTransactionId = '48a75190-45ca-11ef-9001-f3886ec2397c'; +export const pendingTransactionTime = new Date().getTime(); + +const getMetaMaskStateWithUnapprovedIncreaseAllowanceTransaction = (opts?: { + showAdvanceDetails: boolean; +}) => { + const account = + mockMetaMaskState.internalAccounts.accounts[ + mockMetaMaskState.internalAccounts + .selectedAccount as keyof typeof mockMetaMaskState.internalAccounts.accounts + ]; + + return { + ...mockMetaMaskState, + preferences: { + ...mockMetaMaskState.preferences, + redesignedConfirmationsEnabled: true, + showConfirmationAdvancedDetails: opts?.showAdvanceDetails ?? false, + }, + pendingApprovals: { + [pendingTransactionId]: { + id: pendingTransactionId, + origin: 'origin', + time: pendingTransactionTime, + type: ApprovalType.Transaction, + requestData: { + txId: pendingTransactionId, + }, + requestState: null, + expectsResult: false, + }, + }, + pendingApprovalCount: 1, + knownMethodData: { + '0x39509351': { + name: 'increaseAllowance', + params: [ + { + type: 'address', + }, + { + type: 'uint256', + }, + ], + }, + }, + transactions: [ + getUnapprovedIncreaseAllowanceTransaction( + account.address, + pendingTransactionId, + pendingTransactionTime, + ), + ], + }; +}; + +const advancedDetailsMockedRequests = { + getGasFeeTimeEstimate: { + lowerTimeBound: new Date().getTime(), + upperTimeBound: new Date().getTime(), + }, + getNextNonce: '9', + decodeTransactionData: { + data: [ + { + name: 'increaseAllowance', + params: [ + { + type: 'address', + value: '0x2e0D7E8c45221FcA00d74a3609A0f7097035d09B', + }, + { + type: 'uint256', + value: 1, + }, + ], + }, + ], + source: 'FourByte', + }, +}; + +const setupSubmitRequestToBackgroundMocks = ( + mockRequests?: Record, +) => { + mockedBackgroundConnection.submitRequestToBackground.mockImplementation( + createMockImplementation({ + ...advancedDetailsMockedRequests, + ...(mockRequests ?? {}), + }), + ); + + mockedBackgroundConnection.callBackgroundMethod.mockImplementation( + createMockImplementation({ addKnownMethodData: {} }), + ); +}; + +describe('ERC20 increaseAllowance Confirmation', () => { + beforeAll(() => { + const { provider } = createTestProviderTools({ + networkId: 'sepolia', + chainId: '0xaa36a7', + }); + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + global.ethereumProvider = provider as any; + }); + + beforeEach(() => { + jest.resetAllMocks(); + setupSubmitRequestToBackgroundMocks({ + getTokenStandardAndDetails: { + standard: TokenStandard.ERC20, + }, + }); + const INCREASE_ALLOWANCE_ERC20_HEX_SIG = '0x39509351'; + const INCREASE_ALLOWANCE_ERC20_TEXT_SIG = + 'increaseAllowance(address,uint256)'; + mock4byte( + INCREASE_ALLOWANCE_ERC20_HEX_SIG, + INCREASE_ALLOWANCE_ERC20_TEXT_SIG, + ); + }); + + afterEach(() => { + nock.cleanAll(); + }); + + afterAll(() => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + delete (global as any).ethereumProvider; + }); + + it('displays spending cap request title', async () => { + const mockedMetaMaskState = + getMetaMaskStateWithUnapprovedIncreaseAllowanceTransaction(); + + await act(async () => { + await integrationTestRender({ + preloadedState: mockedMetaMaskState, + backgroundConnection: backgroundConnectionMocked, + }); + }); + + expect( + screen.getByText(tEn('confirmTitlePermitTokens') as string), + ).toBeInTheDocument(); + expect( + screen.getByText(tEn('confirmTitleDescPermitSignature') as string), + ).toBeInTheDocument(); + }); + + it('displays increase allowance simulation section', async () => { + const mockedMetaMaskState = + getMetaMaskStateWithUnapprovedIncreaseAllowanceTransaction(); + + await act(async () => { + await integrationTestRender({ + preloadedState: mockedMetaMaskState, + backgroundConnection: backgroundConnectionMocked, + }); + }); + + const simulationSection = screen.getByTestId( + 'confirmation__simulation_section', + ); + expect(simulationSection).toBeInTheDocument(); + + expect(simulationSection).toHaveTextContent( + tEn('simulationDetailsERC20ApproveDesc') as string, + ); + expect(simulationSection).toHaveTextContent(tEn('spendingCap') as string); + const spendingCapValue = screen.getByTestId('simulation-token-value'); + expect(simulationSection).toContainElement(spendingCapValue); + expect(spendingCapValue).toHaveTextContent('1'); + expect(simulationSection).toHaveTextContent('0x07614...3ad68'); + }); + + it('displays approve details with correct data', async () => { + const testUser = userEvent.setup(); + + const mockedMetaMaskState = + getMetaMaskStateWithUnapprovedIncreaseAllowanceTransaction(); + + await act(async () => { + await integrationTestRender({ + preloadedState: mockedMetaMaskState, + backgroundConnection: backgroundConnectionMocked, + }); + }); + + const approveDetails = screen.getByTestId('confirmation__approve-details'); + expect(approveDetails).toBeInTheDocument(); + const approveDetailsSpender = screen.getByTestId( + 'confirmation__approve-spender', + ); + + expect(approveDetails).toContainElement(approveDetailsSpender); + expect(approveDetailsSpender).toHaveTextContent(tEn('spender') as string); + expect(approveDetailsSpender).toHaveTextContent('0x2e0D7...5d09B'); + const spenderTooltip = screen.getByTestId( + 'confirmation__approve-spender-tooltip', + ); + expect(approveDetailsSpender).toContainElement(spenderTooltip); + await testUser.hover(spenderTooltip); + + const spenderTooltipContent = await screen.findByText( + tEn('spenderTooltipERC20ApproveDesc') as string, + ); + expect(spenderTooltipContent).toBeInTheDocument(); + + const approveDetailsRequestFrom = screen.getByTestId( + 'transaction-details-origin-row', + ); + expect(approveDetails).toContainElement(approveDetailsRequestFrom); + expect(approveDetailsRequestFrom).toHaveTextContent('Request from'); + expect(approveDetailsRequestFrom).toHaveTextContent( + 'http://localhost:8086/', + ); + + const approveDetailsRequestFromTooltip = screen.getByTestId( + 'transaction-details-origin-row-tooltip', + ); + expect(approveDetailsRequestFrom).toContainElement( + approveDetailsRequestFromTooltip, + ); + await testUser.hover(approveDetailsRequestFromTooltip); + const requestFromTooltipContent = await screen.findByText( + tEn('requestFromTransactionDescription') as string, + ); + expect(requestFromTooltipContent).toBeInTheDocument(); + }); + + it('displays spending cap section with correct data', async () => { + const testUser = userEvent.setup(); + + const mockedMetaMaskState = + getMetaMaskStateWithUnapprovedIncreaseAllowanceTransaction(); + + await act(async () => { + await integrationTestRender({ + preloadedState: mockedMetaMaskState, + backgroundConnection: backgroundConnectionMocked, + }); + }); + + const spendingCapSection = screen.getByTestId( + 'confirmation__approve-spending-cap-section', + ); + expect(spendingCapSection).toBeInTheDocument(); + + expect(spendingCapSection).toHaveTextContent( + tEn('accountBalance') as string, + ); + expect(spendingCapSection).toHaveTextContent('0'); + const spendingCapGroup = screen.getByTestId( + 'confirmation__approve-spending-cap-group', + ); + expect(spendingCapSection).toContainElement(spendingCapGroup); + expect(spendingCapGroup).toHaveTextContent(tEn('spendingCap') as string); + expect(spendingCapGroup).toHaveTextContent('1'); + + const spendingCapGroupTooltip = screen.getByTestId( + 'confirmation__approve-spending-cap-group-tooltip', + ); + expect(spendingCapGroup).toContainElement(spendingCapGroupTooltip); + await testUser.hover(spendingCapGroupTooltip); + const requestFromTooltipContent = await screen.findByText( + tEn('spendingCapTooltipDesc') as string, + ); + expect(requestFromTooltipContent).toBeInTheDocument(); + }); + + it('displays the advanced transaction details section', async () => { + const testUser = userEvent.setup(); + + const mockedMetaMaskState = + getMetaMaskStateWithUnapprovedIncreaseAllowanceTransaction({ + showAdvanceDetails: true, + }); + + await act(async () => { + await integrationTestRender({ + preloadedState: mockedMetaMaskState, + backgroundConnection: backgroundConnectionMocked, + }); + }); + + const approveDetails = screen.getByTestId('confirmation__approve-details'); + expect(approveDetails).toBeInTheDocument(); + + const approveDetailsRecipient = screen.getByTestId( + 'transaction-details-recipient-row', + ); + expect(approveDetails).toContainElement(approveDetailsRecipient); + expect(approveDetailsRecipient).toHaveTextContent( + tEn('interactingWith') as string, + ); + expect(approveDetailsRecipient).toHaveTextContent('0x07614...3ad68'); + + const approveDetailsRecipientTooltip = screen.getByTestId( + 'transaction-details-recipient-row-tooltip', + ); + expect(approveDetailsRecipient).toContainElement( + approveDetailsRecipientTooltip, + ); + await testUser.hover(approveDetailsRecipientTooltip); + const recipientTooltipContent = await screen.findByText( + tEn('interactingWithTransactionDescription') as string, + ); + expect(recipientTooltipContent).toBeInTheDocument(); + + const approveMethodData = await screen.findByTestId( + 'transaction-details-method-data-row', + ); + expect(approveDetails).toContainElement(approveMethodData); + expect(approveMethodData).toHaveTextContent(tEn('methodData') as string); + expect(approveMethodData).toHaveTextContent('increaseAllowance'); + const approveMethodDataTooltip = screen.getByTestId( + 'transaction-details-method-data-row-tooltip', + ); + expect(approveMethodData).toContainElement(approveMethodDataTooltip); + await testUser.hover(approveMethodDataTooltip); + const approveMethodDataTooltipContent = await screen.findByText( + tEn('methodDataTransactionDesc') as string, + ); + expect(approveMethodDataTooltipContent).toBeInTheDocument(); + + const approveDetailsNonce = screen.getByTestId( + 'advanced-details-nonce-section', + ); + expect(approveDetailsNonce).toBeInTheDocument(); + + const dataSection = screen.getByTestId('advanced-details-data-section'); + expect(dataSection).toBeInTheDocument(); + + const dataSectionFunction = screen.getByTestId( + 'advanced-details-data-function', + ); + expect(dataSection).toContainElement(dataSectionFunction); + expect(dataSectionFunction).toHaveTextContent( + tEn('transactionDataFunction') as string, + ); + expect(dataSectionFunction).toHaveTextContent('increaseAllowance'); + + const approveDataParams1 = screen.getByTestId( + 'advanced-details-data-param-0', + ); + expect(dataSection).toContainElement(approveDataParams1); + expect(approveDataParams1).toHaveTextContent('Param #1'); + expect(approveDataParams1).toHaveTextContent('0x2e0D7...5d09B'); + + const approveDataParams2 = screen.getByTestId( + 'advanced-details-data-param-1', + ); + expect(dataSection).toContainElement(approveDataParams2); + expect(approveDataParams2).toHaveTextContent('Param #2'); + expect(approveDataParams2).toHaveTextContent('1'); + }); +}); diff --git a/test/integration/confirmations/transactions/set-approval-for-all.test.tsx b/test/integration/confirmations/transactions/set-approval-for-all.test.tsx new file mode 100644 index 000000000000..a65688030e90 --- /dev/null +++ b/test/integration/confirmations/transactions/set-approval-for-all.test.tsx @@ -0,0 +1,348 @@ +import { ApprovalType } from '@metamask/controller-utils'; +import { act, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import nock from 'nock'; +import { TokenStandard } from '../../../../shared/constants/transaction'; +import * as backgroundConnection from '../../../../ui/store/background-connection'; +import { tEn } from '../../../lib/i18n-helpers'; +import { integrationTestRender } from '../../../lib/render-helpers'; +import { createTestProviderTools } from '../../../stub/provider'; +import mockMetaMaskState from '../../data/integration-init-state.json'; +import { createMockImplementation, mock4byte } from '../../helpers'; +import { getUnapprovedSetApprovalForAllTransaction } from './transactionDataHelpers'; + +jest.mock('../../../../ui/store/background-connection', () => ({ + ...jest.requireActual('../../../../ui/store/background-connection'), + submitRequestToBackground: jest.fn(), + callBackgroundMethod: jest.fn(), +})); + +const mockedBackgroundConnection = jest.mocked(backgroundConnection); + +const backgroundConnectionMocked = { + onNotification: jest.fn(), +}; +export const pendingTransactionId = '48a75190-45ca-11ef-9001-f3886ec2397c'; +export const pendingTransactionTime = new Date().getTime(); + +const getMetaMaskStateWithUnapprovedSetApprovalForAllTransaction = (opts?: { + showAdvanceDetails: boolean; +}) => { + const account = + mockMetaMaskState.internalAccounts.accounts[ + mockMetaMaskState.internalAccounts + .selectedAccount as keyof typeof mockMetaMaskState.internalAccounts.accounts + ]; + + return { + ...mockMetaMaskState, + preferences: { + ...mockMetaMaskState.preferences, + redesignedConfirmationsEnabled: true, + showConfirmationAdvancedDetails: opts?.showAdvanceDetails ?? false, + }, + pendingApprovals: { + [pendingTransactionId]: { + id: pendingTransactionId, + origin: 'origin', + time: pendingTransactionTime, + type: ApprovalType.Transaction, + requestData: { + txId: pendingTransactionId, + }, + requestState: null, + expectsResult: false, + }, + }, + pendingApprovalCount: 1, + knownMethodData: { + '0xa22cb465': { + name: 'setApprovalForAll', + params: [ + { + type: 'address', + }, + { + type: 'bool', + }, + ], + }, + }, + transactions: [ + getUnapprovedSetApprovalForAllTransaction( + account.address, + pendingTransactionId, + pendingTransactionTime, + ), + ], + }; +}; + +const advancedDetailsMockedRequests = { + getGasFeeTimeEstimate: { + lowerTimeBound: new Date().getTime(), + upperTimeBound: new Date().getTime(), + }, + getNextNonce: '9', + decodeTransactionData: { + data: [ + { + name: 'setApprovalForAll', + params: [ + { + type: 'address', + value: '0x2e0D7E8c45221FcA00d74a3609A0f7097035d09B', + }, + { + type: 'bool', + value: true, + }, + ], + }, + ], + source: 'FourByte', + }, +}; + +const setupSubmitRequestToBackgroundMocks = ( + mockRequests?: Record, +) => { + mockedBackgroundConnection.submitRequestToBackground.mockImplementation( + createMockImplementation({ + ...advancedDetailsMockedRequests, + ...(mockRequests ?? {}), + }), + ); + + mockedBackgroundConnection.callBackgroundMethod.mockImplementation( + createMockImplementation({ addKnownMethodData: {} }), + ); +}; + +describe('ERC721 setApprovalForAll Confirmation', () => { + beforeAll(() => { + const { provider } = createTestProviderTools({ + networkId: 'sepolia', + chainId: '0xaa36a7', + }); + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + global.ethereumProvider = provider as any; + }); + + beforeEach(() => { + jest.resetAllMocks(); + setupSubmitRequestToBackgroundMocks({ + getTokenStandardAndDetails: { + standard: TokenStandard.ERC721, + }, + }); + const INCREASE_SET_APPROVAL_FOR_ALL_HEX_SIG = '0xa22cb465'; + const INCREASE_SET_APPROVAL_FOR_ALL_TEXT_SIG = + 'setApprovalForAll(address,bool)'; + mock4byte( + INCREASE_SET_APPROVAL_FOR_ALL_HEX_SIG, + INCREASE_SET_APPROVAL_FOR_ALL_TEXT_SIG, + ); + }); + + afterEach(() => { + nock.cleanAll(); + }); + + afterAll(() => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + delete (global as any).ethereumProvider; + }); + + it('displays set approval for all request title', async () => { + const mockedMetaMaskState = + getMetaMaskStateWithUnapprovedSetApprovalForAllTransaction(); + + await act(async () => { + await integrationTestRender({ + preloadedState: mockedMetaMaskState, + backgroundConnection: backgroundConnectionMocked, + }); + }); + + expect( + screen.getByText(tEn('setApprovalForAllRedesignedTitle') as string), + ).toBeInTheDocument(); + expect( + screen.getByText(tEn('confirmTitleDescApproveTransaction') as string), + ).toBeInTheDocument(); + }); + + it('displays set approval for all simulation section', async () => { + const mockedMetaMaskState = + getMetaMaskStateWithUnapprovedSetApprovalForAllTransaction(); + + await act(async () => { + await integrationTestRender({ + preloadedState: mockedMetaMaskState, + backgroundConnection: backgroundConnectionMocked, + }); + }); + + const simulationSection = screen.getByTestId( + 'confirmation__simulation_section', + ); + expect(simulationSection).toBeInTheDocument(); + + expect(simulationSection).toHaveTextContent( + tEn('simulationDetailsSetApprovalForAllDesc') as string, + ); + expect(simulationSection).toHaveTextContent(tEn('withdrawing') as string); + const spendingCapValue = screen.getByTestId('simulation-token-value'); + expect(simulationSection).toContainElement(spendingCapValue); + expect(spendingCapValue).toHaveTextContent(tEn('all') as string); + expect(simulationSection).toHaveTextContent('0x07614...3ad68'); + }); + + it('displays approve details with correct data', async () => { + const testUser = userEvent.setup(); + + const mockedMetaMaskState = + getMetaMaskStateWithUnapprovedSetApprovalForAllTransaction(); + + await act(async () => { + await integrationTestRender({ + preloadedState: mockedMetaMaskState, + backgroundConnection: backgroundConnectionMocked, + }); + }); + + const approveDetails = screen.getByTestId('confirmation__approve-details'); + expect(approveDetails).toBeInTheDocument(); + const approveDetailsSpender = screen.getByTestId( + 'confirmation__approve-spender', + ); + + expect(approveDetails).toContainElement(approveDetailsSpender); + expect(approveDetailsSpender).toHaveTextContent( + tEn('permissionFor') as string, + ); + expect(approveDetailsSpender).toHaveTextContent('0x2e0D7...5d09B'); + const spenderTooltip = screen.getByTestId( + 'confirmation__approve-spender-tooltip', + ); + expect(approveDetailsSpender).toContainElement(spenderTooltip); + await testUser.hover(spenderTooltip); + + const spenderTooltipContent = await screen.findByText( + tEn('spenderTooltipDesc') as string, + ); + expect(spenderTooltipContent).toBeInTheDocument(); + + const approveDetailsRequestFrom = screen.getByTestId( + 'transaction-details-origin-row', + ); + expect(approveDetails).toContainElement(approveDetailsRequestFrom); + expect(approveDetailsRequestFrom).toHaveTextContent( + tEn('requestFrom') as string, + ); + expect(approveDetailsRequestFrom).toHaveTextContent( + 'http://localhost:8086/', + ); + + const approveDetailsRequestFromTooltip = screen.getByTestId( + 'transaction-details-origin-row-tooltip', + ); + expect(approveDetailsRequestFrom).toContainElement( + approveDetailsRequestFromTooltip, + ); + await testUser.hover(approveDetailsRequestFromTooltip); + const requestFromTooltipContent = await screen.findByText( + tEn('requestFromTransactionDescription') as string, + ); + expect(requestFromTooltipContent).toBeInTheDocument(); + }); + + it('displays the advanced transaction details section', async () => { + const testUser = userEvent.setup(); + + const mockedMetaMaskState = + getMetaMaskStateWithUnapprovedSetApprovalForAllTransaction({ + showAdvanceDetails: true, + }); + + await act(async () => { + await integrationTestRender({ + preloadedState: mockedMetaMaskState, + backgroundConnection: backgroundConnectionMocked, + }); + }); + + const approveDetails = screen.getByTestId('confirmation__approve-details'); + expect(approveDetails).toBeInTheDocument(); + + const approveDetailsRecipient = screen.getByTestId( + 'transaction-details-recipient-row', + ); + expect(approveDetails).toContainElement(approveDetailsRecipient); + expect(approveDetailsRecipient).toHaveTextContent( + tEn('interactingWith') as string, + ); + expect(approveDetailsRecipient).toHaveTextContent('0x07614...3ad68'); + + const approveDetailsRecipientTooltip = screen.getByTestId( + 'transaction-details-recipient-row-tooltip', + ); + expect(approveDetailsRecipient).toContainElement( + approveDetailsRecipientTooltip, + ); + await testUser.hover(approveDetailsRecipientTooltip); + const recipientTooltipContent = await screen.findByText( + tEn('interactingWithTransactionDescription') as string, + ); + expect(recipientTooltipContent).toBeInTheDocument(); + + const approveMethodData = await screen.findByTestId( + 'transaction-details-method-data-row', + ); + expect(approveDetails).toContainElement(approveMethodData); + expect(approveMethodData).toHaveTextContent(tEn('methodData') as string); + expect(approveMethodData).toHaveTextContent('setApprovalForAll'); + const approveMethodDataTooltip = screen.getByTestId( + 'transaction-details-method-data-row-tooltip', + ); + expect(approveMethodData).toContainElement(approveMethodDataTooltip); + await testUser.hover(approveMethodDataTooltip); + const approveMethodDataTooltipContent = await screen.findByText( + tEn('methodDataTransactionDesc') as string, + ); + expect(approveMethodDataTooltipContent).toBeInTheDocument(); + + const approveDetailsNonce = screen.getByTestId( + 'advanced-details-nonce-section', + ); + expect(approveDetailsNonce).toBeInTheDocument(); + + const dataSection = screen.getByTestId('advanced-details-data-section'); + expect(dataSection).toBeInTheDocument(); + + const dataSectionFunction = screen.getByTestId( + 'advanced-details-data-function', + ); + expect(dataSection).toContainElement(dataSectionFunction); + expect(dataSectionFunction).toHaveTextContent( + tEn('transactionDataFunction') as string, + ); + expect(dataSectionFunction).toHaveTextContent('setApprovalForAll'); + + const approveDataParams1 = screen.getByTestId( + 'advanced-details-data-param-0', + ); + expect(dataSection).toContainElement(approveDataParams1); + expect(approveDataParams1).toHaveTextContent('Param #1'); + expect(approveDataParams1).toHaveTextContent('0x2e0D7...5d09B'); + + const approveDataParams2 = screen.getByTestId( + 'advanced-details-data-param-1', + ); + expect(dataSection).toContainElement(approveDataParams2); + expect(approveDataParams2).toHaveTextContent('Param #2'); + expect(approveDataParams2).toHaveTextContent('true'); + }); +}); diff --git a/test/integration/confirmations/transactions/transactionDataHelpers.tsx b/test/integration/confirmations/transactions/transactionDataHelpers.tsx index 12550ea5e563..e9bcd7b818f2 100644 --- a/test/integration/confirmations/transactions/transactionDataHelpers.tsx +++ b/test/integration/confirmations/transactions/transactionDataHelpers.tsx @@ -1,6 +1,6 @@ import { TransactionType } from '@metamask/transaction-controller'; -export const getUnapprovedTransaction = ( +export const getUnapprovedContractInteractionTransaction = ( accountAddress: string, pendingTransactionId: string, pendingTransactionTime: number, @@ -70,37 +70,105 @@ export const getUnapprovedTransaction = ( }; }; +export const getUnapprovedContractDeploymentTransaction = ( + accountAddress: string, + pendingTransactionId: string, + pendingTransactionTime: number, +) => { + return { + ...getUnapprovedContractInteractionTransaction( + accountAddress, + pendingTransactionId, + pendingTransactionTime, + ), + txParams: { + ...getUnapprovedContractInteractionTransaction( + accountAddress, + pendingTransactionId, + pendingTransactionTime, + ).txParams, + data: '0xd0e30db0', + }, + type: TransactionType.deployContract, + }; +}; + export const getUnapprovedApproveTransaction = ( accountAddress: string, pendingTransactionId: string, pendingTransactionTime: number, ) => { return { - ...getUnapprovedTransaction( + ...getUnapprovedContractInteractionTransaction( accountAddress, pendingTransactionId, pendingTransactionTime, ), txParams: { - from: accountAddress, + ...getUnapprovedContractInteractionTransaction( + accountAddress, + pendingTransactionId, + pendingTransactionTime, + ).txParams, data: '0x095ea7b30000000000000000000000002e0d7e8c45221fca00d74a3609a0f7097035d09b0000000000000000000000000000000000000000000000000000000000000001', - gas: '0x16a92', - to: '0x076146c765189d51be3160a2140cf80bfc73ad68', - value: '0x0', - maxFeePerGas: '0x5b06b0c0d', - maxPriorityFeePerGas: '0x59682f00', }, type: TransactionType.tokenMethodApprove, }; }; +export const getUnapprovedIncreaseAllowanceTransaction = ( + accountAddress: string, + pendingTransactionId: string, + pendingTransactionTime: number, +) => { + return { + ...getUnapprovedContractInteractionTransaction( + accountAddress, + pendingTransactionId, + pendingTransactionTime, + ), + txParams: { + ...getUnapprovedContractInteractionTransaction( + accountAddress, + pendingTransactionId, + pendingTransactionTime, + ).txParams, + data: '0x395093510000000000000000000000009bc5baf874d2da8d216ae9f137804184ee5afef40000000000000000000000000000000000000000000000000000000000007530', + }, + type: TransactionType.tokenMethodIncreaseAllowance, + }; +}; + +export const getUnapprovedSetApprovalForAllTransaction = ( + accountAddress: string, + pendingTransactionId: string, + pendingTransactionTime: number, +) => { + return { + ...getUnapprovedContractInteractionTransaction( + accountAddress, + pendingTransactionId, + pendingTransactionTime, + ), + txParams: { + ...getUnapprovedContractInteractionTransaction( + accountAddress, + pendingTransactionId, + pendingTransactionTime, + ).txParams, + data: '0xa22cb4650000000000000000000000009bc5baf874d2da8d216ae9f137804184ee5afef40000000000000000000000000000000000000000000000000000000000000001', + }, + type: TransactionType.tokenMethodSetApprovalForAll, + }; +}; + export const getMaliciousUnapprovedTransaction = ( accountAddress: string, pendingTransactionId: string, pendingTransactionTime: number, ) => { return { - ...getUnapprovedTransaction( + ...getUnapprovedContractInteractionTransaction( accountAddress, pendingTransactionId, pendingTransactionTime, diff --git a/test/integration/data/integration-init-state.json b/test/integration/data/integration-init-state.json index b031611a06ea..82c55c9bd7e0 100644 --- a/test/integration/data/integration-init-state.json +++ b/test/integration/data/integration-init-state.json @@ -782,7 +782,6 @@ "showFiatInTestnets": false, "showTestNetworks": true, "smartTransactionsOptInStatus": false, - "useNativeCurrencyAsPrimaryCurrency": true, "petnamesEnabled": false, "showConfirmationAdvancedDetails": false }, diff --git a/test/integration/data/onboarding-completion-route.json b/test/integration/data/onboarding-completion-route.json index 06d85e298409..e651e9c2ce29 100644 --- a/test/integration/data/onboarding-completion-route.json +++ b/test/integration/data/onboarding-completion-route.json @@ -224,7 +224,6 @@ "showFiatInTestnets": false, "showTestNetworks": false, "smartTransactionsOptInStatus": null, - "useNativeCurrencyAsPrimaryCurrency": true, "hideZeroBalanceTokens": false, "petnamesEnabled": true, "redesignedConfirmationsEnabled": true, diff --git a/test/jest/mock-store.js b/test/jest/mock-store.js index 625b6dcf6c83..736b9c4eb325 100644 --- a/test/jest/mock-store.js +++ b/test/jest/mock-store.js @@ -210,7 +210,7 @@ export const createSwapsMockStore = () => { }, ], useCurrencyRateCheck: true, - currentCurrency: 'ETH', + currentCurrency: 'usd', currencyRates: { ETH: { conversionRate: 1, @@ -469,6 +469,23 @@ export const createSwapsMockStore = () => { decimals: 18, }, fee: 1, + isGasIncludedTrade: false, + approvalTxFees: { + feeEstimate: 42000000000000, + fees: [ + { maxFeePerGas: 2310003200, maxPriorityFeePerGas: 513154852 }, + ], + gasLimit: 21000, + gasUsed: 21000, + }, + tradeTxFees: { + feeEstimate: 42000000000000, + fees: [ + { maxFeePerGas: 2310003200, maxPriorityFeePerGas: 513154852 }, + ], + gasLimit: 21000, + gasUsed: 21000, + }, }, TEST_AGG_2: { trade: { @@ -503,6 +520,36 @@ export const createSwapsMockStore = () => { decimals: 18, }, fee: 1, + isGasIncludedTrade: false, + approvalTxFees: { + feeEstimate: 42000000000000, + fees: [ + { maxFeePerGas: 2310003200, maxPriorityFeePerGas: 513154852 }, + ], + gasLimit: 21000, + gasUsed: 21000, + }, + tradeTxFees: { + feeEstimate: 42000000000000, + fees: [ + { + maxFeePerGas: 2310003200, + maxPriorityFeePerGas: 513154852, + tokenFees: [ + { + token: { + address: '0x6b175474e89094c44da98b954eedeac495271d0f', + symbol: 'DAI', + decimals: 18, + }, + balanceNeededToken: '0x426dc933c2e5a', + }, + ], + }, + ], + gasLimit: 21000, + gasUsed: 21000, + }, }, }, fetchParams: { diff --git a/ui/components/app/assets/asset-list/asset-list.tsx b/ui/components/app/assets/asset-list/asset-list.tsx index ebc78c3ab378..a84ec99037f9 100644 --- a/ui/components/app/assets/asset-list/asset-list.tsx +++ b/ui/components/app/assets/asset-list/asset-list.tsx @@ -39,10 +39,6 @@ import { import { useAccountTotalFiatBalance } from '../../../../hooks/useAccountTotalFiatBalance'; import { useIsOriginalNativeTokenSymbol } from '../../../../hooks/useIsOriginalNativeTokenSymbol'; import { useI18nContext } from '../../../../hooks/useI18nContext'; -import { - showPrimaryCurrency, - showSecondaryCurrency, -} from '../../../../../shared/modules/currency-display.utils'; import { roundToDecimalPlacesRemovingExtraZeroes } from '../../../../helpers/utils/util'; import { FundingMethodModal } from '../../../multichain/funding-method-modal/funding-method-modal'; ///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask) @@ -70,7 +66,7 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { const nativeCurrency = useSelector(getMultichainNativeCurrency); const showFiat = useSelector(getMultichainShouldShowFiat); const isMainnet = useSelector(getMultichainIsMainnet); - const { useNativeCurrencyAsPrimaryCurrency } = useSelector(getPreferences); + const { showNativeTokenAsMainBalance } = useSelector(getPreferences); const { chainId, ticker, type, rpcUrl } = useSelector( getMultichainCurrentNetwork, ); @@ -92,11 +88,17 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { const { currency: primaryCurrency, numberOfDecimals: primaryNumberOfDecimals, - } = useUserPreferencedCurrency(PRIMARY, { ethNumberOfDecimals: 4 }); + } = useUserPreferencedCurrency(PRIMARY, { + ethNumberOfDecimals: 4, + shouldCheckShowNativeToken: true, + }); const { currency: secondaryCurrency, numberOfDecimals: secondaryNumberOfDecimals, - } = useUserPreferencedCurrency(SECONDARY, { ethNumberOfDecimals: 4 }); + } = useUserPreferencedCurrency(SECONDARY, { + ethNumberOfDecimals: 4, + shouldCheckShowNativeToken: true, + }); const [primaryCurrencyDisplay, primaryCurrencyProperties] = useCurrencyDisplay(balance, { @@ -195,25 +197,14 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { title={nativeCurrency} // The primary and secondary currencies are subject to change based on the user's settings // TODO: rename this primary/secondary concept here to be more intuitive, regardless of setting - primary={ - showSecondaryCurrency( - isOriginalNativeSymbol, - useNativeCurrencyAsPrimaryCurrency, - ) - ? secondaryCurrencyDisplay - : undefined - } + primary={isOriginalNativeSymbol ? secondaryCurrencyDisplay : undefined} tokenSymbol={ - useNativeCurrencyAsPrimaryCurrency + showNativeTokenAsMainBalance ? primaryCurrencyProperties.suffix : secondaryCurrencyProperties.suffix } secondary={ - showFiat && - showPrimaryCurrency( - isOriginalNativeSymbol, - useNativeCurrencyAsPrimaryCurrency, - ) + showFiat && isOriginalNativeSymbol ? primaryCurrencyDisplay : undefined } diff --git a/ui/components/app/assets/nfts/nft-details/nft-full-image.tsx b/ui/components/app/assets/nfts/nft-details/nft-full-image.tsx index 64e2a3191c0e..42b4ddacbf95 100644 --- a/ui/components/app/assets/nfts/nft-details/nft-full-image.tsx +++ b/ui/components/app/assets/nfts/nft-details/nft-full-image.tsx @@ -30,6 +30,7 @@ export default function NftFullImage() { const nfts = useSelector(getNfts); const nft = nfts.find( ({ address, tokenId }: { address: string; tokenId: string }) => + // @ts-expect-error TODO: Fix this type error by handling undefined parameters isEqualCaseInsensitive(address, asset) && id === tokenId.toString(), ); diff --git a/ui/components/app/assets/token-cell/__snapshots__/token-cell.test.tsx.snap b/ui/components/app/assets/token-cell/__snapshots__/token-cell.test.tsx.snap index 4eeeb5603d46..dfed6aeffa98 100644 --- a/ui/components/app/assets/token-cell/__snapshots__/token-cell.test.tsx.snap +++ b/ui/components/app/assets/token-cell/__snapshots__/token-cell.test.tsx.snap @@ -52,7 +52,7 @@ exports[`Token Cell should match snapshot 1`] = ` class="mm-box mm-box--display-flex" >

@@ -67,7 +67,7 @@ exports[`Token Cell should match snapshot 1`] = ` 5.00

5 diff --git a/ui/components/app/assets/token-cell/token-cell.test.tsx b/ui/components/app/assets/token-cell/token-cell.test.tsx index 70714e9975f8..749fc50fd98e 100644 --- a/ui/components/app/assets/token-cell/token-cell.test.tsx +++ b/ui/components/app/assets/token-cell/token-cell.test.tsx @@ -9,6 +9,7 @@ import { getTokenList } from '../../../../selectors'; import { getMultichainCurrentChainId } from '../../../../selectors/multichain'; import { useIsOriginalTokenSymbol } from '../../../../hooks/useIsOriginalTokenSymbol'; +import { getIntlLocale } from '../../../../ducks/locale/locale'; import TokenCell from '.'; jest.mock('react-redux', () => { @@ -100,6 +101,9 @@ describe('Token Cell', () => { if (selector === getMultichainCurrentChainId) { return '0x89'; } + if (selector === getIntlLocale) { + return 'en-US'; + } return undefined; }); (useTokenFiatAmount as jest.Mock).mockReturnValue('5.00'); diff --git a/ui/components/app/confirm/info/row/currency.stories.tsx b/ui/components/app/confirm/info/row/currency.stories.tsx index 2a520ca5bd35..ca9926e5cc6b 100644 --- a/ui/components/app/confirm/info/row/currency.stories.tsx +++ b/ui/components/app/confirm/info/row/currency.stories.tsx @@ -12,7 +12,7 @@ const store = configureStore({ ...mockState.metamask, preferences: { ...mockState.metamask.preferences, - useNativeCurrencyAsPrimaryCurrency: false, + showNativeTokenAsMainBalance: false, }, }, }); @@ -29,7 +29,7 @@ const ConfirmInfoRowCurrencyStory = { control: 'text', }, }, - decorators: [(story: any) => {story()}] + decorators: [(story: any) => {story()}], }; export const DefaultStory = ({ variant, value }) => ( diff --git a/ui/components/app/confirm/info/row/currency.tsx b/ui/components/app/confirm/info/row/currency.tsx index 82ce82c3a113..51ce1fceba28 100644 --- a/ui/components/app/confirm/info/row/currency.tsx +++ b/ui/components/app/confirm/info/row/currency.tsx @@ -1,6 +1,5 @@ import React from 'react'; -import { PRIMARY } from '../../../../../helpers/constants/common'; import { AlignItems, Display, @@ -38,7 +37,7 @@ export const ConfirmInfoRowCurrency = ({ {currency ? ( ) : ( - + )} ); diff --git a/ui/components/app/modals/cancel-transaction/cancel-transaction-gas-fee/cancel-transaction-gas-fee.component.test.js b/ui/components/app/modals/cancel-transaction/cancel-transaction-gas-fee/cancel-transaction-gas-fee.component.test.js index 05bce9e841a0..8966fa01b749 100644 --- a/ui/components/app/modals/cancel-transaction/cancel-transaction-gas-fee/cancel-transaction-gas-fee.component.test.js +++ b/ui/components/app/modals/cancel-transaction/cancel-transaction-gas-fee/cancel-transaction-gas-fee.component.test.js @@ -11,9 +11,7 @@ describe('CancelTransactionGasFee Component', () => { metamask: { ...mockNetworkState({ chainId: CHAIN_IDS.MAINNET }), currencyRates: {}, - preferences: { - useNativeCurrencyAsPrimaryCurrency: false, - }, + preferences: {}, completedOnboarding: true, internalAccounts: mockState.metamask.internalAccounts, }, diff --git a/ui/components/app/modals/customize-nonce/__snapshots__/customize-nonce.test.js.snap b/ui/components/app/modals/customize-nonce/__snapshots__/customize-nonce.test.js.snap index cab80e399a43..020adaa0c952 100644 --- a/ui/components/app/modals/customize-nonce/__snapshots__/customize-nonce.test.js.snap +++ b/ui/components/app/modals/customize-nonce/__snapshots__/customize-nonce.test.js.snap @@ -75,7 +75,7 @@ exports[`Customize Nonce should match snapshot 1`] = ` class="MuiFormControl-root MuiTextField-root MuiFormControl-marginDense MuiFormControl-fullWidth" >

caveat.type === CaveatTypes.restrictNetworkSwitching, + )?.value; + return ( ); } diff --git a/ui/components/app/snaps/snap-ui-button/index.scss b/ui/components/app/snaps/snap-ui-button/index.scss index 8ed2d9e76ca6..9f5b1b33cb32 100644 --- a/ui/components/app/snaps/snap-ui-button/index.scss +++ b/ui/components/app/snaps/snap-ui-button/index.scss @@ -1,8 +1,11 @@ .snap-ui-renderer__button { background: none; text-align: center; - display: flex; - padding-inline: 0; + + &:has(.snap-ui-renderer__icon, .snap-ui-renderer__image) { + display: flex; + padding-inline: 0; + } &:not(&--disabled) { &:hover { diff --git a/ui/components/app/snaps/snap-ui-button/snap-ui-button.tsx b/ui/components/app/snaps/snap-ui-button/snap-ui-button.tsx index cedcc375c17e..08fef2f9a6b7 100644 --- a/ui/components/app/snaps/snap-ui-button/snap-ui-button.tsx +++ b/ui/components/app/snaps/snap-ui-button/snap-ui-button.tsx @@ -23,7 +23,7 @@ export const SnapUIButton: FunctionComponent< > = ({ name, children, - type, + type = ButtonType.Button, variant = 'primary', disabled = false, className = '', diff --git a/ui/components/app/transaction-breakdown/transaction-breakdown.component.js b/ui/components/app/transaction-breakdown/transaction-breakdown.component.js index 704ceca4c9fc..3d5405b57eb5 100644 --- a/ui/components/app/transaction-breakdown/transaction-breakdown.component.js +++ b/ui/components/app/transaction-breakdown/transaction-breakdown.component.js @@ -4,8 +4,8 @@ import classnames from 'classnames'; import CurrencyDisplay from '../../ui/currency-display'; import UserPreferencedCurrencyDisplay from '../user-preferenced-currency-display'; import HexToDecimal from '../../ui/hex-to-decimal'; -import { PRIMARY, SECONDARY } from '../../../helpers/constants/common'; import { EtherDenomination } from '../../../../shared/constants/common'; +import { PRIMARY, SECONDARY } from '../../../helpers/constants/common'; import TransactionBreakdownRow from './transaction-breakdown-row'; export default class TransactionBreakdown extends PureComponent { diff --git a/ui/components/app/transaction-list-item/transaction-list-item.component.test.js b/ui/components/app/transaction-list-item/transaction-list-item.component.test.js index 2d1ce89eed3e..e305040bf969 100644 --- a/ui/components/app/transaction-list-item/transaction-list-item.component.test.js +++ b/ui/components/app/transaction-list-item/transaction-list-item.component.test.js @@ -105,11 +105,7 @@ const generateUseSelectorRouter = (opts) => (selector) => { } else if (selector === getCurrentNetwork) { return { nickname: 'Ethereum Mainnet' }; } else if (selector === getPreferences) { - return ( - opts.preferences ?? { - useNativeCurrencyAsPrimaryCurrency: true, - } - ); + return opts.preferences ?? {}; } else if (selector === getShouldShowFiat) { return opts.shouldShowFiat ?? false; } else if (selector === getTokens) { diff --git a/ui/components/app/user-preferenced-currency-display/user-preferenced-currency-display.component.d.ts b/ui/components/app/user-preferenced-currency-display/user-preferenced-currency-display.component.d.ts index 9e4ca5565733..3bf65d98d19c 100644 --- a/ui/components/app/user-preferenced-currency-display/user-preferenced-currency-display.component.d.ts +++ b/ui/components/app/user-preferenced-currency-display/user-preferenced-currency-display.component.d.ts @@ -12,6 +12,8 @@ export type UserPrefrencedCurrencyDisplayProps = OverridingUnion< showFiat?: boolean; showNative?: boolean; showCurrencySuffix?: boolean; + shouldCheckShowNativeToken?: boolean; + isAggregatedFiatOverviewBalance?: boolean; } >; diff --git a/ui/components/app/user-preferenced-currency-display/user-preferenced-currency-display.component.js b/ui/components/app/user-preferenced-currency-display/user-preferenced-currency-display.component.js index 294e6063f0ad..4b5492091288 100644 --- a/ui/components/app/user-preferenced-currency-display/user-preferenced-currency-display.component.js +++ b/ui/components/app/user-preferenced-currency-display/user-preferenced-currency-display.component.js @@ -25,6 +25,7 @@ export default function UserPreferencedCurrencyDisplay({ showFiat, showNative, showCurrencySuffix, + shouldCheckShowNativeToken, ...restProps }) { const currentNetwork = useMultichainSelector( @@ -42,6 +43,7 @@ export default function UserPreferencedCurrencyDisplay({ numberOfDecimals: propsNumberOfDecimals, showFiatOverride: showFiat, showNativeOverride: showNative, + shouldCheckShowNativeToken, }); const prefixComponent = useMemo(() => { return ( @@ -112,6 +114,7 @@ const UserPreferencedCurrencyDisplayPropTypes = { prefixComponentWrapperProps: PropTypes.object, textProps: PropTypes.object, suffixProps: PropTypes.object, + shouldCheckShowNativeToken: PropTypes.bool, }; UserPreferencedCurrencyDisplay.propTypes = diff --git a/ui/components/app/user-preferenced-currency-display/user-preferenced-currency-display.test.js b/ui/components/app/user-preferenced-currency-display/user-preferenced-currency-display.test.js index 51ee63d40c17..2a6193847fa4 100644 --- a/ui/components/app/user-preferenced-currency-display/user-preferenced-currency-display.test.js +++ b/ui/components/app/user-preferenced-currency-display/user-preferenced-currency-display.test.js @@ -13,9 +13,7 @@ describe('UserPreferencedCurrencyDisplay Component', () => { ...mockState.metamask, ...mockNetworkState({ chainId: CHAIN_IDS.MAINNET }), currencyRates: {}, - preferences: { - useNativeCurrencyAsPrimaryCurrency: true, - }, + preferences: {}, }, }; const mockStore = configureMockStore()(defaultState); diff --git a/ui/components/app/user-preferenced-currency-input/user-preferenced-currency-input.component.js b/ui/components/app/user-preferenced-currency-input/user-preferenced-currency-input.component.js index 70b232848d16..7e34a90bba27 100644 --- a/ui/components/app/user-preferenced-currency-input/user-preferenced-currency-input.component.js +++ b/ui/components/app/user-preferenced-currency-input/user-preferenced-currency-input.component.js @@ -2,27 +2,21 @@ import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; import CurrencyInput from '../currency-input'; +// Noticed this component is not used in codebase; +// removing usage of useNativeCurrencyAsPrimaryCurrency because its being removed in this PR export default class UserPreferencedCurrencyInput extends PureComponent { static propTypes = { - useNativeCurrencyAsPrimaryCurrency: PropTypes.bool, sendInputCurrencySwitched: PropTypes.bool, ...CurrencyInput.propTypes, }; render() { - const { - useNativeCurrencyAsPrimaryCurrency, - sendInputCurrencySwitched, - ...restProps - } = this.props; + const { sendInputCurrencySwitched, ...restProps } = this.props; return ( ); } diff --git a/ui/components/app/user-preferenced-currency-input/user-preferenced-currency-input.container.js b/ui/components/app/user-preferenced-currency-input/user-preferenced-currency-input.container.js index 042b73c249ae..7bec54e5dd8f 100644 --- a/ui/components/app/user-preferenced-currency-input/user-preferenced-currency-input.container.js +++ b/ui/components/app/user-preferenced-currency-input/user-preferenced-currency-input.container.js @@ -1,13 +1,9 @@ import { connect } from 'react-redux'; import { toggleCurrencySwitch } from '../../../ducks/app/app'; -import { getPreferences } from '../../../selectors'; import UserPreferencedCurrencyInput from './user-preferenced-currency-input.component'; const mapStateToProps = (state) => { - const { useNativeCurrencyAsPrimaryCurrency } = getPreferences(state); - return { - useNativeCurrencyAsPrimaryCurrency, sendInputCurrencySwitched: state.appState.sendInputCurrencySwitched, }; }; diff --git a/ui/components/app/user-preferenced-token-input/user-preferenced-token-input.component.js b/ui/components/app/user-preferenced-token-input/user-preferenced-token-input.component.js index a285446100ed..ee8178664564 100644 --- a/ui/components/app/user-preferenced-token-input/user-preferenced-token-input.component.js +++ b/ui/components/app/user-preferenced-token-input/user-preferenced-token-input.component.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import TokenInput from '../../ui/token-input'; import { getTokenSymbol } from '../../../store/actions'; +// This component is not used in codebase, removing usage of useNativeCurrencyAsPrimaryCurrency in this PR export default class UserPreferencedTokenInput extends PureComponent { static propTypes = { token: PropTypes.shape({ @@ -10,7 +11,6 @@ export default class UserPreferencedTokenInput extends PureComponent { decimals: PropTypes.number, symbol: PropTypes.string, }).isRequired, - useNativeCurrencyAsPrimaryCurrency: PropTypes.bool, }; state = { @@ -28,16 +28,10 @@ export default class UserPreferencedTokenInput extends PureComponent { } render() { - const { useNativeCurrencyAsPrimaryCurrency, ...restProps } = this.props; + const { ...restProps } = this.props; return ( - + ); } } diff --git a/ui/components/app/user-preferenced-token-input/user-preferenced-token-input.container.js b/ui/components/app/user-preferenced-token-input/user-preferenced-token-input.container.js index 33afd8ce24a4..03c0c5eda7bf 100644 --- a/ui/components/app/user-preferenced-token-input/user-preferenced-token-input.container.js +++ b/ui/components/app/user-preferenced-token-input/user-preferenced-token-input.container.js @@ -1,15 +1,8 @@ import { connect } from 'react-redux'; import PropTypes from 'prop-types'; -import { getPreferences } from '../../../selectors'; import UserPreferencedTokenInput from './user-preferenced-token-input.component'; -const mapStateToProps = (state) => { - const { useNativeCurrencyAsPrimaryCurrency } = getPreferences(state); - - return { - useNativeCurrencyAsPrimaryCurrency, - }; -}; +const mapStateToProps = (state) => state; const UserPreferencedTokenInputContainer = connect(mapStateToProps)( UserPreferencedTokenInput, diff --git a/ui/components/app/wallet-overview/__snapshots__/aggregated-percentage-overview.test.tsx.snap b/ui/components/app/wallet-overview/__snapshots__/aggregated-percentage-overview.test.tsx.snap new file mode 100644 index 000000000000..59dac675d1df --- /dev/null +++ b/ui/components/app/wallet-overview/__snapshots__/aggregated-percentage-overview.test.tsx.snap @@ -0,0 +1,23 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AggregatedPercentageOverview render renders correctly 1`] = ` +
+
+

+ +$0.00 +

+

+ (+0.00%) +

+
+
+`; diff --git a/ui/components/app/wallet-overview/aggregated-percentage-overview.test.tsx b/ui/components/app/wallet-overview/aggregated-percentage-overview.test.tsx new file mode 100644 index 000000000000..95e0d92fa2b8 --- /dev/null +++ b/ui/components/app/wallet-overview/aggregated-percentage-overview.test.tsx @@ -0,0 +1,592 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import { getIntlLocale } from '../../../ducks/locale/locale'; +import { + getCurrentCurrency, + getSelectedAccount, + getShouldHideZeroBalanceTokens, + getTokensMarketData, +} from '../../../selectors'; +import { useAccountTotalFiatBalance } from '../../../hooks/useAccountTotalFiatBalance'; +import { AggregatedPercentageOverview } from './aggregated-percentage-overview'; + +jest.mock('react-redux', () => ({ + useSelector: jest.fn((selector) => selector()), +})); + +jest.mock('../../../ducks/locale/locale', () => ({ + getIntlLocale: jest.fn(), +})); + +jest.mock('../../../selectors', () => ({ + getCurrentCurrency: jest.fn(), + getSelectedAccount: jest.fn(), + getShouldHideZeroBalanceTokens: jest.fn(), + getTokensMarketData: jest.fn(), +})); + +jest.mock('../../../hooks/useAccountTotalFiatBalance', () => ({ + useAccountTotalFiatBalance: jest.fn(), +})); + +const mockGetIntlLocale = getIntlLocale as unknown as jest.Mock; +const mockGetCurrentCurrency = getCurrentCurrency as jest.Mock; +const mockGetSelectedAccount = getSelectedAccount as unknown as jest.Mock; +const mockGetShouldHideZeroBalanceTokens = + getShouldHideZeroBalanceTokens as jest.Mock; + +const mockGetTokensMarketData = getTokensMarketData as jest.Mock; + +const selectedAccountMock = { + id: 'd51c0116-de36-4e77-b35b-408d4ea82d01', + address: '0xa259af9db8172f62ef0373d7dfa893a3e245ace9', + options: {}, + methods: [ + 'personal_sign', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData_v1', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + metadata: { + name: 'Account 2', + importTime: 1725467263902, + lastSelected: 1725467263905, + keyring: { + type: 'Simple Key Pair', + }, + }, + balance: '0x0f7e2a03e67666', +}; + +const marketDataMock = { + '0x0000000000000000000000000000000000000000': { + tokenAddress: '0x0000000000000000000000000000000000000000', + currency: 'ETH', + id: 'ethereum', + price: 0.999893213343359, + pricePercentChange1d: -0.7173299395012226, + }, + '0x6B175474E89094C44Da98b954EedeAC495271d0F': { + tokenAddress: '0x6B175474E89094C44Da98b954EedeAC495271d0F', + currency: 'ETH', + id: 'dai', + price: 0.00041861840136257403, + pricePercentChange1d: -0.0862498076183525, + }, + '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48': { + tokenAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', + currency: 'ETH', + id: 'usd-coin', + price: 0.0004185384042093742, + pricePercentChange1d: -0.07612981257899307, + }, + '0xdAC17F958D2ee523a2206206994597C13D831ec7': { + tokenAddress: '0xdAC17F958D2ee523a2206206994597C13D831ec7', + currency: 'ETH', + id: 'tether', + price: 0.0004183549552402562, + pricePercentChange1d: -0.1357979347463155, + }, +}; + +const positiveMarketDataMock = { + '0x0000000000000000000000000000000000000000': { + tokenAddress: '0x0000000000000000000000000000000000000000', + currency: 'ETH', + id: 'ethereum', + price: 0.999893213343359, + pricePercentChange1d: 0.7173299395012226, + }, + '0x6B175474E89094C44Da98b954EedeAC495271d0F': { + tokenAddress: '0x6B175474E89094C44Da98b954EedeAC495271d0F', + currency: 'ETH', + id: 'dai', + price: 0.00041861840136257403, + pricePercentChange1d: 0.0862498076183525, + }, + '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48': { + tokenAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', + currency: 'ETH', + id: 'usd-coin', + price: 0.0004185384042093742, + pricePercentChange1d: 0.07612981257899307, + }, + '0xdAC17F958D2ee523a2206206994597C13D831ec7': { + tokenAddress: '0xdAC17F958D2ee523a2206206994597C13D831ec7', + currency: 'ETH', + id: 'tether', + price: 0.0004183549552402562, + pricePercentChange1d: 0.1357979347463155, + }, +}; + +const mixedMarketDataMock = { + '0x0000000000000000000000000000000000000000': { + tokenAddress: '0x0000000000000000000000000000000000000000', + currency: 'ETH', + id: 'ethereum', + price: 0.999893213343359, + pricePercentChange1d: -0.7173299395012226, + }, + '0x6B175474E89094C44Da98b954EedeAC495271d0F': { + tokenAddress: '0x6B175474E89094C44Da98b954EedeAC495271d0F', + currency: 'ETH', + id: 'dai', + price: 0.00041861840136257403, + pricePercentChange1d: 0.0862498076183525, + }, + '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48': { + tokenAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', + currency: 'ETH', + id: 'usd-coin', + price: 0.0004185384042093742, + pricePercentChange1d: -0.07612981257899307, + }, + '0xdAC17F958D2ee523a2206206994597C13D831ec7': { + tokenAddress: '0xdAC17F958D2ee523a2206206994597C13D831ec7', + currency: 'ETH', + id: 'tether', + price: 0.0004183549552402562, + pricePercentChange1d: 0.1357979347463155, + }, +}; + +describe('AggregatedPercentageOverview', () => { + beforeEach(() => { + mockGetIntlLocale.mockReturnValue('en-US'); + mockGetCurrentCurrency.mockReturnValue('USD'); + mockGetSelectedAccount.mockReturnValue(selectedAccountMock); + mockGetShouldHideZeroBalanceTokens.mockReturnValue(false); + mockGetTokensMarketData.mockReturnValue(marketDataMock); + + jest.clearAllMocks(); + }); + + describe('render', () => { + it('renders correctly', () => { + (useAccountTotalFiatBalance as jest.Mock).mockReturnValue({ + orderedTokenList: [ + { + iconUrl: './images/eth_logo.svg', + symbol: 'ETH', + fiatBalance: '0', + }, + ], + totalFiatBalance: 0, + }); + const { container } = render(); + expect(container).toMatchSnapshot(); + }); + }); + + it('should display zero percentage and amount if balance is zero', () => { + (useAccountTotalFiatBalance as jest.Mock).mockReturnValue({ + orderedTokenList: [ + { + iconUrl: './images/eth_logo.svg', + symbol: 'ETH', + fiatBalance: '0', + }, + ], + totalFiatBalance: 0, + }); + + render(); + const percentageElement = screen.getByText('(+0.00%)'); + const numberElement = screen.getByText('+$0.00'); + expect(percentageElement).toBeInTheDocument(); + expect(numberElement).toBeInTheDocument(); + }); + + it('should display negative aggregated amount and percentage change with all negative market data', () => { + (useAccountTotalFiatBalance as jest.Mock).mockReturnValue({ + orderedTokenList: [ + { + address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + decimals: 6, + iconUrl: + 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48.png', + name: 'USDC', + occurrences: 16, + symbol: 'USDC', + balance: '11754897', + string: '11.75489', + balanceError: null, + fiatBalance: '11.77', + }, + { + iconUrl: './images/eth_logo.svg', + symbol: 'ETH', + fiatBalance: '10.45', + }, + { + address: '0x6b175474e89094c44da98b954eedeac495271d0f', + decimals: 18, + iconUrl: + 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0x6b175474e89094c44da98b954eedeac495271d0f.png', + name: 'Dai Stablecoin', + occurrences: 17, + symbol: 'DAI', + balance: '6520850325578202013', + string: '6.52085', + balanceError: null, + fiatBalance: '6.53', + }, + { + address: '0xdac17f958d2ee523a2206206994597c13d831ec7', + decimals: 6, + iconUrl: + 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0xdac17f958d2ee523a2206206994597c13d831ec7.png', + name: 'Tether USD', + occurrences: 15, + symbol: 'USDT', + balance: '3379966', + string: '3.37996', + balanceError: null, + fiatBalance: '3.38', + }, + ], + totalFiatBalance: 32.13, + }); + const expectedAmountChange = '-$0.09'; + const expectedPercentageChange = '(-0.29%)'; + render(); + const percentageElement = screen.getByText(expectedPercentageChange); + const numberElement = screen.getByText(expectedAmountChange); + expect(percentageElement).toBeInTheDocument(); + expect(numberElement).toBeInTheDocument(); + }); + + it('should display positive aggregated amount and percentage change with all positive market data', () => { + (useAccountTotalFiatBalance as jest.Mock).mockReturnValue({ + orderedTokenList: [ + { + address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + decimals: 6, + iconUrl: + 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48.png', + name: 'USDC', + occurrences: 16, + symbol: 'USDC', + balance: '11754897', + string: '11.75489', + balanceError: null, + fiatBalance: '11.77', + }, + { + iconUrl: './images/eth_logo.svg', + symbol: 'ETH', + fiatBalance: '10.45', + }, + { + address: '0x6b175474e89094c44da98b954eedeac495271d0f', + decimals: 18, + iconUrl: + 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0x6b175474e89094c44da98b954eedeac495271d0f.png', + name: 'Dai Stablecoin', + occurrences: 17, + symbol: 'DAI', + balance: '6520850325578202013', + string: '6.52085', + balanceError: null, + fiatBalance: '6.53', + }, + { + address: '0xdac17f958d2ee523a2206206994597c13d831ec7', + decimals: 6, + iconUrl: + 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0xdac17f958d2ee523a2206206994597c13d831ec7.png', + name: 'Tether USD', + occurrences: 15, + symbol: 'USDT', + balance: '3379966', + string: '3.37996', + balanceError: null, + fiatBalance: '3.38', + }, + ], + totalFiatBalance: 32.13, + }); + mockGetTokensMarketData.mockReturnValue(positiveMarketDataMock); + const expectedAmountChange = '+$0.09'; + const expectedPercentageChange = '(+0.29%)'; + render(); + const percentageElement = screen.getByText(expectedPercentageChange); + const numberElement = screen.getByText(expectedAmountChange); + expect(percentageElement).toBeInTheDocument(); + expect(numberElement).toBeInTheDocument(); + }); + + it('should display correct aggregated amount and percentage change with positive and negative market data', () => { + (useAccountTotalFiatBalance as jest.Mock).mockReturnValue({ + orderedTokenList: [ + { + address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + decimals: 6, + iconUrl: + 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48.png', + name: 'USDC', + occurrences: 16, + symbol: 'USDC', + balance: '11754897', + string: '11.75489', + balanceError: null, + fiatBalance: '11.77', + }, + { + iconUrl: './images/eth_logo.svg', + symbol: 'ETH', + fiatBalance: '10.45', + }, + { + address: '0x6b175474e89094c44da98b954eedeac495271d0f', + decimals: 18, + iconUrl: + 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0x6b175474e89094c44da98b954eedeac495271d0f.png', + name: 'Dai Stablecoin', + occurrences: 17, + symbol: 'DAI', + balance: '6520850325578202013', + string: '6.52085', + balanceError: null, + fiatBalance: '6.53', + }, + { + address: '0xdac17f958d2ee523a2206206994597c13d831ec7', + decimals: 6, + iconUrl: + 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0xdac17f958d2ee523a2206206994597c13d831ec7.png', + name: 'Tether USD', + occurrences: 15, + symbol: 'USDT', + balance: '3379966', + string: '3.37996', + balanceError: null, + fiatBalance: '3.38', + }, + ], + totalFiatBalance: 32.13, + }); + mockGetTokensMarketData.mockReturnValue(mixedMarketDataMock); + const expectedAmountChange = '-$0.07'; + const expectedPercentageChange = '(-0.23%)'; + render(); + const percentageElement = screen.getByText(expectedPercentageChange); + const numberElement = screen.getByText(expectedAmountChange); + expect(percentageElement).toBeInTheDocument(); + expect(numberElement).toBeInTheDocument(); + }); + + it('should display correct aggregated amount and percentage when one ERC20 fiatBalance is undefined', () => { + (useAccountTotalFiatBalance as jest.Mock).mockReturnValue({ + orderedTokenList: [ + { + iconUrl: './images/eth_logo.svg', + symbol: 'ETH', + fiatBalance: '21.12', + }, + { + symbol: 'USDC', + decimals: 6, + occurrences: 16, + iconUrl: + 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48.png', + address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + name: 'USDC', + balance: '11411142', + string: '11.41114', + balanceError: null, + fiatBalance: '11.4', + }, + { + symbol: 'DAI', + decimals: 18, + occurrences: 17, + iconUrl: + 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0x6b175474e89094c44da98b954eedeac495271d0f.png', + address: '0x6b175474e89094c44da98b954eedeac495271d0f', + name: 'Dai Stablecoin', + balance: '3000000000000000000', + string: '3', + balanceError: null, + fiatBalance: '3', + }, + { + symbol: 'OMNI', + decimals: 18, + iconUrl: + 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0x36e66fbbce51e4cd5bd3c62b637eb411b18949d4.png', + address: '0x36e66fbbce51e4cd5bd3c62b637eb411b18949d4', + name: 'Omni Network', + balance: '2161382310000000000', + string: '2.16138', + balanceError: null, + }, + ], + totalFiatBalance: 35.52, + }); + mockGetTokensMarketData.mockReturnValue({ + '0x0000000000000000000000000000000000000000': { + tokenAddress: '0x0000000000000000000000000000000000000000', + currency: 'ETH', + id: 'ethereum', + price: 0.9999598743668833, + marketCap: 120194359.82507178, + allTimeHigh: 2.070186924097962, + allTimeLow: 0.00018374327407907974, + totalVolume: 5495085.267342095, + high1d: 1.022994674939226, + low1d: 0.9882430202069277, + circulatingSupply: 120317181.32366, + dilutedMarketCap: 120194359.82507178, + marketCapPercentChange1d: -1.46534, + priceChange1d: -43.27897193472654, + pricePercentChange1h: 0.39406716228961414, + pricePercentChange1d: -1.8035792813549656, + }, + '0x6B175474E89094C44Da98b954EedeAC495271d0F': { + tokenAddress: '0x6B175474E89094C44Da98b954EedeAC495271d0F', + currency: 'ETH', + id: 'dai', + price: 0.00042436994422149745, + marketCap: 2179091.2357524647, + allTimeHigh: 0.0005177313319502269, + allTimeLow: 0.0003742773160055919, + totalVolume: 25770.310026921918, + high1d: 0.00042564305405416193, + low1d: 0.000422254035679609, + circulatingSupply: 5131139277.03183, + dilutedMarketCap: 2179157.495602445, + marketCapPercentChange1d: -2.78163, + priceChange1d: -0.000450570064429501, + pricePercentChange1h: 0.044140824068107716, + pricePercentChange1d: -0.045030461437871275, + }, + '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48': { + tokenAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', + currency: 'ETH', + id: 'usd-coin', + price: 0.00042436994422149745, + marketCap: 14845337.78504687, + allTimeHigh: 0.000496512834739152, + allTimeLow: 0.00037244700843616456, + totalVolume: 2995848.8988073817, + high1d: 0.0004252186841099404, + low1d: 0.00042304081755619566, + circulatingSupply: 34942418774.2545, + dilutedMarketCap: 14849047.51464122, + marketCapPercentChange1d: 0.25951, + priceChange1d: -0.000469409459860959, + }, + }); + const expectedAmountChange = '-$0.39'; + const expectedPercentageChange = '(-1.08%)'; + render(); + const percentageElement = screen.getByText(expectedPercentageChange); + const numberElement = screen.getByText(expectedAmountChange); + expect(percentageElement).toBeInTheDocument(); + expect(numberElement).toBeInTheDocument(); + }); + it('should display correct aggregated amount and percentage when the native fiatBalance is undefined', () => { + (useAccountTotalFiatBalance as jest.Mock).mockReturnValue({ + orderedTokenList: [ + { + iconUrl: './images/eth_logo.svg', + symbol: 'ETH', + }, + { + symbol: 'USDC', + decimals: 6, + occurrences: 16, + iconUrl: + 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48.png', + address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + name: 'USDC', + balance: '11411142', + string: '11.41114', + balanceError: null, + fiatBalance: '11.4', + }, + { + symbol: 'DAI', + decimals: 18, + occurrences: 17, + iconUrl: + 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0x6b175474e89094c44da98b954eedeac495271d0f.png', + address: '0x6b175474e89094c44da98b954eedeac495271d0f', + name: 'Dai Stablecoin', + balance: '3000000000000000000', + string: '3', + balanceError: null, + fiatBalance: '20', + }, + ], + totalFiatBalance: 31.4, + }); + mockGetTokensMarketData.mockReturnValue({ + '0x0000000000000000000000000000000000000000': { + tokenAddress: '0x0000000000000000000000000000000000000000', + currency: 'ETH', + id: 'ethereum', + price: 0.9999598743668833, + marketCap: 120194359.82507178, + allTimeHigh: 2.070186924097962, + allTimeLow: 0.00018374327407907974, + totalVolume: 5495085.267342095, + high1d: 1.022994674939226, + low1d: 0.9882430202069277, + circulatingSupply: 120317181.32366, + dilutedMarketCap: 120194359.82507178, + marketCapPercentChange1d: -1.46534, + priceChange1d: -43.27897193472654, + pricePercentChange1h: 0.39406716228961414, + pricePercentChange1d: -1.8035792813549656, + }, + '0x6B175474E89094C44Da98b954EedeAC495271d0F': { + tokenAddress: '0x6B175474E89094C44Da98b954EedeAC495271d0F', + currency: 'ETH', + id: 'dai', + price: 0.00042436994422149745, + marketCap: 2179091.2357524647, + allTimeHigh: 0.0005177313319502269, + allTimeLow: 0.0003742773160055919, + totalVolume: 25770.310026921918, + high1d: 0.00042564305405416193, + low1d: 0.000422254035679609, + circulatingSupply: 5131139277.03183, + dilutedMarketCap: 2179157.495602445, + marketCapPercentChange1d: -2.78163, + priceChange1d: -0.000450570064429501, + pricePercentChange1h: 0.044140824068107716, + pricePercentChange1d: -0.045030461437871275, + }, + '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48': { + tokenAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', + currency: 'ETH', + id: 'usd-coin', + price: 0.00042436994422149745, + marketCap: 14845337.78504687, + allTimeHigh: 0.000496512834739152, + allTimeLow: 0.00037244700843616456, + totalVolume: 2995848.8988073817, + high1d: 0.0004252186841099404, + low1d: 0.00042304081755619566, + circulatingSupply: 34942418774.2545, + dilutedMarketCap: 14849047.51464122, + marketCapPercentChange1d: 0.25951, + priceChange1d: -0.000469409459860959, + }, + }); + const expectedAmountChange = '-$0.01'; + const expectedPercentageChange = '(-0.03%)'; + render(); + const percentageElement = screen.getByText(expectedPercentageChange); + const numberElement = screen.getByText(expectedAmountChange); + expect(percentageElement).toBeInTheDocument(); + expect(numberElement).toBeInTheDocument(); + }); +}); diff --git a/ui/components/app/wallet-overview/aggregated-percentage-overview.tsx b/ui/components/app/wallet-overview/aggregated-percentage-overview.tsx new file mode 100644 index 000000000000..e69ff1ed514d --- /dev/null +++ b/ui/components/app/wallet-overview/aggregated-percentage-overview.tsx @@ -0,0 +1,143 @@ +import React, { useMemo } from 'react'; +import { useSelector } from 'react-redux'; + +import { zeroAddress, toChecksumAddress } from 'ethereumjs-util'; +import { + getCurrentCurrency, + getSelectedAccount, + getShouldHideZeroBalanceTokens, + getTokensMarketData, +} from '../../../selectors'; + +import { useAccountTotalFiatBalance } from '../../../hooks/useAccountTotalFiatBalance'; +// TODO: Remove restricted import +// eslint-disable-next-line import/no-restricted-paths +import { formatValue, isValidAmount } from '../../../../app/scripts/lib/util'; +import { getIntlLocale } from '../../../ducks/locale/locale'; +import { + Display, + TextColor, + TextVariant, +} from '../../../helpers/constants/design-system'; +import { Box, Text } from '../../component-library'; +import { getCalculatedTokenAmount1dAgo } from '../../../helpers/utils/util'; + +// core already has this exported type but its not yet available in this version +// todo remove this and use core type once available +type MarketDataDetails = { + tokenAddress: string; + pricePercentChange1d: number; +}; + +export const AggregatedPercentageOverview = () => { + const tokensMarketData: Record = + useSelector(getTokensMarketData); + const locale = useSelector(getIntlLocale); + const fiatCurrency = useSelector(getCurrentCurrency); + const selectedAccount = useSelector(getSelectedAccount); + const shouldHideZeroBalanceTokens = useSelector( + getShouldHideZeroBalanceTokens, + ); + // Get total balance (native + tokens) + const { totalFiatBalance, orderedTokenList } = useAccountTotalFiatBalance( + selectedAccount, + shouldHideZeroBalanceTokens, + ); + + // Memoize the calculation to avoid recalculating unless orderedTokenList or tokensMarketData changes + const totalFiat1dAgo = useMemo(() => { + return orderedTokenList.reduce((total1dAgo, item) => { + if (item.address) { + // This is a regular ERC20 token + // find the relevant pricePercentChange1d in tokensMarketData + // Find the corresponding market data for the token by filtering the values of the tokensMarketData object + const found = tokensMarketData[toChecksumAddress(item.address)]; + + const tokenFiat1dAgo = getCalculatedTokenAmount1dAgo( + item.fiatBalance, + found?.pricePercentChange1d, + ); + return total1dAgo + Number(tokenFiat1dAgo); + } + // native token + const nativePricePercentChange1d = + tokensMarketData?.[zeroAddress()]?.pricePercentChange1d; + const nativeFiat1dAgo = getCalculatedTokenAmount1dAgo( + item.fiatBalance, + nativePricePercentChange1d, + ); + return total1dAgo + Number(nativeFiat1dAgo); + }, 0); // Initial total1dAgo is 0 + }, [orderedTokenList, tokensMarketData]); // Dependencies: recalculate if orderedTokenList or tokensMarketData changes + + const totalBalance: number = Number(totalFiatBalance); + const totalBalance1dAgo = totalFiat1dAgo; + + const amountChange = totalBalance - totalBalance1dAgo; + const percentageChange = (amountChange / totalBalance1dAgo) * 100 || 0; + + const formattedPercentChange = formatValue( + amountChange === 0 ? 0 : percentageChange, + true, + ); + + let formattedAmountChange = ''; + if (isValidAmount(amountChange)) { + formattedAmountChange = (amountChange as number) >= 0 ? '+' : ''; + + const options = { + notation: 'compact', + compactDisplay: 'short', + maximumFractionDigits: 2, + } as const; + + try { + // For currencies compliant with ISO 4217 Standard + formattedAmountChange += `${Intl.NumberFormat(locale, { + ...options, + style: 'currency', + currency: fiatCurrency, + }).format(amountChange as number)} `; + } catch { + // Non-standard Currency Codes + formattedAmountChange += `${Intl.NumberFormat(locale, { + ...options, + minimumFractionDigits: 2, + style: 'decimal', + }).format(amountChange as number)} `; + } + } + + let color = TextColor.textDefault; + + if (isValidAmount(amountChange)) { + if ((amountChange as number) === 0) { + color = TextColor.textDefault; + } else if ((amountChange as number) > 0) { + color = TextColor.successDefault; + } else { + color = TextColor.errorDefault; + } + } + return ( + + + {formattedAmountChange} + + + {formattedPercentChange} + + + ); +}; diff --git a/ui/components/app/wallet-overview/btc-overview.test.tsx b/ui/components/app/wallet-overview/btc-overview.test.tsx index 5adbe8dcc927..2bc93e5e54eb 100644 --- a/ui/components/app/wallet-overview/btc-overview.test.tsx +++ b/ui/components/app/wallet-overview/btc-overview.test.tsx @@ -24,6 +24,7 @@ const BTC_OVERVIEW_PRIMARY_CURRENCY = 'coin-overview__primary-currency'; const mockMetaMetricsId = 'deadbeef'; const mockNonEvmBalance = '1'; +const mockNonEvmBalanceUsd = '1.00'; const mockNonEvmAccount = { address: 'bc1qwl8399fz829uqvqly9tcatgrgtwp3udnhxfq4k', id: '542490c8-d178-433b-9f31-f680b11f45a5', @@ -112,7 +113,7 @@ describe('BtcOverview', () => { setBackgroundConnection({ setBridgeFeatureFlags: jest.fn() } as never); }); - it('shows the primary balance', async () => { + it('shows the primary balance as BTC when showNativeTokenAsMainBalance if true', async () => { const { queryByTestId, queryByText } = renderWithProvider( , getStore(), @@ -125,6 +126,27 @@ describe('BtcOverview', () => { expect(queryByText('*')).toBeInTheDocument(); }); + it('shows the primary balance as fiat when showNativeTokenAsMainBalance if false', async () => { + const { queryByTestId, queryByText } = renderWithProvider( + , + getStore({ + metamask: { + ...mockMetamaskStore, + // The balances won't be available + preferences: { + showNativeTokenAsMainBalance: false, + }, + }, + }), + ); + + const primaryBalance = queryByTestId(BTC_OVERVIEW_PRIMARY_CURRENCY); + expect(primaryBalance).toBeInTheDocument(); + expect(primaryBalance).toHaveTextContent(`$${mockNonEvmBalanceUsd}USD`); + // For now we consider balance to be always cached + expect(queryByText('*')).toBeInTheDocument(); + }); + it('shows a spinner if balance is not available', async () => { const { container } = renderWithProvider( , diff --git a/ui/components/app/wallet-overview/coin-buttons.stories.js b/ui/components/app/wallet-overview/coin-buttons.stories.js new file mode 100644 index 000000000000..40a6879673a8 --- /dev/null +++ b/ui/components/app/wallet-overview/coin-buttons.stories.js @@ -0,0 +1,37 @@ +import React from 'react'; +import CoinButtons from './coin-buttons'; + +export default { + title: 'Components/App/WalletOverview/CoinButtons', + args: { + chainId: '1', + trackingLocation: 'home', + isSwapsChain: true, + isSigningEnabled: true, + isBridgeChain: true, + isBuyableChain: true, + defaultSwapsToken: { + symbol: 'ETH', + name: 'Ether', + address: '0x0000000000000000000000000000000000000000', + decimals: 18, + iconUrl: './images/eth_logo.svg', + balance: '3093640202103801', + string: '0.0031', + }, + classPrefix: 'coin', + iconButtonClassName: '', + }, + component: CoinButtons, + parameters: { + docs: { + description: { + component: 'A component that displays coin buttons', + }, + }, + }, +}; + +const Template = (args) => ; + +export const Default = Template.bind({}); diff --git a/ui/components/app/wallet-overview/coin-buttons.tsx b/ui/components/app/wallet-overview/coin-buttons.tsx index 426713f5d086..0e1947d023f3 100644 --- a/ui/components/app/wallet-overview/coin-buttons.tsx +++ b/ui/components/app/wallet-overview/coin-buttons.tsx @@ -60,7 +60,7 @@ import { IconColor, JustifyContent, } from '../../../helpers/constants/design-system'; -import { Box, Icon, IconName } from '../../component-library'; +import { Box, Icon, IconName, IconSize } from '../../component-library'; import IconButton from '../../ui/icon-button'; ///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask) import useRamps from '../../../hooks/ramps/useRamps/useRamps'; @@ -79,6 +79,7 @@ const CoinButtons = ({ defaultSwapsToken, ///: END:ONLY_INCLUDE_IF classPrefix = 'coin', + iconButtonClassName = '', }: { chainId: `0x${string}` | CaipChainId | number; trackingLocation: string; @@ -90,6 +91,7 @@ const CoinButtons = ({ defaultSwapsToken?: SwapsEthToken; ///: END:ONLY_INCLUDE_IF classPrefix?: string; + iconButtonClassName?: string; }) => { const t = useContext(I18nContext); const dispatch = useDispatch(); @@ -191,15 +193,27 @@ const CoinButtons = ({ <> } + iconButtonClassName={iconButtonClassName} + Icon={ + + } label={t('stake')} onClick={handleMmiStakingOnClick} /> {mmiPortfolioEnabled && ( + } label={t('portfolio')} onClick={handleMmiPortfolioOnClick} @@ -308,8 +322,13 @@ const CoinButtons = ({ ///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask) + } disabled={!isBuyableChain} data-testid={`${classPrefix}-overview-buy`} @@ -327,9 +346,9 @@ const CoinButtons = ({ renderInstitutionalButtons() ///: END:ONLY_INCLUDE_IF } - } onClick={handleSwapOnClick} @@ -350,10 +370,15 @@ const CoinButtons = ({ ///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask) + } label={t('bridge')} onClick={handleBridgeOnClick} @@ -365,11 +390,13 @@ const CoinButtons = ({ } } disabled={!isSigningEnabled} @@ -389,11 +416,13 @@ const CoinButtons = ({ )} } label={t('receive')} diff --git a/ui/components/app/wallet-overview/coin-overview.tsx b/ui/components/app/wallet-overview/coin-overview.tsx index 0293876539e1..c369ef0e89fd 100644 --- a/ui/components/app/wallet-overview/coin-overview.tsx +++ b/ui/components/app/wallet-overview/coin-overview.tsx @@ -1,17 +1,35 @@ import React, { useContext, + useState, ///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask) useCallback, ///: END:ONLY_INCLUDE_IF } from 'react'; -import { useSelector } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import classnames from 'classnames'; import { zeroAddress } from 'ethereumjs-util'; import { CaipChainId } from '@metamask/utils'; import type { Hex } from '@metamask/utils'; + +import { + Box, + ButtonIcon, + ButtonIconSize, + ButtonLink, + ButtonLinkSize, + IconName, + Popover, + PopoverPosition, + Text, +} from '../../component-library'; +import { + AlignItems, + Display, + JustifyContent, + TextAlign, + TextVariant, +} from '../../../helpers/constants/design-system'; ///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask) -import { Icon, IconName, IconSize } from '../../component-library'; -import { IconColor } from '../../../helpers/constants/design-system'; import { getPortfolioUrl } from '../../../helpers/utils/portfolio'; import { MetaMetricsContext } from '../../../contexts/metametrics'; import { @@ -23,10 +41,14 @@ import { import { I18nContext } from '../../../contexts/i18n'; import Tooltip from '../../ui/tooltip'; import UserPreferencedCurrencyDisplay from '../user-preferenced-currency-display'; -import { PRIMARY, SECONDARY } from '../../../helpers/constants/common'; +import { PRIMARY } from '../../../helpers/constants/common'; import { getPreferences, + getSelectedAccount, + getShouldHideZeroBalanceTokens, getTokensMarketData, + getIsTestnet, + getShouldShowAggregatedBalancePopover, ///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask) getDataCollectionForMarketing, getMetaMetricsId, @@ -35,16 +57,17 @@ import { ///: END:ONLY_INCLUDE_IF } from '../../../selectors'; import Spinner from '../../ui/spinner'; -import { useIsOriginalNativeTokenSymbol } from '../../../hooks/useIsOriginalNativeTokenSymbol'; -import { showPrimaryCurrency } from '../../../../shared/modules/currency-display.utils'; + import { PercentageAndAmountChange } from '../../multichain/token-list-item/price/percentage-and-amount-change/percentage-and-amount-change'; -import { - getMultichainIsEvm, - getMultichainProviderConfig, - getMultichainShouldShowFiat, -} from '../../../selectors/multichain'; +import { getMultichainIsEvm } from '../../../selectors/multichain'; +import { useAccountTotalFiatBalance } from '../../../hooks/useAccountTotalFiatBalance'; +import { setAggregatedBalancePopoverShown } from '../../../store/actions'; +import { useTheme } from '../../../hooks/useTheme'; +import { getSpecificSettingsRoute } from '../../../helpers/utils/settings-search'; +import { useI18nContext } from '../../../hooks/useI18nContext'; import WalletOverview from './wallet-overview'; import CoinButtons from './coin-buttons'; +import { AggregatedPercentageOverview } from './aggregated-percentage-overview'; export type CoinOverviewProps = { balance: string; @@ -83,7 +106,7 @@ export const CoinOverview = ({ } ///: END:ONLY_INCLUDE_IF - const t = useContext(I18nContext); + const t: ReturnType = useContext(I18nContext); ///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask) const trackEvent = useContext(MetaMetricsContext); @@ -91,19 +114,61 @@ export const CoinOverview = ({ const metaMetricsId = useSelector(getMetaMetricsId); const isMetaMetricsEnabled = useSelector(getParticipateInMetaMetrics); const isMarketingEnabled = useSelector(getDataCollectionForMarketing); + ///: END:ONLY_INCLUDE_IF - const isEvm = useSelector(getMultichainIsEvm); - const showFiat = useSelector(getMultichainShouldShowFiat); - const { useNativeCurrencyAsPrimaryCurrency } = useSelector(getPreferences); - const { ticker, type, rpcUrl } = useSelector(getMultichainProviderConfig); - const isOriginalNativeSymbol = useIsOriginalNativeTokenSymbol( - chainId, - ticker, - type, - rpcUrl, + const showNativeTokenAsMainBalanceRoute = getSpecificSettingsRoute( + t, + t('general'), + t('showNativeTokenAsMainBalance'), ); + const theme = useTheme(); + const dispatch = useDispatch(); + + const shouldShowPopover = useSelector(getShouldShowAggregatedBalancePopover); + const isTestnet = useSelector(getIsTestnet); + const { showFiatInTestnets } = useSelector(getPreferences); + + const selectedAccount = useSelector(getSelectedAccount); + const shouldHideZeroBalanceTokens = useSelector( + getShouldHideZeroBalanceTokens, + ); + const { totalFiatBalance, loading } = useAccountTotalFiatBalance( + selectedAccount, + shouldHideZeroBalanceTokens, + ); + + const { showNativeTokenAsMainBalance } = useSelector(getPreferences); + + const isEvm = useSelector(getMultichainIsEvm); + const isNotAggregatedFiatBalance = + showNativeTokenAsMainBalance || isTestnet || !isEvm; + let balanceToDisplay; + if (isNotAggregatedFiatBalance) { + balanceToDisplay = balance; + } else if (!loading) { + balanceToDisplay = totalFiatBalance; + } + const tokensMarketData = useSelector(getTokensMarketData); + const [isOpen, setIsOpen] = useState(true); + + const handleMouseEnter = () => { + setIsOpen(true); + }; + + const handleClick = () => { + setIsOpen(!isOpen); + dispatch(setAggregatedBalancePopoverShown()); + }; + + const [referenceElement, setReferenceElement] = + useState(null); + const setBoxRef = (ref: HTMLSpanElement | null) => { + if (ref) { + setReferenceElement(ref); + } + }; ///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask) const handlePortfolioOnClick = useCallback(() => { @@ -126,6 +191,52 @@ export const CoinOverview = ({ }, [isMarketingEnabled, isMetaMetricsEnabled, metaMetricsId, trackEvent]); ///: END:ONLY_INCLUDE_IF + const renderPercentageAndAmountChange = () => { + if (isEvm) { + if (showNativeTokenAsMainBalance) { + return ( + + + { + ///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask) + + {t('portfolio')} + + ///: END:ONLY_INCLUDE_IF + } + + ); + } + return ( + + + { + ///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask) + + {t('portfolio')} + + ///: END:ONLY_INCLUDE_IF + } + + ); + } + return null; + }; + return (
-
- {balance ? ( +
+ {balanceToDisplay ? ( ) : ( @@ -168,43 +280,66 @@ export const CoinOverview = ({ )}
-
- {showFiat && isOriginalNativeSymbol && balance && ( - - )} - { - ///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask) -
- {t('portfolio')} - -
- ///: END:ONLY_INCLUDE_IF - } -
- {isEvm && ( - - )} + {shouldShowPopover && + (!isTestnet || (isTestnet && showFiatInTestnets)) && + !showNativeTokenAsMainBalance ? ( + + + + + {t('yourBalanceIsAggregated')} + + + + + + {t('aggregatedBalancePopover', [ + + {t('settings')} + , + ])} + + + + ) : null} + + {renderPercentageAndAmountChange()}
} @@ -221,6 +356,7 @@ export const CoinOverview = ({ defaultSwapsToken, ///: END:ONLY_INCLUDE_IF classPrefix, + iconButtonClassName: `${classPrefix}-overview__icon-button`, }} /> } diff --git a/ui/components/app/wallet-overview/eth-overview.test.js b/ui/components/app/wallet-overview/eth-overview.test.js index a30654796aa4..cea749a366db 100644 --- a/ui/components/app/wallet-overview/eth-overview.test.js +++ b/ui/components/app/wallet-overview/eth-overview.test.js @@ -47,7 +47,7 @@ describe('EthOverview', () => { }, }, preferences: { - useNativeCurrencyAsPrimaryCurrency: true, + showNativeTokenAsMainBalance: true, }, useExternalServices: true, useCurrencyRateCheck: true, diff --git a/ui/components/app/wallet-overview/index.scss b/ui/components/app/wallet-overview/index.scss index bbbf57075c24..4759af1ffa8c 100644 --- a/ui/components/app/wallet-overview/index.scss +++ b/ui/components/app/wallet-overview/index.scss @@ -3,11 +3,9 @@ .wallet-overview { display: flex; justify-content: space-between; - align-items: center; + align-items: start; flex: 1; - min-height: 209px; min-width: 0; - padding-top: 10px; flex-direction: column; width: 100%; @@ -16,30 +14,26 @@ display: flex; gap: 4px; flex-direction: column; - align-items: center; + align-items: start; width: 100%; } - &__buttons { - display: flex; - flex-direction: row; - height: 68px; - margin-bottom: 24px; + &__icon_button { + margin-top: 0 !important; } - &__portfolio_button { + &__buttons { display: flex; flex-direction: row; - gap: 6px; - cursor: pointer; - align-items: center; - color: var(--color-primary-default); + height: 100%; + margin-bottom: 16px; + padding: 0 16px; } &__currency-wrapper { display: flex; flex-direction: row; - gap: 10px; + gap: 8px; } } @@ -61,14 +55,17 @@ display: flex; flex-direction: column; min-width: 0; - gap: 4px; position: relative; - align-items: center; + align-items: start; margin: 16px 0; padding: 0 16px; max-width: 326px; } + &__icon-button { + margin-top: 0 !important; + } + &__primary-container { display: flex; max-width: inherit; @@ -80,17 +77,13 @@ @include design-system.H2; color: var(--color-text-default); + font-weight: 700; } &__cached-star { margin-left: 4px; } - &__portfolio-button { - height: inherit; - padding-inline-start: 16px; - } - &__cached-balance, &__cached-star { color: var(--color-warning-default); @@ -158,12 +151,14 @@ color: var(--color-text-alternative); } - &__portfolio-button { - height: inherit; - padding-inline-start: 16px; - } - &__button:last-of-type { margin-right: 0; } } + +.balance-popover { + &__container { + z-index: design-system.$modal-z-index; + margin-top: -4px; + } +} diff --git a/ui/components/institutional/interactive-replacement-token-modal/interactive-replacement-token-modal.stories.tsx b/ui/components/institutional/interactive-replacement-token-modal/interactive-replacement-token-modal.stories.tsx index 862b98d350f3..f0327aaa227f 100644 --- a/ui/components/institutional/interactive-replacement-token-modal/interactive-replacement-token-modal.stories.tsx +++ b/ui/components/institutional/interactive-replacement-token-modal/interactive-replacement-token-modal.stories.tsx @@ -47,9 +47,7 @@ const customData = { oldRefreshToken: 'abc', url: 'https://saturn-custody-ui.dev.metamask-institutional.io', }, - preferences: { - useNativeCurrencyAsPrimaryCurrency: true, - }, + preferences: {}, }, }; diff --git a/ui/components/institutional/interactive-replacement-token-modal/interactive-replacement-token-modal.test.tsx b/ui/components/institutional/interactive-replacement-token-modal/interactive-replacement-token-modal.test.tsx index 535b21f2e69b..97eaa364f104 100644 --- a/ui/components/institutional/interactive-replacement-token-modal/interactive-replacement-token-modal.test.tsx +++ b/ui/components/institutional/interactive-replacement-token-modal/interactive-replacement-token-modal.test.tsx @@ -48,9 +48,7 @@ describe('Interactive Replacement Token Modal', function () { oldRefreshToken: 'abc', url: 'https://saturn-custody-ui.dev.metamask-institutional.io', }, - preferences: { - useNativeCurrencyAsPrimaryCurrency: true, - }, + preferences: {}, }, }; diff --git a/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.stories.tsx b/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.stories.tsx index fd169d23881f..381c4573add3 100644 --- a/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.stories.tsx +++ b/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.stories.tsx @@ -14,9 +14,7 @@ const customData = { '81f96a88b6cbc5f50d3864122349fa9a9755833ee82a7e3cf6f268c78aab51ab', url: 'url', }, - preferences: { - useNativeCurrencyAsPrimaryCurrency: true, - }, + preferences: {}, keyrings: [ { type: 'Custody - Saturn', diff --git a/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.test.tsx b/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.test.tsx index 77424a95e86e..4c132ecbd414 100644 --- a/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.test.tsx +++ b/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.test.tsx @@ -72,9 +72,7 @@ describe('Interactive Replacement Token Notification', () => { }, isUnlocked: false, interactiveReplacementToken: { oldRefreshToken: 'abc' }, - preferences: { - useNativeCurrencyAsPrimaryCurrency: true, - }, + preferences: {}, keyrings: [ { type: KeyringType.imported, diff --git a/ui/components/multichain/account-list-menu/account-list-menu.test.tsx b/ui/components/multichain/account-list-menu/account-list-menu.test.tsx index 0f6b64f557f2..7a849577dfa4 100644 --- a/ui/components/multichain/account-list-menu/account-list-menu.test.tsx +++ b/ui/components/multichain/account-list-menu/account-list-menu.test.tsx @@ -105,7 +105,6 @@ describe('AccountListMenu', () => { jest .spyOn(reactRouterDom, 'useHistory') .mockImplementation() - // @ts-expect-error mocking history return .mockReturnValue({ push: historyPushMock }); }); diff --git a/ui/components/multichain/account-list-menu/account-list-menu.tsx b/ui/components/multichain/account-list-menu/account-list-menu.tsx index 4e561ed42245..99051042d2dd 100644 --- a/ui/components/multichain/account-list-menu/account-list-menu.tsx +++ b/ui/components/multichain/account-list-menu/account-list-menu.tsx @@ -59,6 +59,7 @@ import { getIsAddSnapAccountEnabled, ///: END:ONLY_INCLUDE_IF ///: BEGIN:ONLY_INCLUDE_IF(build-flask) + getIsWatchEthereumAccountEnabled, getIsBitcoinSupportEnabled, getIsBitcoinTestnetSupportEnabled, ///: END:ONLY_INCLUDE_IF @@ -66,7 +67,6 @@ import { getOriginOfCurrentTab, getSelectedInternalAccount, getUpdatedAndSortedAccounts, - getIsWatchEthereumAccountEnabled, } from '../../../selectors'; import { setSelectedAccount } from '../../../store/actions'; import { @@ -86,6 +86,12 @@ import { getEnvironmentType } from '../../../../app/scripts/lib/util'; import { ENVIRONMENT_TYPE_POPUP } from '../../../../shared/constants/app'; import { getAccountLabel } from '../../../helpers/utils/accounts'; ///: BEGIN:ONLY_INCLUDE_IF(build-flask) +import { + ACCOUNT_WATCHER_NAME, + ACCOUNT_WATCHER_SNAP_ID, + // TODO: Remove restricted import + // eslint-disable-next-line import/no-restricted-paths +} from '../../../../app/scripts/lib/snap-keyring/account-watcher-snap'; import { hasCreatedBtcMainnetAccount, hasCreatedBtcTestnetAccount, @@ -97,12 +103,6 @@ import { AccountConnections, MergedInternalAccount, } from '../../../selectors/selectors.types'; -import { - ACCOUNT_WATCHER_NAME, - ACCOUNT_WATCHER_SNAP_ID, - // TODO: Remove restricted import - // eslint-disable-next-line import/no-restricted-paths -} from '../../../../app/scripts/lib/snap-keyring/account-watcher-snap'; import { HiddenAccountList } from './hidden-account-list'; const ACTION_MODES = { @@ -112,9 +112,9 @@ const ACTION_MODES = { MENU: 'menu', // Displays the add account form controls ADD: 'add', + ///: BEGIN:ONLY_INCLUDE_IF(build-flask) // Displays the add account form controls (for watch-only account) ADD_WATCH_ONLY: 'add-watch-only', - ///: BEGIN:ONLY_INCLUDE_IF(build-flask) // Displays the add account form controls (for bitcoin account) ADD_BITCOIN: 'add-bitcoin', // Same but for testnet @@ -138,9 +138,9 @@ export const getActionTitle = ( switch (actionMode) { case ACTION_MODES.ADD: case ACTION_MODES.MENU: - case ACTION_MODES.ADD_WATCH_ONLY: return t('addAccount'); ///: BEGIN:ONLY_INCLUDE_IF(build-flask) + case ACTION_MODES.ADD_WATCH_ONLY: case ACTION_MODES.ADD_BITCOIN: return t('addAccount'); case ACTION_MODES.ADD_BITCOIN_TESTNET: @@ -231,6 +231,7 @@ export const AccountListMenu = ({ ///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps) const addSnapAccountEnabled = useSelector(getIsAddSnapAccountEnabled); ///: END:ONLY_INCLUDE_IF + ///: BEGIN:ONLY_INCLUDE_IF(build-flask) const isAddWatchEthereumAccountEnabled = useSelector( getIsWatchEthereumAccountEnabled, ); @@ -248,7 +249,7 @@ export const AccountListMenu = ({ onClose(); history.push(`/snaps/view/${encodeURIComponent(ACCOUNT_WATCHER_SNAP_ID)}`); }, [trackEvent, onClose, history]); - ///: BEGIN:ONLY_INCLUDE_IF(build-flask) + const bitcoinSupportEnabled = useSelector(getIsBitcoinSupportEnabled); const bitcoinTestnetSupportEnabled = useSelector( getIsBitcoinTestnetSupportEnabled, @@ -550,19 +551,23 @@ export const AccountListMenu = ({ ///: END:ONLY_INCLUDE_IF } - {isAddWatchEthereumAccountEnabled && ( - - - {t('addEthereumWatchOnlyAccount')} - - - )} + { + ///: BEGIN:ONLY_INCLUDE_IF(build-flask) + isAddWatchEthereumAccountEnabled && ( + + + {t('addEthereumWatchOnlyAccount')} + + + ) + ///: END:ONLY_INCLUDE_IF + } ) : null} {actionMode === ACTION_MODES.LIST ? ( diff --git a/ui/components/multichain/asset-picker-amount/asset-balance/asset-balance-text.test.tsx b/ui/components/multichain/asset-picker-amount/asset-balance/asset-balance-text.test.tsx index 6613bf785b91..be9d58f23968 100644 --- a/ui/components/multichain/asset-picker-amount/asset-balance/asset-balance-text.test.tsx +++ b/ui/components/multichain/asset-picker-amount/asset-balance/asset-balance-text.test.tsx @@ -11,7 +11,6 @@ const store = configureStore({ ...mockSendState, metamask: { ...mockSendState.metamask, - preferences: { useNativeCurrencyAsPrimaryCurrency: true }, }, appState: { ...mockSendState.appState, sendInputCurrencySwitched: false }, }); diff --git a/ui/components/multichain/asset-picker-amount/asset-picker-modal/AssetList.tsx b/ui/components/multichain/asset-picker-amount/asset-picker-modal/AssetList.tsx index 1ea66e917437..9061592cf37c 100644 --- a/ui/components/multichain/asset-picker-amount/asset-picker-modal/AssetList.tsx +++ b/ui/components/multichain/asset-picker-amount/asset-picker-modal/AssetList.tsx @@ -1,10 +1,7 @@ import React from 'react'; import { useSelector } from 'react-redux'; import classnames from 'classnames'; -import { - getPreferences, - getSelectedAccountCachedBalance, -} from '../../../../selectors'; +import { getSelectedAccountCachedBalance } from '../../../../selectors'; import { getNativeCurrency } from '../../../../ducks/metamask/metamask'; import { useUserPreferencedCurrency } from '../../../../hooks/useUserPreferencedCurrency'; import { PRIMARY, SECONDARY } from '../../../../helpers/constants/common'; @@ -46,7 +43,6 @@ export default function AssetList({ const nativeCurrency = useSelector(getNativeCurrency); const balanceValue = useSelector(getSelectedAccountCachedBalance); - const { useNativeCurrencyAsPrimaryCurrency } = useSelector(getPreferences); const { currency: primaryCurrency, @@ -121,11 +117,7 @@ export default function AssetList({ primaryCurrencyProperties.value ?? secondaryCurrencyProperties.value } - tokenSymbol={ - useNativeCurrencyAsPrimaryCurrency - ? primaryCurrency - : secondaryCurrency - } + tokenSymbol={primaryCurrency} secondary={secondaryCurrencyDisplay} tokenImage={token.image} isOriginalTokenSymbol diff --git a/ui/components/multichain/asset-picker-amount/asset-picker-modal/asset-picker-modal.test.tsx b/ui/components/multichain/asset-picker-amount/asset-picker-modal/asset-picker-modal.test.tsx index be0eb8282258..15cc339775c9 100644 --- a/ui/components/multichain/asset-picker-amount/asset-picker-modal/asset-picker-modal.test.tsx +++ b/ui/components/multichain/asset-picker-amount/asset-picker-modal/asset-picker-modal.test.tsx @@ -14,7 +14,6 @@ import { getCurrentChainId, getCurrentCurrency, getNativeCurrencyImage, - getPreferences, getSelectedAccountCachedBalance, getSelectedInternalAccount, getShouldHideZeroBalanceTokens, @@ -134,9 +133,7 @@ describe('AssetPickerModal', () => { if (selector === getTopAssets) { return []; } - if (selector === getPreferences) { - return { useNativeCurrencyAsPrimaryCurrency: false }; - } + if (selector === getSwapsBlockedTokens) { return new Set(['0xtoken1']); } diff --git a/ui/components/multichain/asset-picker-amount/nft-input/nft-input.test.tsx b/ui/components/multichain/asset-picker-amount/nft-input/nft-input.test.tsx index 05289c604aa3..08e4875ce149 100644 --- a/ui/components/multichain/asset-picker-amount/nft-input/nft-input.test.tsx +++ b/ui/components/multichain/asset-picker-amount/nft-input/nft-input.test.tsx @@ -5,15 +5,11 @@ import mockSendState from '../../../../../test/data/mock-send-state.json'; import configureStore from '../../../../store/store'; import { NFTInput } from './nft-input'; -const createStore = ({ - useNativeCurrencyAsPrimaryCurrency, - sendInputCurrencySwitched, -}: Record) => +const createStore = ({ sendInputCurrencySwitched }: Record) => configureStore({ ...mockSendState, metamask: { ...mockSendState.metamask, - preferences: { useNativeCurrencyAsPrimaryCurrency }, }, appState: { ...mockSendState.appState, sendInputCurrencySwitched }, }); @@ -25,7 +21,6 @@ describe('NFTInput', () => { const { asFragment } = render( @@ -39,7 +34,6 @@ describe('NFTInput', () => { const { getByTestId } = render( @@ -56,7 +50,6 @@ describe('NFTInput', () => { const { queryByTestId } = render( diff --git a/ui/components/multichain/asset-picker-amount/swappable-currency-input/swappable-currency-input.test.tsx b/ui/components/multichain/asset-picker-amount/swappable-currency-input/swappable-currency-input.test.tsx index 693361354f91..8dadccbaf247 100644 --- a/ui/components/multichain/asset-picker-amount/swappable-currency-input/swappable-currency-input.test.tsx +++ b/ui/components/multichain/asset-picker-amount/swappable-currency-input/swappable-currency-input.test.tsx @@ -6,15 +6,11 @@ import mockSendState from '../../../../../test/data/mock-send-state.json'; import configureStore from '../../../../store/store'; import { SwappableCurrencyInput } from './swappable-currency-input'; -const createStore = ({ - useNativeCurrencyAsPrimaryCurrency, - sendInputCurrencySwitched, -}: Record) => +const createStore = ({ sendInputCurrencySwitched }: Record) => configureStore({ ...mockSendState, metamask: { ...mockSendState.metamask, - preferences: { useNativeCurrencyAsPrimaryCurrency }, marketData: { ...mockSendState.metamask.marketData, '0x5': { @@ -37,7 +33,6 @@ describe('SwappableCurrencyInput', () => { const { asFragment, getByText } = render( @@ -68,7 +63,6 @@ describe('SwappableCurrencyInput', () => { const { asFragment, getByText } = render( @@ -101,7 +95,6 @@ describe('SwappableCurrencyInput', () => { const { asFragment } = render( @@ -134,7 +127,6 @@ describe('SwappableCurrencyInput', () => { const { asFragment } = render( diff --git a/ui/components/multichain/asset-picker-amount/utils.test.ts b/ui/components/multichain/asset-picker-amount/utils.test.ts index 91f25dc33d15..c83fe3db797b 100644 --- a/ui/components/multichain/asset-picker-amount/utils.test.ts +++ b/ui/components/multichain/asset-picker-amount/utils.test.ts @@ -2,23 +2,18 @@ import configureStore from '../../../store/store'; import mockSendState from '../../../../test/data/mock-send-state.json'; import { getIsFiatPrimary } from './utils'; -const createStore = ({ - useNativeCurrencyAsPrimaryCurrency, - sendInputCurrencySwitched, -}: Record) => +const createStore = ({ sendInputCurrencySwitched }: Record) => configureStore({ ...mockSendState, metamask: { ...mockSendState.metamask, - preferences: { useNativeCurrencyAsPrimaryCurrency }, }, appState: { ...mockSendState.appState, sendInputCurrencySwitched }, }); describe('getIsFiatPrimary selector', () => { - it('returns true when useNativeCurrencyAsPrimaryCurrency and sendInputCurrencySwitched are both true', () => { + it('returns true when sendInputCurrencySwitched is true', () => { const store = createStore({ - useNativeCurrencyAsPrimaryCurrency: true, sendInputCurrencySwitched: true, }); @@ -26,30 +21,11 @@ describe('getIsFiatPrimary selector', () => { expect(getIsFiatPrimary(state as never)).toBe(true); }); - it('returns true when useNativeCurrencyAsPrimaryCurrency and sendInputCurrencySwitched are both false', () => { + it('returns false when sendInputCurrencySwitched is false', () => { const store = createStore({ - useNativeCurrencyAsPrimaryCurrency: false, sendInputCurrencySwitched: false, }); const state = store.getState(); - expect(getIsFiatPrimary(state as never)).toBe(true); - }); - - it('returns false when useNativeCurrencyAsPrimaryCurrency and sendInputCurrencySwitched have different values', () => { - let store = createStore({ - useNativeCurrencyAsPrimaryCurrency: true, - sendInputCurrencySwitched: false, - }); - - let state = store.getState(); - expect(getIsFiatPrimary(state as never)).toBe(false); - - store = createStore({ - useNativeCurrencyAsPrimaryCurrency: false, - sendInputCurrencySwitched: true, - }); - - state = store.getState(); expect(getIsFiatPrimary(state as never)).toBe(false); }); }); diff --git a/ui/components/multichain/asset-picker-amount/utils.ts b/ui/components/multichain/asset-picker-amount/utils.ts index 664cba0d71f5..ed644c8a86d8 100644 --- a/ui/components/multichain/asset-picker-amount/utils.ts +++ b/ui/components/multichain/asset-picker-amount/utils.ts @@ -1,17 +1,14 @@ import { createSelector } from 'reselect'; +import { AppSliceState } from '../../../ducks/app/app'; -export const getIsFiatPrimary = createSelector( - (state: { - metamask: { preferences: { useNativeCurrencyAsPrimaryCurrency: boolean } }; - appState: { sendInputCurrencySwitched: boolean }; - }) => state.metamask.preferences, - (state) => state.appState.sendInputCurrencySwitched, - ({ useNativeCurrencyAsPrimaryCurrency }, sendInputCurrencySwitched) => { - const isFiatPrimary = Boolean( - (useNativeCurrencyAsPrimaryCurrency && sendInputCurrencySwitched) || - (!useNativeCurrencyAsPrimaryCurrency && !sendInputCurrencySwitched), - ); +function getSendInputCurrencySwitched(state: AppSliceState) { + return state.appState.sendInputCurrencySwitched; +} +export const getIsFiatPrimary = createSelector( + getSendInputCurrencySwitched, + (sendInputCurrencySwitched) => { + const isFiatPrimary = Boolean(sendInputCurrencySwitched); return isFiatPrimary; }, ); diff --git a/ui/components/multichain/pages/connections/connections.test.tsx b/ui/components/multichain/pages/connections/connections.test.tsx index a9b37e585ae3..0840e3a2f9ed 100644 --- a/ui/components/multichain/pages/connections/connections.test.tsx +++ b/ui/components/multichain/pages/connections/connections.test.tsx @@ -1,13 +1,12 @@ import React from 'react'; -import { Router, Route } from 'react-router-dom'; // Import Router and Route -import { createMemoryHistory } from 'history'; +import { MemoryRouter, Route } from 'react-router-dom'; +import mockState from '../../../../../test/data/mock-state.json'; import { fireEvent, renderWithProvider, waitFor, } from '../../../../../test/jest'; import configureStore from '../../../../store/store'; -import mockState from '../../../../../test/data/mock-state.json'; import { Connections } from './connections'; describe('Connections Content', () => { @@ -88,15 +87,14 @@ describe('Connections Content', () => { }); it('should render correctly', () => { - const history = createMemoryHistory(); - history.push('/connect/https%3A%2F%2Fmetamask.github.io'); - const { container, getByTestId } = renderWithProvider( - + - , + , connectedStore, ); expect(container).toMatchSnapshot(); @@ -104,30 +102,28 @@ describe('Connections Content', () => { }); it('it should render Disconnect all Account button of the page', () => { - const history = createMemoryHistory(); - history.push('/connect/https%3A%2F%2Fmetamask.github.io'); - const { getByText } = renderWithProvider( - + - , + , connectedStore, ); expect(getByText('Disconnect all accounts')).toBeInTheDocument(); }); it('it should trigger disconnect all accounts modal flow when disconnect all accounts button is clicked', async () => { - const history = createMemoryHistory(); - history.push('/connect/https%3A%2F%2Fmetamask.github.io'); - const { getByText, getByTestId } = renderWithProvider( - + - , + , connectedStore, ); diff --git a/ui/components/multichain/pages/connections/connections.tsx b/ui/components/multichain/pages/connections/connections.tsx index ae1f5b88193e..4a8b188b86b6 100644 --- a/ui/components/multichain/pages/connections/connections.tsx +++ b/ui/components/multichain/pages/connections/connections.tsx @@ -85,10 +85,10 @@ export const Connections = () => { setShowDisconnectedAllAccountsUpdatedToast, ] = useState(false); - const urlParams: { origin: string } = useParams(); - const securedOrigin = decodeURIComponent(urlParams.origin); + const urlParams = useParams<{ origin: string }>(); + // @ts-expect-error TODO: Fix this type error by handling undefined parameters + const activeTabOrigin = decodeURIComponent(urlParams.origin); - const activeTabOrigin: string = securedOrigin; // TODO: Replace `any` with type // eslint-disable-next-line @typescript-eslint/no-explicit-any const subjectMetadata: { [key: string]: any } = useSelector( @@ -246,7 +246,7 @@ export const Connections = () => { textAlign={TextAlign.Center} ellipsis > - {getURLHost(securedOrigin)} + {getURLHost(activeTabOrigin)} diff --git a/ui/components/multichain/pages/review-permissions-page/review-permissions-page.tsx b/ui/components/multichain/pages/review-permissions-page/review-permissions-page.tsx index 303d9dc2df4a..4b7da8f525fa 100644 --- a/ui/components/multichain/pages/review-permissions-page/review-permissions-page.tsx +++ b/ui/components/multichain/pages/review-permissions-page/review-permissions-page.tsx @@ -60,7 +60,8 @@ export const ReviewPermissions = () => { const t = useI18nContext(); const dispatch = useDispatch(); const history = useHistory(); - const urlParams: { origin: string } = useParams(); + const urlParams = useParams<{ origin: string }>(); + // @ts-expect-error TODO: Fix this type error by handling undefined parameters const securedOrigin = decodeURIComponent(urlParams.origin); const [showAccountToast, setShowAccountToast] = useState(false); const [showNetworkToast, setShowNetworkToast] = useState(false); diff --git a/ui/components/multichain/pages/send/send.test.js b/ui/components/multichain/pages/send/send.test.js index cdba904090b2..5195ee15de5b 100644 --- a/ui/components/multichain/pages/send/send.test.js +++ b/ui/components/multichain/pages/send/send.test.js @@ -167,7 +167,6 @@ const baseStore = { }), tokens: [], preferences: { - useNativeCurrencyAsPrimaryCurrency: false, showFiatInTestnets: true, }, currentCurrency: 'USD', diff --git a/ui/components/multichain/token-list-item/__snapshots__/token-list-item.test.tsx.snap b/ui/components/multichain/token-list-item/__snapshots__/token-list-item.test.tsx.snap index 5c75df62eef1..1330a1490244 100644 --- a/ui/components/multichain/token-list-item/__snapshots__/token-list-item.test.tsx.snap +++ b/ui/components/multichain/token-list-item/__snapshots__/token-list-item.test.tsx.snap @@ -59,7 +59,7 @@ exports[`TokenListItem should render correctly 1`] = ` data-testid="multichain-token-list-item-secondary-value" />

diff --git a/ui/components/multichain/token-list-item/price/percentage-and-amount-change/__snapshots__/percentage-and-amount-change.test.tsx.snap b/ui/components/multichain/token-list-item/price/percentage-and-amount-change/__snapshots__/percentage-and-amount-change.test.tsx.snap index e8ca2345490f..7f88ca5456ec 100644 --- a/ui/components/multichain/token-list-item/price/percentage-and-amount-change/__snapshots__/percentage-and-amount-change.test.tsx.snap +++ b/ui/components/multichain/token-list-item/price/percentage-and-amount-change/__snapshots__/percentage-and-amount-change.test.tsx.snap @@ -6,14 +6,14 @@ exports[`PercentageChange Component render renders correctly 1`] = ` class="mm-box mm-box--display-flex" >

+$12.21

(+5.12%) diff --git a/ui/components/multichain/token-list-item/price/percentage-and-amount-change/percentage-and-amount-change.test.tsx b/ui/components/multichain/token-list-item/price/percentage-and-amount-change/percentage-and-amount-change.test.tsx index c22ff3d724f6..abff9f40da8d 100644 --- a/ui/components/multichain/token-list-item/price/percentage-and-amount-change/percentage-and-amount-change.test.tsx +++ b/ui/components/multichain/token-list-item/price/percentage-and-amount-change/percentage-and-amount-change.test.tsx @@ -39,7 +39,7 @@ const mockGetSelectedAccountCachedBalance = getSelectedAccountCachedBalance as jest.Mock; const mockGetConversionRate = getConversionRate as jest.Mock; const mockGetNativeCurrency = getNativeCurrency as jest.Mock; -const mockGetTOkensMarketData = getTokensMarketData as jest.Mock; +const mockGetTokensMarketData = getTokensMarketData as jest.Mock; describe('PercentageChange Component', () => { beforeEach(() => { @@ -48,7 +48,7 @@ describe('PercentageChange Component', () => { mockGetSelectedAccountCachedBalance.mockReturnValue('0x02e8ac1ede6ade83'); mockGetConversionRate.mockReturnValue(2913.15); mockGetNativeCurrency.mockReturnValue('ETH'); - mockGetTOkensMarketData.mockReturnValue({ + mockGetTokensMarketData.mockReturnValue({ [zeroAddress()]: { pricePercentChange1d: 2, }, diff --git a/ui/components/multichain/token-list-item/price/percentage-and-amount-change/percentage-and-amount-change.tsx b/ui/components/multichain/token-list-item/price/percentage-and-amount-change/percentage-and-amount-change.tsx index 1dbf656986f3..be9921e88793 100644 --- a/ui/components/multichain/token-list-item/price/percentage-and-amount-change/percentage-and-amount-change.tsx +++ b/ui/components/multichain/token-list-item/price/percentage-and-amount-change/percentage-and-amount-change.tsx @@ -5,7 +5,6 @@ import { isHexString, zeroAddress } from 'ethereumjs-util'; import { Text, Box } from '../../../../component-library'; import { Display, - FontWeight, TextColor, TextVariant, } from '../../../../../helpers/constants/design-system'; @@ -28,7 +27,7 @@ import { // eslint-disable-next-line import/no-restricted-paths } from '../../../../../../app/scripts/lib/util'; -const renderPercentageWithNumber = ( +export const renderPercentageWithNumber = ( value: string, formattedValuePrice: string, color: TextColor, @@ -36,8 +35,7 @@ const renderPercentageWithNumber = ( return (

+5.12% diff --git a/ui/components/multichain/token-list-item/price/percentage-change/percentage-change.tsx b/ui/components/multichain/token-list-item/price/percentage-change/percentage-change.tsx index 71f54d2ae5dc..616814886078 100644 --- a/ui/components/multichain/token-list-item/price/percentage-change/percentage-change.tsx +++ b/ui/components/multichain/token-list-item/price/percentage-change/percentage-change.tsx @@ -2,7 +2,6 @@ import React from 'react'; import { Box, Text } from '../../../../component-library'; import { Display, - FontWeight, TextColor, TextVariant, } from '../../../../../helpers/constants/design-system'; @@ -37,8 +36,7 @@ export const PercentageChange = ({ return ( { ).toBeInTheDocument(); }); - it('should render crypto balance if useNativeCurrencyAsPrimaryCurrency is false', () => { + it('should render crypto balance', () => { const store = configureMockStore()({ ...state, - preferences: { - useNativeCurrencyAsPrimaryCurrency: false, - }, + preferences: {}, }); const propsToUse = { primary: '11.9751 ETH', diff --git a/ui/components/multichain/token-list-item/token-list-item.tsx b/ui/components/multichain/token-list-item/token-list-item.tsx index 1198d3bdd165..a653a803dc1c 100644 --- a/ui/components/multichain/token-list-item/token-list-item.tsx +++ b/ui/components/multichain/token-list-item/token-list-item.tsx @@ -396,7 +396,7 @@ export const TokenListItem = ({ {primary} {isNativeCurrency ? '' : tokenSymbol} diff --git a/ui/components/ui/currency-display/currency-display.component.js b/ui/components/ui/currency-display/currency-display.component.js index 15b40ecd8ae5..ca9322661d79 100644 --- a/ui/components/ui/currency-display/currency-display.component.js +++ b/ui/components/ui/currency-display/currency-display.component.js @@ -32,6 +32,7 @@ export default function CurrencyDisplay({ prefixComponentWrapperProps = {}, textProps = {}, suffixProps = {}, + isAggregatedFiatOverviewBalance = false, ...props }) { const [title, parts] = useCurrencyDisplay(value, { @@ -43,6 +44,7 @@ export default function CurrencyDisplay({ denomination, currency, suffix, + isAggregatedFiatOverviewBalance, }); return ( @@ -112,6 +114,7 @@ const CurrencyDisplayPropTypes = { prefixComponentWrapperProps: PropTypes.object, textProps: PropTypes.object, suffixProps: PropTypes.object, + isAggregatedFiatOverviewBalance: PropTypes.bool, }; CurrencyDisplay.propTypes = CurrencyDisplayPropTypes; diff --git a/ui/components/ui/dropdown/dropdown.scss b/ui/components/ui/dropdown/dropdown.scss index e76d7936d303..395a61b68eee 100644 --- a/ui/components/ui/dropdown/dropdown.scss +++ b/ui/components/ui/dropdown/dropdown.scss @@ -3,7 +3,7 @@ .dropdown { position: relative; display: inline-block; - height: 36px; + height: 48px; &__select { appearance: none; @@ -15,9 +15,9 @@ color: var(--color-text-default); border: 1px solid var(--color-border-default); - border-radius: 4px; + border-radius: 8px; background-color: var(--color-background-default); - padding: 8px 40px 8px 16px; + padding: 12px 40px 12px 16px; width: 100%; [dir='rtl'] & { diff --git a/ui/components/ui/icon-button/icon-button.js b/ui/components/ui/icon-button/icon-button.js index 69830128ebcd..30b14c0aa205 100644 --- a/ui/components/ui/icon-button/icon-button.js +++ b/ui/components/ui/icon-button/icon-button.js @@ -16,6 +16,7 @@ export default function IconButton(props) { label, tooltipRender, className, + iconButtonClassName = '', ...otherProps } = props; const renderWrapper = tooltipRender ?? defaultRender; @@ -31,7 +32,10 @@ export default function IconButton(props) { > {renderWrapper( <> -

+
{Icon}
{label.length > 10 ? ( @@ -66,5 +70,6 @@ IconButton.propTypes = { label: PropTypes.string.isRequired, tooltipRender: PropTypes.func, className: PropTypes.string, + iconButtonClassName: PropTypes.string, 'data-testid': PropTypes.string, }; diff --git a/ui/components/ui/icon-button/icon-button.scss b/ui/components/ui/icon-button/icon-button.scss index 97529366befa..e09373b23744 100644 --- a/ui/components/ui/icon-button/icon-button.scss +++ b/ui/components/ui/icon-button/icon-button.scss @@ -6,11 +6,11 @@ align-items: center; background-color: unset; text-align: center; - width: 60px; + width: 64px; @include design-system.H7; - font-size: 13px; + font-size: 12px; cursor: pointer; color: var(--color-primary-default); @@ -21,9 +21,9 @@ height: 36px; width: 36px; background: var(--color-primary-default); - border-radius: 18px; + border-radius: 99px; margin-top: 6px; - margin-bottom: 5px; + margin-bottom: 4px; margin-inline: auto; } diff --git a/ui/components/ui/text-field/text-field.component.js b/ui/components/ui/text-field/text-field.component.js index 6ed0a9bff6fb..0a74978973b3 100644 --- a/ui/components/ui/text-field/text-field.component.js +++ b/ui/components/ui/text-field/text-field.component.js @@ -86,13 +86,14 @@ const styles = { border: '1px solid var(--color-border-default)', color: 'var(--color-text-default)', height: '48px', - borderRadius: '6px', padding: '0 16px', display: 'flex', alignItems: 'center', '&$inputFocused': { border: '1px solid var(--color-primary-default)', }, + borderRadius: '8px', + fontSize: '0.875rem', }, largeInputLabel: { ...inputLabelBase, @@ -212,6 +213,7 @@ const getBorderedThemeInputProps = ({ max, autoComplete, }, + disableUnderline: 'true', }, }); diff --git a/ui/ducks/app/app.ts b/ui/ducks/app/app.ts index a2e553f34012..182ba426a3d7 100644 --- a/ui/ducks/app/app.ts +++ b/ui/ducks/app/app.ts @@ -105,7 +105,7 @@ type AppState = { isMultiRpcOnboarding: boolean; }; -type AppSliceState = { +export type AppSliceState = { appState: AppState; }; diff --git a/ui/ducks/metamask/metamask.js b/ui/ducks/metamask/metamask.js index 4765a87df61d..05cc6d46cb27 100644 --- a/ui/ducks/metamask/metamask.js +++ b/ui/ducks/metamask/metamask.js @@ -48,7 +48,6 @@ const initialState = { showFiatInTestnets: false, showTestNetworks: false, smartTransactionsOptInStatus: false, - useNativeCurrencyAsPrimaryCurrency: true, petnamesEnabled: true, featureNotificationsEnabled: false, showMultiRpcModal: false, diff --git a/ui/ducks/swaps/swaps.js b/ui/ducks/swaps/swaps.js index 8abb63aa4a14..97daa88726d3 100644 --- a/ui/ducks/swaps/swaps.js +++ b/ui/ducks/swaps/swaps.js @@ -435,7 +435,14 @@ export const getPendingSmartTransactions = (state) => { }; export const getSmartTransactionFees = (state) => { - return state.metamask.smartTransactionsState?.fees; + const usedQuote = getUsedQuote(state); + if (!usedQuote?.isGasIncludedTrade) { + return state.metamask.smartTransactionsState?.fees; + } + return { + approvalTxFees: usedQuote.approvalTxFees, + tradeTxFees: usedQuote.tradeTxFees, + }; }; export const getSmartTransactionEstimatedGas = (state) => { @@ -780,6 +787,8 @@ export const fetchQuotesAndSetQuoteState = ( fromAddress: selectedAccount.address, balanceError, sourceDecimals: fromTokenDecimals, + enableGasIncludedQuotes: + currentSmartTransactionsEnabled && smartTransactionsOptInStatus, }, { sourceTokenInfo, @@ -933,6 +942,7 @@ export const signAndSendSwapsSmartTransaction = ({ stx_enabled: smartTransactionsEnabled, current_stx_enabled: currentSmartTransactionsEnabled, stx_user_opt_in: smartTransactionsOptInStatus, + gas_included: usedQuote.isGasIncludedTrade, ...additionalTrackingParams, }; trackEvent({ @@ -964,13 +974,18 @@ export const signAndSendSwapsSmartTransaction = ({ value: '0x0', }; } - const fees = await dispatch( - fetchSwapsSmartTransactionFees({ - unsignedTransaction, - approveTxParams: updatedApproveTxParams, - fallbackOnNotEnoughFunds: true, - }), - ); + let fees; + if (usedQuote.isGasIncludedTrade) { + fees = getSmartTransactionFees(state); + } else { + fees = await dispatch( + fetchSwapsSmartTransactionFees({ + unsignedTransaction, + approveTxParams: updatedApproveTxParams, + fallbackOnNotEnoughFunds: true, + }), + ); + } if (!fees) { log.error('"fetchSwapsSmartTransactionFees" failed'); dispatch(setSwapsSTXSubmitLoading(false)); diff --git a/ui/ducks/swaps/swaps.test.js b/ui/ducks/swaps/swaps.test.js index 0bba5e5a68be..83c133572c0d 100644 --- a/ui/ducks/swaps/swaps.test.js +++ b/ui/ducks/swaps/swaps.test.js @@ -652,13 +652,36 @@ describe('Ducks - Swaps', () => { }); describe('getSmartTransactionFees', () => { - it('returns unsigned transactions and estimates', () => { + it('returns estimates from the STX controller', () => { const state = createSwapsMockStore(); const smartTransactionFees = swaps.getSmartTransactionFees(state); expect(smartTransactionFees).toMatchObject( state.metamask.smartTransactionsState.fees, ); }); + + it('returns estimates from a selected quote', () => { + const state = createSwapsMockStore(); + state.metamask.swapsState.quotes.TEST_AGG_2.isGasIncludedTrade = true; + const smartTransactionFees = swaps.getSmartTransactionFees(state); + expect(smartTransactionFees).toMatchObject({ + approvalTxFees: + state.metamask.swapsState.quotes.TEST_AGG_2.approvalTxFees, + tradeTxFees: state.metamask.swapsState.quotes.TEST_AGG_2.tradeTxFees, + }); + }); + + it('returns estimates from a top quote if no quote is selected', () => { + const state = createSwapsMockStore(); + state.metamask.swapsState.selectedAggId = null; + state.metamask.swapsState.quotes.TEST_AGG_BEST.isGasIncludedTrade = true; + const smartTransactionFees = swaps.getSmartTransactionFees(state); + expect(smartTransactionFees).toMatchObject({ + approvalTxFees: + state.metamask.swapsState.quotes.TEST_AGG_BEST.approvalTxFees, + tradeTxFees: state.metamask.swapsState.quotes.TEST_AGG_BEST.tradeTxFees, + }); + }); }); describe('getSmartTransactionEstimatedGas', () => { diff --git a/ui/helpers/constants/settings.js b/ui/helpers/constants/settings.js index f4529ed1d6ad..569999f8900e 100644 --- a/ui/helpers/constants/settings.js +++ b/ui/helpers/constants/settings.js @@ -34,9 +34,9 @@ const SETTINGS_CONSTANTS = [ }, { tabMessage: (t) => t('general'), - sectionMessage: (t) => t('primaryCurrencySetting'), - descriptionMessage: (t) => t('primaryCurrencySettingDescription'), - route: `${GENERAL_ROUTE}#primary-currency`, + sectionMessage: (t) => t('showNativeTokenAsMainBalance'), + descriptionMessage: (t) => t('showNativeTokenAsMainBalance'), + route: `${GENERAL_ROUTE}#show-native-token-as-main-balance`, iconName: IconName.Setting, }, { diff --git a/ui/helpers/constants/zendesk-url.js b/ui/helpers/constants/zendesk-url.js index 1e29bd9b1fc7..3986df5b41ef 100644 --- a/ui/helpers/constants/zendesk-url.js +++ b/ui/helpers/constants/zendesk-url.js @@ -8,6 +8,8 @@ const ZENDESK_URLS = { CUSTOMIZE_NONCE: 'https://support.metamask.io/transactions-and-gas/transactions/how-to-customize-a-transaction-nonce/', GAS_FEES: 'https://support.metamask.io/transactions-and-gas/gas-fees/', + SWAPS_GAS_FEES: + 'https://support.metamask.io/token-swaps/user-guide-swaps/#gas-fees', HARDWARE_CONNECTION: 'https://support.metamask.io/privacy-and-security/hardware-wallet-hub/', IMPORT_ACCOUNTS: diff --git a/ui/helpers/utils/settings-search.js b/ui/helpers/utils/settings-search.js index 447a39901059..07b4501c0208 100644 --- a/ui/helpers/utils/settings-search.js +++ b/ui/helpers/utils/settings-search.js @@ -25,6 +25,15 @@ function getFilteredSettingsRoutes(t, tabMessage) { }); } +export function getSpecificSettingsRoute(t, tabMessage, sectionMessage) { + return getSettingsRoutes().find((routeObject) => { + return ( + routeObject.tabMessage(t) === tabMessage && + routeObject.sectionMessage(t) === sectionMessage + ); + }); +} + /** * @param {Function} t - context.t function * @param {string} tabMessage @@ -59,7 +68,7 @@ export function handleSettingsRefs(t, tabMessage, settingsRefs) { } } -function colorText(menuElement, regex) { +export function colorText(menuElement, regex) { if (menuElement !== null) { let elemText = menuElement.innerHTML; elemText = elemText.replace('&', '&'); @@ -74,9 +83,20 @@ function colorText(menuElement, regex) { } } +/** + * Replaces any special characters in the input string that have a meaning in regular expressions + * (such as \, *, +, ?, etc.) with their escaped versions (e.g., \ becomes \\). + * + * @param input - The input string to be escaped for use in a regular expression. + * @returns The escaped string safe for use in a regular expression. + */ +export const escapeRegExp = (input) => { + return input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // Escapes special characters +}; + export function highlightSearchedText() { const searchElem = document.getElementById('search-settings'); - const searchRegex = new RegExp(searchElem.value, 'gi'); + const searchRegex = new RegExp(escapeRegExp(searchElem.value), 'gi'); const results = document.querySelectorAll( '.settings-page__header__search__list__item', ); diff --git a/ui/helpers/utils/settings-search.test.js b/ui/helpers/utils/settings-search.test.js index 709b0354a4e7..bb1637ec2cef 100644 --- a/ui/helpers/utils/settings-search.test.js +++ b/ui/helpers/utils/settings-search.test.js @@ -4,6 +4,10 @@ import { getSettingsRoutes, getNumberOfSettingRoutesInTab, handleSettingsRefs, + getSpecificSettingsRoute, + escapeRegExp, + colorText, + highlightSearchedText, } from './settings-search'; const t = (key) => { @@ -198,6 +202,42 @@ describe('Settings Search Utils', () => { }); }); + describe('escapeRegExp', () => { + it('should escape special characters for use in regular expressions', () => { + const input = '.*+?^${}()|[]\\'; + const expectedOutput = '\\.\\*\\+\\?\\^\\$\\{\\}\\(\\)\\|\\[\\]\\\\'; + expect(escapeRegExp(input)).toBe(expectedOutput); + }); + + it('should return the same string if no special characters are present', () => { + const input = 'hello'; + expect(escapeRegExp(input)).toBe(input); + }); + + it('should escape only the special characters in a mixed string', () => { + const input = 'hello.*world'; + const expectedOutput = 'hello\\.\\*world'; + expect(escapeRegExp(input)).toBe(expectedOutput); + }); + + it('should handle an empty string correctly', () => { + const input = ''; + expect(escapeRegExp(input)).toBe(''); + }); + + it('should escape backslashes properly', () => { + const input = '\\'; + const expectedOutput = '\\\\'; + expect(escapeRegExp(input)).toBe(expectedOutput); + }); + + it('should escape backslashes with content properly', () => { + const input = 'foobar\\'; + const expectedOutput = 'foobar\\\\'; + expect(escapeRegExp(input)).toBe(expectedOutput); + }); + }); + // Can't be tested without DOM element describe('handleSettingsRefs', () => { it('should handle general refs', () => { @@ -209,4 +249,167 @@ describe('Settings Search Utils', () => { expect(handleSettingsRefs(t, t('general'), settingsRefs)).toBeUndefined(); }); }); + + describe('getSpecificSettingsRoute', () => { + it('should return show native token as main balance route', () => { + const result = getSpecificSettingsRoute( + t, + t('general'), + t('showNativeTokenAsMainBalance'), + ); + expect(result.route).toBe( + '/settings/general#show-native-token-as-main-balance', + ); + }); + }); + + describe('colorText', () => { + let mockElement; + + beforeEach(() => { + mockElement = { + innerHTML: 'Test & string with multiple words', + }; + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should highlight text that matches the regex', () => { + const regex = /string/giu; + colorText(mockElement, regex); + expect(mockElement.innerHTML).toBe( + 'Test & string with multiple words', + ); + }); + + it('should correctly decode & to &', () => { + const regex = /&/giu; + colorText(mockElement, regex); + expect(mockElement.innerHTML).toBe( + 'Test & string with multiple words', + ); + }); + + it('should remove any existing highlight spans before applying new highlights', () => { + mockElement.innerHTML = + 'Test & string with multiple words'; + const regex = /multiple/giu; + colorText(mockElement, regex); + expect(mockElement.innerHTML).toBe( + 'Test & string with multiple words', + ); + }); + + it('should not modify innerHTML if menuElement is null', () => { + const regex = /string/giu; + const nullElement = null; + colorText(nullElement, regex); + expect(nullElement).toBeNull(); + }); + + it('should not highlight anything if regex doesn’t match', () => { + const regex = /nomatch/giu; + colorText(mockElement, regex); + expect(mockElement.innerHTML).toBe('Test & string with multiple words'); + }); + }); + + describe('highlightSearchedText', () => { + let searchElem; + let mockResultItems; + let mockMenuTabElement; + let mockMenuSectionElement; + + beforeEach(() => { + searchElem = document.createElement('input'); + searchElem.id = 'search-settings'; + searchElem.value = 'test'; + document.body.appendChild(searchElem); + + // Mock result list items + mockResultItems = [...Array(2)].map(() => { + const item = document.createElement('div'); + item.classList.add('settings-page__header__search__list__item'); + + mockMenuTabElement = document.createElement('div'); + mockMenuTabElement.classList.add( + 'settings-page__header__search__list__item__tab', + ); + mockMenuTabElement.innerHTML = 'Test tab'; + + mockMenuSectionElement = document.createElement('div'); + mockMenuSectionElement.classList.add( + 'settings-page__header__search__list__item__section', + ); + mockMenuSectionElement.innerHTML = 'Test section'; + + item.appendChild(mockMenuTabElement); + item.appendChild(mockMenuSectionElement); + + return item; + }); + + mockResultItems.forEach((item) => document.body.appendChild(item)); + }); + + afterEach(() => { + document.body.innerHTML = ''; + }); + + it('should highlight the matching text in both menuTabElement and menuSectionElement', () => { + highlightSearchedText(); + mockResultItems.forEach((item) => { + const tabElement = item.querySelector( + '.settings-page__header__search__list__item__tab', + ); + const sectionElement = item.querySelector( + '.settings-page__header__search__list__item__section', + ); + expect(tabElement.innerHTML).toBe( + 'Test tab', + ); + expect(sectionElement.innerHTML).toBe( + 'Test section', + ); + }); + }); + + it('should not alter the innerHTML if no match is found', () => { + searchElem.value = 'nomatch'; + highlightSearchedText(); + mockResultItems.forEach((item) => { + const tabElement = item.querySelector( + '.settings-page__header__search__list__item__tab', + ); + const sectionElement = item.querySelector( + '.settings-page__header__search__list__item__section', + ); + + expect(tabElement.innerHTML).toBe('Test tab'); + expect(sectionElement.innerHTML).toBe('Test section'); + }); + }); + + it('should do nothing if the search input is empty', () => { + searchElem.value = ''; + highlightSearchedText(); + mockResultItems.forEach((item) => { + const tabElement = item.querySelector( + '.settings-page__header__search__list__item__tab', + ); + const sectionElement = item.querySelector( + '.settings-page__header__search__list__item__section', + ); + + expect(tabElement.innerHTML).toBe( + 'Test tab', + ); + expect(sectionElement.innerHTML).toBe( + 'Test section', + ); + }); + }); + }); }); diff --git a/ui/helpers/utils/util.js b/ui/helpers/utils/util.js index 01cffeea3cdc..fe01bd15f5b1 100644 --- a/ui/helpers/utils/util.js +++ b/ui/helpers/utils/util.js @@ -823,3 +823,18 @@ export const getFilteredSnapPermissions = ( return filteredPermissions; }; +/** + * Helper function to calculate the token amount 1dAgo using price percentage a day ago. + * + * @param {*} tokenFiatBalance - current token fiat balance + * @param {*} tokenPricePercentChange1dAgo - price percentage 1day ago + * @returns token amount 1day ago + */ +export const getCalculatedTokenAmount1dAgo = ( + tokenFiatBalance, + tokenPricePercentChange1dAgo, +) => { + return tokenPricePercentChange1dAgo !== undefined && tokenFiatBalance + ? tokenFiatBalance / (1 + tokenPricePercentChange1dAgo / 100) + : tokenFiatBalance ?? 0; +}; diff --git a/ui/helpers/utils/util.test.js b/ui/helpers/utils/util.test.js index e10c70630dba..dd2282efa531 100644 --- a/ui/helpers/utils/util.test.js +++ b/ui/helpers/utils/util.test.js @@ -1226,4 +1226,37 @@ describe('util', () => { ]); }); }); + + describe('getCalculatedTokenAmount1dAgo', () => { + it('should return successfully balance of token 1dago', () => { + const mockTokenFiatAmount = '10'; + const mockTokenPercent1dAgo = 1; + const expectedRes = 9.900990099009901; + const result = util.getCalculatedTokenAmount1dAgo( + mockTokenFiatAmount, + mockTokenPercent1dAgo, + ); + expect(result).toBe(expectedRes); + }); + + it('should return token balance if percentage is undefined', () => { + const mockTokenFiatAmount = '10'; + const mockTokenPercent1dAgo = undefined; + const result = util.getCalculatedTokenAmount1dAgo( + mockTokenFiatAmount, + mockTokenPercent1dAgo, + ); + expect(result).toBe(mockTokenFiatAmount); + }); + + it('should return zero if token amount is undefined', () => { + const mockTokenFiatAmount = undefined; + const mockTokenPercent1dAgo = 1; + const result = util.getCalculatedTokenAmount1dAgo( + mockTokenFiatAmount, + mockTokenPercent1dAgo, + ); + expect(result).toBe(0); + }); + }); }); diff --git a/ui/hooks/useCurrencyDisplay.js b/ui/hooks/useCurrencyDisplay.js index a7798d5ff10e..12b2cfc06ec3 100644 --- a/ui/hooks/useCurrencyDisplay.js +++ b/ui/hooks/useCurrencyDisplay.js @@ -135,6 +135,7 @@ export function useCurrencyDisplay( numberOfDecimals, denomination, currency, + isAggregatedFiatOverviewBalance, ...opts }, ) { @@ -151,6 +152,7 @@ export function useCurrencyDisplay( getMultichainConversionRate, account, ); + const isUserPreferredCurrency = currency === currentCurrency; const isNativeCurrency = currency === nativeCurrency; @@ -172,6 +174,10 @@ export function useCurrencyDisplay( }); } + if (isAggregatedFiatOverviewBalance) { + return formatCurrency(inputValue, currency); + } + return formatEthCurrencyDisplay({ isNativeCurrency, isUserPreferredCurrency, @@ -194,6 +200,7 @@ export function useCurrencyDisplay( denomination, numberOfDecimals, currentCurrency, + isAggregatedFiatOverviewBalance, ]); let suffix; diff --git a/ui/hooks/useTransactionDisplayData.test.js b/ui/hooks/useTransactionDisplayData.test.js index 0aa77675bd7c..68a4d829bcf8 100644 --- a/ui/hooks/useTransactionDisplayData.test.js +++ b/ui/hooks/useTransactionDisplayData.test.js @@ -211,7 +211,6 @@ const renderHookWithRouter = (cb, tokenAddress) => { currentCurrency: 'ETH', useCurrencyRateCheck: false, // to force getShouldShowFiat to return false preferences: { - useNativeCurrencyAsPrimaryCurrency: true, getShowFiatInTestnets: false, }, allNfts: [], diff --git a/ui/hooks/useUserPreferencedCurrency.js b/ui/hooks/useUserPreferencedCurrency.js index 732d4ec726bb..e9e8133cf9e2 100644 --- a/ui/hooks/useUserPreferencedCurrency.js +++ b/ui/hooks/useUserPreferencedCurrency.js @@ -6,7 +6,7 @@ import { getMultichainShouldShowFiat, } from '../selectors/multichain'; -import { PRIMARY, SECONDARY } from '../helpers/constants/common'; +import { PRIMARY } from '../helpers/constants/common'; import { EtherDenomination } from '../../shared/constants/common'; import { ETH_DEFAULT_DECIMALS } from '../constants'; import { useMultichainSelector } from './useMultichainSelector'; @@ -20,6 +20,8 @@ import { useMultichainSelector } from './useMultichainSelector'; * when using ETH * @property {number} [fiatNumberOfDecimals] - Number of significant decimals to display * when using fiat + * @property {boolean} [shouldCheckShowNativeToken] - Boolean to know if checking the setting + * show native token as main balance is needed */ /** @@ -34,9 +36,10 @@ import { useMultichainSelector } from './useMultichainSelector'; * useUserPreferencedCurrency * * returns an object that contains what currency to use for displaying values based - * on the user's preference settings, as well as the significant number of decimals + * on whether the user needs to check showNativeTokenAsMainBalance setting, as well as the significant number of decimals * to display based on the currency * + * * @param {"PRIMARY" | "SECONDARY"} type - what display type is being rendered * @param {UseUserPreferencedCurrencyOptions} opts - options to override default values * @returns {UserPreferredCurrency} @@ -49,7 +52,7 @@ export function useUserPreferencedCurrency(type, opts = {}) { account, ); - const { useNativeCurrencyAsPrimaryCurrency } = useSelector( + const { showNativeTokenAsMainBalance } = useSelector( getPreferences, shallowEqual, ); @@ -74,12 +77,13 @@ export function useUserPreferencedCurrency(type, opts = {}) { return nativeReturn; } else if (opts.showFiatOverride) { return fiatReturn; + } else if (!showFiat) { + return nativeReturn; } else if ( - !showFiat || - (type === PRIMARY && useNativeCurrencyAsPrimaryCurrency) || - (type === SECONDARY && !useNativeCurrencyAsPrimaryCurrency) + (opts.shouldCheckShowNativeToken && showNativeTokenAsMainBalance) || + !opts.shouldCheckShowNativeToken ) { - return nativeReturn; + return type === PRIMARY ? nativeReturn : fiatReturn; } - return fiatReturn; + return type === PRIMARY ? fiatReturn : nativeReturn; } diff --git a/ui/hooks/useUserPreferencedCurrency.test.js b/ui/hooks/useUserPreferencedCurrency.test.js index 12785d44b5ff..9421834b0e31 100644 --- a/ui/hooks/useUserPreferencedCurrency.test.js +++ b/ui/hooks/useUserPreferencedCurrency.test.js @@ -8,16 +8,43 @@ import { mockNetworkState } from '../../test/stub/networks'; import { CHAIN_IDS } from '../../shared/constants/network'; import { useUserPreferencedCurrency } from './useUserPreferencedCurrency'; +const renderUseUserPreferencedCurrency = (state, value, restProps) => { + const defaultState = { + ...mockState, + metamask: { + ...mockState.metamask, + completedOnboarding: true, + ...mockNetworkState({ + chainId: state.showFiat ? CHAIN_IDS.MAINNET : CHAIN_IDS.SEPOLIA, + ticker: state?.nativeCurrency, + }), + currentCurrency: state.currentCurrency, + currencyRates: { ETH: { conversionRate: 280.45 } }, + preferences: { + showFiatInTestnets: state.showFiat, + showNativeTokenAsMainBalance: state.showNativeTokenAsMainBalance, + }, + }, + }; + + const wrapper = ({ children }) => ( + {children} + ); + + return renderHook(() => useUserPreferencedCurrency(value, restProps), { + wrapper, + }); +}; const tests = [ { state: { - useNativeCurrencyAsPrimaryCurrency: true, + showNativeTokenAsMainBalance: true, nativeCurrency: 'ETH', showFiat: true, currentCurrency: 'usd', }, params: { - type: 'PRIMARY', + showNativeOverride: true, }, result: { currency: 'ETH', @@ -26,13 +53,13 @@ const tests = [ }, { state: { - useNativeCurrencyAsPrimaryCurrency: false, + showNativeTokenAsMainBalance: true, nativeCurrency: 'ETH', showFiat: true, currentCurrency: 'usd', }, params: { - type: 'PRIMARY', + showFiatOverride: true, }, result: { currency: 'usd', @@ -41,45 +68,59 @@ const tests = [ }, { state: { - useNativeCurrencyAsPrimaryCurrency: true, + showNativeTokenAsMainBalance: true, nativeCurrency: 'ETH', showFiat: true, + currentCurrency: 'usd', }, params: { - type: 'SECONDARY', - fiatNumberOfDecimals: 4, - fiatPrefix: '-', + type: 'PRIMARY', + shouldCheckShowNativeToken: true, }, result: { - currency: undefined, - numberOfDecimals: 4, + currency: 'ETH', + numberOfDecimals: 8, }, }, { state: { - useNativeCurrencyAsPrimaryCurrency: false, + showNativeTokenAsMainBalance: false, nativeCurrency: 'ETH', showFiat: true, + currentCurrency: 'usd', }, params: { - type: 'SECONDARY', - fiatNumberOfDecimals: 4, - numberOfDecimals: 3, - fiatPrefix: 'a', + type: 'PRIMARY', }, result: { currency: 'ETH', - numberOfDecimals: 3, + numberOfDecimals: 8, + }, + }, + { + state: { + showNativeTokenAsMainBalance: false, + nativeCurrency: 'ETH', + showFiat: true, + currentCurrency: 'usd', + }, + params: { + type: 'SECONDARY', + }, + result: { + currency: 'usd', + numberOfDecimals: 2, }, }, { state: { - useNativeCurrencyAsPrimaryCurrency: false, + showNativeTokenAsMainBalance: false, nativeCurrency: 'ETH', showFiat: false, + currentCurrency: 'usd', }, params: { - type: 'PRIMARY', + type: 'SECONDARY', }, result: { currency: 'ETH', @@ -88,66 +129,54 @@ const tests = [ }, { state: { - useNativeCurrencyAsPrimaryCurrency: false, + showNativeTokenAsMainBalance: true, nativeCurrency: 'ETH', showFiat: true, + currentCurrency: 'usd', }, params: { type: 'PRIMARY', }, result: { - currency: undefined, + currency: 'ETH', + numberOfDecimals: 8, + }, + }, + { + state: { + showNativeTokenAsMainBalance: true, + nativeCurrency: 'ETH', + showFiat: true, + currentCurrency: 'usd', + }, + params: { + type: 'SECONDARY', + }, + result: { + currency: 'usd', numberOfDecimals: 2, }, }, { state: { - useNativeCurrencyAsPrimaryCurrency: false, + showNativeTokenAsMainBalance: true, nativeCurrency: 'ETH', showFiat: true, + currentCurrency: 'usd', }, params: { - type: 'PRIMARY', + type: 'SECONDARY', + shouldCheckShowNativeToken: true, }, result: { - currency: undefined, + currency: 'usd', numberOfDecimals: 2, }, }, ]; - -const renderUseUserPreferencedCurrency = (state, value, restProps) => { - const defaultState = { - ...mockState, - metamask: { - ...mockState.metamask, - completedOnboarding: true, - ...mockNetworkState({ - chainId: state.showFiat ? CHAIN_IDS.MAINNET : CHAIN_IDS.SEPOLIA, - ticker: state?.nativeCurrency, - }), - currentCurrency: state.currentCurrency, - currencyRates: { ETH: { conversionRate: 280.45 } }, - preferences: { - useNativeCurrencyAsPrimaryCurrency: - state.useNativeCurrencyAsPrimaryCurrency, - showFiatInTestnets: state.showFiat, - }, - }, - }; - - const wrapper = ({ children }) => ( - {children} - ); - - return renderHook(() => useUserPreferencedCurrency(value, restProps), { - wrapper, - }); -}; - describe('useUserPreferencedCurrency', () => { tests.forEach(({ params: { type, ...otherParams }, state, result }) => { - describe(`when showFiat is ${state.showFiat}, useNativeCurrencyAsPrimary is ${state.useNativeCurrencyAsPrimaryCurrency} and type is ${type}`, () => { + describe(`when showFiat is ${state.showFiat}, shouldCheckShowNativeToken is ${otherParams.shouldCheckShowNativeToken}, showNativeTokenAsMainBalance is ${state.showNativeTokenAsMainBalance} and type is ${type}`, () => { const { result: hookResult } = renderUseUserPreferencedCurrency( state, type, diff --git a/ui/pages/asset/asset.tsx b/ui/pages/asset/asset.tsx index 975ff2e5cc25..933c39872265 100644 --- a/ui/pages/asset/asset.tsx +++ b/ui/pages/asset/asset.tsx @@ -21,11 +21,13 @@ const Asset = () => { const { asset, id } = useParams<{ asset: string; id: string }>(); const token = tokens.find(({ address }: { address: string }) => + // @ts-expect-error TODO: Fix this type error by handling undefined parameters isEqualCaseInsensitive(address, asset), ); const nft = nfts.find( ({ address, tokenId }: { address: string; tokenId: string }) => + // @ts-expect-error TODO: Fix this type error by handling undefined parameters isEqualCaseInsensitive(address, asset) && id === tokenId.toString(), ); diff --git a/ui/pages/asset/components/__snapshots__/asset-page.test.tsx.snap b/ui/pages/asset/components/__snapshots__/asset-page.test.tsx.snap index ef6e6331d2ba..95828e3e250e 100644 --- a/ui/pages/asset/components/__snapshots__/asset-page.test.tsx.snap +++ b/ui/pages/asset/components/__snapshots__/asset-page.test.tsx.snap @@ -43,7 +43,7 @@ exports[`AssetPage should render a native asset 1`] = ` data-theme="light" >
@@ -61,7 +61,7 @@ exports[`AssetPage should render a native asset 1`] = ` data-theme="light" >
@@ -79,7 +79,7 @@ exports[`AssetPage should render a native asset 1`] = ` data-theme="light" >
@@ -99,7 +99,7 @@ exports[`AssetPage should render a native asset 1`] = ` data-theme="light" > @@ -118,7 +118,7 @@ exports[`AssetPage should render a native asset 1`] = ` data-theme="light" > @@ -137,7 +137,7 @@ exports[`AssetPage should render a native asset 1`] = ` data-theme="light" > @@ -156,7 +156,7 @@ exports[`AssetPage should render a native asset 1`] = ` data-theme="light" > @@ -236,7 +236,7 @@ exports[`AssetPage should render a native asset 1`] = ` data-testid="multichain-token-list-item-secondary-value" />

0 TEST @@ -352,7 +352,7 @@ exports[`AssetPage should render an ERC20 asset without prices 1`] = ` data-theme="light" > @@ -371,7 +371,7 @@ exports[`AssetPage should render an ERC20 asset without prices 1`] = ` data-theme="light" > @@ -390,7 +390,7 @@ exports[`AssetPage should render an ERC20 asset without prices 1`] = ` data-theme="light" > @@ -409,7 +409,7 @@ exports[`AssetPage should render an ERC20 asset without prices 1`] = ` data-theme="light" > @@ -427,7 +427,7 @@ exports[`AssetPage should render an ERC20 asset without prices 1`] = ` data-theme="light" > @@ -446,7 +446,7 @@ exports[`AssetPage should render an ERC20 asset without prices 1`] = ` data-theme="light" > @@ -515,7 +515,7 @@ exports[`AssetPage should render an ERC20 asset without prices 1`] = ` class="mm-box mm-box--display-flex" >

@@ -528,7 +528,7 @@ exports[`AssetPage should render an ERC20 asset without prices 1`] = ` data-testid="multichain-token-list-item-secondary-value" />

0 @@ -835,7 +835,7 @@ exports[`AssetPage should render an ERC20 token with prices 1`] = ` data-theme="light" > @@ -854,7 +854,7 @@ exports[`AssetPage should render an ERC20 token with prices 1`] = ` data-theme="light" > @@ -873,7 +873,7 @@ exports[`AssetPage should render an ERC20 token with prices 1`] = ` data-theme="light" > @@ -892,7 +892,7 @@ exports[`AssetPage should render an ERC20 token with prices 1`] = ` data-theme="light" > @@ -910,7 +910,7 @@ exports[`AssetPage should render an ERC20 token with prices 1`] = ` data-theme="light" > @@ -929,7 +929,7 @@ exports[`AssetPage should render an ERC20 token with prices 1`] = ` data-theme="light" > @@ -998,7 +998,7 @@ exports[`AssetPage should render an ERC20 token with prices 1`] = ` class="mm-box mm-box--display-flex" >

@@ -1011,7 +1011,7 @@ exports[`AssetPage should render an ERC20 token with prices 1`] = ` data-testid="multichain-token-list-item-secondary-value" />

0 diff --git a/ui/pages/asset/components/asset-page.test.tsx b/ui/pages/asset/components/asset-page.test.tsx index bf616d0aaac9..35721a30a1c2 100644 --- a/ui/pages/asset/components/asset-page.test.tsx +++ b/ui/pages/asset/components/asset-page.test.tsx @@ -49,9 +49,7 @@ describe('AssetPage', () => { }, }, useCurrencyRateCheck: true, - preferences: { - useNativeCurrencyAsPrimaryCurrency: true, - }, + preferences: {}, internalAccounts: { accounts: { 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { diff --git a/ui/pages/asset/components/token-buttons.tsx b/ui/pages/asset/components/token-buttons.tsx index a07cdaca2d48..bb3f129bade8 100644 --- a/ui/pages/asset/components/token-buttons.tsx +++ b/ui/pages/asset/components/token-buttons.tsx @@ -48,7 +48,12 @@ import { JustifyContent, } from '../../../helpers/constants/design-system'; import IconButton from '../../../components/ui/icon-button/icon-button'; -import { Box, Icon, IconName } from '../../../components/component-library'; +import { + Box, + Icon, + IconName, + IconSize, +} from '../../../components/component-library'; ///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask) import { getIsNativeTokenBuyable } from '../../../ducks/ramps'; ///: END:ONLY_INCLUDE_IF @@ -115,7 +120,11 @@ const TokenButtons = ({ + } label={t('buyAndSell')} data-testid="token-overview-buy" @@ -144,7 +153,11 @@ const TokenButtons = ({ + } label={t('stake')} data-testid="token-overview-mmi-stake" @@ -163,6 +176,7 @@ const TokenButtons = ({ } label={t('portfolio')} @@ -215,6 +229,7 @@ const TokenButtons = ({ } label={t('send')} @@ -229,6 +244,7 @@ const TokenButtons = ({ } onClick={() => { @@ -281,7 +297,11 @@ const TokenButtons = ({ className="token-overview__button" data-testid="token-overview-bridge" Icon={ - + } label={t('bridge')} onClick={() => { diff --git a/ui/pages/bridge/index.tsx b/ui/pages/bridge/index.tsx index f216a52ec71d..780a19bd71f4 100644 --- a/ui/pages/bridge/index.tsx +++ b/ui/pages/bridge/index.tsx @@ -40,7 +40,6 @@ const CrossChainSwap = () => { const redirectToDefaultRoute = async () => { history.push({ pathname: DEFAULT_ROUTE, - // @ts-expect-error - property 'state' does not exist on type PartialPath. state: { stayOnHomePage: true }, }); dispatch(clearSwapsState()); diff --git a/ui/pages/confirm-decrypt-message/confirm-decrypt-message.container.js b/ui/pages/confirm-decrypt-message/confirm-decrypt-message.container.js index fd6585381a27..88d7c8deb40b 100644 --- a/ui/pages/confirm-decrypt-message/confirm-decrypt-message.container.js +++ b/ui/pages/confirm-decrypt-message/confirm-decrypt-message.container.js @@ -10,9 +10,7 @@ import { decryptMsgInline, } from '../../store/actions'; import { - conversionRateSelector, getCurrentCurrency, - getPreferences, getTargetAccountWithSendEtherInfo, unconfirmedTransactionsListSelector, } from '../../selectors'; @@ -21,13 +19,12 @@ import { getMostRecentOverviewPage } from '../../ducks/history/history'; import { getNativeCurrency } from '../../ducks/metamask/metamask'; import ConfirmDecryptMessage from './confirm-decrypt-message.component'; +// ConfirmDecryptMessage component is not used in codebase, removing usage of useNativeCurrencyAsPrimaryCurrency function mapStateToProps(state) { const { metamask: { subjectMetadata = {} }, } = state; - const { useNativeCurrencyAsPrimaryCurrency } = getPreferences(state); - const unconfirmedTransactions = unconfirmedTransactionsListSelector(state); const txData = cloneDeep(unconfirmedTransactions[0]); @@ -43,9 +40,7 @@ function mapStateToProps(state) { fromAccount, requester: null, requesterAddress: null, - conversionRate: useNativeCurrencyAsPrimaryCurrency - ? null - : conversionRateSelector(state), + conversionRate: null, mostRecentOverviewPage: getMostRecentOverviewPage(state), nativeCurrency: getNativeCurrency(state), currentCurrency: getCurrentCurrency(state), diff --git a/ui/pages/confirm-encryption-public-key/__snapshots__/confirm-encryption-public-key.component.test.js.snap b/ui/pages/confirm-encryption-public-key/__snapshots__/confirm-encryption-public-key.component.test.js.snap index 05cee4e7016f..b6ae6ed60c6f 100644 --- a/ui/pages/confirm-encryption-public-key/__snapshots__/confirm-encryption-public-key.component.test.js.snap +++ b/ui/pages/confirm-encryption-public-key/__snapshots__/confirm-encryption-public-key.component.test.js.snap @@ -208,252 +208,6 @@ exports[`ConfirmDecryptMessage Component should match snapshot when preference i -

- - test - -
- would like your public encryption key. By consenting, this site will be able to compose encrypted messages to you. - -
- - - - - - - -`; - -exports[`ConfirmDecryptMessage Component should match snapshot when preference is Fiat currency 1`] = ` -
-
-
-
-
- Request encryption public key -
-
-
-
-
-
- -
-
- - T - -
- - -
diff --git a/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.component.js b/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.component.js index 1595576a4fac..dd84bea68360 100644 --- a/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.component.js +++ b/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.component.js @@ -10,8 +10,6 @@ import { MetaMetricsEventCategory } from '../../../shared/constants/metametrics' import SiteOrigin from '../../components/ui/site-origin'; import { Numeric } from '../../../shared/modules/Numeric'; import { EtherDenomination } from '../../../shared/constants/common'; -import { formatCurrency } from '../../helpers/utils/confirm-tx.util'; -import { getValueFromWeiHex } from '../../../shared/modules/conversion.utils'; export default class ConfirmEncryptionPublicKey extends Component { static contextTypes = { @@ -34,8 +32,6 @@ export default class ConfirmEncryptionPublicKey extends Component { subjectMetadata: PropTypes.object, mostRecentOverviewPage: PropTypes.string.isRequired, nativeCurrency: PropTypes.string.isRequired, - currentCurrency: PropTypes.string.isRequired, - conversionRate: PropTypes.number, }; renderHeader = () => { @@ -73,30 +69,20 @@ export default class ConfirmEncryptionPublicKey extends Component { renderBalance = () => { const { - conversionRate, nativeCurrency, - currentCurrency, fromAccount: { balance }, } = this.props; const { t } = this.context; - const nativeCurrencyBalance = conversionRate - ? formatCurrency( - getValueFromWeiHex({ - value: balance, - fromCurrency: nativeCurrency, - toCurrency: currentCurrency, - conversionRate, - numberOfDecimals: 6, - toDenomination: EtherDenomination.ETH, - }), - currentCurrency, - ) - : new Numeric(balance, 16, EtherDenomination.WEI) - .toDenomination(EtherDenomination.ETH) - .round(6) - .toBase(10) - .toString(); + const nativeCurrencyBalance = new Numeric( + balance, + 16, + EtherDenomination.WEI, + ) + .toDenomination(EtherDenomination.ETH) + .round(6) + .toBase(10) + .toString(); return (
@@ -104,9 +90,7 @@ export default class ConfirmEncryptionPublicKey extends Component { {`${t('balance')}:`}
- {`${nativeCurrencyBalance} ${ - conversionRate ? currentCurrency?.toUpperCase() : nativeCurrency - }`} + {`${nativeCurrencyBalance} ${nativeCurrency}`}
); diff --git a/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.component.test.js b/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.component.test.js index 771a5a5f5ef7..3edc10e9d313 100644 --- a/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.component.test.js +++ b/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.component.test.js @@ -61,19 +61,6 @@ describe('ConfirmDecryptMessage Component', () => { ).toMatchInlineSnapshot(`"966.987986 ABC"`); }); - it('should match snapshot when preference is Fiat currency', () => { - const { container } = renderWithProvider( - , - store, - ); - - expect(container).toMatchSnapshot(); - expect( - container.querySelector('.request-encryption-public-key__balance-value') - .textContent, - ).toMatchInlineSnapshot(`"1520956.064158 DEF"`); - }); - it('should match snapshot when there is no txData', () => { const newProps = { ...baseProps, diff --git a/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.container.js b/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.container.js index 489d7d088033..554ba41fdaa4 100644 --- a/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.container.js +++ b/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.container.js @@ -9,11 +9,8 @@ import { } from '../../store/actions'; import { - conversionRateSelector, unconfirmedTransactionsListSelector, getTargetAccountWithSendEtherInfo, - getPreferences, - getCurrentCurrency, } from '../../selectors'; import { clearConfirmTransaction } from '../../ducks/confirm-transaction/confirm-transaction.duck'; @@ -26,8 +23,6 @@ function mapStateToProps(state) { metamask: { subjectMetadata = {} }, } = state; - const { useNativeCurrencyAsPrimaryCurrency } = getPreferences(state); - const unconfirmedTransactions = unconfirmedTransactionsListSelector(state); const txData = unconfirmedTransactions[0]; @@ -43,12 +38,8 @@ function mapStateToProps(state) { fromAccount, requester: null, requesterAddress: null, - conversionRate: useNativeCurrencyAsPrimaryCurrency - ? null - : conversionRateSelector(state), mostRecentOverviewPage: getMostRecentOverviewPage(state), nativeCurrency: getNativeCurrency(state), - currentCurrency: getCurrentCurrency(state), }; } diff --git a/ui/pages/confirmations/components/confirm-gas-display/confirm-gas-display.test.js b/ui/pages/confirmations/components/confirm-gas-display/confirm-gas-display.test.js index c80ef735222b..c1d4ae838301 100644 --- a/ui/pages/confirmations/components/confirm-gas-display/confirm-gas-display.test.js +++ b/ui/pages/confirmations/components/confirm-gas-display/confirm-gas-display.test.js @@ -39,9 +39,7 @@ const render = async ({ transactionProp = {}, contextProps = {} } = {}) => { balance: '0x1F4', }, }, - preferences: { - useNativeCurrencyAsPrimaryCurrency: true, - }, + preferences: {}, gasFeeEstimates: mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, gasFeeEstimatesByChainId: { diff --git a/ui/pages/confirmations/components/confirm-gas-display/confirm-legacy-gas-display/confirm-legacy-gas-display.js b/ui/pages/confirmations/components/confirm-gas-display/confirm-legacy-gas-display/confirm-legacy-gas-display.js index 34440be28693..70d5ed1070f4 100644 --- a/ui/pages/confirmations/components/confirm-gas-display/confirm-legacy-gas-display/confirm-legacy-gas-display.js +++ b/ui/pages/confirmations/components/confirm-gas-display/confirm-legacy-gas-display/confirm-legacy-gas-display.js @@ -5,7 +5,6 @@ import { useSelector } from 'react-redux'; import { useI18nContext } from '../../../../../hooks/useI18nContext'; import { getIsMainnet, - getPreferences, getUnapprovedTransactions, getUseCurrencyRateCheck, transactionFeeSelector, @@ -34,7 +33,6 @@ const ConfirmLegacyGasDisplay = ({ 'data-testid': dataTestId } = {}) => { // state selectors const isMainnet = useSelector(getIsMainnet); const useCurrencyRateCheck = useSelector(getUseCurrencyRateCheck); - const { useNativeCurrencyAsPrimaryCurrency } = useSelector(getPreferences); const unapprovedTxs = useSelector(getUnapprovedTransactions); const transactionData = useDraftTransactionWithTxParams(); const txData = useSelector((state) => txDataSelector(state)); @@ -108,7 +106,7 @@ const ConfirmLegacyGasDisplay = ({ 'data-testid': dataTestId } = {}) => {
) @@ -119,7 +117,6 @@ const ConfirmLegacyGasDisplay = ({ 'data-testid': dataTestId } = {}) => { { key="editGasSubTextFeeAmount" type={PRIMARY} value={estimatedHexMaxFeeTotal} - hideLabel={!useNativeCurrencyAsPrimaryCurrency} />
diff --git a/ui/pages/confirmations/components/confirm-gas-display/confirm-legacy-gas-display/confirm-legacy-gas-display.test.js b/ui/pages/confirmations/components/confirm-gas-display/confirm-legacy-gas-display/confirm-legacy-gas-display.test.js index df5b9ea0e50f..4952fb87edca 100644 --- a/ui/pages/confirmations/components/confirm-gas-display/confirm-legacy-gas-display/confirm-legacy-gas-display.test.js +++ b/ui/pages/confirmations/components/confirm-gas-display/confirm-legacy-gas-display/confirm-legacy-gas-display.test.js @@ -21,9 +21,6 @@ const mmState = { balance: '0x1F4', }, }, - preferences: { - useNativeCurrencyAsPrimaryCurrency: true, - }, }, confirmTransaction: { txData: { diff --git a/ui/pages/confirmations/components/confirm-page-container/confirm-detail-row/confirm-detail-row.component.test.js b/ui/pages/confirmations/components/confirm-page-container/confirm-detail-row/confirm-detail-row.component.test.js index 5b1e505ddc14..5d3065e8a3d3 100644 --- a/ui/pages/confirmations/components/confirm-page-container/confirm-detail-row/confirm-detail-row.component.test.js +++ b/ui/pages/confirmations/components/confirm-page-container/confirm-detail-row/confirm-detail-row.component.test.js @@ -11,9 +11,7 @@ describe('Confirm Detail Row Component', () => { metamask: { currencyRates: {}, ...mockNetworkState({ chainId: CHAIN_IDS.GOERLI }), - preferences: { - useNativeCurrencyAsPrimaryCurrency: true, - }, + preferences: {}, internalAccounts: defaultMockState.metamask.internalAccounts, }, }; diff --git a/ui/pages/confirmations/components/confirm-subtitle/confirm-subtitle.js b/ui/pages/confirmations/components/confirm-subtitle/confirm-subtitle.js index e1219d299288..da99ade8210c 100644 --- a/ui/pages/confirmations/components/confirm-subtitle/confirm-subtitle.js +++ b/ui/pages/confirmations/components/confirm-subtitle/confirm-subtitle.js @@ -29,7 +29,6 @@ const ConfirmSubTitle = ({ if (subtitleComponent) { return subtitleComponent; } - return ( { const t = useI18nContext(); - const { useNativeCurrencyAsPrimaryCurrency: isNativeCurrencyUsed } = - useSelector(getPreferences); - const { currentConfirmation: transactionMeta } = useConfirmContext(); @@ -56,14 +51,14 @@ export const EditGasFeesRow = ({ color={TextColor.textDefault} data-testid="first-gas-field" > - {isNativeCurrencyUsed ? nativeFee : fiatFee} + {nativeFee} - {isNativeCurrencyUsed ? fiatFee : nativeFee} + {fiatFee} { - const { useNativeCurrencyAsPrimaryCurrency: isNativeCurrencyUsed } = - useSelector(getPreferences); - return ( - {isNativeCurrencyUsed ? nativeFee : fiatFee} - - - {isNativeCurrencyUsed ? fiatFee : nativeFee} + {nativeFee} + {fiatFee} ); diff --git a/ui/pages/confirmations/components/fee-details-component/fee-details-component.js b/ui/pages/confirmations/components/fee-details-component/fee-details-component.js index 19bcc25e445f..84ea244ec8cd 100644 --- a/ui/pages/confirmations/components/fee-details-component/fee-details-component.js +++ b/ui/pages/confirmations/components/fee-details-component/fee-details-component.js @@ -1,6 +1,6 @@ import React, { useCallback, useMemo, useState } from 'react'; -import { useSelector } from 'react-redux'; import PropTypes from 'prop-types'; +import { useSelector } from 'react-redux'; import { AlignItems, Display, @@ -19,7 +19,7 @@ import { Text, } from '../../../../components/component-library'; import TransactionDetailItem from '../transaction-detail-item/transaction-detail-item.component'; -import { getPreferences, getShouldShowFiat } from '../../../../selectors'; +import { getShouldShowFiat } from '../../../../selectors'; import { useI18nContext } from '../../../../hooks/useI18nContext'; import LoadingHeartBeat from '../../../../components/ui/loading-heartbeat'; import UserPreferencedCurrencyDisplay from '../../../../components/app/user-preferenced-currency-display/user-preferenced-currency-display.component'; @@ -36,8 +36,6 @@ export default function FeeDetailsComponent({ const [expandFeeDetails, setExpandFeeDetails] = useState(false); const shouldShowFiat = useSelector(getShouldShowFiat); - const { useNativeCurrencyAsPrimaryCurrency } = useSelector(getPreferences); - const t = useI18nContext(); const { minimumCostInHexWei: hexMinimumTransactionFee } = useGasFeeContext(); @@ -64,13 +62,13 @@ export default function FeeDetailsComponent({ color: TextColor.textAlternative, variant: TextVariant.bodySmBold, }} - hideLabel={Boolean(useNativeCurrencyAsPrimaryCurrency)} + hideLabel /> )}
); }, - [txData, useNativeCurrencyAsPrimaryCurrency], + [txData], ); const renderTotalDetailValue = useCallback( @@ -91,13 +89,12 @@ export default function FeeDetailsComponent({ color: TextColor.textAlternative, variant: TextVariant.bodySm, }} - hideLabel={!useNativeCurrencyAsPrimaryCurrency} /> )} ); }, - [txData, useNativeCurrencyAsPrimaryCurrency], + [txData], ); const hasLayer1GasFee = layer1GasFee !== null; diff --git a/ui/pages/confirmations/components/gas-details-item/gas-details-item.js b/ui/pages/confirmations/components/gas-details-item/gas-details-item.js index 90ccbb09ce23..c861a9dce9d9 100644 --- a/ui/pages/confirmations/components/gas-details-item/gas-details-item.js +++ b/ui/pages/confirmations/components/gas-details-item/gas-details-item.js @@ -17,7 +17,6 @@ import { import { PRIMARY, SECONDARY } from '../../../../helpers/constants/common'; import { PriorityLevels } from '../../../../../shared/constants/gas'; import { - getPreferences, getShouldShowFiat, getTxData, transactionFeeSelector, @@ -68,7 +67,6 @@ const GasDetailsItem = ({ supportsEIP1559, } = useGasFeeContext(); - const { useNativeCurrencyAsPrimaryCurrency } = useSelector(getPreferences); const getTransactionFeeTotal = useMemo(() => { if (layer1GasFee) { return sumHexes(hexMinimumTransactionFee, layer1GasFee); @@ -148,7 +146,7 @@ const GasDetailsItem = ({ }} type={SECONDARY} value={getTransactionFeeTotal} - hideLabel={Boolean(useNativeCurrencyAsPrimaryCurrency)} + hideLabel // Label not required here as it will always display fiat value. /> )}
@@ -168,7 +166,7 @@ const GasDetailsItem = ({ }} type={PRIMARY} value={getTransactionFeeTotal || draftHexMinimumTransactionFee} - hideLabel={!useNativeCurrencyAsPrimaryCurrency} + // Label required here as it will always display crypto value />
} @@ -216,7 +214,6 @@ const GasDetailsItem = ({ value={ getMaxTransactionFeeTotal || draftHexMaximumTransactionFee } - hideLabel={!useNativeCurrencyAsPrimaryCurrency} />
diff --git a/ui/pages/confirmations/components/gas-details-item/gas-details-item.test.js b/ui/pages/confirmations/components/gas-details-item/gas-details-item.test.js index ca85dd9abae9..3e45b4c87722 100644 --- a/ui/pages/confirmations/components/gas-details-item/gas-details-item.test.js +++ b/ui/pages/confirmations/components/gas-details-item/gas-details-item.test.js @@ -35,9 +35,7 @@ const render = async ({ contextProps } = {}) => { balance: '0x1F4', }, }, - preferences: { - useNativeCurrencyAsPrimaryCurrency: true, - }, + preferences: {}, gasFeeEstimates: mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, gasFeeEstimatesByChainId: { diff --git a/ui/pages/confirmations/components/signature-request-header/signature-request-header.js b/ui/pages/confirmations/components/signature-request-header/signature-request-header.js index 30f839b3f78c..9c91ca476ebb 100644 --- a/ui/pages/confirmations/components/signature-request-header/signature-request-header.js +++ b/ui/pages/confirmations/components/signature-request-header/signature-request-header.js @@ -9,10 +9,8 @@ import { } from '../../../../ducks/metamask/metamask'; import { accountsWithSendEtherInfoSelector, - conversionRateSelector, getCurrentChainId, getCurrentCurrency, - getPreferences, } from '../../../../selectors'; import { formatCurrency } from '../../../../helpers/utils/confirm-tx.util'; import { @@ -38,11 +36,8 @@ const SignatureRequestHeader = ({ txData }) => { const providerConfig = useSelector(getProviderConfig); const networkName = getNetworkNameFromProviderType(providerConfig.type); - const { useNativeCurrencyAsPrimaryCurrency } = useSelector(getPreferences); - const conversionRateFromSelector = useSelector(conversionRateSelector); - const conversionRate = useNativeCurrencyAsPrimaryCurrency - ? null - : conversionRateFromSelector; + + const conversionRate = null; // setting conversion rate to null by default to display balance in native const currentNetwork = networkName === '' diff --git a/ui/pages/confirmations/components/signature-request/signature-request.test.js b/ui/pages/confirmations/components/signature-request/signature-request.test.js index 0d50f906e5ca..9851cdbef454 100644 --- a/ui/pages/confirmations/components/signature-request/signature-request.test.js +++ b/ui/pages/confirmations/components/signature-request/signature-request.test.js @@ -45,9 +45,7 @@ const mockStore = { rpcUrl: 'http://localhost:8545', ticker: 'ETH', }), - preferences: { - useNativeCurrencyAsPrimaryCurrency: true, - }, + preferences: {}, accounts: { '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5': { address: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5', diff --git a/ui/pages/confirmations/components/simulation-details/simulation-details.stories.tsx b/ui/pages/confirmations/components/simulation-details/simulation-details.stories.tsx index 15bfab8a2428..7c4fdc6e0d22 100644 --- a/ui/pages/confirmations/components/simulation-details/simulation-details.stories.tsx +++ b/ui/pages/confirmations/components/simulation-details/simulation-details.stories.tsx @@ -29,7 +29,7 @@ const storeMock = configureStore({ ...mockState.metamask, preferences: { ...mockState.metamask.preferences, - useNativeCurrencyAsPrimaryCurrency: false, + showNativeTokenAsMainBalance: false, }, ...mockNetworkState({ chainId: CHAIN_ID_MOCK }), useTokenDetection: true, diff --git a/ui/pages/confirmations/confirm-approve/confirm-approve-content/confirm-approve-content.component.js b/ui/pages/confirmations/confirm-approve/confirm-approve-content/confirm-approve-content.component.js index cbe80f86fe8b..ebd57c35a141 100644 --- a/ui/pages/confirmations/confirm-approve/confirm-approve-content/confirm-approve-content.component.js +++ b/ui/pages/confirmations/confirm-approve/confirm-approve-content/confirm-approve-content.component.js @@ -86,7 +86,6 @@ export default class ConfirmApproveContent extends Component { setUserAcknowledgedGasMissing: PropTypes.func, renderSimulationFailureWarning: PropTypes.bool, useCurrencyRateCheck: PropTypes.bool, - useNativeCurrencyAsPrimaryCurrency: PropTypes.bool, }; state = { @@ -159,7 +158,6 @@ export default class ConfirmApproveContent extends Component { userAcknowledgedGasMissing, renderSimulationFailureWarning, useCurrencyRateCheck, - useNativeCurrencyAsPrimaryCurrency, } = this.props; if ( !hasLayer1GasFee && @@ -183,7 +181,6 @@ export default class ConfirmApproveContent extends Component { } noBold diff --git a/ui/pages/confirmations/confirm-approve/confirm-approve-content/confirm-approve-content.component.test.js b/ui/pages/confirmations/confirm-approve/confirm-approve-content/confirm-approve-content.component.test.js index 2abec9ef4c13..ba1c7c5a568c 100644 --- a/ui/pages/confirmations/confirm-approve/confirm-approve-content/confirm-approve-content.component.test.js +++ b/ui/pages/confirmations/confirm-approve/confirm-approve-content/confirm-approve-content.component.test.js @@ -11,9 +11,7 @@ const renderComponent = (props) => { const store = configureMockStore([])({ metamask: { ...mockNetworkState({ chainId: '0x0' }), - preferences: { - useNativeCurrencyAsPrimaryCurrency: true, - }, + preferences: {}, currencyRates: {}, }, }); diff --git a/ui/pages/confirmations/confirm-approve/confirm-approve.js b/ui/pages/confirmations/confirm-approve/confirm-approve.js index 0828c236a38f..a5dcaeb6202d 100644 --- a/ui/pages/confirmations/confirm-approve/confirm-approve.js +++ b/ui/pages/confirmations/confirm-approve/confirm-approve.js @@ -27,7 +27,6 @@ import { getRpcPrefsForCurrentProvider, checkNetworkAndAccountSupports1559, getUseCurrencyRateCheck, - getPreferences, } from '../../../selectors'; import { useApproveTransaction } from '../hooks/useApproveTransaction'; import { useSimulationFailureWarning } from '../hooks/useSimulationFailureWarning'; @@ -84,7 +83,6 @@ export default function ConfirmApprove({ isAddressLedgerByFromAddress(userAddress), ); const useCurrencyRateCheck = useSelector(getUseCurrencyRateCheck); - const { useNativeCurrencyAsPrimaryCurrency } = useSelector(getPreferences); const [customPermissionAmount, setCustomPermissionAmount] = useState(''); const [submitWarning, setSubmitWarning] = useState(''); const [isContract, setIsContract] = useState(false); @@ -298,9 +296,6 @@ export default function ConfirmApprove({ hasLayer1GasFee={layer1GasFee !== undefined} supportsEIP1559={supportsEIP1559} useCurrencyRateCheck={useCurrencyRateCheck} - useNativeCurrencyAsPrimaryCurrency={ - useNativeCurrencyAsPrimaryCurrency - } /> {showCustomizeGasPopover && !supportsEIP1559 && (
0.000021 + + ETH +
@@ -431,13 +436,18 @@ exports[`Confirm Transaction Base should match snapshot 1`] = `
0.000021 + + ETH +
diff --git a/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.component.js b/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.component.js index 31149997a39c..96fd5315e317 100644 --- a/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.component.js +++ b/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.component.js @@ -146,7 +146,6 @@ export default class ConfirmTransactionBase extends Component { secondaryTotalTextOverride: PropTypes.string, gasIsLoading: PropTypes.bool, primaryTotalTextOverrideMaxAmount: PropTypes.string, - useNativeCurrencyAsPrimaryCurrency: PropTypes.bool, maxFeePerGas: PropTypes.string, maxPriorityFeePerGas: PropTypes.string, baseFeePerGas: PropTypes.string, @@ -399,7 +398,6 @@ export default class ConfirmTransactionBase extends Component { nextNonce, getNextNonce, txData, - useNativeCurrencyAsPrimaryCurrency, primaryTotalTextOverrideMaxAmount, showLedgerSteps, nativeCurrency, @@ -459,7 +457,6 @@ export default class ConfirmTransactionBase extends Component { type={PRIMARY} key="total-max-amount" value={getTotalAmount(useMaxFee)} - hideLabel={!useNativeCurrencyAsPrimaryCurrency} /> ); } @@ -468,9 +465,8 @@ export default class ConfirmTransactionBase extends Component { const primaryTotal = useMaxFee ? primaryTotalTextOverrideMaxAmount : primaryTotalTextOverride; - const totalMaxAmount = useNativeCurrencyAsPrimaryCurrency - ? primaryTotal - : secondaryTotalTextOverride; + + const totalMaxAmount = primaryTotal; return isBoldTextAndNotOverridden ? ( {totalMaxAmount} @@ -500,14 +496,12 @@ export default class ConfirmTransactionBase extends Component { color: TextColor.textDefault, variant: TextVariant.bodyMdBold, }} - hideLabel={Boolean(useNativeCurrencyAsPrimaryCurrency)} + hideLabel /> ); } - return useNativeCurrencyAsPrimaryCurrency - ? secondaryTotalTextOverride - : primaryTotalTextOverride; + return secondaryTotalTextOverride; }; const nextNonceValue = diff --git a/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.container.js b/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.container.js index ed012d07e5ce..5d92a1af9c56 100644 --- a/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.container.js +++ b/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.container.js @@ -45,7 +45,6 @@ import { getIsEthGasPriceFetched, getShouldShowFiat, checkNetworkAndAccountSupports1559, - getPreferences, doesAddressRequireLedgerHidConnection, getTokenList, getEnsResolutionByAddress, @@ -266,7 +265,6 @@ const mapStateToProps = (state, ownProps) => { customNonceValue = getCustomNonceValue(state); const isEthGasPriceFetched = getIsEthGasPriceFetched(state); const noGasPrice = !supportsEIP1559 && getNoGasPriceFetched(state); - const { useNativeCurrencyAsPrimaryCurrency } = getPreferences(state); const gasFeeIsCustom = fullTxData.userFeeLevel === CUSTOM_GAS_ESTIMATE || txParamsAreDappSuggested(fullTxData); @@ -347,7 +345,6 @@ const mapStateToProps = (state, ownProps) => { noGasPrice, supportsEIP1559, gasIsLoading: isGasEstimatesLoading || gasLoadingAnimationIsShowing, - useNativeCurrencyAsPrimaryCurrency, maxFeePerGas: gasEstimationObject.maxFeePerGas, maxPriorityFeePerGas: gasEstimationObject.maxPriorityFeePerGas, baseFeePerGas: gasEstimationObject.baseFeePerGas, diff --git a/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.test.js b/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.test.js index f8a7b40430fb..bea6aef1d84d 100644 --- a/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.test.js +++ b/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.test.js @@ -108,9 +108,7 @@ const baseStore = { chainId: CHAIN_IDS.GOERLI, }), tokens: [], - preferences: { - useNativeCurrencyAsPrimaryCurrency: false, - }, + preferences: {}, currentCurrency: 'USD', currencyRates: {}, featureFlags: { diff --git a/ui/pages/confirmations/confirm/stories/utils.tsx b/ui/pages/confirmations/confirm/stories/utils.tsx index dd194d574109..9c68a392cbd7 100644 --- a/ui/pages/confirmations/confirm/stories/utils.tsx +++ b/ui/pages/confirmations/confirm/stories/utils.tsx @@ -46,7 +46,7 @@ export function ConfirmStoryTemplate( }`, ]} > - } /> + } /> ); diff --git a/ui/pages/confirmations/hooks/test-utils.js b/ui/pages/confirmations/hooks/test-utils.js index 8af6bcf3ba40..908f600564f8 100644 --- a/ui/pages/confirmations/hooks/test-utils.js +++ b/ui/pages/confirmations/hooks/test-utils.js @@ -10,10 +10,10 @@ import { import { getCurrentCurrency, getShouldShowFiat, - getPreferences, txDataSelector, getCurrentKeyring, getTokenExchangeRates, + getPreferences, } from '../../../selectors'; import { @@ -118,7 +118,7 @@ export const generateUseSelectorRouter = } if (selector === getPreferences) { return { - useNativeCurrencyAsPrimaryCurrency: true, + showNativeTokenAsMainBalance: true, }; } if ( diff --git a/ui/pages/confirmations/hooks/useLedgerConnection.test.ts b/ui/pages/confirmations/hooks/useLedgerConnection.test.ts index 42868115a369..7041b11b1aa4 100644 --- a/ui/pages/confirmations/hooks/useLedgerConnection.test.ts +++ b/ui/pages/confirmations/hooks/useLedgerConnection.test.ts @@ -1,18 +1,18 @@ -import type { TransactionMeta } from '@metamask/transaction-controller'; import type { KeyringObject } from '@metamask/keyring-controller'; +import type { TransactionMeta } from '@metamask/transaction-controller'; import type { Hex } from '@metamask/utils'; import { cloneDeep } from 'lodash'; -import { KeyringType } from '../../../../shared/constants/keyring'; -import { renderHookWithConfirmContextProvider } from '../../../../test/lib/confirmations/render-helpers'; -import { getMockConfirmStateForTransaction } from '../../../../test/data/confirmations/helper'; -import { genUnapprovedApproveConfirmation } from '../../../../test/data/confirmations/contract-interaction'; -import { flushPromises } from '../../../../test/lib/timer-helpers'; import { + HardwareTransportStates, + LEDGER_USB_VENDOR_ID, LedgerTransportTypes, WebHIDConnectedStatuses, - LEDGER_USB_VENDOR_ID, - HardwareTransportStates, } from '../../../../shared/constants/hardware-wallets'; +import { KeyringType } from '../../../../shared/constants/keyring'; +import { getMockConfirmStateForTransaction } from '../../../../test/data/confirmations/helper'; +import { genUnapprovedApproveConfirmation } from '../../../../test/data/confirmations/token-approve'; +import { renderHookWithConfirmContextProvider } from '../../../../test/lib/confirmations/render-helpers'; +import { flushPromises } from '../../../../test/lib/timer-helpers'; import * as appActions from '../../../ducks/app/app'; import { attemptLedgerTransportCreation } from '../../../store/actions'; import useLedgerConnection from './useLedgerConnection'; diff --git a/ui/pages/confirmations/send/gas-display/gas-display.js b/ui/pages/confirmations/send/gas-display/gas-display.js index 5fbad8445cd6..33a011c2966a 100644 --- a/ui/pages/confirmations/send/gas-display/gas-display.js +++ b/ui/pages/confirmations/send/gas-display/gas-display.js @@ -48,6 +48,7 @@ import { MetaMetricsContext } from '../../../../contexts/metametrics'; import useRamps from '../../../../hooks/ramps/useRamps/useRamps'; import { getIsNativeTokenBuyable } from '../../../../ducks/ramps'; +// This function is no longer used in codebase, to be deleted. export default function GasDisplay({ gasError }) { const t = useContext(I18nContext); const dispatch = useDispatch(); @@ -61,8 +62,7 @@ export default function GasDisplay({ gasError }) { const isBuyableChain = useSelector(getIsNativeTokenBuyable); const draftTransaction = useSelector(getCurrentDraftTransaction); const useCurrencyRateCheck = useSelector(getUseCurrencyRateCheck); - const { showFiatInTestnets, useNativeCurrencyAsPrimaryCurrency } = - useSelector(getPreferences); + const { showFiatInTestnets } = useSelector(getPreferences); const unapprovedTxs = useSelector(getUnapprovedTransactions); const nativeCurrency = useSelector(getNativeCurrency); const { chainId } = providerConfig; @@ -132,7 +132,6 @@ export default function GasDisplay({ gasError }) { type={PRIMARY} key="total-detail-value" value={hexTransactionTotal} - hideLabel={!useNativeCurrencyAsPrimaryCurrency} /> ); @@ -144,10 +143,9 @@ export default function GasDisplay({ gasError }) { draftTransaction.amount.value, hexMaximumTransactionFee, )} - hideLabel={!useNativeCurrencyAsPrimaryCurrency} /> ); - } else if (useNativeCurrencyAsPrimaryCurrency) { + } else { detailTotal = primaryTotalTextOverrideMaxAmount; maxAmount = primaryTotalTextOverrideMaxAmount; } @@ -177,7 +175,7 @@ export default function GasDisplay({ gasError }) { type={SECONDARY} key="total-detail-text" value={hexTransactionTotal} - hideLabel={Boolean(useNativeCurrencyAsPrimaryCurrency)} + hideLabel /> ) diff --git a/ui/pages/home/index.scss b/ui/pages/home/index.scss index 03b4cd5d7cf9..5a85a3eb5d3c 100644 --- a/ui/pages/home/index.scss +++ b/ui/pages/home/index.scss @@ -20,6 +20,7 @@ min-width: 0; display: flex; flex-direction: column; + padding-top: 8px; } &__connect-status-text { diff --git a/ui/pages/index.js b/ui/pages/index.js index 208436c9127a..0b1cdcef78cd 100644 --- a/ui/pages/index.js +++ b/ui/pages/index.js @@ -2,6 +2,7 @@ import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; import { Provider } from 'react-redux'; import { HashRouter } from 'react-router-dom'; +import { CompatRouter } from 'react-router-dom-v5-compat'; import * as Sentry from '@sentry/browser'; import { I18nProvider, LegacyI18nProvider } from '../contexts/i18n'; import { @@ -43,19 +44,21 @@ class Index extends PureComponent { return ( - - - - - - - - - - - - - + + + + + + + + + + + + + + + ); diff --git a/ui/pages/institutional/confirm-add-custodian-token/confirm-add-custodian-token.test.tsx b/ui/pages/institutional/confirm-add-custodian-token/confirm-add-custodian-token.test.tsx index cdefb3986d1f..d7a474ad3b24 100644 --- a/ui/pages/institutional/confirm-add-custodian-token/confirm-add-custodian-token.test.tsx +++ b/ui/pages/institutional/confirm-add-custodian-token/confirm-add-custodian-token.test.tsx @@ -17,9 +17,7 @@ jest.mock('../../../store/institutional/institution-background', () => ({ describe('Confirm Add Custodian Token', () => { const mockStore = { metamask: { - preferences: { - useNativeCurrencyAsPrimaryCurrency: true, - }, + preferences: {}, institutionalFeatures: { connectRequests: [ { @@ -50,9 +48,7 @@ describe('Confirm Add Custodian Token', () => { it('tries to connect to custodian with empty token', async () => { const customMockedStore = { metamask: { - preferences: { - useNativeCurrencyAsPrimaryCurrency: true, - }, + preferences: {}, institutionalFeatures: { connectRequests: [ { diff --git a/ui/pages/institutional/confirm-connect-custodian-modal/confirm-connect-custodian-modal.test.tsx b/ui/pages/institutional/confirm-connect-custodian-modal/confirm-connect-custodian-modal.test.tsx index 5719fb38015f..5044d6085812 100644 --- a/ui/pages/institutional/confirm-connect-custodian-modal/confirm-connect-custodian-modal.test.tsx +++ b/ui/pages/institutional/confirm-connect-custodian-modal/confirm-connect-custodian-modal.test.tsx @@ -9,9 +9,7 @@ describe('Confirm Add Custodian Token', () => { const mockStore = { metamask: { - preferences: { - useNativeCurrencyAsPrimaryCurrency: true, - }, + preferences: {}, }, history: { push: '/', diff --git a/ui/pages/institutional/custody/custody.test.tsx b/ui/pages/institutional/custody/custody.test.tsx index 383e615492da..577e599397ba 100644 --- a/ui/pages/institutional/custody/custody.test.tsx +++ b/ui/pages/institutional/custody/custody.test.tsx @@ -99,9 +99,7 @@ describe('CustodyPage', function () { }, ], }, - preferences: { - useNativeCurrencyAsPrimaryCurrency: true, - }, + preferences: {}, appState: { isLoading: false, }, diff --git a/ui/pages/settings/advanced-tab/__snapshots__/advanced-tab.component.test.js.snap b/ui/pages/settings/advanced-tab/__snapshots__/advanced-tab.component.test.js.snap index fcc11ec8336b..6318abd37570 100644 --- a/ui/pages/settings/advanced-tab/__snapshots__/advanced-tab.component.test.js.snap +++ b/ui/pages/settings/advanced-tab/__snapshots__/advanced-tab.component.test.js.snap @@ -501,7 +501,7 @@ exports[`AdvancedTab Component should match snapshot 1`] = ` class="MuiFormControl-root MuiTextField-root MuiFormControl-marginDense MuiFormControl-fullWidth" >
}); } + ///: BEGIN:ONLY_INCLUDE_IF(build-flask) renderWatchAccountToggle() { const { t, trackEvent } = this.context; const { watchAccountEnabled, setWatchAccountEnabled } = this.props; @@ -297,7 +298,6 @@ export default class ExperimentalTab extends PureComponent }); } - ///: BEGIN:ONLY_INCLUDE_IF(build-flask) // We're only setting the code fences here since // we should remove it for the feature release renderBitcoinSupport() { @@ -385,12 +385,15 @@ export default class ExperimentalTab extends PureComponent this.renderKeyringSnapsToggle() ///: END:ONLY_INCLUDE_IF } - {this.renderWatchAccountToggle()} + { + ///: BEGIN:ONLY_INCLUDE_IF(build-flask) + this.renderWatchAccountToggle() + ///: END:ONLY_INCLUDE_IF + } { ///: BEGIN:ONLY_INCLUDE_IF(build-flask) // We're only setting the code fences here since // we should remove it for the feature release - /* Section: Bitcoin Accounts */ this.renderBitcoinSupport() ///: END:ONLY_INCLUDE_IF diff --git a/ui/pages/settings/index.scss b/ui/pages/settings/index.scss index 48e12e8adebc..b4cea4bef630 100644 --- a/ui/pages/settings/index.scss +++ b/ui/pages/settings/index.scss @@ -263,11 +263,11 @@ } &__body { - padding: 24px; + padding: 0 16px 16px 16px; } &__content-row { - padding: 10px 0 20px; + padding: 16px 0 0; @include design-system.screen-sm-max { flex-wrap: wrap; @@ -296,6 +296,12 @@ margin-top: 10px; } + &__title { + font-size: 14px; + font-weight: 500; + line-height: 22px; + } + &__identicon { display: flex; flex-direction: row; @@ -326,11 +332,7 @@ &__description { @include design-system.H6; - margin-top: 8px; - margin-bottom: 12px; - color: var(--color-text-default); - font-size: 14px; - font-weight: 400; + line-height: 22px; } } diff --git a/ui/pages/settings/security-tab/__snapshots__/security-tab.test.js.snap b/ui/pages/settings/security-tab/__snapshots__/security-tab.test.js.snap index a57775ed145b..d18da9cc2eca 100644 --- a/ui/pages/settings/security-tab/__snapshots__/security-tab.test.js.snap +++ b/ui/pages/settings/security-tab/__snapshots__/security-tab.test.js.snap @@ -1020,7 +1020,7 @@ exports[`Security Tab should match snapshot 1`] = ` class="MuiFormControl-root MuiTextField-root MuiFormControl-marginDense MuiFormControl-fullWidth" >
{ return ( - + ); }; @@ -73,7 +79,11 @@ export default function SettingsSearch({ onClick={() => handleSearch('')} style={{ cursor: 'pointer' }} > - + )} @@ -93,6 +103,7 @@ export default function SettingsSearch({ autoComplete="off" startAdornment={renderStartAdornment()} endAdornment={renderEndAdornment()} + theme="bordered" /> ); } diff --git a/ui/pages/settings/settings-tab/settings-tab.component.js b/ui/pages/settings/settings-tab/settings-tab.component.js index b998cde80515..191bbbc78685 100644 --- a/ui/pages/settings/settings-tab/settings-tab.component.js +++ b/ui/pages/settings/settings-tab/settings-tab.component.js @@ -62,12 +62,10 @@ export default class SettingsTab extends PureComponent { currentLocale: PropTypes.string, useBlockie: PropTypes.bool, currentCurrency: PropTypes.string, - nativeCurrency: PropTypes.string, - useNativeCurrencyAsPrimaryCurrency: PropTypes.bool, - setUseNativeCurrencyAsPrimaryCurrencyPreference: PropTypes.func, + showNativeTokenAsMainBalance: PropTypes.bool, + setShowNativeTokenAsMainBalancePreference: PropTypes.func, hideZeroBalanceTokens: PropTypes.bool, setHideZeroBalanceTokens: PropTypes.func, - lastFetchedConversionDate: PropTypes.number, selectedAddress: PropTypes.string, tokenList: PropTypes.object, theme: PropTypes.string, @@ -94,8 +92,7 @@ export default class SettingsTab extends PureComponent { renderCurrentConversion() { const { t } = this.context; - const { currentCurrency, setCurrentCurrency, lastFetchedConversionDate } = - this.props; + const { currentCurrency, setCurrentCurrency } = this.props; return (
- {t('currencyConversion')} - - {lastFetchedConversionDate - ? t('updatedWithDate', [ - new Date(lastFetchedConversionDate * 1000).toString(), - ]) - : t('noConversionDateAvailable')} - + + {t('currencyConversion')} +
@@ -131,6 +127,7 @@ export default class SettingsTab extends PureComponent { }, }); }} + className="settings-page__content-item__dropdown" />
@@ -141,10 +138,6 @@ export default class SettingsTab extends PureComponent { renderCurrentLocale() { const { t } = this.context; const { updateCurrentLocale, currentLocale } = this.props; - const currentLocaleMeta = locales.find( - (locale) => locale.code === currentLocale, - ); - const currentLocaleName = currentLocaleMeta ? currentLocaleMeta.name : ''; return (
- + {t('currentLanguage')} - - - {currentLocaleName} - +
@@ -191,15 +185,20 @@ export default class SettingsTab extends PureComponent { id="toggle-zero-balance" >
- {t('hideZeroBalanceTokens')} + + {t('hideZeroBalanceTokens')} +
setHideZeroBalanceTokens(!value)} - offLabel={t('off')} - onLabel={t('on')} + data-testid="toggle-zero-balance-button" />
@@ -229,14 +228,19 @@ export default class SettingsTab extends PureComponent {
{t('accountIdenticon')} - + {t('jazzAndBlockies')} - +