1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-22 01:47:00 +01:00

fix(privateKey): Restore hold-to-reveal button for private key export (#20109)

* fix(privateKey): Restore hold-to-reveal button for private key export

* lint and unit test fixes

* adding e2e tests to reveal private key

* fixing lint issues

* fixed: Private key is able to be presented without tapping and holding the "Hold to reveal" CTA

* Incorrect password test and support hold to reveal

* improving unit tests

---------

Co-authored-by: Plasma Corral <32695229+plasmacorral@users.noreply.github.com>
Co-authored-by: Gustavo Antunes <17601467+gantunesr@users.noreply.github.com>
This commit is contained in:
Howard Braham 2023-08-24 14:35:26 -07:00 committed by GitHub
parent d6a0a32714
commit d76b458235
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
88 changed files with 452 additions and 2753 deletions

View File

@ -169,9 +169,6 @@
"copyAddress": {
"message": "አድራሻን ወደ ቅንጥብ ሰሌዳ ቅዳ"
},
"copyPrivateKey": {
"message": "የግል ቁልፍዎ ይህ ነው (ለመቅዳት ጠቅ ያድርጉ)"
},
"copyToClipboard": {
"message": "ወደ ቅንጥብ ሰሌዳ ገልብጥ"
},
@ -232,9 +229,6 @@
"ensRegistrationError": {
"message": "በ ENS የስም ምዝገባ ላይ የተፈጠረ ስህተት"
},
"enterPassword": {
"message": "የይለፍ ቃል ያስገቡ"
},
"enterPasswordContinue": {
"message": "ለመቀጠል የይለፍ ቃል ያስገቡ"
},
@ -247,9 +241,6 @@
"expandView": {
"message": "እይታን ዘርጋ"
},
"exportPrivateKey": {
"message": "የግል ቁልፍን ላክ"
},
"failed": {
"message": "አልተሳካም"
},
@ -648,9 +639,6 @@
"showHexDataDescription": {
"message": "በመላኪያ ማያ ላይ የ hex ውሂብ መስክን ለማሳየት ይህን ይምረጡ"
},
"showPrivateKeys": {
"message": "የግል ቁልፎችን አሳይ"
},
"sigRequest": {
"message": "የፊርማ ጥያቄ"
},
@ -771,9 +759,6 @@
"tryAgain": {
"message": "እንደገና ሞክር"
},
"typePassword": {
"message": "የ MetaMask የይለፍ ቃልዎን ይጻፉ"
},
"unapproved": {
"message": "ያልተፈቀደ"
},

View File

@ -179,9 +179,6 @@
"copyAddress": {
"message": "نسخ العنوان إلى الحافظة"
},
"copyPrivateKey": {
"message": "هذا هو مفتاحك الخاص (انقر للنسخ)"
},
"copyToClipboard": {
"message": "نسخ إلى الحافظة"
},
@ -245,9 +242,6 @@
"ensRegistrationError": {
"message": "خطأ في تسجيل اسم ENS"
},
"enterPassword": {
"message": "أدخل كلمة مرور"
},
"enterPasswordContinue": {
"message": "أدخل كلمة المرور للمتابعة"
},
@ -260,9 +254,6 @@
"expandView": {
"message": "توسيع العرض"
},
"exportPrivateKey": {
"message": "تصدير المفتاح الخاص"
},
"failed": {
"message": "فشل"
},
@ -660,9 +651,6 @@
"showHexDataDescription": {
"message": "حدد هذا لإظهار حقل بيانات سداسي عشرية على شاشة الإرسال"
},
"showPrivateKeys": {
"message": "عرض المفاتيح الخاصة"
},
"sigRequest": {
"message": "طلب التوقيع"
},
@ -783,9 +771,6 @@
"tryAgain": {
"message": "إعادة المحاولة"
},
"typePassword": {
"message": "أدخل كلمة مرور MetaMask الخاصة بك"
},
"unapproved": {
"message": "تم الرفض"
},

View File

@ -175,9 +175,6 @@
"copyAddress": {
"message": "Копирайте адреса в клипборда"
},
"copyPrivateKey": {
"message": "Това е Вашият личен ключ (кликнете, за да го копирате)"
},
"copyToClipboard": {
"message": "Копиране в буферната памет"
},
@ -241,9 +238,6 @@
"ensRegistrationError": {
"message": "Грешка при регистрацията на име на ENS"
},
"enterPassword": {
"message": "Въведете парола"
},
"enterPasswordContinue": {
"message": "Въведете парола, за да продължите"
},
@ -256,9 +250,6 @@
"expandView": {
"message": "Разгъване на изглед"
},
"exportPrivateKey": {
"message": "Експортиране на частен ключ"
},
"failed": {
"message": "Неуспешно"
},
@ -659,9 +650,6 @@
"showHexDataDescription": {
"message": "Изберете това, за да се покаже полето с шестнадесетични данни на екрана за изпращане"
},
"showPrivateKeys": {
"message": "Показване на частни ключове"
},
"sigRequest": {
"message": "Заявка за подпис"
},
@ -782,9 +770,6 @@
"tryAgain": {
"message": "Нов опит"
},
"typePassword": {
"message": "Въведете паролата си за MetaMask"
},
"unapproved": {
"message": "Неодобрено"
},

View File

@ -172,9 +172,6 @@
"copyAddress": {
"message": "ক্লিপবোর্ডে ঠিকানা কপি করুন"
},
"copyPrivateKey": {
"message": "এটি হল আপনার গোপন কী (কপি করতে ক্লিক করুন)"
},
"copyToClipboard": {
"message": "ক্লিপবোর্ডে কপি করুন"
},
@ -238,9 +235,6 @@
"ensRegistrationError": {
"message": "ENS নাম নিবন্ধীকরণে ত্রুটি হয়েছে"
},
"enterPassword": {
"message": "পাসওয়ার্ড লিখুন"
},
"enterPasswordContinue": {
"message": "অবিরত রাখতে পাসওয়ার্ড লিখুন"
},
@ -253,9 +247,6 @@
"expandView": {
"message": "ভিউ সম্প্রসারিত করুন"
},
"exportPrivateKey": {
"message": "ব্যক্তিগত কী রপ্তানি করুন"
},
"failed": {
"message": "ব্যর্থ হয়েছে"
},
@ -657,9 +648,6 @@
"showHexDataDescription": {
"message": "পাঠাবার স্ক্রিনে হেক্স ডেটা ফিল্ডটি দেখাবার জন্য এটি নির্বাচন করুন"
},
"showPrivateKeys": {
"message": "গোপনীয় কীগুলি দেখান"
},
"sigRequest": {
"message": "স্বাক্ষরের অনুরোধ"
},
@ -780,9 +768,6 @@
"tryAgain": {
"message": "আবার করুন"
},
"typePassword": {
"message": "আপনার MetaMask পাসওয়ার্ড টাইপ করুন"
},
"unapproved": {
"message": "অননুমোদিত"
},

View File

@ -172,9 +172,6 @@
"copyAddress": {
"message": "Copiar adreça al porta-retalls"
},
"copyPrivateKey": {
"message": "Aquesta és la teva clau privada (fes clic per a copiar)"
},
"copyToClipboard": {
"message": "Copia al porta-retalls"
},
@ -238,9 +235,6 @@
"ensRegistrationError": {
"message": "Error al registre de nom ENS"
},
"enterPassword": {
"message": "Introdueix contrasenya"
},
"enterPasswordContinue": {
"message": "Introdueix la contrasenya per continuar"
},
@ -253,9 +247,6 @@
"expandView": {
"message": "Eixamplar Vista"
},
"exportPrivateKey": {
"message": "Exportar Clau Privada."
},
"failed": {
"message": "Fallit"
},
@ -644,9 +635,6 @@
"showHexDataDescription": {
"message": "Selecciona això per a mostrar el camp de dades Hex a la pantalla d'enviament"
},
"showPrivateKeys": {
"message": "Mostrar Claus Privades"
},
"sigRequest": {
"message": "Sol·licitud de Signatura"
},
@ -761,9 +749,6 @@
"tryAgain": {
"message": "Torna-ho a provar"
},
"typePassword": {
"message": "Tecleja la teva contrasenya de MetaMask"
},
"unapproved": {
"message": "Pendent d'aprovació"
},

View File

@ -72,9 +72,6 @@
"copiedExclamation": {
"message": "Zkopírováno!"
},
"copyPrivateKey": {
"message": "Toto je váš privátní klíč (kliknutím zkopírujte)"
},
"copyToClipboard": {
"message": "Kopírovat do schránky"
},
@ -105,15 +102,9 @@
"edit": {
"message": "Upravit"
},
"enterPassword": {
"message": "Zadejte heslo"
},
"etherscanView": {
"message": "Prohlédněte si účet na Etherscan"
},
"exportPrivateKey": {
"message": "Exportovat privátní klíč"
},
"failed": {
"message": "Neúspěšné"
},
@ -304,9 +295,6 @@
"settings": {
"message": "Nastavení"
},
"showPrivateKeys": {
"message": "Zobrazit privátní klíče"
},
"sigRequest": {
"message": "Požadavek podpisu"
},
@ -355,9 +343,6 @@
"transactionError": {
"message": "Chyba transakce. Vyhozena výjimka v kódu kontraktu."
},
"typePassword": {
"message": "Zadejte své heslo"
},
"unapproved": {
"message": "Neschváleno"
},

View File

@ -175,9 +175,6 @@
"copyAddress": {
"message": "Kopier adresse til udklipsholder"
},
"copyPrivateKey": {
"message": "Dette er din private nøgle (klik for at kopiere)"
},
"copyToClipboard": {
"message": "Kopiér til udklipsholderen"
},
@ -241,9 +238,6 @@
"ensRegistrationError": {
"message": "Fejl i ENS-navneregistrering"
},
"enterPassword": {
"message": "Indtast kodeord"
},
"enterPasswordContinue": {
"message": "Indtast adgangskode for at fortsætte"
},
@ -256,9 +250,6 @@
"expandView": {
"message": "Udvis Visning"
},
"exportPrivateKey": {
"message": "Eksporter privat nøgle"
},
"failed": {
"message": "Mislykkedes"
},
@ -641,9 +632,6 @@
"showHexDataDescription": {
"message": "Vælg dette for at vise hex-datafeltet på send-skærmen"
},
"showPrivateKeys": {
"message": "Vis private nøgler"
},
"sigRequest": {
"message": "Signaturforespørgsel"
},
@ -755,9 +743,6 @@
"tryAgain": {
"message": "Prøv igen"
},
"typePassword": {
"message": "Skriv din MetaMask-adgangskode"
},
"unapproved": {
"message": "Ikke godkendt"
},

View File

@ -898,9 +898,6 @@
"copyAddress": {
"message": "Adresse in die Zwischenablage kopieren"
},
"copyPrivateKey": {
"message": "Das ist Ihr Private Key (klicken um zu kopieren)"
},
"copyRawTransactionData": {
"message": "Roh-Transaktionsdaten kopieren"
},
@ -1482,9 +1479,6 @@
"enterOptionalPassword": {
"message": "Optionales Passwort eingeben"
},
"enterPassword": {
"message": "Passwort eingeben"
},
"enterPasswordContinue": {
"message": "Zum Fortfahren Passwort eingeben"
},
@ -1561,9 +1555,6 @@
"exploreMetaMaskSnaps": {
"message": "MetaMask Snaps erforschen"
},
"exportPrivateKey": {
"message": "Private Key exportieren"
},
"extendWalletWithSnaps": {
"message": "Erweitern Sie das Wallet-Erlebnis."
},
@ -3868,9 +3859,6 @@
"showPrivateKey": {
"message": "Privaten Key anzeigen"
},
"showPrivateKeys": {
"message": "Private Keys anzeigen"
},
"showTestnetNetworks": {
"message": "Test-Netzwerke anzeigen"
},
@ -5130,9 +5118,6 @@
"txInsightsNotSupported": {
"message": "Transaktionseinsichten für diesen Vertrag zu diesem Zeitpunkt nicht unterstützt."
},
"typePassword": {
"message": "Passwort eingeben"
},
"typeYourSRP": {
"message": "Geben Sie Ihre geheime Wiederherstellungsphrase ein"
},

View File

@ -898,9 +898,6 @@
"copyAddress": {
"message": "Αντιγράψτε τη διεύθυνση στο πρόχειρο"
},
"copyPrivateKey": {
"message": "Αυτό είναι το ιδιωτικό σας κλειδί (κάντε κλικ για αντιγραφή)"
},
"copyRawTransactionData": {
"message": "Αντιγραφή ακατέργαστων δεδομένων συναλλαγών"
},
@ -1482,9 +1479,6 @@
"enterOptionalPassword": {
"message": "Πληκτρολογήστε προαιρετικό κωδικό πρόσβασης"
},
"enterPassword": {
"message": "Εισάγετε τον κωδικό πρόσβασης"
},
"enterPasswordContinue": {
"message": "Πληκτρολογήστε τον κωδικό πρόσβασης για να συνεχίσετε"
},
@ -1561,9 +1555,6 @@
"exploreMetaMaskSnaps": {
"message": "Εξερευνήστε το MetaMask Snaps"
},
"exportPrivateKey": {
"message": "Εξαγωγή Ιδιωτικού Κλειδιού"
},
"extendWalletWithSnaps": {
"message": "Επεκτείνετε την εμπειρία του πορτοφολιού."
},
@ -3868,9 +3859,6 @@
"showPrivateKey": {
"message": "Εμφάνιση ιδιωτικού κλειδιού"
},
"showPrivateKeys": {
"message": "Εμφάνιση Ιδιωτικών Κλειδιών"
},
"showTestnetNetworks": {
"message": "Εμφάνιση δοκιμαστικών δικτύων"
},
@ -5130,9 +5118,6 @@
"txInsightsNotSupported": {
"message": "Οι αναλύσεις συναλλαγών εις βάθος δεν υποστηρίζονται για αυτό το συμβόλαιο αυτή τη στιγμή."
},
"typePassword": {
"message": "Πληκτρολογήστε τον κωδικό πρόσβασής σας MetaMask"
},
"typeYourSRP": {
"message": "Πληκτρολογήστε τη Μυστική σας Φράση Ανάκτησης"
},

View File

@ -901,9 +901,6 @@
"copyAddress": {
"message": "Copy address to clipboard"
},
"copyPrivateKey": {
"message": "This is your private key (click to copy)"
},
"copyRawTransactionData": {
"message": "Copy raw transaction data"
},
@ -1485,9 +1482,6 @@
"enterOptionalPassword": {
"message": "Enter optional password"
},
"enterPassword": {
"message": "Enter password"
},
"enterPasswordContinue": {
"message": "Enter password to continue"
},
@ -1564,9 +1558,6 @@
"exploreMetaMaskSnaps": {
"message": "Explore MetaMask Snaps"
},
"exportPrivateKey": {
"message": "Export private key"
},
"extendWalletWithSnaps": {
"message": "Extend the wallet experience."
},
@ -3871,9 +3862,6 @@
"showPrivateKey": {
"message": "Show private key"
},
"showPrivateKeys": {
"message": "Show Private Keys"
},
"showTestnetNetworks": {
"message": "Show test networks"
},
@ -5133,9 +5121,6 @@
"txInsightsNotSupported": {
"message": "Transaction insights not supported for this contract at this time."
},
"typePassword": {
"message": "Type your MetaMask password"
},
"typeYourSRP": {
"message": "Type your Secret Recovery Phrase"
},

View File

@ -898,9 +898,6 @@
"copyAddress": {
"message": "Copiar dirección al Portapapeles"
},
"copyPrivateKey": {
"message": "Esta es su clave privada (haga clic para copiarla)"
},
"copyRawTransactionData": {
"message": "Copiar los datos de las transacciones en bruto"
},
@ -1482,9 +1479,6 @@
"enterOptionalPassword": {
"message": "Ingrese la contraseña opcional"
},
"enterPassword": {
"message": "Escribir contraseña"
},
"enterPasswordContinue": {
"message": "Escribir contraseña para continuar"
},
@ -1561,9 +1555,6 @@
"exploreMetaMaskSnaps": {
"message": "Explore complementos de MetaMask"
},
"exportPrivateKey": {
"message": "Exportar clave privada"
},
"extendWalletWithSnaps": {
"message": "Amplíe la experiencia de uso de la cartera."
},
@ -3868,9 +3859,6 @@
"showPrivateKey": {
"message": "Mostrar clave privada"
},
"showPrivateKeys": {
"message": "Mostrar claves privadas"
},
"showTestnetNetworks": {
"message": "Mostrar redes de prueba"
},
@ -5130,9 +5118,6 @@
"txInsightsNotSupported": {
"message": "En este momento no se admiten informaciones sobre las transacciones para este contrato."
},
"typePassword": {
"message": "Escriba su contraseña de MetaMask"
},
"typeYourSRP": {
"message": "Escriba la frase secreta de respaldo"
},

View File

@ -475,9 +475,6 @@
"copyAddress": {
"message": "Copiar dirección al Portapapeles"
},
"copyPrivateKey": {
"message": "Esta es su clave privada (haga clic para copiarla)"
},
"copyRawTransactionData": {
"message": "Copiar los datos de las transacciones en bruto"
},
@ -767,9 +764,6 @@
"enterMaxSpendLimit": {
"message": "Escribir límite máximo de gastos"
},
"enterPassword": {
"message": "Escribir contraseña"
},
"enterPasswordContinue": {
"message": "Escribir contraseña para continuar"
},
@ -826,9 +820,6 @@
"experimental": {
"message": "Experimental"
},
"exportPrivateKey": {
"message": "Exportar clave privada"
},
"externalExtension": {
"message": "Extensión externa"
},
@ -2012,9 +2003,6 @@
"showPermissions": {
"message": "Mostrar permisos"
},
"showPrivateKeys": {
"message": "Mostrar claves privadas"
},
"showTestnetNetworks": {
"message": "Mostrar redes de prueba"
},
@ -2629,9 +2617,6 @@
"txInsightsNotSupported": {
"message": "En este momento no se admiten informaciones sobre las transacciones para este contrato."
},
"typePassword": {
"message": "Escriba su contraseña de MetaMask"
},
"u2f": {
"message": "U2F",
"description": "A name on an API for the browser to interact with devices that support the U2F protocol. On some browsers we use it to connect MetaMask to Ledger devices."

View File

@ -175,9 +175,6 @@
"copyAddress": {
"message": "Kopeeri aadress lõikelauale"
},
"copyPrivateKey": {
"message": "See on teie privaatne võti (klõpsake kopeerimiseks)"
},
"copyToClipboard": {
"message": "Kopeeri lõikelauale"
},
@ -241,9 +238,6 @@
"ensRegistrationError": {
"message": "Tõrge ENS-i nime registreerimisel"
},
"enterPassword": {
"message": "Sisestage parool"
},
"enterPasswordContinue": {
"message": "Jätkamiseks sisestage parool"
},
@ -256,9 +250,6 @@
"expandView": {
"message": "Laienda vaadet"
},
"exportPrivateKey": {
"message": "Ekspordi privaatvõti"
},
"failed": {
"message": "Nurjus"
},
@ -653,9 +644,6 @@
"showHexDataDescription": {
"message": "Valige see, et kuvada saatmisekraanil hex-andmete väli"
},
"showPrivateKeys": {
"message": "Kuva privaatvõtmed"
},
"sigRequest": {
"message": "Allkirja taotlus"
},
@ -776,9 +764,6 @@
"tryAgain": {
"message": "Proovi uuesti"
},
"typePassword": {
"message": "Sisestage oma MetaMaski parool"
},
"unapproved": {
"message": "Kinnitamata"
},

View File

@ -175,9 +175,6 @@
"copyAddress": {
"message": "کاپی آدرس به کلیپ بورد"
},
"copyPrivateKey": {
"message": "این کلید خصوصی شما است (برای کاپی نمودن کلیک کنید)"
},
"copyToClipboard": {
"message": "کپی در بریده‌دان"
},
@ -241,9 +238,6 @@
"ensRegistrationError": {
"message": "خطا در ثبت نام ENS"
},
"enterPassword": {
"message": "رمز عبور را وارد کنید"
},
"enterPasswordContinue": {
"message": "برای ادامه رمز عبور را وارد کنید"
},
@ -256,9 +250,6 @@
"expandView": {
"message": "توسعه ساحه دید"
},
"exportPrivateKey": {
"message": "صدور کلید شخصی"
},
"failed": {
"message": "ناموفق شد"
},
@ -663,9 +654,6 @@
"showHexDataDescription": {
"message": "برای نمایش بخش اطلاعات hex در صفحه ارسال این را انتخاب نمایید"
},
"showPrivateKeys": {
"message": "نمایش کلید های شخصی"
},
"sigRequest": {
"message": "درخواست امضاء"
},
@ -786,9 +774,6 @@
"tryAgain": {
"message": "امتحان مجدد"
},
"typePassword": {
"message": "رمز عبور MetaMask تان را تایپ نمایید"
},
"unapproved": {
"message": "تصدیق ناشده"
},

View File

@ -175,9 +175,6 @@
"copyAddress": {
"message": "Kopioi osoite leikepöydälle"
},
"copyPrivateKey": {
"message": "Tämä on yksityinen avaimesi (kopioi napsauttamalla)"
},
"copyToClipboard": {
"message": "Kopioi leikepöydälle"
},
@ -241,9 +238,6 @@
"ensRegistrationError": {
"message": "Virhe ENS-nimen rekisteröinnissä"
},
"enterPassword": {
"message": "Kirjoita salasana"
},
"enterPasswordContinue": {
"message": "Syötä salasana voidaksesi jatkaa"
},
@ -256,9 +250,6 @@
"expandView": {
"message": "Laajenna näkymää"
},
"exportPrivateKey": {
"message": "Vie yksityinen avain"
},
"failed": {
"message": "Epäonnistui"
},
@ -660,9 +651,6 @@
"showHexDataDescription": {
"message": "Näytä hex-tietokenttä lähetysnäytössä valitsemalla tämän"
},
"showPrivateKeys": {
"message": "Näytä yksityiset avaimet"
},
"sigRequest": {
"message": "Allekirjoitus pyydetään"
},
@ -783,9 +771,6 @@
"tryAgain": {
"message": "Yritä uudelleen"
},
"typePassword": {
"message": "Kirjoita MetaMask-salasanasi"
},
"unapproved": {
"message": "Ei hyväksytty"
},

View File

@ -154,9 +154,6 @@
"copyAddress": {
"message": "Kopyahin ang address sa clipboard"
},
"copyPrivateKey": {
"message": "Ito ang iyong pribadong private key (i-click para kopyahin)"
},
"copyToClipboard": {
"message": "Kopyahin sa clipboard"
},
@ -217,9 +214,6 @@
"ensRegistrationError": {
"message": "May error sa pagrerehistro ng ENS name"
},
"enterPassword": {
"message": "Ilagay ang password"
},
"enterPasswordContinue": {
"message": "Ilagay ang password para magpatuloy"
},
@ -229,9 +223,6 @@
"expandView": {
"message": "I-expand ang View"
},
"exportPrivateKey": {
"message": "I-export ang Private Key"
},
"failed": {
"message": "Nabigo"
},
@ -587,9 +578,6 @@
"showHexDataDescription": {
"message": "Piliin ito para ipakita ang hex data field sa screen ng pagpapadala"
},
"showPrivateKeys": {
"message": "Ipakita ang mga Private Key"
},
"sign": {
"message": "I-sign"
},
@ -698,9 +686,6 @@
"tryAgain": {
"message": "Subukang muli"
},
"typePassword": {
"message": "I-type ang iyong password sa MetaMask"
},
"unapproved": {
"message": "Hindi inaprubahan"
},

View File

@ -898,9 +898,6 @@
"copyAddress": {
"message": "Copier laddresse dans le presse-papier"
},
"copyPrivateKey": {
"message": "Ceci est votre clé privée (cliquez pour copier)"
},
"copyRawTransactionData": {
"message": "Copier les données brutes de la transaction"
},
@ -1482,9 +1479,6 @@
"enterOptionalPassword": {
"message": "Entrez le mot de passe facultatif"
},
"enterPassword": {
"message": "Entrez votre mot de passe"
},
"enterPasswordContinue": {
"message": "Entrez votre mot de passe pour continuer"
},
@ -1561,9 +1555,6 @@
"exploreMetaMaskSnaps": {
"message": "Explorer les Snaps MetaMask"
},
"exportPrivateKey": {
"message": "Exporter la clé privée"
},
"extendWalletWithSnaps": {
"message": "Prolongez lexpérience avec ce portefeuille."
},
@ -3868,9 +3859,6 @@
"showPrivateKey": {
"message": "Afficher la clé privée"
},
"showPrivateKeys": {
"message": "Afficher les clés privées"
},
"showTestnetNetworks": {
"message": "Afficher les réseaux de test"
},
@ -5130,9 +5118,6 @@
"txInsightsNotSupported": {
"message": "Les aperçus de transaction ne sont pas pris en charge pour ce contrat à lheure actuelle."
},
"typePassword": {
"message": "Entrez votre mot de passe"
},
"typeYourSRP": {
"message": "Saisissez votre phrase secrète de récupération"
},

View File

@ -175,9 +175,6 @@
"copyAddress": {
"message": "העתק כתובת ללוח"
},
"copyPrivateKey": {
"message": "זה המפתח הפרטי שלך (נא להקיש כדי להעתיק)"
},
"copyToClipboard": {
"message": "העתק ללוח"
},
@ -241,9 +238,6 @@
"ensRegistrationError": {
"message": "שגיאה ברישום שם ENS"
},
"enterPassword": {
"message": "יש להזין ססמה"
},
"enterPasswordContinue": {
"message": "יש להזין ססמה כדי להמשיך"
},
@ -256,9 +250,6 @@
"expandView": {
"message": "הרחב תצוגה"
},
"exportPrivateKey": {
"message": "יצא/י מפתח פרטי"
},
"failed": {
"message": "נכשל"
},
@ -660,9 +651,6 @@
"showHexDataDescription": {
"message": "בחר/י בזה כדי להציג את שדה הנתונים ההקסדצימאלים על מסך השליחה"
},
"showPrivateKeys": {
"message": "הצג מפתחות פרטיים"
},
"sigRequest": {
"message": "בקשת חתימה"
},
@ -783,9 +771,6 @@
"tryAgain": {
"message": "ניסיון חוזר"
},
"typePassword": {
"message": "נא להקליד את סיסמת MetaMask שלך"
},
"unapproved": {
"message": "לא אושר"
},

View File

@ -898,9 +898,6 @@
"copyAddress": {
"message": "क्लिपबोर्ड पर पता कॉपी करें"
},
"copyPrivateKey": {
"message": "यह आपकी निजी कुंजी है (कॉपी करने के लिए क्लिक करें)"
},
"copyRawTransactionData": {
"message": "लेन-देन का अपरिष्कृत डेटा कॉपी करें"
},
@ -1482,9 +1479,6 @@
"enterOptionalPassword": {
"message": "वैकल्पिक पासवर्ड डालें"
},
"enterPassword": {
"message": "पासवर्ड दर्ज करें"
},
"enterPasswordContinue": {
"message": "जारी रखने के लिए पासवर्ड दर्ज करें"
},
@ -1561,9 +1555,6 @@
"exploreMetaMaskSnaps": {
"message": "MetaMask स्नैप्स का अन्वेषण करें"
},
"exportPrivateKey": {
"message": "निजी कुंजी निर्यात करें"
},
"extendWalletWithSnaps": {
"message": "वॉलेट अनुभव का विस्तार करें।"
},
@ -3868,9 +3859,6 @@
"showPrivateKey": {
"message": "निजी कुंजी दिखाएं"
},
"showPrivateKeys": {
"message": "निजी कुंजियां दिखाएं"
},
"showTestnetNetworks": {
"message": "परीक्षण नेटवर्क दिखाएं"
},
@ -5130,9 +5118,6 @@
"txInsightsNotSupported": {
"message": "इस समय इस अनुबंध के लिए लेन-देन की जानकारी समर्थित नहीं है।"
},
"typePassword": {
"message": "अपना MetaMask पासवर्ड टाइप करें"
},
"typeYourSRP": {
"message": "अपना गुप्त रिकवरी वाक्यांश लिखें"
},

View File

@ -60,9 +60,6 @@
"copiedExclamation": {
"message": "कॉपी कर दिया गया!"
},
"copyPrivateKey": {
"message": "यह आपकी निजी कुंजी है (कॉपी करने के लिए क्लिक करें)।"
},
"copyToClipboard": {
"message": "क्लिपबोर्ड पर कॉपी करें"
},
@ -87,15 +84,9 @@
"edit": {
"message": "संपादित करें"
},
"enterPassword": {
"message": "पासवर्ड दर्ज करें"
},
"etherscanView": {
"message": "ईथरस्कैन पर खाता देखें"
},
"exportPrivateKey": {
"message": "निजी कुंजी निर्यात करें"
},
"failed": {
"message": "विफल"
},
@ -281,9 +272,6 @@
"settings": {
"message": "सेटिंग्स"
},
"showPrivateKeys": {
"message": "निजी कुंजी दिखाएँ"
},
"sigRequest": {
"message": "हस्ताक्षर अनुरोध"
},
@ -317,9 +305,6 @@
"total": {
"message": "कुल"
},
"typePassword": {
"message": "अपना पासवर्ड टाइप करें"
},
"unknown": {
"message": "अज्ञात नेटवर्क"
},

View File

@ -175,9 +175,6 @@
"copyAddress": {
"message": "Kopiraj adresu u međuspremnik"
},
"copyPrivateKey": {
"message": "Ovo je vaš privatni ključ (kliknite za kopiranje)"
},
"copyToClipboard": {
"message": "Kopiraj u međuspremnik"
},
@ -241,9 +238,6 @@
"ensRegistrationError": {
"message": "Greška u registraciji naziva ENS"
},
"enterPassword": {
"message": "Upiši lozinku"
},
"enterPasswordContinue": {
"message": "Upišite lozinku za nastavak"
},
@ -256,9 +250,6 @@
"expandView": {
"message": "Proširi prikaz"
},
"exportPrivateKey": {
"message": "Izvezi privatni ključ"
},
"failed": {
"message": "Neuspješno"
},
@ -656,9 +647,6 @@
"showHexDataDescription": {
"message": "Odaberite ovu stavku za prikaz polja namijenjenog za podatke hex na zaslonu za slanje"
},
"showPrivateKeys": {
"message": "Prikaži privatne ključe"
},
"sigRequest": {
"message": "Zahtjev za potpisom"
},
@ -776,9 +764,6 @@
"tryAgain": {
"message": "Pokušaj ponovo"
},
"typePassword": {
"message": "Upišite svoju lozinku MetaMask."
},
"unapproved": {
"message": "Neodobreno"
},

View File

@ -108,9 +108,6 @@
"copyAddress": {
"message": "Kopi adrès clipboard"
},
"copyPrivateKey": {
"message": "Sa a se kle prive ou (klike pou ou kopye)"
},
"copyToClipboard": {
"message": "Kopi clipboard"
},
@ -147,9 +144,6 @@
"edit": {
"message": "Korije"
},
"enterPassword": {
"message": "Mete modpas"
},
"enterPasswordContinue": {
"message": "Mete modpas pou kontinye"
},
@ -159,9 +153,6 @@
"expandView": {
"message": "Elaji Wè"
},
"exportPrivateKey": {
"message": "Voye Kòd Prive"
},
"failed": {
"message": "Tonbe"
},
@ -482,9 +473,6 @@
"showHexDataDescription": {
"message": "Pran sa pouw ka montre chan entèfas hex data a"
},
"showPrivateKeys": {
"message": "Montre Kle Prive"
},
"sigRequest": {
"message": "Demann Siyati"
},
@ -554,9 +542,6 @@
"tryAgain": {
"message": "Eseye anko"
},
"typePassword": {
"message": "Tape modpas ou"
},
"unapproved": {
"message": "Pa apwouve"
},

View File

@ -175,9 +175,6 @@
"copyAddress": {
"message": "Másolja a címet a vágólapra"
},
"copyPrivateKey": {
"message": "Ez a saját titkos kulcsod (kattints rá a másoláshoz)"
},
"copyToClipboard": {
"message": "Másolás a vágólapra"
},
@ -241,9 +238,6 @@
"ensRegistrationError": {
"message": "Hiba történt az ENS név regisztrációjakor"
},
"enterPassword": {
"message": "Adja meg a jelszót"
},
"enterPasswordContinue": {
"message": "A folytatáshoz adja meg a jelszót"
},
@ -256,9 +250,6 @@
"expandView": {
"message": "Nézet nagyítása"
},
"exportPrivateKey": {
"message": "Privát kulcs exportálása"
},
"failed": {
"message": "Sikertelen"
},
@ -656,9 +647,6 @@
"showHexDataDescription": {
"message": "Válassza ezt, ha a hex adatmezőt a küldő képernyőn szeretné megnézni"
},
"showPrivateKeys": {
"message": "Mutassa a privát kulcsokat"
},
"sigRequest": {
"message": "Aláírás kérése"
},
@ -776,9 +764,6 @@
"tryAgain": {
"message": "Újra"
},
"typePassword": {
"message": "Írd be MetaMask jelszavadat"
},
"unapproved": {
"message": "Jóvá nem hagyott"
},

View File

@ -898,9 +898,6 @@
"copyAddress": {
"message": "Salin alamat ke papan klip"
},
"copyPrivateKey": {
"message": "Ini adalah kunci privat Anda (klik untuk menyalin)"
},
"copyRawTransactionData": {
"message": "Salin data transaksi mentah"
},
@ -1482,9 +1479,6 @@
"enterOptionalPassword": {
"message": "Masukkan kata sandi opsional"
},
"enterPassword": {
"message": "Masukkan kata sandi"
},
"enterPasswordContinue": {
"message": "Masukkan kata sandi untuk melanjutkan"
},
@ -1561,9 +1555,6 @@
"exploreMetaMaskSnaps": {
"message": "Jelajahi MetaMask Snaps"
},
"exportPrivateKey": {
"message": "Ekspor kunci privat"
},
"extendWalletWithSnaps": {
"message": "Perluas pengalaman dompet."
},
@ -3868,9 +3859,6 @@
"showPrivateKey": {
"message": "Tampilkan kunci pribadi"
},
"showPrivateKeys": {
"message": "Tampilkan Kunci Privat"
},
"showTestnetNetworks": {
"message": "Tampilkan jaringan pengujian"
},
@ -5130,9 +5118,6 @@
"txInsightsNotSupported": {
"message": "Pemahaman transaksi tidak didukung untuk kontrak ini saat ini."
},
"typePassword": {
"message": "Ketikkan kata sandi MetaMask Anda"
},
"typeYourSRP": {
"message": "Ketik Frasa Pemulihan Rahasia"
},

View File

@ -579,9 +579,6 @@
"copyAddress": {
"message": "Copia l'indirizzo"
},
"copyPrivateKey": {
"message": "Questa è la tua chiave privata (clicca per copiare)"
},
"copyRawTransactionData": {
"message": "Copia i dati grezzi della transazione"
},
@ -840,9 +837,6 @@
"enterMaxSpendLimit": {
"message": "Inserisici Limite Spesa"
},
"enterPassword": {
"message": "Inserisci password"
},
"enterPasswordContinue": {
"message": "Inserisci la tua password per continuare"
},
@ -875,9 +869,6 @@
"expandView": {
"message": "Espandi Vista"
},
"exportPrivateKey": {
"message": "Esporta Chiave Privata"
},
"externalExtension": {
"message": "Estensione Esterna"
},
@ -1439,9 +1430,6 @@
"showPermissions": {
"message": "Mostra permessi"
},
"showPrivateKeys": {
"message": "Mostra Chiave Privata"
},
"sigRequest": {
"message": "Firma Richiesta"
},
@ -1794,9 +1782,6 @@
"tryAgain": {
"message": "Prova di nuovo"
},
"typePassword": {
"message": "Inserisci Password"
},
"unapproved": {
"message": "Non approvata"
},

View File

@ -898,9 +898,6 @@
"copyAddress": {
"message": "アドレスをクリップボードにコピー"
},
"copyPrivateKey": {
"message": "これは秘密鍵です (クリックしてコピー)"
},
"copyRawTransactionData": {
"message": "未処理のトランザクションデータをコピー"
},
@ -1482,9 +1479,6 @@
"enterOptionalPassword": {
"message": "オプションのパスワードを入力してください"
},
"enterPassword": {
"message": "パスワードを入力してください"
},
"enterPasswordContinue": {
"message": "続行するには、パスワードを入力してください"
},
@ -1561,9 +1555,6 @@
"exploreMetaMaskSnaps": {
"message": "MetaMask スナップを閲覧"
},
"exportPrivateKey": {
"message": "秘密鍵のエクスポート"
},
"extendWalletWithSnaps": {
"message": "ウォレットのエクスペリエンスを拡張します。"
},
@ -3868,9 +3859,6 @@
"showPrivateKey": {
"message": "秘密鍵を表示"
},
"showPrivateKeys": {
"message": "秘密鍵を表示"
},
"showTestnetNetworks": {
"message": "テストネットワークを表示"
},
@ -5130,9 +5118,6 @@
"txInsightsNotSupported": {
"message": "現時点ではこのコントラクトでトランザクションインサイトはサポートされていません。"
},
"typePassword": {
"message": "MetaMaskパスワードを入力してください"
},
"typeYourSRP": {
"message": "秘密のリカバリーフレーズを入力してください"
},

View File

@ -175,9 +175,6 @@
"copyAddress": {
"message": "ವಿಳಾಸವನ್ನು ಕ್ಲಿಪ್‌ಬೋರ್ಡ್‌ಗೆ ನಕಲಿಸಿ"
},
"copyPrivateKey": {
"message": "ಇದು ನಿಮ್ಮ ಖಾಸಗಿ ಕೀ ಆಗಿದೆ (ನಕಲಿಸಲು ಕ್ಲಿಕ್ ಮಾಡಿ)"
},
"copyToClipboard": {
"message": "ಕ್ಲಿಪ್‌ಬೋರ್ಡ್‌ಗೆ ನಕಲಿಸಿ"
},
@ -241,9 +238,6 @@
"ensRegistrationError": {
"message": "ENS ಹೆಸರಿನ ನೋಂದಣಿಯಲ್ಲಿ ದೋಷ"
},
"enterPassword": {
"message": "ಪಾಸ್‌ವರ್ಡ್‌ ಅನ್ನು ನಮೂದಿಸಿ"
},
"enterPasswordContinue": {
"message": "ಮುಂದುವರೆಯಲು ಪಾಸ್‌ವರ್ಡ್ ನಮೂದಿಸಿ"
},
@ -256,9 +250,6 @@
"expandView": {
"message": "ವಿಸ್ತರಿಸಿದ ವೀಕ್ಷಣೆ"
},
"exportPrivateKey": {
"message": "ಖಾಸಗಿ ಕೀಲಿಯನ್ನು ರಫ್ತು ಮಾಡಿ"
},
"failed": {
"message": "ವಿಫಲವಾಗಿದೆ"
},
@ -663,9 +654,6 @@
"showHexDataDescription": {
"message": "ಕಳುಹಿಸುವ ಪರದೆಯಲ್ಲಿ ಹೆಕ್ಸ್ ಡೇಟಾ ಕ್ಷೇತ್ರವನ್ನು ತೋರಿಸಲು ಇದನ್ನು ಆಯ್ಕೆಮಾಡಿ"
},
"showPrivateKeys": {
"message": "ಖಾಸಗಿ ಕೀಗಳನ್ನು ತೋರಿಸಿ"
},
"sigRequest": {
"message": "ಸಹಿಯ ವಿನಂತಿ"
},
@ -786,9 +774,6 @@
"tryAgain": {
"message": "ಪುನಃ ಪ್ರಯತ್ನಿಸಿ"
},
"typePassword": {
"message": "ನಿಮ್ಮ MetaMask ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು ಟೈಪ್ ಮಾಡಿ"
},
"unapproved": {
"message": "ಅನುಮೋದಿಸದಿರುವುದು"
},

View File

@ -898,9 +898,6 @@
"copyAddress": {
"message": "주소를 클립보드에 복사"
},
"copyPrivateKey": {
"message": "이는 귀하의 비공개 키입니다(클릭하여 복사)"
},
"copyRawTransactionData": {
"message": "원시 거래 데이터 복사"
},
@ -1482,9 +1479,6 @@
"enterOptionalPassword": {
"message": "선택적 비밀번호를 입력하세요"
},
"enterPassword": {
"message": "비밀번호 입력"
},
"enterPasswordContinue": {
"message": "계속하려면 비밀번호를 입력하세요"
},
@ -1561,9 +1555,6 @@
"exploreMetaMaskSnaps": {
"message": "MetaMask 스냅 탐색"
},
"exportPrivateKey": {
"message": "비공개 키 내보내기"
},
"extendWalletWithSnaps": {
"message": "지갑 경험 확장"
},
@ -3868,9 +3859,6 @@
"showPrivateKey": {
"message": "개인 키 표시"
},
"showPrivateKeys": {
"message": "비공개 키 표시"
},
"showTestnetNetworks": {
"message": "테스트 네트워크 보기"
},
@ -5130,9 +5118,6 @@
"txInsightsNotSupported": {
"message": "현재 이 계약에 대해 거래 인사이트가 지원되지 않습니다."
},
"typePassword": {
"message": "MetaMask 비밀번호를 입력하세요"
},
"typeYourSRP": {
"message": "비밀 복구 구문을 입력하세요"
},

View File

@ -175,9 +175,6 @@
"copyAddress": {
"message": "Kopijuoti adresą į iškarpinę"
},
"copyPrivateKey": {
"message": "Tai yra jūsų asmeninis raktas (spustelėkite, kad nukopijuotumėte)"
},
"copyToClipboard": {
"message": "Kopijuoti į iškarpinę"
},
@ -241,9 +238,6 @@
"ensRegistrationError": {
"message": "ENS pavadinimo registracijos klaida"
},
"enterPassword": {
"message": "Įveskite slaptažodį"
},
"enterPasswordContinue": {
"message": "Norėdami tęsti, įveskite slaptažodį"
},
@ -256,9 +250,6 @@
"expandView": {
"message": "Išskleisti rodinį"
},
"exportPrivateKey": {
"message": "Eksportuoti asmeninį raktą"
},
"failed": {
"message": "Nepavyko"
},
@ -663,9 +654,6 @@
"showHexDataDescription": {
"message": "Pasirinkite tai, kad siuntimo ekrane būtų rodomas šešioliktainių duomenų laukas"
},
"showPrivateKeys": {
"message": "Rodyti asmeninius raktus"
},
"sigRequest": {
"message": "Parašo užklausa"
},
@ -786,9 +774,6 @@
"tryAgain": {
"message": "Bandyti dar kartą"
},
"typePassword": {
"message": "Įveskite savo „MetaMask“ slaptažodį"
},
"unapproved": {
"message": "Nepatvirtinta"
},

View File

@ -175,9 +175,6 @@
"copyAddress": {
"message": "Iekopēt adresi starpliktuvē"
},
"copyPrivateKey": {
"message": "Šī ir jūsu privātā atslēga (noklikšķiniet, lai nokopētu)"
},
"copyToClipboard": {
"message": "Kopēt starpliktuvē"
},
@ -241,9 +238,6 @@
"ensRegistrationError": {
"message": "Kļūda ENS vārda reģistrācijā"
},
"enterPassword": {
"message": "Ievadiet paroli"
},
"enterPasswordContinue": {
"message": "Ievadiet paroli, lai turpinātu"
},
@ -256,9 +250,6 @@
"expandView": {
"message": "Izvērst skatījumu"
},
"exportPrivateKey": {
"message": "Eksportēt privāto atslēgu"
},
"failed": {
"message": "Neizdevās"
},
@ -659,9 +650,6 @@
"showHexDataDescription": {
"message": "Atlasiet šo, lai atvērtu hex datus sūtīšanas ekrānā"
},
"showPrivateKeys": {
"message": "Rādīt privātās atslēgas"
},
"sigRequest": {
"message": "Paraksta pieprasījums"
},
@ -782,9 +770,6 @@
"tryAgain": {
"message": "Mēģināt vēlreiz"
},
"typePassword": {
"message": "Ievadiet savu MetaMask paroli"
},
"unapproved": {
"message": "Nav apstiprināts"
},

View File

@ -175,9 +175,6 @@
"copyAddress": {
"message": "Salin alamat kepada papan klip"
},
"copyPrivateKey": {
"message": "Ini kunci persendirian anda (klik untuk menyalin)"
},
"copyToClipboard": {
"message": "Salin ke papan keratan"
},
@ -238,9 +235,6 @@
"ensRegistrationError": {
"message": "Ralat dalam pendaftaran nama ENS"
},
"enterPassword": {
"message": "Masukkan kata laluan"
},
"enterPasswordContinue": {
"message": "Masukkan kata laluan untuk teruskan"
},
@ -253,9 +247,6 @@
"expandView": {
"message": "Kembangkan Paparan"
},
"exportPrivateKey": {
"message": "Eksport Kekunci Persendirian"
},
"failed": {
"message": "Gagal"
},
@ -643,9 +634,6 @@
"showHexDataDescription": {
"message": "Pilih ini untuk menunjukkan medan data hex pada skrin hantar"
},
"showPrivateKeys": {
"message": "Tunjukkan Kunci Persendirian"
},
"sigRequest": {
"message": "Permintaan Tandatangan"
},
@ -763,9 +751,6 @@
"tryAgain": {
"message": "Cuba lagi"
},
"typePassword": {
"message": "Taip kata laluan MetaMask anda"
},
"unapproved": {
"message": "Belum Diluluskan"
},

View File

@ -60,9 +60,6 @@
"copiedExclamation": {
"message": "Gekopieerd!"
},
"copyPrivateKey": {
"message": "Dit is uw privésleutel (klik om te kopiëren)"
},
"copyToClipboard": {
"message": "Kopieer naar klembord"
},
@ -84,15 +81,9 @@
"edit": {
"message": "Bewerk"
},
"enterPassword": {
"message": "Voer wachtwoord in"
},
"etherscanView": {
"message": "Bekijk account op Etherscan"
},
"exportPrivateKey": {
"message": "Exporteer privésleutel"
},
"failed": {
"message": "mislukt"
},
@ -271,9 +262,6 @@
"settings": {
"message": "instellingen"
},
"showPrivateKeys": {
"message": "Privésleutels weergeven"
},
"sigRequest": {
"message": "Ondertekeningsverzoek"
},
@ -307,9 +295,6 @@
"total": {
"message": "Totaal"
},
"typePassword": {
"message": "Typ uw wachtwoord"
},
"unknown": {
"message": "Onbekend"
},

View File

@ -172,9 +172,6 @@
"copyAddress": {
"message": "Kopier adresse til utklippstavlen "
},
"copyPrivateKey": {
"message": "Dette er din private nøkkel (klikk for å kopiere)"
},
"copyToClipboard": {
"message": "Kopiér til utklippstavlen"
},
@ -238,9 +235,6 @@
"ensRegistrationError": {
"message": "Feil i ENS-navneregistrering"
},
"enterPassword": {
"message": "Skriv inn passord "
},
"enterPasswordContinue": {
"message": "Skriv inn passord for å fortsette"
},
@ -253,9 +247,6 @@
"expandView": {
"message": "Utvid visning"
},
"exportPrivateKey": {
"message": "Eksporter privat nøkkel"
},
"failed": {
"message": "Mislyktes"
},
@ -644,9 +635,6 @@
"showHexDataDescription": {
"message": "Velg dette for å vise hex-datafeltet på sendskjermen"
},
"showPrivateKeys": {
"message": "Vis private nøkler"
},
"sigRequest": {
"message": "Signaturforespørsel "
},
@ -761,9 +749,6 @@
"tryAgain": {
"message": "Prøv igjen"
},
"typePassword": {
"message": "Skriv inn MetaMask-passordet"
},
"unapproved": {
"message": "Ikke godkjent "
},

View File

@ -338,9 +338,6 @@
"copyAddress": {
"message": "Kopyahin ang address sa clipboard"
},
"copyPrivateKey": {
"message": "Ito ang iyong pribadong key (i-click para kopyahin)"
},
"copyToClipboard": {
"message": "Kopyahin sa clipboard"
},
@ -489,9 +486,6 @@
"enterMaxSpendLimit": {
"message": "Ilagay ang Max na Limitasyon sa Paggastos"
},
"enterPassword": {
"message": "Ilagay ang password"
},
"enterPasswordContinue": {
"message": "Ilagay ang password para magpatuloy"
},
@ -542,9 +536,6 @@
"expandView": {
"message": "I-expand ang view"
},
"exportPrivateKey": {
"message": "I-export ang Pribadong Key"
},
"externalExtension": {
"message": "External Extension"
},
@ -1309,9 +1300,6 @@
"showPermissions": {
"message": "Ipakita ang mga pahintulot"
},
"showPrivateKeys": {
"message": "Ipakita ang Mga Private Key"
},
"sigRequest": {
"message": "Request ng Signature"
},
@ -1764,9 +1752,6 @@
"tryAgain": {
"message": "Subukan ulit"
},
"typePassword": {
"message": "Uri ng password ng iyong MetaMask"
},
"unapproved": {
"message": "Hindi inaprubahan"
},

View File

@ -175,9 +175,6 @@
"copyAddress": {
"message": "Skopiuj adres do schowka"
},
"copyPrivateKey": {
"message": "To jest Twój prywatny klucz (kliknij żeby skopiować)"
},
"copyToClipboard": {
"message": "Skopiuj do schowka"
},
@ -241,9 +238,6 @@
"ensRegistrationError": {
"message": "Błąd w rejestracji nazwy ENS"
},
"enterPassword": {
"message": "Wpisz hasło"
},
"enterPasswordContinue": {
"message": "Podaj hasło żeby kontynuować"
},
@ -256,9 +250,6 @@
"expandView": {
"message": "Rozwiń widok"
},
"exportPrivateKey": {
"message": "Eksportuj klucz prywatny"
},
"failed": {
"message": "Nie udało się"
},
@ -657,9 +648,6 @@
"showHexDataDescription": {
"message": "Wybierz to żeby pokazać pole danych hex na ekranie wysyłania"
},
"showPrivateKeys": {
"message": "Pokaż prywatne klucze"
},
"sigRequest": {
"message": "Prośba o podpis"
},
@ -774,9 +762,6 @@
"tryAgain": {
"message": "Spróbuj ponownie"
},
"typePassword": {
"message": "Wpisz hasło"
},
"unapproved": {
"message": "Niezatwierdzone"
},

View File

@ -898,9 +898,6 @@
"copyAddress": {
"message": "Copiar endereço para a área de transferência"
},
"copyPrivateKey": {
"message": "Esta é a sua chave privada (carregue para copiar)"
},
"copyRawTransactionData": {
"message": "Copiar dados brutos da transação"
},
@ -1482,9 +1479,6 @@
"enterOptionalPassword": {
"message": "Insira a senha opcional"
},
"enterPassword": {
"message": "Introduza palavra-passe"
},
"enterPasswordContinue": {
"message": "Insira a senha para continuar"
},
@ -1561,9 +1555,6 @@
"exploreMetaMaskSnaps": {
"message": "Explorar os snaps da MetaMask"
},
"exportPrivateKey": {
"message": "Exportar chave privada"
},
"extendWalletWithSnaps": {
"message": "Amplie a experiência da carteira."
},
@ -3868,9 +3859,6 @@
"showPrivateKey": {
"message": "Exibir chave privada"
},
"showPrivateKeys": {
"message": "Mostrar Chaves Privadas"
},
"showTestnetNetworks": {
"message": "Mostrar redes de teste"
},
@ -5130,9 +5118,6 @@
"txInsightsNotSupported": {
"message": "As informações sobre transações não são suportadas para esse contrato, por ora."
},
"typePassword": {
"message": "Digite a sua Palavra-passe"
},
"typeYourSRP": {
"message": "Digite sua Frase de Recuperação Secreta"
},

View File

@ -475,9 +475,6 @@
"copyAddress": {
"message": "Copiar endereço para a área de transferência"
},
"copyPrivateKey": {
"message": "Essa é a sua chave privada (clique para copiar)"
},
"copyRawTransactionData": {
"message": "Copiar dados brutos da transação"
},
@ -767,9 +764,6 @@
"enterMaxSpendLimit": {
"message": "Digite um limite máximo de gastos"
},
"enterPassword": {
"message": "Digite a senha"
},
"enterPasswordContinue": {
"message": "Digite a senha para continuar"
},
@ -826,9 +820,6 @@
"experimental": {
"message": "Experimental"
},
"exportPrivateKey": {
"message": "Exportar chave privada"
},
"externalExtension": {
"message": "Extensão externa"
},
@ -2016,9 +2007,6 @@
"showPermissions": {
"message": "Mostrar permissões"
},
"showPrivateKeys": {
"message": "Mostrar chaves privadas"
},
"showTestnetNetworks": {
"message": "Mostrar redes de teste"
},
@ -2633,9 +2621,6 @@
"txInsightsNotSupported": {
"message": "As informações sobre transações não são suportadas para esse contrato, por ora."
},
"typePassword": {
"message": "Digite sua senha da MetaMask"
},
"u2f": {
"message": "U2F",
"description": "A name on an API for the browser to interact with devices that support the U2F protocol. On some browsers we use it to connect MetaMask to Ledger devices."

View File

@ -175,9 +175,6 @@
"copyAddress": {
"message": "Copiere adresă în clipboard"
},
"copyPrivateKey": {
"message": "Aceasta este cheia dumneavoastră privată (clic pentru a copia)"
},
"copyToClipboard": {
"message": "Copiați în clipboard"
},
@ -241,9 +238,6 @@
"ensRegistrationError": {
"message": "Eroare la înregistrarea numelui ENS"
},
"enterPassword": {
"message": "Introduceți parola"
},
"enterPasswordContinue": {
"message": "Introduceți parola pentru a continua"
},
@ -256,9 +250,6 @@
"expandView": {
"message": "Extindeți vizualizarea"
},
"exportPrivateKey": {
"message": "Exportați cheia privată"
},
"failed": {
"message": "Eșuat"
},
@ -650,9 +641,6 @@
"showHexDataDescription": {
"message": "Selectați această opțiune pentru a arăta câmpul de date hexazecimale în ecranul de trimitere."
},
"showPrivateKeys": {
"message": "Afișați cheile private"
},
"sigRequest": {
"message": "Solicitare de semnătură"
},
@ -767,9 +755,6 @@
"tryAgain": {
"message": "Încearcă din nou"
},
"typePassword": {
"message": "Scrieți parola dvs. pentru MetaMask"
},
"unapproved": {
"message": "Neaprobat"
},

View File

@ -898,9 +898,6 @@
"copyAddress": {
"message": "Скопировать адрес в буфер обмена"
},
"copyPrivateKey": {
"message": "Это ваш закрытый ключ (нажмите, чтобы скопировать)"
},
"copyRawTransactionData": {
"message": "Копировать необработанные данные транзакции"
},
@ -1482,9 +1479,6 @@
"enterOptionalPassword": {
"message": "Введите необязательный пароль"
},
"enterPassword": {
"message": "Введите пароль"
},
"enterPasswordContinue": {
"message": "Введите пароль, чтобы продолжить"
},
@ -1561,9 +1555,6 @@
"exploreMetaMaskSnaps": {
"message": "Обзор привязок MetaMask"
},
"exportPrivateKey": {
"message": "Экспорт закрытого ключа"
},
"extendWalletWithSnaps": {
"message": "Расширьте возможности кошелька."
},
@ -3868,9 +3859,6 @@
"showPrivateKey": {
"message": "Показать закрытый ключ"
},
"showPrivateKeys": {
"message": "Показать закрытые ключи"
},
"showTestnetNetworks": {
"message": "Показать тестовые сети"
},
@ -5130,9 +5118,6 @@
"txInsightsNotSupported": {
"message": "Для этого контракта сейчас не поддерживается аналитика транзакций."
},
"typePassword": {
"message": "Введите свой пароль MetaMask"
},
"typeYourSRP": {
"message": "Введите секретную фразу для восстановления"
},

View File

@ -169,9 +169,6 @@
"copyAddress": {
"message": "Kopírovať adresu do schránky"
},
"copyPrivateKey": {
"message": "Toto je váš privátní klíč (kliknutím zkopírujte)"
},
"copyToClipboard": {
"message": "Kopírovat do schránky"
},
@ -235,9 +232,6 @@
"ensRegistrationError": {
"message": "Chyba pri registrácii názvu ENS"
},
"enterPassword": {
"message": "Zadejte heslo"
},
"enterPasswordContinue": {
"message": "Pokračujte zadaním hesla"
},
@ -250,9 +244,6 @@
"expandView": {
"message": "Rozbaliť zobrazenie"
},
"exportPrivateKey": {
"message": "Exportovat privátní klíč"
},
"failed": {
"message": "Neúspěšné"
},
@ -635,9 +626,6 @@
"showHexDataDescription": {
"message": "Vyberte toto, ak chcete, aby sa na obrazovke odosielania zobrazilo hex dátové pole"
},
"showPrivateKeys": {
"message": "Zobrazit privátní klíče"
},
"sigRequest": {
"message": "Požadavek podpisu"
},
@ -752,9 +740,6 @@
"tryAgain": {
"message": "Skúsiť znova"
},
"typePassword": {
"message": "Zadejte své heslo"
},
"unapproved": {
"message": "Neschváleno"
},

View File

@ -175,9 +175,6 @@
"copyAddress": {
"message": "Kopiraj naslov v odložišče"
},
"copyPrivateKey": {
"message": "To je vaš zesebni ključ (kliknite za kopiranje)"
},
"copyToClipboard": {
"message": "Kopiraj v odložišče"
},
@ -241,9 +238,6 @@
"ensRegistrationError": {
"message": "Napaka pri registraciji imena ENS"
},
"enterPassword": {
"message": "Vnesite geslo"
},
"enterPasswordContinue": {
"message": "Za nadaljevanje vnesite geslo"
},
@ -256,9 +250,6 @@
"expandView": {
"message": "Razširi pogled"
},
"exportPrivateKey": {
"message": "Izvozi zasebni ključ"
},
"failed": {
"message": "Ni uspelo"
},
@ -651,9 +642,6 @@
"showHexDataDescription": {
"message": "Izberite za prikaz hex podatkov na zaslonu za pošiljanje"
},
"showPrivateKeys": {
"message": "Pokaži zasebni ključ"
},
"sigRequest": {
"message": "Zahteva za podpis"
},
@ -774,9 +762,6 @@
"tryAgain": {
"message": "Poskusi znova"
},
"typePassword": {
"message": "Vnesite vaše MetaMask geslo"
},
"unapproved": {
"message": "Neodobreno"
},

View File

@ -172,9 +172,6 @@
"copyAddress": {
"message": "Kopirajte adresu u ostavu"
},
"copyPrivateKey": {
"message": "Ovo je vaš privatni ključ (kliknite kako biste ga kopirali)"
},
"copyToClipboard": {
"message": "Копирај у меморију"
},
@ -238,9 +235,6 @@
"ensRegistrationError": {
"message": "Greška u registraciji ENS imena."
},
"enterPassword": {
"message": "Unesite lozinku"
},
"enterPasswordContinue": {
"message": "Unesite lozinku kako biste nastavili"
},
@ -253,9 +247,6 @@
"expandView": {
"message": "Proširite prikaz"
},
"exportPrivateKey": {
"message": "Izvezite privatni ključ"
},
"failed": {
"message": "Neuspešno"
},
@ -654,9 +645,6 @@
"showHexDataDescription": {
"message": "Izaberite ovo da bi se pokazalo polje sa hex podacima na „Pošalji” ekranu "
},
"showPrivateKeys": {
"message": "Prikažite privatne ključeve"
},
"sigRequest": {
"message": "Zahtev za potpisom"
},
@ -774,9 +762,6 @@
"tryAgain": {
"message": "Пробај поново"
},
"typePassword": {
"message": "Ukucajte svoju MetaMask šifru"
},
"unapproved": {
"message": "Neodobren"
},

View File

@ -169,9 +169,6 @@
"copyAddress": {
"message": "Kopiera adress till urklipp"
},
"copyPrivateKey": {
"message": "Det här är din privata nyckel (klicka för att kopiera)"
},
"copyToClipboard": {
"message": "Kopiera till Urklipp"
},
@ -235,9 +232,6 @@
"ensRegistrationError": {
"message": "Fel i ENS-namnregistrering"
},
"enterPassword": {
"message": "Ange lösenord"
},
"enterPasswordContinue": {
"message": "Ange lösenord för att fortsätta"
},
@ -250,9 +244,6 @@
"expandView": {
"message": "Expandera vy"
},
"exportPrivateKey": {
"message": "Exportera privat nyckel"
},
"failed": {
"message": "Misslyckades"
},
@ -647,9 +638,6 @@
"showHexDataDescription": {
"message": "Välj detta för att visa hex-datafältet på sändarskärmen"
},
"showPrivateKeys": {
"message": "Visa privata nycklar"
},
"sigRequest": {
"message": "Signaturförfrågan"
},
@ -761,9 +749,6 @@
"tryAgain": {
"message": "Försök igen"
},
"typePassword": {
"message": "Ange ditt MetaMask-lösenord"
},
"unapproved": {
"message": "Inte godkänd"
},

View File

@ -169,9 +169,6 @@
"copyAddress": {
"message": "Nakili anwani kwenye ubao wa kunakilia"
},
"copyPrivateKey": {
"message": "Huu ni ufunguo wako wa kibinafsi (bofya ili unakili)"
},
"copyToClipboard": {
"message": "Nakili kwenye ubao wa kunakili"
},
@ -235,9 +232,6 @@
"ensRegistrationError": {
"message": "Hitilafu imetokea kwenye usajili wa jina la ENS"
},
"enterPassword": {
"message": "Ingiza nenosiri"
},
"enterPasswordContinue": {
"message": "Ingiza nenosiri ili uendelee"
},
@ -250,9 +244,6 @@
"expandView": {
"message": "Panua Mwonekano"
},
"exportPrivateKey": {
"message": "Panua Mwonekano"
},
"failed": {
"message": "Imeshindwa"
},
@ -641,9 +632,6 @@
"showHexDataDescription": {
"message": "Chagua hii ili uonyeshe sehemu ya data ya hex kwenye skrini ya tuma"
},
"showPrivateKeys": {
"message": "Onyesha Fungo Binafsi"
},
"sigRequest": {
"message": "Ombi la Saini"
},
@ -764,9 +752,6 @@
"tryAgain": {
"message": "Jaribu tena"
},
"typePassword": {
"message": "Andika nenosiri lako la MetaMask"
},
"unapproved": {
"message": "Haijaidhinishwa"
},

View File

@ -87,9 +87,6 @@
"copiedExclamation": {
"message": "நகலெடுக்கப்பட்டன!"
},
"copyPrivateKey": {
"message": "இது உங்கள் தனிப்பட்ட விசை (நகலெடுக்க கிளிக் செய்யவும்)"
},
"copyToClipboard": {
"message": "கிளிப்போர்டுக்கு நகலெடு"
},
@ -126,15 +123,9 @@
"edit": {
"message": "திருத்து"
},
"enterPassword": {
"message": "கடவுச்சொல்லை உள்ளிடவும்"
},
"etherscanView": {
"message": "Etherscan கணக்கைப் பார்க்கவும்"
},
"exportPrivateKey": {
"message": "தனியார் விசை ஐ ஏற்றுமதி செய்க"
},
"failed": {
"message": "தோல்வி"
},
@ -374,9 +365,6 @@
"settings": {
"message": "அமைப்புகள்"
},
"showPrivateKeys": {
"message": "தனிப்பட்ட விசைகளைக் காண்பி"
},
"sigRequest": {
"message": "கையொப்பம் கோரிக்கை"
},
@ -425,9 +413,6 @@
"tryAgain": {
"message": "மீண்டும் முயல்க"
},
"typePassword": {
"message": "உங்கள் கடவுச்சொல்லை தட்டச்சு செய்யவும்"
},
"unapproved": {
"message": "அங்கீகரிக்கப்படாத"
},

View File

@ -78,9 +78,6 @@
"copiedExclamation": {
"message": "คัดลอกแล้ว!"
},
"copyPrivateKey": {
"message": "นี่คือคีย์ส่วนตัวของคุณ(กดเพื่อคัดลอก)"
},
"copyToClipboard": {
"message": "คัดลอกไปคลิปบอร์ด"
},
@ -117,18 +114,12 @@
"editContact": {
"message": "แก้ไขผู้ติดต่อ"
},
"enterPassword": {
"message": "ใส่รหัสผ่าน"
},
"etherscanView": {
"message": "ดูบัญชีบน Etherscan"
},
"expandView": {
"message": "ขยายมุมมอง"
},
"exportPrivateKey": {
"message": "ส่งออกคีย์ส่วนตัว"
},
"failed": {
"message": "ล้มเหลว"
},
@ -338,9 +329,6 @@
"settings": {
"message": "การตั้งค่า"
},
"showPrivateKeys": {
"message": "แสดงคีย์ส่วนตัว"
},
"sigRequest": {
"message": "ขอลายเซ็น"
},
@ -392,9 +380,6 @@
"transactionDropped": {
"message": "ธุรกรรมถูกยกเลิกเมื่อ $2"
},
"typePassword": {
"message": "พิมพ์รหัสผ่านของคุณ"
},
"unknown": {
"message": "ไม่รู้จัก"
},

View File

@ -898,9 +898,6 @@
"copyAddress": {
"message": "Kopyahin ang address sa clipboard"
},
"copyPrivateKey": {
"message": "Ito ang iyong pribadong key (i-click para kopyahin)"
},
"copyRawTransactionData": {
"message": "Kopyahin ang raw na data ng transaksyon"
},
@ -1482,9 +1479,6 @@
"enterOptionalPassword": {
"message": "Ilagay ang opsyonal na password"
},
"enterPassword": {
"message": "Ilagay ang password"
},
"enterPasswordContinue": {
"message": "Ilagay ang password para magpatuloy"
},
@ -1561,9 +1555,6 @@
"exploreMetaMaskSnaps": {
"message": "Galugarin ang MetaMask Snaps"
},
"exportPrivateKey": {
"message": "I-export ang Pribadong Key"
},
"extendWalletWithSnaps": {
"message": "Palawakin ang karanasan sa wallet."
},
@ -3868,9 +3859,6 @@
"showPrivateKey": {
"message": "Ipakita ang private key"
},
"showPrivateKeys": {
"message": "Ipakita ang Mga Pribadong Key"
},
"showTestnetNetworks": {
"message": "Ipakita ang mga test networks"
},
@ -5130,9 +5118,6 @@
"txInsightsNotSupported": {
"message": "Hindi magagamit ang mga pag-alam sa transaksyon para sa contract na ito sa oras na ito."
},
"typePassword": {
"message": "Uri ng password ng iyong MetaMask"
},
"typeYourSRP": {
"message": "I-type ang iyong Secret Recovery Phrase"
},

View File

@ -898,9 +898,6 @@
"copyAddress": {
"message": "Adresi panoya kopyala"
},
"copyPrivateKey": {
"message": "Bu sizin özel anahtarınız (kopyalamak için tıklayın)"
},
"copyRawTransactionData": {
"message": "Ham işlem verisini kopyala"
},
@ -1482,9 +1479,6 @@
"enterOptionalPassword": {
"message": "İsteğe bağlı parolayı girin"
},
"enterPassword": {
"message": "Parolanızı girin"
},
"enterPasswordContinue": {
"message": "Devam etmek için parola girin"
},
@ -1561,9 +1555,6 @@
"exploreMetaMaskSnaps": {
"message": "MetaMask Snap'lerini keşfedin"
},
"exportPrivateKey": {
"message": "Özel anahtarı dışa aktar"
},
"extendWalletWithSnaps": {
"message": "Cüzdan deneyimini genişletin."
},
@ -3868,9 +3859,6 @@
"showPrivateKey": {
"message": "Özel anahtarı göster"
},
"showPrivateKeys": {
"message": "Özel Anahtarları Göster"
},
"showTestnetNetworks": {
"message": "Test ağlarını göster"
},
@ -5130,9 +5118,6 @@
"txInsightsNotSupported": {
"message": "Şu anda işlem içgörüleri bu sözleşme için desteklenmiyor."
},
"typePassword": {
"message": "MetaMask parolanızı girin"
},
"typeYourSRP": {
"message": "Gizli Kurtarma İfadenizi girin"
},

View File

@ -175,9 +175,6 @@
"copyAddress": {
"message": "Копіювати адресу в буфер обміну"
},
"copyPrivateKey": {
"message": "Це ваш закритий ключ (натисніть, щоб скопіювати)"
},
"copyToClipboard": {
"message": "Копіювати в буфер"
},
@ -241,9 +238,6 @@
"ensRegistrationError": {
"message": "Помилка у реєстрації ENS ім'я"
},
"enterPassword": {
"message": "Введіть пароль"
},
"enterPasswordContinue": {
"message": "Введіть пароль, щоб продовжити"
},
@ -256,9 +250,6 @@
"expandView": {
"message": "Розгорнути подання"
},
"exportPrivateKey": {
"message": "Експортувати приватний ключ"
},
"failed": {
"message": "Помилка"
},
@ -663,9 +654,6 @@
"showHexDataDescription": {
"message": "Оберіть це, щоб показати поле для шістнадцятирикових даних на екрані надсилання"
},
"showPrivateKeys": {
"message": "Показати приватні ключі"
},
"sigRequest": {
"message": "Запит підпису"
},
@ -786,9 +774,6 @@
"tryAgain": {
"message": "Повторити"
},
"typePassword": {
"message": "Введіть ваш пароль MetaMask"
},
"unapproved": {
"message": "Не затверджено"
},

View File

@ -898,9 +898,6 @@
"copyAddress": {
"message": "Sao chép địa chỉ vào bộ nhớ đệm"
},
"copyPrivateKey": {
"message": "Đây là khóa riêng tư của bạn (hãy nhấn vào để sao chép)"
},
"copyRawTransactionData": {
"message": "Sao chép dữ liệu giao dịch thô"
},
@ -1482,9 +1479,6 @@
"enterOptionalPassword": {
"message": "Nhập mật khẩu tùy chọn"
},
"enterPassword": {
"message": "Nhập mật khẩu"
},
"enterPasswordContinue": {
"message": "Nhập mật khẩu để tiếp tục"
},
@ -1561,9 +1555,6 @@
"exploreMetaMaskSnaps": {
"message": "Khám phá MetaMask Snap"
},
"exportPrivateKey": {
"message": "Xuất khóa riêng tư"
},
"extendWalletWithSnaps": {
"message": "Mở rộng trải nghiệm sử dụng ví."
},
@ -3868,9 +3859,6 @@
"showPrivateKey": {
"message": "Hiển thị khóa riêng tư"
},
"showPrivateKeys": {
"message": "Hiện khóa riêng tư"
},
"showTestnetNetworks": {
"message": "Hiển thị các mạng thử nghiệm"
},
@ -5130,9 +5118,6 @@
"txInsightsNotSupported": {
"message": "Thông tin chi tiết về giao dịch không được hỗ trợ cho hợp đồng này tại thời điểm này."
},
"typePassword": {
"message": "Nhập mật khẩu MetaMask của bạn"
},
"typeYourSRP": {
"message": "Nhập Cụm từ khôi phục bí mật của bạn"
},

View File

@ -898,9 +898,6 @@
"copyAddress": {
"message": "复制地址到剪贴板"
},
"copyPrivateKey": {
"message": "这是您的私钥(点击以复制)"
},
"copyRawTransactionData": {
"message": "复制原始交易数据"
},
@ -1482,9 +1479,6 @@
"enterOptionalPassword": {
"message": "输入可选密码"
},
"enterPassword": {
"message": "输入密码"
},
"enterPasswordContinue": {
"message": "输入密码继续"
},
@ -1561,9 +1555,6 @@
"exploreMetaMaskSnaps": {
"message": "探索MetaMask Snap"
},
"exportPrivateKey": {
"message": "导出私钥"
},
"extendWalletWithSnaps": {
"message": "扩展钱包体验。"
},
@ -3868,9 +3859,6 @@
"showPrivateKey": {
"message": "显示私钥"
},
"showPrivateKeys": {
"message": "显示私钥"
},
"showTestnetNetworks": {
"message": "显示测试网络"
},
@ -5130,9 +5118,6 @@
"txInsightsNotSupported": {
"message": "此合约目前不支持交易见解。"
},
"typePassword": {
"message": "输入您的 MetaMask 密码"
},
"typeYourSRP": {
"message": "输入助记词"
},

View File

@ -334,9 +334,6 @@
"copyAddress": {
"message": "複製到剪貼簿"
},
"copyPrivateKey": {
"message": "這是您的私鑰(點擊複製)"
},
"copyToClipboard": {
"message": "複製到剪貼簿"
},
@ -497,9 +494,6 @@
"enterMaxSpendLimit": {
"message": "輸入最大花費限制"
},
"enterPassword": {
"message": "請輸入密碼"
},
"enterPasswordContinue": {
"message": "請輸入密碼"
},
@ -547,9 +541,6 @@
"expandView": {
"message": "展開畫面"
},
"exportPrivateKey": {
"message": "匯出私鑰"
},
"externalExtension": {
"message": "外部擴充功能"
},
@ -1231,9 +1222,6 @@
"showPermissions": {
"message": "顯示權限"
},
"showPrivateKeys": {
"message": "顯示私鑰"
},
"sigRequest": {
"message": "請求簽署"
},
@ -1440,9 +1428,6 @@
"tryAgain": {
"message": "再試一次"
},
"typePassword": {
"message": "請輸入密碼"
},
"unapproved": {
"message": "未批准"
},

View File

@ -562,13 +562,6 @@
"ui/components/app/modal/modal-content/modal-content.component.test.js",
"ui/components/app/modal/modal.component.js",
"ui/components/app/modal/modal.component.test.js",
"ui/components/app/modals/account-details-modal/account-details-modal.component.js",
"ui/components/app/modals/account-details-modal/account-details-modal.container.js",
"ui/components/app/modals/account-details-modal/account-details-modal.test.js",
"ui/components/app/modals/account-details-modal/index.js",
"ui/components/app/modals/account-modal-container/account-modal-container.component.js",
"ui/components/app/modals/account-modal-container/account-modal-container.container.js",
"ui/components/app/modals/account-modal-container/index.js",
"ui/components/app/modals/cancel-transaction/cancel-transaction-gas-fee/cancel-transaction-gas-fee.component.js",
"ui/components/app/modals/cancel-transaction/cancel-transaction-gas-fee/cancel-transaction-gas-fee.component.test.js",
"ui/components/app/modals/cancel-transaction/cancel-transaction-gas-fee/index.js",
@ -595,10 +588,6 @@
"ui/components/app/modals/edit-approval-permission/edit-approval-permission.component.js",
"ui/components/app/modals/edit-approval-permission/edit-approval-permission.container.js",
"ui/components/app/modals/edit-approval-permission/index.js",
"ui/components/app/modals/export-private-key-modal/export-private-key-modal.component.js",
"ui/components/app/modals/export-private-key-modal/export-private-key-modal.container.js",
"ui/components/app/modals/export-private-key-modal/export-private-key-modal.stories.js",
"ui/components/app/modals/export-private-key-modal/index.js",
"ui/components/app/modals/fade-modal.js",
"ui/components/app/modals/hide-token-confirmation-modal/hide-token-confirmation-modal.js",
"ui/components/app/modals/hide-token-confirmation-modal/hide-token-confirmation.stories.js",

View File

@ -1,6 +1,7 @@
const { strict: assert } = require('assert');
const { convertToHexValue, withFixtures } = require('../helpers');
const { convertToHexValue, withFixtures, unlockWallet } = require('../helpers');
const FixtureBuilder = require('../fixture-builder');
const { tEn } = require('../../lib/i18n-helpers');
describe('Show account details', function () {
const ganacheOptions = {
@ -14,6 +15,7 @@ describe('Show account details', function () {
};
const PASSWORD = 'correct horse battery staple';
const wrongPassword = 'test test test test';
async function revealPrivateKey(driver, useAccountMenu = true) {
if (useAccountMenu) {
@ -27,12 +29,19 @@ describe('Show account details', function () {
await driver.clickElement('[data-testid="account-options-menu-button"]');
await driver.clickElement('[data-testid="account-list-menu-details"]');
}
await driver.clickElement({ css: 'button', text: 'Show private key' });
await driver.clickElement({ css: 'button', text: tEn('showPrivateKey') });
await driver.fill('#account-details-authenticate', PASSWORD);
await driver.press('#account-details-authenticate', driver.Key.ENTER);
await driver.holdMouseDownOnElement(
{
text: tEn('holdToRevealPrivateKey'),
tag: 'span',
},
2000,
);
const keyContainer = await driver.findElement(
'[data-testid="account-details-key"]',
);
@ -49,8 +58,7 @@ describe('Show account details', function () {
},
async ({ driver }) => {
await driver.navigate();
await driver.fill('#password', PASSWORD);
await driver.press('#password', driver.Key.ENTER);
await unlockWallet(driver);
await driver.clickElement('[data-testid="account-menu-icon"]');
await driver.clickElement(
@ -73,8 +81,7 @@ describe('Show account details', function () {
},
async ({ driver }) => {
await driver.navigate();
await driver.fill('#password', PASSWORD);
await driver.press('#password', driver.Key.ENTER);
await unlockWallet(driver);
const key = await revealPrivateKey(driver);
assert.equal(
@ -94,8 +101,7 @@ describe('Show account details', function () {
},
async ({ driver }) => {
await driver.navigate();
await driver.fill('#password', PASSWORD);
await driver.press('#password', driver.Key.ENTER);
await unlockWallet(driver);
// Create and focus on different account
await driver.clickElement('[data-testid="account-menu-icon"]');
@ -103,7 +109,7 @@ describe('Show account details', function () {
'[data-testid="multichain-account-menu-popover-add-account"]',
);
await driver.fill('[placeholder="Account 2"]', '2nd account');
await driver.clickElement({ text: 'Create', tag: 'button' });
await driver.clickElement({ text: tEn('create'), tag: 'button' });
const key = await revealPrivateKey(driver);
assert.equal(
@ -123,8 +129,7 @@ describe('Show account details', function () {
},
async ({ driver }) => {
await driver.navigate();
await driver.fill('#password', PASSWORD);
await driver.press('#password', driver.Key.ENTER);
await unlockWallet(driver);
const key = await revealPrivateKey(driver, false);
assert.equal(
@ -144,8 +149,7 @@ describe('Show account details', function () {
},
async ({ driver }) => {
await driver.navigate();
await driver.fill('#password', PASSWORD);
await driver.press('#password', driver.Key.ENTER);
await unlockWallet(driver);
// Create and focus on different account
await driver.clickElement('[data-testid="account-menu-icon"]');
@ -153,7 +157,7 @@ describe('Show account details', function () {
'[data-testid="multichain-account-menu-popover-add-account"]',
);
await driver.fill('[placeholder="Account 2"]', '2nd account');
await driver.clickElement({ text: 'Create', tag: 'button' });
await driver.clickElement({ text: tEn('create'), tag: 'button' });
const key = await revealPrivateKey(driver, false);
assert.equal(
@ -163,4 +167,40 @@ describe('Show account details', function () {
},
);
});
it('should not reveal private key when password is incorrect', async function () {
await withFixtures(
{
fixtures: new FixtureBuilder().build(),
title: this.test.title,
failOnConsoleError: false,
},
async ({ driver }) => {
await driver.navigate();
await unlockWallet(driver);
// Attempt to reveal private key from account menu
await driver.clickElement('[data-testid="account-menu-icon"]');
await driver.clickElement(
'[data-testid="account-list-item-menu-button"]',
);
await driver.clickElement('[data-testid="account-list-menu-details"]');
await driver.clickElement({
css: 'button',
text: tEn('showPrivateKey'),
});
// Enter incorrect password
await driver.fill('#account-details-authenticate', wrongPassword);
await driver.press('#account-details-authenticate', driver.Key.ENTER);
// Display error when password is incorrect
const passwordErrorIsDisplayed = await driver.isElementPresent({
css: '.mm-help-text',
text: 'Incorrect Password.',
});
assert.equal(passwordErrorIsDisplayed, true);
},
);
});
});

View File

@ -1,161 +0,0 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { getAccountLink } from '@metamask/etherscan-link';
import AccountModalContainer from '../account-modal-container';
import QrView from '../../../ui/qr-code';
import EditableLabel from '../../../ui/editable-label';
import Button from '../../../ui/button';
import {
getURLHostName,
isAbleToExportAccount,
} from '../../../../helpers/utils/util';
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
import CustodyLabels from '../../../institutional/custody-labels/custody-labels';
import { toChecksumHexAddress } from '../../../../../shared/modules/hexstring-utils';
///: END:ONLY_INCLUDE_IN
import {
MetaMetricsEventCategory,
MetaMetricsEventLinkType,
MetaMetricsEventKeyType,
MetaMetricsEventName,
} from '../../../../../shared/constants/metametrics';
import { NETWORKS_ROUTE } from '../../../../helpers/constants/routes';
export default class AccountDetailsModal extends Component {
static propTypes = {
selectedIdentity: PropTypes.object,
chainId: PropTypes.string,
showExportPrivateKeyModal: PropTypes.func,
setAccountLabel: PropTypes.func,
keyrings: PropTypes.array,
rpcPrefs: PropTypes.object,
accounts: PropTypes.array,
history: PropTypes.object,
hideModal: PropTypes.func,
blockExplorerLinkText: PropTypes.object,
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
accountType: PropTypes.string,
custodyAccountDetails: PropTypes.object,
///: END:ONLY_INCLUDE_IN
};
static contextTypes = {
t: PropTypes.func,
trackEvent: PropTypes.func,
};
render() {
const {
selectedIdentity,
chainId,
showExportPrivateKeyModal,
setAccountLabel,
keyrings,
rpcPrefs,
history,
hideModal,
blockExplorerLinkText,
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
accountType,
custodyAccountDetails,
///: END:ONLY_INCLUDE_IN
} = this.props;
const { name, address } = selectedIdentity;
const keyring = keyrings.find((kr) => {
return kr.accounts.includes(address);
});
let exportPrivateKeyFeatureEnabled = isAbleToExportAccount(keyring?.type);
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
if (keyring?.type?.search('Custody') !== -1) {
exportPrivateKeyFeatureEnabled = false;
}
const showCustodyLabels = accountType === 'custody';
const custodyLabels = custodyAccountDetails
? custodyAccountDetails[toChecksumHexAddress(selectedIdentity.address)]
?.labels
: {};
///: END:ONLY_INCLUDE_IN
const routeToAddBlockExplorerUrl = () => {
hideModal();
history.push(`${NETWORKS_ROUTE}#blockExplorerUrl`);
};
const openBlockExplorer = () => {
const accountLink = getAccountLink(address, chainId, rpcPrefs);
this.context.trackEvent({
category: MetaMetricsEventCategory.Navigation,
event: MetaMetricsEventName.ExternalLinkClicked,
properties: {
link_type: MetaMetricsEventLinkType.AccountTracker,
location: 'Account Details Modal',
url_domain: getURLHostName(accountLink),
},
});
global.platform.openTab({
url: accountLink,
});
};
return (
<AccountModalContainer className="account-details-modal">
<EditableLabel
className="account-details-modal__name"
defaultValue={name}
onSubmit={(label) => setAccountLabel(address, label)}
accounts={this.props.accounts}
/>
{
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
showCustodyLabels && <CustodyLabels labels={custodyLabels} />
///: END:ONLY_INCLUDE_IN
}
<QrView
Qr={{
data: address,
}}
/>
<div className="account-details-modal__divider" />
<Button
type="secondary"
className="account-details-modal__button"
onClick={
blockExplorerLinkText.firstPart === 'addBlockExplorer'
? routeToAddBlockExplorerUrl
: openBlockExplorer
}
>
{this.context.t(blockExplorerLinkText.firstPart, [
blockExplorerLinkText.secondPart,
])}
</Button>
{exportPrivateKeyFeatureEnabled && (
<Button
type="secondary"
className="account-details-modal__button"
onClick={() => {
this.context.trackEvent({
category: MetaMetricsEventCategory.Accounts,
event: MetaMetricsEventName.KeyExportSelected,
properties: {
key_type: MetaMetricsEventKeyType.Pkey,
location: 'Account Details Modal',
},
});
showExportPrivateKeyModal();
}}
>
{this.context.t('exportPrivateKey')}
</Button>
)}
</AccountModalContainer>
);
}
}

View File

@ -1,54 +0,0 @@
import { connect } from 'react-redux';
import { compose } from 'redux';
import { withRouter } from 'react-router-dom';
import {
showModal,
setAccountLabel,
hideModal,
} from '../../../../store/actions';
import {
getSelectedIdentity,
getRpcPrefsForCurrentProvider,
getCurrentChainId,
getMetaMaskAccountsOrdered,
getBlockExplorerLinkText,
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
getAccountType,
///: END:ONLY_INCLUDE_IN
} from '../../../../selectors';
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
import { getCustodyAccountDetails } from '../../../../selectors/institutional/selectors';
///: END:ONLY_INCLUDE_IN
import AccountDetailsModal from './account-details-modal.component';
const mapStateToProps = (state) => {
return {
chainId: getCurrentChainId(state),
selectedIdentity: getSelectedIdentity(state),
keyrings: state.metamask.keyrings,
rpcPrefs: getRpcPrefsForCurrentProvider(state),
accounts: getMetaMaskAccountsOrdered(state),
blockExplorerLinkText: getBlockExplorerLinkText(state, true),
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
accountType: getAccountType(state),
custodyAccountDetails: getCustodyAccountDetails(state),
///: END:ONLY_INCLUDE_IN
};
};
const mapDispatchToProps = (dispatch) => {
return {
showExportPrivateKeyModal: () =>
dispatch(showModal({ name: 'EXPORT_PRIVATE_KEY' })),
setAccountLabel: (address, label) =>
dispatch(setAccountLabel(address, label)),
hideModal: () => {
dispatch(hideModal());
},
};
};
export default compose(
withRouter,
connect(mapStateToProps, mapDispatchToProps),
)(AccountDetailsModal);

View File

@ -1,241 +0,0 @@
import React from 'react';
import configureMockState from 'redux-mock-store';
import { fireEvent } from '@testing-library/react';
import thunk from 'redux-thunk';
import { NetworkType } from '@metamask/controller-utils';
import { NetworkStatus } from '@metamask/network-controller';
import { renderWithProvider } from '../../../../../test/lib/render-helpers';
import mockState from '../../../../../test/data/mock-state.json';
import {
etherscanViewOn,
exportPrivateKey,
} from '../../../../../app/_locales/en/messages.json';
import AccountDetailsModal from '.';
const mockShowModal = jest.fn();
jest.mock('../../../../store/actions.ts', () => {
return {
showModal: () => mockShowModal,
};
});
describe('Account Details Modal', () => {
const mockStore = configureMockState([thunk])(mockState);
global.platform = { openTab: jest.fn() };
it('should set account label when changing default account label', () => {
const { queryByTestId, getByPlaceholderText } = renderWithProvider(
<AccountDetailsModal />,
mockStore,
);
const editButton = queryByTestId('editable-label-button');
expect(queryByTestId('editable-input')).not.toBeInTheDocument();
fireEvent.click(editButton);
expect(queryByTestId('editable-input')).toBeInTheDocument();
const editableInput = getByPlaceholderText('Account name');
const newAccountLabel = 'New Label';
fireEvent.change(editableInput, {
target: { value: newAccountLabel },
});
expect(editableInput).toHaveAttribute('value', newAccountLabel);
});
it('opens new tab when view block explorer is clicked', () => {
const { queryByText } = renderWithProvider(
<AccountDetailsModal />,
mockStore,
);
const viewOnEtherscan = queryByText(etherscanViewOn.message);
fireEvent.click(viewOnEtherscan);
expect(global.platform.openTab).toHaveBeenCalled();
});
it('shows export private key modal when clicked', () => {
const { queryByText } = renderWithProvider(
<AccountDetailsModal />,
mockStore,
);
const exportPrivButton = queryByText(exportPrivateKey.message);
fireEvent.click(exportPrivButton);
expect(mockShowModal).toHaveBeenCalled();
});
it('sets blockexplorerview text when block explorer url in rpcPrefs exists', () => {
const blockExplorerUrl = 'https://block.explorer';
const customProviderMockState = {
...mockState,
metamask: {
...mockState.metamask,
networkConfigurations: {
networkConfigurationId: {
chainId: '0x99',
rpcPrefs: {
blockExplorerUrl,
},
},
},
providerConfig: {
chainId: '0x99',
ticker: 'ETH',
},
},
};
const customProviderMockStore = configureMockState([thunk])(
customProviderMockState,
);
const { queryByText } = renderWithProvider(
<AccountDetailsModal />,
customProviderMockStore,
);
expect(queryByText(/block.explorer/u)).toBeInTheDocument();
});
it('does not display export private key if the keyring is snaps', () => {
const mockStateWithSnapKeyring = {
appState: {
networkDropdownOpen: false,
gasIsLoading: false,
isLoading: false,
modal: {
open: false,
modalState: {
name: null,
props: {},
},
previousModalState: {
name: null,
},
},
warning: null,
customTokenAmount: '10',
},
history: {
mostRecentOverviewPage: '/mostRecentOverviewPage',
},
metamask: {
providerConfig: {
type: 'rpc',
chainId: '0x5',
ticker: 'ETH',
id: 'testNetworkConfigurationId',
},
keyrings: [
{
type: 'Snap Keyring',
accounts: [
'0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc',
'0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b',
],
},
{
type: 'Ledger Hardware',
accounts: ['0xc42edfcc21ed14dda456aa0756c153f7985d8813'],
},
{
type: 'Simple Key Pair',
accounts: ['0xeb9e64b93097bc15f01f13eae97015c57ab64823'],
},
],
identities: {
'0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': {
address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc',
name: 'Test Account',
},
'0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b': {
address: '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b',
name: 'Test Account 2',
},
'0xc42edfcc21ed14dda456aa0756c153f7985d8813': {
address: '0xc42edfcc21ed14dda456aa0756c153f7985d8813',
name: 'Test Ledger 1',
},
'0xeb9e64b93097bc15f01f13eae97015c57ab64823': {
name: 'Test Account 3',
address: '0xeb9e64b93097bc15f01f13eae97015c57ab64823',
},
},
networksMetadata: {
selectedNetworkClientId: NetworkType.mainnet,
[NetworkType.mainnet]: {
EIPS: {
1559: false,
},
status: NetworkStatus.Available,
},
},
frequentRpcListDetail: [],
subjectMetadata: {
'npm:@metamask/test-snap-bip44': {
name: '@metamask/test-snap-bip44',
version: '1.2.3',
subjectType: 'snap',
},
},
notifications: {
test: {
id: 'test',
origin: 'local:http://localhost:8086/',
createdDate: 1652967897732,
readDate: null,
message: 'Hello, http://localhost:8086!',
},
test2: {
id: 'test2',
origin: 'local:http://localhost:8086/',
createdDate: 1652967897732,
readDate: 1652967897732,
message: 'Hello, http://localhost:8086!',
},
},
cachedBalances: {},
selectedAddress: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc',
accounts: {
'0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': {
balance: '0x346ba7725f412cbfdb',
address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc',
},
'0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b': {
address: '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b',
balance: '0x0',
},
'0xc42edfcc21ed14dda456aa0756c153f7985d8813': {
address: '0xc42edfcc21ed14dda456aa0756c153f7985d8813',
balance: '0x0',
},
'0xeb9e64b93097bc15f01f13eae97015c57ab64823': {
address: '0xeb9e64b93097bc15f01f13eae97015c57ab64823',
balance: '0x0',
},
},
},
};
const mockStoreWithSnapKeyring = configureMockState([thunk])(
mockStateWithSnapKeyring,
);
const { queryByText } = renderWithProvider(
<AccountDetailsModal />,
mockStoreWithSnapKeyring,
);
const exportPrivateKeyButton = queryByText(exportPrivateKey.message);
expect(exportPrivateKeyButton).not.toBeInTheDocument();
});
});

View File

@ -1 +0,0 @@
export { default } from './account-details-modal.container';

View File

@ -1,30 +0,0 @@
.account-details-modal {
&__name {
@include H4;
margin-top: 9px;
}
& &__button {
margin-top: 17px;
padding: 10px 22px;
width: 284px;
}
&__divider {
width: 100%;
height: 1px;
margin: 16px 0 8px 0;
background-color: var(--color-border-muted);
}
& .qr-header {
@include H4;
margin-top: 9px;
}
& .qr-wrapper {
margin-top: 5px;
}
}

View File

@ -1,57 +0,0 @@
import PropTypes from 'prop-types';
import React from 'react';
import classnames from 'classnames';
import Identicon from '../../../ui/identicon';
export default function AccountModalContainer(props, context) {
const {
className,
selectedIdentity,
showBackButton,
backButtonAction,
hideModal,
children,
} = props;
return (
<div
className={classnames(className, 'account-modal')}
style={{ borderRadius: '4px' }}
>
<div className="account-modal__container">
<div>
<Identicon address={selectedIdentity.address} diameter={64} />
</div>
{showBackButton && (
<div className="account-modal__back" onClick={backButtonAction}>
<i className="fa fa-angle-left fa-lg" />
<span className="account-modal__back-text">
{context.t('back')}
</span>
</div>
)}
<button className="account-modal__close" onClick={hideModal} />
{children}
</div>
</div>
);
}
AccountModalContainer.contextTypes = {
t: PropTypes.func,
};
AccountModalContainer.defaultProps = {
showBackButton: false,
children: null,
backButtonAction: undefined,
};
AccountModalContainer.propTypes = {
className: PropTypes.string,
selectedIdentity: PropTypes.object.isRequired,
showBackButton: PropTypes.bool,
backButtonAction: PropTypes.func,
hideModal: PropTypes.func.isRequired,
children: PropTypes.node,
};

View File

@ -1,23 +0,0 @@
import { connect } from 'react-redux';
import { hideModal } from '../../../../store/actions';
import { getSelectedIdentity } from '../../../../selectors';
import AccountModalContainer from './account-modal-container.component';
function mapStateToProps(state, ownProps) {
return {
selectedIdentity: ownProps.selectedIdentity || getSelectedIdentity(state),
};
}
function mapDispatchToProps(dispatch) {
return {
hideModal: () => {
dispatch(hideModal());
},
};
}
export default connect(
mapStateToProps,
mapDispatchToProps,
)(AccountModalContainer);

View File

@ -1 +0,0 @@
export { default } from './account-modal-container.container';

View File

@ -1,53 +0,0 @@
// Account Modal Container
.account-modal {
&__container {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
position: relative;
padding: 5px 0 31px 0;
border: 1px solid var(--color-border-default);
border-radius: 4px;
}
&__back {
color: var(--color-icon-default);
position: absolute;
top: 13px;
left: 17px;
cursor: pointer;
display: flex;
align-items: center;
}
&__back-text {
@include H6;
padding-left: 3px;
}
&__close {
@include H1;
background-color: transparent;
color: var(--color-text-default);
position: absolute;
cursor: pointer;
top: -10px;
right: 12px;
&::after {
content: '\00D7';
}
}
& .identicon {
position: relative;
left: 0;
right: 0;
margin: 0 auto;
top: -32px;
margin-bottom: -32px;
}
}

View File

@ -1,139 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Export PrivateKey Modal should match snapshot 1`] = `
<div>
<div
class="export-private-key-modal account-modal"
style="border-radius: 4px;"
>
<div
class="account-modal__container"
>
<div>
<div
class=""
>
<div
class="identicon"
style="height: 64px; width: 64px; border-radius: 32px;"
>
<div
style="border-radius: 50px; overflow: hidden; padding: 0px; margin: 0px; width: 64px; height: 64px; display: inline-block; background: rgb(250, 58, 0);"
>
<svg
height="64"
width="64"
x="0"
y="0"
>
<rect
fill="#18CDF2"
height="64"
transform="translate(-2.09678700758788 -6.608568138920997) rotate(328.9 32 32)"
width="64"
x="0"
y="0"
/>
<rect
fill="#035E56"
height="64"
transform="translate(-36.59692341766409 21.1849237434972) rotate(176.2 32 32)"
width="64"
x="0"
y="0"
/>
<rect
fill="#F26602"
height="64"
transform="translate(33.335684036447844 -28.410279445994163) rotate(468.9 32 32)"
width="64"
x="0"
y="0"
/>
</svg>
</div>
</div>
</div>
</div>
<button
class="account-modal__close"
/>
<span
class="mm-box mm-text mm-text--body-lg-medium mm-text--font-weight-normal mm-box--margin-top-2 mm-box--color-text-default"
>
Test Account
</span>
<div
class="box ellip-address-wrapper box--margin-top-2 box--padding-1 box--sm:padding-2 box--md:padding-1 box--lg:padding-2 box--flex-direction-row box--border-style-solid box--border-color-border-default box--border-width-1"
>
0x0DCD5D886577d5081B0c52e242Ef29E70Be3E7bc
</div>
<div
class="box export-private-key-modal__divider box--margin-5 box--md:margin-3 box--flex-direction-row box--width-full"
/>
<p
class="mm-box mm-text mm-text--body-lg-medium mm-text--font-weight-normal mm-box--margin-4 mm-box--sm:margin-0 mm-box--md:margin-4 mm-box--lg:margin-0 mm-box--color-text-default"
>
Show Private Keys
</p>
<div
class="box box--padding-right-5 box--padding-left-5 box--display-flex box--flex-direction-column box--align-items-flex-start box--width-full"
>
<label
class="mm-box mm-text mm-label mm-text--body-sm mm-text--font-weight-medium mm-box--margin-bottom-2 mm-box--display-inline-flex mm-box--align-items-center mm-box--color-text-default"
>
Type your MetaMask password
</label>
<div
class="box mm-text-field mm-text-field--size-md mm-text-field--truncate export-private-key-modal__password-input box--display-inline-flex box--flex-direction-row box--align-items-center box--width-full box--background-color-background-default box--rounded-sm box--border-width-1 box--border-style-solid"
data-testid="password-input"
>
<input
autocomplete="off"
class="mm-box mm-text mm-input mm-input--disable-state-styles mm-text-field__input mm-text--body-md mm-box--margin-0 mm-box--padding-0 mm-box--padding-right-4 mm-box--padding-left-4 mm-box--color-text-default mm-box--background-color-transparent mm-box--border-style-none"
focused="false"
placeholder="Enter password"
type="password"
value=""
/>
</div>
</div>
<p
class="mm-box mm-text mm-text--body-sm mm-box--color-error-default"
/>
<div
class="mm-box mm-banner-base mm-banner-alert mm-banner-alert--severity-danger mm-box--margin-top-4 mm-box--margin-right-5 mm-box--margin-left-5 mm-box--padding-1 mm-box--sm:padding-3 mm-box--md:padding-0 mm-box--lg:padding-3 mm-box--padding-left-2 mm-box--display-flex mm-box--gap-2 mm-box--background-color-error-muted mm-box--rounded-sm"
>
<span
class="mm-box mm-icon mm-icon--size-lg mm-box--display-inline-block mm-box--color-error-default"
style="mask-image: url('./images/icons/danger.svg');"
/>
<div>
<p
class="mm-box mm-text mm-text--body-md mm-box--color-text-default"
>
Warning: Never disclose this key. Anyone with your private keys can steal any assets held in your account.
</p>
</div>
</div>
<div
class="box box--margin-top-3 box--padding-5 box--md:padding-5 box--display-flex box--flex-direction-row box--justify-content-space-between box--width-full"
>
<button
class="mm-box mm-text mm-button-base mm-button-base--size-lg mm-button-primary mm-text--body-md-medium mm-box--margin-right-4 mm-box--padding-0 mm-box--padding-right-4 mm-box--padding-left-4 mm-box--display-inline-flex mm-box--justify-content-center mm-box--align-items-center mm-box--width-1/2 mm-box--color-primary-inverse mm-box--background-color-primary-default mm-box--rounded-pill"
type="secondary"
>
Cancel
</button>
<button
class="mm-box mm-text mm-button-base mm-button-base--size-lg mm-button-base--disabled mm-button-primary mm-button-primary--disabled mm-text--body-md-medium mm-box--padding-0 mm-box--padding-right-4 mm-box--padding-left-4 mm-box--display-inline-flex mm-box--justify-content-center mm-box--align-items-center mm-box--width-1/2 mm-box--color-primary-inverse mm-box--background-color-primary-default mm-box--rounded-pill"
disabled=""
type="primary"
>
Confirm
</button>
</div>
</div>
</div>
</div>
`;

View File

@ -1,247 +0,0 @@
import log from 'loglevel';
import React, { useContext, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import withModalProps from '../../../../helpers/higher-order-components/with-modal-props';
import Box from '../../../ui/box';
import {
BUTTON_SIZES,
BUTTON_VARIANT,
BannerAlert,
Button,
Text,
} from '../../../component-library';
import AccountModalContainer from '../account-modal-container';
import { toChecksumHexAddress } from '../../../../../shared/modules/hexstring-utils';
import {
MetaMetricsEventCategory,
MetaMetricsEventKeyType,
MetaMetricsEventName,
} from '../../../../../shared/constants/metametrics';
import HoldToRevealModal from '../hold-to-reveal-modal/hold-to-reveal-modal';
import { MetaMetricsContext } from '../../../../contexts/metametrics';
import { useI18nContext } from '../../../../hooks/useI18nContext';
import {
BLOCK_SIZES,
BorderColor,
BorderStyle,
Color,
DISPLAY,
FLEX_DIRECTION,
FONT_WEIGHT,
JustifyContent,
TextVariant,
} from '../../../../helpers/constants/design-system';
import PrivateKeyDisplay from './private-key';
import PasswordInput from './password-input';
const ExportPrivateKeyModal = ({
clearAccountDetails,
hideWarning,
exportAccount,
selectedIdentity,
showAccountDetailModal,
hideModal,
warning = null,
previousModalState,
}) => {
const [password, setPassword] = useState('');
const [privateKey, setPrivateKey] = useState(null);
const [showWarning, setShowWarning] = useState(true);
const [showHoldToReveal, setShowHoldToReveal] = useState(false);
const trackEvent = useContext(MetaMetricsContext);
const t = useI18nContext();
useEffect(() => {
return () => {
clearAccountDetails();
hideWarning();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const exportAccountAndGetPrivateKey = async (passwordInput, address) => {
try {
const privateKeyRetrieved = await exportAccount(passwordInput, address);
trackEvent(
{
category: MetaMetricsEventCategory.Keys,
event: MetaMetricsEventName.KeyExportRevealed,
properties: {
key_type: MetaMetricsEventKeyType.Pkey,
},
},
{},
);
setPrivateKey(privateKeyRetrieved);
setShowWarning(false);
setShowHoldToReveal(true);
} catch (e) {
trackEvent(
{
category: MetaMetricsEventCategory.Keys,
event: MetaMetricsEventName.KeyExportFailed,
properties: {
key_type: MetaMetricsEventKeyType.Pkey,
reason: 'incorrect_password',
},
},
{},
);
log.error(e);
}
};
const { name, address } = selectedIdentity;
if (showHoldToReveal) {
return (
<AccountModalContainer
className="export-private-key-modal"
selectedIdentity={selectedIdentity}
showBackButton={previousModalState === 'ACCOUNT_DETAILS'}
backButtonAction={() => showAccountDetailModal()}
>
<HoldToRevealModal
onLongPressed={() => setShowHoldToReveal(false)}
willHide={false}
holdToRevealType="PrivateKey"
/>
</AccountModalContainer>
);
}
return (
<AccountModalContainer
className="export-private-key-modal"
selectedIdentity={selectedIdentity}
showBackButton={previousModalState === 'ACCOUNT_DETAILS'}
backButtonAction={() => showAccountDetailModal()}
>
<Text
as="span"
marginTop={2}
variant={TextVariant.bodyLgMedium}
fontWeight={FONT_WEIGHT.NORMAL}
>
{name}
</Text>
<Box
className="ellip-address-wrapper"
borderStyle={BorderStyle.solid}
borderColor={BorderColor.borderDefault}
borderWidth={1}
marginTop={2}
padding={[1, 2, 1, 2]}
>
{toChecksumHexAddress(address)}
</Box>
<Box
className="export-private-key-modal__divider"
width={BLOCK_SIZES.FULL}
margin={[5, 0, 3, 0]}
/>
<Text
variant={TextVariant.bodyLgMedium}
margin={[4, 0, 4, 0]}
fontWeight={FONT_WEIGHT.NORMAL}
>
{t('showPrivateKeys')}
</Text>
{privateKey ? (
<PrivateKeyDisplay privateKey={privateKey} />
) : (
<PasswordInput setPassword={setPassword} />
)}
{showWarning && (
<Text color={Color.errorDefault} variant={TextVariant.bodySm}>
{warning}
</Text>
)}
<BannerAlert
padding={[1, 3, 0, 3]}
marginLeft={5}
marginRight={5}
marginTop={4}
severity="danger"
>
{t('privateKeyWarning')}
</BannerAlert>
<Box
display={DISPLAY.FLEX}
flexDirection={FLEX_DIRECTION.ROW}
width={BLOCK_SIZES.FULL}
justifyContent={JustifyContent.spaceBetween}
marginTop={3}
padding={[5, 0, 5, 0]}
>
{!privateKey && (
<Button
type={BUTTON_VARIANT.SECONDARY}
size={BUTTON_SIZES.LG}
width={BLOCK_SIZES.HALF}
marginRight={4}
onClick={() => {
trackEvent({
category: MetaMetricsEventCategory.Keys,
event: MetaMetricsEventName.KeyExportCanceled,
properties: {
key_type: MetaMetricsEventKeyType.Pkey,
},
});
hideModal();
}}
>
{t('cancel')}
</Button>
)}
{privateKey ? (
<Button
type={BUTTON_VARIANT.PRIMARY}
size={BUTTON_SIZES.LG}
width={BLOCK_SIZES.FULL}
onClick={() => {
hideModal();
}}
>
{t('done')}
</Button>
) : (
<Button
type={BUTTON_VARIANT.PRIMARY}
size={BUTTON_SIZES.LG}
width={BLOCK_SIZES.HALF}
onClick={() => {
trackEvent({
category: MetaMetricsEventCategory.Keys,
event: MetaMetricsEventName.KeyExportRequested,
properties: {
key_type: MetaMetricsEventKeyType.Pkey,
},
});
exportAccountAndGetPrivateKey(password, address);
}}
disabled={!password}
>
{t('confirm')}
</Button>
)}
</Box>
</AccountModalContainer>
);
};
ExportPrivateKeyModal.propTypes = {
exportAccount: PropTypes.func.isRequired,
selectedIdentity: PropTypes.object.isRequired,
warning: PropTypes.node,
showAccountDetailModal: PropTypes.func.isRequired,
hideModal: PropTypes.func.isRequired,
hideWarning: PropTypes.func.isRequired,
clearAccountDetails: PropTypes.func.isRequired,
previousModalState: PropTypes.string,
};
export default withModalProps(ExportPrivateKeyModal);

View File

@ -1,130 +0,0 @@
import { fireEvent, waitFor } from '@testing-library/react';
import configureMockStore from 'redux-mock-store';
import React from 'react';
import thunk from 'redux-thunk';
import { renderWithProvider } from '../../../../../test/lib/render-helpers';
import ExportPrivateKeyModal from '.';
const mockAddress = '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc';
const mockPrivateKey = 'mock private key';
const mockExportAccount = jest.fn().mockResolvedValue(mockPrivateKey);
const mockClearAccountDetail = jest.fn();
const mockHideWarning = jest.fn();
jest.mock('../../../../store/actions', () => ({
exportAccount: () => mockExportAccount,
clearAccountDetails: () => mockClearAccountDetail,
hideWarning: () => mockHideWarning,
}));
describe('Export Private Key Modal', () => {
const state = {
metamask: {
selectedAddress: mockAddress,
identities: {
'0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': {
address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc',
name: 'Test Account',
},
},
providerConfig: {
type: 'rpc',
chainId: '0x5',
ticker: 'ETH',
id: 'testNetworkConfigurationId',
},
},
appState: {
warning: null,
previousModalState: {
name: null,
},
isLoading: false,
accountDetail: {
privateKey: null,
},
modal: {
modalState: {},
previousModalState: {
name: null,
},
},
},
};
const mockStore = configureMockStore([thunk])(state);
it('renders export private key modal', () => {
const { queryByText } = renderWithProvider(
<ExportPrivateKeyModal />,
mockStore,
);
const title = queryByText('Show Private Keys');
expect(title).toBeInTheDocument();
const warning = queryByText(
'Warning: Never disclose this key. Anyone with your private keys can steal any assets held in your account.',
);
expect(warning).toBeInTheDocument();
expect(queryByText(mockPrivateKey)).not.toBeInTheDocument();
});
it('renders hold to reveal after entering password', async () => {
const { queryByText, getByPlaceholderText } = renderWithProvider(
<ExportPrivateKeyModal />,
mockStore,
);
const nextButton = queryByText('Confirm');
expect(nextButton).toBeInTheDocument();
const input = getByPlaceholderText('Enter password');
fireEvent.change(input, {
target: { value: 'password' },
});
fireEvent.click(nextButton);
await waitFor(() => {
expect(mockExportAccount).toHaveBeenCalled();
expect(queryByText('Keep your private key safe')).toBeInTheDocument();
});
});
it('provides password after passing hold to reveal', async () => {
const { queryByText, getByLabelText, getByText, getByPlaceholderText } =
renderWithProvider(<ExportPrivateKeyModal />, mockStore);
const nextButton = queryByText('Confirm');
expect(nextButton).toBeInTheDocument();
const input = getByPlaceholderText('Enter password');
fireEvent.change(input, {
target: { value: 'password' },
});
fireEvent.click(nextButton);
await waitFor(() => {
expect(mockExportAccount).toHaveBeenCalled();
expect(queryByText('Keep your private key safe')).toBeInTheDocument();
});
const holdButton = getByText('Hold to reveal Private Key');
expect(holdButton).toBeInTheDocument();
fireEvent.pointerDown(holdButton);
const circle = getByLabelText('hold to reveal circle locked');
fireEvent.transitionEnd(circle);
const circleUnlocked = getByLabelText('hold to reveal circle unlocked');
fireEvent.animationEnd(circleUnlocked);
await waitFor(() => {
expect(queryByText('Show Private Keys')).toBeInTheDocument();
expect(queryByText('Done')).toBeInTheDocument();
expect(queryByText(mockPrivateKey)).toBeInTheDocument();
});
});
});

View File

@ -1,48 +0,0 @@
import { connect } from 'react-redux';
import {
exportAccount,
hideWarning,
showModal,
hideModal,
clearAccountDetails,
} from '../../../../store/actions';
import { getSelectedIdentity } from '../../../../selectors';
import ExportPrivateKeyModal from './export-private-key-modal.component';
function mapStateToPropsFactory() {
let selectedIdentity = null;
return function mapStateToProps(state) {
// We should **not** change the identity displayed here even if it changes from underneath us.
// If we do, we will be showing the user one private key and a **different** address and name.
// Note that the selected identity **will** change from underneath us when we unlock the keyring
// which is the expected behavior that we are side-stepping.
selectedIdentity = selectedIdentity || getSelectedIdentity(state);
return {
warning: state.appState.warning,
privateKey: state.appState.accountDetail.privateKey,
selectedIdentity,
previousModalState: state.appState.modal.previousModalState.name,
};
};
}
function mapDispatchToProps(dispatch) {
return {
exportAccount: (password, address) => {
return dispatch(exportAccount(password, address)).then((res) => {
dispatch(hideWarning());
return res;
});
},
showAccountDetailModal: () =>
dispatch(showModal({ name: 'ACCOUNT_DETAILS' })),
hideModal: () => dispatch(hideModal()),
hideWarning: () => dispatch(hideWarning()),
clearAccountDetails: () => dispatch(clearAccountDetails()),
};
}
export default connect(
mapStateToPropsFactory,
mapDispatchToProps,
)(ExportPrivateKeyModal);

View File

@ -1,32 +0,0 @@
import React from 'react';
import { Provider } from 'react-redux';
import testData from '../../../../../.storybook/test-data';
import configureStore from '../../../../store/store';
import ExportPrivateKeyModal from './export-private-key-modal.component';
// Using Test Data For Redux
const store = configureStore(testData);
export default {
title: 'Components/App/Modals/ExportPrivateKeyModal',
decorators: [(story) => <Provider store={store}>{story()}</Provider>],
argsTypes: {
exportAccount: { action: 'exportAccount' },
},
};
export const DefaultStory = () => {
return (
<ExportPrivateKeyModal
// mock actions
exportAccount={() => {
return 'mockPrivateKey';
}}
selectedIdentity={
testData.metamask.identities[testData.metamask.selectedAddress]
}
/>
);
};
DefaultStory.storyName = 'Default';

View File

@ -1,82 +0,0 @@
import React from 'react';
import { fireEvent } from '@testing-library/react';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { renderWithProvider } from '../../../../../test/lib/render-helpers';
import mockState from '../../../../../test/data/mock-state.json';
import * as actions from '../../../../store/actions';
import ExportPrivateKeyModal from '.';
jest.mock('../../../../store/actions.ts', () => ({
...jest.requireActual('../../../../store/actions.ts'),
exportAccount: jest.fn().mockReturnValue(jest.fn().mockResolvedValueOnce()),
hideWarning: () => jest.fn(),
showModal: () => jest.fn(),
hideModal: () => jest.fn(),
clearAccountDetails: () => jest.fn(),
}));
describe('Export PrivateKey Modal', () => {
const password = 'a-password';
const privKeyModalState = {
...mockState,
appState: {
...mockState.appState,
accountDetail: {
privateKey: '0xPrivKey',
},
},
};
const mockStore = configureMockStore([thunk])(privKeyModalState);
afterEach(() => {
jest.clearAllMocks();
});
it('should match snapshot', () => {
const { container } = renderWithProvider(
<ExportPrivateKeyModal />,
mockStore,
);
expect(container).toMatchSnapshot();
});
it('should disable confirm button by default', () => {
const { queryByText } = renderWithProvider(
<ExportPrivateKeyModal />,
mockStore,
);
const confirmButton = queryByText('Confirm');
expect(confirmButton).toBeDisabled();
});
it('should call export account with password and selected address', () => {
const { queryByTestId, queryByText } = renderWithProvider(
<ExportPrivateKeyModal />,
mockStore,
);
const passwordInput =
queryByTestId('password-input').querySelector('input');
const passwordInputEvent = {
target: {
value: password,
},
};
fireEvent.change(passwordInput, passwordInputEvent);
const confirmButton = queryByText('Confirm');
fireEvent.click(confirmButton);
expect(actions.exportAccount).toHaveBeenCalledWith(
password,
mockState.metamask.selectedAddress,
);
});
});

View File

@ -1 +0,0 @@
export { default } from './export-private-key-modal.container';

View File

@ -1,27 +0,0 @@
.export-private-key-modal {
&__divider {
width: 100%;
height: 1px;
margin: 19px 0 8px 0;
background-color: var(--color-border-default);
}
&__password::-webkit-input-placeholder {
color: var(--color-text-muted);
}
&__private-key-display {
height: 80px;
width: 291px;
overflow: hidden;
overflow-wrap: break-word;
}
.ellip-address-wrapper {
max-width: 286px;
direction: ltr;
overflow: hidden;
text-overflow: ellipsis;
}
}

View File

@ -1,50 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
BLOCK_SIZES,
FLEX_DIRECTION,
DISPLAY,
AlignItems,
Color,
TextVariant,
} from '../../../../helpers/constants/design-system';
import Box from '../../../ui/box';
import { useI18nContext } from '../../../../hooks/useI18nContext';
import { Label, TEXT_FIELD_TYPES, TextField } from '../../../component-library';
const PasswordInput = ({ setPassword }) => {
const t = useI18nContext();
return (
<Box
width={BLOCK_SIZES.FULL}
flexDirection={FLEX_DIRECTION.COLUMN}
display={DISPLAY.FLEX}
alignItems={AlignItems.flexStart}
paddingLeft={5}
paddingRight={5}
>
<Label
color={Color.textDefault}
marginBottom={2}
variant={TextVariant.bodySm}
>
{t('typePassword')}
</Label>
<TextField
width={BLOCK_SIZES.FULL}
placeholder={t('enterPassword')}
type={TEXT_FIELD_TYPES.PASSWORD}
className="export-private-key-modal__password-input"
onChange={(event) => setPassword(event.target.value)}
data-testid="password-input"
/>
</Box>
);
};
PasswordInput.propTypes = {
setPassword: PropTypes.func.isRequired,
};
export default PasswordInput;

View File

@ -1,81 +0,0 @@
import copyToClipboard from 'copy-to-clipboard';
import { stripHexPrefix } from 'ethereumjs-util';
import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import Box from '../../../ui/box';
import { useI18nContext } from '../../../../hooks/useI18nContext';
import {
MetaMetricsEventCategory,
MetaMetricsEventName,
MetaMetricsEventKeyType,
} from '../../../../../shared/constants/metametrics';
import { MetaMetricsContext } from '../../../../contexts/metametrics';
import {
BLOCK_SIZES,
BorderStyle,
BorderColor,
BorderRadius,
AlignItems,
DISPLAY,
Color,
FLEX_DIRECTION,
TextVariant,
} from '../../../../helpers/constants/design-system';
import { Label } from '../../../component-library';
const PrivateKeyDisplay = ({ privateKey }) => {
const trackEvent = useContext(MetaMetricsContext);
const t = useI18nContext();
const plainKey = stripHexPrefix(privateKey);
return (
<Box
width={BLOCK_SIZES.FULL}
flexDirection={FLEX_DIRECTION.COLUMN}
display={DISPLAY.FLEX}
alignItems={AlignItems.flexStart}
paddingLeft={4}
paddingRight={4}
>
<Label
color={Color.textDefault}
marginBottom={2}
variant={TextVariant.bodySm}
>
{t('copyPrivateKey')}
</Label>
<Box
className="export-private-key-modal__private-key-display"
width={BLOCK_SIZES.FULL}
borderStyle={BorderStyle.solid}
borderColor={BorderColor.borderDefault}
borderRadius={BorderRadius.XS}
borderWidth={1}
padding={[2, 3, 2]}
color={Color.errorDefault}
onClick={() => {
copyToClipboard(plainKey);
trackEvent(
{
category: MetaMetricsEventCategory.Keys,
event: MetaMetricsEventName.KeyExportCopied,
properties: {
key_type: MetaMetricsEventKeyType.Pkey,
copy_method: 'clipboard',
},
},
{},
);
}}
>
{plainKey}
</Box>
</Box>
);
};
PrivateKeyDisplay.propTypes = {
privateKey: PropTypes.string.isRequired,
};
export default PrivateKeyDisplay;

View File

@ -1,204 +0,0 @@
import PropTypes from 'prop-types';
import React, { useContext } from 'react';
import withModalProps from '../../../../helpers/higher-order-components/with-modal-props';
import Box from '../../../ui/box';
import {
Button,
BUTTON_SIZES,
BUTTON_VARIANT,
ButtonIcon,
IconName,
Text,
} from '../../../component-library';
import {
AlignItems,
Display,
FlexDirection,
JustifyContent,
Size,
TextVariant,
} from '../../../../helpers/constants/design-system';
import HoldToRevealButton from '../../hold-to-reveal-button';
import { useI18nContext } from '../../../../hooks/useI18nContext';
import ZENDESK_URLS from '../../../../helpers/constants/zendesk-url';
import { MetaMetricsContext } from '../../../../contexts/metametrics';
import {
MetaMetricsEventCategory,
MetaMetricsEventKeyType,
MetaMetricsEventName,
} from '../../../../../shared/constants/metametrics';
const HoldToRevealModal = ({
onLongPressed,
hideModal,
willHide = true,
holdToRevealType = 'SRP',
}) => {
const t = useI18nContext();
const holdToRevealTitle =
holdToRevealType === 'SRP'
? 'holdToRevealSRPTitle'
: 'holdToRevealPrivateKeyTitle';
const holdToRevealButton =
holdToRevealType === 'SRP' ? 'holdToRevealSRP' : 'holdToRevealPrivateKey';
const trackEvent = useContext(MetaMetricsContext);
const unlock = () => {
onLongPressed();
if (willHide) {
hideModal();
}
};
const handleCancel = () => {
hideModal();
};
const renderHoldToRevealPrivateKeyContent = () => {
return (
<Box
display={Display.Flex}
flexDirection={FlexDirection.Column}
gap={4}
marginBottom={6}
>
<Text variant={TextVariant.bodyMd}>
{t('holdToRevealContentPrivateKey1', [
<Text
key="hold-to-reveal-2"
variant={TextVariant.bodyMdBold}
as="span"
>
{t('holdToRevealContentPrivateKey2')}
</Text>,
])}
</Text>
<Text variant={TextVariant.bodyMdBold}>
{t('holdToRevealContent3', [
<Text
key="hold-to-reveal-4"
variant={TextVariant.bodyMd}
as="span"
display={Display.Inline}
>
{t('holdToRevealContent4')}
</Text>,
<Button
key="hold-to-reveal-5"
variant={BUTTON_VARIANT.LINK}
size={BUTTON_SIZES.INHERIT}
href={ZENDESK_URLS.NON_CUSTODIAL_WALLET}
target="_blank"
rel="noopener noreferrer"
>
{t('holdToRevealContent5')}
</Button>,
])}
</Text>
</Box>
);
};
const renderHoldToRevealSRPContent = () => {
return (
<Box
display={Display.Flex}
flexDirection={FlexDirection.Column}
gap={4}
marginBottom={6}
>
<Text variant={TextVariant.bodyMd}>
{t('holdToRevealContent1', [
<Text
key="hold-to-reveal-2"
variant={TextVariant.bodyMdBold}
as="span"
>
{t('holdToRevealContent2')}
</Text>,
])}
</Text>
<Text variant={TextVariant.bodyMdBold}>
{t('holdToRevealContent3', [
<Text
key="hold-to-reveal-4"
variant={TextVariant.bodyMd}
as="span"
display={Display.Inline}
>
{t('holdToRevealContent4')}
</Text>,
<Button
key="hold-to-reveal-5"
variant={BUTTON_VARIANT.LINK}
size={Size.auto}
href={ZENDESK_URLS.NON_CUSTODIAL_WALLET}
target="_blank"
rel="noopener noreferrer"
>
{t('holdToRevealContent5')}
</Button>,
])}
</Text>
</Box>
);
};
return (
<Box
className="hold-to-reveal-modal"
display={Display.Flex}
flexDirection={FlexDirection.Column}
justifyContent={JustifyContent.flexStart}
padding={6}
>
<Box
display={Display.Flex}
flexDirection={FlexDirection.Row}
alignItems={AlignItems.center}
justifyContent={JustifyContent.spaceBetween}
marginBottom={6}
>
<Text variant={TextVariant.headingSm}>{t(holdToRevealTitle)}</Text>
{willHide && (
<ButtonIcon
className="hold-to-reveal-modal__close"
iconName={IconName.Close}
size={Size.SM}
onClick={() => {
trackEvent({
category: MetaMetricsEventCategory.Keys,
event: MetaMetricsEventName.SrpHoldToRevealCloseClicked,
properties: {
key_type: MetaMetricsEventKeyType.Srp,
},
});
handleCancel();
}}
ariaLabel={t('close')}
/>
)}
</Box>
{holdToRevealType === 'SRP'
? renderHoldToRevealSRPContent()
: renderHoldToRevealPrivateKeyContent()}
<HoldToRevealButton
buttonText={t(holdToRevealButton)}
onLongPressed={unlock}
marginLeft="auto"
marginRight="auto"
/>
</Box>
);
};
HoldToRevealModal.propTypes = {
// The function to be executed after the hold to reveal long press has been completed
onLongPressed: PropTypes.func.isRequired,
hideModal: PropTypes.func,
willHide: PropTypes.bool,
holdToRevealType: PropTypes.oneOf(['SRP', 'PrivateKey']).isRequired,
};
export default withModalProps(HoldToRevealModal);

View File

@ -1,13 +0,0 @@
import React from 'react';
import HoldToRevealModal from './hold-to-reveal-modal';
export default {
title: 'Components/App/Modals/HoldToRevealModal',
component: HoldToRevealModal,
};
const Template = (args) => <HoldToRevealModal {...args} />;
export const DefaultStory = Template.bind({});
DefaultStory.storyName = 'Default';

View File

@ -0,0 +1,35 @@
import { useArgs } from '@storybook/client-api';
import { Meta, StoryFn } from '@storybook/react';
import React from 'react';
import { Button } from '../../../component-library';
import HoldToRevealModal from './hold-to-reveal-modal';
export default {
title: 'Components/App/HoldToRevealModal',
component: HoldToRevealModal,
argTypes: {
isShowingModal: {
control: 'boolean',
},
},
} as Meta<typeof HoldToRevealModal>;
export const DefaultStory: StoryFn<typeof HoldToRevealModal> = () => {
const [{ isShowingModal }, updateArgs] = useArgs();
return (
<>
<Button onClick={() => updateArgs({ isShowingModal: true })}>
Open modal
</Button>
{isShowingModal && (
<HoldToRevealModal
isOpen={isShowingModal}
onClose={() => updateArgs({ isShowingModal: false })}
/>
)}
</>
);
};
DefaultStory.storyName = 'Default';

View File

@ -1,9 +1,7 @@
import { fireEvent, waitFor } from '@testing-library/react';
import React from 'react';
import configureMockState from 'redux-mock-store';
import { fireEvent, waitFor } from '@testing-library/react';
import thunk from 'redux-thunk';
import { renderWithProvider } from '../../../../../test/lib/render-helpers';
import mockState from '../../../../../test/data/mock-state.json';
import {
holdToRevealContent1,
holdToRevealContent2,
@ -12,32 +10,37 @@ import {
holdToRevealContent5,
holdToRevealSRPTitle,
} from '../../../../../app/_locales/en/messages.json';
import {
MetaMetricsEventCategory,
MetaMetricsEventKeyType,
MetaMetricsEventName,
} from '../../../../../shared/constants/metametrics';
import mockState from '../../../../../test/data/mock-state.json';
import { renderWithProvider } from '../../../../../test/lib/render-helpers';
import { MetaMetricsContext } from '../../../../contexts/metametrics';
import HoldToRevealModal from '.';
describe('Hold to Reveal Modal', () => {
const mockStore = configureMockState([thunk])(mockState);
const onCloseStub = jest.fn();
const onLongPressStub = jest.fn();
const hideModalStub = jest.fn();
const mockTrackEvent = jest.fn();
afterEach(() => {
jest.resetAllMocks();
});
it('should render the srp warning text and button', () => {
const { getByText } = renderWithProvider(
<HoldToRevealModal
onLongPressed={onLongPressStub}
hideModal={hideModalStub}
holdToRevealType="SRP"
/>,
function render(holdToRevealType = 'SRP') {
return renderWithProvider(
<MetaMetricsContext.Provider value={mockTrackEvent}>
<HoldToRevealModal
isOpen
onClose={onCloseStub}
onLongPressed={onLongPressStub}
holdToRevealType={holdToRevealType}
/>
</MetaMetricsContext.Provider>,
mockStore,
);
}
it('should render the srp warning text and button', () => {
const { getByText } = render();
const holdButton = getByText('Hold to reveal SRP');
expect(holdButton).toBeInTheDocument();
@ -73,13 +76,7 @@ describe('Hold to Reveal Modal', () => {
});
it('should should execute onLongPressed after long press', async () => {
const { getByText, queryByLabelText } = renderWithProvider(
<HoldToRevealModal
onLongPressed={onLongPressStub}
hideModal={hideModalStub}
/>,
mockStore,
);
const { getByText, queryByLabelText } = render();
const holdButton = getByText('Hold to reveal SRP');
const circleLocked = queryByLabelText('hold to reveal circle locked');
@ -99,13 +96,7 @@ describe('Hold to Reveal Modal', () => {
});
it('should remain open if long pressed was not complete', async () => {
const { getByText, queryByLabelText } = renderWithProvider(
<HoldToRevealModal
onLongPressed={onLongPressStub}
hideModal={hideModalStub}
/>,
mockStore,
);
const { getByText, queryByLabelText } = render();
const holdButton = getByText('Hold to reveal SRP');
@ -118,64 +109,14 @@ describe('Hold to Reveal Modal', () => {
expect(circleLocked).toBeInTheDocument();
expect(circleUnlocked).not.toBeInTheDocument();
expect(onLongPressStub).not.toHaveBeenCalled();
expect(hideModalStub).not.toHaveBeenCalled();
expect(onCloseStub).not.toHaveBeenCalled();
});
});
it('should fire event when closing', async () => {
const mockTrackEvent = jest.fn();
it('should render in Private Key mode', async () => {
const { getByText } = render('PrivateKey');
const { queryByLabelText } = renderWithProvider(
<MetaMetricsContext.Provider value={mockTrackEvent}>
<HoldToRevealModal
onLongPressed={onLongPressStub}
hideModal={hideModalStub}
/>
,
</MetaMetricsContext.Provider>,
mockStore,
);
const closeButton = queryByLabelText('Close');
fireEvent.click(closeButton);
await waitFor(() => {
expect(mockTrackEvent).toHaveBeenCalledWith({
category: MetaMetricsEventCategory.Keys,
event: MetaMetricsEventName.SrpHoldToRevealCloseClicked,
properties: {
key_type: MetaMetricsEventKeyType.Srp,
},
});
});
});
it('should not hide modal after completing long press if set to false', async () => {
const { getByText, queryByLabelText } = renderWithProvider(
<HoldToRevealModal
onLongPressed={onLongPressStub}
hideModal={hideModalStub}
willHide={false}
/>,
mockStore,
);
const holdButton = getByText('Hold to reveal SRP');
const circleLocked = queryByLabelText('hold to reveal circle locked');
fireEvent.pointerDown(holdButton);
fireEvent.transitionEnd(circleLocked);
const circleUnlocked = queryByLabelText('hold to reveal circle unlocked');
fireEvent.animationEnd(circleUnlocked);
await waitFor(() => {
expect(holdButton.firstChild).toHaveClass(
'hold-to-reveal-button__icon-container',
);
expect(onLongPressStub).toHaveBeenCalled();
expect(hideModalStub).not.toHaveBeenCalled();
});
const holdButton = getByText('Hold to reveal Private Key');
expect(holdButton).toBeInTheDocument();
});
});

View File

@ -0,0 +1,120 @@
import React from 'react';
import {
Display,
FlexDirection,
TextVariant,
} from '../../../../helpers/constants/design-system';
import ZENDESK_URLS from '../../../../helpers/constants/zendesk-url';
import { useI18nContext } from '../../../../hooks/useI18nContext';
import {
BUTTON_SIZES,
BUTTON_VARIANT,
Box,
Button,
Modal,
ModalContent,
ModalHeader,
ModalOverlay,
Text,
} from '../../../component-library';
import HoldToRevealButton from '../../hold-to-reveal-button';
type HoldToRevealModalProps = {
isOpen: boolean;
onClose: () => void;
onLongPressed: () => void;
holdToRevealType: 'SRP' | 'PrivateKey';
};
export default function HoldToRevealModal({
isOpen,
onClose,
onLongPressed,
holdToRevealType,
}: HoldToRevealModalProps) {
const t = useI18nContext();
const holdToRevealTitle =
holdToRevealType === 'SRP'
? 'holdToRevealSRPTitle'
: 'holdToRevealPrivateKeyTitle';
const holdToRevealButton =
holdToRevealType === 'SRP' ? 'holdToRevealSRP' : 'holdToRevealPrivateKey';
const holdToRevealContent =
holdToRevealType === 'SRP'
? 'holdToRevealContent'
: 'holdToRevealContentPrivateKey';
// If this is done inline, verify-locales will output `Forbidden use of template strings in 't' function`
const holdToRevealContent1 = `${holdToRevealContent}1`;
const holdToRevealContent2 = `${holdToRevealContent}2`;
// This is here to stop yarn verify-locales from removing these strings
t('holdToRevealContentPrivateKey1');
t('holdToRevealContentPrivateKey2');
t('holdToRevealContent1');
t('holdToRevealContent2');
const MainContent = () => {
return (
<Box
display={Display.Flex}
flexDirection={FlexDirection.Column}
gap={4}
marginTop={6}
marginBottom={6}
>
<Text variant={TextVariant.bodyMd}>
{t(holdToRevealContent1, [
<Text
key="hold-to-reveal-2"
variant={TextVariant.bodyMdBold}
as="span"
>
{t(holdToRevealContent2)}
</Text>,
])}
</Text>
<Text variant={TextVariant.bodyMdBold}>
{t('holdToRevealContent3', [
<Text
key="hold-to-reveal-4"
variant={TextVariant.bodyMd}
as="span"
display={Display.Inline}
>
{t('holdToRevealContent4')}
</Text>,
<Button
key="hold-to-reveal-5"
variant={BUTTON_VARIANT.LINK}
size={BUTTON_SIZES.INHERIT}
href={ZENDESK_URLS.NON_CUSTODIAL_WALLET}
target="_blank"
rel="noopener noreferrer"
>
{t('holdToRevealContent5')}
</Button>,
])}
</Text>
</Box>
);
};
return (
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader onClose={onClose}>{t(holdToRevealTitle)}</ModalHeader>
<Box display={Display.Flex} flexDirection={FlexDirection.Column}>
<MainContent />
<HoldToRevealButton
buttonText={t(holdToRevealButton)}
onLongPressed={onLongPressed}
/>
</Box>
</ModalContent>
</Modal>
);
}

View File

@ -1,8 +0,0 @@
.hold-to-reveal-modal {
position: relative;
&__close {
position: absolute;
right: 16px;
}
}

View File

@ -1,9 +1,6 @@
@import 'account-details-modal/index';
@import 'account-modal-container/index';
@import 'cancel-transaction/index';
@import 'confirm-remove-account/index';
@import 'edit-approval-permission/index';
@import 'export-private-key-modal/index';
@import 'hide-token-confirmation-modal/index';
@import 'new-account-modal/index';
@import 'qr-scanner/index';
@ -11,7 +8,6 @@
@import 'customize-nonce/index';
@import 'convert-token-to-nft-modal/index';
@import 'contract-details-modal/index';
@import 'hold-to-reveal-modal/index';
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
@import '../../institutional/confirm-remove-jwt-modal/index';
@import '../../institutional/custody-confirm-link-modal/index';

View File

@ -18,14 +18,11 @@ import CustodyConfirmLink from '../../institutional/custody-confirm-link-modal';
import InteractiveReplacementTokenModal from '../../institutional/interactive-replacement-token-modal';
import TransactionFailed from '../../institutional/transaction-failed-modal';
///: END:ONLY_INCLUDE_IN
import AccountDetailsModal from './account-details-modal';
import ExportPrivateKeyModal from './export-private-key-modal';
import HideTokenConfirmationModal from './hide-token-confirmation-modal';
import QRScanner from './qr-scanner';
import ConfirmRemoveAccount from './confirm-remove-account';
import ConfirmResetAccount from './confirm-reset-account';
import HoldToRevealModal from './hold-to-reveal-modal';
import TransactionConfirmed from './transaction-confirmed';
import ConfirmDeleteNetwork from './confirm-delete-network';
@ -145,29 +142,6 @@ const MODALS = {
},
},
ACCOUNT_DETAILS: {
contents: <AccountDetailsModal />,
...accountModalStyle,
},
EXPORT_PRIVATE_KEY: {
contents: <ExportPrivateKeyModal />,
...accountModalStyle,
},
HOLD_TO_REVEAL_SRP: {
contents: <HoldToRevealModal />,
mobileModalStyle: {
...modalContainerMobileStyle,
},
laptopModalStyle: {
...modalContainerLaptopStyle,
},
contentStyle: {
borderRadius: '8px',
},
},
HIDE_TOKEN_CONFIRMATION: {
contents: <HideTokenConfirmationModal />,
mobileModalStyle: {

View File

@ -1,6 +1,6 @@
import PropTypes from 'prop-types';
import React, { useCallback, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import PropTypes from 'prop-types';
import {
Display,
FontWeight,
@ -9,16 +9,21 @@ import {
} from '../../../helpers/constants/design-system';
import {
BannerAlert,
Box,
ButtonPrimary,
ButtonSecondary,
FormTextField,
Box,
} from '../../component-library';
import { useI18nContext } from '../../../hooks/useI18nContext';
import { exportAccount, hideWarning } from '../../../store/actions';
export const AccountDetailsAuthenticate = ({ address, onCancel }) => {
export const AccountDetailsAuthenticate = ({
address,
onCancel,
setPrivateKey,
setShowHoldToReveal,
}) => {
const t = useI18nContext();
const dispatch = useDispatch();
@ -28,11 +33,13 @@ export const AccountDetailsAuthenticate = ({ address, onCancel }) => {
const warning = useSelector((state) => state.appState.warning);
const onSubmit = useCallback(() => {
dispatch(exportAccount(password, address)).then((res) => {
dispatch(
exportAccount(password, address, setPrivateKey, setShowHoldToReveal),
).then((res) => {
dispatch(hideWarning());
return res;
});
}, [dispatch, password, address]);
}, [dispatch, password, address, setPrivateKey, setShowHoldToReveal]);
const handleKeyPress = useCallback(
(e) => {
@ -80,4 +87,6 @@ export const AccountDetailsAuthenticate = ({ address, onCancel }) => {
AccountDetailsAuthenticate.propTypes = {
address: PropTypes.string.isRequired,
onCancel: PropTypes.func.isRequired,
setPrivateKey: PropTypes.func.isRequired,
setShowHoldToReveal: PropTypes.func.isRequired,
};

View File

@ -1,48 +1,54 @@
import React, { useCallback, useState } from 'react';
import PropTypes from 'prop-types';
import React, { useCallback, useContext, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import {
setAccountDetailsAddress,
MetaMetricsEventCategory,
MetaMetricsEventKeyType,
MetaMetricsEventName,
} from '../../../../shared/constants/metametrics';
import { MetaMetricsContext } from '../../../contexts/metametrics';
import {
AlignItems,
Display,
FlexDirection,
TextVariant,
} from '../../../helpers/constants/design-system';
import { useI18nContext } from '../../../hooks/useI18nContext';
import { getMetaMaskAccountsOrdered } from '../../../selectors';
import {
clearAccountDetails,
hideWarning,
setAccountDetailsAddress,
} from '../../../store/actions';
import HoldToRevealModal from '../../app/modals/hold-to-reveal-modal/hold-to-reveal-modal';
import {
AvatarAccount,
AvatarAccountSize,
AvatarAccountVariant,
Box,
Modal,
ModalContent,
ModalHeader,
ModalOverlay,
Box,
Text,
} from '../../component-library';
import { getMetaMaskAccountsOrdered } from '../../../selectors';
import { useI18nContext } from '../../../hooks/useI18nContext';
import {
AlignItems,
TextVariant,
Display,
FlexDirection,
} from '../../../helpers/constants/design-system';
import { AddressCopyButton } from '../address-copy-button';
import { AccountDetailsDisplay } from './account-details-display';
import { AccountDetailsAuthenticate } from './account-details-authenticate';
import { AccountDetailsDisplay } from './account-details-display';
import { AccountDetailsKey } from './account-details-key';
export const AccountDetails = ({ address }) => {
const dispatch = useDispatch();
const t = useI18nContext();
const trackEvent = useContext(MetaMetricsContext);
const useBlockie = useSelector((state) => state.metamask.useBlockie);
const accounts = useSelector(getMetaMaskAccountsOrdered);
const { name } = accounts.find((account) => account.address === address);
const [showHoldToReveal, setShowHoldToReveal] = useState(false);
const [attemptingExport, setAttemptingExport] = useState(false);
// This is only populated when the user properly authenticates
const privateKey = useSelector(
(state) => state.appState.accountDetail.privateKey,
);
const [privateKey, setPrivateKey] = useState('');
const onClose = useCallback(() => {
dispatch(setAccountDetailsAddress(''));
@ -64,63 +70,87 @@ export const AccountDetails = ({ address }) => {
);
return (
<Modal isOpen onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader
onClose={onClose}
onBack={
attemptingExport
? () => {
dispatch(hideWarning());
setAttemptingExport(false);
}
: null
}
>
{attemptingExport ? t('showPrivateKey') : avatar}
</ModalHeader>
{attemptingExport ? (
<>
<Box
display={Display.Flex}
alignItems={AlignItems.center}
flexDirection={FlexDirection.Column}
>
{avatar}
<Text
marginTop={2}
marginBottom={2}
variant={TextVariant.bodyLgMedium}
style={{ wordBreak: 'break-word' }}
<>
{/* This is the Modal that says "Show private key" on top and has a few states */}
<Modal isOpen={!showHoldToReveal} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader
onClose={onClose}
onBack={
attemptingExport &&
(() => {
dispatch(hideWarning());
setAttemptingExport(false);
})
}
>
{attemptingExport ? t('showPrivateKey') : avatar}
</ModalHeader>
{attemptingExport ? (
<>
<Box
display={Display.Flex}
alignItems={AlignItems.center}
flexDirection={FlexDirection.Column}
>
{name}
</Text>
<AddressCopyButton address={address} shorten />
</Box>
{privateKey ? (
<AccountDetailsKey
accountName={name}
onClose={onClose}
privateKey={privateKey}
/>
) : (
<AccountDetailsAuthenticate
address={address}
onCancel={onClose}
/>
)}
</>
) : (
<AccountDetailsDisplay
accounts={accounts}
accountName={name}
address={address}
onExportClick={() => setAttemptingExport(true)}
/>
)}
</ModalContent>
</Modal>
{avatar}
<Text
marginTop={2}
marginBottom={2}
variant={TextVariant.bodyLgMedium}
style={{ wordBreak: 'break-word' }}
>
{name}
</Text>
<AddressCopyButton address={address} shorten />
</Box>
{privateKey ? (
<AccountDetailsKey
accountName={name}
onClose={onClose}
privateKey={privateKey}
/>
) : (
<AccountDetailsAuthenticate
address={address}
onCancel={onClose}
setPrivateKey={setPrivateKey}
setShowHoldToReveal={setShowHoldToReveal}
/>
)}
</>
) : (
<AccountDetailsDisplay
accounts={accounts}
accountName={name}
address={address}
onExportClick={() => setAttemptingExport(true)}
/>
)}
</ModalContent>
</Modal>
{/* This is the Modal that says "Hold to reveal private key" */}
<HoldToRevealModal
isOpen={showHoldToReveal}
onClose={() => {
trackEvent({
category: MetaMetricsEventCategory.Keys,
event: MetaMetricsEventName.KeyExportCanceled,
properties: {
key_type: MetaMetricsEventKeyType.Pkey,
},
});
setPrivateKey('');
setShowHoldToReveal(false);
}}
onLongPressed={() => {
setShowHoldToReveal(false);
}}
holdToRevealType="PrivateKey"
/>
</>
);
};

View File

@ -1,31 +1,35 @@
import React from 'react';
import { screen, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { toChecksumHexAddress } from '@metamask/controller-utils';
import { renderWithProvider } from '../../../../test/jest';
import configureStore from '../../../store/store';
import mockState from '../../../../test/data/mock-state.json';
import { fireEvent, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { showPrivateKey } from '../../../../app/_locales/en/messages.json';
import mockState from '../../../../test/data/mock-state.json';
import { renderWithProvider } from '../../../../test/jest';
import { shortenAddress } from '../../../helpers/utils/util';
import {
setAccountDetailsAddress,
clearAccountDetails,
exportAccount,
hideWarning,
setAccountDetailsAddress,
} from '../../../store/actions';
import { shortenAddress } from '../../../helpers/utils/util';
import configureStore from '../../../store/store';
import { AccountDetailsKey } from './account-details-key';
import { AccountDetails } from '.';
jest.mock('../../../store/actions.ts');
describe('AccountDetails', () => {
const address = '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc';
const mockSetAccountDetailsAddress = jest.fn();
const mockClearAccountDetails = jest.fn();
const mockExportAccount = jest.fn().mockResolvedValue(true);
const mockHideWarning = jest.fn();
const mockSetAccountDetailsAddress = jest.fn();
beforeEach(() => {
setAccountDetailsAddress.mockReturnValue(mockSetAccountDetailsAddress);
clearAccountDetails.mockReturnValue(mockClearAccountDetails);
exportAccount.mockReturnValue(mockExportAccount);
hideWarning.mockReturnValue(mockHideWarning);
setAccountDetailsAddress.mockReturnValue(mockSetAccountDetailsAddress);
});
afterEach(() => jest.clearAllMocks());
@ -79,23 +83,33 @@ describe('AccountDetails', () => {
await userEvent.keyboard(password);
fireEvent.click(queryByText('Confirm'));
expect(exportAccount).toHaveBeenCalledWith(password, address);
expect(exportAccount).toHaveBeenCalledWith(
password,
address,
expect.any(Function),
expect.any(Function),
);
});
it('displays the private key when exposed in state', () => {
it('displays the private key when sent in props', () => {
const samplePrivateKey = '8675309';
const { queryByText } = render(
{},
{ appState: { accountDetail: { privateKey: samplePrivateKey } } },
const { queryByText } = renderWithProvider(
<AccountDetailsKey
accountName="Account 1"
onClose={jest.fn()}
privateKey={samplePrivateKey}
/>,
);
const exportPrivateKeyButton = queryByText(showPrivateKey.message);
fireEvent.click(exportPrivateKeyButton);
expect(
queryByText(shortenAddress(toChecksumHexAddress(address))),
).toBeInTheDocument();
expect(queryByText(samplePrivateKey)).toBeInTheDocument();
});
it('should call AccountDetails.onClose()', () => {
render();
fireEvent.click(screen.getByLabelText('Close'));
expect(screen.queryByText('Account 1')).toBeNull();
});
});

View File

@ -1,48 +1,48 @@
import React, { useContext, useEffect, useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { useHistory } from 'react-router-dom';
import qrCode from 'qrcode-generator';
import { requestRevealSeedWords, showModal } from '../../store/actions';
import ExportTextContainer from '../../components/ui/export-text-container';
import { getMostRecentOverviewPage } from '../../ducks/history/history';
import React, { useContext, useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useHistory } from 'react-router-dom';
import {
MetaMetricsEventCategory,
MetaMetricsEventKeyType,
MetaMetricsEventName,
} from '../../../shared/constants/metametrics';
import HoldToRevealModal from '../../components/app/modals/hold-to-reveal-modal/hold-to-reveal-modal';
import {
TextVariant,
SEVERITIES,
Size,
BLOCK_SIZES,
JustifyContent,
AlignItems,
DISPLAY,
} from '../../helpers/constants/design-system';
import Box from '../../components/ui/box';
import {
Label,
BUTTON_SIZES,
BUTTON_VARIANT,
BannerAlert,
Button,
TextField,
HelpText,
HelpTextSeverity,
BUTTON_VARIANT,
Label,
TEXT_FIELD_SIZES,
TEXT_FIELD_TYPES,
BUTTON_SIZES,
Text,
TextField,
} from '../../components/component-library';
import { useI18nContext } from '../../hooks/useI18nContext';
import Box from '../../components/ui/box';
import ExportTextContainer from '../../components/ui/export-text-container';
import { Tab, Tabs } from '../../components/ui/tabs';
import { MetaMetricsContext } from '../../contexts/metametrics';
import { getMostRecentOverviewPage } from '../../ducks/history/history';
import {
AlignItems,
BlockSize,
Display,
JustifyContent,
Severity,
Size,
TextVariant,
} from '../../helpers/constants/design-system';
import ZENDESK_URLS from '../../helpers/constants/zendesk-url';
import { Tabs, Tab } from '../../components/ui/tabs';
import { useI18nContext } from '../../hooks/useI18nContext';
import { requestRevealSeedWords } from '../../store/actions';
const PASSWORD_PROMPT_SCREEN = 'PASSWORD_PROMPT_SCREEN';
const REVEAL_SEED_SCREEN = 'REVEAL_SEED_SCREEN';
const RevealSeedPage = () => {
export default function RevealSeedPage() {
const history = useHistory();
const dispatch = useDispatch();
const t = useI18nContext();
@ -54,6 +54,7 @@ const RevealSeedPage = () => {
const [completedLongPress, setCompletedLongPress] = useState(false);
const [error, setError] = useState(null);
const mostRecentOverviewPage = useSelector(getMostRecentOverviewPage);
const [isShowingHoldModal, setIsShowingHoldModal] = useState(false);
useEffect(() => {
const passwordBox = document.getElementById('password-box');
@ -85,16 +86,7 @@ const RevealSeedPage = () => {
});
setSeedWords(revealedSeedWords);
dispatch(
showModal({
name: 'HOLD_TO_REVEAL_SRP',
onLongPressed: () => {
setCompletedLongPress(true);
setScreen(REVEAL_SEED_SCREEN);
},
holdToRevealType: 'SRP',
}),
);
setIsShowingHoldModal(true);
})
.catch((e) => {
trackEvent({
@ -111,7 +103,7 @@ const RevealSeedPage = () => {
const renderWarning = () => {
return (
<BannerAlert severity={SEVERITIES.DANGER}>
<BannerAlert severity={Severity.Danger}>
<Text variant={TextVariant.bodyMd}>
{t('revealSeedWordsWarning', [
<Text
@ -142,7 +134,7 @@ const RevealSeedPage = () => {
value={password}
onChange={(event) => setPassword(event.target.value)}
error={error}
width={BLOCK_SIZES.FULL}
width={BlockSize.Full}
/>
{error && (
<HelpText severity={HelpTextSeverity.Danger}>{error}</HelpText>
@ -221,7 +213,7 @@ const RevealSeedPage = () => {
tabKey="qr-srp"
>
<Box
display={DISPLAY.FLEX}
display={Display.Flex}
justifyContent={JustifyContent.center}
alignItems={AlignItems.center}
paddingTop={4}
@ -241,9 +233,9 @@ const RevealSeedPage = () => {
const renderPasswordPromptFooter = () => {
return (
<Box display={DISPLAY.FLEX} marginTop="auto" gap={4}>
<Box display={Display.Flex} marginTop="auto" gap={4}>
<Button
width={BLOCK_SIZES.FULL}
width={BlockSize.Full}
size={Size.LG}
variant={BUTTON_VARIANT.SECONDARY}
onClick={() => {
@ -267,7 +259,7 @@ const RevealSeedPage = () => {
{t('cancel')}
</Button>
<Button
width={BLOCK_SIZES.FULL}
width={BlockSize.Full}
size={Size.LG}
onClick={(event) => {
trackEvent({
@ -299,7 +291,7 @@ const RevealSeedPage = () => {
<Box marginTop="auto">
<Button
variant={BUTTON_VARIANT.SECONDARY}
width={BLOCK_SIZES.FULL}
width={BlockSize.Full}
size={Size.LG}
onClick={() => {
trackEvent({
@ -380,8 +372,25 @@ const RevealSeedPage = () => {
{renderWarning()}
{renderContent()}
{renderFooter()}
<HoldToRevealModal
isOpen={isShowingHoldModal}
onClose={() => {
trackEvent({
category: MetaMetricsEventCategory.Keys,
event: MetaMetricsEventName.SrpHoldToRevealCloseClicked,
properties: {
key_type: MetaMetricsEventKeyType.Srp,
},
});
setIsShowingHoldModal(false);
}}
onLongPressed={() => {
setCompletedLongPress(true);
setIsShowingHoldModal(false);
setScreen(REVEAL_SEED_SCREEN);
}}
holdToRevealType="SRP"
/>
</Box>
);
};
export default RevealSeedPage;
}

View File

@ -1402,15 +1402,17 @@ describe('Actions', () => {
const expectedActions = [
{ type: 'SHOW_LOADING_INDICATION', payload: undefined },
{ type: 'HIDE_LOADING_INDICATION' },
{
type: 'SHOW_PRIVATE_KEY',
payload: testPrivKey,
},
];
await store.dispatch(
actions.exportAccount('a-test-password', '0xAddress'),
actions.exportAccount(
'a-test-password',
'0xAddress',
jest.fn(),
jest.fn(),
),
);
expect(verifyPasswordStub.callCount).toStrictEqual(1);
expect(exportAccountStub.callCount).toStrictEqual(1);
expect(store.getActions()).toStrictEqual(expectedActions);

View File

@ -2564,6 +2564,8 @@ export function hideWarning() {
export function exportAccount(
password: string,
address: string,
setPrivateKey: (key: string) => void,
setShowHoldToReveal: (show: boolean) => void,
): ThunkAction<void, MetaMaskReduxState, unknown, AnyAction> {
return function (dispatch) {
dispatch(showLoadingIndication());
@ -2592,7 +2594,8 @@ export function exportAccount(
return;
}
dispatch(showPrivateKey(result as string));
setPrivateKey(result as string);
setShowHoldToReveal(true);
resolve(result as string);
},
);