aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE/bug-report.md34
-rw-r--r--.github/ISSUE_TEMPLATE/feature-request.md14
-rw-r--r--.github/ISSUE_TEMPLATE/support-request-or-question.md9
-rw-r--r--.npmrc1
-rw-r--r--CHANGELOG.md29
-rw-r--r--app/_locales/de/messages.json4
-rw-r--r--app/_locales/en/messages.json38
-rw-r--r--app/_locales/es/messages.json4
-rw-r--r--app/_locales/fr/messages.json4
-rw-r--r--app/_locales/it/messages.json6
-rw-r--r--app/_locales/nl/messages.json6
-rw-r--r--app/_locales/ph/messages.json2
-rw-r--r--app/_locales/pt/messages.json2
-rw-r--r--app/_locales/ru/messages.json2
-rw-r--r--app/_locales/th/messages.json2
-rw-r--r--app/_locales/tr/messages.json6
-rw-r--r--app/_locales/vi/messages.json2
-rw-r--r--app/_locales/zh_CN/messages.json2
-rw-r--r--app/_locales/zh_TW/messages.json2
-rw-r--r--app/images/webcam.svg18
-rw-r--r--app/manifest.json2
-rw-r--r--app/scripts/background.js4
-rw-r--r--app/scripts/contentscript.js2
-rw-r--r--app/scripts/controllers/detect-tokens.js2
-rw-r--r--app/scripts/controllers/preferences.js94
-rw-r--r--app/scripts/lib/enums.js11
-rw-r--r--app/scripts/lib/ipfsContent.js6
-rw-r--r--app/scripts/lib/setupRaven.js4
-rw-r--r--app/scripts/lib/util.js29
-rw-r--r--app/scripts/metamask-controller.js3
-rw-r--r--app/scripts/migrations/028.js40
-rw-r--r--app/scripts/migrations/index.js1
-rw-r--r--app/scripts/platforms/extension.js7
-rw-r--r--mascara/src/app/first-time/index.css13
-rw-r--r--mascara/src/app/first-time/seed-screen.js16
-rw-r--r--old-ui/app/components/transaction-list-item.js2
-rw-r--r--package-lock.json620
-rw-r--r--package.json11
-rw-r--r--test/integration/lib/tx-list-items.js5
-rw-r--r--test/unit/app/controllers/detect-tokens-test.js35
-rw-r--r--test/unit/app/controllers/preferences-controller-test.js158
-rw-r--r--test/unit/migrations/028-test.js46
-rw-r--r--ui/app/actions.js62
-rw-r--r--ui/app/components/ens-input.js2
-rw-r--r--ui/app/components/modals/index.scss2
-rw-r--r--ui/app/components/modals/modal.js13
-rw-r--r--ui/app/components/modals/qr-scanner/index.js2
-rw-r--r--ui/app/components/modals/qr-scanner/index.scss83
-rw-r--r--ui/app/components/modals/qr-scanner/qr-scanner.component.js216
-rw-r--r--ui/app/components/modals/qr-scanner/qr-scanner.container.js24
-rw-r--r--ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.component.js2
-rw-r--r--ui/app/components/send/send-content/send-content.component.js6
-rw-r--r--ui/app/components/send/send-content/send-to-row/send-to-row.component.js2
-rw-r--r--ui/app/components/send/send.component.js33
-rw-r--r--ui/app/components/send/send.container.js12
-rw-r--r--ui/app/components/send/send.selectors.js5
-rw-r--r--ui/app/components/send/tests/send-container.test.js2
-rw-r--r--ui/app/components/send/to-autocomplete/to-autocomplete.js12
-rw-r--r--ui/app/components/tx-list-item.js8
-rw-r--r--ui/app/components/tx-list.js18
-rw-r--r--ui/app/constants/error-keys.js2
-rw-r--r--ui/app/css/itcss/components/send.scss17
-rw-r--r--ui/app/first-time/init-menu.js2
-rw-r--r--ui/app/reducers/app.js16
-rw-r--r--ui/app/selectors/confirm-transaction.js10
-rw-r--r--ui/app/util.js4
-rw-r--r--ui/lib/webcam-utils.js36
67 files changed, 1461 insertions, 428 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md
new file mode 100644
index 000000000..041803eae
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug-report.md
@@ -0,0 +1,34 @@
+---
+name: Bug Report
+about: Using MetaMask, but it's not working as you expect?
+
+---
+
+<!--
+BEFORE SUBMITTING: PLEASE SEARCH TO MAKE SURE THIS ISSUE HAS NOT BEEN SUBMITTED
+-->
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
+
+**Expected behavior**
+A clear description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Browser details (please complete the following information):**
+ - OS: [e.g. iOS]
+ - Browser [e.g. chrome, safari]
+ - MetaMask Version [e.g. 4.9.0]
+ - Old UI or New / Beta UI?
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md
new file mode 100644
index 000000000..edba657a4
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature-request.md
@@ -0,0 +1,14 @@
+---
+name: Feature Request
+about: Looking for a feature that doesn't exist? Let us know!
+
+---
+
+**What problem are you trying to solve?**
+A short description of what you're trying to do. E.g., "My users need to wrap ETH, but they're intimidated by the confirm screen..." or "I'm trying to debug my application, and XYZ..."
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen. Try to also include any alternative solutions you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.github/ISSUE_TEMPLATE/support-request-or-question.md b/.github/ISSUE_TEMPLATE/support-request-or-question.md
new file mode 100644
index 000000000..aeb31af26
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/support-request-or-question.md
@@ -0,0 +1,9 @@
+---
+name: Support Request or Question
+about: Have a question about how to use MetaMask?
+
+---
+
+FOR USER QUESTIONS, PLEASE DO NOT OPEN A GITHUB ISSUE - IT WILL NOT BE HANDLED HERE.
+
+INSTEAD, PLEASE EMAIL SUPPORT@METAMASK.IO WITH A DESCRIPTION OF YOUR PROBLEM.
diff --git a/.npmrc b/.npmrc
deleted file mode 100644
index b6f27f135..000000000
--- a/.npmrc
+++ /dev/null
@@ -1 +0,0 @@
-engine-strict=true
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7e1e1ff4b..d372c2849 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,13 +1,28 @@
# Changelog
-## Current Master
-
-- Add new tokens auto detection
-- Remove rejected transactions from transaction history
-- Add Trezor Support
-- Allow to remove accounts (Imported and Hardware Wallets)
+## Current Develop Branch
+
+## 4.9.1 Mon Aug 09 2018
+
+- [#4884](https://github.com/MetaMask/metamask-extension/pull/4884): Allow to have tokens per account and network.
+- [#4989](https://github.com/MetaMask/metamask-extension/pull/4989): Continue to use original signedTypedData.
+- [#5010](https://github.com/MetaMask/metamask-extension/pull/5010): Fix ENS resolution issues.
+- [#5000](https://github.com/MetaMask/metamask-extension/pull/5000): Show error while allowing confirmation of tx where simulation fails.
+- [#4995](https://github.com/MetaMask/metamask-extension/pull/4995): Shows retry button on dApp initialized transactions.
+
+## 4.9.0 Mon Aug 07 2018
+
+- [#4926](https://github.com/MetaMask/metamask-extension/pull/4926): Show retry button on the latest tx of the earliest nonce.
+- [#4888](https://github.com/MetaMask/metamask-extension/pull/4888): Suggest using the new user interface.
+- [#4947](https://github.com/MetaMask/metamask-extension/pull/4947): Prevent sending multiple transasctions on multiple confirm clicks.
+- [#4844](https://github.com/MetaMask/metamask-extension/pull/4844): Add new tokens auto detection.
+- [#4667](https://github.com/MetaMask/metamask-extension/pull/4667): Remove rejected transactions from transaction history.
+- [#4625](https://github.com/MetaMask/metamask-extension/pull/4625): Add Trezor Support.
+- [#4625](https://github.com/MetaMask/metamask-extension/pull/4625/commits/523cf9ad33d88719520ae5e7293329d133b64d4d): Allow to remove accounts (Imported and Hardware Wallets)
+- [#4814](https://github.com/MetaMask/metamask-extension/pull/4814): Add hex data input to send screen.
+- [#4691](https://github.com/MetaMask/metamask-extension/pull/4691): Redesign of the Confirm Transaction Screen.
- [#4840](https://github.com/MetaMask/metamask-extension/pull/4840): Now shows notifications when transactions are completed.
-- [#4855](https://github.com/MetaMask/metamask-extension/pull/4855): network.js: convert rpc protocol to lower case.
+- [#4855](https://github.com/MetaMask/metamask-extension/pull/4855): Allow the use of HTTP prefix for custom rpc urls.
## 4.8.0 Thur Jun 14 2018
diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json
index 1d2619672..c06a99250 100644
--- a/app/_locales/de/messages.json
+++ b/app/_locales/de/messages.json
@@ -84,7 +84,7 @@
"message": "Auf Coinbase kaufen"
},
"buyCoinbaseExplainer": {
- "message": "Coinbase ist die weltweit bekannteste Art und Weise um bitcoin, ethereum und litecoin zu kaufen und verkaufen."
+ "message": "Coinbase ist die weltweit bekannteste Art und Weise um Bitcoin, Ethereum und Litecoin zu kaufen und verkaufen."
},
"ok": {
"message": "Ok"
@@ -828,7 +828,7 @@
"message": "Willkommen zur neuen Oberfläche (Beta)"
},
"uiWelcomeMessage": {
- "message": "Du verwendest nun die neue Metamask Oberfläche. Schau dich um, teste die neuen Features wie z.B. das Senden von Token und lass es uns wissen falls du irgendwelche Probleme hast."
+ "message": "Du verwendest nun die neue MetaMask Oberfläche. Schau dich um, teste die neuen Features wie z.B. das Senden von Token und lass es uns wissen falls du irgendwelche Probleme hast."
},
"unapproved": {
"message": "Nicht genehmigt"
diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json
index 1b0183c92..ddfcf6f12 100644
--- a/app/_locales/en/messages.json
+++ b/app/_locales/en/messages.json
@@ -2,6 +2,9 @@
"accept": {
"message": "Accept"
},
+ "accessingYourCamera": {
+ "message": "Accesing your camera..."
+ },
"account": {
"message": "Account"
},
@@ -96,7 +99,7 @@
"message": "Buy on Coinbase"
},
"buyCoinbaseExplainer": {
- "message": "Coinbase is the world’s most popular way to buy and sell bitcoin, ethereum, and litecoin."
+ "message": "Coinbase is the world’s most popular way to buy and sell Bitcoin, Ethereum, and Litecoin."
},
"bytes": {
"message": "Bytes"
@@ -117,7 +120,7 @@
"message": "Close"
},
"chromeRequiredForTrezor":{
- "message": "You need to use Metamask on Google Chrome in order to connect to your TREZOR device."
+ "message": "You need to use MetaMask on Google Chrome in order to connect to your TREZOR device."
},
"confirm": {
"message": "Confirm"
@@ -147,7 +150,7 @@
"message": "Connect to Trezor"
},
"connectToTrezorHelp": {
- "message": "Metamask is able to access your TREZOR ethereum accounts. First make sure your device is connected and unlocked."
+ "message": "MetaMask is able to access your TREZOR Ethereum accounts. First make sure your device is connected and unlocked."
},
"connectToTrezorTrouble": {
"message": "If you are having trouble, please make sure you are using the latest version of the TREZOR firmware."
@@ -656,6 +659,12 @@
"notStarted": {
"message": "Not Started"
},
+ "noWebcamFoundTitle": {
+ "message": "Webcam not found"
+ },
+ "noWebcamFound": {
+ "message": "Your computer's webcam was not found. Please try again."
+ },
"oldUI": {
"message": "Old UI"
},
@@ -940,6 +949,12 @@
"info": {
"message": "Info"
},
+ "scanInstructions": {
+ "message": "Place the QR code in front of your camera"
+ },
+ "scanQrCode": {
+ "message": "Scan QR Code"
+ },
"shapeshiftBuy": {
"message": "Buy with Shapeshift"
},
@@ -1059,6 +1074,9 @@
"message": "We had trouble loading your token balances. You can view them ",
"description": "Followed by a link (here) to view token balances"
},
+ "tryAgain": {
+ "message": "Try again"
+ },
"twelveWords": {
"message": "These 12 words are the only way to restore your MetaMask accounts.\nSave them somewhere safe and secret."
},
@@ -1069,7 +1087,7 @@
"message": "Welcome to the New UI (Beta)"
},
"uiWelcomeMessage": {
- "message": "You are now using the new Metamask UI."
+ "message": "You are now using the new MetaMask UI."
},
"unapproved": {
"message": "Unapproved"
@@ -1089,6 +1107,15 @@
"unknownNetworkId": {
"message": "Unknown network ID"
},
+ "unknownQrCode": {
+ "message": "Error: We couldn't identify that QR code"
+ },
+ "unknownCameraErrorTitle": {
+ "message": "Ooops! Something went wrong...."
+ },
+ "unknownCameraError": {
+ "message": "There was an error while trying to access you camera. Please try again..."
+ },
"unlock": {
"message": "Unlock"
},
@@ -1135,6 +1162,9 @@
"whatsThis": {
"message": "What's this?"
},
+ "youNeedToAllowCameraAccess": {
+ "message": "You need to allow camera access to use this feature."
+ },
"yourSigRequested": {
"message": "Your signature is being requested"
},
diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json
index f287674f1..ed7f8f681 100644
--- a/app/_locales/es/messages.json
+++ b/app/_locales/es/messages.json
@@ -75,7 +75,7 @@
"message": "Pedir prestado con Dharma (Beta)"
},
"builtInCalifornia": {
- "message": "Metamask fue diseñado y construido en California"
+ "message": "MetaMask fue diseñado y construido en California"
},
"buy": {
"message": "Comprar"
@@ -874,7 +874,7 @@
"message": "Advertencia"
},
"welcomeBeta": {
- "message": "Bienvenido a Metamask Beta"
+ "message": "Bienvenido a MetaMask Beta"
},
"whatsThis": {
"message": "¿Qué es esto?"
diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json
index da2cfe4f8..1463e2b5f 100644
--- a/app/_locales/fr/messages.json
+++ b/app/_locales/fr/messages.json
@@ -63,7 +63,7 @@
"message": "Acheter sur Coinbase"
},
"buyCoinbaseExplainer": {
- "message": "Coinbase est le moyen le plus populaire au monde d'acheter et de vendre du bitcoin, de l'ethereum et du litecoin."
+ "message": "Coinbase est le moyen le plus populaire au monde d'acheter et de vendre du Bitcoin, de l'Ethereum et du Litecoin."
},
"cancel": {
"message": "Annuler"
@@ -570,7 +570,7 @@
"message": "Bienvenue dans la nouvelle interface utilisateur (Beta)"
},
"uiWelcomeMessage": {
- "message": "Vous utilisez maintenant la nouvelle interface utilisateur Metamask. Jetez un coup d'oeil, essayez de nouvelles fonctionnalités comme l'envoi de jetons, et faites-nous savoir si vous avez des problèmes."
+ "message": "Vous utilisez maintenant la nouvelle interface utilisateur MetaMask. Jetez un coup d'oeil, essayez de nouvelles fonctionnalités comme l'envoi de jetons, et faites-nous savoir si vous avez des problèmes."
},
"unavailable": {
"message": "Indisponible"
diff --git a/app/_locales/it/messages.json b/app/_locales/it/messages.json
index ef3ed4025..2ae5fae72 100644
--- a/app/_locales/it/messages.json
+++ b/app/_locales/it/messages.json
@@ -81,7 +81,7 @@
"message": "Compra su Coinbase"
},
"buyCoinbaseExplainer": {
- "message": "Coinbase è il servizio più popolare al mondo per comprare e vendere bitcoin, ethereum e litecoin."
+ "message": "Coinbase è il servizio più popolare al mondo per comprare e vendere Bitcoin, Ethereum e Litecoin."
},
"cancel": {
"message": "Cancella"
@@ -178,7 +178,7 @@
"message": "La rete predefinita per transazioni in Ether è la Rete Ethereum Principale."
},
"denExplainer": {
- "message": "Il DEN è il tuo archivio crittato con password dentro Metamask."
+ "message": "Il DEN è il tuo archivio crittato con password dentro MetaMask."
},
"deposit": {
"message": "Deposita"
@@ -816,4 +816,4 @@
"youSign": {
"message": "Ti stai connettendo"
}
-} \ No newline at end of file
+}
diff --git a/app/_locales/nl/messages.json b/app/_locales/nl/messages.json
index 38289f602..46847f1bf 100644
--- a/app/_locales/nl/messages.json
+++ b/app/_locales/nl/messages.json
@@ -81,7 +81,7 @@
"message": "Koop op Coinbase"
},
"buyCoinbaseExplainer": {
- "message": "Coinbase is 's werelds populairste manier om bitcoin, ethereum en litecoin te kopen en verkopen."
+ "message": "Coinbase is 's werelds populairste manier om Bitcoin, Ethereum en Litecoin te kopen en verkopen."
},
"cancel": {
"message": "Annuleer"
@@ -435,7 +435,7 @@
"message": "back-up woorden hebben alleen kleine letters"
},
"mainnet": {
- "message": "belangrijkste ethereum-netwerk"
+ "message": "belangrijkste Ethereum-netwerk"
},
"message": {
"message": "Bericht"
@@ -762,7 +762,7 @@
"message": "Welkom bij de nieuwe gebruikersinterface (bèta)"
},
"uiWelcomeMessage": {
- "message": "U gebruikt nu de nieuwe gebruikersinterface van Metamask. Kijk rond, probeer nieuwe functies uit zoals het verzenden van tokens en laat ons weten of u problemen ondervindt."
+ "message": "U gebruikt nu de nieuwe gebruikersinterface van MetaMask. Kijk rond, probeer nieuwe functies uit zoals het verzenden van tokens en laat ons weten of u problemen ondervindt."
},
"unavailable": {
"message": "Niet beschikbaar"
diff --git a/app/_locales/ph/messages.json b/app/_locales/ph/messages.json
index 29d63be02..9a243447a 100644
--- a/app/_locales/ph/messages.json
+++ b/app/_locales/ph/messages.json
@@ -63,7 +63,7 @@
"message": "Bumili sa Coinbase"
},
"buyCoinbaseExplainer": {
- "message": "Ang Coinbase ang pinakasikat na paraan upang bumili at magbenta ng bitcoin, ethereum, at litecoin sa buong mundo."
+ "message": "Ang Coinbase ang pinakasikat na paraan upang bumili at magbenta ng Bitcoin, Ethereum, at Litecoin sa buong mundo."
},
"cancel": {
"message": "Kanselahin"
diff --git a/app/_locales/pt/messages.json b/app/_locales/pt/messages.json
index e770392d0..6f0bb1584 100644
--- a/app/_locales/pt/messages.json
+++ b/app/_locales/pt/messages.json
@@ -81,7 +81,7 @@
"message": "Comprar no Coinbase"
},
"buyCoinbaseExplainer": {
- "message": "Coinbase é a forma mais conhecida para comprar e vender bitcoin, ethereum, e litecoin."
+ "message": "Coinbase é a forma mais conhecida para comprar e vender Bitcoin, Ethereum, e Litecoin."
},
"cancel": {
"message": "Cancelar"
diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json
index b43251064..bb722735d 100644
--- a/app/_locales/ru/messages.json
+++ b/app/_locales/ru/messages.json
@@ -84,7 +84,7 @@
"message": "Купить на Coinbase"
},
"buyCoinbaseExplainer": {
- "message": "Биржа Coinbase – это наиболее популярный способ купить или продать bitcoin, ethereum и litecoin."
+ "message": "Биржа Coinbase – это наиболее популярный способ купить или продать Bitcoin, Ethereum и Litecoin."
},
"ok": {
"message": "ОК"
diff --git a/app/_locales/th/messages.json b/app/_locales/th/messages.json
index 3d7dec226..c9aaa0394 100644
--- a/app/_locales/th/messages.json
+++ b/app/_locales/th/messages.json
@@ -762,7 +762,7 @@
"message": "ยินดีต้อนรับสู่หน้าตาใหม่ (เบต้า)"
},
"uiWelcomeMessage": {
- "message": "ขณะนี้คุณใช้งาน Metamask หน้าตาใหม่แล้ว ลองใช้ความสามรถใหม่ ๆ เช่นการส่งโทเค็นและหากพบปัญหากรุณาแจ้งให้เราทราบ"
+ "message": "ขณะนี้คุณใช้งาน MetaMask หน้าตาใหม่แล้ว ลองใช้ความสามรถใหม่ ๆ เช่นการส่งโทเค็นและหากพบปัญหากรุณาแจ้งให้เราทราบ"
},
"unavailable": {
"message": "ใช้งานไม่ได้"
diff --git a/app/_locales/tr/messages.json b/app/_locales/tr/messages.json
index c2c09bc91..08ba6cde8 100644
--- a/app/_locales/tr/messages.json
+++ b/app/_locales/tr/messages.json
@@ -84,7 +84,7 @@
"message": "Coinbase'de satın al"
},
"buyCoinbaseExplainer": {
- "message": "Coinbase bitcoin, ethereum, and litecoin alıp satmanın dünyadaki en popüler yolu"
+ "message": "Coinbase Bitcoin, Ethereum, and Litecoin alıp satmanın dünyadaki en popüler yolu"
},
"ok": {
"message": "Tamam"
@@ -852,7 +852,7 @@
"message": "Yeni UI (Beta)'ya hoşgeldiniz"
},
"uiWelcomeMessage": {
- "message": "Şu anda yeni Metamask UI kullanmaktasınız. Gözatın, jeton gönderme gibi yeni özellikleri deneyin ve herhangi bir sorunlar karşılaşırsanız bize haber verin"
+ "message": "Şu anda yeni MetaMask UI kullanmaktasınız. Gözatın, jeton gönderme gibi yeni özellikleri deneyin ve herhangi bir sorunlar karşılaşırsanız bize haber verin"
},
"unapproved": {
"message": "Onaylanmadı"
@@ -909,4 +909,4 @@
"youSign": {
"message": "İmzalıyorsunuz"
}
-} \ No newline at end of file
+}
diff --git a/app/_locales/vi/messages.json b/app/_locales/vi/messages.json
index cd30de4de..782dfd119 100644
--- a/app/_locales/vi/messages.json
+++ b/app/_locales/vi/messages.json
@@ -570,7 +570,7 @@
"message": "Chào mừng bạn đến với giao diện mới (Beta)"
},
"uiWelcomeMessage": {
- "message": "Bạn đang sử dụng giao diện mới của Metamask. Chúng tôi khuyến khích bạn thử nghiệm và khám phá các tính năng mới như gửi token, và nếu bạn có gặp phải vấn đề gì khó khăn, xin hãy liên hệ ngay để chúng tôi có thể giúp đỡ bạn."
+ "message": "Bạn đang sử dụng giao diện mới của MetaMask. Chúng tôi khuyến khích bạn thử nghiệm và khám phá các tính năng mới như gửi token, và nếu bạn có gặp phải vấn đề gì khó khăn, xin hãy liên hệ ngay để chúng tôi có thể giúp đỡ bạn."
},
"unavailable": {
"message": "Không có sẵn"
diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json
index 241ea948d..a39bba9da 100644
--- a/app/_locales/zh_CN/messages.json
+++ b/app/_locales/zh_CN/messages.json
@@ -879,7 +879,7 @@
"message": "欢迎使用新版界面 (Beta)"
},
"uiWelcomeMessage": {
- "message": "你现在正在使用新的 Metamask 界面。 尝试发送代币等新功能,有任何问题请告知我们。"
+ "message": "你现在正在使用新的 MetaMask 界面。 尝试发送代币等新功能,有任何问题请告知我们。"
},
"unapproved": {
"message": "未批准"
diff --git a/app/_locales/zh_TW/messages.json b/app/_locales/zh_TW/messages.json
index 9aaee0e16..200c75c3c 100644
--- a/app/_locales/zh_TW/messages.json
+++ b/app/_locales/zh_TW/messages.json
@@ -362,7 +362,7 @@
"message": "你想怎麼存入 Ether?"
},
"holdEther": {
- "message": "Metamask 讓您能保存 ether 和代幣, 並成為您接觸分散式應用程式的途徑."
+ "message": "MetaMask 讓您能保存 ether 和代幣, 並成為您接觸分散式應用程式的途徑."
},
"import": {
"message": "導入",
diff --git a/app/images/webcam.svg b/app/images/webcam.svg
new file mode 100644
index 000000000..4b9b58148
--- /dev/null
+++ b/app/images/webcam.svg
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="53px" height="53px" viewBox="0 0 53 53" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <!-- Generator: Sketch 50.2 (55047) - http://www.bohemiancoding.com/sketch -->
+ <title>webcam</title>
+ <desc>Created with Sketch.</desc>
+ <defs></defs>
+ <g id="QR-Code-Scan" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+ <g id="Group-4-Copy" transform="translate(-482.000000, -218.000000)">
+ <g id="webcam" transform="translate(482.000000, 218.000000)">
+ <circle id="Oval" fill="#D5ECFA" cx="26.5" cy="26.5" r="26.5"></circle>
+ <g id="Group" transform="translate(14.000000, 19.000000)" fill="#259DE5">
+ <rect id="Rectangle" x="0" y="0" width="18" height="16"></rect>
+ <polygon id="Triangle" points="19 6.57142857 26 3 26 13 19 9.42857143"></polygon>
+ </g>
+ </g>
+ </g>
+ </g>
+</svg> \ No newline at end of file
diff --git a/app/manifest.json b/app/manifest.json
index ed328f19f..84cedd687 100644
--- a/app/manifest.json
+++ b/app/manifest.json
@@ -1,7 +1,7 @@
{
"name": "__MSG_appName__",
"short_name": "__MSG_appName__",
- "version": "4.8.0",
+ "version": "4.9.1",
"manifest_version": 2,
"author": "https://metamask.io",
"description": "__MSG_appDescription__",
diff --git a/app/scripts/background.js b/app/scripts/background.js
index 4cd6dac4c..c7395c810 100644
--- a/app/scripts/background.js
+++ b/app/scripts/background.js
@@ -47,8 +47,8 @@ const notificationManager = new NotificationManager()
global.METAMASK_NOTIFIER = notificationManager
// setup sentry error reporting
-const releaseVersion = platform.getVersion()
-const raven = setupRaven({ releaseVersion })
+const release = platform.getVersion()
+const raven = setupRaven({ 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
diff --git a/app/scripts/contentscript.js b/app/scripts/contentscript.js
index b7496f318..e0a2b0061 100644
--- a/app/scripts/contentscript.js
+++ b/app/scripts/contentscript.js
@@ -198,6 +198,6 @@ function blacklistedDomainCheck () {
*/
function redirectToPhishingWarning () {
console.log('MetaMask - routing to Phishing Warning component')
- let extensionURL = extension.runtime.getURL('phishing.html')
+ const extensionURL = extension.runtime.getURL('phishing.html')
window.location.href = extensionURL
}
diff --git a/app/scripts/controllers/detect-tokens.js b/app/scripts/controllers/detect-tokens.js
index 195ec918a..62e639795 100644
--- a/app/scripts/controllers/detect-tokens.js
+++ b/app/scripts/controllers/detect-tokens.js
@@ -85,7 +85,7 @@ class DetectTokensController {
set preferences (preferences) {
if (!preferences) { return }
this._preferences = preferences
- preferences.store.subscribe(({ tokens }) => { this.tokenAddresses = tokens.map((obj) => { return obj.address }) })
+ preferences.store.subscribe(({ tokens = [] }) => { this.tokenAddresses = tokens.map((obj) => { return obj.address }) })
preferences.store.subscribe(({ selectedAddress }) => {
if (this.selectedAddress !== selectedAddress) {
this.selectedAddress = selectedAddress
diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js
index f6250dc16..707fd7de9 100644
--- a/app/scripts/controllers/preferences.js
+++ b/app/scripts/controllers/preferences.js
@@ -13,6 +13,7 @@ class PreferencesController {
* @property {array} store.frequentRpcList A list of custom rpcs to provide the user
* @property {string} store.currentAccountTab Indicates the selected tab in the ui
* @property {array} store.tokens The tokens the user wants display in their token lists
+ * @property {object} store.accountTokens The tokens stored per account and then per network type
* @property {boolean} store.useBlockie The users preference for blockie identicons within the UI
* @property {object} store.featureFlags A key-boolean map, where keys refer to features and booleans to whether the
* user wishes to see that feature
@@ -24,6 +25,7 @@ class PreferencesController {
const initState = extend({
frequentRpcList: [],
currentAccountTab: 'history',
+ accountTokens: {},
tokens: [],
useBlockie: false,
featureFlags: {},
@@ -33,8 +35,9 @@ class PreferencesController {
}, opts.initState)
this.diagnostics = opts.diagnostics
-
+ this.network = opts.network
this.store = new ObservableStore(initState)
+ this._subscribeProviderType()
}
// PUBLIC METHODS
@@ -77,12 +80,19 @@ class PreferencesController {
*/
setAddresses (addresses) {
const oldIdentities = this.store.getState().identities
+ const oldAccountTokens = this.store.getState().accountTokens
+
const identities = addresses.reduce((ids, address, index) => {
const oldId = oldIdentities[address] || {}
ids[address] = {name: `Account ${index + 1}`, address, ...oldId}
return ids
}, {})
- this.store.updateState({ identities })
+ const accountTokens = addresses.reduce((tokens, address) => {
+ const oldTokens = oldAccountTokens[address] || {}
+ tokens[address] = oldTokens
+ return tokens
+ }, {})
+ this.store.updateState({ identities, accountTokens })
}
/**
@@ -93,11 +103,13 @@ class PreferencesController {
*/
removeAddress (address) {
const identities = this.store.getState().identities
+ const accountTokens = this.store.getState().accountTokens
if (!identities[address]) {
throw new Error(`${address} can't be deleted cause it was not found`)
}
delete identities[address]
- this.store.updateState({ identities })
+ delete accountTokens[address]
+ this.store.updateState({ identities, accountTokens })
// If the selected account is no longer valid,
// select an arbitrary other account:
@@ -117,14 +129,17 @@ class PreferencesController {
*/
addAddresses (addresses) {
const identities = this.store.getState().identities
+ const accountTokens = this.store.getState().accountTokens
addresses.forEach((address) => {
// skip if already exists
if (identities[address]) return
// add missing identity
const identityCount = Object.keys(identities).length
+
+ accountTokens[address] = {}
identities[address] = { name: `Account ${identityCount + 1}`, address }
})
- this.store.updateState({ identities })
+ this.store.updateState({ identities, accountTokens })
}
/*
@@ -175,15 +190,15 @@ class PreferencesController {
* Setter for the `selectedAddress` property
*
* @param {string} _address A new hex address for an account
- * @returns {Promise<void>} Promise resolves with undefined
+ * @returns {Promise<void>} Promise resolves with tokens
*
*/
setSelectedAddress (_address) {
- return new Promise((resolve, reject) => {
- const address = normalizeAddress(_address)
- this.store.updateState({ selectedAddress: address })
- resolve()
- })
+ const address = normalizeAddress(_address)
+ this._updateTokens(address)
+ this.store.updateState({ selectedAddress: address })
+ const tokens = this.store.getState().tokens
+ return Promise.resolve(tokens)
}
/**
@@ -232,9 +247,7 @@ class PreferencesController {
} else {
tokens.push(newEntry)
}
-
- this.store.updateState({ tokens })
-
+ this._updateAccountTokens(tokens)
return Promise.resolve(tokens)
}
@@ -247,10 +260,8 @@ class PreferencesController {
*/
removeToken (rawAddress) {
const tokens = this.store.getState().tokens
-
const updatedTokens = tokens.filter(token => token.address !== rawAddress)
-
- this.store.updateState({ tokens: updatedTokens })
+ this._updateAccountTokens(updatedTokens)
return Promise.resolve(updatedTokens)
}
@@ -376,6 +387,57 @@ class PreferencesController {
//
// PRIVATE METHODS
//
+ /**
+ * Subscription to network provider type.
+ *
+ *
+ */
+ _subscribeProviderType () {
+ this.network.providerStore.subscribe(() => {
+ const { tokens } = this._getTokenRelatedStates()
+ this.store.updateState({ tokens })
+ })
+ }
+
+ /**
+ * Updates `accountTokens` and `tokens` of current account and network according to it.
+ *
+ * @param {array} tokens Array of tokens to be updated.
+ *
+ */
+ _updateAccountTokens (tokens) {
+ const { accountTokens, providerType, selectedAddress } = this._getTokenRelatedStates()
+ accountTokens[selectedAddress][providerType] = tokens
+ this.store.updateState({ accountTokens, tokens })
+ }
+
+ /**
+ * Updates `tokens` of current account and network.
+ *
+ * @param {string} selectedAddress Account address to be updated with.
+ *
+ */
+ _updateTokens (selectedAddress) {
+ const { tokens } = this._getTokenRelatedStates(selectedAddress)
+ this.store.updateState({ tokens })
+ }
+
+ /**
+ * A getter for `tokens` and `accountTokens` related states.
+ *
+ * @param {string} selectedAddress A new hex address for an account
+ * @returns {Object.<array, object, string, string>} States to interact with tokens in `accountTokens`
+ *
+ */
+ _getTokenRelatedStates (selectedAddress) {
+ const accountTokens = this.store.getState().accountTokens
+ if (!selectedAddress) selectedAddress = this.store.getState().selectedAddress
+ const providerType = this.network.providerStore.getState().type
+ if (!(selectedAddress in accountTokens)) accountTokens[selectedAddress] = {}
+ if (!(providerType in accountTokens[selectedAddress])) accountTokens[selectedAddress][providerType] = []
+ const tokens = accountTokens[selectedAddress][providerType]
+ return { tokens, accountTokens, providerType, selectedAddress }
+ }
}
module.exports = PreferencesController
diff --git a/app/scripts/lib/enums.js b/app/scripts/lib/enums.js
index 0a3afca47..c6d57a1bc 100644
--- a/app/scripts/lib/enums.js
+++ b/app/scripts/lib/enums.js
@@ -2,8 +2,19 @@ const ENVIRONMENT_TYPE_POPUP = 'popup'
const ENVIRONMENT_TYPE_NOTIFICATION = 'notification'
const ENVIRONMENT_TYPE_FULLSCREEN = 'fullscreen'
+const PLATFORM_BRAVE = 'Brave'
+const PLATFORM_CHROME = 'Chrome'
+const PLATFORM_EDGE = 'Edge'
+const PLATFORM_FIREFOX = 'Firefox'
+const PLATFORM_OPERA = 'Opera'
+
module.exports = {
ENVIRONMENT_TYPE_POPUP,
ENVIRONMENT_TYPE_NOTIFICATION,
ENVIRONMENT_TYPE_FULLSCREEN,
+ PLATFORM_BRAVE,
+ PLATFORM_CHROME,
+ PLATFORM_EDGE,
+ PLATFORM_FIREFOX,
+ PLATFORM_OPERA,
}
diff --git a/app/scripts/lib/ipfsContent.js b/app/scripts/lib/ipfsContent.js
index 5222151ea..5db63f47d 100644
--- a/app/scripts/lib/ipfsContent.js
+++ b/app/scripts/lib/ipfsContent.js
@@ -5,7 +5,7 @@ module.exports = function (provider) {
function ipfsContent (details) {
const name = details.url.substring(7, details.url.length - 1)
let clearTime = null
- extension.tabs.getSelected(null, tab => {
+ extension.tabs.query({active: true}, tab => {
extension.tabs.update(tab.id, { url: 'loading.html' })
clearTime = setTimeout(() => {
@@ -34,11 +34,11 @@ module.exports = function (provider) {
return { cancel: true }
}
- extension.webRequest.onBeforeRequest.addListener(ipfsContent, {urls: ['*://*.eth/', '*://*.test/']})
+ extension.webRequest.onErrorOccurred.addListener(ipfsContent, {urls: ['*://*.eth/', '*://*.test/']})
return {
remove () {
- extension.webRequest.onBeforeRequest.removeListener(ipfsContent)
+ extension.webRequest.onErrorOccurred.removeListener(ipfsContent)
},
}
}
diff --git a/app/scripts/lib/setupRaven.js b/app/scripts/lib/setupRaven.js
index 9aa2dec0a..e6e511640 100644
--- a/app/scripts/lib/setupRaven.js
+++ b/app/scripts/lib/setupRaven.js
@@ -8,7 +8,7 @@ module.exports = setupRaven
// Setup raven / sentry remote error reporting
function setupRaven (opts) {
- const { releaseVersion } = opts
+ const { release } = opts
let ravenTarget
// detect brave
const isBrave = Boolean(window.chrome.ipcRenderer)
@@ -22,7 +22,7 @@ function setupRaven (opts) {
}
const client = Raven.config(ravenTarget, {
- releaseVersion,
+ release,
transport: function (opts) {
opts.data.extra.isBrave = isBrave
const report = opts.data
diff --git a/app/scripts/lib/util.js b/app/scripts/lib/util.js
index 2b3fe3d6e..ea13b26be 100644
--- a/app/scripts/lib/util.js
+++ b/app/scripts/lib/util.js
@@ -5,6 +5,11 @@ const {
ENVIRONMENT_TYPE_POPUP,
ENVIRONMENT_TYPE_NOTIFICATION,
ENVIRONMENT_TYPE_FULLSCREEN,
+ PLATFORM_FIREFOX,
+ PLATFORM_OPERA,
+ PLATFORM_CHROME,
+ PLATFORM_EDGE,
+ PLATFORM_BRAVE,
} = require('./enums')
/**
@@ -38,6 +43,29 @@ const getEnvironmentType = (url = window.location.href) => {
}
/**
+ * Returns the platform (browser) where the extension is running.
+ *
+ * @returns {string} the platform ENUM
+ *
+ */
+const getPlatform = _ => {
+ const ua = navigator.userAgent
+ if (ua.search('Firefox') !== -1) {
+ return PLATFORM_FIREFOX
+ } else {
+ if (window && window.chrome && window.chrome.ipcRenderer) {
+ return PLATFORM_BRAVE
+ } else if (ua.search('Edge') !== -1) {
+ return PLATFORM_EDGE
+ } else if (ua.search('OPR') !== -1) {
+ return PLATFORM_OPERA
+ } else {
+ return PLATFORM_CHROME
+ }
+ }
+}
+
+/**
* Checks whether a given balance of ETH, represented as a hex string, is sufficient to pay a value plus a gas fee
*
* @param {object} txParams Contains data about a transaction
@@ -114,6 +142,7 @@ function removeListeners (listeners, emitter) {
module.exports = {
removeListeners,
applyListeners,
+ getPlatform,
getStack,
getEnvironmentType,
sufficientBalance,
diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js
index 12daf1603..81bb080ab 100644
--- a/app/scripts/metamask-controller.js
+++ b/app/scripts/metamask-controller.js
@@ -86,6 +86,7 @@ module.exports = class MetamaskController extends EventEmitter {
this.preferencesController = new PreferencesController({
initState: initState.PreferencesController,
initLangCode: opts.initLangCode,
+ network: this.networkController,
})
// currency controller
@@ -1405,7 +1406,7 @@ module.exports = class MetamaskController extends EventEmitter {
}
/**
- * A method for activating the retrieval of price data and auto detect tokens,
+ * A method for activating the retrieval of price data,
* which should only be fetched when the UI is visible.
* @private
* @param {boolean} active - True if price data should be getting fetched.
diff --git a/app/scripts/migrations/028.js b/app/scripts/migrations/028.js
new file mode 100644
index 000000000..9e995ee1a
--- /dev/null
+++ b/app/scripts/migrations/028.js
@@ -0,0 +1,40 @@
+// next version number
+const version = 28
+
+/*
+
+normalizes txParams on unconfirmed txs
+
+*/
+const clone = require('clone')
+
+module.exports = {
+ version,
+
+ migrate: async function (originalVersionedData) {
+ const versionedData = clone(originalVersionedData)
+ versionedData.meta.version = version
+ const state = versionedData.data
+ const newState = transformState(state)
+ versionedData.data = newState
+ return versionedData
+ },
+}
+
+function transformState (state) {
+ const newState = state
+
+ if (newState.PreferencesController) {
+ if (newState.PreferencesController.tokens && newState.PreferencesController.identities) {
+ const identities = newState.PreferencesController.identities
+ const tokens = newState.PreferencesController.tokens
+ newState.PreferencesController.accountTokens = {}
+ for (const identity in identities) {
+ newState.PreferencesController.accountTokens[identity] = {'mainnet': tokens}
+ }
+ newState.PreferencesController.tokens = []
+ }
+ }
+
+ return newState
+}
diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js
index bd0005221..3b512715e 100644
--- a/app/scripts/migrations/index.js
+++ b/app/scripts/migrations/index.js
@@ -38,4 +38,5 @@ module.exports = [
require('./025'),
require('./026'),
require('./027'),
+ require('./028'),
]
diff --git a/app/scripts/platforms/extension.js b/app/scripts/platforms/extension.js
index 0803164e8..71b162dd0 100644
--- a/app/scripts/platforms/extension.js
+++ b/app/scripts/platforms/extension.js
@@ -24,8 +24,13 @@ class ExtensionPlatform {
return extension.runtime.getManifest().version
}
- openExtensionInBrowser (route = null) {
+ openExtensionInBrowser (route = null, queryString = null) {
let extensionURL = extension.runtime.getURL('home.html')
+
+ if (queryString) {
+ extensionURL += `?${queryString}`
+ }
+
if (route) {
extensionURL += `#${route}`
}
diff --git a/mascara/src/app/first-time/index.css b/mascara/src/app/first-time/index.css
index 09e7d378d..2d05a48b8 100644
--- a/mascara/src/app/first-time/index.css
+++ b/mascara/src/app/first-time/index.css
@@ -340,6 +340,19 @@
min-width: 0;
}
+.backup-phrase__tips-text--link {
+ color: #2f9ae0;
+ cursor: pointer;
+}
+
+.backup-phrase__tips-text--link:hover {
+ color: #2f9ae0;
+}
+
+.backup-phrase__tips-text--strong {
+ font-weight: bold;
+}
+
@media only screen and (max-width: 768px) {
.backup-phrase__content-wrapper {
flex-direction: column;
diff --git a/mascara/src/app/first-time/seed-screen.js b/mascara/src/app/first-time/seed-screen.js
index d004be77b..97d5d7930 100644
--- a/mascara/src/app/first-time/seed-screen.js
+++ b/mascara/src/app/first-time/seed-screen.js
@@ -5,6 +5,7 @@ import classnames from 'classnames'
import { withRouter } from 'react-router-dom'
import { compose } from 'recompose'
import Identicon from '../../../../ui/app/components/identicon'
+import {exportAsFile} from '../../../../ui/app/util'
import Breadcrumbs from './breadcrumbs'
import LoadingScreen from './loading-screen'
import { DEFAULT_ROUTE, INITIALIZE_CONFIRM_SEED_ROUTE } from '../../../../ui/app/routes'
@@ -65,6 +66,12 @@ class BackupPhraseScreen extends Component {
}
}
+ exportSeedWords = () => {
+ const { seedWords } = this.props
+
+ exportAsFile('MetaMask Secret Backup Phrase', seedWords, 'text/plain')
+ }
+
renderSecretWordsContainer () {
const { isShowingSecret } = this.state
@@ -111,7 +118,7 @@ class BackupPhraseScreen extends Component {
<div className="backup-phrase__tips">
<div className="backup-phrase__tips-text">Tips:</div>
<div className="backup-phrase__tips-text">
- Store this phrase in a password manager like 1password.
+ Store this phrase in a password manager like 1Password.
</div>
<div className="backup-phrase__tips-text">
Write this phrase on a piece of paper and store in a secure location. If you want even more security, write it down on multiple pieces of paper and store each in 2 - 3 different locations.
@@ -119,6 +126,13 @@ class BackupPhraseScreen extends Component {
<div className="backup-phrase__tips-text">
Memorize this phrase.
</div>
+ <div className="backup-phrase__tips-text">
+ <strong>
+ <a className="backup-phrase__tips-text--link backup-phrase__tips-text--strong" onClick={this.exportSeedWords}>
+ Download this Secret Backup Phrase
+ </a>
+ </strong> and keep it stored safely on an external encrypted hard drive or storage medium.
+ </div>
</div>
<div className="backup-phrase__next-button">
<button
diff --git a/old-ui/app/components/transaction-list-item.js b/old-ui/app/components/transaction-list-item.js
index 015ef6ba6..6ecf7d193 100644
--- a/old-ui/app/components/transaction-list-item.js
+++ b/old-ui/app/components/transaction-list-item.js
@@ -40,7 +40,7 @@ TransactionListItem.prototype.showRetryButton = function () {
const currentNonce = txParams.nonce
const currentNonceTxs = transactions.filter(tx => tx.txParams.nonce === currentNonce)
const currentNonceSubmittedTxs = currentNonceTxs.filter(tx => tx.status === 'submitted')
- const currentSubmittedTxs = transactions.filter(tx => tx.status === 'submitted')
+ const currentSubmittedTxs = transactions.filter(tx => tx.status === 'submitted')
const lastSubmittedTxWithCurrentNonce = currentNonceSubmittedTxs[0]
const currentTxIsLatestWithNonce = lastSubmittedTxWithCurrentNonce &&
lastSubmittedTxWithCurrentNonce.id === transaction.id
diff --git a/package-lock.json b/package-lock.json
index 151a68f0c..a43a62608 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -468,7 +468,7 @@
},
"@sinonjs/formatio": {
"version": "2.0.0",
- "resolved": "http://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz",
+ "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz",
"integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==",
"dev": true,
"requires": {
@@ -1623,6 +1623,15 @@
"@types/react": "*"
}
},
+ "@zxing/library": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@zxing/library/-/library-0.7.0.tgz",
+ "integrity": "sha512-VJ1cJaCWVF8MspnuyaZKGKlrSQLqQ5usgSap8uuCAvWGQ6W6OwN1NeGvnjhT+9hmnwkHK8XjaflvzaDBC7nKnw==",
+ "requires": {
+ "text-encoding": "^0.6.4",
+ "ts-custom-error": "^2.2.1"
+ }
+ },
"JSONStream": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.2.tgz",
@@ -7049,6 +7058,11 @@
}
}
},
+ "detectrtc": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/detectrtc/-/detectrtc-1.3.6.tgz",
+ "integrity": "sha1-2rwDU5gaPadzLelpBxwItt3dW1k="
+ },
"di": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz",
@@ -8275,7 +8289,7 @@
}
},
"eth-contract-metadata": {
- "version": "github:MetaMask/eth-contract-metadata#966a891dd9c79b873fd8968a0155b067ca630502",
+ "version": "github:MetaMask/eth-contract-metadata#2da362052a312dc6c72a7eec116abf6284664f50",
"from": "github:MetaMask/eth-contract-metadata#master"
},
"eth-ens-namehash": {
@@ -8295,38 +8309,18 @@
}
},
"eth-hd-keyring": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/eth-hd-keyring/-/eth-hd-keyring-2.0.0.tgz",
- "integrity": "sha512-lTeANNPNj/j08sWU7LUQZTsx9NUJaUsiOdVxeP0UI5kke7L+Sd7zJWBmCShudEVG8PkqKLE1KJo08o430sl6rw==",
+ "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": "^2.0.1",
- "ethereumjs-abi": "^0.6.5",
+ "eth-sig-util": "^1.4.2",
"ethereumjs-util": "^5.1.1",
"ethereumjs-wallet": "^0.6.0",
"events": "^1.1.1",
"xtend": "^4.0.1"
},
"dependencies": {
- "eth-sig-util": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-2.0.1.tgz",
- "integrity": "sha512-lxHZOQspexk3DaGj4RBbWy4C/qNOWRnxpaJzNnYD3WEmC8shcJ4tHs7Xv878rzvILfJnSFSCCiKQhng1m80oBQ==",
- "requires": {
- "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7",
- "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-util": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz",
@@ -8344,9 +8338,9 @@
}
},
"eth-json-rpc-filters": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/eth-json-rpc-filters/-/eth-json-rpc-filters-2.1.1.tgz",
- "integrity": "sha512-FSFcCMJ1lRS8az1LhIK5Klima8Hyfv4keKSdW2MA3zwiN/wX1NKb/sQSEFO3nstPUqR2Aa02lVokp85UnnrBlA==",
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/eth-json-rpc-filters/-/eth-json-rpc-filters-1.2.8.tgz",
+ "integrity": "sha512-DmnxLMpraZoVayrrBpAUy8b/lEBjfVGVQrEsmS9OvW2Ffexrwrt5wr8ZX0V1wPXfLG3Zpur63rCg17VQyZFcXA==",
"requires": {
"await-semaphore": "^0.1.1",
"eth-json-rpc-middleware": "^1.6.0",
@@ -9710,7 +9704,7 @@
},
"event-stream": {
"version": "3.3.4",
- "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz",
+ "resolved": "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz",
"integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=",
"dev": true,
"requires": {
@@ -11311,36 +11305,32 @@
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"fsevents": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.3.tgz",
- "integrity": "sha512-X+57O5YkDTiEQGiw8i7wYc2nQgweIekqkepI8Q3y4wVlurgBt2SuwxTeYUYMZIGpLZH3r/TsMjczCMXE5ZOt7Q==",
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz",
+ "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==",
"optional": true,
"requires": {
"nan": "^2.9.2",
- "node-pre-gyp": "^0.9.0"
+ "node-pre-gyp": "^0.10.0"
},
"dependencies": {
"abbrev": {
"version": "1.1.1",
- "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
- "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
+ "bundled": true,
"optional": true
},
"ansi-regex": {
"version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
- "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+ "bundled": true
},
"aproba": {
"version": "1.2.0",
- "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
- "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
+ "bundled": true,
"optional": true
},
"are-we-there-yet": {
"version": "1.1.4",
- "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz",
- "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=",
+ "bundled": true,
"optional": true,
"requires": {
"delegates": "^1.0.0",
@@ -11349,13 +11339,11 @@
},
"balanced-match": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
- "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
+ "bundled": true
},
"brace-expansion": {
"version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "bundled": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -11363,56 +11351,52 @@
},
"chownr": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz",
- "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=",
+ "bundled": true,
"optional": true
},
"code-point-at": {
"version": "1.1.0",
- "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
- "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
+ "bundled": true
},
"concat-map": {
"version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+ "bundled": true
},
"console-control-strings": {
"version": "1.1.0",
- "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
- "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
+ "bundled": true
},
"core-util-is": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
- "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+ "bundled": true,
"optional": true
},
"debug": {
"version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "bundled": true,
"optional": true,
"requires": {
"ms": "2.0.0"
}
},
+ "deep-extend": {
+ "version": "0.5.1",
+ "bundled": true,
+ "optional": true
+ },
"delegates": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
- "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
+ "bundled": true,
"optional": true
},
"detect-libc": {
"version": "1.0.3",
- "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
- "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
+ "bundled": true,
"optional": true
},
"fs-minipass": {
"version": "1.2.5",
- "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz",
- "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
+ "bundled": true,
"optional": true,
"requires": {
"minipass": "^2.2.1"
@@ -11420,14 +11404,12 @@
},
"fs.realpath": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+ "bundled": true,
"optional": true
},
"gauge": {
"version": "2.7.4",
- "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
- "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
+ "bundled": true,
"optional": true,
"requires": {
"aproba": "^1.0.3",
@@ -11442,8 +11424,7 @@
},
"glob": {
"version": "7.1.2",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
- "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
+ "bundled": true,
"optional": true,
"requires": {
"fs.realpath": "^1.0.0",
@@ -11456,14 +11437,12 @@
},
"has-unicode": {
"version": "2.0.1",
- "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
- "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
+ "bundled": true,
"optional": true
},
"iconv-lite": {
"version": "0.4.21",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.21.tgz",
- "integrity": "sha512-En5V9za5mBt2oUA03WGD3TwDv0MKAruqsuxstbMUZaj9W9k/m1CV/9py3l0L5kw9Bln8fdHQmzHSYtvpvTLpKw==",
+ "bundled": true,
"optional": true,
"requires": {
"safer-buffer": "^2.1.0"
@@ -11471,8 +11450,7 @@
},
"ignore-walk": {
"version": "3.0.1",
- "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz",
- "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
+ "bundled": true,
"optional": true,
"requires": {
"minimatch": "^3.0.4"
@@ -11480,8 +11458,7 @@
},
"inflight": {
"version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "bundled": true,
"optional": true,
"requires": {
"once": "^1.3.0",
@@ -11490,40 +11467,39 @@
},
"inherits": {
"version": "2.0.3",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
- "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+ "bundled": true
+ },
+ "ini": {
+ "version": "1.3.5",
+ "bundled": true,
+ "optional": true
},
"is-fullwidth-code-point": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
- "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+ "bundled": true,
"requires": {
"number-is-nan": "^1.0.0"
}
},
"isarray": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+ "bundled": true,
"optional": true
},
"minimatch": {
"version": "3.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "bundled": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "0.0.8",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
- "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
+ "bundled": true
},
"minipass": {
"version": "2.2.4",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.2.4.tgz",
- "integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==",
+ "bundled": true,
"requires": {
"safe-buffer": "^5.1.1",
"yallist": "^3.0.0"
@@ -11531,8 +11507,7 @@
},
"minizlib": {
"version": "1.1.0",
- "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.1.0.tgz",
- "integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==",
+ "bundled": true,
"optional": true,
"requires": {
"minipass": "^2.2.1"
@@ -11540,16 +11515,14 @@
},
"mkdirp": {
"version": "0.5.1",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
- "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+ "bundled": true,
"requires": {
"minimist": "0.0.8"
}
},
"ms": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "bundled": true,
"optional": true
},
"nan": {
@@ -11560,8 +11533,7 @@
},
"needle": {
"version": "2.2.0",
- "resolved": "https://registry.npmjs.org/needle/-/needle-2.2.0.tgz",
- "integrity": "sha512-eFagy6c+TYayorXw/qtAdSvaUpEbBsDwDyxYFgLZ0lTojfH7K+OdBqAF7TAFwDokJaGpubpSGG0wO3iC0XPi8w==",
+ "bundled": true,
"optional": true,
"requires": {
"debug": "^2.1.2",
@@ -11570,9 +11542,8 @@
}
},
"node-pre-gyp": {
- "version": "0.9.1",
- "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.9.1.tgz",
- "integrity": "sha1-8RwHUW3ZL4cZnbx+GDjqt81WyeA=",
+ "version": "0.10.0",
+ "bundled": true,
"optional": true,
"requires": {
"detect-libc": "^1.0.2",
@@ -11589,8 +11560,7 @@
},
"nopt": {
"version": "4.0.1",
- "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
- "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
+ "bundled": true,
"optional": true,
"requires": {
"abbrev": "1",
@@ -11599,14 +11569,12 @@
},
"npm-bundled": {
"version": "1.0.3",
- "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.3.tgz",
- "integrity": "sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow==",
+ "bundled": true,
"optional": true
},
"npm-packlist": {
"version": "1.1.10",
- "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.1.10.tgz",
- "integrity": "sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA==",
+ "bundled": true,
"optional": true,
"requires": {
"ignore-walk": "^3.0.1",
@@ -11615,8 +11583,7 @@
},
"npmlog": {
"version": "4.1.2",
- "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
- "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
+ "bundled": true,
"optional": true,
"requires": {
"are-we-there-yet": "~1.1.2",
@@ -11627,39 +11594,33 @@
},
"number-is-nan": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
- "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
+ "bundled": true
},
"object-assign": {
"version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+ "bundled": true,
"optional": true
},
"once": {
"version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "bundled": true,
"requires": {
"wrappy": "1"
}
},
"os-homedir": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
- "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
+ "bundled": true,
"optional": true
},
"os-tmpdir": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
- "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
+ "bundled": true,
"optional": true
},
"osenv": {
"version": "0.1.5",
- "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
- "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
+ "bundled": true,
"optional": true,
"requires": {
"os-homedir": "^1.0.0",
@@ -11668,20 +11629,35 @@
},
"path-is-absolute": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+ "bundled": true,
"optional": true
},
"process-nextick-args": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
- "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
+ "bundled": true,
"optional": true
},
+ "rc": {
+ "version": "1.2.7",
+ "bundled": true,
+ "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",
+ "bundled": true,
+ "optional": true
+ }
+ }
+ },
"readable-stream": {
"version": "2.3.6",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
- "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+ "bundled": true,
"optional": true,
"requires": {
"core-util-is": "~1.0.0",
@@ -11695,8 +11671,7 @@
},
"rimraf": {
"version": "2.6.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
- "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
+ "bundled": true,
"optional": true,
"requires": {
"glob": "^7.0.5"
@@ -11704,43 +11679,36 @@
},
"safe-buffer": {
"version": "5.1.1",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
- "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
+ "bundled": true
},
"safer-buffer": {
"version": "2.1.2",
- "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "bundled": true,
"optional": true
},
"sax": {
"version": "1.2.4",
- "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
- "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
+ "bundled": true,
"optional": true
},
"semver": {
"version": "5.5.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
- "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==",
+ "bundled": true,
"optional": true
},
"set-blocking": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
- "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
+ "bundled": true,
"optional": true
},
"signal-exit": {
"version": "3.0.2",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
- "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
+ "bundled": true,
"optional": true
},
"string-width": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
- "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "bundled": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@@ -11749,8 +11717,7 @@
},
"string_decoder": {
"version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "bundled": true,
"optional": true,
"requires": {
"safe-buffer": "~5.1.0"
@@ -11758,16 +11725,19 @@
},
"strip-ansi": {
"version": "3.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
- "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "bundled": true,
"requires": {
"ansi-regex": "^2.0.0"
}
},
+ "strip-json-comments": {
+ "version": "2.0.1",
+ "bundled": true,
+ "optional": true
+ },
"tar": {
"version": "4.4.1",
- "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.1.tgz",
- "integrity": "sha512-O+v1r9yN4tOsvl90p5HAP4AEqbYhx4036AGMm075fH9F8Qwi3oJ+v4u50FkT/KkvywNGtwkk0zRI+8eYm1X/xg==",
+ "bundled": true,
"optional": true,
"requires": {
"chownr": "^1.0.1",
@@ -11781,14 +11751,12 @@
},
"util-deprecate": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+ "bundled": true,
"optional": true
},
"wide-align": {
"version": "1.1.2",
- "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz",
- "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==",
+ "bundled": true,
"optional": true,
"requires": {
"string-width": "^1.0.2"
@@ -11796,13 +11764,11 @@
},
"wrappy": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+ "bundled": true
},
"yallist": {
"version": "3.0.2",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz",
- "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k="
+ "bundled": true
}
}
},
@@ -21157,7 +21123,7 @@
"dependencies": {
"align-text": {
"version": "0.1.4",
- "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
+ "resolved": false,
"integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=",
"dev": true,
"requires": {
@@ -21168,19 +21134,19 @@
},
"amdefine": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
+ "resolved": false,
"integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
"dev": true
},
"ansi-regex": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
"dev": true
},
"append-transform": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz",
+ "resolved": false,
"integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==",
"dev": true,
"requires": {
@@ -21189,31 +21155,31 @@
},
"archy": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=",
"dev": true
},
"arrify": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
+ "resolved": false,
"integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=",
"dev": true
},
"async": {
"version": "1.5.2",
- "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+ "resolved": false,
"integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=",
"dev": true
},
"balanced-match": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true
},
"brace-expansion": {
"version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "resolved": false,
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"requires": {
@@ -21223,13 +21189,13 @@
},
"builtin-modules": {
"version": "1.1.1",
- "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
+ "resolved": false,
"integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
"dev": true
},
"caching-transform": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-1.0.1.tgz",
+ "resolved": false,
"integrity": "sha1-bb2y8g+Nj7znnz6U6dF0Lc31wKE=",
"dev": true,
"requires": {
@@ -21240,7 +21206,7 @@
"dependencies": {
"md5-hex": {
"version": "1.3.0",
- "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-1.3.0.tgz",
+ "resolved": false,
"integrity": "sha1-0sSv6YPENwZiF5uMrRRSGRNQRsQ=",
"dev": true,
"requires": {
@@ -21251,14 +21217,14 @@
},
"camelcase": {
"version": "1.2.1",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
+ "resolved": false,
"integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=",
"dev": true,
"optional": true
},
"center-align": {
"version": "0.1.3",
- "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
+ "resolved": false,
"integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=",
"dev": true,
"optional": true,
@@ -21269,7 +21235,7 @@
},
"cliui": {
"version": "2.1.0",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
+ "resolved": false,
"integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=",
"dev": true,
"optional": true,
@@ -21281,7 +21247,7 @@
"dependencies": {
"wordwrap": {
"version": "0.0.2",
- "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
+ "resolved": false,
"integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=",
"dev": true,
"optional": true
@@ -21290,31 +21256,31 @@
},
"code-point-at": {
"version": "1.1.0",
- "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+ "resolved": false,
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
"dev": true
},
"commondir": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
+ "resolved": false,
"integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
"dev": true
},
"concat-map": {
"version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "resolved": false,
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true
},
"convert-source-map": {
"version": "1.5.1",
- "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz",
+ "resolved": false,
"integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=",
"dev": true
},
"cross-spawn": {
"version": "4.0.2",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz",
+ "resolved": false,
"integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=",
"dev": true,
"requires": {
@@ -21324,7 +21290,7 @@
},
"debug": {
"version": "3.1.0",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "resolved": false,
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"dev": true,
"requires": {
@@ -21333,19 +21299,19 @@
},
"debug-log": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.1.tgz",
+ "resolved": false,
"integrity": "sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8=",
"dev": true
},
"decamelize": {
"version": "1.2.0",
- "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "resolved": false,
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
"dev": true
},
"default-require-extensions": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=",
"dev": true,
"requires": {
@@ -21354,7 +21320,7 @@
"dependencies": {
"strip-bom": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
"dev": true
}
@@ -21362,7 +21328,7 @@
},
"error-ex": {
"version": "1.3.1",
- "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz",
+ "resolved": false,
"integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=",
"dev": true,
"requires": {
@@ -21371,7 +21337,7 @@
},
"execa": {
"version": "0.7.0",
- "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz",
+ "resolved": false,
"integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=",
"dev": true,
"requires": {
@@ -21386,7 +21352,7 @@
"dependencies": {
"cross-spawn": {
"version": "5.1.0",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
+ "resolved": false,
"integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
"dev": true,
"requires": {
@@ -21399,7 +21365,7 @@
},
"find-cache-dir": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=",
"dev": true,
"requires": {
@@ -21410,7 +21376,7 @@
},
"find-up": {
"version": "2.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
+ "resolved": false,
"integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
"dev": true,
"requires": {
@@ -21419,7 +21385,7 @@
},
"foreground-child": {
"version": "1.5.6",
- "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz",
+ "resolved": false,
"integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=",
"dev": true,
"requires": {
@@ -21429,25 +21395,25 @@
},
"fs.realpath": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": true
},
"get-caller-file": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz",
+ "resolved": false,
"integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=",
"dev": true
},
"get-stream": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
"dev": true
},
"glob": {
"version": "7.1.2",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+ "resolved": false,
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
"dev": true,
"requires": {
@@ -21461,13 +21427,13 @@
},
"graceful-fs": {
"version": "4.1.11",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
+ "resolved": false,
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
"dev": true
},
"handlebars": {
"version": "4.0.11",
- "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz",
+ "resolved": false,
"integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=",
"dev": true,
"requires": {
@@ -21479,7 +21445,7 @@
"dependencies": {
"source-map": {
"version": "0.4.4",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
+ "resolved": false,
"integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
"dev": true,
"requires": {
@@ -21490,25 +21456,25 @@
},
"has-flag": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
"dev": true
},
"hosted-git-info": {
"version": "2.6.0",
- "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.0.tgz",
+ "resolved": false,
"integrity": "sha512-lIbgIIQA3lz5XaB6vxakj6sDHADJiZadYEJB+FgA+C4nubM1NwcuvUr9EJPmnH1skZqpqUzWborWo8EIUi0Sdw==",
"dev": true
},
"imurmurhash": {
"version": "0.1.4",
- "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "resolved": false,
"integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
"dev": true
},
"inflight": {
"version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "resolved": false,
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true,
"requires": {
@@ -21518,31 +21484,31 @@
},
"inherits": {
"version": "2.0.3",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "resolved": false,
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
"dev": true
},
"invert-kv": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=",
"dev": true
},
"is-arrayish": {
"version": "0.2.1",
- "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "resolved": false,
"integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
"dev": true
},
"is-buffer": {
"version": "1.1.6",
- "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "resolved": false,
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
"dev": true
},
"is-builtin-module": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
"dev": true,
"requires": {
@@ -21551,31 +21517,31 @@
},
"is-fullwidth-code-point": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
"dev": true
},
"is-stream": {
"version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
+ "resolved": false,
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
"dev": true
},
"isexe": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
"dev": true
},
"istanbul-lib-coverage": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.0.tgz",
+ "resolved": false,
"integrity": "sha512-yMSw5xLIbdaxiVXHk3amfNM2WeBxLrwH/BCyZ9HvA/fylwziAIJOG2rKqWyLqEJqwKT725vxxqidv+SyynnGAA==",
"dev": true
},
"istanbul-lib-hook": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.0.tgz",
+ "resolved": false,
"integrity": "sha512-qm3dt628HKpCVtIjbdZLuQyXn0+LO8qz+YHQDfkeXuSk5D+p299SEV5DrnUUnPi2SXvdMmWapMYWiuE75o2rUQ==",
"dev": true,
"requires": {
@@ -21584,7 +21550,7 @@
},
"istanbul-lib-report": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.0.tgz",
+ "resolved": false,
"integrity": "sha512-RiELmy9oIRYUv36ITOAhVum9PUvuj6bjyXVEKEHNiD1me6qXtxfx7vSEJWnjOGk2QmYw/GRFjLXWJv3qHpLceQ==",
"dev": true,
"requires": {
@@ -21595,7 +21561,7 @@
},
"istanbul-lib-source-maps": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-2.0.0.tgz",
+ "resolved": false,
"integrity": "sha512-jenUeC0gMSSMGkvqD9xuNfs3nD7XWeXLhqaIkqHsNZ3DJBWPdlKEydE7Ya5aTgdWjrEQhrCYTv+J606cGC2vuQ==",
"dev": true,
"requires": {
@@ -21608,7 +21574,7 @@
"dependencies": {
"source-map": {
"version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "resolved": false,
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
}
@@ -21616,7 +21582,7 @@
},
"istanbul-reports": {
"version": "1.5.0",
- "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.5.0.tgz",
+ "resolved": false,
"integrity": "sha512-HeZG0WHretI9FXBni5wZ9DOgNziqDCEwetxnme5k1Vv5e81uTqcsy3fMH99gXGDGKr1ea87TyGseDMa2h4HEUA==",
"dev": true,
"requires": {
@@ -21625,13 +21591,13 @@
},
"json-parse-better-errors": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
+ "resolved": false,
"integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
"dev": true
},
"kind-of": {
"version": "3.2.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "resolved": false,
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
"dev": true,
"requires": {
@@ -21640,14 +21606,14 @@
},
"lazy-cache": {
"version": "1.0.4",
- "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
+ "resolved": false,
"integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=",
"dev": true,
"optional": true
},
"lcid": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
"dev": true,
"requires": {
@@ -21656,7 +21622,7 @@
},
"locate-path": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
"dev": true,
"requires": {
@@ -21666,7 +21632,7 @@
"dependencies": {
"path-exists": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
"dev": true
}
@@ -21674,13 +21640,13 @@
},
"longest": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
+ "resolved": false,
"integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=",
"dev": true
},
"lru-cache": {
"version": "4.1.3",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz",
+ "resolved": false,
"integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==",
"dev": true,
"requires": {
@@ -21690,7 +21656,7 @@
},
"make-dir": {
"version": "1.3.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
+ "resolved": false,
"integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
"dev": true,
"requires": {
@@ -21699,7 +21665,7 @@
"dependencies": {
"pify": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
"dev": true
}
@@ -21707,7 +21673,7 @@
},
"md5-hex": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-2.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-0FiOnxx0lUSS7NJKwKxs6ZfZLjM=",
"dev": true,
"requires": {
@@ -21716,13 +21682,13 @@
},
"md5-o-matic": {
"version": "0.1.1",
- "resolved": "https://registry.npmjs.org/md5-o-matic/-/md5-o-matic-0.1.1.tgz",
+ "resolved": false,
"integrity": "sha1-givM1l4RfFFPqxdrJZRdVBAKA8M=",
"dev": true
},
"mem": {
"version": "1.1.0",
- "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz",
+ "resolved": false,
"integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=",
"dev": true,
"requires": {
@@ -21731,7 +21697,7 @@
},
"merge-source-map": {
"version": "1.1.0",
- "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz",
+ "resolved": false,
"integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==",
"dev": true,
"requires": {
@@ -21740,7 +21706,7 @@
"dependencies": {
"source-map": {
"version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "resolved": false,
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
}
@@ -21748,13 +21714,13 @@
},
"mimic-fn": {
"version": "1.2.0",
- "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
+ "resolved": false,
"integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
"dev": true
},
"minimatch": {
"version": "3.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "resolved": false,
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"requires": {
@@ -21763,13 +21729,13 @@
},
"minimist": {
"version": "0.0.8",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+ "resolved": false,
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true
},
"mkdirp": {
"version": "0.5.1",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+ "resolved": false,
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true,
"requires": {
@@ -21778,13 +21744,13 @@
},
"ms": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true
},
"normalize-package-data": {
"version": "2.4.0",
- "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
+ "resolved": false,
"integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==",
"dev": true,
"requires": {
@@ -21796,7 +21762,7 @@
},
"npm-run-path": {
"version": "2.0.2",
- "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
+ "resolved": false,
"integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
"dev": true,
"requires": {
@@ -21805,13 +21771,13 @@
},
"number-is-nan": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+ "resolved": false,
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
"dev": true
},
"once": {
"version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "resolved": false,
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"requires": {
@@ -21820,7 +21786,7 @@
},
"optimist": {
"version": "0.6.1",
- "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
+ "resolved": false,
"integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
"dev": true,
"requires": {
@@ -21830,13 +21796,13 @@
},
"os-homedir": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+ "resolved": false,
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
"dev": true
},
"os-locale": {
"version": "2.1.0",
- "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz",
+ "resolved": false,
"integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==",
"dev": true,
"requires": {
@@ -21847,13 +21813,13 @@
},
"p-finally": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
"dev": true
},
"p-limit": {
"version": "1.2.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz",
+ "resolved": false,
"integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==",
"dev": true,
"requires": {
@@ -21862,7 +21828,7 @@
},
"p-locate": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
"dev": true,
"requires": {
@@ -21871,25 +21837,25 @@
},
"p-try": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
"dev": true
},
"path-is-absolute": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "resolved": false,
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"dev": true
},
"path-key": {
"version": "2.0.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+ "resolved": false,
"integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
"dev": true
},
"pkg-dir": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=",
"dev": true,
"requires": {
@@ -21898,37 +21864,37 @@
},
"pseudomap": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+ "resolved": false,
"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
"dev": true
},
"repeat-string": {
"version": "1.6.1",
- "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+ "resolved": false,
"integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
"dev": true
},
"require-directory": {
"version": "2.1.1",
- "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "resolved": false,
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
"dev": true
},
"require-main-filename": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
+ "resolved": false,
"integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=",
"dev": true
},
"resolve-from": {
"version": "4.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "resolved": false,
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
"dev": true
},
"right-align": {
"version": "0.1.3",
- "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
+ "resolved": false,
"integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=",
"dev": true,
"optional": true,
@@ -21938,7 +21904,7 @@
},
"rimraf": {
"version": "2.6.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
+ "resolved": false,
"integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
"dev": true,
"requires": {
@@ -21947,19 +21913,19 @@
},
"semver": {
"version": "5.5.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
+ "resolved": false,
"integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==",
"dev": true
},
"set-blocking": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
"dev": true
},
"shebang-command": {
"version": "1.2.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+ "resolved": false,
"integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
"dev": true,
"requires": {
@@ -21968,32 +21934,32 @@
},
"shebang-regex": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
"dev": true
},
"signal-exit": {
"version": "3.0.2",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+ "resolved": false,
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
"dev": true
},
"slide": {
"version": "1.1.6",
- "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz",
+ "resolved": false,
"integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=",
"dev": true
},
"source-map": {
"version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "resolved": false,
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
"dev": true,
"optional": true
},
"spawn-wrap": {
"version": "1.4.2",
- "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.2.tgz",
+ "resolved": false,
"integrity": "sha512-vMwR3OmmDhnxCVxM8M+xO/FtIp6Ju/mNaDfCMMW7FDcLRTPFWUswec4LXJHTJE2hwTI9O0YBfygu4DalFl7Ylg==",
"dev": true,
"requires": {
@@ -22007,7 +21973,7 @@
},
"spdx-correct": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz",
+ "resolved": false,
"integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==",
"dev": true,
"requires": {
@@ -22017,13 +21983,13 @@
},
"spdx-exceptions": {
"version": "2.1.0",
- "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz",
+ "resolved": false,
"integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==",
"dev": true
},
"spdx-expression-parse": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
+ "resolved": false,
"integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
"dev": true,
"requires": {
@@ -22033,13 +21999,13 @@
},
"spdx-license-ids": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz",
+ "resolved": false,
"integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==",
"dev": true
},
"string-width": {
"version": "2.1.1",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+ "resolved": false,
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
"dev": true,
"requires": {
@@ -22049,7 +22015,7 @@
},
"strip-ansi": {
"version": "4.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
"dev": true,
"requires": {
@@ -22058,13 +22024,13 @@
},
"strip-eof": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
"dev": true
},
"supports-color": {
"version": "5.4.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
+ "resolved": false,
"integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
"dev": true,
"requires": {
@@ -22073,7 +22039,7 @@
},
"test-exclude": {
"version": "4.2.2",
- "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.2.2.tgz",
+ "resolved": false,
"integrity": "sha512-2kTGf+3tykCfrWVREgyTR0bmVO0afE6i7zVXi/m+bZZ8ujV89Aulxdcdv32yH+unVFg3Y5o6GA8IzsHnGQuFgQ==",
"dev": true,
"requires": {
@@ -22085,7 +22051,7 @@
"dependencies": {
"load-json-file": {
"version": "4.0.0",
- "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=",
"dev": true,
"requires": {
@@ -22097,7 +22063,7 @@
},
"parse-json": {
"version": "4.0.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
"dev": true,
"requires": {
@@ -22107,7 +22073,7 @@
},
"path-type": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
+ "resolved": false,
"integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
"dev": true,
"requires": {
@@ -22116,13 +22082,13 @@
},
"pify": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
"dev": true
},
"read-pkg": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=",
"dev": true,
"requires": {
@@ -22133,7 +22099,7 @@
},
"read-pkg-up": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=",
"dev": true,
"requires": {
@@ -22143,7 +22109,7 @@
},
"strip-bom": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
"dev": true
}
@@ -22151,7 +22117,7 @@
},
"uglify-js": {
"version": "2.8.29",
- "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",
+ "resolved": false,
"integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=",
"dev": true,
"optional": true,
@@ -22163,7 +22129,7 @@
"dependencies": {
"yargs": {
"version": "3.10.0",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
+ "resolved": false,
"integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
"dev": true,
"optional": true,
@@ -22178,14 +22144,14 @@
},
"uglify-to-browserify": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
+ "resolved": false,
"integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=",
"dev": true,
"optional": true
},
"validate-npm-package-license": {
"version": "3.0.3",
- "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz",
+ "resolved": false,
"integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==",
"dev": true,
"requires": {
@@ -22195,7 +22161,7 @@
},
"which": {
"version": "1.3.1",
- "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+ "resolved": false,
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
"dev": true,
"requires": {
@@ -22204,26 +22170,26 @@
},
"which-module": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
"dev": true
},
"window-size": {
"version": "0.1.0",
- "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
+ "resolved": false,
"integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=",
"dev": true,
"optional": true
},
"wordwrap": {
"version": "0.0.3",
- "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
+ "resolved": false,
"integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=",
"dev": true
},
"wrap-ansi": {
"version": "2.1.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
+ "resolved": false,
"integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
"dev": true,
"requires": {
@@ -22233,13 +22199,13 @@
"dependencies": {
"ansi-regex": {
"version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "resolved": false,
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
"dev": true
},
"is-fullwidth-code-point": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+ "resolved": false,
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"dev": true,
"requires": {
@@ -22248,7 +22214,7 @@
},
"string-width": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "resolved": false,
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"dev": true,
"requires": {
@@ -22259,7 +22225,7 @@
},
"strip-ansi": {
"version": "3.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "resolved": false,
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"requires": {
@@ -22270,13 +22236,13 @@
},
"wrappy": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "resolved": false,
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true
},
"write-file-atomic": {
"version": "1.3.4",
- "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz",
+ "resolved": false,
"integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=",
"dev": true,
"requires": {
@@ -22287,19 +22253,19 @@
},
"y18n": {
"version": "3.2.1",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
+ "resolved": false,
"integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=",
"dev": true
},
"yallist": {
"version": "2.1.2",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
+ "resolved": false,
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
"dev": true
},
"yargs": {
"version": "11.1.0",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz",
+ "resolved": false,
"integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==",
"dev": true,
"requires": {
@@ -22319,13 +22285,13 @@
"dependencies": {
"camelcase": {
"version": "4.1.0",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
+ "resolved": false,
"integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
"dev": true
},
"cliui": {
"version": "4.1.0",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
+ "resolved": false,
"integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==",
"dev": true,
"requires": {
@@ -22336,7 +22302,7 @@
},
"yargs-parser": {
"version": "9.0.2",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz",
+ "resolved": false,
"integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=",
"dev": true,
"requires": {
@@ -22347,7 +22313,7 @@
},
"yargs-parser": {
"version": "9.0.2",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz",
+ "resolved": false,
"integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=",
"dev": true,
"requires": {
@@ -22356,7 +22322,7 @@
"dependencies": {
"camelcase": {
"version": "4.1.0",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
+ "resolved": false,
"integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
"dev": true
}
@@ -25723,26 +25689,6 @@
"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",
@@ -27183,6 +27129,14 @@
"nearley": "^2.7.10"
}
},
+ "rtcpeerconnection-shim": {
+ "version": "1.2.13",
+ "resolved": "https://registry.npmjs.org/rtcpeerconnection-shim/-/rtcpeerconnection-shim-1.2.13.tgz",
+ "integrity": "sha512-Xz4zQLZNs9lFBvqbaHGIjLWtyZ1V82ec5r+WNEo7NlIx3zF5M3ytn9mkkfYeZmpE032cNg3Vvf0rP8kNXUNd9w==",
+ "requires": {
+ "sdp": "^2.6.0"
+ }
+ },
"run-async": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
@@ -27501,6 +27455,11 @@
}
}
},
+ "sdp": {
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/sdp/-/sdp-2.8.0.tgz",
+ "integrity": "sha512-wRSES07rAwKWAR7aev9UuClT7kdf9ZTdeUK5gTgHue9vlhs19Fbm3ccNEGJO4y2IitH4/JzS4sdzyPl6H2KQLw=="
+ },
"secp256k1": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-3.4.0.tgz",
@@ -30206,8 +30165,7 @@
"text-encoding": {
"version": "0.6.4",
"resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz",
- "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=",
- "dev": true
+ "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk="
},
"text-table": {
"version": "0.2.0",
@@ -30654,6 +30612,11 @@
}
}
},
+ "ts-custom-error": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ts-custom-error/-/ts-custom-error-2.2.1.tgz",
+ "integrity": "sha512-lHKZtU+PXkVuap6nlFZybIAFLUO8B3jbCs1VynBL8AUSAHfeG6HpztcBTDRp5I+fN5820N9kGg+eTIvr+le2yg=="
+ },
"tslib": {
"version": "1.9.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.2.tgz",
@@ -33134,6 +33097,15 @@
}
}
},
+ "webrtc-adapter": {
+ "version": "6.3.2",
+ "resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-6.3.2.tgz",
+ "integrity": "sha512-7pFMXpZCka7ScIQyk8Wo+fOr3OlKLtGd6YHqkHVT74zerpY2Siyds8sxsmkE0bNqsi/J1b0vDzN7WpB34dQzAA==",
+ "requires": {
+ "rtcpeerconnection-shim": "^1.2.10",
+ "sdp": "^2.7.0"
+ }
+ },
"websocket": {
"version": "1.0.26",
"resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.26.tgz",
diff --git a/package.json b/package.json
index 81ab01120..e4d1246a3 100644
--- a/package.json
+++ b/package.json
@@ -74,7 +74,8 @@
]
},
"dependencies": {
- "@material-ui/core": "^1.0.0",
+ "@material-ui/core": "1.0.0",
+ "@zxing/library": "^0.7.0",
"abi-decoder": "^1.0.9",
"asmcrypto.js": "0.22.0",
"async": "^2.5.0",
@@ -97,6 +98,7 @@
"debounce-stream": "^2.0.0",
"deep-extend": "^0.5.1",
"detect-node": "^2.0.3",
+ "detectrtc": "^1.3.6",
"disc": "^1.3.2",
"dnode": "^1.2.2",
"end-of-stream": "^1.1.0",
@@ -105,11 +107,11 @@
"eth-bin-to-ops": "^1.0.1",
"eth-block-tracker": "^4.0.1",
"eth-contract-metadata": "github:MetaMask/eth-contract-metadata#master",
- "eth-json-rpc-filters": "^2.1.1",
"eth-json-rpc-middleware": "^2.4.0",
"eth-keyring-controller": "^3.1.4",
"eth-ens-namehash": "^2.0.8",
- "eth-hd-keyring": "^2.0.0",
+ "eth-hd-keyring": "^1.2.2",
+ "eth-json-rpc-filters": "^1.2.6",
"eth-json-rpc-infura": "^3.0.0",
"eth-method-registry": "^1.0.0",
"eth-phishing-detect": "^1.1.4",
@@ -209,6 +211,7 @@
"vreme": "^3.0.2",
"web3": "^0.20.1",
"web3-stream-provider": "^3.0.1",
+ "webrtc-adapter": "^6.3.0",
"xtend": "^4.0.1"
},
"devDependencies": {
@@ -247,7 +250,7 @@
"eslint-plugin-mocha": "^5.0.0",
"eslint-plugin-react": "^7.4.0",
"eth-json-rpc-middleware": "^1.6.0",
- "eth-keyring-controller": "^4.0.0",
+ "eth-keyring-controller": "^3.3.1",
"file-loader": "^1.1.11",
"fs-extra": "^6.0.1",
"fs-promise": "^2.0.3",
diff --git a/test/integration/lib/tx-list-items.js b/test/integration/lib/tx-list-items.js
index b7aca44d5..9075efe03 100644
--- a/test/integration/lib/tx-list-items.js
+++ b/test/integration/lib/tx-list-items.js
@@ -14,6 +14,11 @@ QUnit.test('renders list items successfully', (assert) => {
})
})
+global.ethQuery = global.ethQuery || {}
+global.ethQuery.getTransactionCount = (_, cb) => {
+ cb(null, '0x3')
+}
+
async function runTxListItemsTest (assert, done) {
console.log('*** start runTxListItemsTest')
const selectState = await queryAsync($, 'select')
diff --git a/test/unit/app/controllers/detect-tokens-test.js b/test/unit/app/controllers/detect-tokens-test.js
index 4ee73599d..d659d51df 100644
--- a/test/unit/app/controllers/detect-tokens-test.js
+++ b/test/unit/app/controllers/detect-tokens-test.js
@@ -1,16 +1,14 @@
const assert = require('assert')
-const sinon = require('sinon')
const nock = require('nock')
+const sinon = require('sinon')
const ObservableStore = require('obs-store')
const DetectTokensController = require('../../../../app/scripts/controllers/detect-tokens')
const NetworkController = require('../../../../app/scripts/controllers/network/network')
const PreferencesController = require('../../../../app/scripts/controllers/preferences')
describe('DetectTokensController', () => {
-
- let clock, network, preferences, controller, keyringMemStore
-
const sandbox = sinon.createSandbox()
+ let clock, keyringMemStore, network, preferences, controller
const noop = () => {}
@@ -20,13 +18,14 @@ describe('DetectTokensController', () => {
beforeEach(async () => {
+
nock('https://api.infura.io')
.get(/.*/)
.reply(200)
keyringMemStore = new ObservableStore({ isUnlocked: false})
network = new NetworkController()
- preferences = new PreferencesController()
+ preferences = new PreferencesController({ network })
controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore })
network.initializeProvider(networkControllerProviderConfig)
@@ -34,8 +33,8 @@ describe('DetectTokensController', () => {
})
after(() => {
- sandbox.restore()
- nock.cleanAll()
+ sandbox.restore()
+ nock.cleanAll()
})
it('should poll on correct interval', async () => {
@@ -50,7 +49,7 @@ describe('DetectTokensController', () => {
const network = new NetworkController()
network.initializeProvider(networkControllerProviderConfig)
network.setProviderType('mainnet')
- const preferences = new PreferencesController()
+ const preferences = new PreferencesController({ network })
const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore })
controller.isOpen = true
controller.isUnlocked = true
@@ -68,7 +67,8 @@ describe('DetectTokensController', () => {
})
it('should not check tokens while in test network', async () => {
- network.setProviderType('rinkeby')
+ // network.setProviderType('rinkeby')
+ // const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore })
controller.isOpen = true
controller.isUnlocked = true
@@ -81,7 +81,8 @@ describe('DetectTokensController', () => {
})
it('should only check and add tokens while in main network', async () => {
- network.setProviderType('mainnet')
+ // network.setProviderType('mainnet')
+ const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore })
controller.isOpen = true
controller.isUnlocked = true
@@ -97,7 +98,8 @@ describe('DetectTokensController', () => {
})
it('should not detect same token while in main network', async () => {
- network.setProviderType('mainnet')
+ // network.setProviderType('mainnet')
+ preferences.addToken('0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', 'J8T', 8)
const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore })
controller.isOpen = true
controller.isUnlocked = true
@@ -114,7 +116,8 @@ describe('DetectTokensController', () => {
})
it('should trigger detect new tokens when change address', async () => {
- network.setProviderType('mainnet')
+ // network.setProviderType('mainnet')
+ // const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore })
controller.isOpen = true
controller.isUnlocked = true
var stub = sandbox.stub(controller, 'detectNewTokens')
@@ -123,7 +126,8 @@ describe('DetectTokensController', () => {
})
it('should trigger detect new tokens when submit password', async () => {
- network.setProviderType('mainnet')
+ // network.setProviderType('mainnet')
+ // const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore })
controller.isOpen = true
controller.selectedAddress = '0x0'
var stub = sandbox.stub(controller, 'detectNewTokens')
@@ -132,7 +136,8 @@ describe('DetectTokensController', () => {
})
it('should not trigger detect new tokens when not open or not unlocked', async () => {
- network.setProviderType('mainnet')
+ // network.setProviderType('mainnet')
+ // const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore })
controller.isOpen = true
controller.isUnlocked = false
var stub = sandbox.stub(controller, 'detectTokenBalance')
@@ -143,4 +148,4 @@ describe('DetectTokensController', () => {
clock.tick(180000)
sandbox.assert.notCalled(stub)
})
-})
+}) \ No newline at end of file
diff --git a/test/unit/app/controllers/preferences-controller-test.js b/test/unit/app/controllers/preferences-controller-test.js
index e055500b1..9b2c846bd 100644
--- a/test/unit/app/controllers/preferences-controller-test.js
+++ b/test/unit/app/controllers/preferences-controller-test.js
@@ -1,11 +1,14 @@
const assert = require('assert')
+const ObservableStore = require('obs-store')
const PreferencesController = require('../../../../app/scripts/controllers/preferences')
describe('preferences controller', function () {
let preferencesController
+ let network
beforeEach(() => {
- preferencesController = new PreferencesController()
+ network = {providerStore: new ObservableStore({ type: 'mainnet' })}
+ preferencesController = new PreferencesController({ network })
})
describe('setAddresses', function () {
@@ -28,6 +31,20 @@ describe('preferences controller', function () {
})
})
+ it('should create account tokens for each account in the store', function () {
+ preferencesController.setAddresses([
+ '0xda22le',
+ '0x7e57e2',
+ ])
+
+ const accountTokens = preferencesController.store.getState().accountTokens
+
+ assert.deepEqual(accountTokens, {
+ '0xda22le': {},
+ '0x7e57e2': {},
+ })
+ })
+
it('should replace its list of addresses', function () {
preferencesController.setAddresses([
'0xda22le',
@@ -64,6 +81,17 @@ describe('preferences controller', function () {
assert.equal(preferencesController.store.getState().identities['0xda22le'], undefined)
})
+ it('should remove an address from state and respective tokens', function () {
+ preferencesController.setAddresses([
+ '0xda22le',
+ '0x7e57e2',
+ ])
+
+ preferencesController.removeAddress('0xda22le')
+
+ assert.equal(preferencesController.store.getState().accountTokens['0xda22le'], undefined)
+ })
+
it('should switch accounts if the selected address is removed', function () {
preferencesController.setAddresses([
'0xda22le',
@@ -158,6 +186,42 @@ describe('preferences controller', function () {
await preferencesController.addToken(address, symbol, decimals)
assert.equal(preferencesController.getTokens().length, 1, 'one token added for 2nd address')
})
+
+ it('should add token per account', async function () {
+ const addressFirst = '0xabcdef1234567'
+ const addressSecond = '0xabcdef1234568'
+ const symbolFirst = 'ABBR'
+ const symbolSecond = 'ABBB'
+ const decimals = 5
+
+ await preferencesController.setSelectedAddress('0x7e57e2')
+ await preferencesController.addToken(addressFirst, symbolFirst, decimals)
+ const tokensFirstAddress = preferencesController.getTokens()
+
+ await preferencesController.setSelectedAddress('0xda22le')
+ await preferencesController.addToken(addressSecond, symbolSecond, decimals)
+ const tokensSeconAddress = preferencesController.getTokens()
+
+ assert.notEqual(tokensFirstAddress, tokensSeconAddress, 'add different tokens for two account and tokens are equal')
+ })
+
+ it('should add token per network', async function () {
+ const addressFirst = '0xabcdef1234567'
+ const addressSecond = '0xabcdef1234568'
+ const symbolFirst = 'ABBR'
+ const symbolSecond = 'ABBB'
+ const decimals = 5
+
+ network.providerStore.updateState({ type: 'mainnet' })
+ await preferencesController.addToken(addressFirst, symbolFirst, decimals)
+ const tokensFirstAddress = preferencesController.getTokens()
+
+ network.providerStore.updateState({ type: 'rinkeby' })
+ await preferencesController.addToken(addressSecond, symbolSecond, decimals)
+ const tokensSeconAddress = preferencesController.getTokens()
+
+ assert.notEqual(tokensFirstAddress, tokensSeconAddress, 'add different tokens for two networks and tokens are equal')
+ })
})
describe('removeToken', function () {
@@ -182,6 +246,98 @@ describe('preferences controller', function () {
const [token1] = tokens
assert.deepEqual(token1, {address: '0xb', symbol: 'B', decimals: 5})
})
+
+ it('should remove a token from its state on corresponding address', async function () {
+ await preferencesController.setSelectedAddress('0x7e57e2')
+ await preferencesController.addToken('0xa', 'A', 4)
+ await preferencesController.addToken('0xb', 'B', 5)
+ await preferencesController.setSelectedAddress('0x7e57e3')
+ await preferencesController.addToken('0xa', 'A', 4)
+ await preferencesController.addToken('0xb', 'B', 5)
+ const initialTokensSecond = preferencesController.getTokens()
+ await preferencesController.setSelectedAddress('0x7e57e2')
+ await preferencesController.removeToken('0xa')
+
+ const tokensFirst = preferencesController.getTokens()
+ assert.equal(tokensFirst.length, 1, 'one token removed in account')
+
+ const [token1] = tokensFirst
+ assert.deepEqual(token1, {address: '0xb', symbol: 'B', decimals: 5})
+
+ await preferencesController.setSelectedAddress('0x7e57e3')
+ const tokensSecond = preferencesController.getTokens()
+ assert.deepEqual(tokensSecond, initialTokensSecond, 'token deleted for account')
+ })
+
+ it('should remove a token from its state on corresponding network', async function () {
+ network.providerStore.updateState({ type: 'mainnet' })
+ await preferencesController.addToken('0xa', 'A', 4)
+ await preferencesController.addToken('0xb', 'B', 5)
+ network.providerStore.updateState({ type: 'rinkeby' })
+ await preferencesController.addToken('0xa', 'A', 4)
+ await preferencesController.addToken('0xb', 'B', 5)
+ const initialTokensSecond = preferencesController.getTokens()
+ network.providerStore.updateState({ type: 'mainnet' })
+ await preferencesController.removeToken('0xa')
+
+ const tokensFirst = preferencesController.getTokens()
+ assert.equal(tokensFirst.length, 1, 'one token removed in network')
+
+ const [token1] = tokensFirst
+ assert.deepEqual(token1, {address: '0xb', symbol: 'B', decimals: 5})
+
+ network.providerStore.updateState({ type: 'rinkeby' })
+ const tokensSecond = preferencesController.getTokens()
+ assert.deepEqual(tokensSecond, initialTokensSecond, 'token deleted for network')
+ })
+ })
+
+ describe('on setSelectedAddress', function () {
+ it('should update tokens from its state on corresponding address', async function () {
+ await preferencesController.setSelectedAddress('0x7e57e2')
+ await preferencesController.addToken('0xa', 'A', 4)
+ await preferencesController.addToken('0xb', 'B', 5)
+ await preferencesController.setSelectedAddress('0x7e57e3')
+ await preferencesController.addToken('0xa', 'C', 4)
+ await preferencesController.addToken('0xb', 'D', 5)
+
+ await preferencesController.setSelectedAddress('0x7e57e2')
+ const initialTokensFirst = preferencesController.getTokens()
+ await preferencesController.setSelectedAddress('0x7e57e3')
+ const initialTokensSecond = preferencesController.getTokens()
+
+ assert.notDeepEqual(initialTokensFirst, initialTokensSecond, 'tokens not equal for different accounts and tokens')
+
+ await preferencesController.setSelectedAddress('0x7e57e2')
+ const tokensFirst = preferencesController.getTokens()
+ await preferencesController.setSelectedAddress('0x7e57e3')
+ const tokensSecond = preferencesController.getTokens()
+
+ assert.deepEqual(tokensFirst, initialTokensFirst, 'tokens equal for same account')
+ assert.deepEqual(tokensSecond, initialTokensSecond, 'tokens equal for same account')
+ })
+ })
+
+ describe('on updateStateNetworkType', function () {
+ it('should remove a token from its state on corresponding network', async function () {
+ network.providerStore.updateState({ type: 'mainnet' })
+ await preferencesController.addToken('0xa', 'A', 4)
+ await preferencesController.addToken('0xb', 'B', 5)
+ const initialTokensFirst = preferencesController.getTokens()
+ network.providerStore.updateState({ type: 'rinkeby' })
+ await preferencesController.addToken('0xa', 'C', 4)
+ await preferencesController.addToken('0xb', 'D', 5)
+ const initialTokensSecond = preferencesController.getTokens()
+
+ assert.notDeepEqual(initialTokensFirst, initialTokensSecond, 'tokens not equal for different networks and tokens')
+
+ network.providerStore.updateState({ type: 'mainnet' })
+ const tokensFirst = preferencesController.getTokens()
+ network.providerStore.updateState({ type: 'rinkeby' })
+ const tokensSecond = preferencesController.getTokens()
+ assert.deepEqual(tokensFirst, initialTokensFirst, 'tokens equal for same network')
+ assert.deepEqual(tokensSecond, initialTokensSecond, 'tokens equal for same network')
+ })
})
})
diff --git a/test/unit/migrations/028-test.js b/test/unit/migrations/028-test.js
new file mode 100644
index 000000000..a9c7dcdf1
--- /dev/null
+++ b/test/unit/migrations/028-test.js
@@ -0,0 +1,46 @@
+const assert = require('assert')
+const migration28 = require('../../../app/scripts/migrations/028')
+
+const oldStorage = {
+ 'meta': {},
+ 'data': {
+ 'PreferencesController': {
+ 'tokens': [{address: '0xa', symbol: 'A', decimals: 4}, {address: '0xb', symbol: 'B', decimals: 4}],
+ 'identities': {
+ '0x6d14': {},
+ '0x3695': {},
+ },
+ },
+ },
+}
+
+describe('migration #28', () => {
+ it('should add corresponding tokens to accountTokens', (done) => {
+ migration28.migrate(oldStorage)
+ .then((newStorage) => {
+ const newTokens = newStorage.data.PreferencesController.tokens
+ const newAccountTokens = newStorage.data.PreferencesController.accountTokens
+
+ const testTokens = [{address: '0xa', symbol: 'A', decimals: 4}, {address: '0xb', symbol: 'B', decimals: 4}]
+ assert.equal(newTokens.length, 0, 'tokens is expected to have the length of 0')
+ assert.equal(newAccountTokens['0x6d14']['mainnet'].length, 2, 'tokens for address is expected to have the length of 2')
+ assert.equal(newAccountTokens['0x3695']['mainnet'].length, 2, 'tokens for address is expected to have the length of 2')
+ assert.equal(Object.keys(newAccountTokens).length, 2, 'account tokens should be created for all identities')
+ assert.deepEqual(newAccountTokens['0x6d14']['mainnet'], testTokens, 'tokens for address should be the same than before')
+ assert.deepEqual(newAccountTokens['0x3695']['mainnet'], testTokens, 'tokens for address should be the same than before')
+ done()
+ })
+ .catch(done)
+ })
+
+ it('should successfully migrate first time state', (done) => {
+ migration28.migrate({
+ meta: {},
+ data: require('../../../app/scripts/first-time-state'),
+ })
+ .then((migratedData) => {
+ assert.equal(migratedData.meta.version, migration28.version)
+ done()
+ }).catch(done)
+ })
+})
diff --git a/ui/app/actions.js b/ui/app/actions.js
index 7a8d9667d..bd5d25327 100644
--- a/ui/app/actions.js
+++ b/ui/app/actions.js
@@ -12,6 +12,7 @@ const { fetchLocale } = require('../i18n-helper')
const log = require('loglevel')
const { ENVIRONMENT_TYPE_NOTIFICATION } = require('../../app/scripts/lib/enums')
const { hasUnconfirmedTransactions } = require('./helpers/confirm-transaction/util')
+const WebcamUtils = require('../lib/webcam-utils')
var actions = {
_setBackgroundConnection: _setBackgroundConnection,
@@ -33,6 +34,8 @@ var actions = {
ALERT_CLOSE: 'UI_ALERT_CLOSE',
showAlert: showAlert,
hideAlert: hideAlert,
+ QR_CODE_DETECTED: 'UI_QR_CODE_DETECTED',
+ qrCodeDetected,
// network dropdown open
NETWORK_DROPDOWN_OPEN: 'UI_NETWORK_DROPDOWN_OPEN',
NETWORK_DROPDOWN_CLOSE: 'UI_NETWORK_DROPDOWN_CLOSE',
@@ -125,7 +128,8 @@ var actions = {
SHOW_CONF_TX_PAGE: 'SHOW_CONF_TX_PAGE',
SHOW_CONF_MSG_PAGE: 'SHOW_CONF_MSG_PAGE',
SET_CURRENT_FIAT: 'SET_CURRENT_FIAT',
- setCurrentCurrency: setCurrentCurrency,
+ showQrScanner,
+ setCurrentCurrency,
setCurrentAccountTab,
// account detail screen
SHOW_SEND_PAGE: 'SHOW_SEND_PAGE',
@@ -143,6 +147,8 @@ var actions = {
exportAccountComplete,
SET_ACCOUNT_LABEL: 'SET_ACCOUNT_LABEL',
setAccountLabel,
+ updateNetworkNonce,
+ SET_NETWORK_NONCE: 'SET_NETWORK_NONCE',
// tx conf screen
COMPLETED_TX: 'COMPLETED_TX',
TRANSACTION_ERROR: 'TRANSACTION_ERROR',
@@ -721,6 +727,28 @@ function showInfoPage () {
}
}
+function showQrScanner (ROUTE) {
+ return (dispatch, getState) => {
+ return WebcamUtils.checkStatus()
+ .then(status => {
+ if (!status.environmentReady) {
+ // We need to switch to fullscreen mode to ask for permission
+ global.platform.openExtensionInBrowser(`${ROUTE}`, `scan=true`)
+ } else {
+ dispatch(actions.showModal({
+ name: 'QR_SCANNER',
+ }))
+ }
+ }).catch(e => {
+ dispatch(actions.showModal({
+ name: 'QR_SCANNER',
+ error: true,
+ errorType: e.type,
+ }))
+ })
+ }
+}
+
function setCurrentCurrency (currencyCode) {
return (dispatch) => {
dispatch(actions.showLoadingIndication())
@@ -1483,11 +1511,12 @@ function showAccountDetail (address) {
return (dispatch) => {
dispatch(actions.showLoadingIndication())
log.debug(`background.setSelectedAddress`)
- background.setSelectedAddress(address, (err) => {
+ background.setSelectedAddress(address, (err, tokens) => {
dispatch(actions.hideLoadingIndication())
if (err) {
return dispatch(actions.displayWarning(err.message))
}
+ dispatch(updateTokens(tokens))
dispatch({
type: actions.SHOW_ACCOUNT_DETAIL,
value: address,
@@ -1806,6 +1835,17 @@ function hideAlert () {
}
}
+/**
+ * This action will receive two types of values via qrCodeData
+ * an object with the following structure {type, values}
+ * or null (used to clear the previous value)
+ */
+function qrCodeDetected (qrCodeData) {
+ return {
+ type: actions.QR_CODE_DETECTED,
+ value: qrCodeData,
+ }
+}
function showLoadingIndication (message) {
return {
@@ -2115,6 +2155,24 @@ function updateFeatureFlags (updatedFeatureFlags) {
}
}
+function setNetworkNonce (networkNonce) {
+ return {
+ type: actions.SET_NETWORK_NONCE,
+ value: networkNonce,
+ }
+}
+
+function updateNetworkNonce (address) {
+ return (dispatch) => {
+ return new Promise((resolve, reject) => {
+ global.ethQuery.getTransactionCount(address, (err, data) => {
+ dispatch(setNetworkNonce(data))
+ resolve(data)
+ })
+ })
+ }
+}
+
function setMouseUserState (isMouseUser) {
return {
type: actions.SET_MOUSE_USER_STATE,
diff --git a/ui/app/components/ens-input.js b/ui/app/components/ens-input.js
index b9f99b3d1..f538fd555 100644
--- a/ui/app/components/ens-input.js
+++ b/ui/app/components/ens-input.js
@@ -27,6 +27,7 @@ function EnsInput () {
}
EnsInput.prototype.onChange = function (recipient) {
+
const network = this.props.network
const networkHasEnsSupport = getNetworkEnsSupport(network)
@@ -54,6 +55,7 @@ EnsInput.prototype.render = function () {
const opts = extend(props, {
list: 'addresses',
onChange: this.onChange.bind(this),
+ qrScanner: true,
})
return h('div', {
style: { width: '100%', position: 'relative' },
diff --git a/ui/app/components/modals/index.scss b/ui/app/components/modals/index.scss
index e198cca44..0acccf172 100644
--- a/ui/app/components/modals/index.scss
+++ b/ui/app/components/modals/index.scss
@@ -1,5 +1,7 @@
@import './customize-gas/index';
+@import './qr-scanner/index';
+
.modal-container {
width: 100%;
height: 100%;
diff --git a/ui/app/components/modals/modal.js b/ui/app/components/modals/modal.js
index f59825ed1..5dda50e52 100644
--- a/ui/app/components/modals/modal.js
+++ b/ui/app/components/modals/modal.js
@@ -21,6 +21,7 @@ const CustomizeGasModal = require('../customize-gas-modal')
const NotifcationModal = require('./notification-modal')
const ConfirmResetAccount = require('./confirm-reset-account')
const ConfirmRemoveAccount = require('./confirm-remove-account')
+const QRScanner = require('./qr-scanner')
const TransactionConfirmed = require('./transaction-confirmed')
const WelcomeBeta = require('./welcome-beta')
const Notification = require('./notification')
@@ -346,6 +347,18 @@ const MODALS = {
borderRadius: '8px',
},
},
+ QR_SCANNER: {
+ contents: h(QRScanner),
+ mobileModalStyle: {
+ ...modalContainerMobileStyle,
+ },
+ laptopModalStyle: {
+ ...modalContainerLaptopStyle,
+ },
+ contentStyle: {
+ borderRadius: '8px',
+ },
+ },
DEFAULT: {
contents: [],
diff --git a/ui/app/components/modals/qr-scanner/index.js b/ui/app/components/modals/qr-scanner/index.js
new file mode 100644
index 000000000..470dee1f4
--- /dev/null
+++ b/ui/app/components/modals/qr-scanner/index.js
@@ -0,0 +1,2 @@
+import QrScanner from './qr-scanner.container'
+module.exports = QrScanner
diff --git a/ui/app/components/modals/qr-scanner/index.scss b/ui/app/components/modals/qr-scanner/index.scss
new file mode 100644
index 000000000..6fa81d51f
--- /dev/null
+++ b/ui/app/components/modals/qr-scanner/index.scss
@@ -0,0 +1,83 @@
+.qr-scanner {
+ width: 100%;
+ height: 100%;
+ background-color: #fff;
+ display: flex;
+ flex-flow: column;
+ border-radius: 8px;
+
+ &__title {
+ font-size: 1.5rem;
+ font-weight: 500;
+ padding: 16px 0;
+ text-align: center;
+ }
+
+ &__content {
+ padding-left: 20px;
+ padding-right: 20px;
+
+ &__video-wrapper {
+ overflow: hidden;
+ width: 100%;
+ height: 275px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ video {
+ transform: scaleX(-1);
+ width: auto;
+ height: 275px;
+ }
+ }
+ }
+
+ &__status {
+ text-align: center;
+ font-size: 14px;
+ padding: 15px;
+ }
+
+ &__image {
+ font-size: 1.5rem;
+ font-weight: 500;
+ padding: 16px 0 0;
+ text-align: center;
+ }
+
+ &__error {
+ text-align: center;
+ font-size: 16px;
+ padding: 15px;
+ }
+
+ &__footer {
+ padding: 20px;
+ flex-direction: row;
+ display: flex;
+
+ button {
+ margin-right: 15px;
+ }
+
+ button:last-of-type {
+ margin-right: 0;
+ background-color: #009eec;
+ border: none;
+ color: #fff;
+ }
+ }
+
+ &__close::after {
+ content: '\00D7';
+ font-size: 35px;
+ color: #9b9b9b;
+ position: absolute;
+ top: 4px;
+ right: 20px;
+ cursor: pointer;
+ font-weight: 300;
+ }
+}
+
diff --git a/ui/app/components/modals/qr-scanner/qr-scanner.component.js b/ui/app/components/modals/qr-scanner/qr-scanner.component.js
new file mode 100644
index 000000000..cb8d07d83
--- /dev/null
+++ b/ui/app/components/modals/qr-scanner/qr-scanner.component.js
@@ -0,0 +1,216 @@
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import { BrowserQRCodeReader } from '@zxing/library'
+import adapter from 'webrtc-adapter' // eslint-disable-line import/no-nodejs-modules, no-unused-vars
+import Spinner from '../../spinner'
+import WebcamUtils from '../../../../lib/webcam-utils'
+import PageContainerFooter from '../../page-container/page-container-footer/page-container-footer.component'
+
+export default class QrScanner extends Component {
+ static propTypes = {
+ hideModal: PropTypes.func.isRequired,
+ qrCodeDetected: PropTypes.func,
+ scanQrCode: PropTypes.func,
+ error: PropTypes.bool,
+ errorType: PropTypes.string,
+ }
+
+ static contextTypes = {
+ t: PropTypes.func,
+ }
+
+ constructor (props, context) {
+ super(props)
+
+ this.state = {
+ ready: false,
+ msg: context.t('accessingYourCamera'),
+ }
+ this.codeReader = null
+ this.permissionChecker = null
+ this.needsToReinit = false
+
+ // Clear pre-existing qr code data before scanning
+ this.props.qrCodeDetected(null)
+ }
+
+ componentDidMount () {
+ this.initCamera()
+ }
+
+ async checkPermisisions () {
+ const { permissions } = await WebcamUtils.checkStatus()
+ if (permissions) {
+ clearTimeout(this.permissionChecker)
+ // Let the video stream load first...
+ setTimeout(_ => {
+ this.setState({
+ ready: true,
+ msg: this.context.t('scanInstructions'),
+ })
+ if (this.needsToReinit) {
+ this.initCamera()
+ this.needsToReinit = false
+ }
+ }, 2000)
+ } else {
+ // Keep checking for permissions
+ this.permissionChecker = setTimeout(_ => {
+ this.checkPermisisions()
+ }, 1000)
+ }
+ }
+
+ componentWillUnmount () {
+ clearTimeout(this.permissionChecker)
+ if (this.codeReader) {
+ this.codeReader.reset()
+ }
+ }
+
+ initCamera () {
+ this.codeReader = new BrowserQRCodeReader()
+ this.codeReader.getVideoInputDevices()
+ .then(videoInputDevices => {
+ clearTimeout(this.permissionChecker)
+ this.checkPermisisions()
+ this.codeReader.decodeFromInputVideoDevice(undefined, 'video')
+ .then(content => {
+ const result = this.parseContent(content.text)
+ if (result.type !== 'unknown') {
+ this.props.qrCodeDetected(result)
+ this.stopAndClose()
+ } else {
+ this.setState({msg: this.context.t('unknownQrCode')})
+ }
+ })
+ .catch(err => {
+ if (err && err.name === 'NotAllowedError') {
+ this.setState({msg: this.context.t('youNeedToAllowCameraAccess')})
+ clearTimeout(this.permissionChecker)
+ this.needsToReinit = true
+ this.checkPermisisions()
+ }
+ })
+ }).catch(err => {
+ console.error('[QR-SCANNER]: getVideoInputDevices threw an exception: ', err)
+ })
+ }
+
+ parseContent (content) {
+ let type = 'unknown'
+ let values = {}
+
+ // Here we could add more cases
+ // To parse other type of links
+ // For ex. EIP-681 (https://eips.ethereum.org/EIPS/eip-681)
+
+
+ // Ethereum address links - fox ex. ethereum:0x.....1111
+ if (content.split('ethereum:').length > 1) {
+
+ type = 'address'
+ values = {'address': content.split('ethereum:')[1] }
+
+ // Regular ethereum addresses - fox ex. 0x.....1111
+ } else if (content.substring(0, 2).toLowerCase() === '0x') {
+
+ type = 'address'
+ values = {'address': content }
+
+ }
+ return {type, values}
+ }
+
+
+ stopAndClose = () => {
+ if (this.codeReader) {
+ this.codeReader.reset()
+ }
+ this.setState({ ready: false })
+ this.props.hideModal()
+ }
+
+ tryAgain = () => {
+ // close the modal
+ this.stopAndClose()
+ // wait for the animation and try again
+ setTimeout(_ => {
+ this.props.scanQrCode()
+ }, 1000)
+ }
+
+ renderVideo () {
+ return (
+ <div className={'qr-scanner__content__video-wrapper'}>
+ <video
+ id="video"
+ style={{
+ display: this.state.ready ? 'block' : 'none',
+ }}
+ />
+ { !this.state.ready ? <Spinner color={'#F7C06C'} /> : null}
+ </div>
+ )
+ }
+
+ renderErrorModal () {
+ let title, msg
+
+ if (this.props.error) {
+ if (this.props.errorType === 'NO_WEBCAM_FOUND') {
+ title = this.context.t('noWebcamFoundTitle')
+ msg = this.context.t('noWebcamFound')
+ } else {
+ title = this.context.t('unknownCameraErrorTitle')
+ msg = this.context.t('unknownCameraError')
+ }
+ }
+
+ return (
+ <div className="qr-scanner">
+ <div className="qr-scanner__close" onClick={this.stopAndClose}></div>
+
+ <div className="qr-scanner__image">
+ <img src={'images/webcam.svg'} width={70} height={70} />
+ </div>
+ <div className="qr-scanner__title">
+ { title }
+ </div>
+ <div className={'qr-scanner__error'}>
+ {msg}
+ </div>
+ <PageContainerFooter
+ onCancel={this.stopAndClose}
+ onSubmit={this.tryAgain}
+ cancelText={this.context.t('cancel')}
+ submitText={this.context.t('tryAgain')}
+ submitButtonType="confirm"
+ />
+ </div>
+ )
+ }
+
+ render () {
+ const { t } = this.context
+
+ if (this.props.error) {
+ return this.renderErrorModal()
+ }
+
+ return (
+ <div className="qr-scanner">
+ <div className="qr-scanner__close" onClick={this.stopAndClose}></div>
+ <div className="qr-scanner__title">
+ { `${t('scanQrCode')}` }
+ </div>
+ <div className="qr-scanner__content">
+ { this.renderVideo() }
+ </div>
+ <div className={'qr-scanner__status'}>
+ {this.state.msg}
+ </div>
+ </div>
+ )
+ }
+}
diff --git a/ui/app/components/modals/qr-scanner/qr-scanner.container.js b/ui/app/components/modals/qr-scanner/qr-scanner.container.js
new file mode 100644
index 000000000..d0a35e03b
--- /dev/null
+++ b/ui/app/components/modals/qr-scanner/qr-scanner.container.js
@@ -0,0 +1,24 @@
+import { connect } from 'react-redux'
+import QrScanner from './qr-scanner.component'
+
+const { hideModal, qrCodeDetected, showQrScanner } = require('../../../actions')
+import {
+ SEND_ROUTE,
+} from '../../../routes'
+
+const mapStateToProps = state => {
+ return {
+ error: state.appState.modal.modalState.props.error,
+ errorType: state.appState.modal.modalState.props.errorType,
+ }
+}
+
+const mapDispatchToProps = dispatch => {
+ return {
+ hideModal: () => dispatch(hideModal()),
+ qrCodeDetected: (data) => dispatch(qrCodeDetected(data)),
+ scanQrCode: () => dispatch(showQrScanner(SEND_ROUTE)),
+ }
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(QrScanner)
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 b170880b4..961aa304e 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
@@ -124,7 +124,7 @@ export default class ConfirmTransactionBase extends Component {
if (simulationFails) {
return {
- valid: false,
+ valid: true,
errorKey: TRANSACTION_ERROR_KEY,
}
}
diff --git a/ui/app/components/send/send-content/send-content.component.js b/ui/app/components/send/send-content/send-content.component.js
index 7a0b1a18e..df7bcb7cc 100644
--- a/ui/app/components/send/send-content/send-content.component.js
+++ b/ui/app/components/send/send-content/send-content.component.js
@@ -11,6 +11,7 @@ export default class SendContent extends Component {
static propTypes = {
updateGas: PropTypes.func,
+ scanQrCode: PropTypes.func,
};
render () {
@@ -18,7 +19,10 @@ export default class SendContent extends Component {
<PageContainerContent>
<div className="send-v2__form">
<SendFromRow />
- <SendToRow updateGas={(updateData) => this.props.updateGas(updateData)} />
+ <SendToRow
+ updateGas={(updateData) => this.props.updateGas(updateData)}
+ scanQrCode={ _ => this.props.scanQrCode()}
+ />
<SendAmountRow updateGas={(updateData) => this.props.updateGas(updateData)} />
<SendGasRow />
<SendHexDataRow />
diff --git a/ui/app/components/send/send-content/send-to-row/send-to-row.component.js b/ui/app/components/send/send-content/send-to-row/send-to-row.component.js
index 892ad5d67..1163dcffc 100644
--- a/ui/app/components/send/send-content/send-to-row/send-to-row.component.js
+++ b/ui/app/components/send/send-content/send-to-row/send-to-row.component.js
@@ -17,6 +17,7 @@ export default class SendToRow extends Component {
updateGas: PropTypes.func,
updateSendTo: PropTypes.func,
updateSendToError: PropTypes.func,
+ scanQrCode: PropTypes.func,
};
static contextTypes = {
@@ -51,6 +52,7 @@ export default class SendToRow extends Component {
showError={inError}
>
<EnsInput
+ scanQrCode={_ => this.props.scanQrCode()}
accounts={toAccounts}
closeDropdown={() => closeToDropdown()}
dropdownOpen={toDropdownOpen}
diff --git a/ui/app/components/send/send.component.js b/ui/app/components/send/send.component.js
index 6f1b20c55..0d8ffd179 100644
--- a/ui/app/components/send/send.component.js
+++ b/ui/app/components/send/send.component.js
@@ -38,12 +38,30 @@ export default class SendTransactionScreen extends PersistentForm {
updateAndSetGasTotal: PropTypes.func,
updateSendErrors: PropTypes.func,
updateSendTokenBalance: PropTypes.func,
+ scanQrCode: PropTypes.func,
+ qrCodeDetected: PropTypes.func,
+ qrCodeData: PropTypes.object,
};
static contextTypes = {
t: PropTypes.func,
};
+ componentWillReceiveProps (nextProps) {
+ if (nextProps.qrCodeData) {
+ if (nextProps.qrCodeData.type === 'address') {
+ const scannedAddress = nextProps.qrCodeData.values.address.toLowerCase()
+ const currentAddress = this.props.to && this.props.to.toLowerCase()
+ if (currentAddress !== scannedAddress) {
+ this.props.updateSendTo(scannedAddress)
+ this.updateGas({ to: scannedAddress })
+ // Clean up QR code data after handling
+ this.props.qrCodeDetected(null)
+ }
+ }
+ }
+ }
+
updateGas ({ to: updatedToAddress, amount: value } = {}) {
const {
amount,
@@ -158,6 +176,16 @@ export default class SendTransactionScreen extends PersistentForm {
address,
})
this.updateGas()
+
+ // Show QR Scanner modal if ?scan=true
+ if (window.location.search === '?scan=true') {
+ this.props.scanQrCode()
+
+ // Clear the queryString param after showing the modal
+ const cleanUrl = location.href.split('?')[0]
+ history.pushState({}, null, `${cleanUrl}`)
+ window.location.hash = '#send'
+ }
}
componentWillUnmount () {
@@ -170,7 +198,10 @@ export default class SendTransactionScreen extends PersistentForm {
return (
<div className="page-container">
<SendHeader history={history}/>
- <SendContent updateGas={(updateData) => this.updateGas(updateData)}/>
+ <SendContent
+ updateGas={(updateData) => this.updateGas(updateData)}
+ scanQrCode={_ => this.props.scanQrCode()}
+ />
<SendFooter history={history}/>
</div>
)
diff --git a/ui/app/components/send/send.container.js b/ui/app/components/send/send.container.js
index 44ebd2792..41735de64 100644
--- a/ui/app/components/send/send.container.js
+++ b/ui/app/components/send/send.container.js
@@ -21,11 +21,15 @@ import {
getSendFromObject,
getSendTo,
getTokenBalance,
+ getQrCodeData,
} from './send.selectors'
import {
+ updateSendTo,
updateSendTokenBalance,
updateGasData,
setGasTotal,
+ showQrScanner,
+ qrCodeDetected,
} from '../../actions'
import {
resetSendState,
@@ -35,6 +39,10 @@ import {
calcGasTotal,
} from './send.utils.js'
+import {
+ SEND_ROUTE,
+} from '../../routes'
+
module.exports = compose(
withRouter,
connect(mapStateToProps, mapDispatchToProps)
@@ -60,6 +68,7 @@ function mapStateToProps (state) {
tokenBalance: getTokenBalance(state),
tokenContract: getSelectedTokenContract(state),
tokenToFiatRate: getSelectedTokenToFiatRate(state),
+ qrCodeData: getQrCodeData(state),
}
}
@@ -89,5 +98,8 @@ function mapDispatchToProps (dispatch) {
},
updateSendErrors: newError => dispatch(updateSendErrors(newError)),
resetSendState: () => dispatch(resetSendState()),
+ scanQrCode: () => dispatch(showQrScanner(SEND_ROUTE)),
+ qrCodeDetected: (data) => dispatch(qrCodeDetected(data)),
+ updateSendTo: (to, nickname) => dispatch(updateSendTo(to, nickname)),
}
}
diff --git a/ui/app/components/send/send.selectors.js b/ui/app/components/send/send.selectors.js
index cf07eafe1..ab3f6d34b 100644
--- a/ui/app/components/send/send.selectors.js
+++ b/ui/app/components/send/send.selectors.js
@@ -46,6 +46,7 @@ const selectors = {
getTokenExchangeRate,
getUnapprovedTxs,
transactionsSelector,
+ getQrCodeData,
}
module.exports = selectors
@@ -282,3 +283,7 @@ function transactionsSelector (state) {
: txsToRender
.sort((a, b) => b.time - a.time)
}
+
+function getQrCodeData (state) {
+ return state.appState.qrCodeData
+}
diff --git a/ui/app/components/send/tests/send-container.test.js b/ui/app/components/send/tests/send-container.test.js
index 7a9120d24..57e332780 100644
--- a/ui/app/components/send/tests/send-container.test.js
+++ b/ui/app/components/send/tests/send-container.test.js
@@ -44,6 +44,7 @@ proxyquire('../send.container.js', {
getSendEditingTransactionId: (s) => `mockEditingTransactionId:${s}`,
getSendFromObject: (s) => `mockFrom:${s}`,
getTokenBalance: (s) => `mockTokenBalance:${s}`,
+ getQrCodeData: (s) => `mockQrCodeData:${s}`,
},
'../../actions': actionSpies,
'../../ducks/send.duck': duckActionSpies,
@@ -76,6 +77,7 @@ describe('send container', () => {
tokenBalance: 'mockTokenBalance:mockState',
tokenContract: 'mockTokenContract:mockState',
tokenToFiatRate: 'mockTokenToFiatRate:mockState',
+ qrCodeData: 'mockQrCodeData:mockState',
})
})
diff --git a/ui/app/components/send/to-autocomplete/to-autocomplete.js b/ui/app/components/send/to-autocomplete/to-autocomplete.js
index 80cfa7a85..49ebf49d9 100644
--- a/ui/app/components/send/to-autocomplete/to-autocomplete.js
+++ b/ui/app/components/send/to-autocomplete/to-autocomplete.js
@@ -4,6 +4,7 @@ const h = require('react-hyperscript')
const inherits = require('util').inherits
const AccountListItem = require('../account-list-item/account-list-item.component').default
const connect = require('react-redux').connect
+const Tooltip = require('../../tooltip')
ToAutoComplete.contextTypes = {
t: PropTypes.func,
@@ -94,11 +95,12 @@ ToAutoComplete.prototype.render = function () {
dropdownOpen,
onChange,
inError,
+ qrScanner,
} = this.props
return h('div.send-v2__to-autocomplete', {}, [
- h('input.send-v2__to-autocomplete__input', {
+ h(`input.send-v2__to-autocomplete__input${qrScanner ? '.with-qr' : ''}`, {
placeholder: this.context.t('recipientAddress'),
className: inError ? `send-v2__error-border` : '',
value: to,
@@ -108,7 +110,13 @@ ToAutoComplete.prototype.render = function () {
borderColor: inError ? 'red' : null,
},
}),
-
+ qrScanner && h(Tooltip, {
+ title: this.context.t('scanQrCode'),
+ position: 'bottom',
+ }, h(`i.fa.fa-qrcode.fa-lg.send-v2__to-autocomplete__qr-code`, {
+ style: { color: '#33333' },
+ onClick: () => this.props.scanQrCode(),
+ })),
!to && h(`i.fa.fa-caret-down.fa-lg.send-v2__to-autocomplete__down-caret`, {
style: { color: '#dedede' },
onClick: () => this.handleInputEvent(),
diff --git a/ui/app/components/tx-list-item.js b/ui/app/components/tx-list-item.js
index 7513ba267..474d62638 100644
--- a/ui/app/components/tx-list-item.js
+++ b/ui/app/components/tx-list-item.js
@@ -35,6 +35,7 @@ function mapStateToProps (state) {
currentCurrency: getCurrentCurrency(state),
contractExchangeRates: state.metamask.contractExchangeRates,
selectedAddressTxList: state.metamask.selectedAddressTxList,
+ networkNonce: state.appState.networkNonce,
}
}
@@ -209,6 +210,7 @@ TxListItem.prototype.showRetryButton = function () {
selectedAddressTxList,
transactionId,
txParams,
+ networkNonce,
} = this.props
if (!txParams) {
return false
@@ -222,11 +224,7 @@ TxListItem.prototype.showRetryButton = function () {
const currentTxIsLatestWithNonce = lastSubmittedTxWithCurrentNonce &&
lastSubmittedTxWithCurrentNonce.id === transactionId
if (currentSubmittedTxs.length > 0) {
- const earliestSubmitted = currentSubmittedTxs.reduce((tx1, tx2) => {
- if (tx1.submittedTime < tx2.submittedTime) return tx1
- return tx2
- })
- currentTxSharesEarliestNonce = currentNonce === earliestSubmitted.txParams.nonce
+ currentTxSharesEarliestNonce = currentNonce === networkNonce
}
return currentTxSharesEarliestNonce && currentTxIsLatestWithNonce && Date.now() - transactionSubmittedTime > 30000
diff --git a/ui/app/components/tx-list.js b/ui/app/components/tx-list.js
index 554febcff..d8c4a9d19 100644
--- a/ui/app/components/tx-list.js
+++ b/ui/app/components/tx-list.js
@@ -8,7 +8,7 @@ const selectors = require('../selectors')
const TxListItem = require('./tx-list-item')
const ShiftListItem = require('./shift-list-item')
const { formatDate } = require('../util')
-const { showConfTxPage } = require('../actions')
+const { showConfTxPage, updateNetworkNonce } = require('../actions')
const classnames = require('classnames')
const { tokenInfoGetter } = require('../token-util')
const { withRouter } = require('react-router-dom')
@@ -28,12 +28,14 @@ function mapStateToProps (state) {
return {
txsToRender: selectors.transactionsSelector(state),
conversionRate: selectors.conversionRateSelector(state),
+ selectedAddress: selectors.getSelectedAddress(state),
}
}
function mapDispatchToProps (dispatch) {
return {
showConfTxPage: ({ id }) => dispatch(showConfTxPage({ id })),
+ updateNetworkNonce: (address) => dispatch(updateNetworkNonce(address)),
}
}
@@ -44,6 +46,20 @@ function TxList () {
TxList.prototype.componentWillMount = function () {
this.tokenInfoGetter = tokenInfoGetter()
+ this.props.updateNetworkNonce(this.props.selectedAddress)
+}
+
+TxList.prototype.componentDidUpdate = function (prevProps) {
+ const oldTxsToRender = prevProps.txsToRender
+ const {
+ txsToRender: newTxsToRender,
+ selectedAddress,
+ updateNetworkNonce,
+ } = this.props
+
+ if (newTxsToRender.length > oldTxsToRender.length) {
+ updateNetworkNonce(selectedAddress)
+ }
}
TxList.prototype.render = function () {
diff --git a/ui/app/constants/error-keys.js b/ui/app/constants/error-keys.js
index 1b89be62e..f70ed3b19 100644
--- a/ui/app/constants/error-keys.js
+++ b/ui/app/constants/error-keys.js
@@ -1,3 +1,3 @@
export const INSUFFICIENT_FUNDS_ERROR_KEY = 'insufficientFunds'
export const GAS_LIMIT_TOO_LOW_ERROR_KEY = 'gasLimitTooLow'
-export const TRANSACTION_ERROR = 'transactionError'
+export const TRANSACTION_ERROR_KEY = 'transactionError'
diff --git a/ui/app/css/itcss/components/send.scss b/ui/app/css/itcss/components/send.scss
index e9c872ea7..806ac8536 100644
--- a/ui/app/css/itcss/components/send.scss
+++ b/ui/app/css/itcss/components/send.scss
@@ -626,6 +626,23 @@
top: 18px;
right: 12px;
}
+
+ &__qr-code {
+ position: absolute;
+ top: 13px;
+ right: 33px;
+ cursor: pointer;
+ padding: 8px 5px 5px;
+ border-radius: 4px;
+ }
+
+ &__qr-code:hover {
+ background: #f1f1f1;
+ }
+
+ &__input.with-qr {
+ padding-right: 65px;
+ }
}
&__to-autocomplete, &__memo-text-area, &__hex-data {
diff --git a/ui/app/first-time/init-menu.js b/ui/app/first-time/init-menu.js
index c20ba2d77..e7bbfb225 100644
--- a/ui/app/first-time/init-menu.js
+++ b/ui/app/first-time/init-menu.js
@@ -130,7 +130,7 @@ class InitializeMenuScreen extends Component {
textDecoration: 'underline',
marginTop: '32px',
},
- }, 'Use classic interface'),
+ }, this.context.t('classicInterface')),
]),
])
diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js
index 50d8bcba7..98d467163 100644
--- a/ui/app/reducers/app.js
+++ b/ui/app/reducers/app.js
@@ -51,6 +51,7 @@ function reduceApp (state, action) {
sidebarOpen: false,
alertOpen: false,
alertMessage: null,
+ qrCodeData: null,
networkDropdownOpen: false,
currentView: seedWords ? seedConfView : defaultView,
accountDetail: {
@@ -65,6 +66,7 @@ function reduceApp (state, action) {
buyView: {},
isMouseUser: false,
gasIsLoading: false,
+ networkNonce: null,
}, state.appState)
switch (action.type) {
@@ -90,7 +92,7 @@ function reduceApp (state, action) {
sidebarOpen: false,
})
- // sidebar methods
+ // alert methods
case actions.ALERT_OPEN:
return extend(appState, {
alertOpen: true,
@@ -103,6 +105,13 @@ function reduceApp (state, action) {
alertMessage: null,
})
+ // qr scanner methods
+ case actions.QR_CODE_DETECTED:
+ return extend(appState, {
+ qrCodeData: action.value,
+ })
+
+
// modal methods:
case actions.MODAL_OPEN:
const { name, ...modalProps } = action.payload
@@ -701,6 +710,11 @@ function reduceApp (state, action) {
gasIsLoading: false,
})
+ case actions.SET_NETWORK_NONCE:
+ return extend(appState, {
+ networkNonce: action.value,
+ })
+
default:
return appState
}
diff --git a/ui/app/selectors/confirm-transaction.js b/ui/app/selectors/confirm-transaction.js
index 9548cf75e..aa1fc5404 100644
--- a/ui/app/selectors/confirm-transaction.js
+++ b/ui/app/selectors/confirm-transaction.js
@@ -147,14 +147,20 @@ export const tokenAmountAndToAddressSelector = createSelector(
export const approveTokenAmountAndToAddressSelector = createSelector(
tokenDataParamsSelector,
- params => {
+ tokenDecimalsSelector,
+ (params, tokenDecimals) => {
let toAddress = ''
let tokenAmount = 0
if (params && params.length) {
toAddress = params.find(param => param.name === TOKEN_PARAM_SPENDER).value
const value = Number(params.find(param => param.name === TOKEN_PARAM_VALUE).value)
- tokenAmount = roundExponential(value)
+
+ if (tokenDecimals) {
+ tokenAmount = calcTokenAmount(value, tokenDecimals)
+ }
+
+ tokenAmount = roundExponential(tokenAmount)
}
return {
diff --git a/ui/app/util.js b/ui/app/util.js
index 8b194e0c7..ade4fec8a 100644
--- a/ui/app/util.js
+++ b/ui/app/util.js
@@ -271,9 +271,9 @@ function getContractAtAddress (tokenAddress) {
return global.eth.contract(abi).at(tokenAddress)
}
-function exportAsFile (filename, data) {
+function exportAsFile (filename, data, type = 'text/csv') {
// source: https://stackoverflow.com/a/33542499 by Ludovic Feltz
- const blob = new Blob([data], {type: 'text/csv'})
+ const blob = new Blob([data], {type})
if (window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveBlob(blob, filename)
} else {
diff --git a/ui/lib/webcam-utils.js b/ui/lib/webcam-utils.js
new file mode 100644
index 000000000..eb717b23a
--- /dev/null
+++ b/ui/lib/webcam-utils.js
@@ -0,0 +1,36 @@
+'use strict'
+
+import DetectRTC from 'detectrtc'
+const { ENVIRONMENT_TYPE_POPUP } = require('../../app/scripts/lib/enums')
+const { getEnvironmentType, getPlatform } = require('../../app/scripts/lib/util')
+const { PLATFORM_BRAVE, PLATFORM_FIREFOX } = require('../../app/scripts/lib/enums')
+
+class WebcamUtils {
+
+ static checkStatus () {
+ return new Promise((resolve, reject) => {
+ const isPopup = getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_POPUP
+ const isFirefoxOrBrave = getPlatform() === (PLATFORM_FIREFOX || PLATFORM_BRAVE)
+ try {
+ DetectRTC.load(_ => {
+ if (DetectRTC.hasWebcam) {
+ let environmentReady = true
+ if ((isFirefoxOrBrave && isPopup) || (isPopup && !DetectRTC.isWebsiteHasWebcamPermissions)) {
+ environmentReady = false
+ }
+ resolve({
+ permissions: DetectRTC.isWebsiteHasWebcamPermissions,
+ environmentReady,
+ })
+ } else {
+ reject({type: 'NO_WEBCAM_FOUND'})
+ }
+ })
+ } catch (e) {
+ reject({type: 'UNKNOWN_ERROR'})
+ }
+ })
+ }
+}
+
+module.exports = WebcamUtils