mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-22 09:57:02 +01:00
Merge pull request from GHSA-c2xw-px2x-pr65
* Remove network config store * Remove inline networks variable in network controller * Re-key network controller 'rpcTarget' to 'rpcUrl' * Require chainId in lookupNetwork, implement eth_chainId * Require chain ID in network form * Add alert, migrations, and tests * Add chainId validation to addToFrequentRpcList * Update public config state selector to match new network controller state * Use network enums in networks-tab.constants * Ensure chainId in provider config is current * Update tests
This commit is contained in:
parent
8f3b81f67a
commit
088d4c34f1
@ -566,9 +566,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "ልክ ያልሆነ Block Explorer ዩአርኤል"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "ልክ ያልሆነ ግቤት።"
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "ልክ ያልሆነ RPC ዩአርኤል"
|
||||
},
|
||||
@ -743,9 +740,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "ኤክስፕሎረር URL አግድ (አማራጭ)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "የሰንሰለት መለያ ቁጥር (አማራጭ)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "ምልክት (አማራጭ)"
|
||||
},
|
||||
|
@ -562,9 +562,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "غير صحيح Block Explorer رابط"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "مدخل غير صحيح."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "رابط آر بي سي غير صحيح"
|
||||
},
|
||||
@ -739,9 +736,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "العنوان الإلكتروني لمستكشف البلوكات (اختياري)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "هوية ChainID (اختياري)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "الرمز (اختياري)"
|
||||
},
|
||||
|
@ -562,9 +562,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Невалиден Block Explorer URL адрес"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Невалидно въвеждане."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "Невалиден RPC URL адрес"
|
||||
},
|
||||
@ -742,9 +739,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "Блокиране на Explorer URL (по избор)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "ChainID (по избор)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Символ (по избор)"
|
||||
},
|
||||
|
@ -566,9 +566,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "অবৈধ Block Explorer URL"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "অবৈধ ইনপুট"
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "অবৈধ RPC URL"
|
||||
},
|
||||
@ -746,9 +743,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "এক্সপ্লোরার URL ব্লক করুন (ঐচ্ছিক)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "ChainID (ঐচ্ছিক)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "প্রতীক (ঐচ্ছিক)"
|
||||
},
|
||||
|
@ -553,9 +553,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "URL de Block Explorer"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Entrada no vàlida."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "URL de RPC"
|
||||
},
|
||||
@ -730,9 +727,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "Bloqueja l'URL d'Explorer (opcional)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "Cadena ID (opcional)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Símbol (opcional)"
|
||||
},
|
||||
|
@ -222,9 +222,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Neplatné Block Explorer URI"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Neplatný vstup."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "Neplatné RPC URI"
|
||||
},
|
||||
|
@ -559,9 +559,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Ugyldig Block Explorer-webadresse"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Ugyldigt input."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "Ugyldig RPC-webadresse"
|
||||
},
|
||||
@ -730,9 +727,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "Blok-stifinder-URL (valgfrit)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "KædeID (valgfrit)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Symbol (valgfrit)"
|
||||
},
|
||||
|
@ -554,9 +554,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Ungültige Block Explorer URI"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Ungültige Eingabe."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "Ungültige RPC URI"
|
||||
},
|
||||
|
@ -563,9 +563,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Μη έγκυρο Block Explorer URL"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Μη έγκυρη είσοδος."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "Μη έγκυρο RPC URL"
|
||||
},
|
||||
@ -743,9 +740,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "Διεύθυνση URL Εξερευνητή Μπλοκ (προαιρετικό)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "Ταυτότητα Αλυσίδας (προαιρετικό)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Σύμβολο (προαιρετικό)"
|
||||
},
|
||||
|
@ -823,12 +823,35 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Invalid Block Explorer URL"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Invalid input."
|
||||
"invalidCustomNetworkAlertContent1": {
|
||||
"message": "The custom network '$1' is missing its chain ID.",
|
||||
"description": "$1 is the name/identifier of the network."
|
||||
},
|
||||
"invalidCustomNetworkAlertContent2": {
|
||||
"message": "To protect you from malicious or faulty network providers, chain IDs are now required for all custom networks."
|
||||
},
|
||||
"invalidCustomNetworkAlertContent3": {
|
||||
"message": "Go to Settings > Network and enter the chain ID. You can find the chain IDs of most popular networks on $1.",
|
||||
"description": "$1 is a link to https://chainid.network"
|
||||
},
|
||||
"invalidCustomNetworkAlertTitle": {
|
||||
"message": "Invalid Custom Network"
|
||||
},
|
||||
"invalidHexNumber": {
|
||||
"message": "Invalid hexadecimal number."
|
||||
},
|
||||
"invalidHexNumberLeadingZeros": {
|
||||
"message": "Invalid hexadecimal number. Remove any leading zeros."
|
||||
},
|
||||
"invalidIpfsGateway": {
|
||||
"message": "Invalid IPFS Gateway: The value must be a valid URL"
|
||||
},
|
||||
"invalidNumber": {
|
||||
"message": "Invalid number. Enter a decimal or hexadecimal number."
|
||||
},
|
||||
"invalidNumberLeadingZeros": {
|
||||
"message": "Invalid number. Remove any leading zeros."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "Invalid RPC URL"
|
||||
},
|
||||
@ -951,6 +974,9 @@
|
||||
"networkName": {
|
||||
"message": "Network Name"
|
||||
},
|
||||
"networkSettingsChainIdDescription": {
|
||||
"message": "The chain ID is used for signing transactions. Enter a decimal or hexadecimal number starting with '0x'."
|
||||
},
|
||||
"networkSettingsDescription": {
|
||||
"message": "Add and edit custom RPC networks"
|
||||
},
|
||||
@ -1062,9 +1088,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "Block Explorer URL (optional)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "ChainID (optional)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Symbol (optional)"
|
||||
},
|
||||
|
@ -463,9 +463,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Invalida URL del Block Explorer"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Entrada inválida"
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "Invalida URL del RPC"
|
||||
},
|
||||
@ -586,9 +583,6 @@
|
||||
"ofTextNofM": {
|
||||
"message": "de"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "ChainID (opcional)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Símbolo (opcional)"
|
||||
},
|
||||
|
@ -557,9 +557,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Block Explorer de URL no válido"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Ingreso no válido."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "RPC de URL no válido"
|
||||
},
|
||||
@ -731,9 +728,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "Bloquear la URL de Explorer (opcional)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "ID de cadena (opcional)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Símbolo (opcional)"
|
||||
},
|
||||
|
@ -562,9 +562,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Vale Block Explorer URL"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Vigane sisend."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "Vale RPC URL"
|
||||
},
|
||||
@ -736,9 +733,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "Blokeeri Exploreri URL (valikuline)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "ChainID (valikuline)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Sümbol (valikuline)"
|
||||
},
|
||||
|
@ -566,9 +566,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Block Explorer URL نا معتبر"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "ورودی نامعتبر."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "RPC URL نا معتبر"
|
||||
},
|
||||
@ -746,9 +743,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "بلاک کردن مرورگر URL (انتخابی)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "آی دی زنجیره (انتخابی)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "سمبول (انتخابی)"
|
||||
},
|
||||
|
@ -566,9 +566,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Virheellinen Block Explorer URL-osoite"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Virheellinen syötetty arvo."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "Virheellinen RPC:n URL-osoite"
|
||||
},
|
||||
@ -743,9 +740,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "Estä Explorerin URL-osoite (valinnainen)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "Ketjun tunnus (valinnainen)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Symboli (valinnainen)"
|
||||
},
|
||||
|
@ -523,9 +523,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Hindi valid ang Block Explorer URL"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Hindi valid ang input."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "Hindi valid ang RPC URL"
|
||||
},
|
||||
@ -677,9 +674,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "Block Explorer URL (opsyonal)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "ChainID (opsyonal)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Simbolo (opsyonal)"
|
||||
},
|
||||
|
@ -551,9 +551,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "URL Block Explorer invalide"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Saisie non valide."
|
||||
},
|
||||
"invalidIpfsGateway": {
|
||||
"message": "IPFS Gateway Invalide: la valeur doit être une URL valide"
|
||||
},
|
||||
@ -728,9 +725,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "Bloquer l'URL de l'explorateur (facultatif)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "ChainID (facultatif)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Symbole (facultatif)"
|
||||
},
|
||||
|
@ -566,9 +566,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "כתובת URL לא חוקית של Block Explorer"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "קלט לא תקין."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "כתובת URL לא חוקית של RPC"
|
||||
},
|
||||
@ -743,9 +740,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "חסום כתובת URL של אקספלורר (אופציונלי)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "ChainID (אופציונלי)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "סמל (אופציונלי)"
|
||||
},
|
||||
|
@ -566,9 +566,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "अमान्य Block Explorer URL"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "अमान्य इनपुट।"
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "अमान्य RPC URL"
|
||||
},
|
||||
@ -743,9 +740,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "एक्सप्लोरर यूआरएल ब्लॉक (वैकल्पिक)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "चैनआईडी (वैकल्पिक)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "सिम्बल (वैकल्पिक)"
|
||||
},
|
||||
|
@ -202,9 +202,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "अमान्य Block Explorer कै URI"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "अमान्य इनपुट।"
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "अमान्य RPC कै URI"
|
||||
},
|
||||
|
@ -562,9 +562,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Nevaljani URL Block Explorer-a"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Nevaljani upis."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "Nevaljani URL RPC-a"
|
||||
},
|
||||
@ -739,9 +736,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "Blokiraj Explorerov URL (neobavezno)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "Identifikacijska oznaka bloka (neobavezno)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Simbol (neobavezno)"
|
||||
},
|
||||
|
@ -325,9 +325,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Block Explorer URI pa valab"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Sa ou rantre a pa valab"
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "RPC URI pa valab"
|
||||
},
|
||||
|
@ -562,9 +562,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Helytelen Block Explorer URL"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Érvénytelen bevitel."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "Helytelen RPC URL"
|
||||
},
|
||||
@ -739,9 +736,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "Explorer URL letiltása (nem kötelező)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "ChainID (nem kötelező)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Szimbólum (opcionális)"
|
||||
},
|
||||
|
@ -553,9 +553,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "URL Block Explorer Tidak Sah"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Input tidak sah."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "URL RPC Tidak Sah"
|
||||
},
|
||||
@ -727,9 +724,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "Blokir URL Penjelajah (opsional)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "ID Rantai (opsional)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Simbol (opsional)"
|
||||
},
|
||||
|
@ -823,9 +823,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "URI Block Explorer invalido"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Input non valido."
|
||||
},
|
||||
"invalidIpfsGateway": {
|
||||
"message": "Portale IPFS non valido: il valore deve essere un URL valido"
|
||||
},
|
||||
@ -1062,9 +1059,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "URL del Block Explorer (opzionale)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "ChainID (opzionale)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Simbolo (opzionale)"
|
||||
},
|
||||
|
@ -265,9 +265,6 @@
|
||||
"invalidAddress": {
|
||||
"message": "アドレスが無効です。"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "インプットが無効です。"
|
||||
},
|
||||
"jsonFile": {
|
||||
"message": "JSONファイル",
|
||||
"description": "format for importing an account"
|
||||
|
@ -566,9 +566,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "ಅಮಾನ್ಯವಾದ Block Explorer URL"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "ಅಮಾನ್ಯವಾದ ಇನ್ಪುಟ್."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "ಅಮಾನ್ಯವಾದ RPC URL"
|
||||
},
|
||||
@ -746,9 +743,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "ಅನ್ವೇಷಕ URL ಅನ್ನು ನಿರ್ಬಂಧಿಸಿ (ಐಚ್ಛಿಕ)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "ಚೈನ್ಐಡಿ (ಐಚ್ಛಿಕ)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "ಚಿಹ್ನೆ (ಐಚ್ಛಿಕ)"
|
||||
},
|
||||
|
@ -560,9 +560,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "올바르지 않은 Block Explorer URI"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "올바르지 않은 입력값"
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "올바르지 않은 RPC URI"
|
||||
},
|
||||
@ -740,9 +737,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "익스플로러 URL 차단 (선택 사항)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "ChainID (선택)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Symbol (선택)"
|
||||
},
|
||||
|
@ -566,9 +566,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Netinkamas Block Explorer URL"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Netinkama įvestis."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "Netinkamas RPC URL"
|
||||
},
|
||||
@ -746,9 +743,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "Blokuoti naršyklės URL (pasirinktinai)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "Grandinės ID (nebūtinas)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Simbolis (nebūtinas)"
|
||||
},
|
||||
|
@ -562,9 +562,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Nederīgs Block Explorer URL"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Nederīga ievadītā vērtība."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "Nederīgs RPC URL"
|
||||
},
|
||||
@ -742,9 +739,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "Bloķēt Explorer URL (pēc izvēles)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "ChainID (neobligāti)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Simbols (neobligāti)"
|
||||
},
|
||||
|
@ -549,9 +549,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "URL Block Explorer tidak sah"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Input tidak sah."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "URL RPC tidak sah"
|
||||
},
|
||||
@ -720,9 +717,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "Sekat URL Explorer (pilihan)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "ChainID (pilihan)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Simbol (pilihan)"
|
||||
},
|
||||
|
@ -196,9 +196,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Ongeldige Block Explorer URI"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Ongeldige invoer."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "Ongeldige RPC-URI"
|
||||
},
|
||||
|
@ -553,9 +553,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Ugyldig Block Explorer URL"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Ugyldig inndata "
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "Ugyldig RPC URL"
|
||||
},
|
||||
@ -733,9 +730,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "Blokker Explorer URL (valgfritt)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "Blokkjede (vagfritt)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Symbol (valgfritt)"
|
||||
},
|
||||
|
@ -154,9 +154,6 @@
|
||||
"invalidAddress": {
|
||||
"message": "Invalid ang address"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Invalid ang input."
|
||||
},
|
||||
"loading": {
|
||||
"message": "Naglo-load..."
|
||||
},
|
||||
|
@ -566,9 +566,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Nieprawidłowe Block Explorer URI"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Nieprawidłowe dane."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "Nieprawidłowe RPC URI"
|
||||
},
|
||||
@ -740,9 +737,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "Adres URL przeglądarki łańcucha bloków (opcjonalnie)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "Identyfikator łańcucha (opcjonalnie)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Symbol (opcjonalnie)"
|
||||
},
|
||||
|
@ -202,9 +202,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Block Explorer URI Inválido"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Campo inválido."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "RPC URI Inválido"
|
||||
},
|
||||
|
@ -560,9 +560,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "URL de Block Explorer inválida"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Entrada inválida."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "URL de RPC inválida"
|
||||
},
|
||||
@ -734,9 +731,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "URL exploradora de blocos (opcional)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "ChainID (opcional)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Símbolo (opcional)"
|
||||
},
|
||||
|
@ -556,9 +556,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "URL Block Explorer nevalid"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Intrare nevalidă."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "URL RPC nevalid"
|
||||
},
|
||||
@ -733,9 +730,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "URL explorator bloc (opțional)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "ChainID (opțional)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Simbol (opțional)"
|
||||
},
|
||||
|
@ -595,9 +595,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Неверный Block Explorer URI"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Неверный ввод."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "Неверный RPC URI"
|
||||
},
|
||||
@ -775,9 +772,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "URL блок-эксплорера (необязательно)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "ID сети (необязательно)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Символ (необязательно)"
|
||||
},
|
||||
|
@ -553,9 +553,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Neplatné Block Explorer URI"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Neplatný vstup."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "Neplatné RPC URI"
|
||||
},
|
||||
@ -715,9 +712,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "Blokovať URL Explorera (voliteľné)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "ChainID (voliteľné)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Symbol (voliteľné)"
|
||||
},
|
||||
|
@ -557,9 +557,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Neveljaven Block Explorer URL"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Neveljaven vnos."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "Neveljaven RPC URL"
|
||||
},
|
||||
@ -731,9 +728,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "Blokiraj URL Explorerja (poljubno)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "ChainID (nezahtevano)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Simbol (nezahtevano)"
|
||||
},
|
||||
|
@ -563,9 +563,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Nevažeći Block Explorer URL"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Nevažeći unos."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "Nevažeći RPC URL"
|
||||
},
|
||||
@ -737,9 +734,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "Blokirajte URL Explorer-a (opciono)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "ChainID (opciono)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Simbol (opciono)"
|
||||
},
|
||||
|
@ -556,9 +556,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Ogiltig Block Explorer URL"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Ogiltigt input."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "Ogiltig RPC-URL"
|
||||
},
|
||||
@ -730,9 +727,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "Block Explorer URL (valfritt)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "ChainID (frivilligt)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Symbol (frivillig)"
|
||||
},
|
||||
|
@ -553,9 +553,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Block Explorer URL batili"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Maandii si sahihi."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "RPC URL batili"
|
||||
},
|
||||
@ -724,9 +721,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "URL ya Block Explorer URL (hiari)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "Utambulisho wa Mnyororo (hiari)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Ishara (hiari)"
|
||||
},
|
||||
|
@ -256,9 +256,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "தவறான Block Explorer URI"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "தவறான உள்ளீடு.."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "தவறான RPC URI"
|
||||
},
|
||||
|
@ -280,9 +280,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Block Explorer URI ไม่ถูกต้อง"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "อินพุทไม่ถูกต้อง"
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "RPC URI ไม่ถูกต้อง"
|
||||
},
|
||||
|
@ -226,9 +226,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Geçersiz Block Explorer URI"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Geçersiz giriş."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "Geçersiz RPC URI"
|
||||
},
|
||||
|
@ -566,9 +566,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "Недійсний Block Explorer URL"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Неприпустимий ввід."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "Недійсний RPC URL"
|
||||
},
|
||||
@ -746,9 +743,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "Блокувати Explorer URL (не обов'язково)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "ChainID (необов’язково)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Символ (не обов'язково)"
|
||||
},
|
||||
|
@ -166,9 +166,6 @@
|
||||
"invalidAddress": {
|
||||
"message": "Địa chỉ không hợp lệ"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "Thông tin nhập vào không hợp lệ"
|
||||
},
|
||||
"jsonFile": {
|
||||
"message": "Tập tin JSON",
|
||||
"description": "format for importing an account"
|
||||
|
@ -557,9 +557,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "无效 Block Explorer URI"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "无效输入."
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "无效 RPC URI"
|
||||
},
|
||||
@ -728,9 +725,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "屏蔽管理器 URL(选填)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "ChainID(选填)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "符号(选填)"
|
||||
},
|
||||
|
@ -566,9 +566,6 @@
|
||||
"invalidBlockExplorerURL": {
|
||||
"message": "無效的區塊鏈瀏覽器 URL"
|
||||
},
|
||||
"invalidInput": {
|
||||
"message": "輸入錯誤。"
|
||||
},
|
||||
"invalidRPC": {
|
||||
"message": "無效的 RPC URI"
|
||||
},
|
||||
@ -737,9 +734,6 @@
|
||||
"optionalBlockExplorerUrl": {
|
||||
"message": "區塊鏈瀏覽器 URL(非必要)"
|
||||
},
|
||||
"optionalChainId": {
|
||||
"message": "ChainID (可選)"
|
||||
},
|
||||
"optionalSymbol": {
|
||||
"message": "Symbol (可選)"
|
||||
},
|
||||
|
@ -97,7 +97,6 @@ initialize().catch(log.error)
|
||||
* @property {boolean} isInitialized - Whether the first vault has been created.
|
||||
* @property {boolean} isUnlocked - Whether the vault is currently decrypted and accounts are available for selection.
|
||||
* @property {boolean} isAccountMenuOpen - Represents whether the main account selection UI is currently displayed.
|
||||
* @property {string} rpcTarget - DEPRECATED - The URL of the current RPC provider.
|
||||
* @property {Object} identities - An object matching lower-case hex addresses to Identity objects with "address" and "name" (nickname) keys.
|
||||
* @property {Object} unapprovedTxs - An object mapping transaction hashes to unapproved transactions.
|
||||
* @property {Array} frequentRpcList - A list of frequently used RPCs, including custom user-provided ones.
|
||||
@ -110,7 +109,7 @@ initialize().catch(log.error)
|
||||
* @property {boolean} welcomeScreen - True if welcome screen should be shown.
|
||||
* @property {string} currentLocale - A locale string matching the user's preferred display language.
|
||||
* @property {Object} provider - The current selected network provider.
|
||||
* @property {string} provider.rpcTarget - The address for the RPC API, if using an RPC API.
|
||||
* @property {string} provider.rpcUrl - The address for the RPC API, if using an RPC API.
|
||||
* @property {string} provider.type - An identifier for the type of network selected, allows MetaMask to use custom provider strategies for known networks.
|
||||
* @property {string} network - A stringified number of the current network ID.
|
||||
* @property {Object} accounts - An object mapping lower-case hex addresses to objects with "balance" and "address" keys, both storing hex string values.
|
||||
|
@ -2,8 +2,11 @@ import ObservableStore from 'obs-store'
|
||||
|
||||
/**
|
||||
* @typedef {Object} AlertControllerInitState
|
||||
* @property {Object} alertEnabledness - A map of any alerts that were suppressed keyed by alert ID, where the value
|
||||
* is the timestamp of when the user suppressed the alert.
|
||||
* @property {Object} alertEnabledness - A map of alerts IDs to booleans, where
|
||||
* `true` indicates that the alert is enabled and shown, and `false` the opposite.
|
||||
* @property {Object} unconnectedAccountAlertShownOrigins - A map of origin
|
||||
* strings to booleans indicating whether the "switch to connected" alert has
|
||||
* been shown (`true`) or otherwise (`false`).
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -13,6 +16,8 @@ import ObservableStore from 'obs-store'
|
||||
|
||||
export const ALERT_TYPES = {
|
||||
unconnectedAccount: 'unconnectedAccount',
|
||||
// enumerated here but has no background state
|
||||
invalidCustomNetwork: 'invalidCustomNetwork',
|
||||
}
|
||||
|
||||
const defaultState = {
|
||||
@ -44,6 +49,7 @@ export default class AlertController {
|
||||
...initState,
|
||||
unconnectedAccountAlertShownOrigins: {},
|
||||
}
|
||||
|
||||
this.store = new ObservableStore(state)
|
||||
|
||||
this.selectedAddress = preferencesStore.getState().selectedAddress
|
||||
|
@ -7,12 +7,13 @@ import createBlockTrackerInspectorMiddleware from 'eth-json-rpc-middleware/block
|
||||
import providerFromMiddleware from 'eth-json-rpc-middleware/providerFromMiddleware'
|
||||
import BlockTracker from 'eth-block-tracker'
|
||||
|
||||
export default function createJsonRpcClient ({ rpcUrl }) {
|
||||
export default function createJsonRpcClient ({ rpcUrl, chainId }) {
|
||||
const fetchMiddleware = createFetchMiddleware({ rpcUrl })
|
||||
const blockProvider = providerFromMiddleware(fetchMiddleware)
|
||||
const blockTracker = new BlockTracker({ provider: blockProvider })
|
||||
|
||||
const networkMiddleware = mergeMiddleware([
|
||||
createChainIdMiddleware(chainId),
|
||||
createBlockRefRewriteMiddleware({ blockTracker }),
|
||||
createBlockCacheMiddleware({ blockTracker }),
|
||||
createInflightMiddleware(),
|
||||
@ -21,3 +22,13 @@ export default function createJsonRpcClient ({ rpcUrl }) {
|
||||
])
|
||||
return { networkMiddleware, blockTracker }
|
||||
}
|
||||
|
||||
function createChainIdMiddleware (chainId) {
|
||||
return (req, res, next, end) => {
|
||||
if (req.method === 'eth_chainId') {
|
||||
res.result = chainId
|
||||
return end()
|
||||
}
|
||||
return next()
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,11 @@ import assert from 'assert'
|
||||
import EventEmitter from 'events'
|
||||
import ObservableStore from 'obs-store'
|
||||
import ComposedStore from 'obs-store/lib/composed'
|
||||
import EthQuery from 'eth-query'
|
||||
import JsonRpcEngine from 'json-rpc-engine'
|
||||
import providerFromEngine from 'eth-json-rpc-middleware/providerFromEngine'
|
||||
import log from 'loglevel'
|
||||
import { createSwappableProxy, createEventEmitterProxy } from 'swappable-obj-proxy'
|
||||
import EthQuery from 'eth-query'
|
||||
import createMetamaskMiddleware from './createMetamaskMiddleware'
|
||||
import createInfuraClient from './createInfuraClient'
|
||||
import createJsonRpcClient from './createJsonRpcClient'
|
||||
@ -17,16 +17,18 @@ import {
|
||||
MAINNET,
|
||||
LOCALHOST,
|
||||
INFURA_PROVIDER_TYPES,
|
||||
NETWORK_TYPE_TO_ID_MAP,
|
||||
} from './enums'
|
||||
|
||||
const networks = { networkList: {} }
|
||||
|
||||
const env = process.env.METAMASK_ENV
|
||||
const { METAMASK_DEBUG } = process.env
|
||||
|
||||
let defaultProviderConfigType
|
||||
let defaultProviderChainId
|
||||
if (process.env.IN_TEST === 'true') {
|
||||
defaultProviderConfigType = LOCALHOST
|
||||
// Decimal 5777, an arbitrary chain ID we use for testing
|
||||
defaultProviderChainId = '0x1691'
|
||||
} else if (METAMASK_DEBUG || env === 'test') {
|
||||
defaultProviderConfigType = RINKEBY
|
||||
} else {
|
||||
@ -35,31 +37,36 @@ if (process.env.IN_TEST === 'true') {
|
||||
|
||||
const defaultProviderConfig = {
|
||||
type: defaultProviderConfigType,
|
||||
}
|
||||
|
||||
const defaultNetworkConfig = {
|
||||
ticker: 'ETH',
|
||||
}
|
||||
if (defaultProviderChainId) {
|
||||
defaultProviderConfig.chainId = defaultProviderChainId
|
||||
}
|
||||
|
||||
export default class NetworkController extends EventEmitter {
|
||||
|
||||
constructor (opts = {}) {
|
||||
super()
|
||||
|
||||
// parse options
|
||||
const providerConfig = opts.provider || defaultProviderConfig
|
||||
// create stores
|
||||
this.providerStore = new ObservableStore(providerConfig)
|
||||
this.providerStore = new ObservableStore(
|
||||
opts.provider || { ...defaultProviderConfig },
|
||||
)
|
||||
this.networkStore = new ObservableStore('loading')
|
||||
this.networkConfig = new ObservableStore(defaultNetworkConfig)
|
||||
this.store = new ComposedStore({ provider: this.providerStore, network: this.networkStore, settings: this.networkConfig })
|
||||
this.on('networkDidChange', this.lookupNetwork)
|
||||
this.store = new ComposedStore({
|
||||
provider: this.providerStore,
|
||||
network: this.networkStore,
|
||||
})
|
||||
|
||||
// provider and block tracker
|
||||
this._provider = null
|
||||
this._blockTracker = null
|
||||
|
||||
// provider and block tracker proxies - because the network changes
|
||||
this._providerProxy = null
|
||||
this._blockTrackerProxy = null
|
||||
|
||||
this.on('networkDidChange', this.lookupNetwork)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -79,8 +86,8 @@ export default class NetworkController extends EventEmitter {
|
||||
|
||||
initializeProvider (providerParams) {
|
||||
this._baseProviderParams = providerParams
|
||||
const { type, rpcTarget, chainId, ticker, nickname } = this.providerStore.getState()
|
||||
this._configureProvider({ type, rpcTarget, chainId, ticker, nickname })
|
||||
const { type, rpcUrl, chainId } = this.getProviderConfig()
|
||||
this._configureProvider({ type, rpcUrl, chainId })
|
||||
this.lookupNetwork()
|
||||
}
|
||||
|
||||
@ -102,21 +109,8 @@ export default class NetworkController extends EventEmitter {
|
||||
return this.networkStore.getState()
|
||||
}
|
||||
|
||||
getNetworkConfig () {
|
||||
return this.networkConfig.getState()
|
||||
}
|
||||
|
||||
setNetworkState (network, type) {
|
||||
if (network === 'loading') {
|
||||
this.networkStore.putState(network)
|
||||
return
|
||||
}
|
||||
|
||||
// type must be defined
|
||||
if (!type) {
|
||||
return
|
||||
}
|
||||
this.networkStore.putState(networks.networkList[type]?.chainId || network)
|
||||
setNetworkState (network) {
|
||||
this.networkStore.putState(network)
|
||||
}
|
||||
|
||||
isNetworkLoading () {
|
||||
@ -129,48 +123,61 @@ export default class NetworkController extends EventEmitter {
|
||||
log.warn('NetworkController - lookupNetwork aborted due to missing provider')
|
||||
return
|
||||
}
|
||||
const { type } = this.providerStore.getState()
|
||||
|
||||
const { type, chainId: configChainId } = this.getProviderConfig()
|
||||
const chainId = NETWORK_TYPE_TO_ID_MAP[type]?.chainId || configChainId
|
||||
|
||||
if (!chainId) {
|
||||
log.warn('NetworkController - lookupNetwork aborted due to missing chainId')
|
||||
this.setNetworkState('loading')
|
||||
return
|
||||
}
|
||||
|
||||
// Ping the RPC endpoint so we can confirm that it works
|
||||
const ethQuery = new EthQuery(this._provider)
|
||||
const initialNetwork = this.getNetworkState()
|
||||
ethQuery.sendAsync({ method: 'net_version' }, (err, network) => {
|
||||
ethQuery.sendAsync({ method: 'net_version' }, (err, _networkVersion) => {
|
||||
const currentNetwork = this.getNetworkState()
|
||||
if (initialNetwork === currentNetwork) {
|
||||
if (err) {
|
||||
this.setNetworkState('loading')
|
||||
return
|
||||
}
|
||||
log.info(`web3.getNetwork returned ${network}`)
|
||||
this.setNetworkState(network, type)
|
||||
|
||||
// Now we set the network state to the chainId computed earlier
|
||||
this.setNetworkState(chainId)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
setRpcTarget (rpcTarget, chainId, ticker = 'ETH', nickname = '', rpcPrefs) {
|
||||
const providerConfig = {
|
||||
setRpcTarget (rpcUrl, chainId, ticker = 'ETH', nickname = '', rpcPrefs) {
|
||||
this.setProviderConfig({
|
||||
type: 'rpc',
|
||||
rpcTarget,
|
||||
rpcUrl,
|
||||
chainId,
|
||||
ticker,
|
||||
nickname,
|
||||
rpcPrefs,
|
||||
}
|
||||
this.providerConfig = providerConfig
|
||||
})
|
||||
}
|
||||
|
||||
async setProviderType (type, rpcTarget = '', ticker = 'ETH', nickname = '') {
|
||||
async setProviderType (type, rpcUrl = '', ticker = 'ETH', nickname = '') {
|
||||
assert.notEqual(type, 'rpc', `NetworkController - cannot call "setProviderType" with type 'rpc'. use "setRpcTarget"`)
|
||||
assert(INFURA_PROVIDER_TYPES.includes(type) || type === LOCALHOST, `NetworkController - Unknown rpc type "${type}"`)
|
||||
const providerConfig = { type, rpcTarget, ticker, nickname }
|
||||
this.providerConfig = providerConfig
|
||||
const { chainId } = NETWORK_TYPE_TO_ID_MAP[type]
|
||||
this.setProviderConfig({ type, rpcUrl, chainId, ticker, nickname })
|
||||
}
|
||||
|
||||
resetConnection () {
|
||||
this.providerConfig = this.getProviderConfig()
|
||||
this.setProviderConfig(this.getProviderConfig())
|
||||
}
|
||||
|
||||
set providerConfig (providerConfig) {
|
||||
this.providerStore.updateState(providerConfig)
|
||||
this._switchNetwork(providerConfig)
|
||||
/**
|
||||
* Sets the provider config and switches the network.
|
||||
*/
|
||||
setProviderConfig (config) {
|
||||
this.providerStore.updateState(config)
|
||||
this._switchNetwork(config)
|
||||
}
|
||||
|
||||
getProviderConfig () {
|
||||
@ -187,8 +194,7 @@ export default class NetworkController extends EventEmitter {
|
||||
this.emit('networkDidChange', opts.type)
|
||||
}
|
||||
|
||||
_configureProvider (opts) {
|
||||
const { type, rpcTarget, chainId, ticker, nickname } = opts
|
||||
_configureProvider ({ type, rpcUrl, chainId }) {
|
||||
// infura type-based endpoints
|
||||
const isInfura = INFURA_PROVIDER_TYPES.includes(type)
|
||||
if (isInfura) {
|
||||
@ -198,7 +204,7 @@ export default class NetworkController extends EventEmitter {
|
||||
this._configureLocalhostProvider()
|
||||
// url-based rpc endpoints
|
||||
} else if (type === 'rpc') {
|
||||
this._configureStandardProvider({ rpcUrl: rpcTarget, chainId, ticker, nickname })
|
||||
this._configureStandardProvider(rpcUrl, chainId)
|
||||
} else {
|
||||
throw new Error(`NetworkController - _configureProvider - unknown type "${type}"`)
|
||||
}
|
||||
@ -211,11 +217,6 @@ export default class NetworkController extends EventEmitter {
|
||||
projectId,
|
||||
})
|
||||
this._setNetworkClient(networkClient)
|
||||
// setup networkConfig
|
||||
const settings = {
|
||||
ticker: 'ETH',
|
||||
}
|
||||
this.networkConfig.putState(settings)
|
||||
}
|
||||
|
||||
_configureLocalhostProvider () {
|
||||
@ -224,22 +225,9 @@ export default class NetworkController extends EventEmitter {
|
||||
this._setNetworkClient(networkClient)
|
||||
}
|
||||
|
||||
_configureStandardProvider ({ rpcUrl, chainId, ticker, nickname }) {
|
||||
_configureStandardProvider (rpcUrl, chainId) {
|
||||
log.info('NetworkController - configureStandardProvider', rpcUrl)
|
||||
const networkClient = createJsonRpcClient({ rpcUrl })
|
||||
// hack to add a 'rpc' network with chainId
|
||||
networks.networkList.rpc = {
|
||||
chainId,
|
||||
rpcUrl,
|
||||
ticker: ticker || 'ETH',
|
||||
nickname,
|
||||
}
|
||||
// setup networkConfig
|
||||
let settings = {
|
||||
network: chainId,
|
||||
}
|
||||
settings = Object.assign(settings, networks.networkList.rpc)
|
||||
this.networkConfig.putState(settings)
|
||||
const networkClient = createJsonRpcClient({ rpcUrl, chainId })
|
||||
this._setNetworkClient(networkClient)
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import ObservableStore from 'obs-store'
|
||||
import { normalize as normalizeAddress } from 'eth-sig-util'
|
||||
import { isValidAddress, sha3, bufferToHex } from 'ethereumjs-util'
|
||||
import { isPrefixedFormattedHexString } from '../lib/util'
|
||||
import { addInternalMethodPrefix } from './permissions'
|
||||
|
||||
export default class PreferencesController {
|
||||
@ -478,10 +479,8 @@ export default class PreferencesController {
|
||||
* @param {string} chainId - Optional chainId of the selected network.
|
||||
* @param {string} ticker - Optional ticker symbol of the selected network.
|
||||
* @param {string} nickname - Optional nickname of the selected network.
|
||||
* @returns {Promise<array>} - Promise resolving to updated frequentRpcList.
|
||||
*
|
||||
*/
|
||||
|
||||
updateRpc (newRpcDetails) {
|
||||
const rpcList = this.getFrequentRpcListDetail()
|
||||
const index = rpcList.findIndex((element) => {
|
||||
@ -494,39 +493,38 @@ export default class PreferencesController {
|
||||
this.store.updateState({ frequentRpcListDetail: rpcList })
|
||||
} else {
|
||||
const { rpcUrl, chainId, ticker, nickname, rpcPrefs = {} } = newRpcDetails
|
||||
return this.addToFrequentRpcList(rpcUrl, chainId, ticker, nickname, rpcPrefs)
|
||||
this.addToFrequentRpcList(rpcUrl, chainId, ticker, nickname, rpcPrefs)
|
||||
}
|
||||
return Promise.resolve(rpcList)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds custom RPC url to state.
|
||||
*
|
||||
* @param {string} url - The RPC url to add to frequentRpcList.
|
||||
* @param {string} chainId - Optional chainId of the selected network.
|
||||
* @param {string} ticker - Optional ticker symbol of the selected network.
|
||||
* @param {string} nickname - Optional nickname of the selected network.
|
||||
* @returns {Promise<array>} - Promise resolving to updated frequentRpcList.
|
||||
* @param {string} rpcUrl - The RPC url to add to frequentRpcList.
|
||||
* @param {string} chainId - The chainId of the selected network.
|
||||
* @param {string} [ticker] - Ticker symbol of the selected network.
|
||||
* @param {string} [nickname] - Nickname of the selected network.
|
||||
*
|
||||
*/
|
||||
addToFrequentRpcList (url, chainId, ticker = 'ETH', nickname = '', rpcPrefs = {}) {
|
||||
addToFrequentRpcList (rpcUrl, chainId, ticker = 'ETH', nickname = '', rpcPrefs = {}) {
|
||||
if (rpcUrl === 'http://localhost:8545') {
|
||||
return
|
||||
}
|
||||
|
||||
const rpcList = this.getFrequentRpcListDetail()
|
||||
const index = rpcList.findIndex((element) => {
|
||||
return element.rpcUrl === url
|
||||
return element.rpcUrl === rpcUrl
|
||||
})
|
||||
if (index !== -1) {
|
||||
rpcList.splice(index, 1)
|
||||
}
|
||||
if (url !== 'http://localhost:8545') {
|
||||
let checkedChainId
|
||||
// eslint-disable-next-line radix
|
||||
if (Boolean(chainId) && !Number.isNaN(parseInt(chainId))) {
|
||||
checkedChainId = chainId
|
||||
}
|
||||
rpcList.push({ rpcUrl: url, chainId: checkedChainId, ticker, nickname, rpcPrefs })
|
||||
|
||||
if (!isPrefixedFormattedHexString(chainId)) {
|
||||
throw new Error(`Invalid chainId: "${chainId}"`)
|
||||
}
|
||||
|
||||
rpcList.push({ rpcUrl, chainId, ticker, nickname, rpcPrefs })
|
||||
this.store.updateState({ frequentRpcListDetail: rpcList })
|
||||
return Promise.resolve(rpcList)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,20 +0,0 @@
|
||||
import {
|
||||
MAINNET_CHAIN_ID,
|
||||
ROPSTEN_CHAIN_ID,
|
||||
RINKEBY_CHAIN_ID,
|
||||
KOVAN_CHAIN_ID,
|
||||
GOERLI_CHAIN_ID,
|
||||
} from '../controllers/network/enums'
|
||||
|
||||
const standardNetworkId = {
|
||||
'1': MAINNET_CHAIN_ID,
|
||||
'3': ROPSTEN_CHAIN_ID,
|
||||
'4': RINKEBY_CHAIN_ID,
|
||||
'42': KOVAN_CHAIN_ID,
|
||||
'5': GOERLI_CHAIN_ID,
|
||||
}
|
||||
|
||||
export default function selectChainId (metamaskState) {
|
||||
const { network, provider: { chainId } } = metamaskState
|
||||
return standardNetworkId[network] || `0x${parseInt(chainId, 10).toString(16)}`
|
||||
}
|
@ -44,11 +44,6 @@ export const SENTRY_STATE = {
|
||||
type: true,
|
||||
},
|
||||
seedPhraseBackedUp: true,
|
||||
settings: {
|
||||
chainId: true,
|
||||
ticker: true,
|
||||
nickname: true,
|
||||
},
|
||||
showRestorePrompt: true,
|
||||
threeBoxDisabled: true,
|
||||
threeBoxLastUpdated: true,
|
||||
|
@ -166,9 +166,12 @@ export default class TypedMessageManager extends EventEmitter {
|
||||
assert.ok(data.primaryType in data.types, `Primary type of "${data.primaryType}" has no type definition.`)
|
||||
assert.equal(validation.errors.length, 0, 'Signing data must conform to EIP-712 schema. See https://git.io/fNtcx.')
|
||||
const { chainId } = data.domain
|
||||
// eslint-disable-next-line radix
|
||||
const activeChainId = parseInt(this.networkController.getNetworkState())
|
||||
chainId && assert.equal(chainId, activeChainId, `Provided chainId "${chainId}" must match the active chainId "${activeChainId}"`)
|
||||
if (chainId) {
|
||||
// eslint-disable-next-line radix
|
||||
const activeChainId = parseInt(this.networkController.getNetworkState())
|
||||
assert.ok(!Number.isNaN(activeChainId), `Cannot sign messages for chainId "${chainId}", because MetaMask is switching networks.`)
|
||||
assert.equal(chainId, activeChainId, `Provided chainId "${chainId}" must match the active chainId "${activeChainId}"`)
|
||||
}
|
||||
break
|
||||
}
|
||||
default:
|
||||
|
@ -149,6 +149,21 @@ function checkForError () {
|
||||
return new Error(lastError.message)
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given value is a 0x-prefixed, non-zero, non-zero-padded,
|
||||
* hexadecimal string.
|
||||
*
|
||||
* @param {any} value - The value to check.
|
||||
* @returns {boolean} True if the value is a correctly formatted hex string,
|
||||
* false otherwise.
|
||||
*/
|
||||
function isPrefixedFormattedHexString (value) {
|
||||
if (typeof value !== 'string') {
|
||||
return false
|
||||
}
|
||||
return (/^0x[1-9a-f]+[0-9a-f]*$/ui).test(value)
|
||||
}
|
||||
|
||||
export {
|
||||
getPlatform,
|
||||
getEnvironmentType,
|
||||
@ -157,4 +172,5 @@ export {
|
||||
bnToHex,
|
||||
BnMultiplyByFraction,
|
||||
checkForError,
|
||||
isPrefixedFormattedHexString,
|
||||
}
|
||||
|
@ -54,7 +54,6 @@ import { PermissionsController } from './controllers/permissions'
|
||||
import getRestrictedMethods from './controllers/permissions/restrictedMethods'
|
||||
import nodeify from './lib/nodeify'
|
||||
import accountImporter from './account-import-strategies'
|
||||
import selectChainId from './lib/select-chain-id'
|
||||
import seedPhraseVerifier from './lib/seed-phrase-verifier'
|
||||
|
||||
import backgroundMetaMetricsEvent from './lib/background-metametrics'
|
||||
@ -376,14 +375,16 @@ export default class MetamaskController extends EventEmitter {
|
||||
}
|
||||
|
||||
function updatePublicConfigStore (memState) {
|
||||
publicConfigStore.putState(selectPublicState(memState))
|
||||
if (memState.network !== 'loading') {
|
||||
publicConfigStore.putState(selectPublicState(memState))
|
||||
}
|
||||
}
|
||||
|
||||
function selectPublicState ({ isUnlocked, network, provider }) {
|
||||
function selectPublicState ({ isUnlocked, network }) {
|
||||
return {
|
||||
isUnlocked,
|
||||
networkVersion: network,
|
||||
chainId: selectChainId({ network, provider }),
|
||||
chainId: network,
|
||||
networkVersion: Number.parseInt(network, 16).toString(),
|
||||
}
|
||||
}
|
||||
return publicConfigStore
|
||||
@ -1849,7 +1850,7 @@ export default class MetamaskController extends EventEmitter {
|
||||
* @param {Function} cb - A callback function returning currency info.
|
||||
*/
|
||||
setCurrentCurrency (currencyCode, cb) {
|
||||
const { ticker } = this.networkController.getNetworkConfig()
|
||||
const { ticker } = this.networkController.getProviderConfig()
|
||||
try {
|
||||
const currencyState = {
|
||||
nativeCurrency: ticker,
|
||||
@ -1866,7 +1867,6 @@ export default class MetamaskController extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
// network
|
||||
/**
|
||||
* A method for selecting a custom URL for an ethereum RPC provider and updating it
|
||||
* @param {string} rpcUrl - A URL for a valid Ethereum RPC API.
|
||||
@ -1875,7 +1875,6 @@ export default class MetamaskController extends EventEmitter {
|
||||
* @param {string} nickname - Optional nickname of the selected network.
|
||||
* @returns {Promise<String>} - The RPC Target URL confirmed.
|
||||
*/
|
||||
|
||||
async updateAndSetCustomRpc (rpcUrl, chainId, ticker = 'ETH', nickname, rpcPrefs) {
|
||||
await this.preferencesController.updateRpc({ rpcUrl, chainId, ticker, nickname, rpcPrefs })
|
||||
this.networkController.setRpcTarget(rpcUrl, chainId, ticker, nickname, rpcPrefs)
|
||||
@ -1884,31 +1883,31 @@ export default class MetamaskController extends EventEmitter {
|
||||
|
||||
/**
|
||||
* A method for selecting a custom URL for an ethereum RPC provider.
|
||||
* @param {string} rpcTarget - A URL for a valid Ethereum RPC API.
|
||||
* @param {string} rpcUrl - A URL for a valid Ethereum RPC API.
|
||||
* @param {string} chainId - The chainId of the selected network.
|
||||
* @param {string} ticker - The ticker symbol of the selected network.
|
||||
* @param {string} nickname - Optional nickname of the selected network.
|
||||
* @returns {Promise<String>} - The RPC Target URL confirmed.
|
||||
*/
|
||||
async setCustomRpc (rpcTarget, chainId, ticker = 'ETH', nickname = '', rpcPrefs = {}) {
|
||||
async setCustomRpc (rpcUrl, chainId, ticker = 'ETH', nickname = '', rpcPrefs = {}) {
|
||||
const frequentRpcListDetail = this.preferencesController.getFrequentRpcListDetail()
|
||||
const rpcSettings = frequentRpcListDetail.find((rpc) => rpcTarget === rpc.rpcUrl)
|
||||
const rpcSettings = frequentRpcListDetail.find((rpc) => rpcUrl === rpc.rpcUrl)
|
||||
|
||||
if (rpcSettings) {
|
||||
this.networkController.setRpcTarget(rpcSettings.rpcUrl, rpcSettings.chainId, rpcSettings.ticker, rpcSettings.nickname, rpcPrefs)
|
||||
} else {
|
||||
this.networkController.setRpcTarget(rpcTarget, chainId, ticker, nickname, rpcPrefs)
|
||||
await this.preferencesController.addToFrequentRpcList(rpcTarget, chainId, ticker, nickname, rpcPrefs)
|
||||
this.networkController.setRpcTarget(rpcUrl, chainId, ticker, nickname, rpcPrefs)
|
||||
await this.preferencesController.addToFrequentRpcList(rpcUrl, chainId, ticker, nickname, rpcPrefs)
|
||||
}
|
||||
return rpcTarget
|
||||
return rpcUrl
|
||||
}
|
||||
|
||||
/**
|
||||
* A method for deleting a selected custom URL.
|
||||
* @param {string} rpcTarget - A RPC URL to delete.
|
||||
* @param {string} rpcUrl - A RPC URL to delete.
|
||||
*/
|
||||
async delCustomRpc (rpcTarget) {
|
||||
await this.preferencesController.removeFromFrequentRpcList(rpcTarget)
|
||||
async delCustomRpc (rpcUrl) {
|
||||
await this.preferencesController.removeFromFrequentRpcList(rpcUrl)
|
||||
}
|
||||
|
||||
async initializeThreeBox () {
|
||||
|
38
app/scripts/migrations/048.js
Normal file
38
app/scripts/migrations/048.js
Normal file
@ -0,0 +1,38 @@
|
||||
import { cloneDeep } from 'lodash'
|
||||
|
||||
const version = 48
|
||||
|
||||
/**
|
||||
* 1. Delete NetworkController.settings
|
||||
* 2a. Delete NetworkController.provider if set to type 'rpc'.
|
||||
* It will be re-set to Mainnet on background initialization.
|
||||
* 2b. Re-key provider.rpcTarget to provider.rpcUrl
|
||||
*/
|
||||
export default {
|
||||
version,
|
||||
async migrate (originalVersionedData) {
|
||||
const versionedData = cloneDeep(originalVersionedData)
|
||||
versionedData.meta.version = version
|
||||
const state = versionedData.data
|
||||
versionedData.data = transformState(state)
|
||||
return versionedData
|
||||
},
|
||||
}
|
||||
|
||||
function transformState (state = {}) {
|
||||
// 1. Delete NetworkController.settings
|
||||
delete state.NetworkController?.settings
|
||||
|
||||
// 2. Delete NetworkController.provider or rename rpcTarget key
|
||||
if (state.NetworkController?.provider?.type === 'rpc') {
|
||||
delete state.NetworkController.provider
|
||||
} else if (state.NetworkController?.provider) {
|
||||
if ('rpcTarget' in state.NetworkController.provider) {
|
||||
const rpcUrl = state.NetworkController.provider.rpcTarget
|
||||
state.NetworkController.provider.rpcUrl = rpcUrl
|
||||
}
|
||||
delete state.NetworkController?.provider?.rpcTarget
|
||||
}
|
||||
|
||||
return state
|
||||
}
|
@ -58,6 +58,7 @@ const migrations = [
|
||||
require('./045').default,
|
||||
require('./046').default,
|
||||
require('./047').default,
|
||||
require('./048').default,
|
||||
]
|
||||
|
||||
export default migrations
|
||||
|
@ -30,12 +30,10 @@
|
||||
"network": "5777",
|
||||
"provider": {
|
||||
"nickname": "",
|
||||
"rpcTarget": "",
|
||||
"rpcUrl": "",
|
||||
"chainId": "0x1691",
|
||||
"ticker": "ETH",
|
||||
"type": "localhost"
|
||||
},
|
||||
"settings": {
|
||||
"ticker": "ETH"
|
||||
}
|
||||
},
|
||||
"OnboardingController": {
|
||||
|
@ -30,12 +30,10 @@
|
||||
"network": "5777",
|
||||
"provider": {
|
||||
"nickname": "",
|
||||
"rpcTarget": "",
|
||||
"rpcUrl": "",
|
||||
"chainId": "0x1691",
|
||||
"ticker": "ETH",
|
||||
"type": "localhost"
|
||||
},
|
||||
"settings": {
|
||||
"ticker": "ETH"
|
||||
}
|
||||
},
|
||||
"OnboardingController": {
|
||||
|
@ -33,14 +33,12 @@
|
||||
"NetworkController": {
|
||||
"provider": {
|
||||
"nickname": "",
|
||||
"rpcTarget": "",
|
||||
"rpcUrl": "",
|
||||
"chainId": "0x1691",
|
||||
"ticker": "ETH",
|
||||
"type": "localhost"
|
||||
},
|
||||
"network": "5777",
|
||||
"settings": {
|
||||
"ticker": "ETH"
|
||||
}
|
||||
"network": "5777"
|
||||
},
|
||||
"OnboardingController": {
|
||||
"onboardingTabs": {},
|
||||
|
@ -1252,15 +1252,15 @@ describe('MetaMask', function () {
|
||||
})
|
||||
|
||||
describe('Stores custom RPC history', function () {
|
||||
const customRpcUrls = [
|
||||
'http://127.0.0.1:8545/1',
|
||||
'http://127.0.0.1:8545/2',
|
||||
'http://127.0.0.1:8545/3',
|
||||
'http://127.0.0.1:8545/4',
|
||||
const customRpcInfo = [
|
||||
{ rpcUrl: 'http://127.0.0.1:8545/1', chainId: '0x1' },
|
||||
{ rpcUrl: 'http://127.0.0.1:8545/2', chainId: '0x2' },
|
||||
{ rpcUrl: 'http://127.0.0.1:8545/3', chainId: '0x3' },
|
||||
{ rpcUrl: 'http://127.0.0.1:8545/4', chainId: '0x4' },
|
||||
]
|
||||
|
||||
customRpcUrls.forEach((customRpcUrl) => {
|
||||
it(`creates custom RPC: ${customRpcUrl}`, async function () {
|
||||
customRpcInfo.forEach(({ rpcUrl, chainId }) => {
|
||||
it(`creates custom RPC: '${rpcUrl}' with chainId '${chainId}'`, async function () {
|
||||
await driver.clickElement(By.css('.network-name'))
|
||||
await driver.delay(regularDelayMs)
|
||||
|
||||
@ -1270,9 +1270,14 @@ describe('MetaMask', function () {
|
||||
await driver.findElement(By.css('.settings-page__sub-header-text'))
|
||||
|
||||
const customRpcInputs = await driver.findElements(By.css('input[type="text"]'))
|
||||
const customRpcInput = customRpcInputs[1]
|
||||
await customRpcInput.clear()
|
||||
await customRpcInput.sendKeys(customRpcUrl)
|
||||
const rpcUrlInput = customRpcInputs[1]
|
||||
const chainIdInput = customRpcInputs[2]
|
||||
|
||||
await rpcUrlInput.clear()
|
||||
await rpcUrlInput.sendKeys(rpcUrl)
|
||||
|
||||
await chainIdInput.clear()
|
||||
await chainIdInput.sendKeys(chainId)
|
||||
|
||||
await driver.clickElement(By.css('.network-form__footer .btn-secondary'))
|
||||
await driver.delay(largeDelayMs * 2)
|
||||
@ -1294,7 +1299,7 @@ describe('MetaMask', function () {
|
||||
// only recent 3 are found and in correct order (most recent at the top)
|
||||
const customRpcs = await driver.findElements(By.xpath(`//span[contains(text(), 'http://127.0.0.1:8545/')]`))
|
||||
|
||||
assert.equal(customRpcs.length, customRpcUrls.length)
|
||||
assert.equal(customRpcs.length, customRpcInfo.length)
|
||||
})
|
||||
|
||||
it('deletes a custom RPC', async function () {
|
||||
|
@ -6,7 +6,7 @@ import * as actionConstants from '../../../ui/app/store/actionConstants'
|
||||
describe('config view actions', function () {
|
||||
const initialState = {
|
||||
metamask: {
|
||||
rpcTarget: 'foo',
|
||||
rpcUrl: 'foo',
|
||||
frequentRpcList: [],
|
||||
},
|
||||
appState: {
|
||||
@ -18,7 +18,7 @@ describe('config view actions', function () {
|
||||
freeze(initialState)
|
||||
|
||||
describe('SET_RPC_TARGET', function () {
|
||||
it('sets the state.metamask.rpcTarget property of the state to the action.value', function () {
|
||||
it('sets the state.metamask.rpcUrl property of the state to the action.value', function () {
|
||||
const action = {
|
||||
type: actionConstants.SET_RPC_TARGET,
|
||||
value: 'foo',
|
||||
@ -26,7 +26,7 @@ describe('config view actions', function () {
|
||||
|
||||
const result = reducers(initialState, action)
|
||||
assert.equal(result.metamask.provider.type, 'rpc')
|
||||
assert.equal(result.metamask.provider.rpcTarget, 'foo')
|
||||
assert.equal(result.metamask.provider.rpcUrl, 'foo')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -524,19 +524,19 @@ describe('MetaMaskController', function () {
|
||||
})
|
||||
|
||||
describe('#setCustomRpc', function () {
|
||||
let rpcTarget
|
||||
let rpcUrl
|
||||
|
||||
beforeEach(function () {
|
||||
rpcTarget = metamaskController.setCustomRpc(CUSTOM_RPC_URL)
|
||||
rpcUrl = metamaskController.setCustomRpc(CUSTOM_RPC_URL)
|
||||
})
|
||||
|
||||
it('returns custom RPC that when called', async function () {
|
||||
assert.equal(await rpcTarget, CUSTOM_RPC_URL)
|
||||
assert.equal(await rpcUrl, CUSTOM_RPC_URL)
|
||||
})
|
||||
|
||||
it('changes the network controller rpc', function () {
|
||||
const networkControllerState = metamaskController.networkController.store.getState()
|
||||
assert.equal(networkControllerState.provider.rpcTarget, CUSTOM_RPC_URL)
|
||||
assert.equal(networkControllerState.provider.rpcUrl, CUSTOM_RPC_URL)
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import assert from 'assert'
|
||||
import { strict as assert } from 'assert'
|
||||
import sinon from 'sinon'
|
||||
import NetworkController from '../../../../../app/scripts/controllers/network'
|
||||
import { getNetworkDisplayName } from '../../../../../app/scripts/controllers/network/util'
|
||||
|
||||
@ -34,9 +35,9 @@ describe('NetworkController', function () {
|
||||
|
||||
describe('#setNetworkState', function () {
|
||||
it('should update the network', function () {
|
||||
networkController.setNetworkState(1, 'rpc')
|
||||
networkController.setNetworkState('1')
|
||||
const networkState = networkController.getNetworkState()
|
||||
assert.equal(networkState, 1, 'network is 1')
|
||||
assert.equal(networkState, '1', 'network is 1')
|
||||
})
|
||||
})
|
||||
|
||||
@ -47,11 +48,21 @@ describe('NetworkController', function () {
|
||||
const { type } = networkController.getProviderConfig()
|
||||
assert.equal(type, 'mainnet', 'provider type is updated')
|
||||
})
|
||||
|
||||
it('should set the network to loading', function () {
|
||||
networkController.initializeProvider(networkControllerProviderConfig)
|
||||
|
||||
const spy = sinon.spy(networkController, 'setNetworkState')
|
||||
networkController.setProviderType('mainnet')
|
||||
const loading = networkController.isNetworkLoading()
|
||||
assert.ok(loading, 'network is loading')
|
||||
|
||||
assert.equal(
|
||||
spy.callCount, 1,
|
||||
'should have called setNetworkState 2 times',
|
||||
)
|
||||
assert.ok(
|
||||
spy.calledOnceWithExactly('loading'),
|
||||
'should have called with "loading" first',
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -498,28 +498,37 @@ describe('preferences controller', function () {
|
||||
|
||||
describe('#updateRpc', function () {
|
||||
it('should update the rpcDetails properly', function () {
|
||||
preferencesController.store.updateState({ frequentRpcListDetail: [{}, { rpcUrl: 'test' }, {}] })
|
||||
preferencesController.updateRpc({ rpcUrl: 'test', chainId: '1' })
|
||||
preferencesController.updateRpc({ rpcUrl: 'test/1', chainId: '1' })
|
||||
preferencesController.updateRpc({ rpcUrl: 'test/2', chainId: '1' })
|
||||
preferencesController.updateRpc({ rpcUrl: 'test/3', chainId: '1' })
|
||||
preferencesController.store.updateState({ frequentRpcListDetail: [{}, { rpcUrl: 'test', chainId: '0x1' }, {}] })
|
||||
preferencesController.updateRpc({ rpcUrl: 'test', chainId: '0x1' })
|
||||
preferencesController.updateRpc({ rpcUrl: 'test/1', chainId: '0x1' })
|
||||
preferencesController.updateRpc({ rpcUrl: 'test/2', chainId: '0x1' })
|
||||
preferencesController.updateRpc({ rpcUrl: 'test/3', chainId: '0x1' })
|
||||
const list = preferencesController.getFrequentRpcListDetail()
|
||||
assert.deepEqual(list[1], { rpcUrl: 'test', chainId: '1' })
|
||||
assert.deepEqual(list[1], { rpcUrl: 'test', chainId: '0x1' })
|
||||
})
|
||||
})
|
||||
|
||||
describe('on updateFrequentRpcList', function () {
|
||||
describe('adding and removing from frequentRpcListDetail', function () {
|
||||
it('should add custom RPC url to state', function () {
|
||||
preferencesController.addToFrequentRpcList('rpc_url', '1')
|
||||
preferencesController.addToFrequentRpcList('http://localhost:8545', '1')
|
||||
assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, [{ rpcUrl: 'rpc_url', chainId: '1', ticker: 'ETH', nickname: '', rpcPrefs: {} }])
|
||||
preferencesController.addToFrequentRpcList('rpc_url', '1')
|
||||
assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, [{ rpcUrl: 'rpc_url', chainId: '1', ticker: 'ETH', nickname: '', rpcPrefs: {} }])
|
||||
preferencesController.addToFrequentRpcList('rpc_url', '0x1')
|
||||
preferencesController.addToFrequentRpcList('http://localhost:8545', '0x1')
|
||||
assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, [{ rpcUrl: 'rpc_url', chainId: '0x1', ticker: 'ETH', nickname: '', rpcPrefs: {} }])
|
||||
preferencesController.addToFrequentRpcList('rpc_url', '0x1')
|
||||
assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, [{ rpcUrl: 'rpc_url', chainId: '0x1', ticker: 'ETH', nickname: '', rpcPrefs: {} }])
|
||||
})
|
||||
|
||||
it('should throw if chainId is invalid', function () {
|
||||
assert.throws(
|
||||
() => {
|
||||
preferencesController.addToFrequentRpcList('rpc_url', '1')
|
||||
},
|
||||
'should throw on invalid chainId',
|
||||
)
|
||||
})
|
||||
|
||||
it('should remove custom RPC url from state', function () {
|
||||
preferencesController.addToFrequentRpcList('rpc_url', '1')
|
||||
assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, [{ rpcUrl: 'rpc_url', chainId: '1', ticker: 'ETH', nickname: '', rpcPrefs: {} }])
|
||||
preferencesController.addToFrequentRpcList('rpc_url', '0x1')
|
||||
assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, [{ rpcUrl: 'rpc_url', chainId: '0x1', ticker: 'ETH', nickname: '', rpcPrefs: {} }])
|
||||
preferencesController.removeFromFrequentRpcList('other_rpc_url')
|
||||
preferencesController.removeFromFrequentRpcList('http://localhost:8545')
|
||||
preferencesController.removeFromFrequentRpcList('rpc_url')
|
||||
|
@ -1,5 +1,9 @@
|
||||
import assert from 'assert'
|
||||
import { getEnvironmentType, sufficientBalance } from '../../../app/scripts/lib/util'
|
||||
import { strict as assert } from 'assert'
|
||||
import {
|
||||
getEnvironmentType,
|
||||
sufficientBalance,
|
||||
isPrefixedFormattedHexString,
|
||||
} from '../../../app/scripts/lib/util'
|
||||
|
||||
import {
|
||||
ENVIRONMENT_TYPE_POPUP,
|
||||
@ -88,4 +92,75 @@ describe('app utils', function () {
|
||||
assert.ok(!result, 'insufficient balance found.')
|
||||
})
|
||||
})
|
||||
|
||||
describe('isPrefixedFormattedHexString', function () {
|
||||
it('should return true for valid hex strings', function () {
|
||||
assert.equal(
|
||||
isPrefixedFormattedHexString('0x1'), true,
|
||||
'should return true',
|
||||
)
|
||||
|
||||
assert.equal(
|
||||
isPrefixedFormattedHexString('0xa'), true,
|
||||
'should return true',
|
||||
)
|
||||
|
||||
assert.equal(
|
||||
isPrefixedFormattedHexString('0xabcd1123fae909aad87452'), true,
|
||||
'should return true',
|
||||
)
|
||||
})
|
||||
|
||||
it('should return false for invalid hex strings', function () {
|
||||
assert.equal(
|
||||
isPrefixedFormattedHexString('0x'), false,
|
||||
'should return false',
|
||||
)
|
||||
|
||||
assert.equal(
|
||||
isPrefixedFormattedHexString('0x0'), false,
|
||||
'should return false',
|
||||
)
|
||||
|
||||
assert.equal(
|
||||
isPrefixedFormattedHexString('0x01'), false,
|
||||
'should return false',
|
||||
)
|
||||
|
||||
assert.equal(
|
||||
isPrefixedFormattedHexString(' 0x1'), false,
|
||||
'should return false',
|
||||
)
|
||||
|
||||
assert.equal(
|
||||
isPrefixedFormattedHexString('0x1 '), false,
|
||||
'should return false',
|
||||
)
|
||||
|
||||
assert.equal(
|
||||
isPrefixedFormattedHexString('0x1afz'), false,
|
||||
'should return false',
|
||||
)
|
||||
|
||||
assert.equal(
|
||||
isPrefixedFormattedHexString('z'), false,
|
||||
'should return false',
|
||||
)
|
||||
|
||||
assert.equal(
|
||||
isPrefixedFormattedHexString(2), false,
|
||||
'should return false',
|
||||
)
|
||||
|
||||
assert.equal(
|
||||
isPrefixedFormattedHexString(['0x1']), false,
|
||||
'should return false',
|
||||
)
|
||||
|
||||
assert.equal(
|
||||
isPrefixedFormattedHexString(), false,
|
||||
'should return false',
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -13,7 +13,7 @@ const initialState = {
|
||||
NetworkController: {
|
||||
provider: {
|
||||
type: 'rpc',
|
||||
rpcTarget: 'http://localhost:8545',
|
||||
rpcUrl: 'http://localhost:8545',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
126
test/unit/migrations/048-test.js
Normal file
126
test/unit/migrations/048-test.js
Normal file
@ -0,0 +1,126 @@
|
||||
import { strict as assert } from 'assert'
|
||||
import migration48 from '../../../app/scripts/migrations/048'
|
||||
|
||||
describe('migration #48', function () {
|
||||
it('should update the version metadata', async function () {
|
||||
const oldStorage = {
|
||||
'meta': {
|
||||
'version': 47,
|
||||
},
|
||||
'data': {},
|
||||
}
|
||||
|
||||
const newStorage = await migration48.migrate(oldStorage)
|
||||
assert.deepEqual(newStorage.meta, {
|
||||
'version': 48,
|
||||
})
|
||||
})
|
||||
|
||||
it('should delete NetworkController.settings', async function () {
|
||||
const oldStorage = {
|
||||
meta: {},
|
||||
data: {
|
||||
NetworkController: {
|
||||
settings: {
|
||||
fizz: 'buzz',
|
||||
},
|
||||
provider: {
|
||||
type: 'notRpc',
|
||||
},
|
||||
},
|
||||
foo: 'bar',
|
||||
},
|
||||
}
|
||||
|
||||
const newStorage = await migration48.migrate(oldStorage)
|
||||
assert.deepEqual(newStorage.data, {
|
||||
NetworkController: {
|
||||
provider: {
|
||||
type: 'notRpc',
|
||||
},
|
||||
},
|
||||
foo: 'bar',
|
||||
})
|
||||
})
|
||||
|
||||
it('should delete NetworkController.provider if the type is "rpc"', async function () {
|
||||
const oldStorage = {
|
||||
meta: {},
|
||||
data: {
|
||||
NetworkController: {
|
||||
provider: {
|
||||
type: 'rpc',
|
||||
fizz: 'buzz',
|
||||
},
|
||||
foo: 'bar',
|
||||
},
|
||||
foo: 'bar',
|
||||
},
|
||||
}
|
||||
|
||||
const newStorage = await migration48.migrate(oldStorage)
|
||||
assert.deepEqual(newStorage.data, {
|
||||
NetworkController: {
|
||||
foo: 'bar',
|
||||
},
|
||||
foo: 'bar',
|
||||
})
|
||||
})
|
||||
|
||||
it('should re-key NetworkController.provider.rpcTarget to rpcUrl if the type is not "rpc"', async function () {
|
||||
const oldStorage = {
|
||||
meta: {},
|
||||
data: {
|
||||
NetworkController: {
|
||||
provider: {
|
||||
type: 'someType',
|
||||
rpcTarget: 'foo.xyz',
|
||||
fizz: 'buzz',
|
||||
},
|
||||
foo: 'bar',
|
||||
},
|
||||
foo: 'bar',
|
||||
},
|
||||
}
|
||||
|
||||
const newStorage = await migration48.migrate(oldStorage)
|
||||
assert.deepEqual(newStorage.data, {
|
||||
NetworkController: {
|
||||
foo: 'bar',
|
||||
provider: {
|
||||
type: 'someType',
|
||||
rpcUrl: 'foo.xyz',
|
||||
fizz: 'buzz',
|
||||
},
|
||||
},
|
||||
foo: 'bar',
|
||||
})
|
||||
})
|
||||
|
||||
it('should do nothing if affected state does not exist', async function () {
|
||||
const oldStorage = {
|
||||
meta: {},
|
||||
data: {
|
||||
NetworkController: {
|
||||
provider: {
|
||||
type: 'notRpc',
|
||||
},
|
||||
},
|
||||
foo: 'bar',
|
||||
},
|
||||
}
|
||||
|
||||
const newStorage = await migration48.migrate(oldStorage)
|
||||
assert.deepEqual(oldStorage.data, newStorage.data)
|
||||
})
|
||||
|
||||
it('should do nothing if state is empty', async function () {
|
||||
const oldStorage = {
|
||||
meta: {},
|
||||
data: {},
|
||||
}
|
||||
|
||||
const newStorage = await migration48.migrate(oldStorage)
|
||||
assert.deepEqual(oldStorage.data, newStorage.data)
|
||||
})
|
||||
})
|
@ -27,7 +27,7 @@ describe('MetaMask Reducers', function () {
|
||||
value: 'https://custom.rpc',
|
||||
})
|
||||
|
||||
assert.equal(state.provider.rpcTarget, 'https://custom.rpc')
|
||||
assert.equal(state.provider.rpcUrl, 'https://custom.rpc')
|
||||
})
|
||||
|
||||
it('sets provider type', function () {
|
||||
|
@ -1,12 +1,21 @@
|
||||
import React from 'react'
|
||||
import { useSelector } from 'react-redux'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { alertIsOpen as unconnectedAccountAlertIsOpen } from '../../../ducks/alerts/unconnected-account'
|
||||
import { alertIsOpen as invalidCustomNetworkAlertIsOpen } from '../../../ducks/alerts/invalid-custom-network'
|
||||
import InvalidCustomNetworkAlert from './invalid-custom-network-alert'
|
||||
import UnconnectedAccountAlert from './unconnected-account-alert'
|
||||
|
||||
const Alerts = () => {
|
||||
const Alerts = ({ history }) => {
|
||||
const _invalidCustomNetworkAlertIsOpen = useSelector(invalidCustomNetworkAlertIsOpen)
|
||||
const _unconnectedAccountAlertIsOpen = useSelector(unconnectedAccountAlertIsOpen)
|
||||
|
||||
if (_invalidCustomNetworkAlertIsOpen) {
|
||||
return (
|
||||
<InvalidCustomNetworkAlert history={history} />
|
||||
)
|
||||
}
|
||||
if (_unconnectedAccountAlertIsOpen) {
|
||||
return (
|
||||
<UnconnectedAccountAlert />
|
||||
@ -16,4 +25,8 @@ const Alerts = () => {
|
||||
return null
|
||||
}
|
||||
|
||||
Alerts.propTypes = {
|
||||
history: PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
export default Alerts
|
||||
|
@ -1 +1,2 @@
|
||||
@import './invalid-custom-network-alert/invalid-custom-network-alert';
|
||||
@import './unconnected-account-alert/unconnected-account-alert';
|
||||
|
@ -0,0 +1 @@
|
||||
export { default } from './invalid-custom-network-alert'
|
@ -0,0 +1,97 @@
|
||||
import React from 'react'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { ALERT_STATE } from '../../../../ducks/alerts'
|
||||
import {
|
||||
dismissAlert,
|
||||
getAlertState,
|
||||
getNetworkName,
|
||||
} from '../../../../ducks/alerts/invalid-custom-network'
|
||||
import Popover from '../../../ui/popover'
|
||||
import Button from '../../../ui/button'
|
||||
import { useI18nContext } from '../../../../hooks/useI18nContext'
|
||||
import { NETWORKS_ROUTE } from '../../../../helpers/constants/routes'
|
||||
|
||||
const {
|
||||
ERROR,
|
||||
LOADING,
|
||||
} = ALERT_STATE
|
||||
|
||||
const InvalidCustomNetworkAlert = ({ history }) => {
|
||||
const t = useI18nContext()
|
||||
const dispatch = useDispatch()
|
||||
const alertState = useSelector(getAlertState)
|
||||
const networkName = useSelector(getNetworkName)
|
||||
|
||||
const onClose = () => dispatch(dismissAlert())
|
||||
|
||||
const footer = (
|
||||
<>
|
||||
{
|
||||
alertState === ERROR
|
||||
? (
|
||||
<div className="invalid-custom-network-alert__error">
|
||||
{ t('failureMessage') }
|
||||
</div>
|
||||
)
|
||||
: null
|
||||
}
|
||||
<div className="invalid-custom-network-alert__footer-row">
|
||||
<Button
|
||||
disabled={alertState === LOADING}
|
||||
onClick={onClose}
|
||||
type="secondary"
|
||||
className="invalid-custom-network-alert__footer-row-button"
|
||||
>
|
||||
{ t('dismiss') }
|
||||
</Button>
|
||||
<Button
|
||||
disabled={alertState === LOADING}
|
||||
onClick={async () => {
|
||||
await onClose()
|
||||
history.push(NETWORKS_ROUTE)
|
||||
}}
|
||||
type="primary"
|
||||
className="invalid-custom-network-alert__footer-row-button"
|
||||
>
|
||||
{ t('settings') }
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
|
||||
return (
|
||||
<Popover
|
||||
title={t('invalidCustomNetworkAlertTitle')}
|
||||
onClose={onClose}
|
||||
contentClassName="invalid-custom-network-alert__content"
|
||||
footerClassName="invalid-custom-network-alert__footer"
|
||||
footer={footer}
|
||||
>
|
||||
<p>{t('invalidCustomNetworkAlertContent1', [networkName])}</p>
|
||||
<p>{t('invalidCustomNetworkAlertContent2')}</p>
|
||||
<p>
|
||||
{
|
||||
t('invalidCustomNetworkAlertContent3', [(
|
||||
<span
|
||||
key="invalidCustomNetworkAlertContentLink"
|
||||
className="invalid-custom-network-alert__content-link"
|
||||
onClick={
|
||||
() => global.platform.openTab({ url: 'https://chainid.network' })
|
||||
}
|
||||
>
|
||||
chainId.network
|
||||
</span>
|
||||
)])
|
||||
}
|
||||
</p>
|
||||
</Popover>
|
||||
)
|
||||
}
|
||||
|
||||
InvalidCustomNetworkAlert.propTypes = {
|
||||
history: PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
export default InvalidCustomNetworkAlert
|
@ -0,0 +1,57 @@
|
||||
.invalid-custom-network-alert {
|
||||
&__content {
|
||||
border-radius: 0;
|
||||
padding: 0 24px 16px 24px;
|
||||
|
||||
> p {
|
||||
@include Paragraph;
|
||||
|
||||
font-size: 14px;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
> p:last-of-type {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__content-link {
|
||||
color: $primary-blue;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&__footer {
|
||||
flex-direction: column;
|
||||
|
||||
> :only-child {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&__footer-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
|
||||
& &-button {
|
||||
height: 40px;
|
||||
width: 50%;
|
||||
border-radius: 100px;
|
||||
margin-right: 24px;
|
||||
|
||||
&:last-of-type {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__error {
|
||||
margin-bottom: 16px;
|
||||
padding: 16px;
|
||||
font-size: 14px;
|
||||
border: 1px solid $accent-red;
|
||||
background: #f8eae8;
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
import React, { useState } from 'react'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
|
||||
import { ALERT_STATE } from '../../../../ducks/alerts'
|
||||
import {
|
||||
ALERT_STATE,
|
||||
connectAccount,
|
||||
dismissAlert,
|
||||
dismissAndDisableAlert,
|
||||
|
@ -4,7 +4,11 @@ import { connect } from 'react-redux'
|
||||
import { withRouter } from 'react-router-dom'
|
||||
import { compose } from 'redux'
|
||||
import * as actions from '../../../store/actions'
|
||||
import {
|
||||
openAlert as displayInvalidCustomNetworkAlert,
|
||||
} from '../../../ducks/alerts/invalid-custom-network'
|
||||
import { NETWORKS_ROUTE } from '../../../helpers/constants/routes'
|
||||
import { isPrefixedFormattedHexString } from '../../../../../app/scripts/lib/util'
|
||||
import { Dropdown, DropdownMenuItem } from './components/dropdown'
|
||||
import NetworkDropdownIcon from './components/network-dropdown-icon'
|
||||
|
||||
@ -22,7 +26,6 @@ function mapStateToProps (state) {
|
||||
provider: state.metamask.provider,
|
||||
frequentRpcListDetail: state.metamask.frequentRpcListDetail || [],
|
||||
networkDropdownOpen: state.appState.networkDropdownOpen,
|
||||
network: state.metamask.network,
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,7 +41,12 @@ function mapDispatchToProps (dispatch) {
|
||||
dispatch(actions.delRpcTarget(target))
|
||||
},
|
||||
hideNetworkDropdown: () => dispatch(actions.hideNetworkDropdown()),
|
||||
setNetworksTabAddMode: (isInAddMode) => dispatch(actions.setNetworksTabAddMode(isInAddMode)),
|
||||
setNetworksTabAddMode: (isInAddMode) => {
|
||||
dispatch(actions.setNetworksTabAddMode(isInAddMode))
|
||||
},
|
||||
displayInvalidCustomNetworkAlert: (networkName) => {
|
||||
dispatch(displayInvalidCustomNetworkAlert(networkName))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,12 +59,11 @@ class NetworkDropdown extends Component {
|
||||
static propTypes = {
|
||||
provider: PropTypes.shape({
|
||||
nickname: PropTypes.string,
|
||||
rpcTarget: PropTypes.string,
|
||||
rpcUrl: PropTypes.string,
|
||||
type: PropTypes.string,
|
||||
ticker: PropTypes.string,
|
||||
}).isRequired,
|
||||
setProviderType: PropTypes.func.isRequired,
|
||||
network: PropTypes.string.isRequired,
|
||||
setRpcTarget: PropTypes.func.isRequired,
|
||||
hideNetworkDropdown: PropTypes.func.isRequired,
|
||||
setNetworksTabAddMode: PropTypes.func.isRequired,
|
||||
@ -64,6 +71,7 @@ class NetworkDropdown extends Component {
|
||||
networkDropdownOpen: PropTypes.bool.isRequired,
|
||||
history: PropTypes.object.isRequired,
|
||||
delRpcTarget: PropTypes.func.isRequired,
|
||||
displayInvalidCustomNetworkAlert: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
handleClick (newProviderType) {
|
||||
@ -84,64 +92,30 @@ class NetworkDropdown extends Component {
|
||||
setProviderType(newProviderType)
|
||||
}
|
||||
|
||||
renderCustomOption (provider) {
|
||||
const { rpcTarget, type, ticker, nickname } = provider
|
||||
const { network } = this.props
|
||||
|
||||
if (type !== 'rpc') {
|
||||
return null
|
||||
}
|
||||
|
||||
switch (rpcTarget) {
|
||||
|
||||
case 'http://localhost:8545':
|
||||
return null
|
||||
|
||||
default:
|
||||
return (
|
||||
<DropdownMenuItem
|
||||
key={rpcTarget}
|
||||
onClick={() => this.props.setRpcTarget(rpcTarget, network, ticker, nickname)}
|
||||
closeMenu={() => this.props.hideNetworkDropdown()}
|
||||
style={{
|
||||
fontSize: '16px',
|
||||
lineHeight: '20px',
|
||||
padding: '12px 0',
|
||||
}}
|
||||
>
|
||||
<i className="fa fa-check" />
|
||||
<i className="fa fa-question-circle fa-med menu-icon-circle" />
|
||||
<span
|
||||
className="network-name-item"
|
||||
style={{
|
||||
color: '#ffffff',
|
||||
}}
|
||||
>
|
||||
{nickname || rpcTarget}
|
||||
</span>
|
||||
</DropdownMenuItem>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
renderCommonRpc (rpcListDetail, provider) {
|
||||
renderCustomRpcList (rpcListDetail, provider) {
|
||||
const reversedRpcListDetail = rpcListDetail.slice().reverse()
|
||||
|
||||
return reversedRpcListDetail.map((entry) => {
|
||||
const rpc = entry.rpcUrl
|
||||
const ticker = entry.ticker || 'ETH'
|
||||
const nickname = entry.nickname || ''
|
||||
const currentRpcTarget = provider.type === 'rpc' && rpc === provider.rpcTarget
|
||||
const { rpcUrl, chainId, ticker = 'ETH', nickname = '' } = entry
|
||||
const currentRpcTarget = (
|
||||
provider.type === 'rpc' && rpcUrl === provider.rpcUrl
|
||||
)
|
||||
|
||||
if ((rpc === 'http://localhost:8545') || currentRpcTarget) {
|
||||
if (rpcUrl === 'http://localhost:8545') {
|
||||
return null
|
||||
}
|
||||
const { chainId } = entry
|
||||
|
||||
return (
|
||||
<DropdownMenuItem
|
||||
key={`common${rpc}`}
|
||||
key={`common${rpcUrl}`}
|
||||
closeMenu={() => this.props.hideNetworkDropdown()}
|
||||
onClick={() => this.props.setRpcTarget(rpc, chainId, ticker, nickname)}
|
||||
onClick={() => {
|
||||
if (isPrefixedFormattedHexString(chainId)) {
|
||||
this.props.setRpcTarget(rpcUrl, chainId, ticker, nickname)
|
||||
} else {
|
||||
this.props.displayInvalidCustomNetworkAlert(nickname || rpcUrl)
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
fontSize: '16px',
|
||||
lineHeight: '20px',
|
||||
@ -162,15 +136,21 @@ class NetworkDropdown extends Component {
|
||||
: '#9b9b9b',
|
||||
}}
|
||||
>
|
||||
{nickname || rpc}
|
||||
{nickname || rpcUrl}
|
||||
</span>
|
||||
<i
|
||||
className="fa fa-times delete"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
this.props.delRpcTarget(rpc)
|
||||
}}
|
||||
/>
|
||||
{
|
||||
currentRpcTarget
|
||||
? null
|
||||
: (
|
||||
<i
|
||||
className="fa fa-times delete"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
this.props.delRpcTarget(rpcUrl)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</DropdownMenuItem>
|
||||
)
|
||||
})
|
||||
@ -202,7 +182,7 @@ class NetworkDropdown extends Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
const { provider: { type: providerType, rpcTarget: activeNetwork }, setNetworksTabAddMode } = this.props
|
||||
const { provider: { type: providerType, rpcUrl: activeNetwork }, setNetworksTabAddMode } = this.props
|
||||
const rpcListDetail = this.props.frequentRpcListDetail
|
||||
const isOpen = this.props.networkDropdownOpen
|
||||
const dropdownMenuItemStyle = {
|
||||
@ -382,8 +362,7 @@ class NetworkDropdown extends Component {
|
||||
{this.context.t('localhost')}
|
||||
</span>
|
||||
</DropdownMenuItem>
|
||||
{this.renderCustomOption(this.props.provider)}
|
||||
{this.renderCommonRpc(rpcListDetail, this.props.provider)}
|
||||
{this.renderCustomRpcList(rpcListDetail, this.props.provider)}
|
||||
<DropdownMenuItem
|
||||
closeMenu={() => this.props.hideNetworkDropdown()}
|
||||
onClick={() => {
|
||||
|
@ -50,7 +50,8 @@ describe('Network Dropdown', function () {
|
||||
'type': 'test',
|
||||
},
|
||||
frequentRpcListDetail: [
|
||||
{ rpcUrl: 'http://localhost:7545' },
|
||||
{ chainId: '0x1a', rpcUrl: 'http://localhost:7545' },
|
||||
{ rpcUrl: 'http://localhost:7546' },
|
||||
],
|
||||
},
|
||||
appState: {
|
||||
@ -65,8 +66,8 @@ describe('Network Dropdown', function () {
|
||||
)
|
||||
})
|
||||
|
||||
it('renders 7 DropDownMenuItems ', function () {
|
||||
assert.equal(wrapper.find(DropdownMenuItem).length, 8)
|
||||
it('renders 9 DropDownMenuItems ', function () {
|
||||
assert.equal(wrapper.find(DropdownMenuItem).length, 9)
|
||||
})
|
||||
|
||||
it('checks background color for first NetworkDropdownIcon', function () {
|
||||
@ -93,8 +94,8 @@ describe('Network Dropdown', function () {
|
||||
assert.equal(wrapper.find(NetworkDropdownIcon).at(5).prop('innerBorder'), '1px solid #9b9b9b')
|
||||
})
|
||||
|
||||
it('checks dropdown for frequestRPCList from state ', function () {
|
||||
assert.equal(wrapper.find(DropdownMenuItem).at(6).text(), '✓http://localhost:7545')
|
||||
it('checks dropdown for frequestRPCList from state', function () {
|
||||
assert.equal(wrapper.find(DropdownMenuItem).at(6).text(), '✓http://localhost:7546')
|
||||
})
|
||||
|
||||
it('checks background color for seventh NetworkDropdownIcon', function () {
|
||||
|
@ -12,10 +12,10 @@ const mapStateToProps = (state) => {
|
||||
provider,
|
||||
network,
|
||||
} = state.metamask
|
||||
const { rpcTarget, chainId, ticker, nickname, type } = provider
|
||||
const { rpcUrl, chainId, ticker, nickname, type } = provider
|
||||
|
||||
const setProviderArgs = type === 'rpc'
|
||||
? [rpcTarget, chainId, ticker, nickname]
|
||||
? [rpcUrl, chainId, ticker, nickname]
|
||||
: [provider.type]
|
||||
|
||||
return {
|
||||
|
@ -47,7 +47,7 @@ export default class Network extends Component {
|
||||
provider: PropTypes.shape({
|
||||
type: PropTypes.string,
|
||||
nickname: PropTypes.string,
|
||||
rpcTarget: PropTypes.string,
|
||||
rpcUrl: PropTypes.string,
|
||||
}).isRequired,
|
||||
disabled: PropTypes.bool,
|
||||
onClick: PropTypes.func.isRequired,
|
||||
@ -69,7 +69,7 @@ export default class Network extends Component {
|
||||
if (provider) {
|
||||
providerName = provider.type
|
||||
providerNick = provider.nickname || ''
|
||||
providerUrl = provider.rpcTarget
|
||||
providerUrl = provider.rpcUrl
|
||||
}
|
||||
|
||||
switch (providerName) {
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
&-header {
|
||||
display: flex;
|
||||
padding: 24px;
|
||||
padding: 24px 24px 16px;
|
||||
flex-direction: column;
|
||||
background: white;
|
||||
position: relative;
|
||||
@ -37,7 +37,6 @@
|
||||
|
||||
font-weight: bold;
|
||||
line-height: 25px;
|
||||
padding-bottom: 8px;
|
||||
|
||||
h2 {
|
||||
white-space: nowrap;
|
||||
@ -53,6 +52,7 @@
|
||||
&__subtitle {
|
||||
@include H6;
|
||||
|
||||
padding-top: 8px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
|
6
ui/app/ducks/alerts/enums.js
Normal file
6
ui/app/ducks/alerts/enums.js
Normal file
@ -0,0 +1,6 @@
|
||||
export const ALERT_STATE = {
|
||||
CLOSED: 'CLOSED',
|
||||
ERROR: 'ERROR',
|
||||
LOADING: 'LOADING',
|
||||
OPEN: 'OPEN',
|
||||
}
|
@ -1 +1,4 @@
|
||||
export { default as unconnectedAccount } from './unconnected-account'
|
||||
export { default as invalidCustomNetwork } from './invalid-custom-network'
|
||||
|
||||
export { ALERT_STATE } from './enums'
|
||||
|
51
ui/app/ducks/alerts/invalid-custom-network.js
Normal file
51
ui/app/ducks/alerts/invalid-custom-network.js
Normal file
@ -0,0 +1,51 @@
|
||||
import { createSlice } from '@reduxjs/toolkit'
|
||||
|
||||
import { ALERT_TYPES } from '../../../../app/scripts/controllers/alert'
|
||||
import { ALERT_STATE } from './enums'
|
||||
|
||||
// Constants
|
||||
|
||||
const name = ALERT_TYPES.invalidCustomNetwork
|
||||
|
||||
const initialState = {
|
||||
state: ALERT_STATE.CLOSED,
|
||||
networkName: '',
|
||||
}
|
||||
|
||||
// Slice (reducer plus auto-generated actions and action creators)
|
||||
|
||||
const slice = createSlice({
|
||||
name,
|
||||
initialState,
|
||||
reducers: {
|
||||
openAlert: (state, action) => {
|
||||
state.state = ALERT_STATE.OPEN
|
||||
state.networkName = action.payload
|
||||
},
|
||||
dismissAlert: (state) => {
|
||||
state.state = ALERT_STATE.CLOSED
|
||||
state.networkName = ''
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const { actions, reducer } = slice
|
||||
|
||||
export default reducer
|
||||
|
||||
// Selectors
|
||||
|
||||
export const getAlertState = (state) => state[name].state
|
||||
|
||||
export const getNetworkName = (state) => state[name].networkName
|
||||
|
||||
export const alertIsOpen = (state) => state[name].state !== ALERT_STATE.CLOSED
|
||||
|
||||
// Actions / action-creators
|
||||
|
||||
const {
|
||||
openAlert,
|
||||
dismissAlert,
|
||||
} = actions
|
||||
|
||||
export { openAlert, dismissAlert }
|
@ -12,16 +12,10 @@ import {
|
||||
getOriginOfCurrentTab,
|
||||
getSelectedAddress,
|
||||
} from '../../selectors'
|
||||
import { ALERT_STATE } from './enums'
|
||||
|
||||
// Constants
|
||||
|
||||
export const ALERT_STATE = {
|
||||
CLOSED: 'CLOSED',
|
||||
ERROR: 'ERROR',
|
||||
LOADING: 'LOADING',
|
||||
OPEN: 'OPEN',
|
||||
}
|
||||
|
||||
const name = ALERT_TYPES.unconnectedAccount
|
||||
|
||||
const initialState = {
|
||||
|
@ -6,10 +6,11 @@ import sendReducer from './send/send.duck'
|
||||
import appStateReducer from './app/app'
|
||||
import confirmTransactionReducer from './confirm-transaction/confirm-transaction.duck'
|
||||
import gasReducer from './gas/gas.duck'
|
||||
import { unconnectedAccount } from './alerts'
|
||||
import { invalidCustomNetwork, unconnectedAccount } from './alerts'
|
||||
import historyReducer from './history/history'
|
||||
|
||||
export default combineReducers({
|
||||
[ALERT_TYPES.invalidCustomNetwork]: invalidCustomNetwork,
|
||||
[ALERT_TYPES.unconnectedAccount]: unconnectedAccount,
|
||||
activeTab: (s) => (s === undefined ? null : s),
|
||||
metamask: metamaskReducer,
|
||||
|
@ -6,7 +6,7 @@ export default function reduceMetamask (state = {}, action) {
|
||||
isInitialized: false,
|
||||
isUnlocked: false,
|
||||
isAccountMenuOpen: false,
|
||||
rpcTarget: 'https://rawtestrpc.metamask.io/',
|
||||
rpcUrl: 'https://rawtestrpc.metamask.io/',
|
||||
identities: {},
|
||||
unapprovedTxs: {},
|
||||
frequentRpcList: [],
|
||||
@ -65,7 +65,7 @@ export default function reduceMetamask (state = {}, action) {
|
||||
...metamaskState,
|
||||
provider: {
|
||||
type: 'rpc',
|
||||
rpcTarget: action.value,
|
||||
rpcUrl: action.value,
|
||||
},
|
||||
}
|
||||
|
||||
@ -375,6 +375,8 @@ export const getCurrentLocale = (state) => state.metamask.currentLocale
|
||||
|
||||
export const getAlertEnabledness = (state) => state.metamask.alertEnabledness
|
||||
|
||||
export const getInvalidCustomNetworkAlertEnabledness = (state) => getAlertEnabledness(state)[ALERT_TYPES.invalidCustomNetwork]
|
||||
|
||||
export const getUnconnectedAccountAlertEnabledness = (state) => getAlertEnabledness(state)[ALERT_TYPES.unconnectedAccount]
|
||||
|
||||
export const getUnconnectedAccountAlertShown = (state) => state.metamask.unconnectedAccountAlertShownOrigins
|
||||
|
@ -256,7 +256,7 @@ export default class Routes extends Component {
|
||||
{
|
||||
isUnlocked
|
||||
? (
|
||||
<Alerts />
|
||||
<Alerts history={this.props.history} />
|
||||
)
|
||||
: null
|
||||
}
|
||||
|
@ -96,6 +96,12 @@
|
||||
}
|
||||
|
||||
&__network-form-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__network-form-label-text {
|
||||
font-family: Roboto;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-size: 14px;
|
||||
@ -103,6 +109,11 @@
|
||||
color: #000;
|
||||
}
|
||||
|
||||
&__network-form-label-tooltip {
|
||||
margin-left: 5px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
&__networks-list {
|
||||
flex: 0.5 0 auto;
|
||||
max-width: 343px;
|
||||
|
@ -1,8 +1,11 @@
|
||||
import React, { PureComponent } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import validUrl from 'valid-url'
|
||||
import BigNumber from 'bignumber.js'
|
||||
import TextField from '../../../../components/ui/text-field'
|
||||
import Button from '../../../../components/ui/button'
|
||||
import Tooltip from '../../../../components/ui/tooltip'
|
||||
import { isPrefixedFormattedHexString } from '../../../../../../app/scripts/lib/util'
|
||||
|
||||
export default class NetworkForm extends PureComponent {
|
||||
static contextTypes = {
|
||||
@ -97,10 +100,17 @@ export default class NetworkForm extends PureComponent {
|
||||
const {
|
||||
networkName,
|
||||
rpcUrl,
|
||||
chainId,
|
||||
chainId: stateChainId,
|
||||
ticker,
|
||||
blockExplorerUrl,
|
||||
} = this.state
|
||||
|
||||
// Ensure chainId is a 0x-prefixed, lowercase hex string
|
||||
let chainId = stateChainId.trim().toLowerCase()
|
||||
if (!chainId.startsWith('0x')) {
|
||||
chainId = `0x${(new BigNumber(chainId, 10)).toString(16)}`
|
||||
}
|
||||
|
||||
if (propsRpcUrl && rpcUrl !== propsRpcUrl) {
|
||||
editRpc(propsRpcUrl, rpcUrl, chainId, ticker, networkName, {
|
||||
blockExplorerUrl: blockExplorerUrl || rpcPrefs.blockExplorerUrl,
|
||||
@ -168,13 +178,30 @@ export default class NetworkForm extends PureComponent {
|
||||
)
|
||||
}
|
||||
|
||||
renderFormTextField (fieldKey, textFieldId, onChange, value, optionalTextFieldKey) {
|
||||
renderFormTextField (fieldKey, textFieldId, onChange, value, optionalTextFieldKey, tooltipText) {
|
||||
const { errors } = this.state
|
||||
const { viewOnly } = this.props
|
||||
|
||||
return (
|
||||
<div className="networks-tab__network-form-row">
|
||||
<div className="networks-tab__network-form-label">{this.context.t(optionalTextFieldKey || fieldKey)}</div>
|
||||
<div className="networks-tab__network-form-label">
|
||||
<div className="networks-tab__network-form-label-text">
|
||||
{this.context.t(optionalTextFieldKey || fieldKey)}
|
||||
</div>
|
||||
{
|
||||
!viewOnly && tooltipText
|
||||
? (
|
||||
<Tooltip
|
||||
position="top"
|
||||
title={tooltipText}
|
||||
wrapperClassName="networks-tab__network-form-label-tooltip"
|
||||
>
|
||||
<i className="fa fa-info-circle" />
|
||||
</Tooltip>
|
||||
)
|
||||
: null
|
||||
}
|
||||
</div>
|
||||
<TextField
|
||||
type="text"
|
||||
id={textFieldId}
|
||||
@ -205,11 +232,23 @@ export default class NetworkForm extends PureComponent {
|
||||
})
|
||||
}
|
||||
|
||||
validateChainId = (chainId) => {
|
||||
// eslint-disable-next-line radix
|
||||
this.setErrorTo('chainId', Boolean(chainId) && Number.isNaN(parseInt(chainId))
|
||||
? `${this.context.t('invalidInput')} chainId`
|
||||
: '')
|
||||
validateChainId = (chainIdArg = '') => {
|
||||
const chainId = chainIdArg.trim()
|
||||
let errorMessage = ''
|
||||
|
||||
if (chainId.startsWith('0x')) {
|
||||
if (!(/^0x[0-9a-f]+$/ui).test(chainId)) {
|
||||
errorMessage = this.context.t('invalidHexNumber')
|
||||
} else if (!isPrefixedFormattedHexString(chainId)) {
|
||||
errorMessage = this.context.t('invalidHexNumberLeadingZeros')
|
||||
}
|
||||
} else if (!(/^[0-9]+$/u).test(chainId)) {
|
||||
errorMessage = this.context.t('invalidNumber')
|
||||
} else if (chainId.startsWith('0')) {
|
||||
errorMessage = this.context.t('invalidNumberLeadingZeros')
|
||||
}
|
||||
|
||||
this.setErrorTo('chainId', errorMessage)
|
||||
}
|
||||
|
||||
isValidWhenAppended = (url) => {
|
||||
@ -262,7 +301,13 @@ export default class NetworkForm extends PureComponent {
|
||||
errors,
|
||||
} = this.state
|
||||
|
||||
const isSubmitDisabled = viewOnly || this.stateIsUnchanged() || Object.values(errors).some((x) => x) || !rpcUrl
|
||||
const isSubmitDisabled = (
|
||||
viewOnly ||
|
||||
this.stateIsUnchanged() ||
|
||||
!rpcUrl ||
|
||||
!chainId ||
|
||||
Object.values(errors).some((x) => x)
|
||||
)
|
||||
const deletable = !networksTabIsInAddMode && !isCurrentRpcTarget && !viewOnly
|
||||
|
||||
return (
|
||||
@ -285,7 +330,8 @@ export default class NetworkForm extends PureComponent {
|
||||
'chainId',
|
||||
this.setStateWithValue('chainId', this.validateChainId),
|
||||
chainId,
|
||||
'optionalChainId',
|
||||
null,
|
||||
t('networkSettingsChainIdDescription'),
|
||||
)}
|
||||
{this.renderFormTextField(
|
||||
'symbol',
|
||||
|
@ -1,54 +1,68 @@
|
||||
import {
|
||||
GOERLI,
|
||||
GOERLI_CHAIN_ID,
|
||||
KOVAN,
|
||||
KOVAN_CHAIN_ID,
|
||||
LOCALHOST,
|
||||
MAINNET,
|
||||
MAINNET_CHAIN_ID,
|
||||
RINKEBY,
|
||||
RINKEBY_CHAIN_ID,
|
||||
ROPSTEN,
|
||||
ROPSTEN_CHAIN_ID,
|
||||
} from '../../../../../app/scripts/controllers/network/enums'
|
||||
|
||||
const defaultNetworksData = [
|
||||
{
|
||||
labelKey: 'mainnet',
|
||||
labelKey: MAINNET,
|
||||
iconColor: '#29B6AF',
|
||||
providerType: 'mainnet',
|
||||
providerType: MAINNET,
|
||||
rpcUrl: `https://mainnet.infura.io/v3/${process.env.INFURA_PROJECT_ID}`,
|
||||
chainId: '1',
|
||||
chainId: MAINNET_CHAIN_ID,
|
||||
ticker: 'ETH',
|
||||
blockExplorerUrl: 'https://etherscan.io',
|
||||
},
|
||||
{
|
||||
labelKey: 'ropsten',
|
||||
labelKey: ROPSTEN,
|
||||
iconColor: '#FF4A8D',
|
||||
providerType: 'ropsten',
|
||||
providerType: ROPSTEN,
|
||||
rpcUrl: `https://ropsten.infura.io/v3/${process.env.INFURA_PROJECT_ID}`,
|
||||
chainId: '3',
|
||||
chainId: ROPSTEN_CHAIN_ID,
|
||||
ticker: 'ETH',
|
||||
blockExplorerUrl: 'https://ropsten.etherscan.io',
|
||||
},
|
||||
{
|
||||
labelKey: 'rinkeby',
|
||||
labelKey: RINKEBY,
|
||||
iconColor: '#F6C343',
|
||||
providerType: 'rinkeby',
|
||||
providerType: RINKEBY,
|
||||
rpcUrl: `https://rinkeby.infura.io/v3/${process.env.INFURA_PROJECT_ID}`,
|
||||
chainId: '4',
|
||||
chainId: RINKEBY_CHAIN_ID,
|
||||
ticker: 'ETH',
|
||||
blockExplorerUrl: 'https://rinkeby.etherscan.io',
|
||||
},
|
||||
{
|
||||
labelKey: 'goerli',
|
||||
labelKey: GOERLI,
|
||||
iconColor: '#3099f2',
|
||||
providerType: 'goerli',
|
||||
providerType: GOERLI,
|
||||
rpcUrl: `https://goerli.infura.io/v3/${process.env.INFURA_PROJECT_ID}`,
|
||||
chainId: '5',
|
||||
chainId: GOERLI_CHAIN_ID,
|
||||
ticker: 'ETH',
|
||||
blockExplorerUrl: 'https://goerli.etherscan.io',
|
||||
},
|
||||
{
|
||||
labelKey: 'kovan',
|
||||
labelKey: KOVAN,
|
||||
iconColor: '#9064FF',
|
||||
providerType: 'kovan',
|
||||
providerType: KOVAN,
|
||||
rpcUrl: `https://kovan.infura.io/v3/${process.env.INFURA_PROJECT_ID}`,
|
||||
chainId: '42',
|
||||
chainId: KOVAN_CHAIN_ID,
|
||||
ticker: 'ETH',
|
||||
blockExplorerUrl: 'https://etherscan.io',
|
||||
},
|
||||
{
|
||||
labelKey: 'localhost',
|
||||
labelKey: LOCALHOST,
|
||||
iconColor: 'white',
|
||||
border: '1px solid #6A737D',
|
||||
providerType: 'localhost',
|
||||
providerType: LOCALHOST,
|
||||
rpcUrl: 'http://localhost:8545/',
|
||||
blockExplorerUrl: 'https://etherscan.io',
|
||||
},
|
||||
|
@ -43,7 +43,7 @@ const mapStateToProps = (state) => {
|
||||
let networkDefaultedToProvider = false
|
||||
if (!networkIsSelected && !networksTabIsInAddMode) {
|
||||
selectedNetwork = networksToRender.find((network) => {
|
||||
return network.rpcUrl === provider.rpcTarget || (network.providerType !== 'rpc' && network.providerType === provider.type)
|
||||
return network.rpcUrl === provider.rpcUrl || (network.providerType !== 'rpc' && network.providerType === provider.type)
|
||||
}) || {}
|
||||
networkDefaultedToProvider = true
|
||||
}
|
||||
@ -54,7 +54,7 @@ const mapStateToProps = (state) => {
|
||||
networkIsSelected,
|
||||
networksTabIsInAddMode,
|
||||
providerType: provider.type,
|
||||
providerUrl: provider.rpcTarget,
|
||||
providerUrl: provider.rpcUrl,
|
||||
networkDefaultedToProvider,
|
||||
}
|
||||
}
|
||||
|
@ -9,9 +9,9 @@ import {
|
||||
import { getPermissionsRequestCount } from './permissions'
|
||||
|
||||
export function getNetworkIdentifier (state) {
|
||||
const { metamask: { provider: { type, nickname, rpcTarget } } } = state
|
||||
const { metamask: { provider: { type, nickname, rpcUrl } } } = state
|
||||
|
||||
return nickname || rpcTarget || type
|
||||
return nickname || rpcUrl || type
|
||||
}
|
||||
|
||||
export function getCurrentKeyring (state) {
|
||||
@ -299,7 +299,7 @@ export const getBackgroundMetaMetricState = (state) => {
|
||||
|
||||
export function getRpcPrefsForCurrentProvider (state) {
|
||||
const { frequentRpcListDetail, provider } = state.metamask
|
||||
const selectRpcInfo = frequentRpcListDetail.find((rpcInfo) => rpcInfo.rpcUrl === provider.rpcTarget)
|
||||
const selectRpcInfo = frequentRpcListDetail.find((rpcInfo) => rpcInfo.rpcUrl === provider.rpcUrl)
|
||||
const { rpcPrefs = {} } = selectRpcInfo || {}
|
||||
return rpcPrefs
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ const state = {
|
||||
'isInitialized': true,
|
||||
'isUnlocked': true,
|
||||
'featureFlags': { 'sendHexData': true },
|
||||
'rpcTarget': 'https://rawtestrpc.metamask.io/',
|
||||
'rpcUrl': 'https://rawtestrpc.metamask.io/',
|
||||
'identities': {
|
||||
'0xfdea65c8e26263f6d9a1b5de9555d2931a33b825': {
|
||||
'address': '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825',
|
||||
|
@ -14,7 +14,7 @@ import txHelper from './lib/tx-helper'
|
||||
import { fetchLocale, loadRelativeTimeFormatLocaleData } from './app/helpers/utils/i18n-helper'
|
||||
import switchDirection from './app/helpers/utils/switch-direction'
|
||||
import { getPermittedAccountsForCurrentTab, getSelectedAddress } from './app/selectors'
|
||||
import { ALERT_STATE } from './app/ducks/alerts/unconnected-account'
|
||||
import { ALERT_STATE } from './app/ducks/alerts'
|
||||
import {
|
||||
getUnconnectedAccountAlertEnabledness,
|
||||
getUnconnectedAccountAlertShown,
|
||||
@ -88,7 +88,9 @@ async function startApp (metamaskState, backgroundConnection, opts) {
|
||||
permittedAccountsForCurrentTab.length > 0 &&
|
||||
!permittedAccountsForCurrentTab.includes(selectedAddress)
|
||||
) {
|
||||
draftInitialState[ALERT_TYPES.unconnectedAccount] = { state: ALERT_STATE.OPEN }
|
||||
draftInitialState[ALERT_TYPES.unconnectedAccount] = {
|
||||
state: ALERT_STATE.OPEN,
|
||||
}
|
||||
actions.setUnconnectedAccountAlertShown(origin)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user