diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index fe0c84afcfac..8d1ed215aa92 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -207,23 +207,6 @@ "addCustomNetwork": { "message": "Benutzerdefiniertes Netzwerk hinzufügen" }, - "addEthereumChainConfirmationDescription": { - "message": "Dadurch kann dieses Netzwerk innerhalb MetaMask verwendet werden." - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMask überprüft keine benutzerdefinierten Netzwerke." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "Erfahren Sie mehr über $1.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "Betrug und Sicherheitsrisiken im Netzwerk", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "Dieser Seite das Hinzufügen eines Netzwerks erlauben?" - }, "addEthereumChainWarningModalHeader": { "message": "Fügen Sie diesen RPC-Anbieter nur hinzu, wenn Sie sich sicher sind, dass Sie ihm vertrauen können. $1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4858,9 +4841,6 @@ "message": "Kontaktieren Sie die Ersteller von $1 für weitere Unterstützung.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "Einige Netzwerke können Sicherheits- und/oder Datenschutzrisiken bergen. Informieren Sie sich über die Risiken, bevor Sie ein Netzwerk hinzufügen und nutzen." - }, "somethingDoesntLookRight": { "message": "Scheint irgendetwas nicht in Ordnung zu sein? $1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6007,9 +5987,6 @@ "viewActivity": { "message": "Aktivität anzeigen" }, - "viewAllDetails": { - "message": "Alle Details anzeigen" - }, "viewAllQuotes": { "message": "alle Angebote anzeigen" }, diff --git a/app/_locales/el/messages.json b/app/_locales/el/messages.json index 5c42a8d829b4..7ccc23b123bb 100644 --- a/app/_locales/el/messages.json +++ b/app/_locales/el/messages.json @@ -207,23 +207,6 @@ "addCustomNetwork": { "message": "Προσθήκη προσαρμοσμένου δικτύου" }, - "addEthereumChainConfirmationDescription": { - "message": "Αυτό θα επιτρέψει σε αυτό το δίκτυο να χρησιμοποιηθεί στο MetaMask." - }, - "addEthereumChainConfirmationRisks": { - "message": "Το MetaMask δεν επαληθεύει τα προσαρμοσμένα δίκτυα." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "Μάθετε για το $1.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "απάτες και κίνδυνοι ασφάλειας δικτύου", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "Επιτρέπετε σε αυτήν την ιστοσελίδα να προσθέσει ένα δίκτυο;" - }, "addEthereumChainWarningModalHeader": { "message": "Προσθέστε αυτόν τον πάροχο RPC μόνο αν είστε σίγουροι ότι μπορείτε να τον εμπιστευτείτε. $1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4858,9 +4841,6 @@ "message": "Επικοινωνήστε με τους διαχειριστές του $1 για περαιτέρω υποστήριξη.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "Ορισμένα δίκτυα ενδέχεται να ενέχουν κινδύνους για την ασφάλεια ή/και το απόρρητο. Ενημερωθείτε για τους κινδύνους πριν προσθέσετε και χρησιμοποιήσετε ένα δίκτυο." - }, "somethingDoesntLookRight": { "message": "Κάτι δεν φαίνεται σωστό; $1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6007,9 +5987,6 @@ "viewActivity": { "message": "Προβολή δραστηριότητας" }, - "viewAllDetails": { - "message": "Προβολή όλων των λεπτομερειών" - }, "viewAllQuotes": { "message": "προβολή όλων των προσφορών" }, diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 70cb4da8cfb6..b36f3ffcdb4e 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -231,23 +231,6 @@ "addCustomNetwork": { "message": "Add custom network" }, - "addEthereumChainConfirmationDescription": { - "message": "This will allow this network to be used within MetaMask." - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMask does not verify custom networks." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "Learn about $1.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "scams and network security risks", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "Allow this site to add a network?" - }, "addEthereumChainWarningModalHeader": { "message": "Only add this RPC provider if you’re sure you can trust it. $1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4668,6 +4651,9 @@ "securityDescription": { "message": "Reduce your chances of joining unsafe networks and protect your accounts" }, + "securityMessageLinkForNetworks": { + "message": "network scams and security risks" + }, "securityPrivacyPath": { "message": "Settings > Security & Privacy." }, @@ -5238,9 +5224,6 @@ "message": "Contact the creators of $1 for further support.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "Some networks may pose security and/or privacy risks. Understand the risks before adding & using a network." - }, "somethingDoesntLookRight": { "message": "Something doesn't look right? $1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6324,9 +6307,6 @@ "unknown": { "message": "Unknown" }, - "unknownChainWarning": { - "message": "We can’t verify custom networks. To avoid malicious providers from recording your network activity, only add networks you trust." - }, "unknownCollection": { "message": "Unnamed collection" }, @@ -6455,9 +6435,6 @@ "viewActivity": { "message": "View activity" }, - "viewAllDetails": { - "message": "View all details" - }, "viewAllQuotes": { "message": "view all quotes" }, @@ -6540,6 +6517,10 @@ "watchEthereumAccountsToggle": { "message": "Watch Ethereum Accounts (Beta)" }, + "watchOutMessage": { + "message": "Beware of $1.", + "description": "$1 is a link with text that is provided by the 'securityMessageLinkForNetworks' key" + }, "weak": { "message": "Weak" }, diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index 97d6f4be9854..a2578d1f4137 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -207,23 +207,6 @@ "addCustomNetwork": { "message": "Agregar red personalizada" }, - "addEthereumChainConfirmationDescription": { - "message": "Esto permitirá que la red se utilice en MetaMask." - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMask no verifica redes personalizadas." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "Obtenga más información sobre $1.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "estafas y riesgos de seguridad de la red", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "¿Permitir que este sitio agregue una red?" - }, "addEthereumChainWarningModalHeader": { "message": "Agregue este proveedor de RPC solo si está seguro de que puede confiar en él. $1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4855,9 +4838,6 @@ "message": "Póngase en contacto con los creadores de $1 para obtener más ayuda.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "Algunas redes pueden presentar riesgos de seguridad y/o privacidad. Comprenda los riesgos antes de agregar y utilizar una red." - }, "somethingDoesntLookRight": { "message": "Algo no se ve bien, ¿cierto? $1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6004,9 +5984,6 @@ "viewActivity": { "message": "Ver actividad" }, - "viewAllDetails": { - "message": "Ver todos los detalles" - }, "viewAllQuotes": { "message": "ver todas las cotizaciones" }, diff --git a/app/_locales/es_419/messages.json b/app/_locales/es_419/messages.json index 672823c370ba..cebfc3cef106 100644 --- a/app/_locales/es_419/messages.json +++ b/app/_locales/es_419/messages.json @@ -100,23 +100,6 @@ "addContact": { "message": "Agregar contacto" }, - "addEthereumChainConfirmationDescription": { - "message": "Esto permitirá que la red se utilice en MetaMask." - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMask no verifica redes personalizadas." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "Obtenga más información sobre $1.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "estafas y riesgos de seguridad de la red", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "¿Permitir que este sitio agregue una red?" - }, "addFriendsAndAddresses": { "message": "Agregue amigos y direcciones de confianza" }, @@ -2335,9 +2318,6 @@ "userName": { "message": "Nombre de usuario" }, - "viewAllDetails": { - "message": "Ver todos los detalles" - }, "viewContact": { "message": "Ver contacto" }, diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index dbaffd44cf38..c3151d3ca53f 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -207,23 +207,6 @@ "addCustomNetwork": { "message": "Ajouter un réseau personnalisé" }, - "addEthereumChainConfirmationDescription": { - "message": "Cela permettra d’utiliser ce réseau dans MetaMask." - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMask ne vérifie pas les réseaux personnalisés." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "En savoir plus sur $1.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "les risques de fraude et de sécurité des réseaux", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "Autoriser ce site à ajouter un réseau ?" - }, "addEthereumChainWarningModalHeader": { "message": "N’ajoutez ce fournisseur de RPC que si vous lui faites confiance. $1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4858,9 +4841,6 @@ "message": "L’interface utilisateur (IU) spécifiée par le snap n’est pas valide.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "Certains réseaux peuvent présenter des risques pour la sécurité et/ou la vie privée. Informez-vous sur les risques avant d’ajouter et d’utiliser un réseau." - }, "somethingDoesntLookRight": { "message": "On dirait que quelque chose ne va pas ? $1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6007,9 +5987,6 @@ "viewActivity": { "message": "Voir l’activité" }, - "viewAllDetails": { - "message": "Afficher tous les détails" - }, "viewAllQuotes": { "message": "afficher toutes les cotations" }, diff --git a/app/_locales/hi/messages.json b/app/_locales/hi/messages.json index 0e624b4ba807..c69c7117d4d0 100644 --- a/app/_locales/hi/messages.json +++ b/app/_locales/hi/messages.json @@ -207,23 +207,6 @@ "addCustomNetwork": { "message": "कस्टम नेटवर्क जोड़ें" }, - "addEthereumChainConfirmationDescription": { - "message": "इससे इस नेटवर्क को MetaMask के अंदर इस्तेमाल करने की अनुमति मिलेगी।" - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMask कस्टम नेटवर्क को वेरीफ़ाई नहीं करता है।" - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "$1 के बारे में जानें।", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "स्कैम और नेटवर्क से जुड़े सुरक्षा जोखिम", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "इस साइट को नेटवर्क जोड़ने की अनुमति दें?" - }, "addEthereumChainWarningModalHeader": { "message": "इस RPC प्रोवाइडर को केवल तभी जोड़ें जब आप निश्चित हैं कि आप इस पर विश्वास कर सकते हैं। $1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4858,9 +4841,6 @@ "message": "अधिक सहायता के लिए $1 के निर्माताओं से कॉन्टेक्ट करें।", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "कुछ नेटवर्क सुरक्षा और/या गोपनीयता संबंधी जोखिम पैदा कर सकते हैं। नेटवर्क जोड़ने और इस्तेमाल करने से पहले जोखिमों को समझें।" - }, "somethingDoesntLookRight": { "message": "कुछ तो गड़बड़ है? $1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6007,9 +5987,6 @@ "viewActivity": { "message": "एक्टिविटी देखें" }, - "viewAllDetails": { - "message": "सभी विवरण देखें" - }, "viewAllQuotes": { "message": "सभी उद्धरण को देखें" }, diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json index 68b52556c3f6..53e7fd923fda 100644 --- a/app/_locales/id/messages.json +++ b/app/_locales/id/messages.json @@ -207,23 +207,6 @@ "addCustomNetwork": { "message": "Tambahkan jaringan khusus" }, - "addEthereumChainConfirmationDescription": { - "message": "Tindakan ini akan membantu jaringan ini agar dapat digunakan di MetaMask." - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMask tidak memverifikasi jaringan kustom." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "Pelajari tentang $1.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "penipuan dan risiko keamanan jaringan", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "Izinkan situs ini untuk menambahkan jaringan?" - }, "addEthereumChainWarningModalHeader": { "message": "Cukup tambahkan penyedia RPC ini jika Anda yakin dapat memercayainya. $1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4858,9 +4841,6 @@ "message": "Hubungi pembuat $1 untuk dukungan lebih lanjut.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "Beberapa jaringan dapat menimbulkan risiko keamanan dan/atau privasi. Pahami risikonya sebelum menambahkan dan menggunakan jaringan." - }, "somethingDoesntLookRight": { "message": "Ada yang tidak beres? $1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6007,9 +5987,6 @@ "viewActivity": { "message": "Lihat aktivitas" }, - "viewAllDetails": { - "message": "Lihat semua detail" - }, "viewAllQuotes": { "message": "lihat semua kuotasi" }, diff --git a/app/_locales/it/messages.json b/app/_locales/it/messages.json index 4dac80c253b3..0c79dd8fc6fc 100644 --- a/app/_locales/it/messages.json +++ b/app/_locales/it/messages.json @@ -152,23 +152,6 @@ "addContact": { "message": "Aggiungi contatto" }, - "addEthereumChainConfirmationDescription": { - "message": "Ciò consentirà a questa rete di essere utilizzata all'interno di MetaMask." - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMask non verifica le reti personalizzate." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "Maggiori informazioni su $1.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "truffe e rischi per la sicurezza della rete", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "Consenti a questo sito di aggiungere una rete?" - }, "addFriendsAndAddresses": { "message": "Aggiungi amici e indirizzi di cui ti fidi" }, @@ -1649,9 +1632,6 @@ "userName": { "message": "Nome utente" }, - "viewAllDetails": { - "message": "Vedi tutti i dettagli" - }, "viewContact": { "message": "Visualizza contatto" }, diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index 73f3f8300646..c26ec67990b2 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -207,23 +207,6 @@ "addCustomNetwork": { "message": "カスタムネットワークを追加" }, - "addEthereumChainConfirmationDescription": { - "message": "これにより、このネットワークはMetaMask内で使用できるようになります。" - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMaskはカスタムネットワークを検証しません。" - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "$1の詳細。", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "詐欺やネットワークセキュリティのリスク", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "このサイトにネットワークの追加を許可しますか?" - }, "addEthereumChainWarningModalHeader": { "message": "このRPCプロバイダーは、確実に信頼できる場合のみ追加してください。$1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4858,9 +4841,6 @@ "message": "今後のサポートは、$1の作成者にお問い合わせください。", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "ネットワークによっては、セキュリティやプライバシーの面でリスクが伴う可能性があります。ネットワークを追加・使用する前にリスクを理解するようにしてください。" - }, "somethingDoesntLookRight": { "message": "何か不審な点があれば、$1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6007,9 +5987,6 @@ "viewActivity": { "message": "アクティビティを表示" }, - "viewAllDetails": { - "message": "すべての詳細の表示" - }, "viewAllQuotes": { "message": "すべてのクォートを表示" }, diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index be1de55c51c7..ad4959a459b9 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -207,23 +207,6 @@ "addCustomNetwork": { "message": "맞춤 네트워크 추가" }, - "addEthereumChainConfirmationDescription": { - "message": "이렇게 하면 MetaMask 내에서 이 네트워크를 사용할 수 있습니다." - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMask는 맞춤 네트워크를 검증하지 않습니다." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "$1에 대해 알아보기", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "사기 및 네트워크 보안 위험", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "이 사이트에서 네트워크를 추가하도록 허용하시겠습니까?" - }, "addEthereumChainWarningModalHeader": { "message": "신뢰할 수 있는 경우에만 이 RPC 공급입체를 추가하세요. $1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4858,9 +4841,6 @@ "message": "$1 작성자에게 연락하여 향후 지원을 요청하세요.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "네트워크에 따라 보안이나 개인 정보 유출의 위험이 있을 수 있습니다. 네트워크 추가 및 사용 이전에 위험 요소를 파악하세요." - }, "somethingDoesntLookRight": { "message": "무언가 잘못되었나요? $1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6007,9 +5987,6 @@ "viewActivity": { "message": "활동 보기" }, - "viewAllDetails": { - "message": "모든 세부 정보 보기" - }, "viewAllQuotes": { "message": "모든 견적 보기" }, diff --git a/app/_locales/ph/messages.json b/app/_locales/ph/messages.json index 1687cb7818f0..e6b4bc3e7811 100644 --- a/app/_locales/ph/messages.json +++ b/app/_locales/ph/messages.json @@ -42,23 +42,6 @@ "addContact": { "message": "Magdagdag ng contact" }, - "addEthereumChainConfirmationDescription": { - "message": "Bibigyang-daan nito na magamit ang network na ito sa MetaMask." - }, - "addEthereumChainConfirmationRisks": { - "message": "Hindi vine-verify ng MetaMask ang mga custom na network." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "Matuto tungkol sa $1.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "mga scam at panganib sa seguridad ng network", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "Payagan ang site na ito na magdagdag ng network?" - }, "addFriendsAndAddresses": { "message": "Magdagdag ng mga kaibigan at address na pinagkakatiwalaan mo" }, @@ -1594,9 +1577,6 @@ "userName": { "message": "Username" }, - "viewAllDetails": { - "message": "Tingnan ang lahat ng detalye" - }, "viewContact": { "message": "Tingnan ang Contact" }, diff --git a/app/_locales/pt/messages.json b/app/_locales/pt/messages.json index 656733cecf65..7831e080500b 100644 --- a/app/_locales/pt/messages.json +++ b/app/_locales/pt/messages.json @@ -207,23 +207,6 @@ "addCustomNetwork": { "message": "Adicionar rede personalizada" }, - "addEthereumChainConfirmationDescription": { - "message": "Isso permitirá que essa rede seja usada dentro da MetaMask." - }, - "addEthereumChainConfirmationRisks": { - "message": "A MetaMask não verifica redes personalizadas." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "Saiba mais sobre $1.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "golpes e riscos de segurança nas redes", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "Permitir que este site adicione uma rede?" - }, "addEthereumChainWarningModalHeader": { "message": "Adicione esse provedor de RPC apenas se tiver certeza de que é confiável. $1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4858,9 +4841,6 @@ "message": "Contate os criadores de $1 para receber mais suporte.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "Algumas redes podem representar riscos de segurança e/ou privacidade. Tenha os riscos em mente antes de adicionar e usar uma rede." - }, "somethingDoesntLookRight": { "message": "Alguma coisa não parece certa? $1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6007,9 +5987,6 @@ "viewActivity": { "message": "Ver atividade" }, - "viewAllDetails": { - "message": "Ver todos os detalhes" - }, "viewAllQuotes": { "message": "ver todas as cotações" }, diff --git a/app/_locales/pt_BR/messages.json b/app/_locales/pt_BR/messages.json index 6062013d6d6f..58d7f6ea8718 100644 --- a/app/_locales/pt_BR/messages.json +++ b/app/_locales/pt_BR/messages.json @@ -100,23 +100,6 @@ "addContact": { "message": "Adicionar contato" }, - "addEthereumChainConfirmationDescription": { - "message": "Isso permitirá que essa rede seja usada dentro da MetaMask." - }, - "addEthereumChainConfirmationRisks": { - "message": "A MetaMask não verifica redes personalizadas." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "Saiba mais sobre $1.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "fraudes e riscos de segurança da rede", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "Permitir que esse site adicione uma rede?" - }, "addFriendsAndAddresses": { "message": "Adicionar amigos e endereços confiáveis" }, @@ -2335,9 +2318,6 @@ "userName": { "message": "Nome de usuário" }, - "viewAllDetails": { - "message": "Ver todos os detalhes" - }, "viewContact": { "message": "Ver contato" }, diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index 0c2f92821ed2..d32a603b367b 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -207,23 +207,6 @@ "addCustomNetwork": { "message": "Добавить пользовательскую сеть" }, - "addEthereumChainConfirmationDescription": { - "message": "Это позволит использовать эту сеть в MetaMask." - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMask не проверяет пользовательские сети." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "Подробнее о $1.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "мошенничестве и угрозах безопасности в сети", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "Разрешить этому сайту добавить сеть?" - }, "addEthereumChainWarningModalHeader": { "message": "Добавляйте этого поставщика RPC только в том случае, если уверены, что ему можно доверять. $1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4858,9 +4841,6 @@ "message": "Свяжитесь с авторами $1 для получения дополнительной поддержки.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "Некоторые сети могут представлять угрозу безопасности и/или конфиденциальности. Прежде чем добавлять и использовать сеть, ознакомьтесь с рисками." - }, "somethingDoesntLookRight": { "message": "Что-то не так? $1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6007,9 +5987,6 @@ "viewActivity": { "message": "Смотреть активность" }, - "viewAllDetails": { - "message": "Смотреть все сведения" - }, "viewAllQuotes": { "message": "смотреть все котировки" }, diff --git a/app/_locales/tl/messages.json b/app/_locales/tl/messages.json index 61d8ff6e5d8c..0c3675d78754 100644 --- a/app/_locales/tl/messages.json +++ b/app/_locales/tl/messages.json @@ -207,23 +207,6 @@ "addCustomNetwork": { "message": "Magdagdag ng custom na network" }, - "addEthereumChainConfirmationDescription": { - "message": "Magpapahintulot ito sa network na ito na gamitin sa loob ng MetaMask." - }, - "addEthereumChainConfirmationRisks": { - "message": "Ang MetaMask ay hindi nagve-verify ng mga custom na network." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "Alamin ang tungkol sa $1.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "mga panloloko at panganib ng seguridad ng network", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "Payagan ang site na ito na magdagdag ng network?" - }, "addEthereumChainWarningModalHeader": { "message": "Idagdag lamang ang RPC provider na ito kung sigurado kang mapagkakatiwalaan ito. $1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4858,9 +4841,6 @@ "message": "Makipag-ugnayan sa mga tagalikha ng $1 para sa karagdagang suporta.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "Maaaring magdulot ang ilang network ng mga panganib sa seguridad at/o pagkapribado. Unawain ang mga panganib bago idagdag o gamitin ang isang network." - }, "somethingDoesntLookRight": { "message": "Mayroon bang hindi tama? $1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6007,9 +5987,6 @@ "viewActivity": { "message": "Tingnan ang aktibidad" }, - "viewAllDetails": { - "message": "Tingnan ang lahat ng detalye" - }, "viewAllQuotes": { "message": "tingnan ang lahat ng quote" }, diff --git a/app/_locales/tr/messages.json b/app/_locales/tr/messages.json index d80d6564b880..253e00845388 100644 --- a/app/_locales/tr/messages.json +++ b/app/_locales/tr/messages.json @@ -207,23 +207,6 @@ "addCustomNetwork": { "message": "Özel ağ ekle" }, - "addEthereumChainConfirmationDescription": { - "message": "Bu, bu ağın MetaMas dahilinde kullanılmasına olanak tanıyacaktır." - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMask özel ağları doğrulamaz." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "$1 hakkında bilgi edinin.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "dolandırıcılık ve ağ güvenliği riskleri", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "Bu sitenin ağ eklemesine izin ver?" - }, "addEthereumChainWarningModalHeader": { "message": "Bu RPC sağlayıcısını sadece ona güvenebileceğinizden eminseniz ekleyin. $1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4858,9 +4841,6 @@ "message": "Daha fazla destek için $1 oluşturucuları ile iletişime geçin.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "Bazı ağlar güvenlik ve/veya gizlilik riskleri teşkil edebilir. Bir ağ eklemeden ve kullanmadan önce riskleri anlayın." - }, "somethingDoesntLookRight": { "message": "Doğru görünmeyen bir şeyler mi var? $1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6007,9 +5987,6 @@ "viewActivity": { "message": "Aktiviteyi görüntüle" }, - "viewAllDetails": { - "message": "Tüm bilgileri görüntüle" - }, "viewAllQuotes": { "message": "tüm teklifleri görüntüle" }, diff --git a/app/_locales/vi/messages.json b/app/_locales/vi/messages.json index 0bac5423d1ee..538108c0677d 100644 --- a/app/_locales/vi/messages.json +++ b/app/_locales/vi/messages.json @@ -207,23 +207,6 @@ "addCustomNetwork": { "message": "Thêm mạng tùy chỉnh" }, - "addEthereumChainConfirmationDescription": { - "message": "Thao tác này sẽ cho phép sử dụng mạng này trong MetaMask." - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMask không xác minh mạng tùy chỉnh." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "Tìm hiểu về $1.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "lừa đảo và các nguy cơ về an ninh mạng", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "Cho phép trang này thêm một mạng?" - }, "addEthereumChainWarningModalHeader": { "message": "Chỉ thêm nhà cung cấp RPC này nếu bạn chắc chắn bạn có thể tin tưởng. $1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4858,9 +4841,6 @@ "message": "Liên hệ với những người tạo ra $1 để được hỗ trợ thêm.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "Một số mạng có thể gây ra rủi ro về bảo mật và/hoặc quyền riêng tư. Bạn cần hiểu rõ các rủi ro này trước khi thêm và sử dụng mạng." - }, "somethingDoesntLookRight": { "message": "Có gì đó không ổn? $1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6007,9 +5987,6 @@ "viewActivity": { "message": "Xem hoạt động" }, - "viewAllDetails": { - "message": "Xem toàn bộ chi tiết" - }, "viewAllQuotes": { "message": "xem tất cả báo giá" }, diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index 7209fb1c5b44..d3a4af11220a 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -207,23 +207,6 @@ "addCustomNetwork": { "message": "添加自定义网络" }, - "addEthereumChainConfirmationDescription": { - "message": "这将允许在 MetaMask 中使用此网络。" - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMask 不验证自定义网络。" - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "了解 $1。", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "欺诈和网络安全风险", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "允许此网站添加一个网络到MetaMask上?" - }, "addEthereumChainWarningModalHeader": { "message": "仅当您确定可以信任此 RPC 提供商时才能添加它。$1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4858,9 +4841,6 @@ "message": "联系 $1 的创建者以获得进一步支持。", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "某些网络可能会带来安全和/或隐私风险。在添加和使用网络之前,请先了解风险。" - }, "somethingDoesntLookRight": { "message": "有什么不对劲吗?$1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6007,9 +5987,6 @@ "viewActivity": { "message": "查看活动" }, - "viewAllDetails": { - "message": "查看所有详情" - }, "viewAllQuotes": { "message": "查看所有报价" }, diff --git a/app/_locales/zh_TW/messages.json b/app/_locales/zh_TW/messages.json index 7cdfa8e28add..7a7fdb68cf1f 100644 --- a/app/_locales/zh_TW/messages.json +++ b/app/_locales/zh_TW/messages.json @@ -42,23 +42,6 @@ "addContact": { "message": "新增合約" }, - "addEthereumChainConfirmationDescription": { - "message": "這會允許在 MetaMask 內使用這個網路。" - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMask 不會對自訂的網路做驗證。" - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "了解更多關於$1的事。", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "詐騙與網路安全風險", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "允許這個網站新增一個網路?" - }, "addFriendsAndAddresses": { "message": "新增朋友和您信任的位址" }, @@ -1370,9 +1353,6 @@ "userName": { "message": "使用者名稱" }, - "viewAllDetails": { - "message": "查看所有詳情" - }, "viewContact": { "message": "觀看聯絡資訊" }, diff --git a/app/images/ape-token.svg b/app/images/ape-token.svg new file mode 100644 index 000000000000..8c1777f1a497 --- /dev/null +++ b/app/images/ape-token.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/scripts/background.js b/app/scripts/background.js index 9f203b35661d..a5759c91a610 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -298,6 +298,9 @@ function maybeDetectPhishing(theController) { category: MetaMetricsEventCategory.Phishing, properties: { url: hostname, + referrer: { + url: hostname, + }, reason: blockReason, }, }); diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index c33485f665b7..24ae9c0b63e7 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -6675,12 +6675,34 @@ export default class MetamaskController extends EventEmitter { * @param {string} origin - the domain to safelist */ safelistPhishingDomain(origin) { + this.metaMetricsController.trackEvent({ + category: MetaMetricsEventCategory.Phishing, + event: MetaMetricsEventName.ProceedAnywayClicked, + properties: { + url: origin, + referrer: { + url: origin, + }, + }, + }); + return this.phishingController.bypass(origin); } async backToSafetyPhishingWarning() { - const extensionURL = this.platform.getExtensionURL(); - await this.platform.switchToAnotherURL(undefined, extensionURL); + const portfolioBaseURL = process.env.PORTFOLIO_URL; + const portfolioURL = `${portfolioBaseURL}/?metamaskEntry=phishing_page_portfolio_button`; + + this.metaMetricsController.trackEvent({ + category: MetaMetricsEventCategory.Navigation, + event: MetaMetricsEventName.PortfolioLinkClicked, + properties: { + location: 'phishing_page', + text: 'Back to safety', + }, + }); + + await this.platform.switchToAnotherURL(undefined, portfolioURL); } /** diff --git a/app/scripts/ui.js b/app/scripts/ui.js index 4f06fb8998c4..794037e12761 100644 --- a/app/scripts/ui.js +++ b/app/scripts/ui.js @@ -104,7 +104,7 @@ async function start() { if (isManifestV3 && isUIInitialised) { // Currently when service worker is revived we create new streams // in later version we might try to improve it by reviving same streams. - updateUiStreams(); + updateUiStreams(connectionStream); } else { await initializeUiWithTab( activeTab, diff --git a/jest.config.js b/jest.config.js index f1d38ab4aea3..56a75bfc68ed 100644 --- a/jest.config.js +++ b/jest.config.js @@ -35,6 +35,7 @@ module.exports = { '/development/**/*.test.(js|ts|tsx)', '/test/unit-global/**/*.test.(js|ts|tsx)', '/test/e2e/helpers.test.js', + '/test/e2e/helpers/**/*.test.(js|ts|tsx)', ], testPathIgnorePatterns: ['/development/webpack/'], testTimeout: 5500, diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 9cbdda6ac03e..d5c71923eebf 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -150,7 +150,7 @@ "console.warn": true }, "packages": { - "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/util>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, "@ethereumjs/tx>ethereum-cryptography": true, "browserify>buffer": true, @@ -158,6 +158,11 @@ "webpack>events": true } }, + "@ethereumjs/tx>@ethereumjs/util>@ethereumjs/rlp": { + "globals": { + "TextEncoder": true + } + }, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": { "globals": { "Headers": true, @@ -182,16 +187,28 @@ "crypto": true }, "packages": { + "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true, "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": true, - "@metamask/message-signing-snap>@noble/curves": true, - "@noble/hashes": true + "@metamask/message-signing-snap>@noble/curves": true + } + }, + "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": { "packages": { + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": true, "@metamask/message-signing-snap>@noble/curves": true, - "@metamask/utils>@scure/base": true, - "@noble/hashes": true + "@metamask/utils>@scure/base": true + } + }, + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "@ethersproject/abi": { @@ -358,7 +375,7 @@ "@ethereumjs/tx": true, "@keystonehq/bc-ur-registry-eth": true, "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring": true, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": true, + "@metamask/obs-store": true, "browserify>buffer": true, "ethereumjs-util>rlp": true, "uuid": true, @@ -381,54 +398,6 @@ "TextEncoder": true } }, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": { - "packages": { - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>@metamask/safe-event-emitter": true, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2": true, - "stream-browserify": true - } - }, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>@metamask/safe-event-emitter": { - "globals": { - "setTimeout": true - }, - "packages": { - "webpack>events": true - } - }, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2": { - "packages": { - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream": true, - "browserify>util": true, - "process": true, - "watchify>xtend": true - } - }, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream": { - "packages": { - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>isarray": true, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": true, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>string_decoder": true, - "browserify>browser-resolve": true, - "browserify>timers-browserify": true, - "process": true, - "pumpify>inherits": true, - "readable-stream-2>core-util-is": true, - "readable-stream-2>process-nextick-args": true, - "readable-stream>util-deprecate": true, - "webpack>events": true - } - }, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": { - "packages": { - "browserify>buffer": true - } - }, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>string_decoder": { - "packages": { - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": true - } - }, "@lavamoat/lavadome-react": { "globals": { "Document.prototype": true, @@ -848,70 +817,13 @@ "console.error": true }, "packages": { - "@metamask/eth-json-rpc-filters>@metamask/eth-query": true, - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine": true, - "@metamask/eth-json-rpc-filters>async-mutex": true, + "@metamask/eth-query": true, + "@metamask/json-rpc-engine": true, + "@metamask/name-controller>async-mutex": true, "@metamask/safe-event-emitter": true, "pify": true } }, - "@metamask/eth-json-rpc-filters>@metamask/eth-query": { - "packages": { - "@metamask/eth-query>json-rpc-random-id": true, - "watchify>xtend": true - } - }, - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine": { - "packages": { - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine>@metamask/rpc-errors": true, - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine>@metamask/utils": true, - "@metamask/safe-event-emitter": true - } - }, - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine>@metamask/rpc-errors": { - "packages": { - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine>@metamask/rpc-errors>@metamask/utils": true, - "@metamask/rpc-errors>fast-safe-stringify": true - } - }, - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine>@metamask/rpc-errors>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/utils>@metamask/superstruct": true, - "@metamask/utils>@scure/base": true, - "@metamask/utils>pony-cause": true, - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true - } - }, - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/utils>@metamask/superstruct": true, - "@metamask/utils>@scure/base": true, - "@metamask/utils>pony-cause": true, - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true - } - }, - "@metamask/eth-json-rpc-filters>async-mutex": { - "globals": { - "setTimeout": true - }, - "packages": { - "@swc/helpers>tslib": true - } - }, "@metamask/eth-json-rpc-middleware": { "globals": { "URL": true, @@ -951,14 +863,19 @@ }, "packages": { "@ethereumjs/tx": true, - "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, "@metamask/eth-sig-util": true, "@metamask/eth-trezor-keyring>hdkey": true, "browserify>buffer": true, "webpack>events": true } }, + "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": { + "globals": { + "TextEncoder": true + } + }, "@metamask/eth-query": { "packages": { "@metamask/eth-query>json-rpc-random-id": true, @@ -1498,7 +1415,13 @@ "TextEncoder": true }, "packages": { - "@noble/hashes": true + "@metamask/message-signing-snap>@noble/curves>@noble/hashes": true + } + }, + "@metamask/message-signing-snap>@noble/curves>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "@metamask/name-controller": { @@ -1780,6 +1703,7 @@ "@metamask/notification-services-controller>@contentful/rich-text-html-renderer": true, "@metamask/notification-services-controller>firebase": true, "@metamask/profile-sync-controller": true, + "@metamask/utils": true, "bignumber.js": true, "loglevel": true, "uuid": true @@ -2414,8 +2338,8 @@ "packages": { "@ethereumjs/tx>ethereum-cryptography": true, "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/common": true, - "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/rlp": true, - "@metamask/smart-transactions-controller>@ethereumjs/util": true + "@metamask/smart-transactions-controller>@ethereumjs/util": true, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/rlp": true } }, "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/common": { @@ -2424,11 +2348,6 @@ "webpack>events": true } }, - "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/rlp": { - "globals": { - "TextEncoder": true - } - }, "@metamask/smart-transactions-controller>@ethereumjs/util": { "globals": { "console.warn": true, @@ -2436,15 +2355,10 @@ }, "packages": { "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/smart-transactions-controller>@ethereumjs/util>@ethereumjs/rlp": true, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/rlp": true, "webpack>events": true } }, - "@metamask/smart-transactions-controller>@ethereumjs/util>@ethereumjs/rlp": { - "globals": { - "TextEncoder": true - } - }, "@metamask/smart-transactions-controller>@metamask/base-controller": { "globals": { "setTimeout": true @@ -2494,21 +2408,26 @@ "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/tx": { "packages": { "@ethereumjs/tx>@ethereumjs/common": true, - "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/tx>@ethereumjs/rlp": true, "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/util": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true } }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/tx>@ethereumjs/rlp": { + "globals": { + "TextEncoder": true + } + }, "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/util": { "globals": { "console.warn": true }, "packages": { - "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/tx>@ethereumjs/rlp": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, "webpack>events": true @@ -4073,59 +3992,16 @@ "setInterval": true }, "packages": { + "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/util": true, "bn.js": true, "browserify>buffer": true, "crypto-browserify": true, - "eth-lattice-keyring>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk": true, "eth-lattice-keyring>rlp": true, "webpack>events": true } }, - "eth-lattice-keyring>@ethereumjs/tx": { - "packages": { - "@ethereumjs/tx>@ethereumjs/common": true, - "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "@ethersproject/providers": true, - "browserify>buffer": true, - "browserify>insert-module-globals>is-buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": { - "packages": { - "browserify": true, - "browserify>buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>case": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": { - "globals": { - "WeakRef": true - }, - "packages": { - "browserify": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "eth-lattice-keyring>gridplus-sdk": { "globals": { "AbortController": true, @@ -4143,67 +4019,59 @@ "packages": { "@ethereumjs/tx>@ethereumjs/common>crc-32": true, "@ethersproject/abi": true, + "@metamask/eth-sig-util": true, "@metamask/ethjs>js-sha3": true, "@metamask/keyring-api>bech32": true, + "@metamask/ppom-validator>elliptic": true, "bn.js": true, "browserify>buffer": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": true, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/rlp": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk>aes-js": true, "eth-lattice-keyring>gridplus-sdk>bignumber.js": true, - "eth-lattice-keyring>gridplus-sdk>bitwise": true, "eth-lattice-keyring>gridplus-sdk>borc": true, - "eth-lattice-keyring>gridplus-sdk>elliptic": true, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": true, - "eth-lattice-keyring>gridplus-sdk>rlp": true, + "eth-lattice-keyring>gridplus-sdk>bs58check": true, "eth-lattice-keyring>gridplus-sdk>secp256k1": true, "eth-lattice-keyring>gridplus-sdk>uuid": true, - "ethereumjs-util>ethereum-cryptography>bs58check": true, "ethers>@ethersproject/sha2>hash.js": true, "lodash": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": { "packages": { - "@ethereumjs/tx>@ethereumjs/common>crc-32": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "browserify>buffer": true, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": true, "webpack>events": true } }, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/rlp": { + "globals": { + "TextEncoder": true + } + }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": { "packages": { - "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "@ethersproject/providers": true, - "browserify>buffer": true, - "browserify>insert-module-globals>is-buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/rlp": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": true + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": { "packages": { - "@ethereumjs/tx>@ethereumjs/common>crc-32": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "browserify>buffer": true, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": true, "webpack>events": true } }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": { + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": { "globals": { - "TextDecoder": true, - "crypto": true + "console.warn": true, + "fetch": true }, "packages": { - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true - } - }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true + "@ethereumjs/tx>ethereum-cryptography": true, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/rlp": true, + "webpack>events": true } }, "eth-lattice-keyring>gridplus-sdk>aes-js": { @@ -4217,11 +4085,6 @@ "define": true } }, - "eth-lattice-keyring>gridplus-sdk>bitwise": { - "packages": { - "browserify>buffer": true - } - }, "eth-lattice-keyring>gridplus-sdk>borc": { "globals": { "console": true @@ -4243,49 +4106,24 @@ "globals": { "URL": true, "URLSearchParams": true, - "location": true + "location": true, + "navigator": true } }, - "eth-lattice-keyring>gridplus-sdk>elliptic": { + "eth-lattice-keyring>gridplus-sdk>bs58check": { "packages": { - "@metamask/ppom-validator>elliptic>brorand": true, - "@metamask/ppom-validator>elliptic>hmac-drbg": true, - "@metamask/ppom-validator>elliptic>minimalistic-assert": true, - "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, - "bn.js": true, - "ethers>@ethersproject/sha2>hash.js": true, - "pumpify>inherits": true + "@noble/hashes": true, + "eth-lattice-keyring>gridplus-sdk>bs58check>bs58": true } }, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": { - "globals": { - "intToBuffer": true - }, + "eth-lattice-keyring>gridplus-sdk>bs58check>bs58": { "packages": { - "@metamask/ethjs>js-sha3": true, - "bn.js": true, - "buffer": true - } - }, - "eth-lattice-keyring>gridplus-sdk>rlp": { - "globals": { - "TextEncoder": true + "eth-lattice-keyring>gridplus-sdk>bs58check>bs58>base-x": true } }, "eth-lattice-keyring>gridplus-sdk>secp256k1": { "packages": { - "eth-lattice-keyring>gridplus-sdk>secp256k1>elliptic": true - } - }, - "eth-lattice-keyring>gridplus-sdk>secp256k1>elliptic": { - "packages": { - "@metamask/ppom-validator>elliptic>brorand": true, - "@metamask/ppom-validator>elliptic>hmac-drbg": true, - "@metamask/ppom-validator>elliptic>minimalistic-assert": true, - "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, - "bn.js": true, - "ethers>@ethersproject/sha2>hash.js": true, - "pumpify>inherits": true + "@metamask/ppom-validator>elliptic": true } }, "eth-lattice-keyring>gridplus-sdk>uuid": { @@ -4609,20 +4447,9 @@ "ethers>@ethersproject/signing-key": { "packages": { "@ethersproject/bytes": true, + "@metamask/ppom-validator>elliptic": true, "ethers>@ethersproject/logger": true, - "ethers>@ethersproject/properties": true, - "ethers>@ethersproject/signing-key>elliptic": true - } - }, - "ethers>@ethersproject/signing-key>elliptic": { - "packages": { - "@metamask/ppom-validator>elliptic>brorand": true, - "@metamask/ppom-validator>elliptic>hmac-drbg": true, - "@metamask/ppom-validator>elliptic>minimalistic-assert": true, - "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, - "bn.js": true, - "ethers>@ethersproject/sha2>hash.js": true, - "pumpify>inherits": true + "ethers>@ethersproject/properties": true } }, "ethers>@ethersproject/solidity": { @@ -5508,16 +5335,6 @@ "webpack>events": true } }, - "readable-stream-2>core-util-is": { - "packages": { - "browserify>insert-module-globals>is-buffer": true - } - }, - "readable-stream-2>process-nextick-args": { - "packages": { - "process": true - } - }, "readable-stream>util-deprecate": { "globals": { "console.trace": true, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index 9cbdda6ac03e..d5c71923eebf 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -150,7 +150,7 @@ "console.warn": true }, "packages": { - "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/util>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, "@ethereumjs/tx>ethereum-cryptography": true, "browserify>buffer": true, @@ -158,6 +158,11 @@ "webpack>events": true } }, + "@ethereumjs/tx>@ethereumjs/util>@ethereumjs/rlp": { + "globals": { + "TextEncoder": true + } + }, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": { "globals": { "Headers": true, @@ -182,16 +187,28 @@ "crypto": true }, "packages": { + "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true, "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": true, - "@metamask/message-signing-snap>@noble/curves": true, - "@noble/hashes": true + "@metamask/message-signing-snap>@noble/curves": true + } + }, + "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": { "packages": { + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": true, "@metamask/message-signing-snap>@noble/curves": true, - "@metamask/utils>@scure/base": true, - "@noble/hashes": true + "@metamask/utils>@scure/base": true + } + }, + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "@ethersproject/abi": { @@ -358,7 +375,7 @@ "@ethereumjs/tx": true, "@keystonehq/bc-ur-registry-eth": true, "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring": true, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": true, + "@metamask/obs-store": true, "browserify>buffer": true, "ethereumjs-util>rlp": true, "uuid": true, @@ -381,54 +398,6 @@ "TextEncoder": true } }, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": { - "packages": { - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>@metamask/safe-event-emitter": true, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2": true, - "stream-browserify": true - } - }, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>@metamask/safe-event-emitter": { - "globals": { - "setTimeout": true - }, - "packages": { - "webpack>events": true - } - }, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2": { - "packages": { - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream": true, - "browserify>util": true, - "process": true, - "watchify>xtend": true - } - }, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream": { - "packages": { - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>isarray": true, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": true, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>string_decoder": true, - "browserify>browser-resolve": true, - "browserify>timers-browserify": true, - "process": true, - "pumpify>inherits": true, - "readable-stream-2>core-util-is": true, - "readable-stream-2>process-nextick-args": true, - "readable-stream>util-deprecate": true, - "webpack>events": true - } - }, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": { - "packages": { - "browserify>buffer": true - } - }, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>string_decoder": { - "packages": { - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": true - } - }, "@lavamoat/lavadome-react": { "globals": { "Document.prototype": true, @@ -848,70 +817,13 @@ "console.error": true }, "packages": { - "@metamask/eth-json-rpc-filters>@metamask/eth-query": true, - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine": true, - "@metamask/eth-json-rpc-filters>async-mutex": true, + "@metamask/eth-query": true, + "@metamask/json-rpc-engine": true, + "@metamask/name-controller>async-mutex": true, "@metamask/safe-event-emitter": true, "pify": true } }, - "@metamask/eth-json-rpc-filters>@metamask/eth-query": { - "packages": { - "@metamask/eth-query>json-rpc-random-id": true, - "watchify>xtend": true - } - }, - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine": { - "packages": { - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine>@metamask/rpc-errors": true, - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine>@metamask/utils": true, - "@metamask/safe-event-emitter": true - } - }, - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine>@metamask/rpc-errors": { - "packages": { - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine>@metamask/rpc-errors>@metamask/utils": true, - "@metamask/rpc-errors>fast-safe-stringify": true - } - }, - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine>@metamask/rpc-errors>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/utils>@metamask/superstruct": true, - "@metamask/utils>@scure/base": true, - "@metamask/utils>pony-cause": true, - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true - } - }, - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/utils>@metamask/superstruct": true, - "@metamask/utils>@scure/base": true, - "@metamask/utils>pony-cause": true, - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true - } - }, - "@metamask/eth-json-rpc-filters>async-mutex": { - "globals": { - "setTimeout": true - }, - "packages": { - "@swc/helpers>tslib": true - } - }, "@metamask/eth-json-rpc-middleware": { "globals": { "URL": true, @@ -951,14 +863,19 @@ }, "packages": { "@ethereumjs/tx": true, - "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, "@metamask/eth-sig-util": true, "@metamask/eth-trezor-keyring>hdkey": true, "browserify>buffer": true, "webpack>events": true } }, + "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": { + "globals": { + "TextEncoder": true + } + }, "@metamask/eth-query": { "packages": { "@metamask/eth-query>json-rpc-random-id": true, @@ -1498,7 +1415,13 @@ "TextEncoder": true }, "packages": { - "@noble/hashes": true + "@metamask/message-signing-snap>@noble/curves>@noble/hashes": true + } + }, + "@metamask/message-signing-snap>@noble/curves>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "@metamask/name-controller": { @@ -1780,6 +1703,7 @@ "@metamask/notification-services-controller>@contentful/rich-text-html-renderer": true, "@metamask/notification-services-controller>firebase": true, "@metamask/profile-sync-controller": true, + "@metamask/utils": true, "bignumber.js": true, "loglevel": true, "uuid": true @@ -2414,8 +2338,8 @@ "packages": { "@ethereumjs/tx>ethereum-cryptography": true, "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/common": true, - "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/rlp": true, - "@metamask/smart-transactions-controller>@ethereumjs/util": true + "@metamask/smart-transactions-controller>@ethereumjs/util": true, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/rlp": true } }, "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/common": { @@ -2424,11 +2348,6 @@ "webpack>events": true } }, - "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/rlp": { - "globals": { - "TextEncoder": true - } - }, "@metamask/smart-transactions-controller>@ethereumjs/util": { "globals": { "console.warn": true, @@ -2436,15 +2355,10 @@ }, "packages": { "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/smart-transactions-controller>@ethereumjs/util>@ethereumjs/rlp": true, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/rlp": true, "webpack>events": true } }, - "@metamask/smart-transactions-controller>@ethereumjs/util>@ethereumjs/rlp": { - "globals": { - "TextEncoder": true - } - }, "@metamask/smart-transactions-controller>@metamask/base-controller": { "globals": { "setTimeout": true @@ -2494,21 +2408,26 @@ "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/tx": { "packages": { "@ethereumjs/tx>@ethereumjs/common": true, - "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/tx>@ethereumjs/rlp": true, "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/util": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true } }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/tx>@ethereumjs/rlp": { + "globals": { + "TextEncoder": true + } + }, "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/util": { "globals": { "console.warn": true }, "packages": { - "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/tx>@ethereumjs/rlp": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, "webpack>events": true @@ -4073,59 +3992,16 @@ "setInterval": true }, "packages": { + "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/util": true, "bn.js": true, "browserify>buffer": true, "crypto-browserify": true, - "eth-lattice-keyring>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk": true, "eth-lattice-keyring>rlp": true, "webpack>events": true } }, - "eth-lattice-keyring>@ethereumjs/tx": { - "packages": { - "@ethereumjs/tx>@ethereumjs/common": true, - "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "@ethersproject/providers": true, - "browserify>buffer": true, - "browserify>insert-module-globals>is-buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": { - "packages": { - "browserify": true, - "browserify>buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>case": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": { - "globals": { - "WeakRef": true - }, - "packages": { - "browserify": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "eth-lattice-keyring>gridplus-sdk": { "globals": { "AbortController": true, @@ -4143,67 +4019,59 @@ "packages": { "@ethereumjs/tx>@ethereumjs/common>crc-32": true, "@ethersproject/abi": true, + "@metamask/eth-sig-util": true, "@metamask/ethjs>js-sha3": true, "@metamask/keyring-api>bech32": true, + "@metamask/ppom-validator>elliptic": true, "bn.js": true, "browserify>buffer": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": true, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/rlp": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk>aes-js": true, "eth-lattice-keyring>gridplus-sdk>bignumber.js": true, - "eth-lattice-keyring>gridplus-sdk>bitwise": true, "eth-lattice-keyring>gridplus-sdk>borc": true, - "eth-lattice-keyring>gridplus-sdk>elliptic": true, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": true, - "eth-lattice-keyring>gridplus-sdk>rlp": true, + "eth-lattice-keyring>gridplus-sdk>bs58check": true, "eth-lattice-keyring>gridplus-sdk>secp256k1": true, "eth-lattice-keyring>gridplus-sdk>uuid": true, - "ethereumjs-util>ethereum-cryptography>bs58check": true, "ethers>@ethersproject/sha2>hash.js": true, "lodash": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": { "packages": { - "@ethereumjs/tx>@ethereumjs/common>crc-32": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "browserify>buffer": true, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": true, "webpack>events": true } }, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/rlp": { + "globals": { + "TextEncoder": true + } + }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": { "packages": { - "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "@ethersproject/providers": true, - "browserify>buffer": true, - "browserify>insert-module-globals>is-buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/rlp": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": true + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": { "packages": { - "@ethereumjs/tx>@ethereumjs/common>crc-32": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "browserify>buffer": true, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": true, "webpack>events": true } }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": { + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": { "globals": { - "TextDecoder": true, - "crypto": true + "console.warn": true, + "fetch": true }, "packages": { - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true - } - }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true + "@ethereumjs/tx>ethereum-cryptography": true, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/rlp": true, + "webpack>events": true } }, "eth-lattice-keyring>gridplus-sdk>aes-js": { @@ -4217,11 +4085,6 @@ "define": true } }, - "eth-lattice-keyring>gridplus-sdk>bitwise": { - "packages": { - "browserify>buffer": true - } - }, "eth-lattice-keyring>gridplus-sdk>borc": { "globals": { "console": true @@ -4243,49 +4106,24 @@ "globals": { "URL": true, "URLSearchParams": true, - "location": true + "location": true, + "navigator": true } }, - "eth-lattice-keyring>gridplus-sdk>elliptic": { + "eth-lattice-keyring>gridplus-sdk>bs58check": { "packages": { - "@metamask/ppom-validator>elliptic>brorand": true, - "@metamask/ppom-validator>elliptic>hmac-drbg": true, - "@metamask/ppom-validator>elliptic>minimalistic-assert": true, - "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, - "bn.js": true, - "ethers>@ethersproject/sha2>hash.js": true, - "pumpify>inherits": true + "@noble/hashes": true, + "eth-lattice-keyring>gridplus-sdk>bs58check>bs58": true } }, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": { - "globals": { - "intToBuffer": true - }, + "eth-lattice-keyring>gridplus-sdk>bs58check>bs58": { "packages": { - "@metamask/ethjs>js-sha3": true, - "bn.js": true, - "buffer": true - } - }, - "eth-lattice-keyring>gridplus-sdk>rlp": { - "globals": { - "TextEncoder": true + "eth-lattice-keyring>gridplus-sdk>bs58check>bs58>base-x": true } }, "eth-lattice-keyring>gridplus-sdk>secp256k1": { "packages": { - "eth-lattice-keyring>gridplus-sdk>secp256k1>elliptic": true - } - }, - "eth-lattice-keyring>gridplus-sdk>secp256k1>elliptic": { - "packages": { - "@metamask/ppom-validator>elliptic>brorand": true, - "@metamask/ppom-validator>elliptic>hmac-drbg": true, - "@metamask/ppom-validator>elliptic>minimalistic-assert": true, - "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, - "bn.js": true, - "ethers>@ethersproject/sha2>hash.js": true, - "pumpify>inherits": true + "@metamask/ppom-validator>elliptic": true } }, "eth-lattice-keyring>gridplus-sdk>uuid": { @@ -4609,20 +4447,9 @@ "ethers>@ethersproject/signing-key": { "packages": { "@ethersproject/bytes": true, + "@metamask/ppom-validator>elliptic": true, "ethers>@ethersproject/logger": true, - "ethers>@ethersproject/properties": true, - "ethers>@ethersproject/signing-key>elliptic": true - } - }, - "ethers>@ethersproject/signing-key>elliptic": { - "packages": { - "@metamask/ppom-validator>elliptic>brorand": true, - "@metamask/ppom-validator>elliptic>hmac-drbg": true, - "@metamask/ppom-validator>elliptic>minimalistic-assert": true, - "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, - "bn.js": true, - "ethers>@ethersproject/sha2>hash.js": true, - "pumpify>inherits": true + "ethers>@ethersproject/properties": true } }, "ethers>@ethersproject/solidity": { @@ -5508,16 +5335,6 @@ "webpack>events": true } }, - "readable-stream-2>core-util-is": { - "packages": { - "browserify>insert-module-globals>is-buffer": true - } - }, - "readable-stream-2>process-nextick-args": { - "packages": { - "process": true - } - }, "readable-stream>util-deprecate": { "globals": { "console.trace": true, diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 9cbdda6ac03e..d5c71923eebf 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -150,7 +150,7 @@ "console.warn": true }, "packages": { - "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/util>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, "@ethereumjs/tx>ethereum-cryptography": true, "browserify>buffer": true, @@ -158,6 +158,11 @@ "webpack>events": true } }, + "@ethereumjs/tx>@ethereumjs/util>@ethereumjs/rlp": { + "globals": { + "TextEncoder": true + } + }, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": { "globals": { "Headers": true, @@ -182,16 +187,28 @@ "crypto": true }, "packages": { + "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true, "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": true, - "@metamask/message-signing-snap>@noble/curves": true, - "@noble/hashes": true + "@metamask/message-signing-snap>@noble/curves": true + } + }, + "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": { "packages": { + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": true, "@metamask/message-signing-snap>@noble/curves": true, - "@metamask/utils>@scure/base": true, - "@noble/hashes": true + "@metamask/utils>@scure/base": true + } + }, + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "@ethersproject/abi": { @@ -358,7 +375,7 @@ "@ethereumjs/tx": true, "@keystonehq/bc-ur-registry-eth": true, "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring": true, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": true, + "@metamask/obs-store": true, "browserify>buffer": true, "ethereumjs-util>rlp": true, "uuid": true, @@ -381,54 +398,6 @@ "TextEncoder": true } }, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": { - "packages": { - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>@metamask/safe-event-emitter": true, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2": true, - "stream-browserify": true - } - }, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>@metamask/safe-event-emitter": { - "globals": { - "setTimeout": true - }, - "packages": { - "webpack>events": true - } - }, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2": { - "packages": { - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream": true, - "browserify>util": true, - "process": true, - "watchify>xtend": true - } - }, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream": { - "packages": { - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>isarray": true, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": true, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>string_decoder": true, - "browserify>browser-resolve": true, - "browserify>timers-browserify": true, - "process": true, - "pumpify>inherits": true, - "readable-stream-2>core-util-is": true, - "readable-stream-2>process-nextick-args": true, - "readable-stream>util-deprecate": true, - "webpack>events": true - } - }, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": { - "packages": { - "browserify>buffer": true - } - }, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>string_decoder": { - "packages": { - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": true - } - }, "@lavamoat/lavadome-react": { "globals": { "Document.prototype": true, @@ -848,70 +817,13 @@ "console.error": true }, "packages": { - "@metamask/eth-json-rpc-filters>@metamask/eth-query": true, - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine": true, - "@metamask/eth-json-rpc-filters>async-mutex": true, + "@metamask/eth-query": true, + "@metamask/json-rpc-engine": true, + "@metamask/name-controller>async-mutex": true, "@metamask/safe-event-emitter": true, "pify": true } }, - "@metamask/eth-json-rpc-filters>@metamask/eth-query": { - "packages": { - "@metamask/eth-query>json-rpc-random-id": true, - "watchify>xtend": true - } - }, - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine": { - "packages": { - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine>@metamask/rpc-errors": true, - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine>@metamask/utils": true, - "@metamask/safe-event-emitter": true - } - }, - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine>@metamask/rpc-errors": { - "packages": { - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine>@metamask/rpc-errors>@metamask/utils": true, - "@metamask/rpc-errors>fast-safe-stringify": true - } - }, - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine>@metamask/rpc-errors>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/utils>@metamask/superstruct": true, - "@metamask/utils>@scure/base": true, - "@metamask/utils>pony-cause": true, - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true - } - }, - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/utils>@metamask/superstruct": true, - "@metamask/utils>@scure/base": true, - "@metamask/utils>pony-cause": true, - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true - } - }, - "@metamask/eth-json-rpc-filters>async-mutex": { - "globals": { - "setTimeout": true - }, - "packages": { - "@swc/helpers>tslib": true - } - }, "@metamask/eth-json-rpc-middleware": { "globals": { "URL": true, @@ -951,14 +863,19 @@ }, "packages": { "@ethereumjs/tx": true, - "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, "@metamask/eth-sig-util": true, "@metamask/eth-trezor-keyring>hdkey": true, "browserify>buffer": true, "webpack>events": true } }, + "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": { + "globals": { + "TextEncoder": true + } + }, "@metamask/eth-query": { "packages": { "@metamask/eth-query>json-rpc-random-id": true, @@ -1498,7 +1415,13 @@ "TextEncoder": true }, "packages": { - "@noble/hashes": true + "@metamask/message-signing-snap>@noble/curves>@noble/hashes": true + } + }, + "@metamask/message-signing-snap>@noble/curves>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "@metamask/name-controller": { @@ -1780,6 +1703,7 @@ "@metamask/notification-services-controller>@contentful/rich-text-html-renderer": true, "@metamask/notification-services-controller>firebase": true, "@metamask/profile-sync-controller": true, + "@metamask/utils": true, "bignumber.js": true, "loglevel": true, "uuid": true @@ -2414,8 +2338,8 @@ "packages": { "@ethereumjs/tx>ethereum-cryptography": true, "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/common": true, - "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/rlp": true, - "@metamask/smart-transactions-controller>@ethereumjs/util": true + "@metamask/smart-transactions-controller>@ethereumjs/util": true, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/rlp": true } }, "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/common": { @@ -2424,11 +2348,6 @@ "webpack>events": true } }, - "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/rlp": { - "globals": { - "TextEncoder": true - } - }, "@metamask/smart-transactions-controller>@ethereumjs/util": { "globals": { "console.warn": true, @@ -2436,15 +2355,10 @@ }, "packages": { "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/smart-transactions-controller>@ethereumjs/util>@ethereumjs/rlp": true, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/rlp": true, "webpack>events": true } }, - "@metamask/smart-transactions-controller>@ethereumjs/util>@ethereumjs/rlp": { - "globals": { - "TextEncoder": true - } - }, "@metamask/smart-transactions-controller>@metamask/base-controller": { "globals": { "setTimeout": true @@ -2494,21 +2408,26 @@ "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/tx": { "packages": { "@ethereumjs/tx>@ethereumjs/common": true, - "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/tx>@ethereumjs/rlp": true, "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/util": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true } }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/tx>@ethereumjs/rlp": { + "globals": { + "TextEncoder": true + } + }, "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/util": { "globals": { "console.warn": true }, "packages": { - "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/tx>@ethereumjs/rlp": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, "webpack>events": true @@ -4073,59 +3992,16 @@ "setInterval": true }, "packages": { + "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/util": true, "bn.js": true, "browserify>buffer": true, "crypto-browserify": true, - "eth-lattice-keyring>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk": true, "eth-lattice-keyring>rlp": true, "webpack>events": true } }, - "eth-lattice-keyring>@ethereumjs/tx": { - "packages": { - "@ethereumjs/tx>@ethereumjs/common": true, - "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "@ethersproject/providers": true, - "browserify>buffer": true, - "browserify>insert-module-globals>is-buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": { - "packages": { - "browserify": true, - "browserify>buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>case": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": { - "globals": { - "WeakRef": true - }, - "packages": { - "browserify": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "eth-lattice-keyring>gridplus-sdk": { "globals": { "AbortController": true, @@ -4143,67 +4019,59 @@ "packages": { "@ethereumjs/tx>@ethereumjs/common>crc-32": true, "@ethersproject/abi": true, + "@metamask/eth-sig-util": true, "@metamask/ethjs>js-sha3": true, "@metamask/keyring-api>bech32": true, + "@metamask/ppom-validator>elliptic": true, "bn.js": true, "browserify>buffer": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": true, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/rlp": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk>aes-js": true, "eth-lattice-keyring>gridplus-sdk>bignumber.js": true, - "eth-lattice-keyring>gridplus-sdk>bitwise": true, "eth-lattice-keyring>gridplus-sdk>borc": true, - "eth-lattice-keyring>gridplus-sdk>elliptic": true, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": true, - "eth-lattice-keyring>gridplus-sdk>rlp": true, + "eth-lattice-keyring>gridplus-sdk>bs58check": true, "eth-lattice-keyring>gridplus-sdk>secp256k1": true, "eth-lattice-keyring>gridplus-sdk>uuid": true, - "ethereumjs-util>ethereum-cryptography>bs58check": true, "ethers>@ethersproject/sha2>hash.js": true, "lodash": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": { "packages": { - "@ethereumjs/tx>@ethereumjs/common>crc-32": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "browserify>buffer": true, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": true, "webpack>events": true } }, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/rlp": { + "globals": { + "TextEncoder": true + } + }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": { "packages": { - "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "@ethersproject/providers": true, - "browserify>buffer": true, - "browserify>insert-module-globals>is-buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/rlp": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": true + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": { "packages": { - "@ethereumjs/tx>@ethereumjs/common>crc-32": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "browserify>buffer": true, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": true, "webpack>events": true } }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": { + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": { "globals": { - "TextDecoder": true, - "crypto": true + "console.warn": true, + "fetch": true }, "packages": { - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true - } - }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true + "@ethereumjs/tx>ethereum-cryptography": true, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/rlp": true, + "webpack>events": true } }, "eth-lattice-keyring>gridplus-sdk>aes-js": { @@ -4217,11 +4085,6 @@ "define": true } }, - "eth-lattice-keyring>gridplus-sdk>bitwise": { - "packages": { - "browserify>buffer": true - } - }, "eth-lattice-keyring>gridplus-sdk>borc": { "globals": { "console": true @@ -4243,49 +4106,24 @@ "globals": { "URL": true, "URLSearchParams": true, - "location": true + "location": true, + "navigator": true } }, - "eth-lattice-keyring>gridplus-sdk>elliptic": { + "eth-lattice-keyring>gridplus-sdk>bs58check": { "packages": { - "@metamask/ppom-validator>elliptic>brorand": true, - "@metamask/ppom-validator>elliptic>hmac-drbg": true, - "@metamask/ppom-validator>elliptic>minimalistic-assert": true, - "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, - "bn.js": true, - "ethers>@ethersproject/sha2>hash.js": true, - "pumpify>inherits": true + "@noble/hashes": true, + "eth-lattice-keyring>gridplus-sdk>bs58check>bs58": true } }, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": { - "globals": { - "intToBuffer": true - }, + "eth-lattice-keyring>gridplus-sdk>bs58check>bs58": { "packages": { - "@metamask/ethjs>js-sha3": true, - "bn.js": true, - "buffer": true - } - }, - "eth-lattice-keyring>gridplus-sdk>rlp": { - "globals": { - "TextEncoder": true + "eth-lattice-keyring>gridplus-sdk>bs58check>bs58>base-x": true } }, "eth-lattice-keyring>gridplus-sdk>secp256k1": { "packages": { - "eth-lattice-keyring>gridplus-sdk>secp256k1>elliptic": true - } - }, - "eth-lattice-keyring>gridplus-sdk>secp256k1>elliptic": { - "packages": { - "@metamask/ppom-validator>elliptic>brorand": true, - "@metamask/ppom-validator>elliptic>hmac-drbg": true, - "@metamask/ppom-validator>elliptic>minimalistic-assert": true, - "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, - "bn.js": true, - "ethers>@ethersproject/sha2>hash.js": true, - "pumpify>inherits": true + "@metamask/ppom-validator>elliptic": true } }, "eth-lattice-keyring>gridplus-sdk>uuid": { @@ -4609,20 +4447,9 @@ "ethers>@ethersproject/signing-key": { "packages": { "@ethersproject/bytes": true, + "@metamask/ppom-validator>elliptic": true, "ethers>@ethersproject/logger": true, - "ethers>@ethersproject/properties": true, - "ethers>@ethersproject/signing-key>elliptic": true - } - }, - "ethers>@ethersproject/signing-key>elliptic": { - "packages": { - "@metamask/ppom-validator>elliptic>brorand": true, - "@metamask/ppom-validator>elliptic>hmac-drbg": true, - "@metamask/ppom-validator>elliptic>minimalistic-assert": true, - "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, - "bn.js": true, - "ethers>@ethersproject/sha2>hash.js": true, - "pumpify>inherits": true + "ethers>@ethersproject/properties": true } }, "ethers>@ethersproject/solidity": { @@ -5508,16 +5335,6 @@ "webpack>events": true } }, - "readable-stream-2>core-util-is": { - "packages": { - "browserify>insert-module-globals>is-buffer": true - } - }, - "readable-stream-2>process-nextick-args": { - "packages": { - "process": true - } - }, "readable-stream>util-deprecate": { "globals": { "console.trace": true, diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index fae253f8b9d5..230d55331aae 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -150,7 +150,7 @@ "console.warn": true }, "packages": { - "@ethereumjs/tx>@ethereumjs/rlp": true, + "@ethereumjs/tx>@ethereumjs/util>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, "@ethereumjs/tx>ethereum-cryptography": true, "browserify>buffer": true, @@ -158,6 +158,11 @@ "webpack>events": true } }, + "@ethereumjs/tx>@ethereumjs/util>@ethereumjs/rlp": { + "globals": { + "TextEncoder": true + } + }, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": { "globals": { "Headers": true, @@ -182,16 +187,28 @@ "crypto": true }, "packages": { + "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true, "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": true, - "@metamask/message-signing-snap>@noble/curves": true, - "@noble/hashes": true + "@metamask/message-signing-snap>@noble/curves": true + } + }, + "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": { "packages": { + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": true, "@metamask/message-signing-snap>@noble/curves": true, - "@metamask/utils>@scure/base": true, - "@noble/hashes": true + "@metamask/utils>@scure/base": true + } + }, + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "@ethersproject/abi": { @@ -358,7 +375,7 @@ "@ethereumjs/tx": true, "@keystonehq/bc-ur-registry-eth": true, "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring": true, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": true, + "@metamask/obs-store": true, "browserify>buffer": true, "ethereumjs-util>rlp": true, "uuid": true, @@ -381,54 +398,6 @@ "TextEncoder": true } }, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store": { - "packages": { - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>@metamask/safe-event-emitter": true, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2": true, - "stream-browserify": true - } - }, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>@metamask/safe-event-emitter": { - "globals": { - "setTimeout": true - }, - "packages": { - "webpack>events": true - } - }, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2": { - "packages": { - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream": true, - "browserify>util": true, - "process": true, - "watchify>xtend": true - } - }, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream": { - "packages": { - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>isarray": true, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": true, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>string_decoder": true, - "browserify>browser-resolve": true, - "browserify>timers-browserify": true, - "process": true, - "pumpify>inherits": true, - "readable-stream-2>core-util-is": true, - "readable-stream-2>process-nextick-args": true, - "readable-stream>util-deprecate": true, - "webpack>events": true - } - }, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": { - "packages": { - "browserify>buffer": true - } - }, - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>string_decoder": { - "packages": { - "@keystonehq/metamask-airgapped-keyring>@metamask/obs-store>through2>readable-stream>safe-buffer": true - } - }, "@lavamoat/lavadome-react": { "globals": { "Document.prototype": true, @@ -940,70 +909,13 @@ "console.error": true }, "packages": { - "@metamask/eth-json-rpc-filters>@metamask/eth-query": true, - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine": true, - "@metamask/eth-json-rpc-filters>async-mutex": true, + "@metamask/eth-query": true, + "@metamask/json-rpc-engine": true, + "@metamask/name-controller>async-mutex": true, "@metamask/safe-event-emitter": true, "pify": true } }, - "@metamask/eth-json-rpc-filters>@metamask/eth-query": { - "packages": { - "@metamask/eth-query>json-rpc-random-id": true, - "watchify>xtend": true - } - }, - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine": { - "packages": { - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine>@metamask/rpc-errors": true, - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine>@metamask/utils": true, - "@metamask/safe-event-emitter": true - } - }, - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine>@metamask/rpc-errors": { - "packages": { - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine>@metamask/rpc-errors>@metamask/utils": true, - "@metamask/rpc-errors>fast-safe-stringify": true - } - }, - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine>@metamask/rpc-errors>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/utils>@metamask/superstruct": true, - "@metamask/utils>@scure/base": true, - "@metamask/utils>pony-cause": true, - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true - } - }, - "@metamask/eth-json-rpc-filters>@metamask/json-rpc-engine>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/utils>@metamask/superstruct": true, - "@metamask/utils>@scure/base": true, - "@metamask/utils>pony-cause": true, - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true - } - }, - "@metamask/eth-json-rpc-filters>async-mutex": { - "globals": { - "setTimeout": true - }, - "packages": { - "@swc/helpers>tslib": true - } - }, "@metamask/eth-json-rpc-middleware": { "globals": { "URL": true, @@ -1043,14 +955,19 @@ }, "packages": { "@ethereumjs/tx": true, - "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util": true, + "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": true, "@metamask/eth-sig-util": true, "@metamask/eth-trezor-keyring>hdkey": true, "browserify>buffer": true, "webpack>events": true } }, + "@metamask/eth-ledger-bridge-keyring>@ethereumjs/rlp": { + "globals": { + "TextEncoder": true + } + }, "@metamask/eth-query": { "packages": { "@metamask/eth-query>json-rpc-random-id": true, @@ -1590,7 +1507,13 @@ "TextEncoder": true }, "packages": { - "@noble/hashes": true + "@metamask/message-signing-snap>@noble/curves>@noble/hashes": true + } + }, + "@metamask/message-signing-snap>@noble/curves>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "@metamask/name-controller": { @@ -1872,6 +1795,7 @@ "@metamask/notification-services-controller>@contentful/rich-text-html-renderer": true, "@metamask/notification-services-controller>firebase": true, "@metamask/profile-sync-controller": true, + "@metamask/utils": true, "bignumber.js": true, "loglevel": true, "uuid": true @@ -2506,8 +2430,8 @@ "packages": { "@ethereumjs/tx>ethereum-cryptography": true, "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/common": true, - "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/rlp": true, - "@metamask/smart-transactions-controller>@ethereumjs/util": true + "@metamask/smart-transactions-controller>@ethereumjs/util": true, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/rlp": true } }, "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/common": { @@ -2516,11 +2440,6 @@ "webpack>events": true } }, - "@metamask/smart-transactions-controller>@ethereumjs/tx>@ethereumjs/rlp": { - "globals": { - "TextEncoder": true - } - }, "@metamask/smart-transactions-controller>@ethereumjs/util": { "globals": { "console.warn": true, @@ -2528,15 +2447,10 @@ }, "packages": { "@ethereumjs/tx>ethereum-cryptography": true, - "@metamask/smart-transactions-controller>@ethereumjs/util>@ethereumjs/rlp": true, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/rlp": true, "webpack>events": true } }, - "@metamask/smart-transactions-controller>@ethereumjs/util>@ethereumjs/rlp": { - "globals": { - "TextEncoder": true - } - }, "@metamask/smart-transactions-controller>@metamask/base-controller": { "globals": { "setTimeout": true @@ -2586,21 +2500,26 @@ "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/tx": { "packages": { "@ethereumjs/tx>@ethereumjs/common": true, - "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/tx>@ethereumjs/rlp": true, "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/util": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true } }, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/tx>@ethereumjs/rlp": { + "globals": { + "TextEncoder": true + } + }, "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/util": { "globals": { "console.warn": true }, "packages": { - "@ethereumjs/tx>@ethereumjs/rlp": true, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/smart-transactions-controller>@metamask/transaction-controller>@ethereumjs/tx>@ethereumjs/rlp": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, "webpack>events": true @@ -4165,59 +4084,16 @@ "setInterval": true }, "packages": { + "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/util": true, "bn.js": true, "browserify>buffer": true, "crypto-browserify": true, - "eth-lattice-keyring>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk": true, "eth-lattice-keyring>rlp": true, "webpack>events": true } }, - "eth-lattice-keyring>@ethereumjs/tx": { - "packages": { - "@ethereumjs/tx>@ethereumjs/common": true, - "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "@ethersproject/providers": true, - "browserify>buffer": true, - "browserify>insert-module-globals>is-buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": { - "packages": { - "browserify": true, - "browserify>buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>case": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": { - "globals": { - "WeakRef": true - }, - "packages": { - "browserify": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "eth-lattice-keyring>gridplus-sdk": { "globals": { "AbortController": true, @@ -4235,67 +4111,59 @@ "packages": { "@ethereumjs/tx>@ethereumjs/common>crc-32": true, "@ethersproject/abi": true, + "@metamask/eth-sig-util": true, "@metamask/ethjs>js-sha3": true, "@metamask/keyring-api>bech32": true, + "@metamask/ppom-validator>elliptic": true, "bn.js": true, "browserify>buffer": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": true, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/rlp": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk>aes-js": true, "eth-lattice-keyring>gridplus-sdk>bignumber.js": true, - "eth-lattice-keyring>gridplus-sdk>bitwise": true, "eth-lattice-keyring>gridplus-sdk>borc": true, - "eth-lattice-keyring>gridplus-sdk>elliptic": true, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": true, - "eth-lattice-keyring>gridplus-sdk>rlp": true, + "eth-lattice-keyring>gridplus-sdk>bs58check": true, "eth-lattice-keyring>gridplus-sdk>secp256k1": true, "eth-lattice-keyring>gridplus-sdk>uuid": true, - "ethereumjs-util>ethereum-cryptography>bs58check": true, "ethers>@ethersproject/sha2>hash.js": true, "lodash": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": { "packages": { - "@ethereumjs/tx>@ethereumjs/common>crc-32": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "browserify>buffer": true, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": true, "webpack>events": true } }, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/rlp": { + "globals": { + "TextEncoder": true + } + }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": { "packages": { - "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "@ethersproject/providers": true, - "browserify>buffer": true, - "browserify>insert-module-globals>is-buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/rlp": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": true + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": true } }, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": { "packages": { - "@ethereumjs/tx>@ethereumjs/common>crc-32": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "browserify>buffer": true, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": true, "webpack>events": true } }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": { + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/util": { "globals": { - "TextDecoder": true, - "crypto": true + "console.warn": true, + "fetch": true }, "packages": { - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true - } - }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true + "@ethereumjs/tx>ethereum-cryptography": true, + "eth-lattice-keyring>gridplus-sdk>@ethereumjs/rlp": true, + "webpack>events": true } }, "eth-lattice-keyring>gridplus-sdk>aes-js": { @@ -4309,11 +4177,6 @@ "define": true } }, - "eth-lattice-keyring>gridplus-sdk>bitwise": { - "packages": { - "browserify>buffer": true - } - }, "eth-lattice-keyring>gridplus-sdk>borc": { "globals": { "console": true @@ -4335,49 +4198,24 @@ "globals": { "URL": true, "URLSearchParams": true, - "location": true + "location": true, + "navigator": true } }, - "eth-lattice-keyring>gridplus-sdk>elliptic": { + "eth-lattice-keyring>gridplus-sdk>bs58check": { "packages": { - "@metamask/ppom-validator>elliptic>brorand": true, - "@metamask/ppom-validator>elliptic>hmac-drbg": true, - "@metamask/ppom-validator>elliptic>minimalistic-assert": true, - "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, - "bn.js": true, - "ethers>@ethersproject/sha2>hash.js": true, - "pumpify>inherits": true + "@noble/hashes": true, + "eth-lattice-keyring>gridplus-sdk>bs58check>bs58": true } }, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": { - "globals": { - "intToBuffer": true - }, + "eth-lattice-keyring>gridplus-sdk>bs58check>bs58": { "packages": { - "@metamask/ethjs>js-sha3": true, - "bn.js": true, - "buffer": true - } - }, - "eth-lattice-keyring>gridplus-sdk>rlp": { - "globals": { - "TextEncoder": true + "eth-lattice-keyring>gridplus-sdk>bs58check>bs58>base-x": true } }, "eth-lattice-keyring>gridplus-sdk>secp256k1": { "packages": { - "eth-lattice-keyring>gridplus-sdk>secp256k1>elliptic": true - } - }, - "eth-lattice-keyring>gridplus-sdk>secp256k1>elliptic": { - "packages": { - "@metamask/ppom-validator>elliptic>brorand": true, - "@metamask/ppom-validator>elliptic>hmac-drbg": true, - "@metamask/ppom-validator>elliptic>minimalistic-assert": true, - "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, - "bn.js": true, - "ethers>@ethersproject/sha2>hash.js": true, - "pumpify>inherits": true + "@metamask/ppom-validator>elliptic": true } }, "eth-lattice-keyring>gridplus-sdk>uuid": { @@ -4701,20 +4539,9 @@ "ethers>@ethersproject/signing-key": { "packages": { "@ethersproject/bytes": true, + "@metamask/ppom-validator>elliptic": true, "ethers>@ethersproject/logger": true, - "ethers>@ethersproject/properties": true, - "ethers>@ethersproject/signing-key>elliptic": true - } - }, - "ethers>@ethersproject/signing-key>elliptic": { - "packages": { - "@metamask/ppom-validator>elliptic>brorand": true, - "@metamask/ppom-validator>elliptic>hmac-drbg": true, - "@metamask/ppom-validator>elliptic>minimalistic-assert": true, - "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, - "bn.js": true, - "ethers>@ethersproject/sha2>hash.js": true, - "pumpify>inherits": true + "ethers>@ethersproject/properties": true } }, "ethers>@ethersproject/solidity": { @@ -5576,16 +5403,6 @@ "webpack>events": true } }, - "readable-stream-2>core-util-is": { - "packages": { - "browserify>insert-module-globals>is-buffer": true - } - }, - "readable-stream-2>process-nextick-args": { - "packages": { - "process": true - } - }, "readable-stream>util-deprecate": { "globals": { "console.trace": true, diff --git a/package.json b/package.json index 575b21bbaca8..a38592b66c44 100644 --- a/package.json +++ b/package.json @@ -132,6 +132,11 @@ }, "resolutions": { "chokidar": "^3.6.0", + "gridplus-sdk/elliptic": "^6.5.7", + "gridplus-sdk/secp256k1": "^5.0.1", + "eth-lattice-keyring/@ethereumjs/tx": "^4.2.0", + "@ethersproject/signing-key/elliptic": "^6.5.7", + "ganache/secp256k1": "^4.0.4", "simple-update-notifier@^1.0.0": "^2.0.0", "@babel/core": "patch:@babel/core@npm%3A7.23.2#~/.yarn/patches/@babel-core-npm-7.23.2-b93f586907.patch", "@types/react": "^16.9.53", @@ -281,12 +286,12 @@ "@ethersproject/wallet": "^5.7.0", "@fortawesome/fontawesome-free": "^5.13.0", "@keystonehq/bc-ur-registry-eth": "^0.19.1", - "@keystonehq/metamask-airgapped-keyring": "^0.13.1", + "@keystonehq/metamask-airgapped-keyring": "^0.14.1", "@lavamoat/lavadome-react": "0.0.17", "@lavamoat/snow": "^2.0.2", "@material-ui/core": "^4.11.0", "@metamask-institutional/custody-controller": "^0.3.0", - "@metamask-institutional/custody-keyring": "^2.1.0", + "@metamask-institutional/custody-keyring": "^2.1.1", "@metamask-institutional/extension": "^0.3.28", "@metamask-institutional/institutional-features": "^1.3.6", "@metamask-institutional/portfolio-dashboard": "^1.4.1", @@ -309,7 +314,7 @@ "@metamask/design-tokens": "^4.0.0", "@metamask/ens-controller": "^13.0.0", "@metamask/ens-resolver-snap": "^0.1.2", - "@metamask/eth-json-rpc-filters": "^7.0.0", + "@metamask/eth-json-rpc-filters": "^9.0.0", "@metamask/eth-json-rpc-middleware": "patch:@metamask/eth-json-rpc-middleware@npm%3A14.0.1#~/.yarn/patches/@metamask-eth-json-rpc-middleware-npm-14.0.1-b6c2ccbe8c.patch", "@metamask/eth-ledger-bridge-keyring": "^3.0.1", "@metamask/eth-query": "^4.0.0", @@ -334,7 +339,7 @@ "@metamask/name-controller": "^8.0.0", "@metamask/network-controller": "patch:@metamask/network-controller@npm%3A21.0.0#~/.yarn/patches/@metamask-network-controller-npm-21.0.0-559aa8e395.patch", "@metamask/notification-controller": "^6.0.0", - "@metamask/notification-services-controller": "^0.7.0", + "@metamask/notification-services-controller": "^0.11.0", "@metamask/object-multiplex": "^2.0.0", "@metamask/obs-store": "^9.0.0", "@metamask/permission-controller": "^10.0.0", @@ -476,7 +481,7 @@ "@metamask/eslint-config-typescript": "^9.0.1", "@metamask/eslint-plugin-design-tokens": "^1.1.0", "@metamask/forwarder": "^1.1.0", - "@metamask/phishing-warning": "^4.0.0", + "@metamask/phishing-warning": "^4.1.0", "@metamask/preferences-controller": "^13.0.2", "@metamask/test-bundler": "^1.0.0", "@metamask/test-dapp": "8.7.0", @@ -698,17 +703,10 @@ "@eth-optimism/contracts>@ethersproject/hardware-wallets>@ledgerhq/hw-transport-node-hid>@ledgerhq/hw-transport-node-hid-noevents>node-hid": false, "@eth-optimism/contracts>@ethersproject/hardware-wallets>@ledgerhq/hw-transport-node-hid>node-hid": false, "@eth-optimism/contracts>@ethersproject/hardware-wallets>@ledgerhq/hw-transport-node-hid>usb": false, - "@metamask/controllers>web3-provider-engine>ethereumjs-util>keccak": false, - "@metamask/controllers>web3-provider-engine>ethereumjs-util>secp256k1": false, - "@metamask/controllers>web3-provider-engine>ethereumjs-vm>merkle-patricia-tree>ethereumjs-util>keccak": false, - "@metamask/controllers>web3-provider-engine>ethereumjs-vm>merkle-patricia-tree>ethereumjs-util>secp256k1": false, - "@metamask/eth-ledger-bridge-keyring>hdkey>secp256k1": false, "@storybook/api>core-js": false, "@storybook/core>@storybook/core-client>@storybook/ui>core-js-pure": false, "@storybook/test-runner>@storybook/core-common>esbuild": false, - "eth-json-rpc-filters>eth-json-rpc-middleware>ethereumjs-util>keccak": false, - "eth-json-rpc-filters>eth-json-rpc-middleware>ethereumjs-util>secp256k1": false, - "eth-lattice-keyring>gridplus-sdk": false, + "eth-lattice-keyring>gridplus-sdk": true, "ethereumjs-util>ethereum-cryptography>keccak": false, "ganache>@trufflesuite/bigint-buffer": false, "ganache>@trufflesuite/uws-js-unofficial>bufferutil": false, @@ -718,13 +716,10 @@ "ganache>leveldown": false, "ganache>secp256k1": false, "ganache>utf-8-validate": false, - "ethereumjs-util>ethereum-cryptography>secp256k1": false, "gulp-watch>chokidar>fsevents": false, "gulp>glob-watcher>chokidar>fsevents": false, "webpack>watchpack>watchpack-chokidar2>chokidar>fsevents": false, - "@keystonehq/bc-ur-registry-eth>hdkey>secp256k1": false, "eth-lattice-keyring>gridplus-sdk>secp256k1": false, - "eth-lattice-keyring>secp256k1": false, "@storybook/react>@pmmmwh/react-refresh-webpack-plugin>core-js-pure": false, "@testing-library/jest-dom>aria-query>@babel/runtime-corejs3>core-js-pure": false, "web3": false, @@ -733,7 +728,6 @@ "web3>web3-core>web3-core-requestmanager>web3-providers-ws>websocket>es5-ext": false, "web3>web3-core>web3-core-requestmanager>web3-providers-ws>websocket>utf-8-validate": false, "web3>web3-shh": false, - "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring>hdkey>secp256k1": false, "@metamask/base-controller>simple-git-hooks": false, "@storybook/core>@storybook/core-server>webpack>watchpack>watchpack-chokidar2>chokidar>fsevents": false, "resolve-url-loader>es6-iterator>es5-ext": false, diff --git a/shared/constants/metametrics.ts b/shared/constants/metametrics.ts index 8107a1040127..e701bda2f626 100644 --- a/shared/constants/metametrics.ts +++ b/shared/constants/metametrics.ts @@ -601,6 +601,7 @@ export enum MetaMetricsEventName { PetnameModalOpened = 'Petname Modal Opened', PetnameUpdated = 'Petname Updated', PhishingPageDisplayed = 'Phishing Page Displayed', + ProceedAnywayClicked = 'Proceed Anyway Clicked', PortfolioLinkClicked = 'Portfolio Link Clicked', ProviderMethodCalled = 'Provider Method Called', PublicAddressCopied = 'Public Address Copied', diff --git a/shared/constants/network.test.ts b/shared/constants/network.test.ts index 20a13ccfb273..9d9ca72b46cd 100644 --- a/shared/constants/network.test.ts +++ b/shared/constants/network.test.ts @@ -35,6 +35,7 @@ describe('NetworkConstants', () => { 'Polygon Mainnet': CHAIN_IDS.POLYGON, 'zkSync Era Mainnet': CHAIN_IDS.ZKSYNC_ERA, 'Base Mainnet': CHAIN_IDS.BASE, + 'Linea Mainnet': CHAIN_IDS.LINEA_MAINNET, }; FEATURED_RPCS.forEach((rpc) => { diff --git a/shared/constants/network.ts b/shared/constants/network.ts index e911ce1aabf5..64d330b73b2c 100644 --- a/shared/constants/network.ts +++ b/shared/constants/network.ts @@ -147,6 +147,7 @@ export const CHAIN_IDS = { NUMBERS: '0x290b', SEI: '0x531', APE_TESTNET: '0x8157', + APE_MAINNET: '0x8173', BERACHAIN: '0x138d5', METACHAIN_ONE: '0x1b6e6', ARBITRUM_SEPOLIA: '0x66eee', @@ -207,6 +208,7 @@ export const CHAINLIST_CHAIN_IDS_MAP = { ZORA_MAINNET: '0x76adf1', FILECOIN: '0x13a', NUMBERS: '0x290b', + APE: '0x8173', } as const; // To add a deprecation warning to a network, add it to the array @@ -371,6 +373,7 @@ const CHAINLIST_CURRENCY_SYMBOLS_MAP = { HUOBI_ECO_CHAIN_MAINNET: 'HT', ACALA_NETWORK: 'ACA', IOTEX_MAINNET: 'IOTX', + APE: 'APE', } as const; export const CHAINLIST_CURRENCY_SYMBOLS_MAP_NETWORK_COLLISION = { @@ -416,6 +419,7 @@ export const FUSE_GOLD_MAINNET_IMAGE_URL = './images/fuse-mainnet.jpg'; export const HAQQ_NETWORK_IMAGE_URL = './images/haqq.svg'; export const IOTEX_MAINNET_IMAGE_URL = './images/iotex.svg'; export const IOTEX_TOKEN_IMAGE_URL = './images/iotex-token.svg'; +export const APE_TOKEN_IMAGE_URL = './images/ape-token.svg'; export const KCC_MAINNET_IMAGE_URL = './images/kcc-mainnet.svg'; export const KLAYTN_MAINNET_IMAGE_URL = './images/klaytn.svg'; export const KROMA_MAINNET_IMAGE_URL = './images/kroma.svg'; @@ -449,7 +453,7 @@ export const NUMBERS_MAINNET_IMAGE_URL = './images/numbers-mainnet.svg'; export const NUMBERS_TOKEN_IMAGE_URL = './images/numbers-token.png'; export const SEI_IMAGE_URL = './images/sei.svg'; export const NEAR_IMAGE_URL = './images/near.svg'; -export const APE_TESTNET_IMAGE_URL = './images/ape.svg'; +export const APE_IMAGE_URL = './images/ape.svg'; export const INFURA_PROVIDER_TYPES = [ NETWORK_TYPES.MAINNET, @@ -564,6 +568,7 @@ export const NETWORK_TO_NAME_MAP = { export const CHAIN_ID_TO_CURRENCY_SYMBOL_MAP = { [CHAINLIST_CHAIN_IDS_MAP.AVALANCHE]: CHAINLIST_CURRENCY_SYMBOLS_MAP.AVALANCHE, + [CHAINLIST_CHAIN_IDS_MAP.APE]: CHAINLIST_CURRENCY_SYMBOLS_MAP.APE, [CHAINLIST_CHAIN_IDS_MAP.BSC]: CHAINLIST_CURRENCY_SYMBOLS_MAP.BNB, [CHAINLIST_CHAIN_IDS_MAP.BASE]: CHAINLIST_CURRENCY_SYMBOLS_MAP.BASE, [CHAINLIST_CHAIN_IDS_MAP.ARBITRUM]: CHAINLIST_CURRENCY_SYMBOLS_MAP.ARBITRUM, @@ -782,7 +787,8 @@ export const CHAIN_ID_TO_NETWORK_IMAGE_URL_MAP = { [CHAINLIST_CHAIN_IDS_MAP.ZKATANA]: ZKATANA_MAINNET_IMAGE_URL, [CHAINLIST_CHAIN_IDS_MAP.ZORA_MAINNET]: ZORA_MAINNET_IMAGE_URL, [CHAINLIST_CHAIN_IDS_MAP.FILECOIN]: FILECOIN_MAINNET_IMAGE_URL, - [CHAINLIST_CHAIN_IDS_MAP.APE_TESTNET]: APE_TESTNET_IMAGE_URL, + [CHAINLIST_CHAIN_IDS_MAP.APE_TESTNET]: APE_IMAGE_URL, + [CHAINLIST_CHAIN_IDS_MAP.APE_MAINNET]: APE_IMAGE_URL, [CHAINLIST_CHAIN_IDS_MAP.BASE]: BASE_TOKEN_IMAGE_URL, [CHAINLIST_CHAIN_IDS_MAP.NUMBERS]: NUMBERS_MAINNET_IMAGE_URL, [CHAINLIST_CHAIN_IDS_MAP.SEI]: SEI_IMAGE_URL, @@ -817,6 +823,7 @@ export const CHAIN_ID_TOKEN_IMAGE_MAP = { [CHAIN_IDS.MOONRIVER]: MOONRIVER_TOKEN_IMAGE_URL, [CHAIN_IDS.MOONBEAM]: MOONBEAM_TOKEN_IMAGE_URL, [CHAINLIST_CHAIN_IDS_MAP.IOTEX_MAINNET]: IOTEX_TOKEN_IMAGE_URL, + [CHAINLIST_CHAIN_IDS_MAP.APE_MAINNET]: APE_TOKEN_IMAGE_URL, } as const; export const INFURA_BLOCKED_KEY = 'countryBlocked'; @@ -932,6 +939,20 @@ export const UNSUPPORTED_RPC_METHODS = new Set([ export const IPFS_DEFAULT_GATEWAY_URL = 'dweb.link'; export const FEATURED_RPCS: AddNetworkFields[] = [ + { + chainId: CHAIN_IDS.LINEA_MAINNET, + name: LINEA_MAINNET_DISPLAY_NAME, + nativeCurrency: CURRENCY_SYMBOLS.ETH, + rpcEndpoints: [ + { + url: `https://linea-mainnet.infura.io/v3/${infuraProjectId}`, + type: RpcEndpointType.Custom, + }, + ], + defaultRpcEndpointIndex: 0, + blockExplorerUrls: ['https://lineascan.build/'], + defaultBlockExplorerUrlIndex: 0, + }, { chainId: CHAIN_IDS.ARBITRUM, name: ARBITRUM_DISPLAY_NAME, diff --git a/test/e2e/fixture-builder.js b/test/e2e/fixture-builder.js index d73b959946c2..29770343488d 100644 --- a/test/e2e/fixture-builder.js +++ b/test/e2e/fixture-builder.js @@ -57,6 +57,7 @@ function onboardingFixture() { }), providerConfig: { id: 'networkConfigurationId' }, }, + NotificationServicesController: {}, PreferencesController: { advancedGasFee: {}, currentLocale: 'en', @@ -138,6 +139,7 @@ function onboardingFixture() { }, }, }, + UserStorageController: {}, TokensController: { allDetectedTokens: {}, allIgnoredTokens: {}, diff --git a/test/e2e/helpers/user-storage/userStorageMockttpController.test.ts b/test/e2e/helpers/user-storage/userStorageMockttpController.test.ts new file mode 100644 index 000000000000..1b6591899c0e --- /dev/null +++ b/test/e2e/helpers/user-storage/userStorageMockttpController.test.ts @@ -0,0 +1,304 @@ +import * as mockttp from 'mockttp'; +import { UserStorageMockttpController } from './userStorageMockttpController'; + +describe('UserStorageMockttpController', () => { + let mockServer: mockttp.Mockttp; + + const baseUrl = 'https://user-storage.api.cx.metamask.io/api/v1/userstorage'; + + describe('mimics user storage behaviour', () => { + mockServer = mockttp.getLocal({ cors: true }); + + it('handles GET requests that have empty response', async () => { + const controller = new UserStorageMockttpController(); + + controller.setupPath('accounts', mockServer); + + const request = await controller.onGet('accounts', { + path: `${baseUrl}/accounts`, + }); + + expect(request.json).toEqual(null); + }); + + it('handles GET requests that have a pre-defined response', async () => { + const controller = new UserStorageMockttpController(); + const mockedData = [ + { + HashedKey: + '7f8a7963423985c50f75f6ad42a6cf4e7eac43a6c55e3c6fcd49d73f01c1471b', + Data: 'data1', + }, + { + HashedKey: + 'c236b92ea7d513b2beda062cb546986961dfa7ca4334a2913f7837e43d050468', + Data: 'data2', + }, + ]; + + controller.setupPath('accounts', mockServer, { + getResponse: mockedData, + }); + + const request = await controller.onGet('accounts', { + path: `${baseUrl}/accounts`, + }); + + expect(request.json).toEqual(mockedData); + }); + + it('handles batch GET requests', async () => { + const controller = new UserStorageMockttpController(); + const mockedData = [ + { + HashedKey: + '7f8a7963423985c50f75f6ad42a6cf4e7eac43a6c55e3c6fcd49d73f01c1471b', + Data: 'data1', + }, + { + HashedKey: + 'c236b92ea7d513b2beda062cb546986961dfa7ca4334a2913f7837e43d050468', + Data: 'data2', + }, + ]; + + controller.setupPath('accounts', mockServer, { + getResponse: mockedData, + }); + + const request = await controller.onGet('accounts', { + path: `${baseUrl}/accounts`, + }); + + expect(request.json).toEqual(mockedData); + }); + + it('handles GET requests for feature entries', async () => { + const controller = new UserStorageMockttpController(); + const mockedData = [ + { + HashedKey: + '7f8a7963423985c50f75f6ad42a6cf4e7eac43a6c55e3c6fcd49d73f01c1471b', + Data: 'data1', + }, + { + HashedKey: + 'c236b92ea7d513b2beda062cb546986961dfa7ca4334a2913f7837e43d050468', + Data: 'data2', + }, + ]; + + controller.setupPath('accounts', mockServer, { + getResponse: mockedData, + }); + + const request = await controller.onGet('accounts', { + path: `${baseUrl}/accounts/7f8a7963423985c50f75f6ad42a6cf4e7eac43a6c55e3c6fcd49d73f01c1471b`, + }); + + expect(request.json).toEqual(mockedData[0]); + }); + + it('handles PUT requests to create new entries', async () => { + const controller = new UserStorageMockttpController(); + const mockedData = [ + { + HashedKey: + '7f8a7963423985c50f75f6ad42a6cf4e7eac43a6c55e3c6fcd49d73f01c1471b', + Data: 'data1', + }, + { + HashedKey: + 'c236b92ea7d513b2beda062cb546986961dfa7ca4334a2913f7837e43d050468', + Data: 'data2', + }, + ]; + const mockedAddedData = { + HashedKey: + '6afbe024087495b4e0d56c4bdfc981c84eba44a7c284d4f455b5db4fcabc2173', + Data: 'data3', + }; + + controller.setupPath('accounts', mockServer, { + getResponse: mockedData, + }); + + const putRequest = await controller.onPut('accounts', { + path: `${baseUrl}/accounts/6afbe024087495b4e0d56c4bdfc981c84eba44a7c284d4f455b5db4fcabc2173`, + body: { + getJson: async () => ({ + data: mockedAddedData.Data, + }), + } as unknown as mockttp.CompletedBody, + }); + + expect(putRequest.statusCode).toEqual(204); + + const getRequest = await controller.onGet('accounts', { + path: `${baseUrl}/accounts`, + }); + + expect(getRequest.json).toEqual([...mockedData, mockedAddedData]); + }); + + it('handles PUT requests to update existing entries', async () => { + const controller = new UserStorageMockttpController(); + const mockedData = [ + { + HashedKey: + '7f8a7963423985c50f75f6ad42a6cf4e7eac43a6c55e3c6fcd49d73f01c1471b', + Data: 'data1', + }, + { + HashedKey: + 'c236b92ea7d513b2beda062cb546986961dfa7ca4334a2913f7837e43d050468', + Data: 'data2', + }, + ]; + const mockedUpdatedData = { + HashedKey: + 'c236b92ea7d513b2beda062cb546986961dfa7ca4334a2913f7837e43d050468', + Data: 'data3', + }; + + controller.setupPath('accounts', mockServer, { + getResponse: mockedData, + }); + + const putRequest = await controller.onPut('accounts', { + path: `${baseUrl}/accounts/c236b92ea7d513b2beda062cb546986961dfa7ca4334a2913f7837e43d050468`, + body: { + getJson: async () => ({ + data: mockedUpdatedData.Data, + }), + } as unknown as mockttp.CompletedBody, + }); + + expect(putRequest.statusCode).toEqual(204); + + const getRequest = await controller.onGet('accounts', { + path: `${baseUrl}/accounts`, + }); + + expect(getRequest.json).toEqual([mockedData[0], mockedUpdatedData]); + }); + + it('handles batch PUT requests', async () => { + const controller = new UserStorageMockttpController(); + const mockedData = [ + { + HashedKey: + '7f8a7963423985c50f75f6ad42a6cf4e7eac43a6c55e3c6fcd49d73f01c1471b', + Data: 'data1', + }, + { + HashedKey: + 'c236b92ea7d513b2beda062cb546986961dfa7ca4334a2913f7837e43d050468', + Data: 'data2', + }, + ]; + const mockedUpdatedData = [ + { + HashedKey: + '7f8a7963423985c50f75f6ad42a6cf4e7eac43a6c55e3c6fcd49d73f01c1471b', + Data: 'data3', + }, + { + HashedKey: + 'c236b92ea7d513b2beda062cb546986961dfa7ca4334a2913f7837e43d050468', + Data: 'data4', + }, + ]; + + controller.setupPath('accounts', mockServer, { + getResponse: mockedData, + }); + + const putData = {} as { [key: string]: string }; + mockedUpdatedData.forEach((entry) => { + putData[entry.HashedKey] = entry.Data; + }); + + const putRequest = await controller.onPut('accounts', { + path: `${baseUrl}/accounts`, + body: { + getJson: async () => ({ + data: putData, + }), + } as unknown as mockttp.CompletedBody, + }); + + expect(putRequest.statusCode).toEqual(204); + + const getRequest = await controller.onGet('accounts', { + path: `${baseUrl}/accounts`, + }); + + expect(getRequest.json).toEqual(mockedUpdatedData); + }); + + it('handles DELETE requests', async () => { + const controller = new UserStorageMockttpController(); + const mockedData = [ + { + HashedKey: + '7f8a7963423985c50f75f6ad42a6cf4e7eac43a6c55e3c6fcd49d73f01c1471b', + Data: 'data1', + }, + { + HashedKey: + 'c236b92ea7d513b2beda062cb546986961dfa7ca4334a2913f7837e43d050468', + Data: 'data2', + }, + ]; + + controller.setupPath('accounts', mockServer, { + getResponse: mockedData, + }); + + const deleteRequest = await controller.onDelete('accounts', { + path: `${baseUrl}/accounts/c236b92ea7d513b2beda062cb546986961dfa7ca4334a2913f7837e43d050468`, + }); + + expect(deleteRequest.statusCode).toEqual(204); + + const getRequest = await controller.onGet('accounts', { + path: `${baseUrl}/accounts`, + }); + + expect(getRequest.json).toEqual([mockedData[0]]); + }); + + it('handles batch DELETE requests', async () => { + const controller = new UserStorageMockttpController(); + const mockedData = [ + { + HashedKey: + '7f8a7963423985c50f75f6ad42a6cf4e7eac43a6c55e3c6fcd49d73f01c1471b', + Data: 'data1', + }, + { + HashedKey: + 'c236b92ea7d513b2beda062cb546986961dfa7ca4334a2913f7837e43d050468', + Data: 'data2', + }, + ]; + + controller.setupPath('accounts', mockServer, { + getResponse: mockedData, + }); + + const deleteRequest = await controller.onDelete('accounts', { + path: `${baseUrl}/accounts`, + }); + + expect(deleteRequest.statusCode).toEqual(204); + + const getRequest = await controller.onGet('accounts', { + path: `${baseUrl}/accounts`, + }); + + expect(getRequest.json).toEqual(null); + }); + }); +}); diff --git a/test/e2e/helpers/user-storage/userStorageMockttpController.ts b/test/e2e/helpers/user-storage/userStorageMockttpController.ts new file mode 100644 index 000000000000..970a10d11120 --- /dev/null +++ b/test/e2e/helpers/user-storage/userStorageMockttpController.ts @@ -0,0 +1,196 @@ +import { CompletedRequest, Mockttp } from 'mockttp'; + +// TODO: Export user storage schema from @metamask/profile-sync-controller +export const pathRegexps = { + accounts: + /https:\/\/user-storage\.api\.cx\.metamask\.io\/api\/v1\/userstorage\/accounts/u, + networks: + /https:\/\/user-storage\.api\.cx\.metamask\.io\/api\/v1\/userstorage\/networks/u, + notifications: + /https:\/\/user-storage\.api\.cx\.metamask\.io\/api\/v1\/userstorage\/notifications/u, +}; + +type UserStorageResponseData = { HashedKey: string; Data: string }; + +const determineIfFeatureEntryFromURL = (url: string) => + url.substring(url.lastIndexOf('userstorage') + 12).split('/').length === 2; + +export class UserStorageMockttpController { + paths: Map< + keyof typeof pathRegexps, + { + response: UserStorageResponseData[]; + server: Mockttp; + } + > = new Map(); + + readonly onGet = async ( + path: keyof typeof pathRegexps, + request: Pick, + statusCode: number = 200, + ) => { + const internalPathData = this.paths.get(path); + + if (!internalPathData) { + return { + statusCode, + json: null, + }; + } + + const isFeatureEntry = determineIfFeatureEntryFromURL(request.path); + + if (isFeatureEntry) { + const json = + internalPathData.response?.find( + (entry) => entry.HashedKey === request.path.split('/').pop(), + ) || null; + + return { + statusCode, + json, + }; + } + + const json = internalPathData?.response.length + ? internalPathData.response + : null; + + return { + statusCode, + json, + }; + }; + + readonly onPut = async ( + path: keyof typeof pathRegexps, + request: Pick, + statusCode: number = 204, + ) => { + const isFeatureEntry = determineIfFeatureEntryFromURL(request.path); + + const data = (await request.body.getJson()) as { + data: string | { [key: string]: string }; + }; + + const newOrUpdatedSingleOrBatchEntries = + isFeatureEntry && typeof data?.data === 'string' + ? [ + { + HashedKey: request.path.split('/').pop() as string, + Data: data?.data, + }, + ] + : Object.entries(data?.data).map(([key, value]) => ({ + HashedKey: key, + Data: value, + })); + + newOrUpdatedSingleOrBatchEntries.forEach((entry) => { + const internalPathData = this.paths.get(path); + + if (!internalPathData) { + return; + } + + const doesThisEntryExist = internalPathData.response?.find( + (existingEntry) => existingEntry.HashedKey === entry.HashedKey, + ); + + if (doesThisEntryExist) { + this.paths.set(path, { + ...internalPathData, + response: internalPathData.response.map((existingEntry) => + existingEntry.HashedKey === entry.HashedKey ? entry : existingEntry, + ), + }); + } else { + this.paths.set(path, { + ...internalPathData, + response: [ + ...(internalPathData?.response || []), + entry as { HashedKey: string; Data: string }, + ], + }); + } + }); + + return { + statusCode, + }; + }; + + readonly onDelete = async ( + path: keyof typeof pathRegexps, + request: Pick, + statusCode: number = 204, + ) => { + const internalPathData = this.paths.get(path); + + if (!internalPathData) { + return { + statusCode, + }; + } + + const isFeatureEntry = determineIfFeatureEntryFromURL(request.path); + + if (isFeatureEntry) { + this.paths.set(path, { + ...internalPathData, + response: internalPathData?.response.filter( + (entry) => entry.HashedKey !== request.path.split('/').pop(), + ), + }); + } else { + this.paths.set(path, { + ...internalPathData, + response: [], + }); + } + + return { + statusCode, + }; + }; + + setupPath = ( + path: keyof typeof pathRegexps, + server: Mockttp, + overrides?: { + getResponse?: UserStorageResponseData[]; + getStatusCode?: number; + putStatusCode?: number; + deleteStatusCode?: number; + }, + ) => { + const previouslySetupPath = this.paths.get(path); + + this.paths.set(path, { + response: overrides?.getResponse || previouslySetupPath?.response || [], + server, + }); + + this.paths + .get(path) + ?.server.forGet(pathRegexps[path]) + .always() + .thenCallback((request) => + this.onGet(path, request, overrides?.getStatusCode), + ); + this.paths + .get(path) + ?.server.forPut(pathRegexps[path]) + .always() + .thenCallback((request) => + this.onPut(path, request, overrides?.putStatusCode), + ); + this.paths + .get(path) + ?.server.forDelete(pathRegexps[path]) + .always() + .thenCallback((request) => + this.onDelete(path, request, overrides?.deleteStatusCode), + ); + }; +} diff --git a/test/e2e/tests/dapp-interactions/dapp-interactions.spec.js b/test/e2e/tests/dapp-interactions/dapp-interactions.spec.js index b992925ffc7a..584408134f1a 100644 --- a/test/e2e/tests/dapp-interactions/dapp-interactions.spec.js +++ b/test/e2e/tests/dapp-interactions/dapp-interactions.spec.js @@ -31,7 +31,7 @@ describe('Dapp interactions', function () { await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); await unlockWallet(driver); const notification = await driver.isElementPresent({ - text: 'Allow this site to add a network?', + text: 'Add Localhost 8546', tag: 'h3', }); diff --git a/test/e2e/tests/metrics/nft-detection-metrics.spec.js b/test/e2e/tests/metrics/nft-detection-metrics.spec.js index 3c77fdb66731..a0c901087425 100644 --- a/test/e2e/tests/metrics/nft-detection-metrics.spec.js +++ b/test/e2e/tests/metrics/nft-detection-metrics.spec.js @@ -101,7 +101,7 @@ describe('Nft detection event @no-mmi', function () { locale: 'en', chain_id: '0x539', environment_type: 'fullscreen', - is_profile_syncing_enabled: null, + is_profile_syncing_enabled: true, }); assert.deepStrictEqual(events[2].properties, { nft_autodetection_enabled: true, diff --git a/test/e2e/tests/metrics/token-detection-metrics.spec.js b/test/e2e/tests/metrics/token-detection-metrics.spec.js index 669aff0a9290..923f7c86a242 100644 --- a/test/e2e/tests/metrics/token-detection-metrics.spec.js +++ b/test/e2e/tests/metrics/token-detection-metrics.spec.js @@ -98,7 +98,7 @@ describe('Token detection event @no-mmi', function () { locale: 'en', chain_id: '0x539', environment_type: 'fullscreen', - is_profile_syncing_enabled: null, + is_profile_syncing_enabled: true, }); assert.deepStrictEqual(events[2].properties, { token_detection_enabled: true, diff --git a/test/e2e/tests/metrics/wallet-created.spec.js b/test/e2e/tests/metrics/wallet-created.spec.js index 890ac9342a8a..fbe80fb595dc 100644 --- a/test/e2e/tests/metrics/wallet-created.spec.js +++ b/test/e2e/tests/metrics/wallet-created.spec.js @@ -87,7 +87,7 @@ describe('Wallet Created Events @no-mmi', function () { locale: 'en', chain_id: '0x539', environment_type: 'fullscreen', - is_profile_syncing_enabled: null, + is_profile_syncing_enabled: true, }); }, ); diff --git a/test/e2e/tests/network/add-custom-network.spec.js b/test/e2e/tests/network/add-custom-network.spec.js index dc8f38e1168c..d24beb431c1c 100644 --- a/test/e2e/tests/network/add-custom-network.spec.js +++ b/test/e2e/tests/network/add-custom-network.spec.js @@ -119,9 +119,7 @@ const inputData = { }; describe('Custom network', function () { - const chainID = '42161'; const networkURL = 'https://arbitrum-mainnet.infura.io'; - const networkNAME = 'Arbitrum One'; const currencySYMBOL = 'ETH'; const blockExplorerURL = 'https://explorer.arbitrum.io'; @@ -456,52 +454,29 @@ describe('Custom network', function () { text: 'Add', }); - // verify network details - const title = await driver.findElement({ - tag: 'span', - text: 'Arbitrum One', - }); - - assert.equal( - await title.getText(), - 'Arbitrum One', - 'Title of popup should be selected network', + const [currencySymbol, networkUrl] = await driver.findElements( + '.definition-list dd', ); - - const [networkName, networkUrl, chainIdElement, currencySymbol] = - await driver.findElements('.definition-list dd'); - assert.equal( - await networkName.getText(), - networkNAME, - 'Network name is not correctly displayed', + await currencySymbol.getText(), + currencySYMBOL, + 'Currency symbol is not correctly displayed', ); assert.equal( await networkUrl.getText(), networkURL, 'Network Url is not correctly displayed', ); - assert.equal( - await chainIdElement.getText(), - chainID.toString(), - 'Chain Id is not correctly displayed', - ); - assert.equal( - await currencySymbol.getText(), - currencySYMBOL, - 'Currency symbol is not correctly displayed', - ); - await driver.clickElement({ tag: 'a', text: 'View all details' }); + await driver.clickElement({ tag: 'a', text: 'See details' }); const networkDetailsLabels = await driver.findElements('dd'); assert.equal( - await networkDetailsLabels[8].getText(), + await networkDetailsLabels[4].getText(), blockExplorerURL, 'Block Explorer URL is not correct', ); - await driver.clickElement({ tag: 'button', text: 'Close' }); await driver.clickElement({ tag: 'button', text: 'Approve' }); // verify network switched diff --git a/test/e2e/tests/notifications/account-syncing/helpers.ts b/test/e2e/tests/notifications/account-syncing/helpers.ts new file mode 100644 index 000000000000..e54a5f6f96ae --- /dev/null +++ b/test/e2e/tests/notifications/account-syncing/helpers.ts @@ -0,0 +1,3 @@ +import { isManifestV3 } from '../../../../../shared/modules/mv3.utils'; + +export const IS_ACCOUNT_SYNCING_ENABLED = isManifestV3; diff --git a/test/e2e/tests/notifications/account-syncing/mockData.ts b/test/e2e/tests/notifications/account-syncing/mockData.ts new file mode 100644 index 000000000000..96e92ecd8491 --- /dev/null +++ b/test/e2e/tests/notifications/account-syncing/mockData.ts @@ -0,0 +1,12 @@ +export const accountsSyncMockResponse = [ + { + HashedKey: + '997050281e559a2bb40d1c2e73d9f0887cbea1b81ff9dd7815917949e37f4f2f', + Data: '{"v":"1","t":"scrypt","d":"1yC/ZXarV57HbqEZ46nH0JWgXfPl86nTHD7kai2g5gm290FM9tw5QjOaAAwIuQESEE8TIM/J9pIj7nmlGi+BZrevTtK3DXWXwnUQsCP7amKd5Q4gs3EEQgXpA0W+WJUgyElj869rwIv/C6tl5E2pK4j/0EAjMSIm1TGoj9FPohyRgZsOIt8VhZfb7w0GODsjPwPIkN6zazvJ3gAFYFPh7yRtebFs86z3fzqCWZ9zakdCHntchC2oZiaApXR9yzaPlGgnPg==","o":{"N":131072,"r":8,"p":1,"dkLen":16},"saltLen":16}', + }, + { + HashedKey: + 'e53d8feb65b4cf0c339e57bee2a81b155e056622f9192c54b707f928c8a42a7a', + Data: '{"v":"1","t":"scrypt","d":"O7QEtUo7q/jG+UNkD/HOxQARGGRXsGPrLsDlkwDfgfoYlPI0To/M3pJRBlKD0RLEFIPHtHBEA5bv/2izB21VljvhMnhHfo0KgQ+e8Uq1t7grwa+r+ge3qbPNY+w78Xt8GtC+Hkrw5fORKvCn+xjzaCHYV6RxKYbp1TpyCJq7hDrr1XiyL8kqbpE0hAHALrrQOoV9/WXJi9pC5J118kquXx8CNA1P5wO/BXKp1AbryGR6kVW3lsp1sy3lYE/TApa5lTj+","o":{"N":131072,"r":8,"p":1,"dkLen":16},"saltLen":16}', + }, +]; diff --git a/test/e2e/tests/notifications/account-syncing/sync-after-adding-custom-name-account.spec.ts b/test/e2e/tests/notifications/account-syncing/sync-after-adding-custom-name-account.spec.ts new file mode 100644 index 000000000000..6ca7c501fc84 --- /dev/null +++ b/test/e2e/tests/notifications/account-syncing/sync-after-adding-custom-name-account.spec.ts @@ -0,0 +1,120 @@ +import { Mockttp } from 'mockttp'; +import { + withFixtures, + defaultGanacheOptions, + completeImportSRPOnboardingFlow, +} from '../../../helpers'; +import FixtureBuilder from '../../../fixture-builder'; +import { mockNotificationServices } from '../mocks'; +import { + NOTIFICATIONS_TEAM_PASSWORD, + NOTIFICATIONS_TEAM_SEED_PHRASE, +} from '../constants'; +import { UserStorageMockttpController } from '../../../helpers/user-storage/userStorageMockttpController'; +import { accountsSyncMockResponse } from './mockData'; +import { IS_ACCOUNT_SYNCING_ENABLED } from './helpers'; + +describe('Account syncing @no-mmi', function () { + if (!IS_ACCOUNT_SYNCING_ENABLED) { + return; + } + describe('from inside MetaMask', function () { + it('syncs newly added accounts', async function () { + const userStorageMockttpController = new UserStorageMockttpController(); + + await withFixtures( + { + fixtures: new FixtureBuilder({ onboarding: true }).build(), + ganacheOptions: defaultGanacheOptions, + title: this.test?.fullTitle(), + testSpecificMock: (server: Mockttp) => { + userStorageMockttpController.setupPath('accounts', server, { + getResponse: accountsSyncMockResponse, + }); + + return mockNotificationServices( + server, + userStorageMockttpController, + ); + }, + }, + async ({ driver }) => { + await driver.navigate(); + await completeImportSRPOnboardingFlow( + driver, + NOTIFICATIONS_TEAM_SEED_PHRASE, + NOTIFICATIONS_TEAM_PASSWORD, + ); + + await driver.clickElement('[data-testid="account-menu-icon"]'); + + await driver.wait(async () => { + const internalAccounts = await driver.findElements( + '.multichain-account-list-item', + ); + return internalAccounts.length === accountsSyncMockResponse.length; + }, 20000); + + await driver.clickElement( + '[data-testid="multichain-account-menu-popover-action-button"]', + ); + await driver.clickElement( + '[data-testid="multichain-account-menu-popover-add-account"]', + ); + await driver.fill('#account-name', 'My third account'); + + await driver.clickElementAndWaitToDisappear( + '[data-testid="submit-add-account-with-name"]', + ); + }, + ); + + await withFixtures( + { + fixtures: new FixtureBuilder({ onboarding: true }).build(), + ganacheOptions: defaultGanacheOptions, + title: this.test?.fullTitle(), + testSpecificMock: (server: Mockttp) => { + userStorageMockttpController.setupPath('accounts', server); + return mockNotificationServices( + server, + userStorageMockttpController, + ); + }, + }, + async ({ driver }) => { + await driver.navigate(); + await completeImportSRPOnboardingFlow( + driver, + NOTIFICATIONS_TEAM_SEED_PHRASE, + NOTIFICATIONS_TEAM_PASSWORD, + ); + + await driver.clickElement('[data-testid="account-menu-icon"]'); + + await driver.wait(async () => { + const internalAccounts = await driver.findElements( + '.multichain-account-list-item', + ); + return ( + internalAccounts.length === + userStorageMockttpController.paths.get('accounts')?.response + .length + ); + }, 20000); + + await driver.wait(async () => { + const internalAccounts = await driver.findElements( + '.multichain-account-list-item .multichain-account-list-item__account-name', + ); + const lastAccountName = await internalAccounts[ + internalAccounts.length - 1 + ].getText(); + + return lastAccountName === 'My third account'; + }, 20000); + }, + ); + }); + }); +}); diff --git a/test/e2e/tests/notifications/account-syncing/sync-after-onboarding.spec.ts b/test/e2e/tests/notifications/account-syncing/sync-after-onboarding.spec.ts new file mode 100644 index 000000000000..1a55e38c713d --- /dev/null +++ b/test/e2e/tests/notifications/account-syncing/sync-after-onboarding.spec.ts @@ -0,0 +1,60 @@ +import { Mockttp } from 'mockttp'; +import { + withFixtures, + defaultGanacheOptions, + completeImportSRPOnboardingFlow, +} from '../../../helpers'; +import FixtureBuilder from '../../../fixture-builder'; +import { mockNotificationServices } from '../mocks'; +import { + NOTIFICATIONS_TEAM_PASSWORD, + NOTIFICATIONS_TEAM_SEED_PHRASE, +} from '../constants'; +import { UserStorageMockttpController } from '../../../helpers/user-storage/userStorageMockttpController'; +import { accountsSyncMockResponse } from './mockData'; +import { IS_ACCOUNT_SYNCING_ENABLED } from './helpers'; + +describe('Account syncing @no-mmi', function () { + if (!IS_ACCOUNT_SYNCING_ENABLED) { + return; + } + describe('from inside MetaMask', function () { + it('retrieves all previously synced accounts', async function () { + const userStorageMockttpController = new UserStorageMockttpController(); + + await withFixtures( + { + fixtures: new FixtureBuilder({ onboarding: true }).build(), + ganacheOptions: defaultGanacheOptions, + title: this.test?.fullTitle(), + testSpecificMock: (server: Mockttp) => { + userStorageMockttpController.setupPath('accounts', server, { + getResponse: accountsSyncMockResponse, + }); + return mockNotificationServices( + server, + userStorageMockttpController, + ); + }, + }, + async ({ driver }) => { + await driver.navigate(); + await completeImportSRPOnboardingFlow( + driver, + NOTIFICATIONS_TEAM_SEED_PHRASE, + NOTIFICATIONS_TEAM_PASSWORD, + ); + + await driver.clickElement('[data-testid="account-menu-icon"]'); + + await driver.wait(async () => { + const internalAccounts = await driver.findElements( + '.multichain-account-list-item', + ); + return internalAccounts.length === accountsSyncMockResponse.length; + }, 20000); + }, + ); + }); + }); +}); diff --git a/test/e2e/tests/notifications/constants.ts b/test/e2e/tests/notifications/constants.ts new file mode 100644 index 000000000000..8c611dcd4f44 --- /dev/null +++ b/test/e2e/tests/notifications/constants.ts @@ -0,0 +1,7 @@ +// As we rely on profile syncing for most of our features, we need to use the same SRP for all of our tests +export const NOTIFICATIONS_TEAM_SEED_PHRASE = + 'leisure swallow trip elbow prison wait rely keep supply hole general mountain'; +export const NOTIFICATIONS_TEAM_PASSWORD = 'notify_password'; +// You can use the storage key below to generate mock data +export const NOTIFICATIONS_TEAM_STORAGE_KEY = + '0d55d30da233959674d14076737198c05ae3fb8631a17e20d3c28c60dddd82f7'; diff --git a/test/e2e/tests/notifications/mocks.ts b/test/e2e/tests/notifications/mocks.ts index 9161faf2967f..2bd6847a0e72 100644 --- a/test/e2e/tests/notifications/mocks.ts +++ b/test/e2e/tests/notifications/mocks.ts @@ -1,15 +1,12 @@ import { Mockttp, RequestRuleBuilder } from 'mockttp'; -import { - AuthenticationController, - UserStorageController, -} from '@metamask/profile-sync-controller'; +import { AuthenticationController } from '@metamask/profile-sync-controller'; import { NotificationServicesController, NotificationServicesPushController, } from '@metamask/notification-services-controller'; +import { UserStorageMockttpController } from '../../helpers/user-storage/userStorageMockttpController'; const AuthMocks = AuthenticationController.Mocks; -const StorageMocks = UserStorageController.Mocks; const NotificationMocks = NotificationServicesController.Mocks; const PushMocks = NotificationServicesPushController.Mocks; @@ -20,32 +17,30 @@ type MockResponse = { }; /** - * E2E mock setup for notification APIs (Auth, Storage, Notifications, Push Notifications, Profile syncing) + * E2E mock setup for notification APIs (Auth, UserStorage, Notifications, Push Notifications, Profile syncing) * * @param server - server obj used to mock our endpoints + * @param userStorageMockttpController - optional controller to mock user storage endpoints */ -export async function mockNotificationServices(server: Mockttp) { +export async function mockNotificationServices( + server: Mockttp, + userStorageMockttpController?: UserStorageMockttpController, +) { // Auth mockAPICall(server, AuthMocks.getMockAuthNonceResponse()); mockAPICall(server, AuthMocks.getMockAuthLoginResponse()); mockAPICall(server, AuthMocks.getMockAuthAccessTokenResponse()); // Storage - mockAPICall(server, await StorageMocks.getMockUserStorageGetResponse()); - mockAPICall(server, await StorageMocks.getMockUserStoragePutResponse()); - - // TODO - add better mock responses for other Profile Sync features - // (Account Sync, Network Sync, ...) - server - .forGet(/https:\/\/user-storage\.api\.cx\.metamask\.io\/.*/gu) - ?.thenCallback(() => ({ - statusCode: 404, - })); - server - .forPut(/https:\/\/user-storage\.api\.cx\.metamask\.io\/.*/gu) - ?.thenCallback(() => ({ - statusCode: 204, - })); + if (!userStorageMockttpController?.paths.get('accounts')) { + new UserStorageMockttpController().setupPath('accounts', server); + } + if (!userStorageMockttpController?.paths.get('networks')) { + new UserStorageMockttpController().setupPath('networks', server); + } + if (!userStorageMockttpController?.paths.get('notifications')) { + new UserStorageMockttpController().setupPath('notifications', server); + } // Notifications mockAPICall(server, NotificationMocks.getMockFeatureAnnouncementResponse()); diff --git a/test/e2e/tests/petnames/petnames-signatures.spec.js b/test/e2e/tests/petnames/petnames-signatures.spec.js index ba6cf7642c59..6c472901057e 100644 --- a/test/e2e/tests/petnames/petnames-signatures.spec.js +++ b/test/e2e/tests/petnames/petnames-signatures.spec.js @@ -46,7 +46,7 @@ async function installNameLookupSnap(driver) { // Confirm Install Modal await driver.clickElement({ - text: 'Install', + text: 'Confirm', tag: 'button', }); @@ -173,9 +173,7 @@ describe('Petnames - Signatures', function () { ); }); - // TODO(dbrans): Re-enable this test when name-lookup endowment is in stable. - // eslint-disable-next-line mocha/no-skipped-tests - it.skip('can propose names using installed snaps', async function () { + it('can propose names using installed snaps', async function () { await withFixtures( { dapp: true, diff --git a/test/e2e/tests/phishing-controller/phishing-detection.spec.js b/test/e2e/tests/phishing-controller/phishing-detection.spec.js index ac9a6d8461d2..67fb82f8fa55 100644 --- a/test/e2e/tests/phishing-controller/phishing-detection.spec.js +++ b/test/e2e/tests/phishing-controller/phishing-detection.spec.js @@ -59,7 +59,7 @@ describe('Phishing Detection', function () { await openDapp(driver); await driver.switchToWindowWithTitle('MetaMask Phishing Detection'); await driver.clickElement({ - text: 'continue to the site.', + text: 'Proceed anyway', }); await driver.wait(until.titleIs(WINDOW_TITLES.TestDApp), 10000); }, @@ -104,7 +104,7 @@ describe('Phishing Detection', function () { await driver.switchToWindowWithTitle('MetaMask Phishing Detection'); await driver.clickElement({ - text: 'continue to the site.', + text: 'Proceed anyway', }); await driver.wait(until.titleIs(WINDOW_TITLES.TestDApp), 10000); @@ -170,7 +170,7 @@ describe('Phishing Detection', function () { }); await driver.switchToWindowWithTitle('MetaMask Phishing Detection'); await driver.clickElement({ - text: 'continue to the site.', + text: 'Proceed anyway', }); // We don't really know what we're going to see at this blocked site, so a waitAtLeast guard of 1000ms is the best choice @@ -253,7 +253,7 @@ describe('Phishing Detection', function () { ); }); - it('should open a new extension expanded view when clicking back to safety button', async function () { + it('should open MetaMask Portfolio when clicking back to safety button', async function () { await withFixtures( { fixtures: new FixtureBuilder().build(), @@ -290,11 +290,10 @@ describe('Phishing Detection', function () { text: 'Back to safety', }); - // Ensure we're redirected to wallet home page - const homePage = await driver.findElement('.home__main-view'); - const homePageDisplayed = await homePage.isDisplayed(); + const currentUrl = await driver.getCurrentUrl(); + const expectedPortfolioUrl = `https://portfolio.metamask.io/?metamaskEntry=phishing_page_portfolio_button`; - assert.equal(homePageDisplayed, true); + assert.equal(currentUrl, expectedPortfolioUrl); }, ); }); diff --git a/test/e2e/tests/ppom/ppom-blockaid-alert-networks-support.spec.js b/test/e2e/tests/ppom/ppom-blockaid-alert-networks-support.spec.js index 719f8cbdc16b..f40fd68f9566 100644 --- a/test/e2e/tests/ppom/ppom-blockaid-alert-networks-support.spec.js +++ b/test/e2e/tests/ppom/ppom-blockaid-alert-networks-support.spec.js @@ -114,7 +114,7 @@ describe('PPOM Blockaid Alert - Multiple Networks Support @no-mmi', function () text: 'Add', }); - await driver.clickElement({ tag: 'a', text: 'View all details' }); + await driver.clickElement({ tag: 'a', text: 'See details' }); await driver.clickElement({ tag: 'button', text: 'Close' }); await driver.clickElement({ tag: 'button', text: 'Approve' }); diff --git a/test/env.js b/test/env.js index 2dacb1d888ba..268f01af0e3b 100644 --- a/test/env.js +++ b/test/env.js @@ -16,3 +16,4 @@ process.env.PUSH_NOTIFICATIONS_SERVICE_URL = process.env.PORTFOLIO_URL = 'https://portfolio.test'; process.env.METAMASK_VERSION = 'MOCK_VERSION'; process.env.ENABLE_CONFIRMATION_REDESIGN = 'true'; +process.env.TZ = 'UTC'; diff --git a/ui/__mocks__/webextension-polyfill.js b/ui/__mocks__/webextension-polyfill.js index 693368f15e0c..dbf15f9ea145 100644 --- a/ui/__mocks__/webextension-polyfill.js +++ b/ui/__mocks__/webextension-polyfill.js @@ -1,3 +1,15 @@ +const getManifest = () => ({ manifest_version: 3 }); + +// Polyfill chrome.runtime for environments that do not support it +// E.g. Storybook +global.chrome = { + ...global?.chrome, + runtime: { + ...global?.chrome?.runtime, + getManifest, + }, +}; + module.exports = { - runtime: { getManifest: () => ({ manifest_version: 3 }) }, + runtime: { getManifest }, }; diff --git a/ui/components/app/app-components.scss b/ui/components/app/app-components.scss index 0995f4b52a4a..9eefd48028ac 100644 --- a/ui/components/app/app-components.scss +++ b/ui/components/app/app-components.scss @@ -25,6 +25,7 @@ @import 'snaps/snap-ui-input/index'; @import 'snaps/snap-ui-file-input/index'; @import 'snaps/snap-ui-selector/index'; +@import 'snaps/snap-ui-link/index'; @import 'snaps/snap-delineator/index'; @import 'snaps/snap-home-menu/index'; @import 'snaps/snap-list-item/index'; diff --git a/ui/components/app/assets/nfts/nfts-detection-notice-nfts-tab/nfts-detection-notice-nfts-tab.js b/ui/components/app/assets/nfts/nfts-detection-notice-nfts-tab/nfts-detection-notice-nfts-tab.js index 3069b6cc5168..0f8f629cada0 100644 --- a/ui/components/app/assets/nfts/nfts-detection-notice-nfts-tab/nfts-detection-notice-nfts-tab.js +++ b/ui/components/app/assets/nfts/nfts-detection-notice-nfts-tab/nfts-detection-notice-nfts-tab.js @@ -1,14 +1,14 @@ import React from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import { BannerAlert } from '../../../../component-library'; import { useI18nContext } from '../../../../../hooks/useI18nContext'; +import { getOpenSeaEnabled } from '../../../../../selectors'; import { detectNfts, setOpenSeaEnabled, - setShowNftDetectionEnablementToast, setUseNftDetection, } from '../../../../../store/actions'; -import { getOpenSeaEnabled } from '../../../../../selectors'; +import { BannerAlert } from '../../../../component-library'; +import { setShowNftDetectionEnablementToast } from '../../../toast-master/utils'; export default function NFTsDetectionNoticeNFTsTab() { const t = useI18nContext(); diff --git a/ui/components/app/confirm/info/row/address.test.tsx b/ui/components/app/confirm/info/row/address.test.tsx index 08a3561691ff..f27e067787b1 100644 --- a/ui/components/app/confirm/info/row/address.test.tsx +++ b/ui/components/app/confirm/info/row/address.test.tsx @@ -8,6 +8,8 @@ import { mockNetworkState } from '../../../../../../test/stub/networks'; import { ConfirmInfoRowAddress } from './address'; import { TEST_ADDRESS } from './constants'; +const CHAIN_ID_MOCK = CHAIN_IDS.MAINNET; + const render = ( // TODO: Replace `any` with type // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -19,7 +21,10 @@ const render = ( ...storeOverrides, }); - return renderWithProvider(, store); + return renderWithProvider( + , + store, + ); }; describe('ConfirmInfoRowAddress', () => { diff --git a/ui/components/app/confirm/info/row/address.tsx b/ui/components/app/confirm/info/row/address.tsx index 7d28851ece92..95fabf26652f 100644 --- a/ui/components/app/confirm/info/row/address.tsx +++ b/ui/components/app/confirm/info/row/address.tsx @@ -22,11 +22,12 @@ import { useFallbackDisplayName } from './hook'; export type ConfirmInfoRowAddressProps = { address: string; + chainId: string; isSnapUsingThis?: boolean; }; export const ConfirmInfoRowAddress = memo( - ({ address, isSnapUsingThis }: ConfirmInfoRowAddressProps) => { + ({ address, chainId, isSnapUsingThis }: ConfirmInfoRowAddressProps) => { const isPetNamesEnabled = useSelector(getPetnamesEnabled); const { displayName, hexAddress } = useFallbackDisplayName(address); const [isNicknamePopoverShown, setIsNicknamePopoverShown] = useState(false); @@ -48,6 +49,7 @@ export const ConfirmInfoRowAddress = memo( value={hexAddress} type={NameType.ETHEREUM_ADDRESS} preferContractSymbol + variation={chainId} /> ) : ( <> diff --git a/ui/components/app/name/name-details/__snapshots__/name-details.test.tsx.snap b/ui/components/app/name/name-details/__snapshots__/name-details.test.tsx.snap index a6d0df79843d..cfa08b3eee01 100644 --- a/ui/components/app/name/name-details/__snapshots__/name-details.test.tsx.snap +++ b/ui/components/app/name/name-details/__snapshots__/name-details.test.tsx.snap @@ -706,15 +706,12 @@ exports[`NameDetails renders with recognized name 1`] = `
-
- -
+ />

diff --git a/ui/components/app/name/name-details/name-details.test.tsx b/ui/components/app/name/name-details/name-details.test.tsx index 9e93384adcd6..0f0df9f5b5f6 100644 --- a/ui/components/app/name/name-details/name-details.test.tsx +++ b/ui/components/app/name/name-details/name-details.test.tsx @@ -11,8 +11,8 @@ import { MetaMetricsEventCategory, MetaMetricsEventName, } from '../../../../../shared/constants/metametrics'; -import { mockNetworkState } from '../../../../../test/stub/networks'; import { CHAIN_IDS } from '../../../../../shared/constants/network'; +import { mockNetworkState } from '../../../../../test/stub/networks'; import NameDetails from './name-details'; jest.mock('../../../../store/actions', () => ({ @@ -37,11 +37,11 @@ const SOURCE_ID_MOCK = 'ens'; const SOURCE_ID_2_MOCK = 'some_snap'; const PROPOSED_NAME_MOCK = 'TestProposedName'; const PROPOSED_NAME_2_MOCK = 'TestProposedName2'; +const VARIATION_MOCK = CHAIN_ID_MOCK; const STATE_MOCK = { metamask: { ...mockNetworkState({ chainId: CHAIN_IDS.MAINNET }), - nameSources: { [SOURCE_ID_2_MOCK]: { label: 'Super Name Resolution Snap' }, }, @@ -85,13 +85,17 @@ const STATE_MOCK = { }, }, useTokenDetection: true, - tokenList: { - '0x0a3bb08b3a15a19b4de82f8acfc862606fb69a2d': { - address: '0x0a3bb08b3a15a19b4de82f8acfc862606fb69a2d', - symbol: 'IUSD', - name: 'iZUMi Bond USD', - iconUrl: - 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0x0a3bb08b3a15a19b4de82f8acfc862606fb69a2d.png', + tokensChainsCache: { + [VARIATION_MOCK]: { + data: { + '0x0a3bb08b3a15a19b4de82f8acfc862606fb69a2d': { + address: '0x0a3bb08b3a15a19b4de82f8acfc862606fb69a2d', + symbol: 'IUSD', + name: 'iZUMi Bond USD', + iconUrl: + 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0x0a3bb08b3a15a19b4de82f8acfc862606fb69a2d.png', + }, + }, }, }, }, @@ -157,6 +161,7 @@ describe('NameDetails', () => { undefined} />, store, @@ -170,6 +175,7 @@ describe('NameDetails', () => { undefined} />, store, @@ -183,6 +189,7 @@ describe('NameDetails', () => { undefined} />, store, @@ -196,6 +203,7 @@ describe('NameDetails', () => { undefined} />, store, @@ -209,6 +217,7 @@ describe('NameDetails', () => { undefined} />, store, @@ -229,6 +238,7 @@ describe('NameDetails', () => { undefined} />, store, @@ -251,6 +261,7 @@ describe('NameDetails', () => { undefined} />, store, @@ -273,6 +284,7 @@ describe('NameDetails', () => { undefined} />, store, @@ -295,6 +307,7 @@ describe('NameDetails', () => { undefined} />, store, @@ -317,6 +330,7 @@ describe('NameDetails', () => { undefined} />, store, @@ -336,6 +350,7 @@ describe('NameDetails', () => { undefined} />, store, @@ -373,6 +388,7 @@ describe('NameDetails', () => { undefined} /> , @@ -399,6 +415,7 @@ describe('NameDetails', () => { undefined} /> , @@ -426,6 +443,7 @@ describe('NameDetails', () => { undefined} /> , @@ -454,6 +472,7 @@ describe('NameDetails', () => { undefined} /> , diff --git a/ui/components/app/name/name-details/name-details.tsx b/ui/components/app/name/name-details/name-details.tsx index 22b0445a0ad5..1bb2b1f1e478 100644 --- a/ui/components/app/name/name-details/name-details.tsx +++ b/ui/components/app/name/name-details/name-details.tsx @@ -46,7 +46,7 @@ import Name from '../name'; import FormComboField, { FormComboFieldOption, } from '../../../ui/form-combo-field/form-combo-field'; -import { getCurrentChainId, getNameSources } from '../../../../selectors'; +import { getNameSources } from '../../../../selectors'; import { setName as saveName, updateProposedNames, @@ -64,6 +64,7 @@ export type NameDetailsProps = { sourcePriority?: string[]; type: NameType; value: string; + variation: string; }; type ProposedNameOption = Required & { @@ -157,12 +158,14 @@ function getInitialSources( return [...resultSources, ...stateSources].sort(); } -function useProposedNames(value: string, type: NameType, chainId: string) { +function useProposedNames(value: string, type: NameType, variation: string) { const dispatch = useDispatch(); - const { proposedNames } = useName(value, type); + const { proposedNames } = useName(value, type, variation); + // TODO: Replace `any` with type // eslint-disable-next-line @typescript-eslint/no-explicit-any const updateInterval = useRef(); + const [initialSources, setInitialSources] = useState(); useEffect(() => { @@ -178,7 +181,7 @@ function useProposedNames(value: string, type: NameType, chainId: string) { value, type, onlyUpdateAfterDelay: true, - variation: chainId, + variation, }), // TODO: Replace `any` with type // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -196,7 +199,7 @@ function useProposedNames(value: string, type: NameType, chainId: string) { updateInterval.current = setInterval(update, UPDATE_DELAY); return reset; - }, [value, type, chainId, dispatch, initialSources, setInitialSources]); + }, [value, type, variation, dispatch, initialSources, setInitialSources]); return { proposedNames, initialSources }; } @@ -205,13 +208,20 @@ export default function NameDetails({ onClose, type, value, + variation, }: NameDetailsProps) { - const chainId = useSelector(getCurrentChainId); - const { name: savedPetname, sourceId: savedSourceId } = useName(value, type); - const { name: displayName, hasPetname: hasSavedPetname } = useDisplayName( + const { name: savedPetname, sourceId: savedSourceId } = useName( value, type, + variation, ); + + const { name: displayName, hasPetname: hasSavedPetname } = useDisplayName({ + value, + type, + variation, + }); + const nameSources = useSelector(getNameSources, isEqual); const [name, setName] = useState(''); const [openMetricSent, setOpenMetricSent] = useState(false); @@ -226,7 +236,7 @@ export default function NameDetails({ const { proposedNames, initialSources } = useProposedNames( value, type, - chainId, + variation, ); const [copiedAddress, handleCopyAddress] = useCopyToClipboard() as [ @@ -275,12 +285,12 @@ export default function NameDetails({ type, name: name?.length ? name : null, sourceId: selectedSourceId, - variation: chainId, + variation, }), ); onClose(); - }, [name, selectedSourceId, onClose, trackPetnamesSaveEvent, chainId]); + }, [name, selectedSourceId, onClose, trackPetnamesSaveEvent, variation]); const handleClose = useCallback(() => { onClose(); @@ -333,6 +343,7 @@ export default function NameDetails({ diff --git a/ui/components/app/name/name.test.tsx b/ui/components/app/name/name.test.tsx index 061d39e670de..33648e98e38c 100644 --- a/ui/components/app/name/name.test.tsx +++ b/ui/components/app/name/name.test.tsx @@ -22,6 +22,7 @@ jest.mock('react-redux', () => ({ const ADDRESS_NO_SAVED_NAME_MOCK = '0xc0ffee254729296a45a3885639ac7e10f9d54977'; const ADDRESS_SAVED_NAME_MOCK = '0xc0ffee254729296a45a3885639ac7e10f9d54979'; const SAVED_NAME_MOCK = 'TestName'; +const VARIATION_MOCK = 'testVariation'; const STATE_MOCK = { metamask: { @@ -44,7 +45,11 @@ describe('Name', () => { }); const { container } = renderWithProvider( - , + , store, ); @@ -61,6 +66,7 @@ describe('Name', () => { , store, ); @@ -75,7 +81,11 @@ describe('Name', () => { }); const { container } = renderWithProvider( - , + , store, ); @@ -90,7 +100,11 @@ describe('Name', () => { }); const { container } = renderWithProvider( - , + , store, ); @@ -114,7 +128,11 @@ describe('Name', () => { renderWithProvider( - + , store, ); diff --git a/ui/components/app/name/name.tsx b/ui/components/app/name/name.tsx index 5af2851c8885..2097d21faf07 100644 --- a/ui/components/app/name/name.tsx +++ b/ui/components/app/name/name.tsx @@ -38,6 +38,12 @@ export type NameProps = { /** The raw value to display the name of. */ value: string; + + /** + * The variation of the value. + * Such as the chain ID if the `type` is an Ethereum address. + */ + variation: string; }; function formatValue(value: string, type: NameType): string { @@ -61,15 +67,17 @@ const Name = memo( disableEdit, internal, preferContractSymbol = false, + variation, }: NameProps) => { const [modalOpen, setModalOpen] = useState(false); const trackEvent = useContext(MetaMetricsContext); - const { name, hasPetname, image } = useDisplayName( + const { name, hasPetname, image } = useDisplayName({ value, type, preferContractSymbol, - ); + variation, + }); useEffect(() => { if (internal) { @@ -100,7 +108,12 @@ const Name = memo( return ( {!disableEdit && modalOpen && ( - + )}

= ({ const shortenedAddress = shortenAddress(transformedAddress); return ( - + {shortenedAddress} diff --git a/ui/components/app/snaps/snap-ui-link/index.scss b/ui/components/app/snaps/snap-ui-link/index.scss new file mode 100644 index 000000000000..7d3f75f0e372 --- /dev/null +++ b/ui/components/app/snaps/snap-ui-link/index.scss @@ -0,0 +1,11 @@ +.snap-ui-renderer__link { + & .snap-ui-renderer__address { + // Fixes an issue where the link end icon would wrap + display: inline-flex; + } + + .snap-ui-renderer__address + .mm-icon { + // This fixes an issue where the icon would be misaligned with the Address component + top: 0; + } +} diff --git a/ui/components/app/snaps/snap-ui-link/snap-ui-link.js b/ui/components/app/snaps/snap-ui-link/snap-ui-link.js index a1289543fd45..58a22008a52a 100644 --- a/ui/components/app/snaps/snap-ui-link/snap-ui-link.js +++ b/ui/components/app/snaps/snap-ui-link/snap-ui-link.js @@ -34,7 +34,7 @@ export const SnapUILink = ({ href, children }) => { {children} @@ -51,7 +51,14 @@ export const SnapUILink = ({ href, children }) => { externalLink size={ButtonLinkSize.Inherit} display={Display.Inline} - className="snap-ui-link" + className="snap-ui-renderer__link" + style={{ + // Prevents the link from taking up the full width of the parent. + width: 'fit-content', + }} + textProps={{ + display: Display.Inline, + }} > {children} diff --git a/ui/components/app/snaps/snap-ui-renderer/index.scss b/ui/components/app/snaps/snap-ui-renderer/index.scss index 7e18e72c917f..d32edf726479 100644 --- a/ui/components/app/snaps/snap-ui-renderer/index.scss +++ b/ui/components/app/snaps/snap-ui-renderer/index.scss @@ -34,6 +34,10 @@ border-radius: 8px; border-color: var(--color-border-muted); + & .mm-icon { + top: 0; + } + .mm-text--overflow-wrap-anywhere { overflow-wrap: normal; } @@ -48,10 +52,6 @@ &__panel { gap: 8px; - - .mm-icon--size-inherit { - top: 0; - } } &__text { diff --git a/ui/components/app/toast-master/selectors.ts b/ui/components/app/toast-master/selectors.ts new file mode 100644 index 000000000000..b88762c3bc19 --- /dev/null +++ b/ui/components/app/toast-master/selectors.ts @@ -0,0 +1,108 @@ +import { InternalAccount, isEvmAccountType } from '@metamask/keyring-api'; +import { getAlertEnabledness } from '../../../ducks/metamask/metamask'; +import { PRIVACY_POLICY_DATE } from '../../../helpers/constants/privacy-policy'; +import { + SURVEY_DATE, + SURVEY_END_TIME, + SURVEY_START_TIME, +} from '../../../helpers/constants/survey'; +import { getPermittedAccountsForCurrentTab } from '../../../selectors'; +import { MetaMaskReduxState } from '../../../store/store'; +import { getIsPrivacyToastRecent } from './utils'; + +// TODO: get this into one of the larger definitions of state type +type State = Omit & { + appState: { + showNftDetectionEnablementToast?: boolean; + }; + metamask: { + newPrivacyPolicyToastClickedOrClosed?: boolean; + newPrivacyPolicyToastShownDate?: number; + onboardingDate?: number; + showNftDetectionEnablementToast?: boolean; + surveyLinkLastClickedOrClosed?: number; + switchedNetworkNeverShowMessage?: boolean; + }; +}; + +/** + * Determines if the survey toast should be shown based on the current time, survey start and end times, and whether the survey link was last clicked or closed. + * + * @param state - The application state containing the necessary survey data. + * @returns True if the current time is between the survey start and end times and the survey link was not last clicked or closed. False otherwise. + */ +export function selectShowSurveyToast(state: State): boolean { + if (state.metamask?.surveyLinkLastClickedOrClosed) { + return false; + } + + const startTime = new Date(`${SURVEY_DATE} ${SURVEY_START_TIME}`).getTime(); + const endTime = new Date(`${SURVEY_DATE} ${SURVEY_END_TIME}`).getTime(); + const now = Date.now(); + + return now > startTime && now < endTime; +} + +/** + * Determines if the privacy policy toast should be shown based on the current date and whether the new privacy policy toast was clicked or closed. + * + * @param state - The application state containing the privacy policy data. + * @returns Boolean is True if the toast should be shown, and the number is the date the toast was last shown. + */ +export function selectShowPrivacyPolicyToast(state: State): { + showPrivacyPolicyToast: boolean; + newPrivacyPolicyToastShownDate?: number; +} { + const { + newPrivacyPolicyToastClickedOrClosed, + newPrivacyPolicyToastShownDate, + onboardingDate, + } = state.metamask || {}; + const newPrivacyPolicyDate = new Date(PRIVACY_POLICY_DATE); + const currentDate = new Date(Date.now()); + + const showPrivacyPolicyToast = + !newPrivacyPolicyToastClickedOrClosed && + currentDate >= newPrivacyPolicyDate && + getIsPrivacyToastRecent(newPrivacyPolicyToastShownDate) && + // users who onboarded before the privacy policy date should see the notice + // and + // old users who don't have onboardingDate set should see the notice + (!onboardingDate || onboardingDate < newPrivacyPolicyDate.valueOf()); + + return { showPrivacyPolicyToast, newPrivacyPolicyToastShownDate }; +} + +export function selectNftDetectionEnablementToast(state: State): boolean { + return Boolean(state.appState?.showNftDetectionEnablementToast); +} + +// If there is more than one connected account to activeTabOrigin, +// *BUT* the current account is not one of them, show the banner +export function selectShowConnectAccountToast( + state: State, + account: InternalAccount, +): boolean { + const allowShowAccountSetting = getAlertEnabledness(state).unconnectedAccount; + const connectedAccounts = getPermittedAccountsForCurrentTab(state); + const isEvmAccount = isEvmAccountType(account?.type); + + return ( + allowShowAccountSetting && + account && + state.activeTab?.origin && + isEvmAccount && + connectedAccounts.length > 0 && + !connectedAccounts.some((address) => address === account.address) + ); +} + +/** + * Retrieves user preference to never see the "Switched Network" toast + * + * @param state - Redux state object. + * @returns Boolean preference value + */ +export function selectSwitchedNetworkNeverShowMessage(state: State): boolean { + return Boolean(state.metamask.switchedNetworkNeverShowMessage); +} diff --git a/ui/components/app/toast-master/toast-master.js b/ui/components/app/toast-master/toast-master.js new file mode 100644 index 000000000000..584f1cc25983 --- /dev/null +++ b/ui/components/app/toast-master/toast-master.js @@ -0,0 +1,299 @@ +/* eslint-disable react/prop-types -- TODO: upgrade to TypeScript */ + +import React, { useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { useHistory, useLocation } from 'react-router-dom'; +import { MILLISECOND, SECOND } from '../../../../shared/constants/time'; +import { + PRIVACY_POLICY_LINK, + SURVEY_LINK, +} from '../../../../shared/lib/ui-utils'; +import { + BorderColor, + BorderRadius, + IconColor, + TextVariant, +} from '../../../helpers/constants/design-system'; +import { + DEFAULT_ROUTE, + REVIEW_PERMISSIONS, +} from '../../../helpers/constants/routes'; +import { getURLHost } from '../../../helpers/utils/util'; +import { useI18nContext } from '../../../hooks/useI18nContext'; +import { usePrevious } from '../../../hooks/usePrevious'; +import { + getCurrentNetwork, + getOriginOfCurrentTab, + getSelectedAccount, + getSwitchedNetworkDetails, + getUseNftDetection, +} from '../../../selectors'; +import { + addPermittedAccount, + clearSwitchedNetworkDetails, + hidePermittedNetworkToast, +} from '../../../store/actions'; +import { + AvatarAccount, + AvatarAccountSize, + AvatarNetwork, + Icon, + IconName, +} from '../../component-library'; +import { Toast, ToastContainer } from '../../multichain'; +import { SurveyToast } from '../../ui/survey-toast'; +import { + selectNftDetectionEnablementToast, + selectShowConnectAccountToast, + selectShowPrivacyPolicyToast, + selectShowSurveyToast, + selectSwitchedNetworkNeverShowMessage, +} from './selectors'; +import { + setNewPrivacyPolicyToastClickedOrClosed, + setNewPrivacyPolicyToastShownDate, + setShowNftDetectionEnablementToast, + setSurveyLinkLastClickedOrClosed, + setSwitchedNetworkNeverShowMessage, +} from './utils'; + +export function ToastMaster() { + const location = useLocation(); + + const onHomeScreen = location.pathname === DEFAULT_ROUTE; + + return ( + onHomeScreen && ( + + + + + + + + + + ) + ); +} + +function ConnectAccountToast() { + const t = useI18nContext(); + const dispatch = useDispatch(); + + const [hideConnectAccountToast, setHideConnectAccountToast] = useState(false); + const account = useSelector(getSelectedAccount); + + // If the account has changed, allow the connect account toast again + const prevAccountAddress = usePrevious(account?.address); + if (account?.address !== prevAccountAddress && hideConnectAccountToast) { + setHideConnectAccountToast(false); + } + + const showConnectAccountToast = useSelector((state) => + selectShowConnectAccountToast(state, account), + ); + + const activeTabOrigin = useSelector(getOriginOfCurrentTab); + + return ( + Boolean(!hideConnectAccountToast && showConnectAccountToast) && ( + + } + text={t('accountIsntConnectedToastText', [ + account?.metadata?.name, + getURLHost(activeTabOrigin), + ])} + actionText={t('connectAccount')} + onActionClick={() => { + // Connect this account + dispatch(addPermittedAccount(activeTabOrigin, account.address)); + // Use setTimeout to prevent React re-render from + // hiding the tooltip + setTimeout(() => { + // Trigger a mouseenter on the header's connection icon + // to display the informative connection tooltip + document + .querySelector( + '[data-testid="connection-menu"] [data-tooltipped]', + ) + ?.dispatchEvent(new CustomEvent('mouseenter', {})); + }, 250 * MILLISECOND); + }} + onClose={() => setHideConnectAccountToast(true)} + /> + ) + ); +} + +function SurveyToastMayDelete() { + const t = useI18nContext(); + + const showSurveyToast = useSelector(selectShowSurveyToast); + + return ( + showSurveyToast && ( + + } + text={t('surveyTitle')} + actionText={t('surveyConversion')} + onActionClick={() => { + global.platform.openTab({ + url: SURVEY_LINK, + }); + setSurveyLinkLastClickedOrClosed(Date.now()); + }} + onClose={() => { + setSurveyLinkLastClickedOrClosed(Date.now()); + }} + /> + ) + ); +} + +function PrivacyPolicyToast() { + const t = useI18nContext(); + + const { showPrivacyPolicyToast, newPrivacyPolicyToastShownDate } = + useSelector(selectShowPrivacyPolicyToast); + + // If the privacy policy toast is shown, and there is no date set, set it + if (showPrivacyPolicyToast && !newPrivacyPolicyToastShownDate) { + setNewPrivacyPolicyToastShownDate(Date.now()); + } + + return ( + showPrivacyPolicyToast && ( + + } + text={t('newPrivacyPolicyTitle')} + actionText={t('newPrivacyPolicyActionButton')} + onActionClick={() => { + global.platform.openTab({ + url: PRIVACY_POLICY_LINK, + }); + setNewPrivacyPolicyToastClickedOrClosed(); + }} + onClose={setNewPrivacyPolicyToastClickedOrClosed} + /> + ) + ); +} + +function SwitchedNetworkToast() { + const t = useI18nContext(); + const dispatch = useDispatch(); + + const switchedNetworkDetails = useSelector(getSwitchedNetworkDetails); + const switchedNetworkNeverShowMessage = useSelector( + selectSwitchedNetworkNeverShowMessage, + ); + + const isShown = switchedNetworkDetails && !switchedNetworkNeverShowMessage; + + return ( + isShown && ( + + } + text={t('switchedNetworkToastMessage', [ + switchedNetworkDetails.nickname, + getURLHost(switchedNetworkDetails.origin), + ])} + actionText={t('switchedNetworkToastDecline')} + onActionClick={setSwitchedNetworkNeverShowMessage} + onClose={() => dispatch(clearSwitchedNetworkDetails())} + /> + ) + ); +} + +function NftEnablementToast() { + const t = useI18nContext(); + const dispatch = useDispatch(); + + const showNftEnablementToast = useSelector(selectNftDetectionEnablementToast); + const useNftDetection = useSelector(getUseNftDetection); + + const autoHideToastDelay = 5 * SECOND; + + return ( + showNftEnablementToast && + useNftDetection && ( + + } + text={t('nftAutoDetectionEnabled')} + borderRadius={BorderRadius.LG} + textVariant={TextVariant.bodyMd} + autoHideTime={autoHideToastDelay} + onAutoHideToast={() => + dispatch(setShowNftDetectionEnablementToast(false)) + } + /> + ) + ); +} + +function PermittedNetworkToast() { + const t = useI18nContext(); + const dispatch = useDispatch(); + + const isPermittedNetworkToastOpen = useSelector( + (state) => state.appState.showPermittedNetworkToastOpen, + ); + + const currentNetwork = useSelector(getCurrentNetwork); + const activeTabOrigin = useSelector(getOriginOfCurrentTab); + const safeEncodedHost = encodeURIComponent(activeTabOrigin); + const history = useHistory(); + + return ( + isPermittedNetworkToastOpen && ( + + } + text={t('permittedChainToastUpdate', [ + getURLHost(activeTabOrigin), + currentNetwork?.nickname, + ])} + actionText={t('editPermissions')} + onActionClick={() => { + dispatch(hidePermittedNetworkToast()); + history.push(`${REVIEW_PERMISSIONS}/${safeEncodedHost}`); + }} + onClose={() => dispatch(hidePermittedNetworkToast())} + /> + ) + ); +} diff --git a/ui/components/app/toast-master/toast-master.test.ts b/ui/components/app/toast-master/toast-master.test.ts new file mode 100644 index 000000000000..8b29f20a240d --- /dev/null +++ b/ui/components/app/toast-master/toast-master.test.ts @@ -0,0 +1,206 @@ +import { PRIVACY_POLICY_DATE } from '../../../helpers/constants/privacy-policy'; +import { SURVEY_DATE, SURVEY_GMT } from '../../../helpers/constants/survey'; +import { + selectShowPrivacyPolicyToast, + selectShowSurveyToast, +} from './selectors'; + +describe('#getShowSurveyToast', () => { + const realDateNow = Date.now; + + afterEach(() => { + Date.now = realDateNow; + }); + + it('shows the survey link when not yet seen and within time bounds', () => { + Date.now = () => + new Date(`${SURVEY_DATE} 12:25:00 ${SURVEY_GMT}`).getTime(); + const result = selectShowSurveyToast({ + // @ts-expect-error: intentionally passing incomplete input + metamask: { + surveyLinkLastClickedOrClosed: undefined, + }, + }); + expect(result).toStrictEqual(true); + }); + + it('does not show the survey link when seen and within time bounds', () => { + Date.now = () => + new Date(`${SURVEY_DATE} 12:25:00 ${SURVEY_GMT}`).getTime(); + const result = selectShowSurveyToast({ + // @ts-expect-error: intentionally passing incomplete input + metamask: { + surveyLinkLastClickedOrClosed: 123456789, + }, + }); + expect(result).toStrictEqual(false); + }); + + it('does not show the survey link before time bounds', () => { + Date.now = () => + new Date(`${SURVEY_DATE} 11:25:00 ${SURVEY_GMT}`).getTime(); + const result = selectShowSurveyToast({ + // @ts-expect-error: intentionally passing incomplete input + metamask: { + surveyLinkLastClickedOrClosed: undefined, + }, + }); + expect(result).toStrictEqual(false); + }); + + it('does not show the survey link after time bounds', () => { + Date.now = () => + new Date(`${SURVEY_DATE} 14:25:00 ${SURVEY_GMT}`).getTime(); + const result = selectShowSurveyToast({ + // @ts-expect-error: intentionally passing incomplete input + metamask: { + surveyLinkLastClickedOrClosed: undefined, + }, + }); + expect(result).toStrictEqual(false); + }); +}); + +describe('#getShowPrivacyPolicyToast', () => { + let dateNowSpy: jest.SpyInstance; + + describe('mock one day after', () => { + beforeEach(() => { + const dayAfterPolicyDate = new Date(PRIVACY_POLICY_DATE); + dayAfterPolicyDate.setDate(dayAfterPolicyDate.getDate() + 1); + + dateNowSpy = jest + .spyOn(Date, 'now') + .mockReturnValue(dayAfterPolicyDate.getTime()); + }); + + afterEach(() => { + dateNowSpy.mockRestore(); + }); + + it('shows the privacy policy toast when not yet seen, on or after the policy date, and onboardingDate is before the policy date', () => { + const result = selectShowPrivacyPolicyToast({ + // @ts-expect-error: intentionally passing incomplete input + metamask: { + newPrivacyPolicyToastClickedOrClosed: false, + onboardingDate: new Date(PRIVACY_POLICY_DATE).setDate( + new Date(PRIVACY_POLICY_DATE).getDate() - 2, + ), + }, + }); + expect(result.showPrivacyPolicyToast).toBe(true); + }); + + it('does not show the privacy policy toast when seen, even if on or after the policy date and onboardingDate is before the policy date', () => { + const result = selectShowPrivacyPolicyToast({ + // @ts-expect-error: intentionally passing incomplete input + metamask: { + newPrivacyPolicyToastClickedOrClosed: true, + onboardingDate: new Date(PRIVACY_POLICY_DATE).setDate( + new Date(PRIVACY_POLICY_DATE).getDate() - 2, + ), + }, + }); + expect(result.showPrivacyPolicyToast).toBe(false); + }); + + it('shows the privacy policy toast when not yet seen, on or after the policy date, and onboardingDate is not set', () => { + const result = selectShowPrivacyPolicyToast({ + // @ts-expect-error: intentionally passing incomplete input + metamask: { + newPrivacyPolicyToastClickedOrClosed: false, + onboardingDate: undefined, + }, + }); + expect(result.showPrivacyPolicyToast).toBe(true); + }); + }); + + describe('mock same day', () => { + beforeEach(() => { + dateNowSpy = jest + .spyOn(Date, 'now') + .mockReturnValue(new Date(PRIVACY_POLICY_DATE).getTime()); + }); + + afterEach(() => { + dateNowSpy.mockRestore(); + }); + + it('shows the privacy policy toast when not yet seen, on or after the policy date, and onboardingDate is before the policy date', () => { + const result = selectShowPrivacyPolicyToast({ + // @ts-expect-error: intentionally passing incomplete input + metamask: { + newPrivacyPolicyToastClickedOrClosed: false, + onboardingDate: new Date(PRIVACY_POLICY_DATE).setDate( + new Date(PRIVACY_POLICY_DATE).getDate() - 2, + ), + }, + }); + expect(result.showPrivacyPolicyToast).toBe(true); + }); + + it('does not show the privacy policy toast when seen, even if on or after the policy date and onboardingDate is before the policy date', () => { + const result = selectShowPrivacyPolicyToast({ + // @ts-expect-error: intentionally passing incomplete input + metamask: { + newPrivacyPolicyToastClickedOrClosed: true, + onboardingDate: new Date(PRIVACY_POLICY_DATE).setDate( + new Date(PRIVACY_POLICY_DATE).getDate() - 2, + ), + }, + }); + expect(result.showPrivacyPolicyToast).toBe(false); + }); + + it('shows the privacy policy toast when not yet seen, on or after the policy date, and onboardingDate is not set', () => { + const result = selectShowPrivacyPolicyToast({ + // @ts-expect-error: intentionally passing incomplete input + metamask: { + newPrivacyPolicyToastClickedOrClosed: false, + onboardingDate: undefined, + }, + }); + expect(result.showPrivacyPolicyToast).toBe(true); + }); + }); + + describe('mock day before', () => { + beforeEach(() => { + const dayBeforePolicyDate = new Date(PRIVACY_POLICY_DATE); + dayBeforePolicyDate.setDate(dayBeforePolicyDate.getDate() - 1); + + dateNowSpy = jest + .spyOn(Date, 'now') + .mockReturnValue(dayBeforePolicyDate.getTime()); + }); + + afterEach(() => { + dateNowSpy.mockRestore(); + }); + + it('does not show the privacy policy toast before the policy date', () => { + const result = selectShowPrivacyPolicyToast({ + // @ts-expect-error: intentionally passing incomplete input + metamask: { + newPrivacyPolicyToastClickedOrClosed: false, + onboardingDate: new Date(PRIVACY_POLICY_DATE).setDate( + new Date(PRIVACY_POLICY_DATE).getDate() - 2, + ), + }, + }); + expect(result.showPrivacyPolicyToast).toBe(false); + }); + + it('does not show the privacy policy toast before the policy date even if onboardingDate is not set', () => { + const result = selectShowPrivacyPolicyToast({ + // @ts-expect-error: intentionally passing incomplete input + metamask: { + newPrivacyPolicyToastClickedOrClosed: false, + onboardingDate: undefined, + }, + }); + expect(result.showPrivacyPolicyToast).toBe(false); + }); + }); +}); diff --git a/ui/components/app/toast-master/utils.ts b/ui/components/app/toast-master/utils.ts new file mode 100644 index 000000000000..d6544707f45d --- /dev/null +++ b/ui/components/app/toast-master/utils.ts @@ -0,0 +1,69 @@ +import { PayloadAction } from '@reduxjs/toolkit'; +import { ReactFragment } from 'react'; +import { SHOW_NFT_DETECTION_ENABLEMENT_TOAST } from '../../../store/actionConstants'; +import { submitRequestToBackground } from '../../../store/background-connection'; + +/** + * Returns true if the privacy policy toast was shown either never, or less than a day ago. + * + * @param newPrivacyPolicyToastShownDate + * @returns true if the privacy policy toast was shown either never, or less than a day ago + */ +export function getIsPrivacyToastRecent( + newPrivacyPolicyToastShownDate?: number, +): boolean { + if (!newPrivacyPolicyToastShownDate) { + return true; + } + + const currentDate = new Date(); + const oneDayInMilliseconds = 24 * 60 * 60 * 1000; + const newPrivacyPolicyToastShownDateObj = new Date( + newPrivacyPolicyToastShownDate, + ); + const toastWasShownLessThanADayAgo = + currentDate.valueOf() - newPrivacyPolicyToastShownDateObj.valueOf() < + oneDayInMilliseconds; + + return toastWasShownLessThanADayAgo; +} + +export function setNewPrivacyPolicyToastShownDate(time: number) { + submitRequestToBackgroundAndCatch('setNewPrivacyPolicyToastShownDate', [ + time, + ]); +} + +export function setNewPrivacyPolicyToastClickedOrClosed() { + submitRequestToBackgroundAndCatch('setNewPrivacyPolicyToastClickedOrClosed'); +} + +export function setShowNftDetectionEnablementToast( + value: boolean, +): PayloadAction { + return { + type: SHOW_NFT_DETECTION_ENABLEMENT_TOAST, + payload: value, + }; +} + +export function setSwitchedNetworkNeverShowMessage() { + submitRequestToBackgroundAndCatch('setSwitchedNetworkNeverShowMessage', [ + true, + ]); +} + +export function setSurveyLinkLastClickedOrClosed(time: number) { + submitRequestToBackgroundAndCatch('setSurveyLinkLastClickedOrClosed', [time]); +} + +// May move this to a different file after discussion with team +export function submitRequestToBackgroundAndCatch( + method: string, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + args?: any[], +) { + submitRequestToBackground(method, args)?.catch((error) => { + console.error('Error caught in submitRequestToBackground', error); + }); +} diff --git a/ui/components/app/transaction-list-item-details/transaction-list-item-details.component.js b/ui/components/app/transaction-list-item-details/transaction-list-item-details.component.js index 751b0f53e73a..226a2a9113c0 100644 --- a/ui/components/app/transaction-list-item-details/transaction-list-item-details.component.js +++ b/ui/components/app/transaction-list-item-details/transaction-list-item-details.component.js @@ -214,7 +214,7 @@ export default class TransactionListItemDetails extends PureComponent { primaryTransaction: transaction, initialTransaction: { type }, } = transactionGroup; - const { hash } = transaction; + const { chainId, hash } = transaction; return ( @@ -332,6 +332,7 @@ export default class TransactionListItemDetails extends PureComponent { recipientMetadataName={recipientMetadataName} senderName={senderNickname} senderAddress={senderAddress} + chainId={chainId} onRecipientClick={() => { this.context.trackEvent({ category: MetaMetricsEventCategory.Navigation, diff --git a/ui/components/multichain/account-list-item/account-list-item.js b/ui/components/multichain/account-list-item/account-list-item.js index 517639b1c86e..9e070b33954b 100644 --- a/ui/components/multichain/account-list-item/account-list-item.js +++ b/ui/components/multichain/account-list-item/account-list-item.js @@ -86,6 +86,7 @@ const AccountListItem = ({ isActive = false, startAccessory, onActionClick, + shouldScrollToWhenSelected = true, }) => { const t = useI18nContext(); const [accountOptionsMenuOpen, setAccountOptionsMenuOpen] = useState(false); @@ -128,10 +129,10 @@ const AccountListItem = ({ // scroll the item into view const itemRef = useRef(null); useEffect(() => { - if (selected) { + if (selected && shouldScrollToWhenSelected) { itemRef.current?.scrollIntoView?.(); } - }, [itemRef, selected]); + }, [itemRef, selected, shouldScrollToWhenSelected]); const trackEvent = useContext(MetaMetricsContext); const primaryTokenImage = useMultichainSelector( @@ -502,6 +503,10 @@ AccountListItem.propTypes = { * Represents start accessory */ startAccessory: PropTypes.node, + /** + * Determines if list item should be scrolled to when selected + */ + shouldScrollToWhenSelected: PropTypes.bool, }; AccountListItem.displayName = 'AccountListItem'; diff --git a/ui/components/multichain/network-list-menu/network-list-menu.tsx b/ui/components/multichain/network-list-menu/network-list-menu.tsx index 5376dc17859e..518f9f19387a 100644 --- a/ui/components/multichain/network-list-menu/network-list-menu.tsx +++ b/ui/components/multichain/network-list-menu/network-list-menu.tsx @@ -251,10 +251,7 @@ export const NetworkListMenu = ({ onClose }: { onClose: () => void }) => { const generateNetworkListItem = (network: NetworkConfiguration) => { const isCurrentNetwork = network.chainId === currentChainId; const canDeleteNetwork = - isUnlocked && - !isCurrentNetwork && - network.chainId !== CHAIN_IDS.MAINNET && - network.chainId !== CHAIN_IDS.LINEA_MAINNET; + isUnlocked && !isCurrentNetwork && network.chainId !== CHAIN_IDS.MAINNET; return ( = ({ setShowEditAccountsModal(true); trackEvent({ category: MetaMetricsEventCategory.Navigation, - event: MetaMetricsEventName.TokenImportButtonClicked, + event: MetaMetricsEventName.ViewPermissionedAccounts, properties: { location: 'Connect view, Permissions toast, Permissions (dapp)', }, @@ -133,7 +133,7 @@ export const SiteCell: React.FC = ({ setShowEditNetworksModal(true); trackEvent({ category: MetaMetricsEventCategory.Navigation, - event: MetaMetricsEventName.TokenImportButtonClicked, + event: MetaMetricsEventName.ViewPermissionedNetworks, properties: { location: 'Connect view, Permissions toast, Permissions (dapp)', }, diff --git a/ui/components/multichain/pages/send/components/your-accounts.tsx b/ui/components/multichain/pages/send/components/your-accounts.tsx index f53d6603cb78..e59d0aa2d5a1 100644 --- a/ui/components/multichain/pages/send/components/your-accounts.tsx +++ b/ui/components/multichain/pages/send/components/your-accounts.tsx @@ -57,6 +57,7 @@ export const SendPageYourAccounts = ({ selected={selectedAccount.address === account.address} key={account.address} isPinned={Boolean(account.pinned)} + shouldScrollToWhenSelected={false} onClick={() => { dispatch( addHistoryEntry( diff --git a/ui/components/ui/definition-list/definition-list.js b/ui/components/ui/definition-list/definition-list.js index 84a23325b37a..84d3f48135ab 100644 --- a/ui/components/ui/definition-list/definition-list.js +++ b/ui/components/ui/definition-list/definition-list.js @@ -32,7 +32,7 @@ export default function DefinitionList({ {Object.entries(dictionary).map(([term, definition]) => ( ) : (
) : (
@@ -292,4 +297,5 @@ SenderToRecipient.propTypes = { onSenderClick: PropTypes.func, warnUserOnAccountMismatch: PropTypes.bool, recipientIsOwnedAccount: PropTypes.bool, + chainId: PropTypes.string, }; diff --git a/ui/components/ui/truncated-definition-list/truncated-definition-list.js b/ui/components/ui/truncated-definition-list/truncated-definition-list.js index ae1782979866..2db9784dad8e 100644 --- a/ui/components/ui/truncated-definition-list/truncated-definition-list.js +++ b/ui/components/ui/truncated-definition-list/truncated-definition-list.js @@ -5,7 +5,6 @@ import { BorderColor, Size } from '../../../helpers/constants/design-system'; import Box from '../box'; import Button from '../button'; import DefinitionList from '../definition-list/definition-list'; -import Popover from '../popover'; import { useI18nContext } from '../../../hooks/useI18nContext'; export default function TruncatedDefinitionList({ @@ -13,7 +12,6 @@ export default function TruncatedDefinitionList({ tooltips, warnings, prefaceKeys, - title, }) { const [isPopoverOpen, setIsPopoverOpen] = useState(false); const t = useI18nContext(); @@ -33,55 +31,27 @@ export default function TruncatedDefinitionList({ type="link" onClick={() => setIsPopoverOpen(true)} > - {t(process.env.CHAIN_PERMISSIONS ? 'seeDetails' : 'viewAllDetails')} + {t('seeDetails')} ); - const renderPopover = () => - isPopoverOpen && ( - setIsPopoverOpen(false)} - footer={ - - } - > - - {renderDefinitionList(true)} - - - ); - const renderContent = () => { - if (process.env.CHAIN_PERMISSIONS) { - return isPopoverOpen ? ( - renderDefinitionList(true) - ) : ( - <> - {renderDefinitionList(false)} - {renderButton()} - - ); - } - return ( + return isPopoverOpen ? ( + renderDefinitionList(true) + ) : ( <> {renderDefinitionList(false)} {renderButton()} - {renderPopover()} ); }; return ( { { srcNetworkAllowlist: [CHAIN_IDS.ARBITRUM] }, { toChainId: '0xe708' }, {}, - { ...mockNetworkState(FEATURED_RPCS[0]) }, + { ...mockNetworkState(FEATURED_RPCS[1]) }, ); const result = getFromChain(state as never); @@ -89,7 +89,7 @@ describe('Bridge selectors', () => { ); const result = getAllBridgeableNetworks(state as never); - expect(result).toHaveLength(7); + expect(result).toHaveLength(8); expect(result[0]).toStrictEqual( expect.objectContaining({ chainId: FEATURED_RPCS[0].chainId }), ); @@ -190,21 +190,19 @@ describe('Bridge selectors', () => { }, {}, {}, - mockNetworkState(...FEATURED_RPCS, { - chainId: CHAIN_IDS.LINEA_MAINNET, - }), + mockNetworkState(...FEATURED_RPCS), ); const result = getToChains(state as never); expect(result).toHaveLength(3); expect(result[0]).toStrictEqual( - expect.objectContaining({ chainId: CHAIN_IDS.OPTIMISM }), + expect.objectContaining({ chainId: CHAIN_IDS.ARBITRUM }), ); expect(result[1]).toStrictEqual( - expect.objectContaining({ chainId: CHAIN_IDS.POLYGON }), + expect.objectContaining({ chainId: CHAIN_IDS.OPTIMISM }), ); expect(result[2]).toStrictEqual( - expect.objectContaining({ chainId: CHAIN_IDS.LINEA_MAINNET }), + expect.objectContaining({ chainId: CHAIN_IDS.POLYGON }), ); }); @@ -297,7 +295,9 @@ describe('Bridge selectors', () => { { ...mockNetworkState( ...Object.values(BUILT_IN_NETWORKS), - ...FEATURED_RPCS, + ...FEATURED_RPCS.filter( + (network) => network.chainId !== CHAIN_IDS.LINEA_MAINNET, // Linea mainnet is both a built in network, as well as featured RPC + ), ), useExternalServices: true, }, diff --git a/ui/helpers/utils/notification.utils.test.ts b/ui/helpers/utils/notification.utils.test.ts index f82f8532cb58..2f4e66c26504 100644 --- a/ui/helpers/utils/notification.utils.test.ts +++ b/ui/helpers/utils/notification.utils.test.ts @@ -9,7 +9,7 @@ import { describe('formatMenuItemDate', () => { beforeAll(() => { jest.useFakeTimers(); - jest.setSystemTime(new Date('2024-06-07T09:40:00Z')); + jest.setSystemTime(new Date(Date.UTC(2024, 5, 7, 9, 40, 0))); // 2024-06-07T09:40:00Z }); afterAll(() => { @@ -28,7 +28,7 @@ describe('formatMenuItemDate', () => { // assert 1 hour ago assertToday((testDate) => { - testDate.setHours(testDate.getHours() - 1); + testDate.setUTCHours(testDate.getUTCHours() - 1); return testDate; }); }); @@ -42,14 +42,14 @@ describe('formatMenuItemDate', () => { // assert exactly 1 day ago assertYesterday((testDate) => { - testDate.setDate(testDate.getDate() - 1); + testDate.setUTCDate(testDate.getUTCDate() - 1); }); // assert almost a day ago, but was still yesterday // E.g. if Today way 09:40AM, but date to test was 23 hours ago (yesterday at 10:40AM), we still want to to show yesterday assertYesterday((testDate) => { - testDate.setDate(testDate.getDate() - 1); - testDate.setHours(testDate.getHours() + 1); + testDate.setUTCDate(testDate.getUTCDate() - 1); + testDate.setUTCHours(testDate.getUTCHours() + 1); }); }); @@ -62,18 +62,18 @@ describe('formatMenuItemDate', () => { // assert exactly 1 month ago assertMonthsAgo((testDate) => { - testDate.setMonth(testDate.getMonth() - 1); + testDate.setUTCMonth(testDate.getUTCMonth() - 1); }); // assert 2 months ago assertMonthsAgo((testDate) => { - testDate.setMonth(testDate.getMonth() - 2); + testDate.setUTCMonth(testDate.getUTCMonth() - 2); }); // assert almost a month ago (where it is a new month, but not 30 days) assertMonthsAgo(() => { // jest mock date is set in july, so we will test with month may - return new Date('2024-05-20T09:40:00Z'); + return new Date(Date.UTC(2024, 4, 20, 9, 40, 0)); // 2024-05-20T09:40:00Z }); }); @@ -86,18 +86,18 @@ describe('formatMenuItemDate', () => { // assert exactly 1 year ago assertYearsAgo((testDate) => { - testDate.setFullYear(testDate.getFullYear() - 1); + testDate.setUTCFullYear(testDate.getUTCFullYear() - 1); }); // assert 2 years ago assertYearsAgo((testDate) => { - testDate.setFullYear(testDate.getFullYear() - 2); + testDate.setUTCFullYear(testDate.getUTCFullYear() - 2); }); // assert almost a year ago (where it is a new year, but not 365 days ago) assertYearsAgo(() => { // jest mock date is set in 2024, so we will test with year 2023 - return new Date('2023-11-20T09:40:00Z'); + return new Date(Date.UTC(2023, 10, 20, 9, 40, 0)); // 2023-11-20T09:40:00Z }); }); }); diff --git a/ui/hooks/metamask-notifications/useNotifications.ts b/ui/hooks/metamask-notifications/useNotifications.ts index 62367cdbe310..9724253a8671 100644 --- a/ui/hooks/metamask-notifications/useNotifications.ts +++ b/ui/hooks/metamask-notifications/useNotifications.ts @@ -54,8 +54,13 @@ export function useListNotifications(): { setLoading(true); setError(null); + const urlParams = new URLSearchParams(window.location.search); + const previewToken = urlParams.get('previewToken'); + try { - const data = await dispatch(fetchAndUpdateMetamaskNotifications()); + const data = await dispatch( + fetchAndUpdateMetamaskNotifications(previewToken ?? undefined), + ); setNotificationsData(data as unknown as Notification[]); return data as unknown as Notification[]; } catch (e) { diff --git a/ui/hooks/useDisplayName.test.ts b/ui/hooks/useDisplayName.test.ts index 1d6fb22b5e69..5c36b0a97ed2 100644 --- a/ui/hooks/useDisplayName.test.ts +++ b/ui/hooks/useDisplayName.test.ts @@ -1,218 +1,533 @@ -import { NameEntry, NameType } from '@metamask/name-controller'; -import { NftContract } from '@metamask/assets-controllers'; -import { renderHook } from '@testing-library/react-hooks'; -import { getRemoteTokens } from '../selectors'; -import { getNftContractsByAddressOnCurrentChain } from '../selectors/nft'; +import { NameType } from '@metamask/name-controller'; +import { CHAIN_IDS } from '@metamask/transaction-controller'; +import { cloneDeep } from 'lodash'; +import { Hex } from '@metamask/utils'; +import { renderHookWithProvider } from '../../test/lib/render-helpers'; +import mockState from '../../test/data/mock-state.json'; +import { + EXPERIENCES_TYPE, + FIRST_PARTY_CONTRACT_NAMES, +} from '../../shared/constants/first-party-contracts'; import { useDisplayName } from './useDisplayName'; -import { useNames } from './useName'; -import { useFirstPartyContractNames } from './useFirstPartyContractName'; import { useNftCollectionsMetadata } from './useNftCollectionsMetadata'; +import { useNames } from './useName'; -jest.mock('react-redux', () => ({ - // TODO: Replace `any` with type - // eslint-disable-next-line @typescript-eslint/no-explicit-any - useSelector: (selector: any) => selector(), -})); - -jest.mock('./useName', () => ({ - useNames: jest.fn(), -})); - -jest.mock('./useFirstPartyContractName', () => ({ - useFirstPartyContractNames: jest.fn(), -})); - -jest.mock('./useNftCollectionsMetadata', () => ({ - useNftCollectionsMetadata: jest.fn(), -})); - -jest.mock('../selectors', () => ({ - getRemoteTokens: jest.fn(), - getCurrentChainId: jest.fn(), -})); - -jest.mock('../selectors/nft', () => ({ - getNftContractsByAddressOnCurrentChain: jest.fn(), -})); - -const VALUE_MOCK = '0xabc123'; -const TYPE_MOCK = NameType.ETHEREUM_ADDRESS; -const NAME_MOCK = 'TestName'; -const CONTRACT_NAME_MOCK = 'TestContractName'; -const FIRST_PARTY_CONTRACT_NAME_MOCK = 'MetaMask Bridge'; -const WATCHED_NFT_NAME_MOCK = 'TestWatchedNFTName'; - -const NO_PETNAME_FOUND_RETURN_VALUE = { - name: null, -} as NameEntry; -const NO_CONTRACT_NAME_FOUND_RETURN_VALUE = undefined; -const NO_FIRST_PARTY_CONTRACT_NAME_FOUND_RETURN_VALUE = null; -const NO_WATCHED_NFT_NAME_FOUND_RETURN_VALUE = {}; - -const PETNAME_FOUND_RETURN_VALUE = { - name: NAME_MOCK, -} as NameEntry; - -const WATCHED_NFT_FOUND_RETURN_VALUE = { - [VALUE_MOCK]: { - name: WATCHED_NFT_NAME_MOCK, - } as NftContract, -}; +jest.mock('./useName'); +jest.mock('./useNftCollectionsMetadata'); + +const VALUE_MOCK = 'testvalue'; +const VARIATION_MOCK = CHAIN_IDS.GOERLI; +const PETNAME_MOCK = 'testName1'; +const ERC20_TOKEN_NAME_MOCK = 'testName2'; +const WATCHED_NFT_NAME_MOCK = 'testName3'; +const NFT_NAME_MOCK = 'testName4'; +const FIRST_PARTY_CONTRACT_NAME_MOCK = 'testName5'; +const SYMBOL_MOCK = 'tes'; +const NFT_IMAGE_MOCK = 'testNftImage'; +const ERC20_IMAGE_MOCK = 'testImage'; +const OTHER_NAME_TYPE = 'test' as NameType; describe('useDisplayName', () => { const useNamesMock = jest.mocked(useNames); - const getRemoteTokensMock = jest.mocked(getRemoteTokens); - const useFirstPartyContractNamesMock = jest.mocked( - useFirstPartyContractNames, - ); - const getNftContractsByAddressOnCurrentChainMock = jest.mocked( - getNftContractsByAddressOnCurrentChain, - ); const useNftCollectionsMetadataMock = jest.mocked(useNftCollectionsMetadata); - beforeEach(() => { - jest.resetAllMocks(); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let state: any; - useNamesMock.mockReturnValue([NO_PETNAME_FOUND_RETURN_VALUE]); - useFirstPartyContractNamesMock.mockReturnValue([ - NO_FIRST_PARTY_CONTRACT_NAME_FOUND_RETURN_VALUE, - ]); - getRemoteTokensMock.mockReturnValue([ + function mockPetname(name: string) { + useNamesMock.mockReturnValue([ { - name: NO_CONTRACT_NAME_FOUND_RETURN_VALUE, + name, + sourceId: null, + proposedNames: {}, + origin: null, }, ]); - getNftContractsByAddressOnCurrentChainMock.mockReturnValue( - NO_WATCHED_NFT_NAME_FOUND_RETURN_VALUE, - ); - useNftCollectionsMetadataMock.mockReturnValue({}); - }); + } + + function mockERC20Token( + value: string, + variation: string, + name: string, + symbol: string, + image: string, + ) { + state.metamask.tokensChainsCache = { + [variation]: { + data: { + [value]: { + name, + symbol, + iconUrl: image, + }, + }, + }, + }; + } - it('handles no name found', () => { - const { result } = renderHook(() => useDisplayName(VALUE_MOCK, TYPE_MOCK)); - expect(result.current).toEqual({ - name: null, - hasPetname: false, + function mockWatchedNFTName(value: string, variation: string, name: string) { + state.metamask.allNftContracts = { + '0x123': { + [variation]: [{ address: value, name }], + }, + }; + } + + function mockNFT( + value: string, + variation: string, + name: string, + image: string, + isSpam: boolean, + ) { + useNftCollectionsMetadataMock.mockReturnValue({ + [variation]: { + [value]: { name, image, isSpam }, + }, }); - }); + } + + function mockFirstPartyContractName( + value: string, + variation: string, + name: string, + ) { + FIRST_PARTY_CONTRACT_NAMES[name as EXPERIENCES_TYPE] = { + [variation as Hex]: value as Hex, + }; + } - it('prioritizes a petname over all else', () => { - useNamesMock.mockReturnValue([PETNAME_FOUND_RETURN_VALUE]); - useFirstPartyContractNamesMock.mockReturnValue([ - FIRST_PARTY_CONTRACT_NAME_MOCK, - ]); - getRemoteTokensMock.mockReturnValue([ + beforeEach(() => { + jest.resetAllMocks(); + + useNftCollectionsMetadataMock.mockReturnValue({}); + + useNamesMock.mockReturnValue([ { - name: CONTRACT_NAME_MOCK, + name: null, + sourceId: null, + proposedNames: {}, + origin: null, }, ]); - getNftContractsByAddressOnCurrentChainMock.mockReturnValue( - WATCHED_NFT_FOUND_RETURN_VALUE, - ); - const { result } = renderHook(() => useDisplayName(VALUE_MOCK, TYPE_MOCK)); + state = cloneDeep(mockState); - expect(result.current).toEqual({ - name: NAME_MOCK, - hasPetname: true, - contractDisplayName: CONTRACT_NAME_MOCK, - }); + delete FIRST_PARTY_CONTRACT_NAMES[ + FIRST_PARTY_CONTRACT_NAME_MOCK as EXPERIENCES_TYPE + ]; }); - it('prioritizes a first-party contract name over a contract name and watched NFT name', () => { - useFirstPartyContractNamesMock.mockReturnValue([ - FIRST_PARTY_CONTRACT_NAME_MOCK, - ]); - getRemoteTokensMock.mockReturnValue({ - name: CONTRACT_NAME_MOCK, - }); - getNftContractsByAddressOnCurrentChainMock.mockReturnValue( - WATCHED_NFT_FOUND_RETURN_VALUE, + it('returns no name if no defaults found', () => { + const { result } = renderHookWithProvider( + () => + useDisplayName({ + value: VALUE_MOCK, + type: NameType.ETHEREUM_ADDRESS, + variation: VARIATION_MOCK, + }), + mockState, ); - const { result } = renderHook(() => useDisplayName(VALUE_MOCK, TYPE_MOCK)); - - expect(result.current).toEqual({ - name: FIRST_PARTY_CONTRACT_NAME_MOCK, + expect(result.current).toStrictEqual({ + contractDisplayName: undefined, hasPetname: false, + image: undefined, + name: null, }); }); - it('prioritizes a contract name over a watched NFT name', () => { - getRemoteTokensMock.mockReturnValue([ - { - name: CONTRACT_NAME_MOCK, - }, - ]); - getNftContractsByAddressOnCurrentChainMock.mockReturnValue( - WATCHED_NFT_FOUND_RETURN_VALUE, - ); + describe('Petname', () => { + it('returns petname', () => { + mockPetname(PETNAME_MOCK); + + const { result } = renderHookWithProvider( + () => + useDisplayName({ + value: VALUE_MOCK, + type: NameType.ETHEREUM_ADDRESS, + variation: VARIATION_MOCK, + }), + state, + ); + + expect(result.current).toStrictEqual({ + contractDisplayName: undefined, + hasPetname: true, + image: undefined, + name: PETNAME_MOCK, + }); + }); + }); - const { result } = renderHook(() => useDisplayName(VALUE_MOCK, TYPE_MOCK)); + describe('ERC-20 Token', () => { + it('returns ERC-20 token name and image', () => { + mockERC20Token( + VALUE_MOCK, + VARIATION_MOCK, + ERC20_TOKEN_NAME_MOCK, + SYMBOL_MOCK, + ERC20_IMAGE_MOCK, + ); + + const { result } = renderHookWithProvider( + () => + useDisplayName({ + value: VALUE_MOCK, + type: NameType.ETHEREUM_ADDRESS, + variation: VARIATION_MOCK, + }), + state, + ); + + expect(result.current).toStrictEqual({ + contractDisplayName: ERC20_TOKEN_NAME_MOCK, + hasPetname: false, + image: ERC20_IMAGE_MOCK, + name: ERC20_TOKEN_NAME_MOCK, + }); + }); - expect(result.current).toEqual({ - name: CONTRACT_NAME_MOCK, - hasPetname: false, - contractDisplayName: CONTRACT_NAME_MOCK, + it('returns ERC-20 token symbol', () => { + mockERC20Token( + VALUE_MOCK, + VARIATION_MOCK, + ERC20_TOKEN_NAME_MOCK, + SYMBOL_MOCK, + ERC20_IMAGE_MOCK, + ); + + const { result } = renderHookWithProvider( + () => + useDisplayName({ + value: VALUE_MOCK, + type: NameType.ETHEREUM_ADDRESS, + variation: CHAIN_IDS.GOERLI, + preferContractSymbol: true, + }), + state, + ); + + expect(result.current).toStrictEqual({ + contractDisplayName: SYMBOL_MOCK, + hasPetname: false, + image: ERC20_IMAGE_MOCK, + name: SYMBOL_MOCK, + }); }); - }); - it('returns a watched NFT name if no other name is found', () => { - getNftContractsByAddressOnCurrentChainMock.mockReturnValue( - WATCHED_NFT_FOUND_RETURN_VALUE, - ); + it('returns no name if type not address', () => { + mockERC20Token( + VALUE_MOCK, + VARIATION_MOCK, + ERC20_TOKEN_NAME_MOCK, + SYMBOL_MOCK, + ERC20_IMAGE_MOCK, + ); + + const { result } = renderHookWithProvider( + () => + useDisplayName({ + value: VALUE_MOCK, + type: OTHER_NAME_TYPE, + variation: CHAIN_IDS.GOERLI, + preferContractSymbol: true, + }), + state, + ); + + expect(result.current).toStrictEqual({ + contractDisplayName: undefined, + hasPetname: false, + image: undefined, + name: null, + }); + }); + }); - const { result } = renderHook(() => useDisplayName(VALUE_MOCK, TYPE_MOCK)); + describe('First-party Contract', () => { + it('returns first-party contract name', () => { + mockFirstPartyContractName( + VALUE_MOCK, + VARIATION_MOCK, + FIRST_PARTY_CONTRACT_NAME_MOCK, + ); + + const { result } = renderHookWithProvider( + () => + useDisplayName({ + value: VALUE_MOCK, + type: NameType.ETHEREUM_ADDRESS, + variation: VARIATION_MOCK, + }), + mockState, + ); + + expect(result.current).toStrictEqual({ + contractDisplayName: undefined, + hasPetname: false, + image: undefined, + name: FIRST_PARTY_CONTRACT_NAME_MOCK, + }); + }); - expect(result.current).toEqual({ - name: WATCHED_NFT_NAME_MOCK, - hasPetname: false, + it('returns no name if type is not address', () => { + const { result } = renderHookWithProvider( + () => + useDisplayName({ + value: + FIRST_PARTY_CONTRACT_NAMES[EXPERIENCES_TYPE.METAMASK_BRIDGE][ + CHAIN_IDS.OPTIMISM + ], + type: OTHER_NAME_TYPE, + variation: CHAIN_IDS.OPTIMISM, + }), + mockState, + ); + + expect(result.current).toStrictEqual({ + contractDisplayName: undefined, + hasPetname: false, + image: undefined, + name: null, + }); }); }); - it('returns nft collection name from metadata if no other name is found', () => { - const IMAGE_MOCK = 'url'; + describe('Watched NFT', () => { + it('returns watched NFT name', () => { + mockWatchedNFTName(VALUE_MOCK, VARIATION_MOCK, WATCHED_NFT_NAME_MOCK); + + const { result } = renderHookWithProvider( + () => + useDisplayName({ + value: VALUE_MOCK, + type: NameType.ETHEREUM_ADDRESS, + variation: VARIATION_MOCK, + }), + state, + ); + + expect(result.current).toStrictEqual({ + contractDisplayName: undefined, + hasPetname: false, + image: undefined, + name: WATCHED_NFT_NAME_MOCK, + }); + }); - useNftCollectionsMetadataMock.mockReturnValue({ - [VALUE_MOCK.toLowerCase()]: { - name: CONTRACT_NAME_MOCK, - image: IMAGE_MOCK, - isSpam: false, - }, + it('returns no name if type is not address', () => { + mockWatchedNFTName(VALUE_MOCK, VARIATION_MOCK, WATCHED_NFT_NAME_MOCK); + + const { result } = renderHookWithProvider( + () => + useDisplayName({ + value: VALUE_MOCK, + type: OTHER_NAME_TYPE, + variation: VARIATION_MOCK, + }), + state, + ); + + expect(result.current).toStrictEqual({ + contractDisplayName: undefined, + hasPetname: false, + image: undefined, + name: null, + }); + }); + }); + + describe('NFT', () => { + it('returns NFT name and image', () => { + mockNFT(VALUE_MOCK, VARIATION_MOCK, NFT_NAME_MOCK, NFT_IMAGE_MOCK, false); + + const { result } = renderHookWithProvider( + () => + useDisplayName({ + value: VALUE_MOCK, + type: NameType.ETHEREUM_ADDRESS, + variation: VARIATION_MOCK, + }), + mockState, + ); + + expect(result.current).toStrictEqual({ + contractDisplayName: undefined, + hasPetname: false, + image: NFT_IMAGE_MOCK, + name: NFT_NAME_MOCK, + }); }); - const { result } = renderHook(() => - useDisplayName(VALUE_MOCK, TYPE_MOCK, false), - ); + it('returns no name if NFT collection is spam', () => { + mockNFT(VALUE_MOCK, VARIATION_MOCK, NFT_NAME_MOCK, NFT_IMAGE_MOCK, true); + + const { result } = renderHookWithProvider( + () => + useDisplayName({ + value: VALUE_MOCK, + type: NameType.ETHEREUM_ADDRESS, + variation: VARIATION_MOCK, + }), + mockState, + ); + + expect(result.current).toStrictEqual({ + contractDisplayName: undefined, + hasPetname: false, + image: undefined, + name: null, + }); + }); - expect(result.current).toEqual({ - name: CONTRACT_NAME_MOCK, - hasPetname: false, - contractDisplayName: undefined, - image: IMAGE_MOCK, + it('returns no name if type not address', () => { + mockNFT(VALUE_MOCK, VARIATION_MOCK, NFT_NAME_MOCK, NFT_IMAGE_MOCK, false); + + const { result } = renderHookWithProvider( + () => + useDisplayName({ + value: VALUE_MOCK, + type: OTHER_NAME_TYPE, + variation: VARIATION_MOCK, + }), + mockState, + ); + + expect(result.current).toStrictEqual({ + contractDisplayName: undefined, + hasPetname: false, + image: undefined, + name: null, + }); }); }); - it('does not return nft collection name if collection is marked as spam', () => { - const IMAGE_MOCK = 'url'; + describe('Priority', () => { + it('uses petname as first priority', () => { + mockPetname(PETNAME_MOCK); + mockFirstPartyContractName( + VALUE_MOCK, + VARIATION_MOCK, + FIRST_PARTY_CONTRACT_NAME_MOCK, + ); + mockNFT(VALUE_MOCK, VARIATION_MOCK, NFT_NAME_MOCK, NFT_IMAGE_MOCK, false); + mockERC20Token( + VALUE_MOCK, + VARIATION_MOCK, + ERC20_TOKEN_NAME_MOCK, + SYMBOL_MOCK, + ERC20_IMAGE_MOCK, + ); + mockWatchedNFTName(VALUE_MOCK, VARIATION_MOCK, WATCHED_NFT_NAME_MOCK); + + const { result } = renderHookWithProvider( + () => + useDisplayName({ + value: VALUE_MOCK, + type: NameType.ETHEREUM_ADDRESS, + variation: VARIATION_MOCK, + }), + state, + ); + + expect(result.current).toStrictEqual({ + contractDisplayName: ERC20_TOKEN_NAME_MOCK, + hasPetname: true, + image: NFT_IMAGE_MOCK, + name: PETNAME_MOCK, + }); + }); - useNftCollectionsMetadataMock.mockReturnValue({ - [VALUE_MOCK.toLowerCase()]: { - name: CONTRACT_NAME_MOCK, - image: IMAGE_MOCK, - isSpam: true, - }, + it('uses first-party contract name as second priority', () => { + mockFirstPartyContractName( + VALUE_MOCK, + VARIATION_MOCK, + FIRST_PARTY_CONTRACT_NAME_MOCK, + ); + mockNFT(VALUE_MOCK, VARIATION_MOCK, NFT_NAME_MOCK, NFT_IMAGE_MOCK, false); + mockERC20Token( + VALUE_MOCK, + VARIATION_MOCK, + ERC20_TOKEN_NAME_MOCK, + SYMBOL_MOCK, + ERC20_IMAGE_MOCK, + ); + mockWatchedNFTName(VALUE_MOCK, VARIATION_MOCK, WATCHED_NFT_NAME_MOCK); + + const { result } = renderHookWithProvider( + () => + useDisplayName({ + value: VALUE_MOCK, + type: NameType.ETHEREUM_ADDRESS, + variation: VARIATION_MOCK, + }), + state, + ); + + expect(result.current).toStrictEqual({ + contractDisplayName: ERC20_TOKEN_NAME_MOCK, + hasPetname: false, + image: NFT_IMAGE_MOCK, + name: FIRST_PARTY_CONTRACT_NAME_MOCK, + }); }); - const { result } = renderHook(() => - useDisplayName(VALUE_MOCK, TYPE_MOCK, false), - ); + it('uses NFT name as third priority', () => { + mockNFT(VALUE_MOCK, VARIATION_MOCK, NFT_NAME_MOCK, NFT_IMAGE_MOCK, false); + mockERC20Token( + VALUE_MOCK, + VARIATION_MOCK, + ERC20_TOKEN_NAME_MOCK, + SYMBOL_MOCK, + ERC20_IMAGE_MOCK, + ); + mockWatchedNFTName(VALUE_MOCK, VARIATION_MOCK, WATCHED_NFT_NAME_MOCK); + + const { result } = renderHookWithProvider( + () => + useDisplayName({ + value: VALUE_MOCK, + type: NameType.ETHEREUM_ADDRESS, + variation: VARIATION_MOCK, + }), + state, + ); + + expect(result.current).toStrictEqual({ + contractDisplayName: ERC20_TOKEN_NAME_MOCK, + hasPetname: false, + image: NFT_IMAGE_MOCK, + name: NFT_NAME_MOCK, + }); + }); - expect(result.current).toEqual( - expect.objectContaining({ - name: null, - image: undefined, - }), - ); + it('uses ERC-20 token name as fourth priority', () => { + mockERC20Token( + VALUE_MOCK, + VARIATION_MOCK, + ERC20_TOKEN_NAME_MOCK, + SYMBOL_MOCK, + ERC20_IMAGE_MOCK, + ); + mockWatchedNFTName(VALUE_MOCK, VARIATION_MOCK, WATCHED_NFT_NAME_MOCK); + + const { result } = renderHookWithProvider( + () => + useDisplayName({ + value: VALUE_MOCK, + type: NameType.ETHEREUM_ADDRESS, + variation: VARIATION_MOCK, + }), + state, + ); + + expect(result.current).toStrictEqual({ + contractDisplayName: ERC20_TOKEN_NAME_MOCK, + hasPetname: false, + image: ERC20_IMAGE_MOCK, + name: ERC20_TOKEN_NAME_MOCK, + }); + }); }); }); diff --git a/ui/hooks/useDisplayName.ts b/ui/hooks/useDisplayName.ts index 64a878d2e357..7b7429c7a0d4 100644 --- a/ui/hooks/useDisplayName.ts +++ b/ui/hooks/useDisplayName.ts @@ -1,16 +1,20 @@ -import { useMemo } from 'react'; import { NameType } from '@metamask/name-controller'; import { useSelector } from 'react-redux'; -import { getRemoteTokens } from '../selectors'; -import { getNftContractsByAddressOnCurrentChain } from '../selectors/nft'; +import { Hex } from '@metamask/utils'; +import { selectERC20TokensByChain } from '../selectors'; +import { getNftContractsByAddressByChain } from '../selectors/nft'; +import { + EXPERIENCES_TYPE, + FIRST_PARTY_CONTRACT_NAMES, +} from '../../shared/constants/first-party-contracts'; import { useNames } from './useName'; -import { useFirstPartyContractNames } from './useFirstPartyContractName'; import { useNftCollectionsMetadata } from './useNftCollectionsMetadata'; export type UseDisplayNameRequest = { - value: string; preferContractSymbol?: boolean; type: NameType; + value: string; + variation: string; }; export type UseDisplayNameResponse = { @@ -23,79 +27,145 @@ export type UseDisplayNameResponse = { export function useDisplayNames( requests: UseDisplayNameRequest[], ): UseDisplayNameResponse[] { - const nameRequests = useMemo( - () => requests.map(({ value, type }) => ({ value, type })), - [requests], - ); - - const nameEntries = useNames(nameRequests); - const firstPartyContractNames = useFirstPartyContractNames(nameRequests); - const nftCollections = useNftCollectionsMetadata(nameRequests); - const values = requests.map(({ value }) => value); - - const contractInfo = useSelector((state) => - // TODO: Replace `any` with type - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (getRemoteTokens as any)(state, values), - ); + const nameEntries = useNames(requests); + const firstPartyContractNames = useFirstPartyContractNames(requests); + const erc20Tokens = useERC20Tokens(requests); + const watchedNFTNames = useWatchedNFTNames(requests); + const nfts = useNFTs(requests); - const watchedNftNames = useSelector(getNftContractsByAddressOnCurrentChain); - - return requests.map(({ value, preferContractSymbol }, index) => { + return requests.map((_request, index) => { const nameEntry = nameEntries[index]; const firstPartyContractName = firstPartyContractNames[index]; - const singleContractInfo = contractInfo[index]; - const watchedNftName = watchedNftNames[value.toLowerCase()]?.name; - const nftCollectionProperties = nftCollections[value.toLowerCase()]; - - const isNotSpam = nftCollectionProperties?.isSpam === false; - - const nftCollectionName = isNotSpam - ? nftCollectionProperties?.name - : undefined; - const nftCollectionImage = isNotSpam - ? nftCollectionProperties?.image - : undefined; - - const contractDisplayName = - preferContractSymbol && singleContractInfo?.symbol - ? singleContractInfo.symbol - : singleContractInfo?.name; + const erc20Token = erc20Tokens[index]; + const watchedNftName = watchedNFTNames[index]; + const nft = nfts[index]; const name = nameEntry?.name || firstPartyContractName || - nftCollectionName || - contractDisplayName || + nft?.name || + erc20Token?.name || watchedNftName || null; + const image = nft?.image || erc20Token?.image; + const hasPetname = Boolean(nameEntry?.name); return { name, hasPetname, - contractDisplayName, - image: nftCollectionImage, + contractDisplayName: erc20Token?.name, + image, }; }); } -/** - * Attempts to resolve the name for the given parameters. - * - * @param value - The address or contract address to resolve. - * @param type - The type of value, e.g. NameType.ETHEREUM_ADDRESS. - * @param preferContractSymbol - Applies to recognized contracts when no petname is saved: - * If true the contract symbol (e.g. WBTC) will be used instead of the contract name. - * @returns An object with two properties: - * - `name` {string|null} - The display name, if it can be resolved, otherwise null. - * - `hasPetname` {boolean} - True if there is a petname for the given address. - */ export function useDisplayName( - value: string, - type: NameType, - preferContractSymbol: boolean = false, + request: UseDisplayNameRequest, ): UseDisplayNameResponse { - return useDisplayNames([{ preferContractSymbol, type, value }])[0]; + return useDisplayNames([request])[0]; +} + +function useERC20Tokens( + nameRequests: UseDisplayNameRequest[], +): ({ name?: string; image?: string } | undefined)[] { + const erc20TokensByChain = useSelector(selectERC20TokensByChain); + + return nameRequests.map( + ({ preferContractSymbol, type, value, variation }) => { + if (type !== NameType.ETHEREUM_ADDRESS) { + return undefined; + } + + const contractAddress = value.toLowerCase(); + + const { + iconUrl: image, + name: tokenName, + symbol, + } = erc20TokensByChain?.[variation]?.data?.[contractAddress] ?? {}; + + const name = preferContractSymbol && symbol ? symbol : tokenName; + + return { name, image }; + }, + ); +} + +function useWatchedNFTNames( + nameRequests: UseDisplayNameRequest[], +): (string | undefined)[] { + const watchedNftNamesByAddressByChain = useSelector( + getNftContractsByAddressByChain, + ); + + return nameRequests.map(({ type, value, variation }) => { + if (type !== NameType.ETHEREUM_ADDRESS) { + return undefined; + } + + const contractAddress = value.toLowerCase(); + const watchedNftNamesByAddress = watchedNftNamesByAddressByChain[variation]; + return watchedNftNamesByAddress?.[contractAddress]?.name; + }); +} + +function useNFTs( + nameRequests: UseDisplayNameRequest[], +): ({ name?: string; image?: string } | undefined)[] { + const requests = nameRequests + .filter(({ type }) => type === NameType.ETHEREUM_ADDRESS) + .map(({ value, variation }) => ({ + chainId: variation, + contractAddress: value, + })); + + const nftCollectionsByAddressByChain = useNftCollectionsMetadata(requests); + + return nameRequests.map( + ({ type, value: contractAddress, variation: chainId }) => { + if (type !== NameType.ETHEREUM_ADDRESS) { + return undefined; + } + + const nftCollectionProperties = + nftCollectionsByAddressByChain[chainId]?.[ + contractAddress.toLowerCase() + ]; + + const isSpam = nftCollectionProperties?.isSpam !== false; + + if (!nftCollectionProperties || isSpam) { + return undefined; + } + + const { name, image } = nftCollectionProperties; + + return { name, image }; + }, + ); +} + +function useFirstPartyContractNames(nameRequests: UseDisplayNameRequest[]) { + return nameRequests.map(({ type, value, variation }) => { + if (type !== NameType.ETHEREUM_ADDRESS) { + return undefined; + } + + const normalizedContractAddress = value.toLowerCase(); + + const contractNames = Object.keys( + FIRST_PARTY_CONTRACT_NAMES, + ) as EXPERIENCES_TYPE[]; + + return contractNames.find((contractName) => { + const currentContractAddress = + FIRST_PARTY_CONTRACT_NAMES[contractName]?.[variation as Hex]; + + return ( + currentContractAddress?.toLowerCase() === normalizedContractAddress + ); + }); + }); } diff --git a/ui/hooks/useFirstPartyContractName.test.ts b/ui/hooks/useFirstPartyContractName.test.ts deleted file mode 100644 index 14d0cd429e6f..000000000000 --- a/ui/hooks/useFirstPartyContractName.test.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { NameType } from '@metamask/name-controller'; -import { getCurrentChainId } from '../selectors'; -import { CHAIN_IDS } from '../../shared/constants/network'; -import { useFirstPartyContractName } from './useFirstPartyContractName'; - -jest.mock('react-redux', () => ({ - // TODO: Replace `any` with type - // eslint-disable-next-line @typescript-eslint/no-explicit-any - useSelector: (selector: any) => selector(), -})); - -jest.mock('../selectors', () => ({ - getCurrentChainId: jest.fn(), - getNames: jest.fn(), -})); - -const BRIDGE_NAME_MOCK = 'MetaMask Bridge'; -const BRIDGE_MAINNET_ADDRESS_MOCK = - '0x0439e60F02a8900a951603950d8D4527f400C3f1'; -const BRIDGE_OPTIMISM_ADDRESS_MOCK = - '0xB90357f2b86dbfD59c3502215d4060f71DF8ca0e'; -const UNKNOWN_ADDRESS_MOCK = '0xabc123'; - -describe('useFirstPartyContractName', () => { - const getCurrentChainIdMock = jest.mocked(getCurrentChainId); - beforeEach(() => { - jest.resetAllMocks(); - - getCurrentChainIdMock.mockReturnValue(CHAIN_IDS.MAINNET); - }); - - it('returns null if no name found', () => { - const name = useFirstPartyContractName( - UNKNOWN_ADDRESS_MOCK, - NameType.ETHEREUM_ADDRESS, - ); - - expect(name).toBe(null); - }); - - it('returns name if found', () => { - const name = useFirstPartyContractName( - BRIDGE_MAINNET_ADDRESS_MOCK, - NameType.ETHEREUM_ADDRESS, - ); - expect(name).toBe(BRIDGE_NAME_MOCK); - }); - - it('uses variation if specified', () => { - const name = useFirstPartyContractName( - BRIDGE_OPTIMISM_ADDRESS_MOCK, - NameType.ETHEREUM_ADDRESS, - CHAIN_IDS.OPTIMISM, - ); - - expect(name).toBe(BRIDGE_NAME_MOCK); - }); - - it('returns null if type is not address', () => { - const alternateType = 'alternateType' as NameType; - - const name = useFirstPartyContractName( - BRIDGE_MAINNET_ADDRESS_MOCK, - alternateType, - ); - - expect(name).toBe(null); - }); - - it('normalizes addresses to lowercase', () => { - const name = useFirstPartyContractName( - BRIDGE_MAINNET_ADDRESS_MOCK.toUpperCase(), - NameType.ETHEREUM_ADDRESS, - ); - - expect(name).toBe(BRIDGE_NAME_MOCK); - }); -}); diff --git a/ui/hooks/useFirstPartyContractName.ts b/ui/hooks/useFirstPartyContractName.ts deleted file mode 100644 index 47468b472955..000000000000 --- a/ui/hooks/useFirstPartyContractName.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { NameType } from '@metamask/name-controller'; -import { useSelector } from 'react-redux'; -import { getCurrentChainId } from '../selectors'; -import { - EXPERIENCES_TYPE, - FIRST_PARTY_CONTRACT_NAMES, -} from '../../shared/constants/first-party-contracts'; - -export type UseFirstPartyContractNameRequest = { - value: string; - type: NameType; - variation?: string; -}; - -export function useFirstPartyContractNames( - requests: UseFirstPartyContractNameRequest[], -): (string | null)[] { - const currentChainId = useSelector(getCurrentChainId); - - return requests.map(({ type, value, variation }) => { - if (type !== NameType.ETHEREUM_ADDRESS) { - return null; - } - - const chainId = variation ?? currentChainId; - const normalizedValue = value.toLowerCase(); - - return ( - Object.keys(FIRST_PARTY_CONTRACT_NAMES).find( - (name) => - FIRST_PARTY_CONTRACT_NAMES[name as EXPERIENCES_TYPE]?.[ - chainId - ]?.toLowerCase() === normalizedValue, - ) ?? null - ); - }); -} - -export function useFirstPartyContractName( - value: string, - type: NameType, - variation?: string, -): string | null { - return useFirstPartyContractNames([{ value, type, variation }])[0]; -} diff --git a/ui/hooks/useName.test.ts b/ui/hooks/useName.test.ts index 76bd5dc593ad..f746c4bb6267 100644 --- a/ui/hooks/useName.test.ts +++ b/ui/hooks/useName.test.ts @@ -5,7 +5,7 @@ import { NameOrigin, NameType, } from '@metamask/name-controller'; -import { getCurrentChainId, getNames } from '../selectors'; +import { getNames } from '../selectors'; import { useName } from './useName'; jest.mock('react-redux', () => ({ @@ -19,13 +19,14 @@ jest.mock('../selectors', () => ({ getNames: jest.fn(), })); -const CHAIN_ID_MOCK = '0x1'; -const CHAIN_ID_2_MOCK = '0x2'; +const VARIATION_MOCK = '0x1'; +const VARIATION_2_MOCK = '0x2'; const VALUE_MOCK = '0xabc123'; const TYPE_MOCK = NameType.ETHEREUM_ADDRESS; const NAME_MOCK = 'TestName'; const SOURCE_ID_MOCK = 'TestSourceId'; const ORIGIN_MOCK = NameOrigin.API; + const PROPOSED_NAMES_MOCK = { [SOURCE_ID_MOCK]: { proposedNames: ['TestProposedName', 'TestProposedName2'], @@ -35,7 +36,6 @@ const PROPOSED_NAMES_MOCK = { }; describe('useName', () => { - const getCurrentChainIdMock = jest.mocked(getCurrentChainId); const getNamesMock = // TODO: Replace `any` with type // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -43,14 +43,12 @@ describe('useName', () => { beforeEach(() => { jest.resetAllMocks(); - - getCurrentChainIdMock.mockReturnValue(CHAIN_ID_MOCK); }); it('returns default values if no state', () => { getNamesMock.mockReturnValue({} as NameControllerState['names']); - const nameEntry = useName(VALUE_MOCK, TYPE_MOCK); + const nameEntry = useName(VALUE_MOCK, TYPE_MOCK, VARIATION_MOCK); expect(nameEntry).toStrictEqual({ name: null, @@ -64,7 +62,7 @@ describe('useName', () => { getNamesMock.mockReturnValue({ [TYPE_MOCK]: { [VALUE_MOCK]: { - [CHAIN_ID_2_MOCK]: { + [VARIATION_2_MOCK]: { name: NAME_MOCK, proposedNames: PROPOSED_NAMES_MOCK, sourceId: SOURCE_ID_MOCK, @@ -74,7 +72,7 @@ describe('useName', () => { }, }); - const nameEntry = useName(VALUE_MOCK, TYPE_MOCK); + const nameEntry = useName(VALUE_MOCK, TYPE_MOCK, VARIATION_MOCK); expect(nameEntry).toStrictEqual({ name: null, @@ -88,7 +86,7 @@ describe('useName', () => { getNamesMock.mockReturnValue({ [TYPE_MOCK]: { [VALUE_MOCK]: { - [CHAIN_ID_MOCK]: { + [VARIATION_MOCK]: { name: NAME_MOCK, proposedNames: PROPOSED_NAMES_MOCK, sourceId: SOURCE_ID_MOCK, @@ -98,7 +96,7 @@ describe('useName', () => { }, }); - const nameEntry = useName(VALUE_MOCK, TYPE_MOCK); + const nameEntry = useName(VALUE_MOCK, TYPE_MOCK, VARIATION_MOCK); expect(nameEntry).toStrictEqual({ name: NAME_MOCK, @@ -112,7 +110,7 @@ describe('useName', () => { getNamesMock.mockReturnValue({ [TYPE_MOCK]: { [VALUE_MOCK]: { - [CHAIN_ID_2_MOCK]: { + [VARIATION_2_MOCK]: { name: NAME_MOCK, proposedNames: PROPOSED_NAMES_MOCK, sourceId: SOURCE_ID_MOCK, @@ -122,7 +120,7 @@ describe('useName', () => { }, }); - const nameEntry = useName(VALUE_MOCK, TYPE_MOCK, CHAIN_ID_2_MOCK); + const nameEntry = useName(VALUE_MOCK, TYPE_MOCK, VARIATION_2_MOCK); expect(nameEntry).toStrictEqual({ name: NAME_MOCK, @@ -147,7 +145,7 @@ describe('useName', () => { }, }); - const nameEntry = useName(VALUE_MOCK, TYPE_MOCK, CHAIN_ID_2_MOCK); + const nameEntry = useName(VALUE_MOCK, TYPE_MOCK, VARIATION_2_MOCK); expect(nameEntry).toStrictEqual({ name: NAME_MOCK, @@ -161,7 +159,7 @@ describe('useName', () => { getNamesMock.mockReturnValue({ [TYPE_MOCK]: { [VALUE_MOCK]: { - [CHAIN_ID_2_MOCK]: { + [VARIATION_2_MOCK]: { name: null, proposedNames: PROPOSED_NAMES_MOCK, sourceId: null, @@ -177,7 +175,7 @@ describe('useName', () => { }, }); - const nameEntry = useName(VALUE_MOCK, TYPE_MOCK, CHAIN_ID_2_MOCK); + const nameEntry = useName(VALUE_MOCK, TYPE_MOCK, VARIATION_2_MOCK); expect(nameEntry).toStrictEqual({ name: NAME_MOCK, @@ -188,37 +186,11 @@ describe('useName', () => { }); }); - it('uses empty string as variation if not specified and type is not address', () => { - const alternateType = 'alternateType' as NameType; - - getNamesMock.mockReturnValue({ - [alternateType]: { - [VALUE_MOCK]: { - '': { - name: NAME_MOCK, - proposedNames: PROPOSED_NAMES_MOCK, - sourceId: SOURCE_ID_MOCK, - origin: ORIGIN_MOCK, - }, - }, - }, - }); - - const nameEntry = useName(VALUE_MOCK, alternateType); - - expect(nameEntry).toStrictEqual({ - name: NAME_MOCK, - sourceId: SOURCE_ID_MOCK, - proposedNames: PROPOSED_NAMES_MOCK, - origin: ORIGIN_MOCK, - }); - }); - it('normalizes addresses to lowercase', () => { getNamesMock.mockReturnValue({ [TYPE_MOCK]: { [VALUE_MOCK]: { - [CHAIN_ID_MOCK]: { + [VARIATION_MOCK]: { name: NAME_MOCK, proposedNames: PROPOSED_NAMES_MOCK, sourceId: SOURCE_ID_MOCK, @@ -228,7 +200,7 @@ describe('useName', () => { }, }); - const nameEntry = useName('0xAbC123', TYPE_MOCK); + const nameEntry = useName('0xAbC123', TYPE_MOCK, VARIATION_MOCK); expect(nameEntry).toStrictEqual({ name: NAME_MOCK, diff --git a/ui/hooks/useName.ts b/ui/hooks/useName.ts index 3af9b0457f79..dd587e81abf6 100644 --- a/ui/hooks/useName.ts +++ b/ui/hooks/useName.ts @@ -5,32 +5,29 @@ import { } from '@metamask/name-controller'; import { useSelector } from 'react-redux'; import { isEqual } from 'lodash'; -import { getCurrentChainId, getNames } from '../selectors'; +import { getNames } from '../selectors'; export type UseNameRequest = { value: string; type: NameType; - variation?: string; + variation: string; }; export function useName( value: string, type: NameType, - variation?: string, + variation: string, ): NameEntry { return useNames([{ value, type, variation }])[0]; } export function useNames(requests: UseNameRequest[]): NameEntry[] { const names = useSelector(getNames, isEqual); - const chainId = useSelector(getCurrentChainId); return requests.map(({ value, type, variation }) => { const normalizedValue = normalizeValue(value, type); - const typeVariationKey = getVariationKey(type, chainId); - const variationKey = variation ?? typeVariationKey; const variationsToNameEntries = names[type]?.[normalizedValue] ?? {}; - const variationEntry = variationsToNameEntries[variationKey]; + const variationEntry = variationsToNameEntries[variation]; const fallbackEntry = variationsToNameEntries[FALLBACK_VARIATION]; const entry = @@ -63,13 +60,3 @@ function normalizeValue(value: string, type: string): string { return value; } } - -function getVariationKey(type: string, chainId: string): string { - switch (type) { - case NameType.ETHEREUM_ADDRESS: - return chainId; - - default: - return ''; - } -} diff --git a/ui/hooks/useNftCollectionsMetadata.test.ts b/ui/hooks/useNftCollectionsMetadata.test.ts index 4897e449e6ad..e1e2b6745ad1 100644 --- a/ui/hooks/useNftCollectionsMetadata.test.ts +++ b/ui/hooks/useNftCollectionsMetadata.test.ts @@ -1,6 +1,5 @@ import { renderHook } from '@testing-library/react-hooks'; import { TokenStandard } from '../../shared/constants/transaction'; -import { getCurrentChainId } from '../selectors'; import { getNFTContractInfo, getTokenStandardAndDetails, @@ -42,7 +41,6 @@ const ERC_721_COLLECTION_2_MOCK = { }; describe('useNftCollectionsMetadata', () => { - const mockGetCurrentChainId = jest.mocked(getCurrentChainId); const mockGetNFTContractInfo = jest.mocked(getNFTContractInfo); const mockGetTokenStandardAndDetails = jest.mocked( getTokenStandardAndDetails, @@ -50,7 +48,6 @@ describe('useNftCollectionsMetadata', () => { beforeEach(() => { jest.resetAllMocks(); - mockGetCurrentChainId.mockReturnValue(CHAIN_ID_MOCK); mockGetNFTContractInfo.mockResolvedValue({ collections: [ERC_721_COLLECTION_1_MOCK, ERC_721_COLLECTION_2_MOCK], }); @@ -67,10 +64,12 @@ describe('useNftCollectionsMetadata', () => { const { result, waitForNextUpdate } = renderHook(() => useNftCollectionsMetadata([ { - value: ERC_721_ADDRESS_1, + chainId: CHAIN_ID_MOCK, + contractAddress: ERC_721_ADDRESS_1, }, { - value: ERC_721_ADDRESS_2, + chainId: CHAIN_ID_MOCK, + contractAddress: ERC_721_ADDRESS_2, }, ]), ); @@ -79,8 +78,10 @@ describe('useNftCollectionsMetadata', () => { expect(mockGetNFTContractInfo).toHaveBeenCalledTimes(1); expect(result.current).toStrictEqual({ - [ERC_721_ADDRESS_1.toLowerCase()]: ERC_721_COLLECTION_1_MOCK, - [ERC_721_ADDRESS_2.toLowerCase()]: ERC_721_COLLECTION_2_MOCK, + [CHAIN_ID_MOCK]: { + [ERC_721_ADDRESS_1.toLowerCase()]: ERC_721_COLLECTION_1_MOCK, + [ERC_721_ADDRESS_2.toLowerCase()]: ERC_721_COLLECTION_2_MOCK, + }, }); }); @@ -99,7 +100,8 @@ describe('useNftCollectionsMetadata', () => { renderHook(() => useNftCollectionsMetadata([ { - value: '0xERC20Address', + chainId: CHAIN_ID_MOCK, + contractAddress: '0xERC20Address', }, ]), ); @@ -114,7 +116,8 @@ describe('useNftCollectionsMetadata', () => { renderHook(() => useNftCollectionsMetadata([ { - value: '0xERC20Address', + chainId: CHAIN_ID_MOCK, + contractAddress: '0xERC20Address', }, ]), ); @@ -126,10 +129,12 @@ describe('useNftCollectionsMetadata', () => { const { waitForNextUpdate, rerender } = renderHook(() => useNftCollectionsMetadata([ { - value: ERC_721_ADDRESS_1, + chainId: CHAIN_ID_MOCK, + contractAddress: ERC_721_ADDRESS_1, }, { - value: ERC_721_ADDRESS_2, + chainId: CHAIN_ID_MOCK, + contractAddress: ERC_721_ADDRESS_2, }, ]), ); diff --git a/ui/hooks/useNftCollectionsMetadata.ts b/ui/hooks/useNftCollectionsMetadata.ts index 641e0fb25dcd..e71216e254c9 100644 --- a/ui/hooks/useNftCollectionsMetadata.ts +++ b/ui/hooks/useNftCollectionsMetadata.ts @@ -1,9 +1,5 @@ -import { useMemo } from 'react'; -import { useSelector } from 'react-redux'; import { Collection } from '@metamask/assets-controllers'; -import type { Hex } from '@metamask/utils'; import { TokenStandard } from '../../shared/constants/transaction'; -import { getCurrentChainId } from '../selectors'; import { getNFTContractInfo, getTokenStandardAndDetails, @@ -11,28 +7,62 @@ import { import { useAsyncResult } from './useAsyncResult'; export type UseNftCollectionsMetadataRequest = { - value: string; - chainId?: string; -}; - -type CollectionsData = { - [key: string]: Collection; + chainId: string; + contractAddress: string; }; // For now, we only support ERC721 tokens const SUPPORTED_NFT_TOKEN_STANDARDS = [TokenStandard.ERC721]; -async function fetchCollections( - memoisedContracts: string[], +export function useNftCollectionsMetadata( + requests: UseNftCollectionsMetadataRequest[], +): Record> { + const { value: collectionsMetadata } = useAsyncResult( + () => fetchCollections(requests), + [JSON.stringify(requests)], + ); + + return collectionsMetadata ?? {}; +} + +async function fetchCollections(requests: UseNftCollectionsMetadataRequest[]) { + const valuesByChainId = requests.reduce>( + (acc, { chainId, contractAddress }) => { + acc[chainId] = [...(acc[chainId] ?? []), contractAddress.toLowerCase()]; + return acc; + }, + {}, + ); + + const chainIds = Object.keys(valuesByChainId); + + const responses = await Promise.all( + chainIds.map((chainId) => { + const contractAddresses = valuesByChainId[chainId]; + return fetchCollectionsForChain(contractAddresses, chainId); + }), + ); + + return chainIds.reduce>>( + (acc, chainId, index) => { + acc[chainId] = responses[index]; + return acc; + }, + {}, + ); +} + +async function fetchCollectionsForChain( + contractAddresses: string[], chainId: string, -): Promise { +) { const contractStandardsResponses = await Promise.all( - memoisedContracts.map((contractAddress) => + contractAddresses.map((contractAddress) => getTokenStandardAndDetails(contractAddress, chainId), ), ); - const supportedNFTContracts = memoisedContracts.filter( + const supportedNFTContracts = contractAddresses.filter( (_contractAddress, index) => SUPPORTED_NFT_TOKEN_STANDARDS.includes( contractStandardsResponses[index].standard as TokenStandard, @@ -48,37 +78,16 @@ async function fetchCollections( chainId, ); - const collectionsData: CollectionsData = collectionsResult.collections.reduce( - (acc: CollectionsData, collection, index) => { - acc[supportedNFTContracts[index]] = { - name: collection?.name, - image: collection?.image, - isSpam: collection?.isSpam, - }; - return acc; - }, - {}, - ); + const collectionsData = collectionsResult.collections.reduce< + Record + >((acc, collection, index) => { + acc[supportedNFTContracts[index]] = { + name: collection?.name, + image: collection?.image, + isSpam: collection?.isSpam, + }; + return acc; + }, {}); return collectionsData; } - -export function useNftCollectionsMetadata( - requests: UseNftCollectionsMetadataRequest[], - providedChainId?: Hex, -) { - const chainId = useSelector(getCurrentChainId) || providedChainId; - - const memoisedContracts = useMemo(() => { - return requests - .filter(({ value }) => value) - .map(({ value }) => value.toLowerCase()); - }, [requests]); - - const { value: collectionsMetadata } = useAsyncResult( - () => fetchCollections(memoisedContracts, chainId), - [JSON.stringify(memoisedContracts), chainId], - ); - - return collectionsMetadata || {}; -} diff --git a/ui/pages/confirmations/components/confirm-page-container/confirm-page-container.component.js b/ui/pages/confirmations/components/confirm-page-container/confirm-page-container.component.js index d4a92172aed6..c61a4193ccd0 100644 --- a/ui/pages/confirmations/components/confirm-page-container/confirm-page-container.component.js +++ b/ui/pages/confirmations/components/confirm-page-container/confirm-page-container.component.js @@ -218,6 +218,7 @@ const ConfirmPageContainer = (props) => { recipientEns={toEns} recipientNickname={toNickname} recipientIsOwnedAccount={recipientIsOwnedAccount} + chainId={currentTransaction.chainId} /> )} diff --git a/ui/pages/confirmations/components/confirm/info/approve/approve-details/approve-details.tsx b/ui/pages/confirmations/components/confirm/info/approve/approve-details/approve-details.tsx index cdcaf7267e06..13d455503db6 100644 --- a/ui/pages/confirmations/components/confirm/info/approve/approve-details/approve-details.tsx +++ b/ui/pages/confirmations/components/confirm/info/approve/approve-details/approve-details.tsx @@ -45,6 +45,7 @@ const Spender = ({ } const spender = value.data[0].params[0].value; + const { chainId } = transactionMeta; if (getIsRevokeSetApprovalForAll(value)) { return null; @@ -59,7 +60,7 @@ const Spender = ({ )} data-testid="confirmation__approve-spender" > - + diff --git a/ui/pages/confirmations/components/confirm/info/approve/approve-static-simulation/approve-static-simulation.tsx b/ui/pages/confirmations/components/confirm/info/approve/approve-static-simulation/approve-static-simulation.tsx index bdbe0e6fbae3..f1117e2a22b2 100644 --- a/ui/pages/confirmations/components/confirm/info/approve/approve-static-simulation/approve-static-simulation.tsx +++ b/ui/pages/confirmations/components/confirm/info/approve/approve-static-simulation/approve-static-simulation.tsx @@ -50,6 +50,8 @@ export const ApproveStaticSimulation = () => { return null; } + const { chainId } = transactionMeta; + const formattedTokenText = ( { value={transactionMeta.txParams.to as string} type={NameType.ETHEREUM_ADDRESS} preferContractSymbol + variation={chainId} /> diff --git a/ui/pages/confirmations/components/confirm/info/approve/revoke-static-simulation/revoke-static-simulation.tsx b/ui/pages/confirmations/components/confirm/info/approve/revoke-static-simulation/revoke-static-simulation.tsx index 38ff93ba9b36..77cee271d667 100644 --- a/ui/pages/confirmations/components/confirm/info/approve/revoke-static-simulation/revoke-static-simulation.tsx +++ b/ui/pages/confirmations/components/confirm/info/approve/revoke-static-simulation/revoke-static-simulation.tsx @@ -16,6 +16,8 @@ export const RevokeStaticSimulation = () => { currentConfirmation: TransactionMeta; }; + const { chainId } = transactionMeta; + const TokenContractRow = ( @@ -24,6 +26,7 @@ export const RevokeStaticSimulation = () => { value={transactionMeta.txParams.to as string} type={NameType.ETHEREUM_ADDRESS} preferContractSymbol + variation={chainId} /> @@ -38,6 +41,7 @@ export const RevokeStaticSimulation = () => { value={transactionMeta.txParams.from as string} type={NameType.ETHEREUM_ADDRESS} preferContractSymbol + variation={chainId} /> diff --git a/ui/pages/confirmations/components/confirm/info/hooks/useEIP1559TxFees.ts b/ui/pages/confirmations/components/confirm/info/hooks/useEIP1559TxFees.ts index 40aca7cf2d31..e4bfaad8d779 100644 --- a/ui/pages/confirmations/components/confirm/info/hooks/useEIP1559TxFees.ts +++ b/ui/pages/confirmations/components/confirm/info/hooks/useEIP1559TxFees.ts @@ -8,8 +8,11 @@ export const useEIP1559TxFees = ( maxFeePerGas: string; maxPriorityFeePerGas: string; } => { - const hexMaxFeePerGas = transactionMeta?.txParams?.maxFeePerGas; + const hexMaxFeePerGas = + transactionMeta.dappSuggestedGasFees?.maxFeePerGas || + transactionMeta?.txParams?.maxFeePerGas; const hexMaxPriorityFeePerGas = + transactionMeta.dappSuggestedGasFees?.maxPriorityFeePerGas || transactionMeta?.txParams?.maxPriorityFeePerGas; return useMemo(() => { diff --git a/ui/pages/confirmations/components/confirm/info/hooks/useFeeCalculations.ts b/ui/pages/confirmations/components/confirm/info/hooks/useFeeCalculations.ts index ceb8a4b2d248..587d70c9c9ef 100644 --- a/ui/pages/confirmations/components/confirm/info/hooks/useFeeCalculations.ts +++ b/ui/pages/confirmations/components/confirm/info/hooks/useFeeCalculations.ts @@ -12,6 +12,7 @@ import { getValueFromWeiHex, multiplyHexes, } from '../../../../../../../shared/modules/conversion.utils'; +import { Numeric } from '../../../../../../../shared/modules/Numeric'; import { getConversionRate } from '../../../../../../ducks/metamask/metamask'; import { useFiatFormatter } from '../../../../../../hooks/useFiatFormatter'; import { useGasFeeEstimates } from '../../../../../../hooks/useGasFeeEstimates'; @@ -114,11 +115,21 @@ export function useFeeCalculations(transactionMeta: TransactionMeta) { } // Logic for any network without L1 and L2 fee components - const minimumFeePerGas = addHexes( + let minimumFeePerGas = addHexes( decGWEIToHexWEI(estimatedBaseFee) || HEX_ZERO, decimalToHex(maxPriorityFeePerGas), ); + // `minimumFeePerGas` should never be higher than the `maxFeePerGas` + if ( + new Numeric(minimumFeePerGas, 16).greaterThan( + decimalToHex(maxFeePerGas), + 16, + ) + ) { + minimumFeePerGas = decimalToHex(maxFeePerGas); + } + const estimatedFee = multiplyHexes( supportsEIP1559 ? (minimumFeePerGas as Hex) : (gasPrice as Hex), gasLimit as Hex, diff --git a/ui/pages/confirmations/components/confirm/info/hooks/useTransactionGasFeeEstimate.ts b/ui/pages/confirmations/components/confirm/info/hooks/useTransactionGasFeeEstimate.ts index 31802eb22feb..f5866a283935 100644 --- a/ui/pages/confirmations/components/confirm/info/hooks/useTransactionGasFeeEstimate.ts +++ b/ui/pages/confirmations/components/confirm/info/hooks/useTransactionGasFeeEstimate.ts @@ -5,6 +5,7 @@ import { addHexes, multiplyHexes, } from '../../../../../../../shared/modules/conversion.utils'; +import { Numeric } from '../../../../../../../shared/modules/Numeric'; import { useGasFeeEstimates } from '../../../../../../hooks/useGasFeeEstimates'; import { HEX_ZERO } from '../shared/constants'; @@ -28,15 +29,24 @@ export function useTransactionGasFeeEstimate( transactionMeta.dappSuggestedGasFees?.maxPriorityFeePerGas || transactionMeta.txParams?.maxPriorityFeePerGas || HEX_ZERO; + const maxFeePerGas = + transactionMeta.dappSuggestedGasFees?.maxFeePerGas || + transactionMeta.txParams?.maxFeePerGas || + HEX_ZERO; let gasEstimate: Hex; if (supportsEIP1559) { // Minimum Total Fee = (estimatedBaseFee + maxPriorityFeePerGas) * gasLimit - const minimumFeePerGas = addHexes( + let minimumFeePerGas = addHexes( estimatedBaseFee || HEX_ZERO, maxPriorityFeePerGas, ); + // `minimumFeePerGas` should never be higher than the `maxFeePerGas` + if (new Numeric(minimumFeePerGas, 16).greaterThan(maxFeePerGas, 16)) { + minimumFeePerGas = maxFeePerGas; + } + gasEstimate = multiplyHexes(minimumFeePerGas as Hex, gasLimit as Hex); } else { gasEstimate = multiplyHexes(gasPrice as Hex, gasLimit as Hex); diff --git a/ui/pages/confirmations/components/confirm/info/personal-sign/personal-sign.tsx b/ui/pages/confirmations/components/confirm/info/personal-sign/personal-sign.tsx index 28b56c8de9ed..370d5e68261f 100644 --- a/ui/pages/confirmations/components/confirm/info/personal-sign/personal-sign.tsx +++ b/ui/pages/confirmations/components/confirm/info/personal-sign/personal-sign.tsx @@ -34,6 +34,7 @@ const PersonalSignInfo: React.FC = () => { const { from } = currentConfirmation.msgParams; const isSIWE = isSIWESignatureRequest(currentConfirmation); + const chainId = currentConfirmation.chainId as string; return ( <> @@ -62,7 +63,7 @@ const PersonalSignInfo: React.FC = () => { label={t('signingInWith')} ownerId={currentConfirmation.id} > - + )} diff --git a/ui/pages/confirmations/components/confirm/info/personal-sign/siwe-sign/siwe-sign.tsx b/ui/pages/confirmations/components/confirm/info/personal-sign/siwe-sign/siwe-sign.tsx index 383bf182ac8c..abf93e50f7b4 100644 --- a/ui/pages/confirmations/components/confirm/info/personal-sign/siwe-sign/siwe-sign.tsx +++ b/ui/pages/confirmations/components/confirm/info/personal-sign/siwe-sign/siwe-sign.tsx @@ -50,7 +50,7 @@ const SIWESignInfo: React.FC = () => { - + diff --git a/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/revoke-set-approval-for-all-static-simulation/revoke-set-approval-for-all-static-simulation.tsx b/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/revoke-set-approval-for-all-static-simulation/revoke-set-approval-for-all-static-simulation.tsx index 64e90a7066e6..d1746ff85f08 100644 --- a/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/revoke-set-approval-for-all-static-simulation/revoke-set-approval-for-all-static-simulation.tsx +++ b/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/revoke-set-approval-for-all-static-simulation/revoke-set-approval-for-all-static-simulation.tsx @@ -22,6 +22,8 @@ export const RevokeSetApprovalForAllStaticSimulation = ({ const { currentConfirmation: transactionMeta } = useConfirmContext(); + const { chainId } = transactionMeta; + const nftsRow = ( @@ -30,6 +32,7 @@ export const RevokeSetApprovalForAllStaticSimulation = ({ value={transactionMeta.txParams.to as string} type={NameType.ETHEREUM_ADDRESS} preferContractSymbol + variation={chainId} /> @@ -44,6 +47,7 @@ export const RevokeSetApprovalForAllStaticSimulation = ({ value={spender} type={NameType.ETHEREUM_ADDRESS} preferContractSymbol + variation={chainId} /> diff --git a/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/set-approval-for-all-static-simulation/set-approval-for-all-static-simulation.tsx b/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/set-approval-for-all-static-simulation/set-approval-for-all-static-simulation.tsx index 177ef4080860..56a27d3397be 100644 --- a/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/set-approval-for-all-static-simulation/set-approval-for-all-static-simulation.tsx +++ b/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/set-approval-for-all-static-simulation/set-approval-for-all-static-simulation.tsx @@ -24,6 +24,8 @@ export const SetApprovalForAllStaticSimulation = () => { currentConfirmation: TransactionMeta; }; + const { chainId } = transactionMeta; + const SetApprovalForAllRow = ( @@ -48,6 +50,7 @@ export const SetApprovalForAllStaticSimulation = () => { value={transactionMeta.txParams.to as string} type={NameType.ETHEREUM_ADDRESS} preferContractSymbol + variation={chainId} /> diff --git a/ui/pages/confirmations/components/confirm/info/shared/transaction-data/transaction-data.tsx b/ui/pages/confirmations/components/confirm/info/shared/transaction-data/transaction-data.tsx index 4af44b5a310d..374aec4f26ce 100644 --- a/ui/pages/confirmations/components/confirm/info/shared/transaction-data/transaction-data.tsx +++ b/ui/pages/confirmations/components/confirm/info/shared/transaction-data/transaction-data.tsx @@ -57,6 +57,7 @@ export const TransactionData = () => { const { data, source } = value; const isExpandable = data.length > 1; + const { chainId } = currentConfirmation; return ( @@ -67,6 +68,7 @@ export const TransactionData = () => { method={method} source={source} isExpandable={isExpandable} + chainId={chainId} /> {index < data.length - 1 && } @@ -119,10 +121,12 @@ function FunctionContainer({ method, source, isExpandable, + chainId, }: { method: DecodedTransactionDataMethod; source?: DecodedTransactionDataSource; isExpandable: boolean; + chainId: string; }) { const t = useI18nContext(); @@ -134,6 +138,7 @@ function FunctionContainer({ param={param} index={paramIndex} source={source} + chainId={chainId} /> ))} @@ -172,18 +177,20 @@ function FunctionContainer({ function ParamValue({ param, source, + chainId, }: { param: DecodedTransactionDataParam; source?: DecodedTransactionDataSource; + chainId: string; }) { const { name, type, value } = param; if (type === 'address') { - return ; + return ; } if (name === 'path' && source === DecodedTransactionDataSource.Uniswap) { - return ; + return ; } let valueString = value.toString(); @@ -199,10 +206,12 @@ function ParamRow({ param, index, source, + chainId, }: { param: DecodedTransactionDataParam; index: number; source?: DecodedTransactionDataSource; + chainId: string; }) { const { name, type, description } = param; const label = name ? _.startCase(name) : `Param #${index + 1}`; @@ -215,20 +224,29 @@ function ParamRow({ param={childParam} index={childIndex} source={source} + chainId={chainId} /> )); return ( <> - {!childRows?.length && } + {!childRows?.length && ( + + )} {childRows && {childRows}} ); } -function UniswapPath({ pathPools }: { pathPools: UniswapPathPool[] }) { +function UniswapPath({ + pathPools, + chainId, +}: { + pathPools: UniswapPathPool[]; + chainId: string; +}) { return ( {pathPools.map((pool, index) => ( <> - {index === 0 && } + {index === 0 && ( + + )} - + ))} diff --git a/ui/pages/confirmations/components/confirm/info/shared/transaction-details/transaction-details.tsx b/ui/pages/confirmations/components/confirm/info/shared/transaction-details/transaction-details.tsx index 706729a8cc0a..89c2da783a4f 100644 --- a/ui/pages/confirmations/components/confirm/info/shared/transaction-details/transaction-details.tsx +++ b/ui/pages/confirmations/components/confirm/info/shared/transaction-details/transaction-details.tsx @@ -56,13 +56,18 @@ export const RecipientRow = () => { return null; } + const { chainId } = currentConfirmation; + return ( - + ); }; @@ -115,7 +120,7 @@ const PaymasterRow = () => { const t = useI18nContext(); const { currentConfirmation } = useConfirmContext(); - const { id: userOperationId } = currentConfirmation ?? {}; + const { id: userOperationId, chainId } = currentConfirmation ?? {}; const isUserOperation = Boolean(currentConfirmation?.isUserOperation); // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -134,7 +139,7 @@ const PaymasterRow = () => { label={t('confirmFieldPaymaster')} tooltip={t('confirmFieldTooltipPaymaster')} > - + ); diff --git a/ui/pages/confirmations/components/confirm/info/token-transfer/token-details-section.tsx b/ui/pages/confirmations/components/confirm/info/token-transfer/token-details-section.tsx index 48a5f2dad74c..6d686873ea1c 100644 --- a/ui/pages/confirmations/components/confirm/info/token-transfer/token-details-section.tsx +++ b/ui/pages/confirmations/components/confirm/info/token-transfer/token-details-section.tsx @@ -63,7 +63,10 @@ export const TokenDetailsSection = () => { const tokenRow = ( - + ); diff --git a/ui/pages/confirmations/components/confirm/info/token-transfer/transaction-flow-section.tsx b/ui/pages/confirmations/components/confirm/info/token-transfer/transaction-flow-section.tsx index de0e928c10f8..250b9bffd2cf 100644 --- a/ui/pages/confirmations/components/confirm/info/token-transfer/transaction-flow-section.tsx +++ b/ui/pages/confirmations/components/confirm/info/token-transfer/transaction-flow-section.tsx @@ -34,6 +34,8 @@ export const TransactionFlowSection = () => { return ; } + const { chainId } = transactionMeta; + return ( { { color={IconColor.iconMuted} /> {recipientAddress && ( - + )} diff --git a/ui/pages/confirmations/components/confirm/info/typed-sign-v1/typed-sign-v1.tsx b/ui/pages/confirmations/components/confirm/info/typed-sign-v1/typed-sign-v1.tsx index 35d8e3e6d672..951acbba6782 100644 --- a/ui/pages/confirmations/components/confirm/info/typed-sign-v1/typed-sign-v1.tsx +++ b/ui/pages/confirmations/components/confirm/info/typed-sign-v1/typed-sign-v1.tsx @@ -23,6 +23,8 @@ const TypedSignV1Info: React.FC = () => { return null; } + const chainId = currentConfirmation.chainId as string; + return ( <> @@ -41,6 +43,7 @@ const TypedSignV1Info: React.FC = () => { diff --git a/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/permit-simulation.tsx b/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/permit-simulation.tsx index 44131ec18fbf..855f7837ba42 100644 --- a/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/permit-simulation.tsx +++ b/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/permit-simulation.tsx @@ -42,6 +42,7 @@ const PermitSimulation: React.FC = () => { const t = useI18nContext(); const { currentConfirmation } = useConfirmContext(); const msgData = currentConfirmation.msgParams?.data; + const chainId = currentConfirmation.chainId as Hex; const { domain: { verifyingContract }, message, @@ -66,6 +67,7 @@ const PermitSimulation: React.FC = () => { primaryType={primaryType} tokenContract={token} value={amount} + chainId={chainId} /> ); @@ -94,6 +96,7 @@ const PermitSimulation: React.FC = () => { tokenContract={verifyingContract} value={message.value} tokenId={message.tokenId} + chainId={chainId} /> )} diff --git a/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/value-display/value-display.test.tsx b/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/value-display/value-display.test.tsx index e8e48c1ca6f9..453f4a1b6d79 100644 --- a/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/value-display/value-display.test.tsx +++ b/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/value-display/value-display.test.tsx @@ -31,6 +31,7 @@ describe('PermitSimulationValueDisplay', () => { , mockStore, ); @@ -48,6 +49,7 @@ describe('PermitSimulationValueDisplay', () => { , mockStore, ); diff --git a/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/value-display/value-display.tsx b/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/value-display/value-display.tsx index e95edc03087b..fa0c911d5eae 100644 --- a/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/value-display/value-display.tsx +++ b/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/value-display/value-display.tsx @@ -32,6 +32,9 @@ import Name from '../../../../../../../../components/app/name/name'; import { TokenDetailsERC20 } from '../../../../../../utils/token'; type PermitSimulationValueDisplayParams = { + /** ID of the associated chain. */ + chainId: Hex; + /** The primaryType of the typed sign message */ primaryType?: string; @@ -51,7 +54,7 @@ type PermitSimulationValueDisplayParams = { const PermitSimulationValueDisplay: React.FC< PermitSimulationValueDisplayParams -> = ({ primaryType, tokenContract, value, tokenId }) => { +> = ({ chainId, primaryType, tokenContract, tokenId, value }) => { const exchangeRate = useTokenExchangeRate(tokenContract); const tokenDetails = useGetTokenStandardAndDetails(tokenContract); @@ -129,6 +132,7 @@ const PermitSimulationValueDisplay: React.FC< diff --git a/ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign.tsx b/ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign.tsx index 7a608fc68b8a..bb011bc68710 100644 --- a/ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign.tsx +++ b/ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign.tsx @@ -43,6 +43,7 @@ const TypedSignInfo: React.FC = () => { const isPermit = isPermitSignatureRequest(currentConfirmation); const isOrder = isOrderSignatureRequest(currentConfirmation); + const chainId = currentConfirmation.chainId as string; useEffect(() => { (async () => { @@ -61,7 +62,7 @@ const TypedSignInfo: React.FC = () => { {isPermit && ( <> - + @@ -76,7 +77,10 @@ const TypedSignInfo: React.FC = () => { {isValidAddress(verifyingContract) && ( - + )} @@ -85,6 +89,7 @@ const TypedSignInfo: React.FC = () => { diff --git a/ui/pages/confirmations/components/confirm/row/dataTree.test.tsx b/ui/pages/confirmations/components/confirm/row/dataTree.test.tsx index b427b6a8ee97..35dafe552cb7 100644 --- a/ui/pages/confirmations/components/confirm/row/dataTree.test.tsx +++ b/ui/pages/confirmations/components/confirm/row/dataTree.test.tsx @@ -10,6 +10,8 @@ import configureStore from '../../../../../store/store'; import { DataTree } from './dataTree'; +const CHAIN_ID_MOCK = '0x123'; + const mockData = { contents: { value: 'Hello, Bob!', type: 'string' }, from: { @@ -67,7 +69,7 @@ const store = configureStore(mockState); describe('DataTree', () => { it('should match snapshot', () => { const { container } = renderWithProvider( - , + , store, ); expect(container).toMatchSnapshot(); @@ -77,6 +79,7 @@ describe('DataTree', () => { const { container } = renderWithProvider( , store, ); @@ -90,7 +93,7 @@ describe('DataTree', () => { mockPermitData.message.deadline = '-1'; const { container } = renderWithProvider( - , + , store, ); expect(container).toMatchSnapshot(); @@ -100,6 +103,7 @@ describe('DataTree', () => { const { container } = renderWithProvider( , store, ); @@ -114,7 +118,10 @@ describe('DataTree', () => { }, 'A number': { type: 'uint32', value: '1337' }, }; - const { container } = renderWithProvider(, store); + const { container } = renderWithProvider( + , + store, + ); expect(container).toMatchSnapshot(); }); }); diff --git a/ui/pages/confirmations/components/confirm/row/dataTree.tsx b/ui/pages/confirmations/components/confirm/row/dataTree.tsx index b295f337deb4..9a089a757004 100644 --- a/ui/pages/confirmations/components/confirm/row/dataTree.tsx +++ b/ui/pages/confirmations/components/confirm/row/dataTree.tsx @@ -97,10 +97,12 @@ export const DataTree = ({ data, primaryType, tokenDecimals: tokenDecimalsProp, + chainId, }: { data: Record | TreeData[]; primaryType?: PrimaryType; tokenDecimals?: number; + chainId: string; }) => { const tokenContract = getTokenContractInDataTree(data); const { decimalsNumber } = useGetTokenStandardAndDetails(tokenContract); @@ -125,6 +127,7 @@ export const DataTree = ({ value={value} type={type} tokenDecimals={tokenDecimals} + chainId={chainId} /> } @@ -150,12 +153,14 @@ const DataField = memo( type, value, tokenDecimals, + chainId, }: { label: string; primaryType?: PrimaryType; type: string; value: ValueType; tokenDecimals?: number; + chainId: string; }) => { const t = useI18nContext(); @@ -165,6 +170,7 @@ const DataField = memo( data={value} primaryType={primaryType} tokenDecimals={tokenDecimals} + chainId={chainId} /> ); } @@ -191,7 +197,7 @@ const DataField = memo( mixedCaseUseChecksum: true, }) ) { - return ; + return ; } return ; diff --git a/ui/pages/confirmations/components/confirm/row/typed-sign-data-v1/typedSignDataV1.test.tsx b/ui/pages/confirmations/components/confirm/row/typed-sign-data-v1/typedSignDataV1.test.tsx index ecf55e3b574d..e01a42782033 100644 --- a/ui/pages/confirmations/components/confirm/row/typed-sign-data-v1/typedSignDataV1.test.tsx +++ b/ui/pages/confirmations/components/confirm/row/typed-sign-data-v1/typedSignDataV1.test.tsx @@ -8,11 +8,14 @@ import { ConfirmInfoRowTypedSignDataV1 } from './typedSignDataV1'; const mockStore = configureMockStore([])(mockState); +const CHAIN_ID_MOCK = '0x123'; + describe('ConfirmInfoRowTypedSignData', () => { it('should match snapshot', () => { const { container } = renderWithProvider( , mockStore, ); @@ -21,7 +24,10 @@ describe('ConfirmInfoRowTypedSignData', () => { it('should return null if data is not defined', () => { const { container } = renderWithProvider( - , + , mockStore, ); expect(container).toBeEmptyDOMElement(); diff --git a/ui/pages/confirmations/components/confirm/row/typed-sign-data-v1/typedSignDataV1.tsx b/ui/pages/confirmations/components/confirm/row/typed-sign-data-v1/typedSignDataV1.tsx index eb7c5c5ecb02..b781a9a6ff3e 100644 --- a/ui/pages/confirmations/components/confirm/row/typed-sign-data-v1/typedSignDataV1.tsx +++ b/ui/pages/confirmations/components/confirm/row/typed-sign-data-v1/typedSignDataV1.tsx @@ -7,8 +7,10 @@ import { DataTree } from '../dataTree'; export const ConfirmInfoRowTypedSignDataV1 = ({ data, + chainId, }: { data?: TypedSignDataV1Type; + chainId: string; }) => { if (!data) { return null; @@ -22,7 +24,7 @@ export const ConfirmInfoRowTypedSignDataV1 = ({ return ( - + ); diff --git a/ui/pages/confirmations/components/confirm/row/typed-sign-data/typedSignData.test.tsx b/ui/pages/confirmations/components/confirm/row/typed-sign-data/typedSignData.test.tsx index 436edbecd3e0..6eb1c5b4236f 100644 --- a/ui/pages/confirmations/components/confirm/row/typed-sign-data/typedSignData.test.tsx +++ b/ui/pages/confirmations/components/confirm/row/typed-sign-data/typedSignData.test.tsx @@ -8,6 +8,8 @@ import { renderWithProvider } from '../../../../../../../test/lib/render-helpers import configureStore from '../../../../../../store/store'; import { ConfirmInfoRowTypedSignData } from './typedSignData'; +const CHAIN_ID_MOCK = '0x123'; + describe('ConfirmInfoRowTypedSignData', () => { const renderWithComponentData = ( data = unapprovedTypedSignMsgV4.msgParams?.data as string, @@ -15,7 +17,7 @@ describe('ConfirmInfoRowTypedSignData', () => { const store = configureStore(mockState); return renderWithProvider( - , + , store, ); }; diff --git a/ui/pages/confirmations/components/confirm/row/typed-sign-data/typedSignData.tsx b/ui/pages/confirmations/components/confirm/row/typed-sign-data/typedSignData.tsx index 828f82f41352..b11b02656e81 100644 --- a/ui/pages/confirmations/components/confirm/row/typed-sign-data/typedSignData.tsx +++ b/ui/pages/confirmations/components/confirm/row/typed-sign-data/typedSignData.tsx @@ -13,10 +13,12 @@ import { DataTree } from '../dataTree'; export const ConfirmInfoRowTypedSignData = ({ data, tokenDecimals, + chainId, }: { data: string; isPermit?: boolean; tokenDecimals?: number; + chainId: string; }) => { const t = useI18nContext(); @@ -39,6 +41,7 @@ export const ConfirmInfoRowTypedSignData = ({ data={sanitizedMessage.value} primaryType={primaryType} tokenDecimals={tokenDecimals} + chainId={chainId} /> diff --git a/ui/pages/confirmations/components/contract-details-modal/contract-details-modal.js b/ui/pages/confirmations/components/contract-details-modal/contract-details-modal.js index 68209a68e35d..a0a16cc838c3 100644 --- a/ui/pages/confirmations/components/contract-details-modal/contract-details-modal.js +++ b/ui/pages/confirmations/components/contract-details-modal/contract-details-modal.js @@ -224,7 +224,11 @@ export default function ContractDetailsModal({ {petnamesEnabled ? ( - + ) : ( {typeof value === 'object' && value !== null ? ( - + ) : ( {petnamesEnabled ? ( - + ) : (
{primaryType} - + ); @@ -99,4 +100,5 @@ SignatureRequestMessage.propTypes = { messageRootRef: PropTypes.object, messageIsScrollable: PropTypes.bool, primaryType: PropTypes.string, + chainId: PropTypes.string, }; diff --git a/ui/pages/confirmations/components/signature-request/signature-request.js b/ui/pages/confirmations/components/signature-request/signature-request.js index ce6967b50f70..3cf2a54327c9 100644 --- a/ui/pages/confirmations/components/signature-request/signature-request.js +++ b/ui/pages/confirmations/components/signature-request/signature-request.js @@ -313,6 +313,7 @@ const SignatureRequest = ({ txData, warnings }) => { messageRootRef={messageRootRef} messageIsScrollable={messageIsScrollable} primaryType={primaryType} + chainId={chainId} />