diff options
author | brunobar79 <brunobar79@gmail.com> | 2018-11-07 09:21:19 +0800 |
---|---|---|
committer | brunobar79 <brunobar79@gmail.com> | 2018-11-07 09:21:19 +0800 |
commit | c651212025ab7cd0309d96be6687c1eba35ab9fa (patch) | |
tree | fa5a6020daae332c5df47bdee3492e8a079375e3 | |
parent | 9c1b2108f69334884473eb95758e2d1c02c984d6 (diff) | |
parent | 7f944923d170d6e7e04f6e238d2fd5f80abe3161 (diff) | |
download | tangerine-wallet-browser-c651212025ab7cd0309d96be6687c1eba35ab9fa.tar.gz tangerine-wallet-browser-c651212025ab7cd0309d96be6687c1eba35ab9fa.tar.zst tangerine-wallet-browser-c651212025ab7cd0309d96be6687c1eba35ab9fa.zip |
fix merge conflicts
191 files changed, 6145 insertions, 3748 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml index 00ba9ffa2..3aac53171 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -47,14 +47,14 @@ workflows: requires: - prep-deps-npm - prep-build - - test-integration-mascara-chrome: - requires: - - prep-deps-npm - - prep-scss - - test-integration-mascara-firefox: - requires: - - prep-deps-npm - - prep-scss + # - test-integration-mascara-chrome: + # requires: + # - prep-deps-npm + # - prep-scss + # - test-integration-mascara-firefox: + # requires: + # - prep-deps-npm + # - prep-scss - test-integration-flat-chrome: requires: - prep-deps-npm @@ -73,8 +73,8 @@ workflows: - test-e2e-beta-chrome - test-e2e-beta-firefox - test-e2e-beta-drizzle - - test-integration-mascara-chrome - - test-integration-mascara-firefox + # - test-integration-mascara-chrome + # - test-integration-mascara-firefox - test-integration-flat-chrome - test-integration-flat-firefox - job-screens: @@ -293,9 +293,9 @@ jobs: - checkout - attach_workspace: at: . - - store_artifacts: - path: dist/mascara - destination: builds/mascara + # - store_artifacts: + # path: dist/mascara + # destination: builds/mascara - store_artifacts: path: dist/sourcemaps destination: builds/sourcemaps @@ -322,9 +322,9 @@ jobs: - run: name: github gh-pages docs publish command: > - git config user.name metamaskbot && - git config user.email admin@metamask.io && - gh-pages -d docs/jsdocs + git config --global user.name "metamaskbot" && + git config --global user.email "admin@metamask.io" && + npm run publish-docs test-unit: docker: diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a9d7703c..7142b815b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,26 @@ ## Current Develop Branch +## 5.0.0 Tuesday November 6 2018 + +- Implements EIP 1102 as a user-activated "Privacy Mode". + +## 4.17.1 Saturday November 3 2018 + +- Revert chain ID lookup change which introduced a bug which caused problems when connecting to mainnet via Infura's RESTful API. + +## 4.17.0 Thursday November 1 2018 + +- Fix bug where data lookups like balances would get stale data (stopped block-tracker bug) +- Transaction Details now show entry for onchain failure +- [#5559](https://github.com/MetaMask/metamask-extension/pull/5559) Localize language names in translation select list +- [#5283](https://github.com/MetaMask/metamask-extension/pull/5283): Fix bug when eth.getCode() called with no contract +- [#5563](https://github.com/MetaMask/metamask-extension/pull/5563#pullrequestreview-166769174) Feature: improve Hatian Creole translations +- Feature: improve Slovenian translations +- Add support for alternate `wallet_watchAsset` rpc method name +- Attempt chain ID lookup via `eth_chainId` before `net_version` +- Fix account display width for large currency values + ## 4.16.0 Wednesday October 17 2018 - Feature: Add toggle for primary currency (eth/fiat) diff --git a/app/_locales/cs/messages.json b/app/_locales/cs/messages.json index ae2413ad9..fde553c9e 100644 --- a/app/_locales/cs/messages.json +++ b/app/_locales/cs/messages.json @@ -1,4 +1,49 @@ { + "privacyMode": { + "message": "Režim súkromia" + }, + "privacyModeDescription": { + "message": "Webové stránky musia požiadať o prístup k zobrazeniu informácií o vašom účte." + }, + "exposeAccounts": { + "message": "Vystavte účty" + }, + "exposeDescription": { + "message": "Vystavte účty na aktuální webové stránky. Užitečné pro starší dappy." + }, + "confirmExpose": { + "message": "Opravdu chcete své účty vystavit na stávajícím webu?" + }, + "confirmClear": { + "message": "Naozaj chcete vymazať schválené webové stránky?" + }, + "clearApprovalDataSuccess": { + "message": "Schválené údaje webových stránek byly úspěšně zrušeny." + }, + "approvalData": { + "message": "Údaje o schválení" + }, + "approvalDataDescription": { + "message": "Vymažte schválené údaje webových stránek, aby všechny weby znovu požádaly o schválení." + }, + "clearApprovalData": { + "message": "Jasné údaje o schválení" + }, + "approve": { + "message": "Schválit" + }, + "reject": { + "message": "Odmítnout" + }, + "providerAPIRequest": { + "message": "Požadavek API Ethereum" + }, + "reviewProviderRequest": { + "message": "Přečtěte si prosím tuto žádost API Ethereum." + }, + "providerRequestInfo": { + "message": "Níže uvedená doména se pokouší požádat o přístup k API Ethereum, aby mohla komunikovat s blokádou Ethereum. Před schválením přístupu Ethereum vždy zkontrolujte, zda jste na správném místě." + }, "accept": { "message": "Přijmout" }, diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index 9e1eb9eac..9404a9824 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -1,4 +1,49 @@ { + "privacyMode": { + "message": "Datenschutzmodus" + }, + "privacyModeDescription": { + "message": "Websites müssen Zugriff anfordern, um Ihre Kontoinformationen anzuzeigen." + }, + "exposeAccounts": { + "message": "Expose Konten" + }, + "exposeDescription": { + "message": "Expose Konten auf der aktuellen Website. Nützlich für ältere Dapps." + }, + "confirmExpose": { + "message": "Möchten Sie Ihre Konten wirklich der aktuellen Website zugänglich machen?" + }, + "confirmClear": { + "message": "Möchten Sie die genehmigten Websites wirklich löschen?" + }, + "clearApprovalDataSuccess": { + "message": "Genehmigte Website-Daten wurden erfolgreich gelöscht." + }, + "approvalData": { + "message": "Genehmigungsdaten" + }, + "approvalDataDescription": { + "message": "Löschen Sie die genehmigten Website-Daten, damit alle Websites erneut eine Genehmigung anfordern müssen." + }, + "clearApprovalData": { + "message": "Genehmigungsdaten löschen" + }, + "approve": { + "message": "Genehmigen" + }, + "reject": { + "message": "Ablehnen" + }, + "providerAPIRequest": { + "message": "Web3-API-Anfrage" + }, + "reviewProviderRequest": { + "message": "Bitte lesen Sie diese Ethereum-API-Anfrage." + }, + "providerRequestInfo": { + "message": "Die unten aufgeführte Domäne versucht, Zugriff auf die Ethereum-API anzufordern, damit sie mit der Ethereum-Blockchain interagieren kann. Überprüfen Sie immer, dass Sie sich auf der richtigen Website befinden, bevor Sie den Web3-Zugriff genehmigen." + }, "accept": { "message": "Annehmen" }, diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index bf5854a31..95c9efeeb 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -1,4 +1,43 @@ { + "privacyMode": { + "message": "Privacy Mode" + }, + "privacyModeDescription": { + "message": "Websites must request access to view your account information." + }, + "exposeAccounts": { + "message": "Expose Accounts" + }, + "exposeDescription": { + "message": "Expose accounts to the current website. Useful for legacy dapps." + }, + "confirmExpose": { + "message": "Are you sure you want to expose your accounts to the current website?" + }, + "confirmClear": { + "message": "Are you sure you want to clear approved websites?" + }, + "clearApprovalDataSuccess": { + "message": "Approved website data cleared successfully." + }, + "approvalData": { + "message": "Privacy Data" + }, + "approvalDataDescription": { + "message": "Clear privacy data so all websites must request access to view account information again." + }, + "clearApprovalData": { + "message": "Clear Privacy Data" + }, + "reject": { + "message": "Reject" + }, + "providerRequest": { + "message": "$1 would like to connect to your account" + }, + "providerRequestInfo": { + "message": "This site is requesting access to view your current account address. Always make sure you trust the sites you interact with." + }, "accept": { "message": "Accept" }, @@ -170,6 +209,9 @@ "connect": { "message": "Connect" }, + "connectRequest": { + "message": "Connect Request" + }, "connecting": { "message": "Connecting..." }, @@ -692,9 +734,27 @@ "newRecipient": { "message": "New Recipient" }, - "newRPC": { + "newNetwork": { + "message": "New Network" + }, + "rpcURL": { "message": "New RPC URL" }, + "showAdvancedOptions": { + "message": "Show Advanced Options" + }, + "hideAdvancedOptions": { + "message": "Hide Advanced Options" + }, + "optionalChainId": { + "message": "ChainID (optional)" + }, + "optionalSymbol": { + "message": "Symbol (optional)" + }, + "optionalNickname": { + "message": "Nickname (optional)" + }, "next": { "message": "Next" }, @@ -803,7 +863,7 @@ "message": "Primary Currency" }, "primaryCurrencySettingDescription": { - "message": "Select ETH to prioritize displaying values in ETH. Select Fiat to prioritize displaying values in your selected currency." + "message": "Select native to prioritize displaying values in the native currency of the chain (e.g. ETH). Select Fiat to prioritize displaying values in your selected fiat currency." }, "privacyMsg": { "message": "Privacy Policy" @@ -842,9 +902,6 @@ "refundAddress": { "message": "Your Refund Address" }, - "reject": { - "message": "Reject" - }, "rejectAll": { "message": "Reject All" }, @@ -1169,12 +1226,18 @@ "transactionUpdatedGas": { "message": "Transaction updated with a gas price of $1 on $2." }, + "transactionErrored": { + "message": "Transaction encountered an error." + }, "transactions": { "message": "transactions" }, "transactionError": { "message": "Transaction Error. Exception thrown in contract code." }, + "transactionErrorNoContract": { + "message": "Trying to call a function on a non-contract address." + }, "transactionMemo": { "message": "Transaction memo (optional)" }, diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index be2a29ab5..55276e1ec 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -1,4 +1,49 @@ { + "privacyMode": { + "message": "Modo privado" + }, + "privacyModeDescription": { + "message": "Los sitios web deben solicitar acceso para ver la información de su cuenta." + }, + "exposeAccounts": { + "message": "Exponer cuentas" + }, + "exposeDescription": { + "message": "Exponer cuentas al sitio web actual. Útil para dapps heredados." + }, + "confirmExpose": { + "message": "¿Seguro que quieres exponer tus cuentas al sitio web actual?" + }, + "confirmClear": { + "message": "¿Seguro que quieres borrar los sitios web aprobados?" + }, + "clearApprovalDataSuccess": { + "message": "Los datos aprobados del sitio web se borraron con éxito." + }, + "approvalData": { + "message": "Datos de aprobación" + }, + "approvalDataDescription": { + "message": "Borre los datos del sitio web aprobado para que todos los sitios deban volver a solicitar la aprobación." + }, + "clearApprovalData": { + "message": "Borrar datos de aprobación" + }, + "approve": { + "message": "Aprobar" + }, + "reject": { + "message": "Rechazar" + }, + "providerAPIRequest": { + "message": "Solicitud de API Web3" + }, + "reviewProviderRequest": { + "message": "Por favor, revise esta solicitud API Ethereum." + }, + "providerRequestInfo": { + "message": "El dominio que se muestra a continuación intenta solicitar acceso a la API Ethereum para que pueda interactuar con la cadena de bloques de Ethereum. Siempre verifique que esté en el sitio correcto antes de aprobar el acceso Ethereum." + }, "accept": { "message": "Aceptar" }, diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index d418cd9aa..17306d0f2 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -1,4 +1,43 @@ { + "privacyMode": { + "message": "Les sites Web doivent demander un accès pour afficher les informations de votre compte." + }, + "privacyModeDescription": { + "message": "Les sites Web doivent demander un accès pour afficher les informations de votre compte." + }, + "exposeAccounts": { + "message": "Exposer les comptes" + }, + "exposeDescription": { + "message": "Exposer des comptes sur le site Web actuel. Utile pour les dapps hérités." + }, + "confirmExpose": { + "message": "Êtes-vous sûr de vouloir exposer vos comptes au site Web actuel?" + }, + "confirmClear": { + "message": "Êtes-vous sûr de vouloir supprimer les sites Web approuvés?" + }, + "clearApprovalDataSuccess": { + "message": "Les données de site Web approuvées ont été supprimées." + }, + "approvalData": { + "message": "Données d'approbation" + }, + "approvalDataDescription": { + "message": "Effacer les données de site Web approuvées afin que tous les sites doivent à nouveau demander l'approbation." + }, + "clearApprovalData": { + "message": "Effacer les données d'approbation" + }, + "providerAPIRequest": { + "message": "Demande d'API Web3" + }, + "reviewProviderRequest": { + "message": "Veuillez consulter cette demande d'API Ethereum." + }, + "providerRequestInfo": { + "message": "Le domaine répertorié ci-dessous tente de demander l'accès à l'API Ethereum pour pouvoir interagir avec la chaîne de blocs Ethereum. Vérifiez toujours que vous êtes sur le bon site avant d'autoriser l'accès à Ethereum." + }, "accept": { "message": "Accepter" }, diff --git a/app/_locales/hn/messages.json b/app/_locales/hn/messages.json index b869560e5..8e2281418 100644 --- a/app/_locales/hn/messages.json +++ b/app/_locales/hn/messages.json @@ -1,4 +1,49 @@ { + "privacyMode": { + "message": "गोपनीयता मोड" + }, + "privacyModeDescription": { + "message": "वेबसाइटों को आपकी खाता जानकारी देखने के लिए पहुंच का अनुरोध करना होगा।" + }, + "exposeAccounts": { + "message": "खातों का पर्दाफाश करें" + }, + "exposeDescription": { + "message": "मौजूदा वेबसाइट पर खातों का पर्दाफाश करें। विरासत डैप्स के लिए उपयोगी।" + }, + "confirmExpose": { + "message": "क्या आप वाकई अपने खातों को वर्तमान वेबसाइट पर बेनकाब करना चाहते हैं?" + }, + "confirmClear": { + "message": "क्या आप वाकई अनुमोदित वेबसाइटों को साफ़ करना चाहते हैं?" + }, + "clearApprovalDataSuccess": { + "message": "स्वीकृत वेबसाइट डेटा सफलतापूर्वक मंजूरी दे दी।" + }, + "approvalData": { + "message": "स्वीकृति डेटा" + }, + "approvalDataDescription": { + "message": "अनुमोदित वेबसाइट डेटा साफ़ करें ताकि सभी साइटों को फिर से अनुमोदन का अनुरोध करना होगा।" + }, + "clearApprovalData": { + "message": "अनुमोदन डेटा साफ़ करें" + }, + "approve": { + "message": "मंजूर" + }, + "reject": { + "message": "अस्वीकार" + }, + "providerAPIRequest": { + "message": "वेब 3 एपीआई अनुरोध" + }, + "reviewProviderRequest": { + "message": "कृपया इस वेब 3 एपीआई अनुरोध की समीक्षा करें।" + }, + "providerRequestInfo": { + "message": "नीचे सूचीबद्ध डोमेन वेब 3 एपीआई तक पहुंच का अनुरोध करने का प्रयास कर रहा है ताकि यह एथेरियम ब्लॉकचेन से बातचीत कर सके। वेब 3 एक्सेस को मंजूरी देने से पहले हमेशा सही जांच करें कि आप सही साइट पर हैं।" + }, "accept": { "message": "स्वीकार करें" }, diff --git a/app/_locales/ht/messages.json b/app/_locales/ht/messages.json index 50a0ec2bb..ff44af903 100644 --- a/app/_locales/ht/messages.json +++ b/app/_locales/ht/messages.json @@ -1,1237 +1,1351 @@ { - "accept": { - "message": "Aksepte" - }, - "accessingYourCamera": { - "message": "Aksè a Kamera" - }, - "account": { - "message": "Kont" - }, - "accountDetails": { - "message": "Detay Kont" - }, - "accountName": { - "message": "Non Kont" - }, - "accountSelectionRequired": { - "message": "Ou bezwen chwazi yon kont!" - }, - "activityLog": { - "message": "aktivite ki fèt" - }, - "address": { - "message": "Adrès" - }, - "addCustomToken": { - "message": "Ajoute token" - }, - "addToken": { - "message": "Ajoute Token" - }, - "addTokens": { - "message": "Ajoute Token" - }, - "addSuggestedTokens": { - "message": "Ajoute Token Yo Sikjere W" - }, - "addAcquiredTokens": { - "message": "Ajoute tokens yo ou te achte lè l sèvi avèk MetaMask" - }, - "amount": { - "message": "Kantite lajan" - }, - "amountPlusGas": { - "message": "Kantite lajan + Gaz" - }, - "appDescription": { - "message": "Ethereum Ekstansyon Navigatè", - "description": "The description of the application" - }, - "appName": { - "message": "MetaMask", - "description": "The name of the application" - }, - "approve": { - "message": "Apwouve" - }, - "approved": { - "message": "Apwouve" - }, - "attemptingConnect": { - "message": "Eseye konekte nan blockchain." - }, - "attributions": { - "message": "Atribisyon" - }, - "available": { - "message": "Disponib" - }, - "back": { - "message": "Retounen" - }, - "balance": { - "message": "Balans" - }, - "balances": { - "message": "Balans Token" - }, - "balanceIsInsufficientGas": { - "message": "Ensifizan balans pou total gaz aktyèl la" - }, - "beta": { - "message": "BETA" - }, - "betweenMinAndMax": { - "message": "dwe plis pase oswa egal a $ 1 mwens ke oswa egal a $ 2.", - "description": "helper for inputting hex as decimal input" - }, - "blockiesIdenticon": { - "message": "Itilize Blockies Identicon" - }, - "borrowDharma": { - "message": "Prete Avèk Dharma (Beta)" - }, - "browserNotSupported": { - "message": "Navigatè ou a pa sipòte..." - }, - "builtInCalifornia": { - "message": "MetaMask fèt e bati nan California." - }, - "buy": { - "message": "Achte" - }, - "buyCoinbase": { - "message": "Achte sou Coinbase" - }, - "buyCoinbaseExplainer": { - "message": "Coinbase se fason ki pi popilè nan mond lan yo achte ak vann Bitcoin, Ethereum, ak Litecoin." - }, - "bytes": { - "message": "Bytes" - }, - "ok": { - "message": "Oke" - }, - "cancel": { - "message": "Anile" - }, - "classicInterface": { - "message": "Sèvi ak fas klasik la" - }, - "clickCopy": { - "message": "Klike sou kopi" - }, - "close": { - "message": "Fèmen" - }, - "chromeRequiredForHardwareWallets": { - "message": "Ou bezwen sèvi ak MetaMask sou Google Chrome yo nan lòd yo konekte sou Hardware Wallet." - }, - "confirm": { - "message": "Konfime" - }, - "confirmed": { - "message": "Konfime" - }, - "confirmContract": { - "message": "Konfime Kontra" - }, - "confirmPassword": { - "message": "Konfime Modpas" - }, - "confirmTransaction": { - "message": "Konfime Tranzaksyon" - }, - "connectHardwareWallet": { - "message": "Konekte Hardware Wallet" - }, - "connect": { - "message": "Konekte" - }, - "connecting": { - "message": "Koneksyon..." - }, - "connectToLedger": { - "message": "Konekte ak Ledger" - }, - "connectToTrezor": { - "message": "Konekte ak Trezor" - }, - "continue": { - "message": "Kontinye" - }, - "continueToCoinbase": { - "message": "Kontinye Coinbase" - }, - "contractDeployment": { - "message": "Kontra Deplwaman" - }, - "conversionProgress": { - "message": "Konvèsyon nan Pwogrè" - }, - "copiedButton": { - "message": "Kopye" - }, - "copiedClipboard": { - "message": "Kopi nan Clipboard" - }, - "copiedExclamation": { - "message": "Kopye!" - }, - "copiedSafe": { - "message": "Mwen te kopye li yon kote ki san danje" - }, - "copy": { - "message": "Kopye" - }, - "copyAddress": { - "message": "Kopi adrès clipboard" - }, - "copyToClipboard": { - "message": "Kopi clipboard" - }, - "copyButton": { - "message": " Kopi " - }, - "copyPrivateKey": { - "message": "Sa a se kle prive ou (klike pou ou kopye)" - }, - "create": { - "message": "Kreye" - }, - "createAccount": { - "message": "Kreye Kont" - }, - "createDen": { - "message": "Kreye" - }, - "crypto": { - "message": "Crypto", - "description": "Change tip (cryptocurrencies)" - }, - "currentConversion": { - "message": "Konvèsyon aktyèl" - }, - "currentNetwork": { - "message": "Rezo aktyèl" - }, - "customGas": { - "message": "Koutim Gaz" - }, - "customToken": { - "message": "Koutim Token" - }, - "customize": { - "message": "Koutim" - }, - "customRPC": { - "message": "Koutim RPC" - }, - "decimalsMustZerotoTen": { - "message": "Desimal yo dwe omwen 0, epi pa dwe plis pase 36." - }, - "decimal": { - "message": "Presizyon desimal la" - }, - "defaultNetwork": { - "message": "Dfo rezo a pou tranzaksyon Ether se Mainnet." - }, - "denExplainer": { - "message": "DEN ou se depo modpas avèk chif ou nan MetaMask." - }, - "deposit": { - "message": "Depo" - }, - "depositBTC": { - "message": "Depoze BTC ou nan adrès ki anba a:" - }, - "depositCoin": { - "message": "Depoze $1 ou nan adrès ki anba a", - "description": "Tells the user what coin they have selected to deposit with shapeshift" - }, - "depositEth": { - "message": "Depo Eth" - }, - "depositEther": { - "message": "Depo Ether" - }, - "depositFiat": { - "message": "Depo ak Fiat" - }, - "depositFromAccount": { - "message": "Depo nan yon lòt kont" - }, - "depositShapeShift": { - "message": "Depo avèk ShapeShift" - }, - "depositShapeShiftExplainer": { - "message": "Si ou posede lòt cryptocurrencies, ou ka chanje ak depo Ether dirèkteman nan Wallet MetaMask ou. Pa gen kont ki nesesè." - }, - "details": { - "message": "Detay yo" - }, - "directDeposit": { - "message": "Depo Dirèk" - }, - "directDepositEther": { - "message": "Dirèkteman Depo Ether" - }, - "directDepositEtherExplainer": { - "message": "Si ou deja gen kèk Ether, fason ki pi rapid yo ka resevwa Ether nan nouvo Wallet ou pa depo dirèk." - }, - "done": { - "message": "Fini" - }, - "downloadGoogleChrome": { - "message": "Telechaje Google Chrome" - }, - "downloadStateLogs": { - "message": "Telechaje State Logs" - }, - "dontHaveAHardwareWallet": { - "message": "Pa gen yon materyèl bous?" - }, - "dropped": { - "message": "Tonbe" - }, - "edit": { - "message": "Korije" - }, - "editAccountName": { - "message": "Korije Non Kont" - }, - "editingTransaction": { - "message": "Fè chanjman nan tranzaksyon ou" - }, - "emailUs": { - "message": "Imèl nou!" - }, - "encryptNewDen": { - "message": "Ankripte nouvo DEN ou" - }, - "ensNameNotFound": { - "message": "Nou pa jwenn non ENS ou a" - }, - "enterPassword": { - "message": "Mete modpas" - }, - "enterPasswordConfirm": { - "message": "Antre nan modpas ou a konfime" - }, - "enterPasswordContinue": { - "message": "Mete modpas pou kontinye" - }, - "parameters": { - "message": "Paramèt" - }, - "passwordNotLongEnough": { - "message": "Modpas la pa ase" - }, - "passwordsDontMatch": { - "message": "Modpas Pa Koresponn ak" - }, - "etherscanView": { - "message": "Gade kont sou Etherscan" - }, - "exchangeRate": { - "message": "Chanje to" - }, - "exportPrivateKey": { - "message": "Voye Kòd Prive" - }, - "exportPrivateKeyWarning": { - "message": "Voye kle prive ak pwòp risk ou." - }, - "failed": { - "message": "Tonbe" - }, - "fiat": { - "message": "FIAT", - "description": "Exchange type" - }, - "fileImportFail": { - "message": "Enpòte dosye ki pa travay? Klike la a!", - "description": "Helps user import their account from a JSON file" - }, - "followTwitter": { - "message": "Swiv nou sou Twitter" - }, - "forgetDevice": { - "message": "Bliye aparèy sa a" - }, - "from": { - "message": "Soti nan" - }, - "fromToSame": { - "message": "Adrès orijinal le ak sa ou resevwa pake menm" - }, - "fromShapeShift": { - "message": "Soti nan ShapeShift" - }, - "functionType": { - "message": "Kalite Fonksyon" - }, - "gas": { - "message": "Gaz", - "description": "Short indication of gas cost" - }, - "gasFee": { - "message": "Frè gaz" - }, - "gasLimit": { - "message": "Limit gaz" - }, - "gasLimitCalculation": { - "message": "Nou kalkile gaz limit sijere a ki baze sou pousantaj siksè rezo a." - }, - "gasLimitRequired": { - "message": "Limit gaz nesesè" - }, - "gasLimitTooLow": { - "message": "Limit gaz dwe omwen 21000" - }, - "generatingSeed": { - "message": "Génération Seed..." - }, - "gasPrice": { - "message": "Pri gaz (GWEI)" - }, - "gasPriceCalculation": { - "message": "Nou kalkile pri yo gaz ki sijere ki baze sou pousantaj siksè rezo." - }, - "gasPriceRequired": { - "message": "Pri Gaz la Egzije" - }, - "generatingTransaction": { - "message": "Tranzaksyon kap fè" - }, - "getEther": { - "message": "Jwenn Ether" - }, - "getEtherFromFaucet": { - "message": "Jwenn Ether nan yon tiyo pou $1 la", - "description": "Displays network name for Ether faucet" - }, - "getHelp": { - "message": "Jwenn èd." - }, - "greaterThanMin": { - "message": "dwe pi gran pase oswa egal a $ 1.", - "description": "helper for inputting hex as decimal input" - }, - "hardware": { - "message": "hardware" - }, - "hardwareWalletConnected": { - "message": "Hardware Wallet konekte" - }, - "hardwareWallets": { - "message": "Hardware Wallet konekte" - }, - "hardwareWalletsMsg": { - "message": "Chwazi yon Hardware Wallet ou ta renmen itilize ak MetaMask" - }, - "havingTroubleConnecting": { - "message": "Èske w gen pwoblèm pou konekte?" - }, - "here": { - "message": "isit la", - "description": "as in -click here- for more information (goes with troubleTokenBalances)" - }, - "hereList": { - "message": "Isit la nan yon lis !!!!" - }, - "hexData": { - "message": "Hex Data" - }, - "hide": { - "message": "Kache" - }, - "hideToken": { - "message": "Kache Token" - }, - "hideTokenPrompt": { - "message": "Kache Token?" - }, - "history": { - "message": "Istwa" - }, - "howToDeposit": { - "message": "Ki jan ou ta renmen depo Ether?" - }, - "holdEther": { - "message": "Li pèmèt ou kenbe ether & tokens, epi sèvi kòm on pon pou desantralize aplikasyon." - }, - "import": { - "message": "Pòte", - "description": "Button to import an account from a selected file" - }, - "importAccount": { - "message": "Pòte Kont" - }, - "importAccountMsg": { - "message": " Kont pòte pa pral asosye avèk orijinal ou te kreye nan kont MetaMask seed fraz. Aprann plis sou kont enpòte " - }, - "importAnAccount": { - "message": "Pòte yon kont" - }, - "importDen": { - "message": "Pòte ki deja egziste DEN" - }, - "imported": { - "message": "Pòte", - "description": "status showing that an account has been fully loaded into the keyring" - }, - "importUsingSeed": { - "message": "Pòte lè sèvi avèk seed fraz" - }, - "infoHelp": { - "message": "Enfo & Èd" - }, - "initialTransactionConfirmed": { - "message": "Premye tranzaksyon ou konfime sou rezo a. Klike sou OK pou tounen." - }, - "insufficientFunds": { - "message": "Lajan ensifizan." - }, - "insufficientTokens": { - "message": "Tokens pa valab." - }, - "invalidAddress": { - "message": "Adrès pa valab" - }, - "invalidAddressRecipient": { - "message": "Moun ki resevwa adrès la pa valab" - }, - "invalidGasParams": { - "message": "Gaz Paramèt la pa valab" - }, - "invalidInput": { - "message": "Sa ou rantre a pa valab" - }, - "invalidRequest": { - "message": "Demann pa valab" - }, - "invalidRPC": { - "message": "RPC URI pa valab" - }, - "invalidSeedPhrase": { - "message": "Seed fraz pa valab" - }, - "jsonFail": { - "message": "Yon bagay ale mal. Tanpri, asire w ke dosye JSON ou an byen fòmate." - }, - "jsonFile": { - "message": "JSON Dosye", - "description": "format for importing an account" - }, - "keepTrackTokens": { - "message": "Gade tokens yo ou te achte ak kont MetaMask ou." - }, - "kovan": { - "message": "Kovan Tès Rezo" - }, - "knowledgeDataBase": { - "message": "Vizite baz nou an" - }, - "max": { - "message": "Maksimòm" - }, - "learnMore": { - "message": "Aprann plis" - }, - "ledgerAccountRestriction": { - "message": "Ou bezwen sèvi ak dènye kont ou anvan ou ka ajoute yon nouvo." - }, - "lessThanMax": { - "message": "dwe mwens pase oswa egal a $ 1.", - "description": "helper for inputting hex as decimal input" - }, - "likeToAddTokens": { - "message": "Èske ou ta renmen ajoute sa nan tokens?" - }, - "links": { - "message": "Lyen" - }, - "limit": { - "message": "Limitasyon" - }, - "loading": { - "message": "Telechaje..." - }, - "loadingTokens": { - "message": "Telechaje Tokens..." - }, - "localhost": { - "message": "Localhost 8545" - }, - "login": { - "message": "Ouvri" - }, - "logout": { - "message": "Dekonekte" - }, - "loose": { - "message": "Pèdi" - }, - "loweCaseWords": { - "message": "seed mo sèlman gen karaktè miniskil" - }, - "mainnet": { - "message": "Main Ethereum Network" - }, - "menu": { - "message": "Opsyon" - }, - "message": { - "message": "Mesaje" - }, - "metamaskDescription": { - "message": "MetaMask sekirize idantite pou Ethereum." - }, - "metamaskSeedWords": { - "message": "MetaMask Seed Mo" - }, - "min": { - "message": "Minimòm" - }, - "myAccounts": { - "message": "Kont mwen" - }, - "mustSelectOne": { - "message": "Ou dwe chwazi omwen 1 token." - }, - "needEtherInWallet": { - "message": "Pou kominike avèk aplikasyon desantralize ou dwe itilize MetaMask, ou pral bezwen Ether nan Wallet ou." - }, - "needImportFile": { - "message": "Ou dwe chwazi yon dosye pou enpòte.", - "description": "User is important an account and needs to add a file to continue" - }, - "needImportPassword": { - "message": "Ou dwe antre nan yon modpas pou dosye ou te chwazi a.", - "description": "Password and file needed to import an account" - }, - "negativeETH": { - "message": "Pa ka voye kantite lajan negatif ETH." - }, - "networks": { - "message": "Rezo" - }, - "nevermind": { - "message": "Pa pwoblèm" - }, - "newAccount": { - "message": "Nouvo Kont" - }, - "newAccountNumberName": { - "message": "Kont $1", - "description": "Default name of next account to be created on create account screen" - }, - "newContract": { - "message": "Nouvo Kontra" - }, - "newPassword": { - "message": "Nouvo modpas (minit 8)" - }, - "newRecipient": { - "message": "Nouvo Benefisyè" - }, - "newRPC": { - "message": "Nouvo RPC URL" - }, - "next": { - "message": "Aprè sa" - }, - "noAddressForName": { - "message": "Pa gen adrès ki etabli pou non sa a." - }, - "noDeposits": { - "message": "Pa gen depo ou te resevwa" - }, - "noConversionRateAvailable": { - "message": "Pa gen okenn Konvèsyon Disponib" - }, - "noTransactionHistory": { - "message": "Pa gen istwa tranzaksyon." - }, - "noTransactions": { - "message": "Pa gen tranzaksyon" - }, - "notFound": { - "message": "Pa jwenn" - }, - "notStarted": { - "message": "Pa kòmanse" - }, - "noWebcamFoundTitle": { - "message": "Pa jwenn webcam" - }, - "noWebcamFound": { - "message": "Nou pakay jwenn webcam òdinatè ou. Tanpri eseye ankò." - }, - "oldUI": { - "message": "Ansyen Itilizatè kouòdone" - }, - "oldUIMessage": { - "message": "Ou te retounen nan Ansyen Itilizatè kouòdone. Ou ka chanje tounen nan nouvo Ansyen Itilizatè nan opsyon a nan meni an tèt la." - }, - "openInTab": { - "message": "Louvri nan etikèt" - }, - "or": { - "message": "oubyen", - "description": "choice between creating or importing a new account" - }, - "origin": { - "message": "Orijin" - }, - "password": { - "message": "Modpas" - }, - "passwordCorrect": { - "message": "Tanpri asire ke modpas ou kòrèk." - }, - "passwordMismatch": { - "message": "modpas sa pa menm", - "description": "in password creation process, the two new password fields did not match" - }, - "passwordShort": { - "message": "modpas pa sifi", - "description": "in password creation process, the password is not long enough to be secure" - }, - "pastePrivateKey": { - "message": "Kole fraz prive ou a la:", - "description": "For importing an account from a private key" - }, - "pasteSeed": { - "message": "Kole seed fraz ou a la!" - }, - "pending": { - "message": "l ap mache" - }, - "personalAddressDetected": { - "message": "Adrès pèsonèl detekte. Antre adrès kontra token la." - }, - "pleaseReviewTransaction": { - "message": "Tanpri revize tranzaksyon ou." - }, - "popularTokens": { - "message": "Popilè Tokens" - }, - "prev": { - "message": "Avan" - }, - "privacyMsg": { - "message": "Règleman sou enfòmasyon prive" - }, - "privateKey": { - "message": "Prive kle", - "description": "select this type of file to use to import an account" - }, - "privateKeyWarning": { - "message": "Atansyon: pa janm divilge kle sa. Nenpòt moun kapab avèk kle prive ou a vòlè sa ou gen ou sou kont ou a." - }, - "privateNetwork": { - "message": "Rezo Prive" - }, - "qrCode": { - "message": "Montre QR Kòd" - }, - "queue": { - "message": "Queue" - }, - "readdToken": { - "message": "Ou ka ajoute token sa aprè sa ankò ou prale nan \"Ajoute token\" nan opsyon meni kont ou an." - }, - "readMore": { - "message": "Li plis isit la." - }, - "readMore2": { - "message": "Li plis isit la." - }, - "receive": { - "message": "Resevwa" - }, - "recipientAddress": { - "message": "Adrès pou resevwa" - }, - "refundAddress": { - "message": "Adrès pou resevwa" - }, - "rejected": { - "message": "Rejte" - }, - "reset": { - "message": "Repwograme" - }, - "resetAccount": { - "message": "Repwograme Kont" - }, - "resetAccountDescription": { - "message": "Repwograme kont a netwaye tranzaksyon ou yo." - }, - "restoreFromSeed": { - "message": "Restore kont?" - }, - "restoreVault": { - "message": "Retabli kazye" - }, - "restoreAccountWithSeed": { - "message": "Retabli kont ou avèk yo Seed Fraz" - }, - "required": { - "message": "Egzije" - }, - "retryWithMoreGas": { - "message": "Reseye ak yon pri gaz pi wo isit la" - }, - "walletSeed": { - "message": "Wallet Seed" - }, - "restore": { - "message": "Retabli" - }, - "revealSeedWords": { - "message": "Revele Seed Mo Yo" - }, - "revealSeedWordsTitle": { - "message": "Seed Fraz" - }, - "revealSeedWordsDescription": { - "message": "Si ou pa janm chanje navigatè ou deplase òdinatè, ou pral bezwen fraz seed la pou ka gen aksè a kont ou. Sere yo on kote an sekirite e an sekrè." - }, - "revealSeedWordsWarningTitle": { - "message": "PA pataje fraz sa a avèk nenpòt moun!" - }, - "revealSeedWordsWarning": { - "message": "Yo ka itilize mo sa pou vòlè kont ou." - }, - "revert": { - "message": "Retounen" - }, - "remove": { - "message": "retire" - }, - "removeAccount": { - "message": "Retire kont" - }, - "removeAccountDescription": { - "message": "Kont sa a pral retire nan Wallet ou. Tanpri, asire ou ke ou gen orijinal fraz seed la oubyen kle prive pou rantre kont lan avan ou kontinye. Oubyen ou ka rantre kont ou ankò apati kont \"drop-down\" ou an." - }, - "readyToConnect": { - "message": "Pare pou konekte?" - }, - "rinkeby": { - "message": "Rinkeby Tès Rezo" - }, - "ropsten": { - "message": "Ropsten Tès Rezo" - }, - "rpc": { - "message": "Koutim RPC" - }, - "currentRpc": { - "message": "Kounya RPC" - }, - "connectingToMainnet": { - "message": "Konekte ak Main (Prensipal) Ethereum Rezo a" - }, - "connectingToRopsten": { - "message": "Konekte ak Ropsten Tès Rezo a" - }, - "connectingToKovan": { - "message": "Konekte nan Kovan Tès Rezo a" - }, - "connectingToRinkeby": { - "message": "Konekte nan Rinkeby Tès Rezo a" - }, - "connectingToUnknown": { - "message": "Konekte nan rezo enkoni" - }, - "sampleAccountName": { - "message": "Pa egzanp, Nouvo kont mwen an", - "description": "Help user understand concept of adding a human-readable name to their account" - }, - "save": { - "message": "Sove" - }, - "speedUp": { - "message": "pi vit" - }, - "speedUpTitle": { - "message": "Monte vitès tranzaksyon" - }, - "speedUpSubtitle": { - "message": "Ogmante pri gaz ou pou eseye efase tranzaksyon ou pi vit" - }, - "saveAsCsvFile": { - "message": "Sove kòm dosye CSV" - }, - "saveAsFile": { - "message": "Sove kòm dosye", - "description": "Account export process" - }, - "saveSeedAsFile": { - "message": "Sove pawòl seed kòm dosye" - }, - "search": { - "message": "Rechèch" - }, - "searchResults": { - "message": "Rezilta rechèch" - }, - "secretPhrase": { - "message": "Antre fraz sekrè douz mo ou a pou w restore kòf ou a." - }, - "showHexData": { - "message": "Montre Hex Data" - }, - "showHexDataDescription": { - "message": "Pran sa pouw ka montre chan entèfas hex data a" - }, - "newPassword8Chars": { - "message": "Nouvo modpas (pou pi pit 8)" - }, - "seedPhraseReq": { - "message": "Seed fraz yo se 12 long mo" - }, - "select": { - "message": "Chwazi" - }, - "selectCurrency": { - "message": "Chwazi Lajan" - }, - "selectService": { - "message": "Chwazi Sèvis" - }, - "selectType": { - "message": "Chwazi Kalite" - }, - "send": { - "message": "Voye" - }, - "sendETH": { - "message": "Voye ETH" - }, - "sendTokens": { - "message": "Voye Tokens" - }, - "sentEther": { - "message": "Voye ether" - }, - "sentTokens": { - "message": "tokens deja voye" - }, - "separateEachWord": { - "message": "Separe chak mo ak yon sèl espas" - }, - "onlySendToEtherAddress": { - "message": "Sèlman voye ETH nan yon adrès Ethereum." - }, - "onlySendTokensToAccountAddress": { - "message": "Sèlman voye $ 1 nan yon adrès kont Ethereum.", - "description": "displays token symbol" - }, - "orderOneHere": { - "message": "Mete nan lòd on Trezor oswa Ledger epi kenbe lajan ou nan yon stòk frèt." - }, - "outgoing": { - "message": "Ap kite" - }, - "searchTokens": { - "message": "Rechèch Tokens" - }, - "selectAnAddress": { - "message": "Chwazi yon adrès" - }, - "selectAnAccount": { - "message": "Chwazi yon kont" - }, - "selectAnAccountHelp": { - "message": "Chwazi kont pou wè nan MetaMask" - }, - "selectHdPath": { - "message": "Chwazi chemen HD" - }, - "selectPathHelp": { - "message": "Si ou pa wè kont Ledger ou te genyen an anba a, eseye chanje chemen an \"Eritaj (MEW / MyCrypto)\"" - }, - "sendTokensAnywhere": { - "message": "Voye Tokens pou nenpòt moun ki gen yon kont Ethereum" - }, - "settings": { - "message": "Paramèt" - }, - "step1HardwareWallet": { - "message": "1. Konekte Materyèl bous" - }, - "step1HardwareWalletMsg": { - "message": "Konekte materyèl bous ou dirèkteman nan òdinatè ou." - }, - "step2HardwareWallet": { - "message": "2. Chwazi yon kont" - }, - "step2HardwareWalletMsg": { - "message": "Chwazi kont ou vle wè a. Ou ka chwazi youn sèlman nan yon moman." - }, - "step3HardwareWallet": { - "message": "3. Kòmanse itilize dApps ak plis ankò!" - }, - "step3HardwareWalletMsg": { - "message": "Sèvi ak kont materyèl ou menm jan ou t ap fè pou kont Etherum. Ouvri sesyon an nan dApps, voye Eth, achte ak stòke ERC20 tokens ak e ki pake chanje tokens tankou CryptoKitties." - }, - "info": { - "message": "Enfòmasyon" - }, - "scanInstructions": { - "message": "Mete kòd QR la devan kamera ou" - }, - "scanQrCode": { - "message": "Enspeksyon QR Kòd" - }, - "shapeshiftBuy": { - "message": "Achte avèk Shapeshift" - }, - "showPrivateKeys": { - "message": "Montre Kle Prive" - }, - "showQRCode": { - "message": "Montre Kòd QR" - }, - "sign": { - "message": "Siyen" - }, - "signatureRequest": { - "message": "Siyati Mande" - }, - "signed": { - "message": "Te Siyen" - }, - "signMessage": { - "message": "Siyen mesaj" - }, - "signNotice": { - "message": "Lè w siyen mesaj sa a ka gen efè segondè ki \ndanjere. Sèlman \nsit mesaj ki soti nan sit ou konplètman fè konfyans ak tout kont ou. \n Metòd danjere sa yo pral retire nan yon vèsyon fiti. " - }, - "sigRequest": { - "message": "Demann Siyati" - }, - "sigRequested": { - "message": "Demann Siyati" - }, - "spaceBetween": { - "message": "ka gen sèlman yon espas ant mo yo" - }, - "status": { - "message": "Kondisyon" - }, - "stateLogs": { - "message": "State Logs" - }, - "stateLogsDescription": { - "message": "State logs gen adrès kont piblik ou yo epi tranzaksyon ou te voye yo." - }, - "stateLogError": { - "message": "Erè nan retwouve State Logs yo." - }, - "submit": { - "message": "Soumèt" - }, - "submitted": { - "message": "Te Soumèt" - }, - "supportCenter": { - "message": "Vizite Sant Sipò Nou" - }, - "symbolBetweenZeroTen": { - "message": "Senbòl yo dwe ant 0 ak 10 karaktè." - }, - "takesTooLong": { - "message": "Pran twò lontan?" - }, - "terms": { - "message": "Tèm pou itilize" - }, - "testFaucet": { - "message": "Tès Tiyo" - }, - "to": { - "message": "Pou" - }, - "toETHviaShapeShift": { - "message": "$1 pou ETH pa ShapeShift", - "description": "system will fill in deposit type in start of message" - }, - "token": { - "message": "Token" - }, - "tokenAddress": { - "message": "Adrès Token" - }, - "tokenAlreadyAdded": { - "message": "Ou te deja ajoute token." - }, - "tokenBalance": { - "message": "Balans Token ou se:" - }, - "tokenSelection": { - "message": "Chache Tokens oswa chwazi nan lis Tokens popilè nou an." - }, - "tokenSymbol": { - "message": "Token Senbòl" - }, - "tokenWarning1": { - "message": "Kenbe tras token yo ou te achte ak kont MetaMask ou. Si ou te achte tokens pandan wap itilize yon kont diferan tokens sa yo pa pral parèt la." - }, - "total": { - "message": "Total" - }, - "transactions": { - "message": "tranzaksyon yo" - }, - "transactionConfirmed": { - "message": "Tranzaksyon ou te konfime pou $2." - }, - "transactionCreated": { - "message": "Tranzaksyon ou te kreye avèk on valè de $1 pou $2." - }, - "transactionDropped": { - "message": "Tranzaksyon ou te tonbe a $2." - }, - "transactionSubmitted": { - "message": "Tranzaksyon ou te soumèt a $2." - }, - "transactionUpdated": { - "message": "Tranzaksyon ou te aktyalize a $2." - }, - "transactionUpdatedGas": { - "message": "Tranzaksyon ou te aktyalize avèk on pri gaz de $1 a $2." - }, - "transactionError": { - "message": "Erè tranzaksyon. Eksepsyon jete nan kòd kontra." - }, - "transactionMemo": { - "message": "Memo tranzaksyon (opsyonèl)" - }, - "transactionNumber": { - "message": "Nimewo Tranzaksyon" - }, - "transfer": { - "message": "Transfè" - }, - "transfers": { - "message": "Transfè yo" - }, - "trezorHardwareWallet": { - "message": "TREZOR Materyèl Bous" - }, - "troubleTokenBalances": { - "message": "Nou te gen pwoblèm chaje balans token ou. Ou ka wè yo ", - "description": "Followed by a link (here) to view token balances" - }, - "tryAgain": { - "message": "Eseye anko" - }, - "twelveWords": { - "message": "12 mo sa yo se sèl fason pou retabli kont MetaMask ou yo. \nKenbe yo yon kote ki an sekirite ak sekrè." - }, - "typePassword": { - "message": "Tape modpas ou" - }, - "uiWelcome": { - "message": "Byenveni nan New itilizatè koòdone (Beta)" - }, - "uiWelcomeMessage": { - "message": "Kounya w ap itilize nouvo MetaMask UI (itilizatè koòdone) a." - }, - "unapproved": { - "message": "Pa apwouve" - }, - "unavailable": { - "message": "Pa disponib" - }, - "units": { - "message": "inite yo" - }, - "unknown": { - "message": "Enkoni" - }, - "unknownFunction": { - "message": "Fonksyon enkoni" - }, - "unknownNetwork": { - "message": "Rezo Prive Enkoni" - }, - "unknownNetworkId": { - "message": "Rezo ID Enkoni" - }, - "unknownQrCode": { - "message": "Erè: Nou pa t kapab idantifye QR kòd sa" - }, - "unknownCameraErrorTitle": { - "message": "Ooops! Yon bagay te ale mal...." - }, - "unknownCameraError": { - "message": "Te gen yon erè pandan y ap eseye jwenn aksè nan kamera ou. Tanpri eseye ankò..." - }, - "unlock": { - "message": "Debloke" - }, - "unlockMessage": { - "message": "Entènèt desantralize a ap tann" - }, - "uriErrorMsg": { - "message": "URIs mande pou apwopriye prefiks HTTP / HTTPS a." - }, - "usaOnly": { - "message": "USA sèlman", - "description": "Using this exchange is limited to people inside the USA" - }, - "usedByClients": { - "message": "Itilize pa yon varyete de kliyan diferan" - }, - "useOldUI": { - "message": "Itilizasyon ansyen UI (itilizatè koòdone)" - }, - "validFileImport": { - "message": "Ou dwe chwazi yon dosye ki valab pou enpòte." - }, - "vaultCreated": { - "message": "Kòf Kreye" - }, - "viewAccount": { - "message": "Wè Kont" - }, - "viewOnEtherscan": { - "message": "Wè sou Etherscan" - }, - "visitWebSite": { - "message": "Vizite sit entènèt nou an" - }, - "warning": { - "message": "Avètisman" - }, - "welcomeBack": { - "message": "Bon retou!" - }, - "welcomeBeta": { - "message": "Byenveni nan MetaMask Beta" - }, - "whatsThis": { - "message": "Kisa sa ye?" - }, - "youNeedToAllowCameraAccess": { - "message": "Ou bezwen bay kamera aksè pou sèvi ak fonksyon sa." - }, - "yourSigRequested": { - "message": "Yo mande siyati ou" - }, - "youSign": { - "message": "Ou ap siyen kounya" - }, - "yourPrivateSeedPhrase": { - "message": "Seed fraz prive ou a" - } + "privacyMode": { + "message": "Mòd Privacy" + }, + "privacyModeDescription": { + "message": "Sou sit entènèt yo dwe mande aksè pou wè enfòmasyon kont ou." + }, + "exposeAccounts": { + "message": "Ekspoze Kont" + }, + "exposeDescription": { + "message": "Ekspoze kont sou sitwèb aktyèl la. Itil pou dapps eritaj." + }, + "confirmExpose": { + "message": "Èske ou sèten ou vle ekspoze kont ou sou sit entènèt aktyèl la?" + }, + "confirmClear": { + "message": "Èske ou sèten ou vle klè sitwèb apwouve?" + }, + "clearApprovalDataSuccess": { + "message": "Done sou sit wèb apwouve yo te klarifye avèk siksè." + }, + "approvalData": { + "message": "Done sou vi prive" + }, + "approvalDataDescription": { + "message": "Done sou vi prive klè pou tout sit entènèt yo dwe mande aksè pou wè enfòmasyon kont ankò." + }, + "clearApprovalData": { + "message": "Klè Done sou vi prive" + }, + "providerAPIRequest": { + "message": "Ethereum API Mande" + }, + "reviewProviderRequest": { + "message": "Tanpri revize sa API demann Ethereum." + }, + "providerRequestInfo": { + "message": "Domèn ki nan lis anba a ap mande pou jwenn aksè a blòkchou Ethereum ak pou wè kont ou ye kounye a. Toujou double tcheke ke ou sou sit ki kòrèk la anvan apwouve aksè." + }, + "accept": { + "message": "Aksepte" + }, + "accessingYourCamera": { + "message": "Aksè a Kamera" + }, + "account": { + "message": "Kont" + }, + "accountDetails": { + "message": "Detay Kont" + }, + "accountName": { + "message": "Non Kont" + }, + "accountOptions": { + "message": "Opsyon kont" + }, + "accountSelectionRequired": { + "message": "Ou bezwen chwazi yon kont!" + }, + "activityLog": { + "message": "aktivite ki fèt" + }, + "address": { + "message": "Adrès" + }, + "addCustomToken": { + "message": "Ajoute token" + }, + "addToken": { + "message": "Ajoute Token" + }, + "addTokens": { + "message": "Ajoute Token" + }, + "addSuggestedTokens": { + "message": "Ajoute Token Yo Sikjere W" + }, + "addAcquiredTokens": { + "message": "Ajoute tokens yo ou te achte lè l sèvi avèk MetaMask" + }, + "amount": { + "message": "Kantite lajan" + }, + "amountPlusGas": { + "message": "Kantite lajan + Gaz" + }, + "appDescription": { + "message": "Ekstansyon Navigatè Ethereum", + "description": "The description of the application" + }, + "appName": { + "message": "MetaMask", + "description": "The name of the application" + }, + "approve": { + "message": "Apwouve" + }, + "approved": { + "message": "Apwouve" + }, + "attemptingConnect": { + "message": "Eseye konekte nan blockchain." + }, + "attemptToCancel": { + "message": "Eseye anile?" + }, + "attemptToCancelDescription": { + "message": "Soumèt tantativ sa a pa garanti ke yo pral anile tranzaksyon ou anile. Si tantativ anile an gen siksè, ou pral chaje frè yo tranzaksyon pi wo a." + }, + "attributions": { + "message": "Atribisyon" + }, + "available": { + "message": "Disponib" + }, + "back": { + "message": "Retounen" + }, + "balance": { + "message": "Balans" + }, + "balances": { + "message": "Balans Token" + }, + "balanceIsInsufficientGas": { + "message": "Ensifizan balans pou total gaz aktyèl la" + }, + "beta": { + "message": "BETA" + }, + "betweenMinAndMax": { + "message": "dwe plis pase oswa egal a $ 1 mwens ke oswa egal a $ 2.", + "description": "helper for inputting hex as decimal input" + }, + "blockiesIdenticon": { + "message": "Itilize Blockies Identicon" + }, + "borrowDharma": { + "message": "Prete Avèk Dharma (Beta)" + }, + "browserNotSupported": { + "message": "Navigatè ou a pa sipòte..." + }, + "builtInCalifornia": { + "message": "MetaMask fèt e bati nan California." + }, + "buy": { + "message": "Achte" + }, + "buyCoinbase": { + "message": "Achte sou Coinbase" + }, + "buyCoinbaseExplainer": { + "message": "Coinbase se fason ki pi popilè nan mond lan yo achte ak vann Bitcoin, Ethereum, ak Litecoin." + }, + "bytes": { + "message": "Bytes" + }, + "ok": { + "message": "Oke" + }, + "cancel": { + "message": "Anile" + }, + "cancelAttempt": { + "message": "Teste Anile" + }, + "cancellationGasFee": { + "message": "Anilasyon Gaz Chaj" + }, + "cancelN": { + "message": "Anile tout $ 1 tranzaksyon" + }, + "classicInterface": { + "message": "Sèvi ak fas klasik la" + }, + "clickCopy": { + "message": "Klike sou kopi" + }, + "clickToAdd": { + "message": "Klike sou $ 1 pou ajoute yo nan kont ou" + }, + "close": { + "message": "Fèmen" + }, + "chromeRequiredForHardwareWallets": { + "message": "Ou bezwen sèvi ak MetaMask sou Google Chrome yo nan lòd yo konekte sou Hardware Wallet." + }, + "confirm": { + "message": "Konfime" + }, + "confirmed": { + "message": "Konfime" + }, + "confirmContract": { + "message": "Konfime Kontra" + }, + "confirmPassword": { + "message": "Konfime Modpas" + }, + "confirmTransaction": { + "message": "Konfime Tranzaksyon" + }, + "connectHardwareWallet": { + "message": "Konekte Materyèl Wallet" + }, + "connect": { + "message": "Konekte" + }, + "connecting": { + "message": "Koneksyon..." + }, + "connectingToKovan": { + "message": "Konekte nan Kovan Tès Rezo a" + }, + "connectingToMainnet": { + "message": "Konekte ak Prensipal Ethereum Rezo a" + }, + "connectingToRopsten": { + "message": "Konekte ak Ropsten Tès Rezo a" + }, + "connectingToRinkeby": { + "message": "Konekte nan Rinkeby Tès Rezo a" + }, + "connectingToUnknown": { + "message": "Konekte nan rezo enkoni" + }, + "connectToLedger": { + "message": "Konekte ak Ledger" + }, + "connectToTrezor": { + "message": "Konekte ak Trezor" + }, + "continue": { + "message": "Kontinye" + }, + "continueToCoinbase": { + "message": "Kontinye Coinbase" + }, + "contractDeployment": { + "message": "Kontra Deplwaman" + }, + "conversionProgress": { + "message": "Konvèsyon nan Pwogrè" + }, + "copiedButton": { + "message": "Kopye" + }, + "copiedClipboard": { + "message": "Kopi nan Clipboard" + }, + "copiedExclamation": { + "message": "Kopye!" + }, + "copiedSafe": { + "message": "Mwen te kopye li yon kote ki san danje" + }, + "copy": { + "message": "Kopye" + }, + "copyAddress": { + "message": "Kopi adrès clipboard" + }, + "copyToClipboard": { + "message": "Kopi clipboard" + }, + "copyButton": { + "message": " Kopi " + }, + "copyPrivateKey": { + "message": "Sa a se kle prive ou (klike pou ou kopye)" + }, + "create": { + "message": "Kreye" + }, + "createAccount": { + "message": "Kreye Kont" + }, + "createDen": { + "message": "Kreye" + }, + "crypto": { + "message": "Crypto", + "description": "Exchange type (cryptocurrencies)" + }, + "currentConversion": { + "message": "Konvèsyon aktyèl" + }, + "currentLanguage": { + "message": "Lang Aktyèl" + }, + "currentNetwork": { + "message": "Rezo aktyèl" + }, + "currentRpc": { + "message": "Aktyèl RPC" + }, + "customGas": { + "message": "Koutim Gaz" + }, + "customToken": { + "message": "Koutim Token" + }, + "customize": { + "message": "Koutim" + }, + "customRPC": { + "message": "Koutim RPC" + }, + "decimalsMustZerotoTen": { + "message": "Desimal yo dwe omwen 0, epi pa dwe plis pase 36." + }, + "decimal": { + "message": "Presizyon desimal la" + }, + "defaultNetwork": { + "message": "Dfo rezo a pou tranzaksyon Ether se Mainnet." + }, + "denExplainer": { + "message": "DEN ou se depo modpas avèk chif ou nan MetaMask." + }, + "deposit": { + "message": "Depo" + }, + "depositBTC": { + "message": "Depoze BTC ou nan adrès ki anba a:" + }, + "depositCoin": { + "message": "Depoze $1 ou nan adrès ki anba a", + "description": "Tells the user what coin they have selected to deposit with shapeshift" + }, + "depositEth": { + "message": "Depo Eth" + }, + "depositEther": { + "message": "Depo Ether" + }, + "depositFiat": { + "message": "Depo ak Fiat" + }, + "depositFromAccount": { + "message": "Depo nan yon lòt kont" + }, + "depositShapeShift": { + "message": "Depo avèk ShapeShift" + }, + "depositShapeShiftExplainer": { + "message": "Si ou posede lòt cryptocurrencies, ou ka chanje ak depo Ether dirèkteman nan Wallet MetaMask ou. Pa gen kont ki nesesè." + }, + "details": { + "message": "Detay yo" + }, + "directDeposit": { + "message": "Depo Dirèk" + }, + "directDepositEther": { + "message": "Dirèkteman Depo Ether" + }, + "directDepositEtherExplainer": { + "message": "Si ou deja gen kèk Ether, fason ki pi rapid yo ka resevwa Ether nan nouvo Wallet ou pa depo dirèk." + }, + "done": { + "message": "Fini" + }, + "downloadGoogleChrome": { + "message": "Telechaje Google Chrome" + }, + "downloadStateLogs": { + "message": "Telechaje State Logs" + }, + "dontHaveAHardwareWallet": { + "message": "Pa gen yon materyèl bous?" + }, + "dropped": { + "message": "Tonbe" + }, + "edit": { + "message": "Korije" + }, + "editAccountName": { + "message": "Korije Non Kont" + }, + "editingTransaction": { + "message": "Fè chanjman nan tranzaksyon ou" + }, + "emailUs": { + "message": "Imèl nou!" + }, + "encryptNewDen": { + "message": "Ankripte nouvo DEN ou" + }, + "ensNameNotFound": { + "message": "Nou pa jwenn non ENS ou a" + }, + "enterPassword": { + "message": "Mete modpas" + }, + "enterPasswordConfirm": { + "message": "Antre nan modpas ou a konfime" + }, + "enterPasswordContinue": { + "message": "Mete modpas pou kontinye" + }, + "eth": { + "message": "ETH" + }, + "etherscanView": { + "message": "Gade kont sou Etherscan" + }, + "exchangeRate": { + "message": "Chanje to" + }, + "expandView": { + "message": "Elaji Wè" + }, + "exportPrivateKey": { + "message": "Voye Kòd Prive" + }, + "exportPrivateKeyWarning": { + "message": "Voye kle prive ak pwòp risk ou." + }, + "failed": { + "message": "Tonbe" + }, + "fiat": { + "message": "FIAT", + "description": "Exchange type" + }, + "fileImportFail": { + "message": "Enpòte dosye ki pa travay? Klike la a!", + "description": "Helps user import their account from a JSON file" + }, + "followTwitter": { + "message": "Swiv nou sou Twitter" + }, + "forgetDevice": { + "message": "Bliye aparèy sa a" + }, + "from": { + "message": "Soti nan" + }, + "fromToSame": { + "message": "Adrès orijinal le ak sa ou resevwa pake menm" + }, + "fromShapeShift": { + "message": "Soti nan ShapeShift" + }, + "functionType": { + "message": "Kalite Fonksyon" + }, + "gas": { + "message": "Gaz", + "description": "Short indication of gas cost" + }, + "gasFee": { + "message": "Frè gaz" + }, + "gasLimit": { + "message": "Limit gaz" + }, + "gasLimitCalculation": { + "message": "Nou kalkile gaz limit sijere a ki baze sou pousantaj siksè rezo a." + }, + "gasLimitRequired": { + "message": "Limit gaz nesesè" + }, + "gasLimitTooLow": { + "message": "Limit gaz dwe omwen 21000" + }, + "gasUsed": { + "message": "Gaz yo Itilize" + }, + "generatingSeed": { + "message": "Grenn jenerasyon..." + }, + "gasPrice": { + "message": "Pri gaz (GWEI)" + }, + "gasPriceCalculation": { + "message": "Nou kalkile pri yo gaz ki sijere ki baze sou pousantaj siksè rezo." + }, + "gasPriceRequired": { + "message": "Pri Gaz la Egzije" + }, + "generatingTransaction": { + "message": "Tranzaksyon kap fè" + }, + "getEther": { + "message": "Jwenn Ether" + }, + "getEtherFromFaucet": { + "message": "Jwenn Ether nan yon tiyo pou $1 la", + "description": "Displays network name for Ether faucet" + }, + "getHelp": { + "message": "Jwenn èd." + }, + "greaterThanMin": { + "message": "dwe pi gran pase oswa egal a $ 1.", + "description": "helper for inputting hex as decimal input" + }, + "hardware": { + "message": "materyèl" + }, + "hardwareWalletConnected": { + "message": "Materyèl Wallet konekte" + }, + "hardwareWallets": { + "message": "Materyèl Wallet konekte" + }, + "hardwareWalletsMsg": { + "message": "Chwazi yon Materyèl Wallet ou ta renmen itilize ak MetaMask" + }, + "havingTroubleConnecting": { + "message": "Èske w gen pwoblèm pou konekte?" + }, + "here": { + "message": "isit la", + "description": "as in -click here- for more information (goes with troubleTokenBalances)" + }, + "hereList": { + "message": "Isit la nan yon lis !!!!" + }, + "hexData": { + "message": "Hex Data" + }, + "hide": { + "message": "Kache" + }, + "hideToken": { + "message": "Kache Token" + }, + "hideTokenPrompt": { + "message": "Kache Token?" + }, + "history": { + "message": "Istwa" + }, + "howToDeposit": { + "message": "Ki jan ou ta renmen depo Ether?" + }, + "holdEther": { + "message": "Li pèmèt ou kenbe ether & tokens, epi sèvi kòm on pon pou desantralize aplikasyon." + }, + "import": { + "message": "Pòte", + "description": "Button to import an account from a selected file" + }, + "importAccount": { + "message": "Pòte Kont" + }, + "importAccountMsg": { + "message": " Kont pòte pa pral asosye avèk orijinal ou te kreye nan kont MetaMask seed fraz. Aprann plis sou kont enpòte " + }, + "importAnAccount": { + "message": "Pòte yon kont" + }, + "importDen": { + "message": "Pòte ki deja egziste DEN" + }, + "imported": { + "message": "Pòte", + "description": "status showing that an account has been fully loaded into the keyring" + }, + "importUsingSeed": { + "message": "Pòte lè sèvi avèk seed fraz" + }, + "info": { + "message": "Enfo" + }, + "infoHelp": { + "message": "Enfo & Èd" + }, + "initialTransactionConfirmed": { + "message": "Premye tranzaksyon ou konfime sou rezo a. Klike sou OK pou tounen." + }, + "insufficientFunds": { + "message": "Lajan ensifizan." + }, + "insufficientTokens": { + "message": "Tokens pa valab." + }, + "invalidAddress": { + "message": "Adrès pa valab" + }, + "invalidAddressRecipient": { + "message": "Moun ki resevwa adrès la pa valab" + }, + "invalidGasParams": { + "message": "Gaz Paramèt la pa valab" + }, + "invalidInput": { + "message": "Sa ou rantre a pa valab" + }, + "invalidRequest": { + "message": "Demann pa valab" + }, + "invalidRPC": { + "message": "RPC URI pa valab" + }, + "invalidSeedPhrase": { + "message": "Seed fraz pa valab" + }, + "jsonFail": { + "message": "Yon bagay ale mal. Tanpri, asire w ke dosye JSON ou an byen fòmate." + }, + "jsonFile": { + "message": "JSON Dosye", + "description": "format for importing an account" + }, + "keepTrackTokens": { + "message": "Gade tokens yo ou te achte ak kont MetaMask ou." + }, + "kovan": { + "message": "Kovan Tès Rezo" + }, + "knowledgeDataBase": { + "message": "Vizite baz nou an" + }, + "max": { + "message": "Maksimòm" + }, + "learnMore": { + "message": "Aprann plis" + }, + "ledgerAccountRestriction": { + "message": "Ou bezwen sèvi ak dènye kont ou anvan ou ka ajoute yon nouvo." + }, + "lessThanMax": { + "message": "dwe mwens pase oswa egal a $ 1.", + "description": "helper for inputting hex as decimal input" + }, + "likeToAddTokens": { + "message": "Èske ou ta renmen ajoute sa nan tokens?" + }, + "links": { + "message": "Lyen" + }, + "limit": { + "message": "Limitasyon" + }, + "loading": { + "message": "Telechaje..." + }, + "loadingTokens": { + "message": "Telechaje Tokens..." + }, + "localhost": { + "message": "Localhost 8545" + }, + "login": { + "message": "Ouvri" + }, + "logout": { + "message": "Dekonekte" + }, + "loose": { + "message": "Pèdi" + }, + "loweCaseWords": { + "message": "seed mo sèlman gen karaktè miniskil" + }, + "mainnet": { + "message": "Prensipal Ethereum Rezo a" + }, + "menu": { + "message": "Opsyon" + }, + "message": { + "message": "Mesaje" + }, + "metamaskDescription": { + "message": "MetaMask sekirize idantite pou Ethereum." + }, + "metamaskSeedWords": { + "message": "MetaMask Seed Mo" + }, + "metamaskVersion": { + "message": "MetaMask Vèsyon" + }, + "min": { + "message": "Minimòm" + }, + "missingYourTokens": { + "message": "Ou pa wè token ou a?" + }, + "myAccounts": { + "message": "Kont mwen" + }, + "mustSelectOne": { + "message": "Ou dwe chwazi omwen 1 token." + }, + "needEtherInWallet": { + "message": "Pou kominike avèk aplikasyon desantralize ou dwe itilize MetaMask, ou pral bezwen Ether nan Wallet ou." + }, + "needImportFile": { + "message": "Ou dwe chwazi yon dosye pou enpòte.", + "description": "User is important an account and needs to add a file to continue" + }, + "needImportPassword": { + "message": "Ou dwe antre nan yon modpas pou dosye ou te chwazi a.", + "description": "Password and file needed to import an account" + }, + "negativeETH": { + "message": "Pa ka voye kantite lajan negatif ETH." + }, + "networks": { + "message": "Rezo" + }, + "nevermind": { + "message": "Pa pwoblèm" + }, + "newAccount": { + "message": "Nouvo Kont" + }, + "newAccountNumberName": { + "message": "Kont $1", + "description": "Default name of next account to be created on create account screen" + }, + "newContract": { + "message": "Nouvo Kontra" + }, + "newPassword": { + "message": "Nouvo modpas (minit 8)" + }, + "newPassword8Chars": { + "message": "Nouvo modpas (minit 8)" + }, + "newRecipient": { + "message": "Nouvo Benefisyè" + }, + "newRPC": { + "message": "Nouvo RPC URL" + }, + "next": { + "message": "Aprè sa" + }, + "noAddressForName": { + "message": "Pa gen adrès ki etabli pou non sa a." + }, + "noDeposits": { + "message": "Pa gen depo ou te resevwa" + }, + "noConversionRateAvailable": { + "message": "Pa gen okenn Konvèsyon Disponib" + }, + "noTransactionHistory": { + "message": "Pa gen istwa tranzaksyon." + }, + "noTransactions": { + "message": "Pa gen tranzaksyon" + }, + "notFound": { + "message": "Pa jwenn" + }, + "notStarted": { + "message": "Pa kòmanse" + }, + "noWebcamFoundTitle": { + "message": "Pa jwenn webcam" + }, + "noWebcamFound": { + "message": "Nou pakay jwenn webcam òdinatè ou. Tanpri eseye ankò." + }, + "oldUI": { + "message": "Ansyen Itilizatè kouòdone" + }, + "oldUIMessage": { + "message": "Ou te retounen nan Ansyen Itilizatè kouòdone. Ou ka chanje tounen nan nouvo Ansyen Itilizatè nan opsyon a nan meni an tèt la." + }, + "onlySendToEtherAddress": { + "message": "Sèlman voye ETH nan yon adrès Ethereum." + }, + "onlySendTokensToAccountAddress": { + "message": "Sèlman voye $ 1 nan yon adrès kont Ethereum.", + "description": "displays token symbol" + }, + "openInTab": { + "message": "Louvri nan etikèt" + }, + "or": { + "message": "oubyen", + "description": "choice between creating or importing a new account" + }, + "orderOneHere": { + "message": "Mete nan lòd on Trezor oswa Ledger epi kenbe lajan ou nan yon stòk frèt." + }, + "origin": { + "message": "Orijin" + }, + "outgoing": { + "message": "Ap kite" + }, + "parameters": { + "message": "Paramèt" + }, + "password": { + "message": "Modpas" + }, + "passwordCorrect": { + "message": "Tanpri asire ke modpas ou kòrèk." + }, + "passwordsDontMatch": { + "message": "Modpas pa matche" + }, + "passwordMismatch": { + "message": "modpas sa pa menm", + "description": "in password creation process, the two new password fields did not match" + }, + "passwordNotLongEnough": { + "message": "Modpas pa lontan ase" + }, + "passwordShort": { + "message": "modpas pa sifi", + "description": "in password creation process, the password is not long enough to be secure" + }, + "pastePrivateKey": { + "message": "Kole fraz prive ou a la:", + "description": "For importing an account from a private key" + }, + "pasteSeed": { + "message": "Kole seed fraz ou a la!" + }, + "pending": { + "message": "l ap mache" + }, + "personalAddressDetected": { + "message": "Adrès pèsonèl detekte. Antre adrès kontra token la." + }, + "pleaseReviewTransaction": { + "message": "Tanpri revize tranzaksyon ou." + }, + "popularTokens": { + "message": "Popilè Tokens" + }, + "prev": { + "message": "Avan" + }, + "primaryCurrencySetting": { + "message": "Lajan ou itilize pi plis la" + }, + "primaryCurrencySettingDescription": { + "message": "Chwazi ETH pou bay priyorite montre valè nan ETH. Chwazi Fiat priyorite montre valè nan lajan ou chwazi a." + }, + "privacyMsg": { + "message": "Règleman sou enfòmasyon prive" + }, + "privateKey": { + "message": "Prive kle", + "description": "select this type of file to use to import an account" + }, + "privateKeyWarning": { + "message": "Atansyon: pa janm divilge kle sa. Nenpòt moun kapab avèk kle prive ou a vòlè sa ou gen ou sou kont ou a." + }, + "privateNetwork": { + "message": "Rezo Prive" + }, + "qrCode": { + "message": "Montre QR Kòd" + }, + "queue": { + "message": "Queue" + }, + "readdToken": { + "message": "Ou ka ajoute token sa aprè sa ankò ou prale nan \"Ajoute token\" nan opsyon meni kont ou an." + }, + "readMore": { + "message": "Li plis isit la." + }, + "readMore2": { + "message": "Li plis isit la." + }, + "receive": { + "message": "Resevwa" + }, + "recipientAddress": { + "message": "Adrès pou resevwa" + }, + "refundAddress": { + "message": "Adrès pou resevwa" + }, + "reject": { + "message": "Rejte" + }, + "rejectAll": { + "message": "Rejte Tout" + }, + "rejectTxsN": { + "message": "Rejete $ 1 tranzaksyon" + }, + "rejectTxsDescription": { + "message": "Ou se sou rejte $ 1 yon anpil nan tranzaksyon yo." + }, + "rejected": { + "message": "Rejete" + }, + "reset": { + "message": "Repwograme" + }, + "resetAccount": { + "message": "Repwograme Kont" + }, + "resetAccountDescription": { + "message": "Repwograme kont a netwaye tranzaksyon ou yo." + }, + "restoreFromSeed": { + "message": "Restore kont?" + }, + "restoreVault": { + "message": "Retabli kazye" + }, + "restoreAccountWithSeed": { + "message": "Retabli kont ou avèk yo Seed Fraz" + }, + "required": { + "message": "Egzije" + }, + "retryWithMoreGas": { + "message": "Reseye ak yon pri gaz pi wo isit la" + }, + "restore": { + "message": "Retabli" + }, + "revealSeedWords": { + "message": "Revele Seed Mo Yo" + }, + "revealSeedWordsTitle": { + "message": "Seed Fraz" + }, + "revealSeedWordsDescription": { + "message": "Si ou pa janm chanje navigatè ou deplase òdinatè, ou pral bezwen fraz seed la pou ka gen aksè a kont ou. Sere yo on kote an sekirite e an sekrè." + }, + "revealSeedWordsWarningTitle": { + "message": "PA pataje fraz sa a avèk nenpòt moun!" + }, + "revealSeedWordsWarning": { + "message": "Yo ka itilize mo sa pou vòlè kont ou." + }, + "revert": { + "message": "Retounen" + }, + "remove": { + "message": "retire" + }, + "removeAccount": { + "message": "Retire kont" + }, + "removeAccountDescription": { + "message": "Kont sa a pral retire nan Wallet ou. Tanpri, asire ou ke ou gen orijinal fraz seed la oubyen kle prive pou rantre kont lan avan ou kontinye. Oubyen ou ka rantre kont ou ankò apati kont \"drop-down\" ou an." + }, + "readyToConnect": { + "message": "Pare pou konekte?" + }, + "rinkeby": { + "message": "Rinkeby Tès Rezo" + }, + "ropsten": { + "message": "Ropsten Tès Rezo" + }, + "rpc": { + "message": "Koutim RPC" + }, + "sampleAccountName": { + "message": "Pa egzanp, Nouvo kont mwen an", + "description": "Help user understand concept of adding a human-readable name to their account" + }, + "save": { + "message": "Sove" + }, + "saveAsCsvFile": { + "message": "Sove kòm dosye CSV" + }, + "saveAsFile": { + "message": "Sove kòm dosye", + "description": "Account export process" + }, + "saveSeedAsFile": { + "message": "Sove pawòl seed kòm dosye" + }, + "scanInstructions": { + "message": "Mete kòd QR la devan kamera ou" + }, + "scanQrCode": { + "message": "Enspeksyon QR Kòd" + }, + "search": { + "message": "Rechèch" + }, + "searchResults": { + "message": "Rezilta rechèch" + }, + "secretPhrase": { + "message": "Antre fraz sekrè douz mo ou a pou w restore kòf ou a." + }, + "seedPhraseReq": { + "message": "Seed fraz yo se 12 long mo" + }, + "select": { + "message": "Chwazi" + }, + "selectCurrency": { + "message": "Chwazi Lajan" + }, + "selectLocale": { + "message": "Chwazi Lokasyon" + }, + "selectService": { + "message": "Chwazi Sèvis" + }, + "selectType": { + "message": "Chwazi Kalite" + }, + "send": { + "message": "Voye" + }, + "sendETH": { + "message": "Voye ETH" + }, + "sendTokens": { + "message": "Voye Tokens" + }, + "sentEther": { + "message": "Voye ether" + }, + "sentTokens": { + "message": "tokens deja voye" + }, + "separateEachWord": { + "message": "Separe chak mo ak yon sèl espas" + }, + "searchTokens": { + "message": "Rechèch Tokens" + }, + "selectAnAddress": { + "message": "Chwazi yon adrès" + }, + "selectAnAccount": { + "message": "Chwazi yon kont" + }, + "selectAnAccountHelp": { + "message": "Chwazi kont pou wè nan MetaMask" + }, + "selectHdPath": { + "message": "Chwazi chemen HD" + }, + "selectPathHelp": { + "message": "Si ou pa wè kont Ledger ou te genyen an anba a, eseye chanje chemen an \"Eritaj (MEW / MyCrypto)\"" + }, + "sendTokensAnywhere": { + "message": "Voye Tokens pou nenpòt moun ki gen yon kont Ethereum" + }, + "settings": { + "message": "Paramèt" + }, + "shapeshiftBuy": { + "message": "Achte avèk Shapeshift" + }, + "showPrivateKeys": { + "message": "Montre Kle Prive" + }, + "showQRCode": { + "message": "Montre Kòd QR" + }, + "showHexData": { + "message": "Montre Hex Data" + }, + "showHexDataDescription": { + "message": "Pran sa pouw ka montre chan entèfas hex data a" + }, + "sign": { + "message": "Siyen" + }, + "signatureRequest": { + "message": "Siyati Mande" + }, + "signed": { + "message": "Te Siyen" + }, + "signMessage": { + "message": "Siyen mesaj" + }, + "signNotice": { + "message": "Lè w siyen mesaj sa a ka gen efè segondè ki \ndanjere. Sèlman \nsit mesaj ki soti nan sit ou konplètman fè konfyans ak tout kont ou. \n Metòd danjere sa yo pral retire nan yon vèsyon fiti. " + }, + "sigRequest": { + "message": "Demann Siyati" + }, + "sigRequested": { + "message": "Demann Siyati" + }, + "spaceBetween": { + "message": "ka gen sèlman yon espas ant mo yo" + }, + "speedUp": { + "message": "pi vit" + }, + "speedUpTitle": { + "message": "Monte vitès tranzaksyon" + }, + "speedUpSubtitle": { + "message": "Ogmante pri gaz ou pou eseye efase tranzaksyon ou pi vit" + }, + "status": { + "message": "Kondisyon" + }, + "stateLogs": { + "message": "State Logs" + }, + "stateLogsDescription": { + "message": "State logs gen adrès kont piblik ou yo epi tranzaksyon ou te voye yo." + }, + "stateLogError": { + "message": "Erè nan retwouve State Logs yo." + }, + "step1HardwareWallet": { + "message": "1. Konekte Materyèl bous" + }, + "step1HardwareWalletMsg": { + "message": "Konekte materyèl bous ou dirèkteman nan òdinatè ou." + }, + "step2HardwareWallet": { + "message": "2. Chwazi yon kont" + }, + "step2HardwareWalletMsg": { + "message": "Chwazi kont ou vle wè a. Ou ka chwazi youn sèlman nan yon moman." + }, + "step3HardwareWallet": { + "message": "3. Kòmanse itilize dApps ak plis ankò!" + }, + "step3HardwareWalletMsg": { + "message": "Sèvi ak kont materyèl ou menm jan ou t ap fè pou kont Etherum. Ouvri sesyon an nan dApps, voye Eth, achte ak stòke ERC20 tokens ak e ki pake chanje tokens tankou CryptoKitties." + }, + "submit": { + "message": "Soumèt" + }, + "submitted": { + "message": "Te Soumèt" + }, + "supportCenter": { + "message": "Vizite Sant Sipò Nou" + }, + "symbolBetweenZeroTen": { + "message": "Senbòl yo dwe ant 0 ak 10 karaktè." + }, + "takesTooLong": { + "message": "Pran twò lontan?" + }, + "terms": { + "message": "Tèm pou itilize" + }, + "testFaucet": { + "message": "Tès Tiyo" + }, + "to": { + "message": "Pou" + }, + "toETHviaShapeShift": { + "message": "$1 pou ETH pa ShapeShift", + "description": "system will fill in deposit type in start of message" + }, + "token": { + "message": "Token" + }, + "tokenAddress": { + "message": "Adrès Token" + }, + "tokenAlreadyAdded": { + "message": "Ou te deja ajoute token." + }, + "tokenBalance": { + "message": "Balans Token ou se:" + }, + "tokenSelection": { + "message": "Chache Tokens oswa chwazi nan lis Tokens popilè nou an." + }, + "tokenSymbol": { + "message": "Token Senbòl" + }, + "tokenWarning1": { + "message": "Kenbe tras token yo ou te achte ak kont MetaMask ou. Si ou te achte tokens pandan wap itilize yon kont diferan tokens sa yo pa pral parèt la." + }, + "total": { + "message": "Total" + }, + "transaction": { + "message": "tranzaksyon yo" + }, + "transactionConfirmed": { + "message": "Tranzaksyon ou te konfime pou $2." + }, + "transactionCreated": { + "message": "Tranzaksyon ou te kreye avèk on valè de $1 pou $2." + }, + "transactionWithNonce": { + "message": "Tranzaksyon $1" + }, + "transactionDropped": { + "message": "Tranzaksyon ou te tonbe a $2." + }, + "transactionSubmitted": { + "message": "Tranzaksyon ou te soumèt a $2." + }, + "transactionUpdated": { + "message": "Tranzaksyon ou te aktyalize a $2." + }, + "transactionUpdatedGas": { + "message": "Tranzaksyon ou te aktyalize avèk on pri gaz de $1 a $2." + }, + "transactions": { + "message": "transactions" + }, + "transactionError": { + "message": "Erè tranzaksyon. Eksepsyon jete nan kòd kontra." + }, + "transactionMemo": { + "message": "Memo tranzaksyon (opsyonèl)" + }, + "transactionNumber": { + "message": "Nimewo Tranzaksyon" + }, + "transfer": { + "message": "Transfè" + }, + "transferFrom": { + "message": "Transfer From" + }, + "transfers": { + "message": "Transfè yo" + }, + "trezorHardwareWallet": { + "message": "TREZOR Materyèl Bous" + }, + "troubleTokenBalances": { + "message": "Nou te gen pwoblèm chaje balans token ou. Ou ka wè yo ", + "description": "Followed by a link (here) to view token balances" + }, + "tryAgain": { + "message": "Eseye anko" + }, + "twelveWords": { + "message": "12 mo sa yo se sèl fason pou retabli kont MetaMask ou yo. \nKenbe yo yon kote ki an sekirite ak sekrè." + }, + "typePassword": { + "message": "Tape modpas ou" + }, + "uiWelcome": { + "message": "Byenveni nan New itilizatè koòdone (Beta)" + }, + "uiWelcomeMessage": { + "message": "Kounya w ap itilize nouvo MetaMask UI (itilizatè koòdone) a." + }, + "unapproved": { + "message": "Pa apwouve" + }, + "unavailable": { + "message": "Pa disponib" + }, + "units": { + "message": "inite yo" + }, + "unknown": { + "message": "Enkoni" + }, + "unknownFunction": { + "message": "Fonksyon enkoni" + }, + "unknownNetwork": { + "message": "Rezo Prive Enkoni" + }, + "unknownNetworkId": { + "message": "Rezo ID Enkoni" + }, + "unknownQrCode": { + "message": "Erè: Nou pa t kapab idantifye QR kòd sa" + }, + "unknownCameraErrorTitle": { + "message": "Ooops! Yon bagay te ale mal...." + }, + "unknownCameraError": { + "message": "Te gen yon erè pandan y ap eseye jwenn aksè nan kamera ou. Tanpri eseye ankò..." + }, + "unlock": { + "message": "Debloke" + }, + "unlockMessage": { + "message": "Entènèt desantralize a ap tann" + }, + "updatedWithDate": { + "message": "Mete ajou $1" + }, + "uriErrorMsg": { + "message": "URIs mande pou apwopriye prefiks HTTP / HTTPS a." + }, + "usaOnly": { + "message": "USA sèlman", + "description": "Using this exchange is limited to people inside the USA" + }, + "usedByClients": { + "message": "Itilize pa yon varyete de kliyan diferan" + }, + "useOldUI": { + "message": "Itilizasyon ansyen UI (itilizatè koòdone)" + }, + "validFileImport": { + "message": "Ou dwe chwazi yon dosye ki valab pou enpòte." + }, + "vaultCreated": { + "message": "Kòf Kreye" + }, + "viewAccount": { + "message": "Wè Kont" + }, + "viewOnEtherscan": { + "message": "Wè sou Etherscan" + }, + "visitWebSite": { + "message": "Vizite sit entènèt nou an" + }, + "walletSeed": { + "message": "Bous Seed" + }, + "warning": { + "message": "Avètisman" + }, + "welcomeBack": { + "message": "Bon Retou!" + }, + "welcomeBeta": { + "message": "Byenveni nan MetaMask Beta" + }, + "whatsThis": { + "message": "Kisa sa ye?" + }, + "yesLetsTry": { + "message": "Wi, ann eseye" + }, + "youNeedToAllowCameraAccess": { + "message": "Ou bezwen bay kamera aksè pou sèvi ak fonksyon sa." + }, + "yourSigRequested": { + "message": "Yo mande siyati ou" + }, + "youSign": { + "message": "Ou ap siyen kounya" + }, + "yourPrivateSeedPhrase": { + "message": "Seed fraz prive ou a" + } } diff --git a/app/_locales/it/messages.json b/app/_locales/it/messages.json index 06e3dc855..e97c28e42 100644 --- a/app/_locales/it/messages.json +++ b/app/_locales/it/messages.json @@ -1,4 +1,46 @@ { + "privacyMode": { + "message": "Modalità di privacy" + }, + "privacyModeDescription": { + "message": "I siti Web devono richiedere l'accesso per visualizzare le informazioni del tuo account." + }, + "exposeAccounts": { + "message": "Expose Accounts" + }, + "exposeDescription": { + "message": "Esporre gli account al sito Web corrente. Utile per dapps legacy." + }, + "confirmExpose": { + "message": "Sei sicuro di voler esporre i tuoi account al sito web corrente?" + }, + "confirmClear": { + "message": "Sei sicuro di voler cancellare i siti Web approvati?" + }, + "clearApprovalDataSuccess": { + "message": "Dati del sito Web approvati cancellati correttamente." + }, + "approvalData": { + "message": "Dati di approvazione" + }, + "approvalDataDescription": { + "message": "Cancella i dati del sito web approvati, quindi tutti i siti devono richiedere nuovamente l'approvazione." + }, + "clearApprovalData": { + "message": "Cancella i dati di approvazione" + }, + "reject": { + "message": "Rifiutare" + }, + "providerAPIRequest": { + "message": "Richiesta API Web3" + }, + "reviewProviderRequest": { + "message": "Si prega di rivedere questa richiesta API Ethereum." + }, + "providerRequestInfo": { + "message": "Il dominio elencato di seguito sta tentando di richiedere l'accesso all'API Ethereum in modo che possa interagire con la blockchain di Ethereum. Controlla sempre di essere sul sito corretto prima di approvare l'accesso a Ethereum." + }, "accept": { "message": "Accetta" }, @@ -824,9 +866,6 @@ "refundAddress": { "message": "Indirizzo di Rimborso" }, - "reject": { - "message": "Reject" - }, "rejectAll": { "message": "Reject All" }, diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index 7b25f386a..8ae363030 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -1,4 +1,49 @@ { + "privacyMode": { + "message": "プライバシーモード" + }, + "privacyModeDescription": { + "message": "ウェブサイトはあなたのアカウント情報を閲覧するためのアクセスを要求する必要があります。" + }, + "exposeAccounts": { + "message": "アカウントを公開する" + }, + "exposeDescription": { + "message": "アカウントを現在のウェブサイトに公開する。従来のdappsに役立ちます。" + }, + "confirmExpose": { + "message": "現在のウェブサイトにアカウントを公開してもよろしいですか?" + }, + "confirmClear": { + "message": "承認されたウェブサイトをクリアしてもよろしいですか?" + }, + "clearApprovalDataSuccess": { + "message": "承認されたウェブサイトデータが正常に消去されました。" + }, + "approvalData": { + "message": "承認データ" + }, + "approvalDataDescription": { + "message": "承認されたウェブサイトのデータをクリアすると、すべてのサイトで承認を再度要求する必要があります" + }, + "clearApprovalData": { + "message": "承認データのクリア" + }, + "approve": { + "message": "承認する" + }, + "reject": { + "message": "拒否" + }, + "providerAPIRequest": { + "message": "Web3 APIリクエスト" + }, + "reviewProviderRequest": { + "message": "このEthereum APIリクエストを確認してください。" + }, + "providerRequestInfo": { + "message": "下記のドメインは、Ethereumブロックチェーンとやり取りできるようにEthereum APIへのアクセスをリクエストしようとしています。 Web3アクセスを承認する前に、正しいサイトにいることを常に確認してください。" + }, "accept": { "message": "承認" }, diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index c8d470188..af1c32615 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -1,4 +1,46 @@ { + "privacyMode": { + "message": "개인 정보 보호 모드" + }, + "privacyModeDescription": { + "message": "웹 사이트는 계정 정보를 볼 수있는 액세스 권한을 요청해야합니다." + }, + "exposeAccounts": { + "message": "계정 노출" + }, + "exposeDescription": { + "message": "계정을 현재 웹 사이트에 노출하십시오. 기존 dapps에 유용합니다." + }, + "confirmExpose": { + "message": "계정을 현재 웹 사이트에 공개 하시겠습니까?" + }, + "confirmClear": { + "message": "승인 된 웹 사이트를 삭제 하시겠습니까?" + }, + "clearApprovalDataSuccess": { + "message": "승인 된 웹 사이트 데이터가 성공적으로 삭제되었습니다." + }, + "approvalData": { + "message": "승인 데이터" + }, + "approvalDataDescription": { + "message": "승인 된 웹 사이트 데이터를 삭제하여 모든 사이트에서 승인을 다시 요청해야합니다." + }, + "clearApprovalData": { + "message": "승인 데이터 삭제" + }, + "reject": { + "message": "받지 않다" + }, + "providerAPIRequest": { + "message": "Web3 API 요청" + }, + "reviewProviderRequest": { + "message": "이 Ethereum API 요청을 검토하십시오." + }, + "providerRequestInfo": { + "message": "아래 나열된 도메인은 Web3 API에 대한 액세스를 요청하여 Ethereum 블록 체인과 상호 작용할 수 있습니다. Ethereum 액세스를 승인하기 전에 항상 올바른 사이트에 있는지 다시 확인하십시오." + }, "accept": { "message": "수락" }, @@ -815,9 +857,6 @@ "refundAddress": { "message": "환불받을 주소" }, - "reject": { - "message": "거부" - }, "rejectAll": { "message": "모두 거부" }, diff --git a/app/_locales/nl/messages.json b/app/_locales/nl/messages.json index e6d09c123..5d9f1f3ab 100644 --- a/app/_locales/nl/messages.json +++ b/app/_locales/nl/messages.json @@ -1,4 +1,49 @@ { + "privacyMode": { + "message": "Privacy-modus" + }, + "privacyModeDescription": { + "message": "Websites moeten toegang vragen om uw accountgegevens te bekijken." + }, + "exposeAccounts": { + "message": "Expose Accounts" + }, + "exposeDescription": { + "message": "Stel accounts vrij op de huidige website. Handig voor legacy dapps." + }, + "confirmExpose": { + "message": "Weet u zeker dat u uw accounts wilt weergeven aan de huidige website?" + }, + "confirmClear": { + "message": "Weet je zeker dat je goedgekeurde websites wilt wissen?" + }, + "clearApprovalDataSuccess": { + "message": "Goedgekeurde websitegegevens zijn met succes gewist." + }, + "approvalData": { + "message": "Goedkeuringsgegevens" + }, + "approvalDataDescription": { + "message": "Goedgekeurde websitegegevens wissen zodat alle sites opnieuw goedkeuring moeten aanvragen." + }, + "clearApprovalData": { + "message": "Gegevens over goedkeuring wissen" + }, + "approve": { + "message": "Goedkeuren" + }, + "reject": { + "message": "Afwijzen" + }, + "providerAPIRequest": { + "message": "Web3 API-aanvraag" + }, + "reviewProviderRequest": { + "message": "Bekijk deze Ethereum API-aanvraag." + }, + "providerRequestInfo": { + "message": "Het onderstaande domein probeert toegang tot de Ethereum API te vragen zodat deze kan communiceren met de Ethereum-blockchain. Controleer altijd eerst of u op de juiste site bent voordat u Ethereum-toegang goedkeurt." + }, "accept": { "message": "Aanvaarden" }, @@ -435,7 +480,7 @@ "message": "back-up woorden hebben alleen kleine letters" }, "mainnet": { - "message": "belangrijkste Ethereum-netwerk" + "message": "Main Netwerk" }, "message": { "message": "Bericht" diff --git a/app/_locales/ph/messages.json b/app/_locales/ph/messages.json index 9a243447a..cef686868 100644 --- a/app/_locales/ph/messages.json +++ b/app/_locales/ph/messages.json @@ -1,4 +1,49 @@ { + "privacyMode": { + "message": "Mode ng Privacy" + }, + "privacyModeDescription": { + "message": "Dapat humiling ng access ang mga website upang tingnan ang impormasyon ng iyong account." + }, + "exposeAccounts": { + "message": "Ilantad ang Mga Account" + }, + "exposeDescription": { + "message": "Ilantad ang mga account sa kasalukuyang website. Kapaki-pakinabang para sa mga dapps ng legacy." + }, + "confirmExpose": { + "message": "Sigurado ka bang gusto mong ilantad ang iyong mga account sa kasalukuyang website?" + }, + "confirmClear": { + "message": "Sigurado ka bang gusto mong i-clear ang mga naaprubahang website?" + }, + "clearApprovalDataSuccess": { + "message": "Matagumpay na na-clear ang data ng aprubadong website." + }, + "approvalData": { + "message": "Data ng Pag-apruba" + }, + "approvalDataDescription": { + "message": "I-clear ang naaprubahang data ng website upang ang lahat ng site ay dapat humiling muli ng pag-apruba" + }, + "clearApprovalData": { + "message": "Tanggalin ang data ng pag-apruba" + }, + "approve": { + "message": "Aprubahan" + }, + "reject": { + "message": "Tanggihan" + }, + "providerAPIRequest": { + "message": "Kahilingan sa Web3 API" + }, + "reviewProviderRequest": { + "message": "Mangyaring suriin ang kahilingan sa Ethereum API na ito." + }, + "providerRequestInfo": { + "message": "Ang domain na nakalista sa ibaba ay sinusubukang humiling ng access sa Ethereum API upang maaari itong makipag-ugnayan sa Ethereum blockchain. Laging i-double check na ikaw ay nasa tamang site bago aprubahan ang Ethereum access." + }, "accept": { "message": "Tanggapin" }, diff --git a/app/_locales/pt/messages.json b/app/_locales/pt/messages.json index 287ae0400..8e07aaef5 100644 --- a/app/_locales/pt/messages.json +++ b/app/_locales/pt/messages.json @@ -1,4 +1,49 @@ { + "privacyMode": { + "message": "Modo de privacidade" + }, + "privacyModeDescription": { + "message": "Os sites devem solicitar acesso para visualizar as informações da sua conta." + }, + "exposeAccounts": { + "message": "Expor contas" + }, + "exposeDescription": { + "message": "Exponha contas ao site atual. Útil para dapps herdados." + }, + "confirmExpose": { + "message": "Tem certeza de que deseja expor suas contas ao site atual?" + }, + "confirmClear": { + "message": "Tem certeza de que deseja limpar sites aprovados?" + }, + "clearApprovalDataSuccess": { + "message": "Dados aprovados do website foram limpos com sucesso." + }, + "approvalData": { + "message": "Dados de aprovação" + }, + "approvalDataDescription": { + "message": "Limpe os dados aprovados do website para que todos os sites solicitem aprovação novamente." + }, + "clearApprovalData": { + "message": "Limpar dados de aprovação" + }, + "approve": { + "message": "Aprovar" + }, + "reject": { + "message": "Rejeitar" + }, + "providerAPIRequest": { + "message": "Solicitação de API do Web3" + }, + "reviewProviderRequest": { + "message": "Por favor, revise esta solicitação da API da Ethereum." + }, + "providerRequestInfo": { + "message": "O domínio listado abaixo está tentando solicitar acesso à API Ethereum para que ele possa interagir com o blockchain Ethereum. Sempre verifique se você está no site correto antes de aprovar o acesso à Ethereum." + }, "accept": { "message": "Aceitar" }, diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index 45bb09683..917b2b615 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -1,4 +1,49 @@ { + "privacyMode": { + "message": "Режим конфиденциальности" + }, + "privacyModeDescription": { + "message": "Веб-сайты должны запрашивать доступ для просмотра информации об учетной записи." + }, + "exposeAccounts": { + "message": "Открыть счета" + }, + "exposeDescription": { + "message": "Выводить счета на текущий веб-сайт. Полезно для старых dapps." + }, + "confirmExpose": { + "message": "Вы уверены, что хотите открыть свои аккаунты на текущем веб-сайте?" + }, + "confirmClear": { + "message": "Вы уверены, что хотите очистить утвержденные веб-сайты?Tem certeza de que deseja limpar sites aprovados?" + }, + "clearApprovalDataSuccess": { + "message": "Утвержденные данные веб-сайта успешно удалены." + }, + "approvalData": { + "message": "Данные об утверждении" + }, + "approvalDataDescription": { + "message": "Очистите утвержденные данные веб-сайта, чтобы все сайты снова запросили подтверждение." + }, + "clearApprovalData": { + "message": "Четкие данные об утверждении" + }, + "approve": { + "message": "Одобрить" + }, + "reject": { + "message": "Отклонить" + }, + "providerAPIRequest": { + "message": "Запрос API Web3" + }, + "reviewProviderRequest": { + "message": "Просмотрите этот запрос API Ethereum." + }, + "providerRequestInfo": { + "message": "Домен, указанный ниже, пытается запросить доступ к API-интерфейсу Ethereum, чтобы он мог взаимодействовать с блокчейном Ethereum. Всегда проверяйте, что вы находитесь на правильном сайте, прежде чем одобрять доступ к веб-сайту." + }, "accept": { "message": "Принять" }, diff --git a/app/_locales/sl/messages.json b/app/_locales/sl/messages.json index a4b04d34b..b9c4ff8e0 100644 --- a/app/_locales/sl/messages.json +++ b/app/_locales/sl/messages.json @@ -1,819 +1,957 @@ { + "privacyMode": { + "message": "Režim súkromia" + }, + "privacyModeDescription": { + "message": "Webové stránky musia požiadať o prístup k zobrazeniu informácií o vašom účte." + }, + "exposeAccounts": { + "message": "Vystavte účty" + }, + "exposeDescription": { + "message": "Vystavte účty na aktuální webové stránky. Užitečné pro starší dappy." + }, + "confirmExpose": { + "message": "Opravdu chcete své účty vystavit na stávajícím webu?" + }, + "confirmClear": { + "message": "Naozaj chcete vymazať schválené webové stránky?" + }, + "clearApprovalDataSuccess": { + "message": "Schválené údaje webových stránek byly úspěšně zrušeny." + }, + "approvalData": { + "message": "Údaje o schválení" + }, + "approvalDataDescription": { + "message": "Vymažte schválené údaje webových stránek, aby všechny weby znovu požádaly o schválení." + }, + "clearApprovalData": { + "message": "Jasné údaje o schválení" + }, + "approve": { + "message": "Schválit" + }, + "reject": { + "message": "Odmítnout" + }, + "providerAPIRequest": { + "message": "Požadavek API Ethereum" + }, + "reviewProviderRequest": { + "message": "Přečtěte si prosím tuto žádost API Ethereum." + }, + "providerRequestInfo": { + "message": "Níže uvedená doména se pokouší požádat o přístup k API Ethereum, aby mohla komunikovat s blokádou Ethereum. Před schválením přístupu Ethereum vždy zkontrolujte, zda jste na správném místě." + }, "accept": { - "message": "Sprejmi" + "message": "Přijmout" }, "account": { - "message": "Račun" + "message": "Účet" }, "accountDetails": { - "message": "Podrobnosti računa" + "message": "Detaily účtu" }, "accountName": { - "message": "Ime računa" + "message": "Název účtu" }, "address": { - "message": "Naslov" + "message": "Adresa" }, "addCustomToken": { - "message": "Dodaj žeton po meri" + "message": "Přidat vlastní token" }, "addToken": { - "message": "Dodaj žeton" + "message": "Přidat token" }, "addTokens": { - "message": "Dodaj žetone" + "message": "Přidat tokeny" }, "amount": { - "message": "Znesek" + "message": "Částka" }, "amountPlusGas": { - "message": "Znesek + Gas" + "message": "Částka + palivo" }, "appDescription": { - "message": "Denarnica za Ethereum v brskalniku", + "message": "Ethereum rozšíření prohlížeče", "description": "The description of the application" }, "appName": { "message": "MetaMask", "description": "The name of the application" }, + "approved": { + "message": "Schváleno" + }, "attemptingConnect": { - "message": "Povezovanje z verigo blokov ..." + "message": "Pokouším se připojit k blockchainu." }, "attributions": { - "message": "Dodelitve" + "message": "Zásluhy" }, "available": { - "message": "Na voljo" + "message": "Dostupné" }, "back": { - "message": "Nazaj" + "message": "Zpět" }, "balance": { - "message": "Znesek:" + "message": "Zůstatek:" }, "balances": { - "message": "Vaš znesek" + "message": "Zůstatek tokenu" }, "balanceIsInsufficientGas": { - "message": "Napačen znesek za skupno gas vrednost" + "message": "Nedostatek prostředků pro aktuální množství paliva" }, "beta": { "message": "BETA" }, "betweenMinAndMax": { - "message": "mora biti večji ali enak $1 in manjši ali enak $1.", + "message": "musí být větší nebo roven $1 a menší nebo roven $2.", "description": "helper for inputting hex as decimal input" }, "blockiesIdenticon": { - "message": "Uporabite Blockies Identicon" + "message": "Použít Blockies Identicon" }, "borrowDharma": { - "message": "Izposoja z Dharma (Beta)" + "message": "Pújčit si přes Dharma (Beta)" }, "builtInCalifornia": { - "message": "MetaMask je ustvarjen v Kaliforniji." + "message": "MetaMask je navržen a vytvořen v Kalifornii." }, "buy": { - "message": "Kupi" + "message": "Koupit" }, "buyCoinbase": { - "message": "Kupi na Coinbase" + "message": "Nákup na Coinbase" }, "buyCoinbaseExplainer": { - "message": "Coinbase je najpopularnejši načun za kupovanje in prodajo bitcoinov, ethereuma, in litecoina." + "message": "Coinbase je světově nejoblíbenější místo k nákupu a prodeji bitcoinu, etherea nebo litecoinu." + }, + "ok": { + "message": "Ok" }, "cancel": { - "message": "Prekliči" + "message": "Zrušit" }, "classicInterface": { - "message": "Uporabi navaden način" + "message": "Použít klasické rozhraní" }, "clickCopy": { - "message": "Kliknite za kopiranje" + "message": "Kliknutím zkopírovat" }, "confirm": { - "message": "Potrdi" + "message": "Potvrdit" + }, + "confirmed": { + "message": "Potvrzeno" }, "confirmContract": { - "message": "Potrdi pogodbo" + "message": "Potvrdit kontrakt" }, "confirmPassword": { - "message": "Potrdi geslo" + "message": "Potvrdit heslo" }, "confirmTransaction": { - "message": "Potrdi transakcijo" + "message": "Potvrdit transakci" }, "continue": { - "message": "Nadaljuj" + "message": "Pokračovat" }, "continueToCoinbase": { - "message": "Nadaljuj na Coinbase" + "message": "Přejít na Coinbase" }, "contractDeployment": { - "message": "Ustvarjanje pogodbe" + "message": "Nasazení kontraktu" }, "conversionProgress": { - "message": "Poteka pretvorba" + "message": "Provádí se převod" }, "copiedButton": { - "message": "Kopirano" + "message": "Zkopírováno" }, "copiedClipboard": { - "message": "Kopirano v odložišče" + "message": "Zkopírováno do schránky" }, "copiedExclamation": { - "message": "Kopirano!" + "message": "Zkopírováno!" }, "copiedSafe": { - "message": "Prilepil sem ga na varno!" + "message": "Zkopíroval jsem to na bezpečné místo" }, "copy": { - "message": "Kopiraj" + "message": "Kopírovat" }, "copyToClipboard": { - "message": "Kopiraj v odložišče" + "message": "Kopírovat do schránky" }, "copyButton": { - "message": " Kopiraj " + "message": " Kopírovat " }, "copyPrivateKey": { - "message": "To je vaš zesebni ključ (kliknite za kopiranje)" + "message": "Toto je váš privátní klíč (kliknutím zkopírujte)" }, "create": { - "message": "Ustvari" + "message": "Vytvořit" }, "createAccount": { - "message": "Ustvari račun" + "message": "Vytvořit účet" }, "createDen": { - "message": "Ustvari" + "message": "Vytvořit" }, "crypto": { - "message": "Kripto", + "message": "Krypto", "description": "Exchange type (cryptocurrencies)" }, "currentConversion": { - "message": "Trenutna cena" + "message": "Aktuální převod" }, "currentNetwork": { - "message": "Trenutno omrežje" + "message": "Aktuální síť" }, "customGas": { - "message": "Prilagodi gas" + "message": "Nastavit palivo" + }, + "customToken": { + "message": "Vlastní token" }, "customize": { - "message": "Prilagodi" + "message": "Nastavit" }, "customRPC": { - "message": "Poljuben RPC" + "message": "Vlastní RPC" }, "decimalsMustZerotoTen": { - "message": "Decimalk mora biti vsaj 0, in ne več kot 36." + "message": "Desetinných míst musí být od 0 do 36." }, "decimal": { - "message": "Decimalke natančnosti" + "message": "Počet desetinných míst přesnosti" }, "defaultNetwork": { - "message": "Privzeto omrežje za transakcije je Main Net." + "message": "Výchozí síť pro Etherové transakce je Main Net." }, "denExplainer": { - "message": "DEN je vaša šifrirana shramba v MetaMasku." + "message": "Váš DEN je heslem šifrované uložiště v MetaMasku." }, "deposit": { - "message": "Vplačaj" + "message": "Vklad" }, "depositBTC": { - "message": "Vplačajte vaš BTC na spodnji naslov:" + "message": "Vložte BTC na níže uvedenou adresu:" }, "depositCoin": { - "message": "Vplačajte $1 na spodnji naslov", + "message": "Vložte $1 na níže uvedenou adresu", "description": "Tells the user what coin they have selected to deposit with shapeshift" }, "depositEth": { - "message": "Vplačilo ETH" + "message": "Vložit Eth" }, "depositEther": { - "message": "Vplačilo ethera" + "message": "Vložit Ether" }, "depositFiat": { - "message": "Vplačilo s klasičnimi valutami" + "message": "Vklad s fiat měnou" }, "depositFromAccount": { - "message": "Vplačilo iz drugega računa" + "message": "Vložte z jiného účtu" }, "depositShapeShift": { - "message": "Vplačilo z ShapeShift" + "message": "Vklad přes ShapeShift" }, "depositShapeShiftExplainer": { - "message": "Če imate druge kriptovalute, lahko vpačate ether neposredno v MetaMask. Brez računov." + "message": "Pokud vlastníte jiné kryptoměny, můžete je směnit Ether a vložit ho přímo do peněženky MetaMask. Bez založení účtu." }, "details": { "message": "Podrobnosti" }, "directDeposit": { - "message": "Direktno vplačilo" + "message": "Přímý vklad" }, "directDepositEther": { - "message": "Direktno vplačilo ehera" + "message": "Vložit Ether přímo" }, "directDepositEtherExplainer": { - "message": "Če že imate ether, ga lahko najhitreje dobite v MetaMask z direktnim vplačilom." + "message": "Pokud už vlastníte nějaký Ether, nejrychleji ho dostanete do peněženky přímým vkladem." }, "done": { - "message": "Končano" + "message": "Hotovo" }, "downloadStateLogs": { - "message": "Prenesi state dnevnike" + "message": "Stáhnout stavové protokoly" + }, + "dropped": { + "message": "Zrušeno" }, "edit": { - "message": "Uredi" + "message": "Upravit" }, "editAccountName": { - "message": "Uredi ime računa" + "message": "Upravit název účtu" }, "emailUs": { - "message": "Pišite nam!" + "message": "Napište nám e-mail!" }, "encryptNewDen": { - "message": "Šifrirajte DEN" + "message": "Zašifrujte svůj nový DEN" }, "enterPassword": { - "message": "Vpišite geslo" + "message": "Zadejte heslo" }, "enterPasswordConfirm": { - "message": "Potrdite geslo" + "message": "Zadejte heslo k potvrzení" + }, + "passwordNotLongEnough": { + "message": "Heslo není dost dlouhé" + }, + "passwordsDontMatch": { + "message": "Hesla nejsou stejná" }, "etherscanView": { - "message": "Poglejte račun na Etherscan" + "message": "Prohlédněte si účet na Etherscan" }, "exchangeRate": { - "message": "Menjalni tečaj" + "message": "Směnný kurz" }, "exportPrivateKey": { - "message": "Izvozi zasebni ključ" + "message": "Exportovat privátní klíč" }, "exportPrivateKeyWarning": { - "message": "Izvažanje zasebnih ključev je na lastno odgovornost." + "message": "Exportujte privátní klíč na vlastní riziko." }, "failed": { - "message": "Ni uspelo" + "message": "Neúspěšné" }, "fiat": { "message": "FIAT", "description": "Exchange type" }, "fileImportFail": { - "message": "Uvoz z datoteko ni uspel? Kliknite tukaj!", + "message": "Import souboru nefunguje? Klikněte sem!", "description": "Helps user import their account from a JSON file" }, "followTwitter": { - "message": "Sledite nam na Twitterju" + "message": "Sledujte nás na Twitteru" }, "from": { "message": "Od" }, "fromToSame": { - "message": "From and To address cannot be the same" + "message": "Adresy odesílatele a příjemce nemohou být stejné" }, "fromShapeShift": { - "message": "Od ShapeShift" + "message": "Z ShapeShift" }, "gas": { - "message": "Gas", + "message": "Palivo", "description": "Short indication of gas cost" }, "gasFee": { - "message": "Gas fee" + "message": "Poplatek za palivo" }, "gasLimit": { - "message": "Gas limit" + "message": "Limit paliva" }, "gasLimitCalculation": { - "message": "Priporočen gas limit je izračunan glede na omrežje." + "message": "Počítáme doporučený limit paliva na základě úspěšnosti v síti." }, "gasLimitRequired": { - "message": "Gas limit je zahtevan" + "message": "Limit paliva je povinný" }, "gasLimitTooLow": { - "message": "Gas limit mora biti najmanj 21000" + "message": "Limit paliva musí být alespoň 21000" }, "generatingSeed": { - "message": "Ustvarjenje seed ..." + "message": "Generuji klíčovou frázi..." }, "gasPrice": { - "message": "Gas price (GWEI)" + "message": "Cena paliva (GWEI)" }, "gasPriceCalculation": { - "message": "Priporočen gas price je izračunan glede na omrežje" + "message": "Počítáme doporučenou cenu paliva na základě úspěšnosti v síti." }, "gasPriceRequired": { - "message": "Gas price je zahtevan" + "message": "Cena paliva je povinná" }, "getEther": { - "message": "Pridobite ether" + "message": "Získejte Ether" }, "getEtherFromFaucet": { - "message": "Pridobite ether iz fauceta za $1", + "message": "Získejte Ether z faucetu za $1.", "description": "Displays network name for Ether faucet" }, "greaterThanMin": { - "message": "mora biti višji ali enak $1.", + "message": "musí být větší nebo roven $1.", "description": "helper for inputting hex as decimal input" }, "here": { - "message": "tukaj", + "message": "zde", "description": "as in -click here- for more information (goes with troubleTokenBalances)" }, "hereList": { - "message": "Tukaj je seznam!!!" + "message": "Tady je seznam!!!!" }, "hide": { - "message": "Skrij" + "message": "Skrýt" }, "hideToken": { - "message": "Skrij žeton" + "message": "Skrýt token" }, "hideTokenPrompt": { - "message": "Skrijem žeton?" + "message": "Skrýt token?" }, "howToDeposit": { - "message": "Kako želite vplačati ether?" + "message": "Jakým způsobem chcete vložit Ether?" }, "holdEther": { - "message": "Omogoča vam, da imate eter in žetone in služi kot most za decentralizirane aplikacije." + "message": "Dovoluje vám držet ether a tokeny a slouží jako most k decentralizovaným aplikacím." }, "import": { - "message": "Uvozi", + "message": "Import", "description": "Button to import an account from a selected file" }, "importAccount": { - "message": "Uvozi račun" + "message": "Import účtu" }, "importAccountMsg": { - "message": " Uvoženi računi ne bodo povezani s prvotnim seedphaseom. Preberite več o uvoženih računih " + "message": "Importované účty nebudou spojeny s vaší původní MetaMaskovou klíčovou frází. Zjistěte více o importovaných účtech " }, "importAnAccount": { - "message": "Uvozi račun" + "message": "Import účtu" }, "importDen": { - "message": "Uvozi DEN" + "message": "Import existujícího DEN" }, "imported": { - "message": "Uvoženo", + "message": "Importováno", "description": "status showing that an account has been fully loaded into the keyring" }, "infoHelp": { - "message": "Info & Pomoč" + "message": "Informace a nápověda" }, "insufficientFunds": { - "message": "Nezadostna sredstva." + "message": "Nedostatek finančních prostředků." }, "insufficientTokens": { - "message": "Nezadostni žetoni." + "message": "Nedostatek tokenů." }, "invalidAddress": { - "message": "Nepravilen naslov" + "message": "Neplatná adresa" }, "invalidAddressRecipient": { - "message": "Prejemnikov naslov je neveljaven" + "message": "Adresa příjemce je neplatná" }, "invalidGasParams": { - "message": "Nepravilno nastavljen gas" + "message": "Neplatná parametry paliva" }, "invalidInput": { - "message": "Napačen vnos." + "message": "Neplatný vstup." }, "invalidRequest": { - "message": "Napačna zahteva" + "message": "Neplatný požadavek" }, "invalidRPC": { - "message": "Napačen RPC URI" + "message": "Neplatné RPC URI" }, "jsonFail": { - "message": "Nekaj je bilo narobe. Prepričajte se, da je JSON datoteka pravilno oblikovana." + "message": "Něco se pokazilo. Prosím, ujistěte se, že váš JSON soubor má správný formát." }, "jsonFile": { - "message": "JSON datoteka", + "message": "JSON soubor", "description": "format for importing an account" }, + "keepTrackTokens": { + "message": "Udržujte si záznamy o tokenech, které jste koupili s účtem v MetaMasku." + }, "kovan": { - "message": "Testno omrežje Kovan" + "message": "Kovan Test Network" }, "knowledgeDataBase": { - "message": "Obiščite našo pomoč" + "message": "Navštivte naši Knowledge Base" + }, + "max": { + "message": "Max" + }, + "learnMore": { + "message": "Zjistěte více." }, "lessThanMax": { - "message": "mora biti večji ali enak $1.", + "message": "musí být menší nebo roven $1.", "description": "helper for inputting hex as decimal input" }, "likeToAddTokens": { - "message": "Želite dodati te žetone?" + "message": "Chcete přidat tyto tokeny?" + }, + "links": { + "message": "Odkazy" }, "limit": { - "message": "Omejitev" + "message": "Limit" }, "loading": { - "message": "Nalaganje ..." + "message": "Načítám..." }, "loadingTokens": { - "message": "Nalaganje žetonov ..." + "message": "Načítám tokeny..." }, "localhost": { "message": "Localhost 8545" }, "login": { - "message": "Prijava" + "message": "Přihlásit" }, "logout": { - "message": "Odjava" + "message": "Odhlásit" }, "loose": { - "message": "Loose" + "message": "Nevázané" }, "loweCaseWords": { - "message": "seed words imajo lahko le male črke" + "message": "slova klíčové fráze mají pouze malá písmena" }, "mainnet": { - "message": "Glavno omrežje" + "message": "Main Ethereum Network" }, "message": { - "message": "Sporočilo" + "message": "Zpráva" }, "metamaskDescription": { - "message": "MetaMask je varen identitetni sklad za Ethereum." + "message": "MetaMask je bezpečný osobní trezor pro Ethereum." }, "min": { - "message": "Najmanj" + "message": "Minimum" }, "myAccounts": { - "message": "Moji računi" + "message": "Moje účty" }, "mustSelectOne": { - "message": "Izbran mora biti vsaj 1 žeton." + "message": "Musíte zvolit aspoň 1 token." }, "needEtherInWallet": { - "message": "Za interakcijo z decentraliziranimi aplikacijami, ki uporabljajo MetaMask, boste v svoji denarnici potrebovali eter." + "message": "Potřebujete Ether v peněžence, abyste mohli pomocí MetaMasku interagovat s decentralizovanými aplikacemi." }, "needImportFile": { - "message": "Za uvoz morate izbrati datoteko.", + "message": "Musíte zvolit soubor k importu.", "description": "User is important an account and needs to add a file to continue" }, "needImportPassword": { - "message": "Za izbrano datoteko morate vnesti geslo.", + "message": "Musíte zadat heslo pro zvolený soubor.", "description": "Password and file needed to import an account" }, "negativeETH": { - "message": "Ni mogoče poslati negativne vsote ETH." + "message": "Nelze odeslat zápornou částku ETH." }, "networks": { - "message": "Omrežja" + "message": "Sítě" }, "newAccount": { - "message": "Nov račun" + "message": "Nový účet" }, "newAccountNumberName": { - "message": "Račun $1", + "message": "Účet $1", "description": "Default name of next account to be created on create account screen" }, "newContract": { - "message": "Nova pogodba" + "message": "Nový kontrakt" }, "newPassword": { - "message": "Novo geslo (min. 8. črk)" + "message": "Nové heslo (min 8 znaků)" }, "newRecipient": { - "message": "Nov prejemnik" + "message": "Nový příjemce" }, "newRPC": { - "message": "Nov RPC URL" + "message": "Nová RPC URL" }, "next": { - "message": "Naprej" + "message": "Další" }, "noAddressForName": { - "message": "Za to ime ni bil nastavljen noben naslov." + "message": "Pro toto jméno nebyla nastavena žádná adresa." }, "noDeposits": { - "message": "Ni prejetih vplačil" + "message": "Žádný vklad" }, "noTransactionHistory": { - "message": "Ni zgodovine transakcij." + "message": "Žádná historie transakcí." }, "noTransactions": { - "message": "Ni transakcij" + "message": "Žádné transakce" }, "notStarted": { - "message": "Ni se začelo" + "message": "Nezačalo" }, "oldUI": { - "message": "Star UI" + "message": "Staré rozhraní" }, "oldUIMessage": { - "message": "Vrnili ste se v star uporabniški vmesnik. V novega se lahko vrnete z možnostjo v spustnem meniju v zgornjem desnem kotu." + "message": "Vrátili jste se ke starému rozhraní. Můžete přepnout na nové rozhraní v nastavení v pravém horním menu." }, "or": { - "message": "ali", + "message": "nebo", "description": "choice between creating or importing a new account" }, "passwordCorrect": { - "message": "Prepričajte se, da je geslo pravilno." + "message": "Ujistěte se, že je vaše heslo správně." }, "passwordMismatch": { - "message": "gesli se ne ujemata", + "message": "hesla nesouhlasí", "description": "in password creation process, the two new password fields did not match" }, "passwordShort": { - "message": "geslo ni dovolj dolgo", + "message": "heslo je krátké", "description": "in password creation process, the password is not long enough to be secure" }, "pastePrivateKey": { - "message": "Tukaj prilepite zasebni ključ:", + "message": "Vložte zde svůj privátní klíč:", "description": "For importing an account from a private key" }, "pasteSeed": { - "message": "Tukaj prilepite seed phrase!" + "message": "Svou klíčovou frázi vložte zde!" }, "personalAddressDetected": { - "message": "Osebni naslov je zaznan. Vnesite naslov žetona." + "message": "Detekována osobní adresa. Zadejte adresu kontraktu tokenu." }, "pleaseReviewTransaction": { - "message": "Preglejte transakcijo." + "message": "Zkontrolujte si transakci." + }, + "popularTokens": { + "message": "Oblíbené tokeny" }, "privacyMsg": { - "message": "Politika zasebnosti" + "message": "Zásady ochrany osobních údajů" }, "privateKey": { - "message": "Zasebni ključ", + "message": "Privátní klíč", "description": "select this type of file to use to import an account" }, "privateKeyWarning": { - "message": "Opozorilo: Nikoli ne razkrijte tega ključa. Vsakdo s svojimi zasebnimi ključi lahko ukrade vse premoženje v računu." + "message": "Upozornění: Nikdy nezveřejněte tento klíč. Kdokoli může s vaším privátním klíčem odcizit vaše aktiva z účtu." }, "privateNetwork": { - "message": "Zasebno omrežje" + "message": "Soukromá síť" }, "qrCode": { - "message": "Prikaži QR kodo" + "message": "Ukázat QR kód" }, "readdToken": { - "message": "Ta žeton lahko dodate tudi v prihodnosti, tako da odprete možnost »Dodaj žeton« v meniju z računi." + "message": "Tento token můžete v budoucnu přidat zpět s „Přidat token“ v nastavení účtu." }, "readMore": { - "message": "Preberite več." + "message": "Přečtěte si více zde." }, "readMore2": { - "message": "Preberite več." + "message": "Přečtěte si více." }, "receive": { - "message": "Prejmite" + "message": "Obrdžet" }, "recipientAddress": { - "message": "Prejemnikov naslov" + "message": "Adresa příjemce" }, "refundAddress": { - "message": "Vaš naslov za vračilo" + "message": "Adresa pro vrácení peněz" }, "rejected": { - "message": "Zavrnjeno" + "message": "Odmítnuto" }, "resetAccount": { - "message": "Ponastavi račun" + "message": "Resetovat účet" }, "restoreFromSeed": { - "message": "Obnovi iz seed phrase" + "message": "Obnovit z seed fráze" + }, + "restoreVault": { + "message": "Obnovit trezor" }, "required": { - "message": "Zahtevano" + "message": "Povinné" }, "retryWithMoreGas": { - "message": "Poskusi z višjim gas price" + "message": "Opakujte s vyšší cenou paliva" + }, + "walletSeed": { + "message": "Klíčová fráze peněženky" }, "revealSeedWords": { - "message": "Prikaži seed words" + "message": "Zobrazit slova klíčové fráze" }, "revealSeedWordsWarning": { - "message": "Ne obnovite seed words na javnem mestu! Te besede se lahko uporabijo za krajo vseh vaših računov." + "message": "Nebnovujte slova klíčové fráze na veřejnosti! Tato slova mohou být použita k odcizení veškerých vyašich účtů." }, "revert": { - "message": "Povrni" + "message": "Zvrátit" }, "rinkeby": { - "message": "Testno omrežje Rinkeby" + "message": "Rinkeby Test Network" }, "ropsten": { - "message": "Testno omrežje Ropsten" + "message": "Ropsten Test Network" + }, + "currentRpc": { + "message": "Současné RPC" + }, + "connectingToMainnet": { + "message": "Připojuji se k Main Ethereum Network" + }, + "connectingToRopsten": { + "message": "Připojuji se k Ropsten Test Network" + }, + "connectingToKovan": { + "message": "Připojuji se k Kovan Test Network" + }, + "connectingToRinkeby": { + "message": "Připojuji se k Rinkeby Test Network" + }, + "connectingToUnknown": { + "message": "Připojuji se k neznámé síti" }, "sampleAccountName": { - "message": "npr. Moj nov račun", + "message": "Např. můj nový účet", "description": "Help user understand concept of adding a human-readable name to their account" }, "save": { - "message": "Shrani" + "message": "Uložit" + }, + "reprice_title": { + "message": "Změnit cenu transakce" + }, + "reprice_subtitle": { + "message": "Navyšte cenu paliva ve snaze k přepsání a urychlení vyší transakce" }, "saveAsFile": { - "message": "Shrani kot datoteko", + "message": "Uložit do souboru", "description": "Account export process" }, "saveSeedAsFile": { - "message": "Shrani seed words kot datoteko" + "message": "Uložit slova klíčové fráze do souboru" }, "search": { - "message": "Iskanje" + "message": "Hledat" }, "secretPhrase": { - "message": "Tukaj vnesite svoje seed words, da obnovite svoje račune." + "message": "Zadejte svých 12 slov tajné fráze k obnovení trezoru." + }, + "newPassword8Chars": { + "message": "Nové heslo (min 8 znaků)" }, "seedPhraseReq": { - "message": "seed phrases so dolgi 12 besed" + "message": "klíčové fráze mají 12 slov" }, "select": { - "message": "Izberi" + "message": "Vybrat" }, "selectCurrency": { - "message": "Izberi valuto" + "message": "Vybrat měnu" }, "selectService": { - "message": "Izberi storitev" + "message": "Vybrat službu" }, "selectType": { - "message": "Izberi vrsto" + "message": "Vybrat typ" }, "send": { - "message": "Pošlji" + "message": "Odeslat" }, "sendETH": { - "message": "Pošlji ETH" + "message": "Odeslat ETH" }, "sendTokens": { - "message": "Pošlji žetone" + "message": "Odeslat tokeny" + }, + "onlySendToEtherAddress": { + "message": "Posílejte jen ETH na Ethereum adresu." + }, + "searchTokens": { + "message": "Hledat tokeny" }, "sendTokensAnywhere": { - "message": "Pošljite žetone vsem, ki imajo Ethereum račun" + "message": "Posílejte tokeny komukoli s Ethereum účtem" }, "settings": { - "message": "Nastavitve" + "message": "Nastavení" + }, + "info": { + "message": "Informace" }, "shapeshiftBuy": { - "message": "Kupite z Shapeshift" + "message": "Nakoupit na ShapeShift" }, "showPrivateKeys": { - "message": "Prikaži zasebne ključe" + "message": "Zobrazit privátní klíče" }, "showQRCode": { - "message": "Prikaži QR kodo" + "message": "Zobrazit QR kód" }, "sign": { - "message": "Podpiši" + "message": "Podepsat" + }, + "signed": { + "message": "Podepsáno" }, "signMessage": { - "message": "Podpiši sporočilo" + "message": "Podepsat zprávu" }, "signNotice": { - "message": "To podpisovanje lahko povzroči \nnevarne stranske učinke. Podpisujte samo sporočila \nstrani, ki jim zaupate s svojim celotnim računom.\n Ta nevarna funkcija bo odstranjena v prihodnji različici. " + "message": "Podepsání zprávy může mít \nnebezpečný vedlejší učinek. Podepisujte zprávy pouze ze \nstránek, kterým plně důvěřujete celým svým účtem.\n Tato nebezpečná metoda bude odebrána v budoucí verzi. " }, "sigRequest": { - "message": "Zahteva za podpis" + "message": "Požadavek podpisu" }, "sigRequested": { - "message": "Podpis je zahtevan" + "message": "Požádáno o podpis" }, "spaceBetween": { - "message": "med besedami je lahko samo presledek" + "message": "mezi slovy může být pouze mezera" }, "status": { - "message": "Status" + "message": "Stav" }, "stateLogs": { - "message": "State dnevniki" + "message": "Stavové protokoly" }, "stateLogsDescription": { - "message": "State dnevniki vsebujejo naslove vašega računa in poslane transakcije.." + "message": "Stavové protokoly obsahují vaše veřejné adresy účtů a odeslané transakce." + }, + "stateLogError": { + "message": "Chyba během získávání stavových protokolů." }, "submit": { - "message": "Potrdi" + "message": "Odeslat" + }, + "submitted": { + "message": "Odesláno" }, "supportCenter": { - "message": "Obiščite našo podporo" + "message": "Navštivte naše centrum podpory" }, "symbolBetweenZeroTen": { - "message": "Simbol mora biti dolg od 0 do 10 znakov." + "message": "Symbol musí být mezi 0 a 10 znaky." }, "takesTooLong": { - "message": "Traja predolgo?" + "message": "Trvá to dlouho?" }, "terms": { - "message": "Pogoji uporabe" + "message": "Podmínky použití" }, "testFaucet": { - "message": "Testni faucet" + "message": "Testovací faucet" }, "to": { - "message": "Za" + "message": "Komu" }, "toETHviaShapeShift": { - "message": "$1 v ETH prek ShapeShift", + "message": "$1 na ETH přes ShapeShift", "description": "system will fill in deposit type in start of message" }, "tokenAddress": { - "message": "Naslov žetona" + "message": "Adresa tokenu" }, "tokenAlreadyAdded": { - "message": "Žeton je že bil dodan." + "message": "Token byl už přidán." }, "tokenBalance": { - "message": "Vaš znesek žetona:" + "message": "Váš zůstatek tokenu je:" }, "tokenSelection": { - "message": "Poiščite žetone ali jih izberite z našega seznama priljubljenih žetonov." + "message": "Vyhledejte token nebo je vyberte z našeho seznamu oblíbených tokenů." }, "tokenSymbol": { - "message": "Simbol žetona" + "message": "Symbol tokenu" }, "tokenWarning1": { - "message": "Spremljajte žetone, ki ste jih kupili s svojim MetaMask računom. Če ste kupili žetone z drugačnim računom, ti žetoni ne bodo prikazani tukaj." + "message": "Mějte přehled o tokenech, které jste koupili s účtem MetaMasku. Pokud jste koupili tokeny s jiným účtem, tyto tokeny se zde nezobrazí." }, "total": { - "message": "Skupno" + "message": "Celkem" }, "transactions": { - "message": "transakcije" + "message": "transakce" + }, + "transactionError": { + "message": "Chyba transakce. Vyhozena výjimka v kódu kontraktu." }, "transactionMemo": { - "message": "Opis transakcije (ni zahtevano)" + "message": "Poznámka transakce (nepovinné)" }, "transactionNumber": { - "message": "Številka transakcije" + "message": "Číslo transakce" }, "transfers": { - "message": "Prenosi" + "message": "Převody" }, "troubleTokenBalances": { - "message": "Imeli smo težave pri nalaganju vaših žetonov. Ogledate si jih lahko ", + "message": "Měli jsme problém s načtením vašich tokenových zůstatků. Můžete je vidět ", "description": "Followed by a link (here) to view token balances" }, "twelveWords": { - "message": "Edini način za obnovitev MetaMask računa, je teh 12 besed.\nShranite jih na varno in skrivno mesto." + "message": "Těchto 12 slov je jedinou možností, jak obnovit MetaMask účet. \nUložte je na bezpečné a neveřejné místo." }, "typePassword": { - "message": "Vpišite vaše geslo" + "message": "Zadejte své heslo" }, "uiWelcome": { - "message": "Dobrodošli v nov UI (Beta)" + "message": "Vítejte v novém rozhraní (Beta)" }, "uiWelcomeMessage": { - "message": "Zdaj uporabljate novi MetaMask uporabniški vmesnik. Razglejte se, preizkusite nove funkcije, kot so pošiljanje žetonov, in nas obvestite, če imate kakšne težave." + "message": "Používáte nyní nové rozhraní MetaMasku. Rozhlédněte se kolem, vyzkoušejte nové funkce, jako jsou zasílání tokenů, a dejte nám vědět, pokud narazíte na problém." + }, + "unapproved": { + "message": "Neschváleno" }, "unavailable": { - "message": "Ni na voljo" + "message": "Nedostupné" }, "unknown": { - "message": "Neznano" + "message": "Neznámé" }, "unknownNetwork": { - "message": "Neznano zasebno omrežje" + "message": "Neznámá soukromá síť" }, "unknownNetworkId": { - "message": "Neznan ID omrežja" + "message": "Neznámé ID sítě" }, "uriErrorMsg": { - "message": "URI-ji zahtevajo ustrezno HTTP/HTTPS predpono." + "message": "URI vyžadují korektní HTTP/HTTPS prefix." }, "usaOnly": { - "message": "Samo za ZDA", + "message": "jen v USA", "description": "Using this exchange is limited to people inside the USA" }, "usedByClients": { - "message": "Uporablja jih več različnih odjemalcev" + "message": "Používána různými klienty" }, "useOldUI": { - "message": "Uporabi star uporabniški vmesnik" + "message": "Použijte staré rozhraní" }, "validFileImport": { - "message": "Za uvoz morate izbrati pravilno datoteko." + "message": "Musíte vybrat validní soubor k importu." }, "vaultCreated": { - "message": "Račun je ustvarjen" + "message": "Trezor vytvořen" }, "viewAccount": { - "message": "Poglej račun" + "message": "Zobrazit účet" }, "visitWebSite": { - "message": "Obiščite našo spletno stran" + "message": "Navštivte naši stránku" }, "warning": { - "message": "Opozorilo" + "message": "Varování" }, "welcomeBeta": { - "message": "Dobrodošli v MetaMask Beta" + "message": "Vítejte v MetaMask Beta" }, "whatsThis": { - "message": "Kaj je to?" + "message": "Co to je?" }, "yourSigRequested": { - "message": "Vaš podpis je bil zahtevan" + "message": "Je vyžadován váš podpis" }, "youSign": { - "message": "Podpisani ste" + "message": "Podepisujete" } -} +}
\ No newline at end of file diff --git a/app/_locales/th/messages.json b/app/_locales/th/messages.json index a9f2f1022..7fabe4eac 100644 --- a/app/_locales/th/messages.json +++ b/app/_locales/th/messages.json @@ -1,4 +1,49 @@ { + "privacyMode": { + "message": "โหมดความเป็นส่วนตัว" + }, + "privacyModeDescription": { + "message": "เว็บไซต์ต้องขอเข้าถึงเพื่อดูข้อมูลบัญชีของคุณ" + }, + "exposeAccounts": { + "message": "เปิดเผยบัญชี" + }, + "exposeDescription": { + "message": "เปิดเผยบัญชีไปยังเว็บไซต์ปัจจุบัน มีประโยชน์สำหรับ dapps แบบเดิม" + }, + "confirmExpose": { + "message": "คุณแน่ใจหรือไม่ว่าต้องการเปิดเผยบัญชีของคุณไปยังเว็บไซต์ปัจจุบัน" + }, + "confirmClear": { + "message": "คุณแน่ใจหรือไม่ว่าต้องการล้างเว็บไซต์ที่ผ่านการอนุมัติ" + }, + "clearApprovalDataSuccess": { + "message": "อนุมัติข้อมูลเว็บไซต์ที่ได้รับอนุมัติแล้ว" + }, + "approvalData": { + "message": "ข้อมูลการอนุมัติ" + }, + "approvalDataDescription": { + "message": "ล้างข้อมูลเว็บไซต์ที่ได้รับการอนุมัติเพื่อให้ทุกไซต์ต้องขออนุมัติอีกครั้ง" + }, + "clearApprovalData": { + "message": "ล้างข้อมูลการอนุมัติ" + }, + "approve": { + "message": "อนุมัติ" + }, + "reject": { + "message": "ปฏิเสธ" + }, + "providerAPIRequest": { + "message": "คำขอ Web3 API" + }, + "reviewProviderRequest": { + "message": "โปรดอ่านคำขอ Ethereum API นี้" + }, + "providerRequestInfo": { + "message": "โดเมนที่แสดงด้านล่างกำลังพยายามขอเข้าถึง API ของ Ethereum เพื่อให้สามารถโต้ตอบกับบล็อค Ethereum ได้ ตรวจสอบว่าคุณอยู่ในไซต์ที่ถูกต้องก่อนที่จะอนุมัติการเข้าถึง Ethereum เสมอ" + }, "accept": { "message": "ยอมรับ" }, diff --git a/app/_locales/tml/messages.json b/app/_locales/tml/messages.json index 8dc242c10..0643ce205 100644 --- a/app/_locales/tml/messages.json +++ b/app/_locales/tml/messages.json @@ -1,4 +1,49 @@ { + "privacyMode": { + "message": "தனியுரிமை முறை" + }, + "privacyModeDescription": { + "message": "உங்கள் கணக்குத் தகவலை பார்வையிட வலைத்தளங்கள் அணுகலைக் கோர வேண்டும்." + }, + "exposeAccounts": { + "message": "கணக்குகளை அம்பலப்படுத்துங்கள்" + }, + "exposeDescription": { + "message": "தற்போதைய இணையதளத்திற்கு கணக்குகளை அம்பலப்படுத்துங்கள். மரபணு டாப்ஸ் பயன்படுத்த." + }, + "confirmExpose": { + "message": "நிச்சயமாக உங்கள் கணக்குகளை தற்போதைய இணையத்தளத்தில் அம்பலப்படுத்த விரும்புகிறீர்களா?" + }, + "confirmClear": { + "message": "அங்கீகரிக்கப்பட்ட வலைத்தளங்களை நிச்சயமாக நீக்க விரும்புகிறீர்களா?" + }, + "clearApprovalDataSuccess": { + "message": "அங்கீகரிக்கப்பட்ட வலைத்தள தரவு வெற்றிகரமாக அழிக்கப்பட்டது." + }, + "approvalData": { + "message": "ஒப்புதல் தரவு" + }, + "approvalDataDescription": { + "message": "அங்கீகரிக்கப்பட்ட வலைத்தள தரவை அழிக்கவும், அனைத்து தளங்களும் ஒப்புதல் மீண்டும் கோர வேண்டும்." + }, + "clearApprovalData": { + "message": "ஒப்புதல் தரவை அழி" + }, + "approve": { + "message": "ஒப்புதல்" + }, + "reject": { + "message": "நிராகரி" + }, + "providerAPIRequest": { + "message": "Web3 API கோரிக்கை" + }, + "reviewProviderRequest": { + "message": "இந்த வலை 3 API கோரிக்கையை மதிப்பாய்வு செய்யவும்." + }, + "providerRequestInfo": { + "message": "கீழே பட்டியலிடப்பட்டுள்ள டொமைன் Web3 ஏபிஐ அணுகலைக் கோருவதற்கு முயற்சிக்கிறது, எனவே இது Ethereum blockchain உடன் தொடர்பு கொள்ள முடியும். Web3 அணுகுமுறையை அங்கீகரிப்பதற்கு முன் சரியான தளத்தில் இருப்பதை எப்போதும் இருமுறை சரிபார்க்கவும்." + }, "accept": { "message": "ஏற்கவும்" }, diff --git a/app/_locales/tr/messages.json b/app/_locales/tr/messages.json index 0dac139dd..1bb149eaa 100644 --- a/app/_locales/tr/messages.json +++ b/app/_locales/tr/messages.json @@ -1,4 +1,49 @@ { + "privacyMode": { + "message": "Gizlilik modu" + }, + "privacyModeDescription": { + "message": "Web siteleri, hesap bilgilerinizi görmek için erişim istemek zorundadır." + }, + "exposeAccounts": { + "message": "Hesapları Açığa Çıkar" + }, + "exposeDescription": { + "message": "Hesapları mevcut web sitesine gösterin. Eski dapps için kullanışlıdır." + }, + "confirmExpose": { + "message": "Hesaplarınızı mevcut web sitesine taşımak istediğinizden emin misiniz?" + }, + "confirmClear": { + "message": "Onaylanmış web sitelerini silmek istediğinizden emin misiniz?" + }, + "clearApprovalDataSuccess": { + "message": "Onaylanan web sitesi verileri başarıyla temizlendi." + }, + "approvalData": { + "message": "Onay Verileri" + }, + "approvalDataDescription": { + "message": "Onaylanan web sitesi verilerini temizle, tüm sitelerin tekrar onay isteğinde bulunması gerekir." + }, + "clearApprovalData": { + "message": "Onay verilerini temizle" + }, + "approve": { + "message": "Onaylamak" + }, + "reject": { + "message": "Reddetmek" + }, + "providerAPIRequest": { + "message": "Web3 API İsteği" + }, + "reviewProviderRequest": { + "message": "Lütfen bu Ethereum API isteğini inceleyin." + }, + "providerRequestInfo": { + "message": "Aşağıda listelenen etki alanı, Ethereum API'sine erişim talep etmeye çalışmaktadır, böylece Ethereum blockchain ile etkileşime girebilir. Web3 erişimini onaylamadan önce her zaman doğru sitede olduğunuzu kontrol edin." + }, "accept": { "message": "Kabul et" }, diff --git a/app/_locales/vi/messages.json b/app/_locales/vi/messages.json index 782dfd119..f0837ba98 100644 --- a/app/_locales/vi/messages.json +++ b/app/_locales/vi/messages.json @@ -1,4 +1,49 @@ { + "privacyMode": { + "message": "Chế độ riêng tư" + }, + "privacyModeDescription": { + "message": "Trang web phải yêu cầu quyền truy cập để xem thông tin tài khoản của bạn." + }, + "exposeAccounts": { + "message": "Hiển thị tài khoản" + }, + "exposeDescription": { + "message": "Hiển thị tài khoản cho trang web hiện tại. Hữu ích cho các ứng dụng cũ." + }, + "confirmExpose": { + "message": "Bạn có chắc chắn muốn hiển thị tài khoản của mình cho trang web hiện tại không?" + }, + "confirmClear": { + "message": "Bạn có chắc chắn muốn xóa các trang web được phê duyệt không?" + }, + "clearApprovalDataSuccess": { + "message": "Đã xóa thành công dữ liệu trang web được phê duyệt." + }, + "approvalData": { + "message": "Dữ liệu phê duyệt" + }, + "approvalDataDescription": { + "message": "Xóa dữ liệu trang web được phê duyệt để tất cả các trang web phải yêu cầu phê duyệt lại." + }, + "clearApprovalData": { + "message": "Xóa dữ liệu phê duyệt" + }, + "approve": { + "message": "Phê duyệt" + }, + "reject": { + "message": "Từ chối" + }, + "providerAPIRequest": { + "message": "Yêu cầu API Web3" + }, + "reviewProviderRequest": { + "message": "Vui lòng xem lại yêu cầu API Ethereum này." + }, + "providerRequestInfo": { + "message": "Miền được liệt kê bên dưới đang cố gắng yêu cầu quyền truy cập vào API Ethereum để nó có thể tương tác với chuỗi khối Ethereum. Luôn kiểm tra kỹ xem bạn có đang ở đúng trang web trước khi phê duyệt quyền truy cập Ethereum hay không." + }, "accept": { "message": "Chấp nhận" }, diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index 90ac2a55b..911ddf476 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -1,4 +1,49 @@ { + "privacyMode": { + "message": "隐私模式" + }, + "privacyModeDescription": { + "message": "网站必须请求访问权限才能查看您的帐户信息。" + }, + "exposeAccounts": { + "message": "公开账户" + }, + "exposeDescription": { + "message": "将帐户公开给当前网站。对传统dapps很有用。" + }, + "confirmExpose": { + "message": "您确定要将帐户公开到当前网站吗?" + }, + "confirmClear": { + "message": "您确定要清除已批准的网站吗?" + }, + "clearApprovalDataSuccess": { + "message": "已批准的网站数据已成功清除。" + }, + "approvalData": { + "message": "审批数据" + }, + "approvalDataDescription": { + "message": "清除已批准的网站数据,以便所有网站都必须再次申请" + }, + "clearApprovalData": { + "message": "清除批准数据" + }, + "approve": { + "message": "批准" + }, + "reject": { + "message": "拒绝" + }, + "providerAPIRequest": { + "message": "Web3 API请求" + }, + "reviewProviderRequest": { + "message": "请查看此Ethereum API请求。" + }, + "providerRequestInfo": { + "message": "下面列出的域正在尝试请求访问Ethereum API,以便它可以与以太坊区块链进行交互。在批准Ethereum访问之前,请务必仔细检查您是否在正确的站点上。" + }, "accept": { "message": "接受" }, diff --git a/app/_locales/zh_TW/messages.json b/app/_locales/zh_TW/messages.json index f71ce311f..3b048fd91 100644 --- a/app/_locales/zh_TW/messages.json +++ b/app/_locales/zh_TW/messages.json @@ -1,4 +1,49 @@ { + "privacyMode": { + "message": "隱私模式" + }, + "privacyModeDescription": { + "message": "網站必須請求訪問權限才能查看您的帳戶信息。" + }, + "exposeAccounts": { + "message": "公開賬戶" + }, + "exposeDescription": { + "message": "將帳戶公開給當前網站。對傳統dapps很有用。" + }, + "confirmExpose": { + "message": "您確定要將帳戶公開到當前網站嗎?" + }, + "confirmClear": { + "message": "您確定要清除已批准的網站嗎?" + }, + "clearApprovalDataSuccess": { + "message": "已批准的網站數據已成功清除。" + }, + "approvalData": { + "message": "審批數據" + }, + "approvalDataDescription": { + "message": "清除已批准的網站數據,以便所有網站都必須再次申請" + }, + "clearApprovalData": { + "message": "清除批准數據" + }, + "approve": { + "message": "批准" + }, + "reject": { + "message": "拒絕" + }, + "providerAPIRequest": { + "message": "Web3 API請求" + }, + "reviewProviderRequest": { + "message": "請查看此Ethereum API請求。" + }, + "providerRequestInfo": { + "message": "下面列出的域正在嘗試請求訪問Ethereum API,以便它可以與以太坊區塊鏈進行交互。在批准Ethereum訪問之前,請務必仔細檢查您是否在正確的站點上。" + }, "accept": { "message": "接受" }, diff --git a/app/images/mm-secure.svg b/app/images/mm-secure.svg new file mode 100644 index 000000000..1345b75b2 --- /dev/null +++ b/app/images/mm-secure.svg @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg width="78" height="22" viewBox="0 0 78 22" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path d="M29.5488 2.89062L31.375 8.04688L33.1914 2.89062H35.1152V10H33.6455V8.05664L33.792 4.70215L31.873 10H30.8672L28.9531 4.70703L29.0996 8.05664V10H27.6348V2.89062H29.5488ZM38.7334 10.0977C37.9587 10.0977 37.3271 9.86003 36.8389 9.38477C36.3538 8.90951 36.1113 8.27637 36.1113 7.48535V7.34863C36.1113 6.81803 36.2139 6.3444 36.4189 5.92773C36.624 5.50781 36.9137 5.18555 37.2881 4.96094C37.6657 4.73307 38.0954 4.61914 38.5771 4.61914C39.2998 4.61914 39.8678 4.84701 40.2812 5.30273C40.6979 5.75846 40.9062 6.40462 40.9062 7.24121V7.81738H37.542C37.5876 8.16243 37.7243 8.43913 37.9521 8.64746C38.1833 8.85579 38.4746 8.95996 38.8262 8.95996C39.3698 8.95996 39.7946 8.76302 40.1006 8.36914L40.7939 9.14551C40.5824 9.44499 40.2959 9.67936 39.9346 9.84863C39.5732 10.0146 39.1729 10.0977 38.7334 10.0977ZM38.5723 5.76172C38.2923 5.76172 38.0645 5.85612 37.8887 6.04492C37.7161 6.23372 37.6055 6.50391 37.5566 6.85547H39.5195V6.74316C39.513 6.43066 39.4284 6.18978 39.2656 6.02051C39.1029 5.84798 38.8717 5.76172 38.5723 5.76172ZM43.4014 3.41797V4.7168H44.3047V5.75195H43.4014V8.38867C43.4014 8.58398 43.4388 8.72396 43.5137 8.80859C43.5885 8.89323 43.7318 8.93555 43.9434 8.93555C44.0996 8.93555 44.238 8.92415 44.3584 8.90137V9.9707C44.0817 10.0553 43.7969 10.0977 43.5039 10.0977C42.5143 10.0977 42.0098 9.59798 41.9902 8.59863V5.75195H41.2188V4.7168H41.9902V3.41797H43.4014ZM48.1523 10C48.0872 9.87305 48.04 9.71517 48.0107 9.52637C47.6689 9.90723 47.2246 10.0977 46.6777 10.0977C46.1602 10.0977 45.7305 9.94792 45.3887 9.64844C45.0501 9.34896 44.8809 8.97135 44.8809 8.51562C44.8809 7.95573 45.0876 7.52604 45.501 7.22656C45.9176 6.92708 46.5182 6.77572 47.3027 6.77246H47.9521V6.46973C47.9521 6.22559 47.8887 6.03027 47.7617 5.88379C47.638 5.7373 47.4411 5.66406 47.1709 5.66406C46.9333 5.66406 46.7461 5.72103 46.6094 5.83496C46.4759 5.94889 46.4092 6.10514 46.4092 6.30371H44.998C44.998 5.99772 45.0924 5.71452 45.2812 5.4541C45.4701 5.19368 45.737 4.99023 46.082 4.84375C46.4271 4.69401 46.8145 4.61914 47.2441 4.61914C47.8952 4.61914 48.4111 4.78353 48.792 5.1123C49.1761 5.43783 49.3682 5.89681 49.3682 6.48926V8.7793C49.3714 9.2806 49.4414 9.65983 49.5781 9.91699V10H48.1523ZM46.9854 9.01855C47.1937 9.01855 47.3857 8.97298 47.5615 8.88184C47.7373 8.78743 47.8675 8.66211 47.9521 8.50586V7.59766H47.4248C46.7184 7.59766 46.3424 7.8418 46.2969 8.33008L46.292 8.41309C46.292 8.58887 46.3538 8.73372 46.4775 8.84766C46.6012 8.96159 46.7705 9.01855 46.9854 9.01855ZM52.459 2.89062L54.2852 8.04688L56.1016 2.89062H58.0254V10H56.5557V8.05664L56.7021 4.70215L54.7832 10H53.7773L51.8633 4.70703L52.0098 8.05664V10H50.5449V2.89062H52.459ZM62.2734 10C62.2083 9.87305 62.1611 9.71517 62.1318 9.52637C61.79 9.90723 61.3457 10.0977 60.7988 10.0977C60.2812 10.0977 59.8516 9.94792 59.5098 9.64844C59.1712 9.34896 59.002 8.97135 59.002 8.51562C59.002 7.95573 59.2087 7.52604 59.6221 7.22656C60.0387 6.92708 60.6393 6.77572 61.4238 6.77246H62.0732V6.46973C62.0732 6.22559 62.0098 6.03027 61.8828 5.88379C61.7591 5.7373 61.5622 5.66406 61.292 5.66406C61.0544 5.66406 60.8672 5.72103 60.7305 5.83496C60.597 5.94889 60.5303 6.10514 60.5303 6.30371H59.1191C59.1191 5.99772 59.2135 5.71452 59.4023 5.4541C59.5911 5.19368 59.8581 4.99023 60.2031 4.84375C60.5482 4.69401 60.9355 4.61914 61.3652 4.61914C62.0163 4.61914 62.5322 4.78353 62.9131 5.1123C63.2972 5.43783 63.4893 5.89681 63.4893 6.48926V8.7793C63.4925 9.2806 63.5625 9.65983 63.6992 9.91699V10H62.2734ZM61.1064 9.01855C61.3148 9.01855 61.5068 8.97298 61.6826 8.88184C61.8584 8.78743 61.9886 8.66211 62.0732 8.50586V7.59766H61.5459C60.8395 7.59766 60.4635 7.8418 60.418 8.33008L60.4131 8.41309C60.4131 8.58887 60.4749 8.73372 60.5986 8.84766C60.7223 8.96159 60.8916 9.01855 61.1064 9.01855ZM67.4346 8.54004C67.4346 8.36751 67.3483 8.23242 67.1758 8.13477C67.0065 8.03385 66.7331 7.94434 66.3555 7.86621C65.099 7.60254 64.4707 7.06868 64.4707 6.26465C64.4707 5.7959 64.6644 5.40527 65.0518 5.09277C65.4424 4.77702 65.9518 4.61914 66.5801 4.61914C67.2507 4.61914 67.7861 4.77702 68.1865 5.09277C68.5902 5.40853 68.792 5.81868 68.792 6.32324H67.3809C67.3809 6.12142 67.3158 5.9554 67.1855 5.8252C67.0553 5.69173 66.8519 5.625 66.5752 5.625C66.3376 5.625 66.1536 5.67871 66.0234 5.78613C65.8932 5.89355 65.8281 6.03027 65.8281 6.19629C65.8281 6.35254 65.9014 6.47949 66.0479 6.57715C66.1976 6.67155 66.4482 6.75456 66.7998 6.82617C67.1514 6.89453 67.4476 6.97266 67.6885 7.06055C68.4339 7.33398 68.8066 7.80762 68.8066 8.48145C68.8066 8.96322 68.5999 9.35384 68.1865 9.65332C67.7731 9.94954 67.2393 10.0977 66.585 10.0977C66.1423 10.0977 65.7484 10.0195 65.4033 9.86328C65.0615 9.70378 64.793 9.4873 64.5977 9.21387C64.4023 8.93717 64.3047 8.63932 64.3047 8.32031H65.6426C65.6556 8.57096 65.7484 8.76302 65.9209 8.89648C66.0934 9.02995 66.3245 9.09668 66.6143 9.09668C66.8844 9.09668 67.0879 9.04622 67.2246 8.94531C67.3646 8.84115 67.4346 8.70605 67.4346 8.54004ZM71.6387 7.88086L71.1309 8.38867V10H69.7197V2.5H71.1309V6.65527L71.4043 6.30371L72.7568 4.7168H74.4512L72.542 6.91895L74.6172 10H72.9961L71.6387 7.88086ZM31.3213 18.1348C31.3213 17.8581 31.2236 17.6465 31.0283 17.5C30.833 17.3503 30.4814 17.194 29.9736 17.0312C29.4658 16.8652 29.0638 16.7025 28.7676 16.543C27.9603 16.1068 27.5566 15.5192 27.5566 14.7803C27.5566 14.3962 27.6641 14.0544 27.8789 13.7549C28.097 13.4521 28.4079 13.2161 28.8115 13.0469C29.2184 12.8776 29.6742 12.793 30.1787 12.793C30.6865 12.793 31.139 12.8857 31.5361 13.0713C31.9333 13.2536 32.2409 13.5124 32.459 13.8477C32.6803 14.1829 32.791 14.5638 32.791 14.9902H31.3262C31.3262 14.6647 31.2236 14.4124 31.0186 14.2334C30.8135 14.0511 30.5254 13.96 30.1543 13.96C29.7962 13.96 29.5179 14.0365 29.3193 14.1895C29.1208 14.3392 29.0215 14.5378 29.0215 14.7852C29.0215 15.0163 29.137 15.21 29.3682 15.3662C29.6025 15.5225 29.946 15.6689 30.3984 15.8057C31.2318 16.0563 31.8389 16.3672 32.2197 16.7383C32.6006 17.1094 32.791 17.5716 32.791 18.125C32.791 18.7402 32.5583 19.2236 32.0928 19.5752C31.6273 19.9235 31.0007 20.0977 30.2129 20.0977C29.666 20.0977 29.168 19.9984 28.7188 19.7998C28.2695 19.598 27.9261 19.3229 27.6885 18.9746C27.4541 18.6263 27.3369 18.2227 27.3369 17.7637H28.8066C28.8066 18.5482 29.2754 18.9404 30.2129 18.9404C30.5612 18.9404 30.833 18.8704 31.0283 18.7305C31.2236 18.5872 31.3213 18.3887 31.3213 18.1348ZM36.126 20.0977C35.3512 20.0977 34.7197 19.86 34.2314 19.3848C33.7464 18.9095 33.5039 18.2764 33.5039 17.4854V17.3486C33.5039 16.818 33.6064 16.3444 33.8115 15.9277C34.0166 15.5078 34.3063 15.1855 34.6807 14.9609C35.0583 14.7331 35.488 14.6191 35.9697 14.6191C36.6924 14.6191 37.2604 14.847 37.6738 15.3027C38.0905 15.7585 38.2988 16.4046 38.2988 17.2412V17.8174H34.9346C34.9801 18.1624 35.1169 18.4391 35.3447 18.6475C35.5758 18.8558 35.8672 18.96 36.2188 18.96C36.7624 18.96 37.1872 18.763 37.4932 18.3691L38.1865 19.1455C37.9749 19.445 37.6885 19.6794 37.3271 19.8486C36.9658 20.0146 36.5654 20.0977 36.126 20.0977ZM35.9648 15.7617C35.6849 15.7617 35.457 15.8561 35.2812 16.0449C35.1087 16.2337 34.998 16.5039 34.9492 16.8555H36.9121V16.7432C36.9056 16.4307 36.821 16.1898 36.6582 16.0205C36.4954 15.848 36.2643 15.7617 35.9648 15.7617ZM41.3018 18.96C41.5622 18.96 41.7738 18.8883 41.9365 18.7451C42.0993 18.6019 42.1839 18.4115 42.1904 18.1738H43.5137C43.5104 18.5319 43.4128 18.8607 43.2207 19.1602C43.0286 19.4564 42.765 19.6875 42.4297 19.8535C42.0977 20.0163 41.7298 20.0977 41.3262 20.0977C40.571 20.0977 39.9753 19.8584 39.5391 19.3799C39.1029 18.8981 38.8848 18.234 38.8848 17.3877V17.2949C38.8848 16.4811 39.1012 15.8317 39.5342 15.3467C39.9671 14.8617 40.5612 14.6191 41.3164 14.6191C41.9772 14.6191 42.5062 14.8079 42.9033 15.1855C43.3037 15.5599 43.5072 16.0596 43.5137 16.6846H42.1904C42.1839 16.4111 42.0993 16.1898 41.9365 16.0205C41.7738 15.848 41.5589 15.7617 41.292 15.7617C40.9632 15.7617 40.7142 15.8822 40.5449 16.123C40.3789 16.3607 40.2959 16.748 40.2959 17.2852V17.4316C40.2959 17.9753 40.3789 18.3659 40.5449 18.6035C40.7109 18.8411 40.9632 18.96 41.3018 18.96ZM47.4834 19.4629C47.1351 19.8861 46.6533 20.0977 46.0381 20.0977C45.4717 20.0977 45.0387 19.9349 44.7393 19.6094C44.443 19.2839 44.2917 18.807 44.2852 18.1787V14.7168H45.6963V18.1299C45.6963 18.68 45.9469 18.9551 46.4482 18.9551C46.9268 18.9551 47.2555 18.7891 47.4346 18.457V14.7168H48.8506V20H47.5225L47.4834 19.4629ZM52.8838 16.04C52.6917 16.014 52.5225 16.001 52.376 16.001C51.8421 16.001 51.4922 16.1816 51.3262 16.543V20H49.915V14.7168H51.248L51.2871 15.3467C51.5703 14.8617 51.9626 14.6191 52.4639 14.6191C52.6201 14.6191 52.7666 14.6403 52.9033 14.6826L52.8838 16.04ZM55.9014 20.0977C55.1266 20.0977 54.4951 19.86 54.0068 19.3848C53.5218 18.9095 53.2793 18.2764 53.2793 17.4854V17.3486C53.2793 16.818 53.3818 16.3444 53.5869 15.9277C53.792 15.5078 54.0817 15.1855 54.4561 14.9609C54.8337 14.7331 55.2633 14.6191 55.7451 14.6191C56.4678 14.6191 57.0358 14.847 57.4492 15.3027C57.8659 15.7585 58.0742 16.4046 58.0742 17.2412V17.8174H54.71C54.7555 18.1624 54.8923 18.4391 55.1201 18.6475C55.3512 18.8558 55.6426 18.96 55.9941 18.96C56.5378 18.96 56.9626 18.763 57.2686 18.3691L57.9619 19.1455C57.7503 19.445 57.4639 19.6794 57.1025 19.8486C56.7412 20.0146 56.3408 20.0977 55.9014 20.0977ZM55.7402 15.7617C55.4603 15.7617 55.2324 15.8561 55.0566 16.0449C54.8841 16.2337 54.7734 16.5039 54.7246 16.8555H56.6875V16.7432C56.681 16.4307 56.5964 16.1898 56.4336 16.0205C56.2708 15.848 56.0397 15.7617 55.7402 15.7617Z" fill="#A2A4AC"/> + <path fill-rule="evenodd" clip-rule="evenodd" d="M0 2.65498L0 8.69867C0 14.9252 4.19995 20.1981 10 22C15.7999 20.1981 20 14.9252 20 8.69867L20 2.65498L10 0L0 2.65498Z" fill="#A2A4AC"/> + <path fill-rule="evenodd" clip-rule="evenodd" d="M8.47027 11.6L7.38462 12.093L8.92308 12.5429L8.47027 11.6ZM11.2204 11.6L10.7692 12.5429L12.3077 12.093L11.2204 11.6ZM10.4442 13.8H9.24372L9.0357 13.9633L8.92308 15.0571L9.02705 14.9484H10.6609L10.7692 15.0571L10.6522 13.9633L10.4442 13.8ZM15.6234 9.86253L15.388 9.69497L15.7646 9.35535L15.4774 9.13192L15.8541 8.84816L15.6046 8.66202L16 6.76348L15.4068 5L11.5888 6.40985L8.41115 6.40985L4.59313 5L4 6.76348L4.40012 8.66202L4.1459 8.84816L4.52253 9.13192L4.23536 9.35535L4.612 9.69497L4.37656 9.86253L4.91795 10.4907L4.09886 13.0127L4.85682 15.5859L7.52607 14.86L8.04391 15.2788L9.09844 16H10.9015L11.9561 15.2788L12.4739 14.86L15.1432 15.5859L15.9058 13.0127L15.082 10.4907L15.6234 9.86253Z" fill="white"/> +</svg> diff --git a/app/images/provider-approval-check.svg b/app/images/provider-approval-check.svg new file mode 100644 index 000000000..c3df71f59 --- /dev/null +++ b/app/images/provider-approval-check.svg @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g filter="url(#filter0_d)"> +<path d="M34.5 19C34.5 27.0081 28.0081 33.5 20 33.5C11.9919 33.5 5.5 27.0081 5.5 19C5.5 10.9919 11.9919 4.5 20 4.5C28.0081 4.5 34.5 10.9919 34.5 19Z" fill="#61BA00" stroke="#61BA00"/> +<path d="M13.2998 19.7195L16.813 23.3195L26.1998 14.0195" stroke="white" stroke-width="2"/> +</g> +<defs> +<filter id="filter0_d" x="0" y="0" width="40" height="40" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> +<feFlood flood-opacity="0" result="BackgroundImageFix"/> +<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/> +<feOffset dy="1"/> +<feGaussianBlur stdDeviation="2.5"/> +<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/> +<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/> +<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/> +</filter> +</defs> +</svg> + diff --git a/app/loading.html b/app/loading.html index aef5d9607..71403a5ac 100644 --- a/app/loading.html +++ b/app/loading.html @@ -1,5 +1,9 @@ -<html> +<!DOCTYPE html> +<html lang="en"> <head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>MetaMask Loading</title> <style> #div-logo { @@ -31,5 +35,11 @@ <div id="div-logo"> <img id="logo" src="./images/loginglogo.svg"> </div> + <script type="text/javascript"> + // redirect to 404 after one minute + setTimeout(() => { + location.href = './404.html' + }, 60000) + </script> </body> </html> diff --git a/app/manifest.json b/app/manifest.json index be1b08c07..a72d474b1 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "__MSG_appName__", "short_name": "__MSG_appName__", - "version": "4.16.0", + "version": "5.0.0", "manifest_version": 2, "author": "https://metamask.io", "description": "__MSG_appDescription__", diff --git a/app/scripts/background.js b/app/scripts/background.js index d20ffe6e3..2dcb79bef 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -23,13 +23,13 @@ const createStreamSink = require('./lib/createStreamSink') const NotificationManager = require('./lib/notification-manager.js') const MetamaskController = require('./metamask-controller') const rawFirstTimeState = require('./first-time-state') -const setupRaven = require('./lib/setupRaven') +const setupSentry = require('./lib/setupSentry') const reportFailedTxToSentry = require('./lib/reportFailedTxToSentry') const setupMetamaskMeshMetrics = require('./lib/setupMetamaskMeshMetrics') const EdgeEncryptor = require('./edge-encryptor') const getFirstPreferredLangCode = require('./lib/get-first-preferred-lang-code') const getObjStructure = require('./lib/getObjStructure') -const ipfsContent = require('./lib/ipfsContent.js') +const setupEnsIpfsResolver = require('./lib/ens-ipfs/setup') const { ENVIRONMENT_TYPE_POPUP, @@ -50,7 +50,7 @@ global.METAMASK_NOTIFIER = notificationManager // setup sentry error reporting const release = platform.getVersion() -const raven = setupRaven({ release }) +const sentry = setupSentry({ release }) // browser check if it is Edge - https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser // Internet Explorer 6-11 @@ -58,7 +58,6 @@ const isIE = !!document.documentMode // Edge 20+ const isEdge = !isIE && !!window.StyleMedia -let ipfsHandle let popupIsOpen = false let notificationIsOpen = false const openMetamaskTabsIDs = {} @@ -164,7 +163,6 @@ async function initialize () { const initLangCode = await getFirstPreferredLangCode() await setupController(initState, initLangCode) log.debug('MetaMask initialization complete.') - ipfsHandle = ipfsContent(initState.NetworkController.provider) } // @@ -197,14 +195,14 @@ async function loadStateFromPersistence () { // we were able to recover (though it might be old) versionedData = diskStoreState const vaultStructure = getObjStructure(versionedData) - raven.captureMessage('MetaMask - Empty vault found - recovered from diskStore', { + sentry.captureMessage('MetaMask - Empty vault found - recovered from diskStore', { // "extra" key is required by Sentry extra: { vaultStructure }, }) } else { // unable to recover, clear state versionedData = migrator.generateInitialState(firstTimeState) - raven.captureMessage('MetaMask - Empty vault found - unable to recover') + sentry.captureMessage('MetaMask - Empty vault found - unable to recover') } } @@ -212,7 +210,7 @@ async function loadStateFromPersistence () { migrator.on('error', (err) => { // get vault structure without secrets const vaultStructure = getObjStructure(versionedData) - raven.captureException(err, { + sentry.captureException(err, { // "extra" key is required by Sentry extra: { vaultStructure }, }) @@ -258,7 +256,8 @@ function setupController (initState, initLangCode) { showUnconfirmedMessage: triggerUi, unlockAccountMessage: triggerUi, showUnapprovedTx: triggerUi, - showWatchAssetUi: showWatchAssetUi, + openPopup: openPopup, + closePopup: notificationManager.closePopup.bind(notificationManager), // initial state initState, // initial locale code @@ -269,17 +268,15 @@ function setupController (initState, initLangCode) { }) global.metamaskController = controller - controller.networkController.on('networkDidChange', () => { - ipfsHandle && ipfsHandle.remove() - ipfsHandle = ipfsContent(controller.networkController.providerStore.getState()) - }) + const provider = controller.provider + setupEnsIpfsResolver({ provider }) // report failed transactions to Sentry controller.txController.on(`tx:status-update`, (txId, status) => { if (status !== 'failed') return const txMeta = controller.txController.txStateManager.getTx(txId) try { - reportFailedTxToSentry({ raven, txMeta }) + reportFailedTxToSentry({ sentry, txMeta }) } catch (e) { console.error(e) } @@ -459,7 +456,7 @@ function triggerUi () { * Opens the browser popup for user confirmation of watchAsset * then it waits until user interact with the UI */ -function showWatchAssetUi () { +function openPopup () { triggerUi() return new Promise( (resolve) => { diff --git a/app/scripts/contentscript.js b/app/scripts/contentscript.js index 33523eb46..1a10cdb34 100644 --- a/app/scripts/contentscript.js +++ b/app/scripts/contentscript.js @@ -7,10 +7,12 @@ const PongStream = require('ping-pong-stream/pong') const ObjectMultiplex = require('obj-multiplex') const extension = require('extensionizer') const PortStream = require('extension-port-stream') +const TransformStream = require('stream').Transform const inpageContent = fs.readFileSync(path.join(__dirname, '..', '..', 'dist', 'chrome', 'inpage.js')).toString() const inpageSuffix = '//# sourceURL=' + extension.extension.getURL('inpage.js') + '\n' const inpageBundle = inpageContent + inpageSuffix +let isEnabled = false // Eventually this streaming injection could be replaced with: // https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Language_Bindings/Components.utils.exportFunction @@ -20,24 +22,27 @@ const inpageBundle = inpageContent + inpageSuffix // MetaMask will be much faster loading and performant on Firefox. if (shouldInjectWeb3()) { - setupInjection() + injectScript(inpageBundle) setupStreams() + listenForProviderRequest() + checkPrivacyMode() } /** - * Creates a script tag that injects inpage.js + * Injects a script tag into the current document + * + * @param {string} content - Code to be executed in the current document */ -function setupInjection () { +function injectScript (content) { try { - // inject in-page script - var scriptTag = document.createElement('script') - scriptTag.textContent = inpageBundle - scriptTag.onload = function () { this.parentNode.removeChild(this) } - var container = document.head || document.documentElement - // append as first child + const container = document.head || document.documentElement + const scriptTag = document.createElement('script') + scriptTag.setAttribute('async', false) + scriptTag.textContent = content container.insertBefore(scriptTag, container.children[0]) + container.removeChild(scriptTag) } catch (e) { - console.error('Metamask injection failed.', e) + console.error('MetaMask script injection failed', e) } } @@ -54,10 +59,22 @@ function setupStreams () { const pluginPort = extension.runtime.connect({ name: 'contentscript' }) const pluginStream = new PortStream(pluginPort) + // Filter out selectedAddress until this origin is enabled + const approvalTransform = new TransformStream({ + objectMode: true, + transform: (data, _, done) => { + if (typeof data === 'object' && data.name && data.name === 'publicConfig' && !isEnabled) { + data.data.selectedAddress = undefined + } + done(null, { ...data }) + }, + }) + // forward communication plugin->inpage pump( pageStream, pluginStream, + approvalTransform, pageStream, (err) => logStreamDisconnectWarning('MetaMask Contentscript Forwarding', err) ) @@ -97,6 +114,69 @@ function setupStreams () { mux.ignoreStream('publicConfig') } +/** + * Establishes listeners for requests to fully-enable the provider from the dapp context + * and for full-provider approvals and rejections from the background script context. Dapps + * should not post messages directly and should instead call provider.enable(), which + * handles posting these messages internally. + */ +function listenForProviderRequest () { + window.addEventListener('message', ({ source, data }) => { + if (source !== window || !data || !data.type) { return } + switch (data.type) { + case 'ETHEREUM_ENABLE_PROVIDER': + extension.runtime.sendMessage({ + action: 'init-provider-request', + force: data.force, + origin: source.location.hostname, + siteImage: getSiteIcon(source), + siteTitle: getSiteName(source), + }) + break + case 'ETHEREUM_IS_APPROVED': + extension.runtime.sendMessage({ + action: 'init-is-approved', + origin: source.location.hostname, + }) + break + case 'METAMASK_IS_UNLOCKED': + extension.runtime.sendMessage({ + action: 'init-is-unlocked', + }) + break + } + }) + + extension.runtime.onMessage.addListener(({ action = '', isApproved, caching, isUnlocked }) => { + switch (action) { + case 'approve-provider-request': + isEnabled = true + injectScript(`window.dispatchEvent(new CustomEvent('ethereumprovider', { detail: {}}))`) + break + case 'reject-provider-request': + injectScript(`window.dispatchEvent(new CustomEvent('ethereumprovider', { detail: { error: 'User rejected provider access' }}))`) + break + case 'answer-is-approved': + injectScript(`window.dispatchEvent(new CustomEvent('ethereumisapproved', { detail: { isApproved: ${isApproved}, caching: ${caching}}}))`) + break + case 'answer-is-unlocked': + injectScript(`window.dispatchEvent(new CustomEvent('metamaskisunlocked', { detail: { isUnlocked: ${isUnlocked}}}))`) + break + case 'metamask-set-locked': + isEnabled = false + injectScript(`window.dispatchEvent(new CustomEvent('metamasksetlocked', { detail: {}}))`) + break + } + }) +} + +/** + * Checks if MetaMask is currently operating in "privacy mode", meaning + * dapps must call ethereum.enable in order to access user accounts + */ +function checkPrivacyMode () { + extension.runtime.sendMessage({ action: 'init-privacy-request' }) +} /** * Error handler for page to plugin stream disconnections @@ -210,3 +290,31 @@ function redirectToPhishingWarning () { href: window.location.href, })}` } + +function getSiteName (window) { + const document = window.document + const siteName = document.querySelector('head > meta[property="og:site_name"]') + if (siteName) { + return siteName.content + } + + return document.title +} + +function getSiteIcon (window) { + const document = window.document + + // Use the site's favicon if it exists + const shortcutIcon = document.querySelector('head > link[rel="shortcut icon"]') + if (shortcutIcon) { + return shortcutIcon.href + } + + // Search through available icons in no particular order + const icon = Array.from(document.querySelectorAll('head > link[rel="icon"]')).find((icon) => Boolean(icon.href)) + if (icon) { + return icon.href + } + + return null +} diff --git a/app/scripts/controllers/blacklist.js b/app/scripts/controllers/blacklist.js index 89c7cc888..e55b09d03 100644 --- a/app/scripts/controllers/blacklist.js +++ b/app/scripts/controllers/blacklist.js @@ -83,8 +83,25 @@ class BlacklistController { * */ async updatePhishingList () { - const response = await fetch('https://api.infura.io/v2/blacklist') - const phishing = await response.json() + // make request + let response + try { + response = await fetch('https://api.infura.io/v2/blacklist') + } catch (err) { + log.error(new Error(`BlacklistController - failed to fetch blacklist:\n${err.stack}`)) + return + } + // parse response + let rawResponse + let phishing + try { + const rawResponse = await response.text() + phishing = JSON.parse(rawResponse) + } catch (err) { + log.error(new Error(`BlacklistController - failed to parse blacklist:\n${rawResponse}`)) + return + } + // update current blacklist this.store.updateState({ phishing }) this._setupPhishingDetector(phishing) return phishing @@ -97,9 +114,9 @@ class BlacklistController { */ scheduleUpdates () { if (this._phishingUpdateIntervalRef) return - this.updatePhishingList().catch(log.warn) + this.updatePhishingList() this._phishingUpdateIntervalRef = setInterval(() => { - this.updatePhishingList().catch(log.warn) + this.updatePhishingList() }, POLLING_INTERVAL) } diff --git a/app/scripts/controllers/currency.js b/app/scripts/controllers/currency.js index d5bc5fe2b..fce65fd9c 100644 --- a/app/scripts/controllers/currency.js +++ b/app/scripts/controllers/currency.js @@ -21,6 +21,7 @@ class CurrencyController { * since midnight of January 1, 1970 * @property {number} conversionInterval The id of the interval created by the scheduleConversionInterval method. * Used to clear an existing interval on subsequent calls of that method. + * @property {string} nativeCurrency The ticker/symbol of the native chain currency * */ constructor (opts = {}) { @@ -28,6 +29,7 @@ class CurrencyController { currentCurrency: 'usd', conversionRate: 0, conversionDate: 'N/A', + nativeCurrency: 'ETH', }, opts.initState) this.store = new ObservableStore(initState) } @@ -37,6 +39,29 @@ class CurrencyController { // /** + * A getter for the nativeCurrency property + * + * @returns {string} A 2-4 character shorthand that describes the specific currency + * + */ + getNativeCurrency () { + return this.store.getState().nativeCurrency + } + + /** + * A setter for the nativeCurrency property + * + * @param {string} nativeCurrency The new currency to set as the nativeCurrency in the store + * + */ + setNativeCurrency (nativeCurrency) { + this.store.updateState({ + nativeCurrency, + ticker: nativeCurrency, + }) + } + + /** * A getter for the currentCurrency property * * @returns {string} A 2-4 character shorthand that describes a specific currency, currently selected by the user @@ -104,17 +129,60 @@ class CurrencyController { * */ async updateConversionRate () { - let currentCurrency + let currentCurrency, nativeCurrency try { currentCurrency = this.getCurrentCurrency() - const response = await fetch(`https://api.infura.io/v1/ticker/eth${currentCurrency.toLowerCase()}`) - const parsedResponse = await response.json() - this.setConversionRate(Number(parsedResponse.bid)) - this.setConversionDate(Number(parsedResponse.timestamp)) + nativeCurrency = this.getNativeCurrency() + // select api + let apiUrl + if (nativeCurrency === 'ETH') { + // ETH + apiUrl = `https://api.infura.io/v1/ticker/eth${currentCurrency.toLowerCase()}` + } else { + // ETC + apiUrl = `https://min-api.cryptocompare.com/data/price?fsym=${nativeCurrency.toUpperCase()}&tsyms=${currentCurrency.toUpperCase()}` + } + // attempt request + let response + try { + response = await fetch(apiUrl) + } catch (err) { + log.error(new Error(`CurrencyController - Failed to request currency from Infura:\n${err.stack}`)) + return + } + // parse response + let rawResponse + let parsedResponse + try { + rawResponse = await response.text() + parsedResponse = JSON.parse(rawResponse) + } catch (err) { + log.error(new Error(`CurrencyController - Failed to parse response "${rawResponse}"`)) + return + } + // set conversion rate + if (nativeCurrency === 'ETH') { + // ETH + this.setConversionRate(Number(parsedResponse.bid)) + this.setConversionDate(Number(parsedResponse.timestamp)) + } else { + // ETC + if (parsedResponse[currentCurrency.toUpperCase()]) { + this.setConversionRate(Number(parsedResponse[currentCurrency.toUpperCase()])) + this.setConversionDate(parseInt((new Date()).getTime() / 1000)) + } else { + this.setConversionRate(0) + this.setConversionDate('N/A') + } + } } catch (err) { - log.warn(`MetaMask - Failed to query currency conversion:`, currentCurrency, err) + // reset current conversion rate + log.warn(`MetaMask - Failed to query currency conversion:`, nativeCurrency, currentCurrency, err) this.setConversionRate(0) this.setConversionDate('N/A') + // throw error + log.error(new Error(`CurrencyController - Failed to query rate for currency "${currentCurrency}":\n${err.stack}`)) + return } } diff --git a/app/scripts/controllers/network/createInfuraClient.js b/app/scripts/controllers/network/createInfuraClient.js index 326bcb355..c70fa9e38 100644 --- a/app/scripts/controllers/network/createInfuraClient.js +++ b/app/scripts/controllers/network/createInfuraClient.js @@ -1,4 +1,5 @@ const mergeMiddleware = require('json-rpc-engine/src/mergeMiddleware') +const createScaffoldMiddleware = require('json-rpc-engine/src/createScaffoldMiddleware') const createBlockReRefMiddleware = require('eth-json-rpc-middleware/block-ref') const createRetryOnEmptyMiddleware = require('eth-json-rpc-middleware/retryOnEmpty') const createBlockCacheMiddleware = require('eth-json-rpc-middleware/block-cache') @@ -16,6 +17,7 @@ function createInfuraClient ({ network }) { const blockTracker = new BlockTracker({ provider: infuraProvider }) const networkMiddleware = mergeMiddleware([ + createNetworkAndChainIdMiddleware({ network }), createBlockCacheMiddleware({ blockTracker }), createInflightMiddleware(), createBlockReRefMiddleware({ blockTracker, provider: infuraProvider }), @@ -25,3 +27,34 @@ function createInfuraClient ({ network }) { ]) return { networkMiddleware, blockTracker } } + +function createNetworkAndChainIdMiddleware({ network }) { + let chainId + let netId + + switch (network) { + case 'mainnet': + netId = '1' + chainId = '0x01' + break + case 'ropsten': + netId = '3' + chainId = '0x03' + break + case 'rinkeby': + netId = '4' + chainId = '0x04' + break + case 'kovan': + netId = '42' + chainId = '0x2a' + break + default: + throw new Error(`createInfuraClient - unknown network "${network}"`) + } + + return createScaffoldMiddleware({ + eth_chainId: chainId, + net_version: netId, + }) +} diff --git a/app/scripts/controllers/network/createMetamaskMiddleware.js b/app/scripts/controllers/network/createMetamaskMiddleware.js index 9e6a45888..319c5bf3e 100644 --- a/app/scripts/controllers/network/createMetamaskMiddleware.js +++ b/app/scripts/controllers/network/createMetamaskMiddleware.js @@ -11,6 +11,7 @@ function createMetamaskMiddleware ({ processTransaction, processEthSignMessage, processTypedMessage, + processTypedMessageV3, processPersonalMessage, getPendingNonce, }) { @@ -25,6 +26,7 @@ function createMetamaskMiddleware ({ processTransaction, processEthSignMessage, processTypedMessage, + processTypedMessageV3, processPersonalMessage, }), createPendingNonceMiddleware({ getPendingNonce }), diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index c1667d9a6..b459b8013 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -11,6 +11,8 @@ const createInfuraClient = require('./createInfuraClient') const createJsonRpcClient = require('./createJsonRpcClient') const createLocalhostClient = require('./createLocalhostClient') const { createSwappableProxy, createEventEmitterProxy } = require('swappable-obj-proxy') +const extend = require('extend') +const networks = { networkList: {} } const { ROPSTEN, @@ -29,6 +31,10 @@ const defaultProviderConfig = { type: testMode ? RINKEBY : MAINNET, } +const defaultNetworkConfig = { + ticker: 'ETH', +} + module.exports = class NetworkController extends EventEmitter { constructor (opts = {}) { @@ -39,7 +45,8 @@ module.exports = class NetworkController extends EventEmitter { // create stores this.providerStore = new ObservableStore(providerConfig) this.networkStore = new ObservableStore('loading') - this.store = new ComposedStore({ provider: this.providerStore, network: this.networkStore }) + this.networkConfig = new ObservableStore(defaultNetworkConfig) + this.store = new ComposedStore({ provider: this.providerStore, network: this.networkStore, settings: this.networkConfig }) this.on('networkDidChange', this.lookupNetwork) // provider and block tracker this._provider = null @@ -51,8 +58,8 @@ module.exports = class NetworkController extends EventEmitter { initializeProvider (providerParams) { this._baseProviderParams = providerParams - const { type, rpcTarget } = this.providerStore.getState() - this._configureProvider({ type, rpcTarget }) + const { type, rpcTarget, chainId, ticker, nickname } = this.providerStore.getState() + this._configureProvider({ type, rpcTarget, chainId, ticker, nickname }) this.lookupNetwork() } @@ -72,7 +79,20 @@ module.exports = class NetworkController extends EventEmitter { return this.networkStore.getState() } - setNetworkState (network) { + getNetworkConfig () { + return this.networkConfig.getState() + } + + setNetworkState (network, type) { + if (network === 'loading') { + return this.networkStore.putState(network) + } + + // type must be defined + if (!type) { + return + } + network = networks.networkList[type] && networks.networkList[type].chainId ? networks.networkList[type].chainId : network return this.networkStore.putState(network) } @@ -85,18 +105,22 @@ module.exports = class NetworkController extends EventEmitter { if (!this._provider) { return log.warn('NetworkController - lookupNetwork aborted due to missing provider') } + var { type } = this.providerStore.getState() const ethQuery = new EthQuery(this._provider) ethQuery.sendAsync({ method: 'net_version' }, (err, network) => { if (err) return this.setNetworkState('loading') log.info('web3.getNetwork returned ' + network) - this.setNetworkState(network) + this.setNetworkState(network, type) }) } - setRpcTarget (rpcTarget) { + setRpcTarget (rpcTarget, chainId, ticker = 'ETH', nickname = '') { const providerConfig = { type: 'rpc', rpcTarget, + chainId, + ticker, + nickname, } this.providerConfig = providerConfig } @@ -132,7 +156,7 @@ module.exports = class NetworkController extends EventEmitter { } _configureProvider (opts) { - const { type, rpcTarget } = opts + const { type, rpcTarget, chainId, ticker, nickname } = opts // infura type-based endpoints const isInfura = INFURA_PROVIDER_TYPES.includes(type) if (isInfura) { @@ -142,7 +166,7 @@ module.exports = class NetworkController extends EventEmitter { this._configureLocalhostProvider() // url-based rpc endpoints } else if (type === 'rpc') { - this._configureStandardProvider({ rpcUrl: rpcTarget }) + this._configureStandardProvider({ rpcUrl: rpcTarget, chainId, ticker, nickname }) } else { throw new Error(`NetworkController - _configureProvider - unknown type "${type}"`) } @@ -152,6 +176,11 @@ module.exports = class NetworkController extends EventEmitter { log.info('NetworkController - configureInfuraProvider', type) const networkClient = createInfuraClient({ network: type }) this._setNetworkClient(networkClient) + // setup networkConfig + var settings = { + ticker: 'ETH', + } + this.networkConfig.putState(settings) } _configureLocalhostProvider () { @@ -160,9 +189,22 @@ module.exports = class NetworkController extends EventEmitter { this._setNetworkClient(networkClient) } - _configureStandardProvider ({ rpcUrl }) { + _configureStandardProvider ({ rpcUrl, chainId, ticker, nickname }) { log.info('NetworkController - configureStandardProvider', rpcUrl) const networkClient = createJsonRpcClient({ rpcUrl }) + // hack to add a 'rpc' network with chainId + networks.networkList['rpc'] = { + chainId: chainId, + rpcUrl, + ticker: ticker || 'ETH', + nickname, + } + // setup networkConfig + var settings = { + network: chainId, + } + settings = extend(settings, networks.networkList['rpc']) + this.networkConfig.putState(settings) this._setNetworkClient(networkClient) } diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 20b13398c..ffb593b09 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -25,7 +25,7 @@ class PreferencesController { */ constructor (opts = {}) { const initState = extend({ - frequentRpcList: [], + frequentRpcListDetail: [], currentAccountTab: 'history', accountTokens: {}, assetImages: {}, @@ -39,14 +39,14 @@ class PreferencesController { seedWords: null, forgottenPassword: false, preferences: { - useETHAsPrimaryCurrency: true, + useNativeCurrencyAsPrimaryCurrency: true, }, }, opts.initState) this.diagnostics = opts.diagnostics this.network = opts.network this.store = new ObservableStore(initState) - this.showWatchAssetUi = opts.showWatchAssetUi + this.openPopup = opts.openPopup this._subscribeProviderType() } // PUBLIC METHODS @@ -392,19 +392,22 @@ class PreferencesController { * Adds custom RPC url to state. * * @param {string} url The RPC url to add to frequentRpcList. + * @param {number} 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. * */ - addToFrequentRpcList (url) { - const rpcList = this.getFrequentRpcList() - const index = rpcList.findIndex((element) => { return element === url }) + addToFrequentRpcList (url, chainId, ticker = 'ETH', nickname = '') { + const rpcList = this.getFrequentRpcListDetail() + const index = rpcList.findIndex((element) => { return element.rpcUrl === url }) if (index !== -1) { rpcList.splice(index, 1) } if (url !== 'http://localhost:8545') { - rpcList.push(url) + rpcList.push({ rpcUrl: url, chainId, ticker, nickname }) } - this.store.updateState({ frequentRpcList: rpcList }) + this.store.updateState({ frequentRpcListDetail: rpcList }) return Promise.resolve(rpcList) } @@ -416,23 +419,23 @@ class PreferencesController { * */ removeFromFrequentRpcList (url) { - const rpcList = this.getFrequentRpcList() - const index = rpcList.findIndex((element) => { return element === url }) + const rpcList = this.getFrequentRpcListDetail() + const index = rpcList.findIndex((element) => { return element.rpcUrl === url }) if (index !== -1) { rpcList.splice(index, 1) } - this.store.updateState({ frequentRpcList: rpcList }) + this.store.updateState({ frequentRpcListDetail: rpcList }) return Promise.resolve(rpcList) } /** - * Getter for the `frequentRpcList` property. + * Getter for the `frequentRpcListDetail` property. * - * @returns {array<string>} An array of one or two rpc urls. + * @returns {array<array>} An array of rpc urls. * */ - getFrequentRpcList () { - return this.store.getState().frequentRpcList + getFrequentRpcListDetail () { + return this.store.getState().frequentRpcListDetail } /** @@ -564,7 +567,7 @@ class PreferencesController { } const tokenOpts = { rawAddress, decimals, symbol, image } this.addSuggestedERC20Asset(tokenOpts) - return this.showWatchAssetUi().then(() => { + return this.openPopup().then(() => { const tokenAddresses = this.getTokens().filter(token => token.address === normalizeAddress(rawAddress)) return tokenAddresses.length > 0 }) @@ -580,8 +583,8 @@ class PreferencesController { */ _validateERC20AssetParams (opts) { const { rawAddress, symbol, decimals } = opts - if (!rawAddress || !symbol || !decimals) throw new Error(`Cannot suggest token without address, symbol, and decimals`) - if (!(symbol.length < 6)) throw new Error(`Invalid symbol ${symbol} more than five characters`) + if (!rawAddress || !symbol || typeof decimals === 'undefined') throw new Error(`Cannot suggest token without address, symbol, and decimals`) + if (!(symbol.length < 7)) throw new Error(`Invalid symbol ${symbol} more than six characters`) const numDecimals = parseInt(decimals, 10) if (isNaN(numDecimals) || numDecimals > 36 || numDecimals < 0) { throw new Error(`Invalid decimals ${decimals} must be at least 0, and not over 36`) diff --git a/app/scripts/controllers/provider-approval.js b/app/scripts/controllers/provider-approval.js new file mode 100644 index 000000000..d3b7f6dff --- /dev/null +++ b/app/scripts/controllers/provider-approval.js @@ -0,0 +1,152 @@ +const ObservableStore = require('obs-store') + +/** + * A controller that services user-approved requests for a full Ethereum provider API + */ +class ProviderApprovalController { + /** + * Determines if caching is enabled + */ + caching = true + + /** + * Creates a ProviderApprovalController + * + * @param {Object} [config] - Options to configure controller + */ + constructor ({ closePopup, keyringController, openPopup, platform, preferencesController, publicConfigStore } = {}) { + this.approvedOrigins = {} + this.closePopup = closePopup + this.keyringController = keyringController + this.openPopup = openPopup + this.platform = platform + this.preferencesController = preferencesController + this.publicConfigStore = publicConfigStore + this.store = new ObservableStore() + + if (platform && platform.addMessageListener) { + platform.addMessageListener(({ action = '', force, origin, siteTitle, siteImage }) => { + switch (action) { + case 'init-provider-request': + this._handleProviderRequest(origin, siteTitle, siteImage, force) + break + case 'init-is-approved': + this._handleIsApproved(origin) + break + case 'init-is-unlocked': + this._handleIsUnlocked() + break + case 'init-privacy-request': + this._handlePrivacyRequest() + break + } + }) + } + } + + /** + * Called when a tab requests access to a full Ethereum provider API + * + * @param {string} origin - Origin of the window requesting full provider access + * @param {string} siteTitle - The title of the document requesting full provider access + * @param {string} siteImage - The icon of the window requesting full provider access + */ + _handleProviderRequest (origin, siteTitle, siteImage, force) { + this.store.updateState({ providerRequests: [{ origin, siteTitle, siteImage }] }) + const isUnlocked = this.keyringController.memStore.getState().isUnlocked + if (!force && this.approvedOrigins[origin] && this.caching && isUnlocked) { + this.approveProviderRequest(origin) + return + } + this.openPopup && this.openPopup() + } + + /** + * Called by a tab to determine if an origin has been approved in the past + * + * @param {string} origin - Origin of the window + */ + _handleIsApproved (origin) { + this.platform && this.platform.sendMessage({ + action: 'answer-is-approved', + isApproved: this.approvedOrigins[origin] && this.caching, + caching: this.caching, + }, { active: true }) + } + + /** + * Called by a tab to determine if MetaMask is currently locked or unlocked + */ + _handleIsUnlocked () { + const isUnlocked = this.keyringController.memStore.getState().isUnlocked + this.platform && this.platform.sendMessage({ action: 'answer-is-unlocked', isUnlocked }, { active: true }) + } + + /** + * Called to check privacy mode; if privacy mode is off, this will automatically enable the provider (legacy behavior) + */ + _handlePrivacyRequest () { + const privacyMode = this.preferencesController.getFeatureFlags().privacyMode + if (!privacyMode) { + this.platform && this.platform.sendMessage({ action: 'approve-provider-request' }, { active: true }) + this.publicConfigStore.emit('update', this.publicConfigStore.getState()) + } + } + + /** + * Called when a user approves access to a full Ethereum provider API + * + * @param {string} origin - Origin of the target window to approve provider access + */ + approveProviderRequest (origin) { + this.closePopup && this.closePopup() + const requests = this.store.getState().providerRequests || [] + this.platform && this.platform.sendMessage({ action: 'approve-provider-request' }, { active: true }) + this.publicConfigStore.emit('update', this.publicConfigStore.getState()) + const providerRequests = requests.filter(request => request.origin !== origin) + this.store.updateState({ providerRequests }) + this.approvedOrigins[origin] = true + } + + /** + * Called when a tab rejects access to a full Ethereum provider API + * + * @param {string} origin - Origin of the target window to reject provider access + */ + rejectProviderRequest (origin) { + this.closePopup && this.closePopup() + const requests = this.store.getState().providerRequests || [] + this.platform && this.platform.sendMessage({ action: 'reject-provider-request' }, { active: true }) + const providerRequests = requests.filter(request => request.origin !== origin) + this.store.updateState({ providerRequests }) + delete this.approvedOrigins[origin] + } + + /** + * Clears any cached approvals for user-approved origins + */ + clearApprovedOrigins () { + this.approvedOrigins = {} + } + + /** + * Determines if a given origin should have accounts exposed + * + * @param {string} origin - Domain origin to check for approval status + * @returns {boolean} - True if the origin has been approved + */ + shouldExposeAccounts (origin) { + const privacyMode = this.preferencesController.getFeatureFlags().privacyMode + return !privacyMode || this.approvedOrigins[origin] + } + + /** + * Tells all tabs that MetaMask is now locked. This is primarily used to set + * internal flags in the contentscript and inpage script. + */ + setLocked () { + this.platform.sendMessage({ action: 'metamask-set-locked' }) + } +} + +module.exports = ProviderApprovalController diff --git a/app/scripts/controllers/token-rates.js b/app/scripts/controllers/token-rates.js index 87d716aa6..b6f084841 100644 --- a/app/scripts/controllers/token-rates.js +++ b/app/scripts/controllers/token-rates.js @@ -1,5 +1,5 @@ const ObservableStore = require('obs-store') -const { warn } = require('loglevel') +const log = require('loglevel') // By default, poll every 3 minutes const DEFAULT_INTERVAL = 180 * 1000 @@ -26,8 +26,11 @@ class TokenRatesController { async updateExchangeRates () { if (!this.isActive) { return } const contractExchangeRates = {} - for (const i in this._tokens) { - const address = this._tokens[i].address + // copy array to ensure its not modified during iteration + const tokens = this._tokens.slice() + for (const token of tokens) { + if (!token) return log.error(`TokenRatesController - invalid tokens state:\n${JSON.stringify(tokens, null, 2)}`) + const address = token.address contractExchangeRates[address] = await this.fetchExchangeRate(address) } this.store.putState({ contractExchangeRates }) @@ -44,7 +47,7 @@ class TokenRatesController { const json = await response.json() return json && json.length ? json[0].averagePrice : 0 } catch (error) { - warn(`MetaMask - TokenRatesController exchange rate fetch failed for ${address}.`, error) + log.warn(`MetaMask - TokenRatesController exchange rate fetch failed for ${address}.`, error) return 0 } } diff --git a/app/scripts/controllers/transactions/tx-gas-utils.js b/app/scripts/controllers/transactions/tx-gas-utils.js index 3dd45507f..def67c2c3 100644 --- a/app/scripts/controllers/transactions/tx-gas-utils.js +++ b/app/scripts/controllers/transactions/tx-gas-utils.js @@ -7,6 +7,8 @@ const { const { addHexPrefix } = require('ethereumjs-util') const SIMPLE_GAS_COST = '0x5208' // Hex for 21000, cost of a simple send. +import { TRANSACTION_NO_CONTRACT_ERROR_KEY } from '../../../../ui/app/constants/error-keys' + /** tx-gas-utils are gas utility methods for Transaction manager its passed ethquery @@ -32,6 +34,7 @@ class TxGasUtil { } catch (err) { txMeta.simulationFails = { reason: err.message, + errorKey: err.errorKey, } return txMeta } @@ -56,24 +59,38 @@ class TxGasUtil { return txParams.gas } - // if recipient has no code, gas is 21k max: const recipient = txParams.to const hasRecipient = Boolean(recipient) - let code - if (recipient) code = await this.query.getCode(recipient) - if (hasRecipient && (!code || code === '0x')) { - txParams.gas = SIMPLE_GAS_COST - txMeta.simpleSend = true // Prevents buffer addition - return SIMPLE_GAS_COST + // see if we can set the gas based on the recipient + if (hasRecipient) { + const code = await this.query.getCode(recipient) + // For an address with no code, geth will return '0x', and ganache-core v2.2.1 will return '0x0' + const codeIsEmpty = !code || code === '0x' || code === '0x0' + + if (codeIsEmpty) { + // if there's data in the params, but there's no contract code, it's not a valid transaction + if (txParams.data) { + const err = new Error('TxGasUtil - Trying to call a function on a non-contract address') + // set error key so ui can display localized error message + err.errorKey = TRANSACTION_NO_CONTRACT_ERROR_KEY + throw err + } + + // This is a standard ether simple send, gas requirement is exactly 21k + txParams.gas = SIMPLE_GAS_COST + // prevents buffer addition + txMeta.simpleSend = true + return SIMPLE_GAS_COST + } } - // if not, fall back to block gasLimit + // fallback to block gasLimit const blockGasLimitBN = hexToBn(blockGasLimitHex) const saferGasLimitBN = BnMultiplyByFraction(blockGasLimitBN, 19, 20) txParams.gas = bnToHex(saferGasLimitBN) - // run tx + // estimate tx gas requirements return await this.query.estimateGas(txParams) } diff --git a/app/scripts/inpage.js b/app/scripts/inpage.js index b885a7e05..327e25042 100644 --- a/app/scripts/inpage.js +++ b/app/scripts/inpage.js @@ -6,14 +6,21 @@ const LocalMessageDuplexStream = require('post-message-stream') const setupDappAutoReload = require('./lib/auto-reload.js') const MetamaskInpageProvider = require('metamask-inpage-provider') +let isEnabled = false +let warned = false +let providerHandle +let isApprovedHandle +let isUnlockedHandle + restoreContextAfterImports() log.setDefaultLevel(process.env.METAMASK_DEBUG ? 'debug' : 'warn') -console.warn('ATTENTION: In an effort to improve user privacy, MetaMask will ' + -'stop exposing user accounts to dapps by default beginning November 2nd, 2018. ' + -'Dapps should call provider.enable() in order to view and use accounts. Please see ' + -'https://bit.ly/2QQHXvF for complete information and up-to-date example code.') +console.warn('ATTENTION: In an effort to improve user privacy, MetaMask ' + +'stopped exposing user accounts to dapps if "privacy mode" is enabled on ' + +'November 2nd, 2018. Dapps should now call provider.enable() in order to view and use ' + +'accounts. Please see https://bit.ly/2QQHXvF for complete information and up-to-date ' + +'example code.') // // setup plugin communication @@ -27,26 +34,125 @@ var metamaskStream = new LocalMessageDuplexStream({ // compose the inpage provider var inpageProvider = new MetamaskInpageProvider(metamaskStream) + // set a high max listener count to avoid unnecesary warnings inpageProvider.setMaxListeners(100) -// Augment the provider with its enable method -inpageProvider.enable = function (options = {}) { +// set up a listener for when MetaMask is locked +window.addEventListener('metamasksetlocked', () => { + isEnabled = false +}) + +// augment the provider with its enable method +inpageProvider.enable = function ({ force } = {}) { return new Promise((resolve, reject) => { - if (options.mockRejection) { - reject('User rejected account access') - } else { - inpageProvider.sendAsync({ method: 'eth_accounts', params: [] }, (error, response) => { - if (error) { - reject(error) - } else { - resolve(response.result) - } - }) + window.removeEventListener('ethereumprovider', providerHandle) + providerHandle = ({ detail }) => { + if (typeof detail.error !== 'undefined') { + reject(detail.error) + } else { + // wait for the publicConfig store to populate with an account + const publicConfig = new Promise((resolve) => { + const { selectedAddress } = inpageProvider.publicConfigStore.getState() + inpageProvider._metamask.isUnlocked().then(unlocked => { + if (!unlocked || selectedAddress) { + resolve() + } else { + inpageProvider.publicConfigStore.on('update', ({ selectedAddress }) => { + selectedAddress && resolve() + }) + } + }) + }) + + // wait for the background to update with an account + const ethAccounts = new Promise((resolveAccounts, rejectAccounts) => { + inpageProvider.sendAsync({ method: 'eth_accounts', params: [] }, (error, response) => { + if (error) { + rejectAccounts(error) + } else { + resolveAccounts(response.result) + } + }) + }) + + Promise.all([ethAccounts, publicConfig]) + .then(([selectedAddress]) => { + isEnabled = true + resolve(selectedAddress) + }) + .catch(reject) + } } + window.addEventListener('ethereumprovider', providerHandle) + window.postMessage({ type: 'ETHEREUM_ENABLE_PROVIDER', force }, '*') }) } +// add metamask-specific convenience methods +inpageProvider._metamask = new Proxy({ + /** + * Determines if this domain is currently enabled + * + * @returns {boolean} - true if this domain is currently enabled + */ + isEnabled: function () { + return isEnabled + }, + + /** + * Determines if this domain has been previously approved + * + * @returns {Promise<boolean>} - Promise resolving to true if this domain has been previously approved + */ + isApproved: function() { + return new Promise((resolve, reject) => { + window.removeEventListener('ethereumisapproved', isApprovedHandle) + isApprovedHandle = ({ detail }) => { + if (typeof detail.error !== 'undefined') { + reject(detail.error) + } else { + if (detail.caching) { + resolve(!!detail.isApproved) + } else { + resolve(false) + } + } + } + window.addEventListener('ethereumisapproved', isApprovedHandle) + window.postMessage({ type: 'ETHEREUM_IS_APPROVED' }, '*') + }) + }, + + /** + * Determines if MetaMask is unlocked by the user + * + * @returns {Promise<boolean>} - Promise resolving to true if MetaMask is currently unlocked + */ + isUnlocked: function () { + return new Promise((resolve, reject) => { + window.removeEventListener('metamaskisunlocked', isUnlockedHandle) + isUnlockedHandle = ({ detail }) => { + if (typeof detail.error !== 'undefined') { + reject(detail.error) + } else { + resolve(!!detail.isUnlocked) + } + } + window.addEventListener('metamaskisunlocked', isUnlockedHandle) + window.postMessage({ type: 'METAMASK_IS_UNLOCKED' }, '*') + }) + }, +}, { + get: function(obj, prop) { + !warned && console.warn('Heads up! ethereum._metamask exposes methods that have ' + + 'not been standardized yet. This means that these methods may not be implemented ' + + 'in other dapp browsers and may be removed from MetaMask in the future.') + warned = true + return obj[prop] + }, +}) + // Work around for web3@1.0 deleting the bound `sendAsync` but not the unbound // `sendAsync` method on the prototype, causing `this` reference issues with drizzle const proxiedInpageProvider = new Proxy(inpageProvider, { @@ -57,6 +163,19 @@ const proxiedInpageProvider = new Proxy(inpageProvider, { window.ethereum = proxiedInpageProvider +// detect eth_requestAccounts and pipe to enable for now +function detectAccountRequest(method) { + const originalMethod = inpageProvider[method] + inpageProvider[method] = function ({ method }) { + if (method === 'eth_requestAccounts') { + return window.ethereum.enable() + } + return originalMethod.apply(this, arguments) + } +} +detectAccountRequest('send') +detectAccountRequest('sendAsync') + // // setup web3 // diff --git a/app/scripts/lib/contracts/registrar.js b/app/scripts/lib/ens-ipfs/contracts/registrar.js index 99ca24458..99ca24458 100644 --- a/app/scripts/lib/contracts/registrar.js +++ b/app/scripts/lib/ens-ipfs/contracts/registrar.js diff --git a/app/scripts/lib/contracts/resolver.js b/app/scripts/lib/ens-ipfs/contracts/resolver.js index 1bf3f90ce..1bf3f90ce 100644 --- a/app/scripts/lib/contracts/resolver.js +++ b/app/scripts/lib/ens-ipfs/contracts/resolver.js diff --git a/app/scripts/lib/ens-ipfs/resolver.js b/app/scripts/lib/ens-ipfs/resolver.js new file mode 100644 index 000000000..fe2dc1134 --- /dev/null +++ b/app/scripts/lib/ens-ipfs/resolver.js @@ -0,0 +1,54 @@ +const namehash = require('eth-ens-namehash') +const multihash = require('multihashes') +const Eth = require('ethjs-query') +const EthContract = require('ethjs-contract') +const registrarAbi = require('./contracts/registrar') +const resolverAbi = require('./contracts/resolver') + +module.exports = resolveEnsToIpfsContentId + + +async function resolveEnsToIpfsContentId ({ provider, name }) { + const eth = new Eth(provider) + const hash = namehash.hash(name) + const contract = new EthContract(eth) + // lookup registrar + const chainId = Number.parseInt(await eth.net_version(), 10) + const registrarAddress = getRegistrarForChainId(chainId) + if (!registrarAddress) { + throw new Error(`EnsIpfsResolver - no known ens-ipfs registrar for chainId "${chainId}"`) + } + const Registrar = contract(registrarAbi).at(registrarAddress) + // lookup resolver + const resolverLookupResult = await Registrar.resolver(hash) + const resolverAddress = resolverLookupResult[0] + if (hexValueIsEmpty(resolverAddress)) { + throw new Error(`EnsIpfsResolver - no resolver found for name "${name}"`) + } + const Resolver = contract(resolverAbi).at(resolverAddress) + // lookup content id + const contentLookupResult = await Resolver.content(hash) + const contentHash = contentLookupResult[0] + if (hexValueIsEmpty(contentHash)) { + throw new Error(`EnsIpfsResolver - no content ID found for name "${name}"`) + } + const nonPrefixedHex = contentHash.slice(2) + const buffer = multihash.fromHexString(nonPrefixedHex) + const contentId = multihash.toB58String(multihash.encode(buffer, 'sha2-256')) + return contentId +} + +function hexValueIsEmpty(value) { + return [undefined, null, '0x', '0x0', '0x0000000000000000000000000000000000000000000000000000000000000000'].includes(value) +} + +function getRegistrarForChainId (chainId) { + switch (chainId) { + // mainnet + case 1: + return '0x314159265dd8dbb310642f98f50c066173c1259b' + // ropsten + case 3: + return '0x112234455c3a32fd11230c42e7bccd4a84e02010' + } +} diff --git a/app/scripts/lib/ens-ipfs/setup.js b/app/scripts/lib/ens-ipfs/setup.js new file mode 100644 index 000000000..45eb1ce14 --- /dev/null +++ b/app/scripts/lib/ens-ipfs/setup.js @@ -0,0 +1,63 @@ +const urlUtil = require('url') +const extension = require('extensionizer') +const resolveEnsToIpfsContentId = require('./resolver.js') + +const supportedTopLevelDomains = ['eth'] + +module.exports = setupEnsIpfsResolver + +function setupEnsIpfsResolver({ provider }) { + + // install listener + const urlPatterns = supportedTopLevelDomains.map(tld => `*://*.${tld}/*`) + extension.webRequest.onErrorOccurred.addListener(webRequestDidFail, { urls: urlPatterns }) + + // return api object + return { + // uninstall listener + remove () { + extension.webRequest.onErrorOccurred.removeListener(webRequestDidFail) + }, + } + + async function webRequestDidFail (details) { + const { tabId, url } = details + // ignore requests that are not associated with tabs + if (tabId === -1) return + // parse ens name + const urlData = urlUtil.parse(url) + const { hostname: name, path, search } = urlData + const domainParts = name.split('.') + const topLevelDomain = domainParts[domainParts.length - 1] + // if unsupported TLD, abort + if (!supportedTopLevelDomains.includes(topLevelDomain)) return + // otherwise attempt resolve + attemptResolve({ tabId, name, path, search }) + } + + async function attemptResolve({ tabId, name, path, search }) { + extension.tabs.update(tabId, { url: `loading.html` }) + try { + const ipfsContentId = await resolveEnsToIpfsContentId({ provider, name }) + let url = `https://gateway.ipfs.io/ipfs/${ipfsContentId}${path}${search || ''}` + try { + // check if ipfs gateway has result + const response = await fetch(url, { method: 'HEAD' }) + // if failure, redirect to 404 page + if (response.status !== 200) { + extension.tabs.update(tabId, { url: '404.html' }) + return + } + // otherwise redirect to the correct page + extension.tabs.update(tabId, { url }) + } catch (err) { + console.warn(err) + // if HEAD fetch failed, redirect so user can see relevant error page + extension.tabs.update(tabId, { url }) + } + } catch (err) { + console.warn(err) + extension.tabs.update(tabId, { url: `error.html?name=${name}` }) + } + } +} diff --git a/app/scripts/lib/ipfsContent.js b/app/scripts/lib/ipfsContent.js deleted file mode 100644 index 8b08453c4..000000000 --- a/app/scripts/lib/ipfsContent.js +++ /dev/null @@ -1,46 +0,0 @@ -const extension = require('extensionizer') -const resolver = require('./resolver.js') - -module.exports = function (provider) { - function ipfsContent (details) { - const name = details.url.substring(7, details.url.length - 1) - let clearTime = null - if (/^.+\.eth$/.test(name) === false) return - - extension.tabs.query({active: true}, tab => { - extension.tabs.update(tab.id, { url: 'loading.html' }) - - clearTime = setTimeout(() => { - return extension.tabs.update(tab.id, { url: '404.html' }) - }, 60000) - - resolver.resolve(name, provider).then(ipfsHash => { - clearTimeout(clearTime) - let url = 'https://ipfs.infura.io/ipfs/' + ipfsHash - return fetch(url, { method: 'HEAD' }).then(response => response.status).then(statusCode => { - if (statusCode !== 200) return extension.tabs.update(tab.id, { url: '404.html' }) - extension.tabs.update(tab.id, { url: url }) - }) - .catch(err => { - url = 'https://ipfs.infura.io/ipfs/' + ipfsHash - extension.tabs.update(tab.id, {url: url}) - return err - }) - }) - .catch(err => { - clearTimeout(clearTime) - const url = err === 'unsupport' ? 'unsupport' : 'error' - extension.tabs.update(tab.id, {url: `${url}.html?name=${name}`}) - }) - }) - return { cancel: true } - } - - extension.webRequest.onErrorOccurred.addListener(ipfsContent, {urls: ['*://*.eth/'], types: ['main_frame']}) - - return { - remove () { - extension.webRequest.onErrorOccurred.removeListener(ipfsContent) - }, - } -} diff --git a/app/scripts/lib/reportFailedTxToSentry.js b/app/scripts/lib/reportFailedTxToSentry.js index df5661e59..de4d57145 100644 --- a/app/scripts/lib/reportFailedTxToSentry.js +++ b/app/scripts/lib/reportFailedTxToSentry.js @@ -7,10 +7,10 @@ module.exports = reportFailedTxToSentry // for sending to sentry // -function reportFailedTxToSentry ({ raven, txMeta }) { +function reportFailedTxToSentry ({ sentry, txMeta }) { const errorMessage = 'Transaction Failed: ' + extractEthjsErrorMessage(txMeta.err.message) - raven.captureMessage(errorMessage, { + sentry.captureMessage(errorMessage, { // "extra" key is required by Sentry - extra: txMeta, + extra: { txMeta }, }) } diff --git a/app/scripts/lib/resolver.js b/app/scripts/lib/resolver.js deleted file mode 100644 index ff0fed161..000000000 --- a/app/scripts/lib/resolver.js +++ /dev/null @@ -1,71 +0,0 @@ -const namehash = require('eth-ens-namehash') -const multihash = require('multihashes') -const HttpProvider = require('ethjs-provider-http') -const Eth = require('ethjs-query') -const EthContract = require('ethjs-contract') -const registrarAbi = require('./contracts/registrar') -const resolverAbi = require('./contracts/resolver') - -function ens (name, provider) { - const eth = new Eth(new HttpProvider(getProvider(provider.type))) - const hash = namehash.hash(name) - const contract = new EthContract(eth) - const Registrar = contract(registrarAbi).at(getRegistrar(provider.type)) - return new Promise((resolve, reject) => { - if (provider.type === 'mainnet' || provider.type === 'ropsten') { - Registrar.resolver(hash).then((address) => { - if (address === '0x0000000000000000000000000000000000000000') { - reject(null) - } else { - const Resolver = contract(resolverAbi).at(address['0']) - return Resolver.content(hash) - } - }).then((contentHash) => { - if (contentHash['0'] === '0x0000000000000000000000000000000000000000000000000000000000000000') reject(null) - if (contentHash.ret !== '0x') { - const hex = contentHash['0'].substring(2) - const buf = multihash.fromHexString(hex) - resolve(multihash.toB58String(multihash.encode(buf, 'sha2-256'))) - } else { - reject(null) - } - }) - } else { - return reject('unsupport') - } - }) -} - -function getProvider (type) { - switch (type) { - case 'mainnet': - return 'https://mainnet.infura.io/' - case 'ropsten': - return 'https://ropsten.infura.io/' - default: - return 'http://localhost:8545/' - } -} - -function getRegistrar (type) { - switch (type) { - case 'mainnet': - return '0x314159265dd8dbb310642f98f50c066173c1259b' - case 'ropsten': - return '0x112234455c3a32fd11230c42e7bccd4a84e02010' - default: - return '0x0000000000000000000000000000000000000000' - } -} - -module.exports.resolve = function (name, provider) { - const path = name.split('.') - const topLevelDomain = path[path.length - 1] - if (topLevelDomain === 'eth' || topLevelDomain === 'test') { - return ens(name, provider) - } else { - return new Promise((resolve, reject) => { - reject(null) - }) - } -} diff --git a/app/scripts/lib/setupFetchDebugging.js b/app/scripts/lib/setupFetchDebugging.js index dd87b65a6..c1ef22d21 100644 --- a/app/scripts/lib/setupFetchDebugging.js +++ b/app/scripts/lib/setupFetchDebugging.js @@ -2,7 +2,7 @@ module.exports = setupFetchDebugging // // This is a utility to help resolve cases where `window.fetch` throws a -// `TypeError: Failed to Fetch` without any stack or context for the request +// `TypeError: Failed to Fetch` without any stack or context for the request // https://github.com/getsentry/sentry-javascript/pull/1293 // @@ -17,9 +17,11 @@ function setupFetchDebugging() { try { return await originalFetch.call(window, ...args) } catch (err) { - console.warn('FetchDebugger - fetch encountered an Error', err) - console.warn('FetchDebugger - overriding stack to point of original call') - err.stack = initialStack + if (!err.stack) { + console.warn('FetchDebugger - fetch encountered an Error without a stack', err) + console.warn('FetchDebugger - overriding stack to point of original call') + err.stack = initialStack + } throw err } } diff --git a/app/scripts/lib/setupRaven.js b/app/scripts/lib/setupSentry.js index e6e511640..69042bc19 100644 --- a/app/scripts/lib/setupRaven.js +++ b/app/scripts/lib/setupSentry.js @@ -1,58 +1,55 @@ -const Raven = require('raven-js') +const Sentry = require('@sentry/browser') const METAMASK_DEBUG = process.env.METAMASK_DEBUG const extractEthjsErrorMessage = require('./extractEthjsErrorMessage') -const PROD = 'https://3567c198f8a8412082d32655da2961d0@sentry.io/273505' -const DEV = 'https://f59f3dd640d2429d9d0e2445a87ea8e1@sentry.io/273496' +const SENTRY_DSN_PROD = 'https://3567c198f8a8412082d32655da2961d0@sentry.io/273505' +const SENTRY_DSN_DEV = 'https://f59f3dd640d2429d9d0e2445a87ea8e1@sentry.io/273496' -module.exports = setupRaven +module.exports = setupSentry -// Setup raven / sentry remote error reporting -function setupRaven (opts) { - const { release } = opts - let ravenTarget +// Setup sentry remote error reporting +function setupSentry (opts) { + const { release, getState } = opts + let sentryTarget // detect brave const isBrave = Boolean(window.chrome.ipcRenderer) if (METAMASK_DEBUG) { - console.log('Setting up Sentry Remote Error Reporting: DEV') - ravenTarget = DEV + console.log('Setting up Sentry Remote Error Reporting: SENTRY_DSN_DEV') + sentryTarget = SENTRY_DSN_DEV } else { - console.log('Setting up Sentry Remote Error Reporting: PROD') - ravenTarget = PROD + console.log('Setting up Sentry Remote Error Reporting: SENTRY_DSN_PROD') + sentryTarget = SENTRY_DSN_PROD } - const client = Raven.config(ravenTarget, { + Sentry.init({ + dsn: sentryTarget, + debug: METAMASK_DEBUG, release, - transport: function (opts) { - opts.data.extra.isBrave = isBrave - const report = opts.data + beforeSend: (report) => rewriteReport(report), + }) - try { - // handle error-like non-error exceptions - rewriteErrorLikeExceptions(report) - // simplify certain complex error messages (e.g. Ethjs) - simplifyErrorMessages(report) - // modify report urls - rewriteReportUrls(report) - } catch (err) { - console.warn(err) - } - // make request normally - client._makeRequest(opts) - }, + Sentry.configureScope(scope => { + scope.setExtra('isBrave', isBrave) }) - client.install() - return Raven -} + function rewriteReport(report) { + try { + // simplify certain complex error messages (e.g. Ethjs) + simplifyErrorMessages(report) + // modify report urls + rewriteReportUrls(report) + // append app state + if (getState) { + const appState = getState() + report.extra.appState = appState + } + } catch (err) { + console.warn(err) + } + return report + } -function rewriteErrorLikeExceptions (report) { - // handle errors that lost their error-ness in serialization (e.g. dnode) - rewriteErrorMessages(report, (errorMessage) => { - if (!errorMessage.includes('Non-Error exception captured with keys:')) return errorMessage - if (!(report.extra && report.extra.__serialized__ && report.extra.__serialized__.message)) return errorMessage - return `Non-Error Exception: ${report.extra.__serialized__.message}` - }) + return Sentry } function simplifyErrorMessages (report) { diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 7913662d4..5ae0f608d 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -37,6 +37,7 @@ const TransactionController = require('./controllers/transactions') const BalancesController = require('./controllers/computed-balances') const TokenRatesController = require('./controllers/token-rates') const DetectTokensController = require('./controllers/detect-tokens') +const ProviderApprovalController = require('./controllers/provider-approval') const nodeify = require('./lib/nodeify') const accountImporter = require('./account-import-strategies') const getBuyEthUrl = require('./lib/buy-eth-url') @@ -89,7 +90,7 @@ module.exports = class MetamaskController extends EventEmitter { this.preferencesController = new PreferencesController({ initState: initState.PreferencesController, initLangCode: opts.initLangCode, - showWatchAssetUi: opts.showWatchAssetUi, + openPopup: opts.openPopup, network: this.networkController, }) @@ -138,12 +139,12 @@ module.exports = class MetamaskController extends EventEmitter { this.accountTracker.stop() } }) - + // ensure accountTracker updates balances after network change this.networkController.on('networkDidChange', () => { this.accountTracker._updateAccounts() }) - + // key mgmt const additionalKeyrings = [TrezorKeyring, LedgerBridgeKeyring] this.keyringController = new KeyringController({ @@ -197,6 +198,8 @@ module.exports = class MetamaskController extends EventEmitter { }) this.networkController.on('networkDidChange', () => { this.balancesController.updateAllBalances() + var currentCurrency = this.currencyController.getCurrentCurrency() + this.setCurrentCurrency(currentCurrency, function() {}) }) this.balancesController.updateAllBalances() @@ -217,6 +220,15 @@ module.exports = class MetamaskController extends EventEmitter { this.typedMessageManager = new TypedMessageManager({ networkController: this.networkController }) this.publicConfigStore = this.initPublicConfigStore() + this.providerApprovalController = new ProviderApprovalController({ + closePopup: opts.closePopup, + keyringController: this.keyringController, + openPopup: opts.openPopup, + platform: opts.platform, + preferencesController: this.preferencesController, + publicConfigStore: this.publicConfigStore, + }) + this.store.updateStructure({ TransactionController: this.txController.store, KeyringController: this.keyringController.store, @@ -246,6 +258,7 @@ module.exports = class MetamaskController extends EventEmitter { NoticeController: this.noticeController.memStore, ShapeshiftController: this.shapeshiftController.store, InfuraController: this.infuraController.store, + ProviderApprovalController: this.providerApprovalController.store, }) this.memStore.subscribe(this.sendUpdate.bind(this)) } @@ -261,7 +274,11 @@ module.exports = class MetamaskController extends EventEmitter { }, version, // account mgmt - getAccounts: async () => { + getAccounts: async ({ origin }) => { + // Expose no accounts if this origin has not been approved, preventing + // account-requring RPC methods from completing successfully + const exposeAccounts = this.providerApprovalController.shouldExposeAccounts(origin) + if (origin !== 'MetaMask' && !exposeAccounts) { return [] } const isUnlocked = this.keyringController.memStore.getState().isUnlocked const selectedAddress = this.preferencesController.getSelectedAddress() // only show address if account is unlocked @@ -275,6 +292,8 @@ module.exports = class MetamaskController extends EventEmitter { processTransaction: this.newUnapprovedTransaction.bind(this), // msg signing processEthSignMessage: this.newUnsignedMessage.bind(this), + processTypedMessage: this.newUnsignedTypedMessage.bind(this), + processTypedMessageV3: this.newUnsignedTypedMessage.bind(this), processPersonalMessage: this.newUnsignedPersonalMessage.bind(this), getPendingNonce: this.getPendingNonce.bind(this), } @@ -345,6 +364,7 @@ module.exports = class MetamaskController extends EventEmitter { const noticeController = this.noticeController const addressBookController = this.addressBookController const networkController = this.networkController + const providerApprovalController = this.providerApprovalController return { // etc @@ -402,7 +422,7 @@ module.exports = class MetamaskController extends EventEmitter { setAddressBook: nodeify(addressBookController.setAddressBook, addressBookController), // KeyringController - setLocked: nodeify(keyringController.setLocked, keyringController), + setLocked: nodeify(this.setLocked, this), createNewVaultAndKeychain: nodeify(this.createNewVaultAndKeychain, this), createNewVaultAndRestore: nodeify(this.createNewVaultAndRestore, this), addNewKeyring: nodeify(keyringController.addNewKeyring, keyringController), @@ -433,6 +453,10 @@ module.exports = class MetamaskController extends EventEmitter { // notices checkNotices: noticeController.updateNoticesList.bind(noticeController), markNoticeRead: noticeController.markNoticeRead.bind(noticeController), + + approveProviderRequest: providerApprovalController.approveProviderRequest.bind(providerApprovalController), + clearApprovedOrigins: providerApprovalController.clearApprovedOrigins.bind(providerApprovalController), + rejectProviderRequest: providerApprovalController.rejectProviderRequest.bind(providerApprovalController), } } @@ -978,8 +1002,8 @@ module.exports = class MetamaskController extends EventEmitter { * @param {Object} msgParams - The params passed to eth_signTypedData. * @param {Function} cb - The callback function, called with the signature. */ - newUnsignedTypedMessage (msgParams, req) { - const promise = this.typedMessageManager.addUnapprovedMessageAsync(msgParams, req) + newUnsignedTypedMessage (msgParams, req, version) { + const promise = this.typedMessageManager.addUnapprovedMessageAsync(msgParams, req, version) this.sendUpdate() this.opts.showUnconfirmedMessage() return promise @@ -1273,10 +1297,6 @@ module.exports = class MetamaskController extends EventEmitter { engine.push(subscriptionManager.middleware) // watch asset engine.push(this.preferencesController.requestWatchAsset.bind(this.preferencesController)) - // sign typed data middleware - engine.push(this.createTypedDataMiddleware('eth_signTypedData', 'V1').bind(this)) - engine.push(this.createTypedDataMiddleware('eth_signTypedData_v1', 'V1').bind(this)) - engine.push(this.createTypedDataMiddleware('eth_signTypedData_v3', 'V3', true).bind(this)) // forward to metamask primary provider engine.push(createProviderMiddleware({ provider })) @@ -1412,10 +1432,13 @@ module.exports = class MetamaskController extends EventEmitter { * @param {Function} cb - A callback function returning currency info. */ setCurrentCurrency (currencyCode, cb) { + const { ticker } = this.networkController.getNetworkConfig() try { + this.currencyController.setNativeCurrency(ticker) this.currencyController.setCurrentCurrency(currencyCode) this.currencyController.updateConversionRate() const data = { + nativeCurrency: ticker || 'ETH', conversionRate: this.currencyController.getConversionRate(), currentCurrency: this.currencyController.getCurrentCurrency(), conversionDate: this.currencyController.getConversionDate(), @@ -1454,11 +1477,14 @@ module.exports = 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 {number} 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) { - this.networkController.setRpcTarget(rpcTarget) - await this.preferencesController.addToFrequentRpcList(rpcTarget) + async setCustomRpc (rpcTarget, chainId, ticker = 'ETH', nickname = '') { + this.networkController.setRpcTarget(rpcTarget, chainId, ticker, nickname) + await this.preferencesController.addToFrequentRpcList(rpcTarget, chainId, ticker, nickname) return rpcTarget } @@ -1542,27 +1568,6 @@ module.exports = class MetamaskController extends EventEmitter { * @param {Function} - next * @param {Function} - end */ - createTypedDataMiddleware (methodName, version, reverse) { - return async (req, res, next, end) => { - const { method, params } = req - if (method === methodName) { - const promise = this.typedMessageManager.addUnapprovedMessageAsync({ - data: reverse ? params[1] : params[0], - from: reverse ? params[0] : params[1], - }, req, version) - this.sendUpdate() - this.opts.showUnconfirmedMessage() - try { - res.result = await promise - end() - } catch (error) { - end(error) - } - } else { - next() - } - } - } /** * Adds a domain to the {@link BlacklistController} whitelist @@ -1571,4 +1576,12 @@ module.exports = class MetamaskController extends EventEmitter { whitelistPhishingDomain (hostname) { return this.blacklistController.whitelistDomain(hostname) } + + /** + * Locks MetaMask + */ + setLocked() { + this.providerApprovalController.setLocked() + return this.keyringController.setLocked() + } } diff --git a/app/scripts/platforms/extension.js b/app/scripts/platforms/extension.js index 71b162dd0..9ef0d22c9 100644 --- a/app/scripts/platforms/extension.js +++ b/app/scripts/platforms/extension.js @@ -57,6 +57,18 @@ class ExtensionPlatform { } } + addMessageListener (cb) { + extension.runtime.onMessage.addListener(cb) + } + + sendMessage (message, query = {}) { + extension.tabs.query(query, tabs => { + tabs.forEach(tab => { + extension.tabs.sendMessage(tab.id, message) + }) + }) + } + _showConfirmedTransaction (txMeta) { this._subscribeToNotificationClicked() diff --git a/app/scripts/ui.js b/app/scripts/ui.js index 98a036338..c4f6615db 100644 --- a/app/scripts/ui.js +++ b/app/scripts/ui.js @@ -9,7 +9,7 @@ const extension = require('extensionizer') const ExtensionPlatform = require('./platforms/extension') const NotificationManager = require('./lib/notification-manager') const notificationManager = new NotificationManager() -const setupRaven = require('./lib/setupRaven') +const setupSentry = require('./lib/setupSentry') const log = require('loglevel') start().catch(log.error) @@ -21,7 +21,17 @@ async function start () { // setup sentry error reporting const release = global.platform.getVersion() - setupRaven({ release }) + setupSentry({ release, getState }) + // provide app state to append to error logs + function getState() { + // get app state + const state = window.getCleanAppState() + // remove unnecessary data + delete state.localeMessages + delete state.metamask.recentBlocks + // return state to be added to request + return state + } // inject css // const css = MetaMaskUiCss() diff --git a/development/states/add-token.json b/development/states/add-token.json index 6a525f2b3..b59e9b757 100644 --- a/development/states/add-token.json +++ b/development/states/add-token.json @@ -109,7 +109,7 @@ }, "currentLocale": "en", "preferences": { - "useETHAsPrimaryCurrency": true + "useNativeCurrencyAsPrimaryCurrency": true } }, "appState": { diff --git a/development/states/confirm-sig-requests.json b/development/states/confirm-sig-requests.json index c7103cd13..1ffde3938 100644 --- a/development/states/confirm-sig-requests.json +++ b/development/states/confirm-sig-requests.json @@ -152,7 +152,7 @@ }, "currentLocale": "en", "preferences": { - "useETHAsPrimaryCurrency": true + "useNativeCurrencyAsPrimaryCurrency": true } }, "appState": { diff --git a/development/states/currency-localization.json b/development/states/currency-localization.json index 7dea42ade..ef28891a3 100644 --- a/development/states/currency-localization.json +++ b/development/states/currency-localization.json @@ -110,7 +110,7 @@ }, "currentLocale": "en", "preferences": { - "useETHAsPrimaryCurrency": true + "useNativeCurrencyAsPrimaryCurrency": true } }, "appState": { diff --git a/development/states/first-time.json b/development/states/first-time.json index 3206b67a3..ff7078720 100644 --- a/development/states/first-time.json +++ b/development/states/first-time.json @@ -39,7 +39,7 @@ "tokens": [], "currentLocale": "en", "preferences": { - "useETHAsPrimaryCurrency": true + "useNativeCurrencyAsPrimaryCurrency": true } }, "appState": { diff --git a/development/states/send-new-ui.json b/development/states/send-new-ui.json index d9924dd74..0cd2f23f2 100644 --- a/development/states/send-new-ui.json +++ b/development/states/send-new-ui.json @@ -111,7 +111,7 @@ }, "currentLocale": "en", "preferences": { - "useETHAsPrimaryCurrency": true + "useNativeCurrencyAsPrimaryCurrency": true } }, "appState": { diff --git a/development/states/tx-list-items.json b/development/states/tx-list-items.json index cbffa98e5..e83179a17 100644 --- a/development/states/tx-list-items.json +++ b/development/states/tx-list-items.json @@ -104,7 +104,7 @@ "send": {}, "currentLocale": "en", "preferences": { - "useETHAsPrimaryCurrency": true + "useNativeCurrencyAsPrimaryCurrency": true } }, "appState": { diff --git a/development/verify-locale-strings.js b/development/verify-locale-strings.js index 0f408ea39..a5d76a269 100644 --- a/development/verify-locale-strings.js +++ b/development/verify-locale-strings.js @@ -30,7 +30,7 @@ if (specifiedLocale) { } -function verifyLocale (localeMeta) { +function verifyLocale ({ localeMeta }) { const localeCode = localeMeta.code const localeName = localeMeta.name let targetLocale, englishLocale diff --git a/old-ui/app/app.js b/old-ui/app/app.js index 9be21ebad..2d364ef6f 100644 --- a/old-ui/app/app.js +++ b/old-ui/app/app.js @@ -33,6 +33,7 @@ const BuyView = require('./components/buy-button-subview') const HDCreateVaultComplete = require('./keychains/hd/create-vault-complete') const HDRestoreVaultScreen = require('./keychains/hd/restore-vault') const RevealSeedConfirmation = require('./keychains/hd/recover-seed/confirmation') +const ProviderApproval = require('./provider-approval') module.exports = connect(mapStateToProps)(App) @@ -49,6 +50,7 @@ function mapStateToProps (state) { noActiveNotices, seedWords, featureFlags, + providerRequests, } = state.metamask const selected = address || Object.keys(accounts)[0] @@ -73,8 +75,9 @@ function mapStateToProps (state) { forgottenPassword: state.appState.forgottenPassword, nextUnreadNotice: state.metamask.nextUnreadNotice, lostAccounts: state.metamask.lostAccounts, - frequentRpcList: state.metamask.frequentRpcList || [], + frequentRpcListDetail: state.metamask.frequentRpcListDetail || [], featureFlags, + providerRequests, suggestedTokens: state.metamask.suggestedTokens, // state needed to get account dropdown temporarily rendering from app bar @@ -147,7 +150,7 @@ App.prototype.renderLoadingIndicator = function ({ isLoading, isLoadingNetwork, App.prototype.renderPrimary = function () { log.debug('rendering primary') var props = this.props - const {isMascara, isOnboarding} = props + const {isMascara, isOnboarding, providerRequests} = props if (isMascara && isOnboarding) { return h(MascaraFirstTime) @@ -215,6 +218,11 @@ App.prototype.renderPrimary = function () { return h(HDCreateVaultComplete, {key: 'HDCreateVaultComplete'}) } + if (providerRequests && providerRequests.length > 0) { + log.debug('rendering provider API approval screen') + return h(ProviderApproval, { origin: providerRequests[0].origin }) + } + // show current view switch (props.currentView.name) { diff --git a/old-ui/app/components/app-bar.js b/old-ui/app/components/app-bar.js index 234c06a01..fa8e499ed 100644 --- a/old-ui/app/components/app-bar.js +++ b/old-ui/app/components/app-bar.js @@ -17,7 +17,7 @@ module.exports = class AppBar extends Component { static propTypes = { dispatch: PropTypes.func.isRequired, - frequentRpcList: PropTypes.array.isRequired, + frequentRpcListDetail: PropTypes.array.isRequired, isMascara: PropTypes.bool.isRequired, isOnboarding: PropTypes.bool.isRequired, identities: PropTypes.any.isRequired, @@ -196,7 +196,7 @@ module.exports = class AppBar extends Component { renderNetworkDropdown () { const { dispatch, - frequentRpcList: rpcList, + frequentRpcListDetail: rpcList, provider, } = this.props const { @@ -321,8 +321,8 @@ module.exports = class AppBar extends Component { ]) } - renderCustomOption ({ rpcTarget, type }) { - const {dispatch} = this.props + renderCustomOption ({ rpcTarget, type, ticker }) { + const {dispatch, network} = this.props if (type !== 'rpc') { return null @@ -340,7 +340,7 @@ module.exports = class AppBar extends Component { default: return h(DropdownMenuItem, { key: rpcTarget, - onClick: () => dispatch(actions.setRpcTarget(rpcTarget)), + onClick: () => dispatch(actions.setRpcTarget(rpcTarget, network, ticker)), closeMenu: () => this.setState({ isNetworkMenuOpen: false }), }, [ h('i.fa.fa-question-circle.fa-lg.menu-icon'), @@ -354,7 +354,8 @@ module.exports = class AppBar extends Component { const {dispatch} = this.props const reversedRpcList = rpcList.slice().reverse() - return reversedRpcList.map((rpc) => { + return reversedRpcList.map((entry) => { + const rpc = entry.rpcUrl const currentRpcTarget = provider.type === 'rpc' && rpc === provider.rpcTarget if ((rpc === LOCALHOST_RPC_URL) || currentRpcTarget) { @@ -363,7 +364,7 @@ module.exports = class AppBar extends Component { return h(DropdownMenuItem, { key: `common${rpc}`, closeMenu: () => this.setState({ isNetworkMenuOpen: false }), - onClick: () => dispatch(actions.setRpcTarget(rpc)), + onClick: () => dispatch(actions.setRpcTarget(rpc, entry.chainId, entry.ticker)), }, [ h('i.fa.fa-question-circle.fa-lg.menu-icon'), rpc, diff --git a/old-ui/app/components/balance.js b/old-ui/app/components/balance.js index 57ca84564..8995f961f 100644 --- a/old-ui/app/components/balance.js +++ b/old-ui/app/components/balance.js @@ -1,12 +1,18 @@ const Component = require('react').Component const h = require('react-hyperscript') +const connect = require('react-redux').connect const inherits = require('util').inherits const formatBalance = require('../util').formatBalance const generateBalanceObject = require('../util').generateBalanceObject const Tooltip = require('./tooltip.js') const FiatValue = require('./fiat-value.js') -module.exports = EthBalanceComponent +module.exports = connect(mapStateToProps)(EthBalanceComponent) +function mapStateToProps (state) { + return { + ticker: state.metamask.ticker, + } +} inherits(EthBalanceComponent, Component) function EthBalanceComponent () { @@ -16,9 +22,10 @@ function EthBalanceComponent () { EthBalanceComponent.prototype.render = function () { var props = this.props let { value } = props + const { ticker } = props var style = props.style var needsParse = this.props.needsParse !== undefined ? this.props.needsParse : true - value = value ? formatBalance(value, 6, needsParse) : '...' + value = value ? formatBalance(value, 6, needsParse, ticker) : '...' var width = props.width return ( diff --git a/old-ui/app/components/eth-balance.js b/old-ui/app/components/eth-balance.js index 4f538fd31..4458e6a9a 100644 --- a/old-ui/app/components/eth-balance.js +++ b/old-ui/app/components/eth-balance.js @@ -1,12 +1,18 @@ const Component = require('react').Component const h = require('react-hyperscript') +const connect = require('react-redux').connect const inherits = require('util').inherits const formatBalance = require('../util').formatBalance const generateBalanceObject = require('../util').generateBalanceObject const Tooltip = require('./tooltip.js') const FiatValue = require('./fiat-value.js') -module.exports = EthBalanceComponent +module.exports = connect(mapStateToProps)(EthBalanceComponent) +function mapStateToProps (state) { + return { + ticker: state.metamask.ticker, + } +} inherits(EthBalanceComponent, Component) function EthBalanceComponent () { @@ -16,9 +22,9 @@ function EthBalanceComponent () { EthBalanceComponent.prototype.render = function () { var props = this.props let { value } = props - const { style, width } = props + const { ticker, style, width } = props var needsParse = this.props.needsParse !== undefined ? this.props.needsParse : true - value = value ? formatBalance(value, 6, needsParse) : '...' + value = value ? formatBalance(value, 6, needsParse, ticker) : '...' return ( diff --git a/old-ui/app/components/pending-tx.js b/old-ui/app/components/pending-tx.js index c8132539c..35e81210e 100644 --- a/old-ui/app/components/pending-tx.js +++ b/old-ui/app/components/pending-tx.js @@ -1,4 +1,5 @@ const Component = require('react').Component +const connect = require('react-redux').connect const h = require('react-hyperscript') const inherits = require('util').inherits const actions = require('../../../ui/app/actions') @@ -19,7 +20,9 @@ const BNInput = require('./bn-as-decimal-input') const MIN_GAS_PRICE_BN = new BN('0') const MIN_GAS_LIMIT_BN = new BN('21000') -module.exports = PendingTx +module.exports = connect()(PendingTx) + + inherits(PendingTx, Component) function PendingTx () { Component.call(this) @@ -445,7 +448,8 @@ PendingTx.prototype.onSubmit = function (event) { const txMeta = this.gatherTxMeta() const valid = this.checkValidity() this.setState({ valid, submitting: true }) - if (valid && this.verifyGasParams()) { + const validGasParams = this.verifyGasParams() + if (valid && validGasParams) { this.props.sendTransaction(txMeta, event) } else { this.props.dispatch(actions.displayWarning('Invalid Gas Parameters')) @@ -488,8 +492,12 @@ PendingTx.prototype.verifyGasParams = function () { ) } -PendingTx.prototype._notZeroOrEmptyString = function (obj) { - return obj !== '' && obj !== '0x0' +PendingTx.prototype._notZeroOrEmptyString = function (value) { + // allow undefined values + if (value === undefined) return true + // Geth will return '0x', and ganache-core v2.2.1 will return '0x0' + const valueIsEmpty = !value || value === '0x' || value === '0x0' + return !valueIsEmpty } PendingTx.prototype.bnMultiplyByFraction = function (targetBN, numerator, denominator) { diff --git a/old-ui/app/config.js b/old-ui/app/config.js index 392a6dba7..2a0643919 100644 --- a/old-ui/app/config.js +++ b/old-ui/app/config.js @@ -68,7 +68,7 @@ ConfigScreen.prototype.render = function () { currentProviderDisplay(metamaskState), - h('div', { style: {display: 'flex'} }, [ + h('div', { style: {display: 'block'} }, [ h('input#new_rpc', { placeholder: 'New RPC URL', style: { @@ -81,7 +81,70 @@ ConfigScreen.prototype.render = function () { if (event.key === 'Enter') { var element = event.target var newRpc = element.value - rpcValidation(newRpc, state) + var chainid = document.querySelector('input#chainid') + var ticker = document.querySelector('input#ticker') + var nickname = document.querySelector('input#nickname') + rpcValidation(newRpc, chainid.value, ticker.value, nickname.value, state) + } + }, + }), + h('br'), + h('input#chainid', { + placeholder: 'ChainId (optional)', + style: { + width: 'inherit', + flex: '1 0 auto', + height: '30px', + margin: '8px', + }, + onKeyPress (event) { + if (event.key === 'Enter') { + var element = document.querySelector('input#new_rpc') + var newRpc = element.value + var chainid = document.querySelector('input#chainid') + var ticker = document.querySelector('input#ticker') + var nickname = document.querySelector('input#nickname') + rpcValidation(newRpc, chainid.value, ticker.value, nickname.value, state) + } + }, + }), + h('br'), + h('input#ticker', { + placeholder: 'Symbol (optional)', + style: { + width: 'inherit', + flex: '1 0 auto', + height: '30px', + margin: '8px', + }, + onKeyPress (event) { + if (event.key === 'Enter') { + var element = document.querySelector('input#new_rpc') + var newRpc = element.value + var chainid = document.querySelector('input#chainid') + var ticker = document.querySelector('input#ticker') + var nickname = document.querySelector('input#nickname') + rpcValidation(newRpc, chainid.value, ticker.value, nickname.value, state) + } + }, + }), + h('br'), + h('input#nickname', { + placeholder: 'Nickname (optional)', + style: { + width: 'inherit', + flex: '1 0 auto', + height: '30px', + margin: '8px', + }, + onKeyPress (event) { + if (event.key === 'Enter') { + var element = document.querySelector('input#new_rpc') + var newRpc = element.value + var chainid = document.querySelector('input#chainid') + var ticker = document.querySelector('input#ticker') + var nickname = document.querySelector('input#nickname') + rpcValidation(newRpc, chainid.value, ticker.value, nickname.value, state) } }, }), @@ -93,7 +156,10 @@ ConfigScreen.prototype.render = function () { event.preventDefault() var element = document.querySelector('input#new_rpc') var newRpc = element.value - rpcValidation(newRpc, state) + var chainid = document.querySelector('input#chainid') + var ticker = document.querySelector('input#ticker') + var nickname = document.querySelector('input#nickname') + rpcValidation(newRpc, chainid.value, ticker.value, nickname.value, state) }, }, 'Save'), ]), @@ -139,6 +205,62 @@ ConfigScreen.prototype.render = function () { marginTop: '20px', }, }, [ + h('p', { + style: { + fontFamily: 'Montserrat Light', + fontSize: '13px', + }, + }, 'Clear privacy data so all websites must request access to view account information again.'), + h('br'), + h('button', { + style: { + alignSelf: 'center', + }, + onClick (event) { + event.preventDefault() + state.dispatch(actions.clearApprovedOrigins()) + }, + }, 'Clear privacy data'), + ]), + + h('hr.horizontal-line'), + + h('div', { + style: { + marginTop: '20px', + }, + }, [ + h('p', { + style: { + fontFamily: 'Montserrat Light', + fontSize: '13px', + }, + }, metamaskState.featureFlags.privacyMode ? + 'Websites will be able to view your account information.' : + 'Websites must request access to view your account information.' + ), + h('br'), + h('button', { + style: { + alignSelf: 'center', + }, + onClick (event) { + event.preventDefault() + state.dispatch(actions.setFeatureFlag('privacyMode', !metamaskState.featureFlags.privacyMode)) + }, + }, metamaskState.featureFlags.privacyMode ? + 'Disable privacy mode' : + 'Enable privacy mode' + ), + ]), + + h('hr.horizontal-line'), + + h('div', { + style: { + marginTop: '20px', + }, + }, [ h('button', { style: { alignSelf: 'center', @@ -189,9 +311,9 @@ ConfigScreen.prototype.render = function () { ) } -function rpcValidation (newRpc, state) { +function rpcValidation (newRpc, chainid, ticker = 'ETH', nickname = '', state) { if (validUrl.isWebUri(newRpc)) { - state.dispatch(actions.setRpcTarget(newRpc)) + state.dispatch(actions.setRpcTarget(newRpc, chainid, ticker, nickname)) } else { var appendedRpc = `http://${newRpc}` if (validUrl.isWebUri(appendedRpc)) { diff --git a/old-ui/app/provider-approval.js b/old-ui/app/provider-approval.js new file mode 100644 index 000000000..c4c7ff64d --- /dev/null +++ b/old-ui/app/provider-approval.js @@ -0,0 +1,64 @@ +import PropTypes from 'prop-types' +import React, { Component } from 'react' +import { approveProviderRequest, rejectProviderRequest } from '../../ui/app/actions' +import { connect } from 'react-redux' +class ProviderApproval extends Component { + render () { + const { approveProviderRequest, origin, rejectProviderRequest } = this.props + return ( + <div className="flex-column flex-grow"> + <style dangerouslySetInnerHTML={{__html: ` + .provider_approval_actions { + display: flex; + justify-content: flex-end; + margin: 14px 25px; + } + .provider_approval_actions button { + margin-left: 10px; + text-transform: uppercase; + } + .provider_approval_content { + padding: 0 25px; + } + .provider_approval_origin { + font-weight: bold; + margin: 14px 0; + } + `}} /> + <div className="section-title flex-row flex-center"> + <i + className="fa fa-arrow-left fa-lg cursor-pointer" + onClick={() => { rejectProviderRequest(origin) }} /> + <h2 className="page-subtitle">Web3 API Request</h2> + </div> + <div className="provider_approval_content"> + {"The domain listed below is requesting access to the Ethereum blockchain and to view your current account. Always double check that you're on the correct site before approving access."} + <div className="provider_approval_origin">{origin}</div> + </div> + <div className="provider_approval_actions"> + <button + className="btn-green" + onClick={() => { approveProviderRequest(origin) }}>APPROVE</button> + <button + className="cancel btn-red" + onClick={() => { rejectProviderRequest(origin) }}>REJECT</button> + </div> + </div> + ) + } +} + +ProviderApproval.propTypes = { + approveProviderRequest: PropTypes.func, + origin: PropTypes.string, + rejectProviderRequest: PropTypes.func, +} + +function mapDispatchToProps (dispatch) { + return { + approveProviderRequest: origin => dispatch(approveProviderRequest(origin)), + rejectProviderRequest: origin => dispatch(rejectProviderRequest(origin)), + } +} + +module.exports = connect(null, mapDispatchToProps)(ProviderApproval) diff --git a/old-ui/app/util.js b/old-ui/app/util.js index 962832ce7..40e79b88c 100644 --- a/old-ui/app/util.js +++ b/old-ui/app/util.js @@ -102,7 +102,7 @@ function parseBalance (balance) { // Takes wei hex, returns an object with three properties. // Its "formatted" property is what we generally use to render values. -function formatBalance (balance, decimalsToKeep, needsParse = true) { +function formatBalance (balance, decimalsToKeep, needsParse = true, ticker = 'ETH') { var parsed = needsParse ? parseBalance(balance) : balance.split('.') var beforeDecimal = parsed[0] var afterDecimal = parsed[1] @@ -112,14 +112,14 @@ function formatBalance (balance, decimalsToKeep, needsParse = true) { if (afterDecimal !== '0') { var sigFigs = afterDecimal.match(/^0*(.{2})/) // default: grabs 2 most significant digits if (sigFigs) { afterDecimal = sigFigs[0] } - formatted = '0.' + afterDecimal + ' ETH' + formatted = '0.' + afterDecimal + ` ${ticker}` } } else { - formatted = beforeDecimal + '.' + afterDecimal.slice(0, 3) + ' ETH' + formatted = beforeDecimal + '.' + afterDecimal.slice(0, 3) + ` ${ticker}` } } else { afterDecimal += Array(decimalsToKeep).join('0') - formatted = beforeDecimal + '.' + afterDecimal.slice(0, decimalsToKeep) + ' ETH' + formatted = beforeDecimal + '.' + afterDecimal.slice(0, decimalsToKeep) + ` ${ticker}` } return formatted } diff --git a/package-lock.json b/package-lock.json index 367115d81..f621997b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -489,6 +489,16 @@ } } }, + "@sentry/browser": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-4.2.3.tgz", + "integrity": "sha512-XvuIc1aclz4zuP2LamDuSy62/gl1mmNxzF+Ni5L8mcghBDq0urnOdkblVQgzqGoH8mc2QfjEctGa5djWxg3Bpg==", + "requires": { + "@sentry/core": "4.2.3", + "@sentry/types": "4.2.3", + "@sentry/utils": "4.2.3" + } + }, "@sentry/cli": { "version": "1.30.3", "resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-1.30.3.tgz", @@ -531,9 +541,51 @@ } } }, + "@sentry/core": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-4.2.3.tgz", + "integrity": "sha512-xo5rvksftnaEdnKbdokyfuqgMnuqw1DFp0lDboIFHlEBcQde/AdThEgLujJWmbVNI3Cg7g8/HvP65f7QBjKfOw==", + "requires": { + "@sentry/hub": "4.2.3", + "@sentry/minimal": "4.2.3", + "@sentry/types": "4.2.3", + "@sentry/utils": "4.2.3" + } + }, + "@sentry/hub": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-4.2.3.tgz", + "integrity": "sha512-7Jc/wz3vybYm1RX2wk/4zAQS8fo3uxvXYBkRfpm3OmnGgTlwDEmJwtegeGWFqufxLl85brZ19V1KAdulmO206A==", + "requires": { + "@sentry/types": "4.2.3", + "@sentry/utils": "4.2.3" + } + }, + "@sentry/minimal": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-4.2.3.tgz", + "integrity": "sha512-Hus7LUeJDGsYpT2RTe6bUjG7mHG9uQoyDmW6pYUMN2dhD+cP5cPoTIXO4yxokwgAeDa+GH2/UXoASWc4s2eA2w==", + "requires": { + "@sentry/hub": "4.2.3", + "@sentry/types": "4.2.3" + } + }, + "@sentry/types": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-4.2.3.tgz", + "integrity": "sha512-Z7laXlLtLSEXcKzgcD2caWPMTM8sAvR86rssYM5uYb3azC5PO0aAvuhjokkdv1+Ke1Bg7lkaNZamiCSyaH/9xg==" + }, + "@sentry/utils": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-4.2.3.tgz", + "integrity": "sha512-D6+M1081wCwGp8adWV3KFOxrxFmVyjMJ45x6/TnYvXdgDyc+t28oil21FHeKhwjld9eMqgQ5Tf1OOvos1MNBQg==", + "requires": { + "@sentry/types": "4.2.3" + } + }, "@sinonjs/formatio": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", + "resolved": "http://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==", "dev": true, "requires": { @@ -743,7 +795,7 @@ }, "autoprefixer": { "version": "7.2.6", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-7.2.6.tgz", + "resolved": "http://registry.npmjs.org/autoprefixer/-/autoprefixer-7.2.6.tgz", "integrity": "sha512-Iq8TRIB+/9eQ8rbGhcP7ct5cYb/3qjNYAR2SnzLCEcwF6rvVOax8+9+fccgXk4bEhQGjOZd5TLhsksmAdsbGqQ==", "dev": true, "requires": { @@ -1085,7 +1137,7 @@ }, "style-loader": { "version": "0.20.3", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.20.3.tgz", + "resolved": "http://registry.npmjs.org/style-loader/-/style-loader-0.20.3.tgz", "integrity": "sha512-2I7AVP73MvK33U7B9TKlYZAqdROyMXDYSMvHLX43qy3GCOaJNiV6i0v/sv9idWIaQ42Yn2dNv79Q5mKXbKhAZg==", "dev": true, "requires": { @@ -1230,7 +1282,7 @@ }, "@storybook/podda": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@storybook/podda/-/podda-1.2.3.tgz", + "resolved": "http://registry.npmjs.org/@storybook/podda/-/podda-1.2.3.tgz", "integrity": "sha512-g7dsdsn50AhlGZ8iIDKdF8bi7Am++iFOq+QN+hNKz3FvgLuf8Dz+mpC/BFl90eE9bEYxXqXKeMf87399Ec5Qhw==", "dev": true, "requires": { @@ -1594,7 +1646,7 @@ "dependencies": { "hoist-non-react-statics": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz", "integrity": "sha1-qkSM8JhtVcxAdzsXF0t90GbLfPs=", "dev": true } @@ -1614,7 +1666,7 @@ "dependencies": { "hoist-non-react-statics": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz", "integrity": "sha1-qkSM8JhtVcxAdzsXF0t90GbLfPs=", "dev": true } @@ -1740,7 +1792,7 @@ "dependencies": { "bignumber.js": { "version": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2", - "from": "bignumber.js@git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2" + "from": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2" }, "chai": { "version": "3.5.0", @@ -1840,7 +1892,7 @@ }, "acorn-jsx": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "resolved": "http://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", "requires": { "acorn": "^3.0.4" @@ -1848,7 +1900,7 @@ "dependencies": { "acorn": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "resolved": "http://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=" } } @@ -2596,7 +2648,7 @@ }, "adjust-sourcemap-loader": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-1.2.0.tgz", "integrity": "sha512-958oaHHVEXMvsY7v7cC5gEkNIcoaAVIhZ4mBReYVZJOTP9IgKmzLjIOhTtzpLMu+qriXvLsVjJ155EeInp45IQ==", "dev": true, "requires": { @@ -2652,9 +2704,9 @@ } }, "adm-zip": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.7.tgz", - "integrity": "sha1-hgbCy/HEJs6MjsABdER/1Jtur8E=", + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.11.tgz", + "integrity": "sha512-L8vcjDTCOIJk7wFvmlEUN7AsSb8T+2JrdP7KINBjzr24TJ5Mwj590sLu3BC7zNZowvJWa/JtPmD8eJCzdtDWjA==", "dev": true }, "aes-js": { @@ -2766,7 +2818,7 @@ }, "readable-stream": { "version": "1.1.14", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true, "optional": true, @@ -3359,7 +3411,7 @@ }, "axios": { "version": "0.15.3", - "resolved": "http://registry.npmjs.org/axios/-/axios-0.15.3.tgz", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.15.3.tgz", "integrity": "sha1-LJ1jiy4ZGgjqHWzJiOrda6W9wFM=", "dev": true, "optional": true, @@ -3369,7 +3421,7 @@ "dependencies": { "follow-redirects": { "version": "1.0.0", - "resolved": "http://registry.npmjs.org/follow-redirects/-/follow-redirects-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.0.0.tgz", "integrity": "sha1-jjQpjL0uF28lTv/sdaHHjMhJ/Tc=", "dev": true, "optional": true, @@ -3591,7 +3643,7 @@ }, "babel-helper-is-nodes-equiv": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz", + "resolved": "http://registry.npmjs.org/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz", "integrity": "sha1-NOmzALFHnd2Y7HfqC76TQt/jloQ=", "dev": true }, @@ -3840,7 +3892,7 @@ }, "babel-plugin-react-docgen": { "version": "1.9.0", - "resolved": "https://registry.npmjs.org/babel-plugin-react-docgen/-/babel-plugin-react-docgen-1.9.0.tgz", + "resolved": "http://registry.npmjs.org/babel-plugin-react-docgen/-/babel-plugin-react-docgen-1.9.0.tgz", "integrity": "sha512-8lQ73p4BL+xcgba03NTiHrddl2X8J6PDMQHPpz73sesrRBf6JtAscQPLIjFWQR/abLokdv81HdshpjYGppOXgA==", "dev": true, "requires": { @@ -3851,77 +3903,77 @@ }, "babel-plugin-syntax-async-functions": { "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", + "resolved": "http://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=" }, "babel-plugin-syntax-async-generators": { "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz", + "resolved": "http://registry.npmjs.org/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz", "integrity": "sha1-a8lj67FuzLrmuStZbrfzXDQqi5o=", "dev": true }, "babel-plugin-syntax-class-constructor-call": { "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz", + "resolved": "http://registry.npmjs.org/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz", "integrity": "sha1-nLnTn+Q8hgC+yBRkVt3L1OGnZBY=", "dev": true }, "babel-plugin-syntax-class-properties": { "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz", + "resolved": "http://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz", "integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94=", "dev": true }, "babel-plugin-syntax-decorators": { "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz", + "resolved": "http://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz", "integrity": "sha1-MSVjtNvePMgGzuPkFszurd0RrAs=", "dev": true }, "babel-plugin-syntax-do-expressions": { "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-do-expressions/-/babel-plugin-syntax-do-expressions-6.13.0.tgz", + "resolved": "http://registry.npmjs.org/babel-plugin-syntax-do-expressions/-/babel-plugin-syntax-do-expressions-6.13.0.tgz", "integrity": "sha1-V0d1YTmqJtOQ0JQQsDdEugfkeW0=", "dev": true }, "babel-plugin-syntax-dynamic-import": { "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz", + "resolved": "http://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz", "integrity": "sha1-jWomIpyDdFqZgqRBBRVyyqF5sdo=", "dev": true }, "babel-plugin-syntax-exponentiation-operator": { "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", + "resolved": "http://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=" }, "babel-plugin-syntax-export-extensions": { "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz", + "resolved": "http://registry.npmjs.org/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz", "integrity": "sha1-cKFITw+QiaToStRLrDU8lbmxJyE=", "dev": true }, "babel-plugin-syntax-flow": { "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz", + "resolved": "http://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz", "integrity": "sha1-TDqyCiryaqIM0lmVw5jE63AxDI0=", "dev": true }, "babel-plugin-syntax-function-bind": { "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-function-bind/-/babel-plugin-syntax-function-bind-6.13.0.tgz", + "resolved": "http://registry.npmjs.org/babel-plugin-syntax-function-bind/-/babel-plugin-syntax-function-bind-6.13.0.tgz", "integrity": "sha1-SMSV8Xe98xqYHnMvVa3AvdJgH0Y=", "dev": true }, "babel-plugin-syntax-jsx": { "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", + "resolved": "http://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=", "dev": true }, "babel-plugin-syntax-object-rest-spread": { "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", + "resolved": "http://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=", "dev": true }, @@ -4828,7 +4880,7 @@ }, "readable-stream": { "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true, "requires": { @@ -4852,7 +4904,7 @@ }, "through": { "version": "2.2.7", - "resolved": "https://registry.npmjs.org/through/-/through-2.2.7.tgz", + "resolved": "http://registry.npmjs.org/through/-/through-2.2.7.tgz", "integrity": "sha1-bo4hIAGR1OtqmfbwEN9Gqhxusr0=", "dev": true }, @@ -5376,7 +5428,7 @@ }, "browserify-rsa": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "requires": { "bn.js": "^4.1.0", @@ -5526,7 +5578,7 @@ }, "cacache": { "version": "10.0.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz", + "resolved": "http://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz", "integrity": "sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==", "dev": true, "requires": { @@ -5618,7 +5670,7 @@ }, "camelcase-keys": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", "requires": { "camelcase": "^2.0.0", @@ -5665,9 +5717,9 @@ "integrity": "sha512-vs79o1mOSKRGv/1pSkp4EXgl4ZviWeYReXw60XfacPU64uQWZwJT6vZNmxRF9O+6zu71sJwMxLK5JXxbzuVrLw==" }, "capture-stack-trace": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz", - "integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", + "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==", "dev": true }, "case-sensitive-paths-webpack-plugin": { @@ -5727,7 +5779,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "requires": { "ansi-styles": "^2.2.1", @@ -5818,8 +5870,7 @@ "chownr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz", - "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", - "dev": true + "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=" }, "chromedriver": { "version": "2.41.0", @@ -5993,7 +6044,7 @@ }, "lodash": { "version": "3.10.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "resolved": "http://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", "dev": true } @@ -6042,9 +6093,9 @@ } }, "clone": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz", - "integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs=" + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=" }, "clone-buffer": { "version": "1.0.0", @@ -6175,7 +6226,7 @@ }, "color": { "version": "0.11.4", - "resolved": "https://registry.npmjs.org/color/-/color-0.11.4.tgz", + "resolved": "http://registry.npmjs.org/color/-/color-0.11.4.tgz", "integrity": "sha1-bXtcdPtl6EHNSHkq0e1eB7kE12Q=", "requires": { "clone": "^1.0.2", @@ -6287,7 +6338,7 @@ }, "yargs": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-1.3.3.tgz", + "resolved": "http://registry.npmjs.org/yargs/-/yargs-1.3.3.tgz", "integrity": "sha1-BU3oth8i7v23IHBZ6u+da4P7kxo=", "dev": true } @@ -6805,7 +6856,7 @@ }, "css-in-js-utils": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/css-in-js-utils/-/css-in-js-utils-2.0.1.tgz", + "resolved": "http://registry.npmjs.org/css-in-js-utils/-/css-in-js-utils-2.0.1.tgz", "integrity": "sha512-PJF0SpJT+WdbVVt0AOYp9C8GnuruRlL/UFW7932nLWmFLQTaWEzTBQEx7/hn4BuV+WON75iAViSUJLiU3PKbpA==", "dev": true, "requires": { @@ -6823,7 +6874,7 @@ }, "css-loader": { "version": "0.28.11", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-0.28.11.tgz", + "resolved": "http://registry.npmjs.org/css-loader/-/css-loader-0.28.11.tgz", "integrity": "sha512-wovHgjAx8ZIMGSL8pTys7edA1ClmzxHeY6n/d97gg5odgsxEgKjULPR0viqyC+FWMCL9sfqoC/QCUBo62tLvPg==", "requires": { "babel-code-frame": "^6.26.0", @@ -6903,7 +6954,7 @@ }, "readable-stream": { "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, "requires": { @@ -6921,7 +6972,7 @@ }, "through2": { "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz", "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", "dev": true, "requires": { @@ -6933,7 +6984,7 @@ }, "css-select": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", "dev": true, "requires": { @@ -6983,7 +7034,7 @@ }, "readable-stream": { "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true, "requires": { @@ -7031,7 +7082,7 @@ }, "cssnano": { "version": "3.10.0", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-3.10.0.tgz", + "resolved": "http://registry.npmjs.org/cssnano/-/cssnano-3.10.0.tgz", "integrity": "sha1-Tzj2zqK5sX+gFJDyPx3GjqZcHDg=", "requires": { "autoprefixer": "^6.3.1", @@ -7201,7 +7252,7 @@ }, "d": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/d/-/d-1.0.0.tgz", "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", "requires": { "es5-ext": "^0.10.9" @@ -7533,6 +7584,12 @@ "repeating": "^2.0.0" } }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "optional": true + }, "detect-newline": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", @@ -8076,7 +8133,7 @@ }, "readable-stream": { "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, "requires": { @@ -8112,7 +8169,7 @@ }, "through2": { "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz", "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", "dev": true, "requires": { @@ -8128,7 +8185,7 @@ }, "yargs": { "version": "3.32.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", + "resolved": "http://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", "integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=", "dev": true, "requires": { @@ -8189,7 +8246,7 @@ "dependencies": { "domelementtype": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", + "resolved": "http://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", "dev": true } @@ -8252,7 +8309,7 @@ }, "dotenv": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-5.0.1.tgz", + "resolved": "http://registry.npmjs.org/dotenv/-/dotenv-5.0.1.tgz", "integrity": "sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow==", "dev": true }, @@ -8284,7 +8341,7 @@ }, "duplexer": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "resolved": "http://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=" }, "duplexer2": { @@ -8302,7 +8359,7 @@ }, "readable-stream": { "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "requires": { "core-util-is": "~1.0.0", @@ -8759,7 +8816,7 @@ }, "es6-promisify": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "resolved": "http://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", "dev": true, "requires": { @@ -9020,7 +9077,7 @@ }, "ansi-escapes": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "resolved": "http://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", "dev": true }, @@ -9127,7 +9184,7 @@ }, "progress": { "version": "1.1.8", - "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "resolved": "http://registry.npmjs.org/progress/-/progress-1.1.8.tgz", "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", "dev": true }, @@ -9169,7 +9226,7 @@ }, "slice-ansi": { "version": "0.0.4", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "resolved": "http://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", "dev": true }, @@ -9310,9 +9367,9 @@ } }, "eth-block-tracker": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-4.0.3.tgz", - "integrity": "sha512-Uy+5hEvOT1/C6N1Lw/uQ10v03ArnNEQEkM0yhJQWwpd8Ymy3sw4jk75SE58s1spfOBBtnr8JaSAFioAFSeg6HA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-4.1.0.tgz", + "integrity": "sha512-991xTy6CzYYbizkHmgRFFI9iGx1OCISve8sSLuOlt7/yD7VFH1Jd8mOmBqxaG5ywGkIXdwAR78nQ2WDReETzBg==", "requires": { "eth-json-rpc-infura": "^3.1.2", "eth-query": "^2.1.0", @@ -9322,9 +9379,9 @@ }, "dependencies": { "cross-fetch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-2.2.2.tgz", - "integrity": "sha1-pH/09/xxLauo9qaVoRyUhEDUVyM=", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-2.2.3.tgz", + "integrity": "sha512-PrWWNH3yL2NYIb/7WF/5vFG3DCQiXDOVf8k3ijatbrtnwNuhMWLC7YF7uqf53tbTFDzHIUD8oITw4Bxt8ST3Nw==", "requires": { "node-fetch": "2.1.2", "whatwg-fetch": "2.0.4" @@ -9383,18 +9440,18 @@ }, "node-fetch": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz", + "resolved": "http://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz", "integrity": "sha1-q4hOjn5X44qUR1POxwb3iNF2i7U=" }, "whatwg-fetch": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", + "resolved": "http://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", "integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==" } } }, "eth-contract-metadata": { - "version": "github:MetaMask/eth-contract-metadata#2da362052a312dc6c72a7eec116abf6284664f50", + "version": "github:MetaMask/eth-contract-metadata#a74deeb46c18e76ad8fa8640aaedbc2a511603b5", "from": "github:MetaMask/eth-contract-metadata#master" }, "eth-ens-namehash": { @@ -9431,22 +9488,12 @@ "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", "ethereumjs-util": "^5.1.1" - }, - "dependencies": { - "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", - "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", - "requires": { - "bn.js": "^4.10.0", - "ethereumjs-util": "^5.0.0" - } - } } }, "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { "bn.js": "^4.10.0", @@ -9512,22 +9559,12 @@ "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", "ethereumjs-util": "^5.1.1" - }, - "dependencies": { - "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", - "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", - "requires": { - "bn.js": "^4.10.0", - "ethereumjs-util": "^5.0.0" - } - } } }, "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { "bn.js": "^4.10.0", @@ -9591,7 +9628,7 @@ }, "eth-json-rpc-middleware": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.6.0.tgz", + "resolved": "http://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.6.0.tgz", "integrity": "sha512-tDVCTlrUvdqHKqivYMjtFZsdD7TtpNLBCfKAcOpaVs7orBMS/A8HWro6dIzNtTZIR05FAbJ3bioFOnZpuCew9Q==", "requires": { "async": "^2.5.0", @@ -9639,29 +9676,26 @@ } }, "eth-json-rpc-middleware": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-3.1.3.tgz", - "integrity": "sha512-glp/mCefhsqrgVOTTuYlHYiTL+9mMPfaZsuQv4vnRg3kqNigblS1nqARaMeVW9WOM8ssh9TqIFpuUr7JDgNmKQ==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-3.1.6.tgz", + "integrity": "sha512-yf17/rAM4ElKMul8oSvuK7JuYIYEFFdy2YGPo2EZbuOEv2Wq1bteMlppgqZ9NYHriXLAOWV+ojY9kWHGbcU4xA==", "dev": true, "requires": { - "async": "^2.5.0", "btoa": "^1.2.1", "clone": "^2.1.1", "eth-query": "^2.1.2", "eth-sig-util": "^1.4.2", - "eth-tx-summary": "^3.1.2", + "eth-tx-summary": "^3.2.3", "ethereumjs-block": "^1.6.0", "ethereumjs-tx": "^1.3.3", "ethereumjs-util": "^5.1.2", - "ethereumjs-vm": "^2.1.0", + "ethereumjs-vm": "^2.4.0", "fetch-ponyfill": "^4.0.0", - "json-rpc-engine": "^3.6.3", + "json-rpc-engine": "^3.8.0", "json-rpc-error": "^2.0.0", "json-stable-stringify": "^1.0.1", "pify": "^3.0.0", - "promise-to-callback": "^1.0.0", - "safe-event-emitter": "^1.0.1", - "tape": "^4.6.3" + "safe-event-emitter": "^1.0.1" }, "dependencies": { "eth-sig-util": { @@ -9670,12 +9704,12 @@ "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "dev": true, "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", "ethereumjs-util": "^5.1.1" } }, "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "dev": true, "requires": { @@ -9697,13 +9731,38 @@ "safe-buffer": "^5.1.1", "secp256k1": "^3.0.1" } + }, + "ethereumjs-vm": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ethereumjs-vm/-/ethereumjs-vm-2.4.0.tgz", + "integrity": "sha512-MJ4lCWa5c6LhahhhvoDKW+YGjK00ZQn0RHHLh4L+WaH1k6Qv7/q3uTluew6sJGNCZdlO0yYMDXYW9qyxLHKlgQ==", + "dev": true, + "requires": { + "async": "^2.1.2", + "async-eventemitter": "^0.2.2", + "ethereumjs-account": "^2.0.3", + "ethereumjs-block": "~1.7.0", + "ethereumjs-common": "~0.4.0", + "ethereumjs-util": "^5.2.0", + "fake-merkle-patricia-tree": "^1.0.1", + "functional-red-black-tree": "^1.0.1", + "merkle-patricia-tree": "^2.1.2", + "rustbn.js": "~0.2.0", + "safe-buffer": "^5.1.1" + } + }, + "rustbn.js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/rustbn.js/-/rustbn.js-0.2.0.tgz", + "integrity": "sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==", + "dev": true } } }, "eth-keyring-controller": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eth-keyring-controller/-/eth-keyring-controller-3.3.0.tgz", - "integrity": "sha512-ZQtWxg0mNSAeQ9JcOaeTKaN5vfr+MbjRhSfeaF1VIWZsQgULpHrbjT6m94qiAFdh7ZngoR7OEpK9PATBH7JNYw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/eth-keyring-controller/-/eth-keyring-controller-3.3.1.tgz", + "integrity": "sha512-Knz3alRHjgJ+/4LUBxXLApXeuoMsehaLOvVHpalSTkU//YPXBjvaITlc6653n+g1vvJ4sD2VbMNfFmYYyFHEtw==", "requires": { "bip39": "^2.4.0", "bluebird": "^3.5.0", @@ -9719,47 +9778,24 @@ "dependencies": { "babelify": { "version": "7.3.0", - "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", + "resolved": "http://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", "requires": { "babel-core": "^6.0.14", "object-assign": "^4.0.0" } }, - "eth-hd-keyring": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/eth-hd-keyring/-/eth-hd-keyring-1.2.2.tgz", - "integrity": "sha1-rV9HkHRDapO0ObC5XHkJXCh5GII=", - "requires": { - "bip39": "^2.2.0", - "eth-sig-util": "^1.4.2", - "ethereumjs-util": "^5.1.1", - "ethereumjs-wallet": "^0.6.0", - "events": "^1.1.1", - "xtend": "^4.0.1" - } - }, "eth-sig-util": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", "ethereumjs-util": "^5.1.1" - }, - "dependencies": { - "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", - "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", - "requires": { - "bn.js": "^4.10.0", - "ethereumjs-util": "^5.0.0" - } - } } }, "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { "bn.js": "^4.10.0", @@ -9811,18 +9847,8 @@ "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", "ethereumjs-util": "^5.1.1" - }, - "dependencies": { - "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", - "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", - "requires": { - "bn.js": "^4.10.0", - "ethereumjs-util": "^5.0.0" - } - } } }, "ethereum-common": { @@ -9831,7 +9857,7 @@ "integrity": "sha1-L9w1dvIykDNYl26znaeDIT/5Uj8=" }, "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { "bn.js": "^4.10.0", @@ -10006,29 +10032,6 @@ "ethereumjs-util": "^5.1.1" }, "dependencies": { - "ethereumjs-abi": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.5.tgz", - "integrity": "sha1-WmN+8Wq0NHP6cqKa2QhxQFs/UkE=", - "requires": { - "bn.js": "^4.10.0", - "ethereumjs-util": "^4.3.0" - }, - "dependencies": { - "ethereumjs-util": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-4.5.0.tgz", - "integrity": "sha1-PpQosxfuvaPXJg2FT93alUsfG8Y=", - "requires": { - "bn.js": "^4.8.0", - "create-hash": "^1.1.2", - "keccakjs": "^0.2.0", - "rlp": "^2.0.0", - "secp256k1": "^3.0.1" - } - } - } - }, "ethereumjs-util": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", @@ -10046,9 +10049,9 @@ } }, "eth-simple-keyring": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eth-simple-keyring/-/eth-simple-keyring-1.3.0.tgz", - "integrity": "sha512-KNB3WXHyY/NfUiVTllsGScJ8AFTR6OGcrjKn4oSYG+HIvhkOoBqMAJ94BR3zGTvzyg5rHywHwT4L2K4+ZPFp5Q==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/eth-simple-keyring/-/eth-simple-keyring-1.3.1.tgz", + "integrity": "sha512-oOASghMej6WO+bjFF+/8bT2DU7D9QKgD81BbS+/qd26z25ueATcgwPNP2LrkoWUbe39OVVM4P5A4fTEEZpGAHg==", "requires": { "eth-sig-util": "^1.4.2", "ethereumjs-util": "^5.1.1", @@ -10062,22 +10065,12 @@ "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", "ethereumjs-util": "^5.1.1" - }, - "dependencies": { - "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", - "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", - "requires": { - "bn.js": "^4.10.0", - "ethereumjs-util": "^5.0.0" - } - } } }, "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { "bn.js": "^4.10.0", @@ -10101,16 +10094,17 @@ } }, "eth-token-tracker": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/eth-token-tracker/-/eth-token-tracker-1.1.5.tgz", - "integrity": "sha512-dyNzEt62i5vpbAAHHj6kEVxSHg/WqCr7TBq1Sbs4y0PvsxcvfWLJpEYtJilndg36H7nJHGadgmHqGW5mYbcNfw==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/eth-token-tracker/-/eth-token-tracker-1.1.6.tgz", + "integrity": "sha512-p3tD2v65XHeFv7DoUUxvln6xOC/MYmmocLyvvcT/s38vcnQdUJ76oNaon98vTQr3Y61qbaiy19c4bvuKaezqlA==", "requires": { "deep-equal": "^1.0.1", "eth-block-tracker": "^1.0.7", "ethjs": "^0.3.6", "ethjs-contract": "^0.2.1", "ethjs-query": "^0.3.7", - "human-standard-token-abi": "^1.0.2" + "human-standard-token-abi": "^1.0.2", + "safe-event-emitter": "^1.0.1" }, "dependencies": { "babelify": { @@ -10247,7 +10241,7 @@ }, "pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" } } @@ -10269,7 +10263,7 @@ "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", "ethereumjs-util": "^5.1.1" } }, @@ -10279,7 +10273,7 @@ "integrity": "sha1-L9w1dvIykDNYl26znaeDIT/5Uj8=" }, "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { "bn.js": "^4.10.0", @@ -10372,7 +10366,7 @@ "dependencies": { "async-eventemitter": { "version": "github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", - "from": "github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", + "from": "async-eventemitter@github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", "requires": { "async": "^2.4.0" } @@ -10394,7 +10388,7 @@ } }, "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { "bn.js": "^4.10.0", @@ -10498,26 +10492,8 @@ "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", "ethereumjs-util": "^5.1.1" - }, - "dependencies": { - "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", - "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", - "requires": { - "bn.js": "^4.10.0", - "ethereumjs-util": "^5.0.0" - } - } - } - }, - "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", - "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", - "requires": { - "bn.js": "^4.10.0", - "ethereumjs-util": "^5.0.0" } }, "ethereumjs-util": { @@ -10559,7 +10535,7 @@ "dependencies": { "ethereumjs-util": { "version": "4.5.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-4.5.0.tgz", + "resolved": "http://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-4.5.0.tgz", "integrity": "sha1-PpQosxfuvaPXJg2FT93alUsfG8Y=", "requires": { "bn.js": "^4.8.0", @@ -10622,6 +10598,12 @@ } } }, + "ethereumjs-common": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/ethereumjs-common/-/ethereumjs-common-0.4.1.tgz", + "integrity": "sha512-ywYGsOeGCsMNWso5Y4GhjWI24FJv9FK7+VyVKiQgXg8ZRDPXJ7F/kJ1CnjtkjTvDF4e0yqU+FWswlqR3bmZQ9Q==", + "dev": true + }, "ethereumjs-tx": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-1.3.3.tgz", @@ -10654,7 +10636,7 @@ }, "ethereumjs-util": { "version": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9", - "from": "ethereumjs-util@github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9", + "from": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9", "requires": { "bn.js": "^4.8.0", "create-hash": "^1.1.2", @@ -11106,7 +11088,7 @@ }, "event-stream": { "version": "3.3.4", - "resolved": "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", "dev": true, "requires": { @@ -11582,7 +11564,7 @@ "dependencies": { "core-js": { "version": "1.2.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "resolved": "http://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" } } @@ -11642,7 +11624,7 @@ }, "file-loader": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.11.tgz", + "resolved": "http://registry.npmjs.org/file-loader/-/file-loader-1.1.11.tgz", "integrity": "sha512-TGR4HU7HUsGg6GCOPJnFk06RhWgEWFLAGWiT6rcD+GRC2keU3s9RGJ+b3Z6/U73jwwNb2gKLJ7YCrp+jvU4ALg==", "requires": { "loader-utils": "^1.0.2", @@ -12123,7 +12105,7 @@ "dependencies": { "async": { "version": "0.2.10", - "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "resolved": "http://registry.npmjs.org/async/-/async-0.2.10.tgz", "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", "dev": true }, @@ -12368,6 +12350,15 @@ } } }, + "fs-minipass": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", + "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, "fs-mkdirp-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", @@ -12434,527 +12425,11 @@ "node-pre-gyp": "^0.10.0" }, "dependencies": { - "abbrev": { - "version": "1.1.1", - "resolved": false, - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": false, - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "aproba": { - "version": "1.2.0", - "resolved": false, - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.4", - "resolved": false, - "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "resolved": false, - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": false, - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.0.1", - "resolved": false, - "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "resolved": false, - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" - }, - "concat-map": { - "version": "0.0.1", - "resolved": false, - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "console-control-strings": { - "version": "1.1.0", - "resolved": false, - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" - }, - "core-util-is": { - "version": "1.0.2", - "resolved": false, - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "optional": true - }, - "debug": { - "version": "2.6.9", - "resolved": false, - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-extend": { - "version": "0.5.1", - "resolved": false, - "integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==", - "optional": true - }, - "delegates": { - "version": "1.0.0", - "resolved": false, - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "resolved": false, - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", - "optional": true - }, - "fs-minipass": { - "version": "1.2.5", - "resolved": false, - "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": false, - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "optional": true - }, - "gauge": { - "version": "2.7.4", - "resolved": false, - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "glob": { - "version": "7.1.2", - "resolved": false, - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "optional": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-unicode": { - "version": "2.0.1", - "resolved": false, - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "optional": true - }, - "iconv-lite": { - "version": "0.4.21", - "resolved": false, - "integrity": "sha512-En5V9za5mBt2oUA03WGD3TwDv0MKAruqsuxstbMUZaj9W9k/m1CV/9py3l0L5kw9Bln8fdHQmzHSYtvpvTLpKw==", - "optional": true, - "requires": { - "safer-buffer": "^2.1.0" - } - }, - "ignore-walk": { - "version": "3.0.1", - "resolved": false, - "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "resolved": false, - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": false, - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "ini": { - "version": "1.3.5", - "resolved": false, - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": false, - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "resolved": false, - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": false, - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": false, - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - }, - "minipass": { - "version": "2.2.4", - "resolved": false, - "integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==", - "requires": { - "safe-buffer": "^5.1.1", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.1.0", - "resolved": false, - "integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==", - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "mkdirp": { - "version": "0.5.1", - "resolved": false, - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "resolved": false, - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "optional": true - }, "nan": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.11.0.tgz", - "integrity": "sha512-F4miItu2rGnV2ySkXOQoA8FKz/SR2Q2sWP0sbTxNxz/tuokeC8WxOhPMcwi0qIyGtVn/rrSeLbvVkznqCdwYnw==", - "optional": true - }, - "needle": { - "version": "2.2.0", - "resolved": false, - "integrity": "sha512-eFagy6c+TYayorXw/qtAdSvaUpEbBsDwDyxYFgLZ0lTojfH7K+OdBqAF7TAFwDokJaGpubpSGG0wO3iC0XPi8w==", - "optional": true, - "requires": { - "debug": "^2.1.2", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.10.0", - "resolved": false, - "integrity": "sha512-G7kEonQLRbcA/mOoFoxvlMrw6Q6dPf92+t/l0DFSMuSlDoWaI9JWIyPwK0jyE1bph//CUEL65/Fz1m2vJbmjQQ==", - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.0", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.1.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } - }, - "nopt": { - "version": "4.0.1", - "resolved": false, - "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.0.3", - "resolved": false, - "integrity": "sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow==", - "optional": true - }, - "npm-packlist": { - "version": "1.1.10", - "resolved": false, - "integrity": "sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA==", - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "resolved": false, - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": false, - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" - }, - "object-assign": { - "version": "4.1.1", - "resolved": false, - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "optional": true - }, - "once": { - "version": "1.4.0", - "resolved": false, - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "resolved": false, - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": false, - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "optional": true - }, - "osenv": { - "version": "0.1.5", - "resolved": false, - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": false, - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "optional": true - }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": false, - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", - "optional": true - }, - "rc": { - "version": "1.2.7", - "resolved": false, - "integrity": "sha512-LdLD8xD4zzLsAT5xyushXDNscEjB7+2ulnl8+r1pnESlYtlJtVSoCMBGr30eDRJ3+2Gq89jK9P9e4tCEH1+ywA==", - "optional": true, - "requires": { - "deep-extend": "^0.5.1", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": false, - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "optional": true - } - } - }, - "readable-stream": { - "version": "2.3.6", - "resolved": false, - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rimraf": { - "version": "2.6.2", - "resolved": false, - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", - "optional": true, - "requires": { - "glob": "^7.0.5" - } - }, - "safe-buffer": { - "version": "5.1.1", - "resolved": false, - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": false, - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "optional": true - }, - "sax": { - "version": "1.2.4", - "resolved": false, - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "optional": true - }, - "semver": { - "version": "5.5.0", - "resolved": false, - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "resolved": false, - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "resolved": false, - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "optional": true - }, - "string-width": { - "version": "1.0.2", - "resolved": false, - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": false, - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": false, - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": false, - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "optional": true - }, - "tar": { - "version": "4.4.1", - "resolved": false, - "integrity": "sha512-O+v1r9yN4tOsvl90p5HAP4AEqbYhx4036AGMm075fH9F8Qwi3oJ+v4u50FkT/KkvywNGtwkk0zRI+8eYm1X/xg==", - "optional": true, - "requires": { - "chownr": "^1.0.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.2.4", - "minizlib": "^1.1.0", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.1", - "yallist": "^3.0.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": false, - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", + "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==", "optional": true - }, - "wide-align": { - "version": "1.1.2", - "resolved": false, - "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", - "optional": true, - "requires": { - "string-width": "^1.0.2" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": false, - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "yallist": { - "version": "3.0.2", - "resolved": false, - "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=" } } }, @@ -12987,7 +12462,7 @@ }, "readable-stream": { "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true, "requires": { @@ -13065,9 +12540,9 @@ } }, "ganache-core": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/ganache-core/-/ganache-core-2.1.5.tgz", - "integrity": "sha512-PuHUfISgrQknb7JpspxSzhpoYfqBWoOdTBHQj/81gu6YypRUHzD2Z6gZmFDxDzG30MFElEHp8JtexaGdgq9iYw==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ganache-core/-/ganache-core-2.2.1.tgz", + "integrity": "sha512-JMLZj7CKxtC5M0qceQYn8FLOx+CZyfISpSRfGdwnKy3juXO8siSAodjq8hviqUY1J0tEdEGqvNm16wSUxtiRjQ==", "dev": true, "requires": { "abstract-leveldown": "^3.0.0", @@ -13077,12 +12552,14 @@ "cachedown": "^1.0.0", "chai": "^3.5.0", "clone": "^2.1.1", + "eth-sig-util": "^2.0.2", + "ethereumjs-abi": "^0.6.5", "ethereumjs-account": "~2.0.4", "ethereumjs-block": "~1.2.2", "ethereumjs-tx": "1.3.4", "ethereumjs-util": "^5.2.0", "ethereumjs-vm": "2.3.5", - "ethereumjs-wallet": "~0.6.0", + "ethereumjs-wallet": "0.6.0", "fake-merkle-patricia-tree": "~1.0.1", "heap": "~0.2.6", "js-scrypt": "^0.2.0", @@ -13241,7 +12718,8 @@ "async-limiter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", - "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", + "dev": true }, "asynckit": { "version": "0.4.0", @@ -13877,7 +13355,7 @@ }, "babelify": { "version": "7.3.0", - "resolved": "http://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", + "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", "dev": true, "requires": { @@ -14082,6 +13560,7 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/browserify-sha3/-/browserify-sha3-0.0.1.tgz", "integrity": "sha1-P/NKMAbvFcD7NWflQbkaI0ASPRE=", + "dev": true, "requires": { "js-sha3": "^0.3.1" } @@ -15007,19 +14486,6 @@ "servify": "^0.1.12", "ws": "^3.0.0", "xhr-request-promise": "^0.1.2" - }, - "dependencies": { - "ws": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", - "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", - "dev": true, - "requires": { - "async-limiter": "~1.0.0", - "safe-buffer": "~5.1.0", - "ultron": "~1.1.0" - } - } } }, "eth-query": { @@ -15036,6 +14502,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-2.0.2.tgz", "integrity": "sha512-tB6E8jf/aZQ943bo3+iojl8xRe3Jzcl+9OT6v8K7kWis6PdIX19SB2vYvN849cB9G9m/XLjYFK381SgdbsnpTA==", + "dev": true, "requires": { "ethereumjs-abi": "0.6.5", "ethereumjs-util": "^5.1.1" @@ -15097,12 +14564,12 @@ "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "dev": true, "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", "ethereumjs-util": "^5.1.1" }, "dependencies": { "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "dev": true, "requires": { @@ -15201,7 +14668,9 @@ }, "ethereumjs-abi": { "version": "0.6.5", - "resolved": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.5.tgz", + "integrity": "sha1-WmN+8Wq0NHP6cqKa2QhxQFs/UkE=", + "dev": true, "requires": { "bn.js": "^4.10.0", "ethereumjs-util": "^4.3.0" @@ -15211,6 +14680,7 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-4.5.0.tgz", "integrity": "sha1-PpQosxfuvaPXJg2FT93alUsfG8Y=", + "dev": true, "requires": { "bn.js": "^4.8.0", "create-hash": "^1.1.2", @@ -16205,7 +15675,8 @@ "js-sha3": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.3.1.tgz", - "integrity": "sha1-hhIoAhQvCChQKg0d7h2V4lO7AkM=" + "integrity": "sha1-hhIoAhQvCChQKg0d7h2V4lO7AkM=", + "dev": true }, "js-tokens": { "version": "3.0.2", @@ -16330,6 +15801,7 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/keccakjs/-/keccakjs-0.2.1.tgz", "integrity": "sha1-HWM6+QfvMFu/ny+mFtVsRFYd+k0=", + "dev": true, "requires": { "browserify-sha3": "^0.0.1", "sha3": "^1.1.0" @@ -17769,6 +17241,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/sha3/-/sha3-1.2.2.tgz", "integrity": "sha1-pmxQmN5MJbyIM27ItIF9AFvKe6k=", + "dev": true, "requires": { "nan": "2.10.0" } @@ -18699,12 +18172,12 @@ "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "dev": true, "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", "ethereumjs-util": "^5.1.1" }, "dependencies": { "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "dev": true, "requires": { @@ -18716,7 +18189,7 @@ }, "ethereumjs-abi": { "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", - "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "from": "ethereumjs-abi@git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", "requires": { "bn.js": "^4.10.0", "ethereumjs-util": "^5.0.0" @@ -18859,11 +18332,14 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "ws": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", - "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, "requires": { - "async-limiter": "~1.0.0" + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" } }, "xhr": { @@ -19010,62 +18486,24 @@ } }, "geckodriver": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/geckodriver/-/geckodriver-1.11.0.tgz", - "integrity": "sha1-KFPM1PQg00fGFULa7teCyHpxhoc=", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/geckodriver/-/geckodriver-1.12.2.tgz", + "integrity": "sha512-nhTroSDoAjbws1GAALCBFGWcjUI7Uy5nLKJFKmOfOmVGCyn7TazdIYQJFpnre/vtKcieKwXOC8RqBD48g0a/4A==", "dev": true, "requires": { - "adm-zip": "0.4.7", + "adm-zip": "0.4.11", "bluebird": "3.4.6", "got": "5.6.0", + "https-proxy-agent": "2.2.1", "tar": "4.0.2" }, "dependencies": { "bluebird": { "version": "3.4.6", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.6.tgz", + "resolved": "http://registry.npmjs.org/bluebird/-/bluebird-3.4.6.tgz", "integrity": "sha1-AdqNgh2HgT0ViWfnQ9X+bGLPjA8=", "dev": true }, - "duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", - "dev": true, - "requires": { - "readable-stream": "^2.0.2" - } - }, - "got": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-5.6.0.tgz", - "integrity": "sha1-ux1+4WO3gIK7yOuDbz85UATqb78=", - "dev": true, - "requires": { - "create-error-class": "^3.0.1", - "duplexer2": "^0.1.4", - "is-plain-obj": "^1.0.0", - "is-redirect": "^1.0.0", - "is-retry-allowed": "^1.0.0", - "is-stream": "^1.0.0", - "lowercase-keys": "^1.0.0", - "node-status-codes": "^1.0.0", - "object-assign": "^4.0.1", - "parse-json": "^2.1.0", - "pinkie-promise": "^2.0.0", - "read-all-stream": "^3.0.0", - "readable-stream": "^2.0.5", - "timed-out": "^2.0.0", - "unzip-response": "^1.0.0", - "url-parse-lax": "^1.0.0" - } - }, - "prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", - "dev": true - }, "tar": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/tar/-/tar-4.0.2.tgz", @@ -19079,21 +18517,6 @@ "yallist": "^3.0.2" } }, - "timed-out": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-2.0.0.tgz", - "integrity": "sha1-84sK6B03R9YoAB9B2vxlKs5nHAo=", - "dev": true - }, - "url-parse-lax": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", - "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", - "dev": true, - "requires": { - "prepend-http": "^1.0.1" - } - }, "yallist": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz", @@ -19141,7 +18564,7 @@ }, "get-stream": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", "dev": true }, @@ -19207,7 +18630,7 @@ }, "commander": { "version": "2.15.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "resolved": "http://registry.npmjs.org/commander/-/commander-2.15.1.tgz", "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", "dev": true }, @@ -19322,13 +18745,13 @@ "dependencies": { "minimist": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.1.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.1.0.tgz", "integrity": "sha1-md9lelJXTCHJBXSX33QnkLK0wN4=", "dev": true }, "yargs": { "version": "1.2.6", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-1.2.6.tgz", + "resolved": "http://registry.npmjs.org/yargs/-/yargs-1.2.6.tgz", "integrity": "sha1-nHtKgv1dWVsr8Xq23MQxNUMv40s=", "dev": true, "requires": { @@ -19812,7 +19235,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" } } @@ -19841,6 +19264,41 @@ "sparkles": "^1.0.0" } }, + "got": { + "version": "5.6.0", + "resolved": "http://registry.npmjs.org/got/-/got-5.6.0.tgz", + "integrity": "sha1-ux1+4WO3gIK7yOuDbz85UATqb78=", + "dev": true, + "requires": { + "create-error-class": "^3.0.1", + "duplexer2": "^0.1.4", + "is-plain-obj": "^1.0.0", + "is-redirect": "^1.0.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "node-status-codes": "^1.0.0", + "object-assign": "^4.0.1", + "parse-json": "^2.1.0", + "pinkie-promise": "^2.0.0", + "read-all-stream": "^3.0.0", + "readable-stream": "^2.0.5", + "timed-out": "^2.0.0", + "unzip-response": "^1.0.0", + "url-parse-lax": "^1.0.0" + }, + "dependencies": { + "duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "dev": true, + "requires": { + "readable-stream": "^2.0.2" + } + } + } + }, "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", @@ -20194,7 +19652,7 @@ "dependencies": { "ansi-regex": { "version": "0.2.1", - "resolved": "http://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz", "integrity": "sha1-DY6UaWej2BQ/k+JOKYUl/BsiNfk=", "dev": true }, @@ -20206,7 +19664,7 @@ }, "chalk": { "version": "0.5.1", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz", "integrity": "sha1-Zjs6ZItotV0EaQ1JFnqoN4WPIXQ=", "dev": true, "requires": { @@ -20239,7 +19697,7 @@ }, "strip-ansi": { "version": "0.3.0", - "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz", "integrity": "sha1-JfSOoiynkYfzF0pNuHWTR7sSYiA=", "dev": true, "requires": { @@ -20524,7 +19982,7 @@ }, "gulp-stylelint": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/gulp-stylelint/-/gulp-stylelint-7.0.0.tgz", + "resolved": "http://registry.npmjs.org/gulp-stylelint/-/gulp-stylelint-7.0.0.tgz", "integrity": "sha512-0PI+tNTzaJz5+qO3i9Jyd04ZPSb+NCN7bZ2GaIArvbQpuyJha9p3lpWxPG+XJtrVT42bIiyLeYKPnLe7uW4dQQ==", "dev": true, "requires": { @@ -21389,7 +20847,7 @@ "dependencies": { "async": { "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "resolved": "http://registry.npmjs.org/async/-/async-1.5.2.tgz", "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", "dev": true } @@ -21412,6 +20870,17 @@ "minimalistic-assert": "^1.0.0" } }, + "hasha": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz", + "integrity": "sha1-eNfL/B5tZjA/55g3NlmEUXsvbuE=", + "dev": true, + "optional": true, + "requires": { + "is-stream": "^1.0.1", + "pinkie-promise": "^2.0.0" + } + }, "hat": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/hat/-/hat-0.0.3.tgz", @@ -21635,7 +21104,7 @@ }, "readable-stream": { "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true, "requires": { @@ -21653,7 +21122,7 @@ }, "through2": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/through2/-/through2-1.1.1.tgz", "integrity": "sha1-CEfLxESfNAVXTb3M2buEG4OsNUU=", "dev": true, "requires": { @@ -21707,7 +21176,7 @@ }, "readable-stream": { "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, "requires": { @@ -21725,7 +21194,7 @@ }, "through2": { "version": "0.4.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.4.2.tgz", + "resolved": "http://registry.npmjs.org/through2/-/through2-0.4.2.tgz", "integrity": "sha1-2/WGYDEVHsg1K7bE22SiKSqEC5s=", "dev": true, "requires": { @@ -21760,7 +21229,7 @@ }, "htmlescape": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz", "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=", "dev": true }, @@ -21860,7 +21329,7 @@ "dependencies": { "async": { "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "resolved": "http://registry.npmjs.org/async/-/async-1.5.2.tgz", "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", "dev": true }, @@ -21950,7 +21419,7 @@ }, "humanize-url": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/humanize-url/-/humanize-url-1.0.1.tgz", + "resolved": "http://registry.npmjs.org/humanize-url/-/humanize-url-1.0.1.tgz", "integrity": "sha1-9KuZ4NKIF0yk4eUEB8VfuuRk7/8=", "dev": true, "requires": { @@ -22036,7 +21505,7 @@ "dependencies": { "babelify": { "version": "7.3.0", - "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", + "resolved": "http://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", "requires": { "babel-core": "^6.0.14", @@ -22121,6 +21590,15 @@ "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.7.tgz", "integrity": "sha512-YGG3ejvBNHRqu0559EOxxNFihD0AjpvHlC/pdGKd3X3ofe+CoJkYazwNJYTNebqpPKN+VVQbh4ZFn1DivMNuHA==" }, + "ignore-walk": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", + "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, "ignorepatterns": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/ignorepatterns/-/ignorepatterns-1.1.0.tgz", @@ -22519,7 +21997,7 @@ }, "is-builtin-module": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "requires": { "builtin-modules": "^1.0.0" @@ -22701,7 +22179,7 @@ }, "is-obj": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "resolved": "http://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" }, "is-object": { @@ -23281,19 +22759,22 @@ "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=" }, "jshint": { - "version": "2.9.5", - "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.5.tgz", - "integrity": "sha1-HnJSkVzmgbQIJ+4UJIxG006apiw=", + "version": "2.9.6", + "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.6.tgz", + "integrity": "sha512-KO9SIAKTlJQOM4lE64GQUtGBRpTOuvbrRrSZw3AhUxMNG266nX9hK2cKA4SBhXOj0irJGyNyGSLT62HGOVDEOA==", "dev": true, "requires": { "cli": "~1.0.0", "console-browserify": "1.1.x", "exit": "0.1.x", "htmlparser2": "3.8.x", - "lodash": "3.7.x", + "lodash": "~4.17.10", "minimatch": "~3.0.2", + "phantom": "~4.0.1", + "phantomjs-prebuilt": "~2.1.7", "shelljs": "0.3.x", - "strip-json-comments": "1.0.x" + "strip-json-comments": "1.0.x", + "unicode-5.2.0": "^0.7.5" }, "dependencies": { "domhandler": { @@ -23307,13 +22788,13 @@ }, "entities": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/entities/-/entities-1.0.0.tgz", "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=", "dev": true }, "htmlparser2": { "version": "3.8.3", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", + "resolved": "http://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", "dev": true, "requires": { @@ -23330,15 +22811,9 @@ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", "dev": true }, - "lodash": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.7.0.tgz", - "integrity": "sha1-Nni9irmVBXwHreg27S7wh9qBHUU=", - "dev": true - }, "readable-stream": { "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true, "requires": { @@ -23411,7 +22886,7 @@ "dependencies": { "babelify": { "version": "7.3.0", - "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", + "resolved": "http://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", "requires": { "babel-core": "^6.0.14", @@ -23522,7 +22997,7 @@ }, "pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" } } @@ -23576,12 +23051,12 @@ }, "json5": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "resolved": "http://registry.npmjs.org/json5/-/json5-0.5.1.tgz", "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" }, "jsonfile": { "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "resolved": "http://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", "requires": { "graceful-fs": "^4.1.6" @@ -23601,7 +23076,7 @@ "dependencies": { "JSONStream": { "version": "0.8.4", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-0.8.4.tgz", + "resolved": "http://registry.npmjs.org/JSONStream/-/JSONStream-0.8.4.tgz", "integrity": "sha1-kWV9/m/4V0gwZhMrRhi2Lo9Ih70=", "dev": true, "requires": { @@ -23623,7 +23098,7 @@ }, "readable-stream": { "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, "requires": { @@ -23651,7 +23126,7 @@ }, "through2": { "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz", "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", "dev": true, "requires": { @@ -23836,19 +23311,19 @@ "dependencies": { "core-js": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.3.0.tgz", + "resolved": "http://registry.npmjs.org/core-js/-/core-js-2.3.0.tgz", "integrity": "sha1-+rg/uwstjchfpjbEudNMdUIMbWU=", "dev": true }, "es6-promise": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz", + "resolved": "http://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz", "integrity": "sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y=", "dev": true }, "readable-stream": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", "dev": true, "requires": { @@ -24354,7 +23829,7 @@ }, "kew": { "version": "0.7.0", - "resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz", + "resolved": "http://registry.npmjs.org/kew/-/kew-0.7.0.tgz", "integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=", "dev": true }, @@ -24469,7 +23944,7 @@ }, "readable-stream": { "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, "requires": { @@ -24487,7 +23962,7 @@ }, "through2": { "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz", "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", "dev": true, "requires": { @@ -24532,7 +24007,7 @@ }, "level-iterator-stream": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-1.3.1.tgz", + "resolved": "http://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-1.3.1.tgz", "integrity": "sha1-5Dt4sagUPm+pek9IXrjqUwNS8u0=", "requires": { "inherits": "^2.0.1", @@ -24548,7 +24023,7 @@ }, "readable-stream": { "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "requires": { "core-util-is": "~1.0.0", @@ -24585,7 +24060,7 @@ }, "readable-stream": { "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "requires": { "core-util-is": "~1.0.0", @@ -24660,7 +24135,7 @@ "dependencies": { "iconv-lite": { "version": "0.4.15", - "resolved": "http://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz", "integrity": "sha1-/iZaIYrGpXz+hUkn6dBMGYJe3es=", "dev": true } @@ -24712,7 +24187,7 @@ }, "load-json-file": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "requires": { "graceful-fs": "^4.1.2", @@ -24724,7 +24199,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" } } @@ -25149,7 +24624,7 @@ }, "bl": { "version": "1.1.2", - "resolved": "http://registry.npmjs.org/bl/-/bl-1.1.2.tgz", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.1.2.tgz", "integrity": "sha1-/cqHGplxOqANGeO7ukHER4emU5g=", "dev": true, "optional": true, @@ -25210,7 +24685,7 @@ }, "readable-stream": { "version": "2.0.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", "dev": true, "optional": true, @@ -25225,7 +24700,7 @@ }, "request": { "version": "2.75.0", - "resolved": "http://registry.npmjs.org/request/-/request-2.75.0.tgz", + "resolved": "https://registry.npmjs.org/request/-/request-2.75.0.tgz", "integrity": "sha1-0rgmiihtoT6qXQGt9dGMyQ9lfZM=", "dev": true, "optional": true, @@ -25345,7 +24820,7 @@ }, "magic-string": { "version": "0.22.5", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz", + "resolved": "http://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz", "integrity": "sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==", "dev": true, "requires": { @@ -25500,7 +24975,7 @@ }, "marked": { "version": "0.3.19", - "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.19.tgz", + "resolved": "http://registry.npmjs.org/marked/-/marked-0.3.19.tgz", "integrity": "sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg==", "dev": true }, @@ -25853,7 +25328,7 @@ }, "media-typer": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, "mem": { @@ -25920,7 +25395,7 @@ }, "meow": { "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "resolved": "http://registry.npmjs.org/meow/-/meow-3.7.0.tgz", "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", "requires": { "camelcase-keys": "^2.0.0", @@ -25974,7 +25449,7 @@ "dependencies": { "async": { "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "resolved": "http://registry.npmjs.org/async/-/async-1.5.2.tgz", "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" }, "ethereumjs-util": { @@ -26021,7 +25496,7 @@ }, "babelify": { "version": "7.3.0", - "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", + "resolved": "http://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", "requires": { "babel-core": "^6.0.14", @@ -26139,7 +25614,7 @@ }, "pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" }, "pump": { @@ -26167,107 +25642,10 @@ "safe-event-emitter": "^1.0.1" }, "dependencies": { - "async-eventemitter": { - "version": "github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", - "from": "github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", - "requires": { - "async": "^2.4.0" - } - }, - "eth-block-tracker": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-2.3.1.tgz", - "integrity": "sha512-NamWuMBIl8kmkJFVj8WzGatySTzQPQag4Xr677yFxdVtIxACFbL/dQowk0MzEqIKk93U1TwY3MjVU6mOcwZnKA==", - "requires": { - "async-eventemitter": "github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", - "eth-query": "^2.1.0", - "ethereumjs-tx": "^1.3.3", - "ethereumjs-util": "^5.1.3", - "ethjs-util": "^0.1.3", - "json-rpc-engine": "^3.6.0", - "pify": "^2.3.0", - "tape": "^4.6.3" - } - }, - "ethereumjs-util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", - "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "ethjs-util": "^0.1.3", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - }, - "ethjs-format": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/ethjs-format/-/ethjs-format-0.2.2.tgz", - "integrity": "sha1-1zs6YFwuElcHn3B3/VRI6ZjOD80=", - "requires": { - "bn.js": "4.11.6", - "ethjs-schema": "0.1.5", - "ethjs-util": "0.1.3", - "is-hex-prefixed": "1.0.0", - "number-to-bn": "1.7.0", - "strip-hex-prefix": "1.0.0" - }, - "dependencies": { - "bn.js": { - "version": "4.11.6", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", - "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=" - }, - "ethjs-util": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.3.tgz", - "integrity": "sha1-39XqSkANxeQhqInK9H4IGtp4u1U=", - "requires": { - "is-hex-prefixed": "1.0.0", - "strip-hex-prefix": "1.0.0" - } - } - } - }, - "ethjs-query": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/ethjs-query/-/ethjs-query-0.2.9.tgz", - "integrity": "sha1-om5rTzhpnpLzSyGE51x4lDKcQvE=", - "requires": { - "ethjs-format": "0.2.2", - "ethjs-rpc": "0.1.5" - } - }, - "ethjs-schema": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/ethjs-schema/-/ethjs-schema-0.1.5.tgz", - "integrity": "sha1-WXQOOzl3vNu5sRvDBoIB6Kzquw0=" - }, - "json-rpc-middleware-stream": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/json-rpc-middleware-stream/-/json-rpc-middleware-stream-2.1.0.tgz", - "integrity": "sha512-JxX+kbS9sDMHvnADFLlV/QtkgeIYVF/2R8UuxXaiZc7ntVEgi/lkzMGbGkDwdRg36rHnUIvCZk6zR/5Y3bAq1w==", - "requires": { - "end-of-stream": "^1.4.0", - "eth-block-tracker": "^2.1.2", - "ethjs-query": "^0.2.9", - "json-rpc-engine": "^3.8.0", - "readable-stream": "^2.3.3", - "safe-event-emitter": "^1.0.1" - } - }, "loglevel": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.1.tgz", "integrity": "sha1-4PyVEztu8nbNyIh82vJKpvFW+Po=" - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" } } }, @@ -26379,7 +25757,7 @@ "dependencies": { "debug": { "version": "2.2.0", - "resolved": "http://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", "dev": true, "requires": { @@ -26402,7 +25780,7 @@ }, "http-errors": { "version": "1.3.1", - "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.3.1.tgz", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.3.1.tgz", "integrity": "sha1-GX4izevUGYWF6GlO9nhhl7ke2UI=", "dev": true, "requires": { @@ -26412,13 +25790,13 @@ }, "iconv-lite": { "version": "0.4.13", - "resolved": "http://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI=", "dev": true }, "ms": { "version": "0.7.1", - "resolved": "http://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", "dev": true }, @@ -26476,7 +25854,6 @@ "version": "2.2.4", "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.2.4.tgz", "integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==", - "dev": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -26485,8 +25862,7 @@ "yallist": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz", - "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=", - "dev": true + "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=" } } }, @@ -26494,7 +25870,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.1.0.tgz", "integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==", - "dev": true, "requires": { "minipass": "^2.2.1" } @@ -26568,7 +25943,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "requires": { "minimist": "0.0.8" @@ -26921,7 +26296,7 @@ "dependencies": { "async": { "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "resolved": "http://registry.npmjs.org/async/-/async-1.5.2.tgz", "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", "dev": true }, @@ -26956,7 +26331,7 @@ }, "ncp": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ncp/-/ncp-1.0.1.tgz", + "resolved": "http://registry.npmjs.org/ncp/-/ncp-1.0.1.tgz", "integrity": "sha1-0VNn5cuHQyuhF9K/gP30Wuz7QkY=", "dev": true }, @@ -26977,7 +26352,6 @@ "version": "2.2.4", "resolved": "https://registry.npmjs.org/needle/-/needle-2.2.4.tgz", "integrity": "sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA==", - "dev": true, "requires": { "debug": "^2.1.2", "iconv-lite": "^0.4.4", @@ -27009,7 +26383,7 @@ }, "next-tick": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", "dev": true }, @@ -27142,7 +26516,7 @@ "dependencies": { "semver": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "resolved": "http://registry.npmjs.org/semver/-/semver-5.3.0.tgz", "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" } } @@ -27179,7 +26553,7 @@ "dependencies": { "buffer": { "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "resolved": "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", "requires": { "base64-js": "^1.0.2", @@ -27220,6 +26594,71 @@ "which": "^1.3.0" } }, + "node-pre-gyp": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz", + "integrity": "sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A==", + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + }, + "dependencies": { + "minipass": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.4.tgz", + "integrity": "sha512-mlouk1OHlaUE8Odt1drMtG1bAJA4ZA6B/ehysgV0LUIrDHdKgo1KorZq3pK0b/7Z7LJIQ12MNM6aC+Tn6lUZ5w==", + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "nopt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "tar": { + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.6.tgz", + "integrity": "sha512-tMkTnh9EdzxyfW+6GK6fCahagXsnYk6kE6S9Gr9pjVdys769+laCTbodXDhPAjzVtEBazRgP0gYqOjnk9dQzLg==", + "optional": true, + "requires": { + "chownr": "^1.0.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.3", + "minizlib": "^1.1.0", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "yallist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz", + "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=" + } + } + }, "node-sass": { "version": "4.9.2", "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.9.2.tgz", @@ -27436,6 +26875,22 @@ "once": "^1.3.2" } }, + "npm-bundled": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.5.tgz", + "integrity": "sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g==", + "optional": true + }, + "npm-packlist": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.1.11.tgz", + "integrity": "sha512-CxKlZ24urLkJk+9kCm48RTQ7L4hsmgSVzEk0TLGPzzyuFxD7VNgy5Sl24tOLMzQv773a/NeJ1ce1DKeacqffEA==", + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -27571,7 +27026,7 @@ }, "load-json-file": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "dev": true, "requires": { @@ -27603,7 +27058,7 @@ }, "pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, @@ -27782,7 +27237,7 @@ "dependencies": { "align-text": { "version": "0.1.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", "dev": true, "requires": { @@ -27793,19 +27248,19 @@ }, "amdefine": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", "dev": true }, "ansi-regex": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, "append-transform": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", "dev": true, "requires": { @@ -27814,31 +27269,31 @@ }, "archy": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", "dev": true }, "arrify": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", "dev": true }, "async": { "version": "1.5.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", "dev": true }, "balanced-match": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, "brace-expansion": { "version": "1.1.11", - "resolved": false, + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { @@ -27848,13 +27303,13 @@ }, "builtin-modules": { "version": "1.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", "dev": true }, "caching-transform": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-1.0.1.tgz", "integrity": "sha1-bb2y8g+Nj7znnz6U6dF0Lc31wKE=", "dev": true, "requires": { @@ -27865,7 +27320,7 @@ "dependencies": { "md5-hex": { "version": "1.3.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-1.3.0.tgz", "integrity": "sha1-0sSv6YPENwZiF5uMrRRSGRNQRsQ=", "dev": true, "requires": { @@ -27876,14 +27331,14 @@ }, "camelcase": { "version": "1.2.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", "dev": true, "optional": true }, "center-align": { "version": "0.1.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", "dev": true, "optional": true, @@ -27894,7 +27349,7 @@ }, "cliui": { "version": "2.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", "dev": true, "optional": true, @@ -27906,7 +27361,7 @@ "dependencies": { "wordwrap": { "version": "0.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", "dev": true, "optional": true @@ -27915,31 +27370,31 @@ }, "code-point-at": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, "commondir": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, "concat-map": { "version": "0.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, "convert-source-map": { "version": "1.5.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=", "dev": true }, "cross-spawn": { "version": "4.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", "dev": true, "requires": { @@ -27949,7 +27404,7 @@ }, "debug": { "version": "3.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, "requires": { @@ -27958,19 +27413,19 @@ }, "debug-log": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.1.tgz", "integrity": "sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8=", "dev": true }, "decamelize": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, "default-require-extensions": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", "dev": true, "requires": { @@ -27979,7 +27434,7 @@ "dependencies": { "strip-bom": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true } @@ -27987,7 +27442,7 @@ }, "error-ex": { "version": "1.3.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", "dev": true, "requires": { @@ -27996,7 +27451,7 @@ }, "execa": { "version": "0.7.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "dev": true, "requires": { @@ -28011,7 +27466,7 @@ "dependencies": { "cross-spawn": { "version": "5.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { @@ -28024,7 +27479,7 @@ }, "find-cache-dir": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", "dev": true, "requires": { @@ -28035,7 +27490,7 @@ }, "find-up": { "version": "2.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { @@ -28044,7 +27499,7 @@ }, "foreground-child": { "version": "1.5.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", "dev": true, "requires": { @@ -28054,25 +27509,25 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, "get-caller-file": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", "dev": true }, "get-stream": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", "dev": true }, "glob": { "version": "7.1.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { @@ -28086,13 +27541,13 @@ }, "graceful-fs": { "version": "4.1.11", - "resolved": false, + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", "dev": true }, "handlebars": { "version": "4.0.11", - "resolved": false, + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz", "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", "dev": true, "requires": { @@ -28104,7 +27559,7 @@ "dependencies": { "source-map": { "version": "0.4.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "dev": true, "requires": { @@ -28115,25 +27570,25 @@ }, "has-flag": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, "hosted-git-info": { "version": "2.6.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.0.tgz", "integrity": "sha512-lIbgIIQA3lz5XaB6vxakj6sDHADJiZadYEJB+FgA+C4nubM1NwcuvUr9EJPmnH1skZqpqUzWborWo8EIUi0Sdw==", "dev": true }, "imurmurhash": { "version": "0.1.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, "inflight": { "version": "1.0.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { @@ -28143,31 +27598,31 @@ }, "inherits": { "version": "2.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, "invert-kv": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", "dev": true }, "is-arrayish": { "version": "0.2.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, "is-buffer": { "version": "1.1.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, "is-builtin-module": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "dev": true, "requires": { @@ -28176,31 +27631,31 @@ }, "is-fullwidth-code-point": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, "is-stream": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, "isexe": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, "istanbul-lib-coverage": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.0.tgz", "integrity": "sha512-yMSw5xLIbdaxiVXHk3amfNM2WeBxLrwH/BCyZ9HvA/fylwziAIJOG2rKqWyLqEJqwKT725vxxqidv+SyynnGAA==", "dev": true }, "istanbul-lib-hook": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.0.tgz", "integrity": "sha512-qm3dt628HKpCVtIjbdZLuQyXn0+LO8qz+YHQDfkeXuSk5D+p299SEV5DrnUUnPi2SXvdMmWapMYWiuE75o2rUQ==", "dev": true, "requires": { @@ -28209,7 +27664,7 @@ }, "istanbul-lib-report": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.0.tgz", "integrity": "sha512-RiELmy9oIRYUv36ITOAhVum9PUvuj6bjyXVEKEHNiD1me6qXtxfx7vSEJWnjOGk2QmYw/GRFjLXWJv3qHpLceQ==", "dev": true, "requires": { @@ -28220,7 +27675,7 @@ }, "istanbul-lib-source-maps": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-2.0.0.tgz", "integrity": "sha512-jenUeC0gMSSMGkvqD9xuNfs3nD7XWeXLhqaIkqHsNZ3DJBWPdlKEydE7Ya5aTgdWjrEQhrCYTv+J606cGC2vuQ==", "dev": true, "requires": { @@ -28233,7 +27688,7 @@ "dependencies": { "source-map": { "version": "0.6.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } @@ -28241,7 +27696,7 @@ }, "istanbul-reports": { "version": "1.5.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.5.0.tgz", "integrity": "sha512-HeZG0WHretI9FXBni5wZ9DOgNziqDCEwetxnme5k1Vv5e81uTqcsy3fMH99gXGDGKr1ea87TyGseDMa2h4HEUA==", "dev": true, "requires": { @@ -28250,13 +27705,13 @@ }, "json-parse-better-errors": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, "kind-of": { "version": "3.2.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { @@ -28265,14 +27720,14 @@ }, "lazy-cache": { "version": "1.0.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", "dev": true, "optional": true }, "lcid": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", "dev": true, "requires": { @@ -28281,7 +27736,7 @@ }, "locate-path": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "dev": true, "requires": { @@ -28291,7 +27746,7 @@ "dependencies": { "path-exists": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true } @@ -28299,13 +27754,13 @@ }, "longest": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", "dev": true }, "lru-cache": { "version": "4.1.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", "dev": true, "requires": { @@ -28315,7 +27770,7 @@ }, "make-dir": { "version": "1.3.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", "dev": true, "requires": { @@ -28324,7 +27779,7 @@ "dependencies": { "pify": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true } @@ -28332,7 +27787,7 @@ }, "md5-hex": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-2.0.0.tgz", "integrity": "sha1-0FiOnxx0lUSS7NJKwKxs6ZfZLjM=", "dev": true, "requires": { @@ -28341,13 +27796,13 @@ }, "md5-o-matic": { "version": "0.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/md5-o-matic/-/md5-o-matic-0.1.1.tgz", "integrity": "sha1-givM1l4RfFFPqxdrJZRdVBAKA8M=", "dev": true }, "mem": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", "dev": true, "requires": { @@ -28356,7 +27811,7 @@ }, "merge-source-map": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", "dev": true, "requires": { @@ -28365,7 +27820,7 @@ "dependencies": { "source-map": { "version": "0.6.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } @@ -28373,13 +27828,13 @@ }, "mimic-fn": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", "dev": true }, "minimatch": { "version": "3.0.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { @@ -28388,13 +27843,13 @@ }, "minimist": { "version": "0.0.8", - "resolved": false, + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true }, "mkdirp": { "version": "0.5.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "requires": { @@ -28403,13 +27858,13 @@ }, "ms": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, "normalize-package-data": { "version": "2.4.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", "dev": true, "requires": { @@ -28421,7 +27876,7 @@ }, "npm-run-path": { "version": "2.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { @@ -28430,13 +27885,13 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, "once": { "version": "1.4.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { @@ -28445,7 +27900,7 @@ }, "optimist": { "version": "0.6.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "dev": true, "requires": { @@ -28455,13 +27910,13 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true }, "os-locale": { "version": "2.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", "dev": true, "requires": { @@ -28472,13 +27927,13 @@ }, "p-finally": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "dev": true }, "p-limit": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", "integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==", "dev": true, "requires": { @@ -28487,7 +27942,7 @@ }, "p-locate": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, "requires": { @@ -28496,25 +27951,25 @@ }, "p-try": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", "dev": true }, "path-is-absolute": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, "path-key": { "version": "2.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true }, "pkg-dir": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", "dev": true, "requires": { @@ -28523,37 +27978,37 @@ }, "pseudomap": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", "dev": true }, "repeat-string": { "version": "1.6.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", "dev": true }, "require-directory": { "version": "2.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, "require-main-filename": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", "dev": true }, "resolve-from": { "version": "4.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, "right-align": { "version": "0.1.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", "dev": true, "optional": true, @@ -28563,7 +28018,7 @@ }, "rimraf": { "version": "2.6.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "requires": { @@ -28572,19 +28027,19 @@ }, "semver": { "version": "5.5.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", "dev": true }, "set-blocking": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, "shebang-command": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { @@ -28593,32 +28048,32 @@ }, "shebang-regex": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, "signal-exit": { "version": "3.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, "slide": { "version": "1.1.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", "dev": true }, "source-map": { "version": "0.5.7", - "resolved": false, + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true, "optional": true }, "spawn-wrap": { "version": "1.4.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.2.tgz", "integrity": "sha512-vMwR3OmmDhnxCVxM8M+xO/FtIp6Ju/mNaDfCMMW7FDcLRTPFWUswec4LXJHTJE2hwTI9O0YBfygu4DalFl7Ylg==", "dev": true, "requires": { @@ -28632,7 +28087,7 @@ }, "spdx-correct": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", "dev": true, "requires": { @@ -28642,13 +28097,13 @@ }, "spdx-exceptions": { "version": "2.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==", "dev": true }, "spdx-expression-parse": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", "dev": true, "requires": { @@ -28658,13 +28113,13 @@ }, "spdx-license-ids": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==", "dev": true }, "string-width": { "version": "2.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { @@ -28674,7 +28129,7 @@ }, "strip-ansi": { "version": "4.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { @@ -28683,13 +28138,13 @@ }, "strip-eof": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, "supports-color": { "version": "5.4.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { @@ -28698,7 +28153,7 @@ }, "test-exclude": { "version": "4.2.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.2.2.tgz", "integrity": "sha512-2kTGf+3tykCfrWVREgyTR0bmVO0afE6i7zVXi/m+bZZ8ujV89Aulxdcdv32yH+unVFg3Y5o6GA8IzsHnGQuFgQ==", "dev": true, "requires": { @@ -28710,7 +28165,7 @@ "dependencies": { "load-json-file": { "version": "4.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", "dev": true, "requires": { @@ -28722,7 +28177,7 @@ }, "parse-json": { "version": "4.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", "dev": true, "requires": { @@ -28732,7 +28187,7 @@ }, "path-type": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, "requires": { @@ -28741,13 +28196,13 @@ }, "pify": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true }, "read-pkg": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", "dev": true, "requires": { @@ -28758,7 +28213,7 @@ }, "read-pkg-up": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", "dev": true, "requires": { @@ -28768,7 +28223,7 @@ }, "strip-bom": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true } @@ -28776,7 +28231,7 @@ }, "uglify-js": { "version": "2.8.29", - "resolved": false, + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", "dev": true, "optional": true, @@ -28788,7 +28243,7 @@ "dependencies": { "yargs": { "version": "3.10.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", "dev": true, "optional": true, @@ -28803,14 +28258,14 @@ }, "uglify-to-browserify": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", "dev": true, "optional": true }, "validate-npm-package-license": { "version": "3.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==", "dev": true, "requires": { @@ -28820,7 +28275,7 @@ }, "which": { "version": "1.3.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { @@ -28829,26 +28284,26 @@ }, "which-module": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, "window-size": { "version": "0.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", "dev": true, "optional": true }, "wordwrap": { "version": "0.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", "dev": true }, "wrap-ansi": { "version": "2.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { @@ -28858,13 +28313,13 @@ "dependencies": { "ansi-regex": { "version": "2.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "requires": { @@ -28873,7 +28328,7 @@ }, "string-width": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { @@ -28884,7 +28339,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { @@ -28895,13 +28350,13 @@ }, "wrappy": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, "write-file-atomic": { "version": "1.3.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz", "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=", "dev": true, "requires": { @@ -28912,19 +28367,19 @@ }, "y18n": { "version": "3.2.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", "dev": true }, "yallist": { "version": "2.1.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", "dev": true }, "yargs": { "version": "11.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz", "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==", "dev": true, "requires": { @@ -28944,13 +28399,13 @@ "dependencies": { "camelcase": { "version": "4.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", "dev": true }, "cliui": { "version": "4.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", "dev": true, "requires": { @@ -28961,7 +28416,7 @@ }, "yargs-parser": { "version": "9.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", "dev": true, "requires": { @@ -28972,7 +28427,7 @@ }, "yargs-parser": { "version": "9.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", "dev": true, "requires": { @@ -28981,7 +28436,7 @@ "dependencies": { "camelcase": { "version": "4.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", "dev": true } @@ -29258,7 +28713,7 @@ "dependencies": { "babelify": { "version": "7.3.0", - "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", + "resolved": "http://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", "requires": { "babel-core": "^6.0.14", @@ -29368,24 +28823,12 @@ } }, "original": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/original/-/original-1.0.0.tgz", - "integrity": "sha1-kUf5P6FpbQS+YeAb1QuurKZWvTs=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", + "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", "dev": true, "requires": { - "url-parse": "1.0.x" - }, - "dependencies": { - "url-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.0.5.tgz", - "integrity": "sha1-CFSGBCKv3P7+tsllxmLUgAFpkns=", - "dev": true, - "requires": { - "querystringify": "0.0.x", - "requires-port": "1.0.x" - } - } + "url-parse": "^1.4.3" } }, "os-browserify": { @@ -29400,7 +28843,7 @@ }, "os-locale": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", "requires": { "lcid": "^1.0.0" @@ -29778,7 +29221,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" } } @@ -29791,7 +29234,7 @@ }, "pause-stream": { "version": "0.0.11", - "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "resolved": "http://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", "dev": true, "requires": { @@ -29826,6 +29269,98 @@ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, + "phantom": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/phantom/-/phantom-4.0.12.tgz", + "integrity": "sha512-Tz82XhtPmwCk1FFPmecy7yRGZG2btpzY2KI9fcoPT7zT9det0CcMyfBFPp1S8DqzsnQnm8ZYEfdy528mwVtksA==", + "dev": true, + "optional": true, + "requires": { + "phantomjs-prebuilt": "^2.1.16", + "split": "^1.0.1", + "winston": "^2.4.0" + }, + "dependencies": { + "async": { + "version": "1.0.0", + "resolved": "http://registry.npmjs.org/async/-/async-1.0.0.tgz", + "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=", + "dev": true, + "optional": true + }, + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "dev": true, + "optional": true + }, + "split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "dev": true, + "optional": true, + "requires": { + "through": "2" + } + }, + "winston": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.4.tgz", + "integrity": "sha512-NBo2Pepn4hK4V01UfcWcDlmiVTs7VTB1h7bgnB0rgP146bYhMxX0ypCz3lBOfNxCO4Zuek7yeT+y/zM1OfMw4Q==", + "dev": true, + "optional": true, + "requires": { + "async": "~1.0.0", + "colors": "1.0.x", + "cycle": "1.0.x", + "eyes": "0.1.x", + "isstream": "0.1.x", + "stack-trace": "0.0.x" + } + } + } + }, + "phantomjs-prebuilt": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.16.tgz", + "integrity": "sha1-79ISpKOWbTZHaE6ouniFSb4q7+8=", + "dev": true, + "optional": true, + "requires": { + "es6-promise": "^4.0.3", + "extract-zip": "^1.6.5", + "fs-extra": "^1.0.0", + "hasha": "^2.2.0", + "kew": "^0.7.0", + "progress": "^1.1.8", + "request": "^2.81.0", + "request-progress": "^2.0.1", + "which": "^1.2.10" + }, + "dependencies": { + "fs-extra": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", + "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", + "dev": true, + "optional": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0" + } + }, + "progress": { + "version": "1.1.8", + "resolved": "http://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", + "dev": true, + "optional": true + } + } + }, "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", @@ -30024,7 +29559,7 @@ "dependencies": { "through2": { "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz", "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", "dev": true, "requires": { @@ -30063,7 +29598,7 @@ }, "readable-stream": { "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, "requires": { @@ -30081,7 +29616,7 @@ }, "through2": { "version": "0.2.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.2.3.tgz", + "resolved": "http://registry.npmjs.org/through2/-/through2-0.2.3.tgz", "integrity": "sha1-6zKE2k6jEbbMis42U3SKUqvyWj8=", "dev": true, "requires": { @@ -30091,7 +29626,7 @@ "dependencies": { "readable-stream": { "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true, "requires": { @@ -30197,7 +29732,7 @@ }, "portfinder": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-0.2.1.tgz", + "resolved": "http://registry.npmjs.org/portfinder/-/portfinder-0.2.1.tgz", "integrity": "sha1-srmwFk+eF/o6nH2yME0KdRQMca0=", "dev": true, "requires": { @@ -30206,7 +29741,7 @@ "dependencies": { "mkdirp": { "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.0.7.tgz", + "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.0.7.tgz", "integrity": "sha1-2JtPDkw+XlylQjWTFnXglP4aUHI=", "dev": true } @@ -30275,7 +29810,7 @@ }, "postcss-calc": { "version": "5.3.1", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-5.3.1.tgz", + "resolved": "http://registry.npmjs.org/postcss-calc/-/postcss-calc-5.3.1.tgz", "integrity": "sha1-d7rnypKK2FcW4v2kLyYb98HWW14=", "requires": { "postcss": "^5.0.2", @@ -30397,7 +29932,7 @@ }, "postcss-discard-comments": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz", + "resolved": "http://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz", "integrity": "sha1-vv6J+v1bPazlzM5Rt2uBUUvgDj0=", "requires": { "postcss": "^5.0.14" @@ -30475,7 +30010,7 @@ }, "postcss-discard-empty": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz", + "resolved": "http://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz", "integrity": "sha1-0rS9nVztXr2Nyt52QMfXzX9PkrU=", "requires": { "postcss": "^5.0.14" @@ -30514,7 +30049,7 @@ }, "postcss-discard-overridden": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz", + "resolved": "http://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz", "integrity": "sha1-ix6vVU9ob7KIzYdMVWZ7CqNmjVg=", "requires": { "postcss": "^5.0.16" @@ -30553,7 +30088,7 @@ }, "postcss-discard-unused": { "version": "2.2.3", - "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz", + "resolved": "http://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz", "integrity": "sha1-vOMLLMWR/8Y0Mitfs0ZLbZNPRDM=", "requires": { "postcss": "^5.0.14", @@ -30641,7 +30176,7 @@ }, "postcss-less": { "version": "0.14.0", - "resolved": "https://registry.npmjs.org/postcss-less/-/postcss-less-0.14.0.tgz", + "resolved": "http://registry.npmjs.org/postcss-less/-/postcss-less-0.14.0.tgz", "integrity": "sha1-xjGwicbM5CK5oQ86lY0r7dOBkyQ=", "dev": true, "requires": { @@ -30748,7 +30283,7 @@ }, "postcss-merge-idents": { "version": "2.1.7", - "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz", + "resolved": "http://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz", "integrity": "sha1-TFUwMTwI4dWzu/PSu8dH4njuonA=", "requires": { "has": "^1.0.1", @@ -30885,7 +30420,7 @@ }, "postcss-minify-font-values": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz", + "resolved": "http://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz", "integrity": "sha1-S1jttWZB66fIR0qzUmyv17vey2k=", "requires": { "object-assign": "^4.0.1", @@ -30926,7 +30461,7 @@ }, "postcss-minify-gradients": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz", + "resolved": "http://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz", "integrity": "sha1-Xb2hE3NwP4PPtKPqOIHY11/15uE=", "requires": { "postcss": "^5.0.12", @@ -30966,7 +30501,7 @@ }, "postcss-minify-params": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz", + "resolved": "http://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz", "integrity": "sha1-rSzgcTc7lDs9kwo/pZo1jCjW8fM=", "requires": { "alphanum-sort": "^1.0.1", @@ -31008,7 +30543,7 @@ }, "postcss-minify-selectors": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz", + "resolved": "http://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz", "integrity": "sha1-ssapjAByz5G5MtGkllCBFDEXNb8=", "requires": { "alphanum-sort": "^1.0.2", @@ -31085,7 +30620,7 @@ }, "postcss-normalize-charset": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz", "integrity": "sha1-757nEhLX/nWceO0WL2HtYrXLk/E=", "requires": { "postcss": "^5.0.5" @@ -31124,7 +30659,7 @@ }, "postcss-normalize-url": { "version": "3.0.8", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz", + "resolved": "http://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz", "integrity": "sha1-EI90s/L82viRov+j6kWSJ5/HgiI=", "requires": { "is-absolute-url": "^2.0.0", @@ -31239,7 +30774,7 @@ }, "postcss-reduce-idents": { "version": "2.4.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz", + "resolved": "http://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz", "integrity": "sha1-wsbSDMlYKE9qv75j92Cb9AkFmtM=", "requires": { "postcss": "^5.0.4", @@ -31279,7 +30814,7 @@ }, "postcss-reduce-initial": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz", + "resolved": "http://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz", "integrity": "sha1-aPgGlfBF0IJjqHmtJA343WT2ROo=", "requires": { "postcss": "^5.0.4" @@ -31318,7 +30853,7 @@ }, "postcss-reduce-transforms": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz", + "resolved": "http://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz", "integrity": "sha1-/3b02CEkN7McKYpC0uFEQCV3GuE=", "requires": { "has": "^1.0.1", @@ -31518,7 +31053,7 @@ }, "postcss-svgo": { "version": "2.1.6", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-2.1.6.tgz", + "resolved": "http://registry.npmjs.org/postcss-svgo/-/postcss-svgo-2.1.6.tgz", "integrity": "sha1-tt8YqmE7Zm4TPwittSGcJoSsEI0=", "requires": { "is-svg": "^2.0.0", @@ -31560,7 +31095,7 @@ }, "postcss-unique-selectors": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz", + "resolved": "http://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz", "integrity": "sha1-mB1X0p3csz57Hf4f1DuGSfkzyh0=", "requires": { "alphanum-sort": "^1.0.1", @@ -31606,7 +31141,7 @@ }, "postcss-zindex": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-2.2.0.tgz", + "resolved": "http://registry.npmjs.org/postcss-zindex/-/postcss-zindex-2.2.0.tgz", "integrity": "sha1-0hCd3AVbka9n/EyzsCWUZjnSryI=", "requires": { "has": "^1.0.1", @@ -31670,6 +31205,12 @@ } } }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + }, "preserve": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", @@ -32026,12 +31567,6 @@ "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" }, - "querystringify": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-0.0.4.tgz", - "integrity": "sha1-DPf4T5Rj/wrlHExLFC2VvjdyTZw=", - "dev": true - }, "quick-format-unescaped": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-3.0.0.tgz", @@ -32055,7 +31590,7 @@ "dependencies": { "chokidar": { "version": "1.6.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.6.1.tgz", + "resolved": "http://registry.npmjs.org/chokidar/-/chokidar-1.6.1.tgz", "integrity": "sha1-L0RHq16W5Q+z14n9kNTHLg5McMI=", "dev": true, "requires": { @@ -32072,7 +31607,7 @@ }, "commander": { "version": "2.9.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "resolved": "http://registry.npmjs.org/commander/-/commander-2.9.0.tgz", "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", "dev": true, "requires": { @@ -32197,7 +31732,7 @@ "dependencies": { "inline-style-prefixer": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-2.0.5.tgz", + "resolved": "http://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-2.0.5.tgz", "integrity": "sha1-wVPH6I/YT+9cYC6VqBaLJ3BnH+c=", "dev": true, "requires": { @@ -32296,11 +31831,6 @@ "eve-raphael": "0.5.0" } }, - "raven-js": { - "version": "3.24.2", - "resolved": "https://registry.npmjs.org/raven-js/-/raven-js-3.24.2.tgz", - "integrity": "sha512-Dy/FHDxuo5pXywVf8Nrs5utB2juMATpkxWGqHjVbpFD3m8CaWYLvkB5SEXjWFUZ5GvUsrBVVQ+Dfcp0x6Z7SOg==" - }, "raw-body": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", @@ -32312,6 +31842,26 @@ "unpipe": "1.0.0" } }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "optional": true + } + } + }, "react": { "version": "15.6.2", "resolved": "https://registry.npmjs.org/react/-/react-15.6.2.tgz", @@ -32397,9 +31947,9 @@ } }, "react-dev-utils": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-5.0.1.tgz", - "integrity": "sha512-+y92rG6pmXt3cpcg/NGmG4w/W309tWNSmyyPL8hCMxuCSg2UP/hUg3npACj2UZc8UKVSXexyLrCnxowizGoAsw==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-5.0.3.tgz", + "integrity": "sha512-Mvs6ofsc2xTjeZIrMaIfbXfsPVrbdVy/cVqq6SAacnqfMlcBpDuivhWZ1ODGeJ8HgmyWTLH971PYjj/EPCDVAw==", "dev": true, "requires": { "address": "1.0.3", @@ -32414,12 +31964,43 @@ "inquirer": "3.3.0", "is-root": "1.0.0", "opn": "5.2.0", - "react-error-overlay": "^4.0.0", + "react-error-overlay": "^4.0.1", "recursive-readdir": "2.2.1", "shell-quote": "1.6.1", - "sockjs-client": "1.1.4", + "sockjs-client": "1.1.5", "strip-ansi": "3.0.1", "text-table": "0.2.0" + }, + "dependencies": { + "faye-websocket": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.1.tgz", + "integrity": "sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg=", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "react-error-overlay": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-4.0.1.tgz", + "integrity": "sha512-xXUbDAZkU08aAkjtUvldqbvI04ogv+a1XdHxvYuHPYKIVk/42BIOD0zSKTHAWV4+gDy3yGm283z2072rA2gdtw==", + "dev": true + }, + "sockjs-client": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.1.5.tgz", + "integrity": "sha1-G7fA9yIsQPQq3xT0RCy9Eml3GoM=", + "dev": true, + "requires": { + "debug": "^2.6.6", + "eventsource": "0.1.6", + "faye-websocket": "~0.11.0", + "inherits": "^2.0.1", + "json3": "^3.3.2", + "url-parse": "^1.1.8" + } + } } }, "react-docgen": { @@ -32490,12 +32071,6 @@ "prop-types": "^15.5.10" } }, - "react-error-overlay": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-4.0.0.tgz", - "integrity": "sha512-FlsPxavEyMuR6TjVbSSywovXSEyOg6ZDj5+Z8nbsRl9EkOzAhEIcS+GLoQDC5fz/t9suhUXWmUrOBrgeUvrMxw==", - "dev": true - }, "react-event-listener": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/react-event-listener/-/react-event-listener-0.5.3.tgz", @@ -32970,7 +32545,7 @@ }, "readable-stream": { "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true, "requires": { @@ -33117,7 +32692,7 @@ }, "reduce-css-calc": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz", + "resolved": "http://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz", "integrity": "sha1-dHyRTgSWFKTJz7umKYca0dKSdxY=", "requires": { "balanced-match": "^0.4.2", @@ -33239,7 +32814,7 @@ }, "regexpp": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", "dev": true }, @@ -33255,7 +32830,7 @@ }, "regjsgen": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "resolved": "http://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=" }, "regjsparser": { @@ -33494,6 +33069,16 @@ } } }, + "request-progress": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz", + "integrity": "sha1-XTa7V5YcZzqlt4jbyBQf3yO0Tgg=", + "dev": true, + "optional": true, + "requires": { + "throttleit": "^1.0.0" + } + }, "request-promise": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.2.tgz", @@ -33723,7 +33308,7 @@ "dependencies": { "convert-source-map": { "version": "0.3.5", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-0.3.5.tgz", + "resolved": "http://registry.npmjs.org/convert-source-map/-/convert-source-map-0.3.5.tgz", "integrity": "sha1-8dgClQr33SYxof6+BZZVDIarMZA=", "dev": true } @@ -33857,7 +33442,7 @@ }, "safe-regex": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "requires": { "ret": "~0.1.10" @@ -33883,7 +33468,7 @@ "dependencies": { "babelify": { "version": "7.3.0", - "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", + "resolved": "http://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", "requires": { "babel-core": "^6.0.14", @@ -34030,7 +33615,7 @@ }, "readable-stream": { "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, "requires": { @@ -34048,7 +33633,7 @@ }, "through2": { "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz", "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", "dev": true, "requires": { @@ -34318,7 +33903,7 @@ }, "shasum": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz", + "resolved": "http://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz", "integrity": "sha1-5wEjENj0F/TetXEhUOVni4euVl8=", "dev": true, "requires": { @@ -35387,31 +34972,6 @@ } } }, - "sockjs-client": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.1.4.tgz", - "integrity": "sha1-W6vjhrd15M8U51IJEUUmVAFsixI=", - "dev": true, - "requires": { - "debug": "^2.6.6", - "eventsource": "0.1.6", - "faye-websocket": "~0.11.0", - "inherits": "^2.0.1", - "json3": "^3.3.2", - "url-parse": "^1.1.8" - }, - "dependencies": { - "faye-websocket": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.1.tgz", - "integrity": "sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg=", - "dev": true, - "requires": { - "websocket-driver": ">=0.5.1" - } - } - } - }, "socks": { "version": "1.1.10", "resolved": "https://registry.npmjs.org/socks/-/socks-1.1.10.tgz", @@ -35458,7 +35018,7 @@ }, "yargs": { "version": "4.8.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", + "resolved": "http://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", "integrity": "sha1-wMQpJMpKqmsObaFznfshZDn53cA=", "requires": { "cliui": "^3.2.0", @@ -35479,7 +35039,7 @@ }, "yargs-parser": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", + "resolved": "http://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", "integrity": "sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ=", "requires": { "camelcase": "^3.0.0", @@ -35577,7 +35137,7 @@ }, "split": { "version": "0.3.3", - "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", + "resolved": "http://registry.npmjs.org/split/-/split-0.3.3.tgz", "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", "dev": true, "requires": { @@ -35628,7 +35188,7 @@ }, "readable-stream": { "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, "requires": { @@ -35646,7 +35206,7 @@ }, "through2": { "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "resolved": "http://registry.npmjs.org/through2/-/through2-0.6.5.tgz", "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", "dev": true, "requires": { @@ -35834,7 +35394,7 @@ "dependencies": { "ansi-regex": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz", + "resolved": "http://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz", "integrity": "sha1-DY6UaWej2BQ/k+JOKYUl/BsiNfk=", "dev": true }, @@ -35846,7 +35406,7 @@ }, "chalk": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz", "integrity": "sha1-Zjs6ZItotV0EaQ1JFnqoN4WPIXQ=", "dev": true, "requires": { @@ -35868,7 +35428,7 @@ }, "strip-ansi": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz", + "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz", "integrity": "sha1-JfSOoiynkYfzF0pNuHWTR7sSYiA=", "dev": true, "requires": { @@ -36014,7 +35574,7 @@ }, "readable-stream": { "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true, "requires": { @@ -36032,7 +35592,7 @@ }, "through2": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/through2/-/through2-1.1.1.tgz", "integrity": "sha1-CEfLxESfNAVXTb3M2buEG4OsNUU=", "dev": true, "requires": { @@ -36166,7 +35726,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { "ansi-regex": "^2.0.0" @@ -36207,7 +35767,7 @@ }, "strip-eof": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, @@ -36595,7 +36155,7 @@ }, "pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, @@ -36865,7 +36425,7 @@ "dependencies": { "babelify": { "version": "7.3.0", - "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", + "resolved": "http://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", "requires": { "babel-core": "^6.0.14", @@ -36890,7 +36450,7 @@ "dependencies": { "babelify": { "version": "7.3.0", - "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", + "resolved": "http://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", "requires": { "babel-core": "^6.0.14", @@ -36935,7 +36495,7 @@ "dependencies": { "css-color-names": { "version": "0.0.3", - "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.3.tgz", + "resolved": "http://registry.npmjs.org/css-color-names/-/css-color-names-0.0.3.tgz", "integrity": "sha1-3gzvFvTYqoIioyDVttfpu62nufY=", "dev": true } @@ -37062,7 +36622,7 @@ }, "tar": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", + "resolved": "http://registry.npmjs.org/tar/-/tar-2.2.1.tgz", "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", "requires": { "block-stream": "*", @@ -37228,7 +36788,7 @@ }, "text-encoding": { "version": "0.6.4", - "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", + "resolved": "http://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=" }, "text-table": { @@ -37293,14 +36853,21 @@ "thenify": ">= 3.1.0 < 4" } }, + "throttleit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", + "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=", + "dev": true, + "optional": true + }, "through": { "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, "through2": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "resolved": "http://registry.npmjs.org/through2/-/through2-2.0.3.tgz", "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", "requires": { "readable-stream": "^2.1.5", @@ -37335,6 +36902,12 @@ "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=" }, + "timed-out": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-2.0.0.tgz", + "integrity": "sha1-84sK6B03R9YoAB9B2vxlKs5nHAo=", + "dev": true + }, "timers-browserify": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", @@ -37667,7 +37240,7 @@ }, "readable-stream": { "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true, "requires": { @@ -37685,7 +37258,7 @@ }, "through2": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/through2/-/through2-1.1.1.tgz", "integrity": "sha1-CEfLxESfNAVXTb3M2buEG4OsNUU=", "dev": true, "requires": { @@ -37813,7 +37386,7 @@ }, "yargs": { "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "resolved": "http://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", "dev": true, "requires": { @@ -37984,6 +37557,12 @@ "xtend": "^4.0.1" } }, + "unicode-5.2.0": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/unicode-5.2.0/-/unicode-5.2.0-0.7.5.tgz", + "integrity": "sha512-KVGLW1Bri30x00yv4HNM8kBxoqFXr0Sbo55735nvrlsx4PYBZol3UtoWgO492fSwmsetzPEZzy73rbU8OGXJcA==", + "dev": true + }, "unified": { "version": "6.1.6", "resolved": "https://registry.npmjs.org/unified/-/unified-6.1.6.tgz", @@ -38256,9 +37835,9 @@ } }, "url-parse": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.0.tgz", - "integrity": "sha512-ERuGxDiQ6Xw/agN4tuoCRbmwRuZP0cJ1lJxJubXr5Q/5cDa78+Dc4wfvtxzhzhkm5VvmW6Mf8EVj9SPGN4l8Lg==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.4.tgz", + "integrity": "sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg==", "dev": true, "requires": { "querystringify": "^2.0.0", @@ -38266,13 +37845,22 @@ }, "dependencies": { "querystringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.0.0.tgz", - "integrity": "sha512-eTPo5t/4bgaMNZxyjWx6N2a6AuE0mq51KWvpc7nU/MAqixcI6v6KrGUKES0HaomdnolQBBXU/++X6/QQ9KL4tw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.0.tgz", + "integrity": "sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg==", "dev": true } } }, + "url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "dev": true, + "requires": { + "prepend-http": "^1.0.1" + } + }, "user-home": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", @@ -38302,7 +37890,7 @@ }, "utf8": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.2.tgz", + "resolved": "http://registry.npmjs.org/utf8/-/utf8-2.1.2.tgz", "integrity": "sha1-H6DZJw6b6FDZsFAn9jUZv0ZFfZY=" }, "util": { @@ -38347,7 +37935,7 @@ "dependencies": { "async": { "version": "0.9.2", - "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "resolved": "http://registry.npmjs.org/async/-/async-0.9.2.tgz", "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=", "dev": true }, @@ -38534,7 +38122,7 @@ }, "pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, @@ -39033,7 +38621,7 @@ "dependencies": { "async": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/async/-/async-1.0.0.tgz", "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=", "dev": true }, @@ -39085,7 +38673,7 @@ }, "wrap-ansi": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "requires": { "string-width": "^1.0.1", @@ -39210,7 +38798,7 @@ }, "xmlbuilder": { "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "resolved": "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", "dev": true }, @@ -39260,7 +38848,7 @@ }, "yargs": { "version": "6.6.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz", + "resolved": "http://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz", "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=", "requires": { "camelcase": "^3.0.0", @@ -39280,7 +38868,7 @@ }, "yargs-parser": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz", + "resolved": "http://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz", "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=", "requires": { "camelcase": "^3.0.0" diff --git a/package.json b/package.json index 4114376a0..dd7496929 100644 --- a/package.json +++ b/package.json @@ -82,6 +82,7 @@ }, "dependencies": { "@material-ui/core": "1.0.0", + "@sentry/browser": "^4.1.1", "@zxing/library": "^0.8.0", "abi-decoder": "^1.0.9", "asmcrypto.js": "0.22.0", @@ -97,7 +98,7 @@ "browserify-derequire": "^0.9.4", "browserify-unibabel": "^3.0.0", "classnames": "^2.2.5", - "clone": "^2.1.1", + "clone": "^2.1.2", "copy-to-clipboard": "^3.0.8", "css-loader": "^0.28.11", "currency-formatter": "^1.4.2", @@ -112,7 +113,7 @@ "ensnare": "^1.0.0", "eslint-plugin-react": "^7.4.0", "eth-bin-to-ops": "^1.0.1", - "eth-block-tracker": "^4.0.3", + "eth-block-tracker": "^4.1.0", "eth-contract-metadata": "github:MetaMask/eth-contract-metadata#master", "eth-ens-namehash": "^2.0.8", "eth-hd-keyring": "^1.2.2", @@ -186,7 +187,6 @@ "pumpify": "^1.3.4", "qrcode-npm": "0.0.3", "ramda": "^0.24.1", - "raven-js": "^3.24.2", "react": "^15.6.2", "react-addons-css-transition-group": "^15.6.0", "react-dom": "^15.6.2", @@ -261,7 +261,7 @@ "eslint-plugin-json": "^1.2.0", "eslint-plugin-mocha": "^5.0.0", "eslint-plugin-react": "^7.4.0", - "eth-json-rpc-middleware": "^3.1.3", + "eth-json-rpc-middleware": "^3.1.6", "eth-keyring-controller": "^3.3.1", "fetch-mock": "^6.5.2", "file-loader": "^1.1.11", diff --git a/test/data/mock-state.json b/test/data/mock-state.json index 7e083c60e..8deff5531 100644 --- a/test/data/mock-state.json +++ b/test/data/mock-state.json @@ -111,7 +111,9 @@ "0x108cf70c7d384c552f42c07c41c0e1e46d77ea0d": 0.00039345803819379796, "0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5": 0.00008189274407698049 }, + "ticker": "ETH", "currentCurrency": "usd", + "nativeCurrency": "ETH", "conversionRate": 556.12, "addressBook": [ { @@ -1248,4 +1250,4 @@ "context": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc" } } -}
\ No newline at end of file +} diff --git a/test/e2e/beta/contract-test/contract.js b/test/e2e/beta/contract-test/contract.js index 39e7238ae..65fb9377f 100644 --- a/test/e2e/beta/contract-test/contract.js +++ b/test/e2e/beta/contract-test/contract.js @@ -28,114 +28,115 @@ The `piggybankContract` is compiled from: } */ -var piggybankContract = web3.eth.contract([{'constant': false, 'inputs': [{'name': 'withdrawAmount', 'type': 'uint256'}], 'name': 'withdraw', 'outputs': [{'name': 'remainingBal', 'type': 'uint256'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'owner', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [], 'name': 'deposit', 'outputs': [{'name': '', 'type': 'uint256'}], 'payable': true, 'stateMutability': 'payable', 'type': 'function'}, {'inputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'constructor'}]) -const deployButton = document.getElementById('deployButton') -const depositButton = document.getElementById('depositButton') -const withdrawButton = document.getElementById('withdrawButton') -const sendButton = document.getElementById('sendButton') -const createToken = document.getElementById('createToken') -const transferTokens = document.getElementById('transferTokens') -const approveTokens = document.getElementById('approveTokens') - -deployButton.addEventListener('click', async function (event) { - document.getElementById('contractStatus').innerHTML = 'Deploying' - - var piggybank = await piggybankContract.new( - { - from: web3.eth.accounts[0], - data: '0x608060405234801561001057600080fd5b5033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000808190555061023b806100686000396000f300608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632e1a7d4d1461005c5780638da5cb5b1461009d578063d0e30db0146100f4575b600080fd5b34801561006857600080fd5b5061008760048036038101908080359060200190929190505050610112565b6040518082815260200191505060405180910390f35b3480156100a957600080fd5b506100b26101d0565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100fc6101f6565b6040518082815260200191505060405180910390f35b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561017057600080fd5b8160008082825403925050819055503373ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f193505050501580156101c5573d6000803e3d6000fd5b506000549050919050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60003460008082825401925050819055506000549050905600a165627a7a72305820f237db3ec816a52589d82512117bc85bc08d3537683ffeff9059108caf3e5d400029', - gas: '4700000', - }, function (e, contract) { - if (e) { - throw e - } - if (typeof contract.address !== 'undefined') { - console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash) - - document.getElementById('contractStatus').innerHTML = 'Deployed' - - depositButton.addEventListener('click', function (event) { - document.getElementById('contractStatus').innerHTML = 'Deposit initiated' - contract.deposit({ from: web3.eth.accounts[0], value: '0x3782dace9d900000' }, function (result) { - console.log(result) - document.getElementById('contractStatus').innerHTML = 'Deposit completed' +web3.currentProvider.enable().then(() => { + var piggybankContract = web3.eth.contract([{'constant': false, 'inputs': [{'name': 'withdrawAmount', 'type': 'uint256'}], 'name': 'withdraw', 'outputs': [{'name': 'remainingBal', 'type': 'uint256'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'owner', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [], 'name': 'deposit', 'outputs': [{'name': '', 'type': 'uint256'}], 'payable': true, 'stateMutability': 'payable', 'type': 'function'}, {'inputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'constructor'}]) + const deployButton = document.getElementById('deployButton') + const depositButton = document.getElementById('depositButton') + const withdrawButton = document.getElementById('withdrawButton') + const sendButton = document.getElementById('sendButton') + const createToken = document.getElementById('createToken') + const transferTokens = document.getElementById('transferTokens') + const approveTokens = document.getElementById('approveTokens') + + deployButton.addEventListener('click', async function (event) { + document.getElementById('contractStatus').innerHTML = 'Deploying' + + var piggybank = await piggybankContract.new( + { + from: web3.eth.accounts[0], + data: '0x608060405234801561001057600080fd5b5033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000808190555061023b806100686000396000f300608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632e1a7d4d1461005c5780638da5cb5b1461009d578063d0e30db0146100f4575b600080fd5b34801561006857600080fd5b5061008760048036038101908080359060200190929190505050610112565b6040518082815260200191505060405180910390f35b3480156100a957600080fd5b506100b26101d0565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100fc6101f6565b6040518082815260200191505060405180910390f35b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561017057600080fd5b8160008082825403925050819055503373ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f193505050501580156101c5573d6000803e3d6000fd5b506000549050919050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60003460008082825401925050819055506000549050905600a165627a7a72305820f237db3ec816a52589d82512117bc85bc08d3537683ffeff9059108caf3e5d400029', + gas: '4700000', + }, function (e, contract) { + if (e) { + throw e + } + if (typeof contract.address !== 'undefined') { + console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash) + + document.getElementById('contractStatus').innerHTML = 'Deployed' + + depositButton.addEventListener('click', function (event) { + document.getElementById('contractStatus').innerHTML = 'Deposit initiated' + contract.deposit({ from: web3.eth.accounts[0], value: '0x3782dace9d900000' }, function (result) { + console.log(result) + document.getElementById('contractStatus').innerHTML = 'Deposit completed' + }) }) - }) - withdrawButton.addEventListener('click', function (event) { - contract.withdraw('0xde0b6b3a7640000', { from: web3.eth.accounts[0] }, function (result) { - console.log(result) - document.getElementById('contractStatus').innerHTML = 'Withdrawn' + withdrawButton.addEventListener('click', function (event) { + contract.withdraw('0xde0b6b3a7640000', { from: web3.eth.accounts[0] }, function (result) { + console.log(result) + document.getElementById('contractStatus').innerHTML = 'Withdrawn' + }) }) - }) - } - }) + } + }) - console.log(piggybank) -}) + console.log(piggybank) + }) -sendButton.addEventListener('click', function (event) { - web3.eth.sendTransaction({ - from: web3.eth.accounts[0], - to: '0x2f318C334780961FB129D2a6c30D0763d9a5C970', - value: '0x29a2241af62c0000', - gas: 21000, - gasPrice: 20000000000, - }, (result) => { - console.log(result) + sendButton.addEventListener('click', function (event) { + web3.eth.sendTransaction({ + from: web3.eth.accounts[0], + to: '0x2f318C334780961FB129D2a6c30D0763d9a5C970', + value: '0x29a2241af62c0000', + gas: 21000, + gasPrice: 20000000000, + }, (result) => { + console.log(result) + }) }) -}) -createToken.addEventListener('click', async function (event) { - var _initialAmount = 100 - var _tokenName = 'TST' - var _decimalUnits = 0 - var _tokenSymbol = 'TST' - var humanstandardtokenContract = web3.eth.contract([{'constant': true, 'inputs': [], 'name': 'name', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': '_spender', 'type': 'address'}, {'name': '_value', 'type': 'uint256'}], 'name': 'approve', 'outputs': [{'name': 'success', 'type': 'bool'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'totalSupply', 'outputs': [{'name': '', 'type': 'uint256'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': '_from', 'type': 'address'}, {'name': '_to', 'type': 'address'}, {'name': '_value', 'type': 'uint256'}], 'name': 'transferFrom', 'outputs': [{'name': 'success', 'type': 'bool'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'decimals', 'outputs': [{'name': '', 'type': 'uint8'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'version', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [{'name': '_owner', 'type': 'address'}], 'name': 'balanceOf', 'outputs': [{'name': 'balance', 'type': 'uint256'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'symbol', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': '_to', 'type': 'address'}, {'name': '_value', 'type': 'uint256'}], 'name': 'transfer', 'outputs': [{'name': 'success', 'type': 'bool'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': false, 'inputs': [{'name': '_spender', 'type': 'address'}, {'name': '_value', 'type': 'uint256'}, {'name': '_extraData', 'type': 'bytes'}], 'name': 'approveAndCall', 'outputs': [{'name': 'success', 'type': 'bool'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [{'name': '_owner', 'type': 'address'}, {'name': '_spender', 'type': 'address'}], 'name': 'allowance', 'outputs': [{'name': 'remaining', 'type': 'uint256'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'inputs': [{'name': '_initialAmount', 'type': 'uint256'}, {'name': '_tokenName', 'type': 'string'}, {'name': '_decimalUnits', 'type': 'uint8'}, {'name': '_tokenSymbol', 'type': 'string'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'constructor'}, {'payable': false, 'stateMutability': 'nonpayable', 'type': 'fallback'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': '_from', 'type': 'address'}, {'indexed': true, 'name': '_to', 'type': 'address'}, {'indexed': false, 'name': '_value', 'type': 'uint256'}], 'name': 'Transfer', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': '_owner', 'type': 'address'}, {'indexed': true, 'name': '_spender', 'type': 'address'}, {'indexed': false, 'name': '_value', 'type': 'uint256'}], 'name': 'Approval', 'type': 'event'}]) - return humanstandardtokenContract.new( - _initialAmount, - _tokenName, - _decimalUnits, - _tokenSymbol, - { - from: web3.eth.accounts[0], - data: '0x60806040526040805190810160405280600481526020017f48302e3100000000000000000000000000000000000000000000000000000000815250600690805190602001906200005192919062000143565b503480156200005f57600080fd5b50604051620011f3380380620011f383398101806040528101908080519060200190929190805182019291906020018051906020019092919080518201929190505050836000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508360028190555082600390805190602001906200010492919062000143565b5081600460006101000a81548160ff021916908360ff16021790555080600590805190602001906200013892919062000143565b5050505050620001f2565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200018657805160ff1916838001178555620001b7565b82800160010185558215620001b7579182015b82811115620001b657825182559160200191906001019062000199565b5b509050620001c69190620001ca565b5090565b620001ef91905b80821115620001eb576000816000905550600101620001d1565b5090565b90565b610ff180620002026000396000f3006080604052600436106100af576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100c1578063095ea7b31461015157806318160ddd146101b657806323b872dd146101e1578063313ce5671461026657806354fd4d501461029757806370a082311461032757806395d89b411461037e578063a9059cbb1461040e578063cae9ca5114610473578063dd62ed3e1461051e575b3480156100bb57600080fd5b50600080fd5b3480156100cd57600080fd5b506100d6610595565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101165780820151818401526020810190506100fb565b50505050905090810190601f1680156101435780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561015d57600080fd5b5061019c600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610633565b604051808215151515815260200191505060405180910390f35b3480156101c257600080fd5b506101cb610725565b6040518082815260200191505060405180910390f35b3480156101ed57600080fd5b5061024c600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061072b565b604051808215151515815260200191505060405180910390f35b34801561027257600080fd5b5061027b6109a4565b604051808260ff1660ff16815260200191505060405180910390f35b3480156102a357600080fd5b506102ac6109b7565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156102ec5780820151818401526020810190506102d1565b50505050905090810190601f1680156103195780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561033357600080fd5b50610368600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610a55565b6040518082815260200191505060405180910390f35b34801561038a57600080fd5b50610393610a9d565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103d35780820151818401526020810190506103b8565b50505050905090810190601f1680156104005780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561041a57600080fd5b50610459600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610b3b565b604051808215151515815260200191505060405180910390f35b34801561047f57600080fd5b50610504600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610ca1565b604051808215151515815260200191505060405180910390f35b34801561052a57600080fd5b5061057f600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610f3e565b6040518082815260200191505060405180910390f35b60038054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561062b5780601f106106005761010080835404028352916020019161062b565b820191906000526020600020905b81548152906001019060200180831161060e57829003601f168201915b505050505081565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60025481565b6000816000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101580156107f7575081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410155b80156108035750600082115b1561099857816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550816000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a36001905061099d565b600090505b9392505050565b600460009054906101000a900460ff1681565b60068054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610a4d5780601f10610a2257610100808354040283529160200191610a4d565b820191906000526020600020905b815481529060010190602001808311610a3057829003601f168201915b505050505081565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60058054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610b335780601f10610b0857610100808354040283529160200191610b33565b820191906000526020600020905b815481529060010190602001808311610b1657829003601f168201915b505050505081565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410158015610b8b5750600082115b15610c9657816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a360019050610c9b565b600090505b92915050565b600082600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925856040518082815260200191505060405180910390a38373ffffffffffffffffffffffffffffffffffffffff1660405180807f72656365697665417070726f76616c28616464726573732c75696e743235362c81526020017f616464726573732c627974657329000000000000000000000000000000000000815250602e01905060405180910390207c01000000000000000000000000000000000000000000000000000000009004338530866040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828051906020019080838360005b83811015610ee2578082015181840152602081019050610ec7565b50505050905090810190601f168015610f0f5780820380516001836020036101000a031916815260200191505b509450505050506000604051808303816000875af1925050501515610f3357600080fd5b600190509392505050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050929150505600a165627a7a723058200052919e0bc22b5adcd3d320be977df3a1dcc35d1a0160287383ba371900a1c50029', - gas: '4700000', - gasPrice: '20000000000', - }, function (e, contract) { - console.log(e, contract) - if (typeof contract.address !== 'undefined') { - console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash) - - document.getElementById('tokenAddress').innerHTML = contract.address - - transferTokens.addEventListener('click', function (event) { - console.log(`event`, event) - contract.transfer('0x2f318C334780961FB129D2a6c30D0763d9a5C970', '7', { - from: web3.eth.accounts[0], - to: contract.address, - data: '0xa9059cbb0000000000000000000000002f318C334780961FB129D2a6c30D0763d9a5C970000000000000000000000000000000000000000000000000000000000000000a', - gas: 60000, - gasPrice: '20000000000', - }, function (result) { - console.log('result', result) + createToken.addEventListener('click', async function (event) { + var _initialAmount = 100 + var _tokenName = 'TST' + var _decimalUnits = 0 + var _tokenSymbol = 'TST' + var humanstandardtokenContract = web3.eth.contract([{'constant': true, 'inputs': [], 'name': 'name', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': '_spender', 'type': 'address'}, {'name': '_value', 'type': 'uint256'}], 'name': 'approve', 'outputs': [{'name': 'success', 'type': 'bool'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'totalSupply', 'outputs': [{'name': '', 'type': 'uint256'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': '_from', 'type': 'address'}, {'name': '_to', 'type': 'address'}, {'name': '_value', 'type': 'uint256'}], 'name': 'transferFrom', 'outputs': [{'name': 'success', 'type': 'bool'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'decimals', 'outputs': [{'name': '', 'type': 'uint8'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'version', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [{'name': '_owner', 'type': 'address'}], 'name': 'balanceOf', 'outputs': [{'name': 'balance', 'type': 'uint256'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'symbol', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': '_to', 'type': 'address'}, {'name': '_value', 'type': 'uint256'}], 'name': 'transfer', 'outputs': [{'name': 'success', 'type': 'bool'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': false, 'inputs': [{'name': '_spender', 'type': 'address'}, {'name': '_value', 'type': 'uint256'}, {'name': '_extraData', 'type': 'bytes'}], 'name': 'approveAndCall', 'outputs': [{'name': 'success', 'type': 'bool'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [{'name': '_owner', 'type': 'address'}, {'name': '_spender', 'type': 'address'}], 'name': 'allowance', 'outputs': [{'name': 'remaining', 'type': 'uint256'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'inputs': [{'name': '_initialAmount', 'type': 'uint256'}, {'name': '_tokenName', 'type': 'string'}, {'name': '_decimalUnits', 'type': 'uint8'}, {'name': '_tokenSymbol', 'type': 'string'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'constructor'}, {'payable': false, 'stateMutability': 'nonpayable', 'type': 'fallback'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': '_from', 'type': 'address'}, {'indexed': true, 'name': '_to', 'type': 'address'}, {'indexed': false, 'name': '_value', 'type': 'uint256'}], 'name': 'Transfer', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': '_owner', 'type': 'address'}, {'indexed': true, 'name': '_spender', 'type': 'address'}, {'indexed': false, 'name': '_value', 'type': 'uint256'}], 'name': 'Approval', 'type': 'event'}]) + return humanstandardtokenContract.new( + _initialAmount, + _tokenName, + _decimalUnits, + _tokenSymbol, + { + from: web3.eth.accounts[0], + data: '0x60806040526040805190810160405280600481526020017f48302e3100000000000000000000000000000000000000000000000000000000815250600690805190602001906200005192919062000143565b503480156200005f57600080fd5b50604051620011f3380380620011f383398101806040528101908080519060200190929190805182019291906020018051906020019092919080518201929190505050836000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508360028190555082600390805190602001906200010492919062000143565b5081600460006101000a81548160ff021916908360ff16021790555080600590805190602001906200013892919062000143565b5050505050620001f2565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200018657805160ff1916838001178555620001b7565b82800160010185558215620001b7579182015b82811115620001b657825182559160200191906001019062000199565b5b509050620001c69190620001ca565b5090565b620001ef91905b80821115620001eb576000816000905550600101620001d1565b5090565b90565b610ff180620002026000396000f3006080604052600436106100af576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100c1578063095ea7b31461015157806318160ddd146101b657806323b872dd146101e1578063313ce5671461026657806354fd4d501461029757806370a082311461032757806395d89b411461037e578063a9059cbb1461040e578063cae9ca5114610473578063dd62ed3e1461051e575b3480156100bb57600080fd5b50600080fd5b3480156100cd57600080fd5b506100d6610595565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101165780820151818401526020810190506100fb565b50505050905090810190601f1680156101435780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561015d57600080fd5b5061019c600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610633565b604051808215151515815260200191505060405180910390f35b3480156101c257600080fd5b506101cb610725565b6040518082815260200191505060405180910390f35b3480156101ed57600080fd5b5061024c600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061072b565b604051808215151515815260200191505060405180910390f35b34801561027257600080fd5b5061027b6109a4565b604051808260ff1660ff16815260200191505060405180910390f35b3480156102a357600080fd5b506102ac6109b7565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156102ec5780820151818401526020810190506102d1565b50505050905090810190601f1680156103195780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561033357600080fd5b50610368600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610a55565b6040518082815260200191505060405180910390f35b34801561038a57600080fd5b50610393610a9d565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103d35780820151818401526020810190506103b8565b50505050905090810190601f1680156104005780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561041a57600080fd5b50610459600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610b3b565b604051808215151515815260200191505060405180910390f35b34801561047f57600080fd5b50610504600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610ca1565b604051808215151515815260200191505060405180910390f35b34801561052a57600080fd5b5061057f600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610f3e565b6040518082815260200191505060405180910390f35b60038054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561062b5780601f106106005761010080835404028352916020019161062b565b820191906000526020600020905b81548152906001019060200180831161060e57829003601f168201915b505050505081565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60025481565b6000816000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101580156107f7575081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410155b80156108035750600082115b1561099857816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550816000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a36001905061099d565b600090505b9392505050565b600460009054906101000a900460ff1681565b60068054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610a4d5780601f10610a2257610100808354040283529160200191610a4d565b820191906000526020600020905b815481529060010190602001808311610a3057829003601f168201915b505050505081565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60058054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610b335780601f10610b0857610100808354040283529160200191610b33565b820191906000526020600020905b815481529060010190602001808311610b1657829003601f168201915b505050505081565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410158015610b8b5750600082115b15610c9657816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a360019050610c9b565b600090505b92915050565b600082600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925856040518082815260200191505060405180910390a38373ffffffffffffffffffffffffffffffffffffffff1660405180807f72656365697665417070726f76616c28616464726573732c75696e743235362c81526020017f616464726573732c627974657329000000000000000000000000000000000000815250602e01905060405180910390207c01000000000000000000000000000000000000000000000000000000009004338530866040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828051906020019080838360005b83811015610ee2578082015181840152602081019050610ec7565b50505050905090810190601f168015610f0f5780820380516001836020036101000a031916815260200191505b509450505050506000604051808303816000875af1925050501515610f3357600080fd5b600190509392505050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050929150505600a165627a7a723058200052919e0bc22b5adcd3d320be977df3a1dcc35d1a0160287383ba371900a1c50029', + gas: '4700000', + gasPrice: '20000000000', + }, function (e, contract) { + console.log(e, contract) + if (typeof contract.address !== 'undefined') { + console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash) + + document.getElementById('tokenAddress').innerHTML = contract.address + + transferTokens.addEventListener('click', function (event) { + console.log(`event`, event) + contract.transfer('0x2f318C334780961FB129D2a6c30D0763d9a5C970', '7', { + from: web3.eth.accounts[0], + to: contract.address, + data: '0xa9059cbb0000000000000000000000002f318C334780961FB129D2a6c30D0763d9a5C970000000000000000000000000000000000000000000000000000000000000000a', + gas: 60000, + gasPrice: '20000000000', + }, function (result) { + console.log('result', result) + }) }) - }) - - approveTokens.addEventListener('click', function (event) { - contract.approve('0x2f318C334780961FB129D2a6c30D0763d9a5C970', '7', { - from: web3.eth.accounts[0], - to: contract.address, - data: '0x095ea7b30000000000000000000000002f318C334780961FB129D2a6c30D0763d9a5C9700000000000000000000000000000000000000000000000000000000000000005', - gas: 60000, - gasPrice: '20000000000', - }, function (result) { - console.log(result) + + approveTokens.addEventListener('click', function (event) { + contract.approve('0x2f318C334780961FB129D2a6c30D0763d9a5C970', '7', { + from: web3.eth.accounts[0], + to: contract.address, + data: '0x095ea7b30000000000000000000000002f318C334780961FB129D2a6c30D0763d9a5C9700000000000000000000000000000000000000000000000000000000000000005', + gas: 60000, + gasPrice: '20000000000', + }, function (result) { + console.log(result) + }) }) - }) - } - }) + } + }) + }) }) - diff --git a/test/e2e/beta/drizzle.spec.js b/test/e2e/beta/drizzle.spec.js index ff4b4b74d..a9d72a9ba 100644 --- a/test/e2e/beta/drizzle.spec.js +++ b/test/e2e/beta/drizzle.spec.js @@ -19,6 +19,7 @@ const { openNewPage, verboseReportOnFailure, waitUntilXWindowHandles, + switchToWindowWithTitle, } = require('./helpers') describe('MetaMask', function () { @@ -266,17 +267,31 @@ describe('MetaMask', function () { }) describe('Drizzle', () => { - it('should be able to detect our eth address', async () => { + let windowHandles + let extension + let popup + let dapp + + it('should be able to connect the account', async () => { await openNewPage(driver, 'http://127.0.0.1:3000/') await delay(regularDelayMs) - await waitUntilXWindowHandles(driver, 2) - const windowHandles = await driver.getAllWindowHandles() - const dapp = windowHandles[1] + await waitUntilXWindowHandles(driver, 3) + windowHandles = await driver.getAllWindowHandles() + + extension = windowHandles[0] + popup = await switchToWindowWithTitle(driver, 'MetaMask Notification', windowHandles) + dapp = windowHandles.find(handle => handle !== extension && handle !== popup) - await driver.switchTo().window(dapp) await delay(regularDelayMs) + const approveButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Connect')]`)) + await approveButton.click() + }) + it('should be able to detect our eth address', async () => { + // Check if address exposed + await driver.switchTo().window(dapp) + await delay(regularDelayMs) const addressElement = await findElement(driver, By.css(`.pure-u-1-1 h4`)) const addressText = await addressElement.getText() diff --git a/test/e2e/beta/from-import-beta-ui.spec.js b/test/e2e/beta/from-import-beta-ui.spec.js index 40b2bd28c..caef99fed 100644 --- a/test/e2e/beta/from-import-beta-ui.spec.js +++ b/test/e2e/beta/from-import-beta-ui.spec.js @@ -319,7 +319,7 @@ describe('Using MetaMask with an existing account', function () { const txValues = await findElements(driver, By.css('.transaction-list-item__amount--primary')) assert.equal(txValues.length, 1) - assert.equal(await txValues[0].getText(), '-1 ETH') + assert.ok(/-1\s*ETH/.test(await txValues[0].getText())) }) }) diff --git a/test/e2e/beta/helpers.js b/test/e2e/beta/helpers.js index 4055d8155..08416857e 100644 --- a/test/e2e/beta/helpers.js +++ b/test/e2e/beta/helpers.js @@ -14,6 +14,7 @@ module.exports = { loadExtension, openNewPage, switchToWindowWithTitle, + switchToWindowWithUrlThatMatches, verboseReportOnFailure, waitUntilXWindowHandles, } @@ -130,3 +131,19 @@ async function assertElementNotPresent (webdriver, driver, by) { } assert.ok(!dataTab, 'Found element that should not be present') } + +async function switchToWindowWithUrlThatMatches (driver, regexp, windowHandles) { + if (!windowHandles) { + windowHandles = await driver.getAllWindowHandles() + } else if (windowHandles.length === 0) { + throw new Error('No window that matches: ' + regexp) + } + const firstHandle = windowHandles[0] + await driver.switchTo().window(firstHandle) + const windowUrl = await driver.getCurrentUrl() + if (windowUrl.match(regexp)) { + return firstHandle + } else { + return await switchToWindowWithUrlThatMatches(driver, regexp, windowHandles.slice(1)) + } +} diff --git a/test/e2e/beta/metamask-beta-ui.spec.js b/test/e2e/beta/metamask-beta-ui.spec.js index f29f242c1..5887d0293 100644 --- a/test/e2e/beta/metamask-beta-ui.spec.js +++ b/test/e2e/beta/metamask-beta-ui.spec.js @@ -284,6 +284,22 @@ describe('MetaMask', function () { }) }) + describe('Enable privacy mode', () => { + it('enables privacy mode', async () => { + const networkDropdown = await findElement(driver, By.css('.network-name')) + await networkDropdown.click() + await delay(regularDelayMs) + + const customRpcButton = await findElement(driver, By.xpath(`//span[contains(text(), 'Custom RPC')]`)) + await customRpcButton.click() + await delay(regularDelayMs) + + const privacyToggle = await findElement(driver, By.css('.settings-page__content-row:nth-of-type(10) .settings-page__content-item-col > div')) + await privacyToggle.click() + await delay(largeDelayMs * 2) + }) + }) + describe('Log out an log back in', () => { it('logs out of the account', async () => { await driver.findElement(By.css('.account-menu__icon')).click() @@ -371,7 +387,7 @@ describe('MetaMask', function () { it('balance renders', async () => { const balance = await findElement(driver, By.css('.balance-display .token-amount')) - await driver.wait(until.elementTextMatches(balance, /100.+ETH/)) + await driver.wait(until.elementTextMatches(balance, /100\s*ETH/)) await delay(regularDelayMs) }) }) @@ -420,30 +436,43 @@ describe('MetaMask', function () { if (process.env.SELENIUM_BROWSER !== 'firefox') { const txValues = await findElement(driver, By.css('.transaction-list-item__amount--primary')) - await driver.wait(until.elementTextMatches(txValues, /-1\sETH/), 10000) + await driver.wait(until.elementTextMatches(txValues, /-1\s*ETH/), 10000) } }) }) describe('Send ETH from dapp', () => { + let windowHandles + let extension + let popup + let dapp + it('starts a send transaction inside the dapp', async () => { await openNewPage(driver, 'http://127.0.0.1:8080/') await delay(regularDelayMs) - await waitUntilXWindowHandles(driver, 2) - let windowHandles = await driver.getAllWindowHandles() - const extension = windowHandles[0] - const dapp = windowHandles[1] + await waitUntilXWindowHandles(driver, 3) + windowHandles = await driver.getAllWindowHandles() + extension = windowHandles[0] + popup = await switchToWindowWithTitle(driver, 'MetaMask Notification', windowHandles) + dapp = windowHandles.find(handle => handle !== extension && handle !== popup) + + await delay(regularDelayMs) + const approveButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Connect')]`)) + await approveButton.click() + }) + + it('initiates a send from the dapp', async () => { await driver.switchTo().window(dapp) await delay(regularDelayMs) const send3eth = await findElement(driver, By.xpath(`//button[contains(text(), 'Send')]`), 10000) await send3eth.click() - await delay(regularDelayMs) + await delay(5000) windowHandles = await driver.getAllWindowHandles() - await driver.switchTo().window(windowHandles[2]) + await switchToWindowWithTitle(driver, 'MetaMask Notification', windowHandles) await delay(regularDelayMs) await assertElementNotPresent(webdriver, driver, By.xpath(`//li[contains(text(), 'Data')]`)) @@ -462,7 +491,7 @@ describe('MetaMask', function () { assert.equal(transactions.length, 2) const txValues = await findElement(driver, By.css('.transaction-list-item__amount--primary')) - await driver.wait(until.elementTextMatches(txValues, /-3\sETH/), 10000) + await driver.wait(until.elementTextMatches(txValues, /-3\s*ETH/), 10000) }) }) @@ -540,7 +569,7 @@ describe('MetaMask', function () { await findElements(driver, By.css('.transaction-list-item')) const [txListValue] = await findElements(driver, By.css('.transaction-list-item__amount--primary')) - await driver.wait(until.elementTextMatches(txListValue, /-4\sETH/), 10000) + await driver.wait(until.elementTextMatches(txListValue, /-4\s*ETH/), 10000) await txListValue.click() await delay(regularDelayMs) @@ -574,7 +603,7 @@ describe('MetaMask', function () { }, 10000) const txValues = await findElements(driver, By.css('.transaction-list-item__amount--primary')) - await driver.wait(until.elementTextMatches(txValues[0], /-4\sETH/), 10000) + await driver.wait(until.elementTextMatches(txValues[0], /-4\s*ETH/), 10000) // const txAccounts = await findElements(driver, By.css('.tx-list-account')) // const firstTxAddress = await txAccounts[0].getText() @@ -606,7 +635,7 @@ describe('MetaMask', function () { }, 10000) const txValues = await findElement(driver, By.css('.transaction-list-item__amount--primary')) - await driver.wait(until.elementTextMatches(txValues, /-0\sETH/), 10000) + await driver.wait(until.elementTextMatches(txValues, /-0\s*ETH/), 10000) await closeAllWindowHandlesExcept(driver, [extension, dapp]) await driver.switchTo().window(extension) @@ -616,9 +645,9 @@ describe('MetaMask', function () { const balance = await findElement(driver, By.css('.transaction-view-balance__primary-balance')) await delay(regularDelayMs) if (process.env.SELENIUM_BROWSER !== 'firefox') { - await driver.wait(until.elementTextMatches(balance, /^92.*ETH.*$/), 10000) + await driver.wait(until.elementTextMatches(balance, /^92.*\s*ETH.*$/), 10000) const tokenAmount = await balance.getText() - assert.ok(/^92.*ETH.*$/.test(tokenAmount)) + assert.ok(/^92.*\s*ETH.*$/.test(tokenAmount)) await delay(regularDelayMs) } }) @@ -764,7 +793,7 @@ describe('MetaMask', function () { // test cancelled on firefox until https://github.com/mozilla/geckodriver/issues/906 is resolved, // or possibly until we use latest version of firefox in the tests if (process.env.SELENIUM_BROWSER !== 'firefox') { - await driver.wait(until.elementTextMatches(txValues[0], /-50\sTST/), 10000) + await driver.wait(until.elementTextMatches(txValues[0], /-50\s*TST/), 10000) } driver.wait(async () => { @@ -798,7 +827,7 @@ describe('MetaMask', function () { await findElements(driver, By.css('.transaction-list__pending-transactions')) const [txListValue] = await findElements(driver, By.css('.transaction-list-item__amount--primary')) - await driver.wait(until.elementTextMatches(txListValue, /-7\sTST/), 10000) + await driver.wait(until.elementTextMatches(txListValue, /-7\s*TST/), 10000) await txListValue.click() await delay(regularDelayMs) @@ -851,7 +880,7 @@ describe('MetaMask', function () { }, 10000) const txValues = await findElements(driver, By.css('.transaction-list-item__amount--primary')) - await driver.wait(until.elementTextMatches(txValues[0], /-7\sTST/)) + await driver.wait(until.elementTextMatches(txValues[0], /-7\s*TST/)) const txStatuses = await findElements(driver, By.css('.transaction-list-item__action')) await driver.wait(until.elementTextMatches(txStatuses[0], /Sent\sToken/)) @@ -897,7 +926,7 @@ describe('MetaMask', function () { const [txListItem] = await findElements(driver, By.css('.transaction-list-item')) const [txListValue] = await findElements(driver, By.css('.transaction-list-item__amount--primary')) - await driver.wait(until.elementTextMatches(txListValue, /-7\sTST/)) + await driver.wait(until.elementTextMatches(txListValue, /-7\s*TST/)) await txListItem.click() await delay(regularDelayMs) }) @@ -974,7 +1003,7 @@ describe('MetaMask', function () { }, 10000) const txValues = await findElements(driver, By.css('.transaction-list-item__amount--primary')) - await driver.wait(until.elementTextMatches(txValues[0], /-7\sTST/)) + await driver.wait(until.elementTextMatches(txValues[0], /-7\s*TST/)) const txStatuses = await findElements(driver, By.css('.transaction-list-item__action')) await driver.wait(until.elementTextMatches(txStatuses[0], /Approve/)) }) @@ -1027,7 +1056,7 @@ describe('MetaMask', function () { it('renders the balance for the chosen token', async () => { const balance = await findElement(driver, By.css('.transaction-view-balance__token-balance')) - await driver.wait(until.elementTextMatches(balance, /0\sBAT/)) + await driver.wait(until.elementTextMatches(balance, /0\s*BAT/)) await delay(regularDelayMs) }) }) diff --git a/test/e2e/beta/run-drizzle.sh b/test/e2e/beta/run-drizzle.sh index 7bfffd7e6..bfb7e6fdb 100755 --- a/test/e2e/beta/run-drizzle.sh +++ b/test/e2e/beta/run-drizzle.sh @@ -11,7 +11,7 @@ sleep 5 cd test/e2e/beta/ rm -rf drizzle-test mkdir drizzle-test && cd drizzle-test -npm install truffle +sudo npm install -g truffle truffle unbox drizzle echo "Deploying contracts for Drizzle test..." truffle compile && truffle migrate diff --git a/test/integration/lib/currency-localization.js b/test/integration/lib/currency-localization.js index 8d5acf5d0..f6b751ba2 100644 --- a/test/integration/lib/currency-localization.js +++ b/test/integration/lib/currency-localization.js @@ -25,5 +25,5 @@ async function runCurrencyLocalizationTest (assert, done) { const txView = await queryAsync($, '.transaction-view') const heroBalance = await findAsync($(txView), '.transaction-view-balance__balance') const fiatAmount = await findAsync($(heroBalance), '.transaction-view-balance__secondary-balance') - assert.equal(fiatAmount[0].textContent, '₱102,707.97 PHP') + assert.equal(fiatAmount[0].textContent, '₱102,707.97PHP') } diff --git a/test/integration/lib/mascara-first-time.js b/test/integration/lib/mascara-first-time.js index 8bbdb4410..6756b83f9 100644 --- a/test/integration/lib/mascara-first-time.js +++ b/test/integration/lib/mascara-first-time.js @@ -77,7 +77,7 @@ async function runFirstTimeUsageTest (assert, done) { assert.ok(lock, 'Lock menu item found') lock.click() - await timeout(1000) + await timeout(5000) const pwBox2 = (await findAsync(app, '#password'))[0] pwBox2.focus() diff --git a/test/integration/lib/send-new-ui.js b/test/integration/lib/send-new-ui.js index e13016e68..271dd91cf 100644 --- a/test/integration/lib/send-new-ui.js +++ b/test/integration/lib/send-new-ui.js @@ -112,9 +112,9 @@ async function runSendFlowTest (assert, done) { errorMessage = $('.send-v2__error') assert.equal(errorMessage.length, 0, 'send should stop rendering amount error message after amount is corrected') - await customizeGas(assert, 0, 21000, '0 ETH', '$0.00 USD') - await customizeGas(assert, 1, 21000, '0.000021 ETH', '$0.03 USD') - await customizeGas(assert, 500, 60000, '0.03 ETH', '$36.03 USD') + await customizeGas(assert, 0, 21000, '0ETH', '$0.00USD') + await customizeGas(assert, 1, 21000, '0.000021ETH', '$0.03USD') + await customizeGas(assert, 500, 60000, '0.03ETH', '$36.03USD') const sendButton = await queryAsync($, 'button.btn-primary.btn--large.page-container__footer-button') assert.equal(sendButton[0].textContent, 'Next', 'next button rendered') diff --git a/test/unit/app/controllers/network-contoller-test.js b/test/unit/app/controllers/network-contoller-test.js index 822311931..7959e6cc1 100644 --- a/test/unit/app/controllers/network-contoller-test.js +++ b/test/unit/app/controllers/network-contoller-test.js @@ -47,7 +47,7 @@ describe('# Network Controller', function () { describe('#setNetworkState', function () { it('should update the network', function () { - networkController.setNetworkState(1) + networkController.setNetworkState(1, 'rpc') const networkState = networkController.getNetworkState() assert.equal(networkState, 1, 'network is 1') }) diff --git a/test/unit/app/controllers/preferences-controller-test.js b/test/unit/app/controllers/preferences-controller-test.js index 7f2804a83..473f22f8b 100644 --- a/test/unit/app/controllers/preferences-controller-test.js +++ b/test/unit/app/controllers/preferences-controller-test.js @@ -418,7 +418,7 @@ describe('preferences controller', function () { req.params.options = { address, symbol, decimals, image } sandbox.stub(preferencesController, '_validateERC20AssetParams').returns(true) - preferencesController.showWatchAssetUi = async () => {} + preferencesController.openPopup = async () => {} await preferencesController._handleWatchAssetERC20(req.params.options) const suggested = preferencesController.getSuggestedTokens() @@ -438,7 +438,7 @@ describe('preferences controller', function () { req.params.options = { address, symbol, decimals, image } sandbox.stub(preferencesController, '_validateERC20AssetParams').returns(true) - preferencesController.showWatchAssetUi = async () => { + preferencesController.openPopup = async () => { await preferencesController.addToken(address, symbol, decimals, image) } @@ -453,6 +453,32 @@ describe('preferences controller', function () { const assetImages = preferencesController.getAssetImages() assert.ok(assetImages[address], `set image correctly`) }) + it('should validate ERC20 asset correctly', async function () { + const validateSpy = sandbox.spy(preferencesController._validateERC20AssetParams) + try { validateSpy({rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABC', decimals: 0}) } catch (e) {} + assert.equal(validateSpy.threw(), false, 'correct options object') + const validateSpyAddress = sandbox.spy(preferencesController._validateERC20AssetParams) + try { validateSpyAddress({symbol: 'ABC', decimals: 0}) } catch (e) {} + assert.equal(validateSpyAddress.threw(), true, 'options object with no address') + const validateSpySymbol = sandbox.spy(preferencesController._validateERC20AssetParams) + try { validateSpySymbol({rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', decimals: 0}) } catch (e) {} + assert.equal(validateSpySymbol.threw(), true, 'options object with no symbol') + const validateSpyDecimals = sandbox.spy(preferencesController._validateERC20AssetParams) + try { validateSpyDecimals({rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABC'}) } catch (e) {} + assert.equal(validateSpyDecimals.threw(), true, 'options object with no decimals') + const validateSpyInvalidSymbol = sandbox.spy(preferencesController._validateERC20AssetParams) + try { validateSpyInvalidSymbol({rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABCDEFGHI', decimals: 0}) } catch (e) {} + assert.equal(validateSpyInvalidSymbol.threw(), true, 'options object with invalid symbol') + const validateSpyInvalidDecimals1 = sandbox.spy(preferencesController._validateERC20AssetParams) + try { validateSpyInvalidDecimals1({rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABCDEFGHI', decimals: -1}) } catch (e) {} + assert.equal(validateSpyInvalidDecimals1.threw(), true, 'options object with decimals less than zero') + const validateSpyInvalidDecimals2 = sandbox.spy(preferencesController._validateERC20AssetParams) + try { validateSpyInvalidDecimals2({rawAddress: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07', symbol: 'ABCDEFGHI', decimals: 38}) } catch (e) {} + assert.equal(validateSpyInvalidDecimals2.threw(), true, 'options object with decimals more than 36') + const validateSpyInvalidAddress = sandbox.spy(preferencesController._validateERC20AssetParams) + try { validateSpyInvalidAddress({rawAddress: '0x123', symbol: 'ABC', decimals: 0}) } catch (e) {} + assert.equal(validateSpyInvalidAddress.threw(), true, 'options object with address invalid') + }) }) describe('setPasswordForgotten', function () { @@ -487,20 +513,20 @@ describe('preferences controller', function () { describe('on updateFrequentRpcList', function () { it('should add custom RPC url to state', function () { - preferencesController.addToFrequentRpcList('rpc_url') - preferencesController.addToFrequentRpcList('http://localhost:8545') - assert.deepEqual(preferencesController.store.getState().frequentRpcList, ['rpc_url']) - preferencesController.addToFrequentRpcList('rpc_url') - assert.deepEqual(preferencesController.store.getState().frequentRpcList, ['rpc_url']) + 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: '' }] ) + preferencesController.addToFrequentRpcList('rpc_url', 1) + assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, [{ rpcUrl: 'rpc_url', chainId: 1, ticker: 'ETH', nickname: '' }] ) }) it('should remove custom RPC url from state', function () { - preferencesController.addToFrequentRpcList('rpc_url') - assert.deepEqual(preferencesController.store.getState().frequentRpcList, ['rpc_url']) + preferencesController.addToFrequentRpcList('rpc_url', 1) + assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, [{ rpcUrl: 'rpc_url', chainId: 1, ticker: 'ETH', nickname: '' }] ) preferencesController.removeFromFrequentRpcList('other_rpc_url') preferencesController.removeFromFrequentRpcList('http://localhost:8545') preferencesController.removeFromFrequentRpcList('rpc_url') - assert.deepEqual(preferencesController.store.getState().frequentRpcList, []) + assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, []) }) }) }) diff --git a/test/unit/ui/app/actions.spec.js b/test/unit/ui/app/actions.spec.js index 748a58b32..df7d2ee8f 100644 --- a/test/unit/ui/app/actions.spec.js +++ b/test/unit/ui/app/actions.spec.js @@ -1133,7 +1133,7 @@ describe('Actions', () => { { type: 'DISPLAY_WARNING', value: 'Had a problem changing networks!' }, ] - setRpcTargetSpy.callsFake((newRpc, callback) => { + setRpcTargetSpy.callsFake((newRpc, chainId, ticker, nickname, callback) => { callback(new Error('error')) }) diff --git a/ui/app/actions.js b/ui/app/actions.js index f8a375e2f..501fef76d 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -309,7 +309,7 @@ var actions = { setPreference, updatePreferences, UPDATE_PREFERENCES: 'UPDATE_PREFERENCES', - setUseETHAsPrimaryCurrencyPreference, + setUseNativeCurrencyAsPrimaryCurrencyPreference, setMouseUserState, SET_MOUSE_USER_STATE: 'SET_MOUSE_USER_STATE', @@ -325,6 +325,9 @@ var actions = { clearPendingTokens, createCancelTransaction, + approveProviderRequest, + rejectProviderRequest, + clearApprovedOrigins, } module.exports = actions @@ -1874,10 +1877,10 @@ function updateProviderType (type) { } } -function setRpcTarget (newRpc) { +function setRpcTarget (newRpc, chainId, ticker = 'ETH', nickname = '') { return (dispatch) => { - log.debug(`background.setRpcTarget: ${newRpc}`) - background.setCustomRpc(newRpc, (err, result) => { + log.debug(`background.setRpcTarget: ${newRpc} ${chainId} ${ticker} ${nickname}`) + background.setCustomRpc(newRpc, chainId, ticker, nickname, (err, result) => { if (err) { log.error(err) return dispatch(actions.displayWarning('Had a problem changing networks!')) @@ -2330,8 +2333,8 @@ function updatePreferences (value) { } } -function setUseETHAsPrimaryCurrencyPreference (value) { - return setPreference('useETHAsPrimaryCurrency', value) +function setUseNativeCurrencyAsPrimaryCurrencyPreference (value) { + return setPreference('useNativeCurrencyAsPrimaryCurrency', value) } function setNetworkNonce (networkNonce) { @@ -2484,3 +2487,21 @@ function setPendingTokens (pendingTokens) { payload: tokens, } } + +function approveProviderRequest (origin) { + return (dispatch) => { + background.approveProviderRequest(origin) + } +} + +function rejectProviderRequest (origin) { + return (dispatch) => { + background.rejectProviderRequest(origin) + } +} + +function clearApprovedOrigins () { + return (dispatch) => { + background.clearApprovedOrigins() + } +} diff --git a/ui/app/app.js b/ui/app/app.js index aeb3d05ee..b3aff1f39 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -101,7 +101,7 @@ class App extends Component { network, isMouseUser, provider, - frequentRpcList, + frequentRpcListDetail, currentView, setMouseUserState, sidebar, @@ -147,7 +147,7 @@ class App extends Component { // network dropdown h(NetworkDropdown, { provider, - frequentRpcList, + frequentRpcListDetail, }, []), h(AccountMenu), @@ -230,7 +230,7 @@ App.propTypes = { alertMessage: PropTypes.string, network: PropTypes.string, provider: PropTypes.object, - frequentRpcList: PropTypes.array, + frequentRpcListDetail: PropTypes.array, currentView: PropTypes.object, sidebar: PropTypes.object, alertOpen: PropTypes.bool, @@ -322,7 +322,7 @@ function mapStateToProps (state) { forgottenPassword: state.appState.forgottenPassword, nextUnreadNotice, lostAccounts, - frequentRpcList: state.metamask.frequentRpcList || [], + frequentRpcListDetail: state.metamask.frequentRpcListDetail || [], currentCurrency: state.metamask.currentCurrency, isMouseUser: state.appState.isMouseUser, betaUI: state.metamask.featureFlags.betaUI, diff --git a/ui/app/components/account-dropdowns.js b/ui/app/components/account-dropdowns.js index 043008a36..06376e48b 100644 --- a/ui/app/components/account-dropdowns.js +++ b/ui/app/components/account-dropdowns.js @@ -6,10 +6,11 @@ const genAccountLink = require('etherscan-link').createAccountLink const connect = require('react-redux').connect const Dropdown = require('./dropdown').Dropdown const DropdownMenuItem = require('./dropdown').DropdownMenuItem -const Identicon = require('./identicon') const copyToClipboard = require('copy-to-clipboard') const { checksumAddress } = require('../util') +import Identicon from './identicon' + class AccountDropdowns extends Component { constructor (props) { super(props) diff --git a/ui/app/components/account-menu/index.js b/ui/app/components/account-menu/index.js index c9c5b60e1..94eae8d07 100644 --- a/ui/app/components/account-menu/index.js +++ b/ui/app/components/account-menu/index.js @@ -7,10 +7,10 @@ const PropTypes = require('prop-types') const h = require('react-hyperscript') const actions = require('../../actions') const { Menu, Item, Divider, CloseArea } = require('../dropdowns/components/menu') -const Identicon = require('../identicon') const { ENVIRONMENT_TYPE_POPUP } = require('../../../../app/scripts/lib/enums') const { getEnvironmentType } = require('../../../../app/scripts/lib/util') const Tooltip = require('../tooltip') +import Identicon from '../identicon' import UserPreferencedCurrencyDisplay from '../user-preferenced-currency-display' import { PRIMARY } from '../../constants/common' diff --git a/ui/app/components/account-panel.js b/ui/app/components/account-panel.js index abaaf8163..a379ed3ac 100644 --- a/ui/app/components/account-panel.js +++ b/ui/app/components/account-panel.js @@ -1,7 +1,7 @@ const inherits = require('util').inherits const Component = require('react').Component const h = require('react-hyperscript') -const Identicon = require('./identicon') +import Identicon from './identicon' const formatBalance = require('../util').formatBalance const addressSummary = require('../util').addressSummary diff --git a/ui/app/components/app-header/app-header.component.js b/ui/app/components/app-header/app-header.component.js index b8b002dcc..c82dc1de9 100644 --- a/ui/app/components/app-header/app-header.component.js +++ b/ui/app/components/app-header/app-header.component.js @@ -2,13 +2,13 @@ import React, { PureComponent } from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' import { matchPath } from 'react-router-dom' +import Identicon from '../identicon' const { ENVIRONMENT_TYPE_NOTIFICATION, ENVIRONMENT_TYPE_POPUP, } = require('../../../../app/scripts/lib/enums') const { DEFAULT_ROUTE, INITIALIZE_ROUTE, CONFIRM_TRANSACTION_ROUTE } = require('../../routes') -const Identicon = require('../identicon') const NetworkIndicator = require('../network') export default class AppHeader extends PureComponent { diff --git a/ui/app/components/balance-component.js b/ui/app/components/balance-component.js index e1fcf08e0..0f8514c81 100644 --- a/ui/app/components/balance-component.js +++ b/ui/app/components/balance-component.js @@ -2,11 +2,11 @@ const Component = require('react').Component const connect = require('react-redux').connect const h = require('react-hyperscript') const inherits = require('util').inherits -const TokenBalance = require('./token-balance') -const Identicon = require('./identicon') +import TokenBalance from './token-balance' +import Identicon from './identicon' import UserPreferencedCurrencyDisplay from './user-preferenced-currency-display' import { PRIMARY, SECONDARY } from '../constants/common' -const { getAssetImages, conversionRateSelector, getCurrentCurrency} = require('../selectors') +const { getNativeCurrency, getAssetImages, conversionRateSelector, getCurrentCurrency} = require('../selectors') const { formatBalance } = require('../util') @@ -21,6 +21,7 @@ function mapStateToProps (state) { return { account, network, + nativeCurrency: getNativeCurrency(state), conversionRate: conversionRateSelector(state), currentCurrency: getCurrentCurrency(state), assetImages: getAssetImages(state), @@ -66,10 +67,10 @@ BalanceComponent.prototype.renderTokenBalance = function () { BalanceComponent.prototype.renderBalance = function () { const props = this.props - const { account } = props + const { account, nativeCurrency } = props const balanceValue = account && account.balance const needsParse = 'needsParse' in props ? props.needsParse : true - const formattedBalance = balanceValue ? formatBalance(balanceValue, 6, needsParse) : '...' + const formattedBalance = balanceValue ? formatBalance(balanceValue, 6, needsParse, nativeCurrency) : '...' const showFiat = 'showFiat' in props ? props.showFiat : true if (formattedBalance === 'None' || formattedBalance === '...') { @@ -81,11 +82,12 @@ BalanceComponent.prototype.renderBalance = function () { } return h('div.flex-column.balance-display', {}, [ - h('div.token-amount', {}, h(UserPreferencedCurrencyDisplay, { + h(UserPreferencedCurrencyDisplay, { + className: 'token-amount', value: balanceValue, type: PRIMARY, ethNumberOfDecimals: 3, - })), + }), showFiat && h(UserPreferencedCurrencyDisplay, { value: balanceValue, diff --git a/ui/app/components/currency-display/currency-display.component.js b/ui/app/components/currency-display/currency-display.component.js index 5f5717be3..2d7413b57 100644 --- a/ui/app/components/currency-display/currency-display.component.js +++ b/ui/app/components/currency-display/currency-display.component.js @@ -1,7 +1,7 @@ import React, { PureComponent } from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' -import { ETH, GWEI } from '../../constants/common' +import { GWEI } from '../../constants/common' export default class CurrencyDisplay extends PureComponent { static propTypes = { @@ -10,8 +10,9 @@ export default class CurrencyDisplay extends PureComponent { prefix: PropTypes.string, prefixComponent: PropTypes.node, style: PropTypes.object, + suffix: PropTypes.string, // Used in container - currency: PropTypes.oneOf([ETH]), + currency: PropTypes.string, denomination: PropTypes.oneOf([GWEI]), value: PropTypes.string, numberOfDecimals: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), @@ -19,17 +20,25 @@ export default class CurrencyDisplay extends PureComponent { } render () { - const { className, displayValue, prefix, prefixComponent, style } = this.props + const { className, displayValue, prefix, prefixComponent, style, suffix } = this.props const text = `${prefix || ''}${displayValue}` + const title = `${text} ${suffix}` return ( <div className={classnames('currency-display-component', className)} style={style} - title={text} + title={title} > { prefixComponent} <span className="currency-display-component__text">{ text }</span> + { + suffix && ( + <span className="currency-display-component__suffix"> + { suffix } + </span> + ) + } </div> ) } diff --git a/ui/app/components/currency-display/currency-display.container.js b/ui/app/components/currency-display/currency-display.container.js index b387229b5..6ddf07172 100644 --- a/ui/app/components/currency-display/currency-display.container.js +++ b/ui/app/components/currency-display/currency-display.container.js @@ -3,16 +3,17 @@ import CurrencyDisplay from './currency-display.component' import { getValueFromWeiHex, formatCurrency } from '../../helpers/confirm-transaction/util' const mapStateToProps = state => { - const { metamask: { currentCurrency, conversionRate } } = state + const { metamask: { nativeCurrency, currentCurrency, conversionRate } } = state return { currentCurrency, conversionRate, + nativeCurrency, } } const mergeProps = (stateProps, dispatchProps, ownProps) => { - const { currentCurrency, conversionRate, ...restStateProps } = stateProps + const { nativeCurrency, currentCurrency, conversionRate, ...restStateProps } = stateProps const { value, numberOfDecimals = 2, @@ -24,16 +25,17 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => { const toCurrency = currency || currentCurrency const convertedValue = getValueFromWeiHex({ - value, toCurrency, conversionRate, numberOfDecimals, toDenomination: denomination, + value, fromCurrency: nativeCurrency, toCurrency, conversionRate, numberOfDecimals, toDenomination: denomination, }) - const formattedValue = formatCurrency(convertedValue, toCurrency) - const displayValue = hideLabel ? formattedValue : `${formattedValue} ${toCurrency.toUpperCase()}` + const displayValue = formatCurrency(convertedValue, toCurrency) + const suffix = hideLabel ? undefined : toCurrency.toUpperCase() return { ...restStateProps, ...dispatchProps, ...restOwnProps, displayValue, + suffix, } } diff --git a/ui/app/components/currency-display/index.scss b/ui/app/components/currency-display/index.scss index 8c0196102..313c932b8 100644 --- a/ui/app/components/currency-display/index.scss +++ b/ui/app/components/currency-display/index.scss @@ -7,4 +7,8 @@ overflow: hidden; text-overflow: ellipsis; } + + &__suffix { + padding-left: 4px; + } } diff --git a/ui/app/components/currency-display/tests/currency-display.container.test.js b/ui/app/components/currency-display/tests/currency-display.container.test.js index b9f98c543..0c886af50 100644 --- a/ui/app/components/currency-display/tests/currency-display.container.test.js +++ b/ui/app/components/currency-display/tests/currency-display.container.test.js @@ -20,12 +20,14 @@ describe('CurrencyDisplay container', () => { metamask: { conversionRate: 280.45, currentCurrency: 'usd', + nativeCurrency: 'ETH', }, } assert.deepEqual(mapStateToProps(mockState), { conversionRate: 280.45, currentCurrency: 'usd', + nativeCurrency: 'ETH', }) }) }) @@ -35,6 +37,7 @@ describe('CurrencyDisplay container', () => { const mockStateProps = { conversionRate: 280.45, currentCurrency: 'usd', + nativeCurrency: 'ETH', } const tests = [ @@ -43,71 +46,93 @@ describe('CurrencyDisplay container', () => { value: '0x2386f26fc10000', numberOfDecimals: 2, currency: 'usd', + nativeCurrency: 'ETH', }, result: { - displayValue: '$2.80 USD', + displayValue: '$2.80', + suffix: 'USD', + nativeCurrency: 'ETH', }, }, { props: { value: '0x2386f26fc10000', + currency: 'usd', + nativeCurrency: 'ETH', }, result: { - displayValue: '$2.80 USD', + displayValue: '$2.80', + suffix: 'USD', + nativeCurrency: 'ETH', }, }, { props: { value: '0x1193461d01595930', currency: 'ETH', + nativeCurrency: 'ETH', numberOfDecimals: 3, }, result: { - displayValue: '1.266 ETH', + displayValue: '1.266', + suffix: 'ETH', + nativeCurrency: 'ETH', }, }, { props: { value: '0x1193461d01595930', currency: 'ETH', + nativeCurrency: 'ETH', numberOfDecimals: 3, hideLabel: true, }, result: { + nativeCurrency: 'ETH', displayValue: '1.266', + suffix: undefined, }, }, { props: { value: '0x3b9aca00', currency: 'ETH', + nativeCurrency: 'ETH', denomination: 'GWEI', hideLabel: true, }, result: { + nativeCurrency: 'ETH', displayValue: '1', + suffix: undefined, }, }, { props: { value: '0x3b9aca00', currency: 'ETH', + nativeCurrency: 'ETH', denomination: 'WEI', hideLabel: true, }, result: { + nativeCurrency: 'ETH', displayValue: '1000000000', + suffix: undefined, }, }, { props: { value: '0x3b9aca00', currency: 'ETH', + nativeCurrency: 'ETH', numberOfDecimals: 100, hideLabel: true, }, result: { + nativeCurrency: 'ETH', displayValue: '1e-9', + suffix: undefined, }, }, ] diff --git a/ui/app/components/currency-input/currency-input.component.js b/ui/app/components/currency-input/currency-input.component.js index 54cd0e1ac..0761a75c5 100644 --- a/ui/app/components/currency-input/currency-input.component.js +++ b/ui/app/components/currency-input/currency-input.component.js @@ -14,6 +14,7 @@ export default class CurrencyInput extends PureComponent { static propTypes = { conversionRate: PropTypes.number, currentCurrency: PropTypes.string, + nativeCurrency: PropTypes.string, onChange: PropTypes.func, onBlur: PropTypes.func, suffix: PropTypes.string, @@ -77,13 +78,13 @@ export default class CurrencyInput extends PureComponent { } renderConversionComponent () { - const { useFiat, currentCurrency } = this.props + const { useFiat, currentCurrency, nativeCurrency } = this.props const { hexValue } = this.state let currency, numberOfDecimals if (useFiat) { // Display ETH - currency = ETH + currency = nativeCurrency || ETH numberOfDecimals = 6 } else { // Display Fiat diff --git a/ui/app/components/currency-input/currency-input.container.js b/ui/app/components/currency-input/currency-input.container.js index 18e5533de..1d1ed7b41 100644 --- a/ui/app/components/currency-input/currency-input.container.js +++ b/ui/app/components/currency-input/currency-input.container.js @@ -3,18 +3,19 @@ import CurrencyInput from './currency-input.component' import { ETH } from '../../constants/common' const mapStateToProps = state => { - const { metamask: { currentCurrency, conversionRate } } = state + const { metamask: { nativeCurrency, currentCurrency, conversionRate } } = state return { + nativeCurrency, currentCurrency, conversionRate, } } const mergeProps = (stateProps, dispatchProps, ownProps) => { - const { currentCurrency } = stateProps + const { nativeCurrency, currentCurrency } = stateProps const { useFiat } = ownProps - const suffix = useFiat ? currentCurrency.toUpperCase() : ETH + const suffix = useFiat ? currentCurrency.toUpperCase() : nativeCurrency || ETH return { ...stateProps, diff --git a/ui/app/components/currency-input/tests/currency-input.component.test.js b/ui/app/components/currency-input/tests/currency-input.component.test.js index 8de0ef863..a33889f94 100644 --- a/ui/app/components/currency-input/tests/currency-input.component.test.js +++ b/ui/app/components/currency-input/tests/currency-input.component.test.js @@ -22,6 +22,7 @@ describe('CurrencyInput Component', () => { it('should render properly with a suffix', () => { const mockStore = { metamask: { + nativeCurrency: 'ETH', currentCurrency: 'usd', conversionRate: 231.06, }, @@ -32,6 +33,7 @@ describe('CurrencyInput Component', () => { <Provider store={store}> <CurrencyInput suffix="ETH" + nativeCurrency="ETH" /> </Provider> ) @@ -45,6 +47,7 @@ describe('CurrencyInput Component', () => { it('should render properly with an ETH value', () => { const mockStore = { metamask: { + nativeCurrency: 'ETH', currentCurrency: 'usd', conversionRate: 231.06, }, @@ -56,6 +59,7 @@ describe('CurrencyInput Component', () => { <CurrencyInput value="de0b6b3a7640000" suffix="ETH" + nativeCurrency="ETH" currentCurrency="usd" conversionRate={231.06} /> @@ -69,12 +73,13 @@ describe('CurrencyInput Component', () => { assert.equal(wrapper.find('.unit-input__suffix').length, 1) assert.equal(wrapper.find('.unit-input__suffix').text(), 'ETH') assert.equal(wrapper.find('.unit-input__input').props().value, '1') - assert.equal(wrapper.find('.currency-display-component').text(), '$231.06 USD') + assert.equal(wrapper.find('.currency-display-component').text(), '$231.06USD') }) it('should render properly with a fiat value', () => { const mockStore = { metamask: { + nativeCurrency: 'ETH', currentCurrency: 'usd', conversionRate: 231.06, }, @@ -87,6 +92,7 @@ describe('CurrencyInput Component', () => { value="f602f2234d0ea" suffix="USD" useFiat + nativeCurrency="ETH" currentCurrency="usd" conversionRate={231.06} /> @@ -100,7 +106,7 @@ describe('CurrencyInput Component', () => { assert.equal(wrapper.find('.unit-input__suffix').length, 1) assert.equal(wrapper.find('.unit-input__suffix').text(), 'USD') assert.equal(wrapper.find('.unit-input__input').props().value, '1') - assert.equal(wrapper.find('.currency-display-component').text(), '0.004328 ETH') + assert.equal(wrapper.find('.currency-display-component').text(), '0.004328ETH') }) }) @@ -116,6 +122,7 @@ describe('CurrencyInput Component', () => { it('should call onChange and onBlur on input changes with the hex value for ETH', () => { const mockStore = { metamask: { + nativeCurrency: 'ETH', currentCurrency: 'usd', conversionRate: 231.06, }, @@ -127,6 +134,7 @@ describe('CurrencyInput Component', () => { onChange={handleChangeSpy} onBlur={handleBlurSpy} suffix="ETH" + nativeCurrency="ETH" currentCurrency="usd" conversionRate={231.06} /> @@ -140,14 +148,14 @@ describe('CurrencyInput Component', () => { const currencyInputInstance = wrapper.find(CurrencyInput).at(0).instance() assert.equal(currencyInputInstance.state.decimalValue, 0) assert.equal(currencyInputInstance.state.hexValue, undefined) - assert.equal(wrapper.find('.currency-display-component').text(), '$0.00 USD') + assert.equal(wrapper.find('.currency-display-component').text(), '$0.00USD') const input = wrapper.find('input') assert.equal(input.props().value, 0) input.simulate('change', { target: { value: 1 } }) assert.equal(handleChangeSpy.callCount, 1) assert.ok(handleChangeSpy.calledWith('de0b6b3a7640000')) - assert.equal(wrapper.find('.currency-display-component').text(), '$231.06 USD') + assert.equal(wrapper.find('.currency-display-component').text(), '$231.06USD') assert.equal(currencyInputInstance.state.decimalValue, 1) assert.equal(currencyInputInstance.state.hexValue, 'de0b6b3a7640000') @@ -160,6 +168,7 @@ describe('CurrencyInput Component', () => { it('should call onChange and onBlur on input changes with the hex value for fiat', () => { const mockStore = { metamask: { + nativeCurrency: 'ETH', currentCurrency: 'usd', conversionRate: 231.06, }, @@ -171,6 +180,7 @@ describe('CurrencyInput Component', () => { onChange={handleChangeSpy} onBlur={handleBlurSpy} suffix="USD" + nativeCurrency="ETH" currentCurrency="usd" conversionRate={231.06} useFiat @@ -185,14 +195,14 @@ describe('CurrencyInput Component', () => { const currencyInputInstance = wrapper.find(CurrencyInput).at(0).instance() assert.equal(currencyInputInstance.state.decimalValue, 0) assert.equal(currencyInputInstance.state.hexValue, undefined) - assert.equal(wrapper.find('.currency-display-component').text(), '0 ETH') + assert.equal(wrapper.find('.currency-display-component').text(), '0ETH') const input = wrapper.find('input') assert.equal(input.props().value, 0) input.simulate('change', { target: { value: 1 } }) assert.equal(handleChangeSpy.callCount, 1) assert.ok(handleChangeSpy.calledWith('f602f2234d0ea')) - assert.equal(wrapper.find('.currency-display-component').text(), '0.004328 ETH') + assert.equal(wrapper.find('.currency-display-component').text(), '0.004328ETH') assert.equal(currencyInputInstance.state.decimalValue, 1) assert.equal(currencyInputInstance.state.hexValue, 'f602f2234d0ea') @@ -205,6 +215,7 @@ describe('CurrencyInput Component', () => { it('should change the state and pass in a new decimalValue when props.value changes', () => { const mockStore = { metamask: { + nativeCurrency: 'ETH', currentCurrency: 'usd', conversionRate: 231.06, }, @@ -216,6 +227,7 @@ describe('CurrencyInput Component', () => { onChange={handleChangeSpy} onBlur={handleBlurSpy} suffix="USD" + nativeCurrency="ETH" currentCurrency="usd" conversionRate={231.06} useFiat diff --git a/ui/app/components/currency-input/tests/currency-input.container.test.js b/ui/app/components/currency-input/tests/currency-input.container.test.js index e77945e4d..5d72958e6 100644 --- a/ui/app/components/currency-input/tests/currency-input.container.test.js +++ b/ui/app/components/currency-input/tests/currency-input.container.test.js @@ -20,12 +20,14 @@ describe('CurrencyInput container', () => { metamask: { conversionRate: 280.45, currentCurrency: 'usd', + nativeCurrency: 'ETH', }, } assert.deepEqual(mapStateToProps(mockState), { conversionRate: 280.45, currentCurrency: 'usd', + nativeCurrency: 'ETH', }) }) }) @@ -35,12 +37,14 @@ describe('CurrencyInput container', () => { const mockStateProps = { conversionRate: 280.45, currentCurrency: 'usd', + nativeCurrency: 'ETH', } const mockDispatchProps = {} assert.deepEqual(mergeProps(mockStateProps, mockDispatchProps, { useFiat: true }), { conversionRate: 280.45, currentCurrency: 'usd', + nativeCurrency: 'ETH', useFiat: true, suffix: 'USD', }) @@ -48,6 +52,7 @@ describe('CurrencyInput container', () => { assert.deepEqual(mergeProps(mockStateProps, mockDispatchProps, {}), { conversionRate: 280.45, currentCurrency: 'usd', + nativeCurrency: 'ETH', suffix: 'ETH', }) }) diff --git a/ui/app/components/dropdowns/components/account-dropdowns.js b/ui/app/components/dropdowns/components/account-dropdowns.js index b497f5c09..e6b3e0c0c 100644 --- a/ui/app/components/dropdowns/components/account-dropdowns.js +++ b/ui/app/components/dropdowns/components/account-dropdowns.js @@ -6,7 +6,7 @@ const genAccountLink = require('../../../../lib/account-link.js') const connect = require('react-redux').connect const Dropdown = require('./dropdown').Dropdown const DropdownMenuItem = require('./dropdown').DropdownMenuItem -const Identicon = require('../../identicon') +import Identicon from '../../identicon' const { checksumAddress } = require('../../../util') const copyToClipboard = require('copy-to-clipboard') const { formatBalance } = require('../../../util') @@ -26,14 +26,14 @@ class AccountDropdowns extends Component { } renderAccounts () { - const { identities, accounts, selected, menuItemStyles, actions, keyrings } = this.props + const { identities, accounts, selected, menuItemStyles, actions, keyrings, ticker } = this.props return Object.keys(identities).map((key, index) => { const identity = identities[key] const isSelected = identity.address === selected const balanceValue = accounts[key].balance - const formattedBalance = balanceValue ? formatBalance(balanceValue, 6) : '...' + const formattedBalance = balanceValue ? formatBalance(balanceValue, 6, true, ticker) : '...' const simpleAddress = identity.address.substring(2).toLowerCase() const keyring = keyrings.find((kr) => { @@ -421,6 +421,7 @@ AccountDropdowns.propTypes = { network: PropTypes.number, // actions.showExportPrivateKeyModal: , style: PropTypes.object, + ticker: PropTypes.string, enableAccountsSelector: PropTypes.bool, enableAccountOption: PropTypes.bool, enableAccountOptions: PropTypes.bool, @@ -458,6 +459,7 @@ const mapDispatchToProps = (dispatch) => { function mapStateToProps (state) { return { + ticker: state.metamask.ticker, keyrings: state.metamask.keyrings, sidebarOpen: state.appState.sidebar.isOpen, } diff --git a/ui/app/components/dropdowns/network-dropdown.js b/ui/app/components/dropdowns/network-dropdown.js index b252b25d9..d4cc695a6 100644 --- a/ui/app/components/dropdowns/network-dropdown.js +++ b/ui/app/components/dropdowns/network-dropdown.js @@ -24,8 +24,9 @@ const notToggleElementClassnames = [ function mapStateToProps (state) { return { provider: state.metamask.provider, - frequentRpcList: state.metamask.frequentRpcList || [], + frequentRpcListDetail: state.metamask.frequentRpcListDetail || [], networkDropdownOpen: state.appState.networkDropdownOpen, + network: state.metamask.network, } } @@ -40,8 +41,8 @@ function mapDispatchToProps (dispatch) { setDefaultRpcTarget: type => { dispatch(actions.setDefaultRpcTarget(type)) }, - setRpcTarget: (target) => { - dispatch(actions.setRpcTarget(target)) + setRpcTarget: (target, network, ticker, nickname) => { + dispatch(actions.setRpcTarget(target, network, ticker, nickname)) }, delRpcTarget: (target) => { dispatch(actions.delRpcTarget(target)) @@ -71,7 +72,7 @@ module.exports = compose( NetworkDropdown.prototype.render = function () { const props = this.props const { provider: { type: providerType, rpcTarget: activeNetwork } } = props - const rpcList = props.frequentRpcList + const rpcListDetail = props.frequentRpcListDetail const isOpen = this.props.networkDropdownOpen const dropdownMenuItemStyle = { fontSize: '16px', @@ -225,7 +226,7 @@ NetworkDropdown.prototype.render = function () { ), this.renderCustomOption(props.provider), - this.renderCommonRpc(rpcList, props.provider), + this.renderCommonRpc(rpcListDetail, props.provider), h( DropdownMenuItem, @@ -267,28 +268,33 @@ NetworkDropdown.prototype.getNetworkName = function () { } else if (providerName === 'rinkeby') { name = this.context.t('rinkeby') } else { - name = this.context.t('unknownNetwork') + name = provider.nickname || this.context.t('unknownNetwork') } return name } -NetworkDropdown.prototype.renderCommonRpc = function (rpcList, provider) { +NetworkDropdown.prototype.renderCommonRpc = function (rpcListDetail, provider) { const props = this.props - const reversedRpcList = rpcList.slice().reverse() + const reversedRpcListDetail = rpcListDetail.slice().reverse() + const network = props.network - return reversedRpcList.map((rpc) => { + 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 if ((rpc === 'http://localhost:8545') || currentRpcTarget) { return null } else { + const chainId = entry.chainId || network return h( DropdownMenuItem, { key: `common${rpc}`, closeMenu: () => this.props.hideNetworkDropdown(), - onClick: () => props.setRpcTarget(rpc), + onClick: () => props.setRpcTarget(rpc, chainId, ticker, nickname), style: { fontSize: '16px', lineHeight: '20px', @@ -302,7 +308,7 @@ NetworkDropdown.prototype.renderCommonRpc = function (rpcList, provider) { style: { color: currentRpcTarget ? '#ffffff' : '#9b9b9b', }, - }, rpc), + }, nickname || rpc), h('i.fa.fa-times.delete', { onClick: (e) => { @@ -317,8 +323,9 @@ NetworkDropdown.prototype.renderCommonRpc = function (rpcList, provider) { } NetworkDropdown.prototype.renderCustomOption = function (provider) { - const { rpcTarget, type } = provider + const { rpcTarget, type, ticker, nickname } = provider const props = this.props + const network = props.network if (type !== 'rpc') return null @@ -332,7 +339,7 @@ NetworkDropdown.prototype.renderCustomOption = function (provider) { DropdownMenuItem, { key: rpcTarget, - onClick: () => props.setRpcTarget(rpcTarget), + onClick: () => props.setRpcTarget(rpcTarget, network, ticker, nickname), closeMenu: () => this.props.hideNetworkDropdown(), style: { fontSize: '16px', @@ -347,7 +354,7 @@ NetworkDropdown.prototype.renderCustomOption = function (provider) { style: { color: '#ffffff', }, - }, rpcTarget), + }, nickname || rpcTarget), ] ) } diff --git a/ui/app/components/dropdowns/tests/network-dropdown.test.js b/ui/app/components/dropdowns/tests/network-dropdown.test.js index 699b54605..88ad56851 100644 --- a/ui/app/components/dropdowns/tests/network-dropdown.test.js +++ b/ui/app/components/dropdowns/tests/network-dropdown.test.js @@ -45,8 +45,8 @@ describe('Network Dropdown', () => { provider: { 'type': 'test', }, - frequentRpcList: [ - 'http://localhost:7545', + frequentRpcListDetail: [ + { rpcUrl: 'http://localhost:7545' }, ], }, appState: { diff --git a/ui/app/components/eth-balance.js b/ui/app/components/eth-balance.js index c3d084bdc..2f6395a2d 100644 --- a/ui/app/components/eth-balance.js +++ b/ui/app/components/eth-balance.js @@ -1,5 +1,6 @@ const { Component } = require('react') const h = require('react-hyperscript') +const connect = require('react-redux').connect const { inherits } = require('util') const { formatBalance, @@ -8,7 +9,12 @@ const { const Tooltip = require('./tooltip.js') const FiatValue = require('./fiat-value.js') -module.exports = EthBalanceComponent +module.exports = connect(mapStateToProps)(EthBalanceComponent) +function mapStateToProps (state) { + return { + ticker: state.metamask.ticker, + } +} inherits(EthBalanceComponent, Component) function EthBalanceComponent () { @@ -17,9 +23,9 @@ function EthBalanceComponent () { EthBalanceComponent.prototype.render = function () { const props = this.props - const { value, style, width, needsParse = true } = props + const { ticker, value, style, width, needsParse = true } = props - const formattedValue = value ? formatBalance(value, 6, needsParse) : '...' + const formattedValue = value ? formatBalance(value, 6, needsParse, ticker) : '...' return ( diff --git a/ui/app/components/identicon.js b/ui/app/components/identicon.js deleted file mode 100644 index 7bd921892..000000000 --- a/ui/app/components/identicon.js +++ /dev/null @@ -1,124 +0,0 @@ -const Component = require('react').Component -const h = require('react-hyperscript') -const inherits = require('util').inherits -const connect = require('react-redux').connect -const isNode = require('detect-node') -const findDOMNode = require('react-dom').findDOMNode -const jazzicon = require('jazzicon') -const iconFactoryGen = require('../../lib/icon-factory') -const iconFactory = iconFactoryGen(jazzicon) -const { toDataUrl } = require('../../lib/blockies') - -module.exports = connect(mapStateToProps)(IdenticonComponent) - -inherits(IdenticonComponent, Component) -function IdenticonComponent () { - Component.call(this) - - this.defaultDiameter = 46 -} - -function mapStateToProps (state) { - return { - useBlockie: state.metamask.useBlockie, - } -} - -IdenticonComponent.prototype.render = function () { - var props = this.props - const { className = '', address, image } = props - var diameter = props.diameter || this.defaultDiameter - const style = { - height: diameter, - width: diameter, - borderRadius: diameter / 2, - } - if (image) { - return h('img', { - className: `${className} identicon`, - src: image, - style: { - ...style, - }, - }) - } else if (address) { - return h('div', { - className: `${className} identicon`, - key: 'identicon-' + address, - style: { - display: 'flex', - flexShrink: 0, - alignItems: 'center', - justifyContent: 'center', - ...style, - overflow: 'hidden', - }, - }) - } else { - return h('img.balance-icon', { - className, - src: './images/eth_logo.svg', - style: { - ...style, - }, - }) - } -} - -IdenticonComponent.prototype.componentDidMount = function () { - var props = this.props - const { address, useBlockie } = props - - if (!address) return - - if (!isNode) { - // eslint-disable-next-line react/no-find-dom-node - var container = findDOMNode(this) - - const diameter = props.diameter || this.defaultDiameter - - if (useBlockie) { - _generateBlockie(container, address, diameter) - } else { - _generateJazzicon(container, address, diameter) - } - } -} - -IdenticonComponent.prototype.componentDidUpdate = function () { - var props = this.props - const { address, useBlockie } = props - - if (!address) return - - if (!isNode) { - // eslint-disable-next-line react/no-find-dom-node - var container = findDOMNode(this) - - var children = container.children - for (var i = 0; i < children.length; i++) { - container.removeChild(children[i]) - } - - const diameter = props.diameter || this.defaultDiameter - - if (useBlockie) { - _generateBlockie(container, address, diameter) - } else { - _generateJazzicon(container, address, diameter) - } - } -} - -function _generateBlockie (container, address, diameter) { - const img = new Image() - img.src = toDataUrl(address) - img.height = diameter - img.width = diameter - container.appendChild(img) -} - -function _generateJazzicon (container, address, diameter) { - const img = iconFactory.iconForAddress(address, diameter) - container.appendChild(img) -} diff --git a/ui/app/components/identicon/identicon.component.js b/ui/app/components/identicon/identicon.component.js new file mode 100644 index 000000000..b892e5ae5 --- /dev/null +++ b/ui/app/components/identicon/identicon.component.js @@ -0,0 +1,99 @@ +import React, { PureComponent } from 'react' +import PropTypes from 'prop-types' +import classnames from 'classnames' +import { toDataUrl } from '../../../lib/blockies' +import contractMap from 'eth-contract-metadata' +import { checksumAddress } from '../../../app/util' +import Jazzicon from '../jazzicon' + +const getStyles = diameter => ( + { + height: diameter, + width: diameter, + borderRadius: diameter / 2, + } +) + +export default class Identicon extends PureComponent { + static propTypes = { + address: PropTypes.string, + className: PropTypes.string, + diameter: PropTypes.number, + image: PropTypes.string, + useBlockie: PropTypes.bool, + } + + static defaultProps = { + diameter: 46, + } + + renderImage () { + const { className, diameter, image } = this.props + + return ( + <img + className={classnames('identicon', className)} + src={image} + style={getStyles(diameter)} + /> + ) + } + + renderJazzicon () { + const { address, className, diameter } = this.props + + return ( + <Jazzicon + address={address} + diameter={diameter} + className={classnames('identicon', className)} + style={getStyles(diameter)} + /> + ) + } + + renderBlockie () { + const { address, className, diameter } = this.props + + return ( + <div + className={classnames('identicon', className)} + style={getStyles(diameter)} + > + <img + src={toDataUrl(address)} + height={diameter} + width={diameter} + /> + </div> + ) + } + + render () { + const { className, address, image, diameter, useBlockie } = this.props + + if (image) { + return this.renderImage() + } + + if (address) { + const checksummedAddress = checksumAddress(address) + + if (contractMap[checksummedAddress] && contractMap[checksummedAddress].logo) { + return this.renderJazzicon() + } + + return useBlockie + ? this.renderBlockie() + : this.renderJazzicon() + } + + return ( + <img + className={classnames('balance-icon', className)} + src="./images/eth_logo.svg" + style={getStyles(diameter)} + /> + ) + } +} diff --git a/ui/app/components/identicon/identicon.container.js b/ui/app/components/identicon/identicon.container.js new file mode 100644 index 000000000..bc49bc18e --- /dev/null +++ b/ui/app/components/identicon/identicon.container.js @@ -0,0 +1,12 @@ +import { connect } from 'react-redux' +import Identicon from './identicon.component' + +const mapStateToProps = state => { + const { metamask: { useBlockie } } = state + + return { + useBlockie, + } +} + +export default connect(mapStateToProps)(Identicon) diff --git a/ui/app/components/identicon/index.js b/ui/app/components/identicon/index.js new file mode 100644 index 000000000..799c886f2 --- /dev/null +++ b/ui/app/components/identicon/index.js @@ -0,0 +1 @@ +export { default } from './identicon.container' diff --git a/ui/app/components/identicon/index.scss b/ui/app/components/identicon/index.scss new file mode 100644 index 000000000..657afc48f --- /dev/null +++ b/ui/app/components/identicon/index.scss @@ -0,0 +1,7 @@ +.identicon { + display: flex; + flex-shrink: 0; + align-items: center; + justify-content: center; + overflow: hidden; +} diff --git a/test/unit/ui/app/components/identicon.spec.js b/ui/app/components/identicon/tests/identicon.component.test.js index a2f8d8246..2944818f5 100644 --- a/test/unit/ui/app/components/identicon.spec.js +++ b/ui/app/components/identicon/tests/identicon.component.test.js @@ -3,11 +3,9 @@ import assert from 'assert' import thunk from 'redux-thunk' import configureMockStore from 'redux-mock-store' import { mount } from 'enzyme' +import Identicon from '../identicon.component' -import IdenticonComponent from '../../../../../ui/app/components/identicon' - -describe('Identicon Component', () => { - +describe('Identicon', () => { const state = { metamask: { useBlockie: false, @@ -19,18 +17,35 @@ describe('Identicon Component', () => { const store = mockStore(state) it('renders default eth_logo identicon with no props', () => { - const wrapper = mount(<IdenticonComponent store={store}/>) + const wrapper = mount( + <Identicon store={store}/> + ) + assert.equal(wrapper.find('img.balance-icon').prop('src'), './images/eth_logo.svg') }) it('renders custom image and add className props', () => { - const wrapper = mount(<IdenticonComponent store={store} className={'test-image'} image={'test-image'} />) - assert.equal(wrapper.find('img.test-image').prop('className'), 'test-image identicon') + const wrapper = mount( + <Identicon + store={store} + className="test-image" + image="test-image" + /> + ) + + assert.equal(wrapper.find('img.test-image').prop('className'), 'identicon test-image') assert.equal(wrapper.find('img.test-image').prop('src'), 'test-image') }) it('renders div with address prop', () => { - const wrapper = mount(<IdenticonComponent store={store} className={'test-address'} address={'0xTest'} />) - assert.equal(wrapper.find('div.test-address').prop('className'), 'test-address identicon') + const wrapper = mount( + <Identicon + store={store} + className="test-address" + address="0xTest" + /> + ) + + assert.equal(wrapper.find('div.test-address').prop('className'), 'identicon test-address') }) }) diff --git a/ui/app/components/index.scss b/ui/app/components/index.scss index beffdb221..e27b0f182 100644 --- a/ui/app/components/index.scss +++ b/ui/app/components/index.scss @@ -16,6 +16,8 @@ @import './export-text-container/index'; +@import './identicon/index'; + @import './info-box/index'; @import './menu-bar/index'; @@ -30,6 +32,8 @@ @import './pages/index'; +@import './provider-page-container/index'; + @import './selected-account/index'; @import './sender-to-recipient/index'; diff --git a/ui/app/components/jazzicon/index.js b/ui/app/components/jazzicon/index.js new file mode 100644 index 000000000..bea900ab9 --- /dev/null +++ b/ui/app/components/jazzicon/index.js @@ -0,0 +1 @@ +export { default } from './jazzicon.component' diff --git a/ui/app/components/jazzicon/jazzicon.component.js b/ui/app/components/jazzicon/jazzicon.component.js new file mode 100644 index 000000000..fcb1c59b1 --- /dev/null +++ b/ui/app/components/jazzicon/jazzicon.component.js @@ -0,0 +1,69 @@ +import React, { PureComponent } from 'react' +import PropTypes from 'prop-types' +import isNode from 'detect-node' +import { findDOMNode } from 'react-dom' +import jazzicon from 'jazzicon' +import iconFactoryGenerator from '../../../lib/icon-factory' +const iconFactory = iconFactoryGenerator(jazzicon) + +/** + * Wrapper around the jazzicon library to return a React component, as the library returns an + * HTMLDivElement which needs to be appended. + */ +export default class Jazzicon extends PureComponent { + static propTypes = { + address: PropTypes.string.isRequired, + className: PropTypes.string, + diameter: PropTypes.number, + style: PropTypes.object, + } + + static defaultProps = { + diameter: 46, + } + + componentDidMount () { + if (!isNode) { + this.appendJazzicon() + } + } + + componentDidUpdate (prevProps) { + const { address: prevAddress } = prevProps + const { address } = this.props + + if (!isNode && address !== prevAddress) { + this.removeExistingChildren() + this.appendJazzicon() + } + } + + removeExistingChildren () { + // eslint-disable-next-line react/no-find-dom-node + const container = findDOMNode(this) + const { children } = container + + for (let i = 0; i < children.length; i++) { + container.removeChild(children[i]) + } + } + + appendJazzicon () { + // eslint-disable-next-line react/no-find-dom-node + const container = findDOMNode(this) + const { address, diameter } = this.props + const image = iconFactory.iconForAddress(address, diameter) + container.appendChild(image) + } + + render () { + const { className, style } = this.props + + return ( + <div + className={className} + style={style} + /> + ) + } +} diff --git a/ui/app/components/modals/account-modal-container.js b/ui/app/components/modals/account-modal-container.js index aa0593df8..2a6c655e1 100644 --- a/ui/app/components/modals/account-modal-container.js +++ b/ui/app/components/modals/account-modal-container.js @@ -5,7 +5,7 @@ const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../actions') const { getSelectedIdentity } = require('../../selectors') -const Identicon = require('../identicon') +import Identicon from '../identicon' function mapStateToProps (state, ownProps) { return { diff --git a/ui/app/components/modals/clear-approved-origins/clear-approved-origins.component.js b/ui/app/components/modals/clear-approved-origins/clear-approved-origins.component.js new file mode 100644 index 000000000..ceaa20a95 --- /dev/null +++ b/ui/app/components/modals/clear-approved-origins/clear-approved-origins.component.js @@ -0,0 +1,39 @@ +import React, { PureComponent } from 'react' +import PropTypes from 'prop-types' +import Modal, { ModalContent } from '../../modal' + +export default class ClearApprovedOrigins extends PureComponent { + static propTypes = { + hideModal: PropTypes.func.isRequired, + clearApprovedOrigins: PropTypes.func.isRequired, + } + + static contextTypes = { + t: PropTypes.func, + } + + handleClear = () => { + const { clearApprovedOrigins, hideModal } = this.props + clearApprovedOrigins() + hideModal() + } + + render () { + const { t } = this.context + + return ( + <Modal + onSubmit={this.handleClear} + onCancel={() => this.props.hideModal()} + submitText={t('ok')} + cancelText={t('nevermind')} + submitType="secondary" + > + <ModalContent + title={t('clearApprovalData')} + description={t('confirmClear')} + /> + </Modal> + ) + } +} diff --git a/ui/app/components/modals/clear-approved-origins/clear-approved-origins.container.js b/ui/app/components/modals/clear-approved-origins/clear-approved-origins.container.js new file mode 100644 index 000000000..3a801a062 --- /dev/null +++ b/ui/app/components/modals/clear-approved-origins/clear-approved-origins.container.js @@ -0,0 +1,16 @@ +import { connect } from 'react-redux' +import { compose } from 'recompose' +import withModalProps from '../../../higher-order-components/with-modal-props' +import ClearApprovedOriginsComponent from './clear-approved-origins.component' +import { clearApprovedOrigins } from '../../../actions' + +const mapDispatchToProps = dispatch => { + return { + clearApprovedOrigins: () => dispatch(clearApprovedOrigins()), + } +} + +export default compose( + withModalProps, + connect(null, mapDispatchToProps) +)(ClearApprovedOriginsComponent) diff --git a/ui/app/components/modals/clear-approved-origins/index.js b/ui/app/components/modals/clear-approved-origins/index.js new file mode 100644 index 000000000..b3e321995 --- /dev/null +++ b/ui/app/components/modals/clear-approved-origins/index.js @@ -0,0 +1 @@ +export { default } from './clear-approved-origins.container' diff --git a/ui/app/components/modals/hide-token-confirmation-modal.js b/ui/app/components/modals/hide-token-confirmation-modal.js index fb38516d3..43f3009a5 100644 --- a/ui/app/components/modals/hide-token-confirmation-modal.js +++ b/ui/app/components/modals/hide-token-confirmation-modal.js @@ -4,7 +4,7 @@ const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../actions') -const Identicon = require('../identicon') +import Identicon from '../identicon' function mapStateToProps (state) { return { diff --git a/ui/app/components/modals/modal.js b/ui/app/components/modals/modal.js index 15ca9deaa..5aff4f5e1 100644 --- a/ui/app/components/modals/modal.js +++ b/ui/app/components/modals/modal.js @@ -27,8 +27,8 @@ import TransactionConfirmed from './transaction-confirmed' import ConfirmCustomizeGasModal from './customize-gas' import CancelTransaction from './cancel-transaction' import WelcomeBeta from './welcome-beta' -import TransactionDetails from './transaction-details' import RejectTransactions from './reject-transactions' +import ClearApprovedOrigins from './clear-approved-origins' const modalContainerBaseStyle = { transform: 'translate3d(-50%, 0, 0px)', @@ -213,6 +213,19 @@ const MODALS = { }, }, + CLEAR_APPROVED_ORIGINS: { + contents: h(ClearApprovedOrigins), + mobileModalStyle: { + ...modalContainerMobileStyle, + }, + laptopModalStyle: { + ...modalContainerLaptopStyle, + }, + contentStyle: { + borderRadius: '8px', + }, + }, + OLD_UI_NOTIFICATION_MODAL: { contents: [ h(NotifcationModal, { @@ -366,19 +379,6 @@ const MODALS = { }, }, - TRANSACTION_DETAILS: { - contents: h(TransactionDetails), - mobileModalStyle: { - ...modalContainerMobileStyle, - }, - laptopModalStyle: { - ...modalContainerLaptopStyle, - }, - contentStyle: { - borderRadius: '8px', - }, - }, - REJECT_TRANSACTIONS: { contents: h(RejectTransactions), mobileModalStyle: { diff --git a/ui/app/components/modals/transaction-details/index.js b/ui/app/components/modals/transaction-details/index.js deleted file mode 100644 index 1fc42c662..000000000 --- a/ui/app/components/modals/transaction-details/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './transaction-details.container' diff --git a/ui/app/components/modals/transaction-details/transaction-details.component.js b/ui/app/components/modals/transaction-details/transaction-details.component.js deleted file mode 100644 index f2fec3409..000000000 --- a/ui/app/components/modals/transaction-details/transaction-details.component.js +++ /dev/null @@ -1,54 +0,0 @@ -import React, { PureComponent } from 'react' -import PropTypes from 'prop-types' -import Modal from '../../modal' -import TransactionListItemDetails from '../../transaction-list-item-details' -import { hexToDecimal } from '../../../helpers/conversions.util' - -export default class TransactionConfirmed extends PureComponent { - static contextTypes = { - t: PropTypes.func, - } - - static propTypes = { - hideModal: PropTypes.func, - transaction: PropTypes.object, - onRetry: PropTypes.func, - showRetry: PropTypes.bool, - onCancel: PropTypes.func, - showCancel: PropTypes.bool, - } - - handleSubmit = () => { - this.props.hideModal() - } - - handleRetry = () => { - const { onRetry, hideModal } = this.props - - Promise.resolve(onRetry()).then(() => hideModal()) - } - - render () { - const { t } = this.context - const { transaction, showRetry, onCancel, showCancel } = this.props - const { txParams: { nonce } = {} } = transaction - const decimalNonce = nonce && hexToDecimal(nonce) - - return ( - <Modal - onSubmit={this.handleSubmit} - onClose={this.handleSubmit} - submitText={t('ok')} - headerText={t('transactionWithNonce', [`#${decimalNonce}`])} - > - <TransactionListItemDetails - transaction={transaction} - onRetry={this.handleRetry} - showRetry={showRetry} - onCancel={() => onCancel()} - showCancel={showCancel} - /> - </Modal> - ) - } -} diff --git a/ui/app/components/modals/transaction-details/transaction-details.container.js b/ui/app/components/modals/transaction-details/transaction-details.container.js deleted file mode 100644 index f212920bb..000000000 --- a/ui/app/components/modals/transaction-details/transaction-details.container.js +++ /dev/null @@ -1,4 +0,0 @@ -import TransactionDetails from './transaction-details.component' -import withModalProps from '../../../higher-order-components/with-modal-props' - -export default withModalProps(TransactionDetails) diff --git a/ui/app/components/network-display/index.scss b/ui/app/components/network-display/index.scss index 2085cff67..e9f2f2057 100644 --- a/ui/app/components/network-display/index.scss +++ b/ui/app/components/network-display/index.scss @@ -3,11 +3,14 @@ display: flex; align-items: center; justify-content: flex-start; - background-color: lighten(rgb(125, 128, 130), 45%); padding: 0 10px; border-radius: 4px; height: 25px; + &--colored { + background-color: lighten(rgb(125, 128, 130), 45%); + } + &--mainnet { background-color: lighten($blue-lagoon, 68%); } diff --git a/ui/app/components/network-display/network-display.component.js b/ui/app/components/network-display/network-display.component.js index 38626af20..22d617099 100644 --- a/ui/app/components/network-display/network-display.component.js +++ b/ui/app/components/network-display/network-display.component.js @@ -16,7 +16,12 @@ const networkToClassHash = { } export default class NetworkDisplay extends Component { + static defaultProps = { + colored: true, + } + static propTypes = { + colored: PropTypes.bool, network: PropTypes.string, provider: PropTypes.object, } @@ -41,14 +46,16 @@ export default class NetworkDisplay extends Component { } render () { - const { network, provider: { type } } = this.props + const { colored, network, provider: { type, nickname } } = this.props const networkClass = networkToClassHash[network] return ( - <div className={classnames( - 'network-display__container', - networkClass && ('network-display__container--' + networkClass) - )}> + <div + className={classnames('network-display__container', { + 'network-display__container--colored': colored, + ['network-display__container--' + networkClass]: colored && networkClass, + })} + > { networkClass ? <div className={`network-display__icon network-display__icon--${networkClass}`} /> @@ -61,7 +68,7 @@ export default class NetworkDisplay extends Component { /> } <div className="network-display__name"> - { this.context.t(type) } + { type === 'rpc' && nickname ? nickname : this.context.t(type) } </div> </div> ) diff --git a/ui/app/components/network.js b/ui/app/components/network.js index 83297c4f2..611aadb7b 100644 --- a/ui/app/components/network.js +++ b/ui/app/components/network.js @@ -23,9 +23,10 @@ Network.prototype.render = function () { const props = this.props const context = this.context const networkNumber = props.network - let providerName + let providerName, providerNick try { providerName = props.provider.type + providerNick = props.provider.nickname || '' } catch (e) { providerName = null } @@ -131,7 +132,7 @@ Network.prototype.render = function () { }, }), - h('.network-name', context.t('privateNetwork')), + h('.network-name', providerNick || context.t('privateNetwork')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) } diff --git a/ui/app/components/page-container/index.scss b/ui/app/components/page-container/index.scss index 6742e3082..ba1215e84 100644 --- a/ui/app/components/page-container/index.scss +++ b/ui/app/components/page-container/index.scss @@ -101,6 +101,7 @@ font-size: 2rem; font-weight: 500; line-height: 2rem; + margin-right: 1.5rem; } &__subtitle { diff --git a/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.component.js b/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.component.js index c92867afe..7d01aaffb 100644 --- a/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.component.js +++ b/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.component.js @@ -136,7 +136,7 @@ export default class ConfirmTransactionBase extends Component { if (simulationFails) { return { valid: true, - errorKey: TRANSACTION_ERROR_KEY, + errorKey: simulationFails.errorKey ? simulationFails.errorKey : TRANSACTION_ERROR_KEY, } } diff --git a/ui/app/components/pages/home/home.component.js b/ui/app/components/pages/home/home.component.js index d3c71c4f6..b9ec3c258 100644 --- a/ui/app/components/pages/home/home.component.js +++ b/ui/app/components/pages/home/home.component.js @@ -4,6 +4,8 @@ import Media from 'react-media' import { Redirect } from 'react-router-dom' import WalletView from '../../wallet-view' import TransactionView from '../../transaction-view' +import ProviderApproval from '../provider-approval' + import { INITIALIZE_BACKUP_PHRASE_ROUTE, RESTORE_VAULT_ROUTE, @@ -21,6 +23,7 @@ export default class Home extends PureComponent { seedWords: PropTypes.string, suggestedTokens: PropTypes.object, unconfirmedTransactionsCount: PropTypes.number, + providerRequests: PropTypes.array, } componentDidMount () { @@ -46,6 +49,7 @@ export default class Home extends PureComponent { lostAccounts, forgottenPassword, seedWords, + providerRequests, } = this.props // notices @@ -62,6 +66,12 @@ export default class Home extends PureComponent { return <Redirect to={{ pathname: RESTORE_VAULT_ROUTE }} /> } + if (providerRequests && providerRequests.length > 0) { + return ( + <ProviderApproval providerRequest={providerRequests[0]} /> + ) + } + return ( <div className="main-container"> <div className="account-and-transaction-details"> diff --git a/ui/app/components/pages/home/home.container.js b/ui/app/components/pages/home/home.container.js index 58001df6b..bb8cf5e81 100644 --- a/ui/app/components/pages/home/home.container.js +++ b/ui/app/components/pages/home/home.container.js @@ -11,6 +11,7 @@ const mapStateToProps = state => { lostAccounts, seedWords, suggestedTokens, + providerRequests, } = metamask const { forgottenPassword } = appState @@ -21,6 +22,7 @@ const mapStateToProps = state => { seedWords, suggestedTokens, unconfirmedTransactionsCount: unconfirmedTransactionsCountSelector(state), + providerRequests, } } diff --git a/ui/app/components/pages/provider-approval/index.js b/ui/app/components/pages/provider-approval/index.js new file mode 100644 index 000000000..4162f3155 --- /dev/null +++ b/ui/app/components/pages/provider-approval/index.js @@ -0,0 +1 @@ +export { default } from './provider-approval.container' diff --git a/ui/app/components/pages/provider-approval/provider-approval.component.js b/ui/app/components/pages/provider-approval/provider-approval.component.js new file mode 100644 index 000000000..da98bc3fc --- /dev/null +++ b/ui/app/components/pages/provider-approval/provider-approval.component.js @@ -0,0 +1,28 @@ +import PropTypes from 'prop-types' +import React, { Component } from 'react' +import ProviderPageContainer from '../../provider-page-container' + +export default class ProviderApproval extends Component { + static propTypes = { + approveProviderRequest: PropTypes.func.isRequired, + providerRequest: PropTypes.object.isRequired, + rejectProviderRequest: PropTypes.func.isRequired, + }; + + static contextTypes = { + t: PropTypes.func, + }; + + render () { + const { approveProviderRequest, providerRequest, rejectProviderRequest } = this.props + return ( + <ProviderPageContainer + approveProviderRequest={approveProviderRequest} + origin={providerRequest.origin} + rejectProviderRequest={rejectProviderRequest} + siteImage={providerRequest.siteImage} + siteTitle={providerRequest.siteTitle} + /> + ) + } +} diff --git a/ui/app/components/pages/provider-approval/provider-approval.container.js b/ui/app/components/pages/provider-approval/provider-approval.container.js new file mode 100644 index 000000000..b223244a1 --- /dev/null +++ b/ui/app/components/pages/provider-approval/provider-approval.container.js @@ -0,0 +1,12 @@ +import { connect } from 'react-redux' +import ProviderApproval from './provider-approval.component' +import { approveProviderRequest, rejectProviderRequest } from '../../../actions' + +function mapDispatchToProps (dispatch) { + return { + approveProviderRequest: origin => dispatch(approveProviderRequest(origin)), + rejectProviderRequest: origin => dispatch(rejectProviderRequest(origin)), + } +} + +export default connect(null, mapDispatchToProps)(ProviderApproval) diff --git a/ui/app/components/pages/settings/settings-tab/index.scss b/ui/app/components/pages/settings/settings-tab/index.scss index 3bf840c86..ef32b0e4c 100644 --- a/ui/app/components/pages/settings/settings-tab/index.scss +++ b/ui/app/components/pages/settings/settings-tab/index.scss @@ -5,12 +5,9 @@ color: $crimson; } - &__rpc-save-button { - align-self: flex-end; - padding: 5px; - text-transform: uppercase; - color: $dusty-gray; - cursor: pointer; + &__advanced-link { + color: $curious-blue; + padding-left: 5px; } &__rpc-save-button { @@ -19,6 +16,9 @@ text-transform: uppercase; color: $dusty-gray; cursor: pointer; + width: 25%; + min-width: 80px; + height: 33px; } &__button--red { diff --git a/ui/app/components/pages/settings/settings-tab/settings-tab.component.js b/ui/app/components/pages/settings/settings-tab/settings-tab.component.js index a9e2a723e..a0a8ed47e 100644 --- a/ui/app/components/pages/settings/settings-tab/settings-tab.component.js +++ b/ui/app/components/pages/settings/settings-tab/settings-tab.component.js @@ -39,12 +39,15 @@ export default class SettingsTab extends PureComponent { metamask: PropTypes.object, setUseBlockie: PropTypes.func, setHexDataFeatureFlag: PropTypes.func, + setPrivacyMode: PropTypes.func, + privacyMode: PropTypes.bool, setCurrentCurrency: PropTypes.func, setRpcTarget: PropTypes.func, delRpcTarget: PropTypes.func, displayWarning: PropTypes.func, revealSeedConfirmation: PropTypes.func, setFeatureFlagToBeta: PropTypes.func, + showClearApprovalModal: PropTypes.func, showResetAccountConfirmationModal: PropTypes.func, warning: PropTypes.string, history: PropTypes.object, @@ -55,12 +58,17 @@ export default class SettingsTab extends PureComponent { sendHexData: PropTypes.bool, currentCurrency: PropTypes.string, conversionDate: PropTypes.number, - useETHAsPrimaryCurrency: PropTypes.bool, - setUseETHAsPrimaryCurrencyPreference: PropTypes.func, + nativeCurrency: PropTypes.string, + useNativeCurrencyAsPrimaryCurrency: PropTypes.bool, + setUseNativeCurrencyAsPrimaryCurrencyPreference: PropTypes.func, } state = { newRpc: '', + chainId: '', + showOptions: false, + ticker: '', + nickname: '', } renderCurrentConversion () { @@ -121,37 +129,98 @@ export default class SettingsTab extends PureComponent { renderNewRpcUrl () { const { t } = this.context - const { newRpc } = this.state + const { newRpc, chainId, ticker, nickname } = this.state return ( <div className="settings-page__content-row"> <div className="settings-page__content-item"> - <span>{ t('newRPC') }</span> + <span>{ t('newNetwork') }</span> </div> <div className="settings-page__content-item"> <div className="settings-page__content-item-col"> <TextField type="text" id="new-rpc" - placeholder={t('newRPC')} + placeholder={t('rpcURL')} value={newRpc} onChange={e => this.setState({ newRpc: e.target.value })} onKeyPress={e => { if (e.key === 'Enter') { - this.validateRpc(newRpc) + this.validateRpc(newRpc, chainId, ticker, nickname) } }} fullWidth - margin="none" + margin="dense" /> - <div - className="settings-tab__rpc-save-button" - onClick={e => { - e.preventDefault() - this.validateRpc(newRpc) + <TextField + type="text" + id="chainid" + placeholder={t('optionalChainId')} + value={chainId} + onChange={e => this.setState({ chainId: e.target.value })} + onKeyPress={e => { + if (e.key === 'Enter') { + this.validateRpc(newRpc, chainId, ticker, nickname) + } }} - > - { t('save') } + style={{ + display: this.state.showOptions ? null : 'none', + }} + fullWidth + margin="dense" + /> + <TextField + type="text" + id="ticker" + placeholder={t('optionalSymbol')} + value={ticker} + onChange={e => this.setState({ ticker: e.target.value })} + onKeyPress={e => { + if (e.key === 'Enter') { + this.validateRpc(newRpc, chainId, ticker, nickname) + } + }} + style={{ + display: this.state.showOptions ? null : 'none', + }} + fullWidth + margin="dense" + /> + <TextField + type="text" + id="nickname" + placeholder={t('optionalNickname')} + value={nickname} + onChange={e => this.setState({ nickname: e.target.value })} + onKeyPress={e => { + if (e.key === 'Enter') { + this.validateRpc(newRpc, chainId, ticker, nickname) + } + }} + style={{ + display: this.state.showOptions ? null : 'none', + }} + fullWidth + margin="dense" + /> + <div className="flex-row flex-align-center space-between"> + <span className="settings-tab__advanced-link" + onClick={e => { + e.preventDefault() + this.setState({ showOptions: !this.state.showOptions }) + }} + > + { t(this.state.showOptions ? 'hideAdvancedOptions' : 'showAdvancedOptions') } + </span> + <button + className="button btn-primary settings-tab__rpc-save-button" + onClick={e => { + e.preventDefault() + this.validateRpc(newRpc, chainId, ticker, nickname) + }} + > + { t('save') } + </button> </div> </div> </div> @@ -159,11 +228,11 @@ export default class SettingsTab extends PureComponent { ) } - validateRpc (newRpc) { + validateRpc (newRpc, chainId, ticker = 'ETH', nickname) { const { setRpcTarget, displayWarning } = this.props if (validUrl.isWebUri(newRpc)) { - setRpcTarget(newRpc) + setRpcTarget(newRpc, chainId, ticker, nickname) } else { const appendedRpc = `http://${newRpc}` @@ -210,6 +279,36 @@ export default class SettingsTab extends PureComponent { ) } + renderClearApproval () { + const { t } = this.context + const { showClearApprovalModal } = this.props + return ( + <div className="settings-page__content-row"> + <div className="settings-page__content-item"> + <span>{ t('approvalData') }</span> + <span className="settings-page__content-description"> + { t('approvalDataDescription') } + </span> + </div> + <div className="settings-page__content-item"> + <div className="settings-page__content-item-col"> + <Button + type="secondary" + large + className="settings-tab__button--orange" + onClick={event => { + event.preventDefault() + showClearApprovalModal() + }} + > + { t('clearApprovalData') } + </Button> + </div> + </div> + </div> + ) + } + renderSeedWords () { const { t } = this.context const { history } = this.props @@ -341,9 +440,13 @@ export default class SettingsTab extends PureComponent { ) } - renderUseEthAsPrimaryCurrency () { + renderUsePrimaryCurrencyOptions () { const { t } = this.context - const { useETHAsPrimaryCurrency, setUseETHAsPrimaryCurrencyPreference } = this.props + const { + nativeCurrency, + setUseNativeCurrencyAsPrimaryCurrencyPreference, + useNativeCurrencyAsPrimaryCurrency, + } = this.props return ( <div className="settings-page__content-row"> @@ -359,23 +462,23 @@ export default class SettingsTab extends PureComponent { <div className="settings-tab__radio-button"> <input type="radio" - id="eth-primary-currency" - onChange={() => setUseETHAsPrimaryCurrencyPreference(true)} - checked={Boolean(useETHAsPrimaryCurrency)} + id="native-primary-currency" + onChange={() => setUseNativeCurrencyAsPrimaryCurrencyPreference(true)} + checked={Boolean(useNativeCurrencyAsPrimaryCurrency)} /> <label - htmlFor="eth-primary-currency" + htmlFor="native-primary-currency" className="settings-tab__radio-label" > - { t('eth') } + { nativeCurrency } </label> </div> <div className="settings-tab__radio-button"> <input type="radio" id="fiat-primary-currency" - onChange={() => setUseETHAsPrimaryCurrencyPreference(false)} - checked={!useETHAsPrimaryCurrency} + onChange={() => setUseNativeCurrencyAsPrimaryCurrencyPreference(false)} + checked={!useNativeCurrencyAsPrimaryCurrency} /> <label htmlFor="fiat-primary-currency" @@ -391,6 +494,32 @@ export default class SettingsTab extends PureComponent { ) } + renderPrivacyOptIn () { + const { t } = this.context + const { privacyMode, setPrivacyMode } = this.props + + return ( + <div className="settings-page__content-row"> + <div className="settings-page__content-item"> + <span>{ t('privacyMode') }</span> + <div className="settings-page__content-description"> + { t('privacyModeDescription') } + </div> + </div> + <div className="settings-page__content-item"> + <div className="settings-page__content-item-col"> + <ToggleButton + value={privacyMode} + onToggle={value => setPrivacyMode(!value)} + activeLabel="" + inactiveLabel="" + /> + </div> + </div> + </div> + ) + } + render () { const { warning, isMascara } = this.props @@ -398,15 +527,17 @@ export default class SettingsTab extends PureComponent { <div className="settings-page__content"> { warning && <div className="settings-tab__error">{ warning }</div> } { this.renderCurrentConversion() } - { this.renderUseEthAsPrimaryCurrency() } + { this.renderUsePrimaryCurrencyOptions() } { this.renderCurrentLocale() } { this.renderNewRpcUrl() } { this.renderStateLogs() } { this.renderSeedWords() } { !isMascara && this.renderOldUI() } { this.renderResetAccount() } - { this.renderBlockieOptIn() } + { this.renderClearApproval() } + { this.renderPrivacyOptIn() } { this.renderHexDataOptIn() } + { this.renderBlockieOptIn() } </div> ) } diff --git a/ui/app/components/pages/settings/settings-tab/settings-tab.container.js b/ui/app/components/pages/settings/settings-tab/settings-tab.container.js index de30f309c..b6c33a5b2 100644 --- a/ui/app/components/pages/settings/settings-tab/settings-tab.container.js +++ b/ui/app/components/pages/settings/settings-tab/settings-tab.container.js @@ -11,7 +11,7 @@ import { updateCurrentLocale, setFeatureFlag, showModal, - setUseETHAsPrimaryCurrencyPreference, + setUseNativeCurrencyAsPrimaryCurrencyPreference, } from '../../../../actions' import { preferencesSelector } from '../../../../selectors' @@ -20,13 +20,17 @@ const mapStateToProps = state => { const { currentCurrency, conversionDate, + nativeCurrency, useBlockie, - featureFlags: { sendHexData } = {}, + featureFlags: { + sendHexData, + privacyMode, + } = {}, provider = {}, isMascara, currentLocale, } = metamask - const { useETHAsPrimaryCurrency } = preferencesSelector(state) + const { useNativeCurrencyAsPrimaryCurrency } = preferencesSelector(state) return { warning, @@ -34,17 +38,19 @@ const mapStateToProps = state => { currentLocale, currentCurrency, conversionDate, + nativeCurrency, useBlockie, sendHexData, + privacyMode, provider, - useETHAsPrimaryCurrency, + useNativeCurrencyAsPrimaryCurrency, } } const mapDispatchToProps = dispatch => { return { setCurrentCurrency: currency => dispatch(setCurrentCurrency(currency)), - setRpcTarget: newRpc => dispatch(setRpcTarget(newRpc)), + setRpcTarget: (newRpc, chainId, ticker, nickname) => dispatch(setRpcTarget(newRpc, chainId, ticker, nickname)), displayWarning: warning => dispatch(displayWarning(warning)), revealSeedConfirmation: () => dispatch(revealSeedConfirmation()), setUseBlockie: value => dispatch(setUseBlockie(value)), @@ -53,10 +59,12 @@ const mapDispatchToProps = dispatch => { return dispatch(setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL')) }, setHexDataFeatureFlag: shouldShow => dispatch(setFeatureFlag('sendHexData', shouldShow)), + setPrivacyMode: enabled => dispatch(setFeatureFlag('privacyMode', enabled)), showResetAccountConfirmationModal: () => dispatch(showModal({ name: 'CONFIRM_RESET_ACCOUNT' })), - setUseETHAsPrimaryCurrencyPreference: value => { - return dispatch(setUseETHAsPrimaryCurrencyPreference(value)) + setUseNativeCurrencyAsPrimaryCurrencyPreference: value => { + return dispatch(setUseNativeCurrencyAsPrimaryCurrencyPreference(value)) }, + showClearApprovalModal: () => dispatch(showModal({ name: 'CLEAR_APPROVED_ORIGINS' })), } } diff --git a/ui/app/components/provider-page-container/index.js b/ui/app/components/provider-page-container/index.js new file mode 100644 index 000000000..927c35940 --- /dev/null +++ b/ui/app/components/provider-page-container/index.js @@ -0,0 +1,3 @@ +export {default} from './provider-page-container.component' +export {default as ProviderPageContainerContent} from './provider-page-container-content' +export {default as ProviderPageContainerHeader} from './provider-page-container-header' diff --git a/ui/app/components/provider-page-container/index.scss b/ui/app/components/provider-page-container/index.scss new file mode 100644 index 000000000..8d35ac179 --- /dev/null +++ b/ui/app/components/provider-page-container/index.scss @@ -0,0 +1,121 @@ +.provider-approval-container { + display: flex; + + &__header { + display: flex; + flex-direction: column; + align-items: flex-end; + border-bottom: 1px solid $geyser; + padding: 9px; + } + + &__content { + display: flex; + overflow-y: auto; + flex: 1; + flex-direction: column; + justify-content: space-between; + color: #7C808E; + + h1, h2 { + color: #4A4A4A; + display: flex; + justify-content: center; + text-align: center; + } + + h2 { + font-size: 16px; + line-height: 18px; + padding: 20px; + } + + h1 { + font-size: 22px; + line-height: 26px; + padding: 20px; + } + + p { + padding: 0 40px; + text-align: center; + font-size: 12px; + line-height: 18px; + } + + a, a:hover { + color: $dodger-blue; + } + + .provider-approval-visual { + display: flex; + flex-direction: row; + justify-content: space-evenly; + position: relative; + margin: 0 32px; + + section { + display: flex; + flex-direction: column; + align-items: center; + flex: 1; + } + + h1 { + font-size: 14px; + line-height: 18px; + padding: 8px 0 0; + } + + h2 { + font-size: 10px; + line-height: 14px; + padding: 0; + color: #A2A4AC; + } + + &__check { + width: 40px; + height: 40px; + background: white url("/images/provider-approval-check.svg") no-repeat; + margin-top: 14px; + } + + &__identicon { + width: 64px; + height: 64px; + + &--default { + background-color: #777A87; + color: white; + width: 64px; + height: 64px; + border-radius: 32px; + display: flex; + align-items: center; + justify-content: center; + font-weight: bold; + } + } + + &:before { + border-top: 2px dashed #CDD1E4; + content: ""; + margin: 0 auto; + position: absolute; + top: 32px; + left: 0; + bottom: 0; + right: 0; + width: 65%; + z-index: -1; + } + } + + .secure-badge { + display: flex; + justify-content: center; + padding: 25px; + } + } +} diff --git a/ui/app/components/provider-page-container/provider-page-container-content/index.js b/ui/app/components/provider-page-container/provider-page-container-content/index.js new file mode 100644 index 000000000..73e491adc --- /dev/null +++ b/ui/app/components/provider-page-container/provider-page-container-content/index.js @@ -0,0 +1 @@ +export {default} from './provider-page-container-content.container' diff --git a/ui/app/components/provider-page-container/provider-page-container-content/provider-page-container-content.component.js b/ui/app/components/provider-page-container/provider-page-container-content/provider-page-container-content.component.js new file mode 100644 index 000000000..268db613f --- /dev/null +++ b/ui/app/components/provider-page-container/provider-page-container-content/provider-page-container-content.component.js @@ -0,0 +1,77 @@ +import PropTypes from 'prop-types' +import React, {PureComponent} from 'react' +import Identicon from '../../identicon' + +export default class ProviderPageContainerContent extends PureComponent { + static propTypes = { + origin: PropTypes.string.isRequired, + selectedIdentity: PropTypes.string.isRequired, + siteImage: PropTypes.string, + siteTitle: PropTypes.string.isRequired, + } + + static contextTypes = { + t: PropTypes.func, + }; + + renderConnectVisual = () => { + const { origin, selectedIdentity, siteImage, siteTitle } = this.props + + return ( + <div className="provider-approval-visual"> + <section> + {siteImage ? ( + <img + className="provider-approval-visual__identicon" + src={siteImage} + /> + ) : ( + <i className="provider-approval-visual__identicon--default"> + {siteTitle.charAt(0).toUpperCase()} + </i> + )} + <h1>{siteTitle}</h1> + <h2>{origin}</h2> + </section> + <span className="provider-approval-visual__check" /> + <section> + <Identicon + className="provider-approval-visual__identicon" + address={selectedIdentity.address} + diameter={64} + /> + <h1>{selectedIdentity.name}</h1> + </section> + </div> + ) + } + + render () { + const { siteTitle } = this.props + const { t } = this.context + + return ( + <div className="provider-approval-container__content"> + <section> + <h2>{t('connectRequest')}</h2> + {this.renderConnectVisual()} + <h1>{t('providerRequest', [siteTitle])}</h1> + <p> + {t('providerRequestInfo')} + <br/> + <a + href="https://medium.com/metamask/introducing-privacy-mode-42549d4870fa" + target="_blank" + rel="noopener noreferrer" + > + {t('learnMore')}. + </a> + </p> + </section> + <section className="secure-badge"> + <img src="/images/mm-secure.svg" /> + </section> + </div> + ) + } +} diff --git a/ui/app/components/provider-page-container/provider-page-container-content/provider-page-container-content.container.js b/ui/app/components/provider-page-container/provider-page-container-content/provider-page-container-content.container.js new file mode 100644 index 000000000..3ea1ce20e --- /dev/null +++ b/ui/app/components/provider-page-container/provider-page-container-content/provider-page-container-content.container.js @@ -0,0 +1,11 @@ +import { connect } from 'react-redux' +import ProviderPageContainerContent from './provider-page-container-content.component' +import { getSelectedIdentity } from '../../../selectors' + +const mapStateToProps = (state) => { + return { + selectedIdentity: getSelectedIdentity(state), + } +} + +export default connect(mapStateToProps)(ProviderPageContainerContent) diff --git a/ui/app/components/provider-page-container/provider-page-container-header/index.js b/ui/app/components/provider-page-container/provider-page-container-header/index.js new file mode 100644 index 000000000..430627d3a --- /dev/null +++ b/ui/app/components/provider-page-container/provider-page-container-header/index.js @@ -0,0 +1 @@ +export {default} from './provider-page-container-header.component' diff --git a/ui/app/components/provider-page-container/provider-page-container-header/provider-page-container-header.component.js b/ui/app/components/provider-page-container/provider-page-container-header/provider-page-container-header.component.js new file mode 100644 index 000000000..41bf6c3dd --- /dev/null +++ b/ui/app/components/provider-page-container/provider-page-container-header/provider-page-container-header.component.js @@ -0,0 +1,12 @@ +import React, {PureComponent} from 'react' +import NetworkDisplay from '../../network-display' + +export default class ProviderPageContainerHeader extends PureComponent { + render () { + return ( + <div className="provider-approval-container__header"> + <NetworkDisplay colored={false} /> + </div> + ) + } +} diff --git a/ui/app/components/provider-page-container/provider-page-container.component.js b/ui/app/components/provider-page-container/provider-page-container.component.js new file mode 100644 index 000000000..902733616 --- /dev/null +++ b/ui/app/components/provider-page-container/provider-page-container.component.js @@ -0,0 +1,50 @@ +import PropTypes from 'prop-types' +import React, {PureComponent} from 'react' +import { ProviderPageContainerContent, ProviderPageContainerHeader } from './' +import { PageContainerFooter } from '../page-container' + +export default class ProviderPageContainer extends PureComponent { + static propTypes = { + approveProviderRequest: PropTypes.func.isRequired, + origin: PropTypes.string.isRequired, + rejectProviderRequest: PropTypes.func.isRequired, + siteImage: PropTypes.string, + siteTitle: PropTypes.string.isRequired, + }; + + static contextTypes = { + t: PropTypes.func, + }; + + onCancel = () => { + const { origin, rejectProviderRequest } = this.props + rejectProviderRequest(origin) + } + + onSubmit = () => { + const { approveProviderRequest, origin } = this.props + approveProviderRequest(origin) + } + + render () { + const {origin, siteImage, siteTitle} = this.props + + return ( + <div className="page-container provider-approval-container"> + <ProviderPageContainerHeader /> + <ProviderPageContainerContent + origin={origin} + siteImage={siteImage} + siteTitle={siteTitle} + /> + <PageContainerFooter + onCancel={() => this.onCancel()} + cancelText={this.context.t('cancel')} + onSubmit={() => this.onSubmit()} + submitText={this.context.t('connect')} + submitButtonType="confirm" + /> + </div> + ) + } +} diff --git a/ui/app/components/send/account-list-item/account-list-item.container.js b/ui/app/components/send/account-list-item/account-list-item.container.js index 4b4519288..f8e73d923 100644 --- a/ui/app/components/send/account-list-item/account-list-item.container.js +++ b/ui/app/components/send/account-list-item/account-list-item.container.js @@ -2,6 +2,7 @@ import { connect } from 'react-redux' import { getConversionRate, getCurrentCurrency, + getNativeCurrency, } from '../send.selectors.js' import AccountListItem from './account-list-item.component' @@ -11,5 +12,6 @@ function mapStateToProps (state) { return { conversionRate: getConversionRate(state), currentCurrency: getCurrentCurrency(state), + nativeCurrency: getNativeCurrency(state), } } diff --git a/ui/app/components/send/account-list-item/tests/account-list-item-component.test.js b/ui/app/components/send/account-list-item/tests/account-list-item-component.test.js index f88c0dbd0..6ffc0b1c6 100644 --- a/ui/app/components/send/account-list-item/tests/account-list-item-component.test.js +++ b/ui/app/components/send/account-list-item/tests/account-list-item-component.test.js @@ -28,6 +28,7 @@ describe('AccountListItem Component', function () { className={'mockClassName'} conversionRate={4} currentCurrency={'mockCurrentyCurrency'} + nativeCurrency={'ETH'} displayAddress={false} displayBalance={false} handleClick={propsMethodSpies.handleClick} diff --git a/ui/app/components/send/account-list-item/tests/account-list-item-container.test.js b/ui/app/components/send/account-list-item/tests/account-list-item-container.test.js index af0859117..7c2f5fcb2 100644 --- a/ui/app/components/send/account-list-item/tests/account-list-item-container.test.js +++ b/ui/app/components/send/account-list-item/tests/account-list-item-container.test.js @@ -13,6 +13,7 @@ proxyquire('../account-list-item.container.js', { '../send.selectors.js': { getConversionRate: (s) => `mockConversionRate:${s}`, getCurrentCurrency: (s) => `mockCurrentCurrency:${s}`, + getNativeCurrency: (s) => `mockNativeCurrency:${s}`, }, }) @@ -24,6 +25,7 @@ describe('account-list-item container', () => { assert.deepEqual(mapStateToProps('mockState'), { conversionRate: 'mockConversionRate:mockState', currentCurrency: 'mockCurrentCurrency:mockState', + nativeCurrency: 'mockNativeCurrency:mockState', }) }) diff --git a/ui/app/components/send/send-content/send-amount-row/tests/send-amount-row-component.test.js b/ui/app/components/send/send-content/send-amount-row/tests/send-amount-row-component.test.js index e63db4a2d..56e80cb83 100644 --- a/ui/app/components/send/send-content/send-amount-row/tests/send-amount-row-component.test.js +++ b/ui/app/components/send/send-content/send-amount-row/tests/send-amount-row-component.test.js @@ -151,7 +151,6 @@ describe('SendAmountRow Component', function () { }) it('should render a UserPreferencedTokenInput as the second child of the SendRowWrapper', () => { - console.log('HI', wrapper.find(SendRowWrapper).childAt(1)) assert(wrapper.find(SendRowWrapper).childAt(1).is(UserPreferencedTokenInput)) }) diff --git a/ui/app/components/send/send.selectors.js b/ui/app/components/send/send.selectors.js index 22e379693..eb22a08b7 100644 --- a/ui/app/components/send/send.selectors.js +++ b/ui/app/components/send/send.selectors.js @@ -19,6 +19,7 @@ const selectors = { getCurrentNetwork, getCurrentViewContext, getForceGasMin, + getNativeCurrency, getGasLimit, getGasPrice, getGasPriceFromRecentBlocks, @@ -111,6 +112,10 @@ function getCurrentCurrency (state) { return state.metamask.currentCurrency } +function getNativeCurrency (state) { + return state.metamask.nativeCurrency +} + function getCurrentNetwork (state) { return state.metamask.network } diff --git a/ui/app/components/send/send.utils.js b/ui/app/components/send/send.utils.js index a18a9e4b3..eb1667c63 100644 --- a/ui/app/components/send/send.utils.js +++ b/ui/app/components/send/send.utils.js @@ -215,7 +215,9 @@ async function estimateGas ({ // if recipient has no code, gas is 21k max: if (!selectedToken && !data) { const code = Boolean(to) && await global.eth.getCode(to) - if (!code || code === '0x') { + // Geth will return '0x', and ganache-core v2.2.1 will return '0x0' + const codeIsEmpty = !code || code === '0x' || code === '0x0' + if (codeIsEmpty) { return SIMPLE_GAS_COST } } else if (selectedToken && !to) { diff --git a/ui/app/components/send/tests/send-selectors-test-data.js b/ui/app/components/send/tests/send-selectors-test-data.js index 8b939dadb..30a2666cf 100644 --- a/ui/app/components/send/tests/send-selectors-test-data.js +++ b/ui/app/components/send/tests/send-selectors-test-data.js @@ -26,6 +26,7 @@ module.exports = { 'currentCurrency': 'USD', 'conversionRate': 1200.88200327, 'conversionDate': 1489013762, + 'nativeCurrency': 'ETH', 'noActiveNotices': true, 'frequentRpcList': [], 'network': '3', diff --git a/ui/app/components/send/tests/send-selectors.test.js b/ui/app/components/send/tests/send-selectors.test.js index 1a47cd209..e7e901f0d 100644 --- a/ui/app/components/send/tests/send-selectors.test.js +++ b/ui/app/components/send/tests/send-selectors.test.js @@ -12,6 +12,7 @@ const { getCurrentCurrency, getCurrentNetwork, getCurrentViewContext, + getNativeCurrency, getForceGasMin, getGasLimit, getGasPrice, @@ -178,6 +179,15 @@ describe('send selectors', () => { }) }) + describe('getNativeCurrency()', () => { + it('should return the ticker symbol of the selected network', () => { + assert.equal( + getNativeCurrency(mockState), + 'ETH' + ) + }) + }) + describe('getCurrentNetwork()', () => { it('should return the id of the currently selected network', () => { assert.equal( diff --git a/ui/app/components/signature-request.js b/ui/app/components/signature-request.js index d76eb5ef8..85af3b00b 100644 --- a/ui/app/components/signature-request.js +++ b/ui/app/components/signature-request.js @@ -2,7 +2,7 @@ const Component = require('react').Component const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits -const Identicon = require('./identicon') +import Identicon from './identicon' const connect = require('react-redux').connect const ethUtil = require('ethereumjs-util') const classnames = require('classnames') diff --git a/ui/app/components/token-cell.js b/ui/app/components/token-cell.js index 477d97597..75ba347fa 100644 --- a/ui/app/components/token-cell.js +++ b/ui/app/components/token-cell.js @@ -2,7 +2,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect -const Identicon = require('./identicon') +import Identicon from './identicon' const prefixForNetwork = require('../../lib/etherscan-prefix-for-network') const selectors = require('../selectors') const actions = require('../actions') diff --git a/ui/app/components/token-input/tests/token-input.component.test.js b/ui/app/components/token-input/tests/token-input.component.test.js index 2131e7705..2dacb9bc4 100644 --- a/ui/app/components/token-input/tests/token-input.component.test.js +++ b/ui/app/components/token-input/tests/token-input.component.test.js @@ -122,7 +122,7 @@ describe('TokenInput Component', () => { assert.equal(wrapper.find('.unit-input__suffix').length, 1) assert.equal(wrapper.find('.unit-input__suffix').text(), 'ABC') assert.equal(wrapper.find('.unit-input__input').props().value, '1') - assert.equal(wrapper.find('.currency-display-component').text(), '2 ETH') + assert.equal(wrapper.find('.currency-display-component').text(), '2ETH') }) it('should render properly with a token value for fiat', () => { @@ -157,7 +157,7 @@ describe('TokenInput Component', () => { assert.equal(wrapper.find('.unit-input__suffix').length, 1) assert.equal(wrapper.find('.unit-input__suffix').text(), 'ABC') assert.equal(wrapper.find('.unit-input__input').props().value, '1') - assert.equal(wrapper.find('.currency-display-component').text(), '$462.12 USD') + assert.equal(wrapper.find('.currency-display-component').text(), '$462.12USD') }) }) @@ -201,14 +201,14 @@ describe('TokenInput Component', () => { const tokenInputInstance = wrapper.find(TokenInput).at(0).instance() assert.equal(tokenInputInstance.state.decimalValue, 0) assert.equal(tokenInputInstance.state.hexValue, undefined) - assert.equal(wrapper.find('.currency-display-component').text(), '0 ETH') + assert.equal(wrapper.find('.currency-display-component').text(), '0ETH') const input = wrapper.find('input') assert.equal(input.props().value, 0) input.simulate('change', { target: { value: 1 } }) assert.equal(handleChangeSpy.callCount, 1) assert.ok(handleChangeSpy.calledWith('2710')) - assert.equal(wrapper.find('.currency-display-component').text(), '2 ETH') + assert.equal(wrapper.find('.currency-display-component').text(), '2ETH') assert.equal(tokenInputInstance.state.decimalValue, 1) assert.equal(tokenInputInstance.state.hexValue, '2710') @@ -250,14 +250,14 @@ describe('TokenInput Component', () => { const tokenInputInstance = wrapper.find(TokenInput).at(0).instance() assert.equal(tokenInputInstance.state.decimalValue, 0) assert.equal(tokenInputInstance.state.hexValue, undefined) - assert.equal(wrapper.find('.currency-display-component').text(), '$0.00 USD') + assert.equal(wrapper.find('.currency-display-component').text(), '$0.00USD') const input = wrapper.find('input') assert.equal(input.props().value, 0) input.simulate('change', { target: { value: 1 } }) assert.equal(handleChangeSpy.callCount, 1) assert.ok(handleChangeSpy.calledWith('2710')) - assert.equal(wrapper.find('.currency-display-component').text(), '$462.12 USD') + assert.equal(wrapper.find('.currency-display-component').text(), '$462.12USD') assert.equal(tokenInputInstance.state.decimalValue, 1) assert.equal(tokenInputInstance.state.hexValue, '2710') diff --git a/ui/app/components/transaction-activity-log/tests/transaction-activity-log.container.test.js b/ui/app/components/transaction-activity-log/tests/transaction-activity-log.container.test.js index 85d56a6a2..a7c35f51e 100644 --- a/ui/app/components/transaction-activity-log/tests/transaction-activity-log.container.test.js +++ b/ui/app/components/transaction-activity-log/tests/transaction-activity-log.container.test.js @@ -18,10 +18,11 @@ describe('TransactionActivityLog container', () => { const mockState = { metamask: { conversionRate: 280.45, + nativeCurrency: 'ETH', }, } - assert.deepEqual(mapStateToProps(mockState), { conversionRate: 280.45 }) + assert.deepEqual(mapStateToProps(mockState), { conversionRate: 280.45, nativeCurrency: 'ETH' }) }) }) }) diff --git a/ui/app/components/transaction-activity-log/transaction-activity-log.component.js b/ui/app/components/transaction-activity-log/transaction-activity-log.component.js index c4cf57d14..58d932a0f 100644 --- a/ui/app/components/transaction-activity-log/transaction-activity-log.component.js +++ b/ui/app/components/transaction-activity-log/transaction-activity-log.component.js @@ -4,7 +4,6 @@ import classnames from 'classnames' import { getActivities } from './transaction-activity-log.util' import Card from '../card' import { getEthConversionFromWeiHex, getValueFromWeiHex } from '../../helpers/conversions.util' -import { ETH } from '../../constants/common' import { formatDate } from '../../util' export default class TransactionActivityLog extends PureComponent { @@ -16,6 +15,7 @@ export default class TransactionActivityLog extends PureComponent { transaction: PropTypes.object, className: PropTypes.string, conversionRate: PropTypes.number, + nativeCurrency: PropTypes.string, } state = { @@ -27,10 +27,14 @@ export default class TransactionActivityLog extends PureComponent { } componentDidUpdate (prevProps) { - const { transaction: { history: prevHistory = [] } = {} } = prevProps - const { transaction: { history = [] } = {} } = this.props + const { + transaction: { history: prevHistory = [], txReceipt: { status: prevStatus } = {} } = {}, + } = prevProps + const { + transaction: { history = [], txReceipt: { status } = {} } = {}, + } = this.props - if (prevHistory.length !== history.length) { + if (prevHistory.length !== history.length || prevStatus !== status) { this.setActivites() } } @@ -41,16 +45,17 @@ export default class TransactionActivityLog extends PureComponent { } renderActivity (activity, index) { - const { conversionRate } = this.props + const { conversionRate, nativeCurrency } = this.props const { eventKey, value, timestamp } = activity const ethValue = index === 0 ? `${getValueFromWeiHex({ value, - toCurrency: ETH, + fromCurrency: nativeCurrency, + toCurrency: nativeCurrency, conversionRate, numberOfDecimals: 6, - })} ${ETH}` - : getEthConversionFromWeiHex({ value, toCurrency: ETH, conversionRate }) + })} ${nativeCurrency}` + : getEthConversionFromWeiHex({ value, fromCurrency: nativeCurrency, conversionRate }) const formattedTimestamp = formatDate(timestamp) const activityText = this.context.t(eventKey, [ethValue, formattedTimestamp]) diff --git a/ui/app/components/transaction-activity-log/transaction-activity-log.container.js b/ui/app/components/transaction-activity-log/transaction-activity-log.container.js index 4c8b6d971..622f77df1 100644 --- a/ui/app/components/transaction-activity-log/transaction-activity-log.container.js +++ b/ui/app/components/transaction-activity-log/transaction-activity-log.container.js @@ -1,10 +1,11 @@ import { connect } from 'react-redux' import TransactionActivityLog from './transaction-activity-log.component' -import { conversionRateSelector } from '../../selectors' +import { conversionRateSelector, getNativeCurrency } from '../../selectors' const mapStateToProps = state => { return { conversionRate: conversionRateSelector(state), + nativeCurrency: getNativeCurrency(state), } } diff --git a/ui/app/components/transaction-activity-log/transaction-activity-log.util.js b/ui/app/components/transaction-activity-log/transaction-activity-log.util.js index 97aa9a8f1..16597ae1a 100644 --- a/ui/app/components/transaction-activity-log/transaction-activity-log.util.js +++ b/ui/app/components/transaction-activity-log/transaction-activity-log.util.js @@ -18,6 +18,7 @@ const TRANSACTION_SUBMITTED_EVENT = 'transactionSubmitted' const TRANSACTION_CONFIRMED_EVENT = 'transactionConfirmed' const TRANSACTION_DROPPED_EVENT = 'transactionDropped' const TRANSACTION_UPDATED_EVENT = 'transactionUpdated' +const TRANSACTION_ERRORED_EVENT = 'transactionErrored' const eventPathsHash = { [STATUS_PATH]: true, @@ -39,9 +40,9 @@ function eventCreator (eventKey, timestamp, value) { } export function getActivities (transaction) { - const { history = [] } = transaction + const { history = [], txReceipt: { status } = {} } = transaction - return history.reduce((acc, base) => { + const historyActivities = history.reduce((acc, base) => { // First history item should be transaction creation if (!Array.isArray(base) && base.status === UNAPPROVED_STATUS && base.txParams) { const { time, txParams: { value } = {} } = base @@ -83,4 +84,10 @@ export function getActivities (transaction) { return acc }, []) + + // If txReceipt.status is '0x0', that means that an on-chain error occured for the transaction, + // so we add an error entry to the Activity Log. + return status === '0x0' + ? historyActivities.concat(eventCreator(TRANSACTION_ERRORED_EVENT)) + : historyActivities } diff --git a/ui/app/components/transaction-breakdown/index.js b/ui/app/components/transaction-breakdown/index.js index c887f504f..4a5b52663 100644 --- a/ui/app/components/transaction-breakdown/index.js +++ b/ui/app/components/transaction-breakdown/index.js @@ -1 +1 @@ -export { default } from './transaction-breakdown.component' +export { default } from './transaction-breakdown.container' diff --git a/ui/app/components/transaction-breakdown/transaction-breakdown.component.js b/ui/app/components/transaction-breakdown/transaction-breakdown.component.js index 77bedcad7..3a7647873 100644 --- a/ui/app/components/transaction-breakdown/transaction-breakdown.component.js +++ b/ui/app/components/transaction-breakdown/transaction-breakdown.component.js @@ -6,7 +6,7 @@ import Card from '../card' import CurrencyDisplay from '../currency-display' import UserPreferencedCurrencyDisplay from '../user-preferenced-currency-display' import HexToDecimal from '../hex-to-decimal' -import { ETH, GWEI, PRIMARY, SECONDARY } from '../../constants/common' +import { GWEI, PRIMARY, SECONDARY } from '../../constants/common' import { getHexGasTotal } from '../../helpers/confirm-transaction/util' import { sumHexes } from '../../helpers/transactions.util' @@ -18,6 +18,7 @@ export default class TransactionBreakdown extends PureComponent { static propTypes = { transaction: PropTypes.object, className: PropTypes.string, + nativeCurrency: PropTypes.string.isRequired, } static defaultProps = { @@ -26,7 +27,7 @@ export default class TransactionBreakdown extends PureComponent { render () { const { t } = this.context - const { transaction, className } = this.props + const { transaction, className, nativeCurrency } = this.props const { txParams: { gas, gasPrice, value } = {}, txReceipt: { gasUsed } = {} } = transaction const gasLimit = typeof gasUsed === 'string' ? gasUsed : gas @@ -72,7 +73,7 @@ export default class TransactionBreakdown extends PureComponent { <TransactionBreakdownRow title={t('gasPrice')}> <CurrencyDisplay className="transaction-breakdown__value" - currency={ETH} + currency={nativeCurrency} denomination={GWEI} value={gasPrice} hideLabel diff --git a/ui/app/components/transaction-breakdown/transaction-breakdown.container.js b/ui/app/components/transaction-breakdown/transaction-breakdown.container.js new file mode 100644 index 000000000..ed2708e03 --- /dev/null +++ b/ui/app/components/transaction-breakdown/transaction-breakdown.container.js @@ -0,0 +1,11 @@ +import { connect } from 'react-redux' +import TransactionBreakdown from './transaction-breakdown.component' +import { getNativeCurrency } from '../../selectors' + +const mapStateToProps = (state) => { + return { + nativeCurrency: getNativeCurrency(state), + } +} + +export default connect(mapStateToProps)(TransactionBreakdown) diff --git a/ui/app/components/transaction-list-item/index.scss b/ui/app/components/transaction-list-item/index.scss index 9d694546b..ac0e7beeb 100644 --- a/ui/app/components/transaction-list-item/index.scss +++ b/ui/app/components/transaction-list-item/index.scss @@ -85,6 +85,7 @@ text-align: end; grid-area: primary-amount; align-self: end; + justify-self: end; @media screen and (max-width: $break-small) { padding-bottom: 2px; @@ -97,6 +98,7 @@ color: #5e6064; grid-area: secondary-amount; align-self: start; + justify-self: end; } } diff --git a/ui/app/components/transaction-list-item/transaction-list-item.component.js b/ui/app/components/transaction-list-item/transaction-list-item.component.js index 88573d2d5..696634fe0 100644 --- a/ui/app/components/transaction-list-item/transaction-list-item.component.js +++ b/ui/app/components/transaction-list-item/transaction-list-item.component.js @@ -10,7 +10,6 @@ import TransactionListItemDetails from '../transaction-list-item-details' import { CONFIRM_TRANSACTION_ROUTE } from '../../routes' import { UNAPPROVED_STATUS, TOKEN_METHOD_TRANSFER } from '../../constants/transactions' import { PRIMARY, SECONDARY } from '../../constants/common' -import { ENVIRONMENT_TYPE_FULLSCREEN } from '../../../../app/scripts/lib/enums' import { getStatusKey } from '../../helpers/transactions.util' export default class TransactionListItem extends PureComponent { @@ -24,7 +23,6 @@ export default class TransactionListItem extends PureComponent { showCancelModal: PropTypes.func, showCancel: PropTypes.bool, showRetry: PropTypes.bool, - showTransactionDetailsModal: PropTypes.func, token: PropTypes.object, tokenData: PropTypes.object, transaction: PropTypes.object, @@ -39,31 +37,16 @@ export default class TransactionListItem extends PureComponent { const { transaction, history, - showTransactionDetailsModal, - methodData, - showCancel, - showRetry, } = this.props const { id, status } = transaction const { showTransactionDetails } = this.state - const windowType = window.METAMASK_UI_TYPE if (status === UNAPPROVED_STATUS) { history.push(`${CONFIRM_TRANSACTION_ROUTE}/${id}`) return } - if (windowType === ENVIRONMENT_TYPE_FULLSCREEN) { - this.setState({ showTransactionDetails: !showTransactionDetails }) - } else { - showTransactionDetailsModal({ - transaction, - onRetry: this.handleRetry, - showRetry: showRetry && methodData.done, - onCancel: this.handleCancel, - showCancel, - }) - } + this.setState({ showTransactionDetails: !showTransactionDetails }) } handleCancel = () => { diff --git a/ui/app/components/transaction-list-item/transaction-list-item.container.js b/ui/app/components/transaction-list-item/transaction-list-item.container.js index 72f5f5d61..62ed7a73f 100644 --- a/ui/app/components/transaction-list-item/transaction-list-item.container.js +++ b/ui/app/components/transaction-list-item/transaction-list-item.container.js @@ -28,16 +28,6 @@ const mapDispatchToProps = dispatch => { showCancelModal: (transactionId, originalGasPrice) => { return dispatch(showModal({ name: 'CANCEL_TRANSACTION', transactionId, originalGasPrice })) }, - showTransactionDetailsModal: ({ transaction, onRetry, showRetry, onCancel, showCancel }) => { - return dispatch(showModal({ - name: 'TRANSACTION_DETAILS', - transaction, - onRetry, - showRetry, - onCancel, - showCancel, - })) - }, } } diff --git a/ui/app/components/transaction-list/index.scss b/ui/app/components/transaction-list/index.scss index 777f701f9..ba7ffd87b 100644 --- a/ui/app/components/transaction-list/index.scss +++ b/ui/app/components/transaction-list/index.scss @@ -2,9 +2,7 @@ display: flex; flex-direction: column; flex: 1; - overflow-y: hidden; margin-top: 8px; - border-top: 1px solid $geyser; &__completed-transactions { display: flex; @@ -26,7 +24,6 @@ &__transactions { flex: 1; - overflow-y: auto; } &__pending-transactions { diff --git a/ui/app/components/transaction-view-balance/index.scss b/ui/app/components/transaction-view-balance/index.scss index 12045ab6d..659f896ff 100644 --- a/ui/app/components/transaction-view-balance/index.scss +++ b/ui/app/components/transaction-view-balance/index.scss @@ -4,11 +4,13 @@ align-items: center; flex: 1; height: 54px; + min-width: 0; &__balance { - margin-left: 12px; + margin: 0 12px; display: flex; flex-direction: column; + min-width: 0; @media screen and (max-width: $break-small) { align-items: center; @@ -21,7 +23,8 @@ font-size: 1.5rem; @media screen and (max-width: $break-small) { - margin-bottom: 12px; + margin: 12px 0; + margin-left: 0; font-size: 1.75rem; } } @@ -30,7 +33,6 @@ font-size: 1.5rem; @media screen and (max-width: $break-small) { - margin-bottom: 12px; font-size: 1.75rem; } } @@ -45,6 +47,7 @@ display: flex; flex-direction: row; align-items: center; + min-width: 0; @media screen and (max-width: $break-small) { flex-direction: column; diff --git a/ui/app/components/transaction-view-balance/transaction-view-balance.container.js b/ui/app/components/transaction-view-balance/transaction-view-balance.container.js index 30c5cab16..cb8078ec1 100644 --- a/ui/app/components/transaction-view-balance/transaction-view-balance.container.js +++ b/ui/app/components/transaction-view-balance/transaction-view-balance.container.js @@ -2,7 +2,7 @@ import { connect } from 'react-redux' import { withRouter } from 'react-router-dom' import { compose } from 'recompose' import TransactionViewBalance from './transaction-view-balance.component' -import { getSelectedToken, getSelectedAddress, getSelectedTokenAssetImage } from '../../selectors' +import { getSelectedToken, getSelectedAddress, getNativeCurrency, getSelectedTokenAssetImage } from '../../selectors' import { showModal } from '../../actions' const mapStateToProps = state => { @@ -15,6 +15,7 @@ const mapStateToProps = state => { selectedToken: getSelectedToken(state), network, balance, + nativeCurrency: getNativeCurrency(state), assetImage: getSelectedTokenAssetImage(state), } } diff --git a/ui/app/components/transaction-view/index.scss b/ui/app/components/transaction-view/index.scss index af9771ce0..13187f0e5 100644 --- a/ui/app/components/transaction-view/index.scss +++ b/ui/app/components/transaction-view/index.scss @@ -4,6 +4,7 @@ min-width: 0; display: flex; flex-direction: column; + overflow-y: auto; &__balance-wrapper { @media screen and (max-width: $break-small) { diff --git a/ui/app/components/user-preferenced-currency-display/tests/user-preferenced-currency-display.container.test.js b/ui/app/components/user-preferenced-currency-display/tests/user-preferenced-currency-display.container.test.js index 41ad3b73e..ba1c23d83 100644 --- a/ui/app/components/user-preferenced-currency-display/tests/user-preferenced-currency-display.container.test.js +++ b/ui/app/components/user-preferenced-currency-display/tests/user-preferenced-currency-display.container.test.js @@ -18,14 +18,16 @@ describe('UserPreferencedCurrencyDisplay container', () => { it('should return the correct props', () => { const mockState = { metamask: { + nativeCurrency: 'ETH', preferences: { - useETHAsPrimaryCurrency: true, + useNativeCurrencyAsPrimaryCurrency: true, }, }, } assert.deepEqual(mapStateToProps(mockState), { - useETHAsPrimaryCurrency: true, + nativeCurrency: 'ETH', + useNativeCurrencyAsPrimaryCurrency: true, }) }) }) @@ -37,33 +39,38 @@ describe('UserPreferencedCurrencyDisplay container', () => { const tests = [ { stateProps: { - useETHAsPrimaryCurrency: true, + useNativeCurrencyAsPrimaryCurrency: true, + nativeCurrency: 'ETH', }, ownProps: { type: 'PRIMARY', }, result: { currency: 'ETH', + nativeCurrency: 'ETH', numberOfDecimals: 6, prefix: undefined, }, }, { stateProps: { - useETHAsPrimaryCurrency: false, + useNativeCurrencyAsPrimaryCurrency: false, + nativeCurrency: 'ETH', }, ownProps: { type: 'PRIMARY', }, result: { currency: undefined, + nativeCurrency: 'ETH', numberOfDecimals: 2, prefix: undefined, }, }, { stateProps: { - useETHAsPrimaryCurrency: true, + useNativeCurrencyAsPrimaryCurrency: true, + nativeCurrency: 'ETH', }, ownProps: { type: 'SECONDARY', @@ -71,6 +78,7 @@ describe('UserPreferencedCurrencyDisplay container', () => { fiatPrefix: '-', }, result: { + nativeCurrency: 'ETH', currency: undefined, numberOfDecimals: 4, prefix: '-', @@ -78,7 +86,8 @@ describe('UserPreferencedCurrencyDisplay container', () => { }, { stateProps: { - useETHAsPrimaryCurrency: false, + useNativeCurrencyAsPrimaryCurrency: false, + nativeCurrency: 'ETH', }, ownProps: { type: 'SECONDARY', @@ -89,6 +98,7 @@ describe('UserPreferencedCurrencyDisplay container', () => { }, result: { currency: 'ETH', + nativeCurrency: 'ETH', numberOfDecimals: 3, prefix: 'b', }, diff --git a/ui/app/components/user-preferenced-currency-display/user-preferenced-currency-display.component.js b/ui/app/components/user-preferenced-currency-display/user-preferenced-currency-display.component.js index 4d948ca6a..f2a834ea7 100644 --- a/ui/app/components/user-preferenced-currency-display/user-preferenced-currency-display.component.js +++ b/ui/app/components/user-preferenced-currency-display/user-preferenced-currency-display.component.js @@ -21,6 +21,7 @@ export default class UserPreferencedCurrencyDisplay extends PureComponent { fiatPrefix: PropTypes.string, // From container currency: PropTypes.string, + nativeCurrency: PropTypes.string, } renderEthLogo () { diff --git a/ui/app/components/user-preferenced-currency-display/user-preferenced-currency-display.container.js b/ui/app/components/user-preferenced-currency-display/user-preferenced-currency-display.container.js index 23240c649..7999301ad 100644 --- a/ui/app/components/user-preferenced-currency-display/user-preferenced-currency-display.container.js +++ b/ui/app/components/user-preferenced-currency-display/user-preferenced-currency-display.container.js @@ -4,15 +4,16 @@ import { preferencesSelector } from '../../selectors' import { ETH, PRIMARY, SECONDARY } from '../../constants/common' const mapStateToProps = (state, ownProps) => { - const { useETHAsPrimaryCurrency } = preferencesSelector(state) + const { useNativeCurrencyAsPrimaryCurrency } = preferencesSelector(state) return { - useETHAsPrimaryCurrency, + useNativeCurrencyAsPrimaryCurrency, + nativeCurrency: state.metamask.nativeCurrency, } } const mergeProps = (stateProps, dispatchProps, ownProps) => { - const { useETHAsPrimaryCurrency, ...restStateProps } = stateProps + const { useNativeCurrencyAsPrimaryCurrency, nativeCurrency, ...restStateProps } = stateProps const { type, numberOfDecimals: propsNumberOfDecimals, @@ -26,14 +27,14 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => { let currency, numberOfDecimals, prefix - if (type === PRIMARY && useETHAsPrimaryCurrency || - type === SECONDARY && !useETHAsPrimaryCurrency) { + if (type === PRIMARY && useNativeCurrencyAsPrimaryCurrency || + type === SECONDARY && !useNativeCurrencyAsPrimaryCurrency) { // Display ETH - currency = ETH + currency = nativeCurrency || ETH numberOfDecimals = propsNumberOfDecimals || ethNumberOfDecimals || 6 prefix = propsPrefix || ethPrefix - } else if (type === SECONDARY && useETHAsPrimaryCurrency || - type === PRIMARY && !useETHAsPrimaryCurrency) { + } else if (type === SECONDARY && useNativeCurrencyAsPrimaryCurrency || + type === PRIMARY && !useNativeCurrencyAsPrimaryCurrency) { // Display Fiat numberOfDecimals = propsNumberOfDecimals || fiatNumberOfDecimals || 2 prefix = propsPrefix || fiatPrefix @@ -43,6 +44,7 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => { ...restStateProps, ...dispatchProps, ...restOwnProps, + nativeCurrency, currency, numberOfDecimals, prefix, diff --git a/ui/app/components/user-preferenced-currency-input/tests/user-preferenced-currency-input.component.test.js b/ui/app/components/user-preferenced-currency-input/tests/user-preferenced-currency-input.component.test.js index 0af80a03d..710b5d519 100644 --- a/ui/app/components/user-preferenced-currency-input/tests/user-preferenced-currency-input.component.test.js +++ b/ui/app/components/user-preferenced-currency-input/tests/user-preferenced-currency-input.component.test.js @@ -15,17 +15,17 @@ describe('UserPreferencedCurrencyInput Component', () => { assert.equal(wrapper.find(CurrencyInput).length, 1) }) - it('should render useFiat for CurrencyInput based on preferences.useETHAsPrimaryCurrency', () => { + it('should render useFiat for CurrencyInput based on preferences.useNativeCurrencyAsPrimaryCurrency', () => { const wrapper = shallow( <UserPreferencedCurrencyInput - useETHAsPrimaryCurrency + useNativeCurrencyAsPrimaryCurrency /> ) assert.ok(wrapper) assert.equal(wrapper.find(CurrencyInput).length, 1) assert.equal(wrapper.find(CurrencyInput).props().useFiat, false) - wrapper.setProps({ useETHAsPrimaryCurrency: false }) + wrapper.setProps({ useNativeCurrencyAsPrimaryCurrency: false }) assert.equal(wrapper.find(CurrencyInput).props().useFiat, true) }) }) diff --git a/ui/app/components/user-preferenced-currency-input/tests/user-preferenced-currency-input.container.test.js b/ui/app/components/user-preferenced-currency-input/tests/user-preferenced-currency-input.container.test.js index d860c38da..959726443 100644 --- a/ui/app/components/user-preferenced-currency-input/tests/user-preferenced-currency-input.container.test.js +++ b/ui/app/components/user-preferenced-currency-input/tests/user-preferenced-currency-input.container.test.js @@ -18,13 +18,13 @@ describe('UserPreferencedCurrencyInput container', () => { const mockState = { metamask: { preferences: { - useETHAsPrimaryCurrency: true, + useNativeCurrencyAsPrimaryCurrency: true, }, }, } assert.deepEqual(mapStateToProps(mockState), { - useETHAsPrimaryCurrency: true, + useNativeCurrencyAsPrimaryCurrency: true, }) }) }) diff --git a/ui/app/components/user-preferenced-currency-input/user-preferenced-currency-input.component.js b/ui/app/components/user-preferenced-currency-input/user-preferenced-currency-input.component.js index 6e0e00a1d..463e66b80 100644 --- a/ui/app/components/user-preferenced-currency-input/user-preferenced-currency-input.component.js +++ b/ui/app/components/user-preferenced-currency-input/user-preferenced-currency-input.component.js @@ -4,16 +4,16 @@ import CurrencyInput from '../currency-input' export default class UserPreferencedCurrencyInput extends PureComponent { static propTypes = { - useETHAsPrimaryCurrency: PropTypes.bool, + useNativeCurrencyAsPrimaryCurrency: PropTypes.bool, } render () { - const { useETHAsPrimaryCurrency, ...restProps } = this.props + const { useNativeCurrencyAsPrimaryCurrency, ...restProps } = this.props return ( <CurrencyInput {...restProps} - useFiat={!useETHAsPrimaryCurrency} + useFiat={!useNativeCurrencyAsPrimaryCurrency} /> ) } diff --git a/ui/app/components/user-preferenced-currency-input/user-preferenced-currency-input.container.js b/ui/app/components/user-preferenced-currency-input/user-preferenced-currency-input.container.js index 397cdc7cc..0b88eb5a7 100644 --- a/ui/app/components/user-preferenced-currency-input/user-preferenced-currency-input.container.js +++ b/ui/app/components/user-preferenced-currency-input/user-preferenced-currency-input.container.js @@ -3,10 +3,10 @@ import UserPreferencedCurrencyInput from './user-preferenced-currency-input.comp import { preferencesSelector } from '../../selectors' const mapStateToProps = state => { - const { useETHAsPrimaryCurrency } = preferencesSelector(state) + const { useNativeCurrencyAsPrimaryCurrency } = preferencesSelector(state) return { - useETHAsPrimaryCurrency, + useNativeCurrencyAsPrimaryCurrency, } } diff --git a/ui/app/components/user-preferenced-token-input/tests/user-preferenced-token-input.component.test.js b/ui/app/components/user-preferenced-token-input/tests/user-preferenced-token-input.component.test.js index 910c7089f..d85bddeeb 100644 --- a/ui/app/components/user-preferenced-token-input/tests/user-preferenced-token-input.component.test.js +++ b/ui/app/components/user-preferenced-token-input/tests/user-preferenced-token-input.component.test.js @@ -15,17 +15,17 @@ describe('UserPreferencedCurrencyInput Component', () => { assert.equal(wrapper.find(TokenInput).length, 1) }) - it('should render showFiat for TokenInput based on preferences.useETHAsPrimaryCurrency', () => { + it('should render showFiat for TokenInput based on preferences.useNativeCurrencyAsPrimaryCurrency', () => { const wrapper = shallow( <UserPreferencedTokenInput - useETHAsPrimaryCurrency + useNativeCurrencyAsPrimaryCurrency /> ) assert.ok(wrapper) assert.equal(wrapper.find(TokenInput).length, 1) assert.equal(wrapper.find(TokenInput).props().showFiat, false) - wrapper.setProps({ useETHAsPrimaryCurrency: false }) + wrapper.setProps({ useNativeCurrencyAsPrimaryCurrency: false }) assert.equal(wrapper.find(TokenInput).props().showFiat, true) }) }) diff --git a/ui/app/components/user-preferenced-token-input/tests/user-preferenced-token-input.container.test.js b/ui/app/components/user-preferenced-token-input/tests/user-preferenced-token-input.container.test.js index e3509149a..2f89fba90 100644 --- a/ui/app/components/user-preferenced-token-input/tests/user-preferenced-token-input.container.test.js +++ b/ui/app/components/user-preferenced-token-input/tests/user-preferenced-token-input.container.test.js @@ -18,13 +18,13 @@ describe('UserPreferencedTokenInput container', () => { const mockState = { metamask: { preferences: { - useETHAsPrimaryCurrency: true, + useNativeCurrencyAsPrimaryCurrency: true, }, }, } assert.deepEqual(mapStateToProps(mockState), { - useETHAsPrimaryCurrency: true, + useNativeCurrencyAsPrimaryCurrency: true, }) }) }) diff --git a/ui/app/components/user-preferenced-token-input/user-preferenced-token-input.component.js b/ui/app/components/user-preferenced-token-input/user-preferenced-token-input.component.js index f2b537f11..8f14231ac 100644 --- a/ui/app/components/user-preferenced-token-input/user-preferenced-token-input.component.js +++ b/ui/app/components/user-preferenced-token-input/user-preferenced-token-input.component.js @@ -4,16 +4,16 @@ import TokenInput from '../token-input' export default class UserPreferencedTokenInput extends PureComponent { static propTypes = { - useETHAsPrimaryCurrency: PropTypes.bool, + useNativeCurrencyAsPrimaryCurrency: PropTypes.bool, } render () { - const { useETHAsPrimaryCurrency, ...restProps } = this.props + const { useNativeCurrencyAsPrimaryCurrency, ...restProps } = this.props return ( <TokenInput {...restProps} - showFiat={!useETHAsPrimaryCurrency} + showFiat={!useNativeCurrencyAsPrimaryCurrency} /> ) } diff --git a/ui/app/components/user-preferenced-token-input/user-preferenced-token-input.container.js b/ui/app/components/user-preferenced-token-input/user-preferenced-token-input.container.js index 416d069dd..3305d4e29 100644 --- a/ui/app/components/user-preferenced-token-input/user-preferenced-token-input.container.js +++ b/ui/app/components/user-preferenced-token-input/user-preferenced-token-input.container.js @@ -3,10 +3,10 @@ import UserPreferencedTokenInput from './user-preferenced-token-input.component' import { preferencesSelector } from '../../selectors' const mapStateToProps = state => { - const { useETHAsPrimaryCurrency } = preferencesSelector(state) + const { useNativeCurrencyAsPrimaryCurrency } = preferencesSelector(state) return { - useETHAsPrimaryCurrency, + useNativeCurrencyAsPrimaryCurrency, } } diff --git a/ui/app/components/wallet-view.js b/ui/app/components/wallet-view.js index 8a7cb0f8d..e050e0ee6 100644 --- a/ui/app/components/wallet-view.js +++ b/ui/app/components/wallet-view.js @@ -7,7 +7,7 @@ const { compose } = require('recompose') const inherits = require('util').inherits const classnames = require('classnames') const { checksumAddress } = require('../util') -const Identicon = require('./identicon') +import Identicon from './identicon' // const AccountDropdowns = require('./dropdowns/index.js').AccountDropdowns const Tooltip = require('./tooltip-v2.js').default const copyToClipboard = require('copy-to-clipboard') @@ -127,7 +127,6 @@ WalletView.prototype.render = function () { identities, } = this.props // temporary logs + fake extra wallets - // console.log('walletview, selectedAccount:', selectedAccount) const checksummedAddress = checksumAddress(selectedAddress) diff --git a/ui/app/constants/error-keys.js b/ui/app/constants/error-keys.js index f70ed3b19..704064c96 100644 --- a/ui/app/constants/error-keys.js +++ b/ui/app/constants/error-keys.js @@ -1,3 +1,4 @@ export const INSUFFICIENT_FUNDS_ERROR_KEY = 'insufficientFunds' export const GAS_LIMIT_TOO_LOW_ERROR_KEY = 'gasLimitTooLow' export const TRANSACTION_ERROR_KEY = 'transactionError' +export const TRANSACTION_NO_CONTRACT_ERROR_KEY = 'transactionErrorNoContract' diff --git a/ui/app/css/itcss/components/buttons.scss b/ui/app/css/itcss/components/buttons.scss index 655188a3e..5826a8b49 100644 --- a/ui/app/css/itcss/components/buttons.scss +++ b/ui/app/css/itcss/components/buttons.scss @@ -3,7 +3,7 @@ */ .button { - height: 44px; + min-height: 44px; background: $white; display: flex; justify-content: center; @@ -82,12 +82,13 @@ box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.08); padding: 6px; height: initial; + min-height: initial; width: initial; min-width: initial; } .btn--large { - height: 54px; + min-height: 54px; } .btn-green { diff --git a/ui/app/css/itcss/components/pages/index.scss b/ui/app/css/itcss/components/pages/index.scss index 709f8baf6..45e47f447 100644 --- a/ui/app/css/itcss/components/pages/index.scss +++ b/ui/app/css/itcss/components/pages/index.scss @@ -1 +1,3 @@ @import './reveal-seed.scss'; + +@import './provider-approval.scss'; diff --git a/ui/app/css/itcss/components/pages/provider-approval.scss b/ui/app/css/itcss/components/pages/provider-approval.scss new file mode 100644 index 000000000..f172165ab --- /dev/null +++ b/ui/app/css/itcss/components/pages/provider-approval.scss @@ -0,0 +1,11 @@ +.provider_approval_content { + height: auto; + overflow: auto; + padding: 16px; +} + +.provider_approval_origin { + font-weight: 999; + margin-top: 16px; + word-wrap: break-word; +} diff --git a/ui/app/css/itcss/components/request-signature.scss b/ui/app/css/itcss/components/request-signature.scss index 445b9ebf5..6c950d846 100644 --- a/ui/app/css/itcss/components/request-signature.scss +++ b/ui/app/css/itcss/components/request-signature.scss @@ -19,7 +19,7 @@ } @media screen and (min-width: $break-large) { - max-height: 620px; + height: 620px; } } diff --git a/ui/app/css/itcss/components/wallet-balance.scss b/ui/app/css/itcss/components/wallet-balance.scss index 293771550..3c3349ae0 100644 --- a/ui/app/css/itcss/components/wallet-balance.scss +++ b/ui/app/css/itcss/components/wallet-balance.scss @@ -29,7 +29,7 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and ( align-items: center; margin: 20px 24px; flex-direction: row; - flex-grow: 3; + min-width: 0; @media #{$wallet-balance-breakpoint-range} { margin: 10% 4%; @@ -38,8 +38,7 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and ( .balance-display { margin-left: 15px; - justify-content: flex-start; - align-items: flex-start; + min-width: 0; .token-amount { font-size: 1.5rem; diff --git a/ui/app/ducks/confirm-transaction.duck.js b/ui/app/ducks/confirm-transaction.duck.js index 2ceafbe08..275eb1551 100644 --- a/ui/app/ducks/confirm-transaction.duck.js +++ b/ui/app/ducks/confirm-transaction.duck.js @@ -2,6 +2,7 @@ import { conversionRateSelector, currentCurrencySelector, unconfirmedTransactionsHashSelector, + getNativeCurrency, } from '../selectors/confirm-transaction' import { @@ -292,16 +293,17 @@ export function updateTxDataAndCalculate (txData) { const state = getState() const currentCurrency = currentCurrencySelector(state) const conversionRate = conversionRateSelector(state) + const nativeCurrency = getNativeCurrency(state) dispatch(updateTxData(txData)) const { txParams: { value = '0x0', gas: gasLimit = '0x0', gasPrice = '0x0' } = {} } = txData const fiatTransactionAmount = getValueFromWeiHex({ - value, toCurrency: currentCurrency, conversionRate, numberOfDecimals: 2, + value, fromCurrency: nativeCurrency, toCurrency: currentCurrency, conversionRate, numberOfDecimals: 2, }) const ethTransactionAmount = getValueFromWeiHex({ - value, toCurrency: 'ETH', conversionRate, numberOfDecimals: 6, + value, fromCurrency: nativeCurrency, toCurrency: nativeCurrency, conversionRate, numberOfDecimals: 6, }) dispatch(updateTransactionAmounts({ @@ -314,13 +316,15 @@ export function updateTxDataAndCalculate (txData) { const fiatTransactionFee = getTransactionFee({ value: hexTransactionFee, + fromCurrency: nativeCurrency, toCurrency: currentCurrency, numberOfDecimals: 2, conversionRate, }) const ethTransactionFee = getTransactionFee({ value: hexTransactionFee, - toCurrency: 'ETH', + fromCurrency: nativeCurrency, + toCurrency: nativeCurrency, numberOfDecimals: 6, conversionRate, }) @@ -329,7 +333,6 @@ export function updateTxDataAndCalculate (txData) { const fiatTransactionTotal = addFiat(fiatTransactionFee, fiatTransactionAmount) const ethTransactionTotal = addEth(ethTransactionFee, ethTransactionAmount) - console.log('HIHIH', value, hexTransactionFee) const hexTransactionTotal = sumHexes(value, hexTransactionFee) dispatch(updateTransactionTotals({ diff --git a/ui/app/helpers/confirm-transaction/util.js b/ui/app/helpers/confirm-transaction/util.js index bcac22500..eb334a4b8 100644 --- a/ui/app/helpers/confirm-transaction/util.js +++ b/ui/app/helpers/confirm-transaction/util.js @@ -55,6 +55,7 @@ export function addFiat (...args) { export function getValueFromWeiHex ({ value, + fromCurrency = 'ETH', toCurrency, conversionRate, numberOfDecimals, @@ -63,7 +64,7 @@ export function getValueFromWeiHex ({ return conversionUtil(value, { fromNumericBase: 'hex', toNumericBase: 'dec', - fromCurrency: 'ETH', + fromCurrency, toCurrency, numberOfDecimals, fromDenomination: 'WEI', @@ -74,6 +75,7 @@ export function getValueFromWeiHex ({ export function getTransactionFee ({ value, + fromCurrency = 'ETH', toCurrency, conversionRate, numberOfDecimals, @@ -82,7 +84,7 @@ export function getTransactionFee ({ fromNumericBase: 'BN', toNumericBase: 'dec', fromDenomination: 'WEI', - fromCurrency: 'ETH', + fromCurrency, toCurrency, numberOfDecimals, conversionRate, @@ -99,6 +101,7 @@ export function formatCurrency (value, currencyCode) { export function convertTokenToFiat ({ value, + fromCurrency = 'ETH', toCurrency, conversionRate, contractExchangeRate, @@ -108,6 +111,7 @@ export function convertTokenToFiat ({ return conversionUtil(value, { fromNumericBase: 'dec', toNumericBase: 'dec', + fromCurrency, toCurrency, numberOfDecimals: 2, conversionRate: totalExchangeRate, diff --git a/ui/app/helpers/conversions.util.js b/ui/app/helpers/conversions.util.js index 777537e1e..cb5e1b90b 100644 --- a/ui/app/helpers/conversions.util.js +++ b/ui/app/helpers/conversions.util.js @@ -20,8 +20,8 @@ export function decimalToHex (decimal) { }) } -export function getEthConversionFromWeiHex ({ value, conversionRate, numberOfDecimals = 6 }) { - const denominations = [ETH, GWEI, WEI] +export function getEthConversionFromWeiHex ({ value, fromCurrency = ETH, conversionRate, numberOfDecimals = 6 }) { + const denominations = [fromCurrency, GWEI, WEI] let nonZeroDenomination @@ -29,7 +29,8 @@ export function getEthConversionFromWeiHex ({ value, conversionRate, numberOfDec const convertedValue = getValueFromWeiHex({ value, conversionRate, - toCurrency: ETH, + fromCurrency, + toCurrency: fromCurrency, numberOfDecimals, toDenomination: denominations[i], }) @@ -45,6 +46,7 @@ export function getEthConversionFromWeiHex ({ value, conversionRate, numberOfDec export function getValueFromWeiHex ({ value, + fromCurrency = ETH, toCurrency, conversionRate, numberOfDecimals, @@ -53,7 +55,7 @@ export function getValueFromWeiHex ({ return conversionUtil(value, { fromNumericBase: 'hex', toNumericBase: 'dec', - fromCurrency: ETH, + fromCurrency, toCurrency, numberOfDecimals, fromDenomination: WEI, diff --git a/ui/app/helpers/transactions.util.js b/ui/app/helpers/transactions.util.js index e50196196..2f4b1d095 100644 --- a/ui/app/helpers/transactions.util.js +++ b/ui/app/helpers/transactions.util.js @@ -27,10 +27,21 @@ export function getTokenData (data = '') { const registry = new MethodRegistry({ provider: global.ethereumProvider }) +/** + * Attempts to return the method data from the MethodRegistry library, if the method exists in the + * registry. Otherwise, returns an empty object. + * @param {string} data - The hex data (@code txParams.data) of a transaction + * @returns {Object} + */ export async function getMethodData (data = '') { const prefixedData = ethUtil.addHexPrefix(data) const fourBytePrefix = prefixedData.slice(0, 10) const sig = await registry.lookup(fourBytePrefix) + + if (!sig) { + return {} + } + const parsedResult = registry.parse(sig) return { @@ -114,7 +125,9 @@ export function getLatestSubmittedTxWithNonce (transactions = [], nonce = '0x0') export async function isSmartContractAddress (address) { const code = await global.eth.getCode(address) - return code && code !== '0x' + // Geth will return '0x', and ganache-core v2.2.1 will return '0x0' + const codeIsEmpty = !code || code === '0x' || code === '0x0' + return !codeIsEmpty } export function sumHexes (...args) { diff --git a/ui/app/reducers.js b/ui/app/reducers.js index 80e76d570..e1a982f93 100644 --- a/ui/app/reducers.js +++ b/ui/app/reducers.js @@ -1,3 +1,4 @@ +const clone = require('clone') const extend = require('xtend') const copyToClipboard = require('copy-to-clipboard') @@ -52,19 +53,24 @@ function rootReducer (state, action) { return state } +window.getCleanAppState = function () { + const state = clone(window.METAMASK_CACHED_LOG_STATE) + // append additional information + state.version = global.platform.getVersion() + state.browser = window.navigator.userAgent + // ensure seedWords are not included + if (state.metamask) delete state.metamask.seedWords + if (state.appState.currentView) delete state.appState.currentView.seedWords + return state +} + window.logStateString = function (cb) { - const state = window.METAMASK_CACHED_LOG_STATE - const version = global.platform.getVersion() - const browser = window.navigator.userAgent - return global.platform.getPlatformInfo((err, platform) => { - if (err) { - return cb(err) - } - state.version = version + const state = window.getCleanAppState() + global.platform.getPlatformInfo((err, platform) => { + if (err) return cb(err) state.platform = platform - state.browser = browser const stateString = JSON.stringify(state, removeSeedWords, 2) - return cb(null, stateString) + cb(null, stateString) }) } diff --git a/ui/app/reducers/metamask.js b/ui/app/reducers/metamask.js index 37d8a9187..22fa53098 100644 --- a/ui/app/reducers/metamask.js +++ b/ui/app/reducers/metamask.js @@ -52,7 +52,7 @@ function reduceMetamask (state, action) { welcomeScreenSeen: false, currentLocale: '', preferences: { - useETHAsPrimaryCurrency: true, + useNativeCurrencyAsPrimaryCurrency: true, }, }, state.metamask) diff --git a/ui/app/selectors.js b/ui/app/selectors.js index 9f11551be..7209f19d1 100644 --- a/ui/app/selectors.js +++ b/ui/app/selectors.js @@ -26,6 +26,7 @@ const selectors = { getAddressBook, getSendFrom, getCurrentCurrency, + getNativeCurrency, getSendAmount, getSelectedTokenToFiatRate, getSelectedTokenContract, @@ -143,6 +144,10 @@ function getCurrentCurrency (state) { return state.metamask.currentCurrency } +function getNativeCurrency (state) { + return state.metamask.nativeCurrency +} + function getSelectedTokenToFiatRate (state) { const selectedTokenExchangeRate = getSelectedTokenExchangeRate(state) const conversionRate = conversionRateSelector(state) diff --git a/ui/app/selectors/confirm-transaction.js b/ui/app/selectors/confirm-transaction.js index 86b10bac3..90924c036 100644 --- a/ui/app/selectors/confirm-transaction.js +++ b/ui/app/selectors/confirm-transaction.js @@ -93,6 +93,7 @@ export const unconfirmedTransactionsCountSelector = createSelector( export const currentCurrencySelector = state => state.metamask.currentCurrency export const conversionRateSelector = state => state.metamask.conversionRate +export const getNativeCurrency = state => state.metamask.nativeCurrency const txDataSelector = state => state.confirmTransaction.txData const tokenDataSelector = state => state.confirmTransaction.tokenData diff --git a/ui/app/util.js b/ui/app/util.js index 37c0fb698..b19a028cc 100644 --- a/ui/app/util.js +++ b/ui/app/util.js @@ -128,7 +128,7 @@ function parseBalance (balance) { // Takes wei hex, returns an object with three properties. // Its "formatted" property is what we generally use to render values. -function formatBalance (balance, decimalsToKeep, needsParse = true) { +function formatBalance (balance, decimalsToKeep, needsParse = true, ticker = 'ETH') { var parsed = needsParse ? parseBalance(balance) : balance.split('.') var beforeDecimal = parsed[0] var afterDecimal = parsed[1] @@ -138,14 +138,14 @@ function formatBalance (balance, decimalsToKeep, needsParse = true) { if (afterDecimal !== '0') { var sigFigs = afterDecimal.match(/^0*(.{2})/) // default: grabs 2 most significant digits if (sigFigs) { afterDecimal = sigFigs[0] } - formatted = '0.' + afterDecimal + ' ETH' + formatted = '0.' + afterDecimal + ` ${ticker}` } } else { - formatted = beforeDecimal + '.' + afterDecimal.slice(0, 3) + ' ETH' + formatted = beforeDecimal + '.' + afterDecimal.slice(0, 3) + ` ${ticker}` } } else { afterDecimal += Array(decimalsToKeep).join('0') - formatted = beforeDecimal + '.' + afterDecimal.slice(0, decimalsToKeep) + ' ETH' + formatted = beforeDecimal + '.' + afterDecimal.slice(0, decimalsToKeep) + ` ${ticker}` } return formatted } |