aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.circleci/config.yml15
-rw-r--r--CHANGELOG.md3
-rw-r--r--app/_locales/en/messages.json33
-rw-r--r--app/images/copy-to-clipboard.svg24
-rw-r--r--app/images/download.svg41
-rw-r--r--app/images/warning.svg22
-rw-r--r--app/manifest.json2
-rw-r--r--app/scripts/background.js6
-rw-r--r--app/scripts/contentscript.js1
-rw-r--r--app/scripts/controllers/token-rates.js6
-rw-r--r--app/scripts/controllers/transactions/README.md92
-rw-r--r--app/scripts/controllers/transactions/index.js (renamed from app/scripts/controllers/transactions.js)332
-rw-r--r--app/scripts/controllers/transactions/lib/tx-state-history-helper.js (renamed from app/scripts/lib/tx-state-history-helper.js)27
-rw-r--r--app/scripts/controllers/transactions/lib/util.js99
-rw-r--r--app/scripts/controllers/transactions/nonce-tracker.js (renamed from app/scripts/lib/nonce-tracker.js)44
-rw-r--r--app/scripts/controllers/transactions/pending-tx-tracker.js (renamed from app/scripts/lib/pending-tx-tracker.js)77
-rw-r--r--app/scripts/controllers/transactions/tx-gas-utils.js (renamed from app/scripts/lib/tx-gas-utils.js)36
-rw-r--r--app/scripts/controllers/transactions/tx-state-manager.js (renamed from app/scripts/lib/tx-state-manager.js)207
-rw-r--r--app/scripts/lib/config-manager.js22
-rw-r--r--app/scripts/lib/setupRaven.js61
-rw-r--r--app/scripts/metamask-controller.js2
-rw-r--r--app/scripts/migrations/018.js2
-rw-r--r--development/sourcemap-validator.js49
-rw-r--r--docs/transaction-flow.pngbin0 -> 141125 bytes
-rw-r--r--gulpfile.js22
-rw-r--r--mascara/src/app/first-time/import-account-screen.js4
-rw-r--r--mascara/src/app/first-time/seed-screen.js71
-rw-r--r--old-ui/app/accounts/import/json.js2
-rw-r--r--old-ui/app/accounts/import/private-key.js2
-rw-r--r--old-ui/app/components/pending-tx.js3
-rw-r--r--old-ui/app/components/shapeshift-form.js2
-rw-r--r--package-lock.json2624
-rw-r--r--package.json15
-rw-r--r--test/integration/lib/send-new-ui.js59
-rw-r--r--test/stub/provider.js24
-rw-r--r--test/unit/metamask-controller-test.js33
-rw-r--r--test/unit/nonce-tracker-test.js2
-rw-r--r--test/unit/pending-tx-test.js2
-rw-r--r--test/unit/tx-controller-test.js121
-rw-r--r--test/unit/tx-gas-util-test.js83
-rw-r--r--test/unit/tx-state-history-helper-test.js2
-rw-r--r--test/unit/tx-state-history-helper.js2
-rw-r--r--test/unit/tx-state-manager-test.js4
-rw-r--r--test/unit/tx-utils-test.js145
-rw-r--r--ui/app/actions.js122
-rw-r--r--ui/app/app.js16
-rw-r--r--ui/app/components/customize-gas-modal/index.js4
-rw-r--r--ui/app/components/export-text-container/export-text-container.component.js45
-rw-r--r--ui/app/components/export-text-container/export-text-container.scss52
-rw-r--r--ui/app/components/export-text-container/index.js2
-rw-r--r--ui/app/components/pages/add-token.js2
-rw-r--r--ui/app/components/pages/create-account/import-account/json.js2
-rw-r--r--ui/app/components/pages/create-account/import-account/private-key.js2
-rw-r--r--ui/app/components/pages/home.js4
-rw-r--r--ui/app/components/pages/keychains/reveal-seed.js259
-rw-r--r--ui/app/components/pending-tx/index.js38
-rw-r--r--ui/app/components/send/currency-display.js15
-rw-r--r--ui/app/components/send/send-constants.js4
-rw-r--r--ui/app/components/shapeshift-form.js13
-rw-r--r--ui/app/css/itcss/components/index.scss2
-rw-r--r--ui/app/css/itcss/components/pages/index.scss2
-rw-r--r--ui/app/css/itcss/components/pages/reveal-seed.scss17
-rw-r--r--ui/app/css/itcss/generic/index.scss67
-rw-r--r--ui/app/css/itcss/settings/variables.scss1
-rw-r--r--ui/app/keychains/hd/recover-seed/confirmation.js138
-rw-r--r--ui/app/send-v2.js2
-rw-r--r--ui/app/token-util.js46
67 files changed, 4049 insertions, 1231 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 6ed731225..88a611af3 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -15,6 +15,9 @@ workflows:
- test-lint:
requires:
- prep-deps-npm
+ - test-deps:
+ requires:
+ - prep-deps-npm
- test-e2e:
requires:
- prep-deps-npm
@@ -43,6 +46,7 @@ workflows:
- all-tests-pass:
requires:
- test-lint
+ - test-deps
- test-unit
- test-e2e
- test-integration-mascara-chrome
@@ -145,6 +149,17 @@ jobs:
name: Test
command: npm run lint
+ test-deps:
+ docker:
+ - image: circleci/node:8-browsers
+ steps:
+ - checkout
+ - restore_cache:
+ key: dependency-cache-{{ .Revision }}
+ - run:
+ name: Test
+ command: npx nsp check
+
test-e2e:
docker:
- image: circleci/node:8-browsers
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3e2b481de..0bb50fd5b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,11 +2,14 @@
## Current Master
+## 4.6.0 Thu Apr 26 2018
+
- Correctly format currency conversion for locally selected preferred currency.
- Improved performance of 3D fox logo.
- Fetch token prices based on contract address, not symbol
- Fix bug that prevents setting language locale in settings.
- Show checksum addresses throughout the UI
+- Allow transactions with a 0 gwei gas price
## 4.5.5 Fri Apr 06 2018
diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json
index 3b20ab49a..a40c2635c 100644
--- a/app/_locales/en/messages.json
+++ b/app/_locales/en/messages.json
@@ -98,6 +98,9 @@
"clickCopy": {
"message": "Click to Copy"
},
+ "close": {
+ "message": "Close"
+ },
"confirm": {
"message": "Confirm"
},
@@ -259,6 +262,9 @@
"enterPasswordConfirm": {
"message": "Enter your password to confirm"
},
+ "enterPasswordContinue": {
+ "message": "Enter password to continue"
+ },
"passwordNotLongEnough": {
"message": "Password not long enough"
},
@@ -331,6 +337,9 @@
"gasPriceRequired": {
"message": "Gas Price Required"
},
+ "generatingTransaction": {
+ "message": "Generating transaction"
+ },
"getEther": {
"message": "Get Ether"
},
@@ -476,6 +485,9 @@
"metamaskDescription": {
"message": "MetaMask is a secure identity vault for Ethereum."
},
+ "metamaskSeedWords": {
+ "message": "MetaMask Seed Words"
+ },
"min": {
"message": "Minimum"
},
@@ -549,6 +561,9 @@
"message": "or",
"description": "choice between creating or importing a new account"
},
+ "password": {
+ "message": "Password"
+ },
"passwordCorrect": {
"message": "Please make sure your password is correct."
},
@@ -634,8 +649,17 @@
"revealSeedWords": {
"message": "Reveal Seed Words"
},
+ "revealSeedWordsTitle": {
+ "message": "Seed Phrase"
+ },
+ "revealSeedWordsDescription": {
+ "message": "If you ever change browsers or move computers, you will need this seed phrase to access your accounts. Save them somewhere safe and secret."
+ },
+ "revealSeedWordsWarningTitle": {
+ "message": "DO NOT share this phrase with anyone!"
+ },
"revealSeedWordsWarning": {
- "message": "Do not recover your seed words in a public place! These words can be used to steal all your accounts."
+ "message": "These words can be used to steal all your accounts."
},
"revert": {
"message": "Revert"
@@ -677,6 +701,9 @@
"reprice_subtitle": {
"message": "Increase your gas price to attempt to overwrite and speed up your transaction"
},
+ "saveAsCsvFile": {
+ "message": "Save as CSV File"
+ },
"saveAsFile": {
"message": "Save as File",
"description": "Account export process"
@@ -909,7 +936,7 @@
"youSign": {
"message": "You are signing"
},
- "generatingTransaction": {
- "message": "Generating transaction"
+ "yourPrivateSeedPhrase": {
+ "message": "Your private seed phrase"
}
}
diff --git a/app/images/copy-to-clipboard.svg b/app/images/copy-to-clipboard.svg
new file mode 100644
index 000000000..c67c2aa84
--- /dev/null
+++ b/app/images/copy-to-clipboard.svg
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="18px" height="17px" viewBox="0 0 18 17" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <!-- Generator: sketchtool 49.3 (51167) - http://www.bohemiancoding.com/sketch -->
+ <title>374E58A5-C29E-4921-83E7-889FA06D6408</title>
+ <desc>Created with sketchtool.</desc>
+ <defs></defs>
+ <g id="Reveal-Seedphrase" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+ <g id="Seed-phrase-2" transform="translate(-39.000000, -379.000000)">
+ <g id="Group-2">
+ <g id="Group-8" transform="translate(16.000000, 248.000000)">
+ <g id="Group-6" transform="translate(23.336478, 120.000000)">
+ <g id="Group-5" transform="translate(0.408805, 11.000000)">
+ <g id="copy-to-clipboard">
+ <rect id="Rectangle-18" stroke="#3098DC" stroke-width="2" x="1" y="1" width="12.0220126" height="12"></rect>
+ <rect id="Rectangle-18-Copy-2" fill="#FFFFFF" x="2.1572327" y="2" width="14.0220126" height="14"></rect>
+ <rect id="Rectangle-18-Copy" stroke="#3098DC" stroke-width="2" x="4.23584906" y="4" width="12.0220126" height="12"></rect>
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+</svg> \ No newline at end of file
diff --git a/app/images/download.svg b/app/images/download.svg
index 137a1190e..b55066414 100644
--- a/app/images/download.svg
+++ b/app/images/download.svg
@@ -1,15 +1,26 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<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"
- width="24.088px" height="24px" viewBox="138.01 0 24.088 24" enable-background="new 138.01 0 24.088 24" xml:space="preserve" fill="#F7861C">
-<g>
- <polygon fill="#F7861C" points="157.551,17.075 156.55,17.075 156.55,19.149 142.569,19.149 142.569,17.075 141.568,17.075
- 141.568,20.145 141.955,20.145 141.955,20.15 157.006,20.15 157.006,20.145 157.551,20.145 "/>
- <polygon fill="#F7861C" points="152.555,10.275 152.555,11.26 152.555,11.268 151.562,11.268 151.562,12.252 150.565,12.252
- 150.565,4.171 149.564,4.171 149.564,12.236 148.564,12.236 148.564,11.252 147.564,11.252 147.564,11.236 147.564,11.221
- 147.564,10.236 146.563,10.236 146.563,11.221 146.563,11.236 146.563,12.221 147.563,12.221 147.563,12.236 147.563,12.252
- 147.563,13.236 148.563,13.236 148.563,14.221 149.564,14.221 149.564,15.725 150.565,15.725 150.565,14.236 151.563,14.236
- 151.563,13.252 152.563,13.252 152.563,12.268 152.563,12.26 153.556,12.26 153.556,11.275 153.556,11.26 153.556,10.275 "/>
-</g>
-</svg>
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="20px" height="18px" viewBox="0 0 20 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <!-- Generator: sketchtool 49.3 (51167) - http://www.bohemiancoding.com/sketch -->
+ <title>50559280-0739-419A-8E87-3CDD16A6996A</title>
+ <desc>Created with sketchtool.</desc>
+ <defs></defs>
+ <g id="Reveal-Seedphrase" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+ <g id="Seed-phrase-2" transform="translate(-212.000000, -379.000000)" stroke="#259DE5" stroke-width="2">
+ <g id="Group-2">
+ <g id="Group-8" transform="translate(16.000000, 248.000000)">
+ <g id="Group-6" transform="translate(23.336478, 120.000000)">
+ <g id="Group-3" transform="translate(174.000000, 11.000000)">
+ <g id="Group-4">
+ <g id="download">
+ <polyline id="Path-5" points="0 11 0 17 17 17 17 11"></polyline>
+ <path d="M8.5,0 L8.5,11" id="Path-6"></path>
+ <polyline id="Path-7" points="3.1875 7 8.5 11 13.8125 7"></polyline>
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+</svg> \ No newline at end of file
diff --git a/app/images/warning.svg b/app/images/warning.svg
new file mode 100644
index 000000000..9c8d697d7
--- /dev/null
+++ b/app/images/warning.svg
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="33px" height="32px" viewBox="0 0 33 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <!-- Generator: Sketch 49.3 (51167) - http://www.bohemiancoding.com/sketch -->
+ <title>Group 7</title>
+ <desc>Created with Sketch.</desc>
+ <defs></defs>
+ <g id="Reveal-Seedphrase" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+ <g id="Seed-phrase-2" transform="translate(-29.000000, -155.000000)">
+ <g id="Group-2" transform="translate(0.000000, 132.000000)">
+ <g id="Group" transform="translate(28.000000, 19.000000)">
+ <g id="Group-19-Copy-2" transform="translate(0.000000, 3.000000)">
+ <g id="Group-7">
+ <path d="M20.1321134,3.85444772 L32.5721829,26.6020033 C33.367162,28.0556794 32.8331826,29.8785746 31.3795065,30.6735537 C30.9381289,30.9149321 30.4431378,31.0414403 29.9400695,31.0414403 L5.05993054,31.0414403 C3.40307629,31.0414403 2.05993054,29.6982946 2.05993054,28.0414403 C2.05993054,27.538372 2.18643873,27.0433809 2.42781712,26.6020033 L14.8678866,3.85444772 C15.6628657,2.40077162 17.4857609,1.86679221 18.939437,2.66177133 C19.442875,2.93708896 19.8567958,3.35100977 20.1321134,3.85444772 Z" id="Triangle-2-Copy" stroke="#FF001F" stroke-width="2"></path>
+ <rect id="Rectangle-5" fill="#FF001F" x="16" y="9" width="3" height="13"></rect>
+ <rect id="Rectangle-5-Copy" fill="#FF001F" x="16" y="24" width="3" height="3"></rect>
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+</svg> \ No newline at end of file
diff --git a/app/manifest.json b/app/manifest.json
index dc46f1ca4..3e5eed205 100644
--- a/app/manifest.json
+++ b/app/manifest.json
@@ -1,7 +1,7 @@
{
"name": "__MSG_appName__",
"short_name": "__MSG_appName__",
- "version": "4.5.5",
+ "version": "4.6.0",
"manifest_version": 2,
"author": "https://metamask.io",
"description": "__MSG_appDescription__",
diff --git a/app/scripts/background.js b/app/scripts/background.js
index 38b871bb5..69d549c85 100644
--- a/app/scripts/background.js
+++ b/app/scripts/background.js
@@ -261,7 +261,11 @@ function setupController (initState, initLangCode) {
controller.txController.on(`tx:status-update`, (txId, status) => {
if (status !== 'failed') return
const txMeta = controller.txController.txStateManager.getTx(txId)
- reportFailedTxToSentry({ raven, txMeta })
+ try {
+ reportFailedTxToSentry({ raven, txMeta })
+ } catch (e) {
+ console.error(e)
+ }
})
// setup state persistence
diff --git a/app/scripts/contentscript.js b/app/scripts/contentscript.js
index dbf1c6d4c..ddf1a9432 100644
--- a/app/scripts/contentscript.js
+++ b/app/scripts/contentscript.js
@@ -174,6 +174,7 @@ function blacklistedDomainCheck () {
'uscourts.gov',
'dropbox.com',
'webbyawards.com',
+ 'cdn.shopify.com/s/javascripts/tricorder/xtld-read-only-frame.html',
]
var currentUrl = window.location.href
var currentRegex
diff --git a/app/scripts/controllers/token-rates.js b/app/scripts/controllers/token-rates.js
index abeec4cc0..87d716aa6 100644
--- a/app/scripts/controllers/token-rates.js
+++ b/app/scripts/controllers/token-rates.js
@@ -1,4 +1,5 @@
const ObservableStore = require('obs-store')
+const { warn } = require('loglevel')
// By default, poll every 3 minutes
const DEFAULT_INTERVAL = 180 * 1000
@@ -42,7 +43,10 @@ class TokenRatesController {
const response = await fetch(`https://metamask.balanc3.net/prices?from=${address}&to=ETH&autoConversion=false&summaryOnly=true`)
const json = await response.json()
return json && json.length ? json[0].averagePrice : 0
- } catch (error) { }
+ } catch (error) {
+ warn(`MetaMask - TokenRatesController exchange rate fetch failed for ${address}.`, error)
+ return 0
+ }
}
/**
diff --git a/app/scripts/controllers/transactions/README.md b/app/scripts/controllers/transactions/README.md
new file mode 100644
index 000000000..b414762dc
--- /dev/null
+++ b/app/scripts/controllers/transactions/README.md
@@ -0,0 +1,92 @@
+# Transaction Controller
+
+Transaction Controller is an aggregate of sub-controllers and trackers
+exposed to the MetaMask controller.
+
+- txStateManager
+ responsible for the state of a transaction and
+ storing the transaction
+- pendingTxTracker
+ watching blocks for transactions to be include
+ and emitting confirmed events
+- txGasUtil
+ gas calculations and safety buffering
+- nonceTracker
+ calculating nonces
+
+## Flow diagram of processing a transaction
+
+![transaction-flow](../../../../docs/transaction-flow.png)
+
+## txMeta's & txParams
+
+A txMeta is the "meta" object it has all the random bits of info we need about a transaction on it. txParams are sacred every thing on txParams gets signed so it must
+be a valid key and be hex prefixed except for the network number. Extra stuff must go on the txMeta!
+
+Here is a txMeta too look at:
+
+```js
+txMeta = {
+ "id": 2828415030114568, // unique id for this txMeta used for look ups
+ "time": 1524094064821, // time of creation
+ "status": "confirmed",
+ "metamaskNetworkId": "1524091532133", //the network id for the transaction
+ "loadingDefaults": false, // used to tell the ui when we are done calculatyig gass defaults
+ "txParams": { // the txParams object
+ "from": "0x8acce2391c0d510a6c5e5d8f819a678f79b7e675",
+ "to": "0x8acce2391c0d510a6c5e5d8f819a678f79b7e675",
+ "value": "0x0",
+ "gasPrice": "0x3b9aca00",
+ "gas": "0x7b0c",
+ "nonce": "0x0"
+ },
+ "history": [{ //debug
+ "id": 2828415030114568,
+ "time": 1524094064821,
+ "status": "unapproved",
+ "metamaskNetworkId": "1524091532133",
+ "loadingDefaults": true,
+ "txParams": {
+ "from": "0x8acce2391c0d510a6c5e5d8f819a678f79b7e675",
+ "to": "0x8acce2391c0d510a6c5e5d8f819a678f79b7e675",
+ "value": "0x0"
+ }
+ },
+ [
+ {
+ "op": "add",
+ "path": "/txParams/gasPrice",
+ "value": "0x3b9aca00"
+ },
+ ...], // I've removed most of history for this
+ "gasPriceSpecified": false, //whether or not the user/dapp has specified gasPrice
+ "gasLimitSpecified": false, //whether or not the user/dapp has specified gas
+ "estimatedGas": "5208",
+ "origin": "MetaMask", //debug
+ "nonceDetails": {
+ "params": {
+ "highestLocallyConfirmed": 0,
+ "highestSuggested": 0,
+ "nextNetworkNonce": 0
+ },
+ "local": {
+ "name": "local",
+ "nonce": 0,
+ "details": {
+ "startPoint": 0,
+ "highest": 0
+ }
+ },
+ "network": {
+ "name": "network",
+ "nonce": 0,
+ "details": {
+ "baseCount": 0
+ }
+ }
+ },
+ "rawTx": "0xf86980843b9aca00827b0c948acce2391c0d510a6c5e5d8f819a678f79b7e67580808602c5b5de66eea05c01a320b96ac730cb210ca56d2cb71fa360e1fc2c21fa5cf333687d18eb323fa02ed05987a6e5fd0f2459fcff80710b76b83b296454ad9a37594a0ccb4643ea90", // used for rebroadcast
+ "hash": "0xa45ba834b97c15e6ff4ed09badd04ecd5ce884b455eb60192cdc73bcc583972a",
+ "submittedTime": 1524094077902 // time of the attempt to submit the raw tx to the network, used in the ui to show the retry button
+}
+```
diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions/index.js
index c8211ebd7..541f1db73 100644
--- a/app/scripts/controllers/transactions.js
+++ b/app/scripts/controllers/transactions/index.js
@@ -3,28 +3,42 @@ const ObservableStore = require('obs-store')
const ethUtil = require('ethereumjs-util')
const Transaction = require('ethereumjs-tx')
const EthQuery = require('ethjs-query')
-const TransactionStateManager = require('../lib/tx-state-manager')
-const TxGasUtil = require('../lib/tx-gas-utils')
-const PendingTransactionTracker = require('../lib/pending-tx-tracker')
-const NonceTracker = require('../lib/nonce-tracker')
+const TransactionStateManager = require('./tx-state-manager')
+const TxGasUtil = require('./tx-gas-utils')
+const PendingTransactionTracker = require('./pending-tx-tracker')
+const NonceTracker = require('./nonce-tracker')
+const txUtils = require('./lib/util')
const log = require('loglevel')
-/*
+/**
Transaction Controller is an aggregate of sub-controllers and trackers
composing them in a way to be exposed to the metamask controller
- - txStateManager
+ <br>- txStateManager
responsible for the state of a transaction and
storing the transaction
- - pendingTxTracker
+ <br>- pendingTxTracker
watching blocks for transactions to be include
and emitting confirmed events
- - txGasUtil
+ <br>- txGasUtil
gas calculations and safety buffering
- - nonceTracker
+ <br>- nonceTracker
calculating nonces
+
+
+ @class
+ @param {object} - opts
+ @param {object} opts.initState - initial transaction list default is an empty array
+ @param {Object} opts.networkStore - an observable store for network number
+ @param {Object} opts.blockTracker - An instance of eth-blocktracker
+ @param {Object} opts.provider - A network provider.
+ @param {Function} opts.signTransaction - function the signs an ethereumjs-tx
+ @param {Function} [opts.getGasPrice] - optional gas price calculator
+ @param {Function} opts.signTransaction - ethTx signer that returns a rawTx
+ @param {Number} [opts.txHistoryLimit] - number *optional* for limiting how many transactions are in state
+ @param {Object} opts.preferencesStore
*/
-module.exports = class TransactionController extends EventEmitter {
+class TransactionController extends EventEmitter {
constructor (opts) {
super()
this.networkStore = opts.networkStore || new ObservableStore({})
@@ -38,45 +52,19 @@ module.exports = class TransactionController extends EventEmitter {
this.query = new EthQuery(this.provider)
this.txGasUtil = new TxGasUtil(this.provider)
+ this._mapMethods()
this.txStateManager = new TransactionStateManager({
initState: opts.initState,
txHistoryLimit: opts.txHistoryLimit,
getNetwork: this.getNetwork.bind(this),
})
-
- this.txStateManager.getFilteredTxList({
- status: 'unapproved',
- loadingDefaults: true,
- }).forEach((tx) => {
- this.addTxDefaults(tx)
- .then((txMeta) => {
- txMeta.loadingDefaults = false
- this.txStateManager.updateTx(txMeta, 'transactions: gas estimation for tx on boot')
- }).catch((error) => {
- this.txStateManager.setTxStatusFailed(tx.id, error)
- })
- })
-
- this.txStateManager.getFilteredTxList({
- status: 'approved',
- }).forEach((txMeta) => {
- const txSignError = new Error('Transaction found as "approved" during boot - possibly stuck during signing')
- this.txStateManager.setTxStatusFailed(txMeta.id, txSignError)
- })
-
+ this._onBootCleanUp()
this.store = this.txStateManager.store
- this.txStateManager.on('tx:status-update', this.emit.bind(this, 'tx:status-update'))
this.nonceTracker = new NonceTracker({
provider: this.provider,
getPendingTransactions: this.txStateManager.getPendingTransactions.bind(this.txStateManager),
- getConfirmedTransactions: (address) => {
- return this.txStateManager.getFilteredTxList({
- from: address,
- status: 'confirmed',
- err: undefined,
- })
- },
+ getConfirmedTransactions: this.txStateManager.getConfirmedTransactions.bind(this.txStateManager),
})
this.pendingTxTracker = new PendingTransactionTracker({
@@ -88,60 +76,14 @@ module.exports = class TransactionController extends EventEmitter {
})
this.txStateManager.store.subscribe(() => this.emit('update:badge'))
-
- this.pendingTxTracker.on('tx:warning', (txMeta) => {
- this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:warning')
- })
- this.pendingTxTracker.on('tx:confirmed', (txId) => this._markNonceDuplicatesDropped(txId))
- this.pendingTxTracker.on('tx:failed', this.txStateManager.setTxStatusFailed.bind(this.txStateManager))
- this.pendingTxTracker.on('tx:block-update', (txMeta, latestBlockNumber) => {
- if (!txMeta.firstRetryBlockNumber) {
- txMeta.firstRetryBlockNumber = latestBlockNumber
- this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:block-update')
- }
- })
- this.pendingTxTracker.on('tx:retry', (txMeta) => {
- if (!('retryCount' in txMeta)) txMeta.retryCount = 0
- txMeta.retryCount++
- this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:retry')
- })
-
- this.blockTracker.on('block', this.pendingTxTracker.checkForTxInBlock.bind(this.pendingTxTracker))
- // this is a little messy but until ethstore has been either
- // removed or redone this is to guard against the race condition
- this.blockTracker.on('latest', this.pendingTxTracker.resubmitPendingTxs.bind(this.pendingTxTracker))
- this.blockTracker.on('sync', this.pendingTxTracker.queryPendingTxs.bind(this.pendingTxTracker))
+ this._setupListners()
// memstore is computed from a few different stores
this._updateMemstore()
this.txStateManager.store.subscribe(() => this._updateMemstore())
this.networkStore.subscribe(() => this._updateMemstore())
this.preferencesStore.subscribe(() => this._updateMemstore())
}
-
- getState () {
- return this.memStore.getState()
- }
-
- getNetwork () {
- return this.networkStore.getState()
- }
-
- getSelectedAddress () {
- return this.preferencesStore.getState().selectedAddress
- }
-
- getUnapprovedTxCount () {
- return Object.keys(this.txStateManager.getUnapprovedTxList()).length
- }
-
- getPendingTxCount (account) {
- return this.txStateManager.getPendingTransactions(account).length
- }
-
- getFilteredTxList (opts) {
- return this.txStateManager.getFilteredTxList(opts)
- }
-
+ /** @returns {number} the chainId*/
getChainId () {
const networkState = this.networkStore.getState()
const getChainId = parseInt(networkState)
@@ -152,16 +94,30 @@ module.exports = class TransactionController extends EventEmitter {
}
}
- wipeTransactions (address) {
- this.txStateManager.wipeTransactions(address)
- }
-
- // Adds a tx to the txlist
+/**
+ Adds a tx to the txlist
+ @emits ${txMeta.id}:unapproved
+*/
addTx (txMeta) {
this.txStateManager.addTx(txMeta)
this.emit(`${txMeta.id}:unapproved`, txMeta)
}
+ /**
+ Wipes the transactions for a given account
+ @param {string} address - hex string of the from address for txs being removed
+ */
+ wipeTransactions (address) {
+ this.txStateManager.wipeTransactions(address)
+ }
+
+ /**
+ add a new unapproved transaction to the pipeline
+
+ @returns {Promise<string>} the hash of the transaction after being submitted to the network
+ @param txParams {object} - txParams for the transaction
+ @param opts {object} - with the key origin to put the origin on the txMeta
+ */
async newUnapprovedTransaction (txParams, opts = {}) {
log.debug(`MetaMaskController newUnapprovedTransaction ${JSON.stringify(txParams)}`)
const initialTxMeta = await this.addUnapprovedTransaction(txParams)
@@ -184,17 +140,24 @@ module.exports = class TransactionController extends EventEmitter {
})
}
+ /**
+ Validates and generates a txMeta with defaults and puts it in txStateManager
+ store
+
+ @returns {txMeta}
+ */
+
async addUnapprovedTransaction (txParams) {
// validate
- const normalizedTxParams = this._normalizeTxParams(txParams)
- this._validateTxParams(normalizedTxParams)
+ const normalizedTxParams = txUtils.normalizeTxParams(txParams)
+ txUtils.validateTxParams(normalizedTxParams)
// construct txMeta
let txMeta = this.txStateManager.generateTxMeta({ txParams: normalizedTxParams })
this.addTx(txMeta)
this.emit('newUnapprovedTx', txMeta)
// add default tx params
try {
- txMeta = await this.addTxDefaults(txMeta)
+ txMeta = await this.addTxGasDefaults(txMeta)
} catch (error) {
console.log(error)
this.txStateManager.setTxStatusFailed(txMeta.id, error)
@@ -206,21 +169,33 @@ module.exports = class TransactionController extends EventEmitter {
return txMeta
}
-
- async addTxDefaults (txMeta) {
+/**
+ adds the tx gas defaults: gas && gasPrice
+ @param txMeta {Object} - the txMeta object
+ @returns {Promise<object>} resolves with txMeta
+*/
+ async addTxGasDefaults (txMeta) {
const txParams = txMeta.txParams
// ensure value
+ txParams.value = txParams.value ? ethUtil.addHexPrefix(txParams.value) : '0x0'
txMeta.gasPriceSpecified = Boolean(txParams.gasPrice)
let gasPrice = txParams.gasPrice
if (!gasPrice) {
gasPrice = this.getGasPrice ? this.getGasPrice() : await this.query.gasPrice()
}
txParams.gasPrice = ethUtil.addHexPrefix(gasPrice.toString(16))
- txParams.value = txParams.value || '0x0'
// set gasLimit
return await this.txGasUtil.analyzeGasUsage(txMeta)
}
+ /**
+ Creates a new txMeta with the same txParams as the original
+ to allow the user to resign the transaction with a higher gas values
+ @param originalTxId {number} - the id of the txMeta that
+ you want to attempt to retry
+ @return {txMeta}
+ */
+
async retryTransaction (originalTxId) {
const originalTxMeta = this.txStateManager.getTx(originalTxId)
const lastGasPrice = originalTxMeta.txParams.gasPrice
@@ -234,15 +209,31 @@ module.exports = class TransactionController extends EventEmitter {
return txMeta
}
+ /**
+ updates the txMeta in the txStateManager
+ @param txMeta {Object} - the updated txMeta
+ */
async updateTransaction (txMeta) {
this.txStateManager.updateTx(txMeta, 'confTx: user updated transaction')
}
+ /**
+ updates and approves the transaction
+ @param txMeta {Object}
+ */
async updateAndApproveTransaction (txMeta) {
this.txStateManager.updateTx(txMeta, 'confTx: user approved transaction')
await this.approveTransaction(txMeta.id)
}
+ /**
+ sets the tx status to approved
+ auto fills the nonce
+ signs the transaction
+ publishes the transaction
+ if any of these steps fails the tx status will be set to failed
+ @param txId {number} - the tx's Id
+ */
async approveTransaction (txId) {
let nonceLock
try {
@@ -274,7 +265,11 @@ module.exports = class TransactionController extends EventEmitter {
throw err
}
}
-
+ /**
+ adds the chain id and signs the transaction and set the status to signed
+ @param txId {number} - the tx's Id
+ @returns - rawTx {string}
+ */
async signTransaction (txId) {
const txMeta = this.txStateManager.getTx(txId)
// add network/chain id
@@ -290,6 +285,12 @@ module.exports = class TransactionController extends EventEmitter {
return rawTx
}
+ /**
+ publishes the raw tx and sets the txMeta to submitted
+ @param txId {number} - the tx's Id
+ @param rawTx {string} - the hex string of the serialized signed transaction
+ @returns {Promise<void>}
+ */
async publishTransaction (txId, rawTx) {
const txMeta = this.txStateManager.getTx(txId)
txMeta.rawTx = rawTx
@@ -299,11 +300,20 @@ module.exports = class TransactionController extends EventEmitter {
this.txStateManager.setTxStatusSubmitted(txId)
}
+ /**
+ Convenience method for the ui thats sets the transaction to rejected
+ @param txId {number} - the tx's Id
+ @returns {Promise<void>}
+ */
async cancelTransaction (txId) {
this.txStateManager.setTxStatusRejected(txId)
}
- // receives a txHash records the tx as signed
+ /**
+ Sets the txHas on the txMeta
+ @param txId {number} - the tx's Id
+ @param txHash {string} - the hash for the txMeta
+ */
setTxHash (txId, txHash) {
// Add the tx hash to the persisted meta-tx object
const txMeta = this.txStateManager.getTx(txId)
@@ -314,63 +324,92 @@ module.exports = class TransactionController extends EventEmitter {
//
// PRIVATE METHODS
//
+ /** maps methods for convenience*/
+ _mapMethods () {
+ /** @returns the state in transaction controller */
+ this.getState = () => this.memStore.getState()
+ /** @returns the network number stored in networkStore */
+ this.getNetwork = () => this.networkStore.getState()
+ /** @returns the user selected address */
+ this.getSelectedAddress = () => this.preferencesStore.getState().selectedAddress
+ /** Returns an array of transactions whos status is unapproved */
+ this.getUnapprovedTxCount = () => Object.keys(this.txStateManager.getUnapprovedTxList()).length
+ /**
+ @returns a number that represents how many transactions have the status submitted
+ @param account {String} - hex prefixed account
+ */
+ this.getPendingTxCount = (account) => this.txStateManager.getPendingTransactions(account).length
+ /** see txStateManager */
+ this.getFilteredTxList = (opts) => this.txStateManager.getFilteredTxList(opts)
+ }
- _normalizeTxParams (txParams) {
- // functions that handle normalizing of that key in txParams
- const whiteList = {
- from: from => ethUtil.addHexPrefix(from).toLowerCase(),
- to: to => ethUtil.addHexPrefix(txParams.to).toLowerCase(),
- nonce: nonce => ethUtil.addHexPrefix(nonce),
- value: value => ethUtil.addHexPrefix(value),
- data: data => ethUtil.addHexPrefix(data),
- gas: gas => ethUtil.addHexPrefix(gas),
- gasPrice: gasPrice => ethUtil.addHexPrefix(gasPrice),
- }
+ /**
+ If transaction controller was rebooted with transactions that are uncompleted
+ in steps of the transaction signing or user confirmation process it will either
+ transition txMetas to a failed state or try to redo those tasks.
+ */
- // apply only keys in the whiteList
- const normalizedTxParams = {}
- Object.keys(whiteList).forEach((key) => {
- if (txParams[key]) normalizedTxParams[key] = whiteList[key](txParams[key])
+ _onBootCleanUp () {
+ this.txStateManager.getFilteredTxList({
+ status: 'unapproved',
+ loadingDefaults: true,
+ }).forEach((tx) => {
+ this.addTxGasDefaults(tx)
+ .then((txMeta) => {
+ txMeta.loadingDefaults = false
+ this.txStateManager.updateTx(txMeta, 'transactions: gas estimation for tx on boot')
+ }).catch((error) => {
+ this.txStateManager.setTxStatusFailed(tx.id, error)
+ })
})
- return normalizedTxParams
+ this.txStateManager.getFilteredTxList({
+ status: 'approved',
+ }).forEach((txMeta) => {
+ const txSignError = new Error('Transaction found as "approved" during boot - possibly stuck during signing')
+ this.txStateManager.setTxStatusFailed(txMeta.id, txSignError)
+ })
}
- _validateTxParams (txParams) {
- this._validateFrom(txParams)
- this._validateRecipient(txParams)
- if ('value' in txParams) {
- const value = txParams.value.toString()
- if (value.includes('-')) {
- throw new Error(`Invalid transaction value of ${txParams.value} not a positive number.`)
+ /**
+ is called in constructor applies the listeners for pendingTxTracker txStateManager
+ and blockTracker
+ */
+ _setupListners () {
+ this.txStateManager.on('tx:status-update', this.emit.bind(this, 'tx:status-update'))
+ this.pendingTxTracker.on('tx:warning', (txMeta) => {
+ this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:warning')
+ })
+ this.pendingTxTracker.on('tx:confirmed', (txId) => this.txStateManager.setTxStatusConfirmed(txId))
+ this.pendingTxTracker.on('tx:confirmed', (txId) => this._markNonceDuplicatesDropped(txId))
+ this.pendingTxTracker.on('tx:failed', this.txStateManager.setTxStatusFailed.bind(this.txStateManager))
+ this.pendingTxTracker.on('tx:block-update', (txMeta, latestBlockNumber) => {
+ if (!txMeta.firstRetryBlockNumber) {
+ txMeta.firstRetryBlockNumber = latestBlockNumber
+ this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:block-update')
}
+ })
+ this.pendingTxTracker.on('tx:retry', (txMeta) => {
+ if (!('retryCount' in txMeta)) txMeta.retryCount = 0
+ txMeta.retryCount++
+ this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:retry')
+ })
- if (value.includes('.')) {
- throw new Error(`Invalid transaction value of ${txParams.value} number must be in wei`)
- }
- }
- }
+ this.blockTracker.on('block', this.pendingTxTracker.checkForTxInBlock.bind(this.pendingTxTracker))
+ // this is a little messy but until ethstore has been either
+ // removed or redone this is to guard against the race condition
+ this.blockTracker.on('latest', this.pendingTxTracker.resubmitPendingTxs.bind(this.pendingTxTracker))
+ this.blockTracker.on('sync', this.pendingTxTracker.queryPendingTxs.bind(this.pendingTxTracker))
- _validateFrom (txParams) {
- if ( !(typeof txParams.from === 'string') ) throw new Error(`Invalid from address ${txParams.from} not a string`)
- if (!ethUtil.isValidAddress(txParams.from)) throw new Error('Invalid from address')
}
- _validateRecipient (txParams) {
- if (txParams.to === '0x' || txParams.to === null ) {
- if (txParams.data) {
- delete txParams.to
- } else {
- throw new Error('Invalid recipient address')
- }
- } else if ( txParams.to !== undefined && !ethUtil.isValidAddress(txParams.to) ) {
- throw new Error('Invalid recipient address')
- }
- return txParams
- }
+ /**
+ Sets other txMeta statuses to dropped if the txMeta that has been confirmed has other transactions
+ in the list have the same nonce
+ @param txId {Number} - the txId of the transaction that has been confirmed in a block
+ */
_markNonceDuplicatesDropped (txId) {
- this.txStateManager.setTxStatusConfirmed(txId)
// get the confirmed transactions nonce and from address
const txMeta = this.txStateManager.getTx(txId)
const { nonce, from } = txMeta.txParams
@@ -385,6 +424,9 @@ module.exports = class TransactionController extends EventEmitter {
})
}
+ /**
+ Updates the memStore in transaction controller
+ */
_updateMemstore () {
const unapprovedTxs = this.txStateManager.getUnapprovedTxList()
const selectedAddressTxList = this.txStateManager.getFilteredTxList({
@@ -394,3 +436,5 @@ module.exports = class TransactionController extends EventEmitter {
this.memStore.updateState({ unapprovedTxs, selectedAddressTxList })
}
}
+
+module.exports = TransactionController
diff --git a/app/scripts/lib/tx-state-history-helper.js b/app/scripts/controllers/transactions/lib/tx-state-history-helper.js
index 94c7b6792..59a4b562c 100644
--- a/app/scripts/lib/tx-state-history-helper.js
+++ b/app/scripts/controllers/transactions/lib/tx-state-history-helper.js
@@ -1,6 +1,6 @@
const jsonDiffer = require('fast-json-patch')
const clone = require('clone')
-
+/** @module*/
module.exports = {
generateHistoryEntry,
replayHistory,
@@ -8,7 +8,11 @@ module.exports = {
migrateFromSnapshotsToDiffs,
}
-
+/**
+ converts non-initial history entries into diffs
+ @param longHistory {array}
+ @returns {array}
+*/
function migrateFromSnapshotsToDiffs (longHistory) {
return (
longHistory
@@ -20,6 +24,17 @@ function migrateFromSnapshotsToDiffs (longHistory) {
)
}
+/**
+ generates an array of history objects sense the previous state.
+ The object has the keys opp(the operation preformed),
+ path(the key and if a nested object then each key will be seperated with a `/`)
+ value
+ with the first entry having the note
+ @param previousState {object} - the previous state of the object
+ @param newState {object} - the update object
+ @param note {string} - a optional note for the state change
+ @reurns {array}
+*/
function generateHistoryEntry (previousState, newState, note) {
const entry = jsonDiffer.compare(previousState, newState)
// Add a note to the first op, since it breaks if we append it to the entry
@@ -27,11 +42,19 @@ function generateHistoryEntry (previousState, newState, note) {
return entry
}
+/**
+ Recovers previous txMeta state obj
+ @return {object}
+*/
function replayHistory (_shortHistory) {
const shortHistory = clone(_shortHistory)
return shortHistory.reduce((val, entry) => jsonDiffer.applyPatch(val, entry).newDocument)
}
+/**
+ @param txMeta {Object}
+ @returns {object} a clone object of the txMeta with out history
+*/
function snapshotFromTxMeta (txMeta) {
// create txMeta snapshot for history
const snapshot = clone(txMeta)
diff --git a/app/scripts/controllers/transactions/lib/util.js b/app/scripts/controllers/transactions/lib/util.js
new file mode 100644
index 000000000..84f7592a0
--- /dev/null
+++ b/app/scripts/controllers/transactions/lib/util.js
@@ -0,0 +1,99 @@
+const {
+ addHexPrefix,
+ isValidAddress,
+} = require('ethereumjs-util')
+
+/**
+@module
+*/
+module.exports = {
+ normalizeTxParams,
+ validateTxParams,
+ validateFrom,
+ validateRecipient,
+ getFinalStates,
+}
+
+
+// functions that handle normalizing of that key in txParams
+const normalizers = {
+ from: from => addHexPrefix(from).toLowerCase(),
+ to: to => addHexPrefix(to).toLowerCase(),
+ nonce: nonce => addHexPrefix(nonce),
+ value: value => addHexPrefix(value),
+ data: data => addHexPrefix(data),
+ gas: gas => addHexPrefix(gas),
+ gasPrice: gasPrice => addHexPrefix(gasPrice),
+}
+
+ /**
+ normalizes txParams
+ @param txParams {object}
+ @returns {object} normalized txParams
+ */
+function normalizeTxParams (txParams) {
+ // apply only keys in the normalizers
+ const normalizedTxParams = {}
+ for (const key in normalizers) {
+ if (txParams[key]) normalizedTxParams[key] = normalizers[key](txParams[key])
+ }
+ return normalizedTxParams
+}
+
+ /**
+ validates txParams
+ @param txParams {object}
+ */
+function validateTxParams (txParams) {
+ validateFrom(txParams)
+ validateRecipient(txParams)
+ if ('value' in txParams) {
+ const value = txParams.value.toString()
+ if (value.includes('-')) {
+ throw new Error(`Invalid transaction value of ${txParams.value} not a positive number.`)
+ }
+
+ if (value.includes('.')) {
+ throw new Error(`Invalid transaction value of ${txParams.value} number must be in wei`)
+ }
+ }
+}
+
+ /**
+ validates the from field in txParams
+ @param txParams {object}
+ */
+function validateFrom (txParams) {
+ if (!(typeof txParams.from === 'string')) throw new Error(`Invalid from address ${txParams.from} not a string`)
+ if (!isValidAddress(txParams.from)) throw new Error('Invalid from address')
+}
+
+ /**
+ validates the to field in txParams
+ @param txParams {object}
+ */
+function validateRecipient (txParams) {
+ if (txParams.to === '0x' || txParams.to === null) {
+ if (txParams.data) {
+ delete txParams.to
+ } else {
+ throw new Error('Invalid recipient address')
+ }
+ } else if (txParams.to !== undefined && !isValidAddress(txParams.to)) {
+ throw new Error('Invalid recipient address')
+ }
+ return txParams
+}
+
+ /**
+ @returns an {array} of states that can be considered final
+ */
+function getFinalStates () {
+ return [
+ 'rejected', // the user has responded no!
+ 'confirmed', // the tx has been included in a block.
+ 'failed', // the tx failed for some reason, included on tx data.
+ 'dropped', // the tx nonce was already used
+ ]
+}
+
diff --git a/app/scripts/lib/nonce-tracker.js b/app/scripts/controllers/transactions/nonce-tracker.js
index 5b1cd7f43..f8cdc5523 100644
--- a/app/scripts/lib/nonce-tracker.js
+++ b/app/scripts/controllers/transactions/nonce-tracker.js
@@ -1,7 +1,15 @@
const EthQuery = require('ethjs-query')
const assert = require('assert')
const Mutex = require('await-semaphore').Mutex
-
+/**
+ @param opts {Object}
+ @param {Object} opts.provider a ethereum provider
+ @param {Function} opts.getPendingTransactions a function that returns an array of txMeta
+ whosee status is `submitted`
+ @param {Function} opts.getConfirmedTransactions a function that returns an array of txMeta
+ whose status is `confirmed`
+ @class
+*/
class NonceTracker {
constructor ({ provider, getPendingTransactions, getConfirmedTransactions }) {
@@ -12,6 +20,9 @@ class NonceTracker {
this.lockMap = {}
}
+ /**
+ @returns {Promise<Object>} with the key releaseLock (the gloabl mutex)
+ */
async getGlobalLock () {
const globalMutex = this._lookupMutex('global')
// await global mutex free
@@ -19,8 +30,20 @@ class NonceTracker {
return { releaseLock }
}
- // releaseLock must be called
- // releaseLock must be called after adding signed tx to pending transactions (or discarding)
+ /**
+ * @typedef NonceDetails
+ * @property {number} highestLocallyConfirmed - A hex string of the highest nonce on a confirmed transaction.
+ * @property {number} nextNetworkNonce - The next nonce suggested by the eth_getTransactionCount method.
+ * @property {number} highetSuggested - The maximum between the other two, the number returned.
+ */
+
+ /**
+ this will return an object with the `nextNonce` `nonceDetails` of type NonceDetails, and the releaseLock
+ Note: releaseLock must be called after adding a signed tx to pending transactions (or discarding).
+
+ @param address {string} the hex string for the address whose nonce we are calculating
+ @returns {Promise<NonceDetails>}
+ */
async getNonceLock (address) {
// await global mutex free
await this._globalMutexFree()
@@ -123,6 +146,17 @@ class NonceTracker {
return highestNonce
}
+ /**
+ @typedef {object} highestContinuousFrom
+ @property {string} - name the name for how the nonce was calculated based on the data used
+ @property {number} - nonce the next suggested nonce
+ @property {object} - details the provided starting nonce that was used (for debugging)
+ */
+ /**
+ @param txList {array} - list of txMeta's
+ @param startPoint {number} - the highest known locally confirmed nonce
+ @returns {highestContinuousFrom}
+ */
_getHighestContinuousFrom (txList, startPoint) {
const nonces = txList.map((txMeta) => {
const nonce = txMeta.txParams.nonce
@@ -140,6 +174,10 @@ class NonceTracker {
// this is a hotfix for the fact that the blockTracker will
// change when the network changes
+
+ /**
+ @returns {Object} the current blockTracker
+ */
_getBlockTracker () {
return this.provider._blockTracker
}
diff --git a/app/scripts/lib/pending-tx-tracker.js b/app/scripts/controllers/transactions/pending-tx-tracker.js
index e8869e6b8..6e2fcb40b 100644
--- a/app/scripts/lib/pending-tx-tracker.js
+++ b/app/scripts/controllers/transactions/pending-tx-tracker.js
@@ -1,23 +1,24 @@
const EventEmitter = require('events')
+const log = require('loglevel')
const EthQuery = require('ethjs-query')
-/*
-
- Utility class for tracking the transactions as they
- go from a pending state to a confirmed (mined in a block) state
+/**
+ Event emitter utility class for tracking the transactions as they<br>
+ go from a pending state to a confirmed (mined in a block) state<br>
+<br>
As well as continues broadcast while in the pending state
+<br>
+@param config {object} - non optional configuration object consists of:
+ @param {Object} config.provider - A network provider.
+ @param {Object} config.nonceTracker see nonce tracker
+ @param {function} config.getPendingTransactions a function for getting an array of transactions,
+ @param {function} config.publishTransaction a async function for publishing raw transactions,
- ~config is not optional~
- requires a: {
- provider: //,
- nonceTracker: //see nonce tracker,
- getPendingTransactions: //() a function for getting an array of transactions,
- publishTransaction: //(rawTx) a async function for publishing raw transactions,
- }
+@class
*/
-module.exports = class PendingTransactionTracker extends EventEmitter {
+class PendingTransactionTracker extends EventEmitter {
constructor (config) {
super()
this.query = new EthQuery(config.provider)
@@ -29,8 +30,13 @@ module.exports = class PendingTransactionTracker extends EventEmitter {
this._checkPendingTxs()
}
- // checks if a signed tx is in a block and
- // if included sets the tx status as 'confirmed'
+ /**
+ checks if a signed tx is in a block and
+ if it is included emits tx status as 'confirmed'
+ @param block {object}, a full block
+ @emits tx:confirmed
+ @emits tx:failed
+ */
checkForTxInBlock (block) {
const signedTxList = this.getPendingTransactions()
if (!signedTxList.length) return
@@ -52,6 +58,11 @@ module.exports = class PendingTransactionTracker extends EventEmitter {
})
}
+ /**
+ asks the network for the transaction to see if a block number is included on it
+ if we have skipped/missed blocks
+ @param object - oldBlock newBlock
+ */
queryPendingTxs ({ oldBlock, newBlock }) {
// check pending transactions on start
if (!oldBlock) {
@@ -63,7 +74,11 @@ module.exports = class PendingTransactionTracker extends EventEmitter {
if (diff > 1) this._checkPendingTxs()
}
-
+ /**
+ Will resubmit any transactions who have not been confirmed in a block
+ @param block {object} - a block object
+ @emits tx:warning
+ */
resubmitPendingTxs (block) {
const pending = this.getPendingTransactions()
// only try resubmitting if their are transactions to resubmit
@@ -100,6 +115,13 @@ module.exports = class PendingTransactionTracker extends EventEmitter {
}))
}
+ /**
+ resubmits the individual txMeta used in resubmitPendingTxs
+ @param txMeta {Object} - txMeta object
+ @param latestBlockNumber {string} - hex string for the latest block number
+ @emits tx:retry
+ @returns txHash {string}
+ */
async _resubmitTx (txMeta, latestBlockNumber) {
if (!txMeta.firstRetryBlockNumber) {
this.emit('tx:block-update', txMeta, latestBlockNumber)
@@ -123,7 +145,13 @@ module.exports = class PendingTransactionTracker extends EventEmitter {
this.emit('tx:retry', txMeta)
return txHash
}
-
+ /**
+ Ask the network for the transaction to see if it has been include in a block
+ @param txMeta {Object} - the txMeta object
+ @emits tx:failed
+ @emits tx:confirmed
+ @emits tx:warning
+ */
async _checkPendingTx (txMeta) {
const txHash = txMeta.hash
const txId = txMeta.id
@@ -162,8 +190,9 @@ module.exports = class PendingTransactionTracker extends EventEmitter {
}
}
- // checks the network for signed txs and
- // if confirmed sets the tx status as 'confirmed'
+ /**
+ checks the network for signed txs and releases the nonce global lock if it is
+ */
async _checkPendingTxs () {
const signedTxList = this.getPendingTransactions()
// in order to keep the nonceTracker accurate we block it while updating pending transactions
@@ -171,12 +200,17 @@ module.exports = class PendingTransactionTracker extends EventEmitter {
try {
await Promise.all(signedTxList.map((txMeta) => this._checkPendingTx(txMeta)))
} catch (err) {
- console.error('PendingTransactionWatcher - Error updating pending transactions')
- console.error(err)
+ log.error('PendingTransactionWatcher - Error updating pending transactions')
+ log.error(err)
}
nonceGlobalLock.releaseLock()
}
+ /**
+ checks to see if a confirmed txMeta has the same nonce
+ @param txMeta {Object} - txMeta object
+ @returns {boolean}
+ */
async _checkIfNonceIsTaken (txMeta) {
const address = txMeta.txParams.from
const completed = this.getCompletedTransactions(address)
@@ -185,5 +219,6 @@ module.exports = class PendingTransactionTracker extends EventEmitter {
})
return sameNonce.length > 0
}
-
}
+
+module.exports = PendingTransactionTracker
diff --git a/app/scripts/lib/tx-gas-utils.js b/app/scripts/controllers/transactions/tx-gas-utils.js
index c579e462a..36b5cdbc9 100644
--- a/app/scripts/lib/tx-gas-utils.js
+++ b/app/scripts/controllers/transactions/tx-gas-utils.js
@@ -3,22 +3,27 @@ const {
hexToBn,
BnMultiplyByFraction,
bnToHex,
-} = require('./util')
+} = require('../../lib/util')
const { addHexPrefix } = require('ethereumjs-util')
const SIMPLE_GAS_COST = '0x5208' // Hex for 21000, cost of a simple send.
-/*
-tx-utils are utility methods for Transaction manager
+/**
+tx-gas-utils are gas utility methods for Transaction manager
its passed ethquery
and used to do things like calculate gas of a tx.
+@param {Object} provider - A network provider.
*/
-module.exports = class TxGasUtil {
+class TxGasUtil {
constructor (provider) {
this.query = new EthQuery(provider)
}
+ /**
+ @param txMeta {Object} - the txMeta object
+ @returns {object} the txMeta object with the gas written to the txParams
+ */
async analyzeGasUsage (txMeta) {
const block = await this.query.getBlockByNumber('latest', true)
let estimatedGasHex
@@ -38,6 +43,12 @@ module.exports = class TxGasUtil {
return txMeta
}
+ /**
+ Estimates the tx's gas usage
+ @param txMeta {Object} - the txMeta object
+ @param blockGasLimitHex {string} - hex string of the block's gas limit
+ @returns {string} the estimated gas limit as a hex string
+ */
async estimateTxGas (txMeta, blockGasLimitHex) {
const txParams = txMeta.txParams
@@ -70,6 +81,12 @@ module.exports = class TxGasUtil {
return await this.query.estimateGas(txParams)
}
+ /**
+ Writes the gas on the txParams in the txMeta
+ @param txMeta {Object} - the txMeta object to write to
+ @param blockGasLimitHex {string} - the block gas limit hex
+ @param estimatedGasHex {string} - the estimated gas hex
+ */
setTxGas (txMeta, blockGasLimitHex, estimatedGasHex) {
txMeta.estimatedGas = addHexPrefix(estimatedGasHex)
const txParams = txMeta.txParams
@@ -87,6 +104,13 @@ module.exports = class TxGasUtil {
return
}
+ /**
+ Adds a gas buffer with out exceeding the block gas limit
+
+ @param initialGasLimitHex {string} - the initial gas limit to add the buffer too
+ @param blockGasLimitHex {string} - the block gas limit
+ @returns {string} the buffered gas limit as a hex string
+ */
addGasBuffer (initialGasLimitHex, blockGasLimitHex) {
const initialGasLimitBn = hexToBn(initialGasLimitHex)
const blockGasLimitBn = hexToBn(blockGasLimitHex)
@@ -100,4 +124,6 @@ module.exports = class TxGasUtil {
// otherwise use blockGasLimit
return bnToHex(upperGasLimitBn)
}
-} \ No newline at end of file
+}
+
+module.exports = TxGasUtil \ No newline at end of file
diff --git a/app/scripts/lib/tx-state-manager.js b/app/scripts/controllers/transactions/tx-state-manager.js
index c6d10ee62..53428c333 100644
--- a/app/scripts/lib/tx-state-manager.js
+++ b/app/scripts/controllers/transactions/tx-state-manager.js
@@ -1,22 +1,33 @@
const extend = require('xtend')
const EventEmitter = require('events')
const ObservableStore = require('obs-store')
-const createId = require('./random-id')
const ethUtil = require('ethereumjs-util')
-const txStateHistoryHelper = require('./tx-state-history-helper')
-
-// STATUS METHODS
- // statuses:
- // - `'unapproved'` the user has not responded
- // - `'rejected'` the user has responded no!
- // - `'approved'` the user has approved the tx
- // - `'signed'` the tx is signed
- // - `'submitted'` the tx is sent to a server
- // - `'confirmed'` the tx has been included in a block.
- // - `'failed'` the tx failed for some reason, included on tx data.
- // - `'dropped'` the tx nonce was already used
-
-module.exports = class TransactionStateManager extends EventEmitter {
+const txStateHistoryHelper = require('./lib/tx-state-history-helper')
+const createId = require('../../lib/random-id')
+const { getFinalStates } = require('./lib/util')
+/**
+ TransactionStateManager is responsible for the state of a transaction and
+ storing the transaction
+ it also has some convenience methods for finding subsets of transactions
+ *
+ *STATUS METHODS
+ <br>statuses:
+ <br> - `'unapproved'` the user has not responded
+ <br> - `'rejected'` the user has responded no!
+ <br> - `'approved'` the user has approved the tx
+ <br> - `'signed'` the tx is signed
+ <br> - `'submitted'` the tx is sent to a server
+ <br> - `'confirmed'` the tx has been included in a block.
+ <br> - `'failed'` the tx failed for some reason, included on tx data.
+ <br> - `'dropped'` the tx nonce was already used
+ @param opts {object}
+ @param {object} [opts.initState={ transactions: [] }] initial transactions list with the key transaction {array}
+ @param {number} [opts.txHistoryLimit] limit for how many finished
+ transactions can hang around in state
+ @param {function} opts.getNetwork return network number
+ @class
+*/
+class TransactionStateManager extends EventEmitter {
constructor ({ initState, txHistoryLimit, getNetwork }) {
super()
@@ -28,6 +39,10 @@ module.exports = class TransactionStateManager extends EventEmitter {
this.getNetwork = getNetwork
}
+ /**
+ @param opts {object} - the object to use when overwriting defaults
+ @returns {txMeta} the default txMeta object
+ */
generateTxMeta (opts) {
return extend({
id: createId(),
@@ -38,17 +53,25 @@ module.exports = class TransactionStateManager extends EventEmitter {
}, opts)
}
+ /**
+ @returns {array} of txMetas that have been filtered for only the current network
+ */
getTxList () {
const network = this.getNetwork()
const fullTxList = this.getFullTxList()
return fullTxList.filter((txMeta) => txMeta.metamaskNetworkId === network)
}
+ /**
+ @returns {array} of all the txMetas in store
+ */
getFullTxList () {
return this.store.getState().transactions
}
- // Returns the tx list
+ /**
+ @returns {array} the tx list whos status is unapproved
+ */
getUnapprovedTxList () {
const txList = this.getTxsByMetaData('status', 'unapproved')
return txList.reduce((result, tx) => {
@@ -57,18 +80,37 @@ module.exports = class TransactionStateManager extends EventEmitter {
}, {})
}
+ /**
+ @param [address] {string} - hex prefixed address to sort the txMetas for [optional]
+ @returns {array} the tx list whos status is submitted if no address is provide
+ returns all txMetas who's status is submitted for the current network
+ */
getPendingTransactions (address) {
const opts = { status: 'submitted' }
if (address) opts.from = address
return this.getFilteredTxList(opts)
}
+ /**
+ @param [address] {string} - hex prefixed address to sort the txMetas for [optional]
+ @returns {array} the tx list whos status is confirmed if no address is provide
+ returns all txMetas who's status is confirmed for the current network
+ */
getConfirmedTransactions (address) {
const opts = { status: 'confirmed' }
if (address) opts.from = address
return this.getFilteredTxList(opts)
}
+ /**
+ Adds the txMeta to the list of transactions in the store.
+ if the list is over txHistoryLimit it will remove a transaction that
+ is in its final state
+ it will allso add the key `history` to the txMeta with the snap shot of the original
+ object
+ @param txMeta {Object}
+ @returns {object} the txMeta
+ */
addTx (txMeta) {
this.once(`${txMeta.id}:signed`, function (txId) {
this.removeAllListeners(`${txMeta.id}:rejected`)
@@ -92,7 +134,9 @@ module.exports = class TransactionStateManager extends EventEmitter {
// or rejected tx's.
// not tx's that are pending or unapproved
if (txCount > txHistoryLimit - 1) {
- let index = transactions.findIndex((metaTx) => metaTx.status === 'confirmed' || metaTx.status === 'rejected')
+ const index = transactions.findIndex((metaTx) => {
+ return getFinalStates().includes(metaTx.status)
+ })
if (index !== -1) {
transactions.splice(index, 1)
}
@@ -101,12 +145,21 @@ module.exports = class TransactionStateManager extends EventEmitter {
this._saveTxList(transactions)
return txMeta
}
- // gets tx by Id and returns it
+ /**
+ @param txId {number}
+ @returns {object} the txMeta who matches the given id if none found
+ for the network returns undefined
+ */
getTx (txId) {
const txMeta = this.getTxsByMetaData('id', txId)[0]
return txMeta
}
+ /**
+ updates the txMeta in the list and adds a history entry
+ @param txMeta {Object} - the txMeta to update
+ @param [note] {string} - a not about the update for history
+ */
updateTx (txMeta, note) {
// validate txParams
if (txMeta.txParams) {
@@ -134,16 +187,23 @@ module.exports = class TransactionStateManager extends EventEmitter {
}
- // merges txParams obj onto txData.txParams
- // use extend to ensure that all fields are filled
+ /**
+ merges txParams obj onto txMeta.txParams
+ use extend to ensure that all fields are filled
+ @param txId {number} - the id of the txMeta
+ @param txParams {object} - the updated txParams
+ */
updateTxParams (txId, txParams) {
const txMeta = this.getTx(txId)
txMeta.txParams = extend(txMeta.txParams, txParams)
this.updateTx(txMeta, `txStateManager#updateTxParams`)
}
- // validates txParams members by type
- validateTxParams(txParams) {
+ /**
+ validates txParams members by type
+ @param txParams {object} - txParams to validate
+ */
+ validateTxParams (txParams) {
Object.keys(txParams).forEach((key) => {
const value = txParams[key]
// validate types
@@ -159,17 +219,19 @@ module.exports = class TransactionStateManager extends EventEmitter {
})
}
-/*
- Takes an object of fields to search for eg:
- let thingsToLookFor = {
- to: '0x0..',
- from: '0x0..',
- status: 'signed',
- err: undefined,
- }
- and returns a list of tx with all
+/**
+ @param opts {object} - an object of fields to search for eg:<br>
+ let <code>thingsToLookFor = {<br>
+ to: '0x0..',<br>
+ from: '0x0..',<br>
+ status: 'signed',<br>
+ err: undefined,<br>
+ }<br></code>
+ @param [initialList=this.getTxList()]
+ @returns a {array} of txMeta with all
options matching
-
+ */
+ /*
****************HINT****************
| `err: undefined` is like looking |
| for a tx with no err |
@@ -190,7 +252,14 @@ module.exports = class TransactionStateManager extends EventEmitter {
})
return filteredTxList
}
+ /**
+ @param key {string} - the key to check
+ @param value - the value your looking for
+ @param [txList=this.getTxList()] {array} - the list to search. default is the txList
+ from txStateManager#getTxList
+ @returns {array} a list of txMetas who matches the search params
+ */
getTxsByMetaData (key, value, txList = this.getTxList()) {
return txList.filter((txMeta) => {
if (txMeta.txParams[key]) {
@@ -203,33 +272,51 @@ module.exports = class TransactionStateManager extends EventEmitter {
// get::set status
- // should return the status of the tx.
+ /**
+ @param txId {number} - the txMeta Id
+ @return {string} the status of the tx.
+ */
getTxStatus (txId) {
const txMeta = this.getTx(txId)
return txMeta.status
}
- // should update the status of the tx to 'rejected'.
+ /**
+ should update the status of the tx to 'rejected'.
+ @param txId {number} - the txMeta Id
+ */
setTxStatusRejected (txId) {
this._setTxStatus(txId, 'rejected')
}
- // should update the status of the tx to 'unapproved'.
+ /**
+ should update the status of the tx to 'unapproved'.
+ @param txId {number} - the txMeta Id
+ */
setTxStatusUnapproved (txId) {
this._setTxStatus(txId, 'unapproved')
}
- // should update the status of the tx to 'approved'.
+ /**
+ should update the status of the tx to 'approved'.
+ @param txId {number} - the txMeta Id
+ */
setTxStatusApproved (txId) {
this._setTxStatus(txId, 'approved')
}
- // should update the status of the tx to 'signed'.
+ /**
+ should update the status of the tx to 'signed'.
+ @param txId {number} - the txMeta Id
+ */
setTxStatusSigned (txId) {
this._setTxStatus(txId, 'signed')
}
- // should update the status of the tx to 'submitted'.
- // and add a time stamp for when it was called
+ /**
+ should update the status of the tx to 'submitted'.
+ and add a time stamp for when it was called
+ @param txId {number} - the txMeta Id
+ */
setTxStatusSubmitted (txId) {
const txMeta = this.getTx(txId)
txMeta.submittedTime = (new Date()).getTime()
@@ -237,17 +324,29 @@ module.exports = class TransactionStateManager extends EventEmitter {
this._setTxStatus(txId, 'submitted')
}
- // should update the status of the tx to 'confirmed'.
+ /**
+ should update the status of the tx to 'confirmed'.
+ @param txId {number} - the txMeta Id
+ */
setTxStatusConfirmed (txId) {
this._setTxStatus(txId, 'confirmed')
}
- // should update the status dropped
+ /**
+ should update the status of the tx to 'dropped'.
+ @param txId {number} - the txMeta Id
+ */
setTxStatusDropped (txId) {
this._setTxStatus(txId, 'dropped')
}
+ /**
+ should update the status of the tx to 'failed'.
+ and put the error on the txMeta
+ @param txId {number} - the txMeta Id
+ @param err {erroObject} - error object
+ */
setTxStatusFailed (txId, err) {
const txMeta = this.getTx(txId)
txMeta.err = {
@@ -258,6 +357,11 @@ module.exports = class TransactionStateManager extends EventEmitter {
this._setTxStatus(txId, 'failed')
}
+ /**
+ Removes transaction from the given address for the current network
+ from the txList
+ @param address {string} - hex string of the from address on the txParams to remove
+ */
wipeTransactions (address) {
// network only tx
const txs = this.getFullTxList()
@@ -273,9 +377,8 @@ module.exports = class TransactionStateManager extends EventEmitter {
// PRIVATE METHODS
//
- // Should find the tx in the tx list and
- // update it.
- // should set the status in txData
+ // STATUS METHODS
+ // statuses:
// - `'unapproved'` the user has not responded
// - `'rejected'` the user has responded no!
// - `'approved'` the user has approved the tx
@@ -283,6 +386,15 @@ module.exports = class TransactionStateManager extends EventEmitter {
// - `'submitted'` the tx is sent to a server
// - `'confirmed'` the tx has been included in a block.
// - `'failed'` the tx failed for some reason, included on tx data.
+ // - `'dropped'` the tx nonce was already used
+
+ /**
+ @param txId {number} - the txMeta Id
+ @param status {string} - the status to set on the txMeta
+ @emits tx:status-update - passes txId and status
+ @emits ${txMeta.id}:finished - if it is a finished state. Passes the txMeta
+ @emits update:badge
+ */
_setTxStatus (txId, status) {
const txMeta = this.getTx(txId)
txMeta.status = status
@@ -295,9 +407,14 @@ module.exports = class TransactionStateManager extends EventEmitter {
this.emit('update:badge')
}
- // Saves the new/updated txList.
+ /**
+ Saves the new/updated txList.
+ @param transactions {array} - the list of transactions to save
+ */
// Function is intended only for internal use
_saveTxList (transactions) {
this.store.updateState({ transactions })
}
}
+
+module.exports = TransactionStateManager
diff --git a/app/scripts/lib/config-manager.js b/app/scripts/lib/config-manager.js
index c10ff2f4e..221746467 100644
--- a/app/scripts/lib/config-manager.js
+++ b/app/scripts/lib/config-manager.js
@@ -101,6 +101,7 @@ ConfigManager.prototype.setShowSeedWords = function (should) {
this.setData(data)
}
+
ConfigManager.prototype.getShouldShowSeedWords = function () {
var data = this.getData()
return data.showSeedWords
@@ -116,27 +117,6 @@ ConfigManager.prototype.getSeedWords = function () {
var data = this.getData()
return data.seedWords
}
-
-/**
- * Called to set the isRevealingSeedWords flag. This happens only when the user chooses to reveal
- * the seed words and not during the first time flow.
- * @param {boolean} reveal - Value to set the isRevealingSeedWords flag.
- */
-ConfigManager.prototype.setIsRevealingSeedWords = function (reveal = false) {
- const data = this.getData()
- data.isRevealingSeedWords = reveal
- this.setData(data)
-}
-
-/**
- * Returns the isRevealingSeedWords flag.
- * @returns {boolean|undefined}
- */
-ConfigManager.prototype.getIsRevealingSeedWords = function () {
- const data = this.getData()
- return data.isRevealingSeedWords
-}
-
ConfigManager.prototype.setRpcTarget = function (rpcUrl) {
var config = this.getConfig()
config.provider = {
diff --git a/app/scripts/lib/setupRaven.js b/app/scripts/lib/setupRaven.js
index 9ec9a256f..b1b67f771 100644
--- a/app/scripts/lib/setupRaven.js
+++ b/app/scripts/lib/setupRaven.js
@@ -23,22 +23,16 @@ function setupRaven(opts) {
release,
transport: function(opts) {
const report = opts.data
- // simplify certain complex error messages
- report.exception.values.forEach(item => {
- let errorMessage = item.value
- // simplify ethjs error messages
- errorMessage = extractEthjsErrorMessage(errorMessage)
- // simplify 'Transaction Failed: known transaction'
- if (errorMessage.indexOf('Transaction Failed: known transaction') === 0) {
- // cut the hash from the error message
- errorMessage = 'Transaction Failed: known transaction'
- }
- // finalize
- item.value = errorMessage
- })
-
- // modify report urls
- rewriteReportUrls(report)
+ try {
+ // handle error-like non-error exceptions
+ nonErrorException(report)
+ // simplify certain complex error messages (e.g. Ethjs)
+ simplifyErrorMessages(report)
+ // modify report urls
+ rewriteReportUrls(report)
+ } catch (err) {
+ console.warn(err)
+ }
// make request normally
client._makeRequest(opts)
},
@@ -48,15 +42,42 @@ function setupRaven(opts) {
return Raven
}
+function nonErrorException(report) {
+ // handle errors that lost their error-ness in serialization
+ if (report.message.includes('Non-Error exception captured with keys: message')) {
+ if (!(report.extra && report.extra.__serialized__)) return
+ report.message = `Non-Error Exception: ${report.extra.__serialized__.message}`
+ }
+}
+
+function simplifyErrorMessages(report) {
+ if (report.exception && report.exception.values) {
+ report.exception.values.forEach(item => {
+ let errorMessage = item.value
+ // simplify ethjs error messages
+ errorMessage = extractEthjsErrorMessage(errorMessage)
+ // simplify 'Transaction Failed: known transaction'
+ if (errorMessage.indexOf('Transaction Failed: known transaction') === 0) {
+ // cut the hash from the error message
+ errorMessage = 'Transaction Failed: known transaction'
+ }
+ // finalize
+ item.value = errorMessage
+ })
+ }
+}
+
function rewriteReportUrls(report) {
// update request url
report.request.url = toMetamaskUrl(report.request.url)
// update exception stack trace
- report.exception.values.forEach(item => {
- item.stacktrace.frames.forEach(frame => {
- frame.filename = toMetamaskUrl(frame.filename)
+ if (report.exception && report.exception.values) {
+ report.exception.values.forEach(item => {
+ item.stacktrace.frames.forEach(frame => {
+ frame.filename = toMetamaskUrl(frame.filename)
+ })
})
- })
+ }
}
function toMetamaskUrl(origUrl) {
diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js
index edde38819..c4a73d8ea 100644
--- a/app/scripts/metamask-controller.js
+++ b/app/scripts/metamask-controller.js
@@ -309,7 +309,6 @@ module.exports = class MetamaskController extends EventEmitter {
lostAccounts: this.configManager.getLostAccounts(),
seedWords: this.configManager.getSeedWords(),
forgottenPassword: this.configManager.getPasswordForgotten(),
- isRevealingSeedWords: Boolean(this.configManager.getIsRevealingSeedWords()),
},
}
}
@@ -351,7 +350,6 @@ module.exports = class MetamaskController extends EventEmitter {
clearSeedWordCache: this.clearSeedWordCache.bind(this),
resetAccount: nodeify(this.resetAccount, this),
importAccountWithStrategy: this.importAccountWithStrategy.bind(this),
- setIsRevealingSeedWords: this.configManager.setIsRevealingSeedWords.bind(this.configManager),
// vault management
submitPassword: nodeify(keyringController.submitPassword, keyringController),
diff --git a/app/scripts/migrations/018.js b/app/scripts/migrations/018.js
index bea1fe3da..ffbf24a4b 100644
--- a/app/scripts/migrations/018.js
+++ b/app/scripts/migrations/018.js
@@ -7,7 +7,7 @@ This migration updates "transaction state history" to diffs style
*/
const clone = require('clone')
-const txStateHistoryHelper = require('../lib/tx-state-history-helper')
+const txStateHistoryHelper = require('../controllers/transactions/lib/tx-state-history-helper')
module.exports = {
diff --git a/development/sourcemap-validator.js b/development/sourcemap-validator.js
new file mode 100644
index 000000000..edc97667a
--- /dev/null
+++ b/development/sourcemap-validator.js
@@ -0,0 +1,49 @@
+const fs = require('fs')
+const { SourceMapConsumer } = require('source-map')
+
+//
+// Utility to help check if sourcemaps are working
+//
+// searches `dist/chrome/inpage.js` for "new Error" statements
+// and prints their source lines using the sourcemaps.
+// if not working it may error or print minified garbage
+//
+
+start()
+
+async function start() {
+ const rawBuild = fs.readFileSync(__dirname + '/../dist/chrome/inpage.js', 'utf8')
+ const rawSourceMap = fs.readFileSync(__dirname + '/../dist/sourcemaps/inpage.js.map', 'utf8')
+ const consumer = await new SourceMapConsumer(rawSourceMap)
+
+ console.log('hasContentsOfAllSources:', consumer.hasContentsOfAllSources(), '\n')
+ console.log('sources:')
+ consumer.sources.map((sourcePath) => console.log(sourcePath))
+
+ console.log('\nexamining "new Error" statements:\n')
+ const sourceLines = rawBuild.split('\n')
+ sourceLines.map(line => indicesOf('new Error', line))
+ .forEach((errorIndices, lineIndex) => {
+ // if (errorIndex === null) return console.log('line does not contain "new Error"')
+ errorIndices.forEach((errorIndex) => {
+ const position = { line: lineIndex + 1, column: errorIndex }
+ const result = consumer.originalPositionFor(position)
+ if (!result.source) return console.warn(`!! missing source for position: ${position}`)
+ // filter out deps distributed minified without sourcemaps
+ if (result.source === 'node_modules/browserify/node_modules/browser-pack/_prelude.js') return // minified mess
+ if (result.source === 'node_modules/web3/dist/web3.min.js') return // minified mess
+ const sourceContent = consumer.sourceContentFor(result.source)
+ const sourceLines = sourceContent.split('\n')
+ const line = sourceLines[result.line-1]
+ console.log(`\n========================== ${result.source} ====================================\n`)
+ console.log(line)
+ console.log(`\n==============================================================================\n`)
+ })
+ })
+}
+
+function indicesOf(substring, string) {
+ var a=[],i=-1;
+ while((i=string.indexOf(substring,i+1)) >= 0) a.push(i);
+ return a;
+}
diff --git a/docs/transaction-flow.png b/docs/transaction-flow.png
new file mode 100644
index 000000000..1059b60d8
--- /dev/null
+++ b/docs/transaction-flow.png
Binary files differ
diff --git a/gulpfile.js b/gulpfile.js
index 4f0da9d60..4dca7089f 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -247,7 +247,7 @@ gulp.task('dev:scss', createScssBuildTask({
src: 'ui/app/css/index.scss',
dest: 'ui/app/css/output',
devMode: true,
- pattern: 'ui/app/css/**/*.scss',
+ pattern: 'ui/app/**/*.scss',
}))
function createScssBuildTask({ src, dest, devMode, pattern }) {
@@ -484,16 +484,6 @@ function generateBundler(opts, performBundle) {
NODE_ENV: opts.devMode ? 'development' : 'production',
}))
- // Minification
- if (opts.minifyBuild) {
- bundler.transform('uglifyify', {
- global: true,
- mangle: {
- reserved: [ 'MetamaskInpageProvider' ]
- },
- })
- }
-
if (opts.watch) {
bundler = watchify(bundler)
// on any file update, re-runs the bundler
@@ -567,6 +557,16 @@ function bundleTask(opts) {
.pipe(sourcemaps.init({ loadMaps: true }))
}
+ // Minification
+ if (opts.minifyBuild) {
+ buildStream = buildStream
+ .pipe(uglify({
+ mangle: {
+ reserved: [ 'MetamaskInpageProvider' ]
+ },
+ }))
+ }
+
// Finalize Source Maps (writes .map file)
if (opts.buildSourceMaps) {
buildStream = buildStream
diff --git a/mascara/src/app/first-time/import-account-screen.js b/mascara/src/app/first-time/import-account-screen.js
index ab0aca0f0..555a26386 100644
--- a/mascara/src/app/first-time/import-account-screen.js
+++ b/mascara/src/app/first-time/import-account-screen.js
@@ -70,10 +70,14 @@ class ImportAccountScreen extends Component {
switch (this.state.selectedOption) {
case OPTIONS.JSON_FILE:
return importNewAccount('JSON File', [ jsonFile, password ])
+ // JS runtime requires caught rejections but failures are handled by Redux
+ .catch()
.then(next)
case OPTIONS.PRIVATE_KEY:
default:
return importNewAccount('Private Key', [ privateKey ])
+ // JS runtime requires caught rejections but failures are handled by Redux
+ .catch()
.then(next)
}
}
diff --git a/mascara/src/app/first-time/seed-screen.js b/mascara/src/app/first-time/seed-screen.js
index 9af9ca3be..d004be77b 100644
--- a/mascara/src/app/first-time/seed-screen.js
+++ b/mascara/src/app/first-time/seed-screen.js
@@ -8,7 +8,6 @@ import Identicon from '../../../../ui/app/components/identicon'
import Breadcrumbs from './breadcrumbs'
import LoadingScreen from './loading-screen'
import { DEFAULT_ROUTE, INITIALIZE_CONFIRM_SEED_ROUTE } from '../../../../ui/app/routes'
-import { confirmSeedWords } from '../../../../ui/app/actions'
const LockIcon = props => (
<svg
@@ -45,8 +44,6 @@ class BackupPhraseScreen extends Component {
address: PropTypes.string.isRequired,
seedWords: PropTypes.string,
history: PropTypes.object,
- isRevealingSeedWords: PropTypes.bool,
- clearSeedWords: PropTypes.func,
};
static defaultProps = {
@@ -61,14 +58,6 @@ class BackupPhraseScreen extends Component {
}
componentWillMount () {
- this.checkSeedWords()
- }
-
- componentDidUpdate () {
- this.checkSeedWords()
- }
-
- checkSeedWords () {
const { seedWords, history } = this.props
if (!seedWords) {
@@ -103,29 +92,9 @@ class BackupPhraseScreen extends Component {
)
}
- renderSubmitButton () {
- const { isRevealingSeedWords, clearSeedWords, history } = this.props
- const { isShowingSecret } = this.state
-
- return isRevealingSeedWords
- ? <button
- className="first-time-flow__button"
- onClick={() => clearSeedWords().then(() => history.push(DEFAULT_ROUTE))}
- disabled={!isShowingSecret}
- >
- Done
- </button>
- : <button
- className="first-time-flow__button"
- onClick={() => isShowingSecret && history.push(INITIALIZE_CONFIRM_SEED_ROUTE)}
- disabled={!isShowingSecret}
- >
- Next
- </button>
- }
-
renderSecretScreen () {
- const { isRevealingSeedWords } = this.props
+ const { isShowingSecret } = this.state
+ const { history } = this.props
return (
<div className="backup-phrase__content-wrapper">
@@ -152,8 +121,14 @@ class BackupPhraseScreen extends Component {
</div>
</div>
<div className="backup-phrase__next-button">
- { this.renderSubmitButton() }
- { !isRevealingSeedWords && <Breadcrumbs total={3} currentIndex={1} />}
+ <button
+ className="first-time-flow__button"
+ onClick={() => isShowingSecret && history.push(INITIALIZE_CONFIRM_SEED_ROUTE)}
+ disabled={!isShowingSecret}
+ >
+ Next
+ </button>
+ <Breadcrumbs total={3} currentIndex={1} />
</div>
</div>
)
@@ -175,25 +150,13 @@ class BackupPhraseScreen extends Component {
}
}
-const mapStateToProps = ({ metamask, appState }) => {
- const { selectedAddress, seedWords, isRevealingSeedWords } = metamask
- const { isLoading } = appState
-
- return {
- seedWords,
- isRevealingSeedWords,
- isLoading,
- address: selectedAddress,
- }
-}
-
-const mapDispatchToProps = dispatch => {
- return {
- clearSeedWords: () => dispatch(confirmSeedWords()),
- }
-}
-
export default compose(
withRouter,
- connect(mapStateToProps, mapDispatchToProps),
+ connect(
+ ({ metamask: { selectedAddress, seedWords }, appState: { isLoading } }) => ({
+ seedWords,
+ isLoading,
+ address: selectedAddress,
+ })
+ )
)(BackupPhraseScreen)
diff --git a/old-ui/app/accounts/import/json.js b/old-ui/app/accounts/import/json.js
index 3ee3b95df..8388f17a7 100644
--- a/old-ui/app/accounts/import/json.js
+++ b/old-ui/app/accounts/import/json.js
@@ -96,6 +96,8 @@ class JsonImportSubview extends Component {
}
this.props.importNewAccount([ fileContents, password ])
+ // JS runtime requires caught rejections but failures are handled by Redux
+ .catch()
}
}
diff --git a/old-ui/app/accounts/import/private-key.js b/old-ui/app/accounts/import/private-key.js
index 105191105..92e42549d 100644
--- a/old-ui/app/accounts/import/private-key.js
+++ b/old-ui/app/accounts/import/private-key.js
@@ -64,4 +64,6 @@ PrivateKeyImportView.prototype.createNewKeychain = function () {
const input = document.getElementById('private-key-box')
const privateKey = input.value
this.props.dispatch(actions.importNewAccount('Private Key', [ privateKey ]))
+ // JS runtime requires caught rejections but failures are handled by Redux
+ .catch()
}
diff --git a/old-ui/app/components/pending-tx.js b/old-ui/app/components/pending-tx.js
index cd4189fc4..c8132539c 100644
--- a/old-ui/app/components/pending-tx.js
+++ b/old-ui/app/components/pending-tx.js
@@ -16,8 +16,7 @@ const addressSummary = util.addressSummary
const nameForAddress = require('../../lib/contract-namer')
const BNInput = require('./bn-as-decimal-input')
-// corresponds with 0.1 GWEI
-const MIN_GAS_PRICE_BN = new BN('100000000')
+const MIN_GAS_PRICE_BN = new BN('0')
const MIN_GAS_LIMIT_BN = new BN('21000')
module.exports = PendingTx
diff --git a/old-ui/app/components/shapeshift-form.js b/old-ui/app/components/shapeshift-form.js
index a54987c04..97068db0a 100644
--- a/old-ui/app/components/shapeshift-form.js
+++ b/old-ui/app/components/shapeshift-form.js
@@ -138,7 +138,7 @@ ShapeshiftForm.prototype.renderMain = function () {
width: '229px',
height: '82px',
},
- }, this.props.warning)
+ }, this.props.warning + '')
: this.renderInfo(),
this.renderRefundAddressForCoin(coin),
diff --git a/package-lock.json b/package-lock.json
index 5b5b82450..1389cb0e8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -419,6 +419,63 @@
"dev": true,
"optional": true
},
+ "adjust-sourcemap-loader": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-1.2.0.tgz",
+ "integrity": "sha512-958oaHHVEXMvsY7v7cC5gEkNIcoaAVIhZ4mBReYVZJOTP9IgKmzLjIOhTtzpLMu+qriXvLsVjJ155EeInp45IQ==",
+ "dev": true,
+ "requires": {
+ "assert": "1.4.1",
+ "camelcase": "1.2.1",
+ "loader-utils": "1.1.0",
+ "lodash.assign": "4.2.0",
+ "lodash.defaults": "3.1.2",
+ "object-path": "0.9.2",
+ "regex-parser": "2.2.9"
+ },
+ "dependencies": {
+ "camelcase": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
+ "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=",
+ "dev": true
+ },
+ "loader-utils": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz",
+ "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=",
+ "dev": true,
+ "requires": {
+ "big.js": "3.2.0",
+ "emojis-list": "2.1.0",
+ "json5": "0.5.1"
+ }
+ },
+ "lodash.defaults": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-3.1.2.tgz",
+ "integrity": "sha1-xzCLGNv4vJNy1wGnNJPGEZK9Liw=",
+ "dev": true,
+ "requires": {
+ "lodash.assign": "3.2.0",
+ "lodash.restparam": "3.6.1"
+ },
+ "dependencies": {
+ "lodash.assign": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-3.2.0.tgz",
+ "integrity": "sha1-POnwI0tLIiPilrj6CsH+6OvKZPo=",
+ "dev": true,
+ "requires": {
+ "lodash._baseassign": "3.2.0",
+ "lodash._createassigner": "3.1.1",
+ "lodash.keys": "3.1.2"
+ }
+ }
+ }
+ }
+ }
+ },
"aes-js": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/aes-js/-/aes-js-0.2.4.tgz",
@@ -474,6 +531,11 @@
"repeat-string": "1.6.1"
}
},
+ "alphanum-sort": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz",
+ "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM="
+ },
"amdefine": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
@@ -655,7 +717,7 @@
"resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz",
"integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=",
"requires": {
- "make-iterator": "1.0.0"
+ "make-iterator": "1.0.1"
}
},
"arr-flatten": {
@@ -668,7 +730,7 @@
"resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz",
"integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=",
"requires": {
- "make-iterator": "1.0.0"
+ "make-iterator": "1.0.1"
}
},
"arr-union": {
@@ -2821,6 +2883,20 @@
"ieee754": "1.1.8"
}
},
+ "buffer-alloc": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.1.0.tgz",
+ "integrity": "sha1-BVFNM78WVtNUDGhPZbEgLpDsowM=",
+ "requires": {
+ "buffer-alloc-unsafe": "0.1.1",
+ "buffer-fill": "0.1.1"
+ }
+ },
+ "buffer-alloc-unsafe": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-0.1.1.tgz",
+ "integrity": "sha1-/+H2dVHdBVc33iUzN7/oU9+rGmo="
+ },
"buffer-crc32": {
"version": "0.2.13",
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
@@ -2831,6 +2907,11 @@
"resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz",
"integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74="
},
+ "buffer-fill": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-0.1.1.tgz",
+ "integrity": "sha512-YgBMBzdRLEfgxJIGu2wrvI2E03tMCFU1p7d1KhB4BOoMN0VxmTFjSyN5JtKt9z8Z9JajMHruI6SE25W96wNv7Q=="
+ },
"buffer-from": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-0.1.2.tgz",
@@ -3016,11 +3097,32 @@
}
}
},
+ "caniuse-api": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.6.1.tgz",
+ "integrity": "sha1-tTTnxzTE+B7F++isoq0kNUuWLGw=",
+ "requires": {
+ "browserslist": "1.7.7",
+ "caniuse-db": "1.0.30000808",
+ "lodash.memoize": "4.1.2",
+ "lodash.uniq": "4.5.0"
+ },
+ "dependencies": {
+ "browserslist": {
+ "version": "1.7.7",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz",
+ "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=",
+ "requires": {
+ "caniuse-db": "1.0.30000808",
+ "electron-to-chromium": "1.3.30"
+ }
+ }
+ }
+ },
"caniuse-db": {
"version": "1.0.30000808",
"resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000808.tgz",
- "integrity": "sha1-MN/YMAnVcE8C3/s3clBo7RKjZrs=",
- "dev": true
+ "integrity": "sha1-MN/YMAnVcE8C3/s3clBo7RKjZrs="
},
"caniuse-lite": {
"version": "1.0.30000786",
@@ -3193,6 +3295,14 @@
"resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz",
"integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A=="
},
+ "clap": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/clap/-/clap-1.2.3.tgz",
+ "integrity": "sha512-4CoL/A3hf90V3VIEjeuhSvlGFEHKzOz+Wfc2IVZc+FaUgU0ZQafJTP49fvnULipOPcAfqhyI2duwQyns6xqjYA==",
+ "requires": {
+ "chalk": "1.1.3"
+ }
+ },
"class-utils": {
"version": "0.3.6",
"resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
@@ -3316,6 +3426,32 @@
}
}
},
+ "cli-table2": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/cli-table2/-/cli-table2-0.2.0.tgz",
+ "integrity": "sha1-LR738hig54biFFQFYtS9F3/jLZc=",
+ "dev": true,
+ "requires": {
+ "colors": "1.2.3",
+ "lodash": "3.10.1",
+ "string-width": "1.0.2"
+ },
+ "dependencies": {
+ "colors": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.2.3.tgz",
+ "integrity": "sha512-qTfM2pNFeMZcLvf/RbrVAzDEVttZjFhaApfx9dplNjvHSX88Ui66zBRb/4YGob/xUWxDceirgoC1lT676asfCQ==",
+ "dev": true,
+ "optional": true
+ },
+ "lodash": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
+ "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=",
+ "dev": true
+ }
+ }
+ },
"cli-truncate": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz",
@@ -3359,6 +3495,35 @@
"resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz",
"integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg="
},
+ "clone-deep": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-2.0.2.tgz",
+ "integrity": "sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ==",
+ "dev": true,
+ "requires": {
+ "for-own": "1.0.0",
+ "is-plain-object": "2.0.4",
+ "kind-of": "6.0.2",
+ "shallow-clone": "1.0.0"
+ },
+ "dependencies": {
+ "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.2"
+ }
+ },
+ "kind-of": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+ "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+ "dev": true
+ }
+ }
+ },
"clone-regexp": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/clone-regexp/-/clone-regexp-1.0.0.tgz",
@@ -3398,6 +3563,14 @@
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
},
+ "coa": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/coa/-/coa-1.0.4.tgz",
+ "integrity": "sha1-qe8VNmDWqGqL3sAomlxoTSF0Mv0=",
+ "requires": {
+ "q": "1.5.1"
+ }
+ },
"code-point-at": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
@@ -3431,7 +3604,7 @@
"requires": {
"arr-map": "2.0.2",
"for-own": "1.0.0",
- "make-iterator": "1.0.0"
+ "make-iterator": "1.0.1"
},
"dependencies": {
"for-own": {
@@ -3573,6 +3746,23 @@
}
}
},
+ "colormin": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/colormin/-/colormin-1.1.2.tgz",
+ "integrity": "sha1-6i90IKcrlogaOKrlnsEkpvcpgTM=",
+ "requires": {
+ "color": "0.11.4",
+ "css-color-names": "0.0.4",
+ "has": "1.0.1"
+ },
+ "dependencies": {
+ "css-color-names": {
+ "version": "0.0.4",
+ "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz",
+ "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA="
+ }
+ }
+ },
"colors": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/colors/-/colors-0.5.1.tgz",
@@ -3603,6 +3793,14 @@
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz",
"integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8="
+ },
+ "source-map": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
+ "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
+ "requires": {
+ "amdefine": "1.0.1"
+ }
}
}
},
@@ -3796,9 +3994,9 @@
"integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40="
},
"copy-props": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.1.tgz",
- "integrity": "sha1-Zl/DIEbKhKiYq6o8WUXn8kjMugA=",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.2.tgz",
+ "integrity": "sha512-/W7IE8h4Zj1jdyf26YhdEjTS/xO42ltxtlH6B9+rmFNeXO+LL7KhzqqJdKJUwwO+4ZZ4IRw7rFhm8VEw95T25A==",
"requires": {
"each-props": "1.3.1",
"is-plain-object": "2.0.4"
@@ -4041,6 +4239,68 @@
"integrity": "sha1-XQVI+iVkVu3kqaDCrHqxnT6xrYE=",
"dev": true
},
+ "css-loader": {
+ "version": "0.28.11",
+ "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-0.28.11.tgz",
+ "integrity": "sha512-wovHgjAx8ZIMGSL8pTys7edA1ClmzxHeY6n/d97gg5odgsxEgKjULPR0viqyC+FWMCL9sfqoC/QCUBo62tLvPg==",
+ "requires": {
+ "babel-code-frame": "6.26.0",
+ "css-selector-tokenizer": "0.7.0",
+ "cssnano": "3.10.0",
+ "icss-utils": "2.1.0",
+ "loader-utils": "1.1.0",
+ "lodash.camelcase": "4.3.0",
+ "object-assign": "4.1.1",
+ "postcss": "5.2.18",
+ "postcss-modules-extract-imports": "1.2.0",
+ "postcss-modules-local-by-default": "1.2.0",
+ "postcss-modules-scope": "1.1.0",
+ "postcss-modules-values": "1.3.0",
+ "postcss-value-parser": "3.3.0",
+ "source-list-map": "2.0.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "loader-utils": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz",
+ "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=",
+ "requires": {
+ "big.js": "3.2.0",
+ "emojis-list": "2.1.0",
+ "json5": "0.5.1"
+ }
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "1.1.3",
+ "js-base64": "2.4.3",
+ "source-map": "0.5.7",
+ "supports-color": "3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "1.0.0"
+ }
+ }
+ }
+ },
"css-rule-stream": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/css-rule-stream/-/css-rule-stream-1.1.0.tgz",
@@ -4101,6 +4361,28 @@
"nth-check": "1.0.1"
}
},
+ "css-selector-tokenizer": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz",
+ "integrity": "sha1-5piEdK6MlTR3v15+/s/OzNnPTIY=",
+ "requires": {
+ "cssesc": "0.1.0",
+ "fastparse": "1.1.1",
+ "regexpu-core": "1.0.0"
+ },
+ "dependencies": {
+ "regexpu-core": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz",
+ "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=",
+ "requires": {
+ "regenerate": "1.3.3",
+ "regjsgen": "0.2.0",
+ "regjsparser": "0.1.5"
+ }
+ }
+ }
+ },
"css-tokenize": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/css-tokenize/-/css-tokenize-1.0.1.tgz",
@@ -4152,6 +4434,119 @@
"through": "2.3.8"
}
},
+ "cssesc": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-0.1.0.tgz",
+ "integrity": "sha1-yBSQPkViM3GgR3tAEJqq++6t27Q="
+ },
+ "cssnano": {
+ "version": "3.10.0",
+ "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-3.10.0.tgz",
+ "integrity": "sha1-Tzj2zqK5sX+gFJDyPx3GjqZcHDg=",
+ "requires": {
+ "autoprefixer": "6.7.7",
+ "decamelize": "1.2.0",
+ "defined": "1.0.0",
+ "has": "1.0.1",
+ "object-assign": "4.1.1",
+ "postcss": "5.2.18",
+ "postcss-calc": "5.3.1",
+ "postcss-colormin": "2.2.2",
+ "postcss-convert-values": "2.6.1",
+ "postcss-discard-comments": "2.0.4",
+ "postcss-discard-duplicates": "2.1.0",
+ "postcss-discard-empty": "2.1.0",
+ "postcss-discard-overridden": "0.1.1",
+ "postcss-discard-unused": "2.2.3",
+ "postcss-filter-plugins": "2.0.2",
+ "postcss-merge-idents": "2.1.7",
+ "postcss-merge-longhand": "2.0.2",
+ "postcss-merge-rules": "2.1.2",
+ "postcss-minify-font-values": "1.0.5",
+ "postcss-minify-gradients": "1.0.5",
+ "postcss-minify-params": "1.2.2",
+ "postcss-minify-selectors": "2.1.1",
+ "postcss-normalize-charset": "1.1.1",
+ "postcss-normalize-url": "3.0.8",
+ "postcss-ordered-values": "2.2.3",
+ "postcss-reduce-idents": "2.4.0",
+ "postcss-reduce-initial": "1.0.1",
+ "postcss-reduce-transforms": "1.0.4",
+ "postcss-svgo": "2.1.6",
+ "postcss-unique-selectors": "2.0.2",
+ "postcss-value-parser": "3.3.0",
+ "postcss-zindex": "2.2.0"
+ },
+ "dependencies": {
+ "autoprefixer": {
+ "version": "6.7.7",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-6.7.7.tgz",
+ "integrity": "sha1-Hb0cg1ZY41zj+ZhAmdsAWFx4IBQ=",
+ "requires": {
+ "browserslist": "1.7.7",
+ "caniuse-db": "1.0.30000808",
+ "normalize-range": "0.1.2",
+ "num2fraction": "1.2.2",
+ "postcss": "5.2.18",
+ "postcss-value-parser": "3.3.0"
+ }
+ },
+ "browserslist": {
+ "version": "1.7.7",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz",
+ "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=",
+ "requires": {
+ "caniuse-db": "1.0.30000808",
+ "electron-to-chromium": "1.3.30"
+ }
+ },
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "1.1.3",
+ "js-base64": "2.4.3",
+ "source-map": "0.5.7",
+ "supports-color": "3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "1.0.0"
+ }
+ }
+ }
+ },
+ "csso": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/csso/-/csso-2.3.2.tgz",
+ "integrity": "sha1-3dUsWHAz9J6Utx/FVWnyUuj/X4U=",
+ "requires": {
+ "clap": "1.2.3",
+ "source-map": "0.5.7"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ }
+ }
+ },
"cssom": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.2.tgz",
@@ -4191,6 +4586,12 @@
"integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=",
"dev": true
},
+ "cvss": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/cvss/-/cvss-1.0.2.tgz",
+ "integrity": "sha1-32fpK/EqeW9J6Sh5nI2zunS5/NY=",
+ "dev": true
+ },
"cycle": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz",
@@ -4350,7 +4751,7 @@
"requires": {
"file-type": "5.2.0",
"is-stream": "1.1.0",
- "tar-stream": "1.5.5"
+ "tar-stream": "1.6.0"
}
},
"decompress-tarbz2": {
@@ -4833,6 +5234,15 @@
"string_decoder": "0.10.31"
}
},
+ "source-map": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
+ "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
+ "dev": true,
+ "requires": {
+ "amdefine": "1.0.1"
+ }
+ },
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
@@ -5870,25 +6280,26 @@
"resolved": "https://registry.npmjs.org/eth-json-rpc-infura/-/eth-json-rpc-infura-3.0.0.tgz",
"integrity": "sha512-Ab6170AxlF4DK+HDImh52+AetwHPHstgg8uWtX4im26rqK7u4ziSfvUIUK2+/LK0pi0wbIFb8hZm5jPKAXDmBA==",
"requires": {
- "eth-json-rpc-middleware": "1.5.0",
+ "eth-json-rpc-middleware": "1.6.0",
"json-rpc-engine": "3.6.1",
"json-rpc-error": "2.0.0",
"tape": "4.8.0"
}
},
"eth-json-rpc-middleware": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.5.0.tgz",
- "integrity": "sha1-FrEFM4aqOAOxJXMqpt4H6t8Ghyk=",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.6.0.tgz",
+ "integrity": "sha512-tDVCTlrUvdqHKqivYMjtFZsdD7TtpNLBCfKAcOpaVs7orBMS/A8HWro6dIzNtTZIR05FAbJ3bioFOnZpuCew9Q==",
"requires": {
"async": "2.6.0",
"eth-query": "2.1.2",
- "eth-tx-summary": "3.1.2",
+ "eth-tx-summary": "3.2.1",
"ethereumjs-block": "1.7.0",
"ethereumjs-tx": "1.3.3",
- "ethereumjs-util": "5.1.5",
+ "ethereumjs-util": "5.2.0",
"ethereumjs-vm": "2.3.2",
"fetch-ponyfill": "4.1.0",
+ "json-rpc-engine": "3.6.1",
"json-rpc-error": "2.0.0",
"json-stable-stringify": "1.0.1",
"promise-to-callback": "1.0.0",
@@ -5896,9 +6307,9 @@
},
"dependencies": {
"ethereumjs-util": {
- "version": "5.1.5",
- "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.1.5.tgz",
- "integrity": "sha512-xPaSEATYJpMTCGowIt0oMZwFP4R1bxd6QsWgkcDvFL0JtXsr39p32WEcD14RscCjfP41YXZPCVWA4yAg0nrJmw==",
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz",
+ "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==",
"requires": {
"bn.js": "4.11.8",
"create-hash": "1.1.3",
@@ -6226,11 +6637,12 @@
}
},
"eth-tx-summary": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/eth-tx-summary/-/eth-tx-summary-3.1.2.tgz",
- "integrity": "sha1-44g2/J+LVvFNdZUvD15XD4j7IiA=",
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/eth-tx-summary/-/eth-tx-summary-3.2.1.tgz",
+ "integrity": "sha512-mu8g5tDkQxlFah58ggFhTzolE4OnYTj6j8SVsnGsiWT7WxN722RwnEsk/bco2foy+PLSEF2Mnoiw+wCqKoY72A==",
"requires": {
"async": "2.6.0",
+ "bn.js": "4.11.8",
"clone": "2.1.1",
"concat-stream": "1.6.0",
"end-of-stream": "1.4.0",
@@ -6238,12 +6650,46 @@
"ethereumjs-block": "1.7.0",
"ethereumjs-tx": "1.3.3",
"ethereumjs-util": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9",
- "ethereumjs-vm": "2.3.2",
+ "ethereumjs-vm": "2.3.5",
"through2": "2.0.3",
"treeify": "1.1.0",
"web3-provider-engine": "13.8.0"
},
"dependencies": {
+ "ethereumjs-vm": {
+ "version": "2.3.5",
+ "resolved": "https://registry.npmjs.org/ethereumjs-vm/-/ethereumjs-vm-2.3.5.tgz",
+ "integrity": "sha512-AJ7x44+xqyE5+UO3Nns19WkTdZfyqFZ+sEjIEpvme7Ipbe3iBU1uwCcHEdiu/yY9bdhr3IfSa/NfIKNeXPaRVQ==",
+ "requires": {
+ "async": "2.6.0",
+ "async-eventemitter": "0.2.4",
+ "ethereum-common": "0.2.0",
+ "ethereumjs-account": "2.0.4",
+ "ethereumjs-block": "1.7.0",
+ "ethereumjs-util": "5.2.0",
+ "fake-merkle-patricia-tree": "1.0.1",
+ "functional-red-black-tree": "1.0.1",
+ "merkle-patricia-tree": "2.3.0",
+ "rustbn.js": "0.1.1",
+ "safe-buffer": "5.1.1"
+ },
+ "dependencies": {
+ "ethereumjs-util": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz",
+ "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==",
+ "requires": {
+ "bn.js": "4.11.8",
+ "create-hash": "1.1.3",
+ "ethjs-util": "0.1.4",
+ "keccak": "1.4.0",
+ "rlp": "2.0.0",
+ "safe-buffer": "5.1.1",
+ "secp256k1": "3.4.0"
+ }
+ }
+ }
+ },
"web3-provider-engine": {
"version": "13.8.0",
"resolved": "https://registry.npmjs.org/web3-provider-engine/-/web3-provider-engine-13.8.0.tgz",
@@ -6255,8 +6701,8 @@
"eth-sig-util": "1.4.2",
"ethereumjs-block": "1.7.0",
"ethereumjs-tx": "1.3.3",
- "ethereumjs-util": "5.1.5",
- "ethereumjs-vm": "2.3.2",
+ "ethereumjs-util": "5.2.0",
+ "ethereumjs-vm": "2.3.5",
"fetch-ponyfill": "4.1.0",
"json-rpc-error": "2.0.0",
"json-stable-stringify": "1.0.1",
@@ -6271,9 +6717,9 @@
},
"dependencies": {
"ethereumjs-util": {
- "version": "5.1.5",
- "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.1.5.tgz",
- "integrity": "sha512-xPaSEATYJpMTCGowIt0oMZwFP4R1bxd6QsWgkcDvFL0JtXsr39p32WEcD14RscCjfP41YXZPCVWA4yAg0nrJmw==",
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz",
+ "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==",
"requires": {
"bn.js": "4.11.8",
"create-hash": "1.1.3",
@@ -7095,6 +7541,11 @@
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
},
+ "fastparse": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.1.tgz",
+ "integrity": "sha1-0eJkOzipTXWDtHkGDmxK/8lAcfg="
+ },
"faye-websocket": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.7.3.tgz",
@@ -7158,6 +7609,27 @@
"object-assign": "4.1.1"
}
},
+ "file-loader": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.11.tgz",
+ "integrity": "sha512-TGR4HU7HUsGg6GCOPJnFk06RhWgEWFLAGWiT6rcD+GRC2keU3s9RGJ+b3Z6/U73jwwNb2gKLJ7YCrp+jvU4ALg==",
+ "requires": {
+ "loader-utils": "1.1.0",
+ "schema-utils": "0.4.5"
+ },
+ "dependencies": {
+ "loader-utils": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz",
+ "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=",
+ "requires": {
+ "big.js": "3.2.0",
+ "emojis-list": "2.1.0",
+ "json5": "0.5.1"
+ }
+ }
+ }
+ },
"file-tree": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-tree/-/file-tree-1.0.0.tgz",
@@ -7259,7 +7731,7 @@
"requires": {
"detect-file": "1.0.0",
"is-glob": "3.1.0",
- "micromatch": "3.1.9",
+ "micromatch": "3.1.10",
"resolve-dir": "1.0.1"
},
"dependencies": {
@@ -7274,32 +7746,22 @@
"integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg="
},
"braces": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.1.tgz",
- "integrity": "sha512-SO5lYHA3vO6gz66erVvedSCkp7AKWdv6VcQ2N4ysXfPxdAlxAMMAdwegGGcv1Bqwm7naF1hNdk5d6AAIEHV2nQ==",
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
"requires": {
"arr-flatten": "1.1.0",
"array-unique": "0.3.2",
- "define-property": "1.0.0",
"extend-shallow": "2.0.1",
"fill-range": "4.0.0",
"isobject": "3.0.1",
- "kind-of": "6.0.2",
"repeat-element": "1.1.2",
"snapdragon": "0.8.1",
"snapdragon-node": "2.1.1",
"split-string": "3.1.0",
- "to-regex": "3.0.1"
+ "to-regex": "3.0.2"
},
"dependencies": {
- "define-property": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
- "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
- "requires": {
- "is-descriptor": "1.0.2"
- }
- },
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
@@ -7330,7 +7792,7 @@
"posix-character-classes": "0.1.1",
"regex-not": "1.0.0",
"snapdragon": "0.8.1",
- "to-regex": "3.0.1"
+ "to-regex": "3.0.2"
},
"dependencies": {
"define-property": {
@@ -7397,7 +7859,7 @@
"fragment-cache": "0.2.1",
"regex-not": "1.0.0",
"snapdragon": "0.8.1",
- "to-regex": "3.0.1"
+ "to-regex": "3.0.2"
},
"dependencies": {
"define-property": {
@@ -7506,21 +7968,6 @@
}
}
},
- "is-odd": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-2.0.0.tgz",
- "integrity": "sha512-OTiixgpZAT1M4NHgS5IguFp/Vz2VI3U7Goh4/HA1adtwyLtSBrxYlcSYkhpAE07s4fKEcjrFxyvtQBND4vFQyQ==",
- "requires": {
- "is-number": "4.0.0"
- },
- "dependencies": {
- "is-number": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
- "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ=="
- }
- }
- },
"isobject": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
@@ -7532,13 +7979,13 @@
"integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA=="
},
"micromatch": {
- "version": "3.1.9",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.9.tgz",
- "integrity": "sha512-SlIz6sv5UPaAVVFRKodKjCg48EbNoIhgetzfK/Cy0v5U52Z6zB136M8tp0UC9jM53LYbmIRihJszvvqpKkfm9g==",
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
"requires": {
"arr-diff": "4.0.0",
"array-unique": "0.3.2",
- "braces": "2.3.1",
+ "braces": "2.3.2",
"define-property": "2.0.2",
"extend-shallow": "3.0.2",
"extglob": "2.0.4",
@@ -7548,26 +7995,29 @@
"object.pick": "1.3.0",
"regex-not": "1.0.0",
"snapdragon": "0.8.1",
- "to-regex": "3.0.1"
+ "to-regex": "3.0.2"
}
},
- "nanomatch": {
- "version": "1.2.9",
- "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.9.tgz",
- "integrity": "sha512-n8R9bS8yQ6eSXaV6jHUpKzD8gLsin02w1HSFiegwrs9E098Ylhw5jdyKPaYqvHknHaSCKTPp7C8dGCQ0q9koXA==",
+ "to-regex": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
"requires": {
- "arr-diff": "4.0.0",
- "array-unique": "0.3.2",
"define-property": "2.0.2",
"extend-shallow": "3.0.2",
- "fragment-cache": "0.2.1",
- "is-odd": "2.0.0",
- "is-windows": "1.0.2",
- "kind-of": "6.0.2",
- "object.pick": "1.3.0",
- "regex-not": "1.0.0",
- "snapdragon": "0.8.1",
- "to-regex": "3.0.1"
+ "regex-not": "1.0.2",
+ "safe-regex": "1.1.0"
+ },
+ "dependencies": {
+ "regex-not": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+ "requires": {
+ "extend-shallow": "3.0.2",
+ "safe-regex": "1.1.0"
+ }
+ }
}
}
}
@@ -7679,9 +8129,9 @@
"dev": true
},
"flush-write-stream": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.2.tgz",
- "integrity": "sha1-yBuQ2HRnZvGmCaRoCZRsRd2K5Bc=",
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz",
+ "integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==",
"requires": {
"inherits": "2.0.3",
"readable-stream": "2.3.3"
@@ -7790,6 +8240,11 @@
"null-check": "1.0.0"
}
},
+ "fs-constants": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
+ },
"fs-exists-sync": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz",
@@ -8871,7 +9326,7 @@
"ethereumjs-account": "2.0.4",
"ethereumjs-block": "1.2.2",
"ethereumjs-tx": "1.3.3",
- "ethereumjs-util": "5.1.5",
+ "ethereumjs-util": "5.2.0",
"ethereumjs-vm": "2.3.3",
"ethereumjs-wallet": "0.6.0",
"fake-merkle-patricia-tree": "1.0.1",
@@ -8892,7 +9347,7 @@
"tmp": "0.0.31",
"web3": "1.0.0-beta.34",
"web3-provider-engine": "13.8.0",
- "websocket": "1.0.25",
+ "websocket": "1.0.26",
"yargs": "7.1.0"
},
"dependencies": {
@@ -8992,9 +9447,9 @@
}
},
"ethereumjs-util": {
- "version": "5.1.5",
- "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.1.5.tgz",
- "integrity": "sha512-xPaSEATYJpMTCGowIt0oMZwFP4R1bxd6QsWgkcDvFL0JtXsr39p32WEcD14RscCjfP41YXZPCVWA4yAg0nrJmw==",
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz",
+ "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==",
"requires": {
"bn.js": "4.11.6",
"create-hash": "1.1.3",
@@ -9015,7 +9470,7 @@
"ethereum-common": "0.2.0",
"ethereumjs-account": "2.0.4",
"ethereumjs-block": "1.7.1",
- "ethereumjs-util": "5.1.5",
+ "ethereumjs-util": "5.2.0",
"fake-merkle-patricia-tree": "1.0.1",
"functional-red-black-tree": "1.0.1",
"merkle-patricia-tree": "2.3.0",
@@ -9036,7 +9491,7 @@
"async": "2.6.0",
"ethereum-common": "0.2.0",
"ethereumjs-tx": "1.3.3",
- "ethereumjs-util": "5.1.5",
+ "ethereumjs-util": "5.2.0",
"merkle-patricia-tree": "2.3.0"
}
}
@@ -9174,7 +9629,7 @@
"eth-sig-util": "1.4.2",
"ethereumjs-block": "1.2.2",
"ethereumjs-tx": "1.3.3",
- "ethereumjs-util": "5.1.5",
+ "ethereumjs-util": "5.2.0",
"ethereumjs-vm": "2.3.3",
"fetch-ponyfill": "4.1.0",
"json-rpc-error": "2.0.0",
@@ -9694,7 +10149,7 @@
"array-sort": "1.0.0",
"color-support": "1.1.3",
"concat-stream": "1.6.0",
- "copy-props": "2.0.1",
+ "copy-props": "2.0.2",
"fancy-log": "1.3.2",
"gulplog": "1.0.0",
"interpret": "1.1.0",
@@ -10422,7 +10877,7 @@
"debug-fabulous": "1.0.0",
"detect-newline": "2.1.0",
"graceful-fs": "4.1.11",
- "source-map": "0.4.4",
+ "source-map": "0.7.2",
"strip-bom-string": "1.0.0",
"through2": "2.0.3"
},
@@ -11483,6 +11938,11 @@
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz",
"integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg=="
},
+ "html-comment-regex": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.1.tgz",
+ "integrity": "sha1-ZouTd26q5V696POtRkswekljYl4="
+ },
"html-encoding-sniffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz",
@@ -11776,6 +12236,19 @@
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
"integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ=="
},
+ "icss-replace-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz",
+ "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0="
+ },
+ "icss-utils": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-2.1.0.tgz",
+ "integrity": "sha1-g/Cg7DeL8yRheLbCrZE28TWxyWI=",
+ "requires": {
+ "postcss": "6.0.19"
+ }
+ },
"idb-global": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/idb-global/-/idb-global-2.1.0.tgz",
@@ -11888,8 +12361,7 @@
"indexes-of": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz",
- "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=",
- "dev": true
+ "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc="
},
"indexof": {
"version": "0.0.1",
@@ -11933,6 +12405,16 @@
"integrity": "sha1-Skxd2OT7Xps82mDIIt+tyu5m4K8=",
"requires": {
"source-map": "0.4.4"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
+ "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
+ "requires": {
+ "amdefine": "1.0.1"
+ }
+ }
}
},
"inquirer": {
@@ -12153,6 +12635,11 @@
"is-windows": "1.0.2"
}
},
+ "is-absolute-url": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz",
+ "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY="
+ },
"is-accessor-descriptor": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
@@ -12406,7 +12893,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-odd/-/is-odd-2.0.0.tgz",
"integrity": "sha512-OTiixgpZAT1M4NHgS5IguFp/Vz2VI3U7Goh4/HA1adtwyLtSBrxYlcSYkhpAE07s4fKEcjrFxyvtQBND4vFQyQ==",
- "dev": true,
"requires": {
"is-number": "4.0.0"
},
@@ -12414,8 +12900,7 @@
"is-number": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
- "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==",
- "dev": true
+ "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ=="
}
}
},
@@ -12543,6 +13028,14 @@
"integrity": "sha1-i1IMhfrnolM4LUsCZS4EVXbhO7g=",
"dev": true
},
+ "is-svg": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-2.1.0.tgz",
+ "integrity": "sha1-z2EJDaDZ77yrhyLeum8DIgjbsOk=",
+ "requires": {
+ "html-comment-regex": "1.1.1"
+ }
+ },
"is-symbol": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz",
@@ -13827,7 +14320,7 @@
"resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz",
"integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=",
"requires": {
- "flush-write-stream": "1.0.2"
+ "flush-write-stream": "1.0.3"
}
},
"left-pad": {
@@ -14472,6 +14965,11 @@
"integrity": "sha1-uo31+4QesKPoBEIysOJjqNxqKKI=",
"dev": true
},
+ "lodash.camelcase": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+ "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY="
+ },
"lodash.castarray": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz",
@@ -14498,6 +14996,12 @@
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
"integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168="
},
+ "lodash.defaults": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
+ "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=",
+ "dev": true
+ },
"lodash.escape": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz",
@@ -14585,6 +15089,12 @@
"integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=",
"dev": true
},
+ "lodash.tail": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.tail/-/lodash.tail-4.1.1.tgz",
+ "integrity": "sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=",
+ "dev": true
+ },
"lodash.template": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz",
@@ -14610,6 +15120,11 @@
"lodash.escape": "3.2.0"
}
},
+ "lodash.uniq": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
+ "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M="
+ },
"lodash.uniqby": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz",
@@ -14973,6 +15488,11 @@
"resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.0.tgz",
"integrity": "sha1-tlul/LNJopkkyOMz98alVi8uSEI="
},
+ "macaddress": {
+ "version": "0.2.8",
+ "resolved": "https://registry.npmjs.org/macaddress/-/macaddress-0.2.8.tgz",
+ "integrity": "sha1-WQTcU3w57G2+/q6QIycTX6hRHxI="
+ },
"mailcomposer": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/mailcomposer/-/mailcomposer-4.0.1.tgz",
@@ -15074,11 +15594,18 @@
}
},
"make-iterator": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.0.tgz",
- "integrity": "sha1-V7713IXSOSO6I3ZzJNjo+PPZaUs=",
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz",
+ "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==",
"requires": {
- "kind-of": "3.2.2"
+ "kind-of": "6.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+ "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA=="
+ }
}
},
"map-async": {
@@ -15127,7 +15654,7 @@
"integrity": "sha1-xvNINKDY28OzfCfui7yyfHd1WC4=",
"requires": {
"findup-sync": "2.0.0",
- "micromatch": "3.1.9",
+ "micromatch": "3.1.10",
"resolve": "1.4.0",
"stack-trace": "0.0.10"
},
@@ -15143,32 +15670,22 @@
"integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg="
},
"braces": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.1.tgz",
- "integrity": "sha512-SO5lYHA3vO6gz66erVvedSCkp7AKWdv6VcQ2N4ysXfPxdAlxAMMAdwegGGcv1Bqwm7naF1hNdk5d6AAIEHV2nQ==",
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
"requires": {
"arr-flatten": "1.1.0",
"array-unique": "0.3.2",
- "define-property": "1.0.0",
"extend-shallow": "2.0.1",
"fill-range": "4.0.0",
"isobject": "3.0.1",
- "kind-of": "6.0.2",
"repeat-element": "1.1.2",
"snapdragon": "0.8.1",
"snapdragon-node": "2.1.1",
"split-string": "3.1.0",
- "to-regex": "3.0.1"
+ "to-regex": "3.0.2"
},
"dependencies": {
- "define-property": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
- "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
- "requires": {
- "is-descriptor": "1.0.2"
- }
- },
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
@@ -15199,7 +15716,7 @@
"posix-character-classes": "0.1.1",
"regex-not": "1.0.0",
"snapdragon": "0.8.1",
- "to-regex": "3.0.1"
+ "to-regex": "3.0.2"
},
"dependencies": {
"define-property": {
@@ -15266,7 +15783,7 @@
"fragment-cache": "0.2.1",
"regex-not": "1.0.0",
"snapdragon": "0.8.1",
- "to-regex": "3.0.1"
+ "to-regex": "3.0.2"
},
"dependencies": {
"define-property": {
@@ -15362,21 +15879,6 @@
}
}
},
- "is-odd": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-2.0.0.tgz",
- "integrity": "sha512-OTiixgpZAT1M4NHgS5IguFp/Vz2VI3U7Goh4/HA1adtwyLtSBrxYlcSYkhpAE07s4fKEcjrFxyvtQBND4vFQyQ==",
- "requires": {
- "is-number": "4.0.0"
- },
- "dependencies": {
- "is-number": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
- "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ=="
- }
- }
- },
"isobject": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
@@ -15388,13 +15890,13 @@
"integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA=="
},
"micromatch": {
- "version": "3.1.9",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.9.tgz",
- "integrity": "sha512-SlIz6sv5UPaAVVFRKodKjCg48EbNoIhgetzfK/Cy0v5U52Z6zB136M8tp0UC9jM53LYbmIRihJszvvqpKkfm9g==",
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
"requires": {
"arr-diff": "4.0.0",
"array-unique": "0.3.2",
- "braces": "2.3.1",
+ "braces": "2.3.2",
"define-property": "2.0.2",
"extend-shallow": "3.0.2",
"extglob": "2.0.4",
@@ -15404,26 +15906,29 @@
"object.pick": "1.3.0",
"regex-not": "1.0.0",
"snapdragon": "0.8.1",
- "to-regex": "3.0.1"
+ "to-regex": "3.0.2"
}
},
- "nanomatch": {
- "version": "1.2.9",
- "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.9.tgz",
- "integrity": "sha512-n8R9bS8yQ6eSXaV6jHUpKzD8gLsin02w1HSFiegwrs9E098Ylhw5jdyKPaYqvHknHaSCKTPp7C8dGCQ0q9koXA==",
+ "to-regex": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
"requires": {
- "arr-diff": "4.0.0",
- "array-unique": "0.3.2",
"define-property": "2.0.2",
"extend-shallow": "3.0.2",
- "fragment-cache": "0.2.1",
- "is-odd": "2.0.0",
- "is-windows": "1.0.2",
- "kind-of": "6.0.2",
- "object.pick": "1.3.0",
- "regex-not": "1.0.0",
- "snapdragon": "0.8.1",
- "to-regex": "3.0.1"
+ "regex-not": "1.0.2",
+ "safe-regex": "1.1.0"
+ },
+ "dependencies": {
+ "regex-not": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+ "requires": {
+ "extend-shallow": "3.0.2",
+ "safe-regex": "1.1.0"
+ }
+ }
}
}
}
@@ -15437,6 +15942,11 @@
"minimatch": "3.0.4"
}
},
+ "math-expression-evaluator": {
+ "version": "1.2.17",
+ "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz",
+ "integrity": "sha1-3oGf282E3M2PrlnGrreWFbnSZqw="
+ },
"mathml-tag-names": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.0.1.tgz",
@@ -15943,6 +16453,24 @@
}
}
},
+ "mixin-object": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz",
+ "integrity": "sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=",
+ "dev": true,
+ "requires": {
+ "for-in": "0.1.8",
+ "is-extendable": "0.1.1"
+ },
+ "dependencies": {
+ "for-in": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz",
+ "integrity": "sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=",
+ "dev": true
+ }
+ }
+ },
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
@@ -16167,7 +16695,6 @@
"version": "1.2.9",
"resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.9.tgz",
"integrity": "sha512-n8R9bS8yQ6eSXaV6jHUpKzD8gLsin02w1HSFiegwrs9E098Ylhw5jdyKPaYqvHknHaSCKTPp7C8dGCQ0q9koXA==",
- "dev": true,
"requires": {
"arr-diff": "4.0.0",
"array-unique": "0.3.2",
@@ -16186,20 +16713,17 @@
"arr-diff": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
- "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
- "dev": true
+ "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA="
},
"array-unique": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
- "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
- "dev": true
+ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg="
},
"define-property": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
"integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
- "dev": true,
"requires": {
"is-descriptor": "1.0.2",
"isobject": "3.0.1"
@@ -16209,7 +16733,6 @@
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
"integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
- "dev": true,
"requires": {
"assign-symbols": "1.0.0",
"is-extendable": "1.0.1"
@@ -16219,7 +16742,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
"integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
- "dev": true,
"requires": {
"is-plain-object": "2.0.4"
}
@@ -16227,14 +16749,12 @@
"isobject": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
- "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
- "dev": true
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
},
"kind-of": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
- "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
- "dev": true
+ "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA=="
}
}
},
@@ -16769,6 +17289,12 @@
"integrity": "sha1-WG24EB2zDLRDjrVGc3pBqtDPE9U=",
"dev": true
},
+ "nodesecurity-npm-utils": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/nodesecurity-npm-utils/-/nodesecurity-npm-utils-6.0.0.tgz",
+ "integrity": "sha512-NLRle1woNaT2orR6fue2jNqkhxDTktgJj3sZxvR/8kp21pvOY7Gwlx5wvo0H8ZVPqdgd2nE2ADB9wDu5Cl8zNg==",
+ "dev": true
+ },
"nomnom": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.6.2.tgz",
@@ -16856,6 +17382,250 @@
"set-blocking": "2.0.0"
}
},
+ "nsp": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/nsp/-/nsp-3.2.1.tgz",
+ "integrity": "sha512-dLmGi7IGixJEHKetErIH460MYiYIzAoxuVsloZFu9e1p9U8K0yULx7YQ1+VzrjZbB+wqq67ES1SfOvKVb/qMDQ==",
+ "dev": true,
+ "requires": {
+ "chalk": "2.4.1",
+ "cli-table2": "0.2.0",
+ "cvss": "1.0.2",
+ "https-proxy-agent": "2.2.1",
+ "inquirer": "3.3.0",
+ "nodesecurity-npm-utils": "6.0.0",
+ "semver": "5.4.1",
+ "wreck": "12.5.1",
+ "yargs": "9.0.1"
+ },
+ "dependencies": {
+ "agent-base": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.0.tgz",
+ "integrity": "sha512-c+R/U5X+2zz2+UCrCFv6odQzJdoqI+YecuhnAJLa1zYaMc13zPfwMwZrr91Pd1DYNo/yPRbiM4WVf9whgwFsIg==",
+ "dev": true,
+ "requires": {
+ "es6-promisify": "5.0.0"
+ }
+ },
+ "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.1"
+ }
+ },
+ "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.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.4.0"
+ }
+ },
+ "debug": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "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.1.0",
+ "get-stream": "3.0.0",
+ "is-stream": "1.1.0",
+ "npm-run-path": "2.0.2",
+ "p-finally": "1.0.0",
+ "signal-exit": "3.0.2",
+ "strip-eof": "1.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"
+ }
+ },
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+ "dev": true
+ },
+ "https-proxy-agent": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz",
+ "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==",
+ "dev": true,
+ "requires": {
+ "agent-base": "4.2.0",
+ "debug": "3.1.0"
+ }
+ },
+ "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
+ },
+ "load-json-file": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
+ "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "4.1.11",
+ "parse-json": "2.2.0",
+ "pify": "2.3.0",
+ "strip-bom": "3.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"
+ }
+ },
+ "path-type": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz",
+ "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=",
+ "dev": true,
+ "requires": {
+ "pify": "2.3.0"
+ }
+ },
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+ "dev": true
+ },
+ "read-pkg": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",
+ "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=",
+ "dev": true,
+ "requires": {
+ "load-json-file": "2.0.0",
+ "normalize-package-data": "2.4.0",
+ "path-type": "2.0.0"
+ }
+ },
+ "read-pkg-up": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz",
+ "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=",
+ "dev": true,
+ "requires": {
+ "find-up": "2.1.0",
+ "read-pkg": "2.0.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": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "5.4.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
+ "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
+ "dev": true,
+ "requires": {
+ "has-flag": "3.0.0"
+ }
+ },
+ "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
+ },
+ "yargs": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-9.0.1.tgz",
+ "integrity": "sha1-UqzCP+7Kw0BCB47njAwAf1CF20w=",
+ "dev": true,
+ "requires": {
+ "camelcase": "4.1.0",
+ "cliui": "3.2.0",
+ "decamelize": "1.2.0",
+ "get-caller-file": "1.0.2",
+ "os-locale": "2.1.0",
+ "read-pkg-up": "2.0.0",
+ "require-directory": "2.1.1",
+ "require-main-filename": "1.0.1",
+ "set-blocking": "2.0.0",
+ "string-width": "2.1.1",
+ "which-module": "2.0.0",
+ "y18n": "3.2.1",
+ "yargs-parser": "7.0.0"
+ }
+ },
+ "yargs-parser": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz",
+ "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=",
+ "dev": true,
+ "requires": {
+ "camelcase": "4.1.0"
+ }
+ }
+ }
+ },
"nth-check": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz",
@@ -18805,6 +19575,12 @@
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz",
"integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0="
},
+ "object-path": {
+ "version": "0.9.2",
+ "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.9.2.tgz",
+ "integrity": "sha1-D9mnT8X60a45aLWGvaXGMr1sBaU=",
+ "dev": true
+ },
"object-visit": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
@@ -18875,7 +19651,7 @@
"integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=",
"requires": {
"for-own": "1.0.0",
- "make-iterator": "1.0.0"
+ "make-iterator": "1.0.1"
},
"dependencies": {
"for-own": {
@@ -18918,7 +19694,7 @@
"integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=",
"requires": {
"for-own": "1.0.0",
- "make-iterator": "1.0.0"
+ "make-iterator": "1.0.1"
},
"dependencies": {
"for-own": {
@@ -19397,6 +20173,24 @@
"resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
"integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ="
},
+ "path": {
+ "version": "0.12.7",
+ "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz",
+ "integrity": "sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=",
+ "dev": true,
+ "requires": {
+ "process": "0.11.10",
+ "util": "0.10.3"
+ },
+ "dependencies": {
+ "process": {
+ "version": "0.11.10",
+ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+ "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=",
+ "dev": true
+ }
+ }
+ },
"path-browserify": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz",
@@ -19903,6 +20697,364 @@
}
}
},
+ "postcss-calc": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-5.3.1.tgz",
+ "integrity": "sha1-d7rnypKK2FcW4v2kLyYb98HWW14=",
+ "requires": {
+ "postcss": "5.2.18",
+ "postcss-message-helpers": "2.0.0",
+ "reduce-css-calc": "1.3.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "1.1.3",
+ "js-base64": "2.4.3",
+ "source-map": "0.5.7",
+ "supports-color": "3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-colormin": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-2.2.2.tgz",
+ "integrity": "sha1-ZjFBfV8OkJo9fsJrJMio0eT5bks=",
+ "requires": {
+ "colormin": "1.1.2",
+ "postcss": "5.2.18",
+ "postcss-value-parser": "3.3.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "1.1.3",
+ "js-base64": "2.4.3",
+ "source-map": "0.5.7",
+ "supports-color": "3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-convert-values": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz",
+ "integrity": "sha1-u9hZPFwf0uPRwyK7kl3K6Nrk1i0=",
+ "requires": {
+ "postcss": "5.2.18",
+ "postcss-value-parser": "3.3.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "1.1.3",
+ "js-base64": "2.4.3",
+ "source-map": "0.5.7",
+ "supports-color": "3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-discard-comments": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz",
+ "integrity": "sha1-vv6J+v1bPazlzM5Rt2uBUUvgDj0=",
+ "requires": {
+ "postcss": "5.2.18"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "1.1.3",
+ "js-base64": "2.4.3",
+ "source-map": "0.5.7",
+ "supports-color": "3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-discard-duplicates": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz",
+ "integrity": "sha1-uavye4isGIFYpesSq8riAmO5GTI=",
+ "requires": {
+ "postcss": "5.2.18"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "1.1.3",
+ "js-base64": "2.4.3",
+ "source-map": "0.5.7",
+ "supports-color": "3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-discard-empty": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz",
+ "integrity": "sha1-0rS9nVztXr2Nyt52QMfXzX9PkrU=",
+ "requires": {
+ "postcss": "5.2.18"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "1.1.3",
+ "js-base64": "2.4.3",
+ "source-map": "0.5.7",
+ "supports-color": "3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-discard-overridden": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz",
+ "integrity": "sha1-ix6vVU9ob7KIzYdMVWZ7CqNmjVg=",
+ "requires": {
+ "postcss": "5.2.18"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "1.1.3",
+ "js-base64": "2.4.3",
+ "source-map": "0.5.7",
+ "supports-color": "3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-discard-unused": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz",
+ "integrity": "sha1-vOMLLMWR/8Y0Mitfs0ZLbZNPRDM=",
+ "requires": {
+ "postcss": "5.2.18",
+ "uniqs": "2.0.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "1.1.3",
+ "js-base64": "2.4.3",
+ "source-map": "0.5.7",
+ "supports-color": "3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-filter-plugins": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-filter-plugins/-/postcss-filter-plugins-2.0.2.tgz",
+ "integrity": "sha1-bYWGJTTXNaxCDkqFgG4fXUKG2Ew=",
+ "requires": {
+ "postcss": "5.2.18",
+ "uniqid": "4.1.1"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "1.1.3",
+ "js-base64": "2.4.3",
+ "source-map": "0.5.7",
+ "supports-color": "3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "1.0.0"
+ }
+ }
+ }
+ },
"postcss-less": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/postcss-less/-/postcss-less-0.14.0.tgz",
@@ -19953,6 +21105,617 @@
"integrity": "sha1-J7Ocb02U+Bsac7j3Y1HGCeXO8kQ=",
"dev": true
},
+ "postcss-merge-idents": {
+ "version": "2.1.7",
+ "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz",
+ "integrity": "sha1-TFUwMTwI4dWzu/PSu8dH4njuonA=",
+ "requires": {
+ "has": "1.0.1",
+ "postcss": "5.2.18",
+ "postcss-value-parser": "3.3.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "1.1.3",
+ "js-base64": "2.4.3",
+ "source-map": "0.5.7",
+ "supports-color": "3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-merge-longhand": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz",
+ "integrity": "sha1-I9kM0Sewp3mUkVMyc5A0oaTz1lg=",
+ "requires": {
+ "postcss": "5.2.18"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "1.1.3",
+ "js-base64": "2.4.3",
+ "source-map": "0.5.7",
+ "supports-color": "3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-merge-rules": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz",
+ "integrity": "sha1-0d9d+qexrMO+VT8OnhDofGG19yE=",
+ "requires": {
+ "browserslist": "1.7.7",
+ "caniuse-api": "1.6.1",
+ "postcss": "5.2.18",
+ "postcss-selector-parser": "2.2.3",
+ "vendors": "1.0.2"
+ },
+ "dependencies": {
+ "browserslist": {
+ "version": "1.7.7",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz",
+ "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=",
+ "requires": {
+ "caniuse-db": "1.0.30000808",
+ "electron-to-chromium": "1.3.30"
+ }
+ },
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "1.1.3",
+ "js-base64": "2.4.3",
+ "source-map": "0.5.7",
+ "supports-color": "3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-message-helpers": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz",
+ "integrity": "sha1-pPL0+rbk/gAvCu0ABHjN9S+bpg4="
+ },
+ "postcss-minify-font-values": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz",
+ "integrity": "sha1-S1jttWZB66fIR0qzUmyv17vey2k=",
+ "requires": {
+ "object-assign": "4.1.1",
+ "postcss": "5.2.18",
+ "postcss-value-parser": "3.3.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "1.1.3",
+ "js-base64": "2.4.3",
+ "source-map": "0.5.7",
+ "supports-color": "3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-minify-gradients": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz",
+ "integrity": "sha1-Xb2hE3NwP4PPtKPqOIHY11/15uE=",
+ "requires": {
+ "postcss": "5.2.18",
+ "postcss-value-parser": "3.3.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "1.1.3",
+ "js-base64": "2.4.3",
+ "source-map": "0.5.7",
+ "supports-color": "3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-minify-params": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz",
+ "integrity": "sha1-rSzgcTc7lDs9kwo/pZo1jCjW8fM=",
+ "requires": {
+ "alphanum-sort": "1.0.2",
+ "postcss": "5.2.18",
+ "postcss-value-parser": "3.3.0",
+ "uniqs": "2.0.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "1.1.3",
+ "js-base64": "2.4.3",
+ "source-map": "0.5.7",
+ "supports-color": "3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-minify-selectors": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz",
+ "integrity": "sha1-ssapjAByz5G5MtGkllCBFDEXNb8=",
+ "requires": {
+ "alphanum-sort": "1.0.2",
+ "has": "1.0.1",
+ "postcss": "5.2.18",
+ "postcss-selector-parser": "2.2.3"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "1.1.3",
+ "js-base64": "2.4.3",
+ "source-map": "0.5.7",
+ "supports-color": "3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-modules-extract-imports": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.0.tgz",
+ "integrity": "sha1-ZhQOzs447wa/DT41XWm/WdFB6oU=",
+ "requires": {
+ "postcss": "6.0.19"
+ }
+ },
+ "postcss-modules-local-by-default": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz",
+ "integrity": "sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=",
+ "requires": {
+ "css-selector-tokenizer": "0.7.0",
+ "postcss": "6.0.19"
+ }
+ },
+ "postcss-modules-scope": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz",
+ "integrity": "sha1-1upkmUx5+XtipytCb75gVqGUu5A=",
+ "requires": {
+ "css-selector-tokenizer": "0.7.0",
+ "postcss": "6.0.19"
+ }
+ },
+ "postcss-modules-values": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz",
+ "integrity": "sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=",
+ "requires": {
+ "icss-replace-symbols": "1.1.0",
+ "postcss": "6.0.19"
+ }
+ },
+ "postcss-normalize-charset": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz",
+ "integrity": "sha1-757nEhLX/nWceO0WL2HtYrXLk/E=",
+ "requires": {
+ "postcss": "5.2.18"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "1.1.3",
+ "js-base64": "2.4.3",
+ "source-map": "0.5.7",
+ "supports-color": "3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-normalize-url": {
+ "version": "3.0.8",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz",
+ "integrity": "sha1-EI90s/L82viRov+j6kWSJ5/HgiI=",
+ "requires": {
+ "is-absolute-url": "2.1.0",
+ "normalize-url": "1.9.1",
+ "postcss": "5.2.18",
+ "postcss-value-parser": "3.3.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "normalize-url": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz",
+ "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=",
+ "requires": {
+ "object-assign": "4.1.1",
+ "prepend-http": "1.0.4",
+ "query-string": "4.3.4",
+ "sort-keys": "1.1.2"
+ }
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "1.1.3",
+ "js-base64": "2.4.3",
+ "source-map": "0.5.7",
+ "supports-color": "3.2.3"
+ }
+ },
+ "prepend-http": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
+ "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw="
+ },
+ "query-string": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
+ "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
+ "requires": {
+ "object-assign": "4.1.1",
+ "strict-uri-encode": "1.1.0"
+ }
+ },
+ "sort-keys": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
+ "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=",
+ "requires": {
+ "is-plain-obj": "1.1.0"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-ordered-values": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz",
+ "integrity": "sha1-7sbCpntsQSqNsgQud/6NpD+VwR0=",
+ "requires": {
+ "postcss": "5.2.18",
+ "postcss-value-parser": "3.3.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "1.1.3",
+ "js-base64": "2.4.3",
+ "source-map": "0.5.7",
+ "supports-color": "3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-reduce-idents": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz",
+ "integrity": "sha1-wsbSDMlYKE9qv75j92Cb9AkFmtM=",
+ "requires": {
+ "postcss": "5.2.18",
+ "postcss-value-parser": "3.3.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "1.1.3",
+ "js-base64": "2.4.3",
+ "source-map": "0.5.7",
+ "supports-color": "3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-reduce-initial": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz",
+ "integrity": "sha1-aPgGlfBF0IJjqHmtJA343WT2ROo=",
+ "requires": {
+ "postcss": "5.2.18"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "1.1.3",
+ "js-base64": "2.4.3",
+ "source-map": "0.5.7",
+ "supports-color": "3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-reduce-transforms": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz",
+ "integrity": "sha1-/3b02CEkN7McKYpC0uFEQCV3GuE=",
+ "requires": {
+ "has": "1.0.1",
+ "postcss": "5.2.18",
+ "postcss-value-parser": "3.3.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "1.1.3",
+ "js-base64": "2.4.3",
+ "source-map": "0.5.7",
+ "supports-color": "3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "1.0.0"
+ }
+ }
+ }
+ },
"postcss-reporter": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-3.0.0.tgz",
@@ -20054,7 +21817,6 @@
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz",
"integrity": "sha1-+UN3iGBsPJrO4W/+jYsWKX8nu5A=",
- "dev": true,
"requires": {
"flatten": "1.0.2",
"indexes-of": "1.0.1",
@@ -20064,8 +21826,7 @@
"flatten": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz",
- "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=",
- "dev": true
+ "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I="
}
}
},
@@ -20114,11 +21875,135 @@
}
}
},
+ "postcss-svgo": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-2.1.6.tgz",
+ "integrity": "sha1-tt8YqmE7Zm4TPwittSGcJoSsEI0=",
+ "requires": {
+ "is-svg": "2.1.0",
+ "postcss": "5.2.18",
+ "postcss-value-parser": "3.3.0",
+ "svgo": "0.7.2"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "1.1.3",
+ "js-base64": "2.4.3",
+ "source-map": "0.5.7",
+ "supports-color": "3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-unique-selectors": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz",
+ "integrity": "sha1-mB1X0p3csz57Hf4f1DuGSfkzyh0=",
+ "requires": {
+ "alphanum-sort": "1.0.2",
+ "postcss": "5.2.18",
+ "uniqs": "2.0.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "1.1.3",
+ "js-base64": "2.4.3",
+ "source-map": "0.5.7",
+ "supports-color": "3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "1.0.0"
+ }
+ }
+ }
+ },
"postcss-value-parser": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz",
"integrity": "sha1-h/OPnxj3dKSrTIojL1xc6IcqnRU="
},
+ "postcss-zindex": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-2.2.0.tgz",
+ "integrity": "sha1-0hCd3AVbka9n/EyzsCWUZjnSryI=",
+ "requires": {
+ "has": "1.0.1",
+ "postcss": "5.2.18",
+ "uniqs": "2.0.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "1.1.3",
+ "js-base64": "2.4.3",
+ "source-map": "0.5.7",
+ "supports-color": "3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "1.0.0"
+ }
+ }
+ }
+ },
"precond": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/precond/-/precond-0.2.3.tgz",
@@ -21171,6 +23056,38 @@
"dev": true,
"optional": true
},
+ "reduce-css-calc": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz",
+ "integrity": "sha1-dHyRTgSWFKTJz7umKYca0dKSdxY=",
+ "requires": {
+ "balanced-match": "0.4.2",
+ "math-expression-evaluator": "1.2.17",
+ "reduce-function-call": "1.0.2"
+ },
+ "dependencies": {
+ "balanced-match": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz",
+ "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg="
+ }
+ }
+ },
+ "reduce-function-call": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.2.tgz",
+ "integrity": "sha1-WiAL+S4ON3UXUv5FsKszD9S2vpk=",
+ "requires": {
+ "balanced-match": "0.4.2"
+ },
+ "dependencies": {
+ "balanced-match": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz",
+ "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg="
+ }
+ }
+ },
"redux": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/redux/-/redux-3.7.2.tgz",
@@ -21237,6 +23154,12 @@
"extend-shallow": "2.0.1"
}
},
+ "regex-parser": {
+ "version": "2.2.9",
+ "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.9.tgz",
+ "integrity": "sha512-VncXxOF6uFlYog5prG2j+e2UGJeam5MfNiJnB/qEgo4KTnMm2XrELCg4rNZ6IlaEUZnGlb8aB6lXowCRQtTkkA==",
+ "dev": true
+ },
"regexpu-core": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz",
@@ -21546,6 +23469,54 @@
"resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
"integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo="
},
+ "resolve-url-loader": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-2.3.0.tgz",
+ "integrity": "sha512-RaEUWgF/B6aTg9VKaOv2o6dfm5f75/lGh8S+SQwoMcBm48WkA2nhLR+V7KEawkxXjU4lLB16IVeHCe7F69nyVw==",
+ "dev": true,
+ "requires": {
+ "adjust-sourcemap-loader": "1.2.0",
+ "camelcase": "4.1.0",
+ "convert-source-map": "1.5.1",
+ "loader-utils": "1.1.0",
+ "lodash.defaults": "4.2.0",
+ "rework": "1.0.1",
+ "rework-visit": "1.0.0",
+ "source-map": "0.5.7",
+ "urix": "0.1.0"
+ },
+ "dependencies": {
+ "camelcase": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
+ "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
+ "dev": true
+ },
+ "convert-source-map": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz",
+ "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=",
+ "dev": true
+ },
+ "loader-utils": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz",
+ "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=",
+ "dev": true,
+ "requires": {
+ "big.js": "3.2.0",
+ "emojis-list": "2.1.0",
+ "json5": "0.5.1"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true
+ }
+ }
+ },
"response-stream": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/response-stream/-/response-stream-0.0.0.tgz",
@@ -21581,8 +23552,7 @@
"ret": {
"version": "0.1.15",
"resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
- "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
- "dev": true
+ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg=="
},
"revalidator": {
"version": "0.1.8",
@@ -21590,6 +23560,30 @@
"integrity": "sha1-/s5hv6DBtSoga9axgZgYS91SOjs=",
"dev": true
},
+ "rework": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/rework/-/rework-1.0.1.tgz",
+ "integrity": "sha1-MIBqhBNCtUUQqkEQhQzUhTQUSqc=",
+ "dev": true,
+ "requires": {
+ "convert-source-map": "0.3.5",
+ "css": "2.2.1"
+ },
+ "dependencies": {
+ "convert-source-map": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-0.3.5.tgz",
+ "integrity": "sha1-8dgClQr33SYxof6+BZZVDIarMZA=",
+ "dev": true
+ }
+ }
+ },
+ "rework-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/rework-visit/-/rework-visit-1.0.0.tgz",
+ "integrity": "sha1-mUWygD8hni96ygCtuLyfZA+ELJo=",
+ "dev": true
+ },
"right-align": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
@@ -21682,7 +23676,6 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
"integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
- "dev": true,
"requires": {
"ret": "0.1.15"
}
@@ -21765,11 +23758,63 @@
}
}
},
+ "sass-loader": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.0.1.tgz",
+ "integrity": "sha512-MeVVJFejJELlAbA7jrRchi88PGP6U9yIfqyiG+bBC4a9s2PX+ulJB9h8bbEohtPBfZmlLhNZ0opQM9hovRXvlw==",
+ "dev": true,
+ "requires": {
+ "clone-deep": "2.0.2",
+ "loader-utils": "1.1.0",
+ "lodash.tail": "4.1.1",
+ "neo-async": "2.5.0",
+ "pify": "3.0.0"
+ },
+ "dependencies": {
+ "loader-utils": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz",
+ "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=",
+ "dev": true,
+ "requires": {
+ "big.js": "3.2.0",
+ "emojis-list": "2.1.0",
+ "json5": "0.5.1"
+ }
+ }
+ }
+ },
"sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
- "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
- "dev": true
+ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
+ },
+ "schema-utils": {
+ "version": "0.4.5",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.5.tgz",
+ "integrity": "sha512-yYrjb9TX2k/J1Y5UNy3KYdZq10xhYcF8nMpAW6o3hy6Q8WSIEf9lJHG/ePnOBfziPM3fvQwfOwa13U/Fh8qTfA==",
+ "requires": {
+ "ajv": "6.4.0",
+ "ajv-keywords": "3.2.0"
+ },
+ "dependencies": {
+ "ajv": {
+ "version": "6.4.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.4.0.tgz",
+ "integrity": "sha1-06/3jpJ3VJdx2vAWTP9ISCt1T8Y=",
+ "requires": {
+ "fast-deep-equal": "1.0.0",
+ "fast-json-stable-stringify": "2.0.0",
+ "json-schema-traverse": "0.3.1",
+ "uri-js": "3.0.2"
+ }
+ },
+ "ajv-keywords": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz",
+ "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo="
+ }
+ }
},
"scoped-regex": {
"version": "1.0.0",
@@ -21856,6 +23901,16 @@
"requires": {
"js-base64": "2.4.3",
"source-map": "0.4.4"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
+ "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
+ "requires": {
+ "amdefine": "1.0.1"
+ }
+ }
}
},
"secp256k1": {
@@ -22036,6 +24091,25 @@
"nan": "2.8.0"
}
},
+ "shallow-clone": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-1.0.0.tgz",
+ "integrity": "sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==",
+ "dev": true,
+ "requires": {
+ "is-extendable": "0.1.1",
+ "kind-of": "5.1.0",
+ "mixin-object": "2.0.1"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+ "dev": true
+ }
+ }
+ },
"shallow-copy": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/shallow-copy/-/shallow-copy-0.0.1.tgz",
@@ -22718,12 +24792,10 @@
"integrity": "sha512-I2UmuJSRr/T8jisiROLU3A3ltr+swpniSmNPI4Ml3ZCX6tVnDsuZzK7F2hl5jTqbZBWCEKlj5HRQiPExXLgE8A=="
},
"source-map": {
- "version": "0.4.4",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
- "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
- "requires": {
- "amdefine": "1.0.1"
- }
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.2.tgz",
+ "integrity": "sha512-NDJB/R2BS7YJG0tP9SbE4DKwKj1idLT5RJqfVYZ7dreFX7wulZT3xxVhbYKrQo9n0JkRptl51TrX/5VK3HodMA==",
+ "dev": true
},
"source-map-resolve": {
"version": "0.5.1",
@@ -22920,7 +24992,7 @@
"requires": {
"esprima": "1.0.4",
"estraverse": "1.3.2",
- "source-map": "0.4.4"
+ "source-map": "0.7.2"
}
},
"esprima": {
@@ -23419,6 +25491,29 @@
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
},
+ "style-loader": {
+ "version": "0.21.0",
+ "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.21.0.tgz",
+ "integrity": "sha512-T+UNsAcl3Yg+BsPKs1vd22Fr8sVT+CJMtzqc6LEw9bbJZb43lm9GoeIfUcDEefBSWC0BhYbcdupV1GtI4DGzxg==",
+ "dev": true,
+ "requires": {
+ "loader-utils": "1.1.0",
+ "schema-utils": "0.4.5"
+ },
+ "dependencies": {
+ "loader-utils": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz",
+ "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=",
+ "dev": true,
+ "requires": {
+ "big.js": "3.2.0",
+ "emojis-list": "2.1.0",
+ "json5": "0.5.1"
+ }
+ }
+ }
+ },
"style-search": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz",
@@ -23954,6 +26049,41 @@
"integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=",
"dev": true
},
+ "svgo": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/svgo/-/svgo-0.7.2.tgz",
+ "integrity": "sha1-n1dyQTlSE1xv779Ar+ak+qiLS7U=",
+ "requires": {
+ "coa": "1.0.4",
+ "colors": "1.1.2",
+ "csso": "2.3.2",
+ "js-yaml": "3.7.0",
+ "mkdirp": "0.5.1",
+ "sax": "1.2.4",
+ "whet.extend": "0.9.9"
+ },
+ "dependencies": {
+ "colors": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
+ "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM="
+ },
+ "esprima": {
+ "version": "2.7.3",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz",
+ "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE="
+ },
+ "js-yaml": {
+ "version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz",
+ "integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=",
+ "requires": {
+ "argparse": "1.0.9",
+ "esprima": "2.7.3"
+ }
+ }
+ }
+ },
"sw-controller": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sw-controller/-/sw-controller-1.0.3.tgz",
@@ -24245,13 +26375,16 @@
}
},
"tar-stream": {
- "version": "1.5.5",
- "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.5.tgz",
- "integrity": "sha512-mQdgLPc/Vjfr3VWqWbfxW8yQNiJCbAZ+Gf6GDu1Cy0bdb33ofyiNGBtAY96jHFhDuivCwgW1H9DgTON+INiXgg==",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.0.tgz",
+ "integrity": "sha512-lh2iAPG/BHNmN6WB9Ybdynk9rEJ5GD/dy4zscHmVlwa1dq2tpE+BH78i5vjYwYVWEaOXGBjzxr89aVACF17Cpw==",
"requires": {
"bl": "1.2.1",
+ "buffer-alloc": "1.1.0",
"end-of-stream": "1.4.0",
+ "fs-constants": "1.0.0",
"readable-stream": "2.3.3",
+ "to-buffer": "1.1.1",
"xtend": "4.0.1"
}
},
@@ -24639,6 +26772,11 @@
"resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
"integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M="
},
+ "to-buffer": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz",
+ "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg=="
+ },
"to-fast-properties": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz",
@@ -24972,55 +27110,12 @@
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.17.tgz",
"integrity": "sha512-uRdSdu1oA1rncCQL7sCj8vSyZkgtL7faaw9Tc9rZ3mGgraQ7+Pdx7w5mnOSF3gw9ZNG6oc+KXfkon3bKuROm0g=="
},
- "uglify-es": {
- "version": "3.3.9",
- "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz",
- "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==",
- "dev": true,
- "requires": {
- "commander": "2.13.0",
- "source-map": "0.6.1"
- },
- "dependencies": {
- "commander": {
- "version": "2.13.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz",
- "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==",
- "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
- }
- }
- },
"uglify-to-browserify": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
"integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=",
"optional": true
},
- "uglifyify": {
- "version": "github:MetaMask/uglifyify#8662585e39125a96a5379d71cb4a606829790f87",
- "dev": true,
- "requires": {
- "convert-source-map": "1.1.3",
- "extend": "1.3.0",
- "minimatch": "3.0.4",
- "through": "2.3.8",
- "uglify-es": "3.3.9"
- },
- "dependencies": {
- "extend": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/extend/-/extend-1.3.0.tgz",
- "integrity": "sha1-0VFvsP9WJNLr+RI+odrFoZlABPg=",
- "dev": true
- }
- }
- },
"ultron": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz",
@@ -25159,6 +27254,19 @@
"resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
"integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8="
},
+ "uniqid": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/uniqid/-/uniqid-4.1.1.tgz",
+ "integrity": "sha1-iSIN32t1GuUrX3JISGNShZa7hME=",
+ "requires": {
+ "macaddress": "0.2.8"
+ }
+ },
+ "uniqs": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz",
+ "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI="
+ },
"unique-stream": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.2.1.tgz",
@@ -25257,6 +27365,21 @@
"integrity": "sha512-d4SJySNBXDaQp+DPrziv3xGS6w3d2Xt69FijJr86zMPBy23JEloMCEOUBBzuN7xCtjLCnmB9tI/z7SBCahHBOw==",
"dev": true
},
+ "uri-js": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-3.0.2.tgz",
+ "integrity": "sha1-+QuFhQf4HepNz7s8TD2/orVX+qo=",
+ "requires": {
+ "punycode": "2.1.0"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz",
+ "integrity": "sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0="
+ }
+ }
+ },
"urix": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
@@ -25501,6 +27624,11 @@
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
},
+ "vendors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.2.tgz",
+ "integrity": "sha512-w/hry/368nO21AN9QljsaIhb9ZiZtZARoVH5f3CsFbawdLdayCgKRPup7CggujvySMxx0I91NOyxdVENohprLQ=="
+ },
"verror": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
@@ -26284,7 +28412,7 @@
"ethereumjs-block": "1.7.0",
"ethereumjs-tx": "1.3.3",
"ethereumjs-util": "5.1.5",
- "ethereumjs-vm": "2.3.4",
+ "ethereumjs-vm": "2.3.5",
"json-rpc-error": "2.0.0",
"json-stable-stringify": "1.0.1",
"promise-to-callback": "1.0.0",
@@ -26317,7 +28445,7 @@
"integrity": "sha512-uMYkEP6fga8CyNo8TMoA/7cxi6bL3V8pTvjKQikOi9iYl6/AO5xlfgniyAMElSiq2mmXz3lYa/9VYDMzt/J5aA==",
"requires": {
"cross-fetch": "2.1.0",
- "eth-json-rpc-middleware": "1.5.0",
+ "eth-json-rpc-middleware": "1.6.0",
"json-rpc-engine": "3.6.1",
"json-rpc-error": "2.0.0",
"tape": "4.8.0"
@@ -26338,9 +28466,9 @@
}
},
"ethereumjs-vm": {
- "version": "2.3.4",
- "resolved": "https://registry.npmjs.org/ethereumjs-vm/-/ethereumjs-vm-2.3.4.tgz",
- "integrity": "sha512-Y4SlzNDqxrCO58jhp98HdnZVdjOqB+HC0hoU+N/DEp1aU+hFkRX/nru5F7/HkQRPIlA6aJlQp/xIA6xZs1kspw==",
+ "version": "2.3.5",
+ "resolved": "https://registry.npmjs.org/ethereumjs-vm/-/ethereumjs-vm-2.3.5.tgz",
+ "integrity": "sha512-AJ7x44+xqyE5+UO3Nns19WkTdZfyqFZ+sEjIEpvme7Ipbe3iBU1uwCcHEdiu/yY9bdhr3IfSa/NfIKNeXPaRVQ==",
"requires": {
"async": "2.6.0",
"async-eventemitter": "0.2.4",
@@ -27017,9 +29145,9 @@
}
},
"websocket": {
- "version": "1.0.25",
- "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.25.tgz",
- "integrity": "sha512-M58njvi6ZxVb5k7kpnHh2BvNKuBWiwIYvsToErBzWhvBZYwlEiLcyLrG41T1jRcrY9ettqPYEqduLI7ul54CVQ==",
+ "version": "1.0.26",
+ "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.26.tgz",
+ "integrity": "sha512-fjcrYDPIQxpTnqFQ9JjxUQcdvR89MFAOjPBlF+vjOt49w/XW4fJknUoMz/mDIn2eK1AdslVojcaOxOqyZZV8rw==",
"requires": {
"debug": "2.6.9",
"nan": "2.8.0",
@@ -27075,6 +29203,11 @@
"dev": true,
"optional": true
},
+ "whet.extend": {
+ "version": "0.9.9",
+ "resolved": "https://registry.npmjs.org/whet.extend/-/whet.extend-0.9.9.tgz",
+ "integrity": "sha1-+HfVv2SMl+WqVC+twW1qJZucEaE="
+ },
"which": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz",
@@ -27155,6 +29288,27 @@
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
+ "wreck": {
+ "version": "12.5.1",
+ "resolved": "https://registry.npmjs.org/wreck/-/wreck-12.5.1.tgz",
+ "integrity": "sha512-l5DUGrc+yDyIflpty1x9XuMj1ehVjC/dTbF3/BasOO77xk0EdEa4M/DuOY8W88MQDAD0fEDqyjc8bkIMHd2E9A==",
+ "dev": true,
+ "requires": {
+ "boom": "5.2.0",
+ "hoek": "4.2.0"
+ },
+ "dependencies": {
+ "boom": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz",
+ "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==",
+ "dev": true,
+ "requires": {
+ "hoek": "4.2.0"
+ }
+ }
+ }
+ },
"write": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz",
diff --git a/package.json b/package.json
index 73892bc28..832021f50 100644
--- a/package.json
+++ b/package.json
@@ -76,6 +76,7 @@
"classnames": "^2.2.5",
"clone": "^2.1.1",
"copy-to-clipboard": "^3.0.8",
+ "css-loader": "^0.28.11",
"currency-formatter": "^1.4.2",
"debounce": "^1.0.0",
"debounce-stream": "^2.0.0",
@@ -87,7 +88,6 @@
"ensnare": "^1.0.0",
"eslint-plugin-react": "^7.4.0",
"eth-bin-to-ops": "^1.0.1",
- "eth-block-tracker": "^2.3.0",
"eth-contract-metadata": "^1.1.5",
"eth-hd-keyring": "^1.2.1",
"eth-json-rpc-filters": "^1.2.6",
@@ -111,6 +111,7 @@
"extensionizer": "^1.0.0",
"fast-json-patch": "^2.0.4",
"fast-levenshtein": "^2.0.6",
+ "file-loader": "^1.1.11",
"fuse.js": "^3.2.0",
"gulp": "github:gulpjs/gulp#4.0",
"gulp-autoprefixer": "^5.0.0",
@@ -204,7 +205,7 @@
"brfs": "^1.4.3",
"browserify": "^16.1.1",
"chai": "^4.1.0",
- "chromedriver": "^2.34.1",
+ "chromedriver": "2.36.0",
"compression": "^1.7.1",
"coveralls": "^3.0.0",
"cross-env": "^5.1.4",
@@ -217,9 +218,10 @@
"eslint-plugin-json": "^1.2.0",
"eslint-plugin-mocha": "^5.0.0",
"eslint-plugin-react": "^7.4.0",
- "eth-json-rpc-middleware": "^1.2.7",
+ "eth-json-rpc-middleware": "^1.6.0",
"fs-promise": "^2.0.3",
"ganache-cli": "^6.1.0",
+ "ganache-core": "^2.1.0",
"gifencoder": "^1.1.0",
"gulp": "github:gulpjs/gulp#6d71a658c61edb3090221579d8f97dbe086ba2ed",
"gulp-babel": "^7.0.0",
@@ -254,8 +256,10 @@
"mocha-sinon": "^2.0.0",
"nock": "^9.0.14",
"node-sass": "^4.7.2",
+ "nsp": "^3.2.1",
"nyc": "^11.0.3",
"open": "0.0.5",
+ "path": "^0.12.7",
"png-file-stream": "^1.0.0",
"prompt": "^1.0.0",
"qs": "^6.2.0",
@@ -265,14 +269,17 @@
"react-test-renderer": "^15.6.2",
"react-testutils-additions": "^15.2.0",
"redux-test-utils": "^0.2.2",
+ "resolve-url-loader": "^2.3.0",
"rimraf": "^2.6.2",
+ "sass-loader": "^7.0.1",
"selenium-webdriver": "^3.5.0",
"shell-parallel": "^1.0.3",
"sinon": "^5.0.0",
+ "source-map": "^0.7.2",
+ "style-loader": "^0.21.0",
"stylelint-config-standard": "^18.2.0",
"tape": "^4.5.1",
"testem": "^2.0.0",
- "uglifyify": "github:MetaMask/uglifyify#keep-flags",
"vinyl-buffer": "^1.0.1",
"vinyl-source-stream": "^2.0.0",
"watchify": "^3.9.0"
diff --git a/test/integration/lib/send-new-ui.js b/test/integration/lib/send-new-ui.js
index 09a074750..3da3f4f95 100644
--- a/test/integration/lib/send-new-ui.js
+++ b/test/integration/lib/send-new-ui.js
@@ -23,6 +23,37 @@ global.ethQuery = {
global.ethereumProvider = {}
+async function customizeGas (assert, price, limit, ethFee, usdFee) {
+ const sendGasOpenCustomizeModalButton = await queryAsync($, '.sliders-icon-container')
+ sendGasOpenCustomizeModalButton[0].click()
+
+ const customizeGasModal = await queryAsync($, '.send-v2__customize-gas')
+ assert.ok(customizeGasModal[0], 'should render the customize gas modal')
+
+ const customizeGasPriceInput = (await queryAsync($, '.send-v2__gas-modal-card')).first().find('input')
+ customizeGasPriceInput.val(price)
+ reactTriggerChange(customizeGasPriceInput[0])
+ const customizeGasLimitInput = (await queryAsync($, '.send-v2__gas-modal-card')).last().find('input')
+ customizeGasLimitInput.val(limit)
+ reactTriggerChange(customizeGasLimitInput[0])
+
+ const customizeGasSaveButton = await queryAsync($, '.send-v2__customize-gas__save')
+ customizeGasSaveButton[0].click()
+ const sendGasField = await queryAsync($, '.send-v2__gas-fee-display')
+
+ assert.equal(
+ (await findAsync(sendGasField, '.currency-display__input-wrapper > input')).val(),
+ ethFee,
+ 'send gas field should show customized gas total'
+ )
+
+ assert.equal(
+ (await findAsync(sendGasField, '.currency-display__converted-value'))[0].textContent,
+ usdFee,
+ 'send gas field should show customized gas total converted to USD'
+ )
+}
+
async function runSendFlowTest(assert, done) {
console.log('*** start runSendFlowTest')
const selectState = await queryAsync($, 'select')
@@ -95,32 +126,8 @@ async function runSendFlowTest(assert, done) {
'send gas field should show estimated gas total converted to USD'
)
- const sendGasOpenCustomizeModalButton = await queryAsync($, '.sliders-icon-container')
- sendGasOpenCustomizeModalButton[0].click()
-
- const customizeGasModal = await queryAsync($, '.send-v2__customize-gas')
- assert.ok(customizeGasModal[0], 'should render the customize gas modal')
-
- const customizeGasPriceInput = (await queryAsync($, '.send-v2__gas-modal-card')).first().find('input')
- customizeGasPriceInput.val(50)
- reactTriggerChange(customizeGasPriceInput[0])
- const customizeGasLimitInput = (await queryAsync($, '.send-v2__gas-modal-card')).last().find('input')
- customizeGasLimitInput.val(60000)
- reactTriggerChange(customizeGasLimitInput[0])
-
- const customizeGasSaveButton = await queryAsync($, '.send-v2__customize-gas__save')
- customizeGasSaveButton[0].click()
-
- assert.equal(
- (await findAsync(sendGasField, '.currency-display__input-wrapper > input')).val(),
- '0.003',
- 'send gas field should show customized gas total'
- )
- assert.equal(
- (await findAsync(sendGasField, '.currency-display__converted-value'))[0].textContent,
- '$3.60 USD',
- 'send gas field should show customized gas total converted to USD'
- )
+ await customizeGas(assert, 0, 21000, '0', '$0.00 USD')
+ await customizeGas(assert, 500, 60000, '0.003', '$3.60 USD')
const sendButton = await queryAsync($, 'button.btn-primary--lg.page-container__footer-button')
assert.equal(sendButton[0].textContent, 'Next', 'next button rendered')
diff --git a/test/stub/provider.js b/test/stub/provider.js
index e77db4e28..a1c70486d 100644
--- a/test/stub/provider.js
+++ b/test/stub/provider.js
@@ -1,14 +1,28 @@
const JsonRpcEngine = require('json-rpc-engine')
const scaffoldMiddleware = require('eth-json-rpc-middleware/scaffold')
-const TestBlockchain = require('eth-block-tracker/test/util/testBlockMiddleware')
+const providerAsMiddleware = require('eth-json-rpc-middleware/providerAsMiddleware')
+const GanacheCore = require('ganache-core')
module.exports = {
createEngineForTestData,
providerFromEngine,
scaffoldMiddleware,
createTestProviderTools,
+ getTestSeed,
+ getTestAccounts,
}
+function getTestSeed () {
+ return 'people carpet cluster attract ankle motor ozone mass dove original primary mask'
+}
+
+function getTestAccounts () {
+ return [
+ { address: '0x88bb7F89eB5e5b30D3e15a57C68DBe03C6aCCB21', key: Buffer.from('254A8D551474F35CCC816388B4ED4D20B945C96B7EB857A68064CB9E9FB2C092', 'hex') },
+ { address: '0x1fe9aAB565Be19629fF4e8541ca2102fb42D7724', key: Buffer.from('6BAB5A4F2A6911AF8EE2BD32C6C05F6643AC48EF6C939CDEAAAE6B1620805A9B', 'hex') },
+ { address: '0xbda5c89aa6bA1b352194291AD6822C92AbC87c7B', key: Buffer.from('9B11D7F833648F26CE94D544855558D7053ECD396E4F4563968C232C012879B0', 'hex') },
+ ]
+}
function createEngineForTestData () {
return new JsonRpcEngine()
@@ -21,11 +35,13 @@ function providerFromEngine (engine) {
function createTestProviderTools (opts = {}) {
const engine = createEngineForTestData()
- const testBlockchain = new TestBlockchain()
// handle provided hooks
engine.push(scaffoldMiddleware(opts.scaffold || {}))
// handle block tracker methods
- engine.push(testBlockchain.createMiddleware())
+ engine.push(providerAsMiddleware(GanacheCore.provider({
+ mnemonic: getTestSeed(),
+ })))
+ // wrap in standard provider interface
const provider = providerFromEngine(engine)
- return { provider, engine, testBlockchain }
+ return { provider, engine }
}
diff --git a/test/unit/metamask-controller-test.js b/test/unit/metamask-controller-test.js
index adeca9b5f..18c3f9ab9 100644
--- a/test/unit/metamask-controller-test.js
+++ b/test/unit/metamask-controller-test.js
@@ -6,6 +6,12 @@ const MetaMaskController = require('../../app/scripts/metamask-controller')
const blacklistJSON = require('../stub/blacklist')
const firstTimeState = require('../../app/scripts/first-time-state')
+const DEFAULT_LABEL = 'Account 1'
+const TEST_SEED = 'debris dizzy just program just float decrease vacant alarm reduce speak stadium'
+const TEST_ADDRESS = '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc'
+const TEST_SEED_ALT = 'setup olympic issue mobile velvet surge alcohol burger horse view reopen gentle'
+const TEST_ADDRESS_ALT = '0xc42edfcc21ed14dda456aa0756c153f7985d8813'
+
describe('MetaMaskController', function () {
let metamaskController
const sandbox = sinon.sandbox.create()
@@ -87,17 +93,28 @@ describe('MetaMaskController', function () {
describe('#createNewVaultAndRestore', function () {
it('should be able to call newVaultAndRestore despite a mistake.', async function () {
-
const password = 'what-what-what'
- const wrongSeed = 'debris dizzy just program just float decrease vacant alarm reduce speak stadiu'
- const rightSeed = 'debris dizzy just program just float decrease vacant alarm reduce speak stadium'
- await metamaskController.createNewVaultAndRestore(password, wrongSeed)
- .catch((e) => {
- return
- })
- await metamaskController.createNewVaultAndRestore(password, rightSeed)
+ await metamaskController.createNewVaultAndRestore(password, TEST_SEED.slice(0, -1)).catch((e) => null)
+ await metamaskController.createNewVaultAndRestore(password, TEST_SEED)
assert(metamaskController.keyringController.createNewVaultAndRestore.calledTwice)
})
+
+ it('should clear previous identities after vault restoration', async () => {
+ await metamaskController.createNewVaultAndRestore('foobar1337', TEST_SEED)
+ assert.deepEqual(metamaskController.getState().identities, {
+ [TEST_ADDRESS]: { address: TEST_ADDRESS, name: DEFAULT_LABEL },
+ })
+
+ await metamaskController.keyringController.saveAccountLabel(TEST_ADDRESS, 'Account Foo')
+ assert.deepEqual(metamaskController.getState().identities, {
+ [TEST_ADDRESS]: { address: TEST_ADDRESS, name: 'Account Foo' },
+ })
+
+ await metamaskController.createNewVaultAndRestore('foobar1337', TEST_SEED_ALT)
+ assert.deepEqual(metamaskController.getState().identities, {
+ [TEST_ADDRESS_ALT]: { address: TEST_ADDRESS_ALT, name: DEFAULT_LABEL },
+ })
+ })
})
})
diff --git a/test/unit/nonce-tracker-test.js b/test/unit/nonce-tracker-test.js
index 5a27882ef..cf26945d3 100644
--- a/test/unit/nonce-tracker-test.js
+++ b/test/unit/nonce-tracker-test.js
@@ -1,5 +1,5 @@
const assert = require('assert')
-const NonceTracker = require('../../app/scripts/lib/nonce-tracker')
+const NonceTracker = require('../../app/scripts/controllers/transactions/nonce-tracker')
const MockTxGen = require('../lib/mock-tx-gen')
let providerResultStub = {}
diff --git a/test/unit/pending-tx-test.js b/test/unit/pending-tx-test.js
index f0b4e3bfc..001b86dd1 100644
--- a/test/unit/pending-tx-test.js
+++ b/test/unit/pending-tx-test.js
@@ -4,7 +4,7 @@ const EthTx = require('ethereumjs-tx')
const ObservableStore = require('obs-store')
const clone = require('clone')
const { createTestProviderTools } = require('../stub/provider')
-const PendingTransactionTracker = require('../../app/scripts/lib/pending-tx-tracker')
+const PendingTransactionTracker = require('../../app/scripts/controllers/transactions/pending-tx-tracker')
const MockTxGen = require('../lib/mock-tx-gen')
const sinon = require('sinon')
const noop = () => true
diff --git a/test/unit/tx-controller-test.js b/test/unit/tx-controller-test.js
index 824574ff2..0b5c7226a 100644
--- a/test/unit/tx-controller-test.js
+++ b/test/unit/tx-controller-test.js
@@ -5,17 +5,16 @@ const EthjsQuery = require('ethjs-query')
const ObservableStore = require('obs-store')
const sinon = require('sinon')
const TransactionController = require('../../app/scripts/controllers/transactions')
-const TxGasUtils = require('../../app/scripts/lib/tx-gas-utils')
-const { createTestProviderTools } = require('../stub/provider')
+const TxGasUtils = require('../../app/scripts/controllers/transactions/tx-gas-utils')
+const { createTestProviderTools, getTestAccounts } = require('../stub/provider')
const noop = () => true
const currentNetworkId = 42
const otherNetworkId = 36
-const privKey = new Buffer('8718b9618a37d1fc78c436511fc6df3c8258d3250635bba617f33003270ec03e', 'hex')
describe('Transaction Controller', function () {
- let txController, provider, providerResultStub, testBlockchain
+ let txController, provider, providerResultStub, query, fromAccount
beforeEach(function () {
providerResultStub = {
@@ -24,9 +23,9 @@ describe('Transaction Controller', function () {
// by default, all accounts are external accounts (not contracts)
eth_getCode: '0x',
}
- const providerTools = createTestProviderTools({ scaffold: providerResultStub })
- provider = providerTools.provider
- testBlockchain = providerTools.testBlockchain
+ provider = createTestProviderTools({ scaffold: providerResultStub }).provider
+ query = new EthjsQuery(provider)
+ fromAccount = getTestAccounts()[0]
txController = new TransactionController({
provider,
@@ -34,7 +33,7 @@ describe('Transaction Controller', function () {
txHistoryLimit: 10,
blockTracker: { getCurrentBlock: noop, on: noop, once: noop },
signTransaction: (ethTx) => new Promise((resolve) => {
- ethTx.sign(privKey)
+ ethTx.sign(fromAccount.key)
resolve()
}),
})
@@ -188,7 +187,7 @@ describe('Transaction Controller', function () {
})
- describe('#addTxDefaults', function () {
+ describe('#addTxGasDefaults', function () {
it('should add the tx defaults if their are none', function (done) {
const txMeta = {
'txParams': {
@@ -199,7 +198,7 @@ describe('Transaction Controller', function () {
providerResultStub.eth_gasPrice = '4a817c800'
providerResultStub.eth_getBlockByNumber = { gasLimit: '47b784' }
providerResultStub.eth_estimateGas = '5209'
- txController.addTxDefaults(txMeta)
+ txController.addTxGasDefaults(txMeta)
.then((txMetaWithDefaults) => {
assert(txMetaWithDefaults.txParams.value, '0x0', 'should have added 0x0 as the value')
assert(txMetaWithDefaults.txParams.gasPrice, 'should have added the gas price')
@@ -210,99 +209,6 @@ describe('Transaction Controller', function () {
})
})
- describe('#_validateTxParams', function () {
- it('does not throw for positive values', function () {
- var sample = {
- from: '0x1678a085c290ebd122dc42cba69373b5953b831d',
- value: '0x01',
- }
- txController._validateTxParams(sample)
- })
-
- it('returns error for negative values', function () {
- var sample = {
- from: '0x1678a085c290ebd122dc42cba69373b5953b831d',
- value: '-0x01',
- }
- try {
- txController._validateTxParams(sample)
- } catch (err) {
- assert.ok(err, 'error')
- }
- })
- })
-
- describe('#_normalizeTxParams', () => {
- it('should normalize txParams', () => {
- let txParams = {
- chainId: '0x1',
- from: 'a7df1beDBF813f57096dF77FCd515f0B3900e402',
- to: null,
- data: '68656c6c6f20776f726c64',
- random: 'hello world',
- }
-
- let normalizedTxParams = txController._normalizeTxParams(txParams)
-
- assert(!normalizedTxParams.chainId, 'their should be no chainId')
- assert(!normalizedTxParams.to, 'their should be no to address if null')
- assert.equal(normalizedTxParams.from.slice(0, 2), '0x', 'from should be hexPrefixd')
- assert.equal(normalizedTxParams.data.slice(0, 2), '0x', 'data should be hexPrefixd')
- assert(!('random' in normalizedTxParams), 'their should be no random key in normalizedTxParams')
-
- txParams.to = 'a7df1beDBF813f57096dF77FCd515f0B3900e402'
- normalizedTxParams = txController._normalizeTxParams(txParams)
- assert.equal(normalizedTxParams.to.slice(0, 2), '0x', 'to should be hexPrefixd')
-
- })
- })
-
- describe('#_validateRecipient', () => {
- it('removes recipient for txParams with 0x when contract data is provided', function () {
- const zeroRecipientandDataTxParams = {
- from: '0x1678a085c290ebd122dc42cba69373b5953b831d',
- to: '0x',
- data: 'bytecode',
- }
- const sanitizedTxParams = txController._validateRecipient(zeroRecipientandDataTxParams)
- assert.deepEqual(sanitizedTxParams, { from: '0x1678a085c290ebd122dc42cba69373b5953b831d', data: 'bytecode' }, 'no recipient with 0x')
- })
-
- it('should error when recipient is 0x', function () {
- const zeroRecipientTxParams = {
- from: '0x1678a085c290ebd122dc42cba69373b5953b831d',
- to: '0x',
- }
- assert.throws(() => { txController._validateRecipient(zeroRecipientTxParams) }, Error, 'Invalid recipient address')
- })
- })
-
-
- describe('#_validateFrom', () => {
- it('should error when from is not a hex string', function () {
-
- // where from is undefined
- const txParams = {}
- assert.throws(() => { txController._validateFrom(txParams) }, Error, `Invalid from address ${txParams.from} not a string`)
-
- // where from is array
- txParams.from = []
- assert.throws(() => { txController._validateFrom(txParams) }, Error, `Invalid from address ${txParams.from} not a string`)
-
- // where from is a object
- txParams.from = {}
- assert.throws(() => { txController._validateFrom(txParams) }, Error, `Invalid from address ${txParams.from} not a string`)
-
- // where from is a invalid address
- txParams.from = 'im going to fail'
- assert.throws(() => { txController._validateFrom(txParams) }, Error, `Invalid from address`)
-
- // should run
- txParams.from ='0x1678a085c290ebd122dc42cba69373b5953b831d'
- txController._validateFrom(txParams)
- })
- })
-
describe('#addTx', function () {
it('should emit updates', function (done) {
const txMeta = {
@@ -391,12 +297,12 @@ describe('Transaction Controller', function () {
describe('#updateAndApproveTransaction', function () {
let txMeta
- beforeEach(function () {
+ beforeEach(() => {
txMeta = {
id: 1,
status: 'unapproved',
txParams: {
- from: '0xc684832530fcbddae4b4230a47e991ddcec2831d',
+ from: fromAccount.address,
to: '0x1678a085c290ebd122dc42cba69373b5953b831d',
gasPrice: '0x77359400',
gas: '0x7b0d',
@@ -405,11 +311,12 @@ describe('Transaction Controller', function () {
metamaskNetworkId: currentNetworkId,
}
})
- it('should update and approve transactions', function () {
+ it('should update and approve transactions', async () => {
txController.txStateManager.addTx(txMeta)
- txController.updateAndApproveTransaction(txMeta)
+ const approvalPromise = txController.updateAndApproveTransaction(txMeta)
const tx = txController.txStateManager.getTx(1)
assert.equal(tx.status, 'approved')
+ await approvalPromise
})
})
diff --git a/test/unit/tx-gas-util-test.js b/test/unit/tx-gas-util-test.js
index 40ea8a7d6..c1d5966da 100644
--- a/test/unit/tx-gas-util-test.js
+++ b/test/unit/tx-gas-util-test.js
@@ -1,14 +1,77 @@
const assert = require('assert')
-const TxGasUtils = require('../../app/scripts/lib/tx-gas-utils')
-const { createTestProviderTools } = require('../stub/provider')
-
-describe('Tx Gas Util', function () {
- let txGasUtil, provider, providerResultStub
- beforeEach(function () {
- providerResultStub = {}
- provider = createTestProviderTools({ scaffold: providerResultStub }).provider
- txGasUtil = new TxGasUtils({
- provider,
+const Transaction = require('ethereumjs-tx')
+const BN = require('bn.js')
+
+
+const { hexToBn, bnToHex } = require('../../app/scripts/lib/util')
+const TxUtils = require('../../app/scripts/controllers/transactions/tx-gas-utils')
+
+
+describe('txUtils', function () {
+ let txUtils
+
+ before(function () {
+ txUtils = new TxUtils(new Proxy({}, {
+ get: (obj, name) => {
+ return () => {}
+ },
+ }))
+ })
+
+ describe('chain Id', function () {
+ it('prepares a transaction with the provided chainId', function () {
+ const txParams = {
+ to: '0x70ad465e0bab6504002ad58c744ed89c7da38524',
+ from: '0x69ad465e0bab6504002ad58c744ed89c7da38525',
+ value: '0x0',
+ gas: '0x7b0c',
+ gasPrice: '0x199c82cc00',
+ data: '0x',
+ nonce: '0x3',
+ chainId: 42,
+ }
+ const ethTx = new Transaction(txParams)
+ assert.equal(ethTx.getChainId(), 42, 'chainId is set from tx params')
+ })
+ })
+
+ describe('addGasBuffer', function () {
+ it('multiplies by 1.5, when within block gas limit', function () {
+ // naive estimatedGas: 0x16e360 (1.5 mil)
+ const inputHex = '0x16e360'
+ // dummy gas limit: 0x3d4c52 (4 mil)
+ const blockGasLimitHex = '0x3d4c52'
+ const output = txUtils.addGasBuffer(inputHex, blockGasLimitHex)
+ const inputBn = hexToBn(inputHex)
+ const outputBn = hexToBn(output)
+ const expectedBn = inputBn.muln(1.5)
+ assert(outputBn.eq(expectedBn), 'returns 1.5 the input value')
+ })
+
+ it('uses original estimatedGas, when above block gas limit', function () {
+ // naive estimatedGas: 0x16e360 (1.5 mil)
+ const inputHex = '0x16e360'
+ // dummy gas limit: 0x0f4240 (1 mil)
+ const blockGasLimitHex = '0x0f4240'
+ const output = txUtils.addGasBuffer(inputHex, blockGasLimitHex)
+ // const inputBn = hexToBn(inputHex)
+ const outputBn = hexToBn(output)
+ const expectedBn = hexToBn(inputHex)
+ assert(outputBn.eq(expectedBn), 'returns the original estimatedGas value')
+ })
+
+ it('buffers up to recommend gas limit recommended ceiling', function () {
+ // naive estimatedGas: 0x16e360 (1.5 mil)
+ const inputHex = '0x16e360'
+ // dummy gas limit: 0x1e8480 (2 mil)
+ const blockGasLimitHex = '0x1e8480'
+ const blockGasLimitBn = hexToBn(blockGasLimitHex)
+ const ceilGasLimitBn = blockGasLimitBn.muln(0.9)
+ const output = txUtils.addGasBuffer(inputHex, blockGasLimitHex)
+ // const inputBn = hexToBn(inputHex)
+ // const outputBn = hexToBn(output)
+ const expectedHex = bnToHex(ceilGasLimitBn)
+ assert.equal(output, expectedHex, 'returns the gas limit recommended ceiling value')
})
})
})
diff --git a/test/unit/tx-state-history-helper-test.js b/test/unit/tx-state-history-helper-test.js
index 90cb10713..35e9ef188 100644
--- a/test/unit/tx-state-history-helper-test.js
+++ b/test/unit/tx-state-history-helper-test.js
@@ -1,6 +1,6 @@
const assert = require('assert')
const clone = require('clone')
-const txStateHistoryHelper = require('../../app/scripts/lib/tx-state-history-helper')
+const txStateHistoryHelper = require('../../app/scripts/controllers/transactions/lib/tx-state-history-helper')
describe('deepCloneFromTxMeta', function () {
it('should clone deep', function () {
diff --git a/test/unit/tx-state-history-helper.js b/test/unit/tx-state-history-helper.js
index 79ee26d6e..35f7dac57 100644
--- a/test/unit/tx-state-history-helper.js
+++ b/test/unit/tx-state-history-helper.js
@@ -1,5 +1,5 @@
const assert = require('assert')
-const txStateHistoryHelper = require('../../app/scripts/lib/tx-state-history-helper')
+const txStateHistoryHelper = require('../../app/scripts/controllers/transactions/lib/tx-state-history-helper')
const testVault = require('../data/v17-long-history.json')
diff --git a/test/unit/tx-state-manager-test.js b/test/unit/tx-state-manager-test.js
index a5ac13664..e5fe68d0b 100644
--- a/test/unit/tx-state-manager-test.js
+++ b/test/unit/tx-state-manager-test.js
@@ -1,8 +1,8 @@
const assert = require('assert')
const clone = require('clone')
const ObservableStore = require('obs-store')
-const TxStateManager = require('../../app/scripts/lib/tx-state-manager')
-const txStateHistoryHelper = require('../../app/scripts/lib/tx-state-history-helper')
+const TxStateManager = require('../../app/scripts/controllers/transactions/tx-state-manager')
+const txStateHistoryHelper = require('../../app/scripts/controllers/transactions/lib/tx-state-history-helper')
const noop = () => true
describe('TransactionStateManager', function () {
diff --git a/test/unit/tx-utils-test.js b/test/unit/tx-utils-test.js
index 8ca13412e..be16225ba 100644
--- a/test/unit/tx-utils-test.js
+++ b/test/unit/tx-utils-test.js
@@ -1,77 +1,98 @@
const assert = require('assert')
-const Transaction = require('ethereumjs-tx')
-const BN = require('bn.js')
-
-
-const { hexToBn, bnToHex } = require('../../app/scripts/lib/util')
-const TxUtils = require('../../app/scripts/lib/tx-gas-utils')
+const txUtils = require('../../app/scripts/controllers/transactions/lib/util')
describe('txUtils', function () {
- let txUtils
-
- before(function () {
- txUtils = new TxUtils(new Proxy({}, {
- get: (obj, name) => {
- return () => {}
- },
- }))
- })
+ describe('#validateTxParams', function () {
+ it('does not throw for positive values', function () {
+ var sample = {
+ from: '0x1678a085c290ebd122dc42cba69373b5953b831d',
+ value: '0x01',
+ }
+ txUtils.validateTxParams(sample)
+ })
- describe('chain Id', function () {
- it('prepares a transaction with the provided chainId', function () {
- const txParams = {
- to: '0x70ad465e0bab6504002ad58c744ed89c7da38524',
- from: '0x69ad465e0bab6504002ad58c744ed89c7da38525',
- value: '0x0',
- gas: '0x7b0c',
- gasPrice: '0x199c82cc00',
- data: '0x',
- nonce: '0x3',
- chainId: 42,
+ it('returns error for negative values', function () {
+ var sample = {
+ from: '0x1678a085c290ebd122dc42cba69373b5953b831d',
+ value: '-0x01',
+ }
+ try {
+ txUtils.validateTxParams(sample)
+ } catch (err) {
+ assert.ok(err, 'error')
}
- const ethTx = new Transaction(txParams)
- assert.equal(ethTx.getChainId(), 42, 'chainId is set from tx params')
})
})
- describe('addGasBuffer', function () {
- it('multiplies by 1.5, when within block gas limit', function () {
- // naive estimatedGas: 0x16e360 (1.5 mil)
- const inputHex = '0x16e360'
- // dummy gas limit: 0x3d4c52 (4 mil)
- const blockGasLimitHex = '0x3d4c52'
- const output = txUtils.addGasBuffer(inputHex, blockGasLimitHex)
- const inputBn = hexToBn(inputHex)
- const outputBn = hexToBn(output)
- const expectedBn = inputBn.muln(1.5)
- assert(outputBn.eq(expectedBn), 'returns 1.5 the input value')
+ describe('#normalizeTxParams', () => {
+ it('should normalize txParams', () => {
+ let txParams = {
+ chainId: '0x1',
+ from: 'a7df1beDBF813f57096dF77FCd515f0B3900e402',
+ to: null,
+ data: '68656c6c6f20776f726c64',
+ random: 'hello world',
+ }
+
+ let normalizedTxParams = txUtils.normalizeTxParams(txParams)
+
+ assert(!normalizedTxParams.chainId, 'their should be no chainId')
+ assert(!normalizedTxParams.to, 'their should be no to address if null')
+ assert.equal(normalizedTxParams.from.slice(0, 2), '0x', 'from should be hexPrefixd')
+ assert.equal(normalizedTxParams.data.slice(0, 2), '0x', 'data should be hexPrefixd')
+ assert(!('random' in normalizedTxParams), 'their should be no random key in normalizedTxParams')
+
+ txParams.to = 'a7df1beDBF813f57096dF77FCd515f0B3900e402'
+ normalizedTxParams = txUtils.normalizeTxParams(txParams)
+ assert.equal(normalizedTxParams.to.slice(0, 2), '0x', 'to should be hexPrefixd')
+
})
+ })
- it('uses original estimatedGas, when above block gas limit', function () {
- // naive estimatedGas: 0x16e360 (1.5 mil)
- const inputHex = '0x16e360'
- // dummy gas limit: 0x0f4240 (1 mil)
- const blockGasLimitHex = '0x0f4240'
- const output = txUtils.addGasBuffer(inputHex, blockGasLimitHex)
- // const inputBn = hexToBn(inputHex)
- const outputBn = hexToBn(output)
- const expectedBn = hexToBn(inputHex)
- assert(outputBn.eq(expectedBn), 'returns the original estimatedGas value')
+ describe('#validateRecipient', () => {
+ it('removes recipient for txParams with 0x when contract data is provided', function () {
+ const zeroRecipientandDataTxParams = {
+ from: '0x1678a085c290ebd122dc42cba69373b5953b831d',
+ to: '0x',
+ data: 'bytecode',
+ }
+ const sanitizedTxParams = txUtils.validateRecipient(zeroRecipientandDataTxParams)
+ assert.deepEqual(sanitizedTxParams, { from: '0x1678a085c290ebd122dc42cba69373b5953b831d', data: 'bytecode' }, 'no recipient with 0x')
})
- it('buffers up to recommend gas limit recommended ceiling', function () {
- // naive estimatedGas: 0x16e360 (1.5 mil)
- const inputHex = '0x16e360'
- // dummy gas limit: 0x1e8480 (2 mil)
- const blockGasLimitHex = '0x1e8480'
- const blockGasLimitBn = hexToBn(blockGasLimitHex)
- const ceilGasLimitBn = blockGasLimitBn.muln(0.9)
- const output = txUtils.addGasBuffer(inputHex, blockGasLimitHex)
- // const inputBn = hexToBn(inputHex)
- // const outputBn = hexToBn(output)
- const expectedHex = bnToHex(ceilGasLimitBn)
- assert.equal(output, expectedHex, 'returns the gas limit recommended ceiling value')
+ it('should error when recipient is 0x', function () {
+ const zeroRecipientTxParams = {
+ from: '0x1678a085c290ebd122dc42cba69373b5953b831d',
+ to: '0x',
+ }
+ assert.throws(() => { txUtils.validateRecipient(zeroRecipientTxParams) }, Error, 'Invalid recipient address')
})
})
-}) \ No newline at end of file
+
+
+ describe('#validateFrom', () => {
+ it('should error when from is not a hex string', function () {
+
+ // where from is undefined
+ const txParams = {}
+ assert.throws(() => { txUtils.validateFrom(txParams) }, Error, `Invalid from address ${txParams.from} not a string`)
+
+ // where from is array
+ txParams.from = []
+ assert.throws(() => { txUtils.validateFrom(txParams) }, Error, `Invalid from address ${txParams.from} not a string`)
+
+ // where from is a object
+ txParams.from = {}
+ assert.throws(() => { txUtils.validateFrom(txParams) }, Error, `Invalid from address ${txParams.from} not a string`)
+
+ // where from is a invalid address
+ txParams.from = 'im going to fail'
+ assert.throws(() => { txUtils.validateFrom(txParams) }, Error, `Invalid from address`)
+
+ // should run
+ txParams.from ='0x1678a085c290ebd122dc42cba69373b5953b831d'
+ txUtils.validateFrom(txParams)
+ })
+ })
+})
diff --git a/ui/app/actions.js b/ui/app/actions.js
index 81d9c333b..f060e40bd 100644
--- a/ui/app/actions.js
+++ b/ui/app/actions.js
@@ -1,4 +1,5 @@
const abi = require('human-standard-token-abi')
+const pify = require('pify')
const getBuyEthUrl = require('../../app/scripts/lib/buy-eth-url')
const { getTokenAddressFromTokenObject } = require('./util')
const ethUtil = require('ethereumjs-util')
@@ -83,7 +84,7 @@ var actions = {
REVEAL_SEED_CONFIRMATION: 'REVEAL_SEED_CONFIRMATION',
revealSeedConfirmation: revealSeedConfirmation,
requestRevealSeed: requestRevealSeed,
-
+ requestRevealSeedWords,
// unlock screen
UNLOCK_IN_PROGRESS: 'UNLOCK_IN_PROGRESS',
UNLOCK_FAILED: 'UNLOCK_FAILED',
@@ -345,11 +346,13 @@ function transitionBackward () {
}
}
-function clearSeedWordCache () {
- log.debug(`background.clearSeedWordCache`)
+function confirmSeedWords () {
return dispatch => {
+ dispatch(actions.showLoadingIndication())
+ log.debug(`background.clearSeedWordCache`)
return new Promise((resolve, reject) => {
background.clearSeedWordCache((err, account) => {
+ dispatch(actions.hideLoadingIndication())
if (err) {
dispatch(actions.displayWarning(err.message))
return reject(err)
@@ -363,22 +366,6 @@ function clearSeedWordCache () {
}
}
-function confirmSeedWords () {
- return async dispatch => {
- dispatch(actions.showLoadingIndication())
- const account = await dispatch(clearSeedWordCache())
- return dispatch(setIsRevealingSeedWords(false))
- .then(() => {
- dispatch(actions.hideLoadingIndication())
- return account
- })
- .catch(() => {
- dispatch(actions.hideLoadingIndication())
- return account
- })
- }
-}
-
function createNewVaultAndRestore (password, seed) {
return (dispatch) => {
dispatch(actions.showLoadingIndication())
@@ -441,6 +428,30 @@ function revealSeedConfirmation () {
}
}
+function verifyPassword (password) {
+ return new Promise((resolve, reject) => {
+ background.submitPassword(password, error => {
+ if (error) {
+ return reject(error)
+ }
+
+ resolve(true)
+ })
+ })
+}
+
+function verifySeedPhrase () {
+ return new Promise((resolve, reject) => {
+ background.verifySeedPhrase((error, seedWords) => {
+ if (error) {
+ return reject(error)
+ }
+
+ resolve(seedWords)
+ })
+ })
+}
+
function requestRevealSeed (password) {
return dispatch => {
dispatch(actions.showLoadingIndication())
@@ -460,13 +471,29 @@ function requestRevealSeed (password) {
}
dispatch(actions.showNewVaultSeed(result))
+ dispatch(actions.hideLoadingIndication())
resolve()
})
})
})
- .then(() => dispatch(setIsRevealingSeedWords(true)))
- .then(() => dispatch(actions.hideLoadingIndication()))
- .catch(() => dispatch(actions.hideLoadingIndication()))
+ }
+}
+
+function requestRevealSeedWords (password) {
+ return async dispatch => {
+ dispatch(actions.showLoadingIndication())
+ log.debug(`background.submitPassword`)
+
+ try {
+ await verifyPassword(password)
+ const seedWords = await verifySeedPhrase()
+ dispatch(actions.hideLoadingIndication())
+ return seedWords
+ } catch (error) {
+ dispatch(actions.hideLoadingIndication())
+ dispatch(actions.displayWarning(error.message))
+ throw new Error(error.message)
+ }
}
}
@@ -497,31 +524,26 @@ function addNewKeyring (type, opts) {
}
function importNewAccount (strategy, args) {
- return (dispatch) => {
- dispatch(actions.showLoadingIndication('This may take a while, be patient.'))
- log.debug(`background.importAccountWithStrategy`)
- return new Promise((resolve, reject) => {
- background.importAccountWithStrategy(strategy, args, (err) => {
- if (err) {
- dispatch(actions.displayWarning(err.message))
- return reject(err)
- }
- log.debug(`background.getState`)
- background.getState((err, newState) => {
- dispatch(actions.hideLoadingIndication())
- if (err) {
- dispatch(actions.displayWarning(err.message))
- return reject(err)
- }
- dispatch(actions.updateMetamaskState(newState))
- dispatch({
- type: actions.SHOW_ACCOUNT_DETAIL,
- value: newState.selectedAddress,
- })
- resolve(newState)
- })
- })
+ return async (dispatch) => {
+ let newState
+ dispatch(actions.showLoadingIndication('This may take a while, please be patient.'))
+ try {
+ log.debug(`background.importAccountWithStrategy`)
+ await pify(background.importAccountWithStrategy).call(background, strategy, args)
+ log.debug(`background.getState`)
+ newState = await pify(background.getState).call(background)
+ } catch (err) {
+ dispatch(actions.hideLoadingIndication())
+ dispatch(actions.displayWarning(err.message))
+ throw err
+ }
+ dispatch(actions.hideLoadingIndication())
+ dispatch(actions.updateMetamaskState(newState))
+ dispatch({
+ type: actions.SHOW_ACCOUNT_DETAIL,
+ value: newState.selectedAddress,
})
+ return newState
}
}
@@ -1923,11 +1945,3 @@ function updateNetworkEndpointType (networkEndpointType) {
value: networkEndpointType,
}
}
-
-function setIsRevealingSeedWords (reveal) {
- return dispatch => {
- log.debug(`background.setIsRevealingSeedWords`)
- background.setIsRevealingSeedWords(reveal)
- return forceUpdateMetamaskState(dispatch)
- }
-}
diff --git a/ui/app/app.js b/ui/app/app.js
index f09d7cf79..c93a6314c 100644
--- a/ui/app/app.js
+++ b/ui/app/app.js
@@ -24,7 +24,7 @@ const Initialized = require('./components/pages/initialized')
const Settings = require('./components/pages/settings')
const UnlockPage = require('./components/pages/unlock')
const RestoreVaultPage = require('./components/pages/keychains/restore-vault')
-const RevealSeedConfirmation = require('./keychains/hd/recover-seed/confirmation')
+const RevealSeedConfirmation = require('./components/pages/keychains/reveal-seed')
const AddTokenPage = require('./components/pages/add-token')
const CreateAccountPage = require('./components/pages/create-account')
const NoticeScreen = require('./components/pages/notice')
@@ -56,20 +56,11 @@ const {
class App extends Component {
componentWillMount () {
- const {
- currentCurrency,
- setCurrentCurrencyToUSD,
- isRevealingSeedWords,
- clearSeedWords,
- } = this.props
+ const { currentCurrency, setCurrentCurrencyToUSD } = this.props
if (!currentCurrency) {
setCurrentCurrencyToUSD()
}
-
- if (isRevealingSeedWords) {
- clearSeedWords()
- }
}
renderRoutes () {
@@ -403,8 +394,6 @@ App.propTypes = {
isMouseUser: PropTypes.bool,
setMouseUserState: PropTypes.func,
t: PropTypes.func,
- isRevealingSeedWords: PropTypes.bool,
- clearSeedWords: PropTypes.func,
}
function mapStateToProps (state) {
@@ -485,7 +474,6 @@ function mapDispatchToProps (dispatch, ownProps) {
setCurrentCurrencyToUSD: () => dispatch(actions.setCurrentCurrency('usd')),
toggleAccountMenu: () => dispatch(actions.toggleAccountMenu()),
setMouseUserState: (isMouseUser) => dispatch(actions.setMouseUserState(isMouseUser)),
- clearSeedWords: () => dispatch(actions.confirmSeedWords()),
}
}
diff --git a/ui/app/components/customize-gas-modal/index.js b/ui/app/components/customize-gas-modal/index.js
index 4c693d1c3..1ff8eea87 100644
--- a/ui/app/components/customize-gas-modal/index.js
+++ b/ui/app/components/customize-gas-modal/index.js
@@ -280,8 +280,7 @@ CustomizeGasModal.prototype.render = function () {
h(GasModalCard, {
value: convertedGasPrice,
min: forceGasMin || MIN_GAS_PRICE_GWEI,
- // max: 1000,
- step: multiplyCurrencies(MIN_GAS_PRICE_GWEI, 10),
+ step: 1,
onChange: value => this.convertAndSetGasPrice(value),
title: this.context.t('gasPrice'),
copy: this.context.t('gasPriceCalculation'),
@@ -290,7 +289,6 @@ CustomizeGasModal.prototype.render = function () {
h(GasModalCard, {
value: convertedGasLimit,
min: 1,
- // max: 100000,
step: 1,
onChange: value => this.convertAndSetGasLimit(value),
title: this.context.t('gasLimit'),
diff --git a/ui/app/components/export-text-container/export-text-container.component.js b/ui/app/components/export-text-container/export-text-container.component.js
new file mode 100644
index 000000000..c2546fa9b
--- /dev/null
+++ b/ui/app/components/export-text-container/export-text-container.component.js
@@ -0,0 +1,45 @@
+const { Component } = require('react')
+const PropTypes = require('prop-types')
+const h = require('react-hyperscript')
+const copyToClipboard = require('copy-to-clipboard')
+const { exportAsFile } = require('../../util')
+
+class ExportTextContainer extends Component {
+ render () {
+ const { text = '', filename = '' } = this.props
+ const { t } = this.context
+
+ return (
+ h('.export-text-container', [
+ h('.export-text-container__text-container', [
+ h('.export-text-container__text', text),
+ ]),
+ h('.export-text-container__buttons-container', [
+ h('.export-text-container__button.export-text-container__button--copy', {
+ onClick: () => copyToClipboard(text),
+ }, [
+ h('img', { src: 'images/copy-to-clipboard.svg' }),
+ h('.export-text-container__button-text', t('copyToClipboard')),
+ ]),
+ h('.export-text-container__button', {
+ onClick: () => exportAsFile(filename, text),
+ }, [
+ h('img', { src: 'images/download.svg' }),
+ h('.export-text-container__button-text', t('saveAsCsvFile')),
+ ]),
+ ]),
+ ])
+ )
+ }
+}
+
+ExportTextContainer.propTypes = {
+ text: PropTypes.string,
+ filename: PropTypes.string,
+}
+
+ExportTextContainer.contextTypes = {
+ t: PropTypes.func,
+}
+
+module.exports = ExportTextContainer
diff --git a/ui/app/components/export-text-container/export-text-container.scss b/ui/app/components/export-text-container/export-text-container.scss
new file mode 100644
index 000000000..a42de8233
--- /dev/null
+++ b/ui/app/components/export-text-container/export-text-container.scss
@@ -0,0 +1,52 @@
+.export-text-container {
+ display: flex;
+ justify-content: center;
+ flex-direction: column;
+ align-items: center;
+ border: 1px solid $alto;
+ border-radius: 4px;
+ font-weight: 400;
+
+ &__text-container {
+ width: 100%;
+ display: flex;
+ justify-content: center;
+ padding: 20px;
+ border-radius: 4px;
+ background: $alabaster;
+ }
+
+ &__text {
+ resize: none;
+ border: none;
+ background: $alabaster;
+ font-size: 20px;
+ text-align: center;
+ }
+
+ &__buttons-container {
+ display: flex;
+ flex-direction: row;
+ border-top: 1px solid $alto;
+ width: 100%;
+ }
+
+ &__button {
+ padding: 10px;
+ flex: 1;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ font-size: 14px;
+ cursor: pointer;
+ color: $curious-blue;
+
+ &--copy {
+ border-right: 1px solid $alto;
+ }
+ }
+
+ &__button-text {
+ padding-left: 10px;
+ }
+}
diff --git a/ui/app/components/export-text-container/index.js b/ui/app/components/export-text-container/index.js
new file mode 100644
index 000000000..b2864a717
--- /dev/null
+++ b/ui/app/components/export-text-container/index.js
@@ -0,0 +1,2 @@
+const ExportTextContainer = require('./export-text-container.component')
+module.exports = ExportTextContainer
diff --git a/ui/app/components/pages/add-token.js b/ui/app/components/pages/add-token.js
index 566e42450..8d52571d0 100644
--- a/ui/app/components/pages/add-token.js
+++ b/ui/app/components/pages/add-token.js
@@ -192,7 +192,7 @@ AddTokenScreen.prototype.attemptToAutoFillTokenParams = async function (address)
if (symbol && decimals) {
this.setState({
customSymbol: symbol,
- customDecimals: decimals.toString(),
+ customDecimals: decimals,
autoFilled: true,
})
}
diff --git a/ui/app/components/pages/create-account/import-account/json.js b/ui/app/components/pages/create-account/import-account/json.js
index 946907a47..0a3314b2a 100644
--- a/ui/app/components/pages/create-account/import-account/json.js
+++ b/ui/app/components/pages/create-account/import-account/json.js
@@ -105,6 +105,8 @@ class JsonImportSubview extends Component {
}
this.props.importNewJsonAccount([ fileContents, password ])
+ // JS runtime requires caught rejections but failures are handled by Redux
+ .catch()
}
}
diff --git a/ui/app/components/pages/create-account/import-account/private-key.js b/ui/app/components/pages/create-account/import-account/private-key.js
index c77612ea4..df7ac910a 100644
--- a/ui/app/components/pages/create-account/import-account/private-key.js
+++ b/ui/app/components/pages/create-account/import-account/private-key.js
@@ -91,5 +91,7 @@ PrivateKeyImportView.prototype.createNewKeychain = function () {
const { importNewAccount, history } = this.props
importNewAccount('Private Key', [ privateKey ])
+ // JS runtime requires caught rejections but failures are handled by Redux
+ .catch()
.then(() => history.push(DEFAULT_ROUTE))
}
diff --git a/ui/app/components/pages/home.js b/ui/app/components/pages/home.js
index 90b8e1d37..9110f8202 100644
--- a/ui/app/components/pages/home.js
+++ b/ui/app/components/pages/home.js
@@ -21,7 +21,7 @@ const QrView = require('../../components/qr-code')
// Routes
const {
- REVEAL_SEED_ROUTE,
+ INITIALIZE_BACKUP_PHRASE_ROUTE,
RESTORE_VAULT_ROUTE,
CONFIRM_TRANSACTION_ROUTE,
NOTICE_ROUTE,
@@ -69,7 +69,7 @@ class Home extends Component {
log.debug('rendering seed words')
return h(Redirect, {
to: {
- pathname: REVEAL_SEED_ROUTE,
+ pathname: INITIALIZE_BACKUP_PHRASE_ROUTE,
},
})
}
diff --git a/ui/app/components/pages/keychains/reveal-seed.js b/ui/app/components/pages/keychains/reveal-seed.js
index 247f3c8e2..685c81074 100644
--- a/ui/app/components/pages/keychains/reveal-seed.js
+++ b/ui/app/components/pages/keychains/reveal-seed.js
@@ -2,11 +2,27 @@ const { Component } = require('react')
const { connect } = require('react-redux')
const PropTypes = require('prop-types')
const h = require('react-hyperscript')
-const { exportAsFile } = require('../../../util')
-const { requestRevealSeed, confirmSeedWords } = require('../../../actions')
+const classnames = require('classnames')
+
+const { requestRevealSeedWords } = require('../../../actions')
const { DEFAULT_ROUTE } = require('../../../routes')
+const ExportTextContainer = require('../../export-text-container')
+
+const PASSWORD_PROMPT_SCREEN = 'PASSWORD_PROMPT_SCREEN'
+const REVEAL_SEED_SCREEN = 'REVEAL_SEED_SCREEN'
class RevealSeedPage extends Component {
+ constructor (props) {
+ super(props)
+
+ this.state = {
+ screen: PASSWORD_PROMPT_SCREEN,
+ password: '',
+ seedWords: null,
+ error: null,
+ }
+ }
+
componentDidMount () {
const passwordBox = document.getElementById('password-box')
if (passwordBox) {
@@ -14,182 +30,135 @@ class RevealSeedPage extends Component {
}
}
- checkConfirmation (event) {
- if (event.key === 'Enter') {
- event.preventDefault()
- this.revealSeedWords()
- }
+ handleSubmit (event) {
+ event.preventDefault()
+ this.setState({ seedWords: null, error: null })
+ this.props.requestRevealSeedWords(this.state.password)
+ .then(seedWords => this.setState({ seedWords, screen: REVEAL_SEED_SCREEN }))
+ .catch(error => this.setState({ error: error.message }))
}
- revealSeedWords () {
- const password = document.getElementById('password-box').value
- this.props.requestRevealSeed(password)
- }
-
- renderSeed () {
- const { seedWords, confirmSeedWords, history } = this.props
-
+ renderWarning () {
return (
- h('.initialize-screen.flex-column.flex-center.flex-grow', [
-
- h('h3.flex-center.text-transform-uppercase', {
- style: {
- background: '#EBEBEB',
- color: '#AEAEAE',
- marginTop: 36,
- marginBottom: 8,
- width: '100%',
- fontSize: '20px',
- padding: 6,
- },
- }, [
- 'Vault Created',
- ]),
-
- h('div', {
- style: {
- fontSize: '1em',
- marginTop: '10px',
- textAlign: 'center',
- },
- }, [
- h('span.error', 'These 12 words are the only way to restore your MetaMask accounts.\nSave them somewhere safe and secret.'),
- ]),
-
- h('textarea.twelve-word-phrase', {
- readOnly: true,
- value: seedWords,
+ h('.page-container__warning-container', [
+ h('img.page-container__warning-icon', {
+ src: 'images/warning.svg',
}),
-
- h('button.primary', {
- onClick: () => confirmSeedWords().then(() => history.push(DEFAULT_ROUTE)),
- style: {
- margin: '24px',
- fontSize: '0.9em',
- marginBottom: '10px',
- },
- }, 'I\'ve copied it somewhere safe'),
-
- h('button.primary', {
- onClick: () => exportAsFile(`MetaMask Seed Words`, seedWords),
- style: {
- margin: '10px',
- fontSize: '0.9em',
- },
- }, 'Save Seed Words As File'),
+ h('.page-container__warning-message', [
+ h('.page-container__warning-title', [this.context.t('revealSeedWordsWarningTitle')]),
+ h('div', [this.context.t('revealSeedWordsWarning')]),
+ ]),
])
)
}
- renderConfirmation () {
- const { history, warning, inProgress } = this.props
+ renderContent () {
+ return this.state.screen === PASSWORD_PROMPT_SCREEN
+ ? this.renderPasswordPromptContent()
+ : this.renderRevealSeedContent()
+ }
+
+ renderPasswordPromptContent () {
+ const { t } = this.context
return (
- h('.initialize-screen.flex-column.flex-center.flex-grow', {
- style: { maxWidth: '420px' },
+ h('form', {
+ onSubmit: event => this.handleSubmit(event),
}, [
-
- h('h3.flex-center.text-transform-uppercase', {
- style: {
- background: '#EBEBEB',
- color: '#AEAEAE',
- marginBottom: 24,
- width: '100%',
- fontSize: '20px',
- padding: 6,
- },
- }, [
- 'Reveal Seed Words',
- ]),
-
- h('.div', {
- style: {
- display: 'flex',
- flexDirection: 'column',
- padding: '20px',
- justifyContent: 'center',
- },
- }, [
-
- h('h4', 'Do not recover your seed words in a public place! These words can be used to steal all your accounts.'),
-
- // confirmation
- h('input.large-input.letter-spacey', {
+ h('label.input-label', {
+ htmlFor: 'password-box',
+ }, t('enterPasswordContinue')),
+ h('.input-group', [
+ h('input.form-control', {
type: 'password',
+ placeholder: t('password'),
id: 'password-box',
- placeholder: 'Enter your password to confirm',
- onKeyPress: this.checkConfirmation.bind(this),
- style: {
- width: 260,
- marginTop: '12px',
- },
+ value: this.state.password,
+ onChange: event => this.setState({ password: event.target.value }),
+ className: classnames({ 'form-control--error': this.state.error }),
}),
+ ]),
+ this.state.error && h('.reveal-seed__error', this.state.error),
+ ])
+ )
+ }
- h('.flex-row.flex-start', {
- style: {
- marginTop: 30,
- width: '50%',
- },
- }, [
- // cancel
- h('button.primary', {
- onClick: () => history.push(DEFAULT_ROUTE),
- }, 'CANCEL'),
-
- // submit
- h('button.primary', {
- style: { marginLeft: '10px' },
- onClick: this.revealSeedWords.bind(this),
- }, 'OK'),
+ renderRevealSeedContent () {
+ const { t } = this.context
- ]),
+ return (
+ h('div', [
+ h('label.reveal-seed__label', t('yourPrivateSeedPhrase')),
+ h(ExportTextContainer, {
+ text: this.state.seedWords,
+ filename: t('metamaskSeedWords'),
+ }),
+ ])
+ )
+ }
- warning && (
- h('span.error', {
- style: {
- margin: '20px',
- },
- }, warning.split('-'))
- ),
-
- inProgress && (
- h('span.in-progress-notification', 'Generating Seed...')
- ),
- ]),
+ renderFooter () {
+ return this.state.screen === PASSWORD_PROMPT_SCREEN
+ ? this.renderPasswordPromptFooter()
+ : this.renderRevealSeedFooter()
+ }
+
+ renderPasswordPromptFooter () {
+ return (
+ h('.page-container__footer', [
+ h('button.btn-secondary--lg.page-container__footer-button', {
+ onClick: () => this.props.history.push(DEFAULT_ROUTE),
+ }, this.context.t('cancel')),
+ h('button.btn-primary--lg.page-container__footer-button', {
+ onClick: event => this.handleSubmit(event),
+ disabled: this.state.password === '',
+ }, this.context.t('next')),
+ ])
+ )
+ }
+
+ renderRevealSeedFooter () {
+ return (
+ h('.page-container__footer', [
+ h('button.btn-secondary--lg.page-container__footer-button', {
+ onClick: () => this.props.history.push(DEFAULT_ROUTE),
+ }, this.context.t('close')),
])
)
}
render () {
- return this.props.seedWords
- ? this.renderSeed()
- : this.renderConfirmation()
+ return (
+ h('.page-container', [
+ h('.page-container__header', [
+ h('.page-container__title', this.context.t('revealSeedWordsTitle')),
+ h('.page-container__subtitle', this.context.t('revealSeedWordsDescription')),
+ ]),
+ h('.page-container__content', [
+ this.renderWarning(),
+ h('.reveal-seed__content', [
+ this.renderContent(),
+ ]),
+ ]),
+ this.renderFooter(),
+ ])
+ )
}
}
RevealSeedPage.propTypes = {
- requestRevealSeed: PropTypes.func,
- confirmSeedWords: PropTypes.func,
- seedWords: PropTypes.string,
- inProgress: PropTypes.bool,
+ requestRevealSeedWords: PropTypes.func,
history: PropTypes.object,
- warning: PropTypes.string,
}
-const mapStateToProps = state => {
- const { appState: { warning }, metamask: { seedWords } } = state
-
- return {
- warning,
- seedWords,
- }
+RevealSeedPage.contextTypes = {
+ t: PropTypes.func,
}
const mapDispatchToProps = dispatch => {
return {
- requestRevealSeed: password => dispatch(requestRevealSeed(password)),
- confirmSeedWords: () => dispatch(confirmSeedWords()),
+ requestRevealSeedWords: password => dispatch(requestRevealSeedWords(password)),
}
}
-module.exports = connect(mapStateToProps, mapDispatchToProps)(RevealSeedPage)
+module.exports = connect(null, mapDispatchToProps)(RevealSeedPage)
diff --git a/ui/app/components/pending-tx/index.js b/ui/app/components/pending-tx/index.js
index ace52748c..893538bcf 100644
--- a/ui/app/components/pending-tx/index.js
+++ b/ui/app/components/pending-tx/index.js
@@ -8,7 +8,7 @@ const abiDecoder = require('abi-decoder')
abiDecoder.addABI(abi)
const inherits = require('util').inherits
const actions = require('../../actions')
-const util = require('../../util')
+const { getSymbolAndDecimals } = require('../../token-util')
const ConfirmSendEther = require('./confirm-send-ether')
const ConfirmSendToken = require('./confirm-send-token')
const ConfirmDeployContract = require('./confirm-deploy-contract')
@@ -26,6 +26,7 @@ function mapStateToProps (state) {
const {
conversionRate,
identities,
+ tokens: existingTokens,
} = state.metamask
const accounts = state.metamask.accounts
const selectedAddress = state.metamask.selectedAddress || Object.keys(accounts)[0]
@@ -33,6 +34,7 @@ function mapStateToProps (state) {
conversionRate,
identities,
selectedAddress,
+ existingTokens,
}
}
@@ -66,6 +68,7 @@ PendingTx.prototype.componentDidUpdate = function (prevProps, prevState) {
}
PendingTx.prototype.setTokenData = async function () {
+ const { existingTokens } = this.props
const txMeta = this.gatherTxMeta()
const txParams = txMeta.txParams || {}
@@ -89,30 +92,15 @@ PendingTx.prototype.setTokenData = async function () {
}
if (isTokenTransaction) {
- const token = util.getContractAtAddress(txParams.to)
- const results = await Promise.all([
- token.symbol(),
- token.decimals(),
- ])
- const [ symbol, decimals ] = results
-
- if (symbol[0] && decimals[0]) {
- this.setState({
- transactionType: TX_TYPES.SEND_TOKEN,
- tokenAddress: txParams.to,
- tokenSymbol: symbol[0],
- tokenDecimals: decimals[0],
- isFetching: false,
- })
- } else {
- this.setState({
- transactionType: TX_TYPES.SEND_TOKEN,
- tokenAddress: txParams.to,
- tokenSymbol: null,
- tokenDecimals: null,
- isFetching: false,
- })
- }
+ const { symbol, decimals } = await getSymbolAndDecimals(txParams.to, existingTokens)
+
+ this.setState({
+ transactionType: TX_TYPES.SEND_TOKEN,
+ tokenAddress: txParams.to,
+ tokenSymbol: symbol,
+ tokenDecimals: decimals,
+ isFetching: false,
+ })
} else {
this.setState({
transactionType: TX_TYPES.SEND_ETHER,
diff --git a/ui/app/components/send/currency-display.js b/ui/app/components/send/currency-display.js
index a7bd5d7ea..90fb2b66c 100644
--- a/ui/app/components/send/currency-display.js
+++ b/ui/app/components/send/currency-display.js
@@ -89,7 +89,6 @@ CurrencyDisplay.prototype.render = function () {
} = this.props
const valueToRender = this.getValueToRender()
-
const convertedValueToRender = this.getConvertedValueToRender(valueToRender)
return h('div', {
@@ -97,22 +96,24 @@ CurrencyDisplay.prototype.render = function () {
style: {
borderColor: inError ? 'red' : null,
},
- onClick: () => this.currencyInput.focus(),
+ onClick: () => this.currencyInput && this.currencyInput.focus(),
}, [
h('div.currency-display__primary-row', [
h('div.currency-display__input-wrapper', [
- h(CurrencyInput, {
+ h(readOnly ? 'input' : CurrencyInput, {
className: primaryBalanceClassName,
value: `${valueToRender}`,
placeholder: '0',
readOnly,
- onInputChange: newValue => {
- handleChange(this.getAmount(newValue))
- },
- inputRef: input => { this.currencyInput = input },
+ ...(!readOnly ? {
+ onInputChange: newValue => {
+ handleChange(this.getAmount(newValue))
+ },
+ inputRef: input => { this.currencyInput = input },
+ } : {}),
}),
h('span.currency-display__currency-symbol', primaryCurrency),
diff --git a/ui/app/components/send/send-constants.js b/ui/app/components/send/send-constants.js
index b3ee0899a..5d89c74aa 100644
--- a/ui/app/components/send/send-constants.js
+++ b/ui/app/components/send/send-constants.js
@@ -1,8 +1,8 @@
const ethUtil = require('ethereumjs-util')
const { conversionUtil, multiplyCurrencies } = require('../../conversion-util')
-const MIN_GAS_PRICE_HEX = (100000000).toString(16)
-const MIN_GAS_PRICE_DEC = '100000000'
+const MIN_GAS_PRICE_DEC = '0'
+const MIN_GAS_PRICE_HEX = (parseInt(MIN_GAS_PRICE_DEC)).toString(16)
const MIN_GAS_LIMIT_DEC = '21000'
const MIN_GAS_LIMIT_HEX = (parseInt(MIN_GAS_LIMIT_DEC)).toString(16)
diff --git a/ui/app/components/shapeshift-form.js b/ui/app/components/shapeshift-form.js
index fd4a80a4a..22ab64426 100644
--- a/ui/app/components/shapeshift-form.js
+++ b/ui/app/components/shapeshift-form.js
@@ -55,6 +55,10 @@ function ShapeshiftForm () {
}
}
+ShapeshiftForm.prototype.getCoinPair = function () {
+ return `${this.state.depositCoin.toUpperCase()}_ETH`
+}
+
ShapeshiftForm.prototype.componentWillMount = function () {
this.props.shapeShiftSubview()
}
@@ -120,14 +124,12 @@ ShapeshiftForm.prototype.renderMetadata = function (label, value) {
}
ShapeshiftForm.prototype.renderMarketInfo = function () {
- const { depositCoin } = this.state
- const coinPair = `${depositCoin}_eth`
const { tokenExchangeRates } = this.props
const {
limit,
rate,
minimum,
- } = tokenExchangeRates[coinPair] || {}
+ } = tokenExchangeRates[this.getCoinPair()] || {}
return h('div.shapeshift-form__metadata', {}, [
@@ -172,10 +174,9 @@ ShapeshiftForm.prototype.renderQrCode = function () {
ShapeshiftForm.prototype.render = function () {
const { coinOptions, btnClass, warning } = this.props
- const { depositCoin, errorMessage, showQrCode, depositAddress } = this.state
- const coinPair = `${depositCoin}_eth`
+ const { errorMessage, showQrCode, depositAddress } = this.state
const { tokenExchangeRates } = this.props
- const token = tokenExchangeRates[coinPair]
+ const token = tokenExchangeRates[this.getCoinPair()]
return h('div.shapeshift-form-wrapper', [
showQrCode
diff --git a/ui/app/css/itcss/components/index.scss b/ui/app/css/itcss/components/index.scss
index 959eb9d15..1c544e162 100644
--- a/ui/app/css/itcss/components/index.scss
+++ b/ui/app/css/itcss/components/index.scss
@@ -61,3 +61,5 @@
@import './welcome-screen.scss';
@import './sender-to-recipient.scss';
+
+@import '../../../components/export-text-container/export-text-container.scss';
diff --git a/ui/app/css/itcss/components/pages/index.scss b/ui/app/css/itcss/components/pages/index.scss
index 82446fd7a..d0b59da53 100644
--- a/ui/app/css/itcss/components/pages/index.scss
+++ b/ui/app/css/itcss/components/pages/index.scss
@@ -1 +1,3 @@
@import './unlock.scss';
+
+@import './reveal-seed.scss';
diff --git a/ui/app/css/itcss/components/pages/reveal-seed.scss b/ui/app/css/itcss/components/pages/reveal-seed.scss
new file mode 100644
index 000000000..b8f13af4a
--- /dev/null
+++ b/ui/app/css/itcss/components/pages/reveal-seed.scss
@@ -0,0 +1,17 @@
+.reveal-seed {
+ &__content {
+ padding: 20px;
+ }
+
+ &__label {
+ padding-bottom: 10px;
+ font-weight: 400;
+ display: inline-block;
+ }
+
+ &__error {
+ color: $crimson;
+ font-size: 14px;
+ padding-top: 5px;
+ }
+}
diff --git a/ui/app/css/itcss/generic/index.scss b/ui/app/css/itcss/generic/index.scss
index 92321394b..7a64810c4 100644
--- a/ui/app/css/itcss/generic/index.scss
+++ b/ui/app/css/itcss/generic/index.scss
@@ -207,6 +207,27 @@ input.large-input {
&__content {
height: 100%;
overflow-y: auto;
+ min-height: 250px;
+ max-height: 400px;
+ }
+
+ &__warning-container {
+ background: $linen;
+ padding: 20px;
+ display: flex;
+ align-items: start;
+ }
+
+ &__warning-message {
+ padding-left: 15px;
+ }
+
+ &__warning-title {
+ font-weight: 500;
+ }
+
+ &__warning-icon {
+ padding-top: 5px;
}
}
@@ -237,3 +258,49 @@ input.large-input {
border-radius: 0;
}
}
+
+@media screen and (min-width: 576px) {
+ .page-container {
+ height: 600px;
+ flex: 0 0 auto;
+ }
+}
+
+.input-label {
+ padding-bottom: 10px;
+ font-weight: 400;
+ display: inline-block;
+}
+
+input.form-control {
+ padding-left: 10px;
+ font-size: 14px;
+ height: 40px;
+ border: 1px solid $alto;
+ border-radius: 3px;
+ width: 100%;
+
+ &::-webkit-input-placeholder {
+ font-weight: 100;
+ color: $dusty-gray;
+ }
+
+ &::-moz-placeholder {
+ font-weight: 100;
+ color: $dusty-gray;
+ }
+
+ &:-ms-input-placeholder {
+ font-weight: 100;
+ color: $dusty-gray;
+ }
+
+ &:-moz-placeholder {
+ font-weight: 100;
+ color: $dusty-gray;
+ }
+
+ &--error {
+ border: 1px solid $monzo;
+ }
+}
diff --git a/ui/app/css/itcss/settings/variables.scss b/ui/app/css/itcss/settings/variables.scss
index 51548306f..814d7a382 100644
--- a/ui/app/css/itcss/settings/variables.scss
+++ b/ui/app/css/itcss/settings/variables.scss
@@ -54,6 +54,7 @@ $saffron: #f6c343;
$dodger-blue: #3099f2;
$zumthor: #edf7ff;
$ecstasy: #f7861c;
+$linen: #fdf4f4;
/*
Z-Indicies
diff --git a/ui/app/keychains/hd/recover-seed/confirmation.js b/ui/app/keychains/hd/recover-seed/confirmation.js
deleted file mode 100644
index eb588415f..000000000
--- a/ui/app/keychains/hd/recover-seed/confirmation.js
+++ /dev/null
@@ -1,138 +0,0 @@
-const inherits = require('util').inherits
-const Component = require('react').Component
-const PropTypes = require('prop-types')
-const connect = require('react-redux').connect
-const h = require('react-hyperscript')
-const actions = require('../../../actions')
-const { withRouter } = require('react-router-dom')
-const { compose } = require('recompose')
-const {
- DEFAULT_ROUTE,
- INITIALIZE_BACKUP_PHRASE_ROUTE,
-} = require('../../../routes')
-
-RevealSeedConfirmation.contextTypes = {
- t: PropTypes.func,
-}
-
-module.exports = compose(
- withRouter,
- connect(mapStateToProps)
-)(RevealSeedConfirmation)
-
-
-inherits(RevealSeedConfirmation, Component)
-function RevealSeedConfirmation () {
- Component.call(this)
-}
-
-function mapStateToProps (state) {
- return {
- warning: state.appState.warning,
- }
-}
-
-RevealSeedConfirmation.prototype.render = function () {
- const props = this.props
-
- return (
-
- h('.initialize-screen.flex-column.flex-center.flex-grow', {
- style: { maxWidth: '420px' },
- }, [
-
- h('h3.flex-center.text-transform-uppercase', {
- style: {
- background: '#EBEBEB',
- color: '#AEAEAE',
- marginBottom: 24,
- width: '100%',
- fontSize: '20px',
- padding: 6,
- },
- }, [
- 'Reveal Seed Words',
- ]),
-
- h('.div', {
- style: {
- display: 'flex',
- flexDirection: 'column',
- padding: '20px',
- justifyContent: 'center',
- },
- }, [
-
- h('h4', this.context.t('revealSeedWordsWarning')),
-
- // confirmation
- h('input.large-input.letter-spacey', {
- type: 'password',
- id: 'password-box',
- placeholder: this.context.t('enterPasswordConfirm'),
- onKeyPress: this.checkConfirmation.bind(this),
- style: {
- width: 260,
- marginTop: '12px',
- },
- }),
-
- h('.flex-row.flex-start', {
- style: {
- marginTop: 30,
- width: '50%',
- },
- }, [
- // cancel
- h('button.primary', {
- onClick: this.goHome.bind(this),
- }, 'CANCEL'),
-
- // submit
- h('button.primary', {
- style: { marginLeft: '10px' },
- onClick: this.revealSeedWords.bind(this),
- }, 'OK'),
-
- ]),
-
- (props.warning) && (
- h('span.error', {
- style: {
- margin: '20px',
- },
- }, props.warning.split('-'))
- ),
-
- props.inProgress && (
- h('span.in-progress-notification', this.context.t('generatingSeed'))
- ),
- ]),
- ])
- )
-}
-
-RevealSeedConfirmation.prototype.componentDidMount = function () {
- document.getElementById('password-box').focus()
-}
-
-RevealSeedConfirmation.prototype.goHome = function () {
- this.props.dispatch(actions.showConfigPage(false))
- this.props.dispatch(actions.confirmSeedWords())
- .then(() => this.props.history.push(DEFAULT_ROUTE))
-}
-
-// create vault
-
-RevealSeedConfirmation.prototype.checkConfirmation = function (event) {
- if (event.key === 'Enter') {
- event.preventDefault()
- this.revealSeedWords()
- }
-}
-
-RevealSeedConfirmation.prototype.revealSeedWords = function () {
- var password = document.getElementById('password-box').value
- this.props.dispatch(actions.requestRevealSeed(password))
- .then(() => this.props.history.push(INITIALIZE_BACKUP_PHRASE_ROUTE))
-}
diff --git a/ui/app/send-v2.js b/ui/app/send-v2.js
index 30d3d3152..bd00b186e 100644
--- a/ui/app/send-v2.js
+++ b/ui/app/send-v2.js
@@ -493,7 +493,7 @@ SendTransactionScreen.prototype.renderFooter = function () {
history,
} = this.props
- const missingTokenBalance = selectedToken && !tokenBalance
+ const missingTokenBalance = selectedToken && (tokenBalance === null || tokenBalance === undefined)
const noErrors = !amountError && toError === null
return h('div.page-container__footer', [
diff --git a/ui/app/token-util.js b/ui/app/token-util.js
index f84051ef5..920442bfc 100644
--- a/ui/app/token-util.js
+++ b/ui/app/token-util.js
@@ -1,14 +1,6 @@
-const abi = require('human-standard-token-abi')
-const Eth = require('ethjs-query')
-const EthContract = require('ethjs-contract')
-
-const tokenInfoGetter = function () {
- if (typeof global.ethereumProvider === 'undefined') return
-
- const eth = new Eth(global.ethereumProvider)
- const contract = new EthContract(eth)
- const TokenContract = contract(abi)
+const util = require('./util')
+function tokenInfoGetter () {
const tokens = {}
return async (address) => {
@@ -16,18 +8,35 @@ const tokenInfoGetter = function () {
return tokens[address]
}
- const contract = TokenContract.at(address)
+ tokens[address] = await getSymbolAndDecimals(address)
- const result = await Promise.all([
- contract.symbol(),
- contract.decimals(),
- ])
+ return tokens[address]
+ }
+}
- const [ symbol = [], decimals = [] ] = result
+async function getSymbolAndDecimals (tokenAddress, existingTokens = []) {
+ const existingToken = existingTokens.find(({ address }) => tokenAddress === address)
+ if (existingToken) {
+ return existingToken
+ }
+
+ let result = []
+ try {
+ const token = util.getContractAtAddress(tokenAddress)
+
+ result = await Promise.all([
+ token.symbol(),
+ token.decimals(),
+ ])
+ } catch (err) {
+ console.log(`symbol() and decimal() calls for token at address ${tokenAddress} resulted in error:`, err)
+ }
- tokens[address] = { symbol: symbol[0], decimals: decimals[0] }
+ const [ symbol = [], decimals = [] ] = result
- return tokens[address]
+ return {
+ symbol: symbol[0] || null,
+ decimals: decimals[0] && decimals[0].toString() || null,
}
}
@@ -42,4 +51,5 @@ function calcTokenAmount (value, decimals) {
module.exports = {
tokenInfoGetter,
calcTokenAmount,
+ getSymbolAndDecimals,
}