aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md16
-rw-r--r--app/manifest.json6
-rw-r--r--app/scripts/background.js8
-rw-r--r--app/scripts/controllers/transactions.js4
-rw-r--r--app/scripts/edge-encryptor.js69
-rw-r--r--app/scripts/lib/tx-state-manager.js2
-rw-r--r--development/run-version-bump.js43
-rw-r--r--development/version-bump.js52
-rw-r--r--docs/bumping_version.md33
-rw-r--r--docs/publishing.md6
-rw-r--r--gulpfile.js4
-rw-r--r--mascara/src/app/first-time/import-seed-phrase-screen.js191
-rw-r--r--mascara/src/app/first-time/index.css16
-rw-r--r--old-ui/app/accounts/import/index.js26
-rw-r--r--old-ui/app/add-token.js3
-rw-r--r--old-ui/app/components/account-dropdowns.js2
-rw-r--r--old-ui/app/components/token-list.js5
-rw-r--r--old-ui/app/components/transaction-list-item.js127
-rw-r--r--old-ui/app/css/lib.css2
-rw-r--r--old-ui/app/info.js6
-rw-r--r--old-ui/app/unlock.js2
-rw-r--r--package.json13
-rw-r--r--test/stub/blacklist.json1374
-rw-r--r--test/unit/blacklist-controller-test.js2
-rw-r--r--test/unit/development/sample-changelog.md914
-rw-r--r--test/unit/development/sample-manifest.json71
-rw-r--r--test/unit/development/version–bump-test.js45
-rw-r--r--test/unit/edge-encryptor-test.js101
-rw-r--r--test/unit/message-manager-test.js4
-rw-r--r--test/unit/metamask-controller-test.js176
-rw-r--r--test/unit/network-contoller-test.js44
-rw-r--r--test/unit/tx-state-manager-test.js4
-rw-r--r--ui/app/accounts/import/index.js15
-rw-r--r--ui/app/actions.js6
-rw-r--r--ui/app/add-token.js26
-rw-r--r--ui/app/app.js26
-rw-r--r--ui/app/components/dropdowns/components/account-dropdowns.js18
-rw-r--r--ui/app/components/dropdowns/network-dropdown.js8
-rw-r--r--ui/app/components/modals/deposit-ether-modal.js5
-rw-r--r--ui/app/components/modals/modal.js12
-rw-r--r--ui/app/components/shapeshift-form.js19
-rw-r--r--ui/app/css/itcss/components/account-menu.scss5
-rw-r--r--ui/app/css/itcss/components/header.scss7
-rw-r--r--ui/app/css/itcss/components/modal.scss4
-rw-r--r--ui/app/css/itcss/components/new-account.scss10
-rw-r--r--ui/app/css/itcss/settings/variables.scss4
-rw-r--r--ui/app/reducers/app.js4
-rw-r--r--ui/app/reducers/metamask.js7
-rw-r--r--ui/app/send-v2.js15
-rw-r--r--ui/app/unlock.js4
-rw-r--r--yarn.lock6
51 files changed, 3230 insertions, 342 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 59f116aed..823b89b45 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,22 @@
## Current Master
+## 4.2.0 Tue Mar 06 2018
+
+- Replace "Loose" wording to "Imported".
+- Replace "Unlock" wording with "Log In".
+- Add Imported Account disclaimer.
+- Allow adding custom tokens to classic ui when balance is 0
+- Allow editing of symbol and decimal info when adding custom token in new-ui
+- NewUI shapeshift form can select all coins (not just BTC)
+- Add most of Microsoft Edge support.
+
+## 4.1.3 2018-2-28
+
+- Ensure MetaMask's inpage provider is named MetamaskInpageProvider to keep some sites from breaking.
+- Add retry transaction button back into classic ui.
+- Add network dropdown styles to support long custom RPC urls
+
## 4.1.2 2018-2-28
- Actually includes all the fixes mentioned in 4.1.1 (sorry)
diff --git a/app/manifest.json b/app/manifest.json
index 1c9c420f9..0c89c2b3e 100644
--- a/app/manifest.json
+++ b/app/manifest.json
@@ -1,7 +1,7 @@
{
"name": "MetaMask",
"short_name": "Metamask",
- "version": "4.1.2",
+ "version": "4.2.0",
"manifest_version": 2,
"author": "https://metamask.io",
"description": "Ethereum Browser Extension",
@@ -59,7 +59,7 @@
"clipboardWrite",
"http://localhost:8545/",
"https://*.infura.io/"
- ],
+ ],
"web_accessible_resources": [
"scripts/inpage.js"
],
@@ -68,4 +68,4 @@
"https://metamask.io/*"
]
}
-}
+} \ No newline at end of file
diff --git a/app/scripts/background.js b/app/scripts/background.js
index 4487ff318..601ae0372 100644
--- a/app/scripts/background.js
+++ b/app/scripts/background.js
@@ -16,6 +16,7 @@ const firstTimeState = require('./first-time-state')
const setupRaven = require('./lib/setupRaven')
const reportFailedTxToSentry = require('./lib/reportFailedTxToSentry')
const setupMetamaskMeshMetrics = require('./lib/setupMetamaskMeshMetrics')
+const EdgeEncryptor = require('./edge-encryptor')
const STORAGE_KEY = 'metamask-config'
@@ -32,6 +33,12 @@ global.METAMASK_NOTIFIER = notificationManager
const release = platform.getVersion()
const raven = setupRaven({ release })
+// browser check if it is Edge - https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser
+// Internet Explorer 6-11
+const isIE = !!document.documentMode
+// Edge 20+
+const isEdge = !isIE && !!window.StyleMedia
+
let popupIsOpen = false
let openMetamaskTabsIDs = {}
@@ -81,6 +88,7 @@ function setupController (initState) {
initState,
// platform specific api
platform,
+ encryptor: isEdge ? new EdgeEncryptor() : undefined,
})
global.metamaskController = controller
diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js
index ef5578d5a..9c2ca0dc8 100644
--- a/app/scripts/controllers/transactions.js
+++ b/app/scripts/controllers/transactions.js
@@ -3,7 +3,7 @@ const ObservableStore = require('obs-store')
const ethUtil = require('ethereumjs-util')
const Transaction = require('ethereumjs-tx')
const EthQuery = require('ethjs-query')
-const TransactionStateManger = require('../lib/tx-state-manager')
+const TransactionStateManager = require('../lib/tx-state-manager')
const TxGasUtil = require('../lib/tx-gas-utils')
const PendingTransactionTracker = require('../lib/pending-tx-tracker')
const createId = require('../lib/random-id')
@@ -38,7 +38,7 @@ module.exports = class TransactionController extends EventEmitter {
this.query = new EthQuery(this.provider)
this.txGasUtil = new TxGasUtil(this.provider)
- this.txStateManager = new TransactionStateManger({
+ this.txStateManager = new TransactionStateManager({
initState: opts.initState,
txHistoryLimit: opts.txHistoryLimit,
getNetwork: this.getNetwork.bind(this),
diff --git a/app/scripts/edge-encryptor.js b/app/scripts/edge-encryptor.js
new file mode 100644
index 000000000..24c0c93a8
--- /dev/null
+++ b/app/scripts/edge-encryptor.js
@@ -0,0 +1,69 @@
+const asmcrypto = require('asmcrypto.js')
+const Unibabel = require('browserify-unibabel')
+
+class EdgeEncryptor {
+
+ encrypt (password, dataObject) {
+
+ var salt = this._generateSalt()
+ return this._keyFromPassword(password, salt)
+ .then(function (key) {
+
+ var data = JSON.stringify(dataObject)
+ var dataBuffer = Unibabel.utf8ToBuffer(data)
+ var vector = global.crypto.getRandomValues(new Uint8Array(16))
+ var resultbuffer = asmcrypto.AES_GCM.encrypt(dataBuffer, key, vector)
+
+ var buffer = new Uint8Array(resultbuffer)
+ var vectorStr = Unibabel.bufferToBase64(vector)
+ var vaultStr = Unibabel.bufferToBase64(buffer)
+ return JSON.stringify({
+ data: vaultStr,
+ iv: vectorStr,
+ salt: salt,
+ })
+ })
+ }
+
+ decrypt (password, text) {
+
+ const payload = JSON.parse(text)
+ const salt = payload.salt
+ return this._keyFromPassword(password, salt)
+ .then(function (key) {
+ const encryptedData = Unibabel.base64ToBuffer(payload.data)
+ const vector = Unibabel.base64ToBuffer(payload.iv)
+ return new Promise((resolve, reject) => {
+ var result
+ try {
+ result = asmcrypto.AES_GCM.decrypt(encryptedData, key, vector)
+ } catch (err) {
+ return reject(new Error('Incorrect password'))
+ }
+ const decryptedData = new Uint8Array(result)
+ const decryptedStr = Unibabel.bufferToUtf8(decryptedData)
+ const decryptedObj = JSON.parse(decryptedStr)
+ resolve(decryptedObj)
+ })
+ })
+ }
+
+ _keyFromPassword (password, salt) {
+
+ var passBuffer = Unibabel.utf8ToBuffer(password)
+ var saltBuffer = Unibabel.base64ToBuffer(salt)
+ return new Promise((resolve) => {
+ var key = asmcrypto.PBKDF2_HMAC_SHA256.bytes(passBuffer, saltBuffer, 10000)
+ resolve(key)
+ })
+ }
+
+ _generateSalt (byteCount = 32) {
+ var view = new Uint8Array(byteCount)
+ global.crypto.getRandomValues(view)
+ var b64encoded = btoa(String.fromCharCode.apply(null, view))
+ return b64encoded
+ }
+}
+
+module.exports = EdgeEncryptor
diff --git a/app/scripts/lib/tx-state-manager.js b/app/scripts/lib/tx-state-manager.js
index 051efd247..2eb006380 100644
--- a/app/scripts/lib/tx-state-manager.js
+++ b/app/scripts/lib/tx-state-manager.js
@@ -4,7 +4,7 @@ const ObservableStore = require('obs-store')
const ethUtil = require('ethereumjs-util')
const txStateHistoryHelper = require('./tx-state-history-helper')
-module.exports = class TransactionStateManger extends EventEmitter {
+module.exports = class TransactionStateManager extends EventEmitter {
constructor ({ initState, txHistoryLimit, getNetwork }) {
super()
diff --git a/development/run-version-bump.js b/development/run-version-bump.js
new file mode 100644
index 000000000..fde14566e
--- /dev/null
+++ b/development/run-version-bump.js
@@ -0,0 +1,43 @@
+const { promisify } = require('util')
+const fs = require('fs')
+const readFile = promisify(fs.readFile)
+const writeFile = promisify(fs.writeFile)
+const path = require('path')
+const changelogPath = path.join(__dirname, '..', 'CHANGELOG.md')
+const manifestPath = path.join(__dirname, '..', 'app', 'manifest.json')
+const manifest = require('../app/manifest.json')
+const versionBump = require('./version-bump')
+const bumpType = normalizeType(process.argv[2])
+
+start().catch(console.error)
+
+async function start() {
+
+ const changeBuffer = await readFile(changelogPath)
+ const changelog = changeBuffer.toString()
+
+ const newData = await versionBump(bumpType, changelog, manifest)
+
+ const manifestString = JSON.stringify(newData.manifest, null, 2)
+
+ await writeFile(changelogPath, newData.changelog)
+ await writeFile(manifestPath, manifestString)
+
+ console.log(`Bumped ${bumpType} to version ${newData.version}`)
+}
+
+
+function normalizeType (userInput) {
+ const err = new Error('First option must be a type (major, minor, or patch)')
+ if (!userInput || typeof userInput !== 'string') {
+ throw err
+ }
+
+ const lower = userInput.toLowerCase()
+
+ if (lower !== 'major' && lower !== 'minor' && lower !== 'patch') {
+ throw err
+ }
+
+ return lower
+}
diff --git a/development/version-bump.js b/development/version-bump.js
new file mode 100644
index 000000000..bedf87c01
--- /dev/null
+++ b/development/version-bump.js
@@ -0,0 +1,52 @@
+const clone = require('clone')
+
+async function versionBump(bumpType, changelog, oldManifest) {
+ const manifest = clone(oldManifest)
+ const newVersion = newVersionFrom(manifest, bumpType)
+
+ manifest.version = newVersion
+ const date = (new Date()).toDateString()
+
+ const logHeader = `\n## ${newVersion} ${date}`
+ const logLines = changelog.split('\n')
+ for (let i = 0; i < logLines.length; i++) {
+ if (logLines[i].includes('Current Master')) {
+ logLines.splice(i + 1, 0, logHeader)
+ break
+ }
+ }
+
+ return {
+ version: newVersion,
+ manifest: manifest,
+ changelog: logLines.join('\n')
+ }
+}
+
+function newVersionFrom (manifest, bumpType) {
+ const string = manifest.version
+ let segments = string.split('.').map((str) => parseInt(str))
+
+ switch (bumpType) {
+ case 'major':
+ segments[0] += 1
+ segments[1] = 0
+ segments[2] = 0
+ break
+ case 'minor':
+ segments[1] += 1
+ segments[2] = 0
+ break
+ case 'patch':
+ segments[2] += 1
+ break
+ }
+
+ return segments.map(String).join('.')
+}
+
+function bumpManifest (manifest, bumpType) {
+
+}
+
+module.exports = versionBump
diff --git a/docs/bumping_version.md b/docs/bumping_version.md
new file mode 100644
index 000000000..df38369a2
--- /dev/null
+++ b/docs/bumping_version.md
@@ -0,0 +1,33 @@
+# How to Bump MetaMask's Version Automatically
+
+```
+npm run version:bump patch
+```
+
+MetaMask publishes using a loose [semver](https://semver.org/) interpretation. We divide the three segments of our version into three types of version bump:
+
+## Major
+
+Means a breaking change, either an API removed, or a major user expectation changed.
+
+## Minor
+
+Means a new API or new user feature.
+
+## Patch
+
+Means a fix for a bug, or correcting something that should have been assumed to work a different way.
+
+# Bumping the version
+
+`npm run version:bump $BUMP_TYPE` where `$BUMP_TYPE` is one of `major`, `minor`, or `patch`.
+
+This will increment the version in the `app/manifest.json` and `CHANGELOG.md` files according to our current protocol, where the manifest's version is updated, and any line items currently under the changelog's "master" section are now under the new dated version section.
+
+# Modifying the bump script
+
+The script that is executed lives [here](../development/run-version-bump.js).
+The main functions all live [here](../development/version-bump.js).
+The test for this behavior is at `test/unit/development/version-bump-test.js`.
+
+
diff --git a/docs/publishing.md b/docs/publishing.md
index 00369acf9..3022b7eda 100644
--- a/docs/publishing.md
+++ b/docs/publishing.md
@@ -4,15 +4,15 @@ When publishing a new version of MetaMask, we follow this procedure:
## Incrementing Version & Changelog
- You must be authorized already on the MetaMask plugin.
+Version can be automatically incremented [using our bump script](./bumping-version.md).
-1. Update the version in `app/manifest.json` and the Changelog in `CHANGELOG.md`.
-2. Visit [the chrome developer dashboard](https://chrome.google.com/webstore/developer/dashboard?authuser=2).
+npm run version:bump $BUMP_TYPE` where `$BUMP_TYPE` is one of `major`, `minor`, or `patch`.
## Publishing
1. `npm run dist` to generate the latest build.
2. Publish to chrome store.
+ - Visit [the chrome developer dashboard](https://chrome.google.com/webstore/developer/dashboard?authuser=2).
3. Publish to firefox addon marketplace.
4. Post on Github releases page.
5. `npm run announce`, post that announcement in our public places.
diff --git a/gulpfile.js b/gulpfile.js
index 3ade82f87..adfb148a9 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -407,7 +407,9 @@ function bundleTask(opts) {
// loads map from browserify file
.pipe(gulpif(debug, sourcemaps.init({ loadMaps: true })))
// Minification
- .pipe(gulpif(opts.isBuild, uglify()))
+ .pipe(gulpif(opts.isBuild, uglify({
+ mangle: { reserved: [ 'MetamaskInpageProvider' ] },
+ })))
// writes .map file
.pipe(gulpif(debug, sourcemaps.write('./')))
// write completed bundles
diff --git a/mascara/src/app/first-time/import-seed-phrase-screen.js b/mascara/src/app/first-time/import-seed-phrase-screen.js
index 93c3f9203..de8d675e1 100644
--- a/mascara/src/app/first-time/import-seed-phrase-screen.js
+++ b/mascara/src/app/first-time/import-seed-phrase-screen.js
@@ -1,13 +1,12 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import {connect} from 'react-redux'
-import LoadingScreen from './loading-screen'
+import classnames from 'classnames'
import {
createNewVaultAndRestore,
hideWarning,
displayWarning,
unMarkPasswordForgotten,
- clearNotices,
} from '../../../../ui/app/actions'
class ImportSeedPhraseScreen extends Component {
@@ -17,8 +16,8 @@ class ImportSeedPhraseScreen extends Component {
next: PropTypes.func.isRequired,
createNewVaultAndRestore: PropTypes.func.isRequired,
hideWarning: PropTypes.func.isRequired,
- isLoading: PropTypes.bool.isRequired,
displayWarning: PropTypes.func,
+ leaveImportSeedScreenState: PropTypes.func,
};
state = {
@@ -27,98 +26,130 @@ class ImportSeedPhraseScreen extends Component {
confirmPassword: '',
}
- onClick = () => {
- const { password, seedPhrase, confirmPassword } = this.state
- const { createNewVaultAndRestore, next, displayWarning, leaveImportSeedScreenState } = this.props
+ parseSeedPhrase = (seedPhrase) => {
+ return seedPhrase
+ .match(/\w+/g)
+ .join(' ')
+ }
- if (seedPhrase.split(' ').length !== 12) {
- this.warning = 'Seed Phrases are 12 words long'
- displayWarning(this.warning)
- return
- }
+ onChange = ({ seedPhrase, password, confirmPassword }) => {
+ const {
+ password: prevPassword,
+ confirmPassword: prevConfirmPassword,
+ } = this.state
+ const { displayWarning, hideWarning } = this.props
+
+ let warning = null
- if (password.length < 8) {
- this.warning = 'Passwords require a mimimum length of 8'
- displayWarning(this.warning)
- return
+ if (seedPhrase && this.parseSeedPhrase(seedPhrase).split(' ').length !== 12) {
+ warning = 'Seed Phrases are 12 words long'
+ } else if (password && password.length < 8) {
+ warning = 'Passwords require a mimimum length of 8'
+ } else if ((password || prevPassword) !== (confirmPassword || prevConfirmPassword)) {
+ warning = 'Confirmed password does not match'
}
- if (password !== confirmPassword) {
- this.warning = 'Confirmed password does not match'
- displayWarning(this.warning)
- return
+ if (warning) {
+ displayWarning(warning)
+ } else {
+ hideWarning()
}
- this.warning = null
+
+ seedPhrase && this.setState({ seedPhrase })
+ password && this.setState({ password })
+ confirmPassword && this.setState({ confirmPassword })
+ }
+
+ onClick = () => {
+ const { password, seedPhrase } = this.state
+ const {
+ createNewVaultAndRestore,
+ next,
+ displayWarning,
+ leaveImportSeedScreenState,
+ } = this.props
+
leaveImportSeedScreenState()
- createNewVaultAndRestore(password, seedPhrase)
+ createNewVaultAndRestore(password, this.parseSeedPhrase(seedPhrase))
.then(next)
}
render () {
- return this.props.isLoading
- ? <LoadingScreen loadingMessage="Creating your new account" />
- : (
- <div className="import-account">
- <a
- className="import-account__back-button"
- onClick={e => {
- e.preventDefault()
- this.props.back()
- }}
- href="#"
- >
- {`< Back`}
- </a>
- <div className="import-account__title">
- Import an Account with Seed Phrase
- </div>
- <div className="import-account__selector-label">
- Enter your secret twelve word phrase here to restore your vault.
- </div>
- <div className="import-account__input-wrapper">
- <label className="import-account__input-label">Wallet Seed</label>
- <textarea
- className="import-account__secret-phrase"
- onChange={e => this.setState({seedPhrase: e.target.value})}
- placeholder="Separate each word with a single space"
- />
- </div>
- <span
- className="error"
- >
- {this.props.warning}
- </span>
- <div className="import-account__input-wrapper">
- <label className="import-account__input-label">New Password</label>
- <input
- className="first-time-flow__input"
- type="password"
- placeholder="New Password (min 8 characters)"
- onChange={e => this.setState({password: e.target.value})}
- />
- </div>
- <div className="import-account__input-wrapper">
- <label className="import-account__input-label">Confirm Password</label>
- <input
- className="first-time-flow__input"
- type="password"
- placeholder="Confirm Password"
- onChange={e => this.setState({confirmPassword: e.target.value})}
- />
- </div>
- <button
- className="first-time-flow__button"
- onClick={this.onClick}
- >
- Import
- </button>
+ const { seedPhrase, password, confirmPassword } = this.state
+ const { warning } = this.props
+ const importDisabled = warning || !seedPhrase || !password || !confirmPassword
+ return (
+ <div className="import-account">
+ <a
+ className="import-account__back-button"
+ onClick={e => {
+ e.preventDefault()
+ this.props.back()
+ }}
+ href="#"
+ >
+ {`< Back`}
+ </a>
+ <div className="import-account__title">
+ Import an Account with Seed Phrase
+ </div>
+ <div className="import-account__selector-label">
+ Enter your secret twelve word phrase here to restore your vault.
+ </div>
+ <div className="import-account__input-wrapper">
+ <label className="import-account__input-label">Wallet Seed</label>
+ <textarea
+ className="import-account__secret-phrase"
+ onChange={e => this.onChange({seedPhrase: e.target.value})}
+ value={this.state.seedPhrase}
+ placeholder="Separate each word with a single space"
+ />
+ </div>
+ <span
+ className="error"
+ >
+ {this.props.warning}
+ </span>
+ <div className="import-account__input-wrapper">
+ <label className="import-account__input-label">New Password</label>
+ <input
+ className="first-time-flow__input"
+ type="password"
+ placeholder="New Password (min 8 characters)"
+ onChange={e => this.onChange({password: e.target.value})}
+ />
+ </div>
+ <div className="import-account__input-wrapper">
+ <label
+ className="import-account__input-label"
+ className={classnames('import-account__input-label', {
+ 'import-account__input-label__disabled': password.length < 8,
+ })}
+ >Confirm Password</label>
+ <input
+ className={classnames('first-time-flow__input', {
+ 'first-time-flow__input__disabled': password.length < 8,
+ })}
+ type="password"
+ placeholder="Confirm Password"
+ onChange={e => this.onChange({confirmPassword: e.target.value})}
+ disabled={password.length < 8}
+ />
</div>
- )
+ <button
+ className="first-time-flow__button"
+ onClick={() => !importDisabled && this.onClick()}
+ disabled={importDisabled}
+ >
+ Import
+ </button>
+ </div>
+ )
}
}
export default connect(
- ({ appState: { isLoading, warning } }) => ({ isLoading, warning }),
+ ({ appState: { warning } }) => ({ warning }),
dispatch => ({
leaveImportSeedScreenState: () => {
dispatch(unMarkPasswordForgotten())
diff --git a/mascara/src/app/first-time/index.css b/mascara/src/app/first-time/index.css
index 109946e1d..f59eb4ce1 100644
--- a/mascara/src/app/first-time/index.css
+++ b/mascara/src/app/first-time/index.css
@@ -1,11 +1,11 @@
.first-time-flow {
- height: 100vh;
width: 100vw;
- background-color: #FFF;
+ background-color: #fff;
overflow: auto;
display: flex;
justify-content: center;
+ flex: 1 0 auto;
}
.alpha-warning {
@@ -45,12 +45,12 @@
.buy-ether {
display: flex;
flex-flow: column nowrap;
- margin: 67px 0 50px 146px;
+ margin: 67px 0 50px;
max-width: 35rem;
}
.create-password {
- margin: 67px 0 50px 0px;
+ margin: 67px 0 50px;
}
.import-account {
@@ -418,6 +418,10 @@ button.backup-phrase__confirm-seed-option:hover {
line-height: 23px;
}
+.import-account__input-label__disabled {
+ opacity: 0.5;
+}
+
.import-account__input {
width: 325px !important;
}
@@ -564,6 +568,10 @@ button.backup-phrase__confirm-seed-option:hover {
background-color: #FFFFFF;
}
+.first-time-flow__input__disabled {
+ opacity: 0.5;
+}
+
.first-time-flow__input::placeholder {
color: #9B9B9B;
font-weight: 200;
diff --git a/old-ui/app/accounts/import/index.js b/old-ui/app/accounts/import/index.js
index 3502efe93..a57525ccf 100644
--- a/old-ui/app/accounts/import/index.js
+++ b/old-ui/app/accounts/import/index.js
@@ -34,10 +34,7 @@ AccountImportSubview.prototype.render = function () {
const { type } = state
return (
- h('div', {
- style: {
- },
- }, [
+ h('div', [
h('.section-title.flex-row.flex-center', [
h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', {
onClick: (event) => {
@@ -46,6 +43,27 @@ AccountImportSubview.prototype.render = function () {
}),
h('h2.page-subtitle', 'Import Accounts'),
]),
+ h('.error', {
+ style: {
+ display: 'inline-block',
+ alignItems: 'center',
+ padding: '5px 15px 0px 15px',
+ },
+ }, [
+ h('span', 'Imported accounts will not be associated with your originally created MetaMask account seedphrase. Learn more about imported accounts '),
+ h('span', {
+ style: {
+ color: 'rgba(247, 134, 28, 1)',
+ cursor: 'pointer',
+ textDecoration: 'underline',
+ },
+ onClick: () => {
+ global.platform.openWindow({
+ url: 'https://metamask.helpscoutdocs.com/article/17-what-are-loose-accounts',
+ })
+ },
+ }, 'here.'),
+ ]),
h('div', {
style: {
padding: '10px',
diff --git a/old-ui/app/add-token.js b/old-ui/app/add-token.js
index 8a3e66978..e869ac39a 100644
--- a/old-ui/app/add-token.js
+++ b/old-ui/app/add-token.js
@@ -156,6 +156,9 @@ AddTokenScreen.prototype.render = function () {
const { address, symbol, decimals } = this.state
this.props.dispatch(actions.addToken(address.trim(), symbol.trim(), decimals))
+ .then(() => {
+ this.props.dispatch(actions.goHome())
+ })
},
}, 'Add'),
]),
diff --git a/old-ui/app/components/account-dropdowns.js b/old-ui/app/components/account-dropdowns.js
index 7a2357921..53468a1a1 100644
--- a/old-ui/app/components/account-dropdowns.js
+++ b/old-ui/app/components/account-dropdowns.js
@@ -79,7 +79,7 @@ class AccountDropdowns extends Component {
try { // Sometimes keyrings aren't loaded yet:
const type = keyring.type
const isLoose = type !== 'HD Key Tree'
- return isLoose ? h('.keyring-label', 'LOOSE') : null
+ return isLoose ? h('.keyring-label', 'IMPORTED') : null
} catch (e) { return }
}
diff --git a/old-ui/app/components/token-list.js b/old-ui/app/components/token-list.js
index 998ec901d..149733b89 100644
--- a/old-ui/app/components/token-list.js
+++ b/old-ui/app/components/token-list.js
@@ -194,10 +194,7 @@ TokenList.prototype.componentWillUpdate = function (nextProps) {
}
TokenList.prototype.updateBalances = function (tokens) {
- const heldTokens = tokens.filter(token => {
- return token.balance !== '0' && token.string !== '0.000'
- })
- this.setState({ tokens: heldTokens, isLoading: false })
+ this.setState({ tokens, isLoading: false })
}
TokenList.prototype.componentWillUnmount = function () {
diff --git a/old-ui/app/components/transaction-list-item.js b/old-ui/app/components/transaction-list-item.js
index 95670bd54..e7251df8d 100644
--- a/old-ui/app/components/transaction-list-item.js
+++ b/old-ui/app/components/transaction-list-item.js
@@ -1,6 +1,7 @@
const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
+const connect = require('react-redux').connect
const EthBalance = require('./eth-balance')
const addressSummary = require('../util').addressSummary
@@ -9,18 +10,33 @@ const CopyButton = require('./copyButton')
const vreme = new (require('vreme'))()
const Tooltip = require('./tooltip')
const numberToBN = require('number-to-bn')
+const actions = require('../../../ui/app/actions')
const TransactionIcon = require('./transaction-list-item-icon')
const ShiftListItem = require('./shift-list-item')
-module.exports = TransactionListItem
+
+const mapDispatchToProps = dispatch => {
+ return {
+ retryTransaction: transactionId => dispatch(actions.retryTransaction(transactionId)),
+ }
+}
+
+module.exports = connect(null, mapDispatchToProps)(TransactionListItem)
inherits(TransactionListItem, Component)
function TransactionListItem () {
Component.call(this)
}
+TransactionListItem.prototype.showRetryButton = function () {
+ const { transaction = {} } = this.props
+ const { status, time } = transaction
+ return status === 'submitted' && Date.now() - time > 30000
+}
+
TransactionListItem.prototype.render = function () {
const { transaction, network, conversionRate, currentCurrency } = this.props
+ const { status } = transaction
if (transaction.key === 'shapeshift') {
if (network === '1') return h(ShiftListItem, transaction)
}
@@ -32,7 +48,7 @@ TransactionListItem.prototype.render = function () {
var isMsg = ('msgParams' in transaction)
var isTx = ('txParams' in transaction)
- var isPending = transaction.status === 'unapproved'
+ var isPending = status === 'unapproved'
let txParams
if (isTx) {
txParams = transaction.txParams
@@ -44,7 +60,7 @@ TransactionListItem.prototype.render = function () {
const isClickable = ('hash' in transaction && isLinkable) || isPending
return (
- h(`.transaction-list-item.flex-row.flex-space-between${isClickable ? '.pointer' : ''}`, {
+ h('.transaction-list-item.flex-column', {
onClick: (event) => {
if (isPending) {
this.props.showTx(transaction.id)
@@ -56,51 +72,92 @@ TransactionListItem.prototype.render = function () {
},
style: {
padding: '20px 0',
- display: 'flex',
- justifyContent: 'space-between',
+ alignItems: 'center',
},
}, [
+ h(`.flex-row.flex-space-between${isClickable ? '.pointer' : ''}`, {
+ style: {
+ width: '100%',
+ },
+ }, [
+ h('.identicon-wrapper.flex-column.flex-center.select-none', [
+ h(TransactionIcon, { txParams, transaction, isTx, isMsg }),
+ ]),
- h('.identicon-wrapper.flex-column.flex-center.select-none', [
- h(TransactionIcon, { txParams, transaction, isTx, isMsg }),
+ h(Tooltip, {
+ title: 'Transaction Number',
+ position: 'right',
+ }, [
+ h('span', {
+ style: {
+ display: 'flex',
+ cursor: 'normal',
+ flexDirection: 'column',
+ alignItems: 'center',
+ justifyContent: 'center',
+ padding: '10px',
+ },
+ }, nonce),
+ ]),
+
+ h('.flex-column', {style: {width: '200px', overflow: 'hidden'}}, [
+ domainField(txParams),
+ h('div', date),
+ recipientField(txParams, transaction, isTx, isMsg),
+ ]),
+
+ // Places a copy button if tx is successful, else places a placeholder empty div.
+ transaction.hash ? h(CopyButton, { value: transaction.hash }) : h('div', {style: { display: 'flex', alignItems: 'center', width: '26px' }}),
+
+ isTx ? h(EthBalance, {
+ value: txParams.value,
+ conversionRate,
+ currentCurrency,
+ width: '55px',
+ shorten: true,
+ showFiat: false,
+ style: {fontSize: '15px'},
+ }) : h('.flex-column'),
]),
- h(Tooltip, {
- title: 'Transaction Number',
- position: 'right',
+ this.showRetryButton() && h('.transition-list-item__retry.grow-on-hover', {
+ onClick: event => {
+ event.stopPropagation()
+ this.resubmit()
+ },
+ style: {
+ height: '22px',
+ borderRadius: '22px',
+ color: '#F9881B',
+ padding: '0 20px',
+ backgroundColor: '#FFE3C9',
+ display: 'flex',
+ justifyContent: 'center',
+ alignItems: 'center',
+ fontSize: '8px',
+ cursor: 'pointer',
+ },
}, [
- h('span', {
+ h('div', {
style: {
- display: 'flex',
- cursor: 'normal',
- flexDirection: 'column',
- alignItems: 'center',
- justifyContent: 'center',
+ paddingRight: '2px',
},
- }, nonce),
- ]),
-
- h('.flex-column', {style: {width: '150px', overflow: 'hidden'}}, [
- domainField(txParams),
- h('div', date),
- recipientField(txParams, transaction, isTx, isMsg),
+ }, 'Taking too long?'),
+ h('div', {
+ style: {
+ textDecoration: 'underline',
+ },
+ }, 'Retry with a higher gas price here'),
]),
-
- // Places a copy button if tx is successful, else places a placeholder empty div.
- transaction.hash ? h(CopyButton, { value: transaction.hash }) : h('div', {style: { display: 'flex', alignItems: 'center', width: '26px' }}),
-
- isTx ? h(EthBalance, {
- value: txParams.value,
- conversionRate,
- currentCurrency,
- shorten: true,
- showFiat: false,
- style: {fontSize: '15px'},
- }) : h('.flex-column'),
])
)
}
+TransactionListItem.prototype.resubmit = function () {
+ const { transaction } = this.props
+ this.props.retryTransaction(transaction.id)
+}
+
function domainField (txParams) {
return h('div', {
style: {
diff --git a/old-ui/app/css/lib.css b/old-ui/app/css/lib.css
index f3acbee76..fd63b2b2e 100644
--- a/old-ui/app/css/lib.css
+++ b/old-ui/app/css/lib.css
@@ -217,7 +217,7 @@ hr.horizontal-line {
background: rgba(255,0,0,0.8);
color: white;
bottom: 0px;
- left: -8px;
+ left: -18px;
border-radius: 10px;
height: 20px;
min-width: 20px;
diff --git a/old-ui/app/info.js b/old-ui/app/info.js
index db9f30f23..d79b8a3d2 100644
--- a/old-ui/app/info.js
+++ b/old-ui/app/info.js
@@ -63,7 +63,7 @@ InfoScreen.prototype.render = function () {
h('a', {
href: 'https://metamask.io/privacy.html',
target: '_blank',
- onClick (event) { this.navigateTo(event.target.href) },
+ onClick: (event) => { this.navigateTo(event.target.href) },
}, [
h('div.info', 'Privacy Policy'),
]),
@@ -72,7 +72,7 @@ InfoScreen.prototype.render = function () {
h('a', {
href: 'https://metamask.io/terms.html',
target: '_blank',
- onClick (event) { this.navigateTo(event.target.href) },
+ onClick: (event) => { this.navigateTo(event.target.href) },
}, [
h('div.info', 'Terms of Use'),
]),
@@ -81,7 +81,7 @@ InfoScreen.prototype.render = function () {
h('a', {
href: 'https://metamask.io/attributions.html',
target: '_blank',
- onClick (event) { this.navigateTo(event.target.href) },
+ onClick: (event) => { this.navigateTo(event.target.href) },
}, [
h('div.info', 'Attributions'),
]),
diff --git a/old-ui/app/unlock.js b/old-ui/app/unlock.js
index a1f791552..7bf4ad29f 100644
--- a/old-ui/app/unlock.js
+++ b/old-ui/app/unlock.js
@@ -69,7 +69,7 @@ UnlockScreen.prototype.render = function () {
style: {
margin: 10,
},
- }, 'Unlock'),
+ }, 'Log In'),
]),
h('.flex-row.flex-center.flex-grow', [
diff --git a/package.json b/package.json
index d712e00ac..fd2554f73 100644
--- a/package.json
+++ b/package.json
@@ -13,7 +13,7 @@
"dist": "npm run dist:clear && npm install && gulp dist",
"dist:clear": "rm -rf node_modules/eth-contract-metadata && rm -rf node_modules/eth-phishing-detect",
"test": "npm run lint && npm run test:coverage && npm run test:integration",
- "test:unit": "METAMASK_ENV=test mocha --exit --compilers js:babel-core/register --require test/helper.js --recursive \"test/unit/**/*.js\"",
+ "test:unit": "METAMASK_ENV=test mocha --exit --require babel-core/register --require test/helper.js --recursive \"test/unit/**/*.js\"",
"test:single": "METAMASK_ENV=test mocha --require test/helper.js",
"test:integration": "gulp build:scss && npm run test:flat && npm run test:mascara",
"test:coverage": "nyc npm run test:unit && npm run test:coveralls-upload",
@@ -32,6 +32,7 @@
"lint:fix": "gulp lint:fix",
"disc": "gulp disc --debug",
"announce": "node development/announcer.js",
+ "version:bump": "node development/run-version-bump.js",
"generateNotice": "node notices/notice-generator.js",
"deleteNotice": "node notices/notice-delete.js"
},
@@ -53,6 +54,7 @@
},
"dependencies": {
"abi-decoder": "^1.0.9",
+ "asmcrypto.js": "0.22.0",
"async": "^2.5.0",
"await-semaphore": "^0.1.1",
"babel-runtime": "^6.23.0",
@@ -63,6 +65,7 @@
"boron": "^0.2.3",
"browser-passworder": "^2.0.3",
"browserify-derequire": "^0.9.4",
+ "browserify-unibabel": "^3.0.0",
"classnames": "^2.2.5",
"client-sw-ready-event": "^3.3.0",
"clone": "^2.1.1",
@@ -77,11 +80,11 @@
"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.5",
"eth-json-rpc-infura": "^3.0.0",
"eth-keyring-controller": "^2.1.4",
- "eth-contract-metadata": "^1.1.5",
- "eth-hd-keyring": "^1.2.1",
"eth-phishing-detect": "^1.1.4",
"eth-query": "^2.1.2",
"eth-sig-util": "^1.4.2",
@@ -211,7 +214,7 @@
"gulp-stylefmt": "^1.1.0",
"gulp-stylelint": "^4.0.0",
"gulp-uglify": "^3.0.0",
- "gulp-uglify-es": "^1.0.0",
+ "gulp-uglify-es": "^1.0.1",
"gulp-util": "^3.0.7",
"gulp-watch": "^5.0.0",
"gulp-zip": "^4.0.0",
@@ -219,7 +222,7 @@
"jsdom": "^11.1.0",
"jsdom-global": "^3.0.2",
"jshint-stylish": "~2.2.1",
- "karma": "^1.7.1",
+ "karma": "^2.0.0",
"karma-chrome-launcher": "^2.2.0",
"karma-cli": "^1.0.1",
"karma-firefox-launcher": "^1.0.1",
diff --git a/test/stub/blacklist.json b/test/stub/blacklist.json
new file mode 100644
index 000000000..6a3230b2f
--- /dev/null
+++ b/test/stub/blacklist.json
@@ -0,0 +1,1374 @@
+{
+ "version": 2,
+ "tolerance": 2,
+ "fuzzylist": [
+ "metamask.io",
+ "myetherwallet.com",
+ "cryptokitties.co",
+ "mycrypto.com"
+ ],
+ "whitelist": [
+ "crypto.pro",
+ "ocrypto.org",
+ "wecrypto.net",
+ "iccrypto.io",
+ "crypto.kred",
+ "ohmycrypto.io",
+ "spcrypto.net",
+ "melcrypto.com",
+ "zzcrypto.org",
+ "zzcrypto.net",
+ "crypto.bg",
+ "mycrypto24.online",
+ "acrypto.io",
+ "mycrypto.ca",
+ "scrypto.io",
+ "mycrypto.dk",
+ "mvzcrypto.com",
+ "ambcrypto.com",
+ "crypto.bi",
+ "crypto.jobs",
+ "crypto.help",
+ "my.crypt.observer",
+ "crypt.observer",
+ "ucrypto.com",
+ "cryptojobslist.com",
+ "crypto.review",
+ "crypto.me",
+ "b3crypto.com",
+ "mycrypto.ninja",
+ "jkcrypto.com",
+ "crypto.cr",
+ "mycrypto.live",
+ "yocrypto.io",
+ "crypto.ba",
+ "zacrypto.info",
+ "mycrypto.com",
+ "remix.ethereum.org",
+ "metahash.io",
+ "metahash.net",
+ "metahash.org",
+ "cryptotitties.com",
+ "cryptocities.net",
+ "cryptoshitties.co",
+ "cryptotitties.fun",
+ "cryptokitties.forsale",
+ "cryptokitties.care",
+ "metamate.cc",
+ "metamesh.tech",
+ "ico.nexus.social",
+ "metamesh.org",
+ "metatask.io",
+ "metmask.com",
+ "metarasa.com",
+ "metapack.com",
+ "metacase.com",
+ "metafas.nl",
+ "metamako.com",
+ "metamast.com",
+ "metamax.ru",
+ "metadesk.io",
+ "metadisk.com",
+ "metallsk.ru",
+ "metamag.fr",
+ "metamaks.ru",
+ "metamap.ru",
+ "metamaps.cc",
+ "metamats.com",
+ "metamax.by",
+ "metamax.com",
+ "metamax.io",
+ "metamuse.net",
+ "metarank.com",
+ "metaxas.com",
+ "megamas2.ru",
+ "metamask.io",
+ "myetherwallet.com",
+ "myethlerwallet.com",
+ "ethereum.org",
+ "myetheroll.com",
+ "myetherapi.com",
+ "ledgerwallet.com",
+ "databrokerdao.com",
+ "etherscan.io",
+ "etherid.org",
+ "ether.cards",
+ "etheroll.com",
+ "ethnews.com",
+ "ethex.market",
+ "ethereumdev.io",
+ "ethereumdev.kr",
+ "dether.io",
+ "ethermine.org",
+ "slaask.com",
+ "etherbtc.io",
+ "ethereal.capital",
+ "etherisc.com",
+ "m.famalk.net",
+ "etherecho.com",
+ "ethereum.os.tc",
+ "theethereum.wiki",
+ "metajack.im",
+ "etherhub.io",
+ "ethereum.network",
+ "ethereum.link",
+ "ethereum.com",
+ "prethereum.org",
+ "ethereumj.io",
+ "etheraus.com",
+ "ethereum.dev",
+ "1ethereum.ru",
+ "ethereum.nz",
+ "nethereum.com",
+ "metabank.com",
+ "metamas.com",
+ "aventus.io",
+ "metabase.com",
+ "etherdelta.com",
+ "metabase.one",
+ "cryptokitties.co",
+ "remme.io",
+ "jibrel.network"
+ ],
+ "blacklist": [
+ "xn--myethrwalle-jb9e19a.com",
+ "xn--myetheralle-7b9ezl.com",
+ "iconfoundation.co",
+ "fundrequest.info",
+ "xn--myetherwale-os8e7x.com",
+ "remme-ico.eu",
+ "gonetwork.live",
+ "token.gonetwork.pro",
+ "gonetwork.pro",
+ "gonetwork.eu",
+ "nucleus-vision.cc",
+ "jibreltoken.in",
+ "dock.so",
+ "dock.promo",
+ "xn--mycrypt-r0a.com",
+ "xn--mycrypt-g1a.com",
+ "xn--mycrpto-y2a.com",
+ "ethexploit.org",
+ "remme.in",
+ "remme.ws",
+ "remme.com.ng",
+ "nyeitthervvallet.com",
+ "xn--myeerhwailet-ooc.com",
+ "myeterhwaliot.com",
+ "remme.live",
+ "xn--yethewalle-to2exkhi.com",
+ "myetherwallet.custom-token.com",
+ "custom-token.com",
+ "sale-earn.com",
+ "bankera.live",
+ "originprotocol.io",
+ "trx.foundation",
+ "tokensale.adhive.net",
+ "adhive.net",
+ "decentral.market",
+ "cryptoexploite.com",
+ "blockclain.net",
+ "xn--blckchin-5za9o.info",
+ "xn--blkhain-m0a4pb.info",
+ "xn--blocchal-gmb8m.info",
+ "xn--blocchaln-orb.info",
+ "xn--blocchan-gmb7c.info",
+ "xn--blockaden-lsen-5pb.com",
+ "xn--blockchai-3vb.info",
+ "xn--blockchai-jvb.info",
+ "xn--blockchal-3vb.info",
+ "xn--blockcham-ipb.info",
+ "xn--blockchan-2pb.com",
+ "xn--blockchan-75a.com",
+ "xn--blockchan-7sb.info",
+ "xn--blockchan-d5a.net",
+ "xn--blockchan-dob.info",
+ "xn--blockchan-ipb.com",
+ "xn--blockchan-ipb.info",
+ "xn--blockchan-nk7d.com",
+ "xn--blockchan-xub.info",
+ "xn--blockchann-4ub.com",
+ "xn--blockchi-n7a50e.info",
+ "xn--blockchi-o8a54d.info",
+ "xn--blockchi-p99co8a.com",
+ "xn--blockchim-hdb.info",
+ "xn--blockchin-1xb.info",
+ "xn--blockchin-61a.info",
+ "xn--blockchin-61a.net",
+ "xn--blockchin-6ib.info",
+ "xn--blockchin-ccb.info",
+ "xn--blockchin-h4a.com",
+ "xn--blockchin-h4a.info",
+ "xn--blockchin-hdb.info",
+ "xn--blockchin-hhb.info",
+ "xn--blockchin-mib.net",
+ "xn--blockchin-wcb.com",
+ "xn--blockchn-fza4j.com",
+ "xn--blockchn-fza4j.info",
+ "xn--blockchn-n7a43b.info",
+ "xn--blockchn-p0a.info",
+ "xn--blockchn-tx0d4p.com",
+ "xn--blockclai-3vb.info",
+ "xn--blockclin-hdb.com",
+ "xn--blockclin-hdb.info",
+ "xn--blockclin-hdb.org",
+ "xn--blockflte-kirchrode-w6b.de",
+ "xn--blockfltenquartett-windspiel-81c.de",
+ "xn--blockhai-obb78c.info",
+ "xn--blockhain-4eb.com",
+ "xn--blockhain-pfb.com",
+ "xn--blockhain-pfb.info",
+ "xn--blockhain-zdb.info",
+ "xn--blockhan-obb65a.info",
+ "xn--blockhas-d6a.com",
+ "xn--blockwallt-j7a.com",
+ "xn--blokchai-fqb.info",
+ "xn--blokchain-nfb.info",
+ "xn--blokhain-28ab.info",
+ "xn--bockclnain-eyb.info",
+ "xn--mymoeo-zt7bzf.com",
+ "xn--mymoer-nqc1368c.com",
+ "xn--mymoero-c13c.com",
+ "xn--mymoero-s13c.com",
+ "xn--mymoneo-f63c.com",
+ "xn--mymoneo-v63c.com",
+ "xn--mymoneo-y53c.com",
+ "xn--mymoner-j0a.com",
+ "xn--mymoner-j5b.com",
+ "xn--mymoner-r0a.com",
+ "xn--mymoner-z0a.com",
+ "xn--mymoner-z2c.com",
+ "xn--mymonro-fya.com",
+ "xn--mymonro-x8a.com",
+ "xn--myetheallet-l58emu.com",
+ "xn--myetheraet-9k2ea77h.com",
+ "xn--myetheralet-ms8e21b.com",
+ "xn--myetheralle-7b9exm.com",
+ "xn--myetherallet-5s5f.com",
+ "xn--myetherallet-fs5f.com",
+ "xn--myetherewalle-1t1g.com",
+ "xn--myetherllet-pl9e6k.com",
+ "xn--myethervvalle-8vc.com",
+ "xn--myetherwaet-61ea.com",
+ "xn--myetherwaet-8eda.com",
+ "xn--myetherwaet-ns8ea.com",
+ "xn--myetherwale-ns8e8x.com",
+ "xn--myetherwalet-0fb.com",
+ "xn--myetherwalet-0z4f.com",
+ "xn--myetherwalet-814f.com",
+ "xn--myetherwalet-d9b.com",
+ "xn--myetherwalet-h14f.com",
+ "xn--myetherwalle-9me.com",
+ "xn--myetherwalle-ek5f.com",
+ "xn--myetherwalle-fqc.com",
+ "xn--myetherwalle-opc.com",
+ "xn--myetherwalle-q05f.com",
+ "xn--myetherwllet-wob.com",
+ "xn--myetherwllt-r7a0i.com",
+ "xn--myethewaliet-9d5f.com",
+ "xn--myethewalle-3ic0947g.com",
+ "xn--myethewallet-0e5f.com",
+ "xn--myethewallet-1kc.com",
+ "xn--myethewallet-bkc.com",
+ "xn--myethewallet-vof.com",
+ "xn--myethewalliet-nm1g.com",
+ "xn--myethewallt-kbb3019g.com",
+ "xn--myethewallt-w48ew7b.com",
+ "xn--myethrwalet-6qb6408g.com",
+ "xn--myethrwalet-ms8e83d.com",
+ "xn--myethrwallet-1db.com",
+ "xn--myethrwallt-29af.com",
+ "xn--myethrwallt-29as.com",
+ "xn--myethrwllet-q7a31e.com",
+ "xn--myethrwllet-r8a3c.com",
+ "fintrux.eu",
+ "refereum-ico.eu",
+ "arcblock-ico.org",
+ "xn--fuson-1sa.org",
+ "refereum-token.com",
+ "fintrux.co",
+ "ico-ton.org",
+ "xn--mytherwallt-cbbv.com",
+ "xmoneta.co",
+ "data-wallet.co",
+ "tokensale.data-wallet.co",
+ "xn--myeerhwallot-ooc.com",
+ "xn--myeterwalet-cm8epi.com",
+ "xn--myeterwalle-cm8ev6a.com",
+ "rnyetherumwallet.com",
+ "republic-protocol.net",
+ "nyeihitervvallatt.com",
+ "arcblock.eu",
+ "republicprotocol.eu",
+ "tokensale-fusion.com",
+ "myetherwalletjoin.com",
+ "medicalchian.com",
+ "myeahteirwaliet.com",
+ "myenhtersvvailct.com",
+ "trinity-token.com",
+ "xn--eo-yzs.com",
+ "zilliqa.in",
+ "sparc.pro",
+ "myetherwallet.import-tokens.com",
+ "token-gram.org",
+ "xn--shapshift-e4a.com",
+ "xn--shapshift-y4a.com",
+ "xn--shpeshift-c2a.com",
+ "xn--shpeshift-r1a.com",
+ "xn--shapshift-o4a.com",
+ "xn--shpeshift-w2a.com",
+ "xn--shapeshft-w5a.com",
+ "tokensale-fusion.org",
+ "fusion-ico.com",
+ "beetolen.com",
+ "tokencrowdsale.online",
+ "fusion.tokencrowdsale.online",
+ "beetokem.com",
+ "block.chaiins.in",
+ "origintrail.in",
+ "bit-z.ru",
+ "xn--myetherallet-nu5f.com",
+ "xn--mytherwalet-3qb08c.com",
+ "xn--myeterwllet-cm8et1d.com",
+ "xn--mytherwllet-q7a01e.com",
+ "xn--biance-xt7b.com",
+ "xn--bnance-wic.com",
+ "xn--biance-jeb.com",
+ "xn--bttrx-9za8334c.com",
+ "wwwkodakcoin.com",
+ "myetherwallet.uk.com",
+ "kodakone.cc",
+ "nyeihitervvallet.com",
+ "xn--myeterwalet-cm8eoi.com",
+ "nucleus.foundation",
+ "beetoken-ico.com",
+ "data-token.com",
+ "tron-labs.com",
+ "ocoin.tech",
+ "aionfoundation.com",
+ "ico-telegram.org",
+ "nyeihitervvallat.com",
+ "telegramcoin.us",
+ "daddi.cloud",
+ "daditoken.com",
+ "blockarray.org",
+ "dadi-cloud.net",
+ "wanchainfunding.org",
+ "ico-telegram.io",
+ "iconfoundation.site",
+ "iost.co",
+ "beetoken-ico.eu",
+ "cindicator.network",
+ "wanchainetwork.org",
+ "wamchain.org",
+ "wanchainltd.org",
+ "wanchainalliance.org",
+ "nucleus-vision.net",
+ "ledgerwallet.by",
+ "nucleuss.vision",
+ "myenhterswailct.com",
+ "cobin-hood.com",
+ "wanchainfoundation.org",
+ "xn--polniex-ex4c.com",
+ "xn--polniex-s1a.com",
+ "xn--polonex-ieb.com",
+ "xn--polonex-sza.com",
+ "xn--polonex-zw4c.com",
+ "xn--polonix-ws4c.com",
+ "xn--polonix-y8a.com",
+ "xn--pooniex-ojb.com",
+ "gramico.info",
+ "dimnsions.network",
+ "www-gemini.com",
+ "login-kucoin.net",
+ "venchain.foundation",
+ "grampreico.com",
+ "tgram.cc",
+ "ton-gramico.com",
+ "wwwpaywithink.com",
+ "coniomi.com",
+ "paywithnk.com",
+ "paywithlnk.com",
+ "iluminatto.com.br",
+ "pundix.eu",
+ "xn--bttrx-esay.com",
+ "xn--bttrex-w8a.com",
+ "xn--bnance-bwa.com",
+ "xn--shpeshift-11a.com",
+ "xn--shapeshif-ts6d.com",
+ "xn--shapshift-yf7d.com",
+ "wwwbluzelle.com",
+ "bluzelie.com",
+ "nucleus-vision.org",
+ "omisegonetwork.site",
+ "etlherzero.com",
+ "etlherdelta.com",
+ "xn--condesk-0ya.com",
+ "xn--condesk-sfb.com",
+ "xn--coindsk-vs4c.com",
+ "iexecplatform.com",
+ "tongramico.com",
+ "nucleus-vision.eu",
+ "intchain.network",
+ "wanchain.cloud",
+ "bluzelle-ico.com",
+ "ethzero-wallet.com",
+ "xn--metherwalle-jb9et7d.com",
+ "xn--coinesk-jo3c.com",
+ "venchainfoundation.com",
+ "myenhtersvvailot.com",
+ "ether-zero.net",
+ "ins.foundation",
+ "nastoken.org",
+ "telcointoken.com",
+ "ether0.org",
+ "eterzero.org",
+ "bluzelle-ico.eu",
+ "bleuzelle.com",
+ "appcoinstoken.org",
+ "xn--quanstamp-8s6d.com",
+ "myehntersvvailct.com",
+ "myeherwalllet.com",
+ "ico-bluzelle.com",
+ "bluzelle.im",
+ "bluzelle.one",
+ "bluzele.sale",
+ "bluzele.co",
+ "sether.ws",
+ "xn--myetherwalet-6gf.com",
+ "xn--rnyethewaliet-om1g.com",
+ "rnyethervailet.com",
+ "mvetherwaliet.com",
+ "rnyetherwailet.com",
+ "myethervaliet.com",
+ "rnyethervaliet.com",
+ "mvetherwalilet.com",
+ "xn--myethewalie-3ic0947g.com",
+ "xn--mthrwallet-z6ac3y.com",
+ "xn--myeherwalie-vici.com",
+ "xn--myethervvalie-8vc.com",
+ "xn--mythrwallt-06acf.com",
+ "xn--mtherwallet-y9a6y.com",
+ "myetherwallet.applytoken.tk",
+ "ethereum-zero.com",
+ "quanstamptoken.tk",
+ "bluzelle.network",
+ "ether-wallet.org",
+ "tron-wallet.info",
+ "appcoinsproject.com",
+ "vechain.foundation",
+ "tronlab.site",
+ "tronlabs.network",
+ "bluzelle.cc",
+ "ethblender.com",
+ "ethpaperwallet.net",
+ "waltontoken.org",
+ "icoselfkey.org",
+ "etherzeroclaim.com",
+ "etherzero.promo",
+ "bluzelle.pro",
+ "token-selfkey.org",
+ "xn--etherdlta-0f7d.com",
+ "sether.in",
+ "xn--ttrex-ysa9423c.com",
+ "bluzelle.eu",
+ "bluzelle.site",
+ "gifto.tech",
+ "xn--os-g7s.com",
+ "selfkey.co",
+ "xn--myeherwalet-ns8exy.com",
+ "xn--coinelegraph-wk5f.com",
+ "dai-stablecoin.com",
+ "eos-token.org",
+ "venchain.org",
+ "gatcoins.io",
+ "deepbrainchain.co",
+ "myetherwalililet.info",
+ "myehvterwallet.com",
+ "myehterumswallet.com",
+ "nucleusico.com",
+ "tronlab.tech",
+ "0x-project.com",
+ "gift-token-events.mywebcommunity.org",
+ "funfairtoken.org",
+ "breadtokenapp.com",
+ "cloudpetstore.com",
+ "myethwalilet.com",
+ "selfkeys.org",
+ "wallet-ethereum.com",
+ "xn--methrwallt-26ar0z.com",
+ "xn--mytherwllet-r8a0c.com",
+ "bluzelle.promo",
+ "tokensale.bluzelle.promo",
+ "cedarlake.org",
+ "marketingleads4u.com",
+ "cashaa.co",
+ "xn--inance-hrb.com",
+ "wanchain.tech",
+ "zenprolocol.com",
+ "ethscan.io",
+ "etherscan.in",
+ "props-project.com",
+ "zilliaq.com",
+ "reqestnetwork.com",
+ "etherdelta.pw",
+ "ethereum-giveaway.org",
+ "mysimpletoken.org",
+ "binancc.com",
+ "blnance.org",
+ "elherdelta.io",
+ "xn--hapeshit-ez9c2y.com",
+ "tenxwallet.co",
+ "singularitynet.info",
+ "mytlherwaliet.info",
+ "iconmainnet.ml",
+ "tokenselfkey.org",
+ "xn--myetewallet-cm8e5y.com",
+ "envione.org",
+ "myetherwalletet.com",
+ "claimbcd.com",
+ "ripiocreditnetwork.in",
+ "xn--yeterwallet-ml8euo.com",
+ "ethclassicwallet.info",
+ "myltherwallet.ru.com",
+ "etherdella.com",
+ "xn--yeterwallet-bm8ewn.com",
+ "singularty.net",
+ "cloudkitties.co",
+ "iconfoundation.io",
+ "kittystat.com",
+ "gatscoin.io",
+ "singularitynet.in",
+ "sale.canay.io",
+ "canay.io",
+ "wabicoin.co",
+ "envion.top",
+ "sirinslabs.com",
+ "tronlab.co",
+ "paxful.com.ng",
+ "changellyli.com",
+ "ethereum-code.com",
+ "xn--plonex-6va6c.com",
+ "envion.co",
+ "envion.cc",
+ "envion.site",
+ "ethereumchain.info",
+ "xn--envon-1sa.org",
+ "xn--btstamp-rfb.net",
+ "envlon.org",
+ "envion-ico.org",
+ "spectivvr.org",
+ "sirinlbs.com",
+ "ethereumdoubler.life",
+ "xn--myetherwllet-fnb.com",
+ "sirin-labs.com",
+ "sirin-labs.org",
+ "envion.one",
+ "envion.live",
+ "propsproject.org",
+ "propsprojects.com",
+ "decentralland.org",
+ "xn--metherwalet-ns8ep4b.com",
+ "redpulsetoken.co",
+ "propsproject.tech",
+ "xn--myeterwalet-nl8emj.com",
+ "powrerledger.com",
+ "cryptokitties.com",
+ "sirinlabs.pro",
+ "sirinlabs.co",
+ "sirnlabs.com",
+ "superbitcoin-blockchain.info",
+ "hellobloom.me",
+ "mobus.network",
+ "powrrledger.com",
+ "xn--myeherwalet-ms8eyy.com",
+ "qlink-ico.com",
+ "gatcoin.in",
+ "tokensale.gamefllp.com",
+ "gamefllp.com",
+ "xn--myeherwalle-vici.com",
+ "xn--myetherwalet-39b.com",
+ "xn--polonex-ffb.com",
+ "xn--birex-leba.com",
+ "raiden-network.org",
+ "sirintabs.com",
+ "xn--metherwallt-79a30a.com",
+ "xn--myethrwllet-2kb3p.com",
+ "myethlerwallet.eu",
+ "xn--btrex-b4a.com",
+ "powerrledger.com",
+ "xn--cointeegraph-wz4f.com",
+ "myerherwalet.com",
+ "qauntstanp.com",
+ "myetherermwallet.com",
+ "xn--myethewalet-ns8eqq.com",
+ "xn--nvion-hza.org",
+ "nnyetherwallelt.ru.com",
+ "ico-wacoin.com",
+ "xn--myeterwalet-nl8enj.com",
+ "bitcoinsilver.io",
+ "t0zero.com",
+ "tokensale.gizer.in",
+ "gizer.in",
+ "wabitoken.com",
+ "gladius.ws",
+ "xn--metherwallt-8bb4w.com",
+ "quanttstamp.com",
+ "gladius.im",
+ "ethereumstorage.net",
+ "powerledgerr.com",
+ "xn--myeherwallet-4j5f.com",
+ "quamtstamp.com",
+ "quntstamp.com",
+ "xn--changely-j59c.com",
+ "shapeshlft.com",
+ "coinbasenews.co.uk",
+ "xn--metherwallet-hmb.com",
+ "envoin.org",
+ "powerledger.com",
+ "bitstannp.net",
+ "xn--myetherallet-4k5fwn.com",
+ "xn--coinbas-pya.com",
+ "requestt.network",
+ "oracls.network",
+ "sirinlabs.website",
+ "powrledger.io",
+ "slackconfirm.com",
+ "shape-shift.io",
+ "oracles-network.org",
+ "xn--myeherwalle-zb9eia.com",
+ "blockstack.one",
+ "urtust.io",
+ "bittrex.one",
+ "t0-ico.com",
+ "xn--cinbase-90a.com",
+ "xn--metherwalet-ns8ez1g.com",
+ "tzero-ico.com",
+ "tzero.su",
+ "tzero.website",
+ "blockstack.network",
+ "ico-tzero.com",
+ "spectre.site",
+ "tzero.pw",
+ "spectre-ai.net",
+ "xn--waxtokn-y8a.com",
+ "dmarket.pro",
+ "bittrex.com11648724328774.cf",
+ "bittrex.com1987465798.ga",
+ "autcus.org",
+ "t-zero.org",
+ "xn--zero-zxb.com",
+ "myetherwalletfork.com",
+ "blokclbain.info",
+ "datum.sale",
+ "spectre-ai.org",
+ "powerledgr.com",
+ "simpletoken.live",
+ "sale.simpletoken.live",
+ "qauntstamp.com",
+ "raiden-network.com",
+ "metalpayme.com",
+ "quantstamp-ico.com",
+ "myetherwailetclient.com",
+ "biockchain.biz",
+ "wallets-blockchain.com",
+ "golemairdrop.com",
+ "omisegoairdrop.net",
+ "blodkchainwallet.info",
+ "walton-chain.org",
+ "elite888-ico.com",
+ "bitflyerjp.com",
+ "chainlinksmartcontract.com",
+ "stormtoken.eu",
+ "omise-go.tech",
+ "saltending.com",
+ "stormltoken.com",
+ "xn--quanttamp-42b.com",
+ "stormtoken.co",
+ "storntoken.com",
+ "stromtoken.com",
+ "storm-token.com",
+ "stormtokens.io",
+ "ether-delta.com",
+ "ethconnect.live",
+ "ethconnect.trade",
+ "xn--bttrex-3va.net",
+ "quantstamp.com.co",
+ "wancha.in",
+ "augur-network.com",
+ "quantstamp.com.ua",
+ "myetherwalletmew.com",
+ "myetherumwalletts.com",
+ "xn--quanstamp-tmd.com",
+ "quantsstamps.com",
+ "changellyl.net",
+ "xn--myetherwalet-1fb.com",
+ "myethereumwallets.com",
+ "xn--myetherwalet-e9b.com",
+ "quantslamp.com",
+ "metelpay.com",
+ "xn--eterdelta-m75d.com",
+ "linksmartcontract.com",
+ "myetherwalletaccess.com",
+ "myetherwalletcheck.com",
+ "myetherwalletcheck.info",
+ "myetherwalletconf.com",
+ "myetherwalleteal.com",
+ "myetherwalletec.com",
+ "myetherwalletgeth.com",
+ "myetherwalletmetamask.com",
+ "myetherwalletmm.com",
+ "myetherwalletmy.com",
+ "myetherwalletnh.com",
+ "myetherwalletnod.com",
+ "myetherwalletrr.com",
+ "myetherwalletrty.com",
+ "myetherwalletsec.com",
+ "myetherwalletsecure.com",
+ "myetherwalletutc.com",
+ "myetherwalletver.info",
+ "myetherwalletview.com",
+ "myetherwalletview.info",
+ "myetherwalletvrf.com",
+ "myetherwalletmist.com",
+ "myetherwalletext.com",
+ "myetherwalletjson.com",
+ "mettalpay.com",
+ "bricklblock.io",
+ "bittrexy.com",
+ "utrust.so",
+ "myethierwallet.org",
+ "metallpay.com",
+ "kraken-wallet.com",
+ "dmarkt.io",
+ "etherdeltla.com",
+ "unlversa.io",
+ "universa.sale",
+ "mercuryprotocol.live",
+ "ripiocredlt.network",
+ "myetlherwa11et.com",
+ "dentacoin.in",
+ "rdrtg.com",
+ "myetherwallet.com.rdrgh.com",
+ "rdrgh.com",
+ "ripiocreditnetwork.co",
+ "riaden.network",
+ "hydrominer.biz",
+ "rdrblock.com",
+ "reqest.network",
+ "senstoken.com",
+ "myetherwallat.services",
+ "ripiocredit.net",
+ "xn--metherwallet-c06f.com",
+ "ico.ripiocredits.com",
+ "ripiocredits.com",
+ "raidens.network",
+ "artoken.co",
+ "myetherwalletlgn.com",
+ "etherblog.click",
+ "stormtoken.site",
+ "httpmyetherwallet.com",
+ "myetherwalletverify.com",
+ "byzantiumfork.com",
+ "myetherwallet.com.byzantiumfork.com",
+ "www-myethervvallet.com",
+ "ether24.info",
+ "block-v.io",
+ "bittrex.cash",
+ "shapishift.io",
+ "ripiocerdit.network",
+ "rnyetherwa11et.com",
+ "claimether.com",
+ "enigmatokensale.com",
+ "ethereum-org.com",
+ "mvetnerwallet.com",
+ "myctherwallet.com",
+ "myetherwaltet.com",
+ "myetherwatlet.com",
+ "privatix.me",
+ "myetherwalletcnf.com",
+ "myetherwalletver.com",
+ "privatix.top",
+ "privatix.pro",
+ "privatex.io",
+ "stormtoken.cc",
+ "raiden.online",
+ "stormstoken.com",
+ "myetereumwallet.com",
+ "stormtokens.net",
+ "myetherwalletconf.info",
+ "storrntoken.com",
+ "worldofbattles.io",
+ "ico.worldofbattles.io",
+ "privatix.live",
+ "riden.network",
+ "raidan.network",
+ "ralden.network",
+ "mymyetherwallet.com",
+ "myetherwallets.net",
+ "myetherwalletverify.info",
+ "stormxtoken.com",
+ "myethereum-wallet.com",
+ "myetherwallet-forkprep.pagedemo.co",
+ "myetnerwailet.com",
+ "www-mvetherwallet.com",
+ "etheirdelta.com",
+ "myetherwalletiu.com",
+ "myetherwaiiett.com",
+ "xn--mytherwalet-cbb87i.com",
+ "xn--myethrwallet-ivb.co",
+ "xn--myeterwallet-f1b.com",
+ "myehterwaliet.com",
+ "omegaone.co",
+ "myetherwaiietw.com",
+ "slack.com.ru",
+ "polkodot.network",
+ "request-network.net",
+ "requestnetwork.live",
+ "binancie.com",
+ "first-eth.info",
+ "myewerthwalliet.com",
+ "enjincoin.pw",
+ "xn--bitrex-k17b.com",
+ "alrswap.io",
+ "www-request.network",
+ "myetnenwallet.com",
+ "www-enigma.co",
+ "cryptoinsidenews.com",
+ "air-swap.tech",
+ "launch.airswap.cc",
+ "airswap.cc",
+ "airswaptoken.com",
+ "launch.airswap.in",
+ "airswap.in",
+ "security-steemit.com.mx",
+ "blockchalnwallet.com",
+ "blodkchainwallet.com",
+ "blodkchaln.com",
+ "myethereumwaiiet.com",
+ "myethereumwaliet.com",
+ "myethereumwalilet.com",
+ "myetherswailet.com",
+ "myetherswaliet.com",
+ "myetherswalilet.com",
+ "myetherwalilett.com",
+ "myetherwalletl.com",
+ "myetherwalletww.com",
+ "myethereunwallet.com",
+ "myethereumwallct.com",
+ "myetherwaiieti.com",
+ "myetherwaiiete.com",
+ "upfirng.com",
+ "paypie.net",
+ "paypie.tech",
+ "soam.co",
+ "myetherwaiict.com",
+ "numerai-token.com",
+ "www-bankera.com",
+ "vvanchain.org",
+ "omisegoairdrop.com",
+ "xn--enjncoin-41a.io",
+ "suncontract.su",
+ "myetherwaiietr.com",
+ "shapeshiff.io",
+ "warchain.org",
+ "myethwallett.com",
+ "myethervvaliet.com",
+ "wanchains.org",
+ "etherparty.in",
+ "enjincoin.me",
+ "etiam.io",
+ "invest.smartlands.tech",
+ "smartlands.tech",
+ "enijncoin.io",
+ "wanchain.network",
+ "nimiq.su",
+ "enjincoin.sale",
+ "tenxwallet.io",
+ "golem-network.net",
+ "myyethwallet.ml",
+ "mywetherwailiet.com",
+ "omg-omise.com",
+ "district0x.tech",
+ "centra-token.com",
+ "etherdetla.com",
+ "etnerparty.io",
+ "etherdelta.su",
+ "myetherwallett.neocities.org",
+ "myetherwallet-secure.com",
+ "myethereumwalletntw.info",
+ "real-markets.io",
+ "wallet-ethereum.org",
+ "request-network.com",
+ "shapeshifth.io",
+ "shiapeshift.in",
+ "coin.red-puise.com",
+ "ibittreix.com",
+ "coinkbase.com",
+ "cindicator.pro",
+ "myetherwallet.com.ailogin.me",
+ "eventchain.co",
+ "kinkik.in",
+ "myetherumwalletview.com",
+ "protostokenhub.com",
+ "coinrbase.com",
+ "myetherwalletlogin.com",
+ "omisegotoken.com",
+ "myethereumwalletntw.com",
+ "reall.markets",
+ "cobinhood.org",
+ "cobinhood.io",
+ "happy-coin.org",
+ "bitfinex.com.co",
+ "bitfienex.com",
+ "iconn.foundation",
+ "centra.vip",
+ "smartcontract.live",
+ "icon.community",
+ "air-token.com",
+ "centra.credit",
+ "myetherwallet-singin.com",
+ "smartcontractlink.com",
+ "shapesshift.io",
+ "0xtoken.io",
+ "augurproject.co",
+ "ethereumus.one",
+ "myetherumwalet.com",
+ "myetherwalletsignin.com",
+ "change-bank.org",
+ "charge-bank.com",
+ "myetherwalletsingin.com",
+ "myetherwalletcontract.com",
+ "change-bank.io",
+ "chainlink.tech",
+ "myetherwallet-confirm.com",
+ "tokensale.kybernet.network",
+ "kybernet.network",
+ "kyberr.network",
+ "kybernetwork.io",
+ "myetherwalletconfirm.com",
+ "kvnuke.github.io",
+ "kin.kikpro.co",
+ "myethereumwallet.co.uk",
+ "tokensale-kyber.network",
+ "kyber-network.co",
+ "tokensale.kyber-network.co",
+ "pyro0.github.io",
+ "tokensale.kyber.digital",
+ "kyber.digital",
+ "omise-go.me",
+ "my.etherwallet.com.de",
+ "bepartof.change-bank.co",
+ "change-bank.co",
+ "enigma-tokens.co",
+ "coinbase.com.eslogin.co",
+ "xn--bittrx-mva.com",
+ "ethrdelta.github.io",
+ "etherdellta.com",
+ "ico-nexus.social",
+ "red-pulse.tech",
+ "bitj0b.io",
+ "xn--bttrex-bwa.com",
+ "kin-klk.com",
+ "kin-crowdsale.com",
+ "ethedelta.com",
+ "coindash.su",
+ "myethwallet.co.uk",
+ "swarm.credit",
+ "myethereumwallet.uk",
+ "iconexu.social",
+ "wanchain.co",
+ "enigrna.co",
+ "linknetwork.co",
+ "qtum-token.com",
+ "omisego.com.co",
+ "rivetzintl.org",
+ "etherdelta.one",
+ "the-ether.pro",
+ "etherdelta.gitnub.io",
+ "kirkik.com",
+ "monetha.ltd",
+ "vlberate.io",
+ "ethereumwallet-kr.info",
+ "omise-go.org",
+ "iconexus.social",
+ "bittirrex.com",
+ "aventus.pro",
+ "atlant.solutions",
+ "aventus.group",
+ "metamak.io",
+ "omise.com.co",
+ "herotokens.io",
+ "starbase.pro",
+ "etherdelta.githulb.io",
+ "herotoken.co",
+ "kinico.net",
+ "dmarket.ltd",
+ "etherdelta.gilthub.io",
+ "golem-network.com",
+ "etnerscan.io",
+ "bllttriex.com",
+ "monetha.me",
+ "monetha.co",
+ "monetha-crowdsale.com",
+ "starbase.tech",
+ "aventus-crowdsale.com",
+ "shapeshift.pro",
+ "bllttrex.com",
+ "kickico.co",
+ "statustoken.im",
+ "bilttrex.com",
+ "tenxpay.io",
+ "bittrex.ltd",
+ "metalpay.im",
+ "aragon.im",
+ "coindash.tech",
+ "decentraland.tech",
+ "decentraland.pro",
+ "status-token.com",
+ "bittrex.cam",
+ "enigmatoken.com",
+ "unocoin.company",
+ "unocoin.fund",
+ "0xproject.io",
+ "0xtoken.com",
+ "numerai.tech",
+ "decentraiand.org",
+ "blockcrein.info",
+ "blockchealn.info",
+ "bllookchain.info",
+ "blockcbhain.info",
+ "myetherwallet.com.ethpromonodes.com",
+ "mettamask.io",
+ "tokenswap.org",
+ "netherum.com",
+ "etherexx.org",
+ "etherume.io",
+ "ethereum.plus",
+ "ehtereum.org",
+ "etereurm.org",
+ "etheream.com",
+ "ethererum.org",
+ "ethereum.io",
+ "etherdelta-glthub.com",
+ "cryptoalliance.herokuapp.com",
+ "bitspark2.com",
+ "indorsetoken.com",
+ "iconexus.tk",
+ "iconexus.ml",
+ "iconexus.ga",
+ "iconexus.cf",
+ "etherwallet.online",
+ "wallet-ethereum.net",
+ "bitsdigit.com",
+ "etherswap.org",
+ "eos.ac",
+ "uasfwallet.com",
+ "ziber.io",
+ "multiply-ethereum.info",
+ "bittrex.comze.com",
+ "karbon.vacau.com",
+ "etherdelta.gitlhub.io",
+ "etherdelta.glthub.io",
+ "digitaldevelopersfund.vacau.com",
+ "district-0x.io",
+ "coin-dash.com",
+ "coindash.ru",
+ "district0x.net",
+ "aragonproject.io",
+ "coin-wallet.info",
+ "coinswallet.info",
+ "contribute-status.im",
+ "ether-api.com",
+ "ether-wall.com",
+ "mycoinwallet.net",
+ "ethereumchamber.com",
+ "ethereumchamber.net",
+ "ethereumchest.com",
+ "ethewallet.com",
+ "myetherwallet.com.vc",
+ "myetherwallet.com.pe",
+ "myetherwallet.us.com",
+ "myetherwallet.com.u0387831.cp.regruhosting.ru",
+ "myethereumwallet.su",
+ "myetherweb.com.de",
+ "myetherieumwallet.com",
+ "myetehrwallet.com",
+ "myeterwalet.com",
+ "myetherwaiiet.com",
+ "myetherwallet.info",
+ "myetherwallet.ch",
+ "myetherwallet.om",
+ "myethervallet.com",
+ "myetherwallet.com.cm",
+ "myetherwallet.com.co",
+ "myetherwallet.com.de",
+ "myetherwallet.com.gl",
+ "myetherwallet.com.im",
+ "myetherwallet.com.ua",
+ "secure-myetherwallet.com",
+ "update-myetherwallet.com",
+ "wwwmyetherwallet.com",
+ "myeatherwallet.com",
+ "myetharwallet.com",
+ "myelherwallel.com",
+ "myetherwaillet.com",
+ "myetherwaliet.com",
+ "myetherwallel.com",
+ "myetherwallet.cam",
+ "myetherwallet.cc",
+ "myetherwallet.co",
+ "myetherwallet.cm",
+ "myetherwallet.cz",
+ "myetherwallet.org",
+ "myetherwallet.tech",
+ "myetherwallet.top",
+ "myetherwallet.net",
+ "myetherwallet.ru.com",
+ "myetherwallet.com.ru",
+ "metherwallet.com",
+ "myetrerwallet.com",
+ "myetlerwallet.com",
+ "myethterwallet.com",
+ "myethwallet.io",
+ "myethterwallet.co",
+ "myehterwallet.co",
+ "myaetherwallet.com",
+ "myetthterwallet.com",
+ "myetherwallet.one",
+ "myelterwallet.com",
+ "myetherwallet.gdn",
+ "myetherwallt.com",
+ "myeterwallet.com",
+ "myeteherwallet.com",
+ "myethearwailet.com",
+ "myetherwallelt.com",
+ "myetherwallett.com",
+ "etherwallet.org",
+ "myetherewallet.com",
+ "myeherwallet.com",
+ "myethcrwallet.com",
+ "myetherwallet.link",
+ "myetherwallets.com",
+ "myethearwaillet.com",
+ "myethearwallet.com",
+ "myetherawllet.com",
+ "myethereallet.com",
+ "myetherswallet.com",
+ "myetherwalet.com",
+ "myetherwaller.com",
+ "myetherwalliet.com",
+ "myetherwllet.com",
+ "etherwallet.io",
+ "myetherwallet.ca",
+ "myetherwallet.me",
+ "myetherwallet.ru",
+ "myetherwallet.xyz",
+ "myetherwallte.com",
+ "myethirwallet.com",
+ "myethrewallet.com",
+ "etherwallet.net",
+ "maetherwallet.com",
+ "meyetherwallet.com",
+ "my.ether-wallet.pw",
+ "myehterwallet.com",
+ "myeitherwallet.com",
+ "myelherwallet.com",
+ "myeltherwallet.com",
+ "myerherwallet.com",
+ "myethearwalet.com",
+ "myetherewalle.com",
+ "myethervvallet.com",
+ "myetherwallent.com",
+ "myetherwallet.fm",
+ "myetherwalllet.com",
+ "myetherwalltet.com",
+ "myetherwollet.com",
+ "myetlherwalet.com",
+ "myetlherwallet.com",
+ "rnyetherwallet.com",
+ "etherclassicwallet.com",
+ "omg-omise.co",
+ "omise-go.com",
+ "omise-go.net",
+ "omise-omg.com",
+ "omise-go.io",
+ "tenx-tech.com",
+ "bitclaive.com",
+ "tokensale-tenx.tech",
+ "ubiqcoin.org",
+ "metamask.com",
+ "ethtrade.io",
+ "myetcwallet.com",
+ "account-kigo.net",
+ "bitcoin-wallet.net",
+ "blocklichan.info",
+ "bloclkicihan.info",
+ "coindash.ml",
+ "eos-bonus.com",
+ "eos-io.info",
+ "ether-wallet.net",
+ "ethereum-wallet.info",
+ "ethereum-wallet.net",
+ "ethereumchest.net",
+ "reservations-kigo.net",
+ "reservations-lodgix.com",
+ "secure-liverez.com",
+ "secure-onerooftop.com",
+ "settings-liverez.com",
+ "software-liverez.com",
+ "software-lodgix.com",
+ "unhackableetherwallets.com",
+ "www-myetherwallet.com",
+ "etherwallet.co.za",
+ "etherwalletchain.com",
+ "etherwallets.net",
+ "etherwallets.nl",
+ "my-ethwallet.com",
+ "my.ether-wallet.co",
+ "myetherwallet.com.am",
+ "myetherwallet.com.ht",
+ "myetherwalletcom.com",
+ "myehterwailet.com",
+ "xn--myetherwalle-xoc.com",
+ "xn--myetherwalle-44i.com",
+ "xn--myetherwalle-xhk.com",
+ "xn--myetherwallt-cfb.com",
+ "xn--myetherwallt-6tb.com",
+ "xn--myetherwallt-xub.com",
+ "xn--myetherwallt-ovb.com",
+ "xn--myetherwallt-fwb.com",
+ "xn--myetherwallt-5wb.com",
+ "xn--myetherwallt-jzi.com",
+ "xn--myetherwallt-2ck.com",
+ "xn--myetherwallt-lok.com",
+ "xn--myetherwallt-lsl.com",
+ "xn--myetherwallt-ce6f.com",
+ "xn--myetherwalet-mcc.com",
+ "xn--myetherwalet-xhf.com",
+ "xn--myetherwalet-lcc.com",
+ "xn--myetherwaet-15ba.com",
+ "xn--myetherwalet-whf.com",
+ "xn--myetherwaet-v2ea.com",
+ "xn--myetherwllet-59a.com",
+ "xn--myetherwllet-jbb.com",
+ "xn--myetherwllet-wbb.com",
+ "xn--myetherwllet-9bb.com",
+ "xn--myetherwllet-ncb.com",
+ "xn--myetherwllet-0cb.com",
+ "xn--myetherwllet-5nb.com",
+ "xn--myetherwllet-ktd.com",
+ "xn--myetherwllet-mre.com",
+ "xn--myetherwllet-76e.com",
+ "xn--myetherwllet-o0l.com",
+ "xn--myetherwllet-c45f.com",
+ "xn--myetherallet-ejn.com",
+ "xn--myethewallet-4nf.com",
+ "xn--myethewallet-iof.com",
+ "xn--myethewallet-mpf.com",
+ "xn--myethewallet-6bk.com",
+ "xn--myethewallet-i31f.com",
+ "xn--myethrwallet-feb.com",
+ "xn--myethrwallt-fbbf.com",
+ "xn--myethrwallet-seb.com",
+ "xn--myethrwallt-rbbf.com",
+ "xn--myethrwallet-5eb.com",
+ "xn--myethrwallt-3bbf.com",
+ "xn--myethrwallet-0tb.com",
+ "xn--myethrwallt-tpbf.com",
+ "xn--myethrwallet-rub.com",
+ "xn--myethrwallt-iqbf.com",
+ "xn--myethrwallet-ivb.com",
+ "xn--myethrwallt-6qbf.com",
+ "xn--myethrwallet-8vb.com",
+ "xn--myethrwallt-vrbf.com",
+ "xn--myethrwallet-zwb.com",
+ "xn--myethrwallt-ksbf.com",
+ "xn--myethrwallet-dzi.com",
+ "xn--myethrwallt-wbif.com",
+ "xn--myethrwallet-wck.com",
+ "xn--myethrwallt-skjf.com",
+ "xn--myethrwallet-fok.com",
+ "xn--myethrwallt-fvjf.com",
+ "xn--myethrwallet-fsl.com",
+ "xn--myethrwallt-fwkf.com",
+ "xn--myethrwallet-5d6f.com",
+ "xn--myethrwallt-319ef.com",
+ "xn--myeterwallet-ufk.com",
+ "xn--myeterwallet-nrl.com",
+ "xn--myeterwallet-von.com",
+ "xn--myeterwallet-jl6c.com",
+ "xn--myeherwallet-ooc.com",
+ "xn--myeherwalle-6hci.com",
+ "xn--myeherwallet-v4i.com",
+ "xn--myeherwalle-zgii.com",
+ "xn--myeherwallet-ohk.com",
+ "xn--myeherwalle-6oji.com",
+ "xn--mytherwallet-ceb.com",
+ "xn--mythrwallet-cbbc.com",
+ "xn--mythrwallt-c7acf.com",
+ "xn--mytherwallet-peb.com",
+ "xn--mythrwallet-obbc.com",
+ "xn--mythrwallt-n7acf.com",
+ "xn--mytherwallet-2eb.com",
+ "xn--mythrwallet-0bbc.com",
+ "xn--mythrwallt-y7acf.com",
+ "xn--mytherwallet-xtb.com",
+ "xn--mythrwallet-qpbc.com",
+ "xn--mythrwallt-jlbcf.com",
+ "xn--mytherwallet-oub.com",
+ "xn--mythrwallet-fqbc.com",
+ "xn--mythrwallt-5lbcf.com",
+ "xn--mythrwallet-3qbc.com",
+ "xn--mythrwallt-smbcf.com",
+ "xn--mytherwallet-5vb.com",
+ "xn--mythrwallet-srbc.com",
+ "xn--mythrwallt-fnbcf.com",
+ "xn--mytherwallet-wwb.com",
+ "xn--mythrwallet-hsbc.com",
+ "xn--mythrwallt-1nbcf.com",
+ "xn--mytherwallet-9yi.com",
+ "xn--mythrwallet-tbic.com",
+ "xn--mythrwallt-dnhcf.com",
+ "xn--mytherwallet-tck.com",
+ "xn--mythrwallet-pkjc.com",
+ "xn--mythrwallt-lsicf.com",
+ "xn--mytherwallet-cok.com",
+ "xn--mythrwallet-cvjc.com",
+ "xn--mythrwallt-c2icf.com",
+ "xn--mytherwallet-csl.com",
+ "xn--mythrwallet-cwkc.com",
+ "xn--mythrwallt-c0jcf.com",
+ "xn--mytherwallet-2d6f.com",
+ "xn--mythrwallet-019ec.com",
+ "xn--mythrwallt-yq3ecf.com",
+ "xn--metherwallet-qlb.com",
+ "xn--metherwallet-1uf.com",
+ "xn--metherwallet-iyi.com",
+ "xn--metherwallet-zhk.com",
+ "xn--metherwallet-3ml.com",
+ "xn--mytherwallet-fvb.com",
+ "xn--myetherwallt-7db.com",
+ "xn--myetherwallt-leb.com",
+ "xn--myetherwallt-yeb.com",
+ "xn--yetherwallet-vjf.com",
+ "xn--yetherwallet-dfk.com",
+ "xn--yetherwallet-1t1f.com",
+ "xn--yetherwallet-634f.com",
+ "xn--myeherwallet-fpc.com",
+ "xn--myethewallt-crb.com",
+ "xn--metherwallet-1vc.com",
+ "xn--myeherwallt-kbb8039g.com",
+ "xn--myeherwallet-vk5f.com",
+ "xn--yethewallet-iw8ejl.com",
+ "xn--bittrx-th8b.com",
+ "xn--polniex-n0a.com",
+ "thekey.vin",
+ "thekey-vip.com",
+ "digitexftures.com",
+ "ethzero-wallet.org",
+ "zeepln.io",
+ "wepowers.network",
+ "wepower.vision"
+ ]
+}
diff --git a/test/unit/blacklist-controller-test.js b/test/unit/blacklist-controller-test.js
index a9260466f..cbf73d3e5 100644
--- a/test/unit/blacklist-controller-test.js
+++ b/test/unit/blacklist-controller-test.js
@@ -38,4 +38,4 @@ describe('blacklist controller', function () {
assert.equal(result, false)
})
})
-}) \ No newline at end of file
+})
diff --git a/test/unit/development/sample-changelog.md b/test/unit/development/sample-changelog.md
new file mode 100644
index 000000000..8fc9d2145
--- /dev/null
+++ b/test/unit/development/sample-changelog.md
@@ -0,0 +1,914 @@
+# Changelog
+
+## Current Master
+
+## 4.1.3 2018-2-28
+
+- Ensure MetaMask's inpage provider is named MetamaskInpageProvider to keep some sites from breaking.
+- Add retry transaction button back into classic ui.
+
+## 4.1.2 2018-2-28
+
+- Actually includes all the fixes mentioned in 4.1.1 (sorry)
+
+## 4.1.1 2018-2-28
+
+- Fix "Add Token" screen referencing missing token logo urls
+- Prevent user from switching network during signature request
+- Fix misleading language "Contract Published" -> "Contract Deployment"
+- Fix cancel button on "Buy Eth" screen
+- Improve new-ui onboarding flow style
+
+## 4.1.0 2018-2-27
+
+- Report failed txs to Sentry with more specific message
+- Fix internal feature flags being sometimes undefined
+- Standardized license to MIT
+
+## 4.0.0 2018-2-22
+
+- Introduce new MetaMask user interface.
+
+## 3.14.2 2018-2-15
+
+- Fix bug where log subscriptions would break when switching network.
+- Fix bug where storage values were cached across blocks.
+- Add MetaMask light client [testing container](https://github.com/MetaMask/mesh-testing)
+
+## 3.14.1 2018-2-1
+
+- Further fix scrolling for Firefox.
+
+## 3.14.0 2018-2-1
+
+- Removed unneeded data from storage
+- Add a "reset account" feature to Settings
+- Add warning for importing some kinds of files.
+- Scrollable Setting view for Firefox.
+
+## 3.13.8 2018-1-29
+
+- Fix provider for Kovan network.
+- Bump limit for EventEmitter listeners before warning.
+- Display Error when empty string is entered as a token address.
+
+## 3.13.7 2018-1-22
+
+- Add ability to bypass gas estimation loading indicator.
+- Forward failed transactions to Sentry error reporting service
+- Re-add changes from 3.13.5
+
+## 3.13.6 2017-1-18
+
+- Roll back changes to 3.13.4 to fix some issues with the new Infura REST provider.
+
+## 3.13.5 2018-1-16
+
+- Estimating gas limit for simple ether sends now faster & cheaper, by avoiding VM usage on recipients with no code.
+- Add an extra px to address for Firefox clipping.
+- Fix Firefox scrollbar.
+- Open metamask popup for transaction confirmation before gas estimation finishes and add a loading screen over transaction confirmation.
+- Fix bug that prevented eth_signTypedData from signing bytes.
+- Further improve gas price estimation.
+
+## 3.13.4 2018-1-9
+
+- Remove recipient field if application initializes a tx with an empty string, or 0x, and tx data. Throw an error with the same condition, but without tx data.
+- Improve gas price suggestion to be closer to the lowest that will be accepted.
+- Throw an error if a application tries to submit a tx whose value is a decimal, and inform that it should be in wei.
+- Fix bug that prevented updating custom token details.
+- No longer mark long-pending transactions as failed, since we now have button to retry with higher gas.
+- Fix rounding error when specifying an ether amount that has too much precision.
+- Fix bug where incorrectly inputting seed phrase would prevent any future attempts from succeeding.
+
+## 3.13.3 2017-12-14
+
+- Show tokens that are held that have no balance.
+- Reduce load on Infura by using a new block polling endpoint.
+
+## 3.13.2 2017-12-9
+
+- Reduce new block polling interval to 8000 ms, to ease server load.
+
+## 3.13.1 2017-12-7
+
+- Allow Dapps to specify a transaction nonce, allowing dapps to propose resubmit and force-cancel transactions.
+
+## 3.13.0 2017-12-7
+
+- Allow resubmitting transactions that are taking long to complete.
+
+## 3.12.1 2017-11-29
+
+- Fix bug where a user could be shown two different seed phrases.
+- Detect when multiple web3 extensions are active, and provide useful error.
+- Adds notice about seed phrase backup.
+
+## 3.12.0 2017-10-25
+
+- Add support for alternative ENS TLDs (Ethereum Name Service Top-Level Domains).
+- Lower minimum gas price to 0.1 GWEI.
+- Remove web3 injection message from production (thanks to @ChainsawBaby)
+- Add additional debugging info to our state logs, specifically OS version and browser version.
+
+## 3.11.2 2017-10-21
+
+- Fix bug where reject button would sometimes not work.
+- Fixed bug where sometimes MetaMask's connection to a page would be unreliable.
+
+## 3.11.1 2017-10-20
+
+- Fix bug where log filters were not populated correctly
+- Fix bug where web3 API was sometimes injected after the page loaded.
+- Fix bug where first account was sometimes not selected correctly after creating or restoring a vault.
+- Fix bug where imported accounts could not use new eth_signTypedData method.
+
+## 3.11.0 2017-10-11
+
+- Add support for new eth_signTypedData method per EIP 712.
+- Fix bug where some transactions would be shown as pending forever, even after successfully mined.
+- Fix bug where a transaction might be shown as pending forever if another tx with the same nonce was mined.
+- Fix link to support article on token addresses.
+
+## 3.10.9 2017-10-5
+
+- Only rebrodcast transactions for a day not a days worth of blocks
+- Remove Slack link from info page, since it is a big phishing target.
+- Stop computing balance based on pending transactions, to avoid edge case where users are unable to send transactions.
+
+## 3.10.8 2017-9-28
+
+- Fixed usage of new currency fetching API.
+
+## 3.10.7 2017-9-28
+
+- Fixed bug where sometimes the current account was not correctly set and exposed to web apps.
+- Added AUD, HKD, SGD, IDR, PHP to currency conversion list
+
+## 3.10.6 2017-9-27
+
+- Fix bug where newly created accounts were not selected.
+- Fix bug where selected account was not persisted between lockings.
+
+## 3.10.5 2017-9-27
+
+- Fix block gas limit estimation.
+
+## 3.10.4 2017-9-27
+
+- Fix bug that could mis-render token balances when very small. (Not actually included in 3.9.9)
+- Fix memory leak warning.
+- Fix bug where new event filters would not include historical events.
+
+## 3.10.3 2017-9-21
+
+- Fix bug where metamask-dapp connections are lost on rpc error
+- Fix bug that would sometimes display transactions as failed that could be successfully mined.
+
+## 3.10.2 2017-9-18
+
+rollback to 3.10.0 due to bug
+
+## 3.10.1 2017-9-18
+
+- Add ability to export private keys as a file.
+- Add ability to export seed words as a file.
+- Changed state logs to a file download than a clipboard copy.
+- Add specific error for failed recipient address checksum.
+- Fixed a long standing memory leak associated with filters installed by dapps
+- Fix link to support center.
+- Fixed tooltip icon locations to avoid overflow.
+- Warn users when a dapp proposes a high gas limit (90% of blockGasLimit or higher
+- Sort currencies by currency name (thanks to strelok1: https://github.com/strelok1).
+
+## 3.10.0 2017-9-11
+
+- Readded loose keyring label back into the account list.
+- Remove cryptonator from chrome permissions.
+- Add info on token contract addresses.
+- Add validation preventing users from inputting their own addresses as token tracking addresses.
+- Added button to reject all transactions (thanks to davidp94! https://github.com/davidp94)
+
+
+## 3.9.13 2017-9-8
+
+- Changed the way we initialize the inpage provider to fix a bug affecting some developers.
+
+## 3.9.12 2017-9-6
+
+- Fix bug that prevented Web3 1.0 compatibility
+- Make eth_sign deprecation warning less noisy
+- Add useful link to eth_sign deprecation warning.
+- Fix bug with network version serialization over synchronous RPC
+- Add MetaMask version to state logs.
+- Add the total amount of tokens when multiple tokens are added under the token list
+- Use HTTPS links for Etherscan.
+- Update Support center link to new one with HTTPS.
+- Make web3 deprecation notice more useful by linking to a descriptive article.
+
+## 3.9.11 2017-8-24
+
+- Fix nonce calculation bug that would sometimes generate very wrong nonces.
+- Give up resubmitting a transaction after 3500 blocks.
+
+## 3.9.10 2017-8-23
+
+- Improve nonce calculation, to prevent bug where people are unable to send transactions reliably.
+- Remove link to eth-tx-viz from identicons in tx history.
+
+## 3.9.9 2017-8-18
+
+- Fix bug where some transaction submission errors would show an empty screen.
+- Fix bug that could mis-render token balances when very small.
+- Fix formatting of eth_sign "Sign Message" view.
+- Add deprecation warning to eth_sign "Sign Message" view.
+
+## 3.9.8 2017-8-16
+
+- Reenable token list.
+- Remove default tokens.
+
+## 3.9.7 2017-8-15
+
+- hotfix - disable token list
+- Added a deprecation warning for web3 https://github.com/ethereum/mist/releases/tag/v0.9.0
+
+## 3.9.6 2017-8-09
+
+- Replace account screen with an account drop-down menu.
+- Replace account buttons with a new account-specific drop-down menu.
+
+## 3.9.5 2017-8-04
+
+- Improved phishing detection configuration update rate
+
+## 3.9.4 2017-8-03
+
+- Fixed bug that prevented transactions from being rejected.
+
+## 3.9.3 2017-8-03
+
+- Add support for EGO ujo token
+- Continuously update blacklist for known phishing sites in background.
+- Automatically detect suspicious URLs too similar to common phishing targets, and blacklist them.
+
+## 3.9.2 2017-7-26
+
+- Fix bugs that could sometimes result in failed transactions after switching networks.
+- Include stack traces in txMeta's to better understand the life cycle of transactions
+- Enhance blacklister functionality to include levenshtein logic. (credit to @sogoiii and @409H for their help!)
+
+## 3.9.1 2017-7-19
+
+- No longer automatically request 1 ropsten ether for the first account in a new vault.
+- Now redirects from known malicious sites faster.
+- Added a link to our new support page to the help screen.
+- Fixed bug where a new transaction would be shown over the current transaction, creating a possible timing attack against user confirmation.
+- Fixed bug in nonce tracker where an incorrect nonce would be calculated.
+- Lowered minimum gas price to 1 Gwei.
+
+## 3.9.0 2017-7-12
+
+- Now detects and blocks known phishing sites.
+
+## 3.8.6 2017-7-11
+
+- Make transaction resubmission more resilient.
+- No longer validate nonce client-side in retry loop.
+- Fix bug where insufficient balance error was sometimes shown on successful transactions.
+
+## 3.8.5 2017-7-7
+
+- Fix transaction resubmit logic to fail slightly less eagerly.
+
+## 3.8.4 2017-7-7
+
+- Improve transaction resubmit logic to fail more eagerly when a user would expect it to.
+
+## 3.8.3 2017-7-6
+
+- Re-enable default token list.
+- Add origin header to dapp-bound requests to allow providers to throttle sites.
+- Fix bug that could sometimes resubmit a transaction that had been stalled due to low balance after balance was restored.
+
+## 3.8.2 2017-7-3
+
+- No longer show network loading indication on config screen, to allow selecting custom RPCs.
+- Visually indicate that network spinner is a menu.
+- Indicate what network is being searched for when disconnected.
+
+## 3.8.1 2017-6-30
+
+- Temporarily disabled loading popular tokens by default to improve performance.
+- Remove SEND token button until a better token sending form can be built, due to some precision issues.
+- Fix precision bug in token balances.
+- Cache token symbol and precisions to reduce network load.
+- Transpile some newer JavaScript, restores compatibility with some older browsers.
+
+## 3.8.0 2017-6-28
+
+- No longer stop rebroadcasting transactions
+- Add list of popular tokens held to the account detail view.
+- Add ability to add Tokens to token list.
+- Add a warning to JSON file import.
+- Add "send" link to token list, which goes to TokenFactory.
+- Fix bug where slowly mined txs would sometimes be incorrectly marked as failed.
+- Fix bug where badge count did not reflect personal_sign pending messages.
+- Seed word confirmation wording is now scarier.
+- Fix error for invalid seed words.
+- Prevent users from submitting two duplicate transactions by disabling submit.
+- Allow Dapps to specify gas price as hex string.
+- Add button for copying state logs to clipboard.
+
+## 3.7.8 2017-6-12
+
+- Add an `ethereum:` prefix to the QR code address
+- The default network on installation is now MainNet
+- Fix currency API URL from cryptonator.
+- Update gasLimit params with every new block seen.
+- Fix ENS resolver symbol UI.
+
+## 3.7.7 2017-6-8
+
+- Fix bug where metamask would show old data after computer being asleep or disconnected from the internet.
+
+## 3.7.6 2017-6-5
+
+- Fix bug that prevented publishing contracts.
+
+## 3.7.5 2017-6-5
+
+- Prevent users from sending to the `0x0` address.
+- Provide useful errors when entering bad characters in ENS name.
+- Add ability to copy addresses from transaction confirmation view.
+
+## 3.7.4 2017-6-2
+
+- Fix bug with inflight cache that caused some block lookups to return bad values (affected OasisDex).
+- Fixed bug with gas limit calculation that would sometimes create unsubmittable gas limits.
+
+## 3.7.3 2017-6-1
+
+- Rebuilt to fix cache clearing bug.
+
+## 3.7.2 2017-5-31
+
+- Now when switching networks sites that use web3 will reload
+- Now when switching networks the extension does not restart
+- Cleanup decimal bugs in our gas inputs.
+- Fix bug where submit button was enabled for invalid gas inputs.
+- Now enforce 95% of block's gasLimit to protect users.
+- Removing provider-engine from the inpage provider. This fixes some error handling inconsistencies introduced in 3.7.0.
+- Added "inflight cache", which prevents identical requests from clogging up the network, dramatically improving ENS performance.
+- Fixed bug where filter subscriptions would sometimes fail to unsubscribe.
+- Some contracts will now display logos instead of jazzicons.
+- Some contracts will now have names displayed in the confirmation view.
+
+## 3.7.0 2017-5-23
+
+- Add Transaction Number (nonce) to transaction list.
+- Label the pending tx icon with a tooltip.
+- Fix bug where website filters would pile up and not deallocate when leaving a site.
+- Continually resubmit pending txs for a period of time to ensure successful broadcast.
+- ENS names will no longer resolve to their owner if no resolver is set. Resolvers must be explicitly set and configured.
+
+## 3.6.5 2017-5-17
+
+- Fix bug where edited gas parameters would not take effect.
+- Trim currency list.
+- Enable decimals in our gas prices.
+- Fix reset button.
+- Fix event filter bug introduced by newer versions of Geth.
+- Fix bug where decimals in gas inputs could result in strange values.
+
+## 3.6.4 2017-5-8
+
+- Fix main-net ENS resolution.
+
+## 3.6.3 2017-5-8
+
+- Fix bug that could stop newer versions of Geth from working with MetaMask.
+
+## 3.6.2 2017-5-8
+
+- Input gas price in Gwei.
+- Enforce Safe Gas Minimum recommended by EthGasStation.
+- Fix bug where block-tracker could stop polling for new blocks.
+- Reduce UI size by removing internal web3.
+- Fix bug where gas parameters would not properly update on adjustment.
+
+## 3.6.1 2017-4-30
+
+- Made fox less nosy.
+- Fix bug where error was reported in debugger console when Chrome opened a new window.
+
+## 3.6.0 2017-4-26
+
+- Add Rinkeby Test Network to our network list.
+
+## 3.5.4 2017-4-25
+
+- Fix occasional nonce tracking issue.
+- Fix bug where some events would not be emitted by web3.
+- Fix bug where an error would be thrown when composing signatures for networks with large ID values.
+
+## 3.5.3 2017-4-24
+
+- Popup new transactions in Firefox.
+- Fix transition issue from account detail screen.
+- Revise buy screen for more modularity.
+- Fixed some other small bugs.
+
+## 3.5.2 2017-3-28
+
+- Fix bug where gas estimate totals were sometimes wrong.
+- Add link to Kovan Test Faucet instructions on buy view.
+- Inject web3 into loaded iFrames.
+
+## 3.5.1 2017-3-27
+
+- Fix edge case where users were unable to enable the notice button if notices were short enough to not require a scrollbar.
+
+## 3.5.0 2017-3-27
+
+- Add better error messages for when a transaction fails on approval
+- Allow sending to ENS names in send form on Ropsten.
+- Added an address book functionality that remembers the last 15 unique addresses sent to.
+- Can now change network to custom RPC URL from lock screen.
+- Removed support for old, lightwallet based vault. Users who have not opened app in over a month will need to recover with their seed phrase. This will allow Firefox support sooner.
+- Fixed bug where spinner wouldn't disappear on incorrect password submission on seed word reveal.
+- Polish the private key UI.
+- Enforce minimum values for gas price and gas limit.
+- Fix bug where total gas was sometimes not live-updated.
+- Fix bug where editing gas value could have some abrupt behaviors (#1233)
+- Add Kovan as an option on our network list.
+- Fixed bug where transactions on other networks would disappear when submitting a transaction on another network.
+
+## 3.4.0 2017-3-8
+
+- Add two most recently used custom RPCs to network dropdown menu.
+- Add personal_sign method support.
+- Add personal_ecRecover method support.
+- Add ability to customize gas and gasPrice on the transaction approval screen.
+- Increase default gas buffer to 1.5x estimated gas value.
+
+## 3.3.0 2017-2-20
+
+- net_version has been made synchronous.
+- Test suite for migrations expanded.
+- Network now changeable from lock screen.
+- Improve test coverage of eth.sign behavior, including a code example of verifying a signature.
+
+## 3.2.2 2017-2-8
+
+- Revert eth.sign behavior to the previous one with a big warning. We will be gradually implementing the new behavior over the coming time. https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign
+
+- Improve test coverage of eth.sign behavior, including a code example of verifying a signature.
+
+## 3.2.2 2017-2-8
+
+- Revert eth.sign behavior to the previous one with a big warning. We will be gradually implementing the new behavior over the coming time. https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign
+
+## 3.2.1 2017-2-8
+
+- Revert back to old style message signing.
+- Fixed some build errors that were causing a variety of bugs.
+
+## 3.2.0 2017-2-8
+
+- Add ability to import accounts in JSON file format (used by Mist, Geth, MyEtherWallet, and more!)
+- Fix unapproved messages not being included in extension badge.
+- Fix rendering bug where the Confirm transaction view would let you approve transactions when the account has insufficient balance.
+
+## 3.1.2 2017-1-24
+
+- Fix "New Account" default keychain
+
+## 3.1.1 2017-1-20
+
+- Fix HD wallet seed export
+
+## 3.1.0 2017-1-18
+
+- Add ability to import accounts by private key.
+- Fixed bug that returned the wrong transaction hashes on private networks that had not implemented EIP 155 replay protection (like TestRPC).
+
+## 3.0.1 2017-1-17
+
+- Fixed bug that prevented eth.sign from working.
+- Fix the displaying of transactions that have been submitted to the network in Transaction History
+
+## 3.0.0 2017-1-16
+
+- Fix seed word account generation (https://medium.com/metamask/metamask-3-migration-guide-914b79533cdd#.t4i1qmmsz).
+- Fix Bug where you see an empty transaction flash by on the confirm transaction view.
+- Create visible difference in transaction history between an approved but not yet included in a block transaction and a transaction who has been confirmed.
+- Fix memory leak in RPC Cache
+- Override RPC commands eth_syncing and web3_clientVersion
+- Remove certain non-essential permissions from certain builds.
+- Add a check for when a tx is included in a block.
+- Fix bug where browser-solidity would sometimes warn of a contract creation error when there was none.
+- Minor modifications to network display.
+- Network now displays properly for pending transactions.
+- Implement replay attack protections allowed by EIP 155.
+- Fix bug where sometimes loading account data would fail by querying a future block.
+
+## 2.14.1 2016-12-20
+
+- Update Coinbase info. and increase the buy amount to $15
+- Fixed ropsten transaction links
+- Temporarily disable extension reload detection causing infinite reload bug.
+- Implemented basic checking for valid RPC URIs.
+
+## 2.14.0 2016-12-16
+
+- Removed Morden testnet provider from provider menu.
+- Add support for notices.
+- Fix broken reload detection.
+- Fix transaction forever cached-as-pending bug.
+
+## 2.13.11 2016-11-23
+
+- Add support for synchronous RPC method "eth_uninstallFilter".
+- Forgotten password prompts now send users directly to seed word restoration.
+
+## 2.13.10 2016-11-22
+
+- Improve gas calculation logic.
+- Default to Dapp-specified gas limits for transactions.
+- Ropsten networks now properly point to the faucet when attempting to buy ether.
+- Ropsten transactions now link to etherscan correctly.
+
+## 2.13.9 2016-11-21
+
+- Add support for the new, default Ropsten Test Network.
+- Fix bug that would cause MetaMask to occasionally lose its StreamProvider connection and drop requests.
+- Fix bug that would cause the Custom RPC menu item to not appear when Localhost 8545 was selected.
+- Point ropsten faucet button to actual faucet.
+- Phase out ethereumjs-util from our encryptor module.
+
+## 2.13.8 2016-11-16
+
+- Show a warning when a transaction fails during simulation.
+- Fix bug where 20% of gas estimate was not being added properly.
+- Render error messages in confirmation screen more gracefully.
+
+## 2.13.7 2016-11-8
+
+- Fix bug where gas estimate would sometimes be very high.
+- Increased our gas estimate from 100k gas to 20% of estimate.
+- Fix GitHub link on info page to point at current repository.
+
+## 2.13.6 2016-10-26
+
+- Add a check for improper Transaction data.
+- Inject up to date version of web3.js
+- Now nicknaming new accounts "Account #" instead of "Wallet #" for clarity.
+- Fix bug where custom provider selection could show duplicate items.
+- Fix bug where connecting to a local morden node would make two providers appear selected.
+- Fix bug that was sometimes preventing transactions from being sent.
+
+## 2.13.5 2016-10-18
+
+- Increase default max gas to `100000` over the RPC's `estimateGas` response.
+- Fix bug where slow-loading dapps would sometimes trigger infinite reload loops.
+
+## 2.13.4 2016-10-17
+
+- Add custom transaction fee field to send form.
+- Fix bug where web3 was being injected into XML files.
+- Fix bug where changing network would not reload current Dapps.
+
+## 2.13.3 2016-10-4
+
+- Fix bug where log queries were filtered out.
+- Decreased vault confirmation button font size to help some Linux users who could not see it.
+- Made popup a little taller because it would sometimes cut off buttons.
+- Fix bug where long account lists would get scrunched instead of scrolling.
+- Add legal information to relevant pages.
+- Rename UI elements to be more consistent with one another.
+- Updated Terms of Service and Usage.
+- Prompt users to re-agree to the Terms of Service when they are updated.
+
+## 2.13.2 2016-10-4
+
+- Fix bug where chosen FIAT exchange rate does no persist when switching networks
+- Fix additional parameters that made MetaMask sometimes receive errors from Parity.
+- Fix bug where invalid transactions would still open the MetaMask popup.
+- Removed hex prefix from private key export, to increase compatibility with Geth, MyEtherWallet, and Jaxx.
+
+## 2.13.1 2016-09-23
+
+- Fix a bug with estimating gas on Parity
+- Show loading indication when selecting ShapeShift as purchasing method.
+
+## 2.13.0 2016-09-18
+
+- Add Parity compatibility, fixing Geth dependency issues.
+- Add a link to the transaction in history that goes to https://metamask.github.io/eth-tx-viz
+too help visualize transactions and to where they are going.
+- Show "Buy Ether" button and warning on tx confirmation when sender balance is insufficient
+
+## 2.12.1 2016-09-14
+
+- Fixed bug where if you send a transaction from within MetaMask extension the
+popup notification opens up.
+- Fixed bug where some tx errors would block subsequent txs until the plugin was refreshed.
+
+## 2.12.0 2016-09-14
+
+- Add a QR button to the Account detail screen
+- Fixed bug where opening MetaMask could close a non-metamask popup.
+- Fixed memory leak that caused occasional crashes.
+
+## 2.11.1 2016-09-12
+
+- Fix bug that prevented caches from being cleared in Opera.
+
+## 2.11.0 2016-09-12
+
+- Fix bug where pending transactions from Test net (or other networks) show up In Main net.
+- Add fiat conversion values to more views.
+- On fresh install, open a new tab with the MetaMask Introduction video. Does not open on update.
+- Block negative values from transactions.
+- Fixed a memory leak.
+- MetaMask logo now renders as super lightweight SVG, improving compatibility and performance.
+- Now showing loading indication during vault unlocking, to clarify behavior for users who are experiencing slow unlocks.
+- Now only initially creates one wallet when restoring a vault, to reduce some users' confusion.
+
+## 2.10.2 2016-09-02
+
+- Fix bug where notification popup would not display.
+
+## 2.10.1 2016-09-02
+
+- Fix bug where provider menu did not allow switching to custom network from a custom network.
+- Sending a transaction from within MetaMask no longer triggers a popup.
+- The ability to build without livereload features (such as for production) can be enabled with the gulp --disableLiveReload flag.
+- Fix Ethereum JSON RPC Filters bug.
+
+## 2.10.0 2016-08-29
+
+- Changed transaction approval from notifications system to popup system.
+- Add a back button to locked screen to allow restoring vault from seed words when password is forgotten.
+- Forms now retain their values even when closing the popup and reopening it.
+- Fixed a spelling error in provider menu.
+
+## 2.9.2 2016-08-24
+
+- Fixed shortcut bug from preventing installation.
+
+## 2.9.1 2016-08-24
+
+- Added static image as fallback for when WebGL isn't supported.
+- Transaction history now has a hard limit.
+- Added info link on account screen that visits Etherscan.
+- Fixed bug where a message signing request would be lost if the vault was locked.
+- Added shortcut to open MetaMask (Ctrl+Alt+M or Cmd+Opt/Alt+M)
+- Prevent API calls in tests.
+- Fixed bug where sign message confirmation would sometimes render blank.
+
+## 2.9.0 2016-08-22
+
+- Added ShapeShift to the transaction history
+- Added affiliate key to Shapeshift requests
+- Added feature to reflect current conversion rates of current vault balance.
+- Modify balance display logic.
+
+## 2.8.0 2016-08-15
+
+- Integrate ShapeShift
+- Add a form for Coinbase to specify amount to buy
+- Fix various typos.
+- Make dapp-metamask connection more reliable
+- Remove Ethereum Classic from provider menu.
+
+## 2.7.3 2016-07-29
+
+- Fix bug where changing an account would not update in a live Dapp.
+
+## 2.7.2 2016-07-29
+
+- Add Ethereum Classic to provider menu
+- Fix bug where host store would fail to receive updates.
+
+## 2.7.1 2016-07-27
+
+- Fix bug where web3 would sometimes not be injected in time for the application.
+- Fixed bug where sometimes when opening the plugin, it would not fully open until closing and re-opening.
+- Got most functionality working within Firefox (still working on review process before it can be available).
+- Fixed menu dropdown bug introduced in Chrome 52.
+
+## 2.7.0 2016-07-21
+
+- Added a Warning screen about storing ETH
+- Add buy Button!
+- MetaMask now throws descriptive errors when apps try to use synchronous web3 methods.
+- Removed firefox-specific line in manifest.
+
+## 2.6.2 2016-07-20
+
+- Fixed bug that would prevent the plugin from reopening on the first try after receiving a new transaction while locked.
+- Fixed bug that would render 0 ETH as a non-exact amount.
+
+## 2.6.1 2016-07-13
+
+- Fix tool tips on Eth balance to show the 6 decimals
+- Fix rendering of recipient SVG in tx approval notification.
+- New vaults now generate only one wallet instead of three.
+- Bumped version of web3 provider engine.
+- Fixed bug where some lowercase or uppercase addresses were not being recognized as valid.
+- Fixed bug where gas cost was misestimated on the tx confirmation view.
+
+## 2.6.0 2016-07-11
+
+- Fix formatting of ETH balance
+- Fix formatting of account details.
+- Use web3 minified dist for faster inject times
+- Fix issue where dropdowns were not in front of icons.
+- Update transaction approval styles.
+- Align failed and successful transaction history text.
+- Fix issue where large domain names and large transaction values would misalign the transaction history.
+- Abbreviate ether balances on transaction details to maintain formatting.
+- General code cleanup.
+
+## 2.5.0 2016-06-29
+
+- Implement new account design.
+- Added a network indicator mark in dropdown menu
+- Added network name next to network indicator
+- Add copy transaction hash button to completed transaction list items.
+- Unify wording for transaction approve/reject options on notifications and the extension.
+- Fix bug where confirmation view would be shown twice.
+
+## 2.4.5 2016-06-29
+
+- Fixed bug where MetaMask interfered with PDF loading.
+- Moved switch account icon into menu bar.
+- Changed status shapes to be a yellow warning sign for failure and ellipsis for pending transactions.
+- Now enforce 20 character limit on wallet names.
+- Wallet titles are now properly truncated in transaction confirmation.
+- Fix formatting on terms & conditions page.
+- Now enforce 30 character limit on wallet names.
+- Fix out-of-place positioning of pending transaction badges on wallet list.
+- Change network status icons to reflect current design.
+
+## 2.4.4 2016-06-23
+
+- Update web3-stream-provider for batch payload bug fix
+
+## 2.4.3 2016-06-23
+
+- Remove redundant network option buttons from settings page
+- Switch out font family Transat for Montserrat
+
+## 2.4.2 2016-06-22
+
+- Change out export icon for key.
+- Unify copy to clipboard icon
+- Fixed eth.sign behavior.
+- Fix behavior of batched outbound transactions.
+
+## 2.4.0 2016-06-20
+
+- Clean up UI.
+- Remove nonfunctional QR code button.
+- Make network loading indicator clickable to select accessible network.
+- Show more characters of addresses when space permits.
+- Fixed bug when signing messages under 64 hex characters long.
+- Add disclaimer view with placeholder text for first time users.
+
+## 2.3.1 2016-06-09
+
+- Style up the info page
+- Cache identicon images to optimize for long lists of transactions.
+- Fix out of gas errors
+
+## 2.3.0 2016-06-06
+
+- Show network status in title bar
+- Added seed word recovery to config screen.
+- Clicking network status indicator now reveals a provider menu.
+
+## 2.2.0 2016-06-02
+
+- Redesigned init, vault create, vault restore and seed confirmation screens.
+- Added pending transactions to transaction list on account screen.
+- Clicking a pending transaction takes you back to the transaction approval screen.
+- Update provider-engine to fix intermittent out of gas errors.
+
+## 2.1.0 2016-05-26
+
+- Added copy address button to account list.
+- Fixed back button on confirm transaction screen.
+- Add indication of pending transactions to account list screen.
+- Fixed bug where error warning was sometimes not cleared on view transition.
+- Updated eth-lightwallet to fix a critical security issue.
+
+## 2.0.0 2016-05-23
+
+- UI Overhaul per Vlad Todirut's designs.
+- Replaced identicons with jazzicons.
+- Fixed glitchy transitions.
+- Added support for capitalization-based address checksums.
+- Send value is no longer limited by javascript number precision, and is always in ETH.
+- Added ability to generate new accounts.
+- Added ability to locally nickname accounts.
+
+## 1.8.4 2016-05-13
+
+- Point rpc servers to https endpoints.
+
+## 1.8.3 2016-05-12
+
+- Bumped web3 to 0.6.0
+- Really fixed `eth_syncing` method response.
+
+## 1.8.2 2016-05-11
+
+- Fixed bug where send view would not load correctly the first time it was visited per account.
+- Migrated all users to new scalable backend.
+- Fixed `eth_syncing` method response.
+
+## 1.8.1 2016-05-10
+
+- Initial usage of scalable blockchain backend.
+- Made official providers more easily configurable for us internally.
+
+## 1.8.0 2016-05-10
+
+- Add support for calls to `eth.sign`.
+- Moved account exporting within subview of the account detail view.
+- Added buttons to the account export process.
+- Improved visual appearance of account detail transition where button heights would change.
+- Restored back button to account detail view.
+- Show transaction list always, never collapsed.
+- Changing provider now reloads current Dapps
+- Improved appearance of transaction list in account detail view.
+
+## 1.7.0 2016-04-29
+
+- Account detail view is now the primary view.
+- The account detail view now has a "Change acct" button which shows the account list.
+- Clicking accounts in the account list now both selects that account and displays that account's detail view.
+- Selected account is now persisted between sessions, so the current account stays selected.
+- Account icons are now "identicons" (deterministically generated from the address).
+- Fixed link to Slack channel.
+- Added a context guard for "define" to avoid UMD's exporting themselves to the wrong module system, fixing interference with some websites.
+- Transaction list now only shows transactions for the current account.
+- Transaction list now only shows transactions for the current network (mainnet, testnet, testrpc).
+- Fixed transaction links to etherscan blockchain explorer.
+- Fixed some UI transitions that had weird behavior.
+
+## 1.6.0 2016-04-22
+
+- Pending transactions are now persisted to localStorage and resume even after browser is closed.
+- Completed transactions are now persisted and can be displayed via UI.
+- Added transaction list to account detail view.
+- Fix bug on config screen where current RPC address was always displayed wrong.
+- Fixed bug where entering a decimal value when sending a transaction would result in sending the wrong amount.
+- Add save button to custom RPC input field.
+- Add quick-select button for RPC on `localhost:8545`.
+- Improve config view styling.
+- Users have been migrated from old test-net RPC to a newer test-net RPC.
+
+## 1.5.1 2016-04-15
+
+- Corrected text above account list. Selected account is visible to all sites, not just the current domain.
+- Merged the UI codebase into the main plugin codebase for simpler maintenance.
+- Fix Ether display rounding error. Now rendering to four decimal points.
+- Fix some inpage synchronous methods
+- Change account rendering to show four decimals and a leading zero.
+
+## 1.5.0 2016-04-13
+
+- Added ability to send ether.
+- Fixed bugs related to using Javascript numbers, which lacked appropriate precision.
+- Replaced Etherscan main-net provider with our own production RPC.
+
+## 1.4.0 2016-04-08
+
+- Removed extra entropy text field for simplified vault creation.
+- Now supports exporting an account's private key.
+- Unified button and input styles across the app.
+- Removed some non-working placeholder UI until it works.
+- Fix popup's web3 stream provider
+- Temporarily deactivated fauceting indication because it would activate when restoring an empty account.
+
+## 1.3.2 2016-04-04
+
+ - When unlocking, first account is auto-selected.
+ - When creating a first vault on the test-net, the first account is auto-funded.
+ - Fixed some styling issues.
+
+## 1.0.1-1.3.1
+
+Many changes not logged. Hopefully beginning to log consistently now!
+
+## 1.0.0
+
+Made seed word restoring BIP44 compatible.
+
+## 0.14.0
+
+Added the ability to restore accounts from seed words.
diff --git a/test/unit/development/sample-manifest.json b/test/unit/development/sample-manifest.json
new file mode 100644
index 000000000..2b3acf1b5
--- /dev/null
+++ b/test/unit/development/sample-manifest.json
@@ -0,0 +1,71 @@
+{
+ "name": "MetaMask",
+ "short_name": "Metamask",
+ "version": "4.1.3",
+ "manifest_version": 2,
+ "author": "https://metamask.io",
+ "description": "Ethereum Browser Extension",
+ "commands": {
+ "_execute_browser_action": {
+ "suggested_key": {
+ "windows": "Alt+Shift+M",
+ "mac": "Alt+Shift+M",
+ "chromeos": "Alt+Shift+M",
+ "linux": "Alt+Shift+M"
+ }
+ }
+ },
+ "icons": {
+ "16": "images/icon-16.png",
+ "128": "images/icon-128.png"
+ },
+ "applications": {
+ "gecko": {
+ "id": "webextension@metamask.io"
+ }
+ },
+ "default_locale": "en",
+ "background": {
+ "scripts": [
+ "scripts/chromereload.js",
+ "scripts/background.js"
+ ],
+ "persistent": true
+ },
+ "browser_action": {
+ "default_icon": {
+ "19": "images/icon-19.png",
+ "38": "images/icon-38.png"
+ },
+ "default_title": "MetaMask",
+ "default_popup": "popup.html"
+ },
+ "content_scripts": [
+ {
+ "matches": [
+ "file://*/*",
+ "http://*/*",
+ "https://*/*"
+ ],
+ "js": [
+ "scripts/contentscript.js"
+ ],
+ "run_at": "document_start",
+ "all_frames": true
+ }
+ ],
+ "permissions": [
+ "storage",
+ "clipboardWrite",
+ "http://localhost:8545/",
+ "https://*.infura.io/"
+ ],
+ "web_accessible_resources": [
+ "scripts/inpage.js"
+ ],
+ "externally_connectable": {
+ "matches": [
+ "https://metamask.io/*"
+ ]
+ }
+}
diff --git a/test/unit/development/version–bump-test.js b/test/unit/development/version–bump-test.js
new file mode 100644
index 000000000..1c445c8b4
--- /dev/null
+++ b/test/unit/development/version–bump-test.js
@@ -0,0 +1,45 @@
+const assert = require('assert')
+const versionBump = require('../../../development/version-bump')
+const { promisify } = require('util')
+const fs = require('fs')
+const readFile = promisify(fs.readFile)
+const path = require('path')
+const changelogPath = path.join(__dirname, 'sample-changelog.md')
+const manifest = require('./sample-manifest.json')
+let changelog
+
+
+describe('version bumper', function () {
+
+ beforeEach(async () => {
+ // load changelog. Mock version is 4.1.3
+ const changeBuffer = await readFile(changelogPath)
+ changelog = changeBuffer.toString()
+ })
+
+ it('returns a properly bumped major version', async function () {
+ const result = await versionBump('major', changelog, manifest)
+ const expected = '5.0.0'
+ assert.equal(result.version, expected, 'major bumps correctly')
+ assert.equal(result.manifest.version, expected, 'major bumps correctly')
+ assert.ok(result.changelog.includes(expected))
+ })
+
+ it('returns a properly bumped minor version', async function () {
+ const result = await versionBump('minor', changelog, manifest)
+ const expected = '4.2.0'
+ assert.equal(result.version, expected, 'minor bumps correctly')
+ assert.equal(result.manifest.version, expected, 'minor bumps correctly')
+ assert.ok(result.changelog.includes(expected))
+ })
+
+ it('returns a properly bumped patch version', async function () {
+ const result = await versionBump('patch', changelog, manifest)
+ const expected = '4.1.4'
+ assert.equal(result.version, expected, 'patch bumps correctly')
+ assert.equal(result.manifest.version, expected, 'patch bumps correctly')
+ assert.ok(result.changelog.includes(expected))
+ })
+})
+
+
diff --git a/test/unit/edge-encryptor-test.js b/test/unit/edge-encryptor-test.js
new file mode 100644
index 000000000..d3f014d74
--- /dev/null
+++ b/test/unit/edge-encryptor-test.js
@@ -0,0 +1,101 @@
+const assert = require('assert')
+
+const EdgeEncryptor = require('../../app/scripts/edge-encryptor')
+
+var password = 'passw0rd1'
+var data = 'some random data'
+
+global.crypto = global.crypto || {
+ getRandomValues: function (array) {
+ for (let i = 0; i < array.length; i++) {
+ array[i] = Math.random() * 100
+ }
+ return array
+ }
+}
+
+describe('EdgeEncryptor', function () {
+
+ const edgeEncryptor = new EdgeEncryptor()
+ describe('encrypt', function () {
+
+ it('should encrypt the data.', function (done) {
+ edgeEncryptor.encrypt(password, data)
+ .then(function (encryptedData) {
+ assert.notEqual(data, encryptedData)
+ assert.notEqual(encryptedData.length, 0)
+ done()
+ }).catch(function (err) {
+ done(err)
+ })
+ })
+
+ it('should return proper format.', function (done) {
+ edgeEncryptor.encrypt(password, data)
+ .then(function (encryptedData) {
+ let encryptedObject = JSON.parse(encryptedData)
+ assert.ok(encryptedObject.data, 'there is no data')
+ assert.ok(encryptedObject.iv && encryptedObject.iv.length != 0, 'there is no iv')
+ assert.ok(encryptedObject.salt && encryptedObject.salt.length != 0, 'there is no salt')
+ done()
+ }).catch(function (err) {
+ done(err)
+ })
+ })
+
+ it('should not return the same twice.', function (done) {
+
+ const encryptPromises = []
+ encryptPromises.push(edgeEncryptor.encrypt(password, data))
+ encryptPromises.push(edgeEncryptor.encrypt(password, data))
+
+ Promise.all(encryptPromises).then((encryptedData) => {
+ assert.equal(encryptedData.length, 2)
+ assert.notEqual(encryptedData[0], encryptedData[1])
+ assert.notEqual(encryptedData[0].length, 0)
+ assert.notEqual(encryptedData[1].length, 0)
+ done()
+ })
+ })
+ })
+
+ describe('decrypt', function () {
+ it('should be able to decrypt the encrypted data.', function (done) {
+
+ edgeEncryptor.encrypt(password, data)
+ .then(function (encryptedData) {
+ edgeEncryptor.decrypt(password, encryptedData)
+ .then(function (decryptedData) {
+ assert.equal(decryptedData, data)
+ done()
+ })
+ .catch(function (err) {
+ done(err)
+ })
+ })
+ .catch(function (err) {
+ done(err)
+ })
+ })
+
+ it('cannot decrypt the encrypted data with wrong password.', function (done) {
+
+ edgeEncryptor.encrypt(password, data)
+ .then(function (encryptedData) {
+ edgeEncryptor.decrypt('wrong password', encryptedData)
+ .then(function (decryptedData) {
+ assert.fail('could decrypt with wrong password')
+ done()
+ })
+ .catch(function (err) {
+ assert.ok(err instanceof Error)
+ assert.equal(err.message, 'Incorrect password')
+ done()
+ })
+ })
+ .catch(function (err) {
+ done(err)
+ })
+ })
+ })
+})
diff --git a/test/unit/message-manager-test.js b/test/unit/message-manager-test.js
index 9b76241ed..5e7039841 100644
--- a/test/unit/message-manager-test.js
+++ b/test/unit/message-manager-test.js
@@ -1,11 +1,11 @@
const assert = require('assert')
-const MessageManger = require('../../app/scripts/lib/message-manager')
+const MessageManager = require('../../app/scripts/lib/message-manager')
describe('Message Manager', function () {
let messageManager
beforeEach(function () {
- messageManager = new MessageManger()
+ messageManager = new MessageManager()
})
describe('#getMsgList', function () {
diff --git a/test/unit/metamask-controller-test.js b/test/unit/metamask-controller-test.js
index 3fc7f9a98..adeca9b5f 100644
--- a/test/unit/metamask-controller-test.js
+++ b/test/unit/metamask-controller-test.js
@@ -1,129 +1,103 @@
const assert = require('assert')
const sinon = require('sinon')
const clone = require('clone')
+const nock = require('nock')
const MetaMaskController = require('../../app/scripts/metamask-controller')
+const blacklistJSON = require('../stub/blacklist')
const firstTimeState = require('../../app/scripts/first-time-state')
-const BN = require('ethereumjs-util').BN
-const GWEI_BN = new BN('1000000000')
describe('MetaMaskController', function () {
- const noop = () => {}
- const metamaskController = new MetaMaskController({
- showUnconfirmedMessage: noop,
- unlockAccountMessage: noop,
- showUnapprovedTx: noop,
- platform: {},
- encryptor: {
- encrypt: function(password, object) {
- this.object = object
- return Promise.resolve()
- },
- decrypt: function () {
- return Promise.resolve(this.object)
- }
- },
- // initial state
- initState: clone(firstTimeState),
- })
+ let metamaskController
+ const sandbox = sinon.sandbox.create()
+ const noop = () => { }
beforeEach(function () {
- // sinon allows stubbing methods that are easily verified
- this.sinon = sinon.sandbox.create()
+
+ nock('https://api.infura.io')
+ .persist()
+ .get('/v2/blacklist')
+ .reply(200, blacklistJSON)
+
+ nock('https://api.infura.io')
+ .persist()
+ .get(/.*/)
+ .reply(200)
+
+ metamaskController = new MetaMaskController({
+ showUnapprovedTx: noop,
+ encryptor: {
+ encrypt: function (password, object) {
+ this.object = object
+ return Promise.resolve()
+ },
+ decrypt: function () {
+ return Promise.resolve(this.object)
+ },
+ },
+ initState: clone(firstTimeState),
+ })
+ sandbox.spy(metamaskController.keyringController, 'createNewVaultAndKeychain')
+ sandbox.spy(metamaskController.keyringController, 'createNewVaultAndRestore')
})
afterEach(function () {
- // sinon requires cleanup otherwise it will overwrite context
- this.sinon.restore()
+ nock.cleanAll()
+ sandbox.restore()
})
- describe('Metamask Controller', function () {
- assert(metamaskController)
-
- beforeEach(function () {
- sinon.spy(metamaskController.keyringController, 'createNewVaultAndKeychain')
- sinon.spy(metamaskController.keyringController, 'createNewVaultAndRestore')
- })
-
- afterEach(function () {
- metamaskController.keyringController.createNewVaultAndKeychain.restore()
- metamaskController.keyringController.createNewVaultAndRestore.restore()
- })
-
- describe('#getGasPrice', function () {
- it('gives the 50th percentile lowest accepted gas price from recentBlocksController', async function () {
- const realRecentBlocksController = metamaskController.recentBlocksController
- metamaskController.recentBlocksController = {
- store: {
- getState: () => {
- return {
- recentBlocks: [
- { gasPrices: [ '0x3b9aca00', '0x174876e800'] },
- { gasPrices: [ '0x3b9aca00', '0x174876e800'] },
- { gasPrices: [ '0x174876e800', '0x174876e800' ]},
- { gasPrices: [ '0x174876e800', '0x174876e800' ]},
- ]
- }
- }
- }
- }
-
- const gasPrice = metamaskController.getGasPrice()
- assert.equal(gasPrice, '0x3b9aca00', 'accurately estimates 50th percentile accepted gas price')
-
- metamaskController.recentBlocksController = realRecentBlocksController
- })
-
- it('gives the 1 gwei price if no blocks have been seen.', async function () {
- const realRecentBlocksController = metamaskController.recentBlocksController
- metamaskController.recentBlocksController = {
- store: {
- getState: () => {
- return {
- recentBlocks: []
- }
+ describe('#getGasPrice', function () {
+ it('gives the 50th percentile lowest accepted gas price from recentBlocksController', async function () {
+ const realRecentBlocksController = metamaskController.recentBlocksController
+ metamaskController.recentBlocksController = {
+ store: {
+ getState: () => {
+ return {
+ recentBlocks: [
+ { gasPrices: [ '0x3b9aca00', '0x174876e800'] },
+ { gasPrices: [ '0x3b9aca00', '0x174876e800'] },
+ { gasPrices: [ '0x174876e800', '0x174876e800' ]},
+ { gasPrices: [ '0x174876e800', '0x174876e800' ]},
+ ],
}
- }
- }
-
- const gasPrice = metamaskController.getGasPrice()
- assert.equal(gasPrice, '0x' + GWEI_BN.toString(16), 'defaults to 1 gwei')
+ },
+ },
+ }
- metamaskController.recentBlocksController = realRecentBlocksController
- })
+ const gasPrice = metamaskController.getGasPrice()
+ assert.equal(gasPrice, '0x3b9aca00', 'accurately estimates 50th percentile accepted gas price')
+ metamaskController.recentBlocksController = realRecentBlocksController
})
+ })
- describe('#createNewVaultAndKeychain', function () {
- it('can only create new vault on keyringController once', async function () {
- const selectStub = sinon.stub(metamaskController, 'selectFirstIdentity')
-
+ describe('#createNewVaultAndKeychain', function () {
+ it('can only create new vault on keyringController once', async function () {
+ const selectStub = sandbox.stub(metamaskController, 'selectFirstIdentity')
- const password = 'a-fake-password'
+ const password = 'a-fake-password'
- const first = await metamaskController.createNewVaultAndKeychain(password)
- const second = await metamaskController.createNewVaultAndKeychain(password)
+ await metamaskController.createNewVaultAndKeychain(password)
+ await metamaskController.createNewVaultAndKeychain(password)
- assert(metamaskController.keyringController.createNewVaultAndKeychain.calledOnce)
+ assert(metamaskController.keyringController.createNewVaultAndKeychain.calledOnce)
- selectStub.reset()
- })
+ selectStub.reset()
})
+ })
+
+ 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)
- describe('#createNewVaultAndRestore', function () {
- it('should be able to call newVaultAndRestore despite a mistake.', async function () {
- // const selectStub = sinon.stub(metamaskController, 'selectFirstIdentity')
-
- 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'
- const first = await metamaskController.createNewVaultAndRestore(password, wrongSeed)
- .catch((e) => {
- return
- })
- const second = await metamaskController.createNewVaultAndRestore(password, rightSeed)
-
- assert(metamaskController.keyringController.createNewVaultAndRestore.calledTwice)
- })
+ assert(metamaskController.keyringController.createNewVaultAndRestore.calledTwice)
})
})
})
diff --git a/test/unit/network-contoller-test.js b/test/unit/network-contoller-test.js
index 0b3b5adeb..51ad09f87 100644
--- a/test/unit/network-contoller-test.js
+++ b/test/unit/network-contoller-test.js
@@ -1,25 +1,38 @@
const assert = require('assert')
+const nock = require('nock')
const NetworkController = require('../../app/scripts/controllers/network')
+const { createTestProviderTools } = require('../stub/provider')
+const providerResultStub = {}
+const provider = createTestProviderTools({ scaffold: providerResultStub }).provider
+
describe('# Network Controller', function () {
let networkController
+ const noop = () => {}
const networkControllerProviderInit = {
- getAccounts: () => {},
+ getAccounts: noop,
}
beforeEach(function () {
+
+ nock('https://api.infura.io')
+ .get('/*/')
+ .reply(200)
+
+ nock('https://rinkeby.infura.io')
+ .post('/metamask')
+ .reply(200)
+
networkController = new NetworkController({
- provider: {
- type: 'rinkeby',
- },
+ provider,
})
- networkController.initializeProvider(networkControllerProviderInit, dummyProviderConstructor)
+ networkController.initializeProvider(networkControllerProviderInit, provider)
})
describe('network', function () {
describe('#provider', function () {
it('provider should be updatable without reassignment', function () {
- networkController.initializeProvider(networkControllerProviderInit, dummyProviderConstructor)
+ networkController.initializeProvider(networkControllerProviderInit, provider)
const proxy = networkController._proxy
proxy.setTarget({ test: true, on: () => {} })
assert.ok(proxy.test)
@@ -64,21 +77,4 @@ describe('# Network Controller', function () {
})
})
})
-})
-
-function dummyProviderConstructor() {
- return {
- // provider
- sendAsync: noop,
- // block tracker
- _blockTracker: {},
- start: noop,
- stop: noop,
- on: noop,
- addListener: noop,
- once: noop,
- removeAllListeners: noop,
- }
-}
-
-function noop() {} \ No newline at end of file
+}) \ No newline at end of file
diff --git a/test/unit/tx-state-manager-test.js b/test/unit/tx-state-manager-test.js
index 02dc52967..220bf501f 100644
--- a/test/unit/tx-state-manager-test.js
+++ b/test/unit/tx-state-manager-test.js
@@ -5,7 +5,7 @@ const TxStateManager = require('../../app/scripts/lib/tx-state-manager')
const txStateHistoryHelper = require('../../app/scripts/lib/tx-state-history-helper')
const noop = () => true
-describe('TransactionStateManger', function () {
+describe('TransactionStateManager', function () {
let txStateManager
const currentNetworkId = 42
const otherNetworkId = 2
@@ -281,4 +281,4 @@ describe('TransactionStateManger', function () {
})
})
-}) \ No newline at end of file
+})
diff --git a/ui/app/accounts/import/index.js b/ui/app/accounts/import/index.js
index 71eb9ae23..adb52db74 100644
--- a/ui/app/accounts/import/index.js
+++ b/ui/app/accounts/import/index.js
@@ -35,6 +35,21 @@ AccountImportSubview.prototype.render = function () {
return (
h('div.new-account-import-form', [
+ h('.new-account-import-disclaimer', [
+ h('span', 'Imported accounts will not be associated with your originally created MetaMask account seedphrase. Learn more about imported accounts '),
+ h('span', {
+ style: {
+ cursor: 'pointer',
+ textDecoration: 'underline',
+ },
+ onClick: () => {
+ global.platform.openWindow({
+ url: 'https://metamask.helpscoutdocs.com/article/17-what-are-loose-accounts',
+ })
+ },
+ }, 'here'),
+ ]),
+
h('div.new-account-import-form__select-section', [
h('div.new-account-import-form__select-label', 'Select Type'),
diff --git a/ui/app/actions.js b/ui/app/actions.js
index 9606841ae..3e26f333b 100644
--- a/ui/app/actions.js
+++ b/ui/app/actions.js
@@ -860,15 +860,16 @@ function markPasswordForgotten () {
function unMarkPasswordForgotten () {
return (dispatch) => {
return background.unMarkPasswordForgotten(() => {
- dispatch(actions.forgotPassword())
+ dispatch(actions.forgotPassword(false))
forceUpdateMetamaskState(dispatch)
})
}
}
-function forgotPassword () {
+function forgotPassword (forgotPasswordState = true) {
return {
type: actions.FORGOT_PASSWORD,
+ value: forgotPasswordState,
}
}
@@ -1504,6 +1505,7 @@ function pairUpdate (coin) {
dispatch(actions.hideWarning())
shapeShiftRequest('marketinfo', {pair: `${coin.toLowerCase()}_eth`}, (mktResponse) => {
dispatch(actions.hideSubLoadingIndication())
+ if (mktResponse.error) return dispatch(actions.displayWarning(mktResponse.error))
dispatch({
type: actions.PAIR_UPDATE,
value: {
diff --git a/ui/app/add-token.js b/ui/app/add-token.js
index 230ab35fe..51c577987 100644
--- a/ui/app/add-token.js
+++ b/ui/app/add-token.js
@@ -52,13 +52,16 @@ function AddTokenScreen () {
isShowingConfirmation: false,
customAddress: '',
customSymbol: '',
- customDecimals: 0,
+ customDecimals: '',
searchQuery: '',
isCollapsed: true,
selectedTokens: {},
errors: {},
+ autoFilled: false,
}
this.tokenAddressDidChange = this.tokenAddressDidChange.bind(this)
+ this.tokenSymbolDidChange = this.tokenSymbolDidChange.bind(this)
+ this.tokenDecimalsDidChange = this.tokenDecimalsDidChange.bind(this)
this.onNext = this.onNext.bind(this)
Component.call(this)
}
@@ -103,6 +106,16 @@ AddTokenScreen.prototype.tokenAddressDidChange = function (e) {
}
}
+AddTokenScreen.prototype.tokenSymbolDidChange = function (e) {
+ const customSymbol = e.target.value.trim()
+ this.setState({ customSymbol })
+}
+
+AddTokenScreen.prototype.tokenDecimalsDidChange = function (e) {
+ const customDecimals = e.target.value.trim()
+ this.setState({ customDecimals })
+}
+
AddTokenScreen.prototype.checkExistingAddresses = function (address) {
if (!address) return false
const tokensList = this.props.tokens
@@ -125,7 +138,7 @@ AddTokenScreen.prototype.validate = function () {
errors.customAddress = 'Address is invalid. '
}
- const validDecimals = customDecimals >= 0 && customDecimals < 36
+ const validDecimals = customDecimals !== null && customDecimals >= 0 && customDecimals < 36
if (!validDecimals) {
errors.customDecimals = 'Decimals must be at least 0, and not over 36.'
}
@@ -166,12 +179,13 @@ AddTokenScreen.prototype.attemptToAutoFillTokenParams = async function (address)
this.setState({
customSymbol: symbol,
customDecimals: decimals.toString(),
+ autoFilled: true,
})
}
}
AddTokenScreen.prototype.renderCustomForm = function () {
- const { customAddress, customSymbol, customDecimals, errors } = this.state
+ const { autoFilled, customAddress, customSymbol, customDecimals, errors } = this.state
return !this.state.isCollapsed && (
h('div.add-token__add-custom-form', [
@@ -196,8 +210,9 @@ AddTokenScreen.prototype.renderCustomForm = function () {
h('div.add-token__add-custom-label', 'Token Symbol'),
h('input.add-token__add-custom-input', {
type: 'text',
+ onChange: this.tokenSymbolDidChange,
value: customSymbol,
- disabled: true,
+ disabled: autoFilled,
}),
h('div.add-token__add-custom-error-message', errors.customSymbol),
]),
@@ -209,8 +224,9 @@ AddTokenScreen.prototype.renderCustomForm = function () {
h('div.add-token__add-custom-label', 'Decimals of Precision'),
h('input.add-token__add-custom-input', {
type: 'number',
+ onChange: this.tokenDecimalsDidChange,
value: customDecimals,
- disabled: true,
+ disabled: autoFilled,
}),
h('div.add-token__add-custom-error-message', errors.customDecimals),
]),
diff --git a/ui/app/app.js b/ui/app/app.js
index 5d37b9bdf..4e6da24c3 100644
--- a/ui/app/app.js
+++ b/ui/app/app.js
@@ -89,6 +89,8 @@ function mapStateToProps (state) {
currentCurrency: state.metamask.currentCurrency,
isMouseUser: state.appState.isMouseUser,
betaUI: state.metamask.featureFlags.betaUI,
+ isRevealingSeedWords: state.metamask.isRevealingSeedWords,
+ Qr: state.appState.Qr,
// state needed to get account dropdown temporarily rendering from app bar
identities,
@@ -286,10 +288,10 @@ App.prototype.renderAppBar = function () {
}),
// metamask name
- h('h1', 'MetaMask'),
-
- h('div.beta-label', 'BETA'),
-
+ h('.flex-row', [
+ h('h1', 'MetaMask'),
+ h('div.beta-label', 'BETA'),
+ ]),
]),
h('div.header__right-actions', [
@@ -362,9 +364,17 @@ App.prototype.renderBackButton = function (style, justArrow = false) {
App.prototype.renderPrimary = function () {
log.debug('rendering primary')
var props = this.props
- const {isMascara, isOnboarding, betaUI} = props
+ const {
+ isMascara,
+ isOnboarding,
+ betaUI,
+ isRevealingSeedWords,
+ Qr,
+ } = props
+ const isMascaraOnboarding = isMascara && isOnboarding
+ const isBetaUIOnboarding = betaUI && isOnboarding && !props.isPopup && !isRevealingSeedWords
- if ((isMascara || betaUI) && isOnboarding && !props.isPopup) {
+ if (isMascaraOnboarding || isBetaUIOnboarding) {
return h(MascaraFirstTime)
}
@@ -388,7 +398,7 @@ App.prototype.renderPrimary = function () {
if (props.isInitialized && props.forgottenPassword) {
log.debug('rendering restore vault screen')
return h(HDRestoreVaultScreen, {key: 'HDRestoreVaultScreen'})
- } else if (!props.isInitialized && !props.isUnlocked) {
+ } else if (!props.isInitialized && !props.isUnlocked && !isRevealingSeedWords) {
log.debug('rendering menu screen')
return props.isPopup
? h(OldUIInitializeMenuScreen, {key: 'menuScreenInit'})
@@ -500,7 +510,7 @@ App.prototype.renderPrimary = function () {
width: '285px',
},
}, [
- h(QrView, {key: 'qr'}),
+ h(QrView, {key: 'qr', Qr}),
]),
])
diff --git a/ui/app/components/dropdowns/components/account-dropdowns.js b/ui/app/components/dropdowns/components/account-dropdowns.js
index fa9ffc632..40918cc53 100644
--- a/ui/app/components/dropdowns/components/account-dropdowns.js
+++ b/ui/app/components/dropdowns/components/account-dropdowns.js
@@ -134,22 +134,6 @@ class AccountDropdowns extends Component {
]),
]),
-// =======
-// },
-// ),
-// this.indicateIfLoose(keyring),
-// h('span', {
-// style: {
-// marginLeft: '20px',
-// fontSize: '24px',
-// maxWidth: '145px',
-// whiteSpace: 'nowrap',
-// overflow: 'hidden',
-// textOverflow: 'ellipsis',
-// },
-// }, identity.name || ''),
-// h('span', { style: { marginLeft: '20px', fontSize: '24px' } }, isSelected ? h('.check', '✓') : null),
-// >>>>>>> master:ui/app/components/account-dropdowns.js
]
)
})
@@ -159,7 +143,7 @@ class AccountDropdowns extends Component {
try { // Sometimes keyrings aren't loaded yet:
const type = keyring.type
const isLoose = type !== 'HD Key Tree'
- return isLoose ? h('.keyring-label', 'LOOSE') : null
+ return isLoose ? h('.keyring-label', 'IMPORTED') : null
} catch (e) { return }
}
diff --git a/ui/app/components/dropdowns/network-dropdown.js b/ui/app/components/dropdowns/network-dropdown.js
index 9be5cc5d1..ff10c0758 100644
--- a/ui/app/components/dropdowns/network-dropdown.js
+++ b/ui/app/components/dropdowns/network-dropdown.js
@@ -114,7 +114,7 @@ NetworkDropdown.prototype.render = function () {
[
providerType === 'mainnet' ? h('i.fa.fa-check') : h('.network-check__transparent', '✓'),
h(NetworkDropdownIcon, {
- backgroundColor: '#038789', // $blue-lagoon
+ backgroundColor: '#29B6AF', // $java
isSelected: providerType === 'mainnet',
}),
h('span.network-name-item', {
@@ -136,7 +136,7 @@ NetworkDropdown.prototype.render = function () {
[
providerType === 'ropsten' ? h('i.fa.fa-check') : h('.network-check__transparent', '✓'),
h(NetworkDropdownIcon, {
- backgroundColor: '#e91550', // $crimson
+ backgroundColor: '#ff4a8d', // $wild-strawberry
isSelected: providerType === 'ropsten',
}),
h('span.network-name-item', {
@@ -158,7 +158,7 @@ NetworkDropdown.prototype.render = function () {
[
providerType === 'kovan' ? h('i.fa.fa-check') : h('.network-check__transparent', '✓'),
h(NetworkDropdownIcon, {
- backgroundColor: '#690496', // $purple
+ backgroundColor: '#7057ff', // $cornflower-blue
isSelected: providerType === 'kovan',
}),
h('span.network-name-item', {
@@ -180,7 +180,7 @@ NetworkDropdown.prototype.render = function () {
[
providerType === 'rinkeby' ? h('i.fa.fa-check') : h('.network-check__transparent', '✓'),
h(NetworkDropdownIcon, {
- backgroundColor: '#ebb33f', // $tulip-tree
+ backgroundColor: '#f6c343', // $saffron
isSelected: providerType === 'rinkeby',
}),
h('span.network-name-item', {
diff --git a/ui/app/components/modals/deposit-ether-modal.js b/ui/app/components/modals/deposit-ether-modal.js
index 532d66653..7547dbcf5 100644
--- a/ui/app/components/modals/deposit-ether-modal.js
+++ b/ui/app/components/modals/deposit-ether-modal.js
@@ -33,6 +33,9 @@ function mapDispatchToProps (dispatch) {
hideModal: () => {
dispatch(actions.hideModal())
},
+ hideWarning: () => {
+ dispatch(actions.hideWarning())
+ },
showAccountDetailModal: () => {
dispatch(actions.showModal({ name: 'ACCOUNT_DETAILS' }))
},
@@ -119,6 +122,7 @@ DepositEtherModal.prototype.render = function () {
h('div.deposit-ether-modal__header__close', {
onClick: () => {
this.setState({ buyingWithShapeshift: false })
+ this.props.hideWarning()
this.props.hideModal()
},
}),
@@ -179,6 +183,7 @@ DepositEtherModal.prototype.render = function () {
}
DepositEtherModal.prototype.goToAccountDetailsModal = function () {
+ this.props.hideWarning()
this.props.hideModal()
this.props.showAccountDetailModal()
}
diff --git a/ui/app/components/modals/modal.js b/ui/app/components/modals/modal.js
index 97fe38292..8e9e58985 100644
--- a/ui/app/components/modals/modal.js
+++ b/ui/app/components/modals/modal.js
@@ -79,6 +79,7 @@ const MODALS = {
contents: [
h(DepositEtherModal, {}, []),
],
+ onHide: (props) => props.hideWarning(),
mobileModalStyle: {
width: '100%',
height: '100%',
@@ -286,6 +287,10 @@ function mapDispatchToProps (dispatch) {
hideModal: () => {
dispatch(actions.hideModal())
},
+ hideWarning: () => {
+ dispatch(actions.hideWarning())
+ },
+
}
}
@@ -308,7 +313,12 @@ Modal.prototype.render = function () {
{
className: 'modal',
keyboard: false,
- onHide: () => { this.onHide() },
+ onHide: () => {
+ if (modal.onHide) {
+ modal.onHide(this.props)
+ }
+ this.onHide()
+ },
ref: (ref) => {
this.modalRef = ref
},
diff --git a/ui/app/components/shapeshift-form.js b/ui/app/components/shapeshift-form.js
index 2270b8236..87eb1588a 100644
--- a/ui/app/components/shapeshift-form.js
+++ b/ui/app/components/shapeshift-form.js
@@ -14,11 +14,13 @@ function mapStateToProps (state) {
tokenExchangeRates,
selectedAddress,
} = state.metamask
+ const { warning } = state.appState
return {
coinOptions,
tokenExchangeRates,
selectedAddress,
+ warning,
}
}
@@ -51,8 +53,7 @@ ShapeshiftForm.prototype.componentWillMount = function () {
this.props.shapeShiftSubview()
}
-ShapeshiftForm.prototype.onCoinChange = function (e) {
- const coin = e.target.value
+ShapeshiftForm.prototype.onCoinChange = function (coin) {
this.setState({
depositCoin: coin,
errorMessage: '',
@@ -133,7 +134,7 @@ ShapeshiftForm.prototype.renderMarketInfo = function () {
}
ShapeshiftForm.prototype.renderQrCode = function () {
- const { depositAddress, isLoading } = this.state
+ const { depositAddress, isLoading, depositCoin } = this.state
const qrImage = qrcode(4, 'M')
qrImage.addData(depositAddress)
qrImage.make()
@@ -141,7 +142,7 @@ ShapeshiftForm.prototype.renderQrCode = function () {
return h('div.shapeshift-form', {}, [
h('div.shapeshift-form__deposit-instruction', [
- 'Deposit your BTC to the address below:',
+ `Deposit your ${depositCoin.toUpperCase()} to the address below:`,
]),
h('div', depositAddress),
@@ -164,7 +165,7 @@ ShapeshiftForm.prototype.renderQrCode = function () {
ShapeshiftForm.prototype.render = function () {
- const { coinOptions, btnClass } = this.props
+ const { coinOptions, btnClass, warning } = this.props
const { depositCoin, errorMessage, showQrCode, depositAddress } = this.state
const coinPair = `${depositCoin}_eth`
const { tokenExchangeRates } = this.props
@@ -182,7 +183,7 @@ ShapeshiftForm.prototype.render = function () {
h(SimpleDropdown, {
selectedOption: this.state.depositCoin,
- onSelect: this.onCoinChange,
+ onSelect: (coin) => this.onCoinChange(coin),
options: Object.entries(coinOptions).map(([coin]) => ({
value: coin.toLowerCase(),
displayValue: coin,
@@ -207,7 +208,9 @@ ShapeshiftForm.prototype.render = function () {
]),
- h('div', {
+ warning && h('div.shapeshift-form__address-input-label', warning),
+
+ !warning && h('div', {
className: classnames('shapeshift-form__address-input-wrapper', {
'shapeshift-form__address-input-wrapper--error': errorMessage,
}),
@@ -228,7 +231,7 @@ ShapeshiftForm.prototype.render = function () {
h('divshapeshift-form__address-input-error-message', [errorMessage]),
]),
- this.renderMarketInfo(),
+ !warning && this.renderMarketInfo(),
]),
diff --git a/ui/app/css/itcss/components/account-menu.scss b/ui/app/css/itcss/components/account-menu.scss
index 8ad7481c7..4752741aa 100644
--- a/ui/app/css/itcss/components/account-menu.scss
+++ b/ui/app/css/itcss/components/account-menu.scss
@@ -66,8 +66,9 @@
.keyring-label {
margin-top: 5px;
- background-color: $black;
- color: $dusty-gray;
+ background-color: $dusty-gray;
+ color: $black;
+ font-weight: normal;
}
}
diff --git a/ui/app/css/itcss/components/header.scss b/ui/app/css/itcss/components/header.scss
index d91ab3c48..eeed9ee06 100644
--- a/ui/app/css/itcss/components/header.scss
+++ b/ui/app/css/itcss/components/header.scss
@@ -80,11 +80,10 @@
font-family: Roboto;
text-transform: uppercase;
font-weight: 500;
- font-size: 0.8rem;
- padding-left: 9px;
+ font-size: .8rem;
color: $buttercup;
- align-self: flex-start;
- margin-top: 10px;
+ margin-left: 5px;
+ line-height: initial;
@media screen and (max-width: 575px) {
display: none;
diff --git a/ui/app/css/itcss/components/modal.scss b/ui/app/css/itcss/components/modal.scss
index 919e1793b..53e3bff00 100644
--- a/ui/app/css/itcss/components/modal.scss
+++ b/ui/app/css/itcss/components/modal.scss
@@ -787,6 +787,10 @@
width: auto;
flex: 1;
}
+
+ @media screen and (max-width: 575px) {
+ width: auto;
+ }
}
}
diff --git a/ui/app/css/itcss/components/new-account.scss b/ui/app/css/itcss/components/new-account.scss
index 81f919df3..c6c254ede 100644
--- a/ui/app/css/itcss/components/new-account.scss
+++ b/ui/app/css/itcss/components/new-account.scss
@@ -54,6 +54,16 @@
}
+.new-account-import-disclaimer {
+ width: 120%;
+ background-color: #F4F9FC;
+ display: inline-block;
+ align-items: center;
+ padding: 20px 30px 20px;
+ font-size: 12px;
+ line-height: 1.5;
+}
+
.new-account-import-form {
display: flex;
flex-flow: column;
diff --git a/ui/app/css/itcss/settings/variables.scss b/ui/app/css/itcss/settings/variables.scss
index 4c0972527..d96c1ae43 100644
--- a/ui/app/css/itcss/settings/variables.scss
+++ b/ui/app/css/itcss/settings/variables.scss
@@ -46,6 +46,10 @@ $manatee: #93949d;
$spindle: #c7ddec;
$mid-gray: #5b5d67;
$cape-cod: #38393a;
+$java: #29b6af;
+$wild-strawberry: #ff4a8d;
+$cornflower-blue: #7057ff;
+$saffron: #f6c343;
/*
Z-Indicies
diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js
index 02f024f7c..4dda839a2 100644
--- a/ui/app/reducers/app.js
+++ b/ui/app/reducers/app.js
@@ -140,10 +140,10 @@ function reduceApp (state, action) {
case actions.FORGOT_PASSWORD:
return extend(appState, {
currentView: {
- name: 'restoreVault',
+ name: action.value ? 'restoreVault' : 'accountDetail',
},
transForward: false,
- forgottenPassword: true,
+ forgottenPassword: action.value,
})
case actions.SHOW_INIT_MENU:
diff --git a/ui/app/reducers/metamask.js b/ui/app/reducers/metamask.js
index beeba948d..cddcd0c1f 100644
--- a/ui/app/reducers/metamask.js
+++ b/ui/app/reducers/metamask.js
@@ -43,12 +43,15 @@ function reduceMetamask (state, action) {
useBlockie: false,
featureFlags: {},
networkEndpointType: OLD_UI_NETWORK_TYPE,
+ isRevealingSeedWords: false,
}, state.metamask)
switch (action.type) {
case actions.SHOW_ACCOUNTS_PAGE:
- newState = extend(metamaskState)
+ newState = extend(metamaskState, {
+ isRevealingSeedWords: false,
+ })
delete newState.seedWords
return newState
@@ -124,10 +127,12 @@ function reduceMetamask (state, action) {
},
})
+
case actions.SHOW_NEW_VAULT_SEED:
return extend(metamaskState, {
isUnlocked: true,
isInitialized: false,
+ isRevealingSeedWords: true,
seedWords: action.value,
})
diff --git a/ui/app/send-v2.js b/ui/app/send-v2.js
index 1d67150e3..fc1df1f51 100644
--- a/ui/app/send-v2.js
+++ b/ui/app/send-v2.js
@@ -361,8 +361,9 @@ SendTransactionScreen.prototype.validateAmount = function (value) {
})
}
+ const verifyTokenBalance = selectedToken && tokenBalance !== null
let sufficientTokens
- if (selectedToken) {
+ if (verifyTokenBalance) {
sufficientTokens = isTokenBalanceSufficient({
tokenBalance,
amount,
@@ -377,7 +378,7 @@ SendTransactionScreen.prototype.validateAmount = function (value) {
if (conversionRate && !sufficientBalance) {
amountError = 'Insufficient funds.'
- } else if (selectedToken && !sufficientTokens) {
+ } else if (verifyTokenBalance && !sufficientTokens) {
amountError = 'Insufficient tokens.'
} else if (amountLessThanZero) {
amountError = 'Can not send negative amounts of ETH.'
@@ -396,14 +397,15 @@ SendTransactionScreen.prototype.renderAmountRow = function () {
amount,
setMaxModeTo,
maxModeOn,
+ gasTotal,
} = this.props
return h('div.send-v2__form-row', [
- h('div.send-v2__form-label', [
+ h('div.send-v2__form-label', [
'Amount:',
this.renderErrorMessage('amount'),
- !errors.amount && h('div.send-v2__amount-max', {
+ !errors.amount && gasTotal && h('div.send-v2__amount-max', {
onClick: (event) => {
event.preventDefault()
setMaxModeTo(true)
@@ -491,9 +493,12 @@ SendTransactionScreen.prototype.renderFooter = function () {
goHome,
clearSend,
gasTotal,
+ tokenBalance,
+ selectedToken,
errors: { amount: amountError, to: toError },
} = this.props
+ const missingTokenBalance = selectedToken && !tokenBalance
const noErrors = !amountError && toError === null
return h('div.page-container__footer', [
@@ -504,7 +509,7 @@ SendTransactionScreen.prototype.renderFooter = function () {
},
}, 'Cancel'),
h('button.btn-clear.page-container__footer-button', {
- disabled: !noErrors || !gasTotal,
+ disabled: !noErrors || !gasTotal || missingTokenBalance,
onClick: event => this.onSubmit(event),
}, 'Next'),
])
diff --git a/ui/app/unlock.js b/ui/app/unlock.js
index 13c3f1274..cafe3a859 100644
--- a/ui/app/unlock.js
+++ b/ui/app/unlock.js
@@ -71,7 +71,7 @@ UnlockScreen.prototype.render = function () {
style: {
margin: 10,
},
- }, 'Unlock'),
+ }, 'Log In'),
]),
h('.flex-row.flex-center.flex-grow', [
@@ -104,7 +104,7 @@ UnlockScreen.prototype.render = function () {
},
}, 'Use classic interface'),
]),
-
+
])
)
}
diff --git a/yarn.lock b/yarn.lock
index d9e456aa9..028ffa44e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -7348,9 +7348,9 @@ mersenne-twister@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/mersenne-twister/-/mersenne-twister-1.1.0.tgz#f916618ee43d7179efcf641bec4531eb9670978a"
-metamascara@^1.3.1:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/metamascara/-/metamascara-1.3.1.tgz#a84d6f20ef4ba401ce44eba120857ee1d680747b"
+metamascara@^2.0.0:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/metamascara/-/metamascara-2.2.1.tgz#f97b87045a245e1bd2e1bcae7a3d4dcd4e17c02a"
dependencies:
iframe "^1.0.0"
iframe-stream "^3.0.0"