diff options
136 files changed, 7910 insertions, 1626 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml index c9d8cdf6a..7eedc3f87 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -39,6 +39,10 @@ workflows: - test-unit: requires: - prep-deps-npm + - test-mozilla-lint: + requires: + - prep-deps-npm + - prep-build - test-integration-mascara-chrome: requires: - prep-deps-npm @@ -59,6 +63,7 @@ workflows: requires: - test-lint - test-unit + - test-mozilla-lint - test-e2e-chrome - test-e2e-firefox - test-e2e-beta-chrome @@ -299,8 +304,8 @@ jobs: - run: name: github gh-pages docs publish command: > - git config user.name metamaskbot - git config user.email admin@metamask.io + git config user.name metamaskbot && + git config user.email admin@metamask.io && gh-pages -d docs/jsdocs test-unit: @@ -313,6 +318,16 @@ jobs: - run: name: test:coverage command: npm run test:coverage + test-mozilla-lint: + docker: + - image: circleci/node:8.11.3-browsers + steps: + - checkout + - attach_workspace: + at: . + - run: + name: test:mozilla-lint + command: npm run mozilla-lint test-integration-flat-firefox: docker: diff --git a/.eslintignore b/.eslintignore index 6c7f99f40..15c9c29a0 100644 --- a/.eslintignore +++ b/.eslintignore @@ -3,6 +3,7 @@ dist/** builds/** test-builds/** docs/** +coverage/ development/bundle.js development/states.js diff --git a/CHANGELOG.md b/CHANGELOG.md index fbc7f9d52..8fd41a559 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,28 @@ ## Current Develop Branch +## 4.12.0 Thursday September 27 2018 + +- Reintroduces changes from 4.10.0 + +## 4.11.1 Tuesday September 25 2018 + +- Adds Ledger support. + +## 4.11.0 Monday September 24 2018 + +- Identical to 4.9.3. A rollback version to give time to fix bugs in the 4.10.x branch. + +## 4.10.0 Mon Sep 17 2018 + +- [#4803](https://github.com/MetaMask/metamask-extension/pull/4803): Implement EIP-712: Sign typed data, but continue to support v1. +- [#4898](https://github.com/MetaMask/metamask-extension/pull/4898): Restore multiple consecutive accounts with balances. +- [#4279](https://github.com/MetaMask/metamask-extension/pull/4279): New BlockTracker and Json-Rpc-Engine based Provider. +- [#5050](https://github.com/MetaMask/metamask-extension/pull/5050): Add Ledger hardware wallet support. +- [#4919](https://github.com/MetaMask/metamask-extension/pull/4919): Refactor and Redesign Transaction List. +- [#5182](https://github.com/MetaMask/metamask-extension/pull/5182): Add Transaction Details to the Transaction List view. +- [#5229](https://github.com/MetaMask/metamask-extension/pull/5229): Clear old seed words when importing new seed words. +- [#5264](https://github.com/MetaMask/metamask-extension/pull/5264): Improve click area for adjustment arrows buttons. - [#4606](https://github.com/MetaMask/metamask-extension/pull/4606): Add new metamask_watchAsset method. - [#5189](https://github.com/MetaMask/metamask-extension/pull/5189): Fix bug where Ropsten loading message is shown when connecting to Kovan. - [#5256](https://github.com/MetaMask/metamask-extension/pull/5256): Add mock EIP-1102 support diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 2cfd15f50..f6cf7cf69 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -61,6 +61,12 @@ "attemptingConnect": { "message": "Attempting to connect to blockchain." }, + "attemptToCancel": { + "message": "Attempt to Cancel?" + }, + "attemptToCancelDescription": { + "message": "Attempting to cancel does not guarantee your original transaction will be cancelled. If cancelled, you are still required to pay a transaction fee to the network." + }, "attributions": { "message": "Attributions" }, @@ -116,6 +122,12 @@ "cancel": { "message": "Cancel" }, + "cancelAttempt": { + "message": "Cancel Attempt" + }, + "cancellationGasFee": { + "message": "Cancellation Gas Fee" + }, "classicInterface": { "message": "Use classic interface" }, @@ -216,6 +228,9 @@ "currentConversion": { "message": "Current Conversion" }, + "currentLanguage": { + "message": "Current Language" + }, "currentNetwork": { "message": "Current Network" }, @@ -596,6 +611,9 @@ "metamaskSeedWords": { "message": "MetaMask Seed Words" }, + "metamaskVersion": { + "message": "MetaMask Version" + }, "min": { "message": "Minimum" }, @@ -906,6 +924,9 @@ "selectCurrency": { "message": "Select Currency" }, + "selectLocale": { + "message": "Select Locale" + }, "selectService": { "message": "Select Service" }, @@ -1100,6 +1121,9 @@ "transactionCreated": { "message": "Transaction created with a value of $1 on $2." }, + "transactionWithNonce": { + "message": "Transaction $1" + }, "transactionDropped": { "message": "Transaction dropped on $2." }, @@ -1188,6 +1212,9 @@ "unlockMessage": { "message": "The decentralized web awaits" }, + "updatedWithDate": { + "message": "Updated $1" + }, "uriErrorMsg": { "message": "URIs require the appropriate HTTP/HTTPS prefix." }, @@ -1228,6 +1255,9 @@ "whatsThis": { "message": "What's this?" }, + "yesLetsTry": { + "message": "Yes, let's try" + }, "youNeedToAllowCameraAccess": { "message": "You need to allow camera access to use this feature." }, diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index a39bba9da..8ce0671a4 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -23,6 +23,9 @@ "addTokens": { "message": "添加代币" }, + "addAcquiredTokens": { + "message": "在Metamask上添加已用的代币" + }, "amount": { "message": "数量" }, @@ -116,6 +119,9 @@ "confirmTransaction": { "message": "确认交易" }, + "connectHardwareWallet": { + "message": "链接硬件钱包" + }, "continue": { "message": "继续" }, @@ -714,6 +720,9 @@ "search": { "message": "搜索" }, + "searchResults": { + "message": "搜索结果" + }, "secretPhrase": { "message": "输入12位助记词以恢复金库." }, diff --git a/app/images/ledger-logo.svg b/app/images/ledger-logo.svg index 21b99d0e5..5ca90e16e 100644 --- a/app/images/ledger-logo.svg +++ b/app/images/ledger-logo.svg @@ -1 +1,33 @@ -<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1916.3 516.8" width="2500" height="674"><style>.st0{fill:#333745}</style><g id="squares_1_"><path class="st0" d="M578.2 392.7V24.3h25.6v344.1h175.3v24.3H578.2zm327.5 5.1c-39.7 0-70.4-12.8-93.4-37.1-21.7-24.3-33.3-58.8-33.3-103.6 0-43.5 10.2-79.3 32-104.9 21.7-26.9 49.9-39.7 87-39.7 32 0 57.6 11.5 76.8 33.3 19.2 23 28.1 53.7 28.1 92.1v20.5H804.6c0 37.1 9 66.5 26.9 85.7 16.6 20.5 42.2 29.4 74.2 29.4 15.3 0 29.4-1.3 40.9-3.8 11.5-2.6 26.9-6.4 44.8-14.1v24.3c-15.3 6.4-29.4 11.5-42.2 14.1-14.3 2.6-28.9 3.9-43.5 3.8zM898 135.6c-26.9 0-47.3 9-64 25.6-15.3 17.9-25.6 42.2-28.1 75.5h168.9c0-32-6.4-56.3-20.5-74.2-12.8-18-32-26.9-56.3-26.9zm238-21.8c19.2 0 37.1 3.8 51.2 10.2 14.1 7.7 26.9 19.2 38.4 37.1h1.3c-1.3-21.7-1.3-42.2-1.3-62.7V0h24.3v392.7h-16.6l-6.4-42.2c-20.5 30.7-51.2 47.3-89.6 47.3s-66.5-11.5-87-35.8c-20.5-23-29.4-57.6-29.4-102.3 0-47.3 10.2-83.2 29.4-108.7 19.2-25.6 48.6-37.2 85.7-37.2zm0 21.8c-29.4 0-52.4 10.2-67.8 32-15.3 20.5-23 51.2-23 92.1 0 78 30.7 116.4 90.8 116.4 30.7 0 53.7-9 67.8-26.9 14.1-17.9 21.7-47.3 21.7-89.6v-3.8c0-42.2-7.7-72.9-21.7-90.8-12.8-20.5-35.8-29.4-67.8-29.4zm379.9-16.6v17.9l-56.3 3.8c15.3 19.2 23 39.7 23 61.4 0 26.9-9 47.3-26.9 64-17.9 16.6-40.9 24.3-70.4 24.3-12.8 0-21.7 0-25.6-1.3-10.2 5.1-17.9 11.5-23 17.9-5.1 7.7-7.7 14.1-7.7 23s3.8 15.3 10.2 19.2c6.4 3.8 17.9 6.4 33.3 6.4h47.3c29.4 0 52.4 6.4 67.8 17.9s24.3 29.4 24.3 53.7c0 29.4-11.5 51.2-34.5 66.5-23 15.3-56.3 23-99.8 23-34.5 0-61.4-6.4-80.6-20.5-19.2-12.8-28.1-32-28.1-55 0-19.2 6.4-34.5 17.9-47.3s28.1-20.5 47.3-25.6c-7.7-3.8-15.3-9-19.2-15.3-5-6.2-7.7-13.8-7.7-21.7 0-17.9 11.5-34.5 34.5-48.6-15.3-6.4-28.1-16.6-37.1-30.7-9-14.1-12.8-30.7-12.8-48.6 0-26.9 9-49.9 25.6-66.5 17.9-16.6 40.9-24.3 70.4-24.3 17.9 0 32 1.3 42.2 5.1h85.7v1.3h.2zm-222.6 319.8c0 37.1 28.1 56.3 84.4 56.3 71.6 0 107.5-23 107.5-69.1 0-16.6-5.1-28.1-16.6-35.8-11.5-7.7-29.4-11.5-55-11.5h-44.8c-49.9 1.2-75.5 20.4-75.5 60.1zm21.8-235.4c0 21.7 6.4 37.1 19.2 49.9 12.8 11.5 29.4 17.9 51.2 17.9 23 0 40.9-6.4 52.4-17.9 12.8-11.5 17.9-28.1 17.9-49.9 0-23-6.4-40.9-19.2-52.4-12.8-11.5-29.4-17.9-52.4-17.9-21.7 0-39.7 6.4-51.2 19.2-12.8 11.4-17.9 29.3-17.9 51.1z"/><path class="st0" d="M1640 397.8c-39.7 0-70.4-12.8-93.4-37.1-21.7-24.3-33.3-58.8-33.3-103.6 0-43.5 10.2-79.3 32-104.9 21.7-26.9 49.9-39.7 87-39.7 32 0 57.6 11.5 76.8 33.3 19.2 23 28.1 53.7 28.1 92.1v20.5h-197c0 37.1 9 66.5 26.9 85.7 16.6 20.5 42.2 29.4 74.2 29.4 15.3 0 29.4-1.3 40.9-3.8 11.5-2.6 26.9-6.4 44.8-14.1v24.3c-15.3 6.4-29.4 11.5-42.2 14.1-14.1 2.6-28.2 3.8-44.8 3.8zm-6.4-262.2c-26.9 0-47.3 9-64 25.6-15.3 17.9-25.6 42.2-28.1 75.5h168.9c0-32-6.4-56.3-20.5-74.2-12.8-18-32-26.9-56.3-26.9zm245.6-21.8c11.5 0 24.3 1.3 37.1 3.8l-5.1 24.3c-11.8-2.6-23.8-3.9-35.8-3.8-23 0-42.2 10.2-57.6 29.4-15.3 20.5-23 44.8-23 75.5v149.7h-25.6V119h21.7l2.6 49.9h1.3c11.5-20.5 23-34.5 35.8-42.2 15.4-9 30.7-12.9 48.6-12.9zM333.9 12.8h-183v245.6h245.6V76.7c.1-34.5-28.1-63.9-62.6-63.9zm-239.2 0H64c-34.5 0-64 28.1-64 64v30.7h94.7V12.8zM0 165h94.7v94.7H0V165zm301.9 245.6h30.7c34.5 0 64-28.1 64-64V316h-94.7v94.6zm-151-94.6h94.7v94.7h-94.7V316zM0 316v30.7c0 34.5 28.1 64 64 64h30.7V316H0z"/></g></svg>
\ No newline at end of file +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="0 0 197.4 48.6" style="enable-background:new 0 0 197.4 48.6;" xml:space="preserve"> +<style type="text/css"> + .st0{fill:#1D2028;} +</style> +<title>Fichier 8</title> +<g> + <path class="st0" d="M34.1,0H15.5v25.1h25.1V6.5C40.6,2.9,37.7,0,34.1,0z"/> + <path class="st0" d="M9.7,0H6.5C2.9,0,0,2.9,0,6.5v3.2h9.7V0z"/> + <rect y="15.5" class="st0" width="9.7" height="9.7"/> + <path class="st0" d="M31,40.6h3.2c3.6,0,6.5-2.9,6.5-6.5V31H31V40.6z"/> + <rect x="15.5" y="31" class="st0" width="9.7" height="9.7"/> + <path class="st0" d="M0,31v3.2c0,3.6,2.9,6.5,6.5,6.5h3.2V31H0z"/> + <g> + <polygon class="st0" points="65.4,2.6 61.6,2.6 61.6,38.1 81.7,38.1 81.7,34.7 65.4,34.7 "/> + <path class="st0" d="M93.9,12c-7.4,0-12.6,5.5-12.6,13.4c0,0.3,0,0.6,0,0.9c0.1,3.4,1.6,6.6,4.1,9c2.4,2.2,5.5,3.5,8.8,3.5 + c0.2,0,0.3,0,0.5,0c3.5,0,6.8-1.3,9.4-3.5l0.1-0.1l-1.7-2.8l-0.2,0.1c-2.1,1.9-4.7,3-7.5,3c-4.6,0-9.3-3-9.6-9.7h19.2v-0.2 + c0,0,0.1-1.2,0.1-1.8C104.5,16.6,100.3,12,93.9,12z M85.3,22.6c0.8-4.5,4.1-7.4,8.4-7.4c3.2,0,6.7,1.9,7,7.4H85.3z"/> + <path class="st0" d="M126.5,15c0,0.4,0,0.9,0,1.3c-1.6-2.7-4.6-4.4-7.7-4.4c-0.1,0-0.2,0-0.3,0c-6.8,0-11.5,5.4-11.5,13.3 + c0,8,4.5,13.4,11.2,13.4c5.3,0,7.7-3.2,8.5-4.6c0,0.4,0,0.8,0,1.1v2.8h3.6V2.6h-3.7V15H126.5z M118.7,35.3c-4.7,0-7.8-4-7.8-10 + c0-5.8,3.3-9.9,7.9-9.9c3.9,0,7.8,3.1,7.8,9.9C126.6,32.7,122.5,35.3,118.7,35.3z"/> + <path class="st0" d="M152.2,15.5c0,0.1,0,0.2,0,0.2c-0.7-1.2-2.9-3.8-8.2-3.8c-6.7,0-11.1,5.1-11.1,12.9s4.6,13.1,11.4,13.1 + c3.7,0,6.2-1.3,7.9-4c0,0.4,0,0.8,0,1.2v2.3c0,4.9-3.1,7.7-8.6,7.7c-2.3,0-4.7-0.6-6.8-1.7l-0.2-0.1l-1.4,3.1l0.2,0.1 + c2.6,1.3,5.5,2,8.3,2c5.9,0,12.2-3,12.2-11.3V12.6h-3.7L152.2,15.5L152.2,15.5z M144.8,34.6c-4.9,0-8.1-3.8-8.1-9.7 + c0-6,2.8-9.4,7.6-9.4c5.3,0,7.8,3.1,7.8,9.4C152.2,31.1,149.6,34.6,144.8,34.6z"/> + <path class="st0" d="M171,12c-7.4,0-12.5,5.5-12.5,13.3c0,0.3,0,0.6,0,0.9c0.1,3.4,1.6,6.6,4.1,9c2.4,2.2,5.5,3.5,8.8,3.5 + c0.2,0,0.3,0,0.5,0c3.5,0,6.8-1.3,9.4-3.5l0.1-0.1l-1.8-2.8l-0.2,0.1c-2.1,1.9-4.7,3-7.5,3c-4.6,0-9.3-3-9.6-9.7h19.3v-0.2 + c0,0,0.1-1.2,0.1-1.8C181.7,16.6,177.5,12,171,12z M162.5,22.6c0.8-4.5,4.1-7.4,8.4-7.4c3.2,0,6.7,1.9,7,7.4H162.5z"/> + <path class="st0" d="M197.3,12.5c-0.5-0.1-0.9-0.1-1.4-0.2c-3.5,0-6.4,2.2-7.9,5.9c0-0.3,0-0.7,0-1.1v-4.6h-3.7l0.1,25.3V38h3.8 + V27.3c0-1.6,0.2-3.3,0.7-4.8c1.2-3.9,3.9-6.4,7.1-6.4c0.4,0,0.8,0,1.2,0.1h0.2v-3.7L197.3,12.5z"/> + </g> +</g> +</svg> diff --git a/app/manifest.json b/app/manifest.json index 3718f5c8a..7c554f1ac 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "__MSG_appName__", "short_name": "__MSG_appName__", - "version": "4.9.3", + "version": "4.12.0", "manifest_version": 2, "author": "https://metamask.io", "description": "__MSG_appDescription__", @@ -77,4 +77,4 @@ "*" ] } -} +}
\ No newline at end of file diff --git a/app/phishing.html b/app/phishing.html index e20c9ac9c..eabb363b3 100644 --- a/app/phishing.html +++ b/app/phishing.html @@ -25,9 +25,9 @@ a { color: white; } - </style> + <script> (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), @@ -43,9 +43,9 @@ ga('create', 'UA-68598031-1', 'auto' {'allowLinker':true}); ga('send', 'pageview'); ga('require', 'linker'); - ga('linker:autoLink', ['harrydenley.com', 'metamask.io'], false, true); + ga('linker:autoLink', ['metamask.io'], false, true); </script> - + <script src="phishing-detect.js"></script> </head> <body> @@ -55,6 +55,7 @@ <h3>ATTENTION</h3> <p>MetaMask believes this domain could currently compromise your security and has prevented you from interacting with it.</p> <p>This is because the site tested positive on the <a href="https://github.com/metamask/eth-phishing-detect">Ethereum Phishing Detector</a>. This includes outright malicious websites and legitimate websites that have been compromised by a malicious actor.</p> + <p id="esdbLink"></p> <p>You can turn MetaMask off to interact with this site, but it is advised not to.</p> <p>If you think this domain is incorrectly flagged or if a blocked legitimate website has resolved its security issues, <a href="https://github.com/metamask/eth-phishing-detect/issues/new">please file an issue</a>.</p> diff --git a/app/scripts/background.js b/app/scripts/background.js index 546fef569..ae450352e 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -406,6 +406,7 @@ function setupController (initState, initLangCode) { controller.txController.on('update:badge', updateBadge) controller.messageManager.on('updateBadge', updateBadge) controller.personalMessageManager.on('updateBadge', updateBadge) + controller.typedMessageManager.on('updateBadge', updateBadge) /** * Updates the Web Extension's "badge" number, on the little fox in the toolbar. diff --git a/app/scripts/contentscript.js b/app/scripts/contentscript.js index 6eee1987a..2cbfb811e 100644 --- a/app/scripts/contentscript.js +++ b/app/scripts/contentscript.js @@ -199,5 +199,5 @@ function blacklistedDomainCheck () { function redirectToPhishingWarning () { console.log('MetaMask - routing to Phishing Warning component') const extensionURL = extension.runtime.getURL('phishing.html') - window.location.href = extensionURL + window.location.href = extensionURL + '#' + window.location.hostname } diff --git a/app/scripts/controllers/network/createMetamaskMiddleware.js b/app/scripts/controllers/network/createMetamaskMiddleware.js index 8b17829b7..9e6a45888 100644 --- a/app/scripts/controllers/network/createMetamaskMiddleware.js +++ b/app/scripts/controllers/network/createMetamaskMiddleware.js @@ -38,6 +38,6 @@ function createPendingNonceMiddleware ({ getPendingNonce }) { const address = req.params[0] const blockRef = req.params[1] if (blockRef !== 'pending') return next() - req.result = await getPendingNonce(address) + res.result = await getPendingNonce(address) }) } diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index 59e30cdde..e2965ceb6 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -18,7 +18,7 @@ const { TRANSACTION_STATUS_APPROVED, } = require('./enums') -const { hexToBn, bnToHex } = require('../../lib/util') +const { hexToBn, bnToHex, BnMultiplyByFraction } = require('../../lib/util') /** Transaction Controller is an aggregate of sub-controllers and trackers @@ -244,7 +244,8 @@ class TransactionController extends EventEmitter { const originalTxMeta = this.txStateManager.getTx(originalTxId) const { txParams } = originalTxMeta const { gasPrice: lastGasPrice, from, nonce } = txParams - const newGasPrice = customGasPrice || bnToHex(hexToBn(lastGasPrice).mul(1.1)) + + const newGasPrice = customGasPrice || bnToHex(BnMultiplyByFraction(hexToBn(lastGasPrice), 11, 10)) const newTxMeta = this.txStateManager.generateTxMeta({ txParams: { from, diff --git a/app/scripts/inpage.js b/app/scripts/inpage.js index d9fda1feb..d924be516 100644 --- a/app/scripts/inpage.js +++ b/app/scripts/inpage.js @@ -9,6 +9,11 @@ restoreContextAfterImports() log.setDefaultLevel(process.env.METAMASK_DEBUG ? 'debug' : 'warn') +console.warn('ATTENTION: In an effort to improve user privacy, MetaMask will ' + +'stop exposing user accounts to dapps by default beginning November 2nd, 2018. ' + +'Dapps should call provider.enable() in order to view and use accounts. Please see ' + +'https://bit.ly/2QQHXvF for complete information and up-to-date example code.') + // // setup plugin communication // @@ -52,6 +57,7 @@ if (typeof window.web3 !== 'undefined') { or MetaMask and another web3 extension. Please remove one and try again.`) } + var web3 = new Web3(inpageProvider) web3.setProvider = function () { log.debug('MetaMask - overrode web3.setProvider') diff --git a/app/scripts/lib/auto-reload.js b/app/scripts/lib/auto-reload.js index cce31c3d2..558391a06 100644 --- a/app/scripts/lib/auto-reload.js +++ b/app/scripts/lib/auto-reload.js @@ -2,18 +2,12 @@ module.exports = setupDappAutoReload function setupDappAutoReload (web3, observable) { // export web3 as a global, checking for usage - let hasBeenWarned = false let reloadInProgress = false let lastTimeUsed let lastSeenNetwork global.web3 = new Proxy(web3, { get: (_web3, key) => { - // show warning once on web3 access - if (!hasBeenWarned && key !== 'currentProvider') { - console.warn('MetaMask: web3 will be deprecated in the near future in favor of the ethereumProvider \nhttps://github.com/MetaMask/faq/blob/master/detecting_metamask.md#web3-deprecation') - hasBeenWarned = true - } // get the time of use lastTimeUsed = Date.now() // return value normally diff --git a/app/scripts/lib/ipfsContent.js b/app/scripts/lib/ipfsContent.js index 38682b916..62a808b90 100644 --- a/app/scripts/lib/ipfsContent.js +++ b/app/scripts/lib/ipfsContent.js @@ -5,6 +5,8 @@ module.exports = function (provider) { function ipfsContent (details) { const name = details.url.substring(7, details.url.length - 1) let clearTime = null + if (/^.+\.eth$/.test(name) === false) return + extension.tabs.query({active: true}, tab => { extension.tabs.update(tab.id, { url: 'loading.html' }) diff --git a/app/scripts/lib/typed-message-manager.js b/app/scripts/lib/typed-message-manager.js index e5e1c94b3..b10145f3b 100644 --- a/app/scripts/lib/typed-message-manager.js +++ b/app/scripts/lib/typed-message-manager.js @@ -4,6 +4,7 @@ const createId = require('./random-id') const assert = require('assert') const sigUtil = require('eth-sig-util') const log = require('loglevel') +const jsonschema = require('jsonschema') /** * Represents, and contains data about, an 'eth_signTypedData' type signature request. These are created when a @@ -17,7 +18,7 @@ const log = require('loglevel') * @property {Object} msgParams.from The address that is making the signature request. * @property {string} msgParams.data A hex string conversion of the raw buffer data of the signature request * @property {number} time The epoch time at which the this message was created - * @property {string} status Indicates whether the signature request is 'unapproved', 'approved', 'signed' or 'rejected' + * @property {string} status Indicates whether the signature request is 'unapproved', 'approved', 'signed', 'rejected', or 'errored' * @property {string} type The json-prc signing method for which a signature request has been made. A 'Message' will * always have a 'eth_signTypedData' type. * @@ -26,17 +27,10 @@ const log = require('loglevel') module.exports = class TypedMessageManager extends EventEmitter { /** * Controller in charge of managing - storing, adding, removing, updating - TypedMessage. - * - * @typedef {Object} TypedMessage - * @param {Object} opts @deprecated - * @property {Object} memStore The observable store where TypedMessage are saved. - * @property {Object} memStore.unapprovedTypedMessages A collection of all TypedMessages in the 'unapproved' state - * @property {number} memStore.unapprovedTypedMessagesCount The count of all TypedMessages in this.memStore.unapprobedMsgs - * @property {array} messages Holds all messages that have been created by this TypedMessage - * */ - constructor (opts) { + constructor ({ networkController }) { super() + this.networkController = networkController this.memStore = new ObservableStore({ unapprovedTypedMessages: {}, unapprovedTypedMessagesCount: 0, @@ -76,15 +70,17 @@ module.exports = class TypedMessageManager extends EventEmitter { * @returns {promise} When the message has been signed or rejected * */ - addUnapprovedMessageAsync (msgParams, req) { + addUnapprovedMessageAsync (msgParams, req, version) { return new Promise((resolve, reject) => { - const msgId = this.addUnapprovedMessage(msgParams, req) + const msgId = this.addUnapprovedMessage(msgParams, req, version) this.once(`${msgId}:finished`, (data) => { switch (data.status) { case 'signed': return resolve(data.rawSig) case 'rejected': return reject(new Error('MetaMask Message Signature: User denied message signature.')) + case 'errored': + return reject(new Error(`MetaMask Message Signature: ${data.error}`)) default: return reject(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`)) } @@ -102,7 +98,8 @@ module.exports = class TypedMessageManager extends EventEmitter { * @returns {number} The id of the newly created TypedMessage. * */ - addUnapprovedMessage (msgParams, req) { + addUnapprovedMessage (msgParams, req, version) { + msgParams.version = version this.validateParams(msgParams) // add origin from request if (req) msgParams.origin = req.origin @@ -132,14 +129,33 @@ module.exports = class TypedMessageManager extends EventEmitter { * */ validateParams (params) { - assert.equal(typeof params, 'object', 'Params should ben an object.') - assert.ok('data' in params, 'Params must include a data field.') - assert.ok('from' in params, 'Params must include a from field.') - assert.ok(Array.isArray(params.data), 'Data should be an array.') - assert.equal(typeof params.from, 'string', 'From field must be a string.') - assert.doesNotThrow(() => { - sigUtil.typedSignatureHash(params.data) - }, 'Expected EIP712 typed data') + switch (params.version) { + case 'V1': + assert.equal(typeof params, 'object', 'Params should ben an object.') + assert.ok('data' in params, 'Params must include a data field.') + assert.ok('from' in params, 'Params must include a from field.') + assert.ok(Array.isArray(params.data), 'Data should be an array.') + assert.equal(typeof params.from, 'string', 'From field must be a string.') + assert.doesNotThrow(() => { + sigUtil.typedSignatureHash(params.data) + }, 'Expected EIP712 typed data') + break + case 'V3': + let data + assert.equal(typeof params, 'object', 'Params should be an object.') + assert.ok('data' in params, 'Params must include a data field.') + assert.ok('from' in params, 'Params must include a from field.') + assert.equal(typeof params.from, 'string', 'From field must be a string.') + assert.equal(typeof params.data, 'string', 'Data must be passed as a valid JSON string.') + assert.doesNotThrow(() => { data = JSON.parse(params.data) }, 'Data must be passed as a valid JSON string.') + const validation = jsonschema.validate(data, sigUtil.TYPED_MESSAGE_SCHEMA) + assert.ok(data.primaryType in data.types, `Primary type of "${data.primaryType}" has no type definition.`) + assert.equal(validation.errors.length, 0, 'Data must conform to EIP-712 schema. See https://git.io/fNtcx.') + const chainId = data.domain.chainId + const activeChainId = parseInt(this.networkController.getNetworkState()) + chainId && assert.equal(chainId, activeChainId, `Provided chainId (${chainId}) must match the active chainId (${activeChainId})`) + break + } } /** @@ -214,6 +230,7 @@ module.exports = class TypedMessageManager extends EventEmitter { */ prepMsgForSigning (msgParams) { delete msgParams.metamaskId + delete msgParams.version return Promise.resolve(msgParams) } @@ -227,6 +244,19 @@ module.exports = class TypedMessageManager extends EventEmitter { this._setMsgStatus(msgId, 'rejected') } + /** + * Sets a TypedMessage status to 'errored' via a call to this._setMsgStatus. + * + * @param {number} msgId The id of the TypedMessage to error + * + */ + errorMessage (msgId, error) { + const msg = this.getMsg(msgId) + msg.error = error + this._updateMsg(msg) + this._setMsgStatus(msgId, 'errored') + } + // // PRIVATE METHODS // @@ -250,7 +280,7 @@ module.exports = class TypedMessageManager extends EventEmitter { msg.status = status this._updateMsg(msg) this.emit(`${msgId}:${status}`, msg) - if (status === 'rejected' || status === 'signed') { + if (status === 'rejected' || status === 'signed' || status === 'errored') { this.emit(`${msgId}:finished`, msg) } } diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index f9a12628b..123e17569 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -49,6 +49,8 @@ const log = require('loglevel') const TrezorKeyring = require('eth-trezor-keyring') const LedgerBridgeKeyring = require('eth-ledger-bridge-keyring') const EthQuery = require('eth-query') +const ethUtil = require('ethereumjs-util') +const sigUtil = require('eth-sig-util') module.exports = class MetamaskController extends EventEmitter { @@ -205,7 +207,7 @@ module.exports = class MetamaskController extends EventEmitter { this.networkController.lookupNetwork() this.messageManager = new MessageManager() this.personalMessageManager = new PersonalMessageManager() - this.typedMessageManager = new TypedMessageManager() + this.typedMessageManager = new TypedMessageManager({ networkController: this.networkController }) this.publicConfigStore = this.initPublicConfigStore() this.store.updateStructure({ @@ -250,6 +252,7 @@ module.exports = class MetamaskController extends EventEmitter { eth_syncing: false, web3_clientVersion: `MetaMask/v${version}`, }, + version, // account mgmt getAccounts: async () => { const isUnlocked = this.keyringController.memStore.getState().isUnlocked @@ -266,7 +269,7 @@ module.exports = class MetamaskController extends EventEmitter { // msg signing processEthSignMessage: this.newUnsignedMessage.bind(this), processPersonalMessage: this.newUnsignedPersonalMessage.bind(this), - processTypedMessage: this.newUnsignedTypedMessage.bind(this), + getPendingNonce: this.getPendingNonce.bind(this), } const providerProxy = this.networkController.initializeProvider(providerOpts) return providerProxy @@ -975,22 +978,31 @@ module.exports = class MetamaskController extends EventEmitter { * @param {Object} msgParams - The params passed to eth_signTypedData. * @returns {Object} Full state update. */ - signTypedMessage (msgParams) { - log.info('MetaMaskController - signTypedMessage') + async signTypedMessage (msgParams) { + log.info('MetaMaskController - eth_signTypedData') const msgId = msgParams.metamaskId - // sets the status op the message to 'approved' - // and removes the metamaskId for signing - return this.typedMessageManager.approveMessage(msgParams) - .then((cleanMsgParams) => { - // signs the message - return this.keyringController.signTypedMessage(cleanMsgParams) - }) - .then((rawSig) => { - // tells the listener that the message has been signed - // and can be returned to the dapp - this.typedMessageManager.setMsgStatusSigned(msgId, rawSig) - return this.getState() - }) + const version = msgParams.version + try { + const cleanMsgParams = await this.typedMessageManager.approveMessage(msgParams) + const address = sigUtil.normalize(cleanMsgParams.from) + const keyring = await this.keyringController.getKeyringForAccount(address) + const wallet = keyring._getWalletForAccount(address) + const privKey = ethUtil.toBuffer(wallet.getPrivateKey()) + let signature + switch (version) { + case 'V1': + signature = sigUtil.signTypedDataLegacy(privKey, { data: cleanMsgParams.data }) + break + case 'V3': + signature = sigUtil.signTypedData(privKey, { data: JSON.parse(cleanMsgParams.data) }) + break + } + this.typedMessageManager.setMsgStatusSigned(msgId, signature) + return this.getState() + } catch (error) { + log.info('MetaMaskController - eth_signTypedData failed.', error) + this.typedMessageManager.errorMessage(msgId, error) + } } /** @@ -1241,6 +1253,9 @@ module.exports = class MetamaskController extends EventEmitter { engine.push(createLoggerMiddleware({ origin })) engine.push(filterMiddleware) engine.push(this.preferencesController.requestWatchAsset.bind(this.preferencesController)) + engine.push(this.createTypedDataMiddleware('eth_signTypedData', 'V1').bind(this)) + engine.push(this.createTypedDataMiddleware('eth_signTypedData_v1', 'V1').bind(this)) + engine.push(this.createTypedDataMiddleware('eth_signTypedData_v3', 'V3', true).bind(this)) engine.push(createProviderMiddleware({ provider: this.provider })) // setup connection @@ -1349,6 +1364,19 @@ module.exports = class MetamaskController extends EventEmitter { return '0x' + percentileNumBn.mul(GWEI_BN).toString(16) } + /** + * Returns the nonce that will be associated with a transaction once approved + * @param address {string} - The hex string address for the transaction + * @returns Promise<number> + */ + async getPendingNonce (address) { + const { nonceDetails, releaseLock} = await this.txController.nonceTracker.getNonceLock(address) + const pendingNonce = nonceDetails.params.highestSuggested + + releaseLock() + return pendingNonce + } + //============================================================================= // CONFIG //============================================================================= @@ -1474,4 +1502,34 @@ module.exports = class MetamaskController extends EventEmitter { set isClientOpenAndUnlocked (active) { this.tokenRatesController.isActive = active } + + /** + * Creates RPC engine middleware for processing eth_signTypedData requests + * + * @param {Object} req - request object + * @param {Object} res - response object + * @param {Function} - next + * @param {Function} - end + */ + createTypedDataMiddleware (methodName, version, reverse) { + return async (req, res, next, end) => { + const { method, params } = req + if (method === methodName) { + const promise = this.typedMessageManager.addUnapprovedMessageAsync({ + data: reverse ? params[1] : params[0], + from: reverse ? params[0] : params[1], + }, req, version) + this.sendUpdate() + this.opts.showUnconfirmedMessage() + try { + res.result = await promise + end() + } catch (error) { + end(error) + } + } else { + next() + } + } + } } diff --git a/app/scripts/phishing-detect.js b/app/scripts/phishing-detect.js new file mode 100644 index 000000000..4168b6618 --- /dev/null +++ b/app/scripts/phishing-detect.js @@ -0,0 +1,5 @@ +window.onload = function() { + if (window.location.pathname === '/phishing.html') { + document.getElementById('esdbLink').innerHTML = '<b>To read more about this scam, navigate to: <a href="https://etherscamdb.info/domain/' + window.location.hash.substring(1) + '"> https://etherscamdb.info/domain/' + window.location.hash.substring(1) + '</a></b>' + } +} diff --git a/gulpfile.js b/gulpfile.js index 480f544d8..5a468d2f3 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -229,11 +229,12 @@ function createScssBuildTask ({ src, dest, devMode, pattern }) { await endOfStream(stream) livereload.changed(event.path) }) + return buildScssWithSourceMaps() } return buildScss() } - function buildScss () { + function buildScssWithSourceMaps () { return gulp.src(src) .pipe(sourcemaps.init()) .pipe(sass().on('error', sass.logError)) @@ -241,6 +242,13 @@ function createScssBuildTask ({ src, dest, devMode, pattern }) { .pipe(autoprefixer()) .pipe(gulp.dest(dest)) } + + function buildScss () { + return gulp.src(src) + .pipe(sass().on('error', sass.logError)) + .pipe(autoprefixer()) + .pipe(gulp.dest(dest)) + } } gulp.task('lint-scss', function () { @@ -267,6 +275,7 @@ const buildJsFiles = [ 'contentscript', 'background', 'ui', + 'phishing-detect', ] // bundle tasks diff --git a/mascara/src/app/first-time/create-password-screen.js b/mascara/src/app/first-time/create-password-screen.js index 6b284f7c5..0908787da 100644 --- a/mascara/src/app/first-time/create-password-screen.js +++ b/mascara/src/app/first-time/create-password-screen.js @@ -63,7 +63,9 @@ class CreatePasswordScreen extends Component { return password === confirmPassword } - createAccount = () => { + createAccount = (event) => { + event.preventDefault() + if (!this.isValid()) { return } @@ -127,7 +129,7 @@ class CreatePasswordScreen extends Component { It allows you to hold ether & tokens, and interact with decentralized applications. </div> </div>} - <div className="create-password"> + <form className="create-password"> <div className="create-password__title"> Create Password </div> @@ -188,7 +190,7 @@ class CreatePasswordScreen extends Component { </a> { */ } <Breadcrumbs total={3} currentIndex={0} /> - </div> + </form> </div> </div> ) diff --git a/mascara/src/app/first-time/index.css b/mascara/src/app/first-time/index.css index 2d05a48b8..a575fe97e 100644 --- a/mascara/src/app/first-time/index.css +++ b/mascara/src/app/first-time/index.css @@ -17,6 +17,12 @@ font-family: Roboto; } +@media screen and (min-height: 576px) { + .first-time-flow { + height: 100vh; + } +} + .alpha-warning__container { display: flex; justify-content: center; diff --git a/old-ui/app/components/pending-typed-msg-details.js b/old-ui/app/components/pending-typed-msg-details.js index b5fd29f71..f95bf43a7 100644 --- a/old-ui/app/components/pending-typed-msg-details.js +++ b/old-ui/app/components/pending-typed-msg-details.js @@ -21,7 +21,7 @@ PendingMsgDetails.prototype.render = function () { var identity = state.identities[address] || { address: address } var account = state.accounts[address] || { address: address } - var { data } = msgParams + var { data, version } = msgParams return ( h('div', { @@ -48,6 +48,7 @@ PendingMsgDetails.prototype.render = function () { h('label.font-small', { style: { display: 'block' } }, 'YOU ARE SIGNING'), h(TypedMessageRenderer, { value: data, + version, style: { height: '215px', }, diff --git a/old-ui/app/components/typed-message-renderer.js b/old-ui/app/components/typed-message-renderer.js index 19e46f4fc..0dc673b8a 100644 --- a/old-ui/app/components/typed-message-renderer.js +++ b/old-ui/app/components/typed-message-renderer.js @@ -2,6 +2,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const extend = require('xtend') +const { ObjectInspector } = require('react-inspector') module.exports = TypedMessageRenderer @@ -12,8 +13,16 @@ function TypedMessageRenderer () { TypedMessageRenderer.prototype.render = function () { const props = this.props - const { value, style } = props - const text = renderTypedData(value) + const { value, version, style } = props + let text + switch (version) { + case 'V1': + text = renderTypedData(value) + break + case 'V3': + text = renderTypedDataV3(value) + break + } const defaultStyle = extend({ width: '315px', @@ -44,3 +53,17 @@ function renderTypedData (values) { ]) }) } + +function renderTypedDataV3 (values) { + const { domain, message } = JSON.parse(values) + return [ + domain ? h('div', [ + h('h1', 'Domain'), + h(ObjectInspector, { data: domain, expandLevel: 1, name: 'domain' }), + ]) : '', + message ? h('div', [ + h('h1', 'Message'), + h(ObjectInspector, { data: message, expandLevel: 1, name: 'message' }), + ]) : '', + ] +} diff --git a/package-lock.json b/package-lock.json index 919bee08f..4b6c3f87c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -193,6 +193,110 @@ "integrity": "sha1-lE0MW6KBK7FZ7b0iZ0Ov0mUXm9w=", "dev": true }, + "@babel/polyfill": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.0.0.tgz", + "integrity": "sha512-dnrMRkyyr74CRelJwvgnnSUDh2ge2NCTyHVwpOdvRMHtJUyxLtMAfhBN3s64pY41zdw0kgiLPh6S20eb1NcX6Q==", + "dev": true, + "requires": { + "core-js": "^2.5.7", + "regenerator-runtime": "^0.11.1" + }, + "dependencies": { + "core-js": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", + "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==", + "dev": true + } + } + }, + "@babel/register": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.0.0.tgz", + "integrity": "sha512-f/+CRmaCe7rVEvcvPvxeA8j5aJhHC3aJie7YuqcMDhUOuyWLA7J/aNrTaHIzoWPEhpHA54mec4Mm8fv8KBlv3g==", + "dev": true, + "requires": { + "core-js": "^2.5.7", + "find-cache-dir": "^1.0.0", + "home-or-tmp": "^3.0.0", + "lodash": "^4.17.10", + "mkdirp": "^0.5.1", + "pirates": "^4.0.0", + "source-map-support": "^0.5.9" + }, + "dependencies": { + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "core-js": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", + "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==", + "dev": true + }, + "find-cache-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", + "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^1.0.0", + "pkg-dir": "^2.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "home-or-tmp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-3.0.0.tgz", + "integrity": "sha1-V6j+JM8zzdUkhgoVgh3cJchmcfs=", + "dev": true + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.9.tgz", + "integrity": "sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + } + } + }, "@babel/runtime": { "version": "7.0.0-beta.47", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0-beta.47.tgz", @@ -429,7 +533,7 @@ }, "@sinonjs/formatio": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", + "resolved": "http://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==", "dev": true, "requires": { @@ -1584,6 +1688,12 @@ "@types/react": "*" } }, + "@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true + }, "@zxing/library": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/@zxing/library/-/library-0.8.0.tgz", @@ -1761,6 +1871,716 @@ } } }, + "addons-linter": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/addons-linter/-/addons-linter-1.3.4.tgz", + "integrity": "sha512-G53aPTMZjSyRGWzELPtD7rp15IoSZgE6ZCapra9gPnzK6eDy15gf7diC4C/jcM61lAmRGGWL41dyVB+WlakdkA==", + "dev": true, + "requires": { + "@babel/polyfill": "7.0.0", + "@babel/register": "7.0.0", + "ajv": "6.5.4", + "ajv-merge-patch": "4.1.0", + "chalk": "2.4.0", + "cheerio": "1.0.0-rc.2", + "columnify": "1.5.4", + "common-tags": "1.8.0", + "crx-parser": "0.1.2", + "deepmerge": "2.1.1", + "dispensary": "0.24.0", + "es6-promisify": "5.0.0", + "eslint": "5.0.1", + "eslint-plugin-no-unsafe-innerhtml": "1.0.16", + "eslint-visitor-keys": "1.0.0", + "espree": "4.0.0", + "esprima": "3.1.3", + "first-chunk-stream": "2.0.0", + "fluent-syntax": "0.7.0", + "fsevents": "1.2.4", + "glob": "7.1.3", + "is-mergeable-object": "1.1.0", + "jed": "1.1.1", + "os-locale": "3.0.1", + "pino": "5.5.0", + "po2json": "0.4.5", + "postcss": "6.0.23", + "probe-image-size": "4.0.0", + "relaxed-json": "1.0.1", + "semver": "5.5.1", + "shelljs": "0.8.2", + "snyk": "^1.88.2", + "source-map-support": "0.5.6", + "strip-bom-stream": "3.0.0", + "tosource": "1.0.0", + "upath": "1.1.0", + "whatwg-url": "7.0.0", + "xmldom": "0.1.27", + "yargs": "12.0.1", + "yauzl": "2.9.2" + }, + "dependencies": { + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "dev": true + }, + "acorn-jsx": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-4.1.1.tgz", + "integrity": "sha512-JY+iV6r+cO21KtntVvFkD+iqjtdpRUpGqKWgfkCdZq1R+kbreEl8EcdcJR4SmiIgsIQT33s6QzheQ9a275Q8xw==", + "dev": true, + "requires": { + "acorn": "^5.0.3" + } + }, + "ajv": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.4.tgz", + "integrity": "sha512-4Wyjt8+t6YszqaXnLDfMmG/8AlO5Zbcsy3ATHncCzjW/NoPzAId8AK6749Ybjmdt+kUY1gP60fCu46oDxPv/mg==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz", + "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=", + "dev": true + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "chalk": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.0.tgz", + "integrity": "sha512-Wr/w0f4o9LuE7K53cD0qmbAMM+2XNLzR29vFn5hqko4sxGlUsyy363NvmyGIyk5tpe9cjTr9SJYbysEyPkRnFw==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + } + }, + "common-tags": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", + "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "debug": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", + "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "decamelize": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-2.0.0.tgz", + "integrity": "sha512-Ikpp5scV3MSYxY39ymh45ZLEecsTdv/Xj2CaQfI8RLMuwi7XvjX9H/fhraiSuU+C5w5NTDu4ZU72xNiZnurBPg==", + "dev": true, + "requires": { + "xregexp": "4.0.0" + } + }, + "deepmerge": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.1.1.tgz", + "integrity": "sha512-urQxA1smbLZ2cBbXbaYObM1dJ82aJ2H57A1C/Kklfh/ZN1bgH4G/n5KWhdNfOK11W98gqZfyYj7W4frJJRwA2w==", + "dev": true + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "eslint": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.0.1.tgz", + "integrity": "sha512-D5nG2rErquLUstgUaxJlWB5+gu+U/3VDY0fk/Iuq8y9CUFy/7Y6oF4N2cR1tV8knzQvciIbfqfohd359xTLIKQ==", + "dev": true, + "requires": { + "ajv": "^6.5.0", + "babel-code-frame": "^6.26.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^3.1.0", + "doctrine": "^2.1.0", + "eslint-scope": "^4.0.0", + "eslint-visitor-keys": "^1.0.0", + "espree": "^4.0.0", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.5.0", + "ignore": "^3.3.3", + "imurmurhash": "^0.1.4", + "inquirer": "^5.2.0", + "is-resolvable": "^1.1.0", + "js-yaml": "^3.11.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.5", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "pluralize": "^7.0.0", + "progress": "^2.0.0", + "regexpp": "^1.1.0", + "require-uncached": "^1.0.3", + "semver": "^5.5.0", + "string.prototype.matchall": "^2.0.0", + "strip-ansi": "^4.0.0", + "strip-json-comments": "^2.0.1", + "table": "^4.0.3", + "text-table": "^0.2.0" + } + }, + "eslint-scope": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", + "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "espree": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-4.0.0.tgz", + "integrity": "sha512-kapdTCt1bjmspxStVKX6huolXVV5ZfyZguY1lcfhVVZstce3bqxH9mcLzNn3/mlgW6wQ732+0fuG9v7h0ZQoKg==", + "dev": true, + "requires": { + "acorn": "^5.6.0", + "acorn-jsx": "^4.1.1" + } + }, + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true + }, + "esquery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "dev": true, + "requires": { + "estraverse": "^4.0.0" + } + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "dev": true, + "requires": { + "pend": "~1.2.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "globals": { + "version": "11.7.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz", + "integrity": "sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "inquirer": { + "version": "5.2.0", + "resolved": "http://registry.npmjs.org/inquirer/-/inquirer-5.2.0.tgz", + "integrity": "sha512-E9BmnJbAKLPGonz0HeWHtbKf+EeSP93paWO3ZYoUpq/aowXvYGjjCSuashhXPpzbArIjBbji39THkxTz9ZeEUQ==", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.1.0", + "figures": "^2.0.0", + "lodash": "^4.3.0", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^5.5.2", + "string-width": "^2.1.0", + "strip-ansi": "^4.0.0", + "through": "^2.3.6" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "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", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "dev": true + }, + "js-yaml": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", + "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "dependencies": { + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + } + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "mem": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.0.0.tgz", + "integrity": "sha512-WQxG/5xYc3tMbYLXoXPm81ET2WDULiU5FxbuIoNbJqLOOI8zehXFdZuiUEgfdrU2mVB1pxBZUGlYORSrpuJreA==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^1.0.0", + "p-is-promise": "^1.1.0" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "os-locale": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.0.1.tgz", + "integrity": "sha512-7g5e7dmXPtzcP4bgsZ8ixDVqA7oWYuEz4lOSujeWyliPai4gfVDiFIcwBg3aGCPnmSGfzOKTK3ccPn0CKv3DBw==", + "dev": true, + "requires": { + "execa": "^0.10.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "p-limit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz", + "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", + "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "postcss": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "semver": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", + "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==", + "dev": true + }, + "shelljs": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.2.tgz", + "integrity": "sha512-pRXeNrCA2Wd9itwhvLp5LZQvPJ0wU6bcjaTMywHHGX5XWhVN2nzSu7WV0q+oUY7mGK3mgSkDDzP3MgjqdyIgbQ==", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.6.tgz", + "integrity": "sha512-N4KXEz7jcKqPf2b2vZF11lQIz9W5ZMuUcIOGj243lduidkf2fjkVKJS9vNxVWn3u/uxX38AcE8U9nnH9FPcq+g==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "strip-bom-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-3.0.0.tgz", + "integrity": "sha1-lWvMXYRDD2klapDtgjdlzYWOFZw=", + "dev": true, + "requires": { + "first-chunk-stream": "^2.0.0", + "strip-bom-buf": "^1.0.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "4.0.3", + "resolved": "http://registry.npmjs.org/table/-/table-4.0.3.tgz", + "integrity": "sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg==", + "dev": true, + "requires": { + "ajv": "^6.0.1", + "ajv-keywords": "^3.0.0", + "chalk": "^2.1.0", + "lodash": "^4.17.4", + "slice-ansi": "1.0.0", + "string-width": "^2.1.1" + } + }, + "upath": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", + "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==", + "dev": true + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "whatwg-url": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz", + "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "xregexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.0.0.tgz", + "integrity": "sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg==", + "dev": true + }, + "yargs": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.1.tgz", + "integrity": "sha512-B0vRAp1hRX4jgIOWFtjfNjd9OA9RWYZ6tqGA9/I/IrTMsxmKvtWy+ersM+jzpQqbC3YfLzeABPdeTgcJ9eu1qQ==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^2.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^10.1.0" + }, + "dependencies": { + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "requires": { + "invert-kv": "^1.0.0" + } + }, + "mem": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", + "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "dev": true, + "requires": { + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" + } + } + } + }, + "yargs-parser": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", + "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } + }, + "yauzl": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.9.2.tgz", + "integrity": "sha1-T7G8euH8L1cDe1SvasyP4QMcW3c=", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + } + } + }, "address": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/address/-/address-1.0.3.tgz", @@ -1893,6 +2713,16 @@ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=" }, + "ajv-merge-patch": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ajv-merge-patch/-/ajv-merge-patch-4.1.0.tgz", + "integrity": "sha512-0mAYXMSauA8RZ7r+B4+EAOYcZEcO9OK5EiQCR7W7Cv4E44pJj56ZnkKLJ9/PAcOc0dT+LlV9fdDcq2TxVJfOYw==", + "dev": true, + "requires": { + "fast-json-patch": "^2.0.6", + "json-merge-patch": "^0.2.3" + } + }, "align-text": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", @@ -2155,6 +2985,12 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "array-from": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", + "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", + "dev": true + }, "array-includes": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", @@ -5564,6 +6400,16 @@ "integrity": "sha1-fQAj6usVTo7p/Oddy5I9DtFmd3Q=", "dev": true }, + "columnify": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.5.4.tgz", + "integrity": "sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs=", + "dev": true, + "requires": { + "strip-ansi": "^3.0.0", + "wcwidth": "^1.0.0" + } + }, "combine-lists": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/combine-lists/-/combine-lists-1.0.1.tgz", @@ -5722,6 +6568,20 @@ "proto-list": "~1.2.1" } }, + "configstore": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", + "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", + "dev": true, + "requires": { + "dot-prop": "^4.1.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" + } + }, "connect": { "version": "3.6.6", "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz", @@ -5972,6 +6832,12 @@ "which": "^1.2.9" } }, + "crx-parser": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/crx-parser/-/crx-parser-0.1.2.tgz", + "integrity": "sha1-fu7tnt3JXiLBiTguNGJARKiaWm0=", + "dev": true + }, "cryptiles": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", @@ -6005,6 +6871,12 @@ "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.8.tgz", "integrity": "sha1-cV8HC/YBTyrpkqmLOSkli3E/CNU=" }, + "crypto-random-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", + "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", + "dev": true + }, "css": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/css/-/css-2.2.3.tgz", @@ -6470,8 +7342,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-1.2.0.tgz", "integrity": "sha512-vKQ9DTQPN1FLYiiEEOQ6IBGFqvjCa5rSK3cWMy/Nespm5d/x3dGFT9UBZnkLxCwua/IXBi2TYnwTEpsOvhC4UQ==", - "dev": true, - "optional": true + "dev": true }, "date-format": { "version": "1.2.0", @@ -6736,6 +7607,23 @@ "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=" }, + "defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "dev": true, + "requires": { + "clone": "^1.0.2" + }, + "dependencies": { + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true + } + } + }, "deferred-leveldown": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-1.2.2.tgz", @@ -6771,7 +7659,6 @@ "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-1.0.4.tgz", "integrity": "sha1-/PSQo37OJmRk2cxDGrmMWBnO0JU=", "dev": true, - "optional": true, "requires": { "ast-types": "0.x.x", "escodegen": "1.x.x", @@ -6782,8 +7669,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", - "dev": true, - "optional": true + "dev": true } } }, @@ -6987,6 +7873,361 @@ "integrity": "sha1-44Mx8IRLukm5qctxx3FYWqsbxlo=", "dev": true }, + "dispensary": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/dispensary/-/dispensary-0.24.0.tgz", + "integrity": "sha512-/NptOwKVS117dfX2hcQIqi7pP3I+qWI8uJEeUtmXS2MpuFXFc3tHMzZY8XxLoiFnKb8E9JXXZzflkinyabrMKQ==", + "dev": true, + "requires": { + "array-from": "~2.1.1", + "async": "~2.6.0", + "natural-compare-lite": "~1.4.0", + "pino": "~5.4.0", + "request": "~2.88.0", + "semver": "~5.5.0", + "sha.js": "~2.4.4", + "source-map-support": "~0.5.4", + "yargs": "~12.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "dev": true + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + } + }, + "combined-stream": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", + "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "decamelize": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-2.0.0.tgz", + "integrity": "sha512-Ikpp5scV3MSYxY39ymh45ZLEecsTdv/Xj2CaQfI8RLMuwi7XvjX9H/fhraiSuU+C5w5NTDu4ZU72xNiZnurBPg==", + "dev": true, + "requires": { + "xregexp": "4.0.0" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "har-validator": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz", + "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==", + "dev": true, + "requires": { + "ajv": "^5.3.0", + "har-schema": "^2.0.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "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", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "mem": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.0.0.tgz", + "integrity": "sha512-WQxG/5xYc3tMbYLXoXPm81ET2WDULiU5FxbuIoNbJqLOOI8zehXFdZuiUEgfdrU2mVB1pxBZUGlYORSrpuJreA==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^1.0.0", + "p-is-promise": "^1.1.0" + } + }, + "mime-db": { + "version": "1.36.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", + "integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==", + "dev": true + }, + "mime-types": { + "version": "2.1.20", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", + "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", + "dev": true, + "requires": { + "mime-db": "~1.36.0" + } + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "os-locale": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.0.1.tgz", + "integrity": "sha512-7g5e7dmXPtzcP4bgsZ8ixDVqA7oWYuEz4lOSujeWyliPai4gfVDiFIcwBg3aGCPnmSGfzOKTK3ccPn0CKv3DBw==", + "dev": true, + "requires": { + "execa": "^0.10.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "p-limit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz", + "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", + "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "pino": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/pino/-/pino-5.4.1.tgz", + "integrity": "sha512-CevmEuLU4MZRkI/P0ulcZaz5vDbruNJdI+m83zdHcwfhU2J+30uxeKaLLPl5D3jXBoH+QcnjMUKtd59DLxJB2g==", + "dev": true, + "requires": { + "fast-json-parse": "^1.0.3", + "fast-redact": "^1.1.14", + "fast-safe-stringify": "^2.0.4", + "flatstr": "^1.0.5", + "pino-std-serializers": "^2.2.0", + "pump": "^3.0.0", + "quick-format-unescaped": "^3.0.0", + "sonic-boom": "^0.6.0" + } + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "semver": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", + "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.9.tgz", + "integrity": "sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "dev": true, + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + } + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "xregexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.0.0.tgz", + "integrity": "sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg==", + "dev": true + }, + "yargs": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.2.tgz", + "integrity": "sha512-e7SkEx6N6SIZ5c5H22RTZae61qtn3PYUE8JYbBFlK9sYmh3DMQ6E5ygtaG/2BW0JZi4WGgTR2IV5ChqlqrDGVQ==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^2.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^10.1.0" + } + }, + "yargs-parser": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", + "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } + } + } + }, "dnode": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/dnode/-/dnode-1.2.2.tgz", @@ -7255,6 +8496,15 @@ "integrity": "sha1-9k0h7b5v8xFJlfEGGmGpNcMAIEs=", "dev": true }, + "dot-prop": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", + "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "dev": true, + "requires": { + "is-obj": "^1.0.0" + } + }, "dotenv": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-5.0.1.tgz", @@ -7434,6 +8684,12 @@ "minimalistic-crypto-utils": "^1.0.0" } }, + "email-validator": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/email-validator/-/email-validator-2.0.4.tgz", + "integrity": "sha512-gYCwo7kh5S3IDyZPLZf6hSS0MnZT8QmJFqYvbqlDZSbwdZlY6QZWxJ4i/6UhITOJ4XzyI647Bm2MXKCLqnJ4nQ==", + "dev": true + }, "emojis-list": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", @@ -7998,6 +9254,235 @@ } } }, + "eslint-plugin-no-unsafe-innerhtml": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/eslint-plugin-no-unsafe-innerhtml/-/eslint-plugin-no-unsafe-innerhtml-1.0.16.tgz", + "integrity": "sha1-fQKHjI6b95FriINtWsEitC8VGTI=", + "dev": true, + "requires": { + "eslint": "^3.7.1" + }, + "dependencies": { + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "dev": true, + "requires": { + "co": "^4.6.0", + "json-stable-stringify": "^1.0.1" + } + }, + "ajv-keywords": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", + "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=", + "dev": true + }, + "ansi-escapes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", + "dev": true + }, + "cli-cursor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", + "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "dev": true, + "requires": { + "restore-cursor": "^1.0.1" + } + }, + "eslint": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz", + "integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=", + "dev": true, + "requires": { + "babel-code-frame": "^6.16.0", + "chalk": "^1.1.3", + "concat-stream": "^1.5.2", + "debug": "^2.1.1", + "doctrine": "^2.0.0", + "escope": "^3.6.0", + "espree": "^3.4.0", + "esquery": "^1.0.0", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "glob": "^7.0.3", + "globals": "^9.14.0", + "ignore": "^3.2.0", + "imurmurhash": "^0.1.4", + "inquirer": "^0.12.0", + "is-my-json-valid": "^2.10.0", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.5.1", + "json-stable-stringify": "^1.0.0", + "levn": "^0.3.0", + "lodash": "^4.0.0", + "mkdirp": "^0.5.0", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.1", + "pluralize": "^1.2.1", + "progress": "^1.1.8", + "require-uncached": "^1.0.2", + "shelljs": "^0.7.5", + "strip-bom": "^3.0.0", + "strip-json-comments": "~2.0.1", + "table": "^3.7.8", + "text-table": "~0.2.0", + "user-home": "^2.0.0" + } + }, + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + } + }, + "inquirer": { + "version": "0.12.0", + "resolved": "http://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", + "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", + "dev": true, + "requires": { + "ansi-escapes": "^1.1.0", + "ansi-regex": "^2.0.0", + "chalk": "^1.0.0", + "cli-cursor": "^1.0.1", + "cli-width": "^2.0.0", + "figures": "^1.3.5", + "lodash": "^4.3.0", + "readline2": "^1.0.1", + "run-async": "^0.1.0", + "rx-lite": "^3.1.2", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.0", + "through": "^2.3.6" + } + }, + "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", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "onetime": { + "version": "1.1.0", + "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", + "dev": true + }, + "pluralize": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", + "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=", + "dev": true + }, + "progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", + "dev": true + }, + "restore-cursor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", + "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "dev": true, + "requires": { + "exit-hook": "^1.0.0", + "onetime": "^1.0.0" + } + }, + "run-async": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", + "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", + "dev": true, + "requires": { + "once": "^1.3.0" + } + }, + "rx-lite": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", + "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=", + "dev": true + }, + "shelljs": { + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", + "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, + "slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", + "dev": true + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "table": { + "version": "3.8.3", + "resolved": "http://registry.npmjs.org/table/-/table-3.8.3.tgz", + "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", + "dev": true, + "requires": { + "ajv": "^4.7.0", + "ajv-keywords": "^1.0.0", + "chalk": "^1.1.1", + "lodash": "^4.0.0", + "slice-ansi": "0.0.4", + "string-width": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + } + } + }, "eslint-plugin-react": { "version": "7.5.1", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.5.1.tgz", @@ -8086,12 +9571,13 @@ } }, "eth-block-tracker": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-4.0.1.tgz", - "integrity": "sha512-ytJxddJ0TMcJHYxPlgGhMyr5EH6/Kyp3bg0WsjXgY9X0uYX3xVHTTeU5WVX6KX+9oJ37ZLUjh5PZ6VYnF1Fx/Q==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-4.0.2.tgz", + "integrity": "sha512-5DHm+9zLOSnUNYUXv1TaZMgGPmT3fuOyPxEnqBrOIVxICbt/AjXypkHnrp+6yIWWWFDhpq58boMdzWb+8Rmt9g==", "requires": { "eth-json-rpc-infura": "^3.1.0", "eth-query": "^2.1.0", + "events": "^3.0.0", "pify": "^3.0.0" }, "dependencies": { @@ -8150,20 +9636,25 @@ "secp256k1": "^3.0.1" } }, + "events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", + "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==" + }, "node-fetch": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz", + "resolved": "http://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz", "integrity": "sha1-q4hOjn5X44qUR1POxwb3iNF2i7U=" }, "whatwg-fetch": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", + "resolved": "http://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", "integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==" } } }, "eth-contract-metadata": { - "version": "github:MetaMask/eth-contract-metadata#2da362052a312dc6c72a7eec116abf6284664f50", + "version": "github:MetaMask/eth-contract-metadata#966a891dd9c79b873fd8968a0155b067ca630502", "from": "github:MetaMask/eth-contract-metadata#master" }, "eth-ens-namehash": { @@ -8195,6 +9686,33 @@ "xtend": "^4.0.1" }, "dependencies": { + "eth-sig-util": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", + "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", + "requires": { + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "ethereumjs-util": "^5.1.1" + }, + "dependencies": { + "ethereumjs-abi": { + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "requires": { + "bn.js": "^4.10.0", + "ethereumjs-util": "^5.0.0" + } + } + } + }, + "ethereumjs-abi": { + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "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", @@ -8223,6 +9741,15 @@ "lodash.flatmap": "^4.5.0" }, "dependencies": { + "babelify": { + "version": "7.3.0", + "resolved": "http://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", + "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", + "requires": { + "babel-core": "^6.0.14", + "object-assign": "^4.0.0" + } + }, "eth-json-rpc-middleware": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.6.0.tgz", @@ -8275,6 +9802,19 @@ "requires": { "promise-to-callback": "^1.0.0" } + }, + "json-rpc-engine": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-3.7.3.tgz", + "integrity": "sha512-+FO3UWu/wafh/+MZ6BXy0HZU+f5plwUn82FgxpC0scJkEh5snOjFrAAtqCITPDfvfLHRUFOG5pQDUx2pspfERQ==", + "requires": { + "async": "^2.0.1", + "babel-preset-env": "^1.3.2", + "babelify": "^7.3.0", + "clone": "^2.1.1", + "json-rpc-error": "^2.0.0", + "promise-to-callback": "^1.0.0" + } } } }, @@ -8289,6 +9829,15 @@ "tape": "^4.8.0" }, "dependencies": { + "babelify": { + "version": "7.3.0", + "resolved": "http://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", + "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", + "requires": { + "babel-core": "^6.0.14", + "object-assign": "^4.0.0" + } + }, "eth-json-rpc-middleware": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.6.0.tgz", @@ -8322,6 +9871,19 @@ "safe-buffer": "^5.1.1", "secp256k1": "^3.0.1" } + }, + "json-rpc-engine": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-3.7.3.tgz", + "integrity": "sha512-+FO3UWu/wafh/+MZ6BXy0HZU+f5plwUn82FgxpC0scJkEh5snOjFrAAtqCITPDfvfLHRUFOG5pQDUx2pspfERQ==", + "requires": { + "async": "^2.0.1", + "babel-preset-env": "^1.3.2", + "babelify": "^7.3.0", + "clone": "^2.1.1", + "json-rpc-error": "^2.0.0", + "promise-to-callback": "^1.0.0" + } } } }, @@ -8348,6 +9910,42 @@ "tape": "^4.6.3" }, "dependencies": { + "babelify": { + "version": "7.3.0", + "resolved": "http://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", + "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", + "requires": { + "babel-core": "^6.0.14", + "object-assign": "^4.0.0" + } + }, + "eth-sig-util": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", + "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", + "requires": { + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "ethereumjs-util": "^5.1.1" + }, + "dependencies": { + "ethereumjs-abi": { + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "requires": { + "bn.js": "^4.10.0", + "ethereumjs-util": "^5.0.0" + } + } + } + }, + "ethereumjs-abi": { + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "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", @@ -8361,6 +9959,19 @@ "safe-buffer": "^5.1.1", "secp256k1": "^3.0.1" } + }, + "json-rpc-engine": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-3.7.3.tgz", + "integrity": "sha512-+FO3UWu/wafh/+MZ6BXy0HZU+f5plwUn82FgxpC0scJkEh5snOjFrAAtqCITPDfvfLHRUFOG5pQDUx2pspfERQ==", + "requires": { + "async": "^2.0.1", + "babel-preset-env": "^1.3.2", + "babelify": "^7.3.0", + "clone": "^2.1.1", + "json-rpc-error": "^2.0.0", + "promise-to-callback": "^1.0.0" + } } } }, @@ -8403,6 +10014,33 @@ "xtend": "^4.0.1" } }, + "eth-sig-util": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", + "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", + "requires": { + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "ethereumjs-util": "^5.1.1" + }, + "dependencies": { + "ethereumjs-abi": { + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "requires": { + "bn.js": "^4.10.0", + "ethereumjs-util": "^5.0.0" + } + } + } + }, + "ethereumjs-abi": { + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "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", @@ -8443,11 +10081,38 @@ "hdkey": "0.8.0" }, "dependencies": { + "eth-sig-util": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", + "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", + "requires": { + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "ethereumjs-util": "^5.1.1" + }, + "dependencies": { + "ethereumjs-abi": { + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "requires": { + "bn.js": "^4.10.0", + "ethereumjs-util": "^5.0.0" + } + } + } + }, "ethereum-common": { "version": "0.0.18", "resolved": "https://registry.npmjs.org/ethereum-common/-/ethereum-common-0.0.18.tgz", "integrity": "sha1-L9w1dvIykDNYl26znaeDIT/5Uj8=" }, + "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-tx": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-1.3.7.tgz", @@ -8623,28 +10288,43 @@ } }, "eth-sig-util": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", - "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-2.0.2.tgz", + "integrity": "sha512-tB6E8jf/aZQ943bo3+iojl8xRe3Jzcl+9OT6v8K7kWis6PdIX19SB2vYvN849cB9G9m/XLjYFK381SgdbsnpTA==", "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "ethereumjs-abi": "0.6.5", "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", + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.5.tgz", + "integrity": "sha1-WmN+8Wq0NHP6cqKa2QhxQFs/UkE=", "requires": { "bn.js": "^4.10.0", - "ethereumjs-util": "^5.0.0" + "ethereumjs-util": "^4.3.0" + }, + "dependencies": { + "ethereumjs-util": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-4.5.0.tgz", + "integrity": "sha1-PpQosxfuvaPXJg2FT93alUsfG8Y=", + "requires": { + "bn.js": "^4.8.0", + "create-hash": "^1.1.2", + "keccakjs": "^0.2.0", + "rlp": "^2.0.0", + "secp256k1": "^3.0.1" + } + } } }, "ethereumjs-util": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.1.3.tgz", - "integrity": "sha512-U/wmHagElZVxnpo3bFsvk5beFADegUcEzqtA/NfQbitAPOs6JoYq8M4SY9NfH4HD8236i63UOkkXafd7bqBL9A==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", + "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", "requires": { - "bn.js": "^4.8.0", + "bn.js": "^4.11.0", "create-hash": "^1.1.2", "ethjs-util": "^0.1.3", "keccak": "^1.0.2", @@ -8896,11 +10576,38 @@ "hdkey": "0.8.0" }, "dependencies": { + "eth-sig-util": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", + "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", + "requires": { + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "ethereumjs-util": "^5.1.1" + }, + "dependencies": { + "ethereumjs-abi": { + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "requires": { + "bn.js": "^4.10.0", + "ethereumjs-util": "^5.0.0" + } + } + } + }, "ethereum-common": { "version": "0.0.18", "resolved": "https://registry.npmjs.org/ethereum-common/-/ethereum-common-0.0.18.tgz", "integrity": "sha1-L9w1dvIykDNYl26znaeDIT/5Uj8=" }, + "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-tx": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-1.3.6.tgz", @@ -8961,6 +10668,15 @@ "web3-provider-engine": "^13.3.2" }, "dependencies": { + "babelify": { + "version": "7.3.0", + "resolved": "http://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", + "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", + "requires": { + "babel-core": "^6.0.14", + "object-assign": "^4.0.0" + } + }, "eth-block-tracker": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-2.3.1.tgz", @@ -8999,6 +10715,14 @@ } } }, + "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", @@ -9047,6 +10771,19 @@ } } }, + "json-rpc-engine": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-3.7.3.tgz", + "integrity": "sha512-+FO3UWu/wafh/+MZ6BXy0HZU+f5plwUn82FgxpC0scJkEh5snOjFrAAtqCITPDfvfLHRUFOG5pQDUx2pspfERQ==", + "requires": { + "async": "^2.0.1", + "babel-preset-env": "^1.3.2", + "babelify": "^7.3.0", + "clone": "^2.1.1", + "json-rpc-error": "^2.0.0", + "promise-to-callback": "^1.0.0" + } + }, "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", @@ -9078,6 +10815,33 @@ "xtend": "^4.0.1" }, "dependencies": { + "eth-sig-util": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", + "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", + "requires": { + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "ethereumjs-util": "^5.1.1" + }, + "dependencies": { + "ethereumjs-abi": { + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "requires": { + "bn.js": "^4.10.0", + "ethereumjs-util": "^5.0.0" + } + } + } + }, + "ethereumjs-abi": { + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "requires": { + "bn.js": "^4.10.0", + "ethereumjs-util": "^5.0.0" + } + }, "ethereumjs-util": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", @@ -9664,7 +11428,7 @@ }, "event-stream": { "version": "3.3.4", - "resolved": "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", "dev": true, "requires": { @@ -9775,6 +11539,12 @@ "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", "dev": true }, + "exit-hook": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", + "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", + "dev": true + }, "expand-braces": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/expand-braces/-/expand-braces-0.1.2.tgz", @@ -10068,6 +11838,12 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=" }, + "fast-json-parse": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fast-json-parse/-/fast-json-parse-1.0.3.tgz", + "integrity": "sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==", + "dev": true + }, "fast-json-patch": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-2.0.6.tgz", @@ -10092,6 +11868,18 @@ "integrity": "sha512-h2avnhux4p3tXTA9xR7ntnQSFQdY4hAkyNj8wDXlVT2Die38JxVCInnrieuktdxzRevRWa3dBjN+SbQe1os0GQ==", "dev": true }, + "fast-redact": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-1.2.0.tgz", + "integrity": "sha512-k/uSk9PtFmvYx0m7bRk5B2gZChQk4euWhrn7Mf3vYSmwZBLh7cGNuMuc/vhH1MKMPyVJMMtl9oMwPnwlKqs7CQ==", + "dev": true + }, + "fast-safe-stringify": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz", + "integrity": "sha512-q8BZ89jjc+mz08rSxROs8VsrBBcn1SIw1kq9NjolL509tkABRk9io01RAjSaEv1Xb2uFLt8VtRiZbGp5H8iDtg==", + "dev": true + }, "fastparse": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.1.tgz", @@ -10208,8 +11996,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "dev": true, - "optional": true + "dev": true }, "filename-regex": { "version": "2.0.1", @@ -10719,11 +12506,23 @@ } } }, + "flatstr": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/flatstr/-/flatstr-1.0.8.tgz", + "integrity": "sha512-YXblbv/vc1zuVVUtnKl1hPqqk7TalZCppnKE7Pr8FI/Rp48vzckS/4SJ4Y9O9RNiI82Vcw/FydmtqdQOg1Dpqw==", + "dev": true + }, "flatten": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/flatten/-/flatten-0.0.1.tgz", "integrity": "sha1-VURAdm2goNYDmZ9DNFP2wvxqdcE=" }, + "fluent-syntax": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/fluent-syntax/-/fluent-syntax-0.7.0.tgz", + "integrity": "sha512-T0iqfhC40jrs3aDjYOKgzIQjjhsH2Fa6LnXB6naPv0ymW3DeYMUFa89y9aLKMpi1P9nl2vEimK7blx4tVnUWBg==", + "dev": true + }, "flush-write-stream": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz", @@ -10958,21 +12757,25 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "optional": true }, "ansi-regex": { "version": "2.1.1", - "bundled": true + "resolved": false, + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, "aproba": { "version": "1.2.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "optional": true }, "are-we-there-yet": { "version": "1.1.4", - "bundled": true, + "resolved": false, + "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", "optional": true, "requires": { "delegates": "^1.0.0", @@ -10981,11 +12784,13 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true + "resolved": false, + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "brace-expansion": { "version": "1.1.11", - "bundled": true, + "resolved": false, + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -10993,29 +12798,35 @@ }, "chownr": { "version": "1.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", "optional": true }, "code-point-at": { "version": "1.1.0", - "bundled": true + "resolved": false, + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "concat-map": { "version": "0.0.1", - "bundled": true + "resolved": false, + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "resolved": false, + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" }, "core-util-is": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "optional": true }, "debug": { "version": "2.6.9", - "bundled": true, + "resolved": false, + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "optional": true, "requires": { "ms": "2.0.0" @@ -11023,22 +12834,26 @@ }, "deep-extend": { "version": "0.5.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==", "optional": true }, "delegates": { "version": "1.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "optional": true }, "detect-libc": { "version": "1.0.3", - "bundled": true, + "resolved": false, + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "optional": true }, "fs-minipass": { "version": "1.2.5", - "bundled": true, + "resolved": false, + "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", "optional": true, "requires": { "minipass": "^2.2.1" @@ -11046,12 +12861,14 @@ }, "fs.realpath": { "version": "1.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "optional": true }, "gauge": { "version": "2.7.4", - "bundled": true, + "resolved": false, + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "optional": true, "requires": { "aproba": "^1.0.3", @@ -11066,7 +12883,8 @@ }, "glob": { "version": "7.1.2", - "bundled": true, + "resolved": false, + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "optional": true, "requires": { "fs.realpath": "^1.0.0", @@ -11079,12 +12897,14 @@ }, "has-unicode": { "version": "2.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "optional": true }, "iconv-lite": { "version": "0.4.21", - "bundled": true, + "resolved": false, + "integrity": "sha512-En5V9za5mBt2oUA03WGD3TwDv0MKAruqsuxstbMUZaj9W9k/m1CV/9py3l0L5kw9Bln8fdHQmzHSYtvpvTLpKw==", "optional": true, "requires": { "safer-buffer": "^2.1.0" @@ -11092,7 +12912,8 @@ }, "ignore-walk": { "version": "3.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", "optional": true, "requires": { "minimatch": "^3.0.4" @@ -11100,7 +12921,8 @@ }, "inflight": { "version": "1.0.6", - "bundled": true, + "resolved": false, + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "optional": true, "requires": { "once": "^1.3.0", @@ -11109,39 +12931,46 @@ }, "inherits": { "version": "2.0.3", - "bundled": true + "resolved": false, + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "ini": { "version": "1.3.5", - "bundled": true, + "resolved": false, + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "requires": { "number-is-nan": "^1.0.0" } }, "isarray": { "version": "1.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "optional": true }, "minimatch": { "version": "3.0.4", - "bundled": true, + "resolved": false, + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true + "resolved": false, + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, "minipass": { "version": "2.2.4", - "bundled": true, + "resolved": false, + "integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==", "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -11149,7 +12978,8 @@ }, "minizlib": { "version": "1.1.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==", "optional": true, "requires": { "minipass": "^2.2.1" @@ -11157,14 +12987,16 @@ }, "mkdirp": { "version": "0.5.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "requires": { "minimist": "0.0.8" } }, "ms": { "version": "2.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "optional": true }, "nan": { @@ -11175,7 +13007,8 @@ }, "needle": { "version": "2.2.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-eFagy6c+TYayorXw/qtAdSvaUpEbBsDwDyxYFgLZ0lTojfH7K+OdBqAF7TAFwDokJaGpubpSGG0wO3iC0XPi8w==", "optional": true, "requires": { "debug": "^2.1.2", @@ -11185,7 +13018,8 @@ }, "node-pre-gyp": { "version": "0.10.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-G7kEonQLRbcA/mOoFoxvlMrw6Q6dPf92+t/l0DFSMuSlDoWaI9JWIyPwK0jyE1bph//CUEL65/Fz1m2vJbmjQQ==", "optional": true, "requires": { "detect-libc": "^1.0.2", @@ -11202,7 +13036,8 @@ }, "nopt": { "version": "4.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "optional": true, "requires": { "abbrev": "1", @@ -11211,12 +13046,14 @@ }, "npm-bundled": { "version": "1.0.3", - "bundled": true, + "resolved": false, + "integrity": "sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow==", "optional": true }, "npm-packlist": { "version": "1.1.10", - "bundled": true, + "resolved": false, + "integrity": "sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA==", "optional": true, "requires": { "ignore-walk": "^3.0.1", @@ -11225,7 +13062,8 @@ }, "npmlog": { "version": "4.1.2", - "bundled": true, + "resolved": false, + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "optional": true, "requires": { "are-we-there-yet": "~1.1.2", @@ -11236,33 +13074,39 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "resolved": false, + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "object-assign": { "version": "4.1.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "optional": true }, "once": { "version": "1.4.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { "wrappy": "1" } }, "os-homedir": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "optional": true }, "os-tmpdir": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "optional": true }, "osenv": { "version": "0.1.5", - "bundled": true, + "resolved": false, + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "optional": true, "requires": { "os-homedir": "^1.0.0", @@ -11271,17 +13115,20 @@ }, "path-is-absolute": { "version": "1.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "optional": true }, "process-nextick-args": { "version": "2.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "optional": true }, "rc": { "version": "1.2.7", - "bundled": true, + "resolved": false, + "integrity": "sha512-LdLD8xD4zzLsAT5xyushXDNscEjB7+2ulnl8+r1pnESlYtlJtVSoCMBGr30eDRJ3+2Gq89jK9P9e4tCEH1+ywA==", "optional": true, "requires": { "deep-extend": "^0.5.1", @@ -11292,14 +13139,16 @@ "dependencies": { "minimist": { "version": "1.2.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "optional": true } } }, "readable-stream": { "version": "2.3.6", - "bundled": true, + "resolved": false, + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "optional": true, "requires": { "core-util-is": "~1.0.0", @@ -11313,7 +13162,8 @@ }, "rimraf": { "version": "2.6.2", - "bundled": true, + "resolved": false, + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "optional": true, "requires": { "glob": "^7.0.5" @@ -11321,36 +13171,43 @@ }, "safe-buffer": { "version": "5.1.1", - "bundled": true + "resolved": false, + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" }, "safer-buffer": { "version": "2.1.2", - "bundled": true, + "resolved": false, + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "optional": true }, "sax": { "version": "1.2.4", - "bundled": true, + "resolved": false, + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "optional": true }, "semver": { "version": "5.5.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", "optional": true }, "set-blocking": { "version": "2.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "optional": true }, "signal-exit": { "version": "3.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "optional": true }, "string-width": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -11359,7 +13216,8 @@ }, "string_decoder": { "version": "1.1.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "optional": true, "requires": { "safe-buffer": "~5.1.0" @@ -11367,19 +13225,22 @@ }, "strip-ansi": { "version": "3.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { "ansi-regex": "^2.0.0" } }, "strip-json-comments": { "version": "2.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "optional": true }, "tar": { "version": "4.4.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-O+v1r9yN4tOsvl90p5HAP4AEqbYhx4036AGMm075fH9F8Qwi3oJ+v4u50FkT/KkvywNGtwkk0zRI+8eYm1X/xg==", "optional": true, "requires": { "chownr": "^1.0.1", @@ -11393,12 +13254,14 @@ }, "util-deprecate": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "optional": true }, "wide-align": { "version": "1.1.2", - "bundled": true, + "resolved": false, + "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", "optional": true, "requires": { "string-width": "^1.0.2" @@ -11406,11 +13269,13 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true + "resolved": false, + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "yallist": { "version": "3.0.2", - "bundled": true + "resolved": false, + "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=" } } }, @@ -11430,7 +13295,6 @@ "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", "integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=", "dev": true, - "optional": true, "requires": { "readable-stream": "1.1.x", "xregexp": "2.0.0" @@ -11440,15 +13304,13 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true, - "optional": true + "dev": true }, "readable-stream": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true, - "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", @@ -11460,8 +13322,7 @@ "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true, - "optional": true + "dev": true } } }, @@ -11574,11 +13435,20 @@ "xtend": "~4.0.0" } }, + "babelify": { + "version": "7.3.0", + "resolved": "http://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", + "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", + "dev": true, + "requires": { + "babel-core": "^6.0.14", + "object-assign": "^4.0.0" + } + }, "bn.js": { "version": "4.11.6", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", - "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=", - "dev": true + "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=" }, "chai": { "version": "3.5.0", @@ -11702,6 +13572,14 @@ "integrity": "sha1-mh4Wnq00q3XgifUMpRK/0PvRJlU=", "dev": true }, + "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-block": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/ethereumjs-block/-/ethereumjs-block-1.2.2.tgz", @@ -11758,7 +13636,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", - "dev": true, "requires": { "bn.js": "^4.11.0", "create-hash": "^1.1.2", @@ -11809,6 +13686,20 @@ } } }, + "json-rpc-engine": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-3.7.3.tgz", + "integrity": "sha512-+FO3UWu/wafh/+MZ6BXy0HZU+f5plwUn82FgxpC0scJkEh5snOjFrAAtqCITPDfvfLHRUFOG5pQDUx2pspfERQ==", + "dev": true, + "requires": { + "async": "^2.0.1", + "babel-preset-env": "^1.3.2", + "babelify": "^7.3.0", + "clone": "^2.1.1", + "json-rpc-error": "^2.0.0", + "promise-to-callback": "^1.0.0" + } + }, "node-fetch": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz", @@ -11922,6 +13813,37 @@ "ws": "^5.1.1", "xhr": "^2.2.0", "xtend": "^4.0.1" + }, + "dependencies": { + "eth-sig-util": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", + "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", + "dev": true, + "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", + "dev": true, + "requires": { + "bn.js": "^4.10.0", + "ethereumjs-util": "^5.0.0" + } + } + } + }, + "ethereumjs-abi": { + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "requires": { + "bn.js": "^4.10.0", + "ethereumjs-util": "^5.0.0" + } + } } }, "whatwg-fetch": { @@ -12109,15 +14031,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", - "dev": true, - "optional": true + "dev": true }, "generate-object-property": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", "dev": true, - "optional": true, "requires": { "is-property": "^1.0.0" } @@ -12161,7 +14081,6 @@ "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-2.0.2.tgz", "integrity": "sha512-ZD325dMZOgerGqF/rF6vZXyFGTAay62svjQIT+X/oU2PtxYpFxvSkbsdi+oxIrsNxlZVd4y8wUDqkaExWTI/Cw==", "dev": true, - "optional": true, "requires": { "data-uri-to-buffer": "1", "debug": "2", @@ -12184,6 +14103,15 @@ "assert-plus": "^1.0.0" } }, + "gettext-parser": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/gettext-parser/-/gettext-parser-1.1.0.tgz", + "integrity": "sha1-LFpmONiTk0ubVQN9CtgstwBLJnk=", + "dev": true, + "requires": { + "encoding": "^0.1.11" + } + }, "gh-pages": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-1.2.0.tgz", @@ -12210,7 +14138,7 @@ }, "commander": { "version": "2.15.1", - "resolved": "http://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", "dev": true }, @@ -12509,6 +14437,15 @@ "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", "dev": true }, + "graphlib": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.5.tgz", + "integrity": "sha512-XvtbqCcw+EM5SqQrIetIKKD+uZVNQtDPD1goIg7K73RuRZtVI5rYMdcCVSHm/AS1sCBZ7vt0p5WgXouucHQaOA==", + "dev": true, + "requires": { + "lodash": "^4.11.1" + } + }, "growl": { "version": "1.10.3", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz", @@ -13937,6 +15874,12 @@ } } }, + "has-color": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", + "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=", + "dev": true + }, "has-cors": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", @@ -14041,6 +15984,23 @@ } } }, + "hasbin": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/hasbin/-/hasbin-1.2.3.tgz", + "integrity": "sha1-eMWSaJPIAhXCtWiuH9P8q3omlrA=", + "dev": true, + "requires": { + "async": "~1.5" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + } + } + }, "hash-base": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz", @@ -14614,6 +16574,45 @@ "requires": { "normalize-url": "^1.0.0", "strip-url-auth": "^1.0.0" + }, + "dependencies": { + "normalize-url": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", + "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", + "dev": true, + "requires": { + "object-assign": "^4.0.1", + "prepend-http": "^1.0.0", + "query-string": "^4.1.0", + "sort-keys": "^1.0.0" + } + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + }, + "query-string": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", + "dev": true, + "requires": { + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, + "sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "dev": true, + "requires": { + "is-plain-obj": "^1.0.0" + } + } } }, "humble-localstorage": { @@ -15210,8 +17209,7 @@ "is-dom": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/is-dom/-/is-dom-1.0.9.tgz", - "integrity": "sha1-SDgy1SlyBz3hK5/j9gMghw2oNw0=", - "dev": true + "integrity": "sha1-SDgy1SlyBz3hK5/j9gMghw2oNw0=" }, "is-dotfile": { "version": "1.0.3", @@ -15285,19 +17283,23 @@ "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", "integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=" }, + "is-mergeable-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-mergeable-object/-/is-mergeable-object-1.1.0.tgz", + "integrity": "sha512-JfyDDwUdtS4yHCgUpxOyKB9dnfZ0gecufxB0eytX6BmSXSE+8dbxDGt+V7CNRIRJ9sYFV/WQt2KJG6hNob2sBw==", + "dev": true + }, "is-my-ip-valid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==", - "dev": true, - "optional": true + "dev": true }, "is-my-json-valid": { "version": "2.17.2", "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz", "integrity": "sha512-IBhBslgngMQN8DDSppmgDv7RNrlFotuuDsKcrCP3+HbFaVivIBU7u9oiiErw8sH4ynx3+gOGQ3q2otkgiSi6kg==", "dev": true, - "optional": true, "requires": { "generate-function": "^2.0.0", "generate-object-property": "^1.1.0", @@ -15417,8 +17419,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", - "dev": true, - "optional": true + "dev": true }, "is-redirect": { "version": "1.0.0", @@ -15741,6 +17742,12 @@ "raphael": "^2.2.0" } }, + "jed": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/jed/-/jed-1.1.1.tgz", + "integrity": "sha1-elSbvZ/+FYWwzQoZHiAwVb7ldLQ=", + "dev": true + }, "js-base64": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.3.tgz", @@ -16027,6 +18034,15 @@ "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz", "integrity": "sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w==" }, + "json-merge-patch": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-merge-patch/-/json-merge-patch-0.2.3.tgz", + "integrity": "sha1-+ixrWvh9p3uuKWalidUuI+2B/kA=", + "dev": true, + "requires": { + "deep-equal": "^1.0.0" + } + }, "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", @@ -16034,14 +18050,13 @@ "dev": true }, "json-rpc-engine": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-3.7.3.tgz", - "integrity": "sha512-+FO3UWu/wafh/+MZ6BXy0HZU+f5plwUn82FgxpC0scJkEh5snOjFrAAtqCITPDfvfLHRUFOG5pQDUx2pspfERQ==", + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-3.7.4.tgz", + "integrity": "sha512-urQunMR6LYIPhGs6ppLGqdwSVkllaVa70Em9uGYgEi5iqG3/oKYZM0B9C9EaRfih30k+tztDn2GG9eHbuaMmwg==", "requires": { "async": "^2.0.1", "babel-preset-env": "^1.3.2", "babelify": "^7.3.0", - "clone": "^2.1.1", "json-rpc-error": "^2.0.0", "promise-to-callback": "^1.0.0" }, @@ -16084,6 +18099,15 @@ "async": "^2.4.0" } }, + "babelify": { + "version": "7.3.0", + "resolved": "http://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", + "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", + "requires": { + "babel-core": "^6.0.14", + "object-assign": "^4.0.0" + } + }, "bn.js": { "version": "4.11.6", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", @@ -16154,6 +18178,19 @@ "strip-hex-prefix": "1.0.0" } }, + "json-rpc-engine": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-3.7.3.tgz", + "integrity": "sha512-+FO3UWu/wafh/+MZ6BXy0HZU+f5plwUn82FgxpC0scJkEh5snOjFrAAtqCITPDfvfLHRUFOG5pQDUx2pspfERQ==", + "requires": { + "async": "^2.0.1", + "babel-preset-env": "^1.3.2", + "babelify": "^7.3.0", + "clone": "^2.1.1", + "json-rpc-error": "^2.0.0", + "promise-to-callback": "^1.0.0" + } + }, "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", @@ -16309,8 +18346,12 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", - "dev": true, - "optional": true + "dev": true + }, + "jsonschema": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.2.4.tgz", + "integrity": "sha512-lz1nOH69GbsVHeVgEdvyavc/33oymY1AZwtePMiMj4HZPMbP5OIKK3zT9INMWjwua/V4Z4yq7wSlBbSG+g4AEw==" }, "jsprim": { "version": "1.4.1", @@ -17053,6 +19094,12 @@ "es6-weak-map": "^2.0.1" } }, + "lazy-cache": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-0.2.7.tgz", + "integrity": "sha1-f+3fLctu23fRHvHRF6tf/fCrG2U=", + "dev": true + }, "lazystream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", @@ -17781,6 +19828,12 @@ "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=" }, + "lodash.set": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", + "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=", + "dev": true + }, "lodash.shuffle": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.shuffle/-/lodash.shuffle-4.2.0.tgz", @@ -18126,6 +20179,12 @@ "resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.0.tgz", "integrity": "sha1-tlul/LNJopkkyOMz98alVi8uSEI=" }, + "macos-release": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-1.1.0.tgz", + "integrity": "sha512-mmLbumEYMi5nXReB9js3WGsB8UE6cDBWyIO62Z4DNx6GbRhDxHNjA1MlzSpJ2S2KM1wyiPRA0d19uHWYYvMHjA==", + "dev": true + }, "magic-string": { "version": "0.22.5", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz", @@ -18215,6 +20274,15 @@ } } }, + "map-age-cleaner": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.2.tgz", + "integrity": "sha512-UN1dNocxQq44IhJyMI4TU8phc2m9BddacHRPRjKGLYaF0jqd3xLz0jS0skpAU9WgYyoR4gHtUpzytNBS385FWQ==", + "dev": true, + "requires": { + "p-defer": "^1.0.0" + } + }, "map-async": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/map-async/-/map-async-0.1.1.tgz", @@ -18795,6 +20863,19 @@ "object-assign": "^4.0.0" } }, + "json-rpc-engine": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-3.7.3.tgz", + "integrity": "sha512-+FO3UWu/wafh/+MZ6BXy0HZU+f5plwUn82FgxpC0scJkEh5snOjFrAAtqCITPDfvfLHRUFOG5pQDUx2pspfERQ==", + "requires": { + "async": "^2.0.1", + "babel-preset-env": "^1.3.2", + "babelify": "^7.3.0", + "clone": "^2.1.1", + "json-rpc-error": "^2.0.0", + "promise-to-callback": "^1.0.0" + } + }, "obs-store": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/obs-store/-/obs-store-2.4.1.tgz", @@ -18819,11 +20900,11 @@ } }, "metamask-inpage-provider": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/metamask-inpage-provider/-/metamask-inpage-provider-1.0.0.tgz", - "integrity": "sha512-8ouTHzBuMb5DlsJstb3ikeA53zKk01ebcXEy3vHzg48MBO8sqHyFII37KYBkzkZ+ZkvouhmxMVCO+n8qo1oTmQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/metamask-inpage-provider/-/metamask-inpage-provider-1.1.1.tgz", + "integrity": "sha512-I7P8mny3e03dwzt0SFsXOmoj1eEz5GpUGiBIAJ4fyXUpx92JkII5ekq/MNkf5muktoJod9cWjDF03//+/DCD2A==", "requires": { - "json-rpc-engine": "^3.7.3", + "json-rpc-engine": "^3.7.4", "json-rpc-middleware-stream": "^1.0.1", "loglevel": "^1.6.1", "obj-multiplex": "^1.0.0", @@ -19501,6 +21582,59 @@ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" }, + "natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha1-F7CVgZiJef3a/gIB6TG6kzyWy7Q=", + "dev": true + }, + "nconf": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/nconf/-/nconf-0.10.0.tgz", + "integrity": "sha512-fKiXMQrpP7CYWJQzKkPPx9hPgmq+YLDyxcG9N8RpiE9FoCkCbzD0NyW0YhE3xn3Aupe7nnDeIx4PFzYehpHT9Q==", + "dev": true, + "requires": { + "async": "^1.4.0", + "ini": "^1.3.0", + "secure-keys": "^1.0.0", + "yargs": "^3.19.0" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "dev": true + }, + "window-size": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz", + "integrity": "sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY=", + "dev": true + }, + "yargs": { + "version": "3.32.0", + "resolved": "http://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", + "integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=", + "dev": true, + "requires": { + "camelcase": "^2.0.1", + "cliui": "^3.0.3", + "decamelize": "^1.1.1", + "os-locale": "^1.4.0", + "string-width": "^1.0.1", + "window-size": "^0.1.4", + "y18n": "^3.2.0" + } + } + } + }, "ncp": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ncp/-/ncp-1.0.1.tgz", @@ -19520,6 +21654,17 @@ "semver": "^5.4.1" } }, + "needle": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.2.4.tgz", + "integrity": "sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA==", + "dev": true, + "requires": { + "debug": "^2.1.2", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, "negotiator": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", @@ -19541,8 +21686,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/netmask/-/netmask-1.0.6.tgz", "integrity": "sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU=", - "dev": true, - "optional": true + "dev": true }, "next-tick": { "version": "1.0.0", @@ -19739,6 +21883,12 @@ } } }, + "node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "dev": true + }, "node-notifier": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.2.1.tgz", @@ -19959,30 +22109,6 @@ "integrity": "sha1-0LFF62kRicY6eNIB3E/bEpPvDAM=", "dev": true }, - "normalize-url": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", - "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", - "dev": true, - "requires": { - "object-assign": "^4.0.1", - "prepend-http": "^1.0.0", - "query-string": "^4.1.0", - "sort-keys": "^1.0.0" - }, - "dependencies": { - "query-string": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", - "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", - "dev": true, - "requires": { - "object-assign": "^4.1.0", - "strict-uri-encode": "^1.0.0" - } - } - } - }, "now-and-later": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.0.tgz", @@ -20337,7 +22463,7 @@ "dependencies": { "align-text": { "version": "0.1.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", "dev": true, "requires": { @@ -20348,19 +22474,19 @@ }, "amdefine": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", "dev": true }, "ansi-regex": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, "append-transform": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", "dev": true, "requires": { @@ -20369,31 +22495,31 @@ }, "archy": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", "dev": true }, "arrify": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", "dev": true }, "async": { "version": "1.5.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", "dev": true }, "balanced-match": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, "brace-expansion": { "version": "1.1.11", - "resolved": false, + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { @@ -20403,13 +22529,13 @@ }, "builtin-modules": { "version": "1.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", "dev": true }, "caching-transform": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-1.0.1.tgz", "integrity": "sha1-bb2y8g+Nj7znnz6U6dF0Lc31wKE=", "dev": true, "requires": { @@ -20420,7 +22546,7 @@ "dependencies": { "md5-hex": { "version": "1.3.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-1.3.0.tgz", "integrity": "sha1-0sSv6YPENwZiF5uMrRRSGRNQRsQ=", "dev": true, "requires": { @@ -20431,14 +22557,14 @@ }, "camelcase": { "version": "1.2.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", "dev": true, "optional": true }, "center-align": { "version": "0.1.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", "dev": true, "optional": true, @@ -20449,7 +22575,7 @@ }, "cliui": { "version": "2.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", "dev": true, "optional": true, @@ -20461,7 +22587,7 @@ "dependencies": { "wordwrap": { "version": "0.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", "dev": true, "optional": true @@ -20470,31 +22596,31 @@ }, "code-point-at": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, "commondir": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, "concat-map": { "version": "0.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, "convert-source-map": { "version": "1.5.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=", "dev": true }, "cross-spawn": { "version": "4.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", "dev": true, "requires": { @@ -20504,7 +22630,7 @@ }, "debug": { "version": "3.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, "requires": { @@ -20513,19 +22639,19 @@ }, "debug-log": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.1.tgz", "integrity": "sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8=", "dev": true }, "decamelize": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, "default-require-extensions": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", "dev": true, "requires": { @@ -20534,7 +22660,7 @@ "dependencies": { "strip-bom": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true } @@ -20542,7 +22668,7 @@ }, "error-ex": { "version": "1.3.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", "dev": true, "requires": { @@ -20551,7 +22677,7 @@ }, "execa": { "version": "0.7.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "dev": true, "requires": { @@ -20566,7 +22692,7 @@ "dependencies": { "cross-spawn": { "version": "5.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { @@ -20579,7 +22705,7 @@ }, "find-cache-dir": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", "dev": true, "requires": { @@ -20590,7 +22716,7 @@ }, "find-up": { "version": "2.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { @@ -20599,7 +22725,7 @@ }, "foreground-child": { "version": "1.5.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", "dev": true, "requires": { @@ -20609,25 +22735,25 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, "get-caller-file": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", "dev": true }, "get-stream": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", "dev": true }, "glob": { "version": "7.1.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { @@ -20641,13 +22767,13 @@ }, "graceful-fs": { "version": "4.1.11", - "resolved": false, + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", "dev": true }, "handlebars": { "version": "4.0.11", - "resolved": false, + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz", "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", "dev": true, "requires": { @@ -20659,7 +22785,7 @@ "dependencies": { "source-map": { "version": "0.4.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "dev": true, "requires": { @@ -20670,25 +22796,25 @@ }, "has-flag": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, "hosted-git-info": { "version": "2.6.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.0.tgz", "integrity": "sha512-lIbgIIQA3lz5XaB6vxakj6sDHADJiZadYEJB+FgA+C4nubM1NwcuvUr9EJPmnH1skZqpqUzWborWo8EIUi0Sdw==", "dev": true }, "imurmurhash": { "version": "0.1.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, "inflight": { "version": "1.0.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { @@ -20698,31 +22824,31 @@ }, "inherits": { "version": "2.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, "invert-kv": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", "dev": true }, "is-arrayish": { "version": "0.2.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, "is-buffer": { "version": "1.1.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, "is-builtin-module": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "dev": true, "requires": { @@ -20731,31 +22857,31 @@ }, "is-fullwidth-code-point": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, "is-stream": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, "isexe": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, "istanbul-lib-coverage": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.0.tgz", "integrity": "sha512-yMSw5xLIbdaxiVXHk3amfNM2WeBxLrwH/BCyZ9HvA/fylwziAIJOG2rKqWyLqEJqwKT725vxxqidv+SyynnGAA==", "dev": true }, "istanbul-lib-hook": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.0.tgz", "integrity": "sha512-qm3dt628HKpCVtIjbdZLuQyXn0+LO8qz+YHQDfkeXuSk5D+p299SEV5DrnUUnPi2SXvdMmWapMYWiuE75o2rUQ==", "dev": true, "requires": { @@ -20764,7 +22890,7 @@ }, "istanbul-lib-report": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.0.tgz", "integrity": "sha512-RiELmy9oIRYUv36ITOAhVum9PUvuj6bjyXVEKEHNiD1me6qXtxfx7vSEJWnjOGk2QmYw/GRFjLXWJv3qHpLceQ==", "dev": true, "requires": { @@ -20775,7 +22901,7 @@ }, "istanbul-lib-source-maps": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-2.0.0.tgz", "integrity": "sha512-jenUeC0gMSSMGkvqD9xuNfs3nD7XWeXLhqaIkqHsNZ3DJBWPdlKEydE7Ya5aTgdWjrEQhrCYTv+J606cGC2vuQ==", "dev": true, "requires": { @@ -20788,7 +22914,7 @@ "dependencies": { "source-map": { "version": "0.6.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } @@ -20796,7 +22922,7 @@ }, "istanbul-reports": { "version": "1.5.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.5.0.tgz", "integrity": "sha512-HeZG0WHretI9FXBni5wZ9DOgNziqDCEwetxnme5k1Vv5e81uTqcsy3fMH99gXGDGKr1ea87TyGseDMa2h4HEUA==", "dev": true, "requires": { @@ -20805,13 +22931,13 @@ }, "json-parse-better-errors": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, "kind-of": { "version": "3.2.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { @@ -20820,14 +22946,14 @@ }, "lazy-cache": { "version": "1.0.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", "dev": true, "optional": true }, "lcid": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", "dev": true, "requires": { @@ -20836,7 +22962,7 @@ }, "locate-path": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "dev": true, "requires": { @@ -20846,7 +22972,7 @@ "dependencies": { "path-exists": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true } @@ -20854,13 +22980,13 @@ }, "longest": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", "dev": true }, "lru-cache": { "version": "4.1.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", "dev": true, "requires": { @@ -20870,7 +22996,7 @@ }, "make-dir": { "version": "1.3.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", "dev": true, "requires": { @@ -20879,7 +23005,7 @@ "dependencies": { "pify": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true } @@ -20887,7 +23013,7 @@ }, "md5-hex": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-2.0.0.tgz", "integrity": "sha1-0FiOnxx0lUSS7NJKwKxs6ZfZLjM=", "dev": true, "requires": { @@ -20896,13 +23022,13 @@ }, "md5-o-matic": { "version": "0.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/md5-o-matic/-/md5-o-matic-0.1.1.tgz", "integrity": "sha1-givM1l4RfFFPqxdrJZRdVBAKA8M=", "dev": true }, "mem": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", "dev": true, "requires": { @@ -20911,7 +23037,7 @@ }, "merge-source-map": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", "dev": true, "requires": { @@ -20920,7 +23046,7 @@ "dependencies": { "source-map": { "version": "0.6.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } @@ -20928,13 +23054,13 @@ }, "mimic-fn": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", "dev": true }, "minimatch": { "version": "3.0.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { @@ -20943,13 +23069,13 @@ }, "minimist": { "version": "0.0.8", - "resolved": false, + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true }, "mkdirp": { "version": "0.5.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "requires": { @@ -20958,13 +23084,13 @@ }, "ms": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, "normalize-package-data": { "version": "2.4.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", "dev": true, "requires": { @@ -20976,7 +23102,7 @@ }, "npm-run-path": { "version": "2.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { @@ -20985,13 +23111,13 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, "once": { "version": "1.4.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { @@ -21000,7 +23126,7 @@ }, "optimist": { "version": "0.6.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "dev": true, "requires": { @@ -21010,13 +23136,13 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true }, "os-locale": { "version": "2.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", "dev": true, "requires": { @@ -21027,13 +23153,13 @@ }, "p-finally": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "dev": true }, "p-limit": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", "integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==", "dev": true, "requires": { @@ -21042,7 +23168,7 @@ }, "p-locate": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, "requires": { @@ -21051,25 +23177,25 @@ }, "p-try": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", "dev": true }, "path-is-absolute": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, "path-key": { "version": "2.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true }, "pkg-dir": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", "dev": true, "requires": { @@ -21078,37 +23204,37 @@ }, "pseudomap": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", "dev": true }, "repeat-string": { "version": "1.6.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", "dev": true }, "require-directory": { "version": "2.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, "require-main-filename": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", "dev": true }, "resolve-from": { "version": "4.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, "right-align": { "version": "0.1.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", "dev": true, "optional": true, @@ -21118,7 +23244,7 @@ }, "rimraf": { "version": "2.6.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "requires": { @@ -21127,19 +23253,19 @@ }, "semver": { "version": "5.5.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", "dev": true }, "set-blocking": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, "shebang-command": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { @@ -21148,32 +23274,32 @@ }, "shebang-regex": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, "signal-exit": { "version": "3.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, "slide": { "version": "1.1.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", "dev": true }, "source-map": { "version": "0.5.7", - "resolved": false, + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true, "optional": true }, "spawn-wrap": { "version": "1.4.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.2.tgz", "integrity": "sha512-vMwR3OmmDhnxCVxM8M+xO/FtIp6Ju/mNaDfCMMW7FDcLRTPFWUswec4LXJHTJE2hwTI9O0YBfygu4DalFl7Ylg==", "dev": true, "requires": { @@ -21187,7 +23313,7 @@ }, "spdx-correct": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", "dev": true, "requires": { @@ -21197,13 +23323,13 @@ }, "spdx-exceptions": { "version": "2.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==", "dev": true }, "spdx-expression-parse": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", "dev": true, "requires": { @@ -21213,13 +23339,13 @@ }, "spdx-license-ids": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==", "dev": true }, "string-width": { "version": "2.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { @@ -21229,7 +23355,7 @@ }, "strip-ansi": { "version": "4.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { @@ -21238,13 +23364,13 @@ }, "strip-eof": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, "supports-color": { "version": "5.4.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { @@ -21253,7 +23379,7 @@ }, "test-exclude": { "version": "4.2.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.2.2.tgz", "integrity": "sha512-2kTGf+3tykCfrWVREgyTR0bmVO0afE6i7zVXi/m+bZZ8ujV89Aulxdcdv32yH+unVFg3Y5o6GA8IzsHnGQuFgQ==", "dev": true, "requires": { @@ -21265,7 +23391,7 @@ "dependencies": { "load-json-file": { "version": "4.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", "dev": true, "requires": { @@ -21277,7 +23403,7 @@ }, "parse-json": { "version": "4.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", "dev": true, "requires": { @@ -21287,7 +23413,7 @@ }, "path-type": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, "requires": { @@ -21296,13 +23422,13 @@ }, "pify": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true }, "read-pkg": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", "dev": true, "requires": { @@ -21313,7 +23439,7 @@ }, "read-pkg-up": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", "dev": true, "requires": { @@ -21323,7 +23449,7 @@ }, "strip-bom": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true } @@ -21331,7 +23457,7 @@ }, "uglify-js": { "version": "2.8.29", - "resolved": false, + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", "dev": true, "optional": true, @@ -21343,7 +23469,7 @@ "dependencies": { "yargs": { "version": "3.10.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", "dev": true, "optional": true, @@ -21358,14 +23484,14 @@ }, "uglify-to-browserify": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", "dev": true, "optional": true }, "validate-npm-package-license": { "version": "3.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==", "dev": true, "requires": { @@ -21375,7 +23501,7 @@ }, "which": { "version": "1.3.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { @@ -21384,26 +23510,26 @@ }, "which-module": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, "window-size": { "version": "0.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", "dev": true, "optional": true }, "wordwrap": { "version": "0.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", "dev": true }, "wrap-ansi": { "version": "2.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { @@ -21413,13 +23539,13 @@ "dependencies": { "ansi-regex": { "version": "2.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "requires": { @@ -21428,7 +23554,7 @@ }, "string-width": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { @@ -21439,7 +23565,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { @@ -21450,13 +23576,13 @@ }, "wrappy": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, "write-file-atomic": { "version": "1.3.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz", "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=", "dev": true, "requires": { @@ -21467,19 +23593,19 @@ }, "y18n": { "version": "3.2.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", "dev": true }, "yallist": { "version": "2.1.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", "dev": true }, "yargs": { "version": "11.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz", "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==", "dev": true, "requires": { @@ -21499,13 +23625,13 @@ "dependencies": { "camelcase": { "version": "4.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", "dev": true }, "cliui": { "version": "4.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", "dev": true, "requires": { @@ -21516,7 +23642,7 @@ }, "yargs-parser": { "version": "9.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", "dev": true, "requires": { @@ -21527,7 +23653,7 @@ }, "yargs-parser": { "version": "9.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", "dev": true, "requires": { @@ -21536,7 +23662,7 @@ "dependencies": { "camelcase": { "version": "4.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", "dev": true } @@ -21822,7 +23948,7 @@ "dependencies": { "babelify": { "version": "7.3.0", - "resolved": "http://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", + "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", "requires": { "babel-core": "^6.0.14", @@ -21970,6 +24096,16 @@ "lcid": "^1.0.0" } }, + "os-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/os-name/-/os-name-2.0.1.tgz", + "integrity": "sha1-uaOGNhwXrjohc27wWZQFyajF3F4=", + "dev": true, + "requires": { + "macos-release": "^1.0.0", + "win-release": "^1.0.0" + } + }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", @@ -21993,12 +24129,24 @@ "shell-quote": "^1.4.2" } }, + "p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", + "dev": true + }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "dev": true }, + "p-is-promise": { + "version": "1.1.0", + "resolved": "http://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", + "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=", + "dev": true + }, "p-limit": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", @@ -22034,7 +24182,6 @@ "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-2.0.2.tgz", "integrity": "sha512-cDNAN1Ehjbf5EHkNY5qnRhGPUCp6SnpyVof5fRzN800QV1Y2OkzbH9rmjZkbBRa8igof903yOnjIl6z0SlAhxA==", "dev": true, - "optional": true, "requires": { "agent-base": "^4.2.0", "debug": "^3.1.0", @@ -22051,7 +24198,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, - "optional": true, "requires": { "ms": "2.0.0" } @@ -22063,7 +24209,6 @@ "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-3.0.0.tgz", "integrity": "sha512-tcc38bsjuE3XZ5+4vP96OfhOugrX+JcnpUbhfuc4LuXBLQhoTthOstZeoQJBDnQUDYzYmdImKsbz0xSl1/9qeA==", "dev": true, - "optional": true, "requires": { "co": "^4.6.0", "degenerator": "^1.0.4", @@ -22399,6 +24544,28 @@ "pinkie": "^2.0.0" } }, + "pino": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-5.5.0.tgz", + "integrity": "sha512-cCaBKVwutiaGwgKXyOvsRSCeBxgi2j0X1PEK1cog1/9SMDhgL8+iJwWvTKUef20HDyGfZIUq5KaH0ZOhWLHYSw==", + "dev": true, + "requires": { + "fast-json-parse": "^1.0.3", + "fast-redact": "^1.2.0", + "fast-safe-stringify": "^2.0.6", + "flatstr": "^1.0.5", + "pino-std-serializers": "^2.2.1", + "pump": "^3.0.0", + "quick-format-unescaped": "^3.0.0", + "sonic-boom": "^0.6.1" + } + }, + "pino-std-serializers": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-2.2.1.tgz", + "integrity": "sha512-QqL7kkF7eMCpFG4hpZD8UPQga/kxkkh3E62HzMzTIL4OQyijyisAnBL8msBEAml8xcb/ioGhH7UUzGxuHqczhQ==", + "dev": true + }, "pipetteur": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/pipetteur/-/pipetteur-2.0.3.tgz", @@ -22409,6 +24576,15 @@ "synesthesia": "^1.0.1" } }, + "pirates": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.0.tgz", + "integrity": "sha512-8t5BsXy1LUIjn3WWOlOuFDuKswhQb/tkak641lvBgmPOBUQHXveORtlMCp6OdPV1dtuTaEahKA8VNz6uLfKBtA==", + "dev": true, + "requires": { + "node-modules-regexp": "^1.0.0" + } + }, "pkg-dir": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", @@ -22640,6 +24816,57 @@ "integrity": "sha1-HMfCEjA6yr50Jj7DrHgAlYAkLZM=", "dev": true }, + "po2json": { + "version": "0.4.5", + "resolved": "http://registry.npmjs.org/po2json/-/po2json-0.4.5.tgz", + "integrity": "sha1-R7spUtoy1Yob4vJWpZjuvAt0URg=", + "dev": true, + "requires": { + "gettext-parser": "1.1.0", + "nomnom": "1.8.1" + }, + "dependencies": { + "ansi-styles": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", + "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=", + "dev": true + }, + "chalk": { + "version": "0.4.0", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", + "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=", + "dev": true, + "requires": { + "ansi-styles": "~1.0.0", + "has-color": "~0.1.0", + "strip-ansi": "~0.1.0" + } + }, + "nomnom": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz", + "integrity": "sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=", + "dev": true, + "requires": { + "chalk": "~0.4.0", + "underscore": "~1.6.0" + } + }, + "strip-ansi": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", + "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=", + "dev": true + }, + "underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", + "dev": true + } + } + }, "pojo-migrator": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/pojo-migrator/-/pojo-migrator-2.1.0.tgz", @@ -24139,12 +26366,6 @@ } } }, - "prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", - "dev": true - }, "preserve": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", @@ -24182,6 +26403,34 @@ "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" }, + "probe-image-size": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/probe-image-size/-/probe-image-size-4.0.0.tgz", + "integrity": "sha512-nm7RvWUxps+2+jZKNLkd04mNapXNariS6G5WIEVzvAqjx7EUuKcY1Dp3e6oUK7GLwzJ+3gbSbPLFAASHFQrPcQ==", + "dev": true, + "requires": { + "any-promise": "^1.3.0", + "deepmerge": "^2.0.1", + "inherits": "^2.0.3", + "next-tick": "^1.0.0", + "request": "^2.83.0", + "stream-parser": "~0.3.1" + }, + "dependencies": { + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", + "dev": true + }, + "deepmerge": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.1.1.tgz", + "integrity": "sha512-urQxA1smbLZ2cBbXbaYObM1dJ82aJ2H57A1C/Kklfh/ZN1bgH4G/n5KWhdNfOK11W98gqZfyYj7W4frJJRwA2w==", + "dev": true + } + } + }, "process": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz", @@ -24389,6 +26638,12 @@ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, + "psl": { + "version": "1.1.29", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", + "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==", + "dev": true + }, "public-encrypt": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.0.tgz", @@ -24542,6 +26797,12 @@ "integrity": "sha1-DPf4T5Rj/wrlHExLFC2VvjdyTZw=", "dev": true }, + "quick-format-unescaped": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-3.0.0.tgz", + "integrity": "sha512-XmIOc07VM2kPm6m3j/U6jgxyUgDm2Rgh2c1PPy0JUHoQRdoh86hOym0bHyF6G1T6sn+N5lildhvl/T59H5KVyA==", + "dev": true + }, "qunitjs": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/qunitjs/-/qunitjs-2.4.1.tgz", @@ -25070,7 +27331,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/react-inspector/-/react-inspector-2.3.0.tgz", "integrity": "sha512-aIcbWb0fKFhEMB+RadoOYawlr1JoMMfrQ1oRgPUG/f/e4zERVJ6nYcIaQmrQmdHCZ63BOqe2cEkoeY0kyLBzNg==", - "dev": true, "requires": { "babel-runtime": "^6.26.0", "is-dom": "^1.0.9" @@ -25510,6 +27770,25 @@ "set-immediate-shim": "^1.0.1" } }, + "readline2": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", + "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "mute-stream": "0.0.5" + }, + "dependencies": { + "mute-stream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz", + "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=", + "dev": true + } + } + }, "recast": { "version": "0.11.23", "resolved": "https://registry.npmjs.org/recast/-/recast-0.11.23.tgz", @@ -25720,6 +27999,21 @@ "integrity": "sha512-VncXxOF6uFlYog5prG2j+e2UGJeam5MfNiJnB/qEgo4KTnMm2XrELCg4rNZ6IlaEUZnGlb8aB6lXowCRQtTkkA==", "dev": true }, + "regexp.prototype.flags": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.2.0.tgz", + "integrity": "sha512-ztaw4M1VqgMwl9HlPpOuiYgItcHlunW0He2fE6eNfT6E/CF2FtYi9ofOYe4mKntstYk0Fyh/rDRBdS3AnxjlrA==", + "dev": true, + "requires": { + "define-properties": "^1.1.2" + } + }, + "regexpp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", + "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", + "dev": true + }, "regexpu-core": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", @@ -25756,6 +28050,16 @@ "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", "dev": true }, + "relaxed-json": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/relaxed-json/-/relaxed-json-1.0.1.tgz", + "integrity": "sha1-fI1KovCVcEzQIOMugJm8rhA/C9Q=", + "dev": true, + "requires": { + "chalk": "^1.0.0", + "commander": "^2.6.0" + } + }, "remark-parse": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-4.0.0.tgz", @@ -26285,6 +28589,23 @@ "rx-lite": "*" } }, + "rxjs": { + "version": "5.5.12", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.12.tgz", + "integrity": "sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw==", + "dev": true, + "requires": { + "symbol-observable": "1.0.1" + }, + "dependencies": { + "symbol-observable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", + "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=", + "dev": true + } + } + }, "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", @@ -26565,6 +28886,12 @@ "safe-buffer": "^5.1.0" } }, + "secure-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/secure-keys/-/secure-keys-1.0.0.tgz", + "integrity": "sha1-8MgtmKOxOah3aogIBQuCRDEIf8o=", + "dev": true + }, "seedrandom": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-2.4.3.tgz", @@ -27226,6 +29553,589 @@ } } }, + "snyk": { + "version": "1.99.0", + "resolved": "https://registry.npmjs.org/snyk/-/snyk-1.99.0.tgz", + "integrity": "sha512-HyvTj7Tap3PLNXN8tXQChL4+Y32TDTYh2Oklp2/5GLPeSlxv/VOBWXwEy/JowwopxcrJ8P8p3px6hSyOoSuvqw==", + "dev": true, + "requires": { + "abbrev": "^1.1.1", + "ansi-escapes": "^3.1.0", + "chalk": "^2.4.1", + "configstore": "^3.1.2", + "debug": "^3.1.0", + "hasbin": "^1.2.3", + "inquirer": "^3.0.0", + "lodash": "^4.17.5", + "needle": "^2.2.4", + "opn": "^5.2.0", + "os-name": "^2.0.1", + "proxy-agent": "^2.0.0", + "proxy-from-env": "^1.0.0", + "recursive-readdir": "^2.2.2", + "semver": "^5.5.0", + "snyk-config": "2.2.0", + "snyk-docker-plugin": "1.11.0", + "snyk-go-plugin": "1.5.2", + "snyk-gradle-plugin": "2.0.0", + "snyk-module": "1.8.2", + "snyk-mvn-plugin": "2.0.0", + "snyk-nodejs-lockfile-parser": "1.5.1", + "snyk-nuget-plugin": "1.6.5", + "snyk-php-plugin": "1.5.1", + "snyk-policy": "1.12.0", + "snyk-python-plugin": "1.8.1", + "snyk-resolve": "1.0.1", + "snyk-resolve-deps": "3.1.0", + "snyk-sbt-plugin": "2.0.0", + "snyk-tree": "^1.0.0", + "snyk-try-require": "1.3.1", + "source-map-support": "^0.5.9", + "tempfile": "^2.0.0", + "then-fs": "^2.0.0", + "undefsafe": "^2.0.0", + "uuid": "^3.2.1" + }, + "dependencies": { + "ansi-escapes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", + "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "debug": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", + "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "lru-cache": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", + "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "proxy-agent": { + "version": "2.3.1", + "resolved": "http://registry.npmjs.org/proxy-agent/-/proxy-agent-2.3.1.tgz", + "integrity": "sha512-CNKuhC1jVtm8KJYFTS2ZRO71VCBx3QSA92So/e6NrY6GoJonkx3Irnk4047EsCcswczwqAekRj3s8qLRGahSKg==", + "dev": true, + "requires": { + "agent-base": "^4.2.0", + "debug": "^3.1.0", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.1", + "lru-cache": "^4.1.2", + "pac-proxy-agent": "^2.0.1", + "proxy-from-env": "^1.0.0", + "socks-proxy-agent": "^3.0.0" + } + }, + "recursive-readdir": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", + "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==", + "dev": true, + "requires": { + "minimatch": "3.0.4" + } + }, + "semver": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", + "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.9.tgz", + "integrity": "sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + } + } + }, + "snyk-config": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/snyk-config/-/snyk-config-2.2.0.tgz", + "integrity": "sha512-mq0wbP/AgjcmRq5i5jg2akVVV3iSYUPTowZwKn7DChRLDL8ySOzWAwan+ImXiyNbrWo87FNI/15O6MpOnTxOIg==", + "dev": true, + "requires": { + "debug": "^3.1.0", + "lodash": "^4.17.5", + "nconf": "^0.10.0" + }, + "dependencies": { + "debug": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", + "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "snyk-docker-plugin": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/snyk-docker-plugin/-/snyk-docker-plugin-1.11.0.tgz", + "integrity": "sha512-rJrSj4FfGtaFGNybWTb0bULEqoQEeZfZBpGoDumiXsGqoSWf61Tr1V/Ck9NGcmHWNEVsLZLcE9CXp6Y6Kbo8qA==", + "dev": true, + "requires": { + "debug": "^3", + "tslib": "^1" + }, + "dependencies": { + "debug": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", + "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "snyk-go-plugin": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/snyk-go-plugin/-/snyk-go-plugin-1.5.2.tgz", + "integrity": "sha512-XWajcSh6Ld+I+WdcyU3DGDuE2ydThQd8ORkESy0nQ2LwekygLYVYN66OBy0uxpqYfd4qoqeg+J8lb4oGzCmyGA==", + "dev": true, + "requires": { + "graphlib": "^2.1.1", + "tmp": "0.0.33", + "toml": "^2.3.2" + } + }, + "snyk-gradle-plugin": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/snyk-gradle-plugin/-/snyk-gradle-plugin-2.0.0.tgz", + "integrity": "sha512-X59ADEscMfZJpOUUGLit4OSlJoK2vuvqfDYPtT7BZXj/Br+/m20bE6Y38YhYjqUH5zj96KSRpmqRp8qsz7lCdg==", + "dev": true, + "requires": { + "clone-deep": "^0.3.0" + }, + "dependencies": { + "clone-deep": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-0.3.0.tgz", + "integrity": "sha1-NIxhrpzb4O3+BT2R/0zFIdeQ7eg=", + "dev": true, + "requires": { + "for-own": "^1.0.0", + "is-plain-object": "^2.0.1", + "kind-of": "^3.2.2", + "shallow-clone": "^0.1.2" + } + }, + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "dev": true, + "requires": { + "for-in": "^1.0.1" + } + }, + "shallow-clone": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-0.1.2.tgz", + "integrity": "sha1-WQnodLp3EG1zrEFM/sH/yofZcGA=", + "dev": true, + "requires": { + "is-extendable": "^0.1.1", + "kind-of": "^2.0.1", + "lazy-cache": "^0.2.3", + "mixin-object": "^2.0.1" + }, + "dependencies": { + "kind-of": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz", + "integrity": "sha1-AY7HpM5+OobLkUG+UZ0kyPqpgbU=", + "dev": true, + "requires": { + "is-buffer": "^1.0.2" + } + } + } + } + } + }, + "snyk-module": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/snyk-module/-/snyk-module-1.8.2.tgz", + "integrity": "sha512-XqhdbZ/CUuJ5gSaYdYfapLqx9qm2Mp6nyRMBCLXe9tJSiohOJsc9fQuUDbdOiRCqpA4BD6WLl+qlwOJmJoszBg==", + "dev": true, + "requires": { + "debug": "^3.1.0", + "hosted-git-info": "^2.1.4" + }, + "dependencies": { + "debug": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", + "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "snyk-mvn-plugin": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/snyk-mvn-plugin/-/snyk-mvn-plugin-2.0.0.tgz", + "integrity": "sha512-9jAhZhv+7YcqtoQYCYlgMoxK+dWBKlk+wkX27Ebg3vNddNop9q5jZitRXTjsXwfSUZHRt+Ptw1f8vei9kjzZVg==", + "dev": true + }, + "snyk-nodejs-lockfile-parser": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/snyk-nodejs-lockfile-parser/-/snyk-nodejs-lockfile-parser-1.5.1.tgz", + "integrity": "sha512-rfFcW+ZrOEH3NxufUCpMBpNLSb4BPOxLbAM6MoRqfYH5DhSdTHsecwRDf1gU6XzQok/9Koav+1qtP8+welJC2A==", + "dev": true, + "requires": { + "@yarnpkg/lockfile": "^1.0.2", + "lodash": "4.17.10", + "path": "0.12.7", + "source-map-support": "^0.5.7" + }, + "dependencies": { + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.9.tgz", + "integrity": "sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + } + } + }, + "snyk-nuget-plugin": { + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/snyk-nuget-plugin/-/snyk-nuget-plugin-1.6.5.tgz", + "integrity": "sha512-3qIndzkxCxiaGvAwMkqChbChGdwhNePPyfi0WjhC/nJGwecqU3Fb/NeTW7lgyT+xoq/dFnzW0DgBJ4+AyNA2gA==", + "dev": true, + "requires": { + "debug": "^3.1.0", + "jszip": "^3.1.5", + "lodash": "^4.17.10", + "xml2js": "^0.4.17" + }, + "dependencies": { + "debug": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", + "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "snyk-php-plugin": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/snyk-php-plugin/-/snyk-php-plugin-1.5.1.tgz", + "integrity": "sha512-g5QSHBsRJ2O4cNxKC4zlWwnQYiSgQ77Y6QgGmo3ihPX3VLZrc1amaZIpPsNe1jwXirnGj2rvR5Xw+jDjbzvHFw==", + "dev": true, + "requires": { + "debug": "^3.1.0", + "lodash": "^4.17.5", + "path": "0.12.7" + }, + "dependencies": { + "debug": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", + "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "snyk-policy": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/snyk-policy/-/snyk-policy-1.12.0.tgz", + "integrity": "sha512-CEioNnDzccHyid7UIVl3bJ1dnG4co4ofI+KxuC1mo0IUXy64gxnBTeVoZF5gVLWbAyxGxSeW8f0+8GmWMHVb7w==", + "dev": true, + "requires": { + "debug": "^3.1.0", + "email-validator": "^2.0.3", + "js-yaml": "^3.5.3", + "lodash.clonedeep": "^4.3.1", + "semver": "^5.5.0", + "snyk-module": "^1.8.2", + "snyk-resolve": "^1.0.1", + "snyk-try-require": "^1.1.1", + "then-fs": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", + "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "semver": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", + "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==", + "dev": true + } + } + }, + "snyk-python-plugin": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/snyk-python-plugin/-/snyk-python-plugin-1.8.1.tgz", + "integrity": "sha512-DsUBkQZiPlXGkwzhxxEo2Tvfq6XhygWQThWM0yRBythi9M5n8UimZEwdkBHPj7xKC1clsB8boM3+sT/E1x6XGA==", + "dev": true, + "requires": { + "tmp": "0.0.33" + } + }, + "snyk-resolve": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/snyk-resolve/-/snyk-resolve-1.0.1.tgz", + "integrity": "sha512-7+i+LLhtBo1Pkth01xv+RYJU8a67zmJ8WFFPvSxyCjdlKIcsps4hPQFebhz+0gC5rMemlaeIV6cqwqUf9PEDpw==", + "dev": true, + "requires": { + "debug": "^3.1.0", + "then-fs": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", + "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "snyk-resolve-deps": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/snyk-resolve-deps/-/snyk-resolve-deps-3.1.0.tgz", + "integrity": "sha512-YVAelR+dTpqLgfk6lf6WgOlw+MGmGI0r3/Dny8tUbJJ9uVTHTRAOdZCbUyTFqJG7oEmEZxUwmfjqgAuniYwx8Q==", + "dev": true, + "requires": { + "ansicolors": "^0.3.2", + "debug": "^3.1.0", + "lodash.assign": "^4.2.0", + "lodash.assignin": "^4.2.0", + "lodash.flatten": "^4.4.0", + "lodash.get": "^4.4.2", + "lodash.set": "^4.3.2", + "lru-cache": "^4.0.0", + "semver": "^5.1.0", + "snyk-module": "^1.6.0", + "snyk-resolve": "^1.0.0", + "snyk-tree": "^1.0.0", + "snyk-try-require": "^1.1.1", + "then-fs": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", + "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", + "dev": true + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "snyk-sbt-plugin": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/snyk-sbt-plugin/-/snyk-sbt-plugin-2.0.0.tgz", + "integrity": "sha512-bOUqsQ1Lysnwfnvf4QQIBfC0M0ZVuhlshTKd7pNwgAJ41YEPJNrPEpzOePl/HfKtwilEEwHh5YHvjYGegEKx0A==", + "dev": true + }, + "snyk-tree": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/snyk-tree/-/snyk-tree-1.0.0.tgz", + "integrity": "sha1-D7cxdtvzLngvGRAClBYESPkRHMg=", + "dev": true, + "requires": { + "archy": "^1.0.0" + } + }, + "snyk-try-require": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/snyk-try-require/-/snyk-try-require-1.3.1.tgz", + "integrity": "sha1-bgJvkuZK9/zM6h7lPVJIQeQYohI=", + "dev": true, + "requires": { + "debug": "^3.1.0", + "lodash.clonedeep": "^4.3.0", + "lru-cache": "^4.0.0", + "then-fs": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", + "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, "socket.io": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.0.4.tgz", @@ -27396,13 +30306,13 @@ } } }, - "sort-keys": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", - "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "sonic-boom": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-0.6.1.tgz", + "integrity": "sha512-3qx6XXDeG+hPNa+jla1H6BMBLcjLl8L8NRERLVeIf/EuPqoqmq4K8owG29Xu7OypT/7/YT/0uKW6YitsKA+nLQ==", "dev": true, "requires": { - "is-plain-obj": "^1.0.0" + "flatstr": "^1.0.5" } }, "source-list-map": { @@ -27886,6 +30796,15 @@ "xtend": "^4.0.0" } }, + "stream-parser": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/stream-parser/-/stream-parser-0.3.1.tgz", + "integrity": "sha1-FhhUhpRCACGhGC/wrxkRwSl2F3M=", + "dev": true, + "requires": { + "debug": "2" + } + }, "stream-shift": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", @@ -28011,6 +30930,19 @@ "strip-ansi": "^3.0.0" } }, + "string.prototype.matchall": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-2.0.0.tgz", + "integrity": "sha512-WoZ+B2ypng1dp4iFLF2kmZlwwlE19gmjgKuhL1FJfDgCREWb3ye3SDVHSzLH6bxfnvYmkCxbzkmWcQZHA4P//Q==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.10.0", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "regexp.prototype.flags": "^1.2.0" + } + }, "string.prototype.padend": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz", @@ -28084,6 +31016,15 @@ "is-utf8": "^0.2.0" } }, + "strip-bom-buf": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-buf/-/strip-bom-buf-1.0.0.tgz", + "integrity": "sha1-HLRar1dTD0yvhsf3UXnSyaUd1XI=", + "dev": true, + "requires": { + "is-utf8": "^0.2.1" + } + }, "strip-bom-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-2.0.0.tgz", @@ -29113,6 +32054,30 @@ } } }, + "temp-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", + "integrity": "sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=", + "dev": true + }, + "tempfile": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tempfile/-/tempfile-2.0.0.tgz", + "integrity": "sha1-awRGhWqbERTRhW/8vlCczLCXcmU=", + "dev": true, + "requires": { + "temp-dir": "^1.0.0", + "uuid": "^3.0.1" + }, + "dependencies": { + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + } + } + }, "testem": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/testem/-/testem-2.8.0.tgz", @@ -29277,6 +32242,15 @@ "prop-types": "^15.5.8" } }, + "then-fs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/then-fs/-/then-fs-2.0.0.tgz", + "integrity": "sha1-cveS3Z0xcFqRrhnr/Piz+WjIHaI=", + "dev": true, + "requires": { + "promise": ">=3.2 <8" + } + }, "thenify": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz", @@ -29330,8 +32304,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/thunkify/-/thunkify-2.1.2.tgz", "integrity": "sha1-+qDp0jDFGsyVyhOjYawFyn4EVT0=", - "dev": true, - "optional": true + "dev": true }, "tildify": { "version": "1.2.0", @@ -29548,12 +32521,24 @@ "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", "integrity": "sha1-bkWxJj8gF/oKzH2J14sVuL932jI=" }, + "toml": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/toml/-/toml-2.3.3.tgz", + "integrity": "sha512-O7L5hhSQHxuufWUdcTRPfuTh3phKfAZ/dqfxZFoxPCj2RYmpaSGLEIs016FCXItQwNr08yefUB5TSjzRYnajTA==", + "dev": true + }, "toposort": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.7.tgz", "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=", "dev": true }, + "tosource": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tosource/-/tosource-1.0.0.tgz", + "integrity": "sha1-QtiN0RZhi88A1hBt1URvNCeQL/E=", + "dev": true + }, "tough-cookie": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", @@ -29700,6 +32685,12 @@ "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.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", + "dev": true + }, "tsscmp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.5.tgz", @@ -29975,6 +32966,15 @@ "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=" }, + "undefsafe": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.2.tgz", + "integrity": "sha1-Il9rngM3Zj4Njnz9aG/Cg2zKznY=", + "dev": true, + "requires": { + "debug": "^2.2.0" + } + }, "underscore": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", @@ -30120,6 +33120,15 @@ "through2-filter": "^2.0.0" } }, + "unique-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", + "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", + "dev": true, + "requires": { + "crypto-random-string": "^1.0.0" + } + }, "unist-util-is": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-2.1.1.tgz", @@ -30320,6 +33329,15 @@ "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=", "dev": true }, + "user-home": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", + "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", + "dev": true, + "requires": { + "os-homedir": "^1.0.0" + } + }, "useragent": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.2.1.tgz", @@ -30733,6 +33751,15 @@ "graceful-fs": "^4.1.2" } }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, "weak": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/weak/-/weak-1.0.1.tgz", @@ -31504,6 +34531,15 @@ "string-width": "^1.0.2" } }, + "win-release": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/win-release/-/win-release-1.1.1.tgz", + "integrity": "sha1-X6VeAr58qTTt/BJmVjLoSbcuUgk=", + "dev": true, + "requires": { + "semver": "^5.0.1" + } + }, "window-size": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", @@ -31625,6 +34661,17 @@ "mkdirp": "^0.5.1" } }, + "write-file-atomic": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz", + "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, "write-file-stdout": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/write-file-stdout/-/write-file-stdout-0.0.2.tgz", @@ -31652,6 +34699,12 @@ "resolved": "https://registry.npmjs.org/x-is-string/-/x-is-string-0.1.0.tgz", "integrity": "sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI=" }, + "xdg-basedir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", + "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", + "dev": true + }, "xhr": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.4.1.tgz", @@ -31741,8 +34794,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=", - "dev": true, - "optional": true + "dev": true }, "xtend": { "version": "4.0.1", diff --git a/package.json b/package.json index dc3412c53..02370eba4 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "sentry:publish": "node ./development/sentry-publish.js", "lint": "eslint .", "lint:fix": "eslint . --fix", + "mozilla-lint": "addons-linter dist/firefox", "ui": "npm run test:flat:build:states && beefy development/ui-dev.js:bundle.js --live --open --index=./development/index.html --cwd ./", "mock": "beefy development/mock-dev.js:bundle.js --live --open --index=./development/index.html --cwd ./", "watch": "mocha watch --recursive \"test/unit/**/*.js\"", @@ -110,7 +111,7 @@ "ensnare": "^1.0.0", "eslint-plugin-react": "^7.4.0", "eth-bin-to-ops": "^1.0.1", - "eth-block-tracker": "^4.0.1", + "eth-block-tracker": "^4.0.2", "eth-contract-metadata": "github:MetaMask/eth-contract-metadata#master", "eth-ens-namehash": "^2.0.8", "eth-hd-keyring": "^1.2.2", @@ -122,7 +123,7 @@ "eth-method-registry": "^1.0.0", "eth-phishing-detect": "^1.1.4", "eth-query": "^2.1.2", - "eth-sig-util": "^1.4.2", + "eth-sig-util": "^2.0.2", "eth-token-tracker": "^1.1.4", "eth-trezor-keyring": "^0.1.0", "ethereumjs-abi": "^0.6.4", @@ -155,15 +156,16 @@ "iframe-stream": "^3.0.0", "inject-css": "^0.1.1", "jazzicon": "^1.2.0", - "json-rpc-engine": "^3.7.3", + "json-rpc-engine": "^3.7.4", "json-rpc-middleware-stream": "^1.0.1", + "jsonschema": "^1.2.4", "lodash.debounce": "^4.0.8", "lodash.memoize": "^4.1.2", "lodash.shuffle": "^4.2.0", "lodash.uniqby": "^4.7.0", "loglevel": "^1.4.1", "metamascara": "^2.0.0", - "metamask-inpage-provider": "^1.0.0", + "metamask-inpage-provider": "^1.1.1", "metamask-logo": "^2.1.4", "mkdirp": "^0.5.1", "multihashes": "^0.4.12", @@ -189,6 +191,7 @@ "react-addons-css-transition-group": "^15.6.0", "react-dom": "^15.6.2", "react-hyperscript": "^3.0.0", + "react-inspector": "^2.3.0", "react-markdown": "^3.0.0", "react-media": "^1.8.0", "react-redux": "^5.0.5", @@ -228,6 +231,7 @@ "@storybook/addon-info": "^3.4.2", "@storybook/addon-knobs": "^3.4.2", "@storybook/react": "^3.4.2", + "addons-linter": "^1.3.4", "babel-core": "^6.24.1", "babel-eslint": "^8.0.0", "babel-plugin-transform-async-to-generator": "^6.24.1", diff --git a/test/data/mock-state.json b/test/data/mock-state.json new file mode 100644 index 000000000..7e083c60e --- /dev/null +++ b/test/data/mock-state.json @@ -0,0 +1,1251 @@ +{ + "metamask": { + "network": "4", + "identities": { + "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc": { + "address": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc", + "name": "Test Account" + }, + "0xc42edfcc21ed14dda456aa0756c153f7985d8813": { + "address": "0xc42edfcc21ed14dda456aa0756c153f7985d8813", + "name": "Test Account 2" + } + }, + "unapprovedTxs": { + "8393540981007587": { + "id": 8393540981007587, + "time": 1536268017676, + "status": "unapproved", + "metamaskNetworkId": "4", + "loadingDefaults": false, + "txParams": { + "from": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc", + "to": "0xc42edfcc21ed14dda456aa0756c153f7985d8813", + "value": "0x0", + "gas": "0x5208", + "gasPrice": "0x3b9aca00" + }, + "history": [ + { + "id": 8393540981007587, + "time": 1536268017676, + "status": "unapproved", + "metamaskNetworkId": "4", + "loadingDefaults": true, + "txParams": { + "from": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc", + "to": "0xc42edfcc21ed14dda456aa0756c153f7985d8813", + "value": "0x0", + "gas": "0x5208", + "gasPrice": "0x3b9aca00" + } + }, + [ + { + "op": "replace", + "path": "/loadingDefaults", + "value": false, + "timestamp": 1536268017685 + }, + { + "op": "add", + "path": "/gasPriceSpecified", + "value": true + }, + { + "op": "add", + "path": "/gasLimitSpecified", + "value": true + }, + { + "op": "add", + "path": "/estimatedGas", + "value": "0x5208" + } + ], + [ + { + "op": "add", + "path": "/origin", + "value": "MetaMask", + "note": "#newUnapprovedTransaction - adding the origin", + "timestamp": 1536268017686 + } + ] + ], + "gasPriceSpecified": true, + "gasLimitSpecified": true, + "estimatedGas": "0x5208", + "origin": "MetaMask" + } + }, + "selectedAddress": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc", + "accounts": { + "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc": { + "balance": "0x0", + "address": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc" + }, + "0xc42edfcc21ed14dda456aa0756c153f7985d8813": { + "address": "0xc42edfcc21ed14dda456aa0756c153f7985d8813", + "balance": "0x0" + } + }, + "tokens": [ + { + "address": "0x108cf70c7d384c552f42c07c41c0e1e46d77ea0d", + "symbol": "TEST", + "decimals": "0" + }, + { + "address": "0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5", + "decimals": "8", + "symbol": "TEST2" + }, + { + "address": "0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4", + "symbol": "META", + "decimals": "18" + } + ], + "contractExchangeRates": { + "0x108cf70c7d384c552f42c07c41c0e1e46d77ea0d": 0.00039345803819379796, + "0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5": 0.00008189274407698049 + }, + "currentCurrency": "usd", + "conversionRate": 556.12, + "addressBook": [ + { + "address": "0xc42edfcc21ed14dda456aa0756c153f7985d8813", + "name": "" + } + ], + "selectedTokenAddress": "0x108cf70c7d384c552f42c07c41c0e1e46d77ea0d", + "unapprovedMsgs": {}, + "unapprovedMsgCount": 0, + "unapprovedPersonalMsgs": {}, + "unapprovedPersonalMsgCount": 0, + "unapprovedTypedMessages": {}, + "unapprovedTypedMessagesCount": 0, + "send": { + "gasLimit": "0x5208", + "gasPrice": "0xee6b2800", + "gasTotal": "0x4c65c6294000", + "tokenBalance": null, + "from": "0xc42edfcc21ed14dda456aa0756c153f7985d8813", + "to": "", + "amount": "1bc16d674ec80000", + "memo": "", + "errors": {}, + "maxModeOn": false, + "editingTransactionId": null, + "forceGasMin": null, + "toNickname": "" + }, + "selectedAddressTxList": [ + { + "id": 3387511061307736, + "time": 1528133130531, + "status": "confirmed", + "metamaskNetworkId": "4", + "loadingDefaults": false, + "txParams": { + "from": "0x3b222de3aaba8ec9771ca9e9af5d8ed757fb7f62", + "to": "0x92e659448c48fc926ec942d0da1459260d36bb33", + "value": "0x1bc16d674ec80000", + "gas": "0xcf08", + "gasPrice": "0x3b9aca00", + "nonce": "0xb5" + }, + "history": [ + { + "id": 3387511061307736, + "time": 1528133130531, + "status": "unapproved", + "metamaskNetworkId": "4", + "loadingDefaults": true, + "txParams": { + "from": "0x3b222de3aaba8ec9771ca9e9af5d8ed757fb7f62", + "to": "0x92e659448c48fc926ec942d0da1459260d36bb33", + "value": "0x1bc16d674ec80000", + "gas": "0xcf08", + "gasPrice": "0x3b9aca00" + } + }, + [ + { + "op": "replace", + "path": "/loadingDefaults", + "value": false, + "timestamp": 1528133130666 + }, + { + "op": "add", + "path": "/gasPriceSpecified", + "value": true + }, + { + "op": "add", + "path": "/gasLimitSpecified", + "value": true + }, + { + "op": "add", + "path": "/estimatedGas", + "value": "0xcf08" + } + ], + [ + { + "op": "add", + "path": "/origin", + "value": "MetaMask", + "note": "#newUnapprovedTransaction - adding the origin", + "timestamp": 1528133130667 + } + ], + [], + [ + { + "op": "replace", + "path": "/status", + "value": "approved", + "note": "txStateManager: setting status to approved", + "timestamp": 1528133131716 + } + ], + [ + { + "op": "add", + "path": "/txParams/nonce", + "value": "0xb5", + "note": "transactions#approveTransaction", + "timestamp": 1528133131806 + }, + { + "op": "add", + "path": "/nonceDetails", + "value": { + "params": { + "highestLocallyConfirmed": 0, + "highestSuggested": 181, + "nextNetworkNonce": 181 + }, + "local": { + "name": "local", + "nonce": 181, + "details": { + "startPoint": 181, + "highest": 181 + } + }, + "network": { + "name": "network", + "nonce": 181, + "details": { + "baseCount": 181 + } + } + } + } + ], + [ + { + "op": "replace", + "path": "/status", + "value": "signed", + "note": "transactions#publishTransaction", + "timestamp": 1528133131825 + }, + { + "op": "add", + "path": "/rawTx", + "value": "0xf86c81b5843b9aca0082cf089492e659448c48fc926ec942d0da1459260d36bb33881bc16d674ec80000802ba03f879cd33a31180da38545d0f809822e00ddf35954d8b0ece83bacf22347ce54a06ad050487978e425ca6a014ed55ea8e9a190069863ed96a0eefa88d729ea1eda" + } + ], + [], + [ + { + "op": "add", + "path": "/hash", + "value": "0x516b77569173a04c76fdb6545cf279ebd0c75f5d25d6e4ce019925205f0e3709", + "note": "transactions#setTxHash", + "timestamp": 1528133131951 + } + ], + [ + { + "op": "add", + "path": "/submittedTime", + "value": 1528133131951, + "note": "txStateManager - add submitted time stamp", + "timestamp": 1528133131952 + } + ], + [ + { + "op": "replace", + "path": "/status", + "value": "submitted", + "note": "txStateManager: setting status to submitted", + "timestamp": 1528133131955 + } + ], + [ + { + "op": "add", + "path": "/firstRetryBlockNumber", + "value": "0x24af6b", + "note": "transactions/pending-tx-tracker#event: tx:block-update", + "timestamp": 1528133134414 + } + ], + [ + { + "op": "replace", + "path": "/status", + "value": "confirmed", + "note": "txStateManager: setting status to confirmed", + "timestamp": 1528133158516 + } + ] + ], + "gasPriceSpecified": true, + "gasLimitSpecified": true, + "estimatedGas": "0xcf08", + "origin": "MetaMask", + "nonceDetails": { + "params": { + "highestLocallyConfirmed": 0, + "highestSuggested": 181, + "nextNetworkNonce": 181 + }, + "local": { + "name": "local", + "nonce": 181, + "details": { + "startPoint": 181, + "highest": 181 + } + }, + "network": { + "name": "network", + "nonce": 181, + "details": { + "baseCount": 181 + } + } + }, + "rawTx": "0xf86c81b5843b9aca0082cf089492e659448c48fc926ec942d0da1459260d36bb33881bc16d674ec80000802ba03f879cd33a31180da38545d0f809822e00ddf35954d8b0ece83bacf22347ce54a06ad050487978e425ca6a014ed55ea8e9a190069863ed96a0eefa88d729ea1eda", + "hash": "0x516b77569173a04c76fdb6545cf279ebd0c75f5d25d6e4ce019925205f0e3709", + "submittedTime": 1528133131951, + "firstRetryBlockNumber": "0x24af6b" + }, + { + "id": 3387511061307737, + "time": 1528133149983, + "status": "confirmed", + "metamaskNetworkId": "4", + "loadingDefaults": false, + "txParams": { + "from": "0x3b222de3aaba8ec9771ca9e9af5d8ed757fb7f62", + "to": "0x92e659448c48fc926ec942d0da1459260d36bb33", + "value": "0x1bc16d674ec80000", + "gas": "0xcf08", + "gasPrice": "0x3b9aca00", + "nonce": "0xb6" + }, + "history": [ + { + "id": 3387511061307737, + "time": 1528133149983, + "status": "unapproved", + "metamaskNetworkId": "4", + "loadingDefaults": true, + "txParams": { + "from": "0x3b222de3aaba8ec9771ca9e9af5d8ed757fb7f62", + "to": "0x92e659448c48fc926ec942d0da1459260d36bb33", + "value": "0x1bc16d674ec80000", + "gas": "0xcf08", + "gasPrice": "0x3b9aca00" + } + }, + [ + { + "op": "replace", + "path": "/loadingDefaults", + "value": false, + "timestamp": 1528133150011 + }, + { + "op": "add", + "path": "/gasPriceSpecified", + "value": true + }, + { + "op": "add", + "path": "/gasLimitSpecified", + "value": true + }, + { + "op": "add", + "path": "/estimatedGas", + "value": "0xcf08" + } + ], + [ + { + "op": "add", + "path": "/origin", + "value": "MetaMask", + "note": "#newUnapprovedTransaction - adding the origin", + "timestamp": 1528133150013 + } + ], + [], + [ + { + "op": "replace", + "path": "/status", + "value": "approved", + "note": "txStateManager: setting status to approved", + "timestamp": 1528133151102 + } + ], + [ + { + "op": "add", + "path": "/txParams/nonce", + "value": "0xb6", + "note": "transactions#approveTransaction", + "timestamp": 1528133151189 + }, + { + "op": "add", + "path": "/nonceDetails", + "value": { + "params": { + "highestLocallyConfirmed": 0, + "highestSuggested": 181, + "nextNetworkNonce": 181 + }, + "local": { + "name": "local", + "nonce": 182, + "details": { + "startPoint": 181, + "highest": 182 + } + }, + "network": { + "name": "network", + "nonce": 181, + "details": { + "baseCount": 181 + } + } + } + } + ], + [ + { + "op": "replace", + "path": "/status", + "value": "signed", + "note": "transactions#publishTransaction", + "timestamp": 1528133151203 + }, + { + "op": "add", + "path": "/rawTx", + "value": "0xf86c81b6843b9aca0082cf089492e659448c48fc926ec942d0da1459260d36bb33881bc16d674ec80000802ba0692deaabf0d79544d41e7c475ad43760679a4f25d0fee908b1da308db1a291a7a0384db85fc6c843ea25986a0760f3c50ab6504fc559fc71fc7f23f60950eb316d" + } + ], + [], + [ + { + "op": "add", + "path": "/hash", + "value": "0x9271b266d05022cfa841362fae43763ebafcee540d84278b0157ef4a68d4e26f", + "note": "transactions#setTxHash", + "timestamp": 1528133151342 + } + ], + [ + { + "op": "add", + "path": "/submittedTime", + "value": 1528133151347, + "note": "txStateManager - add submitted time stamp", + "timestamp": 1528133151347 + } + ], + [ + { + "op": "replace", + "path": "/status", + "value": "submitted", + "note": "txStateManager: setting status to submitted", + "timestamp": 1528133151368 + } + ], + [ + { + "op": "add", + "path": "/firstRetryBlockNumber", + "value": "0x24af6d", + "note": "transactions/pending-tx-tracker#event: tx:block-update", + "timestamp": 1528133158532 + } + ], + [ + { + "op": "replace", + "path": "/status", + "value": "confirmed", + "note": "txStateManager: setting status to confirmed", + "timestamp": 1528133190636 + } + ] + ], + "gasPriceSpecified": true, + "gasLimitSpecified": true, + "estimatedGas": "0xcf08", + "origin": "MetaMask", + "nonceDetails": { + "params": { + "highestLocallyConfirmed": 0, + "highestSuggested": 181, + "nextNetworkNonce": 181 + }, + "local": { + "name": "local", + "nonce": 182, + "details": { + "startPoint": 181, + "highest": 182 + } + }, + "network": { + "name": "network", + "nonce": 181, + "details": { + "baseCount": 181 + } + } + }, + "rawTx": "0xf86c81b6843b9aca0082cf089492e659448c48fc926ec942d0da1459260d36bb33881bc16d674ec80000802ba0692deaabf0d79544d41e7c475ad43760679a4f25d0fee908b1da308db1a291a7a0384db85fc6c843ea25986a0760f3c50ab6504fc559fc71fc7f23f60950eb316d", + "hash": "0x9271b266d05022cfa841362fae43763ebafcee540d84278b0157ef4a68d4e26f", + "submittedTime": 1528133151347, + "firstRetryBlockNumber": "0x24af6d" + }, + { + "id": 3387511061307738, + "time": 1528133180635, + "status": "confirmed", + "metamaskNetworkId": "4", + "loadingDefaults": false, + "txParams": { + "from": "0x3b222de3aaba8ec9771ca9e9af5d8ed757fb7f62", + "to": "0x92e659448c48fc926ec942d0da1459260d36bb33", + "value": "0x1bc16d674ec80000", + "gas": "0xcf08", + "gasPrice": "0x12a05f200", + "nonce": "0xb7" + }, + "history": [ + { + "id": 3387511061307738, + "time": 1528133180635, + "status": "unapproved", + "metamaskNetworkId": "4", + "loadingDefaults": true, + "txParams": { + "from": "0x3b222de3aaba8ec9771ca9e9af5d8ed757fb7f62", + "to": "0x92e659448c48fc926ec942d0da1459260d36bb33", + "value": "0x1bc16d674ec80000", + "gas": "0xcf08", + "gasPrice": "0x12a05f200" + } + }, + [ + { + "op": "replace", + "path": "/loadingDefaults", + "value": false, + "timestamp": 1528133180720 + }, + { + "op": "add", + "path": "/gasPriceSpecified", + "value": true + }, + { + "op": "add", + "path": "/gasLimitSpecified", + "value": true + }, + { + "op": "add", + "path": "/estimatedGas", + "value": "0xcf08" + } + ], + [ + { + "op": "add", + "path": "/origin", + "value": "MetaMask", + "note": "#newUnapprovedTransaction - adding the origin", + "timestamp": 1528133180722 + } + ], + [], + [ + { + "op": "replace", + "path": "/status", + "value": "approved", + "note": "txStateManager: setting status to approved", + "timestamp": 1528133181623 + } + ], + [ + { + "op": "add", + "path": "/txParams/nonce", + "value": "0xb7", + "note": "transactions#approveTransaction", + "timestamp": 1528133181726 + }, + { + "op": "add", + "path": "/nonceDetails", + "value": { + "params": { + "highestLocallyConfirmed": 182, + "highestSuggested": 182, + "nextNetworkNonce": 182 + }, + "local": { + "name": "local", + "nonce": 183, + "details": { + "startPoint": 182, + "highest": 183 + } + }, + "network": { + "name": "network", + "nonce": 182, + "details": { + "baseCount": 182 + } + } + } + } + ], + [ + { + "op": "replace", + "path": "/status", + "value": "signed", + "note": "transactions#publishTransaction", + "timestamp": 1528133181749 + }, + { + "op": "add", + "path": "/rawTx", + "value": "0xf86d81b785012a05f20082cf089492e659448c48fc926ec942d0da1459260d36bb33881bc16d674ec80000802ba086f9846798be6988c39a5cf85f0dbe267e59ca0b96a6a7077e92cba33e10a258a064ffa52ac90c238ce21e6f085283216191b185a1eccd7daae6e2ab66ba26ada0" + } + ], + [], + [ + { + "op": "add", + "path": "/hash", + "value": "0x4e061e977c099735bc9e5203e717f7d9dccb3fcb2f82031a12a3ed326f95d43b", + "note": "transactions#setTxHash", + "timestamp": 1528133181885 + } + ], + [ + { + "op": "add", + "path": "/submittedTime", + "value": 1528133181885, + "note": "txStateManager - add submitted time stamp", + "timestamp": 1528133181885 + } + ], + [ + { + "op": "replace", + "path": "/status", + "value": "submitted", + "note": "txStateManager: setting status to submitted", + "timestamp": 1528133181888 + } + ], + [ + { + "op": "add", + "path": "/firstRetryBlockNumber", + "value": "0x24af6f", + "note": "transactions/pending-tx-tracker#event: tx:block-update", + "timestamp": 1528133190653 + } + ], + [ + { + "op": "replace", + "path": "/status", + "value": "confirmed", + "note": "txStateManager: setting status to confirmed", + "timestamp": 1528133222745 + } + ] + ], + "gasPriceSpecified": true, + "gasLimitSpecified": true, + "estimatedGas": "0xcf08", + "origin": "MetaMask", + "nonceDetails": { + "params": { + "highestLocallyConfirmed": 182, + "highestSuggested": 182, + "nextNetworkNonce": 182 + }, + "local": { + "name": "local", + "nonce": 183, + "details": { + "startPoint": 182, + "highest": 183 + } + }, + "network": { + "name": "network", + "nonce": 182, + "details": { + "baseCount": 182 + } + } + }, + "rawTx": "0xf86d81b785012a05f20082cf089492e659448c48fc926ec942d0da1459260d36bb33881bc16d674ec80000802ba086f9846798be6988c39a5cf85f0dbe267e59ca0b96a6a7077e92cba33e10a258a064ffa52ac90c238ce21e6f085283216191b185a1eccd7daae6e2ab66ba26ada0", + "hash": "0x4e061e977c099735bc9e5203e717f7d9dccb3fcb2f82031a12a3ed326f95d43b", + "submittedTime": 1528133181885, + "firstRetryBlockNumber": "0x24af6f" + }, + { + "id": 3387511061307739, + "time": 1528133223918, + "status": "confirmed", + "metamaskNetworkId": "4", + "loadingDefaults": false, + "txParams": { + "from": "0x3b222de3aaba8ec9771ca9e9af5d8ed757fb7f62", + "to": "0xfe2149773b3513703e79ad23d05a778a185016ee", + "value": "0xaa87bee538000", + "data": "0xea94496b000000000000000000000000000000000000000000000000000000000001e1eb000000000000000000000000000000000000000000000000000000000001de33", + "gasPrice": "0x3b9aca00", + "gas": "0x6169e", + "nonce": "0xb8" + }, + "history": [ + { + "id": 3387511061307739, + "time": 1528133223918, + "status": "unapproved", + "metamaskNetworkId": "4", + "loadingDefaults": true, + "txParams": { + "from": "0x3b222de3aaba8ec9771ca9e9af5d8ed757fb7f62", + "to": "0xfe2149773b3513703e79ad23d05a778a185016ee", + "value": "0xaa87bee538000", + "data": "0xea94496b000000000000000000000000000000000000000000000000000000000001e1eb000000000000000000000000000000000000000000000000000000000001de33", + "gasPrice": "0x3b9aca00" + } + }, + [ + { + "op": "add", + "path": "/txParams/gas", + "value": "0x6169e", + "timestamp": 1528133225488 + }, + { + "op": "replace", + "path": "/loadingDefaults", + "value": false + }, + { + "op": "add", + "path": "/gasPriceSpecified", + "value": true + }, + { + "op": "add", + "path": "/gasLimitSpecified", + "value": false + }, + { + "op": "add", + "path": "/estimatedGas", + "value": "40f14" + } + ], + [ + { + "op": "replace", + "path": "/estimatedGas", + "value": "40f14", + "note": "#newUnapprovedTransaction - adding the origin", + "timestamp": 1528133225492 + }, + { + "op": "add", + "path": "/origin", + "value": "crypko.ai" + } + ], + [], + [ + { + "op": "replace", + "path": "/status", + "value": "approved", + "note": "txStateManager: setting status to approved", + "timestamp": 1528133227279 + } + ], + [ + { + "op": "add", + "path": "/txParams/nonce", + "value": "0xb8", + "note": "transactions#approveTransaction", + "timestamp": 1528133227374 + }, + { + "op": "add", + "path": "/nonceDetails", + "value": { + "params": { + "highestLocallyConfirmed": 184, + "highestSuggested": 184, + "nextNetworkNonce": 184 + }, + "local": { + "name": "local", + "nonce": 184, + "details": { + "startPoint": 184, + "highest": 184 + } + }, + "network": { + "name": "network", + "nonce": 184, + "details": { + "baseCount": 184 + } + } + } + } + ], + [ + { + "op": "replace", + "path": "/status", + "value": "signed", + "note": "transactions#publishTransaction", + "timestamp": 1528133227405 + }, + { + "op": "add", + "path": "/rawTx", + "value": "0xf8b181b8843b9aca008306169e94fe2149773b3513703e79ad23d05a778a185016ee870aa87bee538000b844ea94496b000000000000000000000000000000000000000000000000000000000001e1eb000000000000000000000000000000000000000000000000000000000001de332ca07bb2efbb8529d67606f9f89e7934c594a31d50c7d24a3286c20a2944a3b8c2a9a07b55ebd8aa28728ce0e38dd3b3503b78fccedae80053626d8649c68346c7c49c" + } + ], + [], + [ + { + "op": "add", + "path": "/hash", + "value": "0x466ae7d4b7c270121f0a8d68fbc6c9091ffc4aa976a553a5bfa56a79cf9f63dd", + "note": "transactions#setTxHash", + "timestamp": 1528133227534 + } + ], + [ + { + "op": "add", + "path": "/submittedTime", + "value": 1528133227538, + "note": "txStateManager - add submitted time stamp", + "timestamp": 1528133227538 + } + ], + [ + { + "op": "replace", + "path": "/status", + "value": "submitted", + "note": "txStateManager: setting status to submitted", + "timestamp": 1528133227543 + } + ], + [ + { + "op": "add", + "path": "/firstRetryBlockNumber", + "value": "0x24af72", + "note": "transactions/pending-tx-tracker#event: tx:block-update", + "timestamp": 1528133238980 + } + ], + [ + { + "op": "replace", + "path": "/status", + "value": "confirmed", + "note": "txStateManager: setting status to confirmed", + "timestamp": 1528133255035 + } + ] + ], + "gasPriceSpecified": true, + "gasLimitSpecified": false, + "estimatedGas": "40f14", + "origin": "crypko.ai", + "nonceDetails": { + "params": { + "highestLocallyConfirmed": 184, + "highestSuggested": 184, + "nextNetworkNonce": 184 + }, + "local": { + "name": "local", + "nonce": 184, + "details": { + "startPoint": 184, + "highest": 184 + } + }, + "network": { + "name": "network", + "nonce": 184, + "details": { + "baseCount": 184 + } + } + }, + "rawTx": "0xf8b181b8843b9aca008306169e94fe2149773b3513703e79ad23d05a778a185016ee870aa87bee538000b844ea94496b000000000000000000000000000000000000000000000000000000000001e1eb000000000000000000000000000000000000000000000000000000000001de332ca07bb2efbb8529d67606f9f89e7934c594a31d50c7d24a3286c20a2944a3b8c2a9a07b55ebd8aa28728ce0e38dd3b3503b78fccedae80053626d8649c68346c7c49c", + "hash": "0x466ae7d4b7c270121f0a8d68fbc6c9091ffc4aa976a553a5bfa56a79cf9f63dd", + "submittedTime": 1528133227538, + "firstRetryBlockNumber": "0x24af72" + }, + { + "id": 3387511061307740, + "time": 1528133291381, + "status": "confirmed", + "metamaskNetworkId": "4", + "loadingDefaults": false, + "txParams": { + "from": "0x3b222de3aaba8ec9771ca9e9af5d8ed757fb7f62", + "to": "0x108cf70c7d384c552f42c07c41c0e1e46d77ea0d", + "value": "0x0", + "data": "0xa9059cbb00000000000000000000000092e659448c48fc926ec942d0da1459260d36bb330000000000000000000000000000000000000000000000000000000000000002", + "gas": "0xd508", + "gasPrice": "0x3b9aca00", + "nonce": "0xb9" + }, + "history": [ + { + "id": 3387511061307740, + "time": 1528133291381, + "status": "unapproved", + "metamaskNetworkId": "4", + "loadingDefaults": true, + "txParams": { + "from": "0x3b222de3aaba8ec9771ca9e9af5d8ed757fb7f62", + "to": "0x108cf70c7d384c552f42c07c41c0e1e46d77ea0d", + "value": "0x0", + "data": "0xa9059cbb00000000000000000000000092e659448c48fc926ec942d0da1459260d36bb330000000000000000000000000000000000000000000000000000000000000002", + "gas": "0xd508", + "gasPrice": "0x3b9aca00" + } + }, + [ + { + "op": "replace", + "path": "/loadingDefaults", + "value": false, + "timestamp": 1528133291486 + }, + { + "op": "add", + "path": "/gasPriceSpecified", + "value": true + }, + { + "op": "add", + "path": "/gasLimitSpecified", + "value": true + }, + { + "op": "add", + "path": "/estimatedGas", + "value": "0xd508" + } + ], + [ + { + "op": "add", + "path": "/origin", + "value": "MetaMask", + "note": "#newUnapprovedTransaction - adding the origin", + "timestamp": 1528133291486 + } + ], + [], + [ + { + "op": "replace", + "path": "/status", + "value": "approved", + "note": "txStateManager: setting status to approved", + "timestamp": 1528133293588 + } + ], + [ + { + "op": "add", + "path": "/txParams/nonce", + "value": "0xb9", + "note": "transactions#approveTransaction", + "timestamp": 1528133293706 + }, + { + "op": "add", + "path": "/nonceDetails", + "value": { + "params": { + "highestLocallyConfirmed": 185, + "highestSuggested": 185, + "nextNetworkNonce": 185 + }, + "local": { + "name": "local", + "nonce": 185, + "details": { + "startPoint": 185, + "highest": 185 + } + }, + "network": { + "name": "network", + "nonce": 185, + "details": { + "baseCount": 185 + } + } + } + } + ], + [ + { + "op": "replace", + "path": "/status", + "value": "signed", + "note": "transactions#publishTransaction", + "timestamp": 1528133293724 + }, + { + "op": "add", + "path": "/rawTx", + "value": "0xf8a981b9843b9aca0082d50894108cf70c7d384c552f42c07c41c0e1e46d77ea0d80b844a9059cbb00000000000000000000000092e659448c48fc926ec942d0da1459260d36bb3300000000000000000000000000000000000000000000000000000000000000022ca04f05310490d3e3a9a159ae25f52cec9afb0a69527d30be832aaae12e64ff056ea075f81a5220bed481e764bab8830c57169c59fe528ca9cf3442f47f7618a9b4a9" + } + ], + [], + [ + { + "op": "add", + "path": "/hash", + "value": "0x3680dc9815cd05b620b6dd0017d949604ca7d92f051d5542fc8a5ecaa876af09", + "note": "transactions#setTxHash", + "timestamp": 1528133293853 + } + ], + [ + { + "op": "add", + "path": "/submittedTime", + "value": 1528133293859, + "note": "txStateManager - add submitted time stamp", + "timestamp": 1528133293862 + } + ], + [ + { + "op": "replace", + "path": "/status", + "value": "submitted", + "note": "txStateManager: setting status to submitted", + "timestamp": 1528133293867 + } + ], + [ + { + "op": "add", + "path": "/firstRetryBlockNumber", + "value": "0x24af76", + "note": "transactions/pending-tx-tracker#event: tx:block-update", + "timestamp": 1528133295200 + } + ], + [ + { + "op": "replace", + "path": "/status", + "value": "confirmed", + "note": "txStateManager: setting status to confirmed", + "timestamp": 1528133327522 + } + ] + ], + "gasPriceSpecified": true, + "gasLimitSpecified": true, + "estimatedGas": "0xd508", + "origin": "MetaMask", + "nonceDetails": { + "params": { + "highestLocallyConfirmed": 185, + "highestSuggested": 185, + "nextNetworkNonce": 185 + }, + "local": { + "name": "local", + "nonce": 185, + "details": { + "startPoint": 185, + "highest": 185 + } + }, + "network": { + "name": "network", + "nonce": 185, + "details": { + "baseCount": 185 + } + } + }, + "rawTx": "0xf8a981b9843b9aca0082d50894108cf70c7d384c552f42c07c41c0e1e46d77ea0d80b844a9059cbb00000000000000000000000092e659448c48fc926ec942d0da1459260d36bb3300000000000000000000000000000000000000000000000000000000000000022ca04f05310490d3e3a9a159ae25f52cec9afb0a69527d30be832aaae12e64ff056ea075f81a5220bed481e764bab8830c57169c59fe528ca9cf3442f47f7618a9b4a9", + "hash": "0x3680dc9815cd05b620b6dd0017d949604ca7d92f051d5542fc8a5ecaa876af09", + "submittedTime": 1528133293859, + "firstRetryBlockNumber": "0x24af76" + }, + { + "id": 3387511061307741, + "time": 1528133318440, + "status": "rejected", + "metamaskNetworkId": "4", + "loadingDefaults": false, + "txParams": { + "from": "0x3b222de3aaba8ec9771ca9e9af5d8ed757fb7f62", + "to": "0x3b222de3aaba8ec9771ca9e9af5d8ed757fb7f62", + "value": "0x0", + "gasPrice": "0x3b9aca00", + "gas": "0x5208" + }, + "history": [ + { + "id": 3387511061307741, + "time": 1528133318440, + "status": "unapproved", + "metamaskNetworkId": "4", + "loadingDefaults": true, + "txParams": { + "from": "0x3b222de3aaba8ec9771ca9e9af5d8ed757fb7f62", + "to": "0x3b222de3aaba8ec9771ca9e9af5d8ed757fb7f62" + } + }, + [ + { + "op": "add", + "path": "/txParams/value", + "value": "0x0", + "timestamp": 1528133319641 + }, + { + "op": "add", + "path": "/txParams/gasPrice", + "value": "0x3b9aca00" + }, + { + "op": "add", + "path": "/txParams/gas", + "value": "0x5208" + }, + { + "op": "replace", + "path": "/loadingDefaults", + "value": false + }, + { + "op": "add", + "path": "/gasPriceSpecified", + "value": false + }, + { + "op": "add", + "path": "/gasLimitSpecified", + "value": false + }, + { + "op": "add", + "path": "/simpleSend", + "value": true + }, + { + "op": "add", + "path": "/estimatedGas", + "value": "0x5208" + } + ], + [ + { + "op": "add", + "path": "/origin", + "value": "tmashuang.github.io", + "note": "#newUnapprovedTransaction - adding the origin", + "timestamp": 1528133319642 + } + ], + [ + { + "op": "replace", + "path": "/status", + "value": "rejected", + "note": "txStateManager: setting status to rejected", + "timestamp": 1528133320924 + } + ] + ], + "gasPriceSpecified": false, + "gasLimitSpecified": false, + "simpleSend": true, + "estimatedGas": "0x5208", + "origin": "tmashuang.github.io" + } + ] + }, + "appState": { + "gasIsLoading": false, + "currentView": { + "name": "accountDetail", + "detailView": null, + "context": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc" + } + } +}
\ No newline at end of file diff --git a/test/e2e/beta/metamask-beta-ui.spec.js b/test/e2e/beta/metamask-beta-ui.spec.js index 0864ef236..7370f1a92 100644 --- a/test/e2e/beta/metamask-beta-ui.spec.js +++ b/test/e2e/beta/metamask-beta-ui.spec.js @@ -1043,7 +1043,7 @@ describe('MetaMask', function () { await customRpcInput.clear() await customRpcInput.sendKeys(customRpcUrl) - const customRpcSave = await findElement(driver, By.css('.settings__rpc-save-button')) + const customRpcSave = await findElement(driver, By.css('.settings-tab__rpc-save-button')) await customRpcSave.click() await delay(largeDelayMs * 2) }) diff --git a/test/e2e/metamask.spec.js b/test/e2e/metamask.spec.js index 38246a044..13af6cb22 100644 --- a/test/e2e/metamask.spec.js +++ b/test/e2e/metamask.spec.js @@ -201,17 +201,17 @@ describe('Metamask popup page', function () { }) it('balance renders', async function () { - await delay(200) + await delay(500) const balance = await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > div > div.flex-row > div.ether-balance.ether-balance-amount > div > div > div:nth-child(1) > div:nth-child(1)')) assert.equal(await balance.getText(), '100.000') await delay(200) }) it('sends transaction', async function () { - const sendButton = await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > div > div.flex-row > button:nth-child(4)')) - assert.equal(await sendButton.getText(), 'SEND') - await sendButton.click() - await delay(200) + const sendButton = await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > div > div.flex-row > button:nth-child(4)')) + assert.equal(await sendButton.getText(), 'SEND') + await sendButton.click() + await delay(200) }) it('adds recipient address and amount', async function () { diff --git a/test/integration/lib/tx-list-items.js b/test/integration/lib/tx-list-items.js index 8f291c7b4..f64a8d7de 100644 --- a/test/integration/lib/tx-list-items.js +++ b/test/integration/lib/tx-list-items.js @@ -34,7 +34,7 @@ async function runTxListItemsTest (assert, done) { const retryTxGrid = await findAsync($(txListItems[1]), '.transaction-list-item__grid') retryTxGrid[0].click() - const retryTxDetails = await findAsync($(txListItems[1]), '.transaction-list-item-details') + const retryTxDetails = await findAsync($, '.transaction-list-item-details') const headerButtons = await findAsync($(retryTxDetails[0]), '.transaction-list-item-details__header-button') assert.equal(headerButtons[0].textContent, 'speed up') diff --git a/test/lib/render-helpers.js b/test/lib/render-helpers.js new file mode 100644 index 000000000..81f0e27aa --- /dev/null +++ b/test/lib/render-helpers.js @@ -0,0 +1,42 @@ +const { shallow, mount } = require('enzyme') +import { BrowserRouter } from 'react-router-dom' +import { shape } from 'prop-types' + +module.exports = { + shallowWithStore, + mountWithStore, + mountWithRouter, +} + +function shallowWithStore (component, store) { + const context = { + store, + } + return shallow(component, {context}) +} + +function mountWithStore (component, store) { + const context = { + store, + } + return mount(component, {context}) +} + +function mountWithRouter (node) { + + // Instantiate router context + const router = { + history: new BrowserRouter().history, + route: { + location: {}, + match: {}, + }, + } + + const createContext = () => ({ + context: { router, t: () => {} }, + childContextTypes: { router: shape({}), t: () => {} }, + }) + + return mount(node, createContext()) +} diff --git a/test/lib/shallow-with-store.js b/test/lib/shallow-with-store.js deleted file mode 100644 index 9df10a3c5..000000000 --- a/test/lib/shallow-with-store.js +++ /dev/null @@ -1,20 +0,0 @@ -const { shallow, mount } = require('enzyme') - -module.exports = { - shallowWithStore, - mountWithStore, -} - -function shallowWithStore (component, store) { - const context = { - store, - } - return shallow(component, {context}) -} - -function mountWithStore (component, store) { - const context = { - store, - } - return mount(component, {context}) -} diff --git a/test/unit/app/cleanErrorStack.spec.js b/test/unit/app/cleanErrorStack.spec.js new file mode 100644 index 000000000..7a1ab1ed8 --- /dev/null +++ b/test/unit/app/cleanErrorStack.spec.js @@ -0,0 +1,33 @@ +const assert = require('assert') +const cleanErrorStack = require('../../../app/scripts/lib/cleanErrorStack') + +describe('Clean Error Stack', () => { + + const testMessage = 'Test Message' + const testError = new Error(testMessage) + const undefinedErrorName = new Error(testMessage) + const blankErrorName = new Error(testMessage) + const blankMsgError = new Error() + + beforeEach(() => { + undefinedErrorName.name = undefined + blankErrorName.name = '' + }) + + it('tests error with message', () => { + assert.equal(cleanErrorStack(testError), 'Error: Test Message') + }) + + it('tests error with undefined name', () => { + assert.equal(cleanErrorStack(undefinedErrorName).toString(), 'Error: Test Message') + }) + + it('tests error with blank name', () => { + assert.equal(cleanErrorStack(blankErrorName).toString(), 'Test Message') + }) + + it('tests error with blank message', () => { + assert.equal(cleanErrorStack(blankMsgError), 'Error') + }) + +}) diff --git a/test/unit/app/controllers/detect-tokens-test.js b/test/unit/app/controllers/detect-tokens-test.js index e5539256e..2acc53e92 100644 --- a/test/unit/app/controllers/detect-tokens-test.js +++ b/test/unit/app/controllers/detect-tokens-test.js @@ -138,4 +138,4 @@ describe('DetectTokensController', () => { clock.tick(180000) sandbox.assert.notCalled(stub) }) -})
\ No newline at end of file +}) diff --git a/test/unit/components/balance-component-test.js b/test/unit/components/balance-component-test.js index 81e6fdf9e..aa9763b72 100644 --- a/test/unit/components/balance-component-test.js +++ b/test/unit/components/balance-component-test.js @@ -1,7 +1,7 @@ const assert = require('assert') const h = require('react-hyperscript') const { createMockStore } = require('redux-test-utils') -const { shallowWithStore } = require('../../lib/shallow-with-store') +const { shallowWithStore } = require('../../lib/render-helpers') const BalanceComponent = require('../../../ui/app/components/balance-component') const mockState = { metamask: { @@ -42,4 +42,3 @@ describe('BalanceComponent', function () { }) }) - diff --git a/test/unit/responsive/components/dropdown-test.js b/test/unit/responsive/components/dropdown-test.js index 493b01918..f3f236d90 100644 --- a/test/unit/responsive/components/dropdown-test.js +++ b/test/unit/responsive/components/dropdown-test.js @@ -6,7 +6,7 @@ const path = require('path') const Dropdown = require(path.join(__dirname, '..', '..', '..', '..', 'ui', 'app', 'components', 'dropdowns', 'index.js')).Dropdown const { createMockStore } = require('redux-test-utils') -const { mountWithStore } = require('../../../lib/shallow-with-store') +const { mountWithStore } = require('../../../lib/render-helpers') const mockState = { metamask: { diff --git a/test/unit/ui/add-token.spec.js b/test/unit/ui/add-token.spec.js index 69b7fb620..f6b6155a0 100644 --- a/test/unit/ui/add-token.spec.js +++ b/test/unit/ui/add-token.spec.js @@ -1,7 +1,7 @@ const assert = require('assert') const { createMockStore } = require('redux-test-utils') const h = require('react-hyperscript') -const { shallowWithStore } = require('../../lib/shallow-with-store') +const { shallowWithStore } = require('../../lib/render-helpers') const AddTokenScreen = require('../../../old-ui/app/add-token') describe('Add Token Screen', function () { diff --git a/test/unit/ui/app/components/identicon.spec.js b/test/unit/ui/app/components/identicon.spec.js new file mode 100644 index 000000000..a2f8d8246 --- /dev/null +++ b/test/unit/ui/app/components/identicon.spec.js @@ -0,0 +1,36 @@ +import React from 'react' +import assert from 'assert' +import thunk from 'redux-thunk' +import configureMockStore from 'redux-mock-store' +import { mount } from 'enzyme' + +import IdenticonComponent from '../../../../../ui/app/components/identicon' + +describe('Identicon Component', () => { + + const state = { + metamask: { + useBlockie: false, + }, + } + + const middlewares = [thunk] + const mockStore = configureMockStore(middlewares) + const store = mockStore(state) + + it('renders default eth_logo identicon with no props', () => { + const wrapper = mount(<IdenticonComponent store={store}/>) + assert.equal(wrapper.find('img.balance-icon').prop('src'), './images/eth_logo.svg') + }) + + it('renders custom image and add className props', () => { + const wrapper = mount(<IdenticonComponent store={store} className={'test-image'} image={'test-image'} />) + assert.equal(wrapper.find('img.test-image').prop('className'), 'test-image identicon') + assert.equal(wrapper.find('img.test-image').prop('src'), 'test-image') + }) + + it('renders div with address prop', () => { + const wrapper = mount(<IdenticonComponent store={store} className={'test-address'} address={'0xTest'} />) + assert.equal(wrapper.find('div.test-address').prop('className'), 'test-address identicon') + }) +}) diff --git a/test/unit/ui/app/components/token-cell.spec.js b/test/unit/ui/app/components/token-cell.spec.js new file mode 100644 index 000000000..6145c6924 --- /dev/null +++ b/test/unit/ui/app/components/token-cell.spec.js @@ -0,0 +1,69 @@ +import React from 'react' +import assert from 'assert' +import thunk from 'redux-thunk' +import { Provider } from 'react-redux' +import configureMockStore from 'redux-mock-store' +import { mount } from 'enzyme' + +import TokenCell from '../../../../../ui/app/components/token-cell' +import Identicon from '../../../../../ui/app/components/identicon' + +describe('Token Cell', () => { + let wrapper + + const state = { + metamask: { + network: 'test', + currentCurrency: 'usd', + selectedTokenAddress: '0xToken', + selectedAddress: '0xAddress', + contractExchangeRates: { + '0xAnotherToken': 0.015, + }, + conversionRate: 7.00, + }, + appState: { + sidebar: { + isOpen: true, + }, + }, + } + + const middlewares = [thunk] + const mockStore = configureMockStore(middlewares) + const store = mockStore(state) + + beforeEach(() => { + wrapper = mount( + <Provider store={store}> + <TokenCell + address={'0xAnotherToken'} + symbol={'TEST'} + string={'5.000'} + network={22} + currentCurrency={'usd'} + image={'./test-image'} + /> + </Provider> + ) + }) + + it('renders Identicon with props from token cell', () => { + assert.equal(wrapper.find(Identicon).prop('address'), '0xAnotherToken') + assert.equal(wrapper.find(Identicon).prop('network'), 'test') + assert.equal(wrapper.find(Identicon).prop('image'), './test-image') + }) + + it('renders token balance', () => { + assert.equal(wrapper.find('.token-list-item__token-balance').text(), '5.000') + }) + + it('renders token symbol', () => { + assert.equal(wrapper.find('.token-list-item__token-symbol').text(), 'TEST') + }) + + it('renders converted fiat amount', () => { + assert.equal(wrapper.find('.token-list-item__fiat-amount').text(), '0.52 USD') + }) + +}) diff --git a/test/unit/ui/app/selectors.spec.js b/test/unit/ui/app/selectors.spec.js new file mode 100644 index 000000000..78c4267ee --- /dev/null +++ b/test/unit/ui/app/selectors.spec.js @@ -0,0 +1,175 @@ +const assert = require('assert') +const selectors = require('../../../../ui/app/selectors') +const mockState = require('../../../data/mock-state.json') +const Eth = require('ethjs') + +const { createTestProviderTools } = require('../../../stub/provider') +const provider = createTestProviderTools({ scaffold: {}}).provider + +describe('Selectors', function () { + + describe('#getSelectedAddress', function () { + let state + beforeEach(function () { + state = { + metamask: { + accounts: { + '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': { + 'balance': '0x0', + 'address': '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + }, + }, + }, + } + }) + + it('returns first account if selectedAddress is undefined', function () { + assert.equal(selectors.getSelectedAddress(state), '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc') + }) + + it('returns selectedAddress', function () { + assert.equal(selectors.getSelectedAddress(mockState), '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc') + }) + + }) + + it('returns selected identity', function () { + const identity = selectors.getSelectedIdentity(mockState) + assert.equal(identity.address, '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc') + assert.equal(identity.name, 'Test Account') + }) + + it('returns selected account', function () { + const account = selectors.getSelectedAccount(mockState) + assert.equal(account.balance, '0x0') + assert.equal(account.address, '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc') + }) + + it('returns selected token from first token list', function () { + const token = selectors.getSelectedToken(mockState) + assert.equal(token.address, '0x108cf70c7d384c552f42c07c41c0e1e46d77ea0d') + assert.equal(token.symbol, 'TEST') + assert.equal(token.decimals, '0') + }) + + describe('#getSelectedTokenExchangeRate', function () { + it('returns token exchange rate for first token', function () { + const tokenRate = selectors.getSelectedTokenExchangeRate(mockState) + assert.equal(tokenRate, '0.00039345803819379796') + }) + }) + + + describe('#getTokenExchangeRate', function () { + let missingTokenRate + + beforeEach(function () { + missingTokenRate = { + metamask: { + 'contractExchangeRates': {}, + }, + } + }) + + it('returns 0 token exchange rate for a token not in state', function () { + const tokenRate = selectors.getTokenExchangeRate(missingTokenRate, '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5') + assert.equal(tokenRate, 0) + }) + + it('returns token exchange rate for specified token in state', function () { + const tokenRate = selectors.getTokenExchangeRate(mockState, '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5') + assert.equal(tokenRate, 0.00008189274407698049) + }) + + }) + + it('returns conversionRate from state', function () { + assert.equal(selectors.conversionRateSelector(mockState), 556.12) + }) + + it('returns address book from state', function () { + const addressBook = selectors.getAddressBook(mockState) + assert.equal(addressBook[0].address, '0xc42edfcc21ed14dda456aa0756c153f7985d8813') + assert.equal(addressBook[0].name, '') + }) + + it('returns accounts with balance, address, and name from identity and accounts in state', function () { + const accountsWithSendEther = selectors.accountsWithSendEtherInfoSelector(mockState) + assert.equal(accountsWithSendEther.length, 2) + assert.equal(accountsWithSendEther[0].balance, '0x0') + assert.equal(accountsWithSendEther[0].address, '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc') + assert.equal(accountsWithSendEther[0].name, 'Test Account') + }) + + it('returns selected account with balance, address, and name from accountsWithSendEtherInfoSelector', function () { + const currentAccountwithSendEther = selectors.getCurrentAccountWithSendEtherInfo(mockState) + assert.equal(currentAccountwithSendEther.balance, '0x0') + assert.equal(currentAccountwithSendEther.address, '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc') + assert.equal(currentAccountwithSendEther.name, 'Test Account') + }) + + describe('#transactionSelector', function () { + it('returns transactions from state', function () { + selectors.transactionsSelector(mockState) + }) + }) + + it('#getGasIsLoading', () => { + const gasIsLoading = selectors.getGasIsLoading(mockState) + assert.equal(gasIsLoading, false) + }) + + describe('Send From', () => { + it('#getSendFrom', () => { + const sendFrom = selectors.getSendFrom(mockState) + assert.equal(sendFrom, '0xc42edfcc21ed14dda456aa0756c153f7985d8813') + }) + + it('#getForceGasMin', () => { + const forceGasMin = selectors.getForceGasMin(mockState) + assert.equal(forceGasMin, null) + }) + + it('#getSendAmount', () => { + const sendAmount = selectors.getSendAmount(mockState) + assert.equal(sendAmount, '1bc16d674ec80000') + }) + + it('#getSendMaxModeState', () => { + const sendMaxModeState = selectors.getSendMaxModeState(mockState) + assert.equal(sendMaxModeState, false) + }) + }) + + it('#getCurrentCurrency', () => { + const currentCurrency = selectors.getCurrentCurrency(mockState) + assert.equal(currentCurrency, 'usd') + }) + + it('#getSelectedTokenToFiatRate', () => { + const selectedTokenToFiatRate = selectors.getSelectedTokenToFiatRate(mockState) + assert.equal(selectedTokenToFiatRate, '0.21880988420033493') + }) + + describe('#getSelectedTokenContract', () => { + + beforeEach(() => { + global.eth = new Eth(provider) + }) + + it('', () => { + const selectedTokenContract = selectors.getSelectedTokenContract(mockState) + assert(selectedTokenContract.abi) + }) + }) + + it('#getCurrentViewContext', () => { + const currentViewContext = selectors.getCurrentViewContext(mockState) + assert.equal(currentViewContext, '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc') + }) + + it('#getTotalUnapprovedCount', () => { + const totalUnapprovedCount = selectors.getTotalUnapprovedCount(mockState) + assert.equal(totalUnapprovedCount, 1) + }) +}) diff --git a/test/unit/ui/etherscan-prefix-for-network.spec.js b/test/unit/ui/etherscan-prefix-for-network.spec.js new file mode 100644 index 000000000..f0aeb8306 --- /dev/null +++ b/test/unit/ui/etherscan-prefix-for-network.spec.js @@ -0,0 +1,26 @@ +const assert = require('assert') +const etherscanNetworkPrefix = require('../../../ui/lib/etherscan-prefix-for-network') + +describe('Etherscan Network Prefix', () => { + + it('returns empy string as default value', () => { + assert.equal(etherscanNetworkPrefix(), '') + }) + + it('returns empty string as a prefix for networkId of 1', () => { + assert.equal(etherscanNetworkPrefix(1), '') + }) + + it('returns ropsten as prefix for networkId of 3', () => { + assert.equal(etherscanNetworkPrefix(3), 'ropsten.') + }) + + it('returns rinkeby as prefix for networkId of 4', () => { + assert.equal(etherscanNetworkPrefix(4), 'rinkeby.') + }) + + it('returs kovan as prefix for networkId of 42', () => { + assert.equal(etherscanNetworkPrefix(42), 'kovan.') + }) + +}) diff --git a/ui/app/app.js b/ui/app/app.js index c93f93e75..aeb3d05ee 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -19,9 +19,9 @@ const Sidebar = require('./components/sidebars').default // other views import Home from './components/pages/home' +import Settings from './components/pages/settings' const Authenticated = require('./components/pages/authenticated') const Initialized = require('./components/pages/initialized') -const Settings = require('./components/pages/settings') const RestoreVaultPage = require('./components/pages/keychains/restore-vault').default const RevealSeedConfirmation = require('./components/pages/keychains/reveal-seed') const AddTokenPage = require('./components/pages/add-token') @@ -152,12 +152,14 @@ class App extends Component { h(AccountMenu), - (isLoading || isLoadingNetwork) && h(Loading, { - loadingMessage: loadMessage, - }), + h('div.main-container-wrapper', [ + (isLoading || isLoadingNetwork) && h(Loading, { + loadingMessage: loadMessage, + }), - // content - this.renderRoutes(), + // content + this.renderRoutes(), + ]), ]) ) } diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js index de9aa6eb7..74e95ece6 100644 --- a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js +++ b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js @@ -2,11 +2,8 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' import { Tabs, Tab } from '../../tabs' -import { - ConfirmPageContainerSummary, - ConfirmPageContainerError, - ConfirmPageContainerWarning, -} from './' +import { ConfirmPageContainerSummary, ConfirmPageContainerWarning } from './' +import ErrorMessage from '../../error-message' export default class ConfirmPageContainerContent extends Component { static propTypes = { @@ -95,7 +92,7 @@ export default class ConfirmPageContainerContent extends Component { { (errorKey || errorMessage) && ( <div className="confirm-page-container-content__error-container"> - <ConfirmPageContainerError + <ErrorMessage errorMessage={errorMessage} errorKey={errorKey} /> diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-error/index.js b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-error/index.js deleted file mode 100644 index 4ac95d0e3..000000000 --- a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-error/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './confirm-page-container-error.component' diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/index.js b/ui/app/components/confirm-page-container/confirm-page-container-content/index.js index 1469dd438..4dfd89d92 100644 --- a/ui/app/components/confirm-page-container/confirm-page-container-content/index.js +++ b/ui/app/components/confirm-page-container/confirm-page-container-content/index.js @@ -1,4 +1,3 @@ export { default } from './confirm-page-container-content.component' export { default as ConfirmPageContainerSummary } from './confirm-page-container-summary' -export { default as ConfirmPageContainerError } from './confirm-page-container-error' export { default as ConfirmPageContainerWarning } from './confirm-page-container-warning' diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/index.scss b/ui/app/components/confirm-page-container/confirm-page-container-content/index.scss index 39797a43f..698e624f4 100644 --- a/ui/app/components/confirm-page-container/confirm-page-container-content/index.scss +++ b/ui/app/components/confirm-page-container/confirm-page-container-content/index.scss @@ -1,5 +1,3 @@ -@import './confirm-page-container-error/index'; - @import './confirm-page-container-warning/index'; @import './confirm-page-container-summary/index'; diff --git a/ui/app/components/dropdowns/tests/dropdown.test.js b/ui/app/components/dropdowns/tests/dropdown.test.js new file mode 100644 index 000000000..2b026589a --- /dev/null +++ b/ui/app/components/dropdowns/tests/dropdown.test.js @@ -0,0 +1,37 @@ +import React from 'react' +import assert from 'assert' +import sinon from 'sinon' +import { shallow } from 'enzyme' +import { DropdownMenuItem } from '../components/dropdown.js' + +describe('', () => { + let wrapper + const onClickSpy = sinon.spy() + const closeMenuSpy = sinon.spy() + + beforeEach(() => { + wrapper = shallow( + <DropdownMenuItem + onClick = {onClickSpy} + style = {{test: 'style'}} + closeMenu = {closeMenuSpy} + > + </DropdownMenuItem> + ) + }) + + it('renders li with dropdown-menu-item class', () => { + assert.equal(wrapper.find('li.dropdown-menu-item').length, 1) + }) + + it('adds style based on props passed', () => { + assert.equal(wrapper.prop('style').test, 'style') + }) + + it('simulates click event and calls onClick and closeMenu', () => { + wrapper.prop('onClick')() + assert.equal(onClickSpy.callCount, 1) + assert.equal(closeMenuSpy.callCount, 1) + }) + +}) diff --git a/ui/app/components/dropdowns/tests/menu.test.js b/ui/app/components/dropdowns/tests/menu.test.js new file mode 100644 index 000000000..9f5f13f00 --- /dev/null +++ b/ui/app/components/dropdowns/tests/menu.test.js @@ -0,0 +1,87 @@ +import React from 'react' +import assert from 'assert' +import sinon from 'sinon' +import { shallow } from 'enzyme' +import { Menu, Item, Divider, CloseArea } from '../components/menu' + +describe('Dropdown Menu Components', () => { + + describe('Menu', () => { + let wrapper + + beforeEach(() => { + wrapper = shallow( + <Menu className = {'Test Class'} isShowing = {true}/> + ) + }) + + it('adds prop className to menu', () => { + assert.equal(wrapper.find('.menu').prop('className'), 'menu Test Class') + }) + + }) + + describe('Item', () => { + let wrapper + + const onClickSpy = sinon.spy() + + beforeEach(() => { + wrapper = shallow( + <Item + icon = {'test icon'} + text = {'test text'} + className = {'test className'} + onClick = {onClickSpy} + /> + ) + }) + + it('add className based on props', () => { + assert.equal(wrapper.find('.menu__item').prop('className'), 'menu__item menu__item test className menu__item--clickable') + }) + + it('simulates onClick called', () => { + wrapper.find('.menu__item').prop('onClick')() + assert.equal(onClickSpy.callCount, 1) + }) + + it('adds icon based on icon props', () => { + assert.equal(wrapper.find('.menu__item__icon').text(), 'test icon') + }) + + it('adds html text based on text props', () => { + assert.equal(wrapper.find('.menu__item__text').text(), 'test text') + }) + }) + + describe('Divider', () => { + let wrapper + + before(() => { + wrapper = shallow(<Divider />) + }) + + it('renders menu divider', () => { + assert.equal(wrapper.find('.menu__divider').length, 1) + }) + }) + + describe('CloseArea', () => { + let wrapper + + const onClickSpy = sinon.spy() + + beforeEach(() => { + wrapper = shallow(<CloseArea + onClick = {onClickSpy} + />) + }) + + it('simulates click', () => { + wrapper.prop('onClick')() + assert.equal(onClickSpy.callCount, 1) + }) + }) + +}) diff --git a/ui/app/components/dropdowns/tests/network-dropdown-icon.test.js b/ui/app/components/dropdowns/tests/network-dropdown-icon.test.js new file mode 100644 index 000000000..67b192c11 --- /dev/null +++ b/ui/app/components/dropdowns/tests/network-dropdown-icon.test.js @@ -0,0 +1,25 @@ +import React from 'react' +import assert from 'assert' +import { shallow } from 'enzyme' +import NetworkDropdownIcon from '../components/network-dropdown-icon' + +describe('Network Dropdown Icon', () => { + let wrapper + + beforeEach(() => { + wrapper = shallow(<NetworkDropdownIcon + backgroundColor = {'red'} + isSelected = {false} + innerBorder = {'none'} + diameter = {'12'} + />) + }) + + it('adds style props based on props', () => { + const styleProp = wrapper.find('.menu-icon-circle').children().prop('style') + assert.equal(styleProp.background, 'red') + assert.equal(styleProp.border, 'none') + assert.equal(styleProp.height, '12px') + assert.equal(styleProp.width, '12px') + }) +}) diff --git a/ui/app/components/dropdowns/tests/network-dropdown.test.js b/ui/app/components/dropdowns/tests/network-dropdown.test.js new file mode 100644 index 000000000..699b54605 --- /dev/null +++ b/ui/app/components/dropdowns/tests/network-dropdown.test.js @@ -0,0 +1,97 @@ +import React from 'react' +import assert from 'assert' +import { createMockStore } from 'redux-test-utils' +import { mountWithRouter } from '../../../../../test/lib/render-helpers' +import NetworkDropdown from '../network-dropdown' +import { DropdownMenuItem } from '../components/dropdown' +import NetworkDropdownIcon from '../components/network-dropdown-icon' + +describe('Network Dropdown', () => { + let wrapper + + describe('NetworkDropdown in appState in false', () => { + const mockState = { + metamask: { + provider: { + type: 'test', + }, + }, + appState: { + networkDropdown: false, + }, + } + + const store = createMockStore(mockState) + + beforeEach(() => { + wrapper = mountWithRouter( + <NetworkDropdown store={store} /> + ) + }) + + it('checks for network droppo class', () => { + assert.equal(wrapper.find('.network-droppo').length, 1) + }) + + it('renders only one child when networkDropdown is false in state', () => { + assert.equal(wrapper.children().length, 1) + }) + + }) + + describe('NetworkDropdown in appState is true', () => { + const mockState = { + metamask: { + provider: { + 'type': 'test', + }, + frequentRpcList: [ + 'http://localhost:7545', + ], + }, + appState: { + 'networkDropdownOpen': true, + }, + } + const store = createMockStore(mockState) + + beforeEach(() => { + wrapper = mountWithRouter( + <NetworkDropdown store={store}/>, + ) + }) + + it('renders 7 DropDownMenuItems ', () => { + assert.equal(wrapper.find(DropdownMenuItem).length, 7) + }) + + it('checks background color for first NetworkDropdownIcon', () => { + assert.equal(wrapper.find(NetworkDropdownIcon).at(0).prop('backgroundColor'), '#29B6AF') // Main Ethereum Network Teal + }) + + it('checks background color for second NetworkDropdownIcon', () => { + assert.equal(wrapper.find(NetworkDropdownIcon).at(1).prop('backgroundColor'), '#ff4a8d') // Ropsten Red + }) + + it('checks background color for third NetworkDropdownIcon', () => { + assert.equal(wrapper.find(NetworkDropdownIcon).at(2).prop('backgroundColor'), '#7057ff') // Kovan Purple + }) + + it('checks background color for fourth NetworkDropdownIcon', () => { + assert.equal(wrapper.find(NetworkDropdownIcon).at(3).prop('backgroundColor'), '#f6c343') // Rinkeby Yellow + }) + + it('checks background color for fifth NetworkDropdownIcon', () => { + assert.equal(wrapper.find(NetworkDropdownIcon).at(4).prop('innerBorder'), '1px solid #9b9b9b') + }) + + it('checks dropdown for frequestRPCList from state ', () => { + assert.equal(wrapper.find(DropdownMenuItem).at(5).text(), '✓http://localhost:7545') + }) + + it('checks background color for sixth NetworkDropdownIcon', () => { + assert.equal(wrapper.find(NetworkDropdownIcon).at(5).prop('innerBorder'), '1px solid #9b9b9b') + }) + + }) +}) diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-error/confirm-page-container-error.component.js b/ui/app/components/error-message/error-message.component.js index 4965d7b4e..b4464c33b 100644 --- a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-error/confirm-page-container-error.component.js +++ b/ui/app/components/error-message/error-message.component.js @@ -1,30 +1,30 @@ import React from 'react' import PropTypes from 'prop-types' -const ConfirmPageContainerError = (props, context) => { +const ErrorMessage = (props, context) => { const { errorMessage, errorKey } = props const error = errorKey ? context.t(errorKey) : errorMessage return ( - <div className="confirm-page-container-error"> + <div className="error-message"> <img src="/images/alert-red.svg" - className="confirm-page-container-error__icon" + className="error-message__icon" /> - <div className="confirm-page-container-error__text"> + <div className="error-message__text"> { `ALERT: ${error}` } </div> </div> ) } -ConfirmPageContainerError.propTypes = { +ErrorMessage.propTypes = { errorMessage: PropTypes.string, errorKey: PropTypes.string, } -ConfirmPageContainerError.contextTypes = { +ErrorMessage.contextTypes = { t: PropTypes.func, } -export default ConfirmPageContainerError +export default ErrorMessage diff --git a/ui/app/components/error-message/index.js b/ui/app/components/error-message/index.js new file mode 100644 index 000000000..1c97a9955 --- /dev/null +++ b/ui/app/components/error-message/index.js @@ -0,0 +1 @@ +export { default } from './error-message.component' diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-error/index.scss b/ui/app/components/error-message/index.scss index 89ff25578..5915e21cf 100644 --- a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-error/index.scss +++ b/ui/app/components/error-message/index.scss @@ -1,4 +1,4 @@ -.confirm-page-container-error { +.error-message { min-height: 32px; border: 1px solid $monzo; color: $monzo; diff --git a/ui/app/components/error-message/tests/error-message.component.test.js b/ui/app/components/error-message/tests/error-message.component.test.js new file mode 100644 index 000000000..8c5347173 --- /dev/null +++ b/ui/app/components/error-message/tests/error-message.component.test.js @@ -0,0 +1,36 @@ +import React from 'react' +import assert from 'assert' +import { shallow } from 'enzyme' +import ErrorMessage from '../error-message.component' + +describe('ErrorMessage Component', () => { + const t = key => `translate ${key}` + + it('should render a message from props.errorMessage', () => { + const wrapper = shallow( + <ErrorMessage + errorMessage="This is an error." + />, + { context: { t }} + ) + + assert.ok(wrapper) + assert.equal(wrapper.find('.error-message').length, 1) + assert.equal(wrapper.find('.error-message__icon').length, 1) + assert.equal(wrapper.find('.error-message__text').text(), 'ALERT: This is an error.') + }) + + it('should render a message translated from props.errorKey', () => { + const wrapper = shallow( + <ErrorMessage + errorKey="testKey" + />, + { context: { t }} + ) + + assert.ok(wrapper) + assert.equal(wrapper.find('.error-message').length, 1) + assert.equal(wrapper.find('.error-message__icon').length, 1) + assert.equal(wrapper.find('.error-message__text').text(), 'ALERT: translate testKey') + }) +}) diff --git a/ui/app/components/index.scss b/ui/app/components/index.scss index 983d6b98a..21b65bf55 100644 --- a/ui/app/components/index.scss +++ b/ui/app/components/index.scss @@ -6,12 +6,16 @@ @import './confirm-page-container/index'; +@import './error-message/index'; + @import './export-text-container/index'; @import './info-box/index'; @import './menu-bar/index'; +@import './modal/index'; + @import './modals/index'; @import './network-display/index'; diff --git a/ui/app/components/modal/index.js b/ui/app/components/modal/index.js new file mode 100644 index 000000000..58309abbe --- /dev/null +++ b/ui/app/components/modal/index.js @@ -0,0 +1,2 @@ +export { default } from './modal.component' +export { default as ModalContent } from './modal-content' diff --git a/ui/app/components/modal/index.scss b/ui/app/components/modal/index.scss new file mode 100644 index 000000000..2beb14633 --- /dev/null +++ b/ui/app/components/modal/index.scss @@ -0,0 +1,62 @@ +@import './modal-content/index'; + +.modal-container { + width: 100%; + height: 100%; + background-color: #fff; + display: flex; + flex-flow: column; + border-radius: 8px; + + @media screen and (max-width: 575px) { + max-height: 450px; + } + + &__content { + overflow-y: auto; + flex: 1; + padding: 16px 32px; + + @media screen and (max-width: 575px) { + justify-content: center; + padding: 28px 20px; + } + } + + &__header { + position: relative; + display: flex; + padding: 12px; + justify-content: center; + border-bottom: 1px solid #d2d8dd; + flex: 0 0 auto; + } + + &__header-close::after { + content: '\00D7'; + font-size: 40px; + color: $dusty-gray; + position: absolute; + top: -5px; + right: 10px; + cursor: pointer; + } + + &__footer { + display: flex; + flex-flow: row; + justify-content: center; + border-top: 1px solid #d2d8dd; + padding: 16px; + flex: 0 0 auto; + + &-button { + min-width: 0; + margin-right: 16px; + + &:last-of-type { + margin-right: 0; + } + } + } +} diff --git a/ui/app/components/modal/modal-content/index.js b/ui/app/components/modal/modal-content/index.js new file mode 100644 index 000000000..733cfb3b8 --- /dev/null +++ b/ui/app/components/modal/modal-content/index.js @@ -0,0 +1 @@ +export { default } from './modal-content.component' diff --git a/ui/app/components/modal/modal-content/index.scss b/ui/app/components/modal/modal-content/index.scss new file mode 100644 index 000000000..560505b84 --- /dev/null +++ b/ui/app/components/modal/modal-content/index.scss @@ -0,0 +1,19 @@ +.modal-content { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + padding: 16px 0; + + &__title { + font-size: 1.5rem; + font-weight: 500; + padding: 16px 0; + text-align: center; + } + + &__description { + text-align: center; + font-size: .875rem; + } +} diff --git a/ui/app/components/modal/modal-content/modal-content.component.js b/ui/app/components/modal/modal-content/modal-content.component.js new file mode 100644 index 000000000..ecec0ee5b --- /dev/null +++ b/ui/app/components/modal/modal-content/modal-content.component.js @@ -0,0 +1,32 @@ +import React, { PureComponent } from 'react' +import PropTypes from 'prop-types' + +export default class ModalContent extends PureComponent { + static propTypes = { + title: PropTypes.string, + description: PropTypes.string, + } + + render () { + const { title, description } = this.props + + return ( + <div className="modal-content"> + { + title && ( + <div className="modal-content__title"> + { title } + </div> + ) + } + { + description && ( + <div className="modal-content__description"> + { description } + </div> + ) + } + </div> + ) + } +} diff --git a/ui/app/components/modal/modal-content/tests/modal-content.component.test.js b/ui/app/components/modal/modal-content/tests/modal-content.component.test.js new file mode 100644 index 000000000..17af09f45 --- /dev/null +++ b/ui/app/components/modal/modal-content/tests/modal-content.component.test.js @@ -0,0 +1,44 @@ +import React from 'react' +import assert from 'assert' +import { shallow } from 'enzyme' +import ModalContent from '../modal-content.component' + +describe('ModalContent Component', () => { + it('should render a title', () => { + const wrapper = shallow( + <ModalContent + title="Modal Title" + /> + ) + + assert.equal(wrapper.find('.modal-content__title').length, 1) + assert.equal(wrapper.find('.modal-content__title').text(), 'Modal Title') + assert.equal(wrapper.find('.modal-content__description').length, 0) + }) + + it('should render a description', () => { + const wrapper = shallow( + <ModalContent + description="Modal Description" + /> + ) + + assert.equal(wrapper.find('.modal-content__title').length, 0) + assert.equal(wrapper.find('.modal-content__description').length, 1) + assert.equal(wrapper.find('.modal-content__description').text(), 'Modal Description') + }) + + it('should render both a title and a description', () => { + const wrapper = shallow( + <ModalContent + title="Modal Title" + description="Modal Description" + /> + ) + + assert.equal(wrapper.find('.modal-content__title').length, 1) + assert.equal(wrapper.find('.modal-content__title').text(), 'Modal Title') + assert.equal(wrapper.find('.modal-content__description').length, 1) + assert.equal(wrapper.find('.modal-content__description').text(), 'Modal Description') + }) +}) diff --git a/ui/app/components/modal/modal.component.js b/ui/app/components/modal/modal.component.js new file mode 100644 index 000000000..2a75b559b --- /dev/null +++ b/ui/app/components/modal/modal.component.js @@ -0,0 +1,80 @@ +import React, { PureComponent } from 'react' +import PropTypes from 'prop-types' +import Button from '../button' + +export default class Modal extends PureComponent { + static propTypes = { + children: PropTypes.node, + // Header text + headerText: PropTypes.string, + onClose: PropTypes.func, + // Submit button (right button) + onSubmit: PropTypes.func, + submitType: PropTypes.string, + submitText: PropTypes.string, + // Cancel button (left button) + onCancel: PropTypes.func, + cancelType: PropTypes.string, + cancelText: PropTypes.string, + } + + static defaultProps = { + submitType: 'primary', + cancelType: 'default', + } + + render () { + const { + children, + headerText, + onClose, + onSubmit, + submitType, + submitText, + onCancel, + cancelType, + cancelText, + } = this.props + + return ( + <div className="modal-container"> + { + headerText && ( + <div className="modal-container__header"> + <div className="modal-container__header-text"> + { headerText } + </div> + <div + className="modal-container__header-close" + onClick={onClose} + /> + </div> + ) + } + <div className="modal-container__content"> + { children } + </div> + <div className="modal-container__footer"> + { + onCancel && ( + <Button + type={cancelType} + onClick={onCancel} + className="modal-container__footer-button" + > + { cancelText } + </Button> + ) + } + <Button + type={submitType} + onClick={onSubmit} + className="modal-container__footer-button" + > + { submitText } + </Button> + </div> + </div> + ) + } +} diff --git a/ui/app/components/modal/tests/modal.component.test.js b/ui/app/components/modal/tests/modal.component.test.js new file mode 100644 index 000000000..8cce1a808 --- /dev/null +++ b/ui/app/components/modal/tests/modal.component.test.js @@ -0,0 +1,103 @@ +import React from 'react' +import assert from 'assert' +import { shallow } from 'enzyme' +import sinon from 'sinon' +import Modal from '../modal.component' +import Button from '../../button' + +describe('Modal Component', () => { + it('should render a modal with a submit button', () => { + const wrapper = shallow(<Modal />) + + assert.equal(wrapper.find('.modal-container').length, 1) + const buttons = wrapper.find(Button) + assert.equal(buttons.length, 1) + assert.equal(buttons.at(0).props().type, 'primary') + }) + + it('should render a modal with a cancel and a submit button', () => { + const handleCancel = sinon.spy() + const handleSubmit = sinon.spy() + const wrapper = shallow( + <Modal + onCancel={handleCancel} + cancelText="Cancel" + onSubmit={handleSubmit} + submitText="Submit" + /> + ) + + const buttons = wrapper.find(Button) + assert.equal(buttons.length, 2) + const cancelButton = buttons.at(0) + const submitButton = buttons.at(1) + + assert.equal(cancelButton.props().type, 'default') + assert.equal(cancelButton.props().children, 'Cancel') + assert.equal(handleCancel.callCount, 0) + cancelButton.simulate('click') + assert.equal(handleCancel.callCount, 1) + + assert.equal(submitButton.props().type, 'primary') + assert.equal(submitButton.props().children, 'Submit') + assert.equal(handleSubmit.callCount, 0) + submitButton.simulate('click') + assert.equal(handleSubmit.callCount, 1) + }) + + it('should render a modal with different button types', () => { + const wrapper = shallow( + <Modal + onCancel={() => {}} + cancelText="Cancel" + cancelType="secondary" + onSubmit={() => {}} + submitText="Submit" + submitType="confirm" + /> + ) + + const buttons = wrapper.find(Button) + assert.equal(buttons.length, 2) + assert.equal(buttons.at(0).props().type, 'secondary') + assert.equal(buttons.at(1).props().type, 'confirm') + }) + + it('should render a modal with children', () => { + const wrapper = shallow( + <Modal + onCancel={() => {}} + cancelText="Cancel" + onSubmit={() => {}} + submitText="Submit" + > + <div className="test-child" /> + </Modal> + ) + + assert.ok(wrapper.find('.test-class')) + }) + + it('should render a modal with a header', () => { + const handleCancel = sinon.spy() + const handleSubmit = sinon.spy() + const wrapper = shallow( + <Modal + onCancel={handleCancel} + cancelText="Cancel" + onSubmit={handleSubmit} + submitText="Submit" + headerText="My Header" + onClose={handleCancel} + /> + ) + + assert.ok(wrapper.find('.modal-container__header')) + assert.equal(wrapper.find('.modal-container__header-text').text(), 'My Header') + assert.equal(handleCancel.callCount, 0) + assert.equal(handleSubmit.callCount, 0) + wrapper.find('.modal-container__header-close').simulate('click') + assert.equal(handleCancel.callCount, 1) + assert.equal(handleSubmit.callCount, 0) + }) +}) diff --git a/ui/app/components/modals/cancel-transaction/cancel-transaction-gas-fee/cancel-transaction-gas-fee.component.js b/ui/app/components/modals/cancel-transaction/cancel-transaction-gas-fee/cancel-transaction-gas-fee.component.js new file mode 100644 index 000000000..b082db1d0 --- /dev/null +++ b/ui/app/components/modals/cancel-transaction/cancel-transaction-gas-fee/cancel-transaction-gas-fee.component.js @@ -0,0 +1,29 @@ +import React, { PureComponent } from 'react' +import PropTypes from 'prop-types' +import CurrencyDisplay from '../../../currency-display' +import { ETH } from '../../../../constants/common' + +export default class CancelTransaction extends PureComponent { + static propTypes = { + value: PropTypes.string, + } + + render () { + const { value } = this.props + + return ( + <div className="cancel-transaction-gas-fee"> + <CurrencyDisplay + className="cancel-transaction-gas-fee__eth" + currency={ETH} + value={value} + numberOfDecimals={6} + /> + <CurrencyDisplay + className="cancel-transaction-gas-fee__fiat" + value={value} + /> + </div> + ) + } +} diff --git a/ui/app/components/modals/cancel-transaction/cancel-transaction-gas-fee/index.js b/ui/app/components/modals/cancel-transaction/cancel-transaction-gas-fee/index.js new file mode 100644 index 000000000..1a9ae2e07 --- /dev/null +++ b/ui/app/components/modals/cancel-transaction/cancel-transaction-gas-fee/index.js @@ -0,0 +1 @@ +export { default } from './cancel-transaction-gas-fee.component' diff --git a/ui/app/components/modals/cancel-transaction/cancel-transaction-gas-fee/index.scss b/ui/app/components/modals/cancel-transaction/cancel-transaction-gas-fee/index.scss new file mode 100644 index 000000000..ce81dd448 --- /dev/null +++ b/ui/app/components/modals/cancel-transaction/cancel-transaction-gas-fee/index.scss @@ -0,0 +1,17 @@ +.cancel-transaction-gas-fee { + background: #F1F4F9; + padding: 16px; + display: flex; + flex-direction: column; + align-items: center; + padding: 12px; + + &__eth { + font-size: 1.5rem; + font-weight: 500; + } + + &__fiat { + font-size: .75rem; + } +} diff --git a/ui/app/components/modals/cancel-transaction/cancel-transaction-gas-fee/tests/cancel-transaction-gas-fee.component.test.js b/ui/app/components/modals/cancel-transaction/cancel-transaction-gas-fee/tests/cancel-transaction-gas-fee.component.test.js new file mode 100644 index 000000000..994c2a577 --- /dev/null +++ b/ui/app/components/modals/cancel-transaction/cancel-transaction-gas-fee/tests/cancel-transaction-gas-fee.component.test.js @@ -0,0 +1,27 @@ +import React from 'react' +import assert from 'assert' +import { shallow } from 'enzyme' +import CancelTransactionGasFee from '../cancel-transaction-gas-fee.component' +import CurrencyDisplay from '../../../../currency-display' + +describe('CancelTransactionGasFee Component', () => { + it('should render', () => { + const wrapper = shallow( + <CancelTransactionGasFee + value="0x3b9aca00" + /> + ) + + assert.ok(wrapper) + assert.equal(wrapper.find(CurrencyDisplay).length, 2) + const ethDisplay = wrapper.find(CurrencyDisplay).at(0) + const fiatDisplay = wrapper.find(CurrencyDisplay).at(1) + + assert.equal(ethDisplay.props().value, '0x3b9aca00') + assert.equal(ethDisplay.props().currency, 'ETH') + assert.equal(ethDisplay.props().className, 'cancel-transaction-gas-fee__eth') + + assert.equal(fiatDisplay.props().value, '0x3b9aca00') + assert.equal(fiatDisplay.props().className, 'cancel-transaction-gas-fee__fiat') + }) +}) diff --git a/ui/app/components/modals/cancel-transaction/cancel-transaction.component.js b/ui/app/components/modals/cancel-transaction/cancel-transaction.component.js new file mode 100644 index 000000000..8b00cb9b9 --- /dev/null +++ b/ui/app/components/modals/cancel-transaction/cancel-transaction.component.js @@ -0,0 +1,68 @@ +import React, { PureComponent } from 'react' +import PropTypes from 'prop-types' +import Modal from '../../modal' +import CancelTransactionGasFee from './cancel-transaction-gas-fee' +import { SUBMITTED_STATUS } from '../../../constants/transactions' + +export default class CancelTransaction extends PureComponent { + static contextTypes = { + t: PropTypes.func, + } + + static propTypes = { + createCancelTransaction: PropTypes.func, + hideModal: PropTypes.func, + showTransactionConfirmedModal: PropTypes.func, + transactionStatus: PropTypes.string, + newGasFee: PropTypes.string, + } + + componentDidUpdate () { + const { transactionStatus, showTransactionConfirmedModal } = this.props + + if (transactionStatus !== SUBMITTED_STATUS) { + showTransactionConfirmedModal() + return + } + } + + handleSubmit = async () => { + const { createCancelTransaction, hideModal } = this.props + + await createCancelTransaction() + hideModal() + } + + handleCancel = () => { + this.props.hideModal() + } + + render () { + const { t } = this.context + const { newGasFee } = this.props + + return ( + <Modal + headerText={t('attemptToCancel')} + onClose={this.handleCancel} + onSubmit={this.handleSubmit} + onCancel={this.handleCancel} + submitText={t('yesLetsTry')} + cancelText={t('nevermind')} + submitType="secondary" + > + <div> + <div className="cancel-transaction__title"> + { t('cancellationGasFee') } + </div> + <div className="cancel-transaction__cancel-transaction-gas-fee-container"> + <CancelTransactionGasFee value={newGasFee} /> + </div> + <div className="cancel-transaction__description"> + { t('attemptToCancelDescription') } + </div> + </div> + </Modal> + ) + } +} diff --git a/ui/app/components/modals/cancel-transaction/cancel-transaction.container.js b/ui/app/components/modals/cancel-transaction/cancel-transaction.container.js new file mode 100644 index 000000000..eede8b1ee --- /dev/null +++ b/ui/app/components/modals/cancel-transaction/cancel-transaction.container.js @@ -0,0 +1,62 @@ +import { connect } from 'react-redux' +import { compose } from 'recompose' +import ethUtil from 'ethereumjs-util' +import { multiplyCurrencies } from '../../../conversion-util' +import withModalProps from '../../../higher-order-components/with-modal-props' +import CancelTransaction from './cancel-transaction.component' +import { showModal, createCancelTransaction } from '../../../actions' +import { getHexGasTotal } from '../../../helpers/confirm-transaction/util' + +const mapStateToProps = (state, ownProps) => { + const { metamask } = state + const { transactionId, originalGasPrice } = ownProps + const { selectedAddressTxList } = metamask + const transaction = selectedAddressTxList.find(({ id }) => id === transactionId) + const transactionStatus = transaction ? transaction.status : '' + + const defaultNewGasPrice = ethUtil.addHexPrefix( + multiplyCurrencies(originalGasPrice, 1.1, { + toNumericBase: 'hex', + multiplicandBase: 16, + multiplierBase: 10, + }) + ) + + const newGasFee = getHexGasTotal({ gasPrice: defaultNewGasPrice, gasLimit: '0x5208' }) + + return { + transactionId, + transactionStatus, + originalGasPrice, + newGasFee, + } +} + +const mapDispatchToProps = dispatch => { + return { + createCancelTransaction: txId => dispatch(createCancelTransaction(txId)), + showTransactionConfirmedModal: () => dispatch(showModal({ name: 'TRANSACTION_CONFIRMED' })), + } +} + +const mergeProps = (stateProps, dispatchProps, ownProps) => { + const { transactionId, ...restStateProps } = stateProps + const { + createCancelTransaction: dispatchCreateCancelTransaction, + ...restDispatchProps + } = dispatchProps + + return { + ...restStateProps, + ...restDispatchProps, + ...ownProps, + createCancelTransaction: newGasPrice => { + return dispatchCreateCancelTransaction(transactionId, newGasPrice) + }, + } +} + +export default compose( + withModalProps, + connect(mapStateToProps, mapDispatchToProps, mergeProps), +)(CancelTransaction) diff --git a/ui/app/components/modals/cancel-transaction/index.js b/ui/app/components/modals/cancel-transaction/index.js new file mode 100644 index 000000000..7abc871ee --- /dev/null +++ b/ui/app/components/modals/cancel-transaction/index.js @@ -0,0 +1 @@ +export { default } from './cancel-transaction.container' diff --git a/ui/app/components/modals/cancel-transaction/index.scss b/ui/app/components/modals/cancel-transaction/index.scss new file mode 100644 index 000000000..62e8e36fd --- /dev/null +++ b/ui/app/components/modals/cancel-transaction/index.scss @@ -0,0 +1,18 @@ +@import './cancel-transaction-gas-fee/index'; + +.cancel-transaction { + &__title { + font-weight: 500; + padding-bottom: 16px; + text-align: center; + } + + &__description { + text-align: center; + font-size: .875rem; + } + + &__cancel-transaction-gas-fee-container { + margin-bottom: 16px; + } +}
\ No newline at end of file diff --git a/ui/app/components/modals/cancel-transaction/tests/cancel-transaction.component.test.js b/ui/app/components/modals/cancel-transaction/tests/cancel-transaction.component.test.js new file mode 100644 index 000000000..858fb01a8 --- /dev/null +++ b/ui/app/components/modals/cancel-transaction/tests/cancel-transaction.component.test.js @@ -0,0 +1,56 @@ +import React from 'react' +import assert from 'assert' +import { shallow } from 'enzyme' +import sinon from 'sinon' +import CancelTransaction from '../cancel-transaction.component' +import CancelTransactionGasFee from '../cancel-transaction-gas-fee' +import Modal from '../../../modal' + +describe('CancelTransaction Component', () => { + const t = key => key + + it('should render a CancelTransaction modal', () => { + const wrapper = shallow( + <CancelTransaction + newGasFee="0x1319718a5000" + />, + { context: { t }} + ) + + assert.ok(wrapper) + assert.equal(wrapper.find(Modal).length, 1) + assert.equal(wrapper.find(CancelTransactionGasFee).length, 1) + assert.equal(wrapper.find(CancelTransactionGasFee).props().value, '0x1319718a5000') + assert.equal(wrapper.find('.cancel-transaction__title').text(), 'cancellationGasFee') + assert.equal(wrapper.find('.cancel-transaction__description').text(), 'attemptToCancelDescription') + }) + + it('should pass the correct props to the Modal component', async () => { + const createCancelTransactionSpy = sinon.stub().callsFake(() => Promise.resolve()) + const hideModalSpy = sinon.spy() + + const wrapper = shallow( + <CancelTransaction + defaultNewGasPrice="0x3b9aca00" + createCancelTransaction={createCancelTransactionSpy} + hideModal={hideModalSpy} + />, + { context: { t }} + ) + + assert.equal(wrapper.find(Modal).length, 1) + const modalProps = wrapper.find(Modal).props() + + assert.equal(modalProps.headerText, 'attemptToCancel') + assert.equal(modalProps.submitText, 'yesLetsTry') + assert.equal(modalProps.cancelText, 'nevermind') + + assert.equal(createCancelTransactionSpy.callCount, 0) + assert.equal(hideModalSpy.callCount, 0) + await modalProps.onSubmit() + assert.equal(createCancelTransactionSpy.callCount, 1) + assert.equal(hideModalSpy.callCount, 1) + modalProps.onCancel() + assert.equal(hideModalSpy.callCount, 2) + }) +}) diff --git a/ui/app/components/modals/confirm-remove-account/confirm-remove-account.component.js b/ui/app/components/modals/confirm-remove-account/confirm-remove-account.component.js index 5a9f0f289..eff94a54a 100644 --- a/ui/app/components/modals/confirm-remove-account/confirm-remove-account.component.js +++ b/ui/app/components/modals/confirm-remove-account/confirm-remove-account.component.js @@ -1,11 +1,11 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' -import Button from '../../button' +import Modal from '../../modal' import { addressSummary } from '../../../util' import Identicon from '../../identicon' import genAccountLink from '../../../../lib/account-link' -class ConfirmRemoveAccount extends Component { +export default class ConfirmRemoveAccount extends Component { static propTypes = { hideModal: PropTypes.func.isRequired, removeAccount: PropTypes.func.isRequired, @@ -17,30 +17,34 @@ class ConfirmRemoveAccount extends Component { t: PropTypes.func, } - handleRemove () { + handleRemove = () => { this.props.removeAccount(this.props.identity.address) .then(() => this.props.hideModal()) } + handleCancel = () => { + this.props.hideModal() + } + renderSelectedAccount () { const { identity } = this.props return ( - <div className="modal-container__account"> - <div className="modal-container__account__identicon"> + <div className="confirm-remove-account__account"> + <div className="confirm-remove-account__account__identicon"> <Identicon - address={identity.address} - diameter={32} + address={identity.address} + diameter={32} /> </div> - <div className="modal-container__account__name"> - <span className="modal-container__account__label">Name</span> - <span className="account_value">{identity.name}</span> + <div className="confirm-remove-account__account__name"> + <span className="confirm-remove-account__account__label">Name</span> + <span className="account_value">{identity.name}</span> </div> - <div className="modal-container__account__address"> - <span className="modal-container__account__label">Public Address</span> - <span className="account_value">{ addressSummary(identity.address, 4, 4) }</span> + <div className="confirm-remove-account__account__address"> + <span className="confirm-remove-account__account__label">Public Address</span> + <span className="account_value">{ addressSummary(identity.address, 4, 4) }</span> </div> - <div className="modal-container__account__link"> + <div className="confirm-remove-account__account__link"> <a className="" href={genAccountLink(identity.address, this.props.network)} @@ -58,36 +62,28 @@ class ConfirmRemoveAccount extends Component { const { t } = this.context return ( - <div className="modal-container"> - <div className="modal-container__content"> - <div className="modal-container__title"> - { `${t('removeAccount')}` }? - </div> - { this.renderSelectedAccount() } - <div className="modal-container__description"> + <Modal + headerText={`${t('removeAccount')}?`} + onClose={this.handleCancel} + onSubmit={this.handleRemove} + onCancel={this.handleCancel} + submitText={t('remove')} + cancelText={t('nevermind')} + submitType="secondary" + > + <div> + { this.renderSelectedAccount() } + <div className="confirm-remove-account__description"> { t('removeAccountDescription') } - <a className="modal-container__link" rel="noopener noreferrer" target="_blank" href="https://consensys.zendesk.com/hc/en-us/articles/360004180111-What-are-imported-accounts-New-UI-">{ t('learnMore') }</a> + <a + className="confirm-remove-account__link" + rel="noopener noreferrer" + target="_blank" href="https://consensys.zendesk.com/hc/en-us/articles/360004180111-What-are-imported-accounts-New-UI-"> + { t('learnMore') } + </a> </div> </div> - <div className="modal-container__footer"> - <Button - type="default" - className="modal-container__footer-button" - onClick={() => this.props.hideModal()} - > - { t('nevermind') } - </Button> - <Button - type="secondary" - className="modal-container__footer-button" - onClick={() => this.handleRemove()} - > - { t('remove') } - </Button> - </div> - </div> + </Modal> ) } } - -export default ConfirmRemoveAccount diff --git a/ui/app/components/modals/confirm-remove-account/confirm-remove-account.container.js b/ui/app/components/modals/confirm-remove-account/confirm-remove-account.container.js index 4b194c995..45c6654ab 100644 --- a/ui/app/components/modals/confirm-remove-account/confirm-remove-account.container.js +++ b/ui/app/components/modals/confirm-remove-account/confirm-remove-account.container.js @@ -1,20 +1,22 @@ import { connect } from 'react-redux' +import { compose } from 'recompose' import ConfirmRemoveAccount from './confirm-remove-account.component' - -const { hideModal, removeAccount } = require('../../../actions') +import withModalProps from '../../../higher-order-components/with-modal-props' +import { removeAccount } from '../../../actions' const mapStateToProps = state => { return { - identity: state.appState.modal.modalState.props.identity, network: state.metamask.network, } } const mapDispatchToProps = dispatch => { return { - hideModal: () => dispatch(hideModal()), removeAccount: (address) => dispatch(removeAccount(address)), } } -export default connect(mapStateToProps, mapDispatchToProps)(ConfirmRemoveAccount) +export default compose( + withModalProps, + connect(mapStateToProps, mapDispatchToProps) +)(ConfirmRemoveAccount) diff --git a/ui/app/components/modals/confirm-remove-account/index.js b/ui/app/components/modals/confirm-remove-account/index.js index 9763fbe05..ecb5f7790 100644 --- a/ui/app/components/modals/confirm-remove-account/index.js +++ b/ui/app/components/modals/confirm-remove-account/index.js @@ -1,2 +1 @@ -import ConfirmRemoveAccount from './confirm-remove-account.container' -module.exports = ConfirmRemoveAccount +export { default } from './confirm-remove-account.container' diff --git a/ui/app/components/modals/confirm-remove-account/index.scss b/ui/app/components/modals/confirm-remove-account/index.scss new file mode 100644 index 000000000..3be3a1967 --- /dev/null +++ b/ui/app/components/modals/confirm-remove-account/index.scss @@ -0,0 +1,58 @@ +.confirm-remove-account { + &__description { + text-align: center; + font-size: .875rem; + } + + &__account { + border: 1px solid #b7b7b7; + border-radius: 4px; + padding: 10px; + display: flex; + margin-top: 10px; + margin-bottom: 20px; + width: 100%; + + &__identicon { + margin-right: 10px; + } + + &__name, + &__address { + margin-right: 10px; + font-size: 14px; + } + + &__name { + width: 100px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + &__label { + font-size: 11px; + display: block; + color: #9b9b9b; + } + + &__link { + margin-top: 14px; + + img { + width: 15px; + height: 15px; + } + } + + @media screen and (max-width: 575px) { + &__name { + width: 90px; + } + } + } + + &__link { + color: #2f9ae0; + } +}
\ No newline at end of file diff --git a/ui/app/components/modals/confirm-reset-account/confirm-reset-account.component.js b/ui/app/components/modals/confirm-reset-account/confirm-reset-account.component.js index 14a4da62a..f1a4542ac 100644 --- a/ui/app/components/modals/confirm-reset-account/confirm-reset-account.component.js +++ b/ui/app/components/modals/confirm-reset-account/confirm-reset-account.component.js @@ -1,8 +1,8 @@ -import React, { Component } from 'react' +import React, { PureComponent } from 'react' import PropTypes from 'prop-types' -import Button from '../../button' +import Modal, { ModalContent } from '../../modal' -class ConfirmResetAccount extends Component { +export default class ConfirmResetAccount extends PureComponent { static propTypes = { hideModal: PropTypes.func.isRequired, resetAccount: PropTypes.func.isRequired, @@ -12,7 +12,7 @@ class ConfirmResetAccount extends Component { t: PropTypes.func, } - handleReset () { + handleReset = () => { this.props.resetAccount() .then(() => this.props.hideModal()) } @@ -21,34 +21,18 @@ class ConfirmResetAccount extends Component { const { t } = this.context return ( - <div className="modal-container"> - <div className="modal-container__content"> - <div className="modal-container__title"> - { `${t('resetAccount')}?` } - </div> - <div className="modal-container__description"> - { t('resetAccountDescription') } - </div> - </div> - <div className="modal-container__footer"> - <Button - type="default" - className="modal-container__footer-button" - onClick={() => this.props.hideModal()} - > - { t('nevermind') } - </Button> - <Button - type="secondary" - className="modal-container__footer-button" - onClick={() => this.handleReset()} - > - { t('reset') } - </Button> - </div> - </div> + <Modal + onSubmit={this.handleReset} + onCancel={() => this.props.hideModal()} + submitText={t('reset')} + cancelText={t('nevermind')} + submitType="secondary" + > + <ModalContent + title={`${t('resetAccount')}?`} + description={t('resetAccountDescription')} + /> + </Modal> ) } } - -export default ConfirmResetAccount diff --git a/ui/app/components/modals/confirm-reset-account/confirm-reset-account.container.js b/ui/app/components/modals/confirm-reset-account/confirm-reset-account.container.js index 9630a5593..c8a7b8478 100644 --- a/ui/app/components/modals/confirm-reset-account/confirm-reset-account.container.js +++ b/ui/app/components/modals/confirm-reset-account/confirm-reset-account.container.js @@ -1,13 +1,16 @@ import { connect } from 'react-redux' +import { compose } from 'recompose' +import withModalProps from '../../../higher-order-components/with-modal-props' import ConfirmResetAccount from './confirm-reset-account.component' - -const { hideModal, resetAccount } = require('../../../actions') +import { resetAccount } from '../../../actions' const mapDispatchToProps = dispatch => { return { - hideModal: () => dispatch(hideModal()), resetAccount: () => dispatch(resetAccount()), } } -export default connect(null, mapDispatchToProps)(ConfirmResetAccount) +export default compose( + withModalProps, + connect(null, mapDispatchToProps) +)(ConfirmResetAccount) diff --git a/ui/app/components/modals/confirm-reset-account/index.js b/ui/app/components/modals/confirm-reset-account/index.js index c812ffc55..ca4d9c5bf 100644 --- a/ui/app/components/modals/confirm-reset-account/index.js +++ b/ui/app/components/modals/confirm-reset-account/index.js @@ -1,2 +1 @@ -import ConfirmResetAccount from './confirm-reset-account.container' -module.exports = ConfirmResetAccount +export { default } from './confirm-reset-account.container' diff --git a/ui/app/components/modals/index.scss b/ui/app/components/modals/index.scss index 0acccf172..45453a582 100644 --- a/ui/app/components/modals/index.scss +++ b/ui/app/components/modals/index.scss @@ -1,108 +1,9 @@ -@import './customize-gas/index'; - -@import './qr-scanner/index'; - -.modal-container { - 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; - } - - &__description { - text-align: center; - font-size: .875rem; - } - - &__account { - border: 1px solid #b7b7b7; - border-radius: 4px; - padding: 10px; - display: flex; - margin-top: 10px; - margin-bottom: 20px; - width: 100%; - - &__identicon { - margin-right: 10px; - } - - &__name, - &__address { - margin-right: 10px; - font-size: 14px; - } +@import './cancel-transaction/index'; - &__name { - width: 100px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } +@import './confirm-remove-account/index'; - &__label { - font-size: 11px; - display: block; - color: #9b9b9b; - } - - &__link { - margin-top: 14px; - - img { - width: 15px; - height: 15px; - } - } - - @media screen and (max-width: 575px) { - &__name { - width: 90px; - } - } - } - - &__link { - color: #2f9ae0; - } - - &__content { - overflow-y: auto; - flex: 1; - display: flex; - flex-direction: column; - align-items: center; - padding: 32px; - - @media screen and (max-width: 575px) { - justify-content: center; - padding: 28px 20px; - } - } - - &__footer { - display: flex; - flex-flow: row; - justify-content: center; - border-top: 1px solid #d2d8dd; - padding: 16px; - flex: 0 0 auto; +@import './customize-gas/index'; - &-button { - min-width: 0; - margin-right: 16px; +@import './qr-scanner/index'; - &:last-of-type { - margin-right: 0; - } - } - } -} +@import './transaction-confirmed/index'; diff --git a/ui/app/components/modals/modal.js b/ui/app/components/modals/modal.js index 5dda50e52..6054002c8 100644 --- a/ui/app/components/modals/modal.js +++ b/ui/app/components/modals/modal.js @@ -19,14 +19,15 @@ const ShapeshiftDepositTxModal = require('./shapeshift-deposit-tx-modal.js') const HideTokenConfirmationModal = require('./hide-token-confirmation-modal') 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') +import ConfirmRemoveAccount from './confirm-remove-account' +import ConfirmResetAccount from './confirm-reset-account' +import TransactionConfirmed from './transaction-confirmed' import ConfirmCustomizeGasModal from './customize-gas' +import CancelTransaction from './cancel-transaction' +import WelcomeBeta from './welcome-beta' +import TransactionDetails from './transaction-details' const modalContainerBaseStyle = { transform: 'translate3d(-50%, 0, 0px)', @@ -199,11 +200,7 @@ const MODALS = { }, BETA_UI_NOTIFICATION_MODAL: { - contents: [ - h(Notification, [ - h(WelcomeBeta), - ]), - ], + contents: h(WelcomeBeta), mobileModalStyle: { ...modalContainerMobileStyle, }, @@ -307,9 +304,7 @@ const MODALS = { }, CONFIRM_CUSTOMIZE_GAS: { - contents: [ - h(ConfirmCustomizeGasModal), - ], + contents: h(ConfirmCustomizeGasModal), mobileModalStyle: { width: '100vw', height: '100vh', @@ -332,11 +327,7 @@ const MODALS = { TRANSACTION_CONFIRMED: { disableBackdropClick: true, - contents: [ - h(Notification, [ - h(TransactionConfirmed), - ]), - ], + contents: h(TransactionConfirmed), mobileModalStyle: { ...modalContainerMobileStyle, }, @@ -347,6 +338,7 @@ const MODALS = { borderRadius: '8px', }, }, + QR_SCANNER: { contents: h(QRScanner), mobileModalStyle: { @@ -360,6 +352,32 @@ const MODALS = { }, }, + CANCEL_TRANSACTION: { + contents: h(CancelTransaction), + mobileModalStyle: { + ...modalContainerMobileStyle, + }, + laptopModalStyle: { + ...modalContainerLaptopStyle, + }, + contentStyle: { + borderRadius: '8px', + }, + }, + + TRANSACTION_DETAILS: { + contents: h(TransactionDetails), + mobileModalStyle: { + ...modalContainerMobileStyle, + }, + laptopModalStyle: { + ...modalContainerLaptopStyle, + }, + contentStyle: { + borderRadius: '8px', + }, + }, + DEFAULT: { contents: [], mobileModalStyle: {}, diff --git a/ui/app/components/modals/notification/index.js b/ui/app/components/modals/notification/index.js deleted file mode 100644 index d60a3129b..000000000 --- a/ui/app/components/modals/notification/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import Notification from './notification.container' -module.exports = Notification diff --git a/ui/app/components/modals/notification/notification.component.js b/ui/app/components/modals/notification/notification.component.js deleted file mode 100644 index 1af2f3ca8..000000000 --- a/ui/app/components/modals/notification/notification.component.js +++ /dev/null @@ -1,30 +0,0 @@ -import React from 'react' -import PropTypes from 'prop-types' -import Button from '../../button' - -const Notification = (props, context) => { - return ( - <div className="modal-container"> - { props.children } - <div className="modal-container__footer"> - <Button - type="primary" - onClick={() => props.onHide()} - > - { context.t('ok') } - </Button> - </div> - </div> - ) -} - -Notification.propTypes = { - onHide: PropTypes.func.isRequired, - children: PropTypes.element, -} - -Notification.contextTypes = { - t: PropTypes.func, -} - -export default Notification diff --git a/ui/app/components/modals/notification/notification.container.js b/ui/app/components/modals/notification/notification.container.js deleted file mode 100644 index 5b98714da..000000000 --- a/ui/app/components/modals/notification/notification.container.js +++ /dev/null @@ -1,38 +0,0 @@ -import { connect } from 'react-redux' -import Notification from './notification.component' - -const { hideModal } = require('../../../actions') - -const mapStateToProps = state => { - const { appState: { modal: { modalState: { props } } } } = state - const { onHide } = props - return { - onHide, - } -} - -const mapDispatchToProps = dispatch => { - return { - hideModal: () => dispatch(hideModal()), - } -} - -const mergeProps = (stateProps, dispatchProps, ownProps) => { - const { onHide, ...otherStateProps } = stateProps - const { hideModal, ...otherDispatchProps } = dispatchProps - - return { - ...otherStateProps, - ...otherDispatchProps, - ...ownProps, - onHide: () => { - hideModal() - - if (onHide && typeof onHide === 'function') { - onHide() - } - }, - } -} - -export default connect(mapStateToProps, mapDispatchToProps, mergeProps)(Notification) diff --git a/ui/app/components/modals/transaction-confirmed/index.js b/ui/app/components/modals/transaction-confirmed/index.js index cee8da7f8..7776b969e 100644 --- a/ui/app/components/modals/transaction-confirmed/index.js +++ b/ui/app/components/modals/transaction-confirmed/index.js @@ -1,2 +1 @@ -import TransactionConfirmed from './transaction-confirmed.component' -module.exports = TransactionConfirmed +export { default } from './transaction-confirmed.container' diff --git a/ui/app/components/modals/transaction-confirmed/index.scss b/ui/app/components/modals/transaction-confirmed/index.scss new file mode 100644 index 000000000..c97371fb6 --- /dev/null +++ b/ui/app/components/modals/transaction-confirmed/index.scss @@ -0,0 +1,22 @@ +.transaction-confirmed { + &__title { + font-size: 1.5rem; + font-weight: 500; + padding: 16px 0; + text-align: center; + } + + &__description { + text-align: center; + font-size: .875rem; + } + + &__content { + overflow-y: auto; + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + padding: 16px; + } +} diff --git a/ui/app/components/modals/transaction-confirmed/transaction-confirmed.component.js b/ui/app/components/modals/transaction-confirmed/transaction-confirmed.component.js index c1c8a2976..0a98eb1a1 100644 --- a/ui/app/components/modals/transaction-confirmed/transaction-confirmed.component.js +++ b/ui/app/components/modals/transaction-confirmed/transaction-confirmed.component.js @@ -1,24 +1,45 @@ -import React from 'react' +import React, { PureComponent } from 'react' import PropTypes from 'prop-types' +import Modal from '../../modal' -const TransactionConfirmed = (props, context) => { - const { t } = context +export default class TransactionConfirmed extends PureComponent { + static contextTypes = { + t: PropTypes.func, + } - return ( - <div className="modal-container__content"> - <img src="images/check-icon.svg" /> - <div className="modal-container__title"> - { `${t('confirmed')}!` } - </div> - <div className="modal-container__description"> - { t('initialTransactionConfirmed') } - </div> - </div> - ) -} + static propTypes = { + onSubmit: PropTypes.func, + hideModal: PropTypes.func, + } -TransactionConfirmed.contextTypes = { - t: PropTypes.func, -} + handleSubmit = () => { + const { hideModal, onSubmit } = this.props + + hideModal() -export default TransactionConfirmed + if (onSubmit && typeof onSubmit === 'function') { + onSubmit() + } + } + + render () { + const { t } = this.context + + return ( + <Modal + onSubmit={this.handleSubmit} + submitText={t('ok')} + > + <div className="transaction-confirmed__content"> + <img src="images/check-icon.svg" /> + <div className="transaction-confirmed__title"> + { `${t('confirmed')}!` } + </div> + <div className="transaction-confirmed__description"> + { t('initialTransactionConfirmed') } + </div> + </div> + </Modal> + ) + } +} diff --git a/ui/app/components/modals/transaction-confirmed/transaction-confirmed.container.js b/ui/app/components/modals/transaction-confirmed/transaction-confirmed.container.js new file mode 100644 index 000000000..d4e39681a --- /dev/null +++ b/ui/app/components/modals/transaction-confirmed/transaction-confirmed.container.js @@ -0,0 +1,4 @@ +import TransactionConfirmed from './transaction-confirmed.component' +import withModalProps from '../../../higher-order-components/with-modal-props' + +export default withModalProps(TransactionConfirmed) diff --git a/ui/app/components/modals/transaction-details/index.js b/ui/app/components/modals/transaction-details/index.js new file mode 100644 index 000000000..1fc42c662 --- /dev/null +++ b/ui/app/components/modals/transaction-details/index.js @@ -0,0 +1 @@ +export { default } from './transaction-details.container' diff --git a/ui/app/components/modals/transaction-details/transaction-details.component.js b/ui/app/components/modals/transaction-details/transaction-details.component.js new file mode 100644 index 000000000..f2fec3409 --- /dev/null +++ b/ui/app/components/modals/transaction-details/transaction-details.component.js @@ -0,0 +1,54 @@ +import React, { PureComponent } from 'react' +import PropTypes from 'prop-types' +import Modal from '../../modal' +import TransactionListItemDetails from '../../transaction-list-item-details' +import { hexToDecimal } from '../../../helpers/conversions.util' + +export default class TransactionConfirmed extends PureComponent { + static contextTypes = { + t: PropTypes.func, + } + + static propTypes = { + hideModal: PropTypes.func, + transaction: PropTypes.object, + onRetry: PropTypes.func, + showRetry: PropTypes.bool, + onCancel: PropTypes.func, + showCancel: PropTypes.bool, + } + + handleSubmit = () => { + this.props.hideModal() + } + + handleRetry = () => { + const { onRetry, hideModal } = this.props + + Promise.resolve(onRetry()).then(() => hideModal()) + } + + render () { + const { t } = this.context + const { transaction, showRetry, onCancel, showCancel } = this.props + const { txParams: { nonce } = {} } = transaction + const decimalNonce = nonce && hexToDecimal(nonce) + + return ( + <Modal + onSubmit={this.handleSubmit} + onClose={this.handleSubmit} + submitText={t('ok')} + headerText={t('transactionWithNonce', [`#${decimalNonce}`])} + > + <TransactionListItemDetails + transaction={transaction} + onRetry={this.handleRetry} + showRetry={showRetry} + onCancel={() => onCancel()} + showCancel={showCancel} + /> + </Modal> + ) + } +} diff --git a/ui/app/components/modals/transaction-details/transaction-details.container.js b/ui/app/components/modals/transaction-details/transaction-details.container.js new file mode 100644 index 000000000..f212920bb --- /dev/null +++ b/ui/app/components/modals/transaction-details/transaction-details.container.js @@ -0,0 +1,4 @@ +import TransactionDetails from './transaction-details.component' +import withModalProps from '../../../higher-order-components/with-modal-props' + +export default withModalProps(TransactionDetails) diff --git a/ui/app/components/modals/welcome-beta/index.js b/ui/app/components/modals/welcome-beta/index.js index 515c9cdaf..49e45b9d7 100644 --- a/ui/app/components/modals/welcome-beta/index.js +++ b/ui/app/components/modals/welcome-beta/index.js @@ -1,2 +1 @@ -import WelcomeBeta from './welcome-beta.component' -module.exports = WelcomeBeta +export { default } from './welcome-beta.container' diff --git a/ui/app/components/modals/welcome-beta/welcome-beta.component.js b/ui/app/components/modals/welcome-beta/welcome-beta.component.js index 61571723a..ef1799164 100644 --- a/ui/app/components/modals/welcome-beta/welcome-beta.component.js +++ b/ui/app/components/modals/welcome-beta/welcome-beta.component.js @@ -1,18 +1,21 @@ import React from 'react' import PropTypes from 'prop-types' +import Modal, { ModalContent } from '../../modal' const TransactionConfirmed = (props, context) => { const { t } = context + const { hideModal } = props return ( - <div className="modal-container__content"> - <div className="modal-container__title"> - { `${t('uiWelcome')}` } - </div> - <div className="modal-container__description"> - { t('uiWelcomeMessage') } - </div> - </div> + <Modal + onSubmit={() => hideModal()} + submitText={t('ok')} + > + <ModalContent + title={t('uiWelcome')} + description={t('uiWelcomeMessage')} + /> + </Modal> ) } @@ -20,4 +23,8 @@ TransactionConfirmed.contextTypes = { t: PropTypes.func, } +TransactionConfirmed.propTypes = { + hideModal: PropTypes.func, +} + export default TransactionConfirmed diff --git a/ui/app/components/modals/welcome-beta/welcome-beta.container.js b/ui/app/components/modals/welcome-beta/welcome-beta.container.js new file mode 100644 index 000000000..c5123ad47 --- /dev/null +++ b/ui/app/components/modals/welcome-beta/welcome-beta.container.js @@ -0,0 +1,4 @@ +import WelcomeBeta from './welcome-beta.component' +import withModalProps from '../../../higher-order-components/with-modal-props' + +export default withModalProps(WelcomeBeta) diff --git a/ui/app/components/page-container/index.scss b/ui/app/components/page-container/index.scss index 14cdbacd3..61434cbcf 100644 --- a/ui/app/components/page-container/index.scss +++ b/ui/app/components/page-container/index.scss @@ -182,5 +182,7 @@ max-height: 82vh; min-height: 570px; flex: 0 0 auto; + margin-right: auto; + margin-left: auto; } } diff --git a/ui/app/components/page-container/page-container-footer/tests/page-container-footer.component.test.js b/ui/app/components/page-container/page-container-footer/tests/page-container-footer.component.test.js index e69de29bb..5e5dbf00b 100644 --- a/ui/app/components/page-container/page-container-footer/tests/page-container-footer.component.test.js +++ b/ui/app/components/page-container/page-container-footer/tests/page-container-footer.component.test.js @@ -0,0 +1,69 @@ +import React from 'react' +import assert from 'assert' +import { shallow } from 'enzyme' +import sinon from 'sinon' +import Button from '../../../button' +import PageFooter from '../page-container-footer.component' + +describe('Page Footer', () => { + let wrapper + const onCancel = sinon.spy() + const onSubmit = sinon.spy() + + beforeEach(() => { + wrapper = shallow(<PageFooter + onCancel = {onCancel} + onSubmit = {onSubmit} + cancelText = {'Cancel'} + submitText = {'Submit'} + disabled = {false} + submitButtonType = {'Test Type'} + />) + }) + + it('renders page container footer', () => { + assert.equal(wrapper.find('.page-container__footer').length, 1) + }) + + it('renders two button components', () => { + assert.equal(wrapper.find(Button).length, 2) + }) + + describe('Cancel Button', () => { + + it('has button type of default', () => { + assert.equal(wrapper.find('.page-container__footer-button').first().prop('type'), 'default') + }) + + it('has children text of Cancel', () => { + assert.equal(wrapper.find('.page-container__footer-button').first().prop('children'), 'Cancel') + }) + + it('should call cancel when click is simulated', () => { + wrapper.find('.page-container__footer-button').first().prop('onClick')() + assert.equal(onCancel.callCount, 1) + }) + + }) + + describe('Submit Button', () => { + + it('assigns button type based on props', () => { + assert.equal(wrapper.find('.page-container__footer-button').last().prop('type'), 'Test Type') + }) + + it('has disabled prop', () => { + assert.equal(wrapper.find('.page-container__footer-button').last().prop('disabled'), false) + }) + + it('has children text when submitText prop exists', () => { + assert.equal(wrapper.find('.page-container__footer-button').last().prop('children'), 'Submit') + }) + + it('should call submit when click is simulated', () => { + wrapper.find('.page-container__footer-button').last().prop('onClick')() + assert.equal(onSubmit.callCount, 1) + }) + }) + +}) diff --git a/ui/app/components/page-container/page-container-header/tests/page-container-header.component.test.js b/ui/app/components/page-container/page-container-header/tests/page-container-header.component.test.js index e69de29bb..59304b2bd 100644 --- a/ui/app/components/page-container/page-container-header/tests/page-container-header.component.test.js +++ b/ui/app/components/page-container/page-container-header/tests/page-container-header.component.test.js @@ -0,0 +1,82 @@ +import React from 'react' +import assert from 'assert' +import { shallow } from 'enzyme' +import sinon from 'sinon' +import PageContainerHeader from '../page-container-header.component' + +describe('Page Container Header', () => { + let wrapper, style, onBackButtonClick, onClose + + beforeEach(() => { + style = {test: 'style'} + onBackButtonClick = sinon.spy() + onClose = sinon.spy() + + wrapper = shallow(<PageContainerHeader + showBackButton = {true} + onBackButtonClick = {onBackButtonClick} + backButtonStyles = {style} + title = {'Test Title'} + subtitle = {'Test Subtitle'} + tabs = {'Test Tab'} + onClose = {onClose} + />) + }) + + describe('Render Header Row', () => { + + it('renders back button', () => { + assert.equal(wrapper.find('.page-container__back-button').length, 1) + assert.equal(wrapper.find('.page-container__back-button').text(), 'Back') + }) + + it('ensures style prop', () => { + assert.equal(wrapper.find('.page-container__back-button').props().style, style) + }) + + it('should call back button when click is simulated', () => { + wrapper.find('.page-container__back-button').prop('onClick')() + assert.equal(onBackButtonClick.callCount, 1) + }) + }) + + describe('Render', () => { + let header, headerRow, pageTitle, pageSubtitle, pageClose, pageTab + + beforeEach(() => { + header = wrapper.find('.page-container__header--no-padding-bottom') + headerRow = wrapper.find('.page-container__header-row') + pageTitle = wrapper.find('.page-container__title') + pageSubtitle = wrapper.find('.page-container__subtitle') + pageClose = wrapper.find('.page-container__header-close') + pageTab = wrapper.find('.page-container__tabs') + }) + + it('renders page container', () => { + assert.equal(header.length, 1) + assert.equal(headerRow.length, 1) + assert.equal(pageTitle.length, 1) + assert.equal(pageSubtitle.length, 1) + assert.equal(pageClose.length, 1) + assert.equal(pageTab.length, 1) + }) + + it('renders title', () => { + assert.equal(pageTitle.text(), 'Test Title') + }) + + it('renders subtitle', () => { + assert.equal(pageSubtitle.text(), 'Test Subtitle') + }) + + it('renders tabs', () => { + assert.equal(pageTab.text(), 'Test Tab') + }) + + it('should call close when click is simulated', () => { + pageClose.prop('onClick')() + assert.equal(onClose.callCount, 1) + }) + }) + +}) 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 56cfbccc8..40d8faf50 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 @@ -8,6 +8,7 @@ import { INSUFFICIENT_FUNDS_ERROR_KEY, TRANSACTION_ERROR_KEY, } from '../../../constants/error-keys' +import { CONFIRMED_STATUS, DROPPED_STATUS } from '../../../constants/transactions' export default class ConfirmTransactionBase extends Component { static contextTypes = { @@ -85,9 +86,9 @@ export default class ConfirmTransactionBase extends Component { clearConfirmTransaction, } = this.props - if (transactionStatus === 'dropped') { + if (transactionStatus === DROPPED_STATUS || transactionStatus === CONFIRMED_STATUS) { showTransactionConfirmedModal({ - onHide: () => { + onSubmit: () => { clearConfirmTransaction() history.push(DEFAULT_ROUTE) }, diff --git a/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js b/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js index 8f54c8040..ae31eba17 100644 --- a/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js +++ b/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js @@ -97,8 +97,8 @@ const mapDispatchToProps = dispatch => { return { clearConfirmTransaction: () => dispatch(clearConfirmTransaction()), clearSend: () => dispatch(clearSend()), - showTransactionConfirmedModal: ({ onHide }) => { - return dispatch(showModal({ name: 'TRANSACTION_CONFIRMED', onHide })) + showTransactionConfirmedModal: ({ onSubmit }) => { + return dispatch(showModal({ name: 'TRANSACTION_CONFIRMED', onSubmit })) }, showCustomizeGasModal: ({ txData, onSubmit, validate }) => { return dispatch(showModal({ name: 'CONFIRM_CUSTOMIZE_GAS', txData, onSubmit, validate })) diff --git a/ui/app/components/pages/index.scss b/ui/app/components/pages/index.scss index b15c59863..6551278f5 100644 --- a/ui/app/components/pages/index.scss +++ b/ui/app/components/pages/index.scss @@ -3,3 +3,5 @@ @import './add-token/index'; @import './confirm-add-token/index'; + +@import './settings/index'; diff --git a/ui/app/components/pages/settings/index.js b/ui/app/components/pages/settings/index.js index aee17e0e8..44a9ffa63 100644 --- a/ui/app/components/pages/settings/index.js +++ b/ui/app/components/pages/settings/index.js @@ -1,64 +1 @@ -const { Component } = require('react') -const { Switch, Route, matchPath } = require('react-router-dom') -const PropTypes = require('prop-types') -const h = require('react-hyperscript') -const TabBar = require('../../tab-bar') -const Settings = require('./settings') -const Info = require('./info') -const { DEFAULT_ROUTE, SETTINGS_ROUTE, INFO_ROUTE } = require('../../../routes') - -class Config extends Component { - renderTabs () { - const { history, location } = this.props - - return h('div.settings__tabs', [ - h(TabBar, { - tabs: [ - { content: this.context.t('settings'), key: SETTINGS_ROUTE }, - { content: this.context.t('info'), key: INFO_ROUTE }, - ], - isActive: key => matchPath(location.pathname, { path: key, exact: true }), - onSelect: key => history.push(key), - }), - ]) - } - - render () { - const { history } = this.props - - return ( - h('.main-container.settings', {}, [ - h('.settings__header', [ - h('div.settings__close-button', { - onClick: () => history.push(DEFAULT_ROUTE), - }), - this.renderTabs(), - ]), - h(Switch, [ - h(Route, { - exact: true, - path: INFO_ROUTE, - component: Info, - }), - h(Route, { - exact: true, - path: SETTINGS_ROUTE, - component: Settings, - }), - ]), - ]) - ) - } -} - -Config.propTypes = { - location: PropTypes.object, - history: PropTypes.object, - t: PropTypes.func, -} - -Config.contextTypes = { - t: PropTypes.func, -} - -module.exports = Config +export { default } from './settings.component' diff --git a/ui/app/components/pages/settings/index.scss b/ui/app/components/pages/settings/index.scss new file mode 100644 index 000000000..138ebcfc5 --- /dev/null +++ b/ui/app/components/pages/settings/index.scss @@ -0,0 +1,80 @@ +@import './info-tab/index'; + +@import './settings-tab/index'; + +.settings-page { + position: relative; + background: $white; + display: flex; + flex-flow: column nowrap; + + &__header { + padding: 25px 25px 0; + } + + &__close-button::after { + content: '\00D7'; + font-size: 40px; + color: $dusty-gray; + position: absolute; + top: 25px; + right: 30px; + cursor: pointer; + } + + &__content { + padding: 25px; + height: auto; + overflow: auto; + } + + &__content-row { + display: flex; + flex-direction: row; + padding: 10px 0 20px; + + @media screen and (max-width: 575px) { + flex-direction: column; + padding: 10px 0; + } + } + + &__content-item { + flex: 1; + min-width: 0; + display: flex; + flex-direction: column; + padding: 0 5px; + min-height: 71px; + + @media screen and (max-width: 575px) { + height: initial; + padding: 5px 0; + } + + &--without-height { + height: initial; + } + } + + &__content-label { + text-transform: capitalize; + } + + &__content-description { + font-size: 14px; + color: $dusty-gray; + padding-top: 5px; + } + + &__content-item-col { + max-width: 300px; + display: flex; + flex-direction: column; + + @media screen and (max-width: 575px) { + max-width: 100%; + width: 100%; + } + } +} diff --git a/ui/app/components/pages/settings/info-tab/index.js b/ui/app/components/pages/settings/info-tab/index.js new file mode 100644 index 000000000..7556a258d --- /dev/null +++ b/ui/app/components/pages/settings/info-tab/index.js @@ -0,0 +1 @@ +export { default } from './info-tab.component' diff --git a/ui/app/components/pages/settings/info-tab/index.scss b/ui/app/components/pages/settings/info-tab/index.scss new file mode 100644 index 000000000..43ad6f652 --- /dev/null +++ b/ui/app/components/pages/settings/info-tab/index.scss @@ -0,0 +1,56 @@ +.info-tab { + &__logo-wrapper { + height: 80px; + margin-bottom: 20px; + } + + &__logo { + max-height: 100%; + max-width: 100%; + } + + &__item { + padding: 10px 0; + } + + &__link-header { + padding-bottom: 15px; + + @media screen and (max-width: 575px) { + padding-bottom: 5px; + } + } + + &__link-item { + padding: 15px 0; + + @media screen and (max-width: 575px) { + padding: 5px 0; + } + } + + &__link-text { + color: $curious-blue; + } + + &__version-number { + padding-top: 5px; + font-size: 13px; + color: $dusty-gray; + } + + &__separator { + margin: 15px 0; + width: 80px; + border-color: $alto; + border: none; + height: 1px; + background-color: $alto; + color: $alto; + } + + &__about { + color: $dusty-gray; + margin-bottom: 15px; + } +} diff --git a/ui/app/components/pages/settings/info-tab/info-tab.component.js b/ui/app/components/pages/settings/info-tab/info-tab.component.js new file mode 100644 index 000000000..72f7d835e --- /dev/null +++ b/ui/app/components/pages/settings/info-tab/info-tab.component.js @@ -0,0 +1,136 @@ +import React, { PureComponent } from 'react' +import PropTypes from 'prop-types' + +export default class InfoTab extends PureComponent { + state = { + version: global.platform.getVersion(), + } + + static propTypes = { + tab: PropTypes.string, + metamask: PropTypes.object, + setCurrentCurrency: PropTypes.func, + setRpcTarget: PropTypes.func, + displayWarning: PropTypes.func, + revealSeedConfirmation: PropTypes.func, + warning: PropTypes.string, + location: PropTypes.object, + history: PropTypes.object, + } + + static contextTypes = { + t: PropTypes.func, + } + + renderInfoLinks () { + const { t } = this.context + + return ( + <div className="settings-page__content-item settings-page__content-item--without-height"> + <div className="info-tab__link-header"> + { t('links') } + </div> + <div className="info-tab__link-item"> + <a + href="https://metamask.io/privacy.html" + target="_blank" + rel="noopener noreferrer" + > + <span className="info-tab__link-text"> + { t('privacyMsg') } + </span> + </a> + </div> + <div className="info-tab__link-item"> + <a + href="https://metamask.io/terms.html" + target="_blank" + rel="noopener noreferrer" + > + <span className="info-tab__link-text"> + { t('terms') } + </span> + </a> + </div> + <div className="info-tab__link-item"> + <a + href="https://metamask.io/attributions.html" + target="_blank" + rel="noopener noreferrer" + > + <span className="info-tab__link-text"> + { t('attributions') } + </span> + </a> + </div> + <hr className="info-tab__separator" /> + <div className="info-tab__link-item"> + <a + href="https://support.metamask.io" + target="_blank" + rel="noopener noreferrer" + > + <span className="info-tab__link-text"> + { t('supportCenter') } + </span> + </a> + </div> + <div className="info-tab__link-item"> + <a + href="https://metamask.io/" + target="_blank" + rel="noopener noreferrer" + > + <span className="info-tab__link-text"> + { t('visitWebSite') } + </span> + </a> + </div> + <div className="info-tab__link-item"> + <a + href="mailto:help@metamask.io?subject=Feedback" + target="_blank" + rel="noopener noreferrer" + > + <span className="info-tab__link-text"> + { t('emailUs') } + </span> + </a> + </div> + </div> + ) + } + + render () { + const { t } = this.context + + return ( + <div className="settings-page__content"> + <div className="settings-page__content-row"> + <div className="settings-page__content-item settings-page__content-item--without-height"> + <div className="info-tab__logo-wrapper"> + <img + src="images/info-logo.png" + className="info-tab__logo" + /> + </div> + <div className="info-tab__item"> + <div className="info-tab__version-header"> + { t('metamaskVersion') } + </div> + <div className="info-tab__version-number"> + { this.state.version } + </div> + </div> + <div className="info-tab__item"> + <div className="info-tab__about"> + { t('builtInCalifornia') } + </div> + </div> + </div> + { this.renderInfoLinks() } + </div> + </div> + ) + } +} diff --git a/ui/app/components/pages/settings/info.js b/ui/app/components/pages/settings/info.js deleted file mode 100644 index bd9040499..000000000 --- a/ui/app/components/pages/settings/info.js +++ /dev/null @@ -1,120 +0,0 @@ -const { Component } = require('react') -const PropTypes = require('prop-types') -const h = require('react-hyperscript') - -class Info extends Component { - constructor (props) { - super(props) - - this.state = { - version: global.platform.getVersion(), - } - } - - renderLogo () { - return ( - h('div.settings__info-logo-wrapper', [ - h('img.settings__info-logo', { src: 'images/info-logo.png' }), - ]) - ) - } - - renderInfoLinks () { - return ( - h('div.settings__content-item.settings__content-item--without-height', [ - h('div.settings__info-link-header', this.context.t('links')), - h('div.settings__info-link-item', [ - h('a', { - href: 'https://metamask.io/privacy.html', - target: '_blank', - }, [ - h('span.settings__info-link', this.context.t('privacyMsg')), - ]), - ]), - h('div.settings__info-link-item', [ - h('a', { - href: 'https://metamask.io/terms.html', - target: '_blank', - }, [ - h('span.settings__info-link', this.context.t('terms')), - ]), - ]), - h('div.settings__info-link-item', [ - h('a', { - href: 'https://metamask.io/attributions.html', - target: '_blank', - }, [ - h('span.settings__info-link', this.context.t('attributions')), - ]), - ]), - h('hr.settings__info-separator'), - h('div.settings__info-link-item', [ - h('a', { - href: 'https://support.metamask.io', - target: '_blank', - }, [ - h('span.settings__info-link', this.context.t('supportCenter')), - ]), - ]), - h('div.settings__info-link-item', [ - h('a', { - href: 'https://metamask.io/', - target: '_blank', - }, [ - h('span.settings__info-link', this.context.t('visitWebSite')), - ]), - ]), - h('div.settings__info-link-item', [ - h('a', { - target: '_blank', - href: 'mailto:help@metamask.io?subject=Feedback', - }, [ - h('span.settings__info-link', this.context.t('emailUs')), - ]), - ]), - ]) - ) - } - - render () { - return ( - h('div.settings__content', [ - h('div.settings__content-row', [ - h('div.settings__content-item.settings__content-item--without-height', [ - this.renderLogo(), - h('div.settings__info-item', [ - h('div.settings__info-version-header', 'MetaMask Version'), - h('div.settings__info-version-number', this.state.version), - ]), - h('div.settings__info-item', [ - h( - 'div.settings__info-about', - this.context.t('builtInCalifornia') - ), - ]), - ]), - this.renderInfoLinks(), - ]), - ]) - ) - } -} - -Info.propTypes = { - tab: PropTypes.string, - metamask: PropTypes.object, - setCurrentCurrency: PropTypes.func, - setRpcTarget: PropTypes.func, - displayWarning: PropTypes.func, - revealSeedConfirmation: PropTypes.func, - warning: PropTypes.string, - location: PropTypes.object, - history: PropTypes.object, - t: PropTypes.func, -} - -Info.contextTypes = { - t: PropTypes.func, -} - -module.exports = Info diff --git a/ui/app/components/pages/settings/settings-tab/index.js b/ui/app/components/pages/settings/settings-tab/index.js new file mode 100644 index 000000000..9fdaafd3f --- /dev/null +++ b/ui/app/components/pages/settings/settings-tab/index.js @@ -0,0 +1 @@ +export { default } from './settings-tab.container' diff --git a/ui/app/components/pages/settings/settings-tab/index.scss b/ui/app/components/pages/settings/settings-tab/index.scss new file mode 100644 index 000000000..76a0cec6f --- /dev/null +++ b/ui/app/components/pages/settings/settings-tab/index.scss @@ -0,0 +1,51 @@ +.settings-tab { + &__error { + padding-bottom: 20px; + text-align: center; + color: $crimson; + } + + &__rpc-save-button { + align-self: flex-end; + padding: 5px; + text-transform: uppercase; + color: $dusty-gray; + cursor: pointer; + } + + &__rpc-save-button { + align-self: flex-end; + padding: 5px; + text-transform: uppercase; + color: $dusty-gray; + cursor: pointer; + } + + &__button--red { + border-color: lighten($monzo, 10%); + color: $monzo; + + &:active { + background: lighten($monzo, 55%); + border-color: $monzo; + } + + &:hover { + border-color: $monzo; + } + } + + &__button--orange { + border-color: lighten($ecstasy, 20%); + color: $ecstasy; + + &:active { + background: lighten($ecstasy, 40%); + border-color: $ecstasy; + } + + &:hover { + border-color: $ecstasy; + } + } +} diff --git a/ui/app/components/pages/settings/settings-tab/settings-tab.component.js b/ui/app/components/pages/settings/settings-tab/settings-tab.component.js new file mode 100644 index 000000000..53c4f16e0 --- /dev/null +++ b/ui/app/components/pages/settings/settings-tab/settings-tab.component.js @@ -0,0 +1,359 @@ +import React, { PureComponent } from 'react' +import PropTypes from 'prop-types' +import infuraCurrencies from '../../../../infura-conversion.json' +import validUrl from 'valid-url' +import { exportAsFile } from '../../../../util' +import SimpleDropdown from '../../../dropdowns/simple-dropdown' +import ToggleButton from 'react-toggle-button' +import { REVEAL_SEED_ROUTE } from '../../../../routes' +import locales from '../../../../../../app/_locales/index.json' +import TextField from '../../../text-field' +import Button from '../../../button' + +const sortedCurrencies = infuraCurrencies.objects.sort((a, b) => { + return a.quote.name.toLocaleLowerCase().localeCompare(b.quote.name.toLocaleLowerCase()) +}) + +const infuraCurrencyOptions = sortedCurrencies.map(({ quote: { code, name } }) => { + return { + displayValue: `${code.toUpperCase()} - ${name}`, + key: code, + value: code, + } +}) + +const localeOptions = locales.map(locale => { + return { + displayValue: `${locale.name}`, + key: locale.code, + value: locale.code, + } +}) + +export default class SettingsTab extends PureComponent { + static contextTypes = { + t: PropTypes.func, + } + + static propTypes = { + metamask: PropTypes.object, + setUseBlockie: PropTypes.func, + setHexDataFeatureFlag: PropTypes.func, + setCurrentCurrency: PropTypes.func, + setRpcTarget: PropTypes.func, + displayWarning: PropTypes.func, + revealSeedConfirmation: PropTypes.func, + setFeatureFlagToBeta: PropTypes.func, + showResetAccountConfirmationModal: PropTypes.func, + warning: PropTypes.string, + history: PropTypes.object, + isMascara: PropTypes.bool, + updateCurrentLocale: PropTypes.func, + currentLocale: PropTypes.string, + useBlockie: PropTypes.bool, + sendHexData: PropTypes.bool, + currentCurrency: PropTypes.string, + conversionDate: PropTypes.number, + } + + state = { + newRpc: '', + } + + renderCurrentConversion () { + const { t } = this.context + const { currentCurrency, conversionDate, setCurrentCurrency } = this.props + + return ( + <div className="settings-page__content-row"> + <div className="settings-page__content-item"> + <span>{ t('currentConversion') }</span> + <span className="settings-page__content-description"> + { t('updatedWithDate', [Date(conversionDate)]) } + </span> + </div> + <div className="settings-page__content-item"> + <div className="settings-page__content-item-col"> + <SimpleDropdown + placeholder={t('selectCurrency')} + options={infuraCurrencyOptions} + selectedOption={currentCurrency} + onSelect={newCurrency => setCurrentCurrency(newCurrency)} + /> + </div> + </div> + </div> + ) + } + + renderCurrentLocale () { + const { t } = this.context + const { updateCurrentLocale, currentLocale } = this.props + const currentLocaleMeta = locales.find(locale => locale.code === currentLocale) + const currentLocaleName = currentLocaleMeta ? currentLocaleMeta.name : '' + + return ( + <div className="settings-page__content-row"> + <div className="settings-page__content-item"> + <span className="settings-page__content-label"> + { t('currentLanguage') } + </span> + <span className="settings-page__content-description"> + { currentLocaleName } + </span> + </div> + <div className="settings-page__content-item"> + <div className="settings-page__content-item-col"> + <SimpleDropdown + placeholder={t('selectLocale')} + options={localeOptions} + selectedOption={currentLocale} + onSelect={async newLocale => updateCurrentLocale(newLocale)} + /> + </div> + </div> + </div> + ) + } + + renderNewRpcUrl () { + const { t } = this.context + const { newRpc } = this.state + + return ( + <div className="settings-page__content-row"> + <div className="settings-page__content-item"> + <span>{ t('newRPC') }</span> + </div> + <div className="settings-page__content-item"> + <div className="settings-page__content-item-col"> + <TextField + type="text" + id="new-rpc" + placeholder={t('newRPC')} + value={newRpc} + onChange={e => this.setState({ newRpc: e.target.value })} + onKeyPress={e => { + if (e.key === 'Enter') { + this.validateRpc(newRpc) + } + }} + fullWidth + margin="none" + /> + <div + className="settings-tab__rpc-save-button" + onClick={e => { + e.preventDefault() + this.validateRpc(newRpc) + }} + > + { t('save') } + </div> + </div> + </div> + </div> + ) + } + + validateRpc (newRpc) { + const { setRpcTarget, displayWarning } = this.props + + if (validUrl.isWebUri(newRpc)) { + setRpcTarget(newRpc) + } else { + const appendedRpc = `http://${newRpc}` + + if (validUrl.isWebUri(appendedRpc)) { + displayWarning(this.context.t('uriErrorMsg')) + } else { + displayWarning(this.context.t('invalidRPC')) + } + } + } + + renderStateLogs () { + const { t } = this.context + const { displayWarning } = this.props + + return ( + <div className="settings-page__content-row"> + <div className="settings-page__content-item"> + <span>{ t('stateLogs') }</span> + <span className="settings-page__content-description"> + { t('stateLogsDescription') } + </span> + </div> + <div className="settings-page__content-item"> + <div className="settings-page__content-item-col"> + <Button + type="primary" + large + onClick={() => { + window.logStateString((err, result) => { + if (err) { + displayWarning(t('stateLogError')) + } else { + exportAsFile('MetaMask State Logs.json', result) + } + }) + }} + > + { t('downloadStateLogs') } + </Button> + </div> + </div> + </div> + ) + } + + renderSeedWords () { + const { t } = this.context + const { history } = this.props + + return ( + <div className="settings-page__content-row"> + <div className="settings-page__content-item"> + <span>{ t('revealSeedWords') }</span> + </div> + <div className="settings-page__content-item"> + <div className="settings-page__content-item-col"> + <Button + type="secondary" + large + onClick={event => { + event.preventDefault() + history.push(REVEAL_SEED_ROUTE) + }} + > + { t('revealSeedWords') } + </Button> + </div> + </div> + </div> + ) + } + + renderOldUI () { + const { t } = this.context + const { setFeatureFlagToBeta } = this.props + + return ( + <div className="settings-page__content-row"> + <div className="settings-page__content-item"> + <span>{ t('useOldUI') }</span> + </div> + <div className="settings-page__content-item"> + <div className="settings-page__content-item-col"> + <Button + type="secondary" + large + className="settings-tab__button--orange" + onClick={event => { + event.preventDefault() + setFeatureFlagToBeta() + }} + > + { t('useOldUI') } + </Button> + </div> + </div> + </div> + ) + } + + renderResetAccount () { + const { t } = this.context + const { showResetAccountConfirmationModal } = this.props + + return ( + <div className="settings-page__content-row"> + <div className="settings-page__content-item"> + <span>{ t('resetAccount') }</span> + </div> + <div className="settings-page__content-item"> + <div className="settings-page__content-item-col"> + <Button + type="secondary" + large + className="settings-tab__button--orange" + onClick={event => { + event.preventDefault() + showResetAccountConfirmationModal() + }} + > + { t('resetAccount') } + </Button> + </div> + </div> + </div> + ) + } + + renderBlockieOptIn () { + const { useBlockie, setUseBlockie } = this.props + + return ( + <div className="settings-page__content-row"> + <div className="settings-page__content-item"> + <span>{ this.context.t('blockiesIdenticon') }</span> + </div> + <div className="settings-page__content-item"> + <div className="settings-page__content-item-col"> + <ToggleButton + value={useBlockie} + onToggle={value => setUseBlockie(!value)} + activeLabel="" + inactiveLabel="" + /> + </div> + </div> + </div> + ) + } + + renderHexDataOptIn () { + const { t } = this.context + const { sendHexData, setHexDataFeatureFlag } = this.props + + return ( + <div className="settings-page__content-row"> + <div className="settings-page__content-item"> + <span>{ t('showHexData') }</span> + <div className="settings-page__content-description"> + { t('showHexDataDescription') } + </div> + </div> + <div className="settings-page__content-item"> + <div className="settings-page__content-item-col"> + <ToggleButton + value={sendHexData} + onToggle={value => setHexDataFeatureFlag(!value)} + activeLabel="" + inactiveLabel="" + /> + </div> + </div> + </div> + ) + } + + render () { + const { warning, isMascara } = this.props + + return ( + <div className="settings-page__content"> + { warning && <div className="settings-tab__error">{ warning }</div> } + { this.renderCurrentConversion() } + { this.renderCurrentLocale() } + { this.renderNewRpcUrl() } + { this.renderStateLogs() } + { this.renderSeedWords() } + { !isMascara && this.renderOldUI() } + { this.renderResetAccount() } + { this.renderBlockieOptIn() } + { this.renderHexDataOptIn() } + </div> + ) + } +} diff --git a/ui/app/components/pages/settings/settings-tab/settings-tab.container.js b/ui/app/components/pages/settings/settings-tab/settings-tab.container.js new file mode 100644 index 000000000..665b56f5c --- /dev/null +++ b/ui/app/components/pages/settings/settings-tab/settings-tab.container.js @@ -0,0 +1,59 @@ +import SettingsTab from './settings-tab.component' +import { compose } from 'recompose' +import { connect } from 'react-redux' +import { withRouter } from 'react-router-dom' +import { + setCurrentCurrency, + setRpcTarget, + displayWarning, + revealSeedConfirmation, + setUseBlockie, + updateCurrentLocale, + setFeatureFlag, + showModal, +} from '../../../../actions' + +const mapStateToProps = state => { + const { appState: { warning }, metamask } = state + const { + currentCurrency, + conversionDate, + useBlockie, + featureFlags: { sendHexData } = {}, + provider = {}, + isMascara, + currentLocale, + } = metamask + + return { + warning, + isMascara, + currentLocale, + currentCurrency, + conversionDate, + useBlockie, + sendHexData, + provider, + } +} + +const mapDispatchToProps = dispatch => { + return { + setCurrentCurrency: currency => dispatch(setCurrentCurrency(currency)), + setRpcTarget: newRpc => dispatch(setRpcTarget(newRpc)), + displayWarning: warning => dispatch(displayWarning(warning)), + revealSeedConfirmation: () => dispatch(revealSeedConfirmation()), + setUseBlockie: value => dispatch(setUseBlockie(value)), + updateCurrentLocale: key => dispatch(updateCurrentLocale(key)), + setFeatureFlagToBeta: () => { + return dispatch(setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL')) + }, + setHexDataFeatureFlag: shouldShow => dispatch(setFeatureFlag('sendHexData', shouldShow)), + showResetAccountConfirmationModal: () => dispatch(showModal({ name: 'CONFIRM_RESET_ACCOUNT' })), + } +} + +export default compose( + withRouter, + connect(mapStateToProps, mapDispatchToProps) +)(SettingsTab) diff --git a/ui/app/components/pages/settings/settings.component.js b/ui/app/components/pages/settings/settings.component.js new file mode 100644 index 000000000..94a97bba1 --- /dev/null +++ b/ui/app/components/pages/settings/settings.component.js @@ -0,0 +1,54 @@ +import React, { PureComponent } from 'react' +import PropTypes from 'prop-types' +import { Switch, Route, matchPath } from 'react-router-dom' +import TabBar from '../../tab-bar' +import SettingsTab from './settings-tab' +import InfoTab from './info-tab' +import { DEFAULT_ROUTE, SETTINGS_ROUTE, INFO_ROUTE } from '../../../routes' + +export default class SettingsPage extends PureComponent { + static propTypes = { + location: PropTypes.object, + history: PropTypes.object, + t: PropTypes.func, + } + + static contextTypes = { + t: PropTypes.func, + } + + render () { + const { history, location } = this.props + + return ( + <div className="main-container settings-page"> + <div className="settings-page__header"> + <div + className="settings-page__close-button" + onClick={() => history.push(DEFAULT_ROUTE)} + /> + <TabBar + tabs={[ + { content: this.context.t('settings'), key: SETTINGS_ROUTE }, + { content: this.context.t('info'), key: INFO_ROUTE }, + ]} + isActive={key => matchPath(location.pathname, { path: key, exact: true })} + onSelect={key => history.push(key)} + /> + </div> + <Switch> + <Route + exact + path={INFO_ROUTE} + component={InfoTab} + /> + <Route + exact + path={SETTINGS_ROUTE} + component={SettingsTab} + /> + </Switch> + </div> + ) + } +} diff --git a/ui/app/components/pages/settings/settings.js b/ui/app/components/pages/settings/settings.js deleted file mode 100644 index 423276cf3..000000000 --- a/ui/app/components/pages/settings/settings.js +++ /dev/null @@ -1,408 +0,0 @@ -const { Component } = require('react') -const { withRouter } = require('react-router-dom') -const { compose } = require('recompose') -const PropTypes = require('prop-types') -const h = require('react-hyperscript') -const connect = require('react-redux').connect -const actions = require('../../../actions') -const infuraCurrencies = require('../../../infura-conversion.json') -const validUrl = require('valid-url') -const { exportAsFile } = require('../../../util') -const SimpleDropdown = require('../../dropdowns/simple-dropdown') -const ToggleButton = require('react-toggle-button') -const { REVEAL_SEED_ROUTE } = require('../../../routes') -const locales = require('../../../../../app/_locales/index.json') - -import Button from '../../button' - -const getInfuraCurrencyOptions = () => { - const sortedCurrencies = infuraCurrencies.objects.sort((a, b) => { - return a.quote.name.toLocaleLowerCase().localeCompare(b.quote.name.toLocaleLowerCase()) - }) - - return sortedCurrencies.map(({ quote: { code, name } }) => { - return { - displayValue: `${code.toUpperCase()} - ${name}`, - key: code, - value: code, - } - }) -} - -const getLocaleOptions = () => { - return locales.map((locale) => { - return { - displayValue: `${locale.name}`, - key: locale.code, - value: locale.code, - } - }) -} - -class Settings extends Component { - constructor (props) { - super(props) - - this.state = { - newRpc: '', - } - } - - renderBlockieOptIn () { - const { metamask: { useBlockie }, setUseBlockie } = this.props - - return h('div.settings__content-row', [ - h('div.settings__content-item', [ - h('span', this.context.t('blockiesIdenticon')), - ]), - h('div.settings__content-item', [ - h('div.settings__content-item-col', [ - h(ToggleButton, { - value: useBlockie, - onToggle: (value) => setUseBlockie(!value), - activeLabel: '', - inactiveLabel: '', - }), - ]), - ]), - ]) - } - - renderHexDataOptIn () { - const { metamask: { featureFlags: { sendHexData } }, setHexDataFeatureFlag } = this.props - - return h('div.settings__content-row', [ - h('div.settings__content-item', [ - h('span', this.context.t('showHexData')), - h( - 'div.settings__content-description', - this.context.t('showHexDataDescription') - ), - ]), - h('div.settings__content-item', [ - h('div.settings__content-item-col', [ - h(ToggleButton, { - value: sendHexData, - onToggle: (value) => setHexDataFeatureFlag(!value), - activeLabel: '', - inactiveLabel: '', - }), - ]), - ]), - ]) - } - - renderCurrentConversion () { - const { metamask: { currentCurrency, conversionDate }, setCurrentCurrency } = this.props - - return h('div.settings__content-row', [ - h('div.settings__content-item', [ - h('span', this.context.t('currentConversion')), - h('span.settings__content-description', `Updated ${Date(conversionDate)}`), - ]), - h('div.settings__content-item', [ - h('div.settings__content-item-col', [ - h(SimpleDropdown, { - placeholder: this.context.t('selectCurrency'), - options: getInfuraCurrencyOptions(), - selectedOption: currentCurrency, - onSelect: newCurrency => setCurrentCurrency(newCurrency), - }), - ]), - ]), - ]) - } - - renderCurrentLocale () { - const { updateCurrentLocale, currentLocale } = this.props - const currentLocaleMeta = locales.find(locale => locale.code === currentLocale) - const currentLocaleName = currentLocaleMeta ? currentLocaleMeta.name : '' - - return h('div.settings__content-row', [ - h('div.settings__content-item', [ - h('span', 'Current Language'), - h('span.settings__content-description', `${currentLocaleName}`), - ]), - h('div.settings__content-item', [ - h('div.settings__content-item-col', [ - h(SimpleDropdown, { - placeholder: 'Select Locale', - options: getLocaleOptions(), - selectedOption: currentLocale, - onSelect: async (newLocale) => { - updateCurrentLocale(newLocale) - }, - }), - ]), - ]), - ]) - } - - renderCurrentProvider () { - const { metamask: { provider = {} } } = this.props - let title, value, color - - switch (provider.type) { - - case 'mainnet': - title = this.context.t('currentNetwork') - value = this.context.t('mainnet') - color = '#038789' - break - - case 'ropsten': - title = this.context.t('currentNetwork') - value = this.context.t('ropsten') - color = '#e91550' - break - - case 'kovan': - title = this.context.t('currentNetwork') - value = this.context.t('kovan') - color = '#690496' - break - - case 'rinkeby': - title = this.context.t('currentNetwork') - value = this.context.t('rinkeby') - color = '#ebb33f' - break - - default: - title = this.context.t('currentRpc') - value = provider.rpcTarget - } - - return h('div.settings__content-row', [ - h('div.settings__content-item', title), - h('div.settings__content-item', [ - h('div.settings__content-item-col', [ - h('div.settings__provider-wrapper', [ - h('div.settings__provider-icon', { style: { background: color } }), - h('div', value), - ]), - ]), - ]), - ]) - } - - renderNewRpcUrl () { - return ( - h('div.settings__content-row', [ - h('div.settings__content-item', [ - h('span', this.context.t('newRPC')), - ]), - h('div.settings__content-item', [ - h('div.settings__content-item-col', [ - h('input.settings__input', { - placeholder: this.context.t('newRPC'), - onChange: event => this.setState({ newRpc: event.target.value }), - onKeyPress: event => { - if (event.key === 'Enter') { - this.validateRpc(this.state.newRpc) - } - }, - }), - h('div.settings__rpc-save-button', { - onClick: event => { - event.preventDefault() - this.validateRpc(this.state.newRpc) - }, - }, this.context.t('save')), - ]), - ]), - ]) - ) - } - - validateRpc (newRpc) { - const { setRpcTarget, displayWarning } = this.props - - if (validUrl.isWebUri(newRpc)) { - setRpcTarget(newRpc) - } else { - const appendedRpc = `http://${newRpc}` - - if (validUrl.isWebUri(appendedRpc)) { - displayWarning(this.context.t('uriErrorMsg')) - } else { - displayWarning(this.context.t('invalidRPC')) - } - } - } - - renderStateLogs () { - return ( - h('div.settings__content-row', [ - h('div.settings__content-item', [ - h('div', this.context.t('stateLogs')), - h( - 'div.settings__content-description', - this.context.t('stateLogsDescription') - ), - ]), - h('div.settings__content-item', [ - h('div.settings__content-item-col', [ - h(Button, { - type: 'primary', - large: true, - className: 'settings__button', - onClick (event) { - window.logStateString((err, result) => { - if (err) { - this.state.dispatch(actions.displayWarning(this.context.t('stateLogError'))) - } else { - exportAsFile('MetaMask State Logs.json', result) - } - }) - }, - }, this.context.t('downloadStateLogs')), - ]), - ]), - ]) - ) - } - - renderSeedWords () { - const { history } = this.props - - return ( - h('div.settings__content-row', [ - h('div.settings__content-item', this.context.t('revealSeedWords')), - h('div.settings__content-item', [ - h('div.settings__content-item-col', [ - h(Button, { - type: 'primary', - large: true, - className: 'settings__button--red', - onClick: event => { - event.preventDefault() - history.push(REVEAL_SEED_ROUTE) - }, - }, this.context.t('revealSeedWords')), - ]), - ]), - ]) - ) - } - - renderOldUI () { - const { setFeatureFlagToBeta } = this.props - - return ( - h('div.settings__content-row', [ - h('div.settings__content-item', this.context.t('useOldUI')), - h('div.settings__content-item', [ - h('div.settings__content-item-col', [ - h(Button, { - type: 'primary', - large: true, - className: 'settings__button--orange', - onClick (event) { - event.preventDefault() - setFeatureFlagToBeta() - }, - }, this.context.t('useOldUI')), - ]), - ]), - ]) - ) - } - - renderResetAccount () { - const { showResetAccountConfirmationModal } = this.props - - return h('div.settings__content-row', [ - h('div.settings__content-item', this.context.t('resetAccount')), - h('div.settings__content-item', [ - h('div.settings__content-item-col', [ - h(Button, { - type: 'primary', - large: true, - className: 'settings__button--orange', - onClick (event) { - event.preventDefault() - showResetAccountConfirmationModal() - }, - }, this.context.t('resetAccount')), - ]), - ]), - ]) - } - - render () { - const { warning, isMascara } = this.props - - return ( - h('div.settings__content', [ - warning && h('div.settings__error', warning), - this.renderCurrentConversion(), - this.renderCurrentLocale(), - // this.renderCurrentProvider(), - this.renderNewRpcUrl(), - this.renderStateLogs(), - this.renderSeedWords(), - !isMascara && this.renderOldUI(), - this.renderResetAccount(), - this.renderBlockieOptIn(), - this.renderHexDataOptIn(), - ]) - ) - } -} - -Settings.propTypes = { - metamask: PropTypes.object, - setUseBlockie: PropTypes.func, - setHexDataFeatureFlag: PropTypes.func, - setCurrentCurrency: PropTypes.func, - setRpcTarget: PropTypes.func, - displayWarning: PropTypes.func, - revealSeedConfirmation: PropTypes.func, - setFeatureFlagToBeta: PropTypes.func, - showResetAccountConfirmationModal: PropTypes.func, - warning: PropTypes.string, - history: PropTypes.object, - isMascara: PropTypes.bool, - updateCurrentLocale: PropTypes.func, - currentLocale: PropTypes.string, - t: PropTypes.func, -} - -const mapStateToProps = state => { - return { - metamask: state.metamask, - warning: state.appState.warning, - isMascara: state.metamask.isMascara, - currentLocale: state.metamask.currentLocale, - } -} - -const mapDispatchToProps = dispatch => { - return { - setCurrentCurrency: currency => dispatch(actions.setCurrentCurrency(currency)), - setRpcTarget: newRpc => dispatch(actions.setRpcTarget(newRpc)), - displayWarning: warning => dispatch(actions.displayWarning(warning)), - revealSeedConfirmation: () => dispatch(actions.revealSeedConfirmation()), - setUseBlockie: value => dispatch(actions.setUseBlockie(value)), - updateCurrentLocale: key => dispatch(actions.updateCurrentLocale(key)), - setFeatureFlagToBeta: () => { - return dispatch(actions.setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL')) - }, - setHexDataFeatureFlag: (featureFlagShowState) => { - return dispatch(actions.setFeatureFlag('sendHexData', featureFlagShowState)) - }, - showResetAccountConfirmationModal: () => { - return dispatch(actions.showModal({ name: 'CONFIRM_RESET_ACCOUNT' })) - }, - } -} - -Settings.contextTypes = { - t: PropTypes.func, -} - -module.exports = compose( - withRouter, - connect(mapStateToProps, mapDispatchToProps) -)(Settings) diff --git a/ui/app/components/pages/unlock-page/index.scss b/ui/app/components/pages/unlock-page/index.scss index 3d44bd037..6bd52282d 100644 --- a/ui/app/components/pages/unlock-page/index.scss +++ b/ui/app/components/pages/unlock-page/index.scss @@ -14,6 +14,7 @@ align-self: stretch; justify-content: center; flex: 1 0 auto; + height: 100vh; } &__mascot-container { diff --git a/ui/app/components/send/currency-display/tests/currency-display.test.js b/ui/app/components/send/currency-display/tests/currency-display.test.js new file mode 100644 index 000000000..c9560b81c --- /dev/null +++ b/ui/app/components/send/currency-display/tests/currency-display.test.js @@ -0,0 +1,91 @@ +import React from 'react' +import assert from 'assert' +import sinon from 'sinon' +import { shallow, mount } from 'enzyme' +import CurrencyDisplay from '../currency-display' + +describe('', () => { + + const token = { + address: '0xTest', + symbol: 'TST', + decimals: '13', + } + + it('retuns ETH value for wei value', () => { + const wrapper = mount(<CurrencyDisplay />, {context: {t: str => str + '_t'}}) + + const value = wrapper.instance().getValueToRender({ + // 1000000000000000000 + value: 'DE0B6B3A7640000', + }) + + assert.equal(value, 1) + }) + + it('returns value of token based on token decimals', () => { + const wrapper = mount(<CurrencyDisplay />, {context: {t: str => str + '_t'}}) + + const value = wrapper.instance().getValueToRender({ + selectedToken: token, + // 1000000000000000000 + value: 'DE0B6B3A7640000', + }) + + assert.equal(value, 100000) + }) + + it('returns hex value with decimal adjustment', () => { + + const wrapper = mount( + <CurrencyDisplay + selectedToken={token} + />, {context: {t: str => str + '_t'}}) + + const value = wrapper.instance().getAmount(1) + // 10000000000000 + assert.equal(value, '9184e72a000') + }) + + it('#getConvertedValueToRender converts input value based on conversionRate', () => { + + const wrapper = mount( + <CurrencyDisplay + primaryCurrency={'usd'} + convertedCurrency={'ja'} + conversionRate={2} + />, {context: {t: str => str + '_t'}}) + + const value = wrapper.instance().getConvertedValueToRender(32) + + assert.equal(value, 64) + }) + + it('#onlyRenderConversions renders single element for converted currency and value', () => { + const wrapper = mount( + <CurrencyDisplay + convertedCurrency={'test'} + />, {context: {t: str => str + '_t'}}) + + const value = wrapper.instance().onlyRenderConversions(10) + assert.equal(value.props.className, 'currency-display__converted-value') + assert.equal(value.props.children, '10 TEST') + }) + + it('simulates change value in input', () => { + const handleChangeSpy = sinon.spy() + + const wrapper = shallow( + <CurrencyDisplay + onChange={handleChangeSpy} + />, {context: {t: str => str + '_t'}}) + + const input = wrapper.find('input') + input.simulate('focus') + input.simulate('change', { target: { value: '100' } }) + + assert.equal(wrapper.state().valueToRender, '100') + assert.equal(wrapper.find('input').prop('value'), '100') + }) + +}) diff --git a/ui/app/components/signature-request.js b/ui/app/components/signature-request.js index 2bfa350d3..5b0c7684a 100644 --- a/ui/app/components/signature-request.js +++ b/ui/app/components/signature-request.js @@ -8,6 +8,7 @@ const ethUtil = require('ethereumjs-util') const classnames = require('classnames') const { compose } = require('recompose') const { withRouter } = require('react-router-dom') +const { ObjectInspector } = require('react-inspector') const AccountDropdownMini = require('./dropdowns/account-dropdown-mini') @@ -169,12 +170,29 @@ SignatureRequest.prototype.msgHexToText = function (hex) { } } +// eslint-disable-next-line react/display-name +SignatureRequest.prototype.renderTypedDataV3 = function (data) { + const { domain, message } = JSON.parse(data) + return [ + h('div.request-signature__typed-container', [ + domain ? h('div', [ + h('h1', 'Domain'), + h(ObjectInspector, { data: domain, expandLevel: 1, name: 'domain' }), + ]) : '', + message ? h('div', [ + h('h1', 'Message'), + h(ObjectInspector, { data: message, expandLevel: 1, name: 'message' }), + ]) : '', + ]), + ] +} + SignatureRequest.prototype.renderBody = function () { let rows let notice = this.context.t('youSign') + ':' const { txData } = this.props - const { type, msgParams: { data } } = txData + const { type, msgParams: { data, version } } = txData if (type === 'personal_sign') { rows = [{ name: this.context.t('message'), value: this.msgHexToText(data) }] @@ -205,9 +223,9 @@ SignatureRequest.prototype.renderBody = function () { }), }, [notice]), - h('div.request-signature__rows', [ - - ...rows.map(({ name, value }) => { + h('div.request-signature__rows', type === 'eth_signTypedData' && version === 'V3' ? + this.renderTypedDataV3(data) : + rows.map(({ name, value }) => { if (typeof value === 'boolean') { value = value.toString() } @@ -216,9 +234,7 @@ SignatureRequest.prototype.renderBody = function () { h('div.request-signature__row-value', value), ]) }), - - ]), - + ), ]) } diff --git a/ui/app/components/transaction-action/tests/transaction-action.component.test.js b/ui/app/components/transaction-action/tests/transaction-action.component.test.js index 218792847..9352c7b43 100644 --- a/ui/app/components/transaction-action/tests/transaction-action.component.test.js +++ b/ui/app/components/transaction-action/tests/transaction-action.component.test.js @@ -5,10 +5,9 @@ import sinon from 'sinon' import TransactionAction from '../transaction-action.component' describe('TransactionAction Component', () => { - const tOrDefault = key => key + const t = key => key global.eth = { getCode: sinon.stub().callsFake(address => { - console.log('CALLED') const code = address === 'approveAddress' ? 'contract' : '0x' return Promise.resolve(code) }), @@ -36,7 +35,7 @@ describe('TransactionAction Component', () => { methodData={methodData} transaction={transaction} className="transaction-action" - />, { context: { tOrDefault }}) + />, { context: { t }}) assert.equal(wrapper.find('.transaction-action').length, 1) assert.equal(wrapper.text(), '--') @@ -63,7 +62,7 @@ describe('TransactionAction Component', () => { methodData={methodData} transaction={transaction} className="transaction-action" - />, { context: { tOrDefault }}) + />, { context: { t }}) assert.equal(wrapper.find('.transaction-action').length, 1) wrapper.setState({ transactionAction: 'sentEther' }) @@ -102,7 +101,7 @@ describe('TransactionAction Component', () => { methodData={methodData} transaction={transaction} className="transaction-action" - />, { context: { tOrDefault }}) + />, { context: { t }}) assert.equal(wrapper.find('.transaction-action').length, 1) wrapper.setState({ transactionAction: 'approve' }) diff --git a/ui/app/components/transaction-action/transaction-action.component.js b/ui/app/components/transaction-action/transaction-action.component.js index 81a1e96d0..1729b878c 100644 --- a/ui/app/components/transaction-action/transaction-action.component.js +++ b/ui/app/components/transaction-action/transaction-action.component.js @@ -4,7 +4,7 @@ import { getTransactionActionKey } from '../../helpers/transactions.util' export default class TransactionAction extends PureComponent { static contextTypes = { - tOrDefault: PropTypes.func, + t: PropTypes.func, } static propTypes = { @@ -35,7 +35,7 @@ export default class TransactionAction extends PureComponent { } const actionKey = await getTransactionActionKey(transaction, data) - const action = actionKey && this.context.tOrDefault(actionKey) + const action = actionKey && this.context.t(actionKey) this.setState({ transactionAction: action }) } diff --git a/ui/app/components/transaction-activity-log/index.scss b/ui/app/components/transaction-activity-log/index.scss index 2324d44b1..27f3006b3 100644 --- a/ui/app/components/transaction-activity-log/index.scss +++ b/ui/app/components/transaction-activity-log/index.scss @@ -33,6 +33,10 @@ &:last-child::after { height: 50%; } + + &:first-child:last-child::after { + display: none; + } } &__activity-icon { @@ -47,9 +51,12 @@ &__activity-text { color: $scorpion; font-size: .75rem; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + + @media screen and (min-width: $break-large) { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } } &__value { diff --git a/ui/app/components/transaction-list-item-details/transaction-list-item-details.component.js b/ui/app/components/transaction-list-item-details/transaction-list-item-details.component.js index f65ff4d55..13cb51349 100644 --- a/ui/app/components/transaction-list-item-details/transaction-list-item-details.component.js +++ b/ui/app/components/transaction-list-item-details/transaction-list-item-details.component.js @@ -13,7 +13,9 @@ export default class TransactionListItemDetails extends PureComponent { } static propTypes = { + onCancel: PropTypes.func, onRetry: PropTypes.func, + showCancel: PropTypes.bool, showRetry: PropTypes.bool, transaction: PropTypes.object, } @@ -27,6 +29,13 @@ export default class TransactionListItemDetails extends PureComponent { this.setState({ showTransactionDetails: true }) } + handleCancel = event => { + const { onCancel } = this.props + + event.stopPropagation() + onCancel() + } + handleRetry = event => { const { onRetry } = this.props @@ -36,7 +45,7 @@ export default class TransactionListItemDetails extends PureComponent { render () { const { t } = this.context - const { transaction, showRetry } = this.props + const { transaction, showCancel, showRetry } = this.props const { txParams: { to, from } = {} } = transaction return ( @@ -55,6 +64,17 @@ export default class TransactionListItemDetails extends PureComponent { </Button> ) } + { + showCancel && ( + <Button + type="raised" + onClick={this.handleCancel} + className="transaction-list-item-details__header-button" + > + { t('cancel') } + </Button> + ) + } <Button type="raised" onClick={this.handleEtherscanClick} diff --git a/ui/app/components/transaction-list-item/index.scss b/ui/app/components/transaction-list-item/index.scss index 427686c29..9d694546b 100644 --- a/ui/app/components/transaction-list-item/index.scss +++ b/ui/app/components/transaction-list-item/index.scss @@ -6,6 +6,7 @@ justify-content: center; align-items: center; flex-direction: column; + background: $white; &__grid { cursor: pointer; @@ -117,4 +118,14 @@ background: #f3f4f7; width: 100%; } + + &__expander { + max-height: 0px; + width: 100%; + + &--show { + max-height: 1000px; + transition: max-height 700ms ease-out; + } + } } diff --git a/ui/app/components/transaction-list-item/transaction-list-item.component.js b/ui/app/components/transaction-list-item/transaction-list-item.component.js index e590e96e0..c1c69f59b 100644 --- a/ui/app/components/transaction-list-item/transaction-list-item.component.js +++ b/ui/app/components/transaction-list-item/transaction-list-item.component.js @@ -1,5 +1,6 @@ import React, { PureComponent } from 'react' import PropTypes from 'prop-types' +import classnames from 'classnames' import Identicon from '../identicon' import TransactionStatus from '../transaction-status' import TransactionAction from '../transaction-action' @@ -9,20 +10,24 @@ import TransactionListItemDetails from '../transaction-list-item-details' import { CONFIRM_TRANSACTION_ROUTE } from '../../routes' import { UNAPPROVED_STATUS, TOKEN_METHOD_TRANSFER } from '../../constants/transactions' import { ETH } from '../../constants/common' +import { ENVIRONMENT_TYPE_FULLSCREEN } from '../../../../app/scripts/lib/enums' export default class TransactionListItem extends PureComponent { static propTypes = { + assetImages: PropTypes.object, history: PropTypes.object, - transaction: PropTypes.object, - value: PropTypes.string, methodData: PropTypes.object, - showRetry: PropTypes.bool, + nonceAndDate: PropTypes.string, retryTransaction: PropTypes.func, setSelectedToken: PropTypes.func, - nonceAndDate: PropTypes.string, + showCancelModal: PropTypes.func, + showCancel: PropTypes.bool, + showRetry: PropTypes.bool, + showTransactionDetailsModal: PropTypes.func, token: PropTypes.object, - assetImages: PropTypes.object, tokenData: PropTypes.object, + transaction: PropTypes.object, + value: PropTypes.string, } state = { @@ -30,16 +35,39 @@ export default class TransactionListItem extends PureComponent { } handleClick = () => { - const { transaction, history } = this.props + const { + transaction, + history, + showTransactionDetailsModal, + methodData, + showCancel, + showRetry, + } = this.props const { id, status } = transaction const { showTransactionDetails } = this.state + const windowType = window.METAMASK_UI_TYPE if (status === UNAPPROVED_STATUS) { history.push(`${CONFIRM_TRANSACTION_ROUTE}/${id}`) return } - this.setState({ showTransactionDetails: !showTransactionDetails }) + if (windowType === ENVIRONMENT_TYPE_FULLSCREEN) { + this.setState({ showTransactionDetails: !showTransactionDetails }) + } else { + showTransactionDetailsModal({ + transaction, + onRetry: this.handleRetry, + showRetry: showRetry && methodData.done, + onCancel: this.handleCancel, + showCancel, + }) + } + } + + handleCancel = () => { + const { transaction: { id, txParams: { gasPrice } } = {}, showCancelModal } = this.props + showCancelModal(id, gasPrice) } handleRetry = () => { @@ -53,12 +81,12 @@ export default class TransactionListItem extends PureComponent { setSelectedToken(to) } - this.resubmit() + return this.resubmit() } resubmit () { const { transaction: { id }, retryTransaction, history } = this.props - retryTransaction(id) + return retryTransaction(id) .then(id => history.push(`${CONFIRM_TRANSACTION_ROUTE}/${id}`)) } @@ -100,12 +128,13 @@ export default class TransactionListItem extends PureComponent { render () { const { - transaction, + assetImages, methodData, - showRetry, nonceAndDate, - assetImages, + showCancel, + showRetry, tokenData, + transaction, } = this.props const { txParams = {} } = transaction const { showTransactionDetails } = this.state @@ -148,17 +177,23 @@ export default class TransactionListItem extends PureComponent { { this.renderPrimaryCurrency() } { this.renderSecondaryCurrency() } </div> - { - showTransactionDetails && ( - <div className="transaction-list-item__details-container"> - <TransactionListItemDetails - transaction={transaction} - showRetry={showRetry && methodData.done} - onRetry={this.handleRetry} - /> - </div> - ) - } + <div className={classnames('transaction-list-item__expander', { + 'transaction-list-item__expander--show': showTransactionDetails, + })}> + { + showTransactionDetails && ( + <div className="transaction-list-item__details-container"> + <TransactionListItemDetails + transaction={transaction} + onRetry={this.handleRetry} + showRetry={showRetry && methodData.done} + onCancel={this.handleCancel} + showCancel={showCancel} + /> + </div> + ) + } + </div> </div> ) } diff --git a/ui/app/components/transaction-list-item/transaction-list-item.container.js b/ui/app/components/transaction-list-item/transaction-list-item.container.js index 3db9d40ec..72f5f5d61 100644 --- a/ui/app/components/transaction-list-item/transaction-list-item.container.js +++ b/ui/app/components/transaction-list-item/transaction-list-item.container.js @@ -3,7 +3,7 @@ import { withRouter } from 'react-router-dom' import { compose } from 'recompose' import withMethodData from '../../higher-order-components/with-method-data' import TransactionListItem from './transaction-list-item.component' -import { setSelectedToken, retryTransaction } from '../../actions' +import { setSelectedToken, retryTransaction, showModal } from '../../actions' import { hexToDecimal } from '../../helpers/conversions.util' import { getTokenData } from '../../helpers/transactions.util' import { formatDate } from '../../util' @@ -25,6 +25,19 @@ const mapDispatchToProps = dispatch => { return { setSelectedToken: tokenAddress => dispatch(setSelectedToken(tokenAddress)), retryTransaction: transactionId => dispatch(retryTransaction(transactionId)), + showCancelModal: (transactionId, originalGasPrice) => { + return dispatch(showModal({ name: 'CANCEL_TRANSACTION', transactionId, originalGasPrice })) + }, + showTransactionDetailsModal: ({ transaction, onRetry, showRetry, onCancel, showCancel }) => { + return dispatch(showModal({ + name: 'TRANSACTION_DETAILS', + transaction, + onRetry, + showRetry, + onCancel, + showCancel, + })) + }, } } diff --git a/ui/app/components/transaction-list/index.scss b/ui/app/components/transaction-list/index.scss index d944ef20e..777f701f9 100644 --- a/ui/app/components/transaction-list/index.scss +++ b/ui/app/components/transaction-list/index.scss @@ -3,6 +3,8 @@ flex-direction: column; flex: 1; overflow-y: hidden; + margin-top: 8px; + border-top: 1px solid $geyser; &__completed-transactions { display: flex; @@ -15,7 +17,7 @@ font-size: .875rem; color: $dusty-gray; border-bottom: 1px solid $geyser; - padding: 16px 0 8px 20px; + padding: 8px 0 8px 20px; @media screen and (max-width: $break-small) { padding: 8px 0 8px 16px; diff --git a/ui/app/components/transaction-list/transaction-list.component.js b/ui/app/components/transaction-list/transaction-list.component.js index c864fea3b..eef60186d 100644 --- a/ui/app/components/transaction-list/transaction-list.component.js +++ b/ui/app/components/transaction-list/transaction-list.component.js @@ -56,7 +56,7 @@ export default class TransactionList extends PureComponent { </div> { pendingTransactions.map((transaction, index) => ( - this.renderTransaction(transaction, index) + this.renderTransaction(transaction, index, true) )) } </div> @@ -78,7 +78,7 @@ export default class TransactionList extends PureComponent { ) } - renderTransaction (transaction, index) { + renderTransaction (transaction, index, showCancel) { const { selectedToken, assetImages } = this.props return transaction.key === TRANSACTION_TYPE_SHAPESHIFT @@ -92,6 +92,7 @@ export default class TransactionList extends PureComponent { transaction={transaction} key={transaction.id} showRetry={this.shouldShowRetry(transaction)} + showCancel={showCancel} token={selectedToken} assetImages={assetImages} /> diff --git a/ui/app/conf-tx.js b/ui/app/conf-tx.js index 112ea6bca..0784a872e 100644 --- a/ui/app/conf-tx.js +++ b/ui/app/conf-tx.js @@ -104,7 +104,7 @@ ConfirmTxScreen.prototype.componentDidUpdate = function (prevProps) { if (prevTx && prevTx.status === 'dropped') { this.props.dispatch(actions.showModal({ name: 'TRANSACTION_CONFIRMED', - onHide: () => history.push(DEFAULT_ROUTE), + onSubmit: () => history.push(DEFAULT_ROUTE), })) return diff --git a/ui/app/constants/transactions.js b/ui/app/constants/transactions.js index df6c4c8a4..2dc061091 100644 --- a/ui/app/constants/transactions.js +++ b/ui/app/constants/transactions.js @@ -18,5 +18,6 @@ export const SEND_TOKEN_ACTION_KEY = 'sentTokens' export const TRANSFER_FROM_ACTION_KEY = 'transferFrom' export const SIGNATURE_REQUEST_KEY = 'signatureRequest' export const UNKNOWN_FUNCTION_KEY = 'unknownFunction' +export const CANCEL_ATTEMPT_ACTION_KEY = 'cancelAttempt' export const TRANSACTION_TYPE_SHAPESHIFT = 'shapeshift' diff --git a/ui/app/css/itcss/components/index.scss b/ui/app/css/itcss/components/index.scss index 9e2008b54..99deaf918 100644 --- a/ui/app/css/itcss/components/index.scss +++ b/ui/app/css/itcss/components/index.scss @@ -36,8 +36,6 @@ @import './gas-slider.scss'; -@import './settings.scss'; - @import './tab-bar.scss'; @import './simple-dropdown.scss'; diff --git a/ui/app/css/itcss/components/loading-overlay.scss b/ui/app/css/itcss/components/loading-overlay.scss index b07d6af17..b023c8423 100644 --- a/ui/app/css/itcss/components/loading-overlay.scss +++ b/ui/app/css/itcss/components/loading-overlay.scss @@ -1,6 +1,6 @@ .loading-overlay { left: 0; - z-index: 50; + z-index: 51; position: absolute; flex-direction: column; display: flex; @@ -8,25 +8,9 @@ align-items: center; flex: 1 1 auto; width: 100%; + height: 100%; background: rgba(255, 255, 255, .8); - @media screen and (max-width: 575px) { - margin-top: 66px; - height: calc(100% - 66px); - } - - @media screen and (min-width: 576px) { - margin-top: 75px; - height: calc(100% - 75px); - } - - &--full-screen { - position: fixed; - height: 100vh; - width: 100vw; - margin-top: 0; - } - &__container { position: absolute; top: 33%; diff --git a/ui/app/css/itcss/components/newui-sections.scss b/ui/app/css/itcss/components/newui-sections.scss index 7eb193d6f..8e963d495 100644 --- a/ui/app/css/itcss/components/newui-sections.scss +++ b/ui/app/css/itcss/components/newui-sections.scss @@ -22,6 +22,12 @@ $wallet-view-bg: $alabaster; display: none; } +.main-container-wrapper { + display: flex; + width: 100vw; + justify-content: center; +} + //Account and transaction details .account-and-transaction-details { display: flex; @@ -219,6 +225,10 @@ $wallet-view-bg: $alabaster; overflow-y: auto; background-color: $white; } + + .main-container-wrapper { + height: 100%; + } } // wallet view diff --git a/ui/app/css/itcss/components/request-signature.scss b/ui/app/css/itcss/components/request-signature.scss index b607aded3..445b9ebf5 100644 --- a/ui/app/css/itcss/components/request-signature.scss +++ b/ui/app/css/itcss/components/request-signature.scss @@ -23,6 +23,25 @@ } } + &__typed-container { + padding: 17px; + + h1 { + font-weight: 900; + margin-bottom: 5px; + } + + * { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + > div { + margin-bottom: 10px; + } + } + &__header { height: 64px; width: 100%; diff --git a/ui/app/css/itcss/components/settings.scss b/ui/app/css/itcss/components/settings.scss deleted file mode 100644 index 0dd61ac5e..000000000 --- a/ui/app/css/itcss/components/settings.scss +++ /dev/null @@ -1,214 +0,0 @@ -.settings { - position: relative; - background: $white; - display: flex; - flex-flow: column nowrap; -} - -.settings__header { - padding: 25px; -} - -.settings__close-button::after { - content: '\00D7'; - font-size: 40px; - color: $dusty-gray; - position: absolute; - top: 25px; - right: 30px; - cursor: pointer; -} - -.settings__error { - padding-bottom: 20px; - text-align: center; - color: $crimson; -} - -.settings__content { - padding: 0 25px; - height: auto; - overflow: auto; -} - -.settings__content-row { - display: flex; - flex-direction: row; - padding: 10px 0 20px; - - @media screen and (max-width: 575px) { - flex-direction: column; - padding: 10px 0; - } -} - -.settings__content-item { - flex: 1; - min-width: 0; - display: flex; - flex-direction: column; - padding: 0 5px; - height: 71px; - - @media screen and (max-width: 575px) { - height: initial; - padding: 5px 0; - } - - &--without-height { - height: initial; - } -} - -.settings__content-item-col { - max-width: 300px; - display: flex; - flex-direction: column; - - @media screen and (max-width: 575px) { - max-width: 100%; - width: 100%; - } -} - -.settings__content-description { - font-size: 14px; - color: $dusty-gray; - padding-top: 5px; -} - -.settings__input { - padding-left: 10px; - font-size: 14px; - height: 40px; - border: 1px solid $alto; -} - -.settings__input::-webkit-input-placeholder { - font-weight: 100; - color: $dusty-gray; -} - -.settings__input::-moz-placeholder { - font-weight: 100; - color: $dusty-gray; -} - -.settings__input:-ms-input-placeholder { - font-weight: 100; - color: $dusty-gray; -} - -.settings__input:-moz-placeholder { - font-weight: 100; - color: $dusty-gray; -} - -.settings__provider-wrapper { - font-size: 16px; - border: 1px solid $alto; - border-radius: 2px; - padding: 15px; - background-color: $white; - display: flex; - align-items: center; - justify-content: flex-start; -} - -.settings__provider-icon { - height: 10px; - width: 10px; - margin-right: 10px; - border-radius: 10px; -} - -.settings__rpc-save-button { - align-self: flex-end; - padding: 5px; - text-transform: uppercase; - color: $dusty-gray; - cursor: pointer; -} - -.settings__button--red { - border-color: lighten($monzo, 10%); - color: $monzo; - - &:active { - background: lighten($monzo, 55%); - border-color: $monzo; - } - - &:hover { - border-color: $monzo; - } -} - -.settings__button--orange { - border-color: lighten($ecstasy, 20%); - color: $ecstasy; - - &:active { - background: lighten($ecstasy, 40%); - border-color: $ecstasy; - } - - &:hover { - border-color: $ecstasy; - } -} - -.settings__info-logo-wrapper { - height: 80px; - margin-bottom: 20px; -} - -.settings__info-logo { - max-height: 100%; - max-width: 100%; -} - -.settings__info-item { - padding: 10px 0; -} - -.settings__info-link-header { - padding-bottom: 15px; - - @media screen and (max-width: 575px) { - padding-bottom: 5px; - } -} - -.settings__info-link-item { - padding: 15px 0; - - @media screen and (max-width: 575px) { - padding: 5px 0; - } -} - -.settings__info-version-number { - padding-top: 5px; - font-size: 13px; - color: $dusty-gray; -} - -.settings__info-about { - color: $dusty-gray; - margin-bottom: 15px; -} - -.settings__info-link { - color: $curious-blue; -} - -.settings__info-separator { - margin: 15px 0; - width: 80px; - border-color: $alto; - border: none; - height: 1px; - background-color: $alto; - color: $alto; -} diff --git a/ui/app/helpers/conversions.util.js b/ui/app/helpers/conversions.util.js index 5204faa1f..20ef9e35b 100644 --- a/ui/app/helpers/conversions.util.js +++ b/ui/app/helpers/conversions.util.js @@ -1,6 +1,11 @@ +import ethUtil from 'ethereumjs-util' import { conversionUtil } from '../conversion-util' import { ETH, GWEI, WEI } from '../constants/common' +export function bnToHex (inputBn) { + return ethUtil.addHexPrefix(inputBn.toString(16)) +} + export function hexToDecimal (hexValue) { return conversionUtil(hexValue, { fromNumericBase: 'hex', @@ -8,6 +13,13 @@ export function hexToDecimal (hexValue) { }) } +export function decimalToHex (decimal) { + return conversionUtil(decimal, { + fromNumericBase: 'dec', + toNumericBase: 'hex', + }) +} + export function getEthConversionFromWeiHex ({ value, conversionRate, numberOfDecimals = 6 }) { const denominations = [ETH, GWEI, WEI] diff --git a/ui/app/helpers/tests/transactions.util.test.js b/ui/app/helpers/tests/transactions.util.test.js new file mode 100644 index 000000000..103a84a8c --- /dev/null +++ b/ui/app/helpers/tests/transactions.util.test.js @@ -0,0 +1,22 @@ +import * as utils from '../transactions.util' +import assert from 'assert' + +describe('Transactions utils', () => { + describe('getTokenData', () => { + it('should return token data', () => { + const tokenData = utils.getTokenData('0xa9059cbb00000000000000000000000050a9d56c2b8ba9a5c7f2c08c3d26e0499f23a7060000000000000000000000000000000000000000000000000000000000004e20') + assert.ok(tokenData) + const { name, params } = tokenData + assert.equal(name, 'transfer') + const [to, value] = params + assert.equal(to.name, '_to') + assert.equal(to.type, 'address') + assert.equal(value.name, '_value') + assert.equal(value.type, 'uint256') + }) + + it('should not throw errors when called without arguments', () => { + assert.doesNotThrow(() => utils.getTokenData()) + }) + }) +}) diff --git a/ui/app/helpers/transactions.util.js b/ui/app/helpers/transactions.util.js index 0e1a6ca37..8b87bb538 100644 --- a/ui/app/helpers/transactions.util.js +++ b/ui/app/helpers/transactions.util.js @@ -14,19 +14,20 @@ import { TRANSFER_FROM_ACTION_KEY, SIGNATURE_REQUEST_KEY, UNKNOWN_FUNCTION_KEY, + CANCEL_ATTEMPT_ACTION_KEY, } from '../constants/transactions' import { addCurrencies } from '../conversion-util' abiDecoder.addABI(abi) -export function getTokenData (data = {}) { +export function getTokenData (data = '') { return abiDecoder.decodeMethod(data) } const registry = new MethodRegistry({ provider: global.ethereumProvider }) -export async function getMethodData (data = {}) { +export async function getMethodData (data = '') { const prefixedData = ethUtil.addHexPrefix(data) const fourBytePrefix = prefixedData.slice(0, 10) const sig = await registry.lookup(fourBytePrefix) @@ -44,7 +45,11 @@ export function isConfirmDeployContract (txData = {}) { } export async function getTransactionActionKey (transaction, methodData) { - const { txParams: { data, to } = {}, msgParams } = transaction + const { txParams: { data, to } = {}, msgParams, type } = transaction + + if (type === 'cancel') { + return CANCEL_ATTEMPT_ACTION_KEY + } if (msgParams) { return SIGNATURE_REQUEST_KEY diff --git a/ui/app/higher-order-components/with-modal-props/index.js b/ui/app/higher-order-components/with-modal-props/index.js new file mode 100644 index 000000000..e476b51d2 --- /dev/null +++ b/ui/app/higher-order-components/with-modal-props/index.js @@ -0,0 +1 @@ +export { default } from './with-modal-props' diff --git a/ui/app/higher-order-components/with-modal-props/tests/with-modal-props.test.js b/ui/app/higher-order-components/with-modal-props/tests/with-modal-props.test.js new file mode 100644 index 000000000..654e7062a --- /dev/null +++ b/ui/app/higher-order-components/with-modal-props/tests/with-modal-props.test.js @@ -0,0 +1,43 @@ + +import assert from 'assert' +import configureMockStore from 'redux-mock-store' +import { mount } from 'enzyme' +import React from 'react' +import withModalProps from '../with-modal-props' + +const mockState = { + appState: { + modal: { + modalState: { + props: { + prop1: 'prop1', + prop2: 2, + prop3: true, + }, + }, + }, + }, +} + +describe('withModalProps', () => { + it('should return a component wrapped with modal state props', () => { + const TestComponent = props => ( + <div className="test">Testing</div> + ) + const WrappedComponent = withModalProps(TestComponent) + const store = configureMockStore()(mockState) + const wrapper = mount( + <WrappedComponent store={store} /> + ) + + assert.ok(wrapper) + const testComponent = wrapper.find(TestComponent).at(0) + assert.equal(testComponent.length, 1) + assert.equal(testComponent.find('.test').text(), 'Testing') + const testComponentProps = testComponent.props() + assert.equal(testComponentProps.prop1, 'prop1') + assert.equal(testComponentProps.prop2, 2) + assert.equal(testComponentProps.prop3, true) + assert.equal(typeof testComponentProps.hideModal, 'function') + }) +}) diff --git a/ui/app/higher-order-components/with-modal-props/with-modal-props.js b/ui/app/higher-order-components/with-modal-props/with-modal-props.js new file mode 100644 index 000000000..02f3855af --- /dev/null +++ b/ui/app/higher-order-components/with-modal-props/with-modal-props.js @@ -0,0 +1,21 @@ +import { connect } from 'react-redux' +import { hideModal } from '../../actions' + +const mapStateToProps = state => { + const { appState } = state + const { props: modalProps } = appState.modal.modalState + + return { + ...modalProps, + } +} + +const mapDispatchToProps = dispatch => { + return { + hideModal: () => dispatch(hideModal()), + } +} + +export default function withModalProps (Component) { + return connect(mapStateToProps, mapDispatchToProps)(Component) +} |