aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md17
-rw-r--r--app/manifest.json2
-rw-r--r--app/popup.html4
-rw-r--r--app/scripts/controllers/transactions.js4
-rw-r--r--app/scripts/lib/config-manager.js11
-rw-r--r--app/scripts/lib/tx-state-manager.js11
-rw-r--r--app/scripts/metamask-controller.js36
-rw-r--r--app/scripts/migrations/021.js34
-rw-r--r--app/scripts/migrations/index.js1
-rw-r--r--development/states/first-time.json2
-rw-r--r--gulpfile.js2
-rw-r--r--old-ui/app/add-token.js4
-rw-r--r--old-ui/app/app.js30
-rw-r--r--old-ui/app/components/account-dropdowns.js1
-rw-r--r--old-ui/app/config.js46
-rw-r--r--old-ui/app/css/index.css51
-rw-r--r--package.json15
-rw-r--r--test/integration/lib/first-time.js3
-rw-r--r--test/integration/lib/send-new-ui.js20
-rw-r--r--test/lib/migrations/002.json1
-rw-r--r--test/lib/shallow-with-store.js14
-rw-r--r--test/unit/migrations/021-test.js16
-rw-r--r--test/unit/tx-state-manager-test.js43
-rw-r--r--test/unit/ui/add-token.spec.js43
-rw-r--r--ui/app/accounts/import/json.js6
-rw-r--r--ui/app/actions.js48
-rw-r--r--ui/app/app.js48
-rw-r--r--ui/app/components/account-menu/index.js8
-rw-r--r--ui/app/components/modals/modal.js13
-rw-r--r--ui/app/components/modals/notification-modal.js36
-rw-r--r--ui/app/components/modals/notification-modals/confirm-reset-account.js46
-rw-r--r--ui/app/components/pending-tx/confirm-send-ether.js16
-rw-r--r--ui/app/components/pending-tx/confirm-send-token.js16
-rw-r--r--ui/app/components/shift-list-item.js57
-rw-r--r--ui/app/components/token-cell.js2
-rw-r--r--ui/app/components/tx-list.js7
-rw-r--r--ui/app/css/itcss/base/index.scss6
-rw-r--r--ui/app/css/itcss/components/account-menu.scss2
-rw-r--r--ui/app/css/itcss/components/confirm.scss14
-rw-r--r--ui/app/css/itcss/components/currency-display.scss3
-rw-r--r--ui/app/css/itcss/components/modal.scss74
-rw-r--r--ui/app/css/itcss/components/newui-sections.scss1
-rw-r--r--ui/app/css/itcss/components/send.scss23
-rw-r--r--ui/app/css/itcss/components/token-list.scss2
-rw-r--r--ui/app/css/itcss/generic/index.scss133
-rw-r--r--ui/app/keychains/hd/restore-vault.js4
-rw-r--r--ui/app/main-container.js8
-rw-r--r--ui/app/reducers/app.js7
-rw-r--r--ui/app/reducers/metamask.js2
-rw-r--r--ui/app/selectors.js6
-rw-r--r--ui/app/send-v2.js69
-rw-r--r--ui/app/settings.js23
-rw-r--r--ui/app/unlock.js25
53 files changed, 874 insertions, 242 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 905f1f98f..b44846e13 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,23 @@
## Current Master
+## 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.
diff --git a/app/manifest.json b/app/manifest.json
index d795a225a..a0bb5acf6 100644
--- a/app/manifest.json
+++ b/app/manifest.json
@@ -1,7 +1,7 @@
{
"name": "MetaMask",
"short_name": "Metamask",
- "version": "3.13.7",
+ "version": "3.14.1",
"manifest_version": 2,
"author": "https://metamask.io",
"description": "Ethereum Browser Extension",
diff --git a/app/popup.html b/app/popup.html
index c4e5188e5..bf09b97ca 100644
--- a/app/popup.html
+++ b/app/popup.html
@@ -1,11 +1,11 @@
<!doctype html>
-<html style="width:350px; height:600px;">
+<html style="width:357px; height:600px;">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1 user-scalable=no">
<title>MetaMask Plugin</title>
</head>
- <body style="width:350px; height:600px;">
+ <body style="width:357px; height:600px;">
<div id="app-content"></div>
<script src="./scripts/popup.js" type="text/javascript" charset="utf-8"></script>
</body>
diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js
index 91ec42b69..ef5578d5a 100644
--- a/app/scripts/controllers/transactions.js
+++ b/app/scripts/controllers/transactions.js
@@ -152,6 +152,10 @@ module.exports = class TransactionController extends EventEmitter {
}
}
+ wipeTransactions (address) {
+ this.txStateManager.wipeTransactions(address)
+ }
+
// Adds a tx to the txlist
addTx (txMeta) {
this.txStateManager.addTx(txMeta)
diff --git a/app/scripts/lib/config-manager.js b/app/scripts/lib/config-manager.js
index 9c0dffe9c..34b603b96 100644
--- a/app/scripts/lib/config-manager.js
+++ b/app/scripts/lib/config-manager.js
@@ -42,6 +42,17 @@ ConfigManager.prototype.getData = function () {
return this.store.getState()
}
+ConfigManager.prototype.setPasswordForgotten = function (passwordForgottenState) {
+ const data = this.getData()
+ data.forgottenPassword = passwordForgottenState
+ this.setData(data)
+}
+
+ConfigManager.prototype.getPasswordForgotten = function (passwordForgottenState) {
+ const data = this.getData()
+ return data.forgottenPassword
+}
+
ConfigManager.prototype.setWallet = function (wallet) {
var data = this.getData()
data.wallet = wallet
diff --git a/app/scripts/lib/tx-state-manager.js b/app/scripts/lib/tx-state-manager.js
index a8ef39891..051efd247 100644
--- a/app/scripts/lib/tx-state-manager.js
+++ b/app/scripts/lib/tx-state-manager.js
@@ -221,6 +221,17 @@ module.exports = class TransactionStateManger extends EventEmitter {
this._setTxStatus(txId, 'failed')
}
+ wipeTransactions (address) {
+ // network only tx
+ const txs = this.getFullTxList()
+ const network = this.getNetwork()
+
+ // Filter out the ones from the current account and network
+ const otherAccountTxs = txs.filter((txMeta) => !(txMeta.txParams.from === address && txMeta.metamaskNetworkId === network))
+
+ // Update state
+ this._saveTxList(otherAccountTxs)
+ }
//
// PRIVATE METHODS
//
diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js
index 962516af6..15a30458a 100644
--- a/app/scripts/metamask-controller.js
+++ b/app/scripts/metamask-controller.js
@@ -43,6 +43,8 @@ module.exports = class MetamaskController extends EventEmitter {
constructor (opts) {
super()
+ this.defaultMaxListeners = 20
+
this.sendUpdate = debounce(this.privateSendUpdate.bind(this), 200)
this.opts = opts
@@ -84,9 +86,7 @@ module.exports = class MetamaskController extends EventEmitter {
})
this.infuraController.scheduleInfuraNetworkCheck()
- this.blacklistController = new BlacklistController({
- initState: initState.BlacklistController,
- })
+ this.blacklistController = new BlacklistController()
this.blacklistController.scheduleUpdates()
// rpc provider
@@ -198,12 +198,7 @@ module.exports = class MetamaskController extends EventEmitter {
this.networkController.store.subscribe((state) => {
this.store.updateState({ NetworkController: state })
})
- this.blacklistController.store.subscribe((state) => {
- this.store.updateState({ BlacklistController: state })
- })
- this.recentBlocksController.store.subscribe((state) => {
- this.store.updateState({ RecentBlocks: state })
- })
+
this.infuraController.store.subscribe((state) => {
this.store.updateState({ InfuraController: state })
})
@@ -315,6 +310,7 @@ module.exports = class MetamaskController extends EventEmitter {
{
lostAccounts: this.configManager.getLostAccounts(),
seedWords: this.configManager.getSeedWords(),
+ forgottenPassword: this.configManager.getPasswordForgotten(),
}
)
}
@@ -337,6 +333,8 @@ module.exports = class MetamaskController extends EventEmitter {
setCurrentCurrency: this.setCurrentCurrency.bind(this),
setUseBlockie: this.setUseBlockie.bind(this),
markAccountsFound: this.markAccountsFound.bind(this),
+ markPasswordForgotten: this.markPasswordForgotten.bind(this),
+ unMarkPasswordForgotten: this.unMarkPasswordForgotten.bind(this),
// coinbase
buyEth: this.buyEth.bind(this),
@@ -347,6 +345,7 @@ module.exports = class MetamaskController extends EventEmitter {
addNewAccount: nodeify(this.addNewAccount, this),
placeSeedWords: this.placeSeedWords.bind(this),
clearSeedWordCache: this.clearSeedWordCache.bind(this),
+ resetAccount: this.resetAccount.bind(this),
importAccountWithStrategy: this.importAccountWithStrategy.bind(this),
// vault management
@@ -607,6 +606,13 @@ module.exports = class MetamaskController extends EventEmitter {
cb(null, this.preferencesController.getSelectedAddress())
}
+ resetAccount (cb) {
+ const selectedAddress = this.preferencesController.getSelectedAddress()
+ this.txController.wipeTransactions(selectedAddress)
+ cb(null, selectedAddress)
+ }
+
+
importAccountWithStrategy (strategy, args, cb) {
accountImporter.importAccount(strategy, args)
.then((privateKey) => {
@@ -791,6 +797,18 @@ module.exports = class MetamaskController extends EventEmitter {
cb(null, this.getState())
}
+ markPasswordForgotten(cb) {
+ this.configManager.setPasswordForgotten(true)
+ this.sendUpdate()
+ cb()
+ }
+
+ unMarkPasswordForgotten(cb) {
+ this.configManager.setPasswordForgotten(false)
+ this.sendUpdate()
+ cb()
+ }
+
restoreOldVaultAccounts (migratorOutput) {
const { serialized } = migratorOutput
return this.keyringController.restoreKeyring(serialized)
diff --git a/app/scripts/migrations/021.js b/app/scripts/migrations/021.js
new file mode 100644
index 000000000..d84e77b50
--- /dev/null
+++ b/app/scripts/migrations/021.js
@@ -0,0 +1,34 @@
+const version = 21
+
+/*
+
+This migration removes the BlackListController from disk state
+
+*/
+
+const clone = require('clone')
+
+module.exports = {
+ version,
+
+ migrate: function (originalVersionedData) {
+ const versionedData = clone(originalVersionedData)
+ versionedData.meta.version = version
+ try {
+ const state = versionedData.data
+ const newState = transformState(state)
+ versionedData.data = newState
+ } catch (err) {
+ console.warn(`MetaMask Migration #${version}` + err.stack)
+ }
+ return Promise.resolve(versionedData)
+ },
+}
+
+function transformState (state) {
+ const newState = state
+ delete newState.BlacklistController
+ delete newState.RecentBlocks
+ return newState
+}
+
diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js
index 9d0631042..a0cf5f4d4 100644
--- a/app/scripts/migrations/index.js
+++ b/app/scripts/migrations/index.js
@@ -31,4 +31,5 @@ module.exports = [
require('./018'),
require('./019'),
require('./020'),
+ require('./021'),
]
diff --git a/development/states/first-time.json b/development/states/first-time.json
index 6e7435db1..4f5352992 100644
--- a/development/states/first-time.json
+++ b/development/states/first-time.json
@@ -8,7 +8,7 @@
"frequentRpcList": [],
"unapprovedTxs": {},
"currentCurrency": "USD",
- "featureFlags": {"betaUI": true},
+ "featureFlags": {"betaUI": false},
"conversionRate": 12.7527416,
"conversionDate": 1487624341,
"noActiveNotices": false,
diff --git a/gulpfile.js b/gulpfile.js
index 0d4a3e5c0..3ade82f87 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -303,7 +303,7 @@ gulp.task('apply-prod-environment', function(done) {
gulp.task('dev', gulp.series('build:scss', 'dev:js', 'copy', gulp.parallel('watch:scss', 'copy:watch', 'dev:reload')))
-gulp.task('build', gulp.series('clean', 'build:scss', gulp.parallel('build:js', 'copy', 'deps')))
+gulp.task('build', gulp.series('clean', 'build:scss', gulp.parallel('build:js', 'copy')))
gulp.task('dist', gulp.series('apply-prod-environment', 'build', 'zip'))
// task generators
diff --git a/old-ui/app/add-token.js b/old-ui/app/add-token.js
index 8778f312e..8a3e66978 100644
--- a/old-ui/app/add-token.js
+++ b/old-ui/app/add-token.js
@@ -25,7 +25,7 @@ inherits(AddTokenScreen, Component)
function AddTokenScreen () {
this.state = {
warning: null,
- address: null,
+ address: '',
symbol: 'TOKEN',
decimals: 18,
}
@@ -190,7 +190,7 @@ AddTokenScreen.prototype.validateInputs = function () {
const validAddress = ethUtil.isValidAddress(address)
if (!validAddress) {
- msg += 'Address is invalid. '
+ msg += 'Address is invalid.'
}
const validDecimals = decimals >= 0 && decimals < 36
diff --git a/old-ui/app/app.js b/old-ui/app/app.js
index 6eb1e487f..61f6223bc 100644
--- a/old-ui/app/app.js
+++ b/old-ui/app/app.js
@@ -456,11 +456,31 @@ App.prototype.renderPrimary = function () {
// notices
if (!props.noActiveNotices) {
log.debug('rendering notice screen for unread notices.')
- return h(NoticeScreen, {
- notice: props.lastUnreadNotice,
- key: 'NoticeScreen',
- onConfirm: () => props.dispatch(actions.markNoticeRead(props.lastUnreadNotice)),
- })
+ return h('div', [
+
+ h(NoticeScreen, {
+ notice: props.lastUnreadNotice,
+ key: 'NoticeScreen',
+ onConfirm: () => props.dispatch(actions.markNoticeRead(props.lastUnreadNotice)),
+ }),
+
+ !props.isInitialized && h('.flex-row.flex-center.flex-grow', [
+ h('p.pointer', {
+ onClick: () => {
+ global.platform.openExtensionInBrowser()
+ props.dispatch(actions.setFeatureFlag('betaUI', true, 'BETA_UI_NOTIFICATION_MODAL'))
+ .then(() => props.dispatch(actions.setNetworkEndpoints(BETA_UI_NETWORK_TYPE)))
+ },
+ style: {
+ fontSize: '0.8em',
+ color: '#aeaeae',
+ textDecoration: 'underline',
+ marginTop: '32px',
+ },
+ }, 'Try Beta Version'),
+ ]),
+
+ ])
} else if (props.lostAccounts && props.lostAccounts.length > 0) {
log.debug('rendering notice screen for lost accounts view.')
return h(NoticeScreen, {
diff --git a/old-ui/app/components/account-dropdowns.js b/old-ui/app/components/account-dropdowns.js
index da9f60492..aa7a3ad67 100644
--- a/old-ui/app/components/account-dropdowns.js
+++ b/old-ui/app/components/account-dropdowns.js
@@ -268,6 +268,7 @@ class AccountDropdowns extends Component {
'i.fa.fa-ellipsis-h',
{
style: {
+ margin: '0.5em',
fontSize: '1.8em',
},
onClick: (event) => {
diff --git a/old-ui/app/config.js b/old-ui/app/config.js
index 75198fba5..9e07cf348 100644
--- a/old-ui/app/config.js
+++ b/old-ui/app/config.js
@@ -30,7 +30,12 @@ ConfigScreen.prototype.render = function () {
var warning = state.warning
return (
- h('.flex-column.flex-grow', [
+ h('.flex-column.flex-grow', {
+ style:{
+ maxHeight: '585px',
+ overflowY: 'auto',
+ },
+ }, [
h(Modal, {}, []),
@@ -57,6 +62,7 @@ ConfigScreen.prototype.render = function () {
h('.flex-space-around', {
style: {
padding: '20px',
+ overflow: 'auto',
},
}, [
@@ -144,6 +150,40 @@ ConfigScreen.prototype.render = function () {
}, 'Reveal Seed Words'),
]),
+ h('hr.horizontal-line'),
+
+ h('div', {
+ style: {
+ marginTop: '20px',
+ },
+ }, [
+
+ h('p', {
+ style: {
+ fontFamily: 'Montserrat Light',
+ fontSize: '13px',
+ },
+ }, [
+ 'Resetting is for developer use only. ',
+ h('a', {
+ href: 'http://metamask.helpscoutdocs.com/article/36-resetting-an-account',
+ target: '_blank',
+ onClick (event) { this.navigateTo(event.target.href) },
+ }, 'Read more.'),
+ ]),
+ h('br'),
+
+ h('button', {
+ style: {
+ alignSelf: 'center',
+ },
+ onClick (event) {
+ event.preventDefault()
+ state.dispatch(actions.resetAccount())
+ },
+ }, 'Reset Account'),
+ ]),
+
]),
]),
])
@@ -220,3 +260,7 @@ function currentProviderDisplay (metamaskState) {
h('span', value),
])
}
+
+ConfigScreen.prototype.navigateTo = function (url) {
+ global.platform.openWindow({ url })
+}
diff --git a/old-ui/app/css/index.css b/old-ui/app/css/index.css
index 3bb64647a..67c327f62 100644
--- a/old-ui/app/css/index.css
+++ b/old-ui/app/css/index.css
@@ -285,7 +285,7 @@ app sections
}
.unlock-screen #metamask-mascot-container {
- margin-top: 24px;
+ margin-top: 80px;
}
.unlock-screen h1 {
@@ -443,7 +443,7 @@ input.large-input {
flex-wrap: wrap;
overflow-x: hidden;
overflow-y: auto;
- max-height: 465px;
+ max-height: 585px;
flex-direction: inherit;
}
@@ -761,4 +761,51 @@ div.message-container > div:first-child {
right: 17.5px;
font-family: sans-serif;
cursor: pointer;
+}
+
+.notification-modal__wrapper {
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-start;
+ align-items: center;
+ position: relative;
+ border: 1px solid #dedede;
+ box-shadow: 0 0 2px 2px #dedede;
+ font-family: Roboto;
+}
+
+.notification-modal__header {
+ background: #f6f6f6;
+ width: 100%;
+ display: flex;
+ justify-content: center;
+ padding: 30px;
+ font-size: 22px;
+ color: #1b344d;
+ height: 79px;
+}
+
+.notification-modal__message {
+ padding: 20px;
+ width: 100%;
+ display: flex;
+ justify-content: center;
+ font-size: 17px;
+ color: #1b344d;
+}
+
+.notification-modal__buttons {
+ display: flex;
+ justify-content: space-evenly;
+ width: 100%;
+ margin-bottom: 24px;
+ padding: 0px 42px;
+}
+
+.notification-modal__buttons__btn {
+ cursor: pointer;
+}
+
+.notification-modal__link {
+ color: #2f9ae0;
} \ No newline at end of file
diff --git a/package.json b/package.json
index 330878fb2..826d06c32 100644
--- a/package.json
+++ b/package.json
@@ -78,7 +78,7 @@
"eth-bin-to-ops": "^1.0.1",
"eth-block-tracker": "^2.3.0",
"eth-json-rpc-filters": "^1.2.5",
- "eth-json-rpc-infura": "^2.0.11",
+ "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",
@@ -193,7 +193,7 @@
"deep-freeze-strict": "^1.1.1",
"del": "^3.0.0",
"envify": "^4.0.0",
- "enzyme": "^3.2.0",
+ "enzyme": "^3.3.0",
"enzyme-adapter-react-15": "^1.0.5",
"eslint-plugin-chai": "0.0.1",
"eslint-plugin-mocha": "^4.9.0",
@@ -202,6 +202,7 @@
"fs-promise": "^2.0.3",
"gulp": "github:gulpjs/gulp#6d71a658c61edb3090221579d8f97dbe086ba2ed",
"gulp-babel": "^7.0.0",
+ "gulp-eslint": "^4.0.0",
"gulp-if": "^2.0.2",
"gulp-json-editor": "^2.2.1",
"gulp-livereload": "^3.8.1",
@@ -212,9 +213,8 @@
"gulp-uglify": "^3.0.0",
"gulp-uglify-es": "^1.0.0",
"gulp-util": "^3.0.7",
- "gulp-watch": "^4.3.5",
+ "gulp-watch": "^5.0.0",
"gulp-zip": "^4.0.0",
- "gulp-eslint": "^4.0.0",
"isomorphic-fetch": "^2.2.1",
"jsdom": "^11.1.0",
"jsdom-global": "^3.0.2",
@@ -225,11 +225,12 @@
"karma-firefox-launcher": "^1.0.1",
"karma-qunit": "^1.2.1",
"lodash.assign": "^4.0.6",
- "mocha": "^4.0.0",
+ "mocha": "^5.0.0",
"mocha-eslint": "^4.0.0",
"mocha-jsdom": "^1.1.0",
"mocha-sinon": "^2.0.0",
"nock": "^9.0.14",
+ "node-sass": "^4.7.2",
"nyc": "^11.0.3",
"open": "0.0.5",
"prompt": "^1.0.0",
@@ -238,11 +239,11 @@
"react-addons-test-utils": "^15.5.1",
"react-test-renderer": "^15.6.2",
"react-testutils-additions": "^15.2.0",
- "redux-test-utils": "^0.1.3",
+ "redux-test-utils": "^0.2.2",
"sinon": "^4.0.0",
"stylelint-config-standard": "^17.0.0",
"tape": "^4.5.1",
- "testem": "^1.10.3",
+ "testem": "^2.0.0",
"uglifyify": "^4.0.2",
"vinyl-buffer": "^1.0.1",
"vinyl-source-stream": "^2.0.0",
diff --git a/test/integration/lib/first-time.js b/test/integration/lib/first-time.js
index 6e879dcd0..764eae47c 100644
--- a/test/integration/lib/first-time.js
+++ b/test/integration/lib/first-time.js
@@ -22,7 +22,6 @@ async function runFirstTimeUsageTest(assert, done) {
reactTriggerChange(selectState[0])
await timeout(2000)
-
const app = $('#app-content')
// recurse notices
@@ -46,7 +45,7 @@ async function runFirstTimeUsageTest(assert, done) {
await timeout()
// Scroll through terms
- const title = app.find('h1')[1]
+ const title = app.find('h1')[0]
assert.equal(title.textContent, 'MetaMask', 'title screen')
// enter password
diff --git a/test/integration/lib/send-new-ui.js b/test/integration/lib/send-new-ui.js
index 99571d0e8..3456f2367 100644
--- a/test/integration/lib/send-new-ui.js
+++ b/test/integration/lib/send-new-ui.js
@@ -30,16 +30,10 @@ async function runSendFlowTest(assert, done) {
await timeout(1000)
- const sendContainer = $('.send-v2__container')
- assert.ok(sendContainer[0], 'send container renders')
+ const sendTitle = $('.page-container__title')
+ assert.equal(sendTitle[0].textContent, 'Send ETH', 'Send screen title is correct')
- const sendHeader = $('.send-v2__send-header-icon')
- assert.ok(sendHeader[0], 'send screen has a header icon')
-
- const sendTitle = $('.send-v2__title')
- assert.equal(sendTitle[0].textContent, 'Send Funds', 'Send screen title is correct')
-
- const sendCopy = $('.send-v2__copy')
+ const sendCopy = $('.page-container__subtitle')
assert.equal(sendCopy[0].textContent, 'Only send ETH to an Ethereum address.', 'Send screen has copy')
const sendFromField = $('.send-v2__form-field')
@@ -120,7 +114,7 @@ async function runSendFlowTest(assert, done) {
const customizeGasModal = $('.send-v2__customize-gas')
assert.ok(customizeGasModal[0], 'should render the customize gas modal')
-
+
const customizeGasPriceInput = $('.send-v2__gas-modal-card').first().find('input')
customizeGasPriceInput.val(50)
reactTriggerChange(customizeGasPriceInput[0])
@@ -146,7 +140,8 @@ async function runSendFlowTest(assert, done) {
'send gas field should show customized gas total converted to USD'
)
- const sendButton = $('.send-v2__next-btn')
+ const sendButton = $('button.btn-clear.page-container__footer-button')
+ assert.equal(sendButton[0].textContent, 'Next', 'next button rendered')
sendButton[0].click()
await timeout(2000)
@@ -200,7 +195,8 @@ async function runSendFlowTest(assert, done) {
await timeout()
- const sendButtonInEdit = $('.send-v2__next-btn')
+ const sendButtonInEdit = $('.btn-clear.page-container__footer-button')
+ assert.equal(sendButtonInEdit[0].textContent, 'Next', 'next button in edit rendered')
sendButtonInEdit[0].click()
await timeout()
diff --git a/test/lib/migrations/002.json b/test/lib/migrations/002.json
new file mode 100644
index 000000000..9ad3d4cfe
--- /dev/null
+++ b/test/lib/migrations/002.json
@@ -0,0 +1 @@
+{"meta":{"version":20},"data":{"config":{},"NetworkController":{"provider":{"type":"mainnet","rpcTarget":"https://mainnet.infura.io/metamask"},"network":"1"},"firstTimeInfo":{"version":"3.12.1","date":1517351427287},"NoticeController":{"noticesList":[{"read":false,"date":"Thu Feb 09 2017","title":"Terms of Use","body":"# Terms of Use #\n\n**THIS AGREEMENT IS SUBJECT TO BINDING ARBITRATION AND A WAIVER OF CLASS ACTION RIGHTS AS DETAILED IN SECTION 13. PLEASE READ THE AGREEMENT CAREFULLY.**\n\n_Our Terms of Use have been updated as of September 5, 2016_\n\n## 1. Acceptance of Terms ##\n\nMetaMask provides a platform for managing Ethereum (or \"ETH\") accounts, and allowing ordinary websites to interact with the Ethereum blockchain, while keeping the user in control over what transactions they approve, through our website located at[ ](http://metamask.io)[https://metamask.io/](https://metamask.io/) and browser plugin (the \"Site\") — which includes text, images, audio, code and other materials (collectively, the “Content”) and all of the features, and services provided. The Site, and any other features, tools, materials, or other services offered from time to time by MetaMask are referred to here as the “Service.” Please read these Terms of Use (the “Terms” or “Terms of Use”) carefully before using the Service. By using or otherwise accessing the Services, or clicking to accept or agree to these Terms where that option is made available, you (1) accept and agree to these Terms (2) consent to the collection, use, disclosure and other handling of information as described in our Privacy Policy and (3) any additional terms, rules and conditions of participation issued by MetaMask from time to time. If you do not agree to the Terms, then you may not access or use the Content or Services.\n\n## 2. Modification of Terms of Use ##\n\nExcept for Section 13, providing for binding arbitration and waiver of class action rights, MetaMask reserves the right, at its sole discretion, to modify or replace the Terms of Use at any time. The most current version of these Terms will be posted on our Site. You shall be responsible for reviewing and becoming familiar with any such modifications. Use of the Services by you after any modification to the Terms constitutes your acceptance of the Terms of Use as modified.\n\n\n\n## 3. Eligibility ##\n\nYou hereby represent and warrant that you are fully able and competent to enter into the terms, conditions, obligations, affirmations, representations and warranties set forth in these Terms and to abide by and comply with these Terms.\n\nMetaMask is a global platform and by accessing the Content or Services, you are representing and warranting that, you are of the legal age of majority in your jurisdiction as is required to access such Services and Content and enter into arrangements as provided by the Service. You further represent that you are otherwise legally permitted to use the service in your jurisdiction including owning cryptographic tokens of value, and interacting with the Services or Content in any way. You further represent you are responsible for ensuring compliance with the laws of your jurisdiction and acknowledge that MetaMask is not liable for your compliance with such laws.\n\n## 4 Account Password and Security ##\n\nWhen setting up an account within MetaMask, you will be responsible for keeping your own account secrets, which may be a twelve-word seed phrase, an account file, or other locally stored secret information. MetaMask encrypts this information locally with a password you provide, that we never send to our servers. You agree to (a) never use the same password for MetaMask that you have ever used outside of this service; (b) keep your secret information and password confidential and do not share them with anyone else; (c) immediately notify MetaMask of any unauthorized use of your account or breach of security. MetaMask cannot and will not be liable for any loss or damage arising from your failure to comply with this section.\n\n## 5. Representations, Warranties, and Risks ##\n\n### 5.1. Warranty Disclaimer ###\n\nYou expressly understand and agree that your use of the Service is at your sole risk. The Service (including the Service and the Content) are provided on an \"AS IS\" and \"as available\" basis, without warranties of any kind, either express or implied, including, without limitation, implied warranties of merchantability, fitness for a particular purpose or non-infringement. You acknowledge that MetaMask has no control over, and no duty to take any action regarding: which users gain access to or use the Service; what effects the Content may have on you; how you may interpret or use the Content; or what actions you may take as a result of having been exposed to the Content. You release MetaMask from all liability for you having acquired or not acquired Content through the Service. MetaMask makes no representations concerning any Content contained in or accessed through the Service, and MetaMask will not be responsible or liable for the accuracy, copyright compliance, legality or decency of material contained in or accessed through the Service.\n\n### 5.2 Sophistication and Risk of Cryptographic Systems ###\n\nBy utilizing the Service or interacting with the Content or platform in any way, you represent that you understand the inherent risks associated with cryptographic systems; and warrant that you have an understanding of the usage and intricacies of native cryptographic tokens, like Ether (ETH) and Bitcoin (BTC), smart contract based tokens such as those that follow the Ethereum Token Standard (https://github.com/ethereum/EIPs/issues/20), and blockchain-based software systems.\n\n### 5.3 Risk of Regulatory Actions in One or More Jurisdictions ###\n\nMetaMask and ETH could be impacted by one or more regulatory inquiries or regulatory action, which could impede or limit the ability of MetaMask to continue to develop, or which could impede or limit your ability to access or use the Service or Ethereum blockchain.\n\n### 5.4 Risk of Weaknesses or Exploits in the Field of Cryptography ###\n\nYou acknowledge and understand that Cryptography is a progressing field. Advances in code cracking or technical advances such as the development of quantum computers may present risks to cryptocurrencies and Services of Content, which could result in the theft or loss of your cryptographic tokens or property. To the extent possible, MetaMask intends to update the protocol underlying Services to account for any advances in cryptography and to incorporate additional security measures, but does not guarantee or otherwise represent full security of the system. By using the Service or accessing Content, you acknowledge these inherent risks.\n\n### 5.5 Volatility of Crypto Currencies ###\n\nYou understand that Ethereum and other blockchain technologies and associated currencies or tokens are highly volatile due to many factors including but not limited to adoption, speculation, technology and security risks. You also acknowledge that the cost of transacting on such technologies is variable and may increase at any time causing impact to any activities taking place on the Ethereum blockchain. You acknowledge these risks and represent that MetaMask cannot be held liable for such fluctuations or increased costs.\n\n### 5.6 Application Security ###\n\nYou acknowledge that Ethereum applications are code subject to flaws and acknowledge that you are solely responsible for evaluating any code provided by the Services or Content and the trustworthiness of any third-party websites, products, smart-contracts, or Content you access or use through the Service. You further expressly acknowledge and represent that Ethereum applications can be written maliciously or negligently, that MetaMask cannot be held liable for your interaction with such applications and that such applications may cause the loss of property or even identity. This warning and others later provided by MetaMask in no way evidence or represent an on-going duty to alert you to all of the potential risks of utilizing the Service or Content.\n\n## 6. Indemnity ##\n\nYou agree to release and to indemnify, defend and hold harmless MetaMask and its parents, subsidiaries, affiliates and agencies, as well as the officers, directors, employees, shareholders and representatives of any of the foregoing entities, from and against any and all losses, liabilities, expenses, damages, costs (including attorneys’ fees and court costs) claims or actions of any kind whatsoever arising or resulting from your use of the Service, your violation of these Terms of Use, and any of your acts or omissions that implicate publicity rights, defamation or invasion of privacy. MetaMask reserves the right, at its own expense, to assume exclusive defense and control of any matter otherwise subject to indemnification by you and, in such case, you agree to cooperate with MetaMask in the defense of such matter.\n\n## 7. Limitation on liability ##\n\nYOU ACKNOWLEDGE AND AGREE THAT YOU ASSUME FULL RESPONSIBILITY FOR YOUR USE OF THE SITE AND SERVICE. YOU ACKNOWLEDGE AND AGREE THAT ANY INFORMATION YOU SEND OR RECEIVE DURING YOUR USE OF THE SITE AND SERVICE MAY NOT BE SECURE AND MAY BE INTERCEPTED OR LATER ACQUIRED BY UNAUTHORIZED PARTIES. YOU ACKNOWLEDGE AND AGREE THAT YOUR USE OF THE SITE AND SERVICE IS AT YOUR OWN RISK. RECOGNIZING SUCH, YOU UNDERSTAND AND AGREE THAT, TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, NEITHER METAMASK NOR ITS SUPPLIERS OR LICENSORS WILL BE LIABLE TO YOU FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY OR OTHER DAMAGES OF ANY KIND, INCLUDING WITHOUT LIMITATION DAMAGES FOR LOSS OF PROFITS, GOODWILL, USE, DATA OR OTHER TANGIBLE OR INTANGIBLE LOSSES OR ANY OTHER DAMAGES BASED ON CONTRACT, TORT, STRICT LIABILITY OR ANY OTHER THEORY (EVEN IF METAMASK HAD BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES), RESULTING FROM THE SITE OR SERVICE; THE USE OR THE INABILITY TO USE THE SITE OR SERVICE; UNAUTHORIZED ACCESS TO OR ALTERATION OF YOUR TRANSMISSIONS OR DATA; STATEMENTS OR CONDUCT OF ANY THIRD PARTY ON THE SITE OR SERVICE; ANY ACTIONS WE TAKE OR FAIL TO TAKE AS A RESULT OF COMMUNICATIONS YOU SEND TO US; HUMAN ERRORS; TECHNICAL MALFUNCTIONS; FAILURES, INCLUDING PUBLIC UTILITY OR TELEPHONE OUTAGES; OMISSIONS, INTERRUPTIONS, LATENCY, DELETIONS OR DEFECTS OF ANY DEVICE OR NETWORK, PROVIDERS, OR SOFTWARE (INCLUDING, BUT NOT LIMITED TO, THOSE THAT DO NOT PERMIT PARTICIPATION IN THE SERVICE); ANY INJURY OR DAMAGE TO COMPUTER EQUIPMENT; INABILITY TO FULLY ACCESS THE SITE OR SERVICE OR ANY OTHER WEBSITE; THEFT, TAMPERING, DESTRUCTION, OR UNAUTHORIZED ACCESS TO, IMAGES OR OTHER CONTENT OF ANY KIND; DATA THAT IS PROCESSED LATE OR INCORRECTLY OR IS INCOMPLETE OR LOST; TYPOGRAPHICAL, PRINTING OR OTHER ERRORS, OR ANY COMBINATION THEREOF; OR ANY OTHER MATTER RELATING TO THE SITE OR SERVICE.\n\nSOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF CERTAIN WARRANTIES OR THE LIMITATION OR EXCLUSION OF LIABILITY FOR INCIDENTAL OR CONSEQUENTIAL DAMAGES. ACCORDINGLY, SOME OF THE ABOVE LIMITATIONS MAY NOT APPLY TO YOU.\n\n## 8. Our Proprietary Rights ##\n\nAll title, ownership and intellectual property rights in and to the Service are owned by MetaMask or its licensors. You acknowledge and agree that the Service contains proprietary and confidential information that is protected by applicable intellectual property and other laws. Except as expressly authorized by MetaMask, you agree not to copy, modify, rent, lease, loan, sell, distribute, perform, display or create derivative works based on the Service, in whole or in part. MetaMask issues a license for MetaMask, found [here](https://github.com/MetaMask/metamask-plugin/blob/master/LICENSE). For information on other licenses utilized in the development of MetaMask, please see our attribution page at: [https://metamask.io/attributions.html](https://metamask.io/attributions.html)\n\n## 9. Links ##\n\nThe Service provides, or third parties may provide, links to other World Wide Web or accessible sites, applications or resources. Because MetaMask has no control over such sites, applications and resources, you acknowledge and agree that MetaMask is not responsible for the availability of such external sites, applications or resources, and does not endorse and is not responsible or liable for any content, advertising, products or other materials on or available from such sites or resources. You further acknowledge and agree that MetaMask shall not be responsible or liable, directly or indirectly, for any damage or loss caused or alleged to be caused by or in connection with use of or reliance on any such content, goods or services available on or through any such site or resource.\n\n## 10. Termination and Suspension ##\n\nMetaMask may terminate or suspend all or part of the Service and your MetaMask access immediately, without prior notice or liability, if you breach any of the terms or conditions of the Terms. Upon termination of your access, your right to use the Service will immediately cease.\n\nThe following provisions of the Terms survive any termination of these Terms: INDEMNITY; WARRANTY DISCLAIMERS; LIMITATION ON LIABILITY; OUR PROPRIETARY RIGHTS; LINKS; TERMINATION; NO THIRD PARTY BENEFICIARIES; BINDING ARBITRATION AND CLASS ACTION WAIVER; GENERAL INFORMATION.\n\n## 11. No Third Party Beneficiaries ##\n\nYou agree that, except as otherwise expressly provided in these Terms, there shall be no third party beneficiaries to the Terms.\n\n## 12. Notice and Procedure For Making Claims of Copyright Infringement ##\n\nIf you believe that your copyright or the copyright of a person on whose behalf you are authorized to act has been infringed, please provide MetaMask’s Copyright Agent a written Notice containing the following information:\n\n· an electronic or physical signature of the person authorized to act on behalf of the owner of the copyright or other intellectual property interest;\n\n· a description of the copyrighted work or other intellectual property that you claim has been infringed;\n\n· a description of where the material that you claim is infringing is located on the Service;\n\n· your address, telephone number, and email address;\n\n· a statement by you that you have a good faith belief that the disputed use is not authorized by the copyright owner, its agent, or the law;\n\n· a statement by you, made under penalty of perjury, that the above information in your Notice is accurate and that you are the copyright or intellectual property owner or authorized to act on the copyright or intellectual property owner's behalf.\n\nMetaMask’s Copyright Agent can be reached at:\n\nEmail: copyright [at] metamask [dot] io\n\nMail:\n\nAttention:\n\nMetaMask Copyright ℅ ConsenSys\n\n49 Bogart Street\n\nBrooklyn, NY 11206\n\n## 13. Binding Arbitration and Class Action Waiver ##\n\nPLEASE READ THIS SECTION CAREFULLY – IT MAY SIGNIFICANTLY AFFECT YOUR LEGAL RIGHTS, INCLUDING YOUR RIGHT TO FILE A LAWSUIT IN COURT\n\n### 13.1 Initial Dispute Resolution ###\n\nThe parties shall use their best efforts to engage directly to settle any dispute, claim, question, or disagreement and engage in good faith negotiations which shall be a condition to either party initiating a lawsuit or arbitration.\n\n### 13.2 Binding Arbitration ###\n\nIf the parties do not reach an agreed upon solution within a period of 30 days from the time informal dispute resolution under the Initial Dispute Resolution provision begins, then either party may initiate binding arbitration as the sole means to resolve claims, subject to the terms set forth below. Specifically, all claims arising out of or relating to these Terms (including their formation, performance and breach), the parties’ relationship with each other and/or your use of the Service shall be finally settled by binding arbitration administered by the American Arbitration Association in accordance with the provisions of its Commercial Arbitration Rules and the supplementary procedures for consumer related disputes of the American Arbitration Association (the \"AAA\"), excluding any rules or procedures governing or permitting class actions.\n\nThe arbitrator, and not any federal, state or local court or agency, shall have exclusive authority to resolve all disputes arising out of or relating to the interpretation, applicability, enforceability or formation of these Terms, including, but not limited to any claim that all or any part of these Terms are void or voidable, or whether a claim is subject to arbitration. The arbitrator shall be empowered to grant whatever relief would be available in a court under law or in equity. The arbitrator’s award shall be written, and binding on the parties and may be entered as a judgment in any court of competent jurisdiction.\n\nThe parties understand that, absent this mandatory provision, they would have the right to sue in court and have a jury trial. They further understand that, in some instances, the costs of arbitration could exceed the costs of litigation and the right to discovery may be more limited in arbitration than in court.\n\n### 13.3 Location ###\n\nBinding arbitration shall take place in New York. You agree to submit to the personal jurisdiction of any federal or state court in New York County, New York, in order to compel arbitration, to stay proceedings pending arbitration, or to confirm, modify, vacate or enter judgment on the award entered by the arbitrator.\n\n### 13.4 Class Action Waiver ###\n\nThe parties further agree that any arbitration shall be conducted in their individual capacities only and not as a class action or other representative action, and the parties expressly waive their right to file a class action or seek relief on a class basis. YOU AND METAMASK AGREE THAT EACH MAY BRING CLAIMS AGAINST THE OTHER ONLY IN YOUR OR ITS INDIVIDUAL CAPACITY, AND NOT AS A PLAINTIFF OR CLASS MEMBER IN ANY PURPORTED CLASS OR REPRESENTATIVE PROCEEDING. If any court or arbitrator determines that the class action waiver set forth in this paragraph is void or unenforceable for any reason or that an arbitration can proceed on a class basis, then the arbitration provision set forth above shall be deemed null and void in its entirety and the parties shall be deemed to have not agreed to arbitrate disputes.\n\n### 13.5 Exception - Litigation of Intellectual Property and Small Claims Court Claims ###\n\nNotwithstanding the parties' decision to resolve all disputes through arbitration, either party may bring an action in state or federal court to protect its intellectual property rights (\"intellectual property rights\" means patents, copyrights, moral rights, trademarks, and trade secrets, but not privacy or publicity rights). Either party may also seek relief in a small claims court for disputes or claims within the scope of that court’s jurisdiction.\n\n### 13.6 30-Day Right to Opt Out ###\n\nYou have the right to opt-out and not be bound by the arbitration and class action waiver provisions set forth above by sending written notice of your decision to opt-out to the following address: MetaMask ℅ ConsenSys, 49 Bogart Street, Brooklyn NY 11206 and via email at legal-opt@metamask.io. The notice must be sent within 30 days of September 6, 2016 or your first use of the Service, whichever is later, otherwise you shall be bound to arbitrate disputes in accordance with the terms of those paragraphs. If you opt-out of these arbitration provisions, MetaMask also will not be bound by them.\n\n### 13.7 Changes to This Section ###\n\nMetaMask will provide 60-days’ notice of any changes to this section. Changes will become effective on the 60th day, and will apply prospectively only to any claims arising after the 60th day.\n\nFor any dispute not subject to arbitration you and MetaMask agree to submit to the personal and exclusive jurisdiction of and venue in the federal and state courts located in New York, New York. You further agree to accept service of process by mail, and hereby waive any and all jurisdictional and venue defenses otherwise available.\n\nThe Terms and the relationship between you and MetaMask shall be governed by the laws of the State of New York without regard to conflict of law provisions.\n\n## 14. General Information ##\n\n### 14.1 Entire Agreement ###\n\nThese Terms (and any additional terms, rules and conditions of participation that MetaMask may post on the Service) constitute the entire agreement between you and MetaMask with respect to the Service and supersedes any prior agreements, oral or written, between you and MetaMask. In the event of a conflict between these Terms and the additional terms, rules and conditions of participation, the latter will prevail over the Terms to the extent of the conflict.\n\n### 14.2 Waiver and Severability of Terms ###\n\nThe failure of MetaMask to exercise or enforce any right or provision of the Terms shall not constitute a waiver of such right or provision. If any provision of the Terms is found by an arbitrator or court of competent jurisdiction to be invalid, the parties nevertheless agree that the arbitrator or court should endeavor to give effect to the parties' intentions as reflected in the provision, and the other provisions of the Terms remain in full force and effect.\n\n### 14.3 Statute of Limitations ###\n\nYou agree that regardless of any statute or law to the contrary, any claim or cause of action arising out of or related to the use of the Service or the Terms must be filed within one (1) year after such claim or cause of action arose or be forever barred.\n\n### 14.4 Section Titles ###\n\nThe section titles in the Terms are for convenience only and have no legal or contractual effect.\n\n### 14.5 Communications ###\n\nUsers with questions, complaints or claims with respect to the Service may contact us using the relevant contact information set forth above and at communications@metamask.io.\n\n## 15 Related Links ##\n\n**[Terms of Use](https://metamask.io/terms.html)**\n\n**[Privacy](https://metamask.io/privacy.html)**\n\n**[Attributions](https://metamask.io/attributions.html)**\n\n","id":0},{"read":false,"date":"Mon May 08 2017","title":"Privacy Notice","body":"MetaMask is beta software. \n\nWhen you log in to MetaMask, your current account is visible to every new site you visit.\n\nFor your privacy, for now, please sign out of MetaMask when you're done using a site.\n\nAlso, by default, you will be signed in to a test network. To use real Ether, you must connect to the main network manually in the top left network menu.\n\n","id":2}]},"BlacklistController":{"phishing":{"version":2,"tolerance":2,"fuzzylist":["metamask.io","myetherwallet.com","cryptokitties.co"],"whitelist":["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"],"blacklist":["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"]}},"CurrencyController":{"currentCurrency":"usd","conversionRate":1112,"conversionDate":1517351401}}} \ No newline at end of file
diff --git a/test/lib/shallow-with-store.js b/test/lib/shallow-with-store.js
index 2a66adb17..9df10a3c5 100644
--- a/test/lib/shallow-with-store.js
+++ b/test/lib/shallow-with-store.js
@@ -1,16 +1,20 @@
const { shallow, mount } = require('enzyme')
-exports.shallowWithStore = function shallowWithStore (component, store) {
+module.exports = {
+ shallowWithStore,
+ mountWithStore,
+}
+
+function shallowWithStore (component, store) {
const context = {
store,
}
-
- return shallow(component, { context })
+ return shallow(component, {context})
}
-exports.mountWithStore = function mountWithStore (component, store) {
+function mountWithStore (component, store) {
const context = {
store,
}
- return mount(component, { context })
+ return mount(component, {context})
}
diff --git a/test/unit/migrations/021-test.js b/test/unit/migrations/021-test.js
new file mode 100644
index 000000000..458e9b4b5
--- /dev/null
+++ b/test/unit/migrations/021-test.js
@@ -0,0 +1,16 @@
+const assert = require('assert')
+
+const wallet2 = require('../../lib/migrations/002.json')
+const migration21 = require('../../../app/scripts/migrations/021')
+
+describe('wallet2 is migrated successfully with out the BlacklistController', () => {
+ it('should delete BlacklistController key', (done) => {
+ migration21.migrate(wallet2)
+ .then((migratedData) => {
+ assert.equal(migratedData.meta.version, 21)
+ assert(!migratedData.data.BlacklistController)
+ assert(!migratedData.data.RecentBlocks)
+ done()
+ }).catch(done)
+ })
+})
diff --git a/test/unit/tx-state-manager-test.js b/test/unit/tx-state-manager-test.js
index 464e50ee4..02dc52967 100644
--- a/test/unit/tx-state-manager-test.js
+++ b/test/unit/tx-state-manager-test.js
@@ -238,4 +238,47 @@ describe('TransactionStateManger', function () {
assert.equal(txStateManager.getFilteredTxList(filterParams).length, 5, `getFilteredTxList - ${JSON.stringify(filterParams)}`)
})
})
+
+ describe('#wipeTransactions', function () {
+
+ const specificAddress = '0xaa'
+ const otherAddress = '0xbb'
+
+ it('should remove only the transactions from a specific address', function () {
+
+ const txMetas = [
+ { id: 0, status: 'unapproved', txParams: { from: specificAddress, to: otherAddress }, metamaskNetworkId: currentNetworkId },
+ { id: 1, status: 'confirmed', txParams: { from: otherAddress, to: specificAddress }, metamaskNetworkId: currentNetworkId },
+ { id: 2, status: 'confirmed', txParams: { from: otherAddress, to: specificAddress }, metamaskNetworkId: currentNetworkId },
+ ]
+ txMetas.forEach((txMeta) => txStateManager.addTx(txMeta, noop))
+
+ txStateManager.wipeTransactions(specificAddress)
+
+ const transactionsFromCurrentAddress = txStateManager.getTxList().filter((txMeta) => txMeta.txParams.from === specificAddress)
+ const transactionsFromOtherAddresses = txStateManager.getTxList().filter((txMeta) => txMeta.txParams.from !== specificAddress)
+
+ assert.equal(transactionsFromCurrentAddress.length, 0)
+ assert.equal(transactionsFromOtherAddresses.length, 2)
+ })
+
+ it('should not remove the transactions from other networks', function () {
+ const txMetas = [
+ { id: 0, status: 'unapproved', txParams: { from: specificAddress, to: otherAddress }, metamaskNetworkId: currentNetworkId },
+ { id: 1, status: 'confirmed', txParams: { from: specificAddress, to: otherAddress }, metamaskNetworkId: otherNetworkId },
+ { id: 2, status: 'confirmed', txParams: { from: specificAddress, to: otherAddress }, metamaskNetworkId: otherNetworkId },
+ ]
+
+ txMetas.forEach((txMeta) => txStateManager.addTx(txMeta, noop))
+
+ txStateManager.wipeTransactions(specificAddress)
+
+ const txsFromCurrentNetworkAndAddress = txStateManager.getTxList().filter((txMeta) => txMeta.txParams.from === specificAddress)
+ const txFromOtherNetworks = txStateManager.getFullTxList().filter((txMeta) => txMeta.metamaskNetworkId === otherNetworkId)
+
+ assert.equal(txsFromCurrentNetworkAndAddress.length, 0)
+ assert.equal(txFromOtherNetworks.length, 2)
+
+ })
+ })
}) \ No newline at end of file
diff --git a/test/unit/ui/add-token.spec.js b/test/unit/ui/add-token.spec.js
new file mode 100644
index 000000000..69b7fb620
--- /dev/null
+++ b/test/unit/ui/add-token.spec.js
@@ -0,0 +1,43 @@
+const assert = require('assert')
+const { createMockStore } = require('redux-test-utils')
+const h = require('react-hyperscript')
+const { shallowWithStore } = require('../../lib/shallow-with-store')
+const AddTokenScreen = require('../../../old-ui/app/add-token')
+
+describe('Add Token Screen', function () {
+ let addTokenComponent, store, component
+ const mockState = {
+ metamask: {
+ identities: {
+ '0x7d3517b0d011698406d6e0aed8453f0be2697926': {
+ 'address': '0x7d3517b0d011698406d6e0aed8453f0be2697926',
+ 'name': 'Add Token Name',
+ },
+ },
+ },
+ }
+ beforeEach(function () {
+ store = createMockStore(mockState)
+ component = shallowWithStore(h(AddTokenScreen), store)
+ addTokenComponent = component.dive()
+ })
+
+ describe('#ValidateInputs', function () {
+
+ it('Default State', function () {
+ addTokenComponent.instance().validateInputs()
+ const state = addTokenComponent.state()
+ assert.equal(state.warning, 'Address is invalid.')
+ })
+
+ it('Address is a Metamask Identity', function () {
+ addTokenComponent.setState({
+ address: '0x7d3517b0d011698406d6e0aed8453f0be2697926',
+ })
+ addTokenComponent.instance().validateInputs()
+ const state = addTokenComponent.state()
+ assert.equal(state.warning, 'Personal address detected. Input the token contract address.')
+ })
+
+ })
+})
diff --git a/ui/app/accounts/import/json.js b/ui/app/accounts/import/json.js
index 9cefcfa77..dd5dfad22 100644
--- a/ui/app/accounts/import/json.js
+++ b/ui/app/accounts/import/json.js
@@ -81,6 +81,12 @@ JsonImportSubview.prototype.createKeyringOnEnter = function (event) {
JsonImportSubview.prototype.createNewKeychain = function () {
const state = this.state
+
+ if (!state) {
+ const message = 'You must select a valid file to import.'
+ return this.props.dispatch(actions.displayWarning(message))
+ }
+
const { fileContents } = state
if (!fileContents) {
diff --git a/ui/app/actions.js b/ui/app/actions.js
index c52b3cf93..4bc1f379e 100644
--- a/ui/app/actions.js
+++ b/ui/app/actions.js
@@ -47,6 +47,8 @@ var actions = {
SHOW_RESTORE_VAULT: 'SHOW_RESTORE_VAULT',
FORGOT_PASSWORD: 'FORGOT_PASSWORD',
forgotPassword: forgotPassword,
+ markPasswordForgotten,
+ unMarkPasswordForgotten,
SHOW_INIT_MENU: 'SHOW_INIT_MENU',
SHOW_NEW_VAULT_SEED: 'SHOW_NEW_VAULT_SEED',
SHOW_INFO_PAGE: 'SHOW_INFO_PAGE',
@@ -70,12 +72,14 @@ var actions = {
addNewAccount,
NEW_ACCOUNT_SCREEN: 'NEW_ACCOUNT_SCREEN',
navigateToNewAccountScreen,
+ resetAccount,
showNewVaultSeed: showNewVaultSeed,
showInfoPage: showInfoPage,
// seed recovery actions
REVEAL_SEED_CONFIRMATION: 'REVEAL_SEED_CONFIRMATION',
revealSeedConfirmation: revealSeedConfirmation,
requestRevealSeed: requestRevealSeed,
+
// unlock screen
UNLOCK_IN_PROGRESS: 'UNLOCK_IN_PROGRESS',
UNLOCK_FAILED: 'UNLOCK_FAILED',
@@ -253,6 +257,9 @@ var actions = {
updateFeatureFlags,
UPDATE_FEATURE_FLAGS: 'UPDATE_FEATURE_FLAGS',
+ setMouseUserState,
+ SET_MOUSE_USER_STATE: 'SET_MOUSE_USER_STATE',
+
// Network
setNetworkEndpoints,
updateNetworkEndpointType,
@@ -399,6 +406,20 @@ function requestRevealSeed (password) {
}
}
+function resetAccount () {
+ return (dispatch) => {
+ background.resetAccount((err, account) => {
+ dispatch(actions.hideLoadingIndication())
+ if (err) {
+ dispatch(actions.displayWarning(err.message))
+ }
+
+ log.info('Transaction history reset for ' + account)
+ dispatch(actions.showAccountsPage())
+ })
+ }
+}
+
function addNewKeyring (type, opts) {
return (dispatch) => {
dispatch(actions.showLoadingIndication())
@@ -819,6 +840,26 @@ function showRestoreVault () {
}
}
+function markPasswordForgotten () {
+ return (dispatch) => {
+ return background.markPasswordForgotten(() => {
+ dispatch(actions.hideLoadingIndication())
+ dispatch(actions.forgotPassword())
+ forceUpdateMetamaskState(dispatch)
+ })
+ }
+}
+
+function unMarkPasswordForgotten () {
+ return (dispatch) => {
+ return background.unMarkPasswordForgotten(() => {
+ dispatch(actions.hideLoadingIndication())
+ dispatch(actions.forgotPassword())
+ forceUpdateMetamaskState(dispatch)
+ })
+ }
+}
+
function forgotPassword () {
return {
type: actions.FORGOT_PASSWORD,
@@ -1621,6 +1662,13 @@ function updateFeatureFlags (updatedFeatureFlags) {
}
}
+function setMouseUserState (isMouseUser) {
+ return {
+ type: actions.SET_MOUSE_USER_STATE,
+ value: isMouseUser,
+ }
+}
+
// Call Background Then Update
//
// A function generator for a common pattern wherein:
diff --git a/ui/app/app.js b/ui/app/app.js
index df9eab03c..5ffd263d1 100644
--- a/ui/app/app.js
+++ b/ui/app/app.js
@@ -9,7 +9,7 @@ const classnames = require('classnames')
const MascaraFirstTime = require('../../mascara/src/app/first-time').default
const MascaraBuyEtherScreen = require('../../mascara/src/app/first-time/buy-ether-screen').default
// init
-const InitializeMenuScreen = require('./first-time/init-menu')
+const InitializeMenuScreen = MascaraFirstTime
const NewKeyChainScreen = require('./new-keychain')
// accounts
const MainContainer = require('./main-container')
@@ -74,17 +74,20 @@ function mapStateToProps (state) {
transForward: state.appState.transForward,
isMascara: state.metamask.isMascara,
isOnboarding: Boolean(!noActiveNotices || seedWords || !isInitialized),
+ isPopup: state.metamask.isPopup,
seedWords: state.metamask.seedWords,
unapprovedTxs: state.metamask.unapprovedTxs,
unapprovedMsgs: state.metamask.unapprovedMsgs,
menuOpen: state.appState.menuOpen,
network: state.metamask.network,
provider: state.metamask.provider,
- forgottenPassword: state.appState.forgottenPassword,
+ forgottenPassword: state.metamask.forgottenPassword,
lastUnreadNotice: state.metamask.lastUnreadNotice,
lostAccounts: state.metamask.lostAccounts,
frequentRpcList: state.metamask.frequentRpcList || [],
currentCurrency: state.metamask.currentCurrency,
+ isMouseUser: state.appState.isMouseUser,
+ betaUI: state.metamask.featureFlags.betaUI,
// state needed to get account dropdown temporarily rendering from app bar
identities,
@@ -101,6 +104,7 @@ function mapDispatchToProps (dispatch, ownProps) {
hideNetworkDropdown: () => dispatch(actions.hideNetworkDropdown()),
setCurrentCurrencyToUSD: () => dispatch(actions.setCurrentCurrency('usd')),
toggleAccountMenu: () => dispatch(actions.toggleAccountMenu()),
+ setMouseUserState: (isMouseUser) => dispatch(actions.setMouseUserState(isMouseUser)),
}
}
@@ -112,7 +116,13 @@ App.prototype.componentWillMount = function () {
App.prototype.render = function () {
var props = this.props
- const { isLoading, loadingMessage, network } = props
+ const {
+ isLoading,
+ loadingMessage,
+ network,
+ isMouseUser,
+ setMouseUserState,
+ } = props
const isLoadingNetwork = network === 'loading' && props.currentView.name !== 'config'
const loadMessage = loadingMessage || isLoadingNetwork ?
`Connecting to ${this.getNetworkName()}` : null
@@ -120,11 +130,19 @@ App.prototype.render = function () {
return (
h('.flex-column.full-height', {
+ className: classnames({ 'mouse-user-styles': isMouseUser }),
style: {
overflowX: 'hidden',
position: 'relative',
alignItems: 'center',
},
+ tabIndex: '0',
+ onClick: () => setMouseUserState(true),
+ onKeyDown: (e) => {
+ if (e.keyCode === 9) {
+ setMouseUserState(false)
+ }
+ },
}, [
// global modal
@@ -335,9 +353,9 @@ App.prototype.renderBackButton = function (style, justArrow = false) {
App.prototype.renderPrimary = function () {
log.debug('rendering primary')
var props = this.props
- const {isMascara, isOnboarding} = props
+ const {isMascara, isOnboarding, betaUI} = props
- if (isMascara && isOnboarding) {
+ if ((isMascara || betaUI) && isOnboarding && !props.isPopup) {
return h(MascaraFirstTime)
}
@@ -358,20 +376,12 @@ App.prototype.renderPrimary = function () {
})
}
- // show initialize screen
- if (!props.isInitialized || props.forgottenPassword) {
- // show current view
- log.debug('rendering an initialize screen')
- switch (props.currentView.name) {
-
- case 'restoreVault':
- log.debug('rendering restore vault screen')
- return h(HDRestoreVaultScreen, {key: 'HDRestoreVaultScreen'})
-
- default:
- log.debug('rendering menu screen')
- return h(InitializeMenuScreen, {key: 'menuScreenInit'})
- }
+ if (props.isInitialized && props.forgottenPassword) {
+ log.debug('rendering restore vault screen')
+ return h(HDRestoreVaultScreen, {key: 'HDRestoreVaultScreen'})
+ } else if (!props.isInitialized) {
+ log.debug('rendering menu screen')
+ return h(InitializeMenuScreen, {key: 'menuScreenInit'})
}
// show unlock screen
diff --git a/ui/app/components/account-menu/index.js b/ui/app/components/account-menu/index.js
index aeb8a0b38..1a0103d4f 100644
--- a/ui/app/components/account-menu/index.js
+++ b/ui/app/components/account-menu/index.js
@@ -80,23 +80,23 @@ AccountMenu.prototype.render = function () {
h(Divider),
h(Item, {
onClick: () => showNewAccountPage('CREATE'),
- icon: h('img', { src: 'images/plus-btn-white.svg' }),
+ icon: h('img.account-menu__item-icon', { src: 'images/plus-btn-white.svg' }),
text: 'Create Account',
}),
h(Item, {
onClick: () => showNewAccountPage('IMPORT'),
- icon: h('img', { src: 'images/import-account.svg' }),
+ icon: h('img.account-menu__item-icon', { src: 'images/import-account.svg' }),
text: 'Import Account',
}),
h(Divider),
h(Item, {
onClick: showInfoPage,
- icon: h('img', { src: 'images/mm-info-icon.svg' }),
+ icon: h('img.account-menu__item-icon', { src: 'images/mm-info-icon.svg' }),
text: 'Info & Help',
}),
h(Item, {
onClick: showConfigPage,
- icon: h('img', { src: 'images/settings.svg' }),
+ icon: h('img.account-menu__item-icon', { src: 'images/settings.svg' }),
text: 'Settings',
}),
])
diff --git a/ui/app/components/modals/modal.js b/ui/app/components/modals/modal.js
index afb2a2175..97fe38292 100644
--- a/ui/app/components/modals/modal.js
+++ b/ui/app/components/modals/modal.js
@@ -18,6 +18,7 @@ const ShapeshiftDepositTxModal = require('./shapeshift-deposit-tx-modal.js')
const HideTokenConfirmationModal = require('./hide-token-confirmation-modal')
const CustomizeGasModal = require('../customize-gas-modal')
const NotifcationModal = require('./notification-modal')
+const ConfirmResetAccount = require('./notification-modals/confirm-reset-account')
const accountModalStyle = {
mobileModalStyle: {
@@ -202,6 +203,18 @@ const MODALS = {
},
},
+ CONFIRM_RESET_ACCOUNT: {
+ contents: h(ConfirmResetAccount),
+ mobileModalStyle: {
+ width: '95%',
+ top: isPopupOrNotification() === 'popup' ? '52vh' : '36.5vh',
+ },
+ laptopModalStyle: {
+ width: '473px',
+ top: 'calc(33% + 45px)',
+ },
+ },
+
NEW_ACCOUNT: {
contents: [
h(NewAccountModal, {}, []),
diff --git a/ui/app/components/modals/notification-modal.js b/ui/app/components/modals/notification-modal.js
index 239144b0c..621a974d0 100644
--- a/ui/app/components/modals/notification-modal.js
+++ b/ui/app/components/modals/notification-modal.js
@@ -9,26 +9,47 @@ class NotificationModal extends Component {
const {
header,
message,
+ showCancelButton = false,
+ showConfirmButton = false,
+ hideModal,
+ onConfirm,
} = this.props
+ const showButtons = showCancelButton || showConfirmButton
+
return h('div', [
- h('div.notification-modal-wrapper', {
+ h('div.notification-modal__wrapper', {
}, [
- h('div.notification-modal-header', {}, [
+ h('div.notification-modal__header', {}, [
header,
]),
- h('div.notification-modal-message-wrapper', {}, [
- h('div.notification-modal-message', {}, [
+ h('div.notification-modal__message-wrapper', {}, [
+ h('div.notification-modal__message', {}, [
message,
]),
]),
h('div.modal-close-x', {
- onClick: this.props.hideModal,
+ onClick: hideModal,
}),
+ showButtons && h('div.notification-modal__buttons', [
+
+ showCancelButton && h('div.btn-cancel.notification-modal__buttons__btn', {
+ onClick: hideModal,
+ }, 'Cancel'),
+
+ showConfirmButton && h('div.btn-clear.notification-modal__buttons__btn', {
+ onClick: () => {
+ onConfirm()
+ hideModal()
+ },
+ }, 'Confirm'),
+
+ ]),
+
]),
])
}
@@ -37,7 +58,10 @@ class NotificationModal extends Component {
NotificationModal.propTypes = {
hideModal: PropTypes.func,
header: PropTypes.string,
- message: PropTypes.string,
+ message: PropTypes.node,
+ showCancelButton: PropTypes.bool,
+ showConfirmButton: PropTypes.bool,
+ onConfirm: PropTypes.func,
}
const mapDispatchToProps = dispatch => {
diff --git a/ui/app/components/modals/notification-modals/confirm-reset-account.js b/ui/app/components/modals/notification-modals/confirm-reset-account.js
new file mode 100644
index 000000000..e1bc91b24
--- /dev/null
+++ b/ui/app/components/modals/notification-modals/confirm-reset-account.js
@@ -0,0 +1,46 @@
+const { Component } = require('react')
+const PropTypes = require('prop-types')
+const h = require('react-hyperscript')
+const { connect } = require('react-redux')
+const actions = require('../../../actions')
+const NotifcationModal = require('../notification-modal')
+
+class ConfirmResetAccount extends Component {
+ render () {
+ const { resetAccount } = this.props
+
+ return h(NotifcationModal, {
+ header: 'Are you sure you want to reset account?',
+ message: h('div', [
+
+ h('span', `Resetting is for developer use only. This button wipes the current account's transaction history,
+ which is used to calculate the current account nonce. `),
+
+ h('a.notification-modal__link', {
+ href: 'http://metamask.helpscoutdocs.com/article/36-resetting-an-account',
+ target: '_blank',
+ onClick (event) { global.platform.openWindow({ url: event.target.href }) },
+ }, 'Read more.'),
+
+ ]),
+ showCancelButton: true,
+ showConfirmButton: true,
+ onConfirm: resetAccount,
+
+ })
+ }
+}
+
+ConfirmResetAccount.propTypes = {
+ resetAccount: PropTypes.func,
+}
+
+const mapDispatchToProps = dispatch => {
+ return {
+ resetAccount: () => {
+ dispatch(actions.resetAccount())
+ },
+ }
+}
+
+module.exports = connect(null, mapDispatchToProps)(ConfirmResetAccount)
diff --git a/ui/app/components/pending-tx/confirm-send-ether.js b/ui/app/components/pending-tx/confirm-send-ether.js
index 652300c94..3f8d9c28f 100644
--- a/ui/app/components/pending-tx/confirm-send-ether.js
+++ b/ui/app/components/pending-tx/confirm-send-ether.js
@@ -213,17 +213,15 @@ ConfirmSendEther.prototype.render = function () {
this.inputs = []
return (
- h('div.confirm-screen-container.confirm-send-ether', {
- style: { minWidth: '355px' },
- }, [
+ h('div.confirm-screen-container.confirm-send-ether', [
// Main Send token Card
- h('div.confirm-screen-wrapper.flex-column.flex-grow', [
- h('h3.flex-center.confirm-screen-header', [
- h('button.btn-clear.confirm-screen-back-button', {
+ h('div.page-container', [
+ h('div.page-container__header', [
+ h('button.confirm-screen-back-button', {
onClick: () => editTransaction(txMeta),
- }, 'EDIT'),
- h('div.confirm-screen-title', 'Confirm Transaction'),
- h('div.confirm-screen-header-tip'),
+ }, 'Edit'),
+ h('div.page-container__title', 'Confirm'),
+ h('div.page-container__subtitle', `Please review your transaction.`),
]),
h('div.flex-row.flex-center.confirm-screen-identicons', [
h('div.confirm-screen-account-wrapper', [
diff --git a/ui/app/components/pending-tx/confirm-send-token.js b/ui/app/components/pending-tx/confirm-send-token.js
index ad489c3e9..e4b0c186a 100644
--- a/ui/app/components/pending-tx/confirm-send-token.js
+++ b/ui/app/components/pending-tx/confirm-send-token.js
@@ -308,17 +308,15 @@ ConfirmSendToken.prototype.render = function () {
this.inputs = []
return (
- h('div.confirm-screen-container.confirm-send-token', {
- style: { minWidth: '355px' },
- }, [
+ h('div.confirm-screen-container.confirm-send-token', [
// Main Send token Card
- h('div.confirm-screen-wrapper.flex-column.flex-grow', [
- h('h3.flex-center.confirm-screen-header', [
- h('button.btn-clear.confirm-screen-back-button', {
+ h('div.page-container', [
+ h('div.page-container__header', [
+ h('button.confirm-screen-back-button', {
onClick: () => editTransaction(txMeta),
- }, 'EDIT'),
- h('div.confirm-screen-title', 'Confirm Transaction'),
- h('div.confirm-screen-header-tip'),
+ }, 'Edit'),
+ h('div.page-container__title', 'Confirm'),
+ h('div.page-container__subtitle', `Please review your transaction.`),
]),
h('div.flex-row.flex-center.confirm-screen-identicons', [
h('div.confirm-screen-account-wrapper', [
diff --git a/ui/app/components/shift-list-item.js b/ui/app/components/shift-list-item.js
index 111a77df4..017bf9f0c 100644
--- a/ui/app/components/shift-list-item.js
+++ b/ui/app/components/shift-list-item.js
@@ -29,40 +29,35 @@ function ShiftListItem () {
}
ShiftListItem.prototype.render = function () {
- const { selectedAddress, receivingAddress } = this.props
- return (
- selectedAddress === receivingAddress
- ? h('div.tx-list-item.tx-list-clickable', {
+ return h('div.tx-list-item.tx-list-clickable', {
+ style: {
+ paddingTop: '20px',
+ paddingBottom: '20px',
+ justifyContent: 'space-around',
+ alignItems: 'center',
+ },
+ }, [
+ h('div', {
+ style: {
+ width: '0px',
+ position: 'relative',
+ bottom: '19px',
+ },
+ }, [
+ h('img', {
+ src: 'https://info.shapeshift.io/sites/default/files/logo.png',
style: {
- paddingTop: '20px',
- paddingBottom: '20px',
- justifyContent: 'space-around',
- alignItems: 'center',
+ height: '35px',
+ width: '132px',
+ position: 'absolute',
+ clip: 'rect(0px,23px,34px,0px)',
},
- }, [
- h('div', {
- style: {
- width: '0px',
- position: 'relative',
- bottom: '19px',
- },
- }, [
- h('img', {
- src: 'https://info.shapeshift.io/sites/default/files/logo.png',
- style: {
- height: '35px',
- width: '132px',
- position: 'absolute',
- clip: 'rect(0px,23px,34px,0px)',
- },
- }),
- ]),
+ }),
+ ]),
- this.renderInfo(),
- this.renderUtilComponents(),
- ])
- : null
- )
+ this.renderInfo(),
+ this.renderUtilComponents(),
+ ])
}
function formatDate (date) {
diff --git a/ui/app/components/token-cell.js b/ui/app/components/token-cell.js
index 677f22a75..0332fde88 100644
--- a/ui/app/components/token-cell.js
+++ b/ui/app/components/token-cell.js
@@ -111,7 +111,7 @@ TokenCell.prototype.render = function () {
network,
}),
- h('div.token-list-item__balance-wrapper', null, [
+ h('div.token-list-item__balance-ellipsis', null, [
h('div.token-list-item__balance-wrapper', null, [
h('h3.token-list-item__token-balance', `${string || 0} ${symbol}`),
diff --git a/ui/app/components/tx-list.js b/ui/app/components/tx-list.js
index 84cd0f093..1729e6a6f 100644
--- a/ui/app/components/tx-list.js
+++ b/ui/app/components/tx-list.js
@@ -50,6 +50,7 @@ TxList.prototype.render = function () {
TxList.prototype.renderTransaction = function () {
const { txsToRender, conversionRate } = this.props
+
return txsToRender.length
? txsToRender.map((transaction, i) => this.renderTransactionListItem(transaction, conversionRate, i))
: [h(
@@ -65,11 +66,7 @@ TxList.prototype.renderTransactionListItem = function (transaction, conversionRa
// refer to transaction-list.js:line 58
if (transaction.key === 'shapeshift') {
- return h('div', {
- key: `shapeshift${index}`,
- }, [
- h(ShiftListItem, transaction),
- ])
+ return h(ShiftListItem, { ...transaction, key: `shapeshift${index}` })
}
const props = {
diff --git a/ui/app/css/itcss/base/index.scss b/ui/app/css/itcss/base/index.scss
index baa6ea037..1475e8bb5 100644
--- a/ui/app/css/itcss/base/index.scss
+++ b/ui/app/css/itcss/base/index.scss
@@ -1 +1,7 @@
// Base
+
+.mouse-user-styles {
+ button:focus {
+ outline: 0;
+ }
+}
diff --git a/ui/app/css/itcss/components/account-menu.scss b/ui/app/css/itcss/components/account-menu.scss
index e16d2e024..8ad7481c7 100644
--- a/ui/app/css/itcss/components/account-menu.scss
+++ b/ui/app/css/itcss/components/account-menu.scss
@@ -43,7 +43,7 @@
font-weight: 300;
}
- img {
+ &__item-icon {
width: 16px;
height: 16px;
}
diff --git a/ui/app/css/itcss/components/confirm.scss b/ui/app/css/itcss/components/confirm.scss
index 255f66e66..878495290 100644
--- a/ui/app/css/itcss/components/confirm.scss
+++ b/ui/app/css/itcss/components/confirm.scss
@@ -103,15 +103,13 @@
}
.confirm-screen-back-button {
- background: transparent;
- left: 24px;
+ color: $curious-blue;
+ font-family: Roboto;
+ font-size: 1rem;
position: absolute;
- padding: 6px 12px;
- font-size: .7rem;
-
- @media screen and (max-width: $break-small) {
- margin-right: 12px;
- }
+ top: 38px;
+ right: 38px;
+ background: none;
}
.confirm-screen-account-wrapper {
diff --git a/ui/app/css/itcss/components/currency-display.scss b/ui/app/css/itcss/components/currency-display.scss
index 9459629b6..e043c1966 100644
--- a/ui/app/css/itcss/components/currency-display.scss
+++ b/ui/app/css/itcss/components/currency-display.scss
@@ -4,7 +4,7 @@
border: 1px solid $alto;
border-radius: 4px;
background-color: $white;
- color: $dusty-gray;
+ color: $scorpion;
font-family: Roboto;
font-size: 16px;
font-weight: 300;
@@ -52,5 +52,6 @@
&__currency-symbol {
margin-top: 1px;
+ color: $scorpion;
}
} \ No newline at end of file
diff --git a/ui/app/css/itcss/components/modal.scss b/ui/app/css/itcss/components/modal.scss
index 5bca4a07d..919e1793b 100644
--- a/ui/app/css/itcss/components/modal.scss
+++ b/ui/app/css/itcss/components/modal.scss
@@ -547,38 +547,54 @@
//Notification Modal
-.notification-modal-wrapper {
- display: flex;
- flex-direction: column;
- justify-content: flex-start;
- align-items: center;
- position: relative;
- border: 1px solid $alto;
- box-shadow: 0 0 2px 2px $alto;
- font-family: Roboto;
-}
+.notification-modal {
-.notification-modal-header {
- background: $wild-sand;
- width: 100%;
- display: flex;
- justify-content: center;
- padding: 30px;
- font-size: 22px;
- color: $nile-blue;
- height: 79px;
-}
+ &__wrapper {
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-start;
+ align-items: center;
+ position: relative;
+ border: 1px solid $alto;
+ box-shadow: 0 0 2px 2px $alto;
+ font-family: Roboto;
+ }
-.notification-modal-message {
- padding: 20px;
-}
+ &__header {
+ background: $wild-sand;
+ width: 100%;
+ display: flex;
+ justify-content: center;
+ padding: 30px;
+ font-size: 22px;
+ color: $nile-blue;
+ height: 79px;
+ }
-.notification-modal-message {
- width: 100%;
- display: flex;
- justify-content: center;
- font-size: 17px;
- color: $nile-blue;
+ &__message {
+ padding: 20px;
+ width: 100%;
+ display: flex;
+ justify-content: center;
+ font-size: 17px;
+ color: $nile-blue;
+ }
+
+ &__buttons {
+ display: flex;
+ justify-content: space-evenly;
+ width: 100%;
+ margin-bottom: 24px;
+ padding: 0px 42px;
+
+ &__btn {
+ cursor: pointer;
+ }
+ }
+
+ &__link {
+ color: $curious-blue;
+ }
}
// Deposit Ether Modal
diff --git a/ui/app/css/itcss/components/newui-sections.scss b/ui/app/css/itcss/components/newui-sections.scss
index a5e4523b9..73faebe8b 100644
--- a/ui/app/css/itcss/components/newui-sections.scss
+++ b/ui/app/css/itcss/components/newui-sections.scss
@@ -105,6 +105,7 @@ $wallet-view-bg: $alabaster;
&__tooltip {
display: flex;
justify-content: center;
+ align-items: center;
padding: 24px;
}
diff --git a/ui/app/css/itcss/components/send.scss b/ui/app/css/itcss/components/send.scss
index 7a6e2823b..bb17e53cd 100644
--- a/ui/app/css/itcss/components/send.scss
+++ b/ui/app/css/itcss/components/send.scss
@@ -533,7 +533,6 @@
@media screen and (max-width: $break-small) {
padding: 13px 0;
margin: 0;
- height: 0;
overflow-y: auto;
flex: 1 1 auto;
}
@@ -558,6 +557,25 @@
&__form-field {
flex: 1 1 auto;
+
+ .currency-display {
+ color: $tundora;
+
+ &__currency-symbol {
+ color: $tundora;
+ }
+
+ &__converted-value,
+ &__converted-currency {
+ color: $tundora;
+ }
+ }
+
+ .account-list-item {
+ &__account-secondary-balance {
+ color: $tundora;
+ }
+ }
}
&__form-label {
@@ -566,6 +584,7 @@
font-size: 16px;
line-height: 22px;
width: 88px;
+ font-weight: 400;
}
&__from-dropdown {
@@ -621,7 +640,7 @@
border: 1px solid $alto;
border-radius: 4px;
background-color: $white;
- color: $dusty-gray;
+ color: $tundora;
padding: 10px;
font-family: Roboto;
font-size: 16px;
diff --git a/ui/app/css/itcss/components/token-list.scss b/ui/app/css/itcss/components/token-list.scss
index e90418c97..9dc4f1055 100644
--- a/ui/app/css/itcss/components/token-list.scss
+++ b/ui/app/css/itcss/components/token-list.scss
@@ -51,7 +51,7 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and (
&__balance-ellipsis {
display: flex;
align-items: center;
- justify-content: space-around;
+ width: 100%;
}
&__ellipsis {
diff --git a/ui/app/css/itcss/generic/index.scss b/ui/app/css/itcss/generic/index.scss
index 9d55324e3..9b3d7475b 100644
--- a/ui/app/css/itcss/generic/index.scss
+++ b/ui/app/css/itcss/generic/index.scss
@@ -69,3 +69,136 @@ textarea.large-input {
input.large-input {
height: 36px;
}
+
+.page-container {
+ width: 400px;
+ background-color: $white;
+ box-shadow: 0 0 7px 0 rgba(0, 0, 0, .08);
+ z-index: 25;
+ display: flex;
+ flex-flow: column;
+
+ &__header {
+ display: flex;
+ flex-flow: column;
+ border-bottom: 1px solid $geyser;
+ padding: 1.15rem 0.95rem;
+ flex: 0 0 auto;
+ background: $alabaster;
+ position: relative;
+ }
+
+ &__header-close::after {
+ content: '\00D7';
+ font-size: 40px;
+ color: $tundora;
+ position: absolute;
+ top: 21.5px;
+ right: 28.5px;
+ cursor: pointer;
+ }
+
+ &__footer {
+ display: flex;
+ flex-flow: row;
+ justify-content: center;
+ border-top: 1px solid $geyser;
+ padding: 1.6rem;
+ flex: 0 0 auto;
+
+ .btn-clear,
+ .btn-cancel {
+ font-size: 1rem;
+ }
+ }
+
+ &__footer-button {
+ width: 165px;
+ height: 60px;
+ font-size: 1rem;
+ text-transform: uppercase;
+ margin-right: 1rem;
+ border-radius: 2px;
+
+ &:last-of-type {
+ margin-right: 0;
+ }
+ }
+
+ &__title {
+ color: $black;
+ font-family: Roboto;
+ font-size: 2rem;
+ font-weight: 500;
+ line-height: initial;
+ }
+
+ &__subtitle {
+ padding-top: .5rem;
+ line-height: initial;
+ font-size: .9rem;
+ color: $gray;
+ }
+
+ &__tabs {
+ padding: 0 1.3rem;
+ display: flex;
+ }
+
+ &__tab {
+ min-width: 5rem;
+ padding: .2rem .8rem .9rem;
+ color: $dusty-gray;
+ font-family: Roboto;
+ font-size: 1.1rem;
+ line-height: initial;
+ text-align: center;
+ cursor: pointer;
+ border-bottom: none;
+ margin-right: 1rem;
+
+ &:hover {
+ color: $black;
+ }
+
+ &:last-of-type {
+ margin-right: 0;
+ }
+
+ &--selected {
+ color: $curious-blue;
+ border-bottom: 3px solid $curious-blue;
+
+ &:hover {
+ color: $curious-blue;
+ }
+ }
+ }
+}
+
+@media screen and (max-width: 250px) {
+ .page-container {
+ &__footer {
+ flex-flow: column-reverse;
+ }
+
+ &__footer-button {
+ width: 100%;
+ margin-bottom: 1rem;
+ margin-right: 0;
+
+ &:first-of-type {
+ margin-bottom: 0;
+ }
+ }
+ }
+}
+
+@media screen and (max-width: 575px) {
+ .page-container {
+ height: 100%;
+ width: 100%;
+ overflow-y: auto;
+ background-color: $white;
+ }
+}
diff --git a/ui/app/keychains/hd/restore-vault.js b/ui/app/keychains/hd/restore-vault.js
index 24b37a83d..a4ed137f9 100644
--- a/ui/app/keychains/hd/restore-vault.js
+++ b/ui/app/keychains/hd/restore-vault.js
@@ -107,6 +107,7 @@ RestoreVaultScreen.prototype.render = function () {
}
RestoreVaultScreen.prototype.showInitializeMenu = function () {
+ this.props.dispatch(actions.unMarkPasswordForgotten())
if (this.props.forgottenPassword) {
this.props.dispatch(actions.backToUnlockView())
} else {
@@ -149,6 +150,9 @@ RestoreVaultScreen.prototype.createNewVaultAndRestore = function () {
this.warning = null
this.props.dispatch(actions.displayWarning(this.warning))
this.props.dispatch(actions.createNewVaultAndRestore(password, seed))
+ .then(() => {
+ this.props.dispatch(actions.unMarkPasswordForgotten())
+ })
.catch((err) => {
log.error(err.message)
})
diff --git a/ui/app/main-container.js b/ui/app/main-container.js
index 031f61e84..292abcc3d 100644
--- a/ui/app/main-container.js
+++ b/ui/app/main-container.js
@@ -2,7 +2,6 @@ const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const AccountAndTransactionDetails = require('./account-and-transaction-details')
-const HDRestoreVaultScreen = require('./keychains/hd/restore-vault')
const Settings = require('./settings')
const UnlockScreen = require('./unlock')
@@ -28,13 +27,6 @@ MainContainer.prototype.render = function () {
if (this.props.isUnlocked === false) {
switch (this.props.currentViewName) {
- case 'restoreVault':
- log.debug('rendering restore vault screen')
- contents = {
- component: HDRestoreVaultScreen,
- key: 'HDRestoreVaultScreen',
- }
- break
case 'config':
log.debug('rendering config screen from unlock screen.')
return h(Settings, {key: 'config'})
diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js
index 6885d029a..02f024f7c 100644
--- a/ui/app/reducers/app.js
+++ b/ui/app/reducers/app.js
@@ -59,6 +59,7 @@ function reduceApp (state, action) {
// Used to display error text
warning: null,
buyView: {},
+ isMouseUser: false,
}, state.appState)
switch (action.type) {
@@ -658,6 +659,12 @@ function reduceApp (state, action) {
data: action.value.data,
},
})
+
+ case actions.SET_MOUSE_USER_STATE:
+ return extend(appState, {
+ isMouseUser: action.value,
+ })
+
default:
return appState
}
diff --git a/ui/app/reducers/metamask.js b/ui/app/reducers/metamask.js
index 294c29948..beeba948d 100644
--- a/ui/app/reducers/metamask.js
+++ b/ui/app/reducers/metamask.js
@@ -1,6 +1,7 @@
const extend = require('xtend')
const actions = require('../actions')
const MetamascaraPlatform = require('../../../app/scripts/platforms/window')
+const environmentType = require('../../../app/scripts/lib/environment-type')
const { OLD_UI_NETWORK_TYPE } = require('../../../app/scripts/config').enums
module.exports = reduceMetamask
@@ -14,6 +15,7 @@ function reduceMetamask (state, action) {
isUnlocked: false,
isAccountMenuOpen: false,
isMascara: window.platform instanceof MetamascaraPlatform,
+ isPopup: environmentType() === 'popup',
rpcTarget: 'https://rawtestrpc.metamask.io/',
identities: {},
unapprovedTxs: {},
diff --git a/ui/app/selectors.js b/ui/app/selectors.js
index 38a96c48b..5d2635775 100644
--- a/ui/app/selectors.js
+++ b/ui/app/selectors.js
@@ -116,7 +116,7 @@ function transactionsSelector (state) {
// console.log({txsToRender, selectedTokenAddress})
return selectedTokenAddress
? txsToRender
- .filter(({ txParams: { to } }) => to === selectedTokenAddress)
+ .filter(({ txParams }) => txParams && txParams.to === selectedTokenAddress)
.sort((a, b) => b.time - a.time)
: txsToRender
.sort((a, b) => b.time - a.time)
@@ -179,11 +179,11 @@ function autoAddToBetaUI (state) {
(numberOfAccounts > autoAddAccountsThreshold) &&
(numberOfTokensAdded > autoAddTokensThreshold)
const userIsNotInBeta = !state.metamask.featureFlags.betaUI
-
+
return userIsNotInBeta && userPassesThreshold
}
function getCurrentViewContext (state) {
const { currentView = {} } = state.appState
- return currentView.context
+ return currentView.context
} \ No newline at end of file
diff --git a/ui/app/send-v2.js b/ui/app/send-v2.js
index 897caf16e..1d67150e3 100644
--- a/ui/app/send-v2.js
+++ b/ui/app/send-v2.js
@@ -5,7 +5,6 @@ const h = require('react-hyperscript')
const ethAbi = require('ethereumjs-abi')
const ethUtil = require('ethereumjs-util')
-const Identicon = require('./components/identicon')
const FromDropdown = require('./components/send/from-dropdown')
const ToAutoComplete = require('./components/send/to-autocomplete')
const CurrencyDisplay = require('./components/send/currency-display')
@@ -179,52 +178,22 @@ SendTransactionScreen.prototype.componentDidUpdate = function (prevProps) {
}
}
-SendTransactionScreen.prototype.renderHeaderIcon = function () {
- const { selectedToken } = this.props
-
- return h('div.send-v2__send-header-icon-container', [
- selectedToken
- ? h(Identicon, {
- diameter: 40,
- address: selectedToken.address,
- })
- : h('img.send-v2__send-header-icon', { src: '../images/eth_logo.svg' }),
- ])
-}
-
-SendTransactionScreen.prototype.renderTitle = function () {
- const { selectedToken } = this.props
-
- return h('div.send-v2__title', [selectedToken ? 'Send Tokens' : 'Send Funds'])
-}
-
-SendTransactionScreen.prototype.renderCopy = function () {
- const { selectedToken } = this.props
-
- const tokenText = selectedToken ? 'tokens' : 'ETH'
-
- return h('div.send-v2__form-header-copy', [
-
- h('div.send-v2__copy', `Only send ${tokenText} to an Ethereum address.`),
-
- h('div.send-v2__copy', 'Sending to a different crytpocurrency that is not Ethereum may result in permanent loss.'),
-
- ])
-}
-
SendTransactionScreen.prototype.renderHeader = function () {
- return h('div', [
- h('div.send-v2__header', {}, [
+ const { selectedToken, clearSend, goHome } = this.props
+ const tokenText = selectedToken ? 'tokens' : 'ETH'
- this.renderHeaderIcon(),
+ return h('div.page-container__header', [
- h('div.send-v2__arrow-background', [
- h('i.fa.fa-lg.fa-arrow-circle-right.send-v2__send-arrow-icon'),
- ]),
+ h('div.page-container__title', selectedToken ? 'Send Tokens' : 'Send ETH'),
- h('div.send-v2__header-tip'),
+ h('div.page-container__subtitle', `Only send ${tokenText} to an Ethereum address.`),
- ]),
+ h('div.page-container__header-close', {
+ onClick: () => {
+ clearSend()
+ goHome()
+ },
+ }),
])
}
@@ -504,14 +473,6 @@ SendTransactionScreen.prototype.renderMemoRow = function () {
SendTransactionScreen.prototype.renderForm = function () {
return h('div.send-v2__form', {}, [
- h('div.sendV2__form-header', [
-
- this.renderTitle(),
-
- this.renderCopy(),
-
- ]),
-
this.renderFromRow(),
this.renderToRow(),
@@ -535,14 +496,14 @@ SendTransactionScreen.prototype.renderFooter = function () {
const noErrors = !amountError && toError === null
- return h('div.send-v2__footer', [
- h('button.btn-cancel.send-v2__cancel-btn', {
+ return h('div.page-container__footer', [
+ h('button.btn-cancel.page-container__footer-button', {
onClick: () => {
clearSend()
goHome()
},
}, 'Cancel'),
- h('button.btn-clear.send-v2__next-btn', {
+ h('button.btn-clear.page-container__footer-button', {
disabled: !noErrors || !gasTotal,
onClick: event => this.onSubmit(event),
}, 'Next'),
@@ -552,7 +513,7 @@ SendTransactionScreen.prototype.renderFooter = function () {
SendTransactionScreen.prototype.render = function () {
return (
- h('div.send-v2__container', [
+ h('div.page-container', [
this.renderHeader(),
diff --git a/ui/app/settings.js b/ui/app/settings.js
index 476bad296..988ddea8d 100644
--- a/ui/app/settings.js
+++ b/ui/app/settings.js
@@ -250,6 +250,24 @@ class Settings extends Component {
)
}
+ renderResetAccount () {
+ const { showResetAccountConfirmationModal } = this.props
+
+ return h('div.settings__content-row', [
+ h('div.settings__content-item', 'Reset Account'),
+ h('div.settings__content-item', [
+ h('div.settings__content-item-col', [
+ h('button.settings__clear-button.settings__clear-button--orange', {
+ onClick (event) {
+ event.preventDefault()
+ showResetAccountConfirmationModal()
+ },
+ }, 'Reset Account'),
+ ]),
+ ]),
+ ])
+ }
+
renderSettingsContent () {
const { warning, isMascara } = this.props
@@ -262,6 +280,7 @@ class Settings extends Component {
this.renderStateLogs(),
this.renderSeedWords(),
!isMascara && this.renderOldUI(),
+ this.renderResetAccount(),
this.renderBlockieOptIn(),
])
)
@@ -387,6 +406,7 @@ Settings.propTypes = {
displayWarning: PropTypes.func,
revealSeedConfirmation: PropTypes.func,
setFeatureFlagToBeta: PropTypes.func,
+ showResetAccountConfirmationModal: PropTypes.func,
warning: PropTypes.string,
goHome: PropTypes.func,
isMascara: PropTypes.bool,
@@ -412,6 +432,9 @@ const mapDispatchToProps = dispatch => {
return dispatch(actions.setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL'))
.then(() => dispatch(actions.setNetworkEndpoints(OLD_UI_NETWORK_TYPE)))
},
+ showResetAccountConfirmationModal: () => {
+ return dispatch(actions.showModal({ name: 'CONFIRM_RESET_ACCOUNT' }))
+ },
}
}
diff --git a/ui/app/unlock.js b/ui/app/unlock.js
index ec97b03bf..13c3f1274 100644
--- a/ui/app/unlock.js
+++ b/ui/app/unlock.js
@@ -5,6 +5,8 @@ const connect = require('react-redux').connect
const actions = require('./actions')
const getCaretCoordinates = require('textarea-caret')
const EventEmitter = require('events').EventEmitter
+const { OLD_UI_NETWORK_TYPE } = require('../../app/scripts/config').enums
+const environmentType = require('../../app/scripts/lib/environment-type')
const Mascot = require('./components/mascot')
@@ -74,7 +76,12 @@ UnlockScreen.prototype.render = function () {
h('.flex-row.flex-center.flex-grow', [
h('p.pointer', {
- onClick: () => this.props.dispatch(actions.forgotPassword()),
+ onClick: () => {
+ this.props.dispatch(actions.markPasswordForgotten())
+ if (environmentType() === 'popup') {
+ global.platform.openExtensionInBrowser()
+ }
+ },
style: {
fontSize: '0.8em',
color: 'rgb(247, 134, 28)',
@@ -82,6 +89,22 @@ UnlockScreen.prototype.render = function () {
},
}, 'Restore from seed phrase'),
]),
+
+ h('.flex-row.flex-center.flex-grow', [
+ h('p.pointer', {
+ onClick: () => {
+ this.props.dispatch(actions.setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL'))
+ .then(() => this.props.dispatch(actions.setNetworkEndpoints(OLD_UI_NETWORK_TYPE)))
+ },
+ style: {
+ fontSize: '0.8em',
+ color: '#aeaeae',
+ textDecoration: 'underline',
+ marginTop: '32px',
+ },
+ }, 'Use classic interface'),
+ ]),
+
])
)
}