From 6a7ea00cd34f83b257f6b4280a5f4e20aa5d34ee Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 6 Apr 2017 14:30:14 -0700 Subject: [PATCH 001/392] mascara deploy - improve deploy instructions --- Dockerfile | 5 ++++- mascara/README.md | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index d06f5377b..d79584c15 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,10 @@ WORKDIR /www/ # install dependencies COPY ./package.json /www/package.json -RUN npm install +# RUN npm install -g node-gyp +RUN npm install >> npm_log 2>> npm_err || true + +RUN cat npm_log && cat npm_err # copy over app dir COPY ./ /www/ diff --git a/mascara/README.md b/mascara/README.md index cdeb4795c..d79f04ae2 100644 --- a/mascara/README.md +++ b/mascara/README.md @@ -18,3 +18,9 @@ node server.js Standing problems: - [ ] IndexDb + +### deploy + +``` +docker-compose build && docker-compose stop && docker-compose up -d && docker-compose logs -f --tail 10 +``` \ No newline at end of file From 19c375fa69ae69977443fc5ec1f638c7879305ff Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Fri, 13 Oct 2017 19:22:02 +0000 Subject: [PATCH 002/392] fix(package): update metamascara to version 2.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2b7b2056a..7a1be5579 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,7 @@ "json-rpc-engine": "^3.2.0", "json-rpc-middleware-stream": "^1.0.1", "loglevel": "^1.4.1", - "metamascara": "^1.3.1", + "metamascara": "^2.0.0", "metamask-logo": "^2.1.2", "mississippi": "^1.2.0", "mkdirp": "^0.5.1", From e81ba29359fd934f3075625854b5786e6872fb36 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Thu, 21 Dec 2017 16:45:03 +0000 Subject: [PATCH 003/392] chore(package): update karma to version 2.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7184e3ea8..8858d4a5b 100644 --- a/package.json +++ b/package.json @@ -193,7 +193,7 @@ "jsdom": "^11.1.0", "jsdom-global": "^3.0.2", "jshint-stylish": "~2.2.1", - "karma": "^1.7.1", + "karma": "^2.0.0", "karma-chrome-launcher": "^2.2.0", "karma-cli": "^1.0.1", "karma-firefox-launcher": "^1.0.1", From a76324f6d397c3e746ba501cfd858c4869cb0af7 Mon Sep 17 00:00:00 2001 From: Ellie Day Date: Sat, 23 Dec 2017 08:23:34 -0600 Subject: [PATCH 004/392] Add ExtensionStore and add basic store instance syncing to main controller --- app/scripts/background.js | 12 ++++++++++++ app/scripts/lib/extension-store.js | 20 ++++++++++++++++++++ test/unit/extension-store-test.js | 29 +++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 app/scripts/lib/extension-store.js create mode 100644 test/unit/extension-store-test.js diff --git a/app/scripts/background.js b/app/scripts/background.js index da022c490..45da2f6d0 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -4,6 +4,7 @@ const pump = require('pump') const log = require('loglevel') const extension = require('extensionizer') const LocalStorageStore = require('obs-store/lib/localStorage') +const ExtensionStore = require('./lib/extension-store') const storeTransform = require('obs-store/lib/transform') const asStream = require('obs-store/lib/asStream') const ExtensionPlatform = require('./platforms/extension') @@ -28,6 +29,7 @@ let popupIsOpen = false // state persistence const diskStore = new LocalStorageStore({ storageKey: STORAGE_KEY }) +const extensionStore = new ExtensionStore() // initialization flow initialize().catch(log.error) @@ -45,8 +47,12 @@ async function initialize () { async function loadStateFromPersistence () { // migrations const migrator = new Migrator({ migrations }) + // fetch from extension store + const extensionData = await extensionStore.fetch() // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) // read from disk let versionedData = diskStore.getState() || migrator.generateInitialState(firstTimeState) + // merge extension and versioned data + versionedData = { ...versionedData, ...extensionData } // migrate data versionedData = await migrator.migrateData(versionedData) // write to disk @@ -76,6 +82,7 @@ function setupController (initState) { pump( asStream(controller.store), storeTransform(versionifyData), + storeTransform(syncDataWithExtension), asStream(diskStore) ) @@ -85,6 +92,11 @@ function setupController (initState) { return versionedData } + function syncDataWithExtension(state) { + extensionStore.sync(state) // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) + return state + } + // // connect to other contexts // diff --git a/app/scripts/lib/extension-store.js b/app/scripts/lib/extension-store.js new file mode 100644 index 000000000..a8b730a65 --- /dev/null +++ b/app/scripts/lib/extension-store.js @@ -0,0 +1,20 @@ +const extension = require('extensionizer') + +const KEYS_TO_SYNC = ['KeyringController', 'PreferencesController'] + +module.exports = class ExtensionStore { + async fetch() { + return new Promise((resolve) => { + extension.storage.sync.get(KEYS_TO_SYNC, data => resolve(data)) + }) + } + async sync(state) { + const dataToSync = KEYS_TO_SYNC.reduce((result, key) => { + result[key] = state.data[key] + return result + }, {}) + return new Promise((resolve) => { + extension.storage.sync.set(dataToSync, () => resolve()) + }) + } +} diff --git a/test/unit/extension-store-test.js b/test/unit/extension-store-test.js new file mode 100644 index 000000000..e3b5713fb --- /dev/null +++ b/test/unit/extension-store-test.js @@ -0,0 +1,29 @@ +const assert = require('assert') + +const ExtensionStore = require('../../app/scripts/lib/extension-store') + +describe('Extension Store', function () { + let extensionStore + + beforeEach(function () { + extensionStore = new ExtensionStore() + }) + + describe('#fetch', function () { + it('should return a promise', function () { + + }) + it('after promise resolution, should have loaded the proper data from the extension', function () { + + }) + }) + + describe('#sync', function () { + it('should return a promise', function () { + + }) + it('after promise resolution, should have synced the proper data from the extension', function () { + + }) + }) +}) From 7184db7632ef79d4bde0e643fdc1a4ee910c77fb Mon Sep 17 00:00:00 2001 From: Ellie Day Date: Tue, 2 Jan 2018 21:31:17 -0800 Subject: [PATCH 005/392] handle situation where storage.sync is disabled in certain versions of firefox --- app/scripts/background.js | 5 ++--- app/scripts/lib/extension-store.js | 19 +++++++++++++++++-- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/app/scripts/background.js b/app/scripts/background.js index 45da2f6d0..732f47590 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -47,11 +47,10 @@ async function initialize () { async function loadStateFromPersistence () { // migrations const migrator = new Migrator({ migrations }) - // fetch from extension store - const extensionData = await extensionStore.fetch() // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) // read from disk let versionedData = diskStore.getState() || migrator.generateInitialState(firstTimeState) - // merge extension and versioned data + // fetch from extension store and merge in data + const extensionData = await extensionStore.fetch() // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) versionedData = { ...versionedData, ...extensionData } // migrate data versionedData = await migrator.migrateData(versionedData) diff --git a/app/scripts/lib/extension-store.js b/app/scripts/lib/extension-store.js index a8b730a65..dd0f82f36 100644 --- a/app/scripts/lib/extension-store.js +++ b/app/scripts/lib/extension-store.js @@ -1,11 +1,24 @@ const extension = require('extensionizer') const KEYS_TO_SYNC = ['KeyringController', 'PreferencesController'] +const FIREFOX_SYNC_DISABLED_MESSAGE = 'Please set webextensions.storage.sync.enabled to true in about:config' + +const handleDisabledSyncAndResolve = (resolve, toResolve) => { + // Firefox 52 has sync available on extension.storage, but it is disabled by default + const lastError = extension.runtime.lastError + if (lastError && lastError.message.includes(FIREFOX_SYNC_DISABLED_MESSAGE)) { + resolve({}) + } else { + resolve(toResolve) + } +} module.exports = class ExtensionStore { async fetch() { return new Promise((resolve) => { - extension.storage.sync.get(KEYS_TO_SYNC, data => resolve(data)) + extension.storage.sync.get(KEYS_TO_SYNC, (data) => { + handleDisabledSyncAndResolve(resolve, data) + }) }) } async sync(state) { @@ -14,7 +27,9 @@ module.exports = class ExtensionStore { return result }, {}) return new Promise((resolve) => { - extension.storage.sync.set(dataToSync, () => resolve()) + extension.storage.sync.set(dataToSync, () => { + handleDisabledSyncAndResolve(resolve) + }) }) } } From 3c6a5b16ad37c83f548028d5b6fa3d0f75293ca5 Mon Sep 17 00:00:00 2001 From: Ellie Day Date: Tue, 2 Jan 2018 21:53:11 -0800 Subject: [PATCH 006/392] conditionally use extension store if supported or enabled --- app/scripts/background.js | 12 +++++++++--- app/scripts/lib/extension-store.js | 4 ++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/app/scripts/background.js b/app/scripts/background.js index 732f47590..d9a2b0a6e 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -50,8 +50,12 @@ async function loadStateFromPersistence () { // read from disk let versionedData = diskStore.getState() || migrator.generateInitialState(firstTimeState) // fetch from extension store and merge in data - const extensionData = await extensionStore.fetch() // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) - versionedData = { ...versionedData, ...extensionData } + + if (extensionStore.isSupported && extensionStore.isEnabled) { + const extensionData = await extensionStore.fetch() // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) + versionedData = { ...versionedData, ...extensionData } + } + // migrate data versionedData = await migrator.migrateData(versionedData) // write to disk @@ -92,7 +96,9 @@ function setupController (initState) { } function syncDataWithExtension(state) { - extensionStore.sync(state) // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) + if (extensionStore.isSupported && extensionStore.isEnabled) { + extensionStore.sync(state) // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) + } return state } diff --git a/app/scripts/lib/extension-store.js b/app/scripts/lib/extension-store.js index dd0f82f36..67ee71f16 100644 --- a/app/scripts/lib/extension-store.js +++ b/app/scripts/lib/extension-store.js @@ -14,6 +14,10 @@ const handleDisabledSyncAndResolve = (resolve, toResolve) => { } module.exports = class ExtensionStore { + constructor() { + this.isSupported = !!(extension.storage.sync) + this.isEnabled = true // TODO: get value from user settings + } async fetch() { return new Promise((resolve) => { extension.storage.sync.get(KEYS_TO_SYNC, (data) => { From bad70eb1b328aa911a2523ccab642d7607161b4b Mon Sep 17 00:00:00 2001 From: Nick Doiron Date: Mon, 22 Jan 2018 23:48:03 -1000 Subject: [PATCH 007/392] first steps to i18n --- app/_locales/en/messages.json | 167 +++++++++++++++++- ui/app/components/account-dropdowns.js | 12 +- ui/app/components/account-export.js | 8 +- ui/app/components/account-menu/index.js | 14 +- ui/app/components/buy-button-subview.js | 8 +- ui/app/components/coinbase-form.js | 4 +- ui/app/components/copyButton.js | 2 +- ui/app/components/copyable.js | 2 +- .../components/customize-gas-modal/index.js | 20 +-- .../dropdowns/components/account-dropdowns.js | 19 +- .../components/dropdowns/network-dropdown.js | 26 +-- .../dropdowns/token-menu-dropdown.js | 2 +- ui/app/components/ens-input.js | 4 +- ui/app/components/hex-as-decimal-input.js | 2 +- ui/app/components/network.js | 24 +-- ui/app/components/notice.js | 2 +- ui/app/components/pending-msg-details.js | 3 +- ui/app/components/pending-msg.js | 14 +- .../pending-personal-msg-details.js | 3 +- .../components/pending-typed-msg-details.js | 2 +- ui/app/components/pending-typed-msg.js | 6 +- ui/app/components/shapeshift-form.js | 22 +-- ui/app/components/shift-list-item.js | 8 +- ui/app/components/signature-request.js | 24 ++- ui/app/components/token-list.js | 6 +- ui/app/components/transaction-list-item.js | 16 +- ui/app/components/transaction-list.js | 3 +- ui/app/components/tx-list-item.js | 2 +- ui/app/components/tx-list.js | 4 +- ui/app/components/tx-view.js | 6 +- ui/app/components/wallet-view.js | 8 +- ui/app/first-time/init-menu.js | 25 ++- 32 files changed, 314 insertions(+), 154 deletions(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 8c28f1c43..6967a44d2 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -6,5 +6,170 @@ "appDescription": { "message": "Ethereum Identity Management", "description": "The description of the application" - } + }, + "encryptNewDen": { + "message": "Encrypt your new DEN" + }, + "denExplainer": { + "message": "Your DEN is your password-encrypted storage within MetaMask." + }, + "importDen": { + "message": "Import Existing DEN" + }, + "createDen": { + "message": "Create" + }, + "newPassword": { + "message": "New Password (min 8 chars)" + }, + "confirmPassword": { + "message": "Confirm Password" + }, + "passwordMismatch": { + "message": "passwords don't match" + }, + "passwordShort": { + "message": "password not long enough" + }, + "myAccounts": { + "message": "My Accounts" + }, + "logout": { + "message": "Log out" + }, + "createAccount": { + "message": "Create Account" + }, + "importAccount": { + "message": "Import Account" + }, + "account": { + "message": "Account:" + }, + "infoHelp": { + "message": "Info & Help" + }, + "settings": { + "message": "Settings" + }, + "importedCaps": { + "message": "IMPORTED" + }, + "saveButton": { + "message": "SAVE" + }, + "cancelButton": { + "message": "CANCEL" + }, + "signButton": { + "message": "SIGN" + }, + "revert": { + "message": "Revert" + }, + "gasLimit": { + "message": "Gas Limit" + }, + "gasLimitCalculation": { + "message": "We calculate the suggested gas limit based on network success rates." + }, + "gasPrice": { + "message": "Gas Price (GWEI)" + }, + "gasPriceCalculation": { + "message": "We calculate the suggested gas prices based on network success rates." + }, + "customGas": { + "message": "Customize Gas" + }, + "balanceIsInsufficientGas": { + "message": "Insufficient balance for current gas total" + }, + "gasLimitTooLow": { + "message": "Gas limit must be at least 21000" + }, + "editButton": { + "message": "Edit" + }, + "looseCaps": { + "message": "LOOSE" + }, + "addToken": "Add Token", + "exportPrivateKey": "Export Private Key", + "copyAddress": "Copy Address to clipboard", + "etherscanView": "View account on Etherscan", + "qrCode": "Show QR Code", + "accDetails": "Account Details", + "networks": "Networks", + "defaultNetwork": "The default network for Ether transactions is Main Net.", + "mainnet": "Main Ethereum Network", + "unknownNetwork": "Unknown Private Network", + "rinkeby": "Rinkeby Test Network", + "kovan": "Kovan Test Network", + "ropsten": "Ropsten Test Network", + "localhost": "Localhost 8545", + "customRPC": "Custom RPC", + "hideToken": "Hide Token", + "copiedClipboard": "Copied to Clipboard", + "detailsCaps": "DETAILS", + "sendButton": "SEND", + "depositButton": "DEPOSIT", + "notStarted": "Not Started", + "noTransactions": "No Transactions", + "contractPublished": "Contract Published", + "noTransactionHistory": "No transaction history.", + "warning": "Warning", + "failed": "Failed", + "rejected": "Rejected", + "sigRequested": "Signature Requested", + "yourSigRequested": "Your signature is being requested", + "balance": "Balance:", + "retryWithMoreGas": "Retry with a higher gas price here", + "takesTooLong": "Taking too long?", + "transactionNumber": "Transaction Number", + "loadingTokens": "Loading Tokens...", + "troubleTokenBalances": "We had trouble loading your token balances. You can view them ", + "here": "here", + "message": "Message", + "signNotice": "Signing this message can have \ndangerous side effects. Only sign messages from \nsites you fully trust with your entire account.\n This dangerous method will be removed in a future version. ", + "youSign": "You are signing:", + "conversionProgress": "Conversion in progress", + "noDeposits": "No deposits received", + "fromShapeShift": "From ShapeShift", + "invalidRequest": "Invalid Request", + "status": "Status", + "limit": "Limit", + "exchangeRate": "Exchange Rate", + "min": "Minimum", + "available": "Available", + "unavailable": "Unavailable", + "depositBTC": "Deposit your BTC to the address below:", + "deposit": "Deposit", + "receive": "Receive", + "refundAddress": "Your Refund Address", + "buyButton": "Buy", + "signMessage": "Sign Message", + "youSignCaps": "YOU ARE SIGNING", + "messageCaps": "MESSAGE", + "readMore": "Read more here.", + "cancel": "Cancel", + "sign": "Sign", + "accept": "Accept", + "attemptingConnect": "Attempting to connect to blockchain.", + "privateNetwork": "Private Network", + "invalidInput": "Invalid input.", + "noAddressForName": "No address has been set for this name.", + "clickCopy": "Click to Copy", + "copyButton": " Copy ", + "copiedButton": "Copied", + "copy": "Copy", + "copiedExclamation": "Copied!", + "continueToCoinbase": "Continue to Coinbase", + "depositEth": "Deposit Eth", + "selectService": "Select Service", + "unknownNetworkId": "Unknown network ID", + "borrowDharma": "Borrow With Dharma (Beta)", + "exportPrivateKeyWarning": "Export private keys at your own risk.", + "confirmPasswordSmall": "confirm password", + "submit": "Submit", } diff --git a/ui/app/components/account-dropdowns.js b/ui/app/components/account-dropdowns.js index 0c34a5154..3e5805c0e 100644 --- a/ui/app/components/account-dropdowns.js +++ b/ui/app/components/account-dropdowns.js @@ -79,7 +79,7 @@ class AccountDropdowns extends Component { try { // Sometimes keyrings aren't loaded yet: const type = keyring.type const isLoose = type !== 'HD Key Tree' - return isLoose ? h('.keyring-label', 'LOOSE') : null + return isLoose ? h('.keyring-label', t('looseCaps')) : null } catch (e) { return } } @@ -129,7 +129,7 @@ class AccountDropdowns extends Component { diameter: 32, }, ), - h('span', { style: { marginLeft: '20px', fontSize: '24px' } }, 'Create Account'), + h('span', { style: { marginLeft: '20px', fontSize: '24px' } }, t('createAccount')), ], ), h( @@ -192,7 +192,7 @@ class AccountDropdowns extends Component { global.platform.openWindow({ url }) }, }, - 'View account on Etherscan', + t('etherscanView'), ), h( DropdownMenuItem, @@ -204,7 +204,7 @@ class AccountDropdowns extends Component { actions.showQrView(selected, identity ? identity.name : '') }, }, - 'Show QR Code', + t('qrCode'), ), h( DropdownMenuItem, @@ -216,7 +216,7 @@ class AccountDropdowns extends Component { copyToClipboard(checkSumAddress) }, }, - 'Copy Address to clipboard', + t('copyAddress'), ), h( DropdownMenuItem, @@ -226,7 +226,7 @@ class AccountDropdowns extends Component { actions.requestAccountExport() }, }, - 'Export Private Key', + t('exportPrivateKey'), ), ] ) diff --git a/ui/app/components/account-export.js b/ui/app/components/account-export.js index 32b103c86..346872a97 100644 --- a/ui/app/components/account-export.js +++ b/ui/app/components/account-export.js @@ -35,7 +35,7 @@ ExportAccountView.prototype.render = function () { if (notExporting) return h('div') if (exportRequested) { - const warning = `Export private keys at your own risk.` + const warning = t('exportPrivateKeyWarning') return ( h('div', { style: { @@ -53,7 +53,7 @@ ExportAccountView.prototype.render = function () { h('p.error', warning), h('input#exportAccount.sizing-input', { type: 'password', - placeholder: 'confirm password', + placeholder: t('confirmPasswordSmall'), onKeyPress: this.onExportKeyPress.bind(this), style: { position: 'relative', @@ -74,10 +74,10 @@ ExportAccountView.prototype.render = function () { style: { marginRight: '10px', }, - }, 'Submit'), + }, t('submit')), h('button', { onClick: () => this.props.dispatch(actions.backToAccountDetail(this.props.address)), - }, 'Cancel'), + }, t('cancel')), ]), (this.props.warning) && ( h('span.error', { diff --git a/ui/app/components/account-menu/index.js b/ui/app/components/account-menu/index.js index aeb8a0b38..aec00ff6b 100644 --- a/ui/app/components/account-menu/index.js +++ b/ui/app/components/account-menu/index.js @@ -70,10 +70,10 @@ AccountMenu.prototype.render = function () { h(Item, { className: 'account-menu__header', }, [ - 'My Accounts', + t('myAccounts'), h('button.account-menu__logout-button', { onClick: lockMetamask, - }, 'Log out'), + }, t('logout')), ]), h(Divider), h('div.account-menu__accounts', this.renderAccounts()), @@ -81,23 +81,23 @@ AccountMenu.prototype.render = function () { h(Item, { onClick: () => showNewAccountPage('CREATE'), icon: h('img', { src: 'images/plus-btn-white.svg' }), - text: 'Create Account', + text: t('createAccount'), }), h(Item, { onClick: () => showNewAccountPage('IMPORT'), icon: h('img', { src: 'images/import-account.svg' }), - text: 'Import Account', + text: t('importAccount'), }), h(Divider), h(Item, { onClick: showInfoPage, icon: h('img', { src: 'images/mm-info-icon.svg' }), - text: 'Info & Help', + text: t('infoHelp'), }), h(Item, { onClick: showConfigPage, icon: h('img', { src: 'images/settings.svg' }), - text: 'Settings', + text: t('settings'), }), ]) } @@ -155,6 +155,6 @@ AccountMenu.prototype.indicateIfLoose = function (keyring) { try { // Sometimes keyrings aren't loaded yet: const type = keyring.type const isLoose = type !== 'HD Key Tree' - return isLoose ? h('.keyring-label', 'IMPORTED') : null + return isLoose ? h('.keyring-label', t('importedCaps')) : null } catch (e) { return } } diff --git a/ui/app/components/buy-button-subview.js b/ui/app/components/buy-button-subview.js index d5958787b..76da4fc9d 100644 --- a/ui/app/components/buy-button-subview.js +++ b/ui/app/components/buy-button-subview.js @@ -76,7 +76,7 @@ BuyButtonSubview.prototype.headerSubview = function () { paddingTop: '4px', paddingBottom: '4px', }, - }, 'Deposit Eth'), + }, t('depositEth')), ]), // loading indication @@ -118,7 +118,7 @@ BuyButtonSubview.prototype.headerSubview = function () { paddingTop: '4px', paddingBottom: '4px', }, - }, 'Select Service'), + }, t('selectService')), ]), ]) @@ -164,14 +164,14 @@ BuyButtonSubview.prototype.primarySubview = function () { style: { marginTop: '15px', }, - }, 'Borrow With Dharma (Beta)') + }, t('borrowDharma')) ) : null, ]) ) default: return ( - h('h2.error', 'Unknown network ID') + h('h2.error', t('unknownNetworkId')) ) } diff --git a/ui/app/components/coinbase-form.js b/ui/app/components/coinbase-form.js index f70208625..6532cb3bf 100644 --- a/ui/app/components/coinbase-form.js +++ b/ui/app/components/coinbase-form.js @@ -37,11 +37,11 @@ CoinbaseForm.prototype.render = function () { }, [ h('button.btn-green', { onClick: this.toCoinbase.bind(this), - }, 'Continue to Coinbase'), + }, t('continueToCoinbase')), h('button.btn-red', { onClick: () => props.dispatch(actions.goHome()), - }, 'Cancel'), + }, t('cancel')), ]), ]) } diff --git a/ui/app/components/copyButton.js b/ui/app/components/copyButton.js index a25d0719c..5d5be8feb 100644 --- a/ui/app/components/copyButton.js +++ b/ui/app/components/copyButton.js @@ -22,7 +22,7 @@ CopyButton.prototype.render = function () { const value = props.value const copied = state.copied - const message = copied ? 'Copied' : props.title || ' Copy ' + const message = copied ? t('copiedButton') : props.title || t('copyButton') return h('.copy-button', { style: { diff --git a/ui/app/components/copyable.js b/ui/app/components/copyable.js index a4f6f4bc6..690e44153 100644 --- a/ui/app/components/copyable.js +++ b/ui/app/components/copyable.js @@ -22,7 +22,7 @@ Copyable.prototype.render = function () { const { copied } = state return h(Tooltip, { - title: copied ? 'Copied!' : 'Copy', + title: copied ? t('copiedExclamation') : t('copy'), position: 'bottom', }, h('span', { style: { diff --git a/ui/app/components/customize-gas-modal/index.js b/ui/app/components/customize-gas-modal/index.js index 826d2cd4b..a5384daaf 100644 --- a/ui/app/components/customize-gas-modal/index.js +++ b/ui/app/components/customize-gas-modal/index.js @@ -146,7 +146,7 @@ CustomizeGasModal.prototype.validate = function ({ gasTotal, gasLimit }) { }) if (!balanceIsSufficient) { - error = 'Insufficient balance for current gas total' + error = t('balanceIsInsufficientGas') } const gasLimitTooLow = gasLimit && conversionGreaterThan( @@ -162,7 +162,7 @@ CustomizeGasModal.prototype.validate = function ({ gasTotal, gasLimit }) { ) if (gasLimitTooLow) { - error = 'Gas limit must be at least 21000' + error = t('gasLimitTooLow') } this.setState({ error }) @@ -239,7 +239,7 @@ CustomizeGasModal.prototype.render = function () { }, [ h('div.send-v2__customize-gas__header', {}, [ - h('div.send-v2__customize-gas__title', 'Customize Gas'), + h('div.send-v2__customize-gas__title', t('customGas')), h('div.send-v2__customize-gas__close', { onClick: hideModal, @@ -255,8 +255,8 @@ CustomizeGasModal.prototype.render = function () { // max: 1000, step: multiplyCurrencies(MIN_GAS_PRICE_GWEI, 10), onChange: value => this.convertAndSetGasPrice(value), - title: 'Gas Price (GWEI)', - copy: 'We calculate the suggested gas prices based on network success rates.', + title: t('gasPrice'), + copy: t('gasPriceCalculation'), }), h(GasModalCard, { @@ -265,8 +265,8 @@ CustomizeGasModal.prototype.render = function () { // max: 100000, step: 1, onChange: value => this.convertAndSetGasLimit(value), - title: 'Gas Limit', - copy: 'We calculate the suggested gas limit based on network success rates.', + title: t('gasLimit'), + copy: t('gasLimitCalculation'), }), ]), @@ -279,16 +279,16 @@ CustomizeGasModal.prototype.render = function () { h('div.send-v2__customize-gas__revert', { onClick: () => this.revert(), - }, ['Revert']), + }, [t('revert')]), h('div.send-v2__customize-gas__buttons', [ h('div.send-v2__customize-gas__cancel', { onClick: this.props.hideModal, - }, ['CANCEL']), + }, [t('cancelButton')]), h(`div.send-v2__customize-gas__save${error ? '__error' : ''}`, { onClick: () => !error && this.save(gasPrice, gasLimit, gasTotal), - }, ['SAVE']), + }, [t('saveButton')]), ]), ]), diff --git a/ui/app/components/dropdowns/components/account-dropdowns.js b/ui/app/components/dropdowns/components/account-dropdowns.js index f97ac0691..7ecec38d2 100644 --- a/ui/app/components/dropdowns/components/account-dropdowns.js +++ b/ui/app/components/dropdowns/components/account-dropdowns.js @@ -129,7 +129,7 @@ class AccountDropdowns extends Component { actions.showEditAccountModal(identity) }, }, [ - 'Edit', + t('editButton'), ]), ]), @@ -159,7 +159,7 @@ class AccountDropdowns extends Component { try { // Sometimes keyrings aren't loaded yet: const type = keyring.type const isLoose = type !== 'HD Key Tree' - return isLoose ? h('.keyring-label', 'LOOSE') : null + return isLoose ? h('.keyring-label', t('looseCaps')) : null } catch (e) { return } } @@ -217,7 +217,7 @@ class AccountDropdowns extends Component { fontSize: '16px', lineHeight: '23px', }, - }, 'Create Account'), + }, t('createAccount')), ], ), h( @@ -251,7 +251,7 @@ class AccountDropdowns extends Component { fontSize: '16px', lineHeight: '23px', }, - }, 'Import Account'), + }, t('importAccount')), ] ), ] @@ -302,7 +302,7 @@ class AccountDropdowns extends Component { menuItemStyles, ), }, - 'Account Details', + t('accDetails'), ), h( DropdownMenuItem, @@ -318,7 +318,7 @@ class AccountDropdowns extends Component { menuItemStyles, ), }, - 'View account on Etherscan', + t('etherscanView'), ), h( DropdownMenuItem, @@ -334,7 +334,7 @@ class AccountDropdowns extends Component { menuItemStyles, ), }, - 'Copy Address to clipboard', + t('copyAddress'), ), h( DropdownMenuItem, @@ -346,7 +346,7 @@ class AccountDropdowns extends Component { menuItemStyles, ), }, - 'Export Private Key', + t('exportPrivateKey'), ), h( DropdownMenuItem, @@ -361,7 +361,7 @@ class AccountDropdowns extends Component { menuItemStyles, ), }, - 'Add Token', + t('addToken'), ), ] @@ -479,4 +479,3 @@ function mapStateToProps (state) { } module.exports = connect(mapStateToProps, mapDispatchToProps)(AccountDropdowns) - diff --git a/ui/app/components/dropdowns/network-dropdown.js b/ui/app/components/dropdowns/network-dropdown.js index dfaa6b22c..02773fb46 100644 --- a/ui/app/components/dropdowns/network-dropdown.js +++ b/ui/app/components/dropdowns/network-dropdown.js @@ -93,13 +93,13 @@ NetworkDropdown.prototype.render = function () { }, [ h('div.network-dropdown-header', {}, [ - h('div.network-dropdown-title', {}, 'Networks'), + h('div.network-dropdown-title', {}, t('networks')), h('div.network-dropdown-divider'), h('div.network-dropdown-content', {}, - 'The default network for Ether transactions is Main Net.' + t('defaultNetwork') ), ]), @@ -121,7 +121,7 @@ NetworkDropdown.prototype.render = function () { style: { color: providerType === 'mainnet' ? '#ffffff' : '#9b9b9b', }, - }, 'Main Ethereum Network'), + }, t('mainnet')), ] ), @@ -143,7 +143,7 @@ NetworkDropdown.prototype.render = function () { style: { color: providerType === 'ropsten' ? '#ffffff' : '#9b9b9b', }, - }, 'Ropsten Test Network'), + }, t('ropsten')), ] ), @@ -165,7 +165,7 @@ NetworkDropdown.prototype.render = function () { style: { color: providerType === 'kovan' ? '#ffffff' : '#9b9b9b', }, - }, 'Kovan Test Network'), + }, t('kovan')), ] ), @@ -187,7 +187,7 @@ NetworkDropdown.prototype.render = function () { style: { color: providerType === 'rinkeby' ? '#ffffff' : '#9b9b9b', }, - }, 'Rinkeby Test Network'), + }, t('rinkeby')), ] ), @@ -209,7 +209,7 @@ NetworkDropdown.prototype.render = function () { style: { color: activeNetwork === 'http://localhost:8545' ? '#ffffff' : '#9b9b9b', }, - }, 'Localhost 8545'), + }, t('localhost')), ] ), @@ -233,7 +233,7 @@ NetworkDropdown.prototype.render = function () { style: { color: activeNetwork === 'custom' ? '#ffffff' : '#9b9b9b', }, - }, 'Custom RPC'), + }, t('customRPC')), ] ), @@ -248,15 +248,15 @@ NetworkDropdown.prototype.getNetworkName = function () { let name if (providerName === 'mainnet') { - name = 'Main Ethereum Network' + name = t('mainnet') } else if (providerName === 'ropsten') { - name = 'Ropsten Test Network' + name = t('ropsten') } else if (providerName === 'kovan') { - name = 'Kovan Test Network' + name = t('kovan') } else if (providerName === 'rinkeby') { - name = 'Rinkeby Test Network' + name = t('rinkeby') } else { - name = 'Unknown Private Network' + name = t('unknownNetwork') } return name diff --git a/ui/app/components/dropdowns/token-menu-dropdown.js b/ui/app/components/dropdowns/token-menu-dropdown.js index dc7a985e3..3dfcec5a8 100644 --- a/ui/app/components/dropdowns/token-menu-dropdown.js +++ b/ui/app/components/dropdowns/token-menu-dropdown.js @@ -43,7 +43,7 @@ TokenMenuDropdown.prototype.render = function () { showHideTokenConfirmationModal(this.props.token) this.props.onClose() }, - }, 'Hide Token'), + }, t('hideToken')), ]), ]), diff --git a/ui/app/components/ens-input.js b/ui/app/components/ens-input.js index 6553053f7..3e7a23369 100644 --- a/ui/app/components/ens-input.js +++ b/ui/app/components/ens-input.js @@ -89,13 +89,13 @@ EnsInput.prototype.lookupEnsName = function () { log.info(`ENS attempting to resolve name: ${recipient}`) this.ens.lookup(recipient.trim()) .then((address) => { - if (address === ZERO_ADDRESS) throw new Error('No address has been set for this name.') + if (address === ZERO_ADDRESS) throw new Error(t('noAddressForName')) if (address !== ensResolution) { this.setState({ loadingEns: false, ensResolution: address, nickname: recipient.trim(), - hoverText: address + '\nClick to Copy', + hoverText: address + '\n' + t('clickCopy'), ensFailure: false, }) } diff --git a/ui/app/components/hex-as-decimal-input.js b/ui/app/components/hex-as-decimal-input.js index 4a71e9585..07432a1f2 100644 --- a/ui/app/components/hex-as-decimal-input.js +++ b/ui/app/components/hex-as-decimal-input.js @@ -132,7 +132,7 @@ HexAsDecimalInput.prototype.constructWarning = function () { } else if (max) { message += `must be less than or equal to ${max}.` } else { - message += 'Invalid input.' + message += t('invalidInput') } return message diff --git a/ui/app/components/network.js b/ui/app/components/network.js index 3e91fa807..6cb1ff53d 100644 --- a/ui/app/components/network.js +++ b/ui/app/components/network.js @@ -33,7 +33,7 @@ Network.prototype.render = function () { onClick: (event) => this.props.onClick(event), }, [ h('img', { - title: 'Attempting to connect to blockchain.', + title: t('attemptingConnect'), style: { width: '27px', }, @@ -41,22 +41,22 @@ Network.prototype.render = function () { }), ]) } else if (providerName === 'mainnet') { - hoverText = 'Main Ethereum Network' + hoverText = t('mainnet') iconName = 'ethereum-network' } else if (providerName === 'ropsten') { - hoverText = 'Ropsten Test Network' + hoverText = t('ropsten') iconName = 'ropsten-test-network' } else if (parseInt(networkNumber) === 3) { - hoverText = 'Ropsten Test Network' + hoverText = t('ropsten') iconName = 'ropsten-test-network' } else if (providerName === 'kovan') { - hoverText = 'Kovan Test Network' + hoverText = t('kovan') iconName = 'kovan-test-network' } else if (providerName === 'rinkeby') { - hoverText = 'Rinkeby Test Network' + hoverText = t('rinkeby') iconName = 'rinkeby-test-network' } else { - hoverText = 'Unknown Private Network' + hoverText = t('unknownNetwork') iconName = 'unknown-private-network' } @@ -84,7 +84,7 @@ Network.prototype.render = function () { backgroundColor: '#038789', // $blue-lagoon nonSelectBackgroundColor: '#15afb2', }), - h('.network-name', 'Main Network'), + h('.network-name', t('mainnet')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) case 'ropsten-test-network': @@ -93,7 +93,7 @@ Network.prototype.render = function () { backgroundColor: '#e91550', // $crimson nonSelectBackgroundColor: '#ec2c50', }), - h('.network-name', 'Ropsten Test Net'), + h('.network-name', t('ropsten')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) case 'kovan-test-network': @@ -102,7 +102,7 @@ Network.prototype.render = function () { backgroundColor: '#690496', // $purple nonSelectBackgroundColor: '#b039f3', }), - h('.network-name', 'Kovan Test Net'), + h('.network-name', t('kovan')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) case 'rinkeby-test-network': @@ -111,7 +111,7 @@ Network.prototype.render = function () { backgroundColor: '#ebb33f', // $tulip-tree nonSelectBackgroundColor: '#ecb23e', }), - h('.network-name', 'Rinkeby Test Net'), + h('.network-name', t('rinkeby')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) default: @@ -123,7 +123,7 @@ Network.prototype.render = function () { }, }), - h('.network-name', 'Private Network'), + h('.network-name', t('privateNetwork')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) } diff --git a/ui/app/components/notice.js b/ui/app/components/notice.js index 941ac33e6..5bda329ed 100644 --- a/ui/app/components/notice.js +++ b/ui/app/components/notice.js @@ -111,7 +111,7 @@ Notice.prototype.render = function () { style: { marginTop: '18px', }, - }, 'Accept'), + }, t('accept')), ]) ) } diff --git a/ui/app/components/pending-msg-details.js b/ui/app/components/pending-msg-details.js index 718a22de0..3ea063c3c 100644 --- a/ui/app/components/pending-msg-details.js +++ b/ui/app/components/pending-msg-details.js @@ -39,7 +39,7 @@ PendingMsgDetails.prototype.render = function () { // message data h('.tx-data.flex-column.flex-justify-center.flex-grow.select-none', [ h('.flex-column.flex-space-between', [ - h('label.font-small', 'MESSAGE'), + h('label.font-small', t('messageCaps')), h('span.font-small', msgParams.data), ]), ]), @@ -47,4 +47,3 @@ PendingMsgDetails.prototype.render = function () { ]) ) } - diff --git a/ui/app/components/pending-msg.js b/ui/app/components/pending-msg.js index 834719c53..236849c18 100644 --- a/ui/app/components/pending-msg.js +++ b/ui/app/components/pending-msg.js @@ -29,17 +29,14 @@ PendingMsg.prototype.render = function () { fontWeight: 'bold', textAlign: 'center', }, - }, 'Sign Message'), + }, t('signMessage')), h('.error', { style: { margin: '10px', }, }, [ - `Signing this message can have - dangerous side effects. Only sign messages from - sites you fully trust with your entire account. - This dangerous method will be removed in a future version. `, + t('signNotice'), h('a', { href: 'https://medium.com/metamask/the-new-secure-way-to-sign-data-in-your-browser-6af9dd2a1527', style: { color: 'rgb(247, 134, 28)' }, @@ -48,7 +45,7 @@ PendingMsg.prototype.render = function () { const url = 'https://medium.com/metamask/the-new-secure-way-to-sign-data-in-your-browser-6af9dd2a1527' global.platform.openWindow({ url }) }, - }, 'Read more here.'), + }, t('readMore')), ]), // message details @@ -58,13 +55,12 @@ PendingMsg.prototype.render = function () { h('.flex-row.flex-space-around', [ h('button', { onClick: state.cancelMessage, - }, 'Cancel'), + }, t('cancel')), h('button', { onClick: state.signMessage, - }, 'Sign'), + }, t('sign')), ]), ]) ) } - diff --git a/ui/app/components/pending-personal-msg-details.js b/ui/app/components/pending-personal-msg-details.js index 1050513f2..30c475347 100644 --- a/ui/app/components/pending-personal-msg-details.js +++ b/ui/app/components/pending-personal-msg-details.js @@ -45,7 +45,7 @@ PendingMsgDetails.prototype.render = function () { height: '260px', }, }, [ - h('label.font-small', { style: { display: 'block' } }, 'MESSAGE'), + h('label.font-small', { style: { display: 'block' } }, t('messageCaps')), h(BinaryRenderer, { value: data, style: { @@ -57,4 +57,3 @@ PendingMsgDetails.prototype.render = function () { ]) ) } - diff --git a/ui/app/components/pending-typed-msg-details.js b/ui/app/components/pending-typed-msg-details.js index b5fd29f71..a3381174d 100644 --- a/ui/app/components/pending-typed-msg-details.js +++ b/ui/app/components/pending-typed-msg-details.js @@ -45,7 +45,7 @@ PendingMsgDetails.prototype.render = function () { height: '260px', }, }, [ - h('label.font-small', { style: { display: 'block' } }, 'YOU ARE SIGNING'), + h('label.font-small', { style: { display: 'block' } }, t('youSignCaps')), h(TypedMessageRenderer, { value: data, style: { diff --git a/ui/app/components/pending-typed-msg.js b/ui/app/components/pending-typed-msg.js index f8926d0a3..73702d0f8 100644 --- a/ui/app/components/pending-typed-msg.js +++ b/ui/app/components/pending-typed-msg.js @@ -26,7 +26,7 @@ PendingMsg.prototype.render = function () { fontWeight: 'bold', textAlign: 'center', }, - }, 'Sign Message'), + }, t('signMessage')), // message details h(PendingTxDetails, state), @@ -35,10 +35,10 @@ PendingMsg.prototype.render = function () { h('.flex-row.flex-space-around', [ h('button', { onClick: state.cancelTypedMessage, - }, 'Cancel'), + }, t('cancelButton')), h('button', { onClick: state.signTypedMessage, - }, 'Sign'), + }, t('signButton')), ]), ]) diff --git a/ui/app/components/shapeshift-form.js b/ui/app/components/shapeshift-form.js index 2270b8236..773ff227c 100644 --- a/ui/app/components/shapeshift-form.js +++ b/ui/app/components/shapeshift-form.js @@ -14,7 +14,7 @@ function mapStateToProps (state) { tokenExchangeRates, selectedAddress, } = state.metamask - + return { coinOptions, tokenExchangeRates, @@ -92,7 +92,7 @@ ShapeshiftForm.prototype.onBuyWithShapeShift = function () { })) .catch(() => this.setState({ showQrCode: false, - errorMessage: 'Invalid Request', + errorMessage: t('invalidRequest'), isLoading: false, })) } @@ -124,10 +124,10 @@ ShapeshiftForm.prototype.renderMarketInfo = function () { return h('div.shapeshift-form__metadata', {}, [ - this.renderMetadata('Status', limit ? 'Available' : 'Unavailable'), - this.renderMetadata('Limit', limit), - this.renderMetadata('Exchange Rate', rate), - this.renderMetadata('Minimum', minimum), + this.renderMetadata(t('status'), limit ? t('available') : t('unavailable')), + this.renderMetadata(t('limit'), limit), + this.renderMetadata(t('exchangeRate'), rate), + this.renderMetadata(t('min'), minimum), ]) } @@ -141,7 +141,7 @@ ShapeshiftForm.prototype.renderQrCode = function () { return h('div.shapeshift-form', {}, [ h('div.shapeshift-form__deposit-instruction', [ - 'Deposit your BTC to the address below:', + t('depositBTC'), ]), h('div', depositAddress), @@ -178,7 +178,7 @@ ShapeshiftForm.prototype.render = function () { h('div.shapeshift-form__selector', [ - h('div.shapeshift-form__selector-label', 'Deposit'), + h('div.shapeshift-form__selector-label', t('deposit')), h(SimpleDropdown, { selectedOption: this.state.depositCoin, @@ -198,7 +198,7 @@ ShapeshiftForm.prototype.render = function () { h('div.shapeshift-form__selector', [ h('div.shapeshift-form__selector-label', [ - 'Receive', + t('receive'), ]), h('div.shapeshift-form__selector-input', ['ETH']), @@ -214,7 +214,7 @@ ShapeshiftForm.prototype.render = function () { }, [ h('div.shapeshift-form__address-input-label', [ - 'Your Refund Address', + t('refundAddress'), ]), h('input.shapeshift-form__address-input', { @@ -236,7 +236,7 @@ ShapeshiftForm.prototype.render = function () { className: btnClass, disabled: !token, onClick: () => this.onBuyWithShapeShift(), - }, ['Buy']), + }, [t('buyButton')]), ]) } diff --git a/ui/app/components/shift-list-item.js b/ui/app/components/shift-list-item.js index 111a77df4..6e5be641f 100644 --- a/ui/app/components/shift-list-item.js +++ b/ui/app/components/shift-list-item.js @@ -141,7 +141,7 @@ ShiftListItem.prototype.renderInfo = function () { width: '100%', }, }, `${props.depositType} to ETH via ShapeShift`), - h('div', 'No deposits received'), + h('div', t('noDeposits')), h('div', { style: { fontSize: 'x-small', @@ -164,7 +164,7 @@ ShiftListItem.prototype.renderInfo = function () { width: '100%', }, }, `${props.depositType} to ETH via ShapeShift`), - h('div', 'Conversion in progress'), + h('div', t('conversionProgress')), h('div', { style: { fontSize: 'x-small', @@ -189,7 +189,7 @@ ShiftListItem.prototype.renderInfo = function () { color: '#ABA9AA', width: '100%', }, - }, 'From ShapeShift'), + }, t('fromShapeShift')), h('div', formatDate(props.time)), h('div', { style: { @@ -201,7 +201,7 @@ ShiftListItem.prototype.renderInfo = function () { ]) case 'failed': - return h('span.error', '(Failed)') + return h('span.error', '(' + t('failed') + ')') default: return '' } diff --git a/ui/app/components/signature-request.js b/ui/app/components/signature-request.js index c5cc23aa8..459d6a1a2 100644 --- a/ui/app/components/signature-request.js +++ b/ui/app/components/signature-request.js @@ -54,7 +54,7 @@ SignatureRequest.prototype.renderHeader = function () { h('div.request-signature__header-background'), - h('div.request-signature__header__text', 'Signature Request'), + h('div.request-signature__header__text', t('sigRequest')), h('div.request-signature__header__tip-container', [ h('div.request-signature__header__tip'), @@ -75,7 +75,7 @@ SignatureRequest.prototype.renderAccountDropdown = function () { return h('div.request-signature__account', [ - h('div.request-signature__account-text', ['Account:']), + h('div.request-signature__account-text', [t('account')]), h(AccountDropdownMini, { selectedAccount, @@ -102,7 +102,7 @@ SignatureRequest.prototype.renderBalance = function () { return h('div.request-signature__balance', [ - h('div.request-signature__balance-text', ['Balance:']), + h('div.request-signature__balance-text', [t('balance')]), h('div.request-signature__balance-value', `${balanceInEther} ETH`), @@ -136,7 +136,7 @@ SignatureRequest.prototype.renderRequestInfo = function () { return h('div.request-signature__request-info', [ h('div.request-signature__headline', [ - `Your signature is being requested`, + t('yourSigRequested'), ]), ]) @@ -154,21 +154,18 @@ SignatureRequest.prototype.msgHexToText = function (hex) { SignatureRequest.prototype.renderBody = function () { let rows - let notice = 'You are signing:' + let notice = t('youSign') const { txData } = this.props const { type, msgParams: { data } } = txData if (type === 'personal_sign') { - rows = [{ name: 'Message', value: this.msgHexToText(data) }] + rows = [{ name: t('message'), value: this.msgHexToText(data) }] } else if (type === 'eth_signTypedData') { rows = data } else if (type === 'eth_sign') { - rows = [{ name: 'Message', value: data }] - notice = `Signing this message can have - dangerous side effects. Only sign messages from - sites you fully trust with your entire account. - This dangerous method will be removed in a future version. ` + rows = [{ name: t('message'), value: data }] + notice = t('signNotice') } return h('div.request-signature__body', {}, [ @@ -227,10 +224,10 @@ SignatureRequest.prototype.renderFooter = function () { return h('div.request-signature__footer', [ h('button.request-signature__footer__cancel-button', { onClick: cancel, - }, 'CANCEL'), + }, t('cancelButton')), h('button.request-signature__footer__sign-button', { onClick: sign, - }, 'SIGN'), + }, t('signButton')), ]) } @@ -250,4 +247,3 @@ SignatureRequest.prototype.render = function () { ) } - diff --git a/ui/app/components/token-list.js b/ui/app/components/token-list.js index 8e06e0f27..a25566e64 100644 --- a/ui/app/components/token-list.js +++ b/ui/app/components/token-list.js @@ -42,7 +42,7 @@ TokenList.prototype.render = function () { const { tokens, isLoading, error } = state if (isLoading) { - return this.message('Loading Tokens...') + return this.message(t('loadingTokens')) } if (error) { @@ -52,7 +52,7 @@ TokenList.prototype.render = function () { padding: '80px', }, }, [ - 'We had trouble loading your token balances. You can view them ', + t('troubleTokenBalances'), h('span.hotFix', { style: { color: 'rgba(247, 134, 28, 1)', @@ -63,7 +63,7 @@ TokenList.prototype.render = function () { url: `https://ethplorer.io/address/${userAddress}`, }) }, - }, 'here'), + }, t('here')), ]) } diff --git a/ui/app/components/transaction-list-item.js b/ui/app/components/transaction-list-item.js index 4e3d2cb93..10d4236cb 100644 --- a/ui/app/components/transaction-list-item.js +++ b/ui/app/components/transaction-list-item.js @@ -85,7 +85,7 @@ TransactionListItem.prototype.render = function () { ]), h(Tooltip, { - title: 'Transaction Number', + title: t('transactionNumber'), position: 'right', }, [ h('span', { @@ -142,12 +142,12 @@ TransactionListItem.prototype.render = function () { style: { paddingRight: '2px', }, - }, 'Taking too long?'), + }, t('takesTooLong')), h('div', { style: { textDecoration: 'underline', }, - }, 'Retry with a higher gas price here'), + }, t('retryWithMoreGas')), ]), ]) ) @@ -176,11 +176,11 @@ function recipientField (txParams, transaction, isTx, isMsg) { let message if (isMsg) { - message = 'Signature Requested' + message = t('sigRequested') } else if (txParams.to) { message = addressSummary(txParams.to) } else { - message = 'Contract Published' + message = t('contractPublished') } return h('div', { @@ -203,7 +203,7 @@ function renderErrorOrWarning (transaction) { // show rejected if (status === 'rejected') { - return h('span.error', ' (Rejected)') + return h('span.error', ' (' + t('rejected') + ')') } if (transaction.err || transaction.warning) { const { err, warning = {} } = transaction @@ -219,7 +219,7 @@ function renderErrorOrWarning (transaction) { title: message, position: 'bottom', }, [ - h(`span.error`, ` (Failed)`), + h(`span.error`, ` (` + t('failed') + `)`), ]) ) } @@ -231,7 +231,7 @@ function renderErrorOrWarning (transaction) { title: message, position: 'bottom', }, [ - h(`span.warning`, ` (Warning)`), + h(`span.warning`, ` (` + t('warning') + `)`), ]) } } diff --git a/ui/app/components/transaction-list.js b/ui/app/components/transaction-list.js index 69b72614c..cb3f8097b 100644 --- a/ui/app/components/transaction-list.js +++ b/ui/app/components/transaction-list.js @@ -78,10 +78,9 @@ TransactionList.prototype.render = function () { style: { marginTop: '50px', }, - }, 'No transaction history.'), + }, t('noTransactionHistory')), ]), ]), ]) ) } - diff --git a/ui/app/components/tx-list-item.js b/ui/app/components/tx-list-item.js index 7ccc5c315..d53277925 100644 --- a/ui/app/components/tx-list-item.js +++ b/ui/app/components/tx-list-item.js @@ -63,7 +63,7 @@ TxListItem.prototype.getAddressText = function () { default: return address ? `${address.slice(0, 10)}...${address.slice(-4)}` - : 'Contract Published' + : t('contractPublished') } } diff --git a/ui/app/components/tx-list.js b/ui/app/components/tx-list.js index 84cd0f093..6076ab5d3 100644 --- a/ui/app/components/tx-list.js +++ b/ui/app/components/tx-list.js @@ -55,7 +55,7 @@ TxList.prototype.renderTransaction = function () { : [h( 'div.tx-list-item.tx-list-item--empty', { key: 'tx-list-none' }, - [ 'No Transactions' ], + [ t('noTransactions') ], )] } @@ -110,7 +110,7 @@ TxList.prototype.renderTransactionListItem = function (transaction, conversionRa if (isUnapproved) { opts.onClick = () => showConfTxPage({id: transActionId}) - opts.transactionStatus = 'Not Started' + opts.transactionStatus = t('Not Started') } else if (transactionHash) { opts.onClick = () => this.view(transactionHash, transactionNetworkId) } diff --git a/ui/app/components/tx-view.js b/ui/app/components/tx-view.js index b25d8e0f9..423234d4f 100644 --- a/ui/app/components/tx-view.js +++ b/ui/app/components/tx-view.js @@ -72,21 +72,21 @@ TxView.prototype.renderButtons = function () { onClick: () => showModal({ name: 'DEPOSIT_ETHER', }), - }, 'DEPOSIT'), + }, t('depositButton')), h('button.btn-clear.hero-balance-button', { style: { marginLeft: '0.8em', }, onClick: showSendPage, - }, 'SEND'), + }, t('sendButton')), ]) ) : ( h('div.flex-row.flex-center.hero-balance-buttons', [ h('button.btn-clear.hero-balance-button', { onClick: showSendTokenPage, - }, 'SEND'), + }, t('sendButton')), ]) ) } diff --git a/ui/app/components/wallet-view.js b/ui/app/components/wallet-view.js index b1ef83cee..3d9c01c6e 100644 --- a/ui/app/components/wallet-view.js +++ b/ui/app/components/wallet-view.js @@ -113,7 +113,7 @@ WalletView.prototype.render = function () { onClick: hideSidebar, }), - h('div.wallet-view__keyring-label', isLoose ? 'IMPORTED' : ''), + h('div.wallet-view__keyring-label', isLoose ? t('importedCaps') : ''), h('div.flex-column.flex-center.wallet-view__name-container', { style: { margin: '0 auto' }, @@ -130,7 +130,7 @@ WalletView.prototype.render = function () { selectedIdentity.name, ]), - h('button.btn-clear.wallet-view__details-button', 'DETAILS'), + h('button.btn-clear.wallet-view__details-button', t('detailsCaps')), ]), ]), @@ -142,7 +142,7 @@ WalletView.prototype.render = function () { setTimeout(() => this.setState({ hasCopied: false }), 3000) }, }, [ - this.state.hasCopied && 'Copied to Clipboard', + this.state.hasCopied && t('copiedClipboard'), !this.state.hasCopied && `${selectedAddress.slice(0, 4)}...${selectedAddress.slice(-4)}`, h('i.fa.fa-clipboard', { style: { marginLeft: '8px' } }), ]), @@ -156,7 +156,7 @@ WalletView.prototype.render = function () { showAddTokenPage() hideSidebar() }, - }, 'Add Token'), + }, t('addToken')), ]) } diff --git a/ui/app/first-time/init-menu.js b/ui/app/first-time/init-menu.js index b4587f1ee..c496690a7 100644 --- a/ui/app/first-time/init-menu.js +++ b/ui/app/first-time/init-menu.js @@ -10,6 +10,13 @@ const getCaretCoordinates = require('textarea-caret') let isSubmitting = false +let t = chrome.i18n.getMessage || (function() { + let msg = require('../../../app/_locales/en/messages.json'); + return (function(key) { + return msg[key].message; + }); +})(); + module.exports = connect(mapStateToProps)(InitializeMenuScreen) inherits(InitializeMenuScreen, Component) @@ -57,7 +64,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { color: '#7F8082', marginBottom: 10, }, - }, 'MetaMask'), + }, t('appName')), h('div', [ @@ -67,10 +74,10 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { color: '#7F8082', display: 'inline', }, - }, 'Encrypt your new DEN'), + }, t('encryptNewDen')), h(Tooltip, { - title: 'Your DEN is your password-encrypted storage within MetaMask.', + title: t('denExplainer'), }, [ h('i.fa.fa-question-circle.pointer', { style: { @@ -90,7 +97,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { h('input.large-input.letter-spacey', { type: 'password', id: 'password-box', - placeholder: 'New Password (min 8 chars)', + placeholder: t('newPassword'), onInput: this.inputChanged.bind(this), style: { width: 260, @@ -102,7 +109,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { h('input.large-input.letter-spacey', { type: 'password', id: 'password-box-confirm', - placeholder: 'Confirm Password', + placeholder: t('confirmPassword'), onKeyPress: this.createVaultOnEnter.bind(this), onInput: this.inputChanged.bind(this), style: { @@ -117,7 +124,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { style: { margin: 12, }, - }, 'Create'), + }, t('createDen')), h('.flex-row.flex-center.flex-grow', [ h('p.pointer', { @@ -127,7 +134,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { color: 'rgb(247, 134, 28)', textDecoration: 'underline', }, - }, 'Import Existing DEN'), + }, t('importDen')), ]), ]) @@ -156,12 +163,12 @@ InitializeMenuScreen.prototype.createNewVaultAndKeychain = function () { var passwordConfirm = passwordConfirmBox.value if (password.length < 8) { - this.warning = 'password not long enough' + this.warning = t('passwordShort') this.props.dispatch(actions.displayWarning(this.warning)) return } if (password !== passwordConfirm) { - this.warning = 'passwords don\'t match' + this.warning = t('passwordMismatch') this.props.dispatch(actions.displayWarning(this.warning)) return } From 03c64ba8a646cbc5a62f2b2a8c5881bb4a4bda60 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 23 Jan 2018 15:45:33 -0800 Subject: [PATCH 008/392] Add unlimitedStorage option to manifest --- app/manifest.json | 1 + 1 file changed, 1 insertion(+) diff --git a/app/manifest.json b/app/manifest.json index d795a225a..13ba074e7 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -60,6 +60,7 @@ "http://localhost:8545/", "https://*.infura.io/" ], + "unlimitedStorage": true, "web_accessible_resources": [ "scripts/inpage.js" ], From 456dfdb9fdc0b7b0637d50808beb85ae33602f5b Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 23 Jan 2018 16:26:50 -0800 Subject: [PATCH 009/392] Modify @heyellieday's work to use storage.local to replace main storage --- app/scripts/background.js | 15 ++++++++------- app/scripts/lib/local-store.js | 25 +++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 app/scripts/lib/local-store.js diff --git a/app/scripts/background.js b/app/scripts/background.js index d9a2b0a6e..9790129aa 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -4,7 +4,7 @@ const pump = require('pump') const log = require('loglevel') const extension = require('extensionizer') const LocalStorageStore = require('obs-store/lib/localStorage') -const ExtensionStore = require('./lib/extension-store') +const LocalStore = require('./lib/local-store') const storeTransform = require('obs-store/lib/transform') const asStream = require('obs-store/lib/asStream') const ExtensionPlatform = require('./platforms/extension') @@ -29,7 +29,7 @@ let popupIsOpen = false // state persistence const diskStore = new LocalStorageStore({ storageKey: STORAGE_KEY }) -const extensionStore = new ExtensionStore() +const localStore = new LocalStore() // initialization flow initialize().catch(log.error) @@ -51,9 +51,10 @@ async function loadStateFromPersistence () { let versionedData = diskStore.getState() || migrator.generateInitialState(firstTimeState) // fetch from extension store and merge in data - if (extensionStore.isSupported && extensionStore.isEnabled) { - const extensionData = await extensionStore.fetch() // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) - versionedData = { ...versionedData, ...extensionData } + if (localStore.isSupported) { + const localData = await localStore.get() + // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) + versionedData = localData || versionedData } // migrate data @@ -96,8 +97,8 @@ function setupController (initState) { } function syncDataWithExtension(state) { - if (extensionStore.isSupported && extensionStore.isEnabled) { - extensionStore.sync(state) // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) + if (localStore.isSupported) { + localStore.set(state) // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) } return state } diff --git a/app/scripts/lib/local-store.js b/app/scripts/lib/local-store.js new file mode 100644 index 000000000..32faac96b --- /dev/null +++ b/app/scripts/lib/local-store.js @@ -0,0 +1,25 @@ +// We should not rely on local storage in an extension! +// We should use this instead! +// https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/storage/local + +const extension = require('extensionizer') +const STORAGE_KEY = 'metamask-config' + +module.exports = class ExtensionStore { + constructor() { + this.isSupported = !!(extension.storage.local) + if (!this.isSupported) { + log.error('Storage local API not available.') + } + } + async get() { + return new Promise((resolve) => { + extension.storage.local.get(STORAGE_KEY, resolve) + }) + } + async set(state) { + return new Promise((resolve) => { + extension.storage.local.set(state, resolve) + }) + } +} From 99898ac77594d8fe6d4d2aa5bc3e3ba6492f4a10 Mon Sep 17 00:00:00 2001 From: Nick Doiron Date: Tue, 23 Jan 2018 22:14:47 -1000 Subject: [PATCH 010/392] better organization of locale file; i18n in more view files --- app/_locales/en/messages.json | 631 ++++++++++++++---- ui/app/accounts/import/json.js | 14 +- ui/app/accounts/import/private-key.js | 6 +- ui/app/accounts/import/seed.js | 5 +- ui/app/accounts/new-account/create-form.js | 8 +- ui/app/accounts/new-account/index.js | 8 +- .../components/customize-gas-modal/index.js | 4 +- .../dropdowns/components/account-dropdowns.js | 2 +- .../modals/account-details-modal.js | 4 +- .../modals/account-modal-container.js | 2 +- ui/app/components/modals/buy-options-modal.js | 14 +- .../components/modals/deposit-ether-modal.js | 29 +- .../modals/edit-account-name-modal.js | 4 +- .../modals/export-private-key-modal.js | 15 +- .../modals/hide-token-confirmation-modal.js | 8 +- ui/app/components/modals/modal.js | 10 +- ui/app/components/modals/new-account-modal.js | 12 +- .../pending-tx/confirm-deploy-contract.js | 20 +- .../pending-tx/confirm-send-ether.js | 18 +- .../pending-tx/confirm-send-token.js | 26 +- ui/app/components/pending-typed-msg.js | 4 +- ui/app/components/send-token/index.js | 32 +- ui/app/components/send/gas-fee-display-v2.js | 3 +- ui/app/components/send/gas-tooltip.js | 3 +- ui/app/components/send/to-autocomplete.js | 3 +- ui/app/components/signature-request.js | 4 +- 26 files changed, 629 insertions(+), 260 deletions(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 6967a44d2..54f266318 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -1,71 +1,224 @@ { - "appName": { - "message": "MetaMask", - "description": "The name of the application" + "accept": { + "message": "Accept" + }, + "account": { + "message": "Account:" + }, + "accDetails": { + "message": "Account Details" + }, + "accountName": { + "message": "Account Name" + }, + "address": { + "message": "Address" + }, + "addToken": { + "message": "Add Token" + }, + "amountPlusGas": { + "message": "Amount + Gas" }, "appDescription": { "message": "Ethereum Identity Management", "description": "The description of the application" }, - "encryptNewDen": { - "message": "Encrypt your new DEN" + "appName": { + "message": "MetaMask", + "description": "The name of the application" }, - "denExplainer": { - "message": "Your DEN is your password-encrypted storage within MetaMask." + "attemptingConnect": { + "message": "Attempting to connect to blockchain." }, - "importDen": { - "message": "Import Existing DEN" + "available": { + "message": "Available" }, - "createDen": { - "message": "Create" + "back": { + "message": "Back" }, - "newPassword": { - "message": "New Password (min 8 chars)" + "balance": { + "message": "Balance:" + }, + "balanceIsInsufficientGas": { + "message": "Insufficient balance for current gas total" + }, + "borrowDharma": { + "message": "Borrow With Dharma (Beta)" + }, + "buyButton": { + "message": "Buy" + }, + "buyCoinbase": { + "message": "Buy on Coinbase" + }, + "buyCoinbaseExplainer": { + "message": "Coinbase is the world’s most popular way to buy and sell bitcoin, ethereum, and litecoin." + }, + "cancel": { + "message": "Cancel" + }, + "cancelCaps": { + "message": "CANCEL" + }, + "clickCopy": { + "message": "Click to Copy" + }, + "confirm": { + "message": "Confirm" + }, + "confirmCaps": { + "message": "CONFIRM" + }, + "confirmContract": { + "message": "Confirm Contract" }, "confirmPassword": { "message": "Confirm Password" }, - "passwordMismatch": { - "message": "passwords don't match" + "confirmPasswordSmall": { + "message": "confirm password" }, - "passwordShort": { - "message": "password not long enough" + "continueToCoinbase": { + "message": "Continue to Coinbase" }, - "myAccounts": { - "message": "My Accounts" + "contractPublished": { + "message": "Contract Published" }, - "logout": { - "message": "Log out" + "conversionProgress": { + "message": "Conversion in progress" + }, + "copiedButton": { + "message": "Copied" + }, + "copiedClipboard": { + "message": "Copied to Clipboard" + }, + "copiedExclamation": { + "message": "Copied!" + }, + "copy": { + "message": "Copy" + }, + "copyAddress": { + "message": "Copy Address to clipboard" + }, + "copyButton": { + "message": " Copy " + }, + "copyPrivateKey": { + "message": "This is your private key (click to copy)" }, "createAccount": { "message": "Create Account" }, - "importAccount": { - "message": "Import Account" + "createCaps": { + "message": "CREATE" }, - "account": { - "message": "Account:" + "createDen": { + "message": "Create" }, - "infoHelp": { - "message": "Info & Help" + "customGas": { + "message": "Customize Gas" }, - "settings": { - "message": "Settings" + "customize": { + "message": "Customize" }, - "importedCaps": { - "message": "IMPORTED" + "customRPC": { + "message": "Custom RPC" }, - "saveButton": { - "message": "SAVE" + "defaultNetwork": { + "message": "The default network for Ether transactions is Main Net." }, - "cancelButton": { - "message": "CANCEL" + "denExplainer": { + "message": "Your DEN is your password-encrypted storage within MetaMask." }, - "signButton": { - "message": "SIGN" + "deposit": { + "message": "Deposit" }, - "revert": { - "message": "Revert" + "depositBTC": { + "message": "Deposit your BTC to the address below:" + }, + "depositButton": { + "message": "DEPOSIT" + }, + "depositEth": { + "message": "Deposit Eth" + }, + "depositEther": { + "message": "Deposit Ether" + }, + "depositFiat": { + "message": "Deposit with Fiat" + }, + "depositFromAccount": { + "message": "Deposit from another account" + }, + "depositShapeShift": { + "message": "Deposit with ShapeShift" + }, + "depositShapeShiftExplainer": { + "message": "If you own other cryptocurrencies, you can trade and deposit Ether directly into your MetaMask wallet. No Account Needed." + }, + "detailsCaps": { + "message": "DETAILS" + }, + "directDeposit": { + "message": "Direct Deposit" + }, + "directDepositEther": { + "message": "Directly Deposit Ether" + }, + "directDepositEtherExplainer": { + "message": "If you already have some Ether, the quickest way to get Ether in your new wallet by direct deposit." + }, + "done": { + "message": "Done" + }, + "editAccountName": { + "message": "Edit Account Name" + }, + "editCaps": { + "message": "EDIT" + }, + "encryptNewDen": { + "message": "Encrypt your new DEN" + }, + "enterPassword": { + "message": "Enter password" + }, + "etherscanView": { + "message": "View account on Etherscan" + }, + "exchangeRate": { + "message": "Exchange Rate" + }, + "exportPrivateKey": { + "message": "Export Private Key" + }, + "exportPrivateKeyLower": { + "message": "Export private key" + }, + "exportPrivateKeyWarning": { + "message": "Export private keys at your own risk." + }, + "failed": { + "message": "Failed" + }, + "fileImportFail": { + "message": "File import not working? Click here!" + }, + "from": { + "message": "From" + }, + "fromShapeShift": { + "message": "From ShapeShift" + }, + "gasFee": { + "message": "Gas Fee" + }, + "gasFeeSpecific": { + "message": "Gas fee:" }, "gasLimit": { "message": "Gas Limit" @@ -73,103 +226,331 @@ "gasLimitCalculation": { "message": "We calculate the suggested gas limit based on network success rates." }, + "gasLimitRequired": { + "message": "Gas Limit Required" + }, + "gasLimitTooLow": { + "message": "Gas limit must be at least 21000" + }, "gasPrice": { "message": "Gas Price (GWEI)" }, "gasPriceCalculation": { "message": "We calculate the suggested gas prices based on network success rates." }, - "customGas": { - "message": "Customize Gas" + "gasPriceRequired": { + "message": "Gas Price Required" }, - "balanceIsInsufficientGas": { - "message": "Insufficient balance for current gas total" + "getEther": { + "message": "Get Ether" }, - "gasLimitTooLow": { - "message": "Gas limit must be at least 21000" + "here": { + "message": "here" }, - "editButton": { - "message": "Edit" + "hideCaps": { + "message": "HIDE" + }, + "hideToken": { + "message": "Hide Token" + }, + "hideTokenPrompt": { + "message": "Hide Token?" + }, + "howToDeposit": { + "message": "How would you like to deposit Ether?" + }, + "import": { + "message": "Import" + }, + "importAccount": { + "message": "Import Account" + }, + "importAnAccount": { + "message": "Import an account" + }, + "importCaps": { + "message": "IMPORT" + }, + "importDen": { + "message": "Import Existing DEN" + }, + "importedCaps": { + "message": "IMPORTED" + }, + "infoHelp": { + "message": "Info & Help" + }, + "invalidAddress": { + "message": "Invalid address" + }, + "invalidGasParams": { + "message": "Invalid Gas Parameters" + }, + "invalidInput": { + "message": "Invalid input." + }, + "invalidRequest": { + "message": "Invalid Request" + }, + "kovan": { + "message": "Kovan Test Network" + }, + "limit": { + "message": "Limit" + }, + "loading": { + "message": "Loading..." + }, + "loadingTokens": { + "message": "Loading Tokens..." + }, + "localhost": { + "message": "Localhost 8545" + }, + "logout": { + "message": "Log out" }, "looseCaps": { "message": "LOOSE" }, - "addToken": "Add Token", - "exportPrivateKey": "Export Private Key", - "copyAddress": "Copy Address to clipboard", - "etherscanView": "View account on Etherscan", - "qrCode": "Show QR Code", - "accDetails": "Account Details", - "networks": "Networks", - "defaultNetwork": "The default network for Ether transactions is Main Net.", - "mainnet": "Main Ethereum Network", - "unknownNetwork": "Unknown Private Network", - "rinkeby": "Rinkeby Test Network", - "kovan": "Kovan Test Network", - "ropsten": "Ropsten Test Network", - "localhost": "Localhost 8545", - "customRPC": "Custom RPC", - "hideToken": "Hide Token", - "copiedClipboard": "Copied to Clipboard", - "detailsCaps": "DETAILS", - "sendButton": "SEND", - "depositButton": "DEPOSIT", - "notStarted": "Not Started", - "noTransactions": "No Transactions", - "contractPublished": "Contract Published", - "noTransactionHistory": "No transaction history.", - "warning": "Warning", - "failed": "Failed", - "rejected": "Rejected", - "sigRequested": "Signature Requested", - "yourSigRequested": "Your signature is being requested", - "balance": "Balance:", - "retryWithMoreGas": "Retry with a higher gas price here", - "takesTooLong": "Taking too long?", - "transactionNumber": "Transaction Number", - "loadingTokens": "Loading Tokens...", - "troubleTokenBalances": "We had trouble loading your token balances. You can view them ", - "here": "here", - "message": "Message", - "signNotice": "Signing this message can have \ndangerous side effects. Only sign messages from \nsites you fully trust with your entire account.\n This dangerous method will be removed in a future version. ", - "youSign": "You are signing:", - "conversionProgress": "Conversion in progress", - "noDeposits": "No deposits received", - "fromShapeShift": "From ShapeShift", - "invalidRequest": "Invalid Request", - "status": "Status", - "limit": "Limit", - "exchangeRate": "Exchange Rate", - "min": "Minimum", - "available": "Available", - "unavailable": "Unavailable", - "depositBTC": "Deposit your BTC to the address below:", - "deposit": "Deposit", - "receive": "Receive", - "refundAddress": "Your Refund Address", - "buyButton": "Buy", - "signMessage": "Sign Message", - "youSignCaps": "YOU ARE SIGNING", - "messageCaps": "MESSAGE", - "readMore": "Read more here.", - "cancel": "Cancel", - "sign": "Sign", - "accept": "Accept", - "attemptingConnect": "Attempting to connect to blockchain.", - "privateNetwork": "Private Network", - "invalidInput": "Invalid input.", - "noAddressForName": "No address has been set for this name.", - "clickCopy": "Click to Copy", - "copyButton": " Copy ", - "copiedButton": "Copied", - "copy": "Copy", - "copiedExclamation": "Copied!", - "continueToCoinbase": "Continue to Coinbase", - "depositEth": "Deposit Eth", - "selectService": "Select Service", - "unknownNetworkId": "Unknown network ID", - "borrowDharma": "Borrow With Dharma (Beta)", - "exportPrivateKeyWarning": "Export private keys at your own risk.", - "confirmPasswordSmall": "confirm password", - "submit": "Submit", + "mainnet": { + "message": "Main Ethereum Network" + }, + "message": { + "message": "Message" + }, + "messageCaps": { + "message": "MESSAGE" + }, + "min": { + "message": "Minimum" + }, + "myAccounts": { + "message": "My Accounts" + }, + "needEtherInWallet": { + "message": "To interact with decentralized applications using MetaMask, you’ll need Ether in your wallet." + }, + "needImportFile": { + "message": "You must select a file to import." + }, + "needImportPassword": { + "message": "You must enter a password for the selected file." + }, + "networks": { + "message": "Networks" + }, + "newAccount": { + "message": "New Account" + }, + "newContract": { + "message": "New Contract" + }, + "newPassword": { + "message": "New Password (min 8 chars)" + }, + "newRecipient": { + "message": "New Recipient" + }, + "next": { + "message": "Next" + }, + "noAddressForName": { + "message": "No address has been set for this name." + }, + "noDeposits": { + "message": "No deposits received" + }, + "noTransactionHistory": { + "message": "No transaction history." + }, + "noTransactions": { + "message": "No Transactions" + }, + "notStarted": { + "message": "Not Started" + }, + "oldUI": { + "message": "Old UI" + }, + "oldUIMessage": { + "message": "You have returned to the old UI. You can switch back to the New UI through the option in the top right dropdown menu." + }, + "or": { + "message": "or" + }, + "passwordMismatch": { + "message": "passwords don't match" + }, + "passwordShort": { + "message": "password not long enough" + }, + "pastePrivateKey": { + "message": "Paste your private key string here:" + }, + "pasteSeed": { + "message": "Paste your seed phrase here!" + }, + "privateKeyWarning": { + "message": "Warning: Never disclose this key. Anyone with your private keys can take steal any assets held in your account." + }, + "privateNetwork": { + "message": "Private Network" + }, + "qrCode": { + "message": "Show QR Code" + }, + "readdToken": { + "message": "You can add this token back in the future by going go to “Add token” in your accounts options menu." + }, + "readMore": { + "message": "Read more here." + }, + "receive": { + "message": "Receive" + }, + "recipientAddress": { + "message": "Recipient Address" + }, + "refundAddress": { + "message": "Your Refund Address" + }, + "rejected": { + "message": "Rejected" + }, + "required": { + "message": "Required" + }, + "retryWithMoreGas": { + "message": "Retry with a higher gas price here" + }, + "revert": { + "message": "Revert" + }, + "rinkeby": { + "message": "Rinkeby Test Network" + }, + "ropsten": { + "message": "Ropsten Test Network" + }, + "sampleAccountName": { + "message": "E.g. My new account" + }, + "saveCaps": { + "message": "SAVE" + }, + "selectService": { + "message": "Select Service" + }, + "sendButton": { + "message": "SEND" + }, + "sendTokens": { + "message": "Send Tokens" + }, + "sendTokensAnywhere": { + "message": "Send Tokens to anyone with an Ethereum account" + }, + "settings": { + "message": "Settings" + }, + "shapeshiftBuy": { + "message": "Buy with Shapeshift" + }, + "showPrivateKeys": { + "message": "Show Private Keys" + }, + "sign": { + "message": "Sign" + }, + "signCaps": { + "message": "SIGN" + }, + "signMessage": { + "message": "Sign Message" + }, + "signNotice": { + "message": "Signing this message can have \ndangerous side effects. Only sign messages from \nsites you fully trust with your entire account.\n This dangerous method will be removed in a future version. " + }, + "sigRequested": { + "message": "Signature Requested" + }, + "status": { + "message": "Status" + }, + "submit": { + "message": "Submit" + }, + "takesTooLong": { + "message": "Taking too long?" + }, + "testFaucet": { + "message": "Test Faucet" + }, + "to": { + "message": "To" + }, + "tokenBalance": { + "message": "Your Token Balance is:" + }, + "toSpecific": { + "message": "To:" + }, + "total": { + "message": "Total" + }, + "transactionMemo": { + "message": "Transaction memo (optional)" + }, + "transactionNumber": { + "message": "Transaction Number" + }, + "transfers": { + "message": "Transfers" + }, + "troubleTokenBalances": { + "message": "We had trouble loading your token balances. You can view them " + }, + "typePassword": { + "message": "Type Your Password" + }, + "uiWelcome": { + "message": "Welcome to the New UI (Beta)" + }, + "uiWelcomeMessage": { + "message": "You are now using the new Metamask UI. Take a look around, try out new features like sending tokens, and let us know if you have any issues." + }, + "unavailable": { + "message": "Unavailable" + }, + "unknown": { + "message": "Unknown" + }, + "unknownNetwork": { + "message": "Unknown Private Network" + }, + "unknownNetworkId": { + "message": "Unknown network ID" + }, + "usedByClients": { + "message": "Used by a variety of different clients" + }, + "viewAccount": { + "message": "View Account" + }, + "warning": { + "message": "Warning" + }, + "whatsThis": { + "message": "What's this?" + }, + "yourSigRequested": { + "message": "Your signature is being requested" + }, + "youSign": { + "message": "You are signing:" + }, + "youSignCaps": { + "message": "YOU ARE SIGNING" + } } diff --git a/ui/app/accounts/import/json.js b/ui/app/accounts/import/json.js index 9cefcfa77..ca9a29e34 100644 --- a/ui/app/accounts/import/json.js +++ b/ui/app/accounts/import/json.js @@ -26,8 +26,8 @@ JsonImportSubview.prototype.render = function () { return ( h('div.new-account-import-form__json', [ - h('p', 'Used by a variety of different clients'), - h('a.warning', { href: HELP_LINK, target: '_blank' }, 'File import not working? Click here!'), + h('p', t('usedByClients')), + h('a.warning', { href: HELP_LINK, target: '_blank' }, t('fileImportFail')), h(FileInput, { readAs: 'text', @@ -42,7 +42,7 @@ JsonImportSubview.prototype.render = function () { h('input.new-account-import-form__input-password', { type: 'password', - placeholder: 'Enter password', + placeholder: t('enterPassword'), id: 'json-password-box', onKeyPress: this.createKeyringOnEnter.bind(this), }), @@ -52,13 +52,13 @@ JsonImportSubview.prototype.render = function () { h('button.new-account-create-form__button-cancel', { onClick: () => this.props.goHome(), }, [ - 'CANCEL', + t('cancelCaps'), ]), h('button.new-account-create-form__button-create', { onClick: () => this.createNewKeychain.bind(this), }, [ - 'IMPORT', + t('importCaps'), ]), ]), @@ -84,7 +84,7 @@ JsonImportSubview.prototype.createNewKeychain = function () { const { fileContents } = state if (!fileContents) { - const message = 'You must select a file to import.' + const message = t('needImportFile') return this.props.dispatch(actions.displayWarning(message)) } @@ -92,7 +92,7 @@ JsonImportSubview.prototype.createNewKeychain = function () { const password = passwordInput.value if (!password) { - const message = 'You must enter a password for the selected file.' + const message = t('needImportPassword') return this.props.dispatch(actions.displayWarning(message)) } diff --git a/ui/app/accounts/import/private-key.js b/ui/app/accounts/import/private-key.js index 43afbca87..d8aa1a3d8 100644 --- a/ui/app/accounts/import/private-key.js +++ b/ui/app/accounts/import/private-key.js @@ -32,7 +32,7 @@ PrivateKeyImportView.prototype.render = function () { return ( h('div.new-account-import-form__private-key', [ - h('span.new-account-create-form__instruction', 'Paste your private key string here:'), + h('span.new-account-create-form__instruction', t('pastePrivateKey')), h('input.new-account-import-form__input-password', { type: 'password', @@ -45,13 +45,13 @@ PrivateKeyImportView.prototype.render = function () { h('button.new-account-create-form__button-cancel', { onClick: () => goHome(), }, [ - 'CANCEL', + t('cancelCaps'), ]), h('button.new-account-create-form__button-create', { onClick: () => this.createNewKeychain(), }, [ - 'IMPORT', + t('importCaps'), ]), ]), diff --git a/ui/app/accounts/import/seed.js b/ui/app/accounts/import/seed.js index b4a7c0afa..241200c6f 100644 --- a/ui/app/accounts/import/seed.js +++ b/ui/app/accounts/import/seed.js @@ -20,11 +20,10 @@ SeedImportSubview.prototype.render = function () { style: { }, }, [ - `Paste your seed phrase here!`, + t('pasteSeed'), h('textarea'), h('br'), - h('button', 'Submit'), + h('button', t('submit')), ]) ) } - diff --git a/ui/app/accounts/new-account/create-form.js b/ui/app/accounts/new-account/create-form.js index 494726ae4..f9faa928c 100644 --- a/ui/app/accounts/new-account/create-form.js +++ b/ui/app/accounts/new-account/create-form.js @@ -21,13 +21,13 @@ class NewAccountCreateForm extends Component { return h('div.new-account-create-form', [ h('div.new-account-create-form__input-label', {}, [ - 'Account Name', + t('accountName'), ]), h('div.new-account-create-form__input-wrapper', {}, [ h('input.new-account-create-form__input', { value: this.state.newAccountName, - placeholder: 'E.g. My new account', + placeholder: t('sampleAccountName'), onChange: event => this.setState({ newAccountName: event.target.value }), }, []), ]), @@ -37,13 +37,13 @@ class NewAccountCreateForm extends Component { h('button.new-account-create-form__button-cancel', { onClick: () => this.props.goHome(), }, [ - 'CANCEL', + t('cancelCaps'), ]), h('button.new-account-create-form__button-create', { onClick: () => this.props.createAccount(newAccountName), }, [ - 'CREATE', + t('createCaps'), ]), ]), diff --git a/ui/app/accounts/new-account/index.js b/ui/app/accounts/new-account/index.js index acf0dc6e4..1ed43ae08 100644 --- a/ui/app/accounts/new-account/index.js +++ b/ui/app/accounts/new-account/index.js @@ -42,10 +42,10 @@ AccountDetailsModal.prototype.render = function () { const { displayedForm, displayForm } = this.props return h('div.new-account', {}, [ - + h('div.new-account__header', [ - h('div.new-account__title', 'New Account'), + h('div.new-account__title', t('newAccount')), h('div.new-account__tabs', [ @@ -55,7 +55,7 @@ AccountDetailsModal.prototype.render = function () { 'new-account__tabs__unselected cursor-pointer': displayedForm !== 'CREATE', }), onClick: () => displayForm('CREATE'), - }, 'Create'), + }, t('createDen')), h('div.new-account__tabs__tab', { className: classnames('new-account__tabs__tab', { @@ -63,7 +63,7 @@ AccountDetailsModal.prototype.render = function () { 'new-account__tabs__unselected cursor-pointer': displayedForm !== 'IMPORT', }), onClick: () => displayForm('IMPORT'), - }, 'Import'), + }, t('import')), ]), diff --git a/ui/app/components/customize-gas-modal/index.js b/ui/app/components/customize-gas-modal/index.js index a5384daaf..ae9ff769d 100644 --- a/ui/app/components/customize-gas-modal/index.js +++ b/ui/app/components/customize-gas-modal/index.js @@ -284,11 +284,11 @@ CustomizeGasModal.prototype.render = function () { h('div.send-v2__customize-gas__buttons', [ h('div.send-v2__customize-gas__cancel', { onClick: this.props.hideModal, - }, [t('cancelButton')]), + }, [t('cancelCaps')]), h(`div.send-v2__customize-gas__save${error ? '__error' : ''}`, { onClick: () => !error && this.save(gasPrice, gasLimit, gasTotal), - }, [t('saveButton')]), + }, [t('saveCaps')]), ]), ]), diff --git a/ui/app/components/dropdowns/components/account-dropdowns.js b/ui/app/components/dropdowns/components/account-dropdowns.js index 7ecec38d2..76fbb8060 100644 --- a/ui/app/components/dropdowns/components/account-dropdowns.js +++ b/ui/app/components/dropdowns/components/account-dropdowns.js @@ -129,7 +129,7 @@ class AccountDropdowns extends Component { actions.showEditAccountModal(identity) }, }, [ - t('editButton'), + t('editCaps'), ]), ]), diff --git a/ui/app/components/modals/account-details-modal.js b/ui/app/components/modals/account-details-modal.js index c1f7a3236..746c6de4c 100644 --- a/ui/app/components/modals/account-details-modal.js +++ b/ui/app/components/modals/account-details-modal.js @@ -64,12 +64,12 @@ AccountDetailsModal.prototype.render = function () { h('button.btn-clear.account-modal__button', { onClick: () => global.platform.openWindow({ url: genAccountLink(address, network) }), - }, 'View account on Etherscan'), + }, t('etherscanView')), // Holding on redesign for Export Private Key functionality h('button.btn-clear.account-modal__button', { onClick: () => showExportPrivateKeyModal(), - }, 'Export private key'), + }, t('exportPrivateKeyLower')), ]) } diff --git a/ui/app/components/modals/account-modal-container.js b/ui/app/components/modals/account-modal-container.js index c548fb7b3..538edcf13 100644 --- a/ui/app/components/modals/account-modal-container.js +++ b/ui/app/components/modals/account-modal-container.js @@ -59,7 +59,7 @@ AccountModalContainer.prototype.render = function () { h('i.fa.fa-angle-left.fa-lg'), - h('span.account-modal-back__text', ' Back'), + h('span.account-modal-back__text', ' ' + t('back')), ]), diff --git a/ui/app/components/modals/buy-options-modal.js b/ui/app/components/modals/buy-options-modal.js index 74a7a847e..60fef7db4 100644 --- a/ui/app/components/modals/buy-options-modal.js +++ b/ui/app/components/modals/buy-options-modal.js @@ -56,15 +56,15 @@ BuyOptions.prototype.render = function () { }, [ h('div.buy-modal-content-title', { style: {}, - }, 'Transfers'), - h('div', {}, 'How would you like to deposit Ether?'), + }, t('transfers')), + h('div', {}, t('howToDeposit')), ]), h('div.buy-modal-content-options.flex-column.flex-center', {}, [ isTestNetwork - ? this.renderModalContentOption(networkName, 'Test Faucet', () => toFaucet(network)) - : this.renderModalContentOption('Coinbase', 'Deposit with Fiat', () => toCoinbase(address)), + ? this.renderModalContentOption(networkName, t('testFaucet'), () => toFaucet(network)) + : this.renderModalContentOption('Coinbase', t('depositFiat'), () => toCoinbase(address)), // h('div.buy-modal-content-option', {}, [ // h('div.buy-modal-content-option-title', {}, 'Shapeshift'), @@ -72,8 +72,8 @@ BuyOptions.prototype.render = function () { // ]),, this.renderModalContentOption( - 'Direct Deposit', - 'Deposit from another account', + t('directDeposit'), + t('depositFromAccount'), () => this.goToAccountDetailsModal() ), @@ -84,7 +84,7 @@ BuyOptions.prototype.render = function () { background: 'white', }, onClick: () => { this.props.hideModal() }, - }, h('div.buy-modal-content-footer#buy-modal-content-footer-text', {}, 'Cancel')), + }, h('div.buy-modal-content-footer#buy-modal-content-footer-text', {}, t('cancel'))), ]), ]) } diff --git a/ui/app/components/modals/deposit-ether-modal.js b/ui/app/components/modals/deposit-ether-modal.js index 532d66653..85f640a68 100644 --- a/ui/app/components/modals/deposit-ether-modal.js +++ b/ui/app/components/modals/deposit-ether-modal.js @@ -6,16 +6,13 @@ const actions = require('../../actions') const networkNames = require('../../../../app/scripts/config.js').networkNames const ShapeshiftForm = require('../shapeshift-form') -const DIRECT_DEPOSIT_ROW_TITLE = 'Directly Deposit Ether' -const DIRECT_DEPOSIT_ROW_TEXT = `If you already have some Ether, the quickest way to get Ether in -your new wallet by direct deposit.` -const COINBASE_ROW_TITLE = 'Buy on Coinbase' -const COINBASE_ROW_TEXT = `Coinbase is the world’s most popular way to buy and sell bitcoin, -ethereum, and litecoin.` -const SHAPESHIFT_ROW_TITLE = 'Deposit with ShapeShift' -const SHAPESHIFT_ROW_TEXT = `If you own other cryptocurrencies, you can trade and deposit Ether -directly into your MetaMask wallet. No Account Needed.` -const FAUCET_ROW_TITLE = 'Test Faucet' +const DIRECT_DEPOSIT_ROW_TITLE = t('directDepositEther') +const DIRECT_DEPOSIT_ROW_TEXT = t('directDepositEtherExplainer') +const COINBASE_ROW_TITLE = t('buyCoinbase') +const COINBASE_ROW_TEXT = t('buyCoinbaseExplainer') +const SHAPESHIFT_ROW_TITLE = t('depositShapeShift') +const SHAPESHIFT_ROW_TEXT = t('depositShapeShiftExplainer') +const FAUCET_ROW_TITLE = t('testFaucet') const facuetRowText = networkName => `Get Ether from a faucet for the ${networkName}` function mapStateToProps (state) { @@ -110,10 +107,10 @@ DepositEtherModal.prototype.render = function () { h('div.deposit-ether-modal__header', [ - h('div.deposit-ether-modal__header__title', ['Deposit Ether']), + h('div.deposit-ether-modal__header__title', [t('depositEther')]), h('div.deposit-ether-modal__header__description', [ - 'To interact with decentralized applications using MetaMask, you’ll need Ether in your wallet.', + t('needEtherInWallet'), ]), h('div.deposit-ether-modal__header__close', { @@ -131,7 +128,7 @@ DepositEtherModal.prototype.render = function () { logo: h('img.deposit-ether-modal__buy-row__eth-logo', { src: '../../../images/eth_logo.svg' }), title: DIRECT_DEPOSIT_ROW_TITLE, text: DIRECT_DEPOSIT_ROW_TEXT, - buttonLabel: 'View Account', + buttonLabel: t('viewAccount'), onButtonClick: () => this.goToAccountDetailsModal(), hide: buyingWithShapeshift, }), @@ -140,7 +137,7 @@ DepositEtherModal.prototype.render = function () { logo: h('i.fa.fa-tint.fa-2x'), title: FAUCET_ROW_TITLE, text: facuetRowText(networkName), - buttonLabel: 'Get Ether', + buttonLabel: t('getEther'), onButtonClick: () => toFaucet(network), hide: !isTestNetwork || buyingWithShapeshift, }), @@ -151,7 +148,7 @@ DepositEtherModal.prototype.render = function () { }), title: COINBASE_ROW_TITLE, text: COINBASE_ROW_TEXT, - buttonLabel: 'Continue to Coinbase', + buttonLabel: t('continueToCoinbase'), onButtonClick: () => toCoinbase(address), hide: isTestNetwork || buyingWithShapeshift, }), @@ -162,7 +159,7 @@ DepositEtherModal.prototype.render = function () { }), title: SHAPESHIFT_ROW_TITLE, text: SHAPESHIFT_ROW_TEXT, - buttonLabel: 'Buy with Shapeshift', + buttonLabel: t('shapeshiftBuy'), onButtonClick: () => this.setState({ buyingWithShapeshift: true }), hide: isTestNetwork, hideButton: buyingWithShapeshift, diff --git a/ui/app/components/modals/edit-account-name-modal.js b/ui/app/components/modals/edit-account-name-modal.js index e2361140d..410fac7ba 100644 --- a/ui/app/components/modals/edit-account-name-modal.js +++ b/ui/app/components/modals/edit-account-name-modal.js @@ -50,7 +50,7 @@ EditAccountNameModal.prototype.render = function () { ]), h('div.edit-account-name-modal-title', { - }, ['Edit Account Name']), + }, [t('editAccountName')]), h('input.edit-account-name-modal-input', { placeholder: identity.name, @@ -69,7 +69,7 @@ EditAccountNameModal.prototype.render = function () { }, disabled: this.state.inputText.length === 0, }, [ - 'SAVE', + t('saveCaps'), ]), ]), diff --git a/ui/app/components/modals/export-private-key-modal.js b/ui/app/components/modals/export-private-key-modal.js index 422f23f44..0745827cb 100644 --- a/ui/app/components/modals/export-private-key-modal.js +++ b/ui/app/components/modals/export-private-key-modal.js @@ -48,8 +48,8 @@ ExportPrivateKeyModal.prototype.exportAccountAndGetPrivateKey = function (passwo ExportPrivateKeyModal.prototype.renderPasswordLabel = function (privateKey) { return h('span.private-key-password-label', privateKey - ? 'This is your private key (click to copy)' - : 'Type Your Password' + ? t('copyPrivateKey') + : t('typePassword') ) } @@ -86,8 +86,8 @@ ExportPrivateKeyModal.prototype.renderButtons = function (privateKey, password, ), (privateKey - ? this.renderButton('btn-clear export-private-key__button', () => hideModal(), 'Done') - : this.renderButton('btn-clear export-private-key__button', () => this.exportAccountAndGetPrivateKey(this.state.password, address), 'Confirm') + ? this.renderButton('btn-clear export-private-key__button', () => hideModal(), t('done')) + : this.renderButton('btn-clear export-private-key__button', () => this.exportAccountAndGetPrivateKey(this.state.password, address), t('confirm')) ), ]) @@ -120,7 +120,7 @@ ExportPrivateKeyModal.prototype.render = function () { h('div.account-modal-divider'), - h('span.modal-body-title', 'Show Private Keys'), + h('span.modal-body-title', t('showPrivateKeys')), h('div.private-key-password', {}, [ this.renderPasswordLabel(privateKey), @@ -130,10 +130,7 @@ ExportPrivateKeyModal.prototype.render = function () { !warning ? null : h('span.private-key-password-error', warning), ]), - h('div.private-key-password-warning', `Warning: Never disclose this key. - Anyone with your private keys can take steal any assets held in your - account.` - ), + h('div.private-key-password-warning', t('privateKeyWarning')), this.renderButtons(privateKey, this.state.password, address, hideModal), diff --git a/ui/app/components/modals/hide-token-confirmation-modal.js b/ui/app/components/modals/hide-token-confirmation-modal.js index 56c7ba299..55f1695af 100644 --- a/ui/app/components/modals/hide-token-confirmation-modal.js +++ b/ui/app/components/modals/hide-token-confirmation-modal.js @@ -41,7 +41,7 @@ HideTokenConfirmationModal.prototype.render = function () { h('div.hide-token-confirmation__container', { }, [ h('div.hide-token-confirmation__title', {}, [ - 'Hide Token?', + t('hideTokenPrompt'), ]), h(Identicon, { @@ -54,19 +54,19 @@ HideTokenConfirmationModal.prototype.render = function () { h('div.hide-token-confirmation__symbol', {}, symbol), h('div.hide-token-confirmation__copy', {}, [ - 'You can add this token back in the future by going go to “Add token” in your accounts options menu.', + t('readdToken'), ]), h('div.hide-token-confirmation__buttons', {}, [ h('button.btn-cancel.hide-token-confirmation__button', { onClick: () => hideModal(), }, [ - 'CANCEL', + t('cancelCaps'), ]), h('button.btn-clear.hide-token-confirmation__button', { onClick: () => hideToken(address), }, [ - 'HIDE', + t('hideCaps'), ]), ]), ]), diff --git a/ui/app/components/modals/modal.js b/ui/app/components/modals/modal.js index afb2a2175..e4e644d40 100644 --- a/ui/app/components/modals/modal.js +++ b/ui/app/components/modals/modal.js @@ -169,9 +169,8 @@ const MODALS = { BETA_UI_NOTIFICATION_MODAL: { contents: [ h(NotifcationModal, { - header: 'Welcome to the New UI (Beta)', - message: `You are now using the new Metamask UI. Take a look around, try out new features like sending tokens, - and let us know if you have any issues.`, + header: t('uiWelcome'), + message: t('uiWelcomeMessage'), }), ], mobileModalStyle: { @@ -187,9 +186,8 @@ const MODALS = { OLD_UI_NOTIFICATION_MODAL: { contents: [ h(NotifcationModal, { - header: 'Old UI', - message: `You have returned to the old UI. You can switch back to the New UI through the option in the top - right dropdown menu.`, + header: t('oldUI'), + message: t('oldUIMessage'), }), ], mobileModalStyle: { diff --git a/ui/app/components/modals/new-account-modal.js b/ui/app/components/modals/new-account-modal.js index fc1fd413d..4fdfbd745 100644 --- a/ui/app/components/modals/new-account-modal.js +++ b/ui/app/components/modals/new-account-modal.js @@ -22,7 +22,7 @@ class NewAccountModal extends Component { h('div.new-account-modal-wrapper', { }, [ h('div.new-account-modal-header', {}, [ - 'New Account', + t('newAccount'), ]), h('div.modal-close-x', { @@ -30,19 +30,19 @@ class NewAccountModal extends Component { }), h('div.new-account-modal-content', {}, [ - 'Account Name', + t('accountName'), ]), h('div.new-account-input-wrapper', {}, [ h('input.new-account-input', { value: this.state.newAccountName, - placeholder: 'E.g. My new account', + placeholder: t('sampleAccountName'), onChange: event => this.setState({ newAccountName: event.target.value }), }, []), ]), h('div.new-account-modal-content.after-input', {}, [ - 'or', + t('or'), ]), h('div.new-account-modal-content.after-input.pointer', { @@ -50,13 +50,13 @@ class NewAccountModal extends Component { this.props.hideModal() this.props.showImportPage() }, - }, 'Import an account'), + }, t('importAnAccount')), h('div.new-account-modal-content.button', {}, [ h('button.btn-clear', { onClick: () => this.props.createAccount(newAccountName), }, [ - 'SAVE', + t('saveCaps'), ]), ]), ]), diff --git a/ui/app/components/pending-tx/confirm-deploy-contract.js b/ui/app/components/pending-tx/confirm-deploy-contract.js index ae6c6ef7b..0d8b2721f 100644 --- a/ui/app/components/pending-tx/confirm-deploy-contract.js +++ b/ui/app/components/pending-tx/confirm-deploy-contract.js @@ -200,7 +200,7 @@ ConfirmDeployContract.prototype.renderGasFee = function () { return ( h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ 'Gas Fee' ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ t('gasFee') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', `${fiatGas} ${currentCurrency.toUpperCase()}`), @@ -239,8 +239,8 @@ ConfirmDeployContract.prototype.renderTotalPlusGas = function () { return ( h('section.flex-row.flex-center.confirm-screen-total-box ', [ h('div.confirm-screen-section-column', [ - h('span.confirm-screen-label', [ 'Total ' ]), - h('div.confirm-screen-total-box__subtitle', [ 'Amount + Gas' ]), + h('span.confirm-screen-label', [ t('total') + ' ' ]), + h('div.confirm-screen-total-box__subtitle', [ t('amountPlusGas') ]), ]), h('div.confirm-screen-section-column', [ @@ -274,7 +274,7 @@ ConfirmDeployContract.prototype.render = function () { h('button.confirm-screen-back-button', { onClick: () => backToAccountDetail(selectedAddress), }, 'BACK'), - h('div.confirm-screen-title', 'Confirm Contract'), + h('div.confirm-screen-title', t('confirmContract')), h('div.confirm-screen-header-tip'), ]), h('div.flex-row.flex-center.confirm-screen-identicons', [ @@ -292,7 +292,7 @@ ConfirmDeployContract.prototype.render = function () { h('i.fa.fa-arrow-right.fa-lg'), h('div.confirm-screen-account-wrapper', [ h('i.fa.fa-file-text-o'), - h('span.confirm-screen-account-name', 'New Contract'), + h('span.confirm-screen-account-name', t('newContract')), h('span.confirm-screen-account-number', ' '), ]), ]), @@ -310,7 +310,7 @@ ConfirmDeployContract.prototype.render = function () { h('div.confirm-screen-rows', [ h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ 'From' ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ t('from') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', fromName), h('div.confirm-screen-row-detail', `...${fromAddress.slice(fromAddress.length - 4)}`), @@ -318,9 +318,9 @@ ConfirmDeployContract.prototype.render = function () { ]), h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ 'To' ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ t('to') ]), h('div.confirm-screen-section-column', [ - h('div.confirm-screen-row-info', 'New Contract'), + h('div.confirm-screen-row-info', t('newContract')), ]), ]), @@ -337,10 +337,10 @@ ConfirmDeployContract.prototype.render = function () { // Cancel Button h('div.cancel.btn-light.confirm-screen-cancel-button', { onClick: (event) => this.cancel(event, txMeta), - }, 'CANCEL'), + }, t('cancelCaps')), // Accept Button - h('button.confirm-screen-confirm-button', ['CONFIRM']), + h('button.confirm-screen-confirm-button', [t('confirmCaps')]), ]), ]) diff --git a/ui/app/components/pending-tx/confirm-send-ether.js b/ui/app/components/pending-tx/confirm-send-ether.js index 652300c94..7608e02ad 100644 --- a/ui/app/components/pending-tx/confirm-send-ether.js +++ b/ui/app/components/pending-tx/confirm-send-ether.js @@ -165,7 +165,7 @@ ConfirmSendEther.prototype.getData = function () { }, to: { address: txParams.to, - name: identities[txParams.to] ? identities[txParams.to].name : 'New Recipient', + name: identities[txParams.to] ? identities[txParams.to].name : t('newRecipient'), }, memo: txParams.memo || '', gasFeeInFIAT, @@ -268,7 +268,7 @@ ConfirmSendEther.prototype.render = function () { h('div.confirm-screen-rows', [ h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ 'From' ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ t('from') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', fromName), h('div.confirm-screen-row-detail', `...${fromAddress.slice(fromAddress.length - 4)}`), @@ -276,7 +276,7 @@ ConfirmSendEther.prototype.render = function () { ]), h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ 'To' ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ t('to') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', toName), h('div.confirm-screen-row-detail', `...${toAddress.slice(toAddress.length - 4)}`), @@ -284,7 +284,7 @@ ConfirmSendEther.prototype.render = function () { ]), h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ 'Gas Fee' ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ t('gasFee') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', `${gasFeeInFIAT} ${currentCurrency.toUpperCase()}`), @@ -295,8 +295,8 @@ ConfirmSendEther.prototype.render = function () { h('section.flex-row.flex-center.confirm-screen-total-box ', [ h('div.confirm-screen-section-column', [ - h('span.confirm-screen-label', [ 'Total ' ]), - h('div.confirm-screen-total-box__subtitle', [ 'Amount + Gas' ]), + h('span.confirm-screen-label', [ t('total') + ' ' ]), + h('div.confirm-screen-total-box__subtitle', [ t('amountPlusGas') ]), ]), h('div.confirm-screen-section-column', [ @@ -396,10 +396,10 @@ ConfirmSendEther.prototype.render = function () { clearSend() this.cancel(event, txMeta) }, - }, 'CANCEL'), + }, t('cancelCaps')), // Accept Button - h('button.confirm-screen-confirm-button', ['CONFIRM']), + h('button.confirm-screen-confirm-button', [t('confirmCaps')]), ]), ]) ) @@ -414,7 +414,7 @@ ConfirmSendEther.prototype.onSubmit = function (event) { if (valid && this.verifyGasParams()) { this.props.sendTransaction(txMeta, event) } else { - this.props.dispatch(actions.displayWarning('Invalid Gas Parameters')) + this.props.dispatch(actions.displayWarning(t('invalidGasParams'))) this.setState({ submitting: false }) } } diff --git a/ui/app/components/pending-tx/confirm-send-token.js b/ui/app/components/pending-tx/confirm-send-token.js index ad489c3e9..88644d57a 100644 --- a/ui/app/components/pending-tx/confirm-send-token.js +++ b/ui/app/components/pending-tx/confirm-send-token.js @@ -133,7 +133,7 @@ ConfirmSendToken.prototype.getAmount = function () { ? +(sendTokenAmount * tokenExchangeRate * conversionRate).toFixed(2) : null, token: typeof value === 'undefined' - ? 'Unknown' + ? t('unknown') : +sendTokenAmount.toFixed(decimals), } @@ -204,7 +204,7 @@ ConfirmSendToken.prototype.getData = function () { }, to: { address: value, - name: identities[value] ? identities[value].name : 'New Recipient', + name: identities[value] ? identities[value].name : t('newRecipient'), }, memo: txParams.memo || '', } @@ -244,7 +244,7 @@ ConfirmSendToken.prototype.renderGasFee = function () { return ( h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ 'Gas Fee' ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ t('gasFee') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', `${fiatGas} ${currentCurrency}`), @@ -266,8 +266,8 @@ ConfirmSendToken.prototype.renderTotalPlusGas = function () { ? ( h('section.flex-row.flex-center.confirm-screen-total-box ', [ h('div.confirm-screen-section-column', [ - h('span.confirm-screen-label', [ 'Total ' ]), - h('div.confirm-screen-total-box__subtitle', [ 'Amount + Gas' ]), + h('span.confirm-screen-label', [ t('total') + ' ' ]), + h('div.confirm-screen-total-box__subtitle', [ t('amountPlusGas') ]), ]), h('div.confirm-screen-section-column', [ @@ -279,8 +279,8 @@ ConfirmSendToken.prototype.renderTotalPlusGas = function () { : ( h('section.flex-row.flex-center.confirm-screen-total-box ', [ h('div.confirm-screen-section-column', [ - h('span.confirm-screen-label', [ 'Total ' ]), - h('div.confirm-screen-total-box__subtitle', [ 'Amount + Gas' ]), + h('span.confirm-screen-label', [ t('total') + ' ' ]), + h('div.confirm-screen-total-box__subtitle', [ t('amountPlusGas') ]), ]), h('div.confirm-screen-section-column', [ @@ -316,7 +316,7 @@ ConfirmSendToken.prototype.render = function () { h('h3.flex-center.confirm-screen-header', [ h('button.btn-clear.confirm-screen-back-button', { onClick: () => editTransaction(txMeta), - }, 'EDIT'), + }, t('editCaps')), h('div.confirm-screen-title', 'Confirm Transaction'), h('div.confirm-screen-header-tip'), ]), @@ -359,7 +359,7 @@ ConfirmSendToken.prototype.render = function () { h('div.confirm-screen-rows', [ h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ 'From' ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ t('from') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', fromName), h('div.confirm-screen-row-detail', `...${fromAddress.slice(fromAddress.length - 4)}`), @@ -367,7 +367,7 @@ ConfirmSendToken.prototype.render = function () { ]), toAddress && h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ 'To' ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ t('to') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', toName), h('div.confirm-screen-row-detail', `...${toAddress.slice(toAddress.length - 4)}`), @@ -387,10 +387,10 @@ ConfirmSendToken.prototype.render = function () { // Cancel Button h('div.cancel.btn-light.confirm-screen-cancel-button', { onClick: (event) => this.cancel(event, txMeta), - }, 'CANCEL'), + }, t('cancelCaps')), // Accept Button - h('button.confirm-screen-confirm-button', ['CONFIRM']), + h('button.confirm-screen-confirm-button', [t('confirmCaps')]), ]), @@ -407,7 +407,7 @@ ConfirmSendToken.prototype.onSubmit = function (event) { if (valid && this.verifyGasParams()) { this.props.sendTransaction(txMeta, event) } else { - this.props.dispatch(actions.displayWarning('Invalid Gas Parameters')) + this.props.dispatch(actions.displayWarning(t('invalidGasParams'))) this.setState({ submitting: false }) } } diff --git a/ui/app/components/pending-typed-msg.js b/ui/app/components/pending-typed-msg.js index 73702d0f8..f0f846027 100644 --- a/ui/app/components/pending-typed-msg.js +++ b/ui/app/components/pending-typed-msg.js @@ -35,10 +35,10 @@ PendingMsg.prototype.render = function () { h('.flex-row.flex-space-around', [ h('button', { onClick: state.cancelTypedMessage, - }, t('cancelButton')), + }, t('cancelCaps')), h('button', { onClick: state.signTypedMessage, - }, t('signButton')), + }, t('signCaps')), ]), ]) diff --git a/ui/app/components/send-token/index.js b/ui/app/components/send-token/index.js index 99d078251..a40664977 100644 --- a/ui/app/components/send-token/index.js +++ b/ui/app/components/send-token/index.js @@ -126,14 +126,14 @@ SendTokenScreen.prototype.validate = function () { const amount = Number(stringAmount) const errors = { - to: !to ? 'Required' : null, - amount: !amount ? 'Required' : null, - gasPrice: !gasPrice ? 'Gas Price Required' : null, - gasLimit: !gasLimit ? 'Gas Limit Required' : null, + to: !to ? t('required') : null, + amount: !amount ? t('required') : null, + gasPrice: !gasPrice ? t('gasPriceRequired') : null, + gasLimit: !gasLimit ? t('gasLimitRequired') : null, } if (to && !isValidAddress(to)) { - errors.to = 'Invalid address' + errors.to = t('invalidAddress') } const isValid = Object.entries(errors).every(([key, value]) => value === null) @@ -233,11 +233,11 @@ SendTokenScreen.prototype.renderToAddressInput = function () { 'send-screen-input-wrapper--error': errorMessage, }), }, [ - h('div', ['To:']), + h('div', [t('toSpecific')]), h('input.large-input.send-screen-input', { name: 'address', list: 'addresses', - placeholder: 'Address', + placeholder: t('address'), value: to, onChange: e => this.setState({ to: e.target.value, @@ -355,8 +355,8 @@ SendTokenScreen.prototype.renderGasInput = function () { }), h('div.send-screen-gas-labels', {}, [ - h('span', [ h('i.fa.fa-bolt'), 'Gas fee:']), - h('span', ['What\'s this?']), + h('span', [ h('i.fa.fa-bolt'), t('gasFeeSpecific')]), + h('span', [t('whatsThis')]), ]), h('div.large-input.send-screen-gas-input', [ h(GasFeeDisplay, { @@ -370,7 +370,7 @@ SendTokenScreen.prototype.renderGasInput = function () { h( 'div.send-screen-gas-input-customize', { onClick: () => this.setState({ isGasTooltipOpen: !isGasTooltipOpen }) }, - ['Customize'] + [t('customize')] ), ]), h('div.send-screen-input-wrapper__error-message', [ @@ -381,7 +381,7 @@ SendTokenScreen.prototype.renderGasInput = function () { SendTokenScreen.prototype.renderMemoInput = function () { return h('div.send-screen-input-wrapper', [ - h('div', {}, ['Transaction memo (optional)']), + h('div', {}, [t('transactionMemo')]), h( 'input.large-input.send-screen-input', { onChange: e => this.setState({ memo: e.target.value }) } @@ -397,10 +397,10 @@ SendTokenScreen.prototype.renderButtons = function () { h('button.send-token__button-next.btn-secondary', { className: !isValid && 'send-screen__send-button__disabled', onClick: () => isValid && this.submit(), - }, ['Next']), + }, [t('next')]), h('button.send-token__button-cancel.btn-tertiary', { onClick: () => backToAccountDetail(selectedAddress), - }, ['Cancel']), + }, [t('cancel')]), ]) } @@ -417,9 +417,9 @@ SendTokenScreen.prototype.render = function () { diameter: 75, address: selectedTokenAddress, }), - h('div.send-token__title', ['Send Tokens']), - h('div.send-token__description', ['Send Tokens to anyone with an Ethereum account']), - h('div.send-token__balance-text', ['Your Token Balance is:']), + h('div.send-token__title', [t('sendTokens')]), + h('div.send-token__description', [t('sendTokensAnywhere')]), + h('div.send-token__balance-text', [t('tokenBalance')]), h('div.send-token__token-balance', [ h(TokenBalance, { token: selectedToken, balanceOnly: true }), ]), diff --git a/ui/app/components/send/gas-fee-display-v2.js b/ui/app/components/send/gas-fee-display-v2.js index 0c4c3f7a9..edaa297b9 100644 --- a/ui/app/components/send/gas-fee-display-v2.js +++ b/ui/app/components/send/gas-fee-display-v2.js @@ -30,7 +30,7 @@ GasFeeDisplay.prototype.render = function () { convertedPrefix: '$', readOnly: true, }) - : h('div.currency-display', 'Loading...'), + : h('div.currency-display', t('loading')), h('button.send-v2__sliders-icon-container', { onClick, @@ -41,4 +41,3 @@ GasFeeDisplay.prototype.render = function () { ]) } - diff --git a/ui/app/components/send/gas-tooltip.js b/ui/app/components/send/gas-tooltip.js index 46aff3499..da2a53c9e 100644 --- a/ui/app/components/send/gas-tooltip.js +++ b/ui/app/components/send/gas-tooltip.js @@ -81,7 +81,7 @@ GasTooltip.prototype.render = function () { 'marginTop': '81px', }, }, [ - h('span.gas-tooltip-label', {}, ['Gas Limit']), + h('span.gas-tooltip-label', {}, [t('gasLimit')]), h('i.fa.fa-info-circle'), ]), h(InputNumber, { @@ -97,4 +97,3 @@ GasTooltip.prototype.render = function () { ]), ]) } - diff --git a/ui/app/components/send/to-autocomplete.js b/ui/app/components/send/to-autocomplete.js index e0cdd0a58..85e7bfa0e 100644 --- a/ui/app/components/send/to-autocomplete.js +++ b/ui/app/components/send/to-autocomplete.js @@ -92,7 +92,7 @@ ToAutoComplete.prototype.render = function () { return h('div.send-v2__to-autocomplete', {}, [ h('input.send-v2__to-autocomplete__input', { - placeholder: 'Recipient Address', + placeholder: t('recipientAddress'), className: inError ? `send-v2__error-border` : '', value: to, onChange: event => onChange(event.target.value), @@ -111,4 +111,3 @@ ToAutoComplete.prototype.render = function () { ]) } - diff --git a/ui/app/components/signature-request.js b/ui/app/components/signature-request.js index 459d6a1a2..8003f8b1d 100644 --- a/ui/app/components/signature-request.js +++ b/ui/app/components/signature-request.js @@ -224,10 +224,10 @@ SignatureRequest.prototype.renderFooter = function () { return h('div.request-signature__footer', [ h('button.request-signature__footer__cancel-button', { onClick: cancel, - }, t('cancelButton')), + }, t('cancelCaps')), h('button.request-signature__footer__sign-button', { onClick: sign, - }, t('signButton')), + }, t('signCaps')), ]) } From 0164030e56b1db8117a1a0bdff91987321b2cd1a Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 24 Jan 2018 09:41:32 -0330 Subject: [PATCH 011/392] Handle errors when getting and setting to localStore. --- app/scripts/background.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/app/scripts/background.js b/app/scripts/background.js index 280c28d70..88600bf1e 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -57,7 +57,13 @@ async function loadStateFromPersistence () { // fetch from extension store and merge in data if (localStore.isSupported) { - const localData = await localStore.get() + let localData + try { + localData = await localStore.get() + } catch (err) { + log.error('error fetching state from local store:', err) + } + // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) versionedData = Object.keys(localData).length > 0 ? localData : versionedData } @@ -113,7 +119,11 @@ function setupController (initState) { function syncDataWithExtension(state) { if (localStore.isSupported) { - localStore.set(state) // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) + try { + localStore.set(state) + } catch (err) { + log.error('error setting state in local store:', err) + } } return state } From b7ae77f57a0e2bc68e9548364baa120805a1420c Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 24 Jan 2018 09:43:20 -0330 Subject: [PATCH 012/392] Check that extension.storage exists before attempting to call methods on it. --- app/scripts/lib/extension-store.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/scripts/lib/extension-store.js b/app/scripts/lib/extension-store.js index 67ee71f16..4a970321c 100644 --- a/app/scripts/lib/extension-store.js +++ b/app/scripts/lib/extension-store.js @@ -15,12 +15,12 @@ const handleDisabledSyncAndResolve = (resolve, toResolve) => { module.exports = class ExtensionStore { constructor() { - this.isSupported = !!(extension.storage.sync) + this.isSupported = !!(extension.storage && extension.storage.sync) this.isEnabled = true // TODO: get value from user settings } async fetch() { return new Promise((resolve) => { - extension.storage.sync.get(KEYS_TO_SYNC, (data) => { + extension.storage && extension.storage.sync.get(KEYS_TO_SYNC, (data) => { handleDisabledSyncAndResolve(resolve, data) }) }) @@ -31,7 +31,7 @@ module.exports = class ExtensionStore { return result }, {}) return new Promise((resolve) => { - extension.storage.sync.set(dataToSync, () => { + extension.storage && extension.storage.sync.set(dataToSync, () => { handleDisabledSyncAndResolve(resolve) }) }) From 598390e83ec68feaef256c0cfa3a239c6595475a Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 24 Jan 2018 09:44:00 -0330 Subject: [PATCH 013/392] Finish tests for extension-store fetch and sync. --- test/unit/extension-store-test.js | 50 +++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/test/unit/extension-store-test.js b/test/unit/extension-store-test.js index e3b5713fb..e32f37d3c 100644 --- a/test/unit/extension-store-test.js +++ b/test/unit/extension-store-test.js @@ -1,5 +1,18 @@ const assert = require('assert') +const sinon = require('sinon') +const KEYS_TO_SYNC = ['KeyringController', 'PreferencesController'] +const mockSyncGetResult = 123 +const syncGetStub = sinon.stub().callsFake((str, cb) => cb(mockSyncGetResult)) +const syncSetStub = sinon.stub().callsFake((str, cb) => cb()) + +window.storage = { + sync: { + get: syncGetStub, + set: syncSetStub, + }, +} +window.runtime = {} const ExtensionStore = require('../../app/scripts/lib/extension-store') describe('Extension Store', function () { @@ -11,19 +24,44 @@ describe('Extension Store', function () { describe('#fetch', function () { it('should return a promise', function () { - + const extensionStoreFetchResult = extensionStore.fetch() + assert.ok(Promise.resolve(extensionStoreFetchResult) === extensionStoreFetchResult) }) - it('after promise resolution, should have loaded the proper data from the extension', function () { - + it('after promise resolution, should have loaded the proper data from the extension', function (done) { + extensionStore.fetch() + .then((result) => { + assert.deepEqual(syncGetStub.getCall(0).args[0], KEYS_TO_SYNC.slice(0)) + assert.equal(result, mockSyncGetResult) + done() + }) }) }) describe('#sync', function () { it('should return a promise', function () { - + const extensionStoreSyncResult = extensionStore.sync() + assert.ok(Promise.resolve(extensionStoreSyncResult) === extensionStoreSyncResult) }) - it('after promise resolution, should have synced the proper data from the extension', function () { - + it('after promise resolution, should have synced the proper data from the extension', function (done) { + const mockState = { + data: { + KeyringController: 5, + PreferencesController: 6, + someOtherData: 7 + }, + someOtherProp: { + evenMoreData: 8, + }, + } + const expectedDataToSync = { + KeyringController: 5, + PreferencesController: 6, + } + extensionStore.sync(mockState) + .then(() => { + assert.deepEqual(syncSetStub.getCall(0).args[0], expectedDataToSync) + done() + }) }) }) }) From 61cf5e9474676878853263a8f43b2d24e739f526 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 24 Jan 2018 11:03:24 -0800 Subject: [PATCH 014/392] Bump changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 905f1f98f..89ecb33ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +- Fix bug that could cause MetaMask to lose all of its local data. + ## 3.13.7 2018-1-22 - Add ability to bypass gas estimation loading indicator. From dd80bd48babc1bfebf91ac2350491b06971b1fc1 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 24 Jan 2018 11:36:15 -0800 Subject: [PATCH 015/392] Corrected unlimitedStorage permission --- app/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/manifest.json b/app/manifest.json index 13ba074e7..114586d0f 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -56,11 +56,11 @@ ], "permissions": [ "storage", + "unlimitedStorage", "clipboardWrite", "http://localhost:8545/", "https://*.infura.io/" ], - "unlimitedStorage": true, "web_accessible_resources": [ "scripts/inpage.js" ], From f09d72fa2aa88f0def76d228cb7d8eab29e3b092 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 24 Jan 2018 11:36:42 -0800 Subject: [PATCH 016/392] Remove extension-store since we aren't using it yet --- app/scripts/lib/extension-store.js | 39 ----------------- test/unit/extension-store-test.js | 67 ------------------------------ 2 files changed, 106 deletions(-) delete mode 100644 app/scripts/lib/extension-store.js delete mode 100644 test/unit/extension-store-test.js diff --git a/app/scripts/lib/extension-store.js b/app/scripts/lib/extension-store.js deleted file mode 100644 index 4a970321c..000000000 --- a/app/scripts/lib/extension-store.js +++ /dev/null @@ -1,39 +0,0 @@ -const extension = require('extensionizer') - -const KEYS_TO_SYNC = ['KeyringController', 'PreferencesController'] -const FIREFOX_SYNC_DISABLED_MESSAGE = 'Please set webextensions.storage.sync.enabled to true in about:config' - -const handleDisabledSyncAndResolve = (resolve, toResolve) => { - // Firefox 52 has sync available on extension.storage, but it is disabled by default - const lastError = extension.runtime.lastError - if (lastError && lastError.message.includes(FIREFOX_SYNC_DISABLED_MESSAGE)) { - resolve({}) - } else { - resolve(toResolve) - } -} - -module.exports = class ExtensionStore { - constructor() { - this.isSupported = !!(extension.storage && extension.storage.sync) - this.isEnabled = true // TODO: get value from user settings - } - async fetch() { - return new Promise((resolve) => { - extension.storage && extension.storage.sync.get(KEYS_TO_SYNC, (data) => { - handleDisabledSyncAndResolve(resolve, data) - }) - }) - } - async sync(state) { - const dataToSync = KEYS_TO_SYNC.reduce((result, key) => { - result[key] = state.data[key] - return result - }, {}) - return new Promise((resolve) => { - extension.storage && extension.storage.sync.set(dataToSync, () => { - handleDisabledSyncAndResolve(resolve) - }) - }) - } -} diff --git a/test/unit/extension-store-test.js b/test/unit/extension-store-test.js deleted file mode 100644 index e32f37d3c..000000000 --- a/test/unit/extension-store-test.js +++ /dev/null @@ -1,67 +0,0 @@ -const assert = require('assert') -const sinon = require('sinon') - -const KEYS_TO_SYNC = ['KeyringController', 'PreferencesController'] -const mockSyncGetResult = 123 -const syncGetStub = sinon.stub().callsFake((str, cb) => cb(mockSyncGetResult)) -const syncSetStub = sinon.stub().callsFake((str, cb) => cb()) - -window.storage = { - sync: { - get: syncGetStub, - set: syncSetStub, - }, -} -window.runtime = {} -const ExtensionStore = require('../../app/scripts/lib/extension-store') - -describe('Extension Store', function () { - let extensionStore - - beforeEach(function () { - extensionStore = new ExtensionStore() - }) - - describe('#fetch', function () { - it('should return a promise', function () { - const extensionStoreFetchResult = extensionStore.fetch() - assert.ok(Promise.resolve(extensionStoreFetchResult) === extensionStoreFetchResult) - }) - it('after promise resolution, should have loaded the proper data from the extension', function (done) { - extensionStore.fetch() - .then((result) => { - assert.deepEqual(syncGetStub.getCall(0).args[0], KEYS_TO_SYNC.slice(0)) - assert.equal(result, mockSyncGetResult) - done() - }) - }) - }) - - describe('#sync', function () { - it('should return a promise', function () { - const extensionStoreSyncResult = extensionStore.sync() - assert.ok(Promise.resolve(extensionStoreSyncResult) === extensionStoreSyncResult) - }) - it('after promise resolution, should have synced the proper data from the extension', function (done) { - const mockState = { - data: { - KeyringController: 5, - PreferencesController: 6, - someOtherData: 7 - }, - someOtherProp: { - evenMoreData: 8, - }, - } - const expectedDataToSync = { - KeyringController: 5, - PreferencesController: 6, - } - extensionStore.sync(mockState) - .then(() => { - assert.deepEqual(syncSetStub.getCall(0).args[0], expectedDataToSync) - done() - }) - }) - }) -}) From 7da52c599784130a5f7b6737f5b017bd3a95c1ed Mon Sep 17 00:00:00 2001 From: Nick Doiron Date: Wed, 24 Jan 2018 10:10:28 -1000 Subject: [PATCH 017/392] separate out cross-browser i18n for extensions --- ui/app/accounts/import/json.js | 1 + ui/app/accounts/import/private-key.js | 1 + ui/app/accounts/import/seed.js | 1 + ui/app/accounts/new-account/create-form.js | 1 + ui/app/accounts/new-account/index.js | 1 + ui/app/components/account-menu/index.js | 1 + ui/app/components/customize-gas-modal/index.js | 1 + .../dropdowns/components/account-dropdowns.js | 1 + .../components/dropdowns/network-dropdown.js | 1 + .../dropdowns/token-menu-dropdown.js | 1 + .../components/modals/account-details-modal.js | 1 + .../modals/account-modal-container.js | 1 + ui/app/components/modals/buy-options-modal.js | 1 + .../components/modals/deposit-ether-modal.js | 1 + .../modals/edit-account-name-modal.js | 1 + .../modals/export-private-key-modal.js | 1 + .../modals/hide-token-confirmation-modal.js | 1 + ui/app/components/modals/modal.js | 1 + ui/app/components/modals/new-account-modal.js | 1 + .../pending-tx/confirm-deploy-contract.js | 1 + .../pending-tx/confirm-send-ether.js | 1 + .../pending-tx/confirm-send-token.js | 1 + ui/app/first-time/init-menu.js | 8 +------- ui/i18n.js | 18 ++++++++++++++++++ 24 files changed, 41 insertions(+), 7 deletions(-) create mode 100644 ui/i18n.js diff --git a/ui/app/accounts/import/json.js b/ui/app/accounts/import/json.js index ca9a29e34..8b5a2b469 100644 --- a/ui/app/accounts/import/json.js +++ b/ui/app/accounts/import/json.js @@ -4,6 +4,7 @@ const h = require('react-hyperscript') const connect = require('react-redux').connect const actions = require('../../actions') const FileInput = require('react-simple-file-input').default +const t = require('../../../i18n') const HELP_LINK = 'https://support.metamask.io/kb/article/7-importing-accounts' diff --git a/ui/app/accounts/import/private-key.js b/ui/app/accounts/import/private-key.js index d8aa1a3d8..4a04156e0 100644 --- a/ui/app/accounts/import/private-key.js +++ b/ui/app/accounts/import/private-key.js @@ -3,6 +3,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const connect = require('react-redux').connect const actions = require('../../actions') +const t = require('../../../i18n') module.exports = connect(mapStateToProps, mapDispatchToProps)(PrivateKeyImportView) diff --git a/ui/app/accounts/import/seed.js b/ui/app/accounts/import/seed.js index 241200c6f..9ffc669a2 100644 --- a/ui/app/accounts/import/seed.js +++ b/ui/app/accounts/import/seed.js @@ -2,6 +2,7 @@ const inherits = require('util').inherits const Component = require('react').Component const h = require('react-hyperscript') const connect = require('react-redux').connect +const t = require('../../../i18n') module.exports = connect(mapStateToProps)(SeedImportSubview) diff --git a/ui/app/accounts/new-account/create-form.js b/ui/app/accounts/new-account/create-form.js index f9faa928c..6f35e8886 100644 --- a/ui/app/accounts/new-account/create-form.js +++ b/ui/app/accounts/new-account/create-form.js @@ -3,6 +3,7 @@ const PropTypes = require('prop-types') const h = require('react-hyperscript') const { connect } = require('react-redux') const actions = require('../../actions') +const t = require('../../../i18n') class NewAccountCreateForm extends Component { constructor (props) { diff --git a/ui/app/accounts/new-account/index.js b/ui/app/accounts/new-account/index.js index 1ed43ae08..854568c77 100644 --- a/ui/app/accounts/new-account/index.js +++ b/ui/app/accounts/new-account/index.js @@ -3,6 +3,7 @@ const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../actions') +const t = require('../../../i18n') const { getCurrentViewContext } = require('../../selectors') const classnames = require('classnames') diff --git a/ui/app/components/account-menu/index.js b/ui/app/components/account-menu/index.js index aec00ff6b..9c7b6b15a 100644 --- a/ui/app/components/account-menu/index.js +++ b/ui/app/components/account-menu/index.js @@ -6,6 +6,7 @@ const actions = require('../../actions') const { Menu, Item, Divider, CloseArea } = require('../dropdowns/components/menu') const Identicon = require('../identicon') const { formatBalance } = require('../../util') +const t = require('../../../i18n') module.exports = connect(mapStateToProps, mapDispatchToProps)(AccountMenu) diff --git a/ui/app/components/customize-gas-modal/index.js b/ui/app/components/customize-gas-modal/index.js index ae9ff769d..1c6036867 100644 --- a/ui/app/components/customize-gas-modal/index.js +++ b/ui/app/components/customize-gas-modal/index.js @@ -3,6 +3,7 @@ const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../actions') +const t = require('../../../i18n') const GasModalCard = require('./gas-modal-card') const ethUtil = require('ethereumjs-util') diff --git a/ui/app/components/dropdowns/components/account-dropdowns.js b/ui/app/components/dropdowns/components/account-dropdowns.js index 76fbb8060..dfa5e5fac 100644 --- a/ui/app/components/dropdowns/components/account-dropdowns.js +++ b/ui/app/components/dropdowns/components/account-dropdowns.js @@ -10,6 +10,7 @@ const Identicon = require('../../identicon') const ethUtil = require('ethereumjs-util') const copyToClipboard = require('copy-to-clipboard') const { formatBalance } = require('../../../util') +const t = require('../../../../i18n') class AccountDropdowns extends Component { constructor (props) { diff --git a/ui/app/components/dropdowns/network-dropdown.js b/ui/app/components/dropdowns/network-dropdown.js index 02773fb46..0e16048d5 100644 --- a/ui/app/components/dropdowns/network-dropdown.js +++ b/ui/app/components/dropdowns/network-dropdown.js @@ -6,6 +6,7 @@ const actions = require('../../actions') const Dropdown = require('./components/dropdown').Dropdown const DropdownMenuItem = require('./components/dropdown').DropdownMenuItem const NetworkDropdownIcon = require('./components/network-dropdown-icon') +const t = require('../../../i18n') const R = require('ramda') // classes from nodes of the toggle element. diff --git a/ui/app/components/dropdowns/token-menu-dropdown.js b/ui/app/components/dropdowns/token-menu-dropdown.js index 3dfcec5a8..a4f93b505 100644 --- a/ui/app/components/dropdowns/token-menu-dropdown.js +++ b/ui/app/components/dropdowns/token-menu-dropdown.js @@ -3,6 +3,7 @@ const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../actions') +const t = require('../../../i18n') module.exports = connect(null, mapDispatchToProps)(TokenMenuDropdown) diff --git a/ui/app/components/modals/account-details-modal.js b/ui/app/components/modals/account-details-modal.js index 746c6de4c..17760dc1a 100644 --- a/ui/app/components/modals/account-details-modal.js +++ b/ui/app/components/modals/account-details-modal.js @@ -8,6 +8,7 @@ const { getSelectedIdentity } = require('../../selectors') const genAccountLink = require('../../../lib/account-link.js') const QrView = require('../qr-code') const EditableLabel = require('../editable-label') +const t = require('../../../i18n') function mapStateToProps (state) { return { diff --git a/ui/app/components/modals/account-modal-container.js b/ui/app/components/modals/account-modal-container.js index 538edcf13..08540aa76 100644 --- a/ui/app/components/modals/account-modal-container.js +++ b/ui/app/components/modals/account-modal-container.js @@ -5,6 +5,7 @@ const connect = require('react-redux').connect const actions = require('../../actions') const { getSelectedIdentity } = require('../../selectors') const Identicon = require('../identicon') +const t = require('../../../i18n') function mapStateToProps (state) { return { diff --git a/ui/app/components/modals/buy-options-modal.js b/ui/app/components/modals/buy-options-modal.js index 60fef7db4..7eb73c3a6 100644 --- a/ui/app/components/modals/buy-options-modal.js +++ b/ui/app/components/modals/buy-options-modal.js @@ -4,6 +4,7 @@ const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../actions') const networkNames = require('../../../../app/scripts/config.js').networkNames +const t = require('../../../i18n') function mapStateToProps (state) { return { diff --git a/ui/app/components/modals/deposit-ether-modal.js b/ui/app/components/modals/deposit-ether-modal.js index 85f640a68..e91b43841 100644 --- a/ui/app/components/modals/deposit-ether-modal.js +++ b/ui/app/components/modals/deposit-ether-modal.js @@ -5,6 +5,7 @@ const connect = require('react-redux').connect const actions = require('../../actions') const networkNames = require('../../../../app/scripts/config.js').networkNames const ShapeshiftForm = require('../shapeshift-form') +const t = require('../../../i18n') const DIRECT_DEPOSIT_ROW_TITLE = t('directDepositEther') const DIRECT_DEPOSIT_ROW_TEXT = t('directDepositEtherExplainer') diff --git a/ui/app/components/modals/edit-account-name-modal.js b/ui/app/components/modals/edit-account-name-modal.js index 410fac7ba..611def005 100644 --- a/ui/app/components/modals/edit-account-name-modal.js +++ b/ui/app/components/modals/edit-account-name-modal.js @@ -4,6 +4,7 @@ const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../actions') const { getSelectedAccount } = require('../../selectors') +const t = require('../../../i18n') function mapStateToProps (state) { return { diff --git a/ui/app/components/modals/export-private-key-modal.js b/ui/app/components/modals/export-private-key-modal.js index 0745827cb..017177cfd 100644 --- a/ui/app/components/modals/export-private-key-modal.js +++ b/ui/app/components/modals/export-private-key-modal.js @@ -7,6 +7,7 @@ const actions = require('../../actions') const AccountModalContainer = require('./account-modal-container') const { getSelectedIdentity } = require('../../selectors') const ReadOnlyInput = require('../readonly-input') +const t = require('../../../i18n') const copyToClipboard = require('copy-to-clipboard') function mapStateToProps (state) { diff --git a/ui/app/components/modals/hide-token-confirmation-modal.js b/ui/app/components/modals/hide-token-confirmation-modal.js index 55f1695af..98b1e2d03 100644 --- a/ui/app/components/modals/hide-token-confirmation-modal.js +++ b/ui/app/components/modals/hide-token-confirmation-modal.js @@ -4,6 +4,7 @@ const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../actions') const Identicon = require('../identicon') +const t = require('../../../i18n') function mapStateToProps (state) { return { diff --git a/ui/app/components/modals/modal.js b/ui/app/components/modals/modal.js index e4e644d40..ea6ac5135 100644 --- a/ui/app/components/modals/modal.js +++ b/ui/app/components/modals/modal.js @@ -6,6 +6,7 @@ const FadeModal = require('boron').FadeModal const actions = require('../../actions') const isMobileView = require('../../../lib/is-mobile-view') const isPopupOrNotification = require('../../../../app/scripts/lib/is-popup-or-notification') +const t = require('../../../i18n') // Modal Components const BuyOptions = require('./buy-options-modal') diff --git a/ui/app/components/modals/new-account-modal.js b/ui/app/components/modals/new-account-modal.js index 4fdfbd745..35f4764a6 100644 --- a/ui/app/components/modals/new-account-modal.js +++ b/ui/app/components/modals/new-account-modal.js @@ -3,6 +3,7 @@ const PropTypes = require('prop-types') const h = require('react-hyperscript') const { connect } = require('react-redux') const actions = require('../../actions') +const t = require('../../../i18n') class NewAccountModal extends Component { constructor (props) { diff --git a/ui/app/components/pending-tx/confirm-deploy-contract.js b/ui/app/components/pending-tx/confirm-deploy-contract.js index 0d8b2721f..e6972c541 100644 --- a/ui/app/components/pending-tx/confirm-deploy-contract.js +++ b/ui/app/components/pending-tx/confirm-deploy-contract.js @@ -9,6 +9,7 @@ const ethUtil = require('ethereumjs-util') const BN = ethUtil.BN const hexToBn = require('../../../../app/scripts/lib/hex-to-bn') const { conversionUtil } = require('../../conversion-util') +const t = require('../../../i18n') const { MIN_GAS_PRICE_HEX } = require('../send/send-constants') diff --git a/ui/app/components/pending-tx/confirm-send-ether.js b/ui/app/components/pending-tx/confirm-send-ether.js index 7608e02ad..52693b4f6 100644 --- a/ui/app/components/pending-tx/confirm-send-ether.js +++ b/ui/app/components/pending-tx/confirm-send-ether.js @@ -9,6 +9,7 @@ const ethUtil = require('ethereumjs-util') const BN = ethUtil.BN const hexToBn = require('../../../../app/scripts/lib/hex-to-bn') const { conversionUtil, addCurrencies } = require('../../conversion-util') +const t = require('../../../i18n') const { MIN_GAS_PRICE_HEX } = require('../send/send-constants') diff --git a/ui/app/components/pending-tx/confirm-send-token.js b/ui/app/components/pending-tx/confirm-send-token.js index 88644d57a..14523461f 100644 --- a/ui/app/components/pending-tx/confirm-send-token.js +++ b/ui/app/components/pending-tx/confirm-send-token.js @@ -6,6 +6,7 @@ const tokenAbi = require('human-standard-token-abi') const abiDecoder = require('abi-decoder') abiDecoder.addABI(tokenAbi) const actions = require('../../actions') +const t = require('../../../i18n') const clone = require('clone') const Identicon = require('../identicon') const ethUtil = require('ethereumjs-util') diff --git a/ui/app/first-time/init-menu.js b/ui/app/first-time/init-menu.js index c496690a7..6b50bf504 100644 --- a/ui/app/first-time/init-menu.js +++ b/ui/app/first-time/init-menu.js @@ -6,17 +6,11 @@ const h = require('react-hyperscript') const Mascot = require('../components/mascot') const actions = require('../actions') const Tooltip = require('../components/tooltip') +const t = require('../../i18n') const getCaretCoordinates = require('textarea-caret') let isSubmitting = false -let t = chrome.i18n.getMessage || (function() { - let msg = require('../../../app/_locales/en/messages.json'); - return (function(key) { - return msg[key].message; - }); -})(); - module.exports = connect(mapStateToProps)(InitializeMenuScreen) inherits(InitializeMenuScreen, Component) diff --git a/ui/i18n.js b/ui/i18n.js new file mode 100644 index 000000000..e842c9ef9 --- /dev/null +++ b/ui/i18n.js @@ -0,0 +1,18 @@ + +// cross-browser connection to extension i18n API + +var getMessage; + +if ((chrome && chrome.i18n && chrome.i18n.getMessage) || + (browser && browser.i18n && browser.i18n.getMessage)) { + getMessage = (chrome || browser).i18n.getMessage; +} else { + // fallback function + console.warn('browser.i18n API not available?'); + let msg = require('../app/_locales/en/messages.json'); + getMessage = function(key) { + return msg[key].message; + }); +} + +module.exports = getMessage; From b281a5275983c4e2d924ba696c4885fd779d2c44 Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 24 Jan 2018 16:49:12 -0330 Subject: [PATCH 018/392] Remove already handled TODO comment. --- app/scripts/background.js | 1 - 1 file changed, 1 deletion(-) diff --git a/app/scripts/background.js b/app/scripts/background.js index 88600bf1e..3e04a31b3 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -64,7 +64,6 @@ async function loadStateFromPersistence () { log.error('error fetching state from local store:', err) } - // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) versionedData = Object.keys(localData).length > 0 ? localData : versionedData } From cd5eaa4393a122247295c7627a3fad3e678bea30 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 24 Jan 2018 13:05:13 -0800 Subject: [PATCH 019/392] Remove redundant async modifiers --- app/scripts/lib/local-store.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/scripts/lib/local-store.js b/app/scripts/lib/local-store.js index 32faac96b..9114364b6 100644 --- a/app/scripts/lib/local-store.js +++ b/app/scripts/lib/local-store.js @@ -12,12 +12,12 @@ module.exports = class ExtensionStore { log.error('Storage local API not available.') } } - async get() { + get() { return new Promise((resolve) => { extension.storage.local.get(STORAGE_KEY, resolve) }) } - async set(state) { + set(state) { return new Promise((resolve) => { extension.storage.local.set(state, resolve) }) From 76521cf7399c1e694a7202dcb9725ed5e1e2a0d7 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 24 Jan 2018 15:03:16 -0800 Subject: [PATCH 020/392] Fix retrieval of object --- app/scripts/lib/local-store.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/scripts/lib/local-store.js b/app/scripts/lib/local-store.js index 9114364b6..9e8d8db37 100644 --- a/app/scripts/lib/local-store.js +++ b/app/scripts/lib/local-store.js @@ -3,7 +3,6 @@ // https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/storage/local const extension = require('extensionizer') -const STORAGE_KEY = 'metamask-config' module.exports = class ExtensionStore { constructor() { @@ -14,7 +13,7 @@ module.exports = class ExtensionStore { } get() { return new Promise((resolve) => { - extension.storage.local.get(STORAGE_KEY, resolve) + extension.storage.local.get(null, resolve) }) } set(state) { From 2f13790653cb20d9d967700133df6cf31ff02d14 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 24 Jan 2018 15:28:15 -0800 Subject: [PATCH 021/392] Remove local storage writes, add log --- app/scripts/background.js | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/app/scripts/background.js b/app/scripts/background.js index 3e04a31b3..a77763c41 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -35,6 +35,7 @@ let popupIsOpen = false // state persistence const diskStore = new LocalStorageStore({ storageKey: STORAGE_KEY }) const localStore = new LocalStore() +let versionedData // initialization flow initialize().catch(log.error) @@ -53,7 +54,7 @@ async function loadStateFromPersistence () { // migrations const migrator = new Migrator({ migrations }) // read from disk - let versionedData = diskStore.getState() || migrator.generateInitialState(firstTimeState) + versionedData = diskStore.getState() || migrator.generateInitialState(firstTimeState) // fetch from extension store and merge in data if (localStore.isSupported) { @@ -64,13 +65,24 @@ async function loadStateFromPersistence () { log.error('error fetching state from local store:', err) } - versionedData = Object.keys(localData).length > 0 ? localData : versionedData + console.log('Comparing localdata and versionedData') + console.dir({ localData }) + + if (Object.keys(localData).length > 0) { + console.log('using the local store data') + versionedData = localData + } } // migrate data versionedData = await migrator.migrateData(versionedData) + // write to disk - diskStore.putState(versionedData) + localStore.set(versionedData) + .catch((reason) => { + log.error('Problem saving migrated data', versionedData) + }) + // return just the data return versionedData.data } @@ -107,11 +119,9 @@ function setupController (initState) { asStream(controller.store), storeTransform(versionifyData), storeTransform(syncDataWithExtension), - asStream(diskStore) ) function versionifyData (state) { - const versionedData = diskStore.getState() versionedData.data = state return versionedData } @@ -119,6 +129,7 @@ function setupController (initState) { function syncDataWithExtension(state) { if (localStore.isSupported) { try { + console.log('persisting state', state) localStore.set(state) } catch (err) { log.error('error setting state in local store:', err) From 9c133aaab30decce16a1bf4120071d4614f99bc8 Mon Sep 17 00:00:00 2001 From: Nick Doiron Date: Wed, 24 Jan 2018 19:41:29 -1000 Subject: [PATCH 022/392] get t imported in all files currently using i18n --- ui/app/components/account-dropdowns.js | 1 + ui/app/components/account-export.js | 1 + ui/app/components/buy-button-subview.js | 1 + ui/app/components/coinbase-form.js | 1 + ui/app/components/copyButton.js | 1 + ui/app/components/copyable.js | 1 + ui/app/components/ens-input.js | 1 + ui/app/components/hex-as-decimal-input.js | 1 + ui/app/components/network.js | 1 + ui/app/components/notice.js | 1 + ui/app/components/pending-msg-details.js | 1 + ui/app/components/pending-msg.js | 1 + ui/app/components/pending-personal-msg-details.js | 1 + ui/app/components/pending-typed-msg-details.js | 1 + ui/app/components/pending-typed-msg.js | 1 + ui/app/components/send-token/index.js | 1 + ui/app/components/send/gas-fee-display-v2.js | 1 + ui/app/components/send/gas-tooltip.js | 1 + ui/app/components/send/to-autocomplete.js | 1 + ui/app/components/shapeshift-form.js | 1 + ui/app/components/shift-list-item.js | 1 + ui/app/components/signature-request.js | 1 + ui/app/components/token-list.js | 1 + ui/app/components/transaction-list-item.js | 1 + ui/app/components/transaction-list.js | 1 + ui/app/components/tx-list-item.js | 1 + ui/app/components/tx-list.js | 1 + ui/app/components/tx-view.js | 1 + ui/app/components/wallet-view.js | 1 + ui/i18n.js | 2 +- 30 files changed, 30 insertions(+), 1 deletion(-) diff --git a/ui/app/components/account-dropdowns.js b/ui/app/components/account-dropdowns.js index 3e5805c0e..ede40d3f2 100644 --- a/ui/app/components/account-dropdowns.js +++ b/ui/app/components/account-dropdowns.js @@ -9,6 +9,7 @@ const DropdownMenuItem = require('./dropdown').DropdownMenuItem const Identicon = require('./identicon') const ethUtil = require('ethereumjs-util') const copyToClipboard = require('copy-to-clipboard') +const t = require('../../i18n') class AccountDropdowns extends Component { constructor (props) { diff --git a/ui/app/components/account-export.js b/ui/app/components/account-export.js index 346872a97..25f36da58 100644 --- a/ui/app/components/account-export.js +++ b/ui/app/components/account-export.js @@ -6,6 +6,7 @@ const copyToClipboard = require('copy-to-clipboard') const actions = require('../actions') const ethUtil = require('ethereumjs-util') const connect = require('react-redux').connect +const t = require('../../i18n') module.exports = connect(mapStateToProps)(ExportAccountView) diff --git a/ui/app/components/buy-button-subview.js b/ui/app/components/buy-button-subview.js index 76da4fc9d..6f2c74b6d 100644 --- a/ui/app/components/buy-button-subview.js +++ b/ui/app/components/buy-button-subview.js @@ -9,6 +9,7 @@ const Loading = require('./loading') const AccountPanel = require('./account-panel') const RadioList = require('./custom-radio-list') const networkNames = require('../../../app/scripts/config.js').networkNames +const t = require('../../i18n') module.exports = connect(mapStateToProps)(BuyButtonSubview) diff --git a/ui/app/components/coinbase-form.js b/ui/app/components/coinbase-form.js index 6532cb3bf..e442b43d5 100644 --- a/ui/app/components/coinbase-form.js +++ b/ui/app/components/coinbase-form.js @@ -3,6 +3,7 @@ const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../actions') +const t = require('../../i18n') module.exports = connect(mapStateToProps)(CoinbaseForm) diff --git a/ui/app/components/copyButton.js b/ui/app/components/copyButton.js index 5d5be8feb..355f78d45 100644 --- a/ui/app/components/copyButton.js +++ b/ui/app/components/copyButton.js @@ -2,6 +2,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const copyToClipboard = require('copy-to-clipboard') +const t = require('../../i18n') const Tooltip = require('./tooltip') diff --git a/ui/app/components/copyable.js b/ui/app/components/copyable.js index 690e44153..fca7d3863 100644 --- a/ui/app/components/copyable.js +++ b/ui/app/components/copyable.js @@ -4,6 +4,7 @@ const inherits = require('util').inherits const Tooltip = require('./tooltip') const copyToClipboard = require('copy-to-clipboard') +const t = require('../../i18n') module.exports = Copyable diff --git a/ui/app/components/ens-input.js b/ui/app/components/ens-input.js index 3e7a23369..add67ea35 100644 --- a/ui/app/components/ens-input.js +++ b/ui/app/components/ens-input.js @@ -8,6 +8,7 @@ const ENS = require('ethjs-ens') const networkMap = require('ethjs-ens/lib/network-map.json') const ensRE = /.+\..+$/ const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000' +const t = require('../../i18n') module.exports = EnsInput diff --git a/ui/app/components/hex-as-decimal-input.js b/ui/app/components/hex-as-decimal-input.js index 07432a1f2..992d8c8cd 100644 --- a/ui/app/components/hex-as-decimal-input.js +++ b/ui/app/components/hex-as-decimal-input.js @@ -4,6 +4,7 @@ const inherits = require('util').inherits const ethUtil = require('ethereumjs-util') const BN = ethUtil.BN const extend = require('xtend') +const t = require('../../i18n') module.exports = HexAsDecimalInput diff --git a/ui/app/components/network.js b/ui/app/components/network.js index 6cb1ff53d..f3df2242a 100644 --- a/ui/app/components/network.js +++ b/ui/app/components/network.js @@ -3,6 +3,7 @@ const h = require('react-hyperscript') const classnames = require('classnames') const inherits = require('util').inherits const NetworkDropdownIcon = require('./dropdowns/components/network-dropdown-icon') +const t = require('../../i18n') module.exports = Network diff --git a/ui/app/components/notice.js b/ui/app/components/notice.js index 5bda329ed..390639297 100644 --- a/ui/app/components/notice.js +++ b/ui/app/components/notice.js @@ -4,6 +4,7 @@ const h = require('react-hyperscript') const ReactMarkdown = require('react-markdown') const linker = require('extension-link-enabler') const findDOMNode = require('react-dom').findDOMNode +const t = require('../../i18n') module.exports = Notice diff --git a/ui/app/components/pending-msg-details.js b/ui/app/components/pending-msg-details.js index 3ea063c3c..b66657f3b 100644 --- a/ui/app/components/pending-msg-details.js +++ b/ui/app/components/pending-msg-details.js @@ -1,6 +1,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits +const t = require('../../i18n') const AccountPanel = require('./account-panel') diff --git a/ui/app/components/pending-msg.js b/ui/app/components/pending-msg.js index 236849c18..dc406b955 100644 --- a/ui/app/components/pending-msg.js +++ b/ui/app/components/pending-msg.js @@ -2,6 +2,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const PendingTxDetails = require('./pending-msg-details') +const t = require('../../i18n') module.exports = PendingMsg diff --git a/ui/app/components/pending-personal-msg-details.js b/ui/app/components/pending-personal-msg-details.js index 30c475347..d21689f86 100644 --- a/ui/app/components/pending-personal-msg-details.js +++ b/ui/app/components/pending-personal-msg-details.js @@ -1,6 +1,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits +const t = require('../../i18n') const AccountPanel = require('./account-panel') const BinaryRenderer = require('./binary-renderer') diff --git a/ui/app/components/pending-typed-msg-details.js b/ui/app/components/pending-typed-msg-details.js index a3381174d..9708ed1d7 100644 --- a/ui/app/components/pending-typed-msg-details.js +++ b/ui/app/components/pending-typed-msg-details.js @@ -4,6 +4,7 @@ const inherits = require('util').inherits const AccountPanel = require('./account-panel') const TypedMessageRenderer = require('./typed-message-renderer') +const t = require('../../i18n') module.exports = PendingMsgDetails diff --git a/ui/app/components/pending-typed-msg.js b/ui/app/components/pending-typed-msg.js index f0f846027..3d473f47d 100644 --- a/ui/app/components/pending-typed-msg.js +++ b/ui/app/components/pending-typed-msg.js @@ -2,6 +2,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const PendingTxDetails = require('./pending-typed-msg-details') +const t = require('../../i18n') module.exports = PendingMsg diff --git a/ui/app/components/send-token/index.js b/ui/app/components/send-token/index.js index a40664977..2ad7c9dd0 100644 --- a/ui/app/components/send-token/index.js +++ b/ui/app/components/send-token/index.js @@ -7,6 +7,7 @@ const inherits = require('util').inherits const actions = require('../../actions') const selectors = require('../../selectors') const { isValidAddress, allNull } = require('../../util') +const t = require('../../../i18n') // const BalanceComponent = require('./balance-component') const Identicon = require('../identicon') diff --git a/ui/app/components/send/gas-fee-display-v2.js b/ui/app/components/send/gas-fee-display-v2.js index edaa297b9..0c6f76303 100644 --- a/ui/app/components/send/gas-fee-display-v2.js +++ b/ui/app/components/send/gas-fee-display-v2.js @@ -2,6 +2,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const CurrencyDisplay = require('./currency-display') +const t = require('../../../i18n') module.exports = GasFeeDisplay diff --git a/ui/app/components/send/gas-tooltip.js b/ui/app/components/send/gas-tooltip.js index da2a53c9e..d925d3ed8 100644 --- a/ui/app/components/send/gas-tooltip.js +++ b/ui/app/components/send/gas-tooltip.js @@ -2,6 +2,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const InputNumber = require('../input-number.js') +const t = require('../../../i18n') module.exports = GasTooltip diff --git a/ui/app/components/send/to-autocomplete.js b/ui/app/components/send/to-autocomplete.js index 85e7bfa0e..72074229e 100644 --- a/ui/app/components/send/to-autocomplete.js +++ b/ui/app/components/send/to-autocomplete.js @@ -2,6 +2,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const AccountListItem = require('./account-list-item') +const t = require('../../../i18n') module.exports = ToAutoComplete diff --git a/ui/app/components/shapeshift-form.js b/ui/app/components/shapeshift-form.js index 773ff227c..329feb38f 100644 --- a/ui/app/components/shapeshift-form.js +++ b/ui/app/components/shapeshift-form.js @@ -7,6 +7,7 @@ const { qrcode } = require('qrcode-npm') const { shapeShiftSubview, pairUpdate, buyWithShapeShift } = require('../actions') const { isValidAddress } = require('../util') const SimpleDropdown = require('./dropdowns/simple-dropdown') +const t = require('../../i18n') function mapStateToProps (state) { const { diff --git a/ui/app/components/shift-list-item.js b/ui/app/components/shift-list-item.js index 6e5be641f..21d41a06c 100644 --- a/ui/app/components/shift-list-item.js +++ b/ui/app/components/shift-list-item.js @@ -6,6 +6,7 @@ const vreme = new (require('vreme'))() const explorerLink = require('etherscan-link').createExplorerLink const actions = require('../actions') const addressSummary = require('../util').addressSummary +const t = require('../../i18n') const CopyButton = require('./copyButton') const EthBalance = require('./eth-balance') diff --git a/ui/app/components/signature-request.js b/ui/app/components/signature-request.js index 8003f8b1d..d0e568bca 100644 --- a/ui/app/components/signature-request.js +++ b/ui/app/components/signature-request.js @@ -9,6 +9,7 @@ const classnames = require('classnames') const AccountDropdownMini = require('./dropdowns/account-dropdown-mini') const actions = require('../actions') +const t = require('../../i18n') const { conversionUtil } = require('../conversion-util') const { diff --git a/ui/app/components/token-list.js b/ui/app/components/token-list.js index a25566e64..01529aeda 100644 --- a/ui/app/components/token-list.js +++ b/ui/app/components/token-list.js @@ -5,6 +5,7 @@ const TokenTracker = require('eth-token-tracker') const TokenCell = require('./token-cell.js') const connect = require('react-redux').connect const selectors = require('../selectors') +const t = require('../../i18n') function mapStateToProps (state) { return { diff --git a/ui/app/components/transaction-list-item.js b/ui/app/components/transaction-list-item.js index 10d4236cb..6baf60141 100644 --- a/ui/app/components/transaction-list-item.js +++ b/ui/app/components/transaction-list-item.js @@ -11,6 +11,7 @@ const vreme = new (require('vreme'))() const Tooltip = require('./tooltip') const numberToBN = require('number-to-bn') const actions = require('../actions') +const t = require('../../i18n') const TransactionIcon = require('./transaction-list-item-icon') const ShiftListItem = require('./shift-list-item') diff --git a/ui/app/components/transaction-list.js b/ui/app/components/transaction-list.js index cb3f8097b..07f7a06ae 100644 --- a/ui/app/components/transaction-list.js +++ b/ui/app/components/transaction-list.js @@ -3,6 +3,7 @@ const h = require('react-hyperscript') const inherits = require('util').inherits const TransactionListItem = require('./transaction-list-item') +const t = require('../../i18n') module.exports = TransactionList diff --git a/ui/app/components/tx-list-item.js b/ui/app/components/tx-list-item.js index d53277925..7a38096b6 100644 --- a/ui/app/components/tx-list-item.js +++ b/ui/app/components/tx-list-item.js @@ -13,6 +13,7 @@ const { conversionUtil, multiplyCurrencies } = require('../conversion-util') const { calcTokenAmount } = require('../token-util') const { getCurrentCurrency } = require('../selectors') +const t = require('../../i18n') module.exports = connect(mapStateToProps)(TxListItem) diff --git a/ui/app/components/tx-list.js b/ui/app/components/tx-list.js index 6076ab5d3..8343ec46b 100644 --- a/ui/app/components/tx-list.js +++ b/ui/app/components/tx-list.js @@ -10,6 +10,7 @@ const { formatDate } = require('../util') const { showConfTxPage } = require('../actions') const classnames = require('classnames') const { tokenInfoGetter } = require('../token-util') +const t = require('../../i18n') module.exports = connect(mapStateToProps, mapDispatchToProps)(TxList) diff --git a/ui/app/components/tx-view.js b/ui/app/components/tx-view.js index 423234d4f..adc9b8e94 100644 --- a/ui/app/components/tx-view.js +++ b/ui/app/components/tx-view.js @@ -5,6 +5,7 @@ const ethUtil = require('ethereumjs-util') const inherits = require('util').inherits const actions = require('../actions') const selectors = require('../selectors') +const t = require('../../i18n') const BalanceComponent = require('./balance-component') const TxList = require('./tx-list') diff --git a/ui/app/components/wallet-view.js b/ui/app/components/wallet-view.js index 3d9c01c6e..60a780fc6 100644 --- a/ui/app/components/wallet-view.js +++ b/ui/app/components/wallet-view.js @@ -9,6 +9,7 @@ const actions = require('../actions') const BalanceComponent = require('./balance-component') const TokenList = require('./token-list') const selectors = require('../selectors') +const t = require('../../i18n') module.exports = connect(mapStateToProps, mapDispatchToProps)(WalletView) diff --git a/ui/i18n.js b/ui/i18n.js index e842c9ef9..c2cf9b449 100644 --- a/ui/i18n.js +++ b/ui/i18n.js @@ -12,7 +12,7 @@ if ((chrome && chrome.i18n && chrome.i18n.getMessage) || let msg = require('../app/_locales/en/messages.json'); getMessage = function(key) { return msg[key].message; - }); + }; } module.exports = getMessage; From ceebc6caa4f3eab1cf6c9ec8f47dc8bd450ca4a9 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 25 Jan 2018 13:01:03 -0800 Subject: [PATCH 023/392] Debounce storage to avoid crashing pump --- app/scripts/background.js | 16 ++++++++-------- package.json | 1 + 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/app/scripts/background.js b/app/scripts/background.js index a77763c41..2a8efd844 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -1,6 +1,7 @@ const urlUtil = require('url') const endOfStream = require('end-of-stream') const pump = require('pump') +const debounce = require('debounce-stream') const log = require('loglevel') const extension = require('extensionizer') const LocalStorageStore = require('obs-store/lib/localStorage') @@ -65,11 +66,7 @@ async function loadStateFromPersistence () { log.error('error fetching state from local store:', err) } - console.log('Comparing localdata and versionedData') - console.dir({ localData }) - if (Object.keys(localData).length > 0) { - console.log('using the local store data') versionedData = localData } } @@ -117,8 +114,12 @@ function setupController (initState) { // setup state persistence pump( asStream(controller.store), + debounce(200), storeTransform(versionifyData), storeTransform(syncDataWithExtension), + (error) => { + log.error('pump hit error', error) + } ) function versionifyData (state) { @@ -126,15 +127,14 @@ function setupController (initState) { return versionedData } - function syncDataWithExtension(state) { + async function syncDataWithExtension(state) { if (localStore.isSupported) { try { - console.log('persisting state', state) - localStore.set(state) + await localStore.set(state) } catch (err) { log.error('error setting state in local store:', err) } - } + } else { log.error('local store not supported') } return state } diff --git a/package.json b/package.json index a1de1db14..c50b29e42 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "clone": "^2.1.1", "copy-to-clipboard": "^3.0.8", "debounce": "^1.0.0", + "debounce-stream": "^2.0.0", "deep-extend": "^0.5.0", "detect-node": "^2.0.3", "disc": "^1.3.2", From 8ba64c657ff801425c06db166e2c9a06289047de Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 25 Jan 2018 15:38:43 -0800 Subject: [PATCH 024/392] Increase storage debounce value --- app/scripts/background.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/background.js b/app/scripts/background.js index 2a8efd844..07a260a4f 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -114,7 +114,7 @@ function setupController (initState) { // setup state persistence pump( asStream(controller.store), - debounce(200), + debounce(1000), storeTransform(versionifyData), storeTransform(syncDataWithExtension), (error) => { From f673c2a8a4d6aac1d22813c3e076fe91f08823f2 Mon Sep 17 00:00:00 2001 From: Nick Doiron Date: Sun, 28 Jan 2018 00:20:56 -0500 Subject: [PATCH 025/392] pass linter, update ui test --- test/integration/lib/first-time.js | 2 +- ui/i18n.js | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/test/integration/lib/first-time.js b/test/integration/lib/first-time.js index e59897713..318119902 100644 --- a/test/integration/lib/first-time.js +++ b/test/integration/lib/first-time.js @@ -41,7 +41,7 @@ async function runFirstTimeUsageTest(assert, done) { // Scroll through terms const title = app.find('h1').text() // TODO Find where Metamask is getting added twice in the title - assert.equal(title, 'MetaMaskMetaMask', 'title screen') + assert.equal(title, 'MetaMask', 'title screen') // enter password const pwBox = app.find('#password-box')[0] diff --git a/ui/i18n.js b/ui/i18n.js index c2cf9b449..0f4e9fce4 100644 --- a/ui/i18n.js +++ b/ui/i18n.js @@ -1,18 +1,20 @@ // cross-browser connection to extension i18n API -var getMessage; +const chrome = chrome || null +const browser = browser || null +let getMessage = null if ((chrome && chrome.i18n && chrome.i18n.getMessage) || (browser && browser.i18n && browser.i18n.getMessage)) { - getMessage = (chrome || browser).i18n.getMessage; + getMessage = (chrome || browser).i18n.getMessage } else { // fallback function - console.warn('browser.i18n API not available?'); - let msg = require('../app/_locales/en/messages.json'); - getMessage = function(key) { - return msg[key].message; - }; + console.warn('browser.i18n API not available?') + let msg = require('../app/_locales/en/messages.json') + getMessage = function (key) { + return msg[key].message + } } -module.exports = getMessage; +module.exports = getMessage From 1698541bcdce6c2933c8b3b4e1c89e2f391c3a68 Mon Sep 17 00:00:00 2001 From: Nick Doiron Date: Sun, 28 Jan 2018 21:14:06 -0500 Subject: [PATCH 026/392] CI still has MetaMask title doubled --- test/integration/lib/first-time.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/lib/first-time.js b/test/integration/lib/first-time.js index 318119902..e59897713 100644 --- a/test/integration/lib/first-time.js +++ b/test/integration/lib/first-time.js @@ -41,7 +41,7 @@ async function runFirstTimeUsageTest(assert, done) { // Scroll through terms const title = app.find('h1').text() // TODO Find where Metamask is getting added twice in the title - assert.equal(title, 'MetaMask', 'title screen') + assert.equal(title, 'MetaMaskMetaMask', 'title screen') // enter password const pwBox = app.find('#password-box')[0] From abfa74f09a0119345165a32090d88a1d95df6c80 Mon Sep 17 00:00:00 2001 From: Nick Doiron Date: Mon, 29 Jan 2018 15:29:01 -0500 Subject: [PATCH 027/392] complete i18n across new UI --- app/_locales/en/messages.json | 170 +++++++++++------- app/manifest.json | 6 +- ui/app/accounts/import/index.js | 9 +- ui/app/accounts/import/json.js | 8 +- ui/app/accounts/import/private-key.js | 8 +- ui/app/accounts/new-account/create-form.js | 8 +- ui/app/components/account-dropdowns.js | 6 +- ui/app/components/account-export.js | 8 +- ui/app/components/account-menu/index.js | 2 +- ui/app/components/bn-as-decimal-input.js | 9 +- ui/app/components/buy-button-subview.js | 6 +- .../components/customize-gas-modal/index.js | 8 +- .../dropdowns/components/account-dropdowns.js | 8 +- ui/app/components/hex-as-decimal-input.js | 6 +- .../modals/account-details-modal.js | 2 +- .../components/modals/deposit-ether-modal.js | 4 +- .../modals/edit-account-name-modal.js | 4 +- .../modals/hide-token-confirmation-modal.js | 8 +- ui/app/components/modals/new-account-modal.js | 6 +- ui/app/components/pending-msg-details.js | 2 +- .../pending-personal-msg-details.js | 2 +- .../pending-tx/confirm-deploy-contract.js | 12 +- .../pending-tx/confirm-send-ether.js | 6 +- .../pending-tx/confirm-send-token.js | 14 +- .../components/pending-typed-msg-details.js | 2 +- ui/app/components/pending-typed-msg.js | 8 +- ui/app/components/send-token/index.js | 6 +- ui/app/components/shapeshift-form.js | 2 +- ui/app/components/shift-list-item.js | 6 +- ui/app/components/signature-request.js | 8 +- ui/app/components/tx-view.js | 8 +- ui/app/components/wallet-view.js | 4 +- ui/app/css/itcss/generic/index.scss | 4 + ui/i18n.js | 17 +- 34 files changed, 221 insertions(+), 166 deletions(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 54f266318..a0c9088cb 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -3,9 +3,9 @@ "message": "Accept" }, "account": { - "message": "Account:" + "message": "Account" }, - "accDetails": { + "accountDetails": { "message": "Account Details" }, "accountName": { @@ -17,11 +17,14 @@ "addToken": { "message": "Add Token" }, + "amount": { + "message": "Amount" + }, "amountPlusGas": { "message": "Amount + Gas" }, "appDescription": { - "message": "Ethereum Identity Management", + "message": "Ethereum Browser Extension", "description": "The description of the application" }, "appName": { @@ -43,10 +46,14 @@ "balanceIsInsufficientGas": { "message": "Insufficient balance for current gas total" }, + "betweenMinAndMax": { + "message": "must be greater than or equal to $1 and less than or equal to $2.", + "description": "helper for inputting hex as decimal input" + }, "borrowDharma": { "message": "Borrow With Dharma (Beta)" }, - "buyButton": { + "buy": { "message": "Buy" }, "buyCoinbase": { @@ -58,26 +65,20 @@ "cancel": { "message": "Cancel" }, - "cancelCaps": { - "message": "CANCEL" - }, "clickCopy": { "message": "Click to Copy" }, "confirm": { "message": "Confirm" }, - "confirmCaps": { - "message": "CONFIRM" - }, "confirmContract": { "message": "Confirm Contract" }, "confirmPassword": { "message": "Confirm Password" }, - "confirmPasswordSmall": { - "message": "confirm password" + "confirmTransaction": { + "message": "Confirm Transaction" }, "continueToCoinbase": { "message": "Continue to Coinbase" @@ -109,15 +110,19 @@ "copyPrivateKey": { "message": "This is your private key (click to copy)" }, + "create": { + "message": "Create" + }, "createAccount": { "message": "Create Account" }, - "createCaps": { - "message": "CREATE" - }, "createDen": { "message": "Create" }, + "crypto": { + "message": "Crypto", + "description": "Exchange type (cryptocurrencies)" + }, "customGas": { "message": "Customize Gas" }, @@ -139,9 +144,6 @@ "depositBTC": { "message": "Deposit your BTC to the address below:" }, - "depositButton": { - "message": "DEPOSIT" - }, "depositEth": { "message": "Deposit Eth" }, @@ -160,8 +162,8 @@ "depositShapeShiftExplainer": { "message": "If you own other cryptocurrencies, you can trade and deposit Ether directly into your MetaMask wallet. No Account Needed." }, - "detailsCaps": { - "message": "DETAILS" + "details": { + "message": "Details" }, "directDeposit": { "message": "Direct Deposit" @@ -175,12 +177,12 @@ "done": { "message": "Done" }, + "edit": { + "message": "Edit" + }, "editAccountName": { "message": "Edit Account Name" }, - "editCaps": { - "message": "EDIT" - }, "encryptNewDen": { "message": "Encrypt your new DEN" }, @@ -196,17 +198,19 @@ "exportPrivateKey": { "message": "Export Private Key" }, - "exportPrivateKeyLower": { - "message": "Export private key" - }, "exportPrivateKeyWarning": { "message": "Export private keys at your own risk." }, "failed": { "message": "Failed" }, + "fiat": { + "message": "FIAT", + "description": "Exchange type" + }, "fileImportFail": { - "message": "File import not working? Click here!" + "message": "File import not working? Click here!", + "description": "Helps user import their account from a JSON file" }, "from": { "message": "From" @@ -214,12 +218,13 @@ "fromShapeShift": { "message": "From ShapeShift" }, + "gas": { + "message": "Gas", + "description": "Short indication of gas cost" + }, "gasFee": { "message": "Gas Fee" }, - "gasFeeSpecific": { - "message": "Gas fee:" - }, "gasLimit": { "message": "Gas Limit" }, @@ -244,11 +249,20 @@ "getEther": { "message": "Get Ether" }, - "here": { - "message": "here" + "getEtherFromFaucet": { + "message": "Get Ether from a faucet for the $1", + "description": "Displays network name for Ether faucet" }, - "hideCaps": { - "message": "HIDE" + "greaterThanMin": { + "message": "must be greater than or equal to $1.", + "description": "helper for inputting hex as decimal input" + }, + "here": { + "message": "here", + "description": "as in -click here- for more information (goes with troubleTokenBalances)" + }, + "hide": { + "message": "Hide" }, "hideToken": { "message": "Hide Token" @@ -260,7 +274,8 @@ "message": "How would you like to deposit Ether?" }, "import": { - "message": "Import" + "message": "Import", + "description": "Button to import an account from a selected file" }, "importAccount": { "message": "Import Account" @@ -268,14 +283,12 @@ "importAnAccount": { "message": "Import an account" }, - "importCaps": { - "message": "IMPORT" - }, "importDen": { "message": "Import Existing DEN" }, - "importedCaps": { - "message": "IMPORTED" + "imported": { + "message": "Imported", + "description": "status showing that an account has been fully loaded into the keyring" }, "infoHelp": { "message": "Info & Help" @@ -292,9 +305,17 @@ "invalidRequest": { "message": "Invalid Request" }, + "jsonFile": { + "message": "JSON File", + "description": "format for importing an account" + }, "kovan": { "message": "Kovan Test Network" }, + "lessThanMax": { + "message": "must be less than or equal to $1.", + "description": "helper for inputting hex as decimal input" + }, "limit": { "message": "Limit" }, @@ -310,8 +331,8 @@ "logout": { "message": "Log out" }, - "looseCaps": { - "message": "LOOSE" + "loose": { + "message": "Loose" }, "mainnet": { "message": "Main Ethereum Network" @@ -319,9 +340,6 @@ "message": { "message": "Message" }, - "messageCaps": { - "message": "MESSAGE" - }, "min": { "message": "Minimum" }, @@ -332,10 +350,12 @@ "message": "To interact with decentralized applications using MetaMask, you’ll need Ether in your wallet." }, "needImportFile": { - "message": "You must select a file to import." + "message": "You must select a file to import.", + "description": "User is important an account and needs to add a file to continue" }, "needImportPassword": { - "message": "You must enter a password for the selected file." + "message": "You must enter a password for the selected file.", + "description": "Password and file needed to import an account" }, "networks": { "message": "Networks" @@ -377,20 +397,28 @@ "message": "You have returned to the old UI. You can switch back to the New UI through the option in the top right dropdown menu." }, "or": { - "message": "or" + "message": "or", + "description": "choice between creating or importing a new account" }, "passwordMismatch": { - "message": "passwords don't match" + "message": "passwords don't match", + "description": "in password creation process, the two new password fields did not match" }, "passwordShort": { - "message": "password not long enough" + "message": "password not long enough", + "description": "in password creation process, the password is not long enough to be secure" }, "pastePrivateKey": { - "message": "Paste your private key string here:" + "message": "Paste your private key string here:", + "description": "For importing an account from a private key" }, "pasteSeed": { "message": "Paste your seed phrase here!" }, + "privateKey": { + "message": "Private Key", + "description": "select this type of file to use to import an account" + }, "privateKeyWarning": { "message": "Warning: Never disclose this key. Anyone with your private keys can take steal any assets held in your account." }, @@ -434,16 +462,21 @@ "message": "Ropsten Test Network" }, "sampleAccountName": { - "message": "E.g. My new account" + "message": "E.g. My new account", + "description": "Help user understand concept of adding a human-readable name to their account" }, - "saveCaps": { - "message": "SAVE" + "save": { + "message": "Save" + }, + "saveAsFile": { + "message": "Save as File", + "description": "Account export process" }, "selectService": { "message": "Select Service" }, - "sendButton": { - "message": "SEND" + "send": { + "message": "Send" }, "sendTokens": { "message": "Send Tokens" @@ -460,12 +493,12 @@ "showPrivateKeys": { "message": "Show Private Keys" }, + "showQRCode": { + "message": "Show QR Code" + }, "sign": { "message": "Sign" }, - "signCaps": { - "message": "SIGN" - }, "signMessage": { "message": "Sign Message" }, @@ -490,12 +523,13 @@ "to": { "message": "To" }, + "toETHviaShapeShift": { + "message": "$1 to ETH via ShapeShift", + "description": "system will fill in deposit type in start of message" + }, "tokenBalance": { "message": "Your Token Balance is:" }, - "toSpecific": { - "message": "To:" - }, "total": { "message": "Total" }, @@ -509,7 +543,8 @@ "message": "Transfers" }, "troubleTokenBalances": { - "message": "We had trouble loading your token balances. You can view them " + "message": "We had trouble loading your token balances. You can view them ", + "description": "Followed by a link (here) to view token balances" }, "typePassword": { "message": "Type Your Password" @@ -532,6 +567,10 @@ "unknownNetworkId": { "message": "Unknown network ID" }, + "usaOnly": { + "message": "USA only", + "description": "Using this exchange is limited to people inside the USA" + }, "usedByClients": { "message": "Used by a variety of different clients" }, @@ -548,9 +587,6 @@ "message": "Your signature is being requested" }, "youSign": { - "message": "You are signing:" - }, - "youSignCaps": { - "message": "YOU ARE SIGNING" + "message": "You are signing" } } diff --git a/app/manifest.json b/app/manifest.json index d906382e9..b52d3245d 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,10 +1,10 @@ { - "name": "MetaMask", - "short_name": "Metamask", + "name": "__MSG_appName__", + "short_name": "__MSG_appName__", "version": "4.0.10", "manifest_version": 2, "author": "https://metamask.io", - "description": "Ethereum Browser Extension", + "description": "__MSG_appDescription__", "commands": { "_execute_browser_action": { "suggested_key": { diff --git a/ui/app/accounts/import/index.js b/ui/app/accounts/import/index.js index 0c901c09b..6ae74864f 100644 --- a/ui/app/accounts/import/index.js +++ b/ui/app/accounts/import/index.js @@ -2,6 +2,7 @@ const inherits = require('util').inherits const Component = require('react').Component const h = require('react-hyperscript') const connect = require('react-redux').connect +const t = require('../../../i18n') import Select from 'react-select' // Subviews @@ -9,8 +10,8 @@ const JsonImportView = require('./json.js') const PrivateKeyImportView = require('./private-key.js') const menuItems = [ - 'Private Key', - 'JSON File', + t('privateKey'), + t('jsonFile'), ] module.exports = connect(mapStateToProps)(AccountImportSubview) @@ -70,9 +71,9 @@ AccountImportSubview.prototype.renderImportView = function () { const current = type || menuItems[0] switch (current) { - case 'Private Key': + case t('privateKey'): return h(PrivateKeyImportView) - case 'JSON File': + case t('jsonFile'): return h(JsonImportView) default: return h(JsonImportView) diff --git a/ui/app/accounts/import/json.js b/ui/app/accounts/import/json.js index 8b5a2b469..eb63a98a9 100644 --- a/ui/app/accounts/import/json.js +++ b/ui/app/accounts/import/json.js @@ -50,16 +50,16 @@ JsonImportSubview.prototype.render = function () { h('div.new-account-create-form__buttons', {}, [ - h('button.new-account-create-form__button-cancel', { + h('button.new-account-create-form__button-cancel.allcaps', { onClick: () => this.props.goHome(), }, [ - t('cancelCaps'), + t('cancel'), ]), - h('button.new-account-create-form__button-create', { + h('button.new-account-create-form__button-create.allcaps', { onClick: () => this.createNewKeychain.bind(this), }, [ - t('importCaps'), + t('import'), ]), ]), diff --git a/ui/app/accounts/import/private-key.js b/ui/app/accounts/import/private-key.js index 4a04156e0..e8c192a61 100644 --- a/ui/app/accounts/import/private-key.js +++ b/ui/app/accounts/import/private-key.js @@ -43,16 +43,16 @@ PrivateKeyImportView.prototype.render = function () { h('div.new-account-create-form__buttons', {}, [ - h('button.new-account-create-form__button-cancel', { + h('button.new-account-create-form__button-cancel.allcaps', { onClick: () => goHome(), }, [ - t('cancelCaps'), + t('cancel'), ]), - h('button.new-account-create-form__button-create', { + h('button.new-account-create-form__button-create.allcaps', { onClick: () => this.createNewKeychain(), }, [ - t('importCaps'), + t('import'), ]), ]), diff --git a/ui/app/accounts/new-account/create-form.js b/ui/app/accounts/new-account/create-form.js index 6f35e8886..ce8af394a 100644 --- a/ui/app/accounts/new-account/create-form.js +++ b/ui/app/accounts/new-account/create-form.js @@ -35,16 +35,16 @@ class NewAccountCreateForm extends Component { h('div.new-account-create-form__buttons', {}, [ - h('button.new-account-create-form__button-cancel', { + h('button.new-account-create-form__button-cancel.allcaps', { onClick: () => this.props.goHome(), }, [ - t('cancelCaps'), + t('cancel'), ]), - h('button.new-account-create-form__button-create', { + h('button.new-account-create-form__button-create.allcaps', { onClick: () => this.props.createAccount(newAccountName), }, [ - t('createCaps'), + t('create'), ]), ]), diff --git a/ui/app/components/account-dropdowns.js b/ui/app/components/account-dropdowns.js index ede40d3f2..e92da8947 100644 --- a/ui/app/components/account-dropdowns.js +++ b/ui/app/components/account-dropdowns.js @@ -80,7 +80,7 @@ class AccountDropdowns extends Component { try { // Sometimes keyrings aren't loaded yet: const type = keyring.type const isLoose = type !== 'HD Key Tree' - return isLoose ? h('.keyring-label', t('looseCaps')) : null + return isLoose ? h('.keyring-label.allcaps', t('loose')) : null } catch (e) { return } } @@ -155,7 +155,7 @@ class AccountDropdowns extends Component { fontSize: '24px', marginBottom: '5px', }, - }, 'Import Account'), + }, t('importAccount')), ] ), ] @@ -205,7 +205,7 @@ class AccountDropdowns extends Component { actions.showQrView(selected, identity ? identity.name : '') }, }, - t('qrCode'), + t('showQRCode'), ), h( DropdownMenuItem, diff --git a/ui/app/components/account-export.js b/ui/app/components/account-export.js index 25f36da58..5637bc8d0 100644 --- a/ui/app/components/account-export.js +++ b/ui/app/components/account-export.js @@ -54,7 +54,7 @@ ExportAccountView.prototype.render = function () { h('p.error', warning), h('input#exportAccount.sizing-input', { type: 'password', - placeholder: t('confirmPasswordSmall'), + placeholder: t('confirmPassword').toLowerCase(), onKeyPress: this.onExportKeyPress.bind(this), style: { position: 'relative', @@ -99,7 +99,7 @@ ExportAccountView.prototype.render = function () { margin: '0 20px', }, }, [ - h('label', 'Your private key (click to copy):'), + h('label', t('copyPrivateKey') + ':'), h('p.error.cursor-pointer', { style: { textOverflow: 'ellipsis', @@ -113,13 +113,13 @@ ExportAccountView.prototype.render = function () { }, plainKey), h('button', { onClick: () => this.props.dispatch(actions.backToAccountDetail(this.props.address)), - }, 'Done'), + }, t('done')), h('button', { style: { marginLeft: '10px', }, onClick: () => exportAsFile(`MetaMask ${nickname} Private Key`, plainKey), - }, 'Save as File'), + }, t('saveAsFile')), ]) } } diff --git a/ui/app/components/account-menu/index.js b/ui/app/components/account-menu/index.js index 9c7b6b15a..d9cf8cdce 100644 --- a/ui/app/components/account-menu/index.js +++ b/ui/app/components/account-menu/index.js @@ -156,6 +156,6 @@ AccountMenu.prototype.indicateIfLoose = function (keyring) { try { // Sometimes keyrings aren't loaded yet: const type = keyring.type const isLoose = type !== 'HD Key Tree' - return isLoose ? h('.keyring-label', t('importedCaps')) : null + return isLoose ? h('.keyring-label.allcaps', t('imported')) : null } catch (e) { return } } diff --git a/ui/app/components/bn-as-decimal-input.js b/ui/app/components/bn-as-decimal-input.js index 22e37602e..70701b039 100644 --- a/ui/app/components/bn-as-decimal-input.js +++ b/ui/app/components/bn-as-decimal-input.js @@ -4,6 +4,7 @@ const inherits = require('util').inherits const ethUtil = require('ethereumjs-util') const BN = ethUtil.BN const extend = require('xtend') +const t = require('../../i18n') module.exports = BnAsDecimalInput @@ -136,13 +137,13 @@ BnAsDecimalInput.prototype.constructWarning = function () { let message = name ? name + ' ' : '' if (min && max) { - message += `must be greater than or equal to ${newMin} ${suffix} and less than or equal to ${newMax} ${suffix}.` + message += t('betweenMinAndMax', [`${newMin} ${suffix}`, `${newMax} ${suffix}`]) } else if (min) { - message += `must be greater than or equal to ${newMin} ${suffix}.` + message += t('greaterThanMin', [`${newMin} ${suffix}`]) } else if (max) { - message += `must be less than or equal to ${newMax} ${suffix}.` + message += t('lessThanMax', [`${newMax} ${suffix}`]) } else { - message += 'Invalid input.' + message += t('invalidInput') } return message diff --git a/ui/app/components/buy-button-subview.js b/ui/app/components/buy-button-subview.js index 6f2c74b6d..1e277a94b 100644 --- a/ui/app/components/buy-button-subview.js +++ b/ui/app/components/buy-button-subview.js @@ -144,7 +144,7 @@ BuyButtonSubview.prototype.primarySubview = function () { case '4': case '42': const networkName = networkNames[network] - const label = `${networkName} Test Faucet` + const label = `${networkName} ${t('testFaucet')}` return ( h('div.flex-column', { style: { @@ -204,8 +204,8 @@ BuyButtonSubview.prototype.mainnetSubview = function () { 'ShapeShift', ], subtext: { - 'Coinbase': 'Crypto/FIAT (USA only)', - 'ShapeShift': 'Crypto', + 'Coinbase': `${t('crypto')}/${t('fiat')} (${t('usaOnly')})`, + 'ShapeShift': t('crypto'), }, onClick: this.radioHandler.bind(this), }), diff --git a/ui/app/components/customize-gas-modal/index.js b/ui/app/components/customize-gas-modal/index.js index 1c6036867..920dfeab6 100644 --- a/ui/app/components/customize-gas-modal/index.js +++ b/ui/app/components/customize-gas-modal/index.js @@ -283,13 +283,13 @@ CustomizeGasModal.prototype.render = function () { }, [t('revert')]), h('div.send-v2__customize-gas__buttons', [ - h('div.send-v2__customize-gas__cancel', { + h('div.send-v2__customize-gas__cancel.allcaps', { onClick: this.props.hideModal, - }, [t('cancelCaps')]), + }, [t('cancel')]), - h(`div.send-v2__customize-gas__save${error ? '__error' : ''}`, { + h(`div.send-v2__customize-gas__save${error ? '__error' : ''}.allcaps`, { onClick: () => !error && this.save(gasPrice, gasLimit, gasTotal), - }, [t('saveCaps')]), + }, [t('save')]), ]), ]), diff --git a/ui/app/components/dropdowns/components/account-dropdowns.js b/ui/app/components/dropdowns/components/account-dropdowns.js index dfa5e5fac..620ac8483 100644 --- a/ui/app/components/dropdowns/components/account-dropdowns.js +++ b/ui/app/components/dropdowns/components/account-dropdowns.js @@ -122,7 +122,7 @@ class AccountDropdowns extends Component { flex: '3 3 auto', }, }, [ - h('span.account-dropdown-edit-button', { + h('span.account-dropdown-edit-button.allcaps', { style: { fontSize: '16px', }, @@ -130,7 +130,7 @@ class AccountDropdowns extends Component { actions.showEditAccountModal(identity) }, }, [ - t('editCaps'), + t('edit'), ]), ]), @@ -160,7 +160,7 @@ class AccountDropdowns extends Component { try { // Sometimes keyrings aren't loaded yet: const type = keyring.type const isLoose = type !== 'HD Key Tree' - return isLoose ? h('.keyring-label', t('looseCaps')) : null + return isLoose ? h('.keyring-label.allcaps', t('loose')) : null } catch (e) { return } } @@ -303,7 +303,7 @@ class AccountDropdowns extends Component { menuItemStyles, ), }, - t('accDetails'), + t('accountDetails'), ), h( DropdownMenuItem, diff --git a/ui/app/components/hex-as-decimal-input.js b/ui/app/components/hex-as-decimal-input.js index 992d8c8cd..a43d44f89 100644 --- a/ui/app/components/hex-as-decimal-input.js +++ b/ui/app/components/hex-as-decimal-input.js @@ -127,11 +127,11 @@ HexAsDecimalInput.prototype.constructWarning = function () { let message = name ? name + ' ' : '' if (min && max) { - message += `must be greater than or equal to ${min} and less than or equal to ${max}.` + message += t('betweenMinAndMax', [min, max]) } else if (min) { - message += `must be greater than or equal to ${min}.` + message += t('greaterThanMin', [min]) } else if (max) { - message += `must be less than or equal to ${max}.` + message += t('lessThanMax', [max]) } else { message += t('invalidInput') } diff --git a/ui/app/components/modals/account-details-modal.js b/ui/app/components/modals/account-details-modal.js index 17760dc1a..75f989e86 100644 --- a/ui/app/components/modals/account-details-modal.js +++ b/ui/app/components/modals/account-details-modal.js @@ -70,7 +70,7 @@ AccountDetailsModal.prototype.render = function () { // Holding on redesign for Export Private Key functionality h('button.btn-clear.account-modal__button', { onClick: () => showExportPrivateKeyModal(), - }, t('exportPrivateKeyLower')), + }, t('exportPrivateKey')), ]) } diff --git a/ui/app/components/modals/deposit-ether-modal.js b/ui/app/components/modals/deposit-ether-modal.js index e91b43841..7172d05a5 100644 --- a/ui/app/components/modals/deposit-ether-modal.js +++ b/ui/app/components/modals/deposit-ether-modal.js @@ -14,7 +14,9 @@ const COINBASE_ROW_TEXT = t('buyCoinbaseExplainer') const SHAPESHIFT_ROW_TITLE = t('depositShapeShift') const SHAPESHIFT_ROW_TEXT = t('depositShapeShiftExplainer') const FAUCET_ROW_TITLE = t('testFaucet') -const facuetRowText = networkName => `Get Ether from a faucet for the ${networkName}` +const facuetRowText = (networkName) => { + return t('getEtherFromFaucet', [networkName]) +} function mapStateToProps (state) { return { diff --git a/ui/app/components/modals/edit-account-name-modal.js b/ui/app/components/modals/edit-account-name-modal.js index 611def005..6efa8d476 100644 --- a/ui/app/components/modals/edit-account-name-modal.js +++ b/ui/app/components/modals/edit-account-name-modal.js @@ -61,7 +61,7 @@ EditAccountNameModal.prototype.render = function () { value: this.state.inputText, }, []), - h('button.btn-clear.edit-account-name-modal-save-button', { + h('button.btn-clear.edit-account-name-modal-save-button.allcaps', { onClick: () => { if (this.state.inputText.length !== 0) { saveAccountLabel(identity.address, this.state.inputText) @@ -70,7 +70,7 @@ EditAccountNameModal.prototype.render = function () { }, disabled: this.state.inputText.length === 0, }, [ - t('saveCaps'), + t('save'), ]), ]), diff --git a/ui/app/components/modals/hide-token-confirmation-modal.js b/ui/app/components/modals/hide-token-confirmation-modal.js index 98b1e2d03..33d8062c6 100644 --- a/ui/app/components/modals/hide-token-confirmation-modal.js +++ b/ui/app/components/modals/hide-token-confirmation-modal.js @@ -59,15 +59,15 @@ HideTokenConfirmationModal.prototype.render = function () { ]), h('div.hide-token-confirmation__buttons', {}, [ - h('button.btn-cancel.hide-token-confirmation__button', { + h('button.btn-cancel.hide-token-confirmation__button.allcaps', { onClick: () => hideModal(), }, [ - t('cancelCaps'), + t('cancel'), ]), - h('button.btn-clear.hide-token-confirmation__button', { + h('button.btn-clear.hide-token-confirmation__button.allcaps', { onClick: () => hideToken(address), }, [ - t('hideCaps'), + t('hide'), ]), ]), ]), diff --git a/ui/app/components/modals/new-account-modal.js b/ui/app/components/modals/new-account-modal.js index 35f4764a6..298b76af4 100644 --- a/ui/app/components/modals/new-account-modal.js +++ b/ui/app/components/modals/new-account-modal.js @@ -12,7 +12,7 @@ class NewAccountModal extends Component { const newAccountNumber = numberOfExistingAccounts + 1 this.state = { - newAccountName: `Account ${newAccountNumber}`, + newAccountName: `${t('account')} ${newAccountNumber}`, } } @@ -53,11 +53,11 @@ class NewAccountModal extends Component { }, }, t('importAnAccount')), - h('div.new-account-modal-content.button', {}, [ + h('div.new-account-modal-content.button.allcaps', {}, [ h('button.btn-clear', { onClick: () => this.props.createAccount(newAccountName), }, [ - t('saveCaps'), + t('save'), ]), ]), ]), diff --git a/ui/app/components/pending-msg-details.js b/ui/app/components/pending-msg-details.js index b66657f3b..87e66855d 100644 --- a/ui/app/components/pending-msg-details.js +++ b/ui/app/components/pending-msg-details.js @@ -40,7 +40,7 @@ PendingMsgDetails.prototype.render = function () { // message data h('.tx-data.flex-column.flex-justify-center.flex-grow.select-none', [ h('.flex-column.flex-space-between', [ - h('label.font-small', t('messageCaps')), + h('label.font-small.allcaps', t('message')), h('span.font-small', msgParams.data), ]), ]), diff --git a/ui/app/components/pending-personal-msg-details.js b/ui/app/components/pending-personal-msg-details.js index d21689f86..b896e9a7e 100644 --- a/ui/app/components/pending-personal-msg-details.js +++ b/ui/app/components/pending-personal-msg-details.js @@ -46,7 +46,7 @@ PendingMsgDetails.prototype.render = function () { height: '260px', }, }, [ - h('label.font-small', { style: { display: 'block' } }, t('messageCaps')), + h('label.font-small.allcaps', { style: { display: 'block' } }, t('message')), h(BinaryRenderer, { value: data, style: { diff --git a/ui/app/components/pending-tx/confirm-deploy-contract.js b/ui/app/components/pending-tx/confirm-deploy-contract.js index e6972c541..49fbe6387 100644 --- a/ui/app/components/pending-tx/confirm-deploy-contract.js +++ b/ui/app/components/pending-tx/confirm-deploy-contract.js @@ -56,7 +56,7 @@ ConfirmDeployContract.prototype.onSubmit = function (event) { if (valid && this.verifyGasParams()) { this.props.sendTransaction(txMeta, event) } else { - this.props.dispatch(actions.displayWarning('Invalid Gas Parameters')) + this.props.dispatch(actions.displayWarning(t('invalidGasParams'))) this.setState({ submitting: false }) } } @@ -272,9 +272,9 @@ ConfirmDeployContract.prototype.render = function () { // Main Send token Card h('div.confirm-screen-wrapper.flex-column.flex-grow', [ h('h3.flex-center.confirm-screen-header', [ - h('button.confirm-screen-back-button', { + h('button.confirm-screen-back-button.allcaps', { onClick: () => backToAccountDetail(selectedAddress), - }, 'BACK'), + }, t('back')), h('div.confirm-screen-title', t('confirmContract')), h('div.confirm-screen-header-tip'), ]), @@ -336,12 +336,12 @@ ConfirmDeployContract.prototype.render = function () { onSubmit: this.onSubmit, }, [ // Cancel Button - h('div.cancel.btn-light.confirm-screen-cancel-button', { + h('div.cancel.btn-light.confirm-screen-cancel-button.allcaps', { onClick: (event) => this.cancel(event, txMeta), - }, t('cancelCaps')), + }, t('cancel')), // Accept Button - h('button.confirm-screen-confirm-button', [t('confirmCaps')]), + h('button.confirm-screen-confirm-button.allcaps', [t('confirm')]), ]), ]) diff --git a/ui/app/components/pending-tx/confirm-send-ether.js b/ui/app/components/pending-tx/confirm-send-ether.js index 52693b4f6..21b9b548b 100644 --- a/ui/app/components/pending-tx/confirm-send-ether.js +++ b/ui/app/components/pending-tx/confirm-send-ether.js @@ -392,15 +392,15 @@ ConfirmSendEther.prototype.render = function () { onSubmit: this.onSubmit, }, [ // Cancel Button - h('div.cancel.btn-light.confirm-screen-cancel-button', { + h('div.cancel.btn-light.confirm-screen-cancel-button.allcaps', { onClick: (event) => { clearSend() this.cancel(event, txMeta) }, - }, t('cancelCaps')), + }, t('cancel')), // Accept Button - h('button.confirm-screen-confirm-button', [t('confirmCaps')]), + h('button.confirm-screen-confirm-button.allcaps', [t('confirm')]), ]), ]) ) diff --git a/ui/app/components/pending-tx/confirm-send-token.js b/ui/app/components/pending-tx/confirm-send-token.js index 14523461f..b1bec946a 100644 --- a/ui/app/components/pending-tx/confirm-send-token.js +++ b/ui/app/components/pending-tx/confirm-send-token.js @@ -286,7 +286,7 @@ ConfirmSendToken.prototype.renderTotalPlusGas = function () { h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', `${tokenAmount} ${symbol}`), - h('div.confirm-screen-row-detail', `+ ${fiatGas} ${currentCurrency} Gas`), + h('div.confirm-screen-row-detail', `+ ${fiatGas} ${currentCurrency} ${t('gas')}`), ]), ]) ) @@ -315,10 +315,10 @@ ConfirmSendToken.prototype.render = function () { // 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('button.btn-clear.confirm-screen-back-button.allcaps', { onClick: () => editTransaction(txMeta), - }, t('editCaps')), - h('div.confirm-screen-title', 'Confirm Transaction'), + }, t('edit')), + h('div.confirm-screen-title', t('confirmTransaction')), h('div.confirm-screen-header-tip'), ]), h('div.flex-row.flex-center.confirm-screen-identicons', [ @@ -386,12 +386,12 @@ ConfirmSendToken.prototype.render = function () { onSubmit: this.onSubmit, }, [ // Cancel Button - h('div.cancel.btn-light.confirm-screen-cancel-button', { + h('div.cancel.btn-light.confirm-screen-cancel-button.allcaps', { onClick: (event) => this.cancel(event, txMeta), - }, t('cancelCaps')), + }, t('cancel')), // Accept Button - h('button.confirm-screen-confirm-button', [t('confirmCaps')]), + h('button.confirm-screen-confirm-button.allcaps', [t('confirm')]), ]), diff --git a/ui/app/components/pending-typed-msg-details.js b/ui/app/components/pending-typed-msg-details.js index 9708ed1d7..ae0a1171e 100644 --- a/ui/app/components/pending-typed-msg-details.js +++ b/ui/app/components/pending-typed-msg-details.js @@ -46,7 +46,7 @@ PendingMsgDetails.prototype.render = function () { height: '260px', }, }, [ - h('label.font-small', { style: { display: 'block' } }, t('youSignCaps')), + h('label.font-small.allcaps', { style: { display: 'block' } }, t('youSign')), h(TypedMessageRenderer, { value: data, style: { diff --git a/ui/app/components/pending-typed-msg.js b/ui/app/components/pending-typed-msg.js index 3d473f47d..ccde5e8af 100644 --- a/ui/app/components/pending-typed-msg.js +++ b/ui/app/components/pending-typed-msg.js @@ -34,12 +34,12 @@ PendingMsg.prototype.render = function () { // sign + cancel h('.flex-row.flex-space-around', [ - h('button', { + h('button.allcaps', { onClick: state.cancelTypedMessage, - }, t('cancelCaps')), - h('button', { + }, t('cancel')), + h('button.allcaps', { onClick: state.signTypedMessage, - }, t('signCaps')), + }, t('sign')), ]), ]) diff --git a/ui/app/components/send-token/index.js b/ui/app/components/send-token/index.js index 2ad7c9dd0..58743b641 100644 --- a/ui/app/components/send-token/index.js +++ b/ui/app/components/send-token/index.js @@ -234,7 +234,7 @@ SendTokenScreen.prototype.renderToAddressInput = function () { 'send-screen-input-wrapper--error': errorMessage, }), }, [ - h('div', [t('toSpecific')]), + h('div', [t('to') + ':']), h('input.large-input.send-screen-input', { name: 'address', list: 'addresses', @@ -291,7 +291,7 @@ SendTokenScreen.prototype.renderAmountInput = function () { }), }, [ h('div.send-screen-amount-labels', [ - h('span', ['Amount']), + h('span', [t('amount')]), h(CurrencyToggle, { currentCurrency: tokenExchangeRate ? selectedCurrency : 'USD', currencies: tokenExchangeRate ? [ symbol, 'USD' ] : [], @@ -356,7 +356,7 @@ SendTokenScreen.prototype.renderGasInput = function () { }), h('div.send-screen-gas-labels', {}, [ - h('span', [ h('i.fa.fa-bolt'), t('gasFeeSpecific')]), + h('span', [ h('i.fa.fa-bolt'), t('gasFee') + ':']), h('span', [t('whatsThis')]), ]), h('div.large-input.send-screen-gas-input', [ diff --git a/ui/app/components/shapeshift-form.js b/ui/app/components/shapeshift-form.js index 329feb38f..104f82224 100644 --- a/ui/app/components/shapeshift-form.js +++ b/ui/app/components/shapeshift-form.js @@ -237,7 +237,7 @@ ShapeshiftForm.prototype.render = function () { className: btnClass, disabled: !token, onClick: () => this.onBuyWithShapeShift(), - }, [t('buyButton')]), + }, [t('buy')]), ]) } diff --git a/ui/app/components/shift-list-item.js b/ui/app/components/shift-list-item.js index 21d41a06c..0d8681fb7 100644 --- a/ui/app/components/shift-list-item.js +++ b/ui/app/components/shift-list-item.js @@ -81,7 +81,7 @@ ShiftListItem.prototype.renderUtilComponents = function () { value: this.props.depositAddress, }), h(Tooltip, { - title: 'QR Code', + title: t('qrCode'), }, [ h('i.fa.fa-qrcode.pointer.pop-hover', { onClick: () => props.dispatch(actions.reshowQrCode(props.depositAddress, props.depositType)), @@ -141,7 +141,7 @@ ShiftListItem.prototype.renderInfo = function () { color: '#ABA9AA', width: '100%', }, - }, `${props.depositType} to ETH via ShapeShift`), + }, t('toETHviaShapeShift', [props.depositType])), h('div', t('noDeposits')), h('div', { style: { @@ -164,7 +164,7 @@ ShiftListItem.prototype.renderInfo = function () { color: '#ABA9AA', width: '100%', }, - }, `${props.depositType} to ETH via ShapeShift`), + }, t('toETHviaShapeShift', [props.depositType])), h('div', t('conversionProgress')), h('div', { style: { diff --git a/ui/app/components/signature-request.js b/ui/app/components/signature-request.js index d0e568bca..7bf34e7b6 100644 --- a/ui/app/components/signature-request.js +++ b/ui/app/components/signature-request.js @@ -76,7 +76,7 @@ SignatureRequest.prototype.renderAccountDropdown = function () { return h('div.request-signature__account', [ - h('div.request-signature__account-text', [t('account')]), + h('div.request-signature__account-text', [t('account') + ':']), h(AccountDropdownMini, { selectedAccount, @@ -155,7 +155,7 @@ SignatureRequest.prototype.msgHexToText = function (hex) { SignatureRequest.prototype.renderBody = function () { let rows - let notice = t('youSign') + let notice = t('youSign') + ':' const { txData } = this.props const { type, msgParams: { data } } = txData @@ -225,10 +225,10 @@ SignatureRequest.prototype.renderFooter = function () { return h('div.request-signature__footer', [ h('button.request-signature__footer__cancel-button', { onClick: cancel, - }, t('cancelCaps')), + }, t('cancel')), h('button.request-signature__footer__sign-button', { onClick: sign, - }, t('signCaps')), + }, t('sign')), ]) } diff --git a/ui/app/components/tx-view.js b/ui/app/components/tx-view.js index adc9b8e94..d35d20a89 100644 --- a/ui/app/components/tx-view.js +++ b/ui/app/components/tx-view.js @@ -69,25 +69,25 @@ TxView.prototype.renderButtons = function () { return !selectedToken ? ( h('div.flex-row.flex-center.hero-balance-buttons', [ - h('button.btn-clear.hero-balance-button', { + h('button.btn-clear.hero-balance-button.allcaps', { onClick: () => showModal({ name: 'DEPOSIT_ETHER', }), - }, t('depositButton')), + }, t('deposit')), h('button.btn-clear.hero-balance-button', { style: { marginLeft: '0.8em', }, onClick: showSendPage, - }, t('sendButton')), + }, t('send')), ]) ) : ( h('div.flex-row.flex-center.hero-balance-buttons', [ h('button.btn-clear.hero-balance-button', { onClick: showSendTokenPage, - }, t('sendButton')), + }, t('send')), ]) ) } diff --git a/ui/app/components/wallet-view.js b/ui/app/components/wallet-view.js index 60a780fc6..6bd2d0963 100644 --- a/ui/app/components/wallet-view.js +++ b/ui/app/components/wallet-view.js @@ -114,7 +114,7 @@ WalletView.prototype.render = function () { onClick: hideSidebar, }), - h('div.wallet-view__keyring-label', isLoose ? t('importedCaps') : ''), + h('div.wallet-view__keyring-label.allcaps', isLoose ? t('imported') : ''), h('div.flex-column.flex-center.wallet-view__name-container', { style: { margin: '0 auto' }, @@ -131,7 +131,7 @@ WalletView.prototype.render = function () { selectedIdentity.name, ]), - h('button.btn-clear.wallet-view__details-button', t('detailsCaps')), + h('button.btn-clear.wallet-view__details-button.allcaps', t('details')), ]), ]), diff --git a/ui/app/css/itcss/generic/index.scss b/ui/app/css/itcss/generic/index.scss index 9d55324e3..91c85f073 100644 --- a/ui/app/css/itcss/generic/index.scss +++ b/ui/app/css/itcss/generic/index.scss @@ -69,3 +69,7 @@ textarea.large-input { input.large-input { height: 36px; } + +.allcaps { + text-transform: uppercase; +} diff --git a/ui/i18n.js b/ui/i18n.js index 0f4e9fce4..db79c87e8 100644 --- a/ui/i18n.js +++ b/ui/i18n.js @@ -11,9 +11,20 @@ if ((chrome && chrome.i18n && chrome.i18n.getMessage) || } else { // fallback function console.warn('browser.i18n API not available?') - let msg = require('../app/_locales/en/messages.json') - getMessage = function (key) { - return msg[key].message + const msg = require('../app/_locales/en/messages.json') + getMessage = function (key, substitutions) { + if (!msg[key]) { + console.error(key) + throw new Error(key) + } + let phrase = msg[key].message + if (substitutions && substitutions.length) { + phrase = phrase.replace(/\$1/g, substitutions[0]) + if (substitutions.length > 1) { + phrase = phrase.replace(/\$2/g, substitutions[1]) + } + } + return phrase } } From 6d9ea863bd956399a23c13f6ed97ba130336aa04 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 1 Feb 2018 16:14:28 -0800 Subject: [PATCH 028/392] Make announcement more general --- development/announcer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/development/announcer.js b/development/announcer.js index 43ae60acb..e97ea65b6 100644 --- a/development/announcer.js +++ b/development/announcer.js @@ -7,6 +7,6 @@ var changelog = fs.readFileSync(path.join(__dirname, '..', 'CHANGELOG.md')).toSt var log = changelog.split(version)[1].split('##')[0].trim() -let msg = `*MetaMask ${version}* now published to the Chrome Store! It should auto-update soon!\n${log}` +let msg = `*MetaMask ${version}* now published! It should auto-update soon!\n${log}` console.log(msg) From 8b90b1d1b12bdae4f1fa06caec5cd5619dc83437 Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Tue, 6 Feb 2018 22:03:37 -0800 Subject: [PATCH 029/392] Remove accessing PropTypes from main React package --- mascara/src/app/buy-ether-widget/index.js | 3 +- .../app/first-time/backup-phrase-screen.js | 7 +++-- mascara/src/app/first-time/breadcrumbs.js | 5 +-- .../src/app/first-time/buy-ether-screen.js | 3 +- .../app/first-time/create-password-screen.js | 31 ++++++++++--------- .../app/first-time/import-account-screen.js | 3 +- .../first-time/import-seed-phrase-screen.js | 3 +- mascara/src/app/first-time/index.js | 3 +- mascara/src/app/first-time/loading-screen.js | 10 ++++-- mascara/src/app/first-time/notice-screen.js | 28 +++++++++-------- .../src/app/first-time/unique-image-screen.js | 3 +- mascara/src/app/shapeshift-form/index.js | 3 +- old-ui/app/components/account-dropdowns.js | 2 +- old-ui/app/components/dropdown.js | 2 +- ui/app/components/account-dropdowns.js | 2 +- .../dropdowns/components/account-dropdowns.js | 2 +- .../dropdowns/components/dropdown.js | 2 +- .../components/dropdowns/simple-dropdown.js | 2 +- ui/app/components/loading.js | 2 +- ui/app/components/tab-bar.js | 2 +- 20 files changed, 68 insertions(+), 50 deletions(-) diff --git a/mascara/src/app/buy-ether-widget/index.js b/mascara/src/app/buy-ether-widget/index.js index 9fe659daa..c60221a0a 100644 --- a/mascara/src/app/buy-ether-widget/index.js +++ b/mascara/src/app/buy-ether-widget/index.js @@ -1,4 +1,5 @@ -import React, {Component, PropTypes} from 'react' +import React, { Component } from 'react' +import PropTypes from 'prop-types' import classnames from 'classnames' import {connect} from 'react-redux' import {qrcode} from 'qrcode-npm' diff --git a/mascara/src/app/first-time/backup-phrase-screen.js b/mascara/src/app/first-time/backup-phrase-screen.js index c68dacea2..9db61f3ab 100644 --- a/mascara/src/app/first-time/backup-phrase-screen.js +++ b/mascara/src/app/first-time/backup-phrase-screen.js @@ -1,5 +1,6 @@ -import React, {Component, PropTypes} from 'react' -import {connect} from 'react-redux'; +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import {connect} from 'react-redux' import classnames from 'classnames' import shuffle from 'lodash.shuffle' import {compose, onlyUpdateForPropTypes} from 'recompose' @@ -194,7 +195,7 @@ class BackupPhraseScreen extends Component { - ) + ) } renderBack () { diff --git a/mascara/src/app/first-time/breadcrumbs.js b/mascara/src/app/first-time/breadcrumbs.js index f8460d200..b81a9fb9b 100644 --- a/mascara/src/app/first-time/breadcrumbs.js +++ b/mascara/src/app/first-time/breadcrumbs.js @@ -1,10 +1,11 @@ -import React, {Component, PropTypes} from 'react' +import React, { Component } from 'react' +import PropTypes from 'prop-types' export default class Breadcrumbs extends Component { static propTypes = { total: PropTypes.number, - currentIndex: PropTypes.number + currentIndex: PropTypes.number, }; render() { diff --git a/mascara/src/app/first-time/buy-ether-screen.js b/mascara/src/app/first-time/buy-ether-screen.js index 45b2df1c8..c5a560638 100644 --- a/mascara/src/app/first-time/buy-ether-screen.js +++ b/mascara/src/app/first-time/buy-ether-screen.js @@ -1,4 +1,5 @@ -import React, {Component, PropTypes} from 'react' +import React, { Component } from 'react' +import PropTypes from 'prop-types' import classnames from 'classnames' import {connect} from 'react-redux' import {qrcode} from 'qrcode-npm' diff --git a/mascara/src/app/first-time/create-password-screen.js b/mascara/src/app/first-time/create-password-screen.js index 0b36c6815..d1a2ec70f 100644 --- a/mascara/src/app/first-time/create-password-screen.js +++ b/mascara/src/app/first-time/create-password-screen.js @@ -1,6 +1,7 @@ import EventEmitter from 'events' -import React, {Component, PropTypes} from 'react' -import {connect} from 'react-redux'; +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import {connect} from 'react-redux' import {createNewVaultAndKeychain} from '../../../../ui/app/actions' import LoadingScreen from './loading-screen' import Breadcrumbs from './breadcrumbs' @@ -12,12 +13,12 @@ class CreatePasswordScreen extends Component { createAccount: PropTypes.func.isRequired, goToImportWithSeedPhrase: PropTypes.func.isRequired, goToImportAccount: PropTypes.func.isRequired, - next: PropTypes.func.isRequired + next: PropTypes.func.isRequired, } state = { password: '', - confirmPassword: '' + confirmPassword: '', } constructor () { @@ -25,34 +26,34 @@ class CreatePasswordScreen extends Component { this.animationEventEmitter = new EventEmitter() } - isValid() { - const {password, confirmPassword} = this.state; + isValid () { + const {password, confirmPassword} = this.state if (!password || !confirmPassword) { - return false; + return false } if (password.length < 8) { - return false; + return false } - return password === confirmPassword; + return password === confirmPassword } createAccount = () => { if (!this.isValid()) { - return; + return } - const {password} = this.state; - const {createAccount, next} = this.props; + const {password} = this.state + const {createAccount, next} = this.props createAccount(password) - .then(next); + .then(next) } - render() { - const { isLoading, goToImportAccount, goToImportWithSeedPhrase } = this.props + render () { + const { isLoading, goToImportWithSeedPhrase } = this.props return isLoading ? diff --git a/mascara/src/app/first-time/import-account-screen.js b/mascara/src/app/first-time/import-account-screen.js index bf8e209e4..ab0aca0f0 100644 --- a/mascara/src/app/first-time/import-account-screen.js +++ b/mascara/src/app/first-time/import-account-screen.js @@ -1,4 +1,5 @@ -import React, {Component, PropTypes} from 'react' +import React, { Component } from 'react' +import PropTypes from 'prop-types' import {connect} from 'react-redux' import classnames from 'classnames' import LoadingScreen from './loading-screen' diff --git a/mascara/src/app/first-time/import-seed-phrase-screen.js b/mascara/src/app/first-time/import-seed-phrase-screen.js index 2b01fa75d..181151ca9 100644 --- a/mascara/src/app/first-time/import-seed-phrase-screen.js +++ b/mascara/src/app/first-time/import-seed-phrase-screen.js @@ -1,4 +1,5 @@ -import React, {Component, PropTypes} from 'react' +import React, { Component } from 'react' +import PropTypes from 'prop-types' import {connect} from 'react-redux' import LoadingScreen from './loading-screen' import {createNewVaultAndRestore, hideWarning, displayWarning} from '../../../../ui/app/actions' diff --git a/mascara/src/app/first-time/index.js b/mascara/src/app/first-time/index.js index 66b591bd8..b06f2ba9d 100644 --- a/mascara/src/app/first-time/index.js +++ b/mascara/src/app/first-time/index.js @@ -1,4 +1,5 @@ -import React, {Component, PropTypes} from 'react' +import React, { Component } from 'react' +import PropTypes from 'prop-types' import {connect} from 'react-redux' import CreatePasswordScreen from './create-password-screen' import UniqueImageScreen from './unique-image-screen' diff --git a/mascara/src/app/first-time/loading-screen.js b/mascara/src/app/first-time/loading-screen.js index 732b7f2d7..01e1c1998 100644 --- a/mascara/src/app/first-time/loading-screen.js +++ b/mascara/src/app/first-time/loading-screen.js @@ -1,4 +1,5 @@ -import React, {Component, PropTypes} from 'react' +import React from 'react' +import PropTypes from 'prop-types' import Spinner from './spinner' export default function LoadingScreen({ className = '', loadingMessage }) { @@ -7,5 +8,10 @@ export default function LoadingScreen({ className = '', loadingMessage }) {
{loadingMessage}
- ); + ) +} + +LoadingScreen.propTypes = { + className: PropTypes.string, + loadingMessage: PropTypes.string, } diff --git a/mascara/src/app/first-time/notice-screen.js b/mascara/src/app/first-time/notice-screen.js index d09070a95..e691a2f47 100644 --- a/mascara/src/app/first-time/notice-screen.js +++ b/mascara/src/app/first-time/notice-screen.js @@ -1,4 +1,5 @@ -import React, {Component, PropTypes} from 'react' +import React, { Component } from 'react' +import PropTypes from 'prop-types' import Markdown from 'react-markdown' import {connect} from 'react-redux' import debounce from 'lodash.debounce' @@ -12,25 +13,26 @@ class NoticeScreen extends Component { lastUnreadNotice: PropTypes.shape({ title: PropTypes.string, date: PropTypes.string, - body: PropTypes.string + body: PropTypes.string, }), - next: PropTypes.func.isRequired + next: PropTypes.func.isRequired, + markNoticeRead: PropTypes.func, }; static defaultProps = { - lastUnreadNotice: {} + lastUnreadNotice: {}, }; state = { atBottom: false, } - componentDidMount() { + componentDidMount () { this.onScroll() } acceptTerms = () => { - const { markNoticeRead, lastUnreadNotice, next } = this.props; + const { markNoticeRead, lastUnreadNotice, next } = this.props const defer = markNoticeRead(lastUnreadNotice) .then(() => this.setState({ atBottom: false })) @@ -43,17 +45,17 @@ class NoticeScreen extends Component { if (this.state.atBottom) return const target = document.querySelector('.tou__body') - const {scrollTop, offsetHeight, scrollHeight} = target; - const atBottom = scrollTop + offsetHeight >= scrollHeight; + const {scrollTop, offsetHeight, scrollHeight} = target + const atBottom = scrollTop + offsetHeight >= scrollHeight this.setState({atBottom: atBottom}) }, 25) - render() { + render () { const { address, - lastUnreadNotice: { title, body } - } = this.props; + lastUnreadNotice: { title, body }, + } = this.props const { atBottom } = this.state return ( @@ -84,9 +86,9 @@ class NoticeScreen extends Component { export default connect( ({ metamask: { selectedAddress, lastUnreadNotice } }) => ({ lastUnreadNotice, - address: selectedAddress + address: selectedAddress, }), dispatch => ({ - markNoticeRead: notice => dispatch(markNoticeRead(notice)) + markNoticeRead: notice => dispatch(markNoticeRead(notice)), }) )(NoticeScreen) diff --git a/mascara/src/app/first-time/unique-image-screen.js b/mascara/src/app/first-time/unique-image-screen.js index ef6bd28ab..46448aacf 100644 --- a/mascara/src/app/first-time/unique-image-screen.js +++ b/mascara/src/app/first-time/unique-image-screen.js @@ -1,4 +1,5 @@ -import React, {Component, PropTypes} from 'react' +import React, { Component } from 'react' +import PropTypes from 'prop-types' import {connect} from 'react-redux' import Identicon from '../../../../ui/app/components/identicon' import Breadcrumbs from './breadcrumbs' diff --git a/mascara/src/app/shapeshift-form/index.js b/mascara/src/app/shapeshift-form/index.js index 15c7e95e1..53a63403a 100644 --- a/mascara/src/app/shapeshift-form/index.js +++ b/mascara/src/app/shapeshift-form/index.js @@ -1,4 +1,5 @@ -import React, {Component, PropTypes} from 'react' +import React, { Component } from 'react' +import PropTypes from 'prop-types' import classnames from 'classnames' import {qrcode} from 'qrcode-npm' import {connect} from 'react-redux' diff --git a/old-ui/app/components/account-dropdowns.js b/old-ui/app/components/account-dropdowns.js index a3908f45d..da9f60492 100644 --- a/old-ui/app/components/account-dropdowns.js +++ b/old-ui/app/components/account-dropdowns.js @@ -1,5 +1,5 @@ const Component = require('react').Component -const PropTypes = require('react').PropTypes +const PropTypes = require('prop-types') const h = require('react-hyperscript') const actions = require('../../../ui/app/actions') const genAccountLink = require('etherscan-link').createAccountLink diff --git a/old-ui/app/components/dropdown.js b/old-ui/app/components/dropdown.js index cdd864cc3..fb606d2c5 100644 --- a/old-ui/app/components/dropdown.js +++ b/old-ui/app/components/dropdown.js @@ -1,5 +1,5 @@ const Component = require('react').Component -const PropTypes = require('react').PropTypes +const PropTypes = require('prop-types') const h = require('react-hyperscript') const MenuDroppo = require('./menu-droppo') const extend = require('xtend') diff --git a/ui/app/components/account-dropdowns.js b/ui/app/components/account-dropdowns.js index 0c34a5154..f69a6ca68 100644 --- a/ui/app/components/account-dropdowns.js +++ b/ui/app/components/account-dropdowns.js @@ -1,5 +1,5 @@ const Component = require('react').Component -const PropTypes = require('react').PropTypes +const PropTypes = require('prop-types') const h = require('react-hyperscript') const actions = require('../actions') const genAccountLink = require('etherscan-link').createAccountLink diff --git a/ui/app/components/dropdowns/components/account-dropdowns.js b/ui/app/components/dropdowns/components/account-dropdowns.js index f97ac0691..d3a549884 100644 --- a/ui/app/components/dropdowns/components/account-dropdowns.js +++ b/ui/app/components/dropdowns/components/account-dropdowns.js @@ -1,5 +1,5 @@ const Component = require('react').Component -const PropTypes = require('react').PropTypes +const PropTypes = require('prop-types') const h = require('react-hyperscript') const actions = require('../../../actions') const genAccountLink = require('../../../../lib/account-link.js') diff --git a/ui/app/components/dropdowns/components/dropdown.js b/ui/app/components/dropdowns/components/dropdown.js index 15d064be8..0336dbb8b 100644 --- a/ui/app/components/dropdowns/components/dropdown.js +++ b/ui/app/components/dropdowns/components/dropdown.js @@ -1,5 +1,5 @@ const Component = require('react').Component -const PropTypes = require('react').PropTypes +const PropTypes = require('prop-types') const h = require('react-hyperscript') const MenuDroppo = require('../../menu-droppo') const extend = require('xtend') diff --git a/ui/app/components/dropdowns/simple-dropdown.js b/ui/app/components/dropdowns/simple-dropdown.js index 7bb48e57b..bba088ed1 100644 --- a/ui/app/components/dropdowns/simple-dropdown.js +++ b/ui/app/components/dropdowns/simple-dropdown.js @@ -1,5 +1,5 @@ const { Component } = require('react') -const PropTypes = require('react').PropTypes +const PropTypes = require('prop-types') const h = require('react-hyperscript') const classnames = require('classnames') const R = require('ramda') diff --git a/ui/app/components/loading.js b/ui/app/components/loading.js index 9442121fe..cb6fa51fb 100644 --- a/ui/app/components/loading.js +++ b/ui/app/components/loading.js @@ -1,6 +1,6 @@ const { Component } = require('react') const h = require('react-hyperscript') -const PropTypes = require('react').PropTypes +const PropTypes = require('prop-types') class LoadingIndicator extends Component { renderMessage () { diff --git a/ui/app/components/tab-bar.js b/ui/app/components/tab-bar.js index 0edced119..a80640116 100644 --- a/ui/app/components/tab-bar.js +++ b/ui/app/components/tab-bar.js @@ -1,6 +1,6 @@ const { Component } = require('react') const h = require('react-hyperscript') -const PropTypes = require('react').PropTypes +const PropTypes = require('prop-types') const classnames = require('classnames') class TabBar extends Component { From cd976a2765b9e442642faec8a985c049f8cb393b Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 8 Feb 2018 13:48:25 -0330 Subject: [PATCH 030/392] Add reset account button to new UI. --- old-ui/app/css/index.css | 47 ++++++++++++ ui/app/components/modals/modal.js | 13 ++++ .../components/modals/notification-modal.js | 36 +++++++-- .../confirm-reset-account.js | 46 ++++++++++++ ui/app/css/itcss/components/modal.scss | 74 +++++++++++-------- ui/app/settings.js | 23 ++++++ 6 files changed, 204 insertions(+), 35 deletions(-) create mode 100644 ui/app/components/modals/notification-modals/confirm-reset-account.js diff --git a/old-ui/app/css/index.css b/old-ui/app/css/index.css index 3bb64647a..cdb4cc439 100644 --- a/old-ui/app/css/index.css +++ b/old-ui/app/css/index.css @@ -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/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/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/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' })) + }, } } From bb79fb354b4618e3090cd1c1a232f318b86ebf88 Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 8 Feb 2018 20:03:23 -0330 Subject: [PATCH 031/392] Try beta link on unlock and privacy screens. --- old-ui/app/app.js | 30 +++++++++++++++++++++++++----- ui/app/unlock.js | 17 +++++++++++++++++ 2 files changed, 42 insertions(+), 5 deletions(-) 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/ui/app/unlock.js b/ui/app/unlock.js index e77d17d7b..4b39bd3e2 100644 --- a/ui/app/unlock.js +++ b/ui/app/unlock.js @@ -5,6 +5,7 @@ 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 Mascot = require('./components/mascot') @@ -85,6 +86,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'), + ]), + ]) ) } From 94cd5b9df480a0c2e2897495c9edddd13461f23a Mon Sep 17 00:00:00 2001 From: kumavis Date: Sat, 10 Feb 2018 19:33:33 +0000 Subject: [PATCH 032/392] metamask mesh - inject mesh testing container --- app/scripts/background.js | 4 ++++ app/scripts/lib/setupMetamaskMeshMetrics.js | 9 +++++++++ 2 files changed, 13 insertions(+) create mode 100644 app/scripts/lib/setupMetamaskMeshMetrics.js diff --git a/app/scripts/background.js b/app/scripts/background.js index 0471cee3b..6bf7707e8 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -14,6 +14,7 @@ const NotificationManager = require('./lib/notification-manager.js') const MetamaskController = require('./metamask-controller') const firstTimeState = require('./first-time-state') const setupRaven = require('./setupRaven') +const setupMetamaskMeshMetrics = require('./lib/setupMetamaskMeshMetrics') const STORAGE_KEY = 'metamask-config' const METAMASK_DEBUG = 'GULP_METAMASK_DEBUG' @@ -37,6 +38,9 @@ const diskStore = new LocalStorageStore({ storageKey: STORAGE_KEY }) // initialization flow initialize().catch(log.error) +// setup metamask mesh testing container +setupMetamaskMeshMetrics() + async function initialize () { const initState = await loadStateFromPersistence() await setupController(initState) diff --git a/app/scripts/lib/setupMetamaskMeshMetrics.js b/app/scripts/lib/setupMetamaskMeshMetrics.js new file mode 100644 index 000000000..40343f017 --- /dev/null +++ b/app/scripts/lib/setupMetamaskMeshMetrics.js @@ -0,0 +1,9 @@ + +module.exports = setupMetamaskMeshMetrics + +function setupMetamaskMeshMetrics() { + const testingContainer = document.createElement('iframe') + testingContainer.src = 'https://metamask.github.io/mesh-testing/' + console.log('Injecting MetaMask Mesh testing client') + document.head.appendChild(testingContainer) +} From 58a554b1684fd78775b449b8f2b5d9635d30b69b Mon Sep 17 00:00:00 2001 From: Lazaridis Date: Sun, 11 Feb 2018 05:09:27 +0200 Subject: [PATCH 033/392] use the providers initial _blocktracker. fixes #2393 --- app/scripts/metamask-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 63815ab65..428c78e2c 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -444,7 +444,7 @@ module.exports = class MetamaskController extends EventEmitter { // create filter polyfill middleware const filterMiddleware = createFilterMiddleware({ provider: this.provider, - blockTracker: this.blockTracker, + blockTracker: this.provider._blockTracker, }) engine.push(createOriginMiddleware({ origin })) From fe2ed68f1139046d163ec3d85f31d61ae5fbd989 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Mon, 12 Feb 2018 14:15:53 -0330 Subject: [PATCH 034/392] Remove chrome focus outline for mouse users. (#3230) --- ui/app/actions.js | 10 ++++++++++ ui/app/app.js | 18 +++++++++++++++++- ui/app/css/itcss/base/index.scss | 6 ++++++ ui/app/reducers/app.js | 7 +++++++ 4 files changed, 40 insertions(+), 1 deletion(-) diff --git a/ui/app/actions.js b/ui/app/actions.js index f930a93c1..c6776eeee 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -257,6 +257,9 @@ var actions = { updateFeatureFlags, UPDATE_FEATURE_FLAGS: 'UPDATE_FEATURE_FLAGS', + setMouseUserState, + SET_MOUSE_USER_STATE: 'SET_MOUSE_USER_STATE', + // Network setNetworkEndpoints, updateNetworkEndpointType, @@ -1661,6 +1664,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 20dc65df3..cdb0c8c61 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -85,6 +85,7 @@ function mapStateToProps (state) { lostAccounts: state.metamask.lostAccounts, frequentRpcList: state.metamask.frequentRpcList || [], currentCurrency: state.metamask.currentCurrency, + isMouseUser: state.appState.isMouseUser, // state needed to get account dropdown temporarily rendering from app bar identities, @@ -101,6 +102,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 +114,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 +128,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 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/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 } From e4c83466befc439f26cdd9c32d130b367bc552a7 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Tue, 13 Feb 2018 03:09:15 -0330 Subject: [PATCH 035/392] Send screen style updates. (#3234) --- .../itcss/components/currency-display.scss | 3 ++- ui/app/css/itcss/components/send.scss | 22 +++++++++++++++++- ui/app/css/itcss/generic/index.scss | 23 +++++++++++++++++-- ui/app/send-v2.js | 13 +++++++---- 4 files changed, 52 insertions(+), 9 deletions(-) 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/send.scss b/ui/app/css/itcss/components/send.scss index fd73275e0..bb17e53cd 100644 --- a/ui/app/css/itcss/components/send.scss +++ b/ui/app/css/itcss/components/send.scss @@ -557,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 { @@ -565,6 +584,7 @@ font-size: 16px; line-height: 22px; width: 88px; + font-weight: 400; } &__from-dropdown { @@ -620,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/generic/index.scss b/ui/app/css/itcss/generic/index.scss index 75f823320..9b3d7475b 100644 --- a/ui/app/css/itcss/generic/index.scss +++ b/ui/app/css/itcss/generic/index.scss @@ -82,8 +82,20 @@ input.large-input { display: flex; flex-flow: column; border-bottom: 1px solid $geyser; - padding: 1.6rem 1rem; + 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 { @@ -93,6 +105,11 @@ input.large-input { border-top: 1px solid $geyser; padding: 1.6rem; flex: 0 0 auto; + + .btn-clear, + .btn-cancel { + font-size: 1rem; + } } &__footer-button { @@ -101,6 +118,7 @@ input.large-input { font-size: 1rem; text-transform: uppercase; margin-right: 1rem; + border-radius: 2px; &:last-of-type { margin-right: 0; @@ -108,7 +126,7 @@ input.large-input { } &__title { - color: $tundora; + color: $black; font-family: Roboto; font-size: 2rem; font-weight: 500; @@ -119,6 +137,7 @@ input.large-input { padding-top: .5rem; line-height: initial; font-size: .9rem; + color: $gray; } &__tabs { diff --git a/ui/app/send-v2.js b/ui/app/send-v2.js index d4e15dfa8..1d67150e3 100644 --- a/ui/app/send-v2.js +++ b/ui/app/send-v2.js @@ -179,7 +179,7 @@ SendTransactionScreen.prototype.componentDidUpdate = function (prevProps) { } SendTransactionScreen.prototype.renderHeader = function () { - const { selectedToken } = this.props + const { selectedToken, clearSend, goHome } = this.props const tokenText = selectedToken ? 'tokens' : 'ETH' return h('div.page-container__header', [ @@ -188,10 +188,13 @@ SendTransactionScreen.prototype.renderHeader = function () { h('div.page-container__subtitle', `Only send ${tokenText} to an Ethereum address.`), - h( - 'div.page-container__subtitle', - 'Sending to a different crytpocurrency that is not Ethereum may result in permanent loss.' - ), + h('div.page-container__header-close', { + onClick: () => { + clearSend() + goHome() + }, + }), + ]) } From 35c762da47c4b604f44e903940245f87eb7a3d3a Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Tue, 13 Feb 2018 03:21:05 -0330 Subject: [PATCH 036/392] Updates the styling of confirm send ether and token screens. (#3235) --- .../components/pending-tx/confirm-send-ether.js | 16 +++++++--------- .../components/pending-tx/confirm-send-token.js | 16 +++++++--------- ui/app/css/itcss/components/confirm.scss | 14 ++++++-------- 3 files changed, 20 insertions(+), 26 deletions(-) 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/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 { From b5b16e4ce09b5fa27ce4775b30a44bacea7ee329 Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 12 Feb 2018 13:25:00 -0330 Subject: [PATCH 037/392] Only open a new window on restore from seed if in extension view. --- app/scripts/platforms/extension.js | 16 ++++++++++++++++ ui/app/actions.js | 2 -- ui/app/unlock.js | 7 ++++++- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/app/scripts/platforms/extension.js b/app/scripts/platforms/extension.js index f5cc255d1..60bcce324 100644 --- a/app/scripts/platforms/extension.js +++ b/app/scripts/platforms/extension.js @@ -22,6 +22,22 @@ class ExtensionPlatform { this.openWindow({ url: extensionURL }) } + isInBrowser () { + return new Promise((resolve, reject) => { + try { + extension.tabs.getCurrent(currentTab => { + if (currentTab) { + resolve(true) + } else { + resolve(false) + } + }) + } catch (e) { + reject(e) + } + }) + } + getPlatformInfo (cb) { try { extension.runtime.getPlatformInfo((platform) => { diff --git a/ui/app/actions.js b/ui/app/actions.js index c6776eeee..4bc1f379e 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -842,7 +842,6 @@ function showRestoreVault () { function markPasswordForgotten () { return (dispatch) => { - dispatch(actions.showLoadingIndication()) return background.markPasswordForgotten(() => { dispatch(actions.hideLoadingIndication()) dispatch(actions.forgotPassword()) @@ -853,7 +852,6 @@ function markPasswordForgotten () { function unMarkPasswordForgotten () { return (dispatch) => { - dispatch(actions.showLoadingIndication()) return background.unMarkPasswordForgotten(() => { dispatch(actions.hideLoadingIndication()) dispatch(actions.forgotPassword()) diff --git a/ui/app/unlock.js b/ui/app/unlock.js index 4b39bd3e2..db88fa9d0 100644 --- a/ui/app/unlock.js +++ b/ui/app/unlock.js @@ -77,7 +77,12 @@ UnlockScreen.prototype.render = function () { h('p.pointer', { onClick: () => { this.props.dispatch(actions.markPasswordForgotten()) - global.platform.openExtensionInBrowser() + global.platform.isInBrowser() + .then((isInBrowser) => { + if (!isInBrowser) { + global.platform.openExtensionInBrowser() + } + }) }, style: { fontSize: '0.8em', From 5e9dc74a59d2507f36e1cb5796f97982f5f4993d Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 13 Feb 2018 14:29:43 -0330 Subject: [PATCH 038/392] Remove isInBrowser method and use environment-type.js --- app/scripts/platforms/extension.js | 16 ---------------- ui/app/unlock.js | 10 ++++------ 2 files changed, 4 insertions(+), 22 deletions(-) diff --git a/app/scripts/platforms/extension.js b/app/scripts/platforms/extension.js index 60bcce324..f5cc255d1 100644 --- a/app/scripts/platforms/extension.js +++ b/app/scripts/platforms/extension.js @@ -22,22 +22,6 @@ class ExtensionPlatform { this.openWindow({ url: extensionURL }) } - isInBrowser () { - return new Promise((resolve, reject) => { - try { - extension.tabs.getCurrent(currentTab => { - if (currentTab) { - resolve(true) - } else { - resolve(false) - } - }) - } catch (e) { - reject(e) - } - }) - } - getPlatformInfo (cb) { try { extension.runtime.getPlatformInfo((platform) => { diff --git a/ui/app/unlock.js b/ui/app/unlock.js index db88fa9d0..13c3f1274 100644 --- a/ui/app/unlock.js +++ b/ui/app/unlock.js @@ -6,6 +6,7 @@ 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') @@ -77,12 +78,9 @@ UnlockScreen.prototype.render = function () { h('p.pointer', { onClick: () => { this.props.dispatch(actions.markPasswordForgotten()) - global.platform.isInBrowser() - .then((isInBrowser) => { - if (!isInBrowser) { - global.platform.openExtensionInBrowser() - } - }) + if (environmentType() === 'popup') { + global.platform.openExtensionInBrowser() + } }, style: { fontSize: '0.8em', From e422294ad1ee46fa9a8a7be291266c24f8a15901 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 13 Feb 2018 11:35:30 -0800 Subject: [PATCH 039/392] Add node-sass to dev dependencies To fix build --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index c5223c333..826d06c32 100644 --- a/package.json +++ b/package.json @@ -230,6 +230,7 @@ "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", From 7a820bedda9b74ccc08f768597577ba839ef2c83 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 13 Feb 2018 13:35:03 -0800 Subject: [PATCH 040/392] Bump changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b44846e13..bfae566ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +- Fix bug where log subscriptions would break when switching network. + ## 3.14.1 2018-2-1 - Further fix scrolling for Firefox. From bcd3042491b5465f782abe0945cfd48b752e1f0e Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Tue, 13 Feb 2018 14:17:13 -0800 Subject: [PATCH 041/392] Standardize license. --- LICENSE | 40 +++++++++++++--------------------------- 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/LICENSE b/LICENSE index 429f4eaee..96e55582b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,34 +1,20 @@ +MIT License + Copyright (c) 2016 MetaMask -The Ethereum Project Contributor Asset Distribution Terms ( MIT + Share-alike ) - - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and - -associated documentation files (the "Software"), to deal in the Software without restriction, - -including without limitation the rights to use, copy, modify, merge, publish, distribute, - -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is - +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all copies or substantial - -portions of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT - -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - -OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR - -THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -These licence terms have been adapted from the MIT licence. \ No newline at end of file +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE From dc3f3e79ca7319b97255456a5225a266d38a4d6f Mon Sep 17 00:00:00 2001 From: frankiebee Date: Wed, 14 Feb 2018 14:37:02 -0800 Subject: [PATCH 042/392] fix - hex prefix estimatedGas on txMeta --- app/scripts/lib/tx-gas-utils.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/scripts/lib/tx-gas-utils.js b/app/scripts/lib/tx-gas-utils.js index f68f3a9e2..6f6ff7852 100644 --- a/app/scripts/lib/tx-gas-utils.js +++ b/app/scripts/lib/tx-gas-utils.js @@ -4,6 +4,7 @@ const { BnMultiplyByFraction, bnToHex, } = require('./util') +const addHexPrefix = require('ethereumjs-util').addHexPrefix const SIMPLE_GAS_COST = '0x5208' // Hex for 21000, cost of a simple send. /* @@ -13,7 +14,7 @@ and used to do things like calculate gas of a tx. */ module.exports = class TxGasUtil { - + constructor (provider) { this.query = new EthQuery(provider) } @@ -68,7 +69,7 @@ module.exports = class TxGasUtil { } setTxGas (txMeta, blockGasLimitHex, estimatedGasHex) { - txMeta.estimatedGas = estimatedGasHex + txMeta.estimatedGas = addHexPrefix(estimatedGasHex) const txParams = txMeta.txParams // if gasLimit was specified and doesnt OOG, From 33182efb1384dc05c8ecdb8994d12dd30abcbc7e Mon Sep 17 00:00:00 2001 From: Thomas Huang Date: Thu, 15 Feb 2018 08:34:31 -0800 Subject: [PATCH 043/392] Offline testing --- package.json | 2 +- test/stub/blacklist.json | 1374 ++++++++++++++++++++++++ test/stub/first-time-state.js | 14 + test/unit/blacklist-controller-test.js | 2 +- test/unit/metamask-controller-test.js | 174 ++- test/unit/network-contoller-test.js | 4 + 6 files changed, 1468 insertions(+), 102 deletions(-) create mode 100644 test/stub/blacklist.json create mode 100644 test/stub/first-time-state.js diff --git a/package.json b/package.json index 74a9f15d0..9f5003c87 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "dist": "npm run dist:clear && npm install && gulp dist", "dist:clear": "rm -rf node_modules/eth-contract-metadata && rm -rf node_modules/eth-phishing-detect", "test": "npm run lint && npm run test:coverage && npm run test:integration", - "test:unit": "METAMASK_ENV=test mocha --exit --compilers js:babel-core/register --require test/helper.js --recursive \"test/unit/**/*.js\"", + "test:unit": "METAMASK_ENV=test mocha --exit --require babel-core/register --require test/helper.js --recursive \"test/unit/**/*.js\"", "test:single": "METAMASK_ENV=test mocha --require test/helper.js", "test:integration": "npm run test:flat && npm run test:mascara", "test:coverage": "nyc npm run test:unit && npm run test:coveralls-upload", diff --git a/test/stub/blacklist.json b/test/stub/blacklist.json new file mode 100644 index 000000000..6a3230b2f --- /dev/null +++ b/test/stub/blacklist.json @@ -0,0 +1,1374 @@ +{ + "version": 2, + "tolerance": 2, + "fuzzylist": [ + "metamask.io", + "myetherwallet.com", + "cryptokitties.co", + "mycrypto.com" + ], + "whitelist": [ + "crypto.pro", + "ocrypto.org", + "wecrypto.net", + "iccrypto.io", + "crypto.kred", + "ohmycrypto.io", + "spcrypto.net", + "melcrypto.com", + "zzcrypto.org", + "zzcrypto.net", + "crypto.bg", + "mycrypto24.online", + "acrypto.io", + "mycrypto.ca", + "scrypto.io", + "mycrypto.dk", + "mvzcrypto.com", + "ambcrypto.com", + "crypto.bi", + "crypto.jobs", + "crypto.help", + "my.crypt.observer", + "crypt.observer", + "ucrypto.com", + "cryptojobslist.com", + "crypto.review", + "crypto.me", + "b3crypto.com", + "mycrypto.ninja", + "jkcrypto.com", + "crypto.cr", + "mycrypto.live", + "yocrypto.io", + "crypto.ba", + "zacrypto.info", + "mycrypto.com", + "remix.ethereum.org", + "metahash.io", + "metahash.net", + "metahash.org", + "cryptotitties.com", + "cryptocities.net", + "cryptoshitties.co", + "cryptotitties.fun", + "cryptokitties.forsale", + "cryptokitties.care", + "metamate.cc", + "metamesh.tech", + "ico.nexus.social", + "metamesh.org", + "metatask.io", + "metmask.com", + "metarasa.com", + "metapack.com", + "metacase.com", + "metafas.nl", + "metamako.com", + "metamast.com", + "metamax.ru", + "metadesk.io", + "metadisk.com", + "metallsk.ru", + "metamag.fr", + "metamaks.ru", + "metamap.ru", + "metamaps.cc", + "metamats.com", + "metamax.by", + "metamax.com", + "metamax.io", + "metamuse.net", + "metarank.com", + "metaxas.com", + "megamas2.ru", + "metamask.io", + "myetherwallet.com", + "myethlerwallet.com", + "ethereum.org", + "myetheroll.com", + "myetherapi.com", + "ledgerwallet.com", + "databrokerdao.com", + "etherscan.io", + "etherid.org", + "ether.cards", + "etheroll.com", + "ethnews.com", + "ethex.market", + "ethereumdev.io", + "ethereumdev.kr", + "dether.io", + "ethermine.org", + "slaask.com", + "etherbtc.io", + "ethereal.capital", + "etherisc.com", + "m.famalk.net", + "etherecho.com", + "ethereum.os.tc", + "theethereum.wiki", + "metajack.im", + "etherhub.io", + "ethereum.network", + "ethereum.link", + "ethereum.com", + "prethereum.org", + "ethereumj.io", + "etheraus.com", + "ethereum.dev", + "1ethereum.ru", + "ethereum.nz", + "nethereum.com", + "metabank.com", + "metamas.com", + "aventus.io", + "metabase.com", + "etherdelta.com", + "metabase.one", + "cryptokitties.co", + "remme.io", + "jibrel.network" + ], + "blacklist": [ + "xn--myethrwalle-jb9e19a.com", + "xn--myetheralle-7b9ezl.com", + "iconfoundation.co", + "fundrequest.info", + "xn--myetherwale-os8e7x.com", + "remme-ico.eu", + "gonetwork.live", + "token.gonetwork.pro", + "gonetwork.pro", + "gonetwork.eu", + "nucleus-vision.cc", + "jibreltoken.in", + "dock.so", + "dock.promo", + "xn--mycrypt-r0a.com", + "xn--mycrypt-g1a.com", + "xn--mycrpto-y2a.com", + "ethexploit.org", + "remme.in", + "remme.ws", + "remme.com.ng", + "nyeitthervvallet.com", + "xn--myeerhwailet-ooc.com", + "myeterhwaliot.com", + "remme.live", + "xn--yethewalle-to2exkhi.com", + "myetherwallet.custom-token.com", + "custom-token.com", + "sale-earn.com", + "bankera.live", + "originprotocol.io", + "trx.foundation", + "tokensale.adhive.net", + "adhive.net", + "decentral.market", + "cryptoexploite.com", + "blockclain.net", + "xn--blckchin-5za9o.info", + "xn--blkhain-m0a4pb.info", + "xn--blocchal-gmb8m.info", + "xn--blocchaln-orb.info", + "xn--blocchan-gmb7c.info", + "xn--blockaden-lsen-5pb.com", + "xn--blockchai-3vb.info", + "xn--blockchai-jvb.info", + "xn--blockchal-3vb.info", + "xn--blockcham-ipb.info", + "xn--blockchan-2pb.com", + "xn--blockchan-75a.com", + "xn--blockchan-7sb.info", + "xn--blockchan-d5a.net", + "xn--blockchan-dob.info", + "xn--blockchan-ipb.com", + "xn--blockchan-ipb.info", + "xn--blockchan-nk7d.com", + "xn--blockchan-xub.info", + "xn--blockchann-4ub.com", + "xn--blockchi-n7a50e.info", + "xn--blockchi-o8a54d.info", + "xn--blockchi-p99co8a.com", + "xn--blockchim-hdb.info", + "xn--blockchin-1xb.info", + "xn--blockchin-61a.info", + "xn--blockchin-61a.net", + "xn--blockchin-6ib.info", + "xn--blockchin-ccb.info", + "xn--blockchin-h4a.com", + "xn--blockchin-h4a.info", + "xn--blockchin-hdb.info", + "xn--blockchin-hhb.info", + "xn--blockchin-mib.net", + "xn--blockchin-wcb.com", + "xn--blockchn-fza4j.com", + "xn--blockchn-fza4j.info", + "xn--blockchn-n7a43b.info", + "xn--blockchn-p0a.info", + "xn--blockchn-tx0d4p.com", + "xn--blockclai-3vb.info", + "xn--blockclin-hdb.com", + "xn--blockclin-hdb.info", + "xn--blockclin-hdb.org", + "xn--blockflte-kirchrode-w6b.de", + "xn--blockfltenquartett-windspiel-81c.de", + "xn--blockhai-obb78c.info", + "xn--blockhain-4eb.com", + "xn--blockhain-pfb.com", + "xn--blockhain-pfb.info", + "xn--blockhain-zdb.info", + "xn--blockhan-obb65a.info", + "xn--blockhas-d6a.com", + "xn--blockwallt-j7a.com", + "xn--blokchai-fqb.info", + "xn--blokchain-nfb.info", + "xn--blokhain-28ab.info", + "xn--bockclnain-eyb.info", + "xn--mymoeo-zt7bzf.com", + "xn--mymoer-nqc1368c.com", + "xn--mymoero-c13c.com", + "xn--mymoero-s13c.com", + "xn--mymoneo-f63c.com", + "xn--mymoneo-v63c.com", + "xn--mymoneo-y53c.com", + "xn--mymoner-j0a.com", + "xn--mymoner-j5b.com", + "xn--mymoner-r0a.com", + "xn--mymoner-z0a.com", + "xn--mymoner-z2c.com", + "xn--mymonro-fya.com", + "xn--mymonro-x8a.com", + "xn--myetheallet-l58emu.com", + "xn--myetheraet-9k2ea77h.com", + "xn--myetheralet-ms8e21b.com", + "xn--myetheralle-7b9exm.com", + "xn--myetherallet-5s5f.com", + "xn--myetherallet-fs5f.com", + "xn--myetherewalle-1t1g.com", + "xn--myetherllet-pl9e6k.com", + "xn--myethervvalle-8vc.com", + "xn--myetherwaet-61ea.com", + "xn--myetherwaet-8eda.com", + "xn--myetherwaet-ns8ea.com", + "xn--myetherwale-ns8e8x.com", + "xn--myetherwalet-0fb.com", + "xn--myetherwalet-0z4f.com", + "xn--myetherwalet-814f.com", + "xn--myetherwalet-d9b.com", + "xn--myetherwalet-h14f.com", + "xn--myetherwalle-9me.com", + "xn--myetherwalle-ek5f.com", + "xn--myetherwalle-fqc.com", + "xn--myetherwalle-opc.com", + "xn--myetherwalle-q05f.com", + "xn--myetherwllet-wob.com", + "xn--myetherwllt-r7a0i.com", + "xn--myethewaliet-9d5f.com", + "xn--myethewalle-3ic0947g.com", + "xn--myethewallet-0e5f.com", + "xn--myethewallet-1kc.com", + "xn--myethewallet-bkc.com", + "xn--myethewallet-vof.com", + "xn--myethewalliet-nm1g.com", + "xn--myethewallt-kbb3019g.com", + "xn--myethewallt-w48ew7b.com", + "xn--myethrwalet-6qb6408g.com", + "xn--myethrwalet-ms8e83d.com", + "xn--myethrwallet-1db.com", + "xn--myethrwallt-29af.com", + "xn--myethrwallt-29as.com", + "xn--myethrwllet-q7a31e.com", + "xn--myethrwllet-r8a3c.com", + "fintrux.eu", + "refereum-ico.eu", + "arcblock-ico.org", + "xn--fuson-1sa.org", + "refereum-token.com", + "fintrux.co", + "ico-ton.org", + "xn--mytherwallt-cbbv.com", + "xmoneta.co", + "data-wallet.co", + "tokensale.data-wallet.co", + "xn--myeerhwallot-ooc.com", + "xn--myeterwalet-cm8epi.com", + "xn--myeterwalle-cm8ev6a.com", + "rnyetherumwallet.com", + "republic-protocol.net", + "nyeihitervvallatt.com", + "arcblock.eu", + "republicprotocol.eu", + "tokensale-fusion.com", + "myetherwalletjoin.com", + "medicalchian.com", + "myeahteirwaliet.com", + "myenhtersvvailct.com", + "trinity-token.com", + "xn--eo-yzs.com", + "zilliqa.in", + "sparc.pro", + "myetherwallet.import-tokens.com", + "token-gram.org", + "xn--shapshift-e4a.com", + "xn--shapshift-y4a.com", + "xn--shpeshift-c2a.com", + "xn--shpeshift-r1a.com", + "xn--shapshift-o4a.com", + "xn--shpeshift-w2a.com", + "xn--shapeshft-w5a.com", + "tokensale-fusion.org", + "fusion-ico.com", + "beetolen.com", + "tokencrowdsale.online", + "fusion.tokencrowdsale.online", + "beetokem.com", + "block.chaiins.in", + "origintrail.in", + "bit-z.ru", + "xn--myetherallet-nu5f.com", + "xn--mytherwalet-3qb08c.com", + "xn--myeterwllet-cm8et1d.com", + "xn--mytherwllet-q7a01e.com", + "xn--biance-xt7b.com", + "xn--bnance-wic.com", + "xn--biance-jeb.com", + "xn--bttrx-9za8334c.com", + "wwwkodakcoin.com", + "myetherwallet.uk.com", + "kodakone.cc", + "nyeihitervvallet.com", + "xn--myeterwalet-cm8eoi.com", + "nucleus.foundation", + "beetoken-ico.com", + "data-token.com", + "tron-labs.com", + "ocoin.tech", + "aionfoundation.com", + "ico-telegram.org", + "nyeihitervvallat.com", + "telegramcoin.us", + "daddi.cloud", + "daditoken.com", + "blockarray.org", + "dadi-cloud.net", + "wanchainfunding.org", + "ico-telegram.io", + "iconfoundation.site", + "iost.co", + "beetoken-ico.eu", + "cindicator.network", + "wanchainetwork.org", + "wamchain.org", + "wanchainltd.org", + "wanchainalliance.org", + "nucleus-vision.net", + "ledgerwallet.by", + "nucleuss.vision", + "myenhterswailct.com", + "cobin-hood.com", + "wanchainfoundation.org", + "xn--polniex-ex4c.com", + "xn--polniex-s1a.com", + "xn--polonex-ieb.com", + "xn--polonex-sza.com", + "xn--polonex-zw4c.com", + "xn--polonix-ws4c.com", + "xn--polonix-y8a.com", + "xn--pooniex-ojb.com", + "gramico.info", + "dimnsions.network", + "www-gemini.com", + "login-kucoin.net", + "venchain.foundation", + "grampreico.com", + "tgram.cc", + "ton-gramico.com", + "wwwpaywithink.com", + "coniomi.com", + "paywithnk.com", + "paywithlnk.com", + "iluminatto.com.br", + "pundix.eu", + "xn--bttrx-esay.com", + "xn--bttrex-w8a.com", + "xn--bnance-bwa.com", + "xn--shpeshift-11a.com", + "xn--shapeshif-ts6d.com", + "xn--shapshift-yf7d.com", + "wwwbluzelle.com", + "bluzelie.com", + "nucleus-vision.org", + "omisegonetwork.site", + "etlherzero.com", + "etlherdelta.com", + "xn--condesk-0ya.com", + "xn--condesk-sfb.com", + "xn--coindsk-vs4c.com", + "iexecplatform.com", + "tongramico.com", + "nucleus-vision.eu", + "intchain.network", + "wanchain.cloud", + "bluzelle-ico.com", + "ethzero-wallet.com", + "xn--metherwalle-jb9et7d.com", + "xn--coinesk-jo3c.com", + "venchainfoundation.com", + "myenhtersvvailot.com", + "ether-zero.net", + "ins.foundation", + "nastoken.org", + "telcointoken.com", + "ether0.org", + "eterzero.org", + "bluzelle-ico.eu", + "bleuzelle.com", + "appcoinstoken.org", + "xn--quanstamp-8s6d.com", + "myehntersvvailct.com", + "myeherwalllet.com", + "ico-bluzelle.com", + "bluzelle.im", + "bluzelle.one", + "bluzele.sale", + "bluzele.co", + "sether.ws", + "xn--myetherwalet-6gf.com", + "xn--rnyethewaliet-om1g.com", + "rnyethervailet.com", + "mvetherwaliet.com", + "rnyetherwailet.com", + "myethervaliet.com", + "rnyethervaliet.com", + "mvetherwalilet.com", + "xn--myethewalie-3ic0947g.com", + "xn--mthrwallet-z6ac3y.com", + "xn--myeherwalie-vici.com", + "xn--myethervvalie-8vc.com", + "xn--mythrwallt-06acf.com", + "xn--mtherwallet-y9a6y.com", + "myetherwallet.applytoken.tk", + "ethereum-zero.com", + "quanstamptoken.tk", + "bluzelle.network", + "ether-wallet.org", + "tron-wallet.info", + "appcoinsproject.com", + "vechain.foundation", + "tronlab.site", + "tronlabs.network", + "bluzelle.cc", + "ethblender.com", + "ethpaperwallet.net", + "waltontoken.org", + "icoselfkey.org", + "etherzeroclaim.com", + "etherzero.promo", + "bluzelle.pro", + "token-selfkey.org", + "xn--etherdlta-0f7d.com", + "sether.in", + "xn--ttrex-ysa9423c.com", + "bluzelle.eu", + "bluzelle.site", + "gifto.tech", + "xn--os-g7s.com", + "selfkey.co", + "xn--myeherwalet-ns8exy.com", + "xn--coinelegraph-wk5f.com", + "dai-stablecoin.com", + "eos-token.org", + "venchain.org", + "gatcoins.io", + "deepbrainchain.co", + "myetherwalililet.info", + "myehvterwallet.com", + "myehterumswallet.com", + "nucleusico.com", + "tronlab.tech", + "0x-project.com", + "gift-token-events.mywebcommunity.org", + "funfairtoken.org", + "breadtokenapp.com", + "cloudpetstore.com", + "myethwalilet.com", + "selfkeys.org", + "wallet-ethereum.com", + "xn--methrwallt-26ar0z.com", + "xn--mytherwllet-r8a0c.com", + "bluzelle.promo", + "tokensale.bluzelle.promo", + "cedarlake.org", + "marketingleads4u.com", + "cashaa.co", + "xn--inance-hrb.com", + "wanchain.tech", + "zenprolocol.com", + "ethscan.io", + "etherscan.in", + "props-project.com", + "zilliaq.com", + "reqestnetwork.com", + "etherdelta.pw", + "ethereum-giveaway.org", + "mysimpletoken.org", + "binancc.com", + "blnance.org", + "elherdelta.io", + "xn--hapeshit-ez9c2y.com", + "tenxwallet.co", + "singularitynet.info", + "mytlherwaliet.info", + "iconmainnet.ml", + "tokenselfkey.org", + "xn--myetewallet-cm8e5y.com", + "envione.org", + "myetherwalletet.com", + "claimbcd.com", + "ripiocreditnetwork.in", + "xn--yeterwallet-ml8euo.com", + "ethclassicwallet.info", + "myltherwallet.ru.com", + "etherdella.com", + "xn--yeterwallet-bm8ewn.com", + "singularty.net", + "cloudkitties.co", + "iconfoundation.io", + "kittystat.com", + "gatscoin.io", + "singularitynet.in", + "sale.canay.io", + "canay.io", + "wabicoin.co", + "envion.top", + "sirinslabs.com", + "tronlab.co", + "paxful.com.ng", + "changellyli.com", + "ethereum-code.com", + "xn--plonex-6va6c.com", + "envion.co", + "envion.cc", + "envion.site", + "ethereumchain.info", + "xn--envon-1sa.org", + "xn--btstamp-rfb.net", + "envlon.org", + "envion-ico.org", + "spectivvr.org", + "sirinlbs.com", + "ethereumdoubler.life", + "xn--myetherwllet-fnb.com", + "sirin-labs.com", + "sirin-labs.org", + "envion.one", + "envion.live", + "propsproject.org", + "propsprojects.com", + "decentralland.org", + "xn--metherwalet-ns8ep4b.com", + "redpulsetoken.co", + "propsproject.tech", + "xn--myeterwalet-nl8emj.com", + "powrerledger.com", + "cryptokitties.com", + "sirinlabs.pro", + "sirinlabs.co", + "sirnlabs.com", + "superbitcoin-blockchain.info", + "hellobloom.me", + "mobus.network", + "powrrledger.com", + "xn--myeherwalet-ms8eyy.com", + "qlink-ico.com", + "gatcoin.in", + "tokensale.gamefllp.com", + "gamefllp.com", + "xn--myeherwalle-vici.com", + "xn--myetherwalet-39b.com", + "xn--polonex-ffb.com", + "xn--birex-leba.com", + "raiden-network.org", + "sirintabs.com", + "xn--metherwallt-79a30a.com", + "xn--myethrwllet-2kb3p.com", + "myethlerwallet.eu", + "xn--btrex-b4a.com", + "powerrledger.com", + "xn--cointeegraph-wz4f.com", + "myerherwalet.com", + "qauntstanp.com", + "myetherermwallet.com", + "xn--myethewalet-ns8eqq.com", + "xn--nvion-hza.org", + "nnyetherwallelt.ru.com", + "ico-wacoin.com", + "xn--myeterwalet-nl8enj.com", + "bitcoinsilver.io", + "t0zero.com", + "tokensale.gizer.in", + "gizer.in", + "wabitoken.com", + "gladius.ws", + "xn--metherwallt-8bb4w.com", + "quanttstamp.com", + "gladius.im", + "ethereumstorage.net", + "powerledgerr.com", + "xn--myeherwallet-4j5f.com", + "quamtstamp.com", + "quntstamp.com", + "xn--changely-j59c.com", + "shapeshlft.com", + "coinbasenews.co.uk", + "xn--metherwallet-hmb.com", + "envoin.org", + "powerledger.com", + "bitstannp.net", + "xn--myetherallet-4k5fwn.com", + "xn--coinbas-pya.com", + "requestt.network", + "oracls.network", + "sirinlabs.website", + "powrledger.io", + "slackconfirm.com", + "shape-shift.io", + "oracles-network.org", + "xn--myeherwalle-zb9eia.com", + "blockstack.one", + "urtust.io", + "bittrex.one", + "t0-ico.com", + "xn--cinbase-90a.com", + "xn--metherwalet-ns8ez1g.com", + "tzero-ico.com", + "tzero.su", + "tzero.website", + "blockstack.network", + "ico-tzero.com", + "spectre.site", + "tzero.pw", + "spectre-ai.net", + "xn--waxtokn-y8a.com", + "dmarket.pro", + "bittrex.com11648724328774.cf", + "bittrex.com1987465798.ga", + "autcus.org", + "t-zero.org", + "xn--zero-zxb.com", + "myetherwalletfork.com", + "blokclbain.info", + "datum.sale", + "spectre-ai.org", + "powerledgr.com", + "simpletoken.live", + "sale.simpletoken.live", + "qauntstamp.com", + "raiden-network.com", + "metalpayme.com", + "quantstamp-ico.com", + "myetherwailetclient.com", + "biockchain.biz", + "wallets-blockchain.com", + "golemairdrop.com", + "omisegoairdrop.net", + "blodkchainwallet.info", + "walton-chain.org", + "elite888-ico.com", + "bitflyerjp.com", + "chainlinksmartcontract.com", + "stormtoken.eu", + "omise-go.tech", + "saltending.com", + "stormltoken.com", + "xn--quanttamp-42b.com", + "stormtoken.co", + "storntoken.com", + "stromtoken.com", + "storm-token.com", + "stormtokens.io", + "ether-delta.com", + "ethconnect.live", + "ethconnect.trade", + "xn--bttrex-3va.net", + "quantstamp.com.co", + "wancha.in", + "augur-network.com", + "quantstamp.com.ua", + "myetherwalletmew.com", + "myetherumwalletts.com", + "xn--quanstamp-tmd.com", + "quantsstamps.com", + "changellyl.net", + "xn--myetherwalet-1fb.com", + "myethereumwallets.com", + "xn--myetherwalet-e9b.com", + "quantslamp.com", + "metelpay.com", + "xn--eterdelta-m75d.com", + "linksmartcontract.com", + "myetherwalletaccess.com", + "myetherwalletcheck.com", + "myetherwalletcheck.info", + "myetherwalletconf.com", + "myetherwalleteal.com", + "myetherwalletec.com", + "myetherwalletgeth.com", + "myetherwalletmetamask.com", + "myetherwalletmm.com", + "myetherwalletmy.com", + "myetherwalletnh.com", + "myetherwalletnod.com", + "myetherwalletrr.com", + "myetherwalletrty.com", + "myetherwalletsec.com", + "myetherwalletsecure.com", + "myetherwalletutc.com", + "myetherwalletver.info", + "myetherwalletview.com", + "myetherwalletview.info", + "myetherwalletvrf.com", + "myetherwalletmist.com", + "myetherwalletext.com", + "myetherwalletjson.com", + "mettalpay.com", + "bricklblock.io", + "bittrexy.com", + "utrust.so", + "myethierwallet.org", + "metallpay.com", + "kraken-wallet.com", + "dmarkt.io", + "etherdeltla.com", + "unlversa.io", + "universa.sale", + "mercuryprotocol.live", + "ripiocredlt.network", + "myetlherwa11et.com", + "dentacoin.in", + "rdrtg.com", + "myetherwallet.com.rdrgh.com", + "rdrgh.com", + "ripiocreditnetwork.co", + "riaden.network", + "hydrominer.biz", + "rdrblock.com", + "reqest.network", + "senstoken.com", + "myetherwallat.services", + "ripiocredit.net", + "xn--metherwallet-c06f.com", + "ico.ripiocredits.com", + "ripiocredits.com", + "raidens.network", + "artoken.co", + "myetherwalletlgn.com", + "etherblog.click", + "stormtoken.site", + "httpmyetherwallet.com", + "myetherwalletverify.com", + "byzantiumfork.com", + "myetherwallet.com.byzantiumfork.com", + "www-myethervvallet.com", + "ether24.info", + "block-v.io", + "bittrex.cash", + "shapishift.io", + "ripiocerdit.network", + "rnyetherwa11et.com", + "claimether.com", + "enigmatokensale.com", + "ethereum-org.com", + "mvetnerwallet.com", + "myctherwallet.com", + "myetherwaltet.com", + "myetherwatlet.com", + "privatix.me", + "myetherwalletcnf.com", + "myetherwalletver.com", + "privatix.top", + "privatix.pro", + "privatex.io", + "stormtoken.cc", + "raiden.online", + "stormstoken.com", + "myetereumwallet.com", + "stormtokens.net", + "myetherwalletconf.info", + "storrntoken.com", + "worldofbattles.io", + "ico.worldofbattles.io", + "privatix.live", + "riden.network", + "raidan.network", + "ralden.network", + "mymyetherwallet.com", + "myetherwallets.net", + "myetherwalletverify.info", + "stormxtoken.com", + "myethereum-wallet.com", + "myetherwallet-forkprep.pagedemo.co", + "myetnerwailet.com", + "www-mvetherwallet.com", + "etheirdelta.com", + "myetherwalletiu.com", + "myetherwaiiett.com", + "xn--mytherwalet-cbb87i.com", + "xn--myethrwallet-ivb.co", + "xn--myeterwallet-f1b.com", + "myehterwaliet.com", + "omegaone.co", + "myetherwaiietw.com", + "slack.com.ru", + "polkodot.network", + "request-network.net", + "requestnetwork.live", + "binancie.com", + "first-eth.info", + "myewerthwalliet.com", + "enjincoin.pw", + "xn--bitrex-k17b.com", + "alrswap.io", + "www-request.network", + "myetnenwallet.com", + "www-enigma.co", + "cryptoinsidenews.com", + "air-swap.tech", + "launch.airswap.cc", + "airswap.cc", + "airswaptoken.com", + "launch.airswap.in", + "airswap.in", + "security-steemit.com.mx", + "blockchalnwallet.com", + "blodkchainwallet.com", + "blodkchaln.com", + "myethereumwaiiet.com", + "myethereumwaliet.com", + "myethereumwalilet.com", + "myetherswailet.com", + "myetherswaliet.com", + "myetherswalilet.com", + "myetherwalilett.com", + "myetherwalletl.com", + "myetherwalletww.com", + "myethereunwallet.com", + "myethereumwallct.com", + "myetherwaiieti.com", + "myetherwaiiete.com", + "upfirng.com", + "paypie.net", + "paypie.tech", + "soam.co", + "myetherwaiict.com", + "numerai-token.com", + "www-bankera.com", + "vvanchain.org", + "omisegoairdrop.com", + "xn--enjncoin-41a.io", + "suncontract.su", + "myetherwaiietr.com", + "shapeshiff.io", + "warchain.org", + "myethwallett.com", + "myethervvaliet.com", + "wanchains.org", + "etherparty.in", + "enjincoin.me", + "etiam.io", + "invest.smartlands.tech", + "smartlands.tech", + "enijncoin.io", + "wanchain.network", + "nimiq.su", + "enjincoin.sale", + "tenxwallet.io", + "golem-network.net", + "myyethwallet.ml", + "mywetherwailiet.com", + "omg-omise.com", + "district0x.tech", + "centra-token.com", + "etherdetla.com", + "etnerparty.io", + "etherdelta.su", + "myetherwallett.neocities.org", + "myetherwallet-secure.com", + "myethereumwalletntw.info", + "real-markets.io", + "wallet-ethereum.org", + "request-network.com", + "shapeshifth.io", + "shiapeshift.in", + "coin.red-puise.com", + "ibittreix.com", + "coinkbase.com", + "cindicator.pro", + "myetherwallet.com.ailogin.me", + "eventchain.co", + "kinkik.in", + "myetherumwalletview.com", + "protostokenhub.com", + "coinrbase.com", + "myetherwalletlogin.com", + "omisegotoken.com", + "myethereumwalletntw.com", + "reall.markets", + "cobinhood.org", + "cobinhood.io", + "happy-coin.org", + "bitfinex.com.co", + "bitfienex.com", + "iconn.foundation", + "centra.vip", + "smartcontract.live", + "icon.community", + "air-token.com", + "centra.credit", + "myetherwallet-singin.com", + "smartcontractlink.com", + "shapesshift.io", + "0xtoken.io", + "augurproject.co", + "ethereumus.one", + "myetherumwalet.com", + "myetherwalletsignin.com", + "change-bank.org", + "charge-bank.com", + "myetherwalletsingin.com", + "myetherwalletcontract.com", + "change-bank.io", + "chainlink.tech", + "myetherwallet-confirm.com", + "tokensale.kybernet.network", + "kybernet.network", + "kyberr.network", + "kybernetwork.io", + "myetherwalletconfirm.com", + "kvnuke.github.io", + "kin.kikpro.co", + "myethereumwallet.co.uk", + "tokensale-kyber.network", + "kyber-network.co", + "tokensale.kyber-network.co", + "pyro0.github.io", + "tokensale.kyber.digital", + "kyber.digital", + "omise-go.me", + "my.etherwallet.com.de", + "bepartof.change-bank.co", + "change-bank.co", + "enigma-tokens.co", + "coinbase.com.eslogin.co", + "xn--bittrx-mva.com", + "ethrdelta.github.io", + "etherdellta.com", + "ico-nexus.social", + "red-pulse.tech", + "bitj0b.io", + "xn--bttrex-bwa.com", + "kin-klk.com", + "kin-crowdsale.com", + "ethedelta.com", + "coindash.su", + "myethwallet.co.uk", + "swarm.credit", + "myethereumwallet.uk", + "iconexu.social", + "wanchain.co", + "enigrna.co", + "linknetwork.co", + "qtum-token.com", + "omisego.com.co", + "rivetzintl.org", + "etherdelta.one", + "the-ether.pro", + "etherdelta.gitnub.io", + "kirkik.com", + "monetha.ltd", + "vlberate.io", + "ethereumwallet-kr.info", + "omise-go.org", + "iconexus.social", + "bittirrex.com", + "aventus.pro", + "atlant.solutions", + "aventus.group", + "metamak.io", + "omise.com.co", + "herotokens.io", + "starbase.pro", + "etherdelta.githulb.io", + "herotoken.co", + "kinico.net", + "dmarket.ltd", + "etherdelta.gilthub.io", + "golem-network.com", + "etnerscan.io", + "bllttriex.com", + "monetha.me", + "monetha.co", + "monetha-crowdsale.com", + "starbase.tech", + "aventus-crowdsale.com", + "shapeshift.pro", + "bllttrex.com", + "kickico.co", + "statustoken.im", + "bilttrex.com", + "tenxpay.io", + "bittrex.ltd", + "metalpay.im", + "aragon.im", + "coindash.tech", + "decentraland.tech", + "decentraland.pro", + "status-token.com", + "bittrex.cam", + "enigmatoken.com", + "unocoin.company", + "unocoin.fund", + "0xproject.io", + "0xtoken.com", + "numerai.tech", + "decentraiand.org", + "blockcrein.info", + "blockchealn.info", + "bllookchain.info", + "blockcbhain.info", + "myetherwallet.com.ethpromonodes.com", + "mettamask.io", + "tokenswap.org", + "netherum.com", + "etherexx.org", + "etherume.io", + "ethereum.plus", + "ehtereum.org", + "etereurm.org", + "etheream.com", + "ethererum.org", + "ethereum.io", + "etherdelta-glthub.com", + "cryptoalliance.herokuapp.com", + "bitspark2.com", + "indorsetoken.com", + "iconexus.tk", + "iconexus.ml", + "iconexus.ga", + "iconexus.cf", + "etherwallet.online", + "wallet-ethereum.net", + "bitsdigit.com", + "etherswap.org", + "eos.ac", + "uasfwallet.com", + "ziber.io", + "multiply-ethereum.info", + "bittrex.comze.com", + "karbon.vacau.com", + "etherdelta.gitlhub.io", + "etherdelta.glthub.io", + "digitaldevelopersfund.vacau.com", + "district-0x.io", + "coin-dash.com", + "coindash.ru", + "district0x.net", + "aragonproject.io", + "coin-wallet.info", + "coinswallet.info", + "contribute-status.im", + "ether-api.com", + "ether-wall.com", + "mycoinwallet.net", + "ethereumchamber.com", + "ethereumchamber.net", + "ethereumchest.com", + "ethewallet.com", + "myetherwallet.com.vc", + "myetherwallet.com.pe", + "myetherwallet.us.com", + "myetherwallet.com.u0387831.cp.regruhosting.ru", + "myethereumwallet.su", + "myetherweb.com.de", + "myetherieumwallet.com", + "myetehrwallet.com", + "myeterwalet.com", + "myetherwaiiet.com", + "myetherwallet.info", + "myetherwallet.ch", + "myetherwallet.om", + "myethervallet.com", + "myetherwallet.com.cm", + "myetherwallet.com.co", + "myetherwallet.com.de", + "myetherwallet.com.gl", + "myetherwallet.com.im", + "myetherwallet.com.ua", + "secure-myetherwallet.com", + "update-myetherwallet.com", + "wwwmyetherwallet.com", + "myeatherwallet.com", + "myetharwallet.com", + "myelherwallel.com", + "myetherwaillet.com", + "myetherwaliet.com", + "myetherwallel.com", + "myetherwallet.cam", + "myetherwallet.cc", + "myetherwallet.co", + "myetherwallet.cm", + "myetherwallet.cz", + "myetherwallet.org", + "myetherwallet.tech", + "myetherwallet.top", + "myetherwallet.net", + "myetherwallet.ru.com", + "myetherwallet.com.ru", + "metherwallet.com", + "myetrerwallet.com", + "myetlerwallet.com", + "myethterwallet.com", + "myethwallet.io", + "myethterwallet.co", + "myehterwallet.co", + "myaetherwallet.com", + "myetthterwallet.com", + "myetherwallet.one", + "myelterwallet.com", + "myetherwallet.gdn", + "myetherwallt.com", + "myeterwallet.com", + "myeteherwallet.com", + "myethearwailet.com", + "myetherwallelt.com", + "myetherwallett.com", + "etherwallet.org", + "myetherewallet.com", + "myeherwallet.com", + "myethcrwallet.com", + "myetherwallet.link", + "myetherwallets.com", + "myethearwaillet.com", + "myethearwallet.com", + "myetherawllet.com", + "myethereallet.com", + "myetherswallet.com", + "myetherwalet.com", + "myetherwaller.com", + "myetherwalliet.com", + "myetherwllet.com", + "etherwallet.io", + "myetherwallet.ca", + "myetherwallet.me", + "myetherwallet.ru", + "myetherwallet.xyz", + "myetherwallte.com", + "myethirwallet.com", + "myethrewallet.com", + "etherwallet.net", + "maetherwallet.com", + "meyetherwallet.com", + "my.ether-wallet.pw", + "myehterwallet.com", + "myeitherwallet.com", + "myelherwallet.com", + "myeltherwallet.com", + "myerherwallet.com", + "myethearwalet.com", + "myetherewalle.com", + "myethervvallet.com", + "myetherwallent.com", + "myetherwallet.fm", + "myetherwalllet.com", + "myetherwalltet.com", + "myetherwollet.com", + "myetlherwalet.com", + "myetlherwallet.com", + "rnyetherwallet.com", + "etherclassicwallet.com", + "omg-omise.co", + "omise-go.com", + "omise-go.net", + "omise-omg.com", + "omise-go.io", + "tenx-tech.com", + "bitclaive.com", + "tokensale-tenx.tech", + "ubiqcoin.org", + "metamask.com", + "ethtrade.io", + "myetcwallet.com", + "account-kigo.net", + "bitcoin-wallet.net", + "blocklichan.info", + "bloclkicihan.info", + "coindash.ml", + "eos-bonus.com", + "eos-io.info", + "ether-wallet.net", + "ethereum-wallet.info", + "ethereum-wallet.net", + "ethereumchest.net", + "reservations-kigo.net", + "reservations-lodgix.com", + "secure-liverez.com", + "secure-onerooftop.com", + "settings-liverez.com", + "software-liverez.com", + "software-lodgix.com", + "unhackableetherwallets.com", + "www-myetherwallet.com", + "etherwallet.co.za", + "etherwalletchain.com", + "etherwallets.net", + "etherwallets.nl", + "my-ethwallet.com", + "my.ether-wallet.co", + "myetherwallet.com.am", + "myetherwallet.com.ht", + "myetherwalletcom.com", + "myehterwailet.com", + "xn--myetherwalle-xoc.com", + "xn--myetherwalle-44i.com", + "xn--myetherwalle-xhk.com", + "xn--myetherwallt-cfb.com", + "xn--myetherwallt-6tb.com", + "xn--myetherwallt-xub.com", + "xn--myetherwallt-ovb.com", + "xn--myetherwallt-fwb.com", + "xn--myetherwallt-5wb.com", + "xn--myetherwallt-jzi.com", + "xn--myetherwallt-2ck.com", + "xn--myetherwallt-lok.com", + "xn--myetherwallt-lsl.com", + "xn--myetherwallt-ce6f.com", + "xn--myetherwalet-mcc.com", + "xn--myetherwalet-xhf.com", + "xn--myetherwalet-lcc.com", + "xn--myetherwaet-15ba.com", + "xn--myetherwalet-whf.com", + "xn--myetherwaet-v2ea.com", + "xn--myetherwllet-59a.com", + "xn--myetherwllet-jbb.com", + "xn--myetherwllet-wbb.com", + "xn--myetherwllet-9bb.com", + "xn--myetherwllet-ncb.com", + "xn--myetherwllet-0cb.com", + "xn--myetherwllet-5nb.com", + "xn--myetherwllet-ktd.com", + "xn--myetherwllet-mre.com", + "xn--myetherwllet-76e.com", + "xn--myetherwllet-o0l.com", + "xn--myetherwllet-c45f.com", + "xn--myetherallet-ejn.com", + "xn--myethewallet-4nf.com", + "xn--myethewallet-iof.com", + "xn--myethewallet-mpf.com", + "xn--myethewallet-6bk.com", + "xn--myethewallet-i31f.com", + "xn--myethrwallet-feb.com", + "xn--myethrwallt-fbbf.com", + "xn--myethrwallet-seb.com", + "xn--myethrwallt-rbbf.com", + "xn--myethrwallet-5eb.com", + "xn--myethrwallt-3bbf.com", + "xn--myethrwallet-0tb.com", + "xn--myethrwallt-tpbf.com", + "xn--myethrwallet-rub.com", + "xn--myethrwallt-iqbf.com", + "xn--myethrwallet-ivb.com", + "xn--myethrwallt-6qbf.com", + "xn--myethrwallet-8vb.com", + "xn--myethrwallt-vrbf.com", + "xn--myethrwallet-zwb.com", + "xn--myethrwallt-ksbf.com", + "xn--myethrwallet-dzi.com", + "xn--myethrwallt-wbif.com", + "xn--myethrwallet-wck.com", + "xn--myethrwallt-skjf.com", + "xn--myethrwallet-fok.com", + "xn--myethrwallt-fvjf.com", + "xn--myethrwallet-fsl.com", + "xn--myethrwallt-fwkf.com", + "xn--myethrwallet-5d6f.com", + "xn--myethrwallt-319ef.com", + "xn--myeterwallet-ufk.com", + "xn--myeterwallet-nrl.com", + "xn--myeterwallet-von.com", + "xn--myeterwallet-jl6c.com", + "xn--myeherwallet-ooc.com", + "xn--myeherwalle-6hci.com", + "xn--myeherwallet-v4i.com", + "xn--myeherwalle-zgii.com", + "xn--myeherwallet-ohk.com", + "xn--myeherwalle-6oji.com", + "xn--mytherwallet-ceb.com", + "xn--mythrwallet-cbbc.com", + "xn--mythrwallt-c7acf.com", + "xn--mytherwallet-peb.com", + "xn--mythrwallet-obbc.com", + "xn--mythrwallt-n7acf.com", + "xn--mytherwallet-2eb.com", + "xn--mythrwallet-0bbc.com", + "xn--mythrwallt-y7acf.com", + "xn--mytherwallet-xtb.com", + "xn--mythrwallet-qpbc.com", + "xn--mythrwallt-jlbcf.com", + "xn--mytherwallet-oub.com", + "xn--mythrwallet-fqbc.com", + "xn--mythrwallt-5lbcf.com", + "xn--mythrwallet-3qbc.com", + "xn--mythrwallt-smbcf.com", + "xn--mytherwallet-5vb.com", + "xn--mythrwallet-srbc.com", + "xn--mythrwallt-fnbcf.com", + "xn--mytherwallet-wwb.com", + "xn--mythrwallet-hsbc.com", + "xn--mythrwallt-1nbcf.com", + "xn--mytherwallet-9yi.com", + "xn--mythrwallet-tbic.com", + "xn--mythrwallt-dnhcf.com", + "xn--mytherwallet-tck.com", + "xn--mythrwallet-pkjc.com", + "xn--mythrwallt-lsicf.com", + "xn--mytherwallet-cok.com", + "xn--mythrwallet-cvjc.com", + "xn--mythrwallt-c2icf.com", + "xn--mytherwallet-csl.com", + "xn--mythrwallet-cwkc.com", + "xn--mythrwallt-c0jcf.com", + "xn--mytherwallet-2d6f.com", + "xn--mythrwallet-019ec.com", + "xn--mythrwallt-yq3ecf.com", + "xn--metherwallet-qlb.com", + "xn--metherwallet-1uf.com", + "xn--metherwallet-iyi.com", + "xn--metherwallet-zhk.com", + "xn--metherwallet-3ml.com", + "xn--mytherwallet-fvb.com", + "xn--myetherwallt-7db.com", + "xn--myetherwallt-leb.com", + "xn--myetherwallt-yeb.com", + "xn--yetherwallet-vjf.com", + "xn--yetherwallet-dfk.com", + "xn--yetherwallet-1t1f.com", + "xn--yetherwallet-634f.com", + "xn--myeherwallet-fpc.com", + "xn--myethewallt-crb.com", + "xn--metherwallet-1vc.com", + "xn--myeherwallt-kbb8039g.com", + "xn--myeherwallet-vk5f.com", + "xn--yethewallet-iw8ejl.com", + "xn--bittrx-th8b.com", + "xn--polniex-n0a.com", + "thekey.vin", + "thekey-vip.com", + "digitexftures.com", + "ethzero-wallet.org", + "zeepln.io", + "wepowers.network", + "wepower.vision" + ] +} diff --git a/test/stub/first-time-state.js b/test/stub/first-time-state.js new file mode 100644 index 000000000..c9d5a4fe9 --- /dev/null +++ b/test/stub/first-time-state.js @@ -0,0 +1,14 @@ + +// test and development environment variables +const { createTestProviderTools } = require('../stub/provider') +const providerResultStub = {} +const provider = createTestProviderTools({ scaffold: providerResultStub }).provider +// +// The default state of MetaMask +// +module.exports = { + config: {}, + NetworkController: { + provider, + }, +} diff --git a/test/unit/blacklist-controller-test.js b/test/unit/blacklist-controller-test.js index a9260466f..cbf73d3e5 100644 --- a/test/unit/blacklist-controller-test.js +++ b/test/unit/blacklist-controller-test.js @@ -38,4 +38,4 @@ describe('blacklist controller', function () { assert.equal(result, false) }) }) -}) \ No newline at end of file +}) diff --git a/test/unit/metamask-controller-test.js b/test/unit/metamask-controller-test.js index 3fc7f9a98..ac984faf5 100644 --- a/test/unit/metamask-controller-test.js +++ b/test/unit/metamask-controller-test.js @@ -1,129 +1,103 @@ const assert = require('assert') const sinon = require('sinon') const clone = require('clone') +const nock = require('nock') const MetaMaskController = require('../../app/scripts/metamask-controller') -const firstTimeState = require('../../app/scripts/first-time-state') -const BN = require('ethereumjs-util').BN -const GWEI_BN = new BN('1000000000') +const blacklistJSON = require('../stub/blacklist') +const firstTimeState = require('../stub/first-time-state') describe('MetaMaskController', function () { - const noop = () => {} - const metamaskController = new MetaMaskController({ - showUnconfirmedMessage: noop, - unlockAccountMessage: noop, - showUnapprovedTx: noop, - platform: {}, - encryptor: { - encrypt: function(password, object) { - this.object = object - return Promise.resolve() - }, - decrypt: function () { - return Promise.resolve(this.object) - } - }, - // initial state - initState: clone(firstTimeState), - }) + let metamaskController + const sandbox = sinon.sandbox.create() + const noop = () => { } beforeEach(function () { - // sinon allows stubbing methods that are easily verified - this.sinon = sinon.sandbox.create() + + nock('https://api.infura.io') + .persist() + .get('/v2/blacklist') + .reply(200, blacklistJSON) + + nock('https://rinkeby.infura.io') + .persist() + .post('/metamask') + .reply(200) + + metamaskController = new MetaMaskController({ + showUnapprovedTx: noop, + encryptor: { + encrypt: function (password, object) { + this.object = object + return Promise.resolve() + }, + decrypt: function () { + return Promise.resolve(this.object) + }, + }, + initState: clone(firstTimeState), + }) + sandbox.spy(metamaskController.keyringController, 'createNewVaultAndKeychain') + sandbox.spy(metamaskController.keyringController, 'createNewVaultAndRestore') }) afterEach(function () { - // sinon requires cleanup otherwise it will overwrite context - this.sinon.restore() + nock.cleanAll() + sandbox.restore() }) - describe('Metamask Controller', function () { - assert(metamaskController) - - beforeEach(function () { - sinon.spy(metamaskController.keyringController, 'createNewVaultAndKeychain') - sinon.spy(metamaskController.keyringController, 'createNewVaultAndRestore') - }) - - afterEach(function () { - metamaskController.keyringController.createNewVaultAndKeychain.restore() - metamaskController.keyringController.createNewVaultAndRestore.restore() - }) - - describe('#getGasPrice', function () { - it('gives the 50th percentile lowest accepted gas price from recentBlocksController', async function () { - const realRecentBlocksController = metamaskController.recentBlocksController - metamaskController.recentBlocksController = { - store: { - getState: () => { - return { - recentBlocks: [ - { gasPrices: [ '0x3b9aca00', '0x174876e800'] }, - { gasPrices: [ '0x3b9aca00', '0x174876e800'] }, - { gasPrices: [ '0x174876e800', '0x174876e800' ]}, - { gasPrices: [ '0x174876e800', '0x174876e800' ]}, - ] - } + describe('#getGasPrice', function () { + it('gives the 50th percentile lowest accepted gas price from recentBlocksController', async function () { + const realRecentBlocksController = metamaskController.recentBlocksController + metamaskController.recentBlocksController = { + store: { + getState: () => { + return { + recentBlocks: [ + { gasPrices: [ '0x3b9aca00', '0x174876e800'] }, + { gasPrices: [ '0x3b9aca00', '0x174876e800'] }, + { gasPrices: [ '0x174876e800', '0x174876e800' ]}, + { gasPrices: [ '0x174876e800', '0x174876e800' ]}, + ], } - } - } + }, + }, + } - const gasPrice = metamaskController.getGasPrice() - assert.equal(gasPrice, '0x3b9aca00', 'accurately estimates 50th percentile accepted gas price') - - metamaskController.recentBlocksController = realRecentBlocksController - }) - - it('gives the 1 gwei price if no blocks have been seen.', async function () { - const realRecentBlocksController = metamaskController.recentBlocksController - metamaskController.recentBlocksController = { - store: { - getState: () => { - return { - recentBlocks: [] - } - } - } - } - - const gasPrice = metamaskController.getGasPrice() - assert.equal(gasPrice, '0x' + GWEI_BN.toString(16), 'defaults to 1 gwei') - - metamaskController.recentBlocksController = realRecentBlocksController - }) + const gasPrice = metamaskController.getGasPrice() + assert.equal(gasPrice, '0x3b9aca00', 'accurately estimates 50th percentile accepted gas price') + metamaskController.recentBlocksController = realRecentBlocksController }) + }) - describe('#createNewVaultAndKeychain', function () { - it('can only create new vault on keyringController once', async function () { - const selectStub = sinon.stub(metamaskController, 'selectFirstIdentity') + describe('#createNewVaultAndKeychain', function () { + it('can only create new vault on keyringController once', async function () { + const selectStub = sandbox.stub(metamaskController, 'selectFirstIdentity') + const password = 'a-fake-password' - const password = 'a-fake-password' + await metamaskController.createNewVaultAndKeychain(password) + await metamaskController.createNewVaultAndKeychain(password) - const first = await metamaskController.createNewVaultAndKeychain(password) - const second = await metamaskController.createNewVaultAndKeychain(password) + assert(metamaskController.keyringController.createNewVaultAndKeychain.calledOnce) - assert(metamaskController.keyringController.createNewVaultAndKeychain.calledOnce) - - selectStub.reset() - }) + selectStub.reset() }) + }) - describe('#createNewVaultAndRestore', function () { - it('should be able to call newVaultAndRestore despite a mistake.', async function () { - // const selectStub = sinon.stub(metamaskController, 'selectFirstIdentity') + describe('#createNewVaultAndRestore', function () { + it('should be able to call newVaultAndRestore despite a mistake.', async function () { - const password = 'what-what-what' - const wrongSeed = 'debris dizzy just program just float decrease vacant alarm reduce speak stadiu' - const rightSeed = 'debris dizzy just program just float decrease vacant alarm reduce speak stadium' - const first = await metamaskController.createNewVaultAndRestore(password, wrongSeed) - .catch((e) => { - return - }) - const second = await metamaskController.createNewVaultAndRestore(password, rightSeed) + const password = 'what-what-what' + const wrongSeed = 'debris dizzy just program just float decrease vacant alarm reduce speak stadiu' + const rightSeed = 'debris dizzy just program just float decrease vacant alarm reduce speak stadium' + await metamaskController.createNewVaultAndRestore(password, wrongSeed) + .catch((e) => { + return + }) + await metamaskController.createNewVaultAndRestore(password, rightSeed) - assert(metamaskController.keyringController.createNewVaultAndRestore.calledTwice) - }) + assert(metamaskController.keyringController.createNewVaultAndRestore.calledTwice) }) }) }) diff --git a/test/unit/network-contoller-test.js b/test/unit/network-contoller-test.js index 0b3b5adeb..fe3b9e66a 100644 --- a/test/unit/network-contoller-test.js +++ b/test/unit/network-contoller-test.js @@ -1,4 +1,5 @@ const assert = require('assert') +const nock = require('nock') const NetworkController = require('../../app/scripts/controllers/network') describe('# Network Controller', function () { @@ -8,6 +9,9 @@ describe('# Network Controller', function () { } beforeEach(function () { + nock('https://api.infura.io') + .get('/*/') + .reply(200, {}) networkController = new NetworkController({ provider: { type: 'rinkeby', From 8f7094a73d4ca5879e8290e3b1aefdc42397767d Mon Sep 17 00:00:00 2001 From: Thomas Huang Date: Thu, 15 Feb 2018 09:54:22 -0800 Subject: [PATCH 044/392] Network controller nock --- test/unit/network-contoller-test.js | 40 ++++++++++++----------------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/test/unit/network-contoller-test.js b/test/unit/network-contoller-test.js index fe3b9e66a..cd8c345c5 100644 --- a/test/unit/network-contoller-test.js +++ b/test/unit/network-contoller-test.js @@ -2,28 +2,37 @@ const assert = require('assert') const nock = require('nock') const NetworkController = require('../../app/scripts/controllers/network') +const { createTestProviderTools } = require('../stub/provider') +const providerResultStub = {} +const provider = createTestProviderTools({ scaffold: providerResultStub }).provider + describe('# Network Controller', function () { let networkController + const noop = () => {} const networkControllerProviderInit = { getAccounts: () => {}, } beforeEach(function () { + nock('https://api.infura.io') .get('/*/') - .reply(200, {}) + .reply(200) + + nock('https://rinkeby.infura.io') + .post('/metamask') + .reply(200) + networkController = new NetworkController({ - provider: { - type: 'rinkeby', - }, + provider, }) - networkController.initializeProvider(networkControllerProviderInit, dummyProviderConstructor) + networkController.initializeProvider(networkControllerProviderInit, provider) }) describe('network', function () { describe('#provider', function () { it('provider should be updatable without reassignment', function () { - networkController.initializeProvider(networkControllerProviderInit, dummyProviderConstructor) + networkController.initializeProvider(networkControllerProviderInit, provider) const proxy = networkController._proxy proxy.setTarget({ test: true, on: () => {} }) assert.ok(proxy.test) @@ -68,21 +77,4 @@ describe('# Network Controller', function () { }) }) }) -}) - -function dummyProviderConstructor() { - return { - // provider - sendAsync: noop, - // block tracker - _blockTracker: {}, - start: noop, - stop: noop, - on: noop, - addListener: noop, - once: noop, - removeAllListeners: noop, - } -} - -function noop() {} \ No newline at end of file +}) \ No newline at end of file From a5056a62d1a8538049c182b4b104bcfb2645ad28 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 15 Feb 2018 12:04:19 -0800 Subject: [PATCH 045/392] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bfae566ea..595bc00e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Current Master - Fix bug where log subscriptions would break when switching network. +- Add MetaMask light client [testing container](https://github.com/MetaMask/mesh-testing) ## 3.14.1 2018-2-1 From ed33f3160a35e2e765012a4726ff90f9b3608998 Mon Sep 17 00:00:00 2001 From: Thomas Huang Date: Thu, 15 Feb 2018 12:36:26 -0800 Subject: [PATCH 046/392] Make oldui compatible with newUI style changes --- app/popup.html | 4 ++-- old-ui/app/components/account-dropdowns.js | 1 + old-ui/app/config.js | 2 +- old-ui/app/css/index.css | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) 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 @@ - + MetaMask Plugin - +
diff --git a/old-ui/app/components/account-dropdowns.js b/old-ui/app/components/account-dropdowns.js index a3908f45d..7cc581f84 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 689385a02..9e07cf348 100644 --- a/old-ui/app/config.js +++ b/old-ui/app/config.js @@ -32,7 +32,7 @@ ConfigScreen.prototype.render = function () { return ( h('.flex-column.flex-grow', { style:{ - maxHeight: '465px', + maxHeight: '585px', overflowY: 'auto', }, }, [ diff --git a/old-ui/app/css/index.css b/old-ui/app/css/index.css index cdb4cc439..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; } From 71be537f1cdfe7df41e350f6720c12f5a7bb9b2d Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 15 Feb 2018 14:23:22 -0800 Subject: [PATCH 047/392] Version 3.14.2 --- CHANGELOG.md | 3 +++ app/manifest.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 595bc00e6..fae2e0800 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,10 @@ ## Current Master +## 3.14.2 2018-2-15 + - Fix bug where log subscriptions would break when switching network. +- Fix bug where storage values were cached across blocks. - Add MetaMask light client [testing container](https://github.com/MetaMask/mesh-testing) ## 3.14.1 2018-2-1 diff --git a/app/manifest.json b/app/manifest.json index a0bb5acf6..3a80cc4fc 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "MetaMask", "short_name": "Metamask", - "version": "3.14.1", + "version": "3.14.2", "manifest_version": 2, "author": "https://metamask.io", "description": "Ethereum Browser Extension", From 70132e6df6de0722113f5b461b4cec2419c45266 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 15 Feb 2018 15:15:07 -0800 Subject: [PATCH 048/392] Default validated block gas limit to 8MM when none identified Mitigates #3266 --- ui/app/components/pending-tx.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/app/components/pending-tx.js b/ui/app/components/pending-tx.js index 32d54902e..eb6ece176 100644 --- a/ui/app/components/pending-tx.js +++ b/ui/app/components/pending-tx.js @@ -60,7 +60,7 @@ PendingTx.prototype.render = function () { // Gas const gas = txParams.gas const gasBn = hexToBn(gas) - const gasLimit = new BN(parseInt(blockGasLimit)) + const gasLimit = new BN(parseInt(blockGasLimit) || '8000000') // default to 8MM gas limit const safeGasLimitBN = this.bnMultiplyByFraction(gasLimit, 19, 20) const saferGasLimitBN = this.bnMultiplyByFraction(gasLimit, 18, 20) const safeGasLimit = safeGasLimitBN.toString(10) From 73e5ae6e29d04481cc3ffdd32d5d096e6a10b3b3 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 15 Feb 2018 15:32:48 -0800 Subject: [PATCH 049/392] Fix incorrect promise instantiation --- app/scripts/lib/nonce-tracker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/lib/nonce-tracker.js b/app/scripts/lib/nonce-tracker.js index 0029ac953..ed9dd3f11 100644 --- a/app/scripts/lib/nonce-tracker.js +++ b/app/scripts/lib/nonce-tracker.js @@ -56,7 +56,7 @@ class NonceTracker { const blockTracker = this._getBlockTracker() const currentBlock = blockTracker.getCurrentBlock() if (currentBlock) return currentBlock - return await Promise((reject, resolve) => { + return await new Promise((reject, resolve) => { blockTracker.once('latest', resolve) }) } From 170c7602b70e475e75fbd1c7181d03e22465ae24 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Fri, 16 Feb 2018 06:15:09 -0330 Subject: [PATCH 050/392] [NewUI] Adds the mascara first time flow to betaUI extension (#3257) * Adds the mascara first time flow to the extension when opened in browser. * Fix tests after addition of mascara first time flow to new ui. --- development/states/first-time.json | 2 +- test/integration/lib/first-time.js | 3 +-- ui/app/app.js | 10 ++++++---- ui/app/reducers/metamask.js | 2 ++ 4 files changed, 10 insertions(+), 7 deletions(-) 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/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/ui/app/app.js b/ui/app/app.js index cdb0c8c61..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,6 +74,7 @@ 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, @@ -85,7 +86,8 @@ function mapStateToProps (state) { lostAccounts: state.metamask.lostAccounts, frequentRpcList: state.metamask.frequentRpcList || [], currentCurrency: state.metamask.currentCurrency, - isMouseUser: state.appState.isMouseUser, + isMouseUser: state.appState.isMouseUser, + betaUI: state.metamask.featureFlags.betaUI, // state needed to get account dropdown temporarily rendering from app bar identities, @@ -351,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) } 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: {}, From 8e80081966e6411fae41f398e063ac0a62fe415c Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 16 Feb 2018 07:50:51 -0800 Subject: [PATCH 051/392] lint - lift comment to new line --- ui/app/components/pending-tx.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/app/components/pending-tx.js b/ui/app/components/pending-tx.js index eb6ece176..98193ea6f 100644 --- a/ui/app/components/pending-tx.js +++ b/ui/app/components/pending-tx.js @@ -60,7 +60,8 @@ PendingTx.prototype.render = function () { // Gas const gas = txParams.gas const gasBn = hexToBn(gas) - const gasLimit = new BN(parseInt(blockGasLimit) || '8000000') // default to 8MM gas limit + // default to 8MM gas limit + const gasLimit = new BN(parseInt(blockGasLimit) || '8000000') const safeGasLimitBN = this.bnMultiplyByFraction(gasLimit, 19, 20) const saferGasLimitBN = this.bnMultiplyByFraction(gasLimit, 18, 20) const safeGasLimit = safeGasLimitBN.toString(10) From 06838774fa0bfb0ddea4db049211f92781841ff5 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 16 Feb 2018 10:21:06 -0800 Subject: [PATCH 052/392] sentry - report failed tx with more specific message --- app/scripts/background.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/scripts/background.js b/app/scripts/background.js index 6bf7707e8..3e1178457 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -85,7 +85,8 @@ function setupController (initState) { controller.txController.on(`tx:status-update`, (txId, status) => { if (status !== 'failed') return const txMeta = controller.txController.txStateManager.getTx(txId) - raven.captureMessage('Transaction Failed', { + const errorMessage = `Transaction Failed: ${txMeta.err.message}` + raven.captureMessage(errorMessage, { // "extra" key is required by Sentry extra: txMeta, }) From 81eb5c8796b3a044c1b1e66f509bb14870f7ba92 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Fri, 16 Feb 2018 19:21:16 -0330 Subject: [PATCH 053/392] Ensures that mascara initialize screen is not shown in popup. (#3279) --- ui/app/app.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ui/app/app.js b/ui/app/app.js index 5ffd263d1..1a64bb1a4 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -9,6 +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 OldUIInitializeMenuScreen = require('./first-time/init-menu') const InitializeMenuScreen = MascaraFirstTime const NewKeyChainScreen = require('./new-keychain') // accounts @@ -381,7 +382,9 @@ App.prototype.renderPrimary = function () { return h(HDRestoreVaultScreen, {key: 'HDRestoreVaultScreen'}) } else if (!props.isInitialized) { log.debug('rendering menu screen') - return h(InitializeMenuScreen, {key: 'menuScreenInit'}) + return props.isPopup + ? h(OldUIInitializeMenuScreen, {key: 'menuScreenInit'}) + : h(InitializeMenuScreen, {key: 'menuScreenInit'}) } // show unlock screen From 7169cb1eb83ae9a378dad3240527989e6df0f158 Mon Sep 17 00:00:00 2001 From: Dan Date: Fri, 16 Feb 2018 19:36:17 -0330 Subject: [PATCH 054/392] Bump uat version to 4.0.12 --- app/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/manifest.json b/app/manifest.json index a0bb5acf6..c4e134053 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "MetaMask", "short_name": "Metamask", - "version": "3.14.1", + "version": "4.0.12", "manifest_version": 2, "author": "https://metamask.io", "description": "Ethereum Browser Extension", From c26e0d555b7cb89e88713041714206abd8f4275e Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 19 Feb 2018 22:46:18 -0330 Subject: [PATCH 055/392] Fix Import Existing DEN in popup New UI first time flow. --- .../first-time/import-seed-phrase-screen.js | 14 +++++- mascara/src/app/first-time/index.js | 49 +++++++++++++++++-- ui/app/app.js | 2 +- ui/app/first-time/init-menu.js | 24 ++++++++- 4 files changed, 80 insertions(+), 9 deletions(-) diff --git a/mascara/src/app/first-time/import-seed-phrase-screen.js b/mascara/src/app/first-time/import-seed-phrase-screen.js index 181151ca9..a03a16329 100644 --- a/mascara/src/app/first-time/import-seed-phrase-screen.js +++ b/mascara/src/app/first-time/import-seed-phrase-screen.js @@ -2,7 +2,13 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' import {connect} from 'react-redux' import LoadingScreen from './loading-screen' -import {createNewVaultAndRestore, hideWarning, displayWarning} from '../../../../ui/app/actions' +import { + createNewVaultAndRestore, + hideWarning, + displayWarning, + unMarkPasswordForgotten, + clearNotices, +} from '../../../../ui/app/actions' class ImportSeedPhraseScreen extends Component { static propTypes = { @@ -23,7 +29,7 @@ class ImportSeedPhraseScreen extends Component { onClick = () => { const { password, seedPhrase, confirmPassword } = this.state - const { createNewVaultAndRestore, next, displayWarning } = this.props + const { createNewVaultAndRestore, next, displayWarning, leaveImportSeedSreenState } = this.props if (seedPhrase.split(' ').length !== 12) { this.warning = 'Seed Phrases are 12 words long' @@ -43,6 +49,7 @@ class ImportSeedPhraseScreen extends Component { return } this.warning = null + leaveImportSeedSreenState() createNewVaultAndRestore(password, seedPhrase) .then(next) } @@ -113,6 +120,9 @@ class ImportSeedPhraseScreen extends Component { export default connect( ({ appState: { isLoading, warning } }) => ({ isLoading, warning }), dispatch => ({ + leaveImportSeedSreenState: () => { + dispatch(unMarkPasswordForgotten()) + }, createNewVaultAndRestore: (pw, seed) => dispatch(createNewVaultAndRestore(pw, seed)), displayWarning: (warning) => dispatch(displayWarning(warning)), hideWarning: () => dispatch(hideWarning()), diff --git a/mascara/src/app/first-time/index.js b/mascara/src/app/first-time/index.js index b06f2ba9d..883342d16 100644 --- a/mascara/src/app/first-time/index.js +++ b/mascara/src/app/first-time/index.js @@ -7,7 +7,11 @@ import NoticeScreen from './notice-screen' import BackupPhraseScreen from './backup-phrase-screen' import ImportAccountScreen from './import-account-screen' import ImportSeedPhraseScreen from './import-seed-phrase-screen' -import {onboardingBuyEthView} from '../../../../ui/app/actions' +const Loading = require('../../../../ui/app//components/loading') +import { + onboardingBuyEthView, + unMarkPasswordForgotten, +} from '../../../../ui/app/actions' class FirstTimeFlow extends Component { @@ -33,6 +37,7 @@ class FirstTimeFlow extends Component { NOTICE: 'notice', BACK_UP_PHRASE: 'back_up_phrase', CONFIRM_BACK_UP_PHRASE: 'confirm_back_up_phrase', + LOADING: 'loading', }; constructor (props) { @@ -51,11 +56,15 @@ class FirstTimeFlow extends Component { isInitialized, seedWords, noActiveNotices, + forgottenPassword, } = this.props const {SCREEN_TYPE} = FirstTimeFlow // return SCREEN_TYPE.NOTICE + if (forgottenPassword) { + return SCREEN_TYPE.IMPORT_SEED_PHRASE + } if (!isInitialized) { return SCREEN_TYPE.CREATE_PASSWORD } @@ -71,7 +80,17 @@ class FirstTimeFlow extends Component { renderScreen () { const {SCREEN_TYPE} = FirstTimeFlow - const {goToBuyEtherView, address} = this.props + const { + goToBuyEtherView, + address, + restoreCreatePasswordScreen, + forgottenPassword, + isLoading, + } = this.props + + if (isLoading) { + return h(Loading) + } switch (this.state.screenType) { case SCREEN_TYPE.CREATE_PASSWORD: @@ -92,8 +111,14 @@ class FirstTimeFlow extends Component { case SCREEN_TYPE.IMPORT_SEED_PHRASE: return ( this.setScreenType(SCREEN_TYPE.CREATE_PASSWORD)} - next={() => this.setScreenType(SCREEN_TYPE.NOTICE)} + back={() => { + leaveImportSeedSreenState() + this.setScreenType(SCREEN_TYPE.CREATE_PASSWORD) + }} + next={() => { + const newScreenType = forgottenPassword ? null : SCREEN_TYPE.NOTICE + this.setScreenType(newScreenType) + }} /> ) case SCREEN_TYPE.UNIQUE_IMAGE: @@ -130,13 +155,27 @@ class FirstTimeFlow extends Component { } export default connect( - ({ metamask: { isInitialized, seedWords, noActiveNotices, selectedAddress } }) => ({ + ({ + metamask: { + isInitialized, + seedWords, + noActiveNotices, + selectedAddress, + forgottenPassword, + }, + appState: { + isLoading, + } + }) => ({ isInitialized, seedWords, noActiveNotices, address: selectedAddress, + forgottenPassword, + isLoading, }), dispatch => ({ + leaveImportSeedSreenState: () => dispatch(unMarkPasswordForgotten()), goToBuyEtherView: address => dispatch(onboardingBuyEthView(address)), }) )(FirstTimeFlow) diff --git a/ui/app/app.js b/ui/app/app.js index 1a64bb1a4..58e38a077 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -380,7 +380,7 @@ App.prototype.renderPrimary = function () { if (props.isInitialized && props.forgottenPassword) { log.debug('rendering restore vault screen') return h(HDRestoreVaultScreen, {key: 'HDRestoreVaultScreen'}) - } else if (!props.isInitialized) { + } else if (!props.isInitialized && !props.isUnlocked) { log.debug('rendering menu screen') return props.isPopup ? h(OldUIInitializeMenuScreen, {key: 'menuScreenInit'}) diff --git a/ui/app/first-time/init-menu.js b/ui/app/first-time/init-menu.js index b4587f1ee..0e08da8db 100644 --- a/ui/app/first-time/init-menu.js +++ b/ui/app/first-time/init-menu.js @@ -7,6 +7,8 @@ const Mascot = require('../components/mascot') const actions = require('../actions') const Tooltip = require('../components/tooltip') const getCaretCoordinates = require('textarea-caret') +const environmentType = require('../../../app/scripts/lib/environment-type') +const { OLD_UI_NETWORK_TYPE } = require('../../../app/scripts/config').enums let isSubmitting = false @@ -130,6 +132,18 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { }, 'Import Existing DEN'), ]), + h('.flex-row.flex-center.flex-grow', [ + h('p.pointer', { + onClick: this.showOldUI.bind(this), + style: { + fontSize: '0.8em', + color: '#aeaeae', + textDecoration: 'underline', + marginTop: '32px', + }, + }, 'Use classic interface'), + ]), + ]) ) } @@ -146,7 +160,15 @@ InitializeMenuScreen.prototype.componentDidMount = function () { } InitializeMenuScreen.prototype.showRestoreVault = function () { - this.props.dispatch(actions.showRestoreVault()) + this.props.dispatch(actions.markPasswordForgotten()) + if (environmentType() === 'popup') { + global.platform.openExtensionInBrowser() + } +} + +InitializeMenuScreen.prototype.showOldUI = function () { + this.props.dispatch(actions.setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL')) + .then(() => this.props.dispatch(actions.setNetworkEndpoints(OLD_UI_NETWORK_TYPE))) } InitializeMenuScreen.prototype.createNewVaultAndKeychain = function () { From 00c5dd2736cd389c6658778bb5238eefb2d2f926 Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 20 Feb 2018 14:00:35 -0330 Subject: [PATCH 056/392] Fix variable spelling error. --- mascara/src/app/first-time/import-seed-phrase-screen.js | 6 +++--- mascara/src/app/first-time/index.js | 9 +++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/mascara/src/app/first-time/import-seed-phrase-screen.js b/mascara/src/app/first-time/import-seed-phrase-screen.js index a03a16329..93c3f9203 100644 --- a/mascara/src/app/first-time/import-seed-phrase-screen.js +++ b/mascara/src/app/first-time/import-seed-phrase-screen.js @@ -29,7 +29,7 @@ class ImportSeedPhraseScreen extends Component { onClick = () => { const { password, seedPhrase, confirmPassword } = this.state - const { createNewVaultAndRestore, next, displayWarning, leaveImportSeedSreenState } = this.props + const { createNewVaultAndRestore, next, displayWarning, leaveImportSeedScreenState } = this.props if (seedPhrase.split(' ').length !== 12) { this.warning = 'Seed Phrases are 12 words long' @@ -49,7 +49,7 @@ class ImportSeedPhraseScreen extends Component { return } this.warning = null - leaveImportSeedSreenState() + leaveImportSeedScreenState() createNewVaultAndRestore(password, seedPhrase) .then(next) } @@ -120,7 +120,7 @@ class ImportSeedPhraseScreen extends Component { export default connect( ({ appState: { isLoading, warning } }) => ({ isLoading, warning }), dispatch => ({ - leaveImportSeedSreenState: () => { + leaveImportSeedScreenState: () => { dispatch(unMarkPasswordForgotten()) }, createNewVaultAndRestore: (pw, seed) => dispatch(createNewVaultAndRestore(pw, seed)), diff --git a/mascara/src/app/first-time/index.js b/mascara/src/app/first-time/index.js index 883342d16..a05e0aa96 100644 --- a/mascara/src/app/first-time/index.js +++ b/mascara/src/app/first-time/index.js @@ -7,7 +7,7 @@ import NoticeScreen from './notice-screen' import BackupPhraseScreen from './backup-phrase-screen' import ImportAccountScreen from './import-account-screen' import ImportSeedPhraseScreen from './import-seed-phrase-screen' -const Loading = require('../../../../ui/app//components/loading') +const Loading = require('../../../../ui/app/components/loading') import { onboardingBuyEthView, unMarkPasswordForgotten, @@ -86,10 +86,11 @@ class FirstTimeFlow extends Component { restoreCreatePasswordScreen, forgottenPassword, isLoading, + leaveImportSeedScreenState, } = this.props if (isLoading) { - return h(Loading) + return () } switch (this.state.screenType) { @@ -112,7 +113,7 @@ class FirstTimeFlow extends Component { return ( { - leaveImportSeedSreenState() + leaveImportSeedScreenState() this.setScreenType(SCREEN_TYPE.CREATE_PASSWORD) }} next={() => { @@ -175,7 +176,7 @@ export default connect( isLoading, }), dispatch => ({ - leaveImportSeedSreenState: () => dispatch(unMarkPasswordForgotten()), + leaveImportSeedScreenState: () => dispatch(unMarkPasswordForgotten()), goToBuyEtherView: address => dispatch(onboardingBuyEthView(address)), }) )(FirstTimeFlow) From cca931c783dcff4f368611c4dc48a938d2856cc5 Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 20 Feb 2018 16:17:30 -0330 Subject: [PATCH 057/392] Temporarily disable loading indicator. --- mascara/src/app/first-time/index.js | 7 +- output | 1889 +++++++++++++++++++++++++++ 2 files changed, 1893 insertions(+), 3 deletions(-) create mode 100644 output diff --git a/mascara/src/app/first-time/index.js b/mascara/src/app/first-time/index.js index a05e0aa96..46b821c8b 100644 --- a/mascara/src/app/first-time/index.js +++ b/mascara/src/app/first-time/index.js @@ -89,9 +89,10 @@ class FirstTimeFlow extends Component { leaveImportSeedScreenState, } = this.props - if (isLoading) { - return () - } + // Disable until testing bug resolved + // if (isLoading) { + // return () + // } switch (this.state.screenType) { case SCREEN_TYPE.CREATE_PASSWORD: diff --git a/output b/output new file mode 100644 index 000000000..dfb259888 --- /dev/null +++ b/output @@ -0,0 +1,1889 @@ + +> metamask-crx@0.0.0 test:mascara /Users/danmiller/kyokan/metamask/metamask-extension +> npm run test:mascara:build && karma start test/mascara.conf.js + + +> metamask-crx@0.0.0 test:mascara:build /Users/danmiller/kyokan/metamask/metamask-extension +> mkdir -p dist/mascara && npm run test:mascara:build:ui && npm run test:mascara:build:background && npm run test:mascara:build:tests + + +> metamask-crx@0.0.0 test:mascara:build:ui /Users/danmiller/kyokan/metamask/metamask-extension +> browserify mascara/test/test-ui.js -o dist/mascara/ui.js + + +> metamask-crx@0.0.0 test:mascara:build:background /Users/danmiller/kyokan/metamask/metamask-extension +> browserify mascara/src/background.js -o dist/mascara/background.js + + +> metamask-crx@0.0.0 test:mascara:build:tests /Users/danmiller/kyokan/metamask/metamask-extension +> browserify test/integration/lib/first-time.js -o dist/mascara/tests.js + +20 02 2018 15:29:25.773:INFO [karma]: Karma v1.7.1 server started at http://0.0.0.0:9876/ +20 02 2018 15:29:25.776:INFO [launcher]: Launching browser Chrome with concurrency 1 +20 02 2018 15:29:25.822:INFO [launcher]: Starting browser Chrome +20 02 2018 15:29:31.117:INFO [Chrome 64.0.3282 (Mac OS X 10.12.6)]: Connected on socket xl57FfHdT0vJ5kbQAAAA with id 3100832 +Chrome 64.0.3282 (Mac OS X 10.12.6) WARN: 'Warning: Accessing PropTypes via the main React package is deprecated, and will be removed in React v16.0. Use the latest available v15.* prop-types package from npm instead. For info on usage, compatibility, migration and more, see https://fb.me/prop-types-docs' + +Chrome 64.0.3282 (Mac OS X 10.12.6) WARN: 'Warning: Accessing createClass via the main React package is deprecated, and will be removed in React v16.0. Use a plain JavaScript class instead. If you're not yet ready to migrate, create-react-class v15.* is available on npm as a temporary, drop-in replacement. For more info see https://fb.me/react-create-class' + + +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got @@redux/INIT' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'background.setNetworkEndpoints' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'Main ui render function' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'rendering primary' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: false, seedWords: '', noActiveNotices: false, address: undefined, forgottenPassword: undefined, isLoading: false, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.state*************************', Object{screenType: 'create_password'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************isLoading*************************', false +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '**************************************************************************' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'hello from MetaMascara ui!' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'hello from cb ready event!' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got UPDATE_NETWORK_ENDPOINT_TYPE' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: false}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'UPDATE_NETWORK_ENDPOINT_TYPE', value: 'network'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: false}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'No more notices...' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got UPDATE_METAMASK_STATE' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'Main ui render function' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'rendering primary' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: false}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'UPDATE_METAMASK_STATE', value: Object{isInitialized: false, provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', unapprovedTxs: Object{}, selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, isUnlocked: false, keyringTypes: [..., ...], keyrings: [], identities: Object{}, computedBalances: Object{}, frequentRpcList: [], currentAccountTab: 'history', tokens: [], useBlockie: false, featureFlags: Object{}, addressBook: [], currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, noActiveNotices: false, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: false}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got UPDATE_METAMASK_STATE' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'Main ui render function' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'rendering primary' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: false}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'UPDATE_METAMASK_STATE', value: Object{isInitialized: false, provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', unapprovedTxs: Object{}, selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, isUnlocked: false, keyringTypes: [..., ...], keyrings: [], identities: Object{}, computedBalances: Object{}, frequentRpcList: [], currentAccountTab: 'history', tokens: [], useBlockie: false, featureFlags: Object{}, addressBook: [], currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, noActiveNotices: false, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: false}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got UPDATE_METAMASK_STATE' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'Main ui render function' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'rendering primary' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: false}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'UPDATE_METAMASK_STATE', value: Object{isInitialized: false, provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', unapprovedTxs: Object{}, selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, isUnlocked: false, keyringTypes: [..., ...], keyrings: [], identities: Object{}, computedBalances: Object{}, frequentRpcList: [], currentAccountTab: 'history', tokens: [], useBlockie: false, featureFlags: Object{}, addressBook: [], currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, noActiveNotices: false, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: false}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got UPDATE_METAMASK_STATE' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'Main ui render function' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'rendering primary' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: false}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'UPDATE_METAMASK_STATE', value: Object{isInitialized: false, provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', unapprovedTxs: Object{}, selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, isUnlocked: false, keyringTypes: [..., ...], keyrings: [], identities: Object{}, computedBalances: Object{}, frequentRpcList: [], currentAccountTab: 'history', tokens: [], useBlockie: false, featureFlags: Object{}, addressBook: [], currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, noActiveNotices: false, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: false}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got UPDATE_METAMASK_STATE' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'Main ui render function' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'rendering primary' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: false}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'UPDATE_METAMASK_STATE', value: Object{isInitialized: false, provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', unapprovedTxs: Object{}, selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, isUnlocked: false, keyringTypes: [..., ...], keyrings: [], identities: Object{}, computedBalances: Object{}, frequentRpcList: [], currentAccountTab: 'history', tokens: [], useBlockie: false, featureFlags: Object{}, addressBook: [], currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, noActiveNotices: false, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: false}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got SHOW_LOADING_INDICATION' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: false}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'SHOW_LOADING_INDICATION', value: undefined} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: false, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'background.createNewVaultAndKeychain' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got SET_MOUSE_USER_STATE' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: false, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'SET_MOUSE_USER_STATE', value: true} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'Main ui render function' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'rendering primary' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: false, seedWords: '', noActiveNotices: false, address: undefined, forgottenPassword: undefined, isLoading: true, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.state*************************', Object{screenType: 'create_password'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************isLoading*************************', true +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'background.placeSeedWords' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got HIDE_LOADING_INDICATION' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'Main ui render function' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'rendering primary' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: false, seedWords: '', noActiveNotices: false, address: undefined, forgottenPassword: undefined, isLoading: false, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.state*************************', Object{screenType: 'create_password'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************isLoading*************************', false +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '**************************************************************************' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'HIDE_LOADING_INDICATION'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'background.getState' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: false, seedWords: '', noActiveNotices: false, address: undefined, forgottenPassword: undefined, isLoading: false, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.state*************************', Object{screenType: 'unique_image'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************isLoading*************************', false +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '**************************************************************************' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got UPDATE_METAMASK_STATE' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got SHOW_LOADING_INDICATION' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'UPDATE_METAMASK_STATE', value: Object{isInitialized: true, provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', unapprovedTxs: Object{}, selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, isUnlocked: true, keyringTypes: [..., ...], keyrings: [...], identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, computedBalances: Object{}, frequentRpcList: [], currentAccountTab: 'history', tokens: [], useBlockie: false, featureFlags: Object{}, selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', addressBook: [], currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, noActiveNotices: false, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'SHOW_LOADING_INDICATION', value: undefined} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'Main ui render function' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'rendering primary' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: true, seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert', noActiveNotices: false, address: '0x77abfc38dea988c2f9602daa758867918b877f3a', forgottenPassword: undefined, isLoading: true, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.state*************************', Object{screenType: 'unique_image'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************isLoading*************************', true +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got HIDE_LOADING_INDICATION' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'Main ui render function' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'rendering primary' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: true, seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert', noActiveNotices: false, address: '0x77abfc38dea988c2f9602daa758867918b877f3a', forgottenPassword: undefined, isLoading: false, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.state*************************', Object{screenType: 'unique_image'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************isLoading*************************', false +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '**************************************************************************' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'HIDE_LOADING_INDICATION'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got UPDATE_FEATURE_FLAGS' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got SHOW_LOADING_INDICATION' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'UPDATE_FEATURE_FLAGS', value: Object{betaUI: true}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'SHOW_LOADING_INDICATION', value: undefined} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'Main ui render function' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'rendering primary' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: true, seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert', noActiveNotices: false, address: '0x77abfc38dea988c2f9602daa758867918b877f3a', forgottenPassword: undefined, isLoading: true, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.state*************************', Object{screenType: 'unique_image'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************isLoading*************************', true +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'background.setNetworkEndpoints' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got HIDE_LOADING_INDICATION' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'Main ui render function' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'rendering primary' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: true, seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert', noActiveNotices: false, address: '0x77abfc38dea988c2f9602daa758867918b877f3a', forgottenPassword: undefined, isLoading: false, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.state*************************', Object{screenType: 'unique_image'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************isLoading*************************', false +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '**************************************************************************' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'HIDE_LOADING_INDICATION'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got UPDATE_FEATURE_FLAGS' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'UPDATE_FEATURE_FLAGS', value: Object{betaUI: true}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'background.setNetworkEndpoints' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got UPDATE_NETWORK_ENDPOINT_TYPE' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'UPDATE_NETWORK_ENDPOINT_TYPE', value: 'networkBeta'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got UPDATE_NETWORK_ENDPOINT_TYPE' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'UPDATE_NETWORK_ENDPOINT_TYPE', value: 'networkBeta'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got SET_MOUSE_USER_STATE' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'SET_MOUSE_USER_STATE', value: true} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: true, seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert', noActiveNotices: false, address: '0x77abfc38dea988c2f9602daa758867918b877f3a', forgottenPassword: undefined, isLoading: false, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.state*************************', Object{screenType: 'notice'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************isLoading*************************', false +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '**************************************************************************' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'document.body', + + + + + + + + + + + + +
Created with Raphaël 2.2.0
Privacy Notice

MetaMask is beta software.

When you log in to MetaMask, your current account is visible to every new site you visit.

For your privacy, for now, please sign out of MetaMask when you're done using a site.

+Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got UPDATE_METAMASK_STATE' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'Main ui render function' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'rendering primary' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'UPDATE_METAMASK_STATE', value: Object{isInitialized: true, provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', unapprovedTxs: Object{}, selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, isUnlocked: true, keyringTypes: [..., ...], keyrings: [...], identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, computedBalances: Object{}, frequentRpcList: [], currentAccountTab: 'history', tokens: [], useBlockie: false, featureFlags: Object{betaUI: ...}, selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', addressBook: [], currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, noActiveNotices: false, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got SHOW_LOADING_INDICATION' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'SHOW_LOADING_INDICATION', value: undefined} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'background.markNoticeRead' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got SET_MOUSE_USER_STATE' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'SET_MOUSE_USER_STATE', value: true} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'Main ui render function' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'rendering primary' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: true, seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert', noActiveNotices: false, address: '0x77abfc38dea988c2f9602daa758867918b877f3a', forgottenPassword: undefined, isLoading: true, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.state*************************', Object{screenType: 'notice'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************isLoading*************************', true +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got HIDE_LOADING_INDICATION' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'Main ui render function' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'rendering primary' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: true, seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert', noActiveNotices: false, address: '0x77abfc38dea988c2f9602daa758867918b877f3a', forgottenPassword: undefined, isLoading: false, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.state*************************', Object{screenType: 'notice'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************isLoading*************************', false +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '**************************************************************************' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'HIDE_LOADING_INDICATION'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got SHOW_NOTICE' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'Main ui render function' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'rendering primary' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'SHOW_NOTICE', value: Object{read: false, date: 'Thu Feb 09 2017', title: 'Terms of Use', body: '# Terms of Use # + +**THIS AGREEMENT IS SUBJECT TO BINDING ARBITRATION AND A WAIVER OF CLASS ACTION RIGHTS AS DETAILED IN SECTION 13. PLEASE READ THE AGREEMENT CAREFULLY.** + +_Our Terms of Use have been updated as of September 5, 2016_ + +## 1. Acceptance of Terms ## + +MetaMask 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. + +## 2. Modification of Terms of Use ## + +Except 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. + + + +## 3. Eligibility ## + +You 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. + +MetaMask 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. + +## 4 Account Password and Security ## + +When 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. + +## 5. Representations, Warranties, and Risks ## + +### 5.1. Warranty Disclaimer ### + +You 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. + +### 5.2 Sophistication and Risk of Cryptographic Systems ### + +By 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. + +### 5.3 Risk of Regulatory Actions in One or More Jurisdictions ### + +MetaMask 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. + +### 5.4 Risk of Weaknesses or Exploits in the Field of Cryptography ### + +You 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. + +### 5.5 Volatility of Crypto Currencies ### + +You 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. + +### 5.6 Application Security ### + +You 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. + +## 6. Indemnity ## + +You 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. + +## 7. Limitation on liability ## + +YOU 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. + +SOME 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. + +## 8. Our Proprietary Rights ## + +All 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) + +## 9. Links ## + +The 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. + +## 10. Termination and Suspension ## + +MetaMask 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. + +The 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. + +## 11. No Third Party Beneficiaries ## + +You agree that, except as otherwise expressly provided in these Terms, there shall be no third party beneficiaries to the Terms. + +## 12. Notice and Procedure For Making Claims of Copyright Infringement ## + +If 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: + +· an electronic or physical signature of the person authorized to act on behalf of the owner of the copyright or other intellectual property interest; + +· a description of the copyrighted work or other intellectual property that you claim has been infringed; + +· a description of where the material that you claim is infringing is located on the Service; + +· your address, telephone number, and email address; + +· 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; + +· 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. + +MetaMask’s Copyright Agent can be reached at: + +Email: copyright [at] metamask [dot] io + +Mail: + +Attention: + +MetaMask Copyright ℅ ConsenSys + +49 Bogart Street + +Brooklyn, NY 11206 + +## 13. Binding Arbitration and Class Action Waiver ## + +PLEASE READ THIS SECTION CAREFULLY – IT MAY SIGNIFICANTLY AFFECT YOUR LEGAL RIGHTS, INCLUDING YOUR RIGHT TO FILE A LAWSUIT IN COURT + +### 13.1 Initial Dispute Resolution ### + +The 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. + +### 13.2 Binding Arbitration ### + +If 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. + +The 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. + +The 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. + +### 13.3 Location ### + +Binding 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. + +### 13.4 Class Action Waiver ### + +The 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. + +### 13.5 Exception - Litigation of Intellectual Property and Small Claims Court Claims ### + +Notwithstanding 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. + +### 13.6 30-Day Right to Opt Out ### + +You 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. + +### 13.7 Changes to This Section ### + +MetaMask 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. + +For 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. + +The 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. + +## 14. General Information ## + +### 14.1 Entire Agreement ### + +These 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. + +### 14.2 Waiver and Severability of Terms ### + +The 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. + +### 14.3 Statute of Limitations ### + +You 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. + +### 14.4 Section Titles ### + +The section titles in the Terms are for convenience only and have no legal or contractual effect. + +### 14.5 Communications ### + +Users 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. + +## 15 Related Links ## + +**[Terms of Use](https://metamask.io/terms.html)** + +**[Privacy](https://metamask.io/privacy.html)** + +**[Attributions](https://metamask.io/attributions.html)** + +', id: 0}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +ERROR: 'Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the NoticeScreen component.' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'document.body', + + + + + + + + + + + + +
Created with Raphaël 2.2.0
Terms of Use

Terms of Use

THIS AGREEMENT IS SUBJECT TO BINDING ARBITRATION AND A WAIVER OF CLASS ACTION RIGHTS AS DETAILED IN SECTION 13. PLEASE READ THE AGREEMENT CAREFULLY.

Our Terms of Use have been updated as of September 5, 2016

1. Acceptance of Terms

MetaMask 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 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.

2. Modification of Terms of Use

Except 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.

3. Eligibility

You 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.

MetaMask 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.

4 Account Password and Security

When 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.

5. Representations, Warranties, and Risks

5.1. Warranty Disclaimer

You 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.

5.2 Sophistication and Risk of Cryptographic Systems

By 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.

5.3 Risk of Regulatory Actions in One or More Jurisdictions

MetaMask 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.

5.4 Risk of Weaknesses or Exploits in the Field of Cryptography

You 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.

5.5 Volatility of Crypto Currencies

You 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.

5.6 Application Security

You 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.

6. Indemnity

You 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.

7. Limitation on liability

YOU 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.

SOME 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.

8. Our Proprietary Rights

All 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. For information on other licenses utilized in the development of MetaMask, please see our attribution page at: https://metamask.io/attributions.html

9. Links

The 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.

10. Termination and Suspension

MetaMask 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.

The 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.

11. No Third Party Beneficiaries

You agree that, except as otherwise expressly provided in these Terms, there shall be no third party beneficiaries to the Terms.

12. Notice and Procedure For Making Claims of Copyright Infringement

If 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:

· an electronic or physical signature of the person authorized to act on behalf of the owner of the copyright or other intellectual property interest;

· a description of the copyrighted work or other intellectual property that you claim has been infringed;

· a description of where the material that you claim is infringing is located on the Service;

· your address, telephone number, and email address;

· 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;

· 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.

MetaMask’s Copyright Agent can be reached at:

Email: copyright at metamask dot io

Mail:

Attention:

MetaMask Copyright ℅ ConsenSys

49 Bogart Street

Brooklyn, NY 11206

13. Binding Arbitration and Class Action Waiver

PLEASE READ THIS SECTION CAREFULLY – IT MAY SIGNIFICANTLY AFFECT YOUR LEGAL RIGHTS, INCLUDING YOUR RIGHT TO FILE A LAWSUIT IN COURT

13.1 Initial Dispute Resolution

The 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.

13.2 Binding Arbitration

If 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.

The 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.

The 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.

13.3 Location

Binding 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.

13.4 Class Action Waiver

The 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.

13.5 Exception - Litigation of Intellectual Property and Small Claims Court Claims

Notwithstanding 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.

13.6 30-Day Right to Opt Out

You 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.

13.7 Changes to This Section

MetaMask 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.

For 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.

The 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.

14. General Information

14.1 Entire Agreement

These 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.

14.2 Waiver and Severability of Terms

The 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.

14.3 Statute of Limitations

You 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.

14.4 Section Titles

The section titles in the Terms are for convenience only and have no legal or contractual effect.

14.5 Communications

Users 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.

15 Related Links

Terms of Use

Privacy

Attributions

+Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got UPDATE_METAMASK_STATE' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'Main ui render function' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'rendering primary' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'UPDATE_METAMASK_STATE', value: Object{isInitialized: true, provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', unapprovedTxs: Object{}, selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, isUnlocked: true, keyringTypes: [..., ...], keyrings: [...], identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, computedBalances: Object{}, frequentRpcList: [], currentAccountTab: 'history', tokens: [], useBlockie: false, featureFlags: Object{betaUI: ...}, selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', addressBook: [], currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, noActiveNotices: false, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'document.body', + + + + + + + + + + + + +
Created with Raphaël 2.2.0
Terms of Use

Terms of Use

THIS AGREEMENT IS SUBJECT TO BINDING ARBITRATION AND A WAIVER OF CLASS ACTION RIGHTS AS DETAILED IN SECTION 13. PLEASE READ THE AGREEMENT CAREFULLY.

Our Terms of Use have been updated as of September 5, 2016

1. Acceptance of Terms

MetaMask 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 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.

2. Modification of Terms of Use

Except 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.

3. Eligibility

You 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.

MetaMask 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.

4 Account Password and Security

When 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.

5. Representations, Warranties, and Risks

5.1. Warranty Disclaimer

You 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.

5.2 Sophistication and Risk of Cryptographic Systems

By 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.

5.3 Risk of Regulatory Actions in One or More Jurisdictions

MetaMask 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.

5.4 Risk of Weaknesses or Exploits in the Field of Cryptography

You 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.

5.5 Volatility of Crypto Currencies

You 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.

5.6 Application Security

You 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.

6. Indemnity

You 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.

7. Limitation on liability

YOU 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.

SOME 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.

8. Our Proprietary Rights

All 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. For information on other licenses utilized in the development of MetaMask, please see our attribution page at: https://metamask.io/attributions.html

9. Links

The 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.

10. Termination and Suspension

MetaMask 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.

The 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.

11. No Third Party Beneficiaries

You agree that, except as otherwise expressly provided in these Terms, there shall be no third party beneficiaries to the Terms.

12. Notice and Procedure For Making Claims of Copyright Infringement

If 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:

· an electronic or physical signature of the person authorized to act on behalf of the owner of the copyright or other intellectual property interest;

· a description of the copyrighted work or other intellectual property that you claim has been infringed;

· a description of where the material that you claim is infringing is located on the Service;

· your address, telephone number, and email address;

· 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;

· 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.

MetaMask’s Copyright Agent can be reached at:

Email: copyright at metamask dot io

Mail:

Attention:

MetaMask Copyright ℅ ConsenSys

49 Bogart Street

Brooklyn, NY 11206

13. Binding Arbitration and Class Action Waiver

PLEASE READ THIS SECTION CAREFULLY – IT MAY SIGNIFICANTLY AFFECT YOUR LEGAL RIGHTS, INCLUDING YOUR RIGHT TO FILE A LAWSUIT IN COURT

13.1 Initial Dispute Resolution

The 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.

13.2 Binding Arbitration

If 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.

The 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.

The 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.

13.3 Location

Binding 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.

13.4 Class Action Waiver

The 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.

13.5 Exception - Litigation of Intellectual Property and Small Claims Court Claims

Notwithstanding 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.

13.6 30-Day Right to Opt Out

You 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.

13.7 Changes to This Section

MetaMask 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.

For 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.

The 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.

14. General Information

14.1 Entire Agreement

These 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.

14.2 Waiver and Severability of Terms

The 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.

14.3 Statute of Limitations

You 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.

14.4 Section Titles

The section titles in the Terms are for convenience only and have no legal or contractual effect.

14.5 Communications

Users 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.

15 Related Links

Terms of Use

Privacy

Attributions

+Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got SHOW_LOADING_INDICATION' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'SHOW_LOADING_INDICATION', value: undefined} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'background.markNoticeRead' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got SET_MOUSE_USER_STATE' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'SET_MOUSE_USER_STATE', value: true} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'Main ui render function' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'rendering primary' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: true, seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert', noActiveNotices: false, address: '0x77abfc38dea988c2f9602daa758867918b877f3a', forgottenPassword: undefined, isLoading: true, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.state*************************', Object{screenType: 'notice'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************isLoading*************************', true +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got HIDE_LOADING_INDICATION' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'Main ui render function' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'rendering primary' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: true, seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert', noActiveNotices: false, address: '0x77abfc38dea988c2f9602daa758867918b877f3a', forgottenPassword: undefined, isLoading: false, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.state*************************', Object{screenType: 'notice'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************isLoading*************************', false +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '**************************************************************************' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'HIDE_LOADING_INDICATION'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got CLEAR_NOTICES' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'Main ui render function' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'rendering primary' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: true, seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert', noActiveNotices: true, address: '0x77abfc38dea988c2f9602daa758867918b877f3a', forgottenPassword: undefined, isLoading: false, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.state*************************', Object{screenType: 'notice'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************isLoading*************************', false +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '**************************************************************************' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'CLEAR_NOTICES'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: true, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +ERROR: 'Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the NoticeScreen component.' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: true, seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert', noActiveNotices: true, address: '0x77abfc38dea988c2f9602daa758867918b877f3a', forgottenPassword: undefined, isLoading: false, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************this.state*************************', Object{screenType: 'back_up_phrase'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '*************************isLoading*************************', false +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '**************************************************************************' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'App Reducer got UPDATE_METAMASK_STATE' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx-helper called with params:' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unapproved txs' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned personal messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'tx helper found 0 unsigned typed messages' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'Main ui render function' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'rendering primary' +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: true, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'UPDATE_METAMASK_STATE', value: Object{isInitialized: true, provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', unapprovedTxs: Object{}, selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, isUnlocked: true, keyringTypes: [..., ...], keyrings: [...], identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, computedBalances: Object{}, frequentRpcList: [], currentAccountTab: 'history', tokens: [], useBlockie: false, featureFlags: Object{betaUI: ...}, selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', addressBook: [], currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, noActiveNotices: true, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: true, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +LOG: 'document.body', + + + + + + + + + + + + +
Created with Raphaël 2.2.0
Secret Backup Phrase
Your secret backup phrase makes it easy to back up and restore your account.
WARNING: Never disclose your backup phrase. Anyone with this phrase can take your Ether forever.
seven lobster found cream soccer country indicate history track yellow chat desert
Tips:
Store this phrase in a password manager like 1password.
Write this phrase on a piece of paper and store in a secure location. If you want even more security, write it down on multiple pieces of paper and store each in 2 - 3 different locations.
Memorize this phrase.
+Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) +Chrome 64.0.3282 (Mac OS X 10.12.6) ERROR + Uncaught TypeError: Cannot read property 'scrollTop' of null + at dist/mascara/ui.js:2311 +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 ERROR (0 secs / 0 secs) +Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 ERROR (16.275 secs / 0 secs) From 6740be109be1b545e1efa327901c6ac4a46b8bf0 Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 20 Feb 2018 16:17:30 -0330 Subject: [PATCH 058/392] Temporarily disable loading indicator. --- mascara/src/app/first-time/index.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mascara/src/app/first-time/index.js b/mascara/src/app/first-time/index.js index a05e0aa96..46b821c8b 100644 --- a/mascara/src/app/first-time/index.js +++ b/mascara/src/app/first-time/index.js @@ -89,9 +89,10 @@ class FirstTimeFlow extends Component { leaveImportSeedScreenState, } = this.props - if (isLoading) { - return () - } + // Disable until testing bug resolved + // if (isLoading) { + // return () + // } switch (this.state.screenType) { case SCREEN_TYPE.CREATE_PASSWORD: From a1b72e5252e15113c98180194cfa7f1640bde08e Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 20 Feb 2018 13:51:06 -0800 Subject: [PATCH 059/392] Try fixing notice screen synchronous state call --- ui/app/components/notice.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ui/app/components/notice.js b/ui/app/components/notice.js index 941ac33e6..9d2e89cb0 100644 --- a/ui/app/components/notice.js +++ b/ui/app/components/notice.js @@ -105,8 +105,7 @@ Notice.prototype.render = function () { h('button.primary', { disabled, onClick: () => { - this.setState({disclaimerDisabled: true}) - onConfirm() + this.setState({disclaimerDisabled: true}, () => onConfirm()) }, style: { marginTop: '18px', From 16f9ddc72c4a1c49402ea3b883a0e580c19f0651 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 20 Feb 2018 15:44:04 -0800 Subject: [PATCH 060/392] Add 8MM gas limit default to send screen --- old-ui/app/components/pending-tx.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/old-ui/app/components/pending-tx.js b/old-ui/app/components/pending-tx.js index 10208b5ce..720df2243 100644 --- a/old-ui/app/components/pending-tx.js +++ b/old-ui/app/components/pending-tx.js @@ -60,7 +60,8 @@ PendingTx.prototype.render = function () { // Gas const gas = txParams.gas const gasBn = hexToBn(gas) - const gasLimit = new BN(parseInt(blockGasLimit)) + // default to 8MM gas limit + const gasLimit = new BN(parseInt(blockGasLimit) || '8000000') const safeGasLimitBN = this.bnMultiplyByFraction(gasLimit, 19, 20) const saferGasLimitBN = this.bnMultiplyByFraction(gasLimit, 18, 20) const safeGasLimit = safeGasLimitBN.toString(10) From 98d3fba3efaedb65ee0cf60b4cc3f954a1fd9740 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 20 Feb 2018 15:45:48 -0800 Subject: [PATCH 061/392] Fix promise construction --- app/scripts/lib/nonce-tracker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/lib/nonce-tracker.js b/app/scripts/lib/nonce-tracker.js index 0029ac953..ed9dd3f11 100644 --- a/app/scripts/lib/nonce-tracker.js +++ b/app/scripts/lib/nonce-tracker.js @@ -56,7 +56,7 @@ class NonceTracker { const blockTracker = this._getBlockTracker() const currentBlock = blockTracker.getCurrentBlock() if (currentBlock) return currentBlock - return await Promise((reject, resolve) => { + return await new Promise((reject, resolve) => { blockTracker.once('latest', resolve) }) } From 66f55f954e9f3868396e478fd79c4bbd8f8673e5 Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 20 Feb 2018 20:51:45 -0330 Subject: [PATCH 062/392] Render loading inside notice screen, and don't set isLoading from unMarkPasswordForgotten. --- mascara/src/app/first-time/index.js | 11 ------ mascara/src/app/first-time/notice-screen.js | 44 +++++++++++---------- ui/app/actions.js | 1 - 3 files changed, 24 insertions(+), 32 deletions(-) diff --git a/mascara/src/app/first-time/index.js b/mascara/src/app/first-time/index.js index 46b821c8b..da2f6bab9 100644 --- a/mascara/src/app/first-time/index.js +++ b/mascara/src/app/first-time/index.js @@ -7,7 +7,6 @@ import NoticeScreen from './notice-screen' import BackupPhraseScreen from './backup-phrase-screen' import ImportAccountScreen from './import-account-screen' import ImportSeedPhraseScreen from './import-seed-phrase-screen' -const Loading = require('../../../../ui/app/components/loading') import { onboardingBuyEthView, unMarkPasswordForgotten, @@ -85,15 +84,9 @@ class FirstTimeFlow extends Component { address, restoreCreatePasswordScreen, forgottenPassword, - isLoading, leaveImportSeedScreenState, } = this.props - // Disable until testing bug resolved - // if (isLoading) { - // return () - // } - switch (this.state.screenType) { case SCREEN_TYPE.CREATE_PASSWORD: return ( @@ -164,9 +157,6 @@ export default connect( noActiveNotices, selectedAddress, forgottenPassword, - }, - appState: { - isLoading, } }) => ({ isInitialized, @@ -174,7 +164,6 @@ export default connect( noActiveNotices, address: selectedAddress, forgottenPassword, - isLoading, }), dispatch => ({ leaveImportSeedScreenState: () => dispatch(unMarkPasswordForgotten()), diff --git a/mascara/src/app/first-time/notice-screen.js b/mascara/src/app/first-time/notice-screen.js index e691a2f47..0f0a7e95d 100644 --- a/mascara/src/app/first-time/notice-screen.js +++ b/mascara/src/app/first-time/notice-screen.js @@ -6,6 +6,7 @@ import debounce from 'lodash.debounce' import {markNoticeRead} from '../../../../ui/app/actions' import Identicon from '../../../../ui/app/components/identicon' import Breadcrumbs from './breadcrumbs' +import LoadingScreen from './loading-screen' class NoticeScreen extends Component { static propTypes = { @@ -55,36 +56,39 @@ class NoticeScreen extends Component { const { address, lastUnreadNotice: { title, body }, + isLoading, } = this.props const { atBottom } = this.state return ( -
- -
{title}
- - - -
+ +
{title}
+ + + + ) } } export default connect( - ({ metamask: { selectedAddress, lastUnreadNotice } }) => ({ + ({ metamask: { selectedAddress, lastUnreadNotice }, appState: { isLoading } }) => ({ lastUnreadNotice, address: selectedAddress, }), diff --git a/ui/app/actions.js b/ui/app/actions.js index 4bc1f379e..64d5b67e0 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -853,7 +853,6 @@ function markPasswordForgotten () { function unMarkPasswordForgotten () { return (dispatch) => { return background.unMarkPasswordForgotten(() => { - dispatch(actions.hideLoadingIndication()) dispatch(actions.forgotPassword()) forceUpdateMetamaskState(dispatch) }) From b1b97727313eaa3a375541e85f43b5f2253ad6de Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 20 Feb 2018 21:34:55 -0330 Subject: [PATCH 063/392] Fix old-ui active notices width. --- old-ui/app/app.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/old-ui/app/app.js b/old-ui/app/app.js index 61f6223bc..c79ac633a 100644 --- a/old-ui/app/app.js +++ b/old-ui/app/app.js @@ -456,7 +456,9 @@ App.prototype.renderPrimary = function () { // notices if (!props.noActiveNotices) { log.debug('rendering notice screen for unread notices.') - return h('div', [ + return h('div', { + style: { width: '100%' }, + }, [ h(NoticeScreen, { notice: props.lastUnreadNotice, From 84c023ba40b11ace63e2f2281a7c0ef1e1f2f3cb Mon Sep 17 00:00:00 2001 From: Thomas Huang Date: Tue, 20 Feb 2018 19:52:32 -0800 Subject: [PATCH 064/392] Use same logic for downloading state logs in the old/uat --- ui/app/settings.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ui/app/settings.js b/ui/app/settings.js index 988ddea8d..466f739d5 100644 --- a/ui/app/settings.js +++ b/ui/app/settings.js @@ -201,7 +201,13 @@ class Settings extends Component { h('div.settings__content-item-col', [ h('button.settings__clear-button', { onClick (event) { - exportAsFile('MetaMask State Logs', window.logState()) + window.logStateString((err, result) => { + if (err) { + this.state.dispatch(actions.displayWarning('Error in retrieving state logs.')) + } else { + exportAsFile('MetaMask State Logs.json', result) + } + }) }, }, 'Download State Logs'), ]), From c26c57fad774e21fcb0b817227e9d0d99418f8a0 Mon Sep 17 00:00:00 2001 From: Thomas Huang Date: Tue, 20 Feb 2018 20:09:32 -0800 Subject: [PATCH 065/392] Remove output file --- output | 1889 -------------------------------------------------------- 1 file changed, 1889 deletions(-) delete mode 100644 output diff --git a/output b/output deleted file mode 100644 index dfb259888..000000000 --- a/output +++ /dev/null @@ -1,1889 +0,0 @@ - -> metamask-crx@0.0.0 test:mascara /Users/danmiller/kyokan/metamask/metamask-extension -> npm run test:mascara:build && karma start test/mascara.conf.js - - -> metamask-crx@0.0.0 test:mascara:build /Users/danmiller/kyokan/metamask/metamask-extension -> mkdir -p dist/mascara && npm run test:mascara:build:ui && npm run test:mascara:build:background && npm run test:mascara:build:tests - - -> metamask-crx@0.0.0 test:mascara:build:ui /Users/danmiller/kyokan/metamask/metamask-extension -> browserify mascara/test/test-ui.js -o dist/mascara/ui.js - - -> metamask-crx@0.0.0 test:mascara:build:background /Users/danmiller/kyokan/metamask/metamask-extension -> browserify mascara/src/background.js -o dist/mascara/background.js - - -> metamask-crx@0.0.0 test:mascara:build:tests /Users/danmiller/kyokan/metamask/metamask-extension -> browserify test/integration/lib/first-time.js -o dist/mascara/tests.js - -20 02 2018 15:29:25.773:INFO [karma]: Karma v1.7.1 server started at http://0.0.0.0:9876/ -20 02 2018 15:29:25.776:INFO [launcher]: Launching browser Chrome with concurrency 1 -20 02 2018 15:29:25.822:INFO [launcher]: Starting browser Chrome -20 02 2018 15:29:31.117:INFO [Chrome 64.0.3282 (Mac OS X 10.12.6)]: Connected on socket xl57FfHdT0vJ5kbQAAAA with id 3100832 -Chrome 64.0.3282 (Mac OS X 10.12.6) WARN: 'Warning: Accessing PropTypes via the main React package is deprecated, and will be removed in React v16.0. Use the latest available v15.* prop-types package from npm instead. For info on usage, compatibility, migration and more, see https://fb.me/prop-types-docs' - -Chrome 64.0.3282 (Mac OS X 10.12.6) WARN: 'Warning: Accessing createClass via the main React package is deprecated, and will be removed in React v16.0. Use a plain JavaScript class instead. If you're not yet ready to migrate, create-react-class v15.* is available on npm as a temporary, drop-in replacement. For more info see https://fb.me/react-create-class' - - -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got @@redux/INIT' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'background.setNetworkEndpoints' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'Main ui render function' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'rendering primary' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: false, seedWords: '', noActiveNotices: false, address: undefined, forgottenPassword: undefined, isLoading: false, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.state*************************', Object{screenType: 'create_password'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************isLoading*************************', false -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '**************************************************************************' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'hello from MetaMascara ui!' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'hello from cb ready event!' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got UPDATE_NETWORK_ENDPOINT_TYPE' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: false}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'UPDATE_NETWORK_ENDPOINT_TYPE', value: 'network'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: false}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'No more notices...' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got UPDATE_METAMASK_STATE' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'Main ui render function' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'rendering primary' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: false}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'UPDATE_METAMASK_STATE', value: Object{isInitialized: false, provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', unapprovedTxs: Object{}, selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, isUnlocked: false, keyringTypes: [..., ...], keyrings: [], identities: Object{}, computedBalances: Object{}, frequentRpcList: [], currentAccountTab: 'history', tokens: [], useBlockie: false, featureFlags: Object{}, addressBook: [], currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, noActiveNotices: false, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: false}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got UPDATE_METAMASK_STATE' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'Main ui render function' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'rendering primary' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: false}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'UPDATE_METAMASK_STATE', value: Object{isInitialized: false, provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', unapprovedTxs: Object{}, selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, isUnlocked: false, keyringTypes: [..., ...], keyrings: [], identities: Object{}, computedBalances: Object{}, frequentRpcList: [], currentAccountTab: 'history', tokens: [], useBlockie: false, featureFlags: Object{}, addressBook: [], currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, noActiveNotices: false, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: false}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got UPDATE_METAMASK_STATE' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'Main ui render function' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'rendering primary' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: false}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'UPDATE_METAMASK_STATE', value: Object{isInitialized: false, provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', unapprovedTxs: Object{}, selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, isUnlocked: false, keyringTypes: [..., ...], keyrings: [], identities: Object{}, computedBalances: Object{}, frequentRpcList: [], currentAccountTab: 'history', tokens: [], useBlockie: false, featureFlags: Object{}, addressBook: [], currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, noActiveNotices: false, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: false}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got UPDATE_METAMASK_STATE' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'Main ui render function' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'rendering primary' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: false}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'UPDATE_METAMASK_STATE', value: Object{isInitialized: false, provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', unapprovedTxs: Object{}, selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, isUnlocked: false, keyringTypes: [..., ...], keyrings: [], identities: Object{}, computedBalances: Object{}, frequentRpcList: [], currentAccountTab: 'history', tokens: [], useBlockie: false, featureFlags: Object{}, addressBook: [], currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, noActiveNotices: false, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: false}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got UPDATE_METAMASK_STATE' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'Main ui render function' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'rendering primary' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: false}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'UPDATE_METAMASK_STATE', value: Object{isInitialized: false, provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', unapprovedTxs: Object{}, selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, isUnlocked: false, keyringTypes: [..., ...], keyrings: [], identities: Object{}, computedBalances: Object{}, frequentRpcList: [], currentAccountTab: 'history', tokens: [], useBlockie: false, featureFlags: Object{}, addressBook: [], currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, noActiveNotices: false, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: false}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got SHOW_LOADING_INDICATION' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: false}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'SHOW_LOADING_INDICATION', value: undefined} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: false, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'background.createNewVaultAndKeychain' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got SET_MOUSE_USER_STATE' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: false, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'SET_MOUSE_USER_STATE', value: true} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'Main ui render function' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'rendering primary' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: false, seedWords: '', noActiveNotices: false, address: undefined, forgottenPassword: undefined, isLoading: true, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.state*************************', Object{screenType: 'create_password'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************isLoading*************************', true -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'background.placeSeedWords' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got HIDE_LOADING_INDICATION' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'Main ui render function' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'rendering primary' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: false, seedWords: '', noActiveNotices: false, address: undefined, forgottenPassword: undefined, isLoading: false, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.state*************************', Object{screenType: 'create_password'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************isLoading*************************', false -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '**************************************************************************' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'HIDE_LOADING_INDICATION'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'background.getState' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: false, seedWords: '', noActiveNotices: false, address: undefined, forgottenPassword: undefined, isLoading: false, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.state*************************', Object{screenType: 'unique_image'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************isLoading*************************', false -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '**************************************************************************' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got UPDATE_METAMASK_STATE' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got SHOW_LOADING_INDICATION' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: false, isUnlocked: false, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: []}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'UPDATE_METAMASK_STATE', value: Object{isInitialized: true, provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', unapprovedTxs: Object{}, selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, isUnlocked: true, keyringTypes: [..., ...], keyrings: [...], identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, computedBalances: Object{}, frequentRpcList: [], currentAccountTab: 'history', tokens: [], useBlockie: false, featureFlags: Object{}, selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', addressBook: [], currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, noActiveNotices: false, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'SHOW_LOADING_INDICATION', value: undefined} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'Main ui render function' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'rendering primary' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: true, seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert', noActiveNotices: false, address: '0x77abfc38dea988c2f9602daa758867918b877f3a', forgottenPassword: undefined, isLoading: true, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.state*************************', Object{screenType: 'unique_image'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************isLoading*************************', true -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got HIDE_LOADING_INDICATION' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'Main ui render function' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'rendering primary' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: true, seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert', noActiveNotices: false, address: '0x77abfc38dea988c2f9602daa758867918b877f3a', forgottenPassword: undefined, isLoading: false, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.state*************************', Object{screenType: 'unique_image'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************isLoading*************************', false -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '**************************************************************************' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'HIDE_LOADING_INDICATION'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got UPDATE_FEATURE_FLAGS' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got SHOW_LOADING_INDICATION' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'UPDATE_FEATURE_FLAGS', value: Object{betaUI: true}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'SHOW_LOADING_INDICATION', value: undefined} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'Main ui render function' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'rendering primary' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: true, seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert', noActiveNotices: false, address: '0x77abfc38dea988c2f9602daa758867918b877f3a', forgottenPassword: undefined, isLoading: true, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.state*************************', Object{screenType: 'unique_image'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************isLoading*************************', true -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'background.setNetworkEndpoints' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got HIDE_LOADING_INDICATION' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'Main ui render function' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'rendering primary' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: true, seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert', noActiveNotices: false, address: '0x77abfc38dea988c2f9602daa758867918b877f3a', forgottenPassword: undefined, isLoading: false, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.state*************************', Object{screenType: 'unique_image'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************isLoading*************************', false -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '**************************************************************************' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'HIDE_LOADING_INDICATION'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got UPDATE_FEATURE_FLAGS' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'UPDATE_FEATURE_FLAGS', value: Object{betaUI: true}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'background.setNetworkEndpoints' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got UPDATE_NETWORK_ENDPOINT_TYPE' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'network', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'UPDATE_NETWORK_ENDPOINT_TYPE', value: 'networkBeta'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got UPDATE_NETWORK_ENDPOINT_TYPE' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'UPDATE_NETWORK_ENDPOINT_TYPE', value: 'networkBeta'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got SET_MOUSE_USER_STATE' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'SET_MOUSE_USER_STATE', value: true} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: true, seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert', noActiveNotices: false, address: '0x77abfc38dea988c2f9602daa758867918b877f3a', forgottenPassword: undefined, isLoading: false, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.state*************************', Object{screenType: 'notice'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************isLoading*************************', false -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '**************************************************************************' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'document.body', - - - - - - - - - - - - -
Created with Raphaël 2.2.0
Privacy Notice

MetaMask is beta software.

When you log in to MetaMask, your current account is visible to every new site you visit.

For your privacy, for now, please sign out of MetaMask when you're done using a site.

-Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got UPDATE_METAMASK_STATE' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'Main ui render function' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'rendering primary' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'UPDATE_METAMASK_STATE', value: Object{isInitialized: true, provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', unapprovedTxs: Object{}, selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, isUnlocked: true, keyringTypes: [..., ...], keyrings: [...], identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, computedBalances: Object{}, frequentRpcList: [], currentAccountTab: 'history', tokens: [], useBlockie: false, featureFlags: Object{betaUI: ...}, selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', addressBook: [], currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, noActiveNotices: false, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got SHOW_LOADING_INDICATION' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'SHOW_LOADING_INDICATION', value: undefined} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'background.markNoticeRead' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got SET_MOUSE_USER_STATE' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'SET_MOUSE_USER_STATE', value: true} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'Main ui render function' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'rendering primary' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: true, seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert', noActiveNotices: false, address: '0x77abfc38dea988c2f9602daa758867918b877f3a', forgottenPassword: undefined, isLoading: true, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.state*************************', Object{screenType: 'notice'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************isLoading*************************', true -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got HIDE_LOADING_INDICATION' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'Main ui render function' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'rendering primary' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: true, seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert', noActiveNotices: false, address: '0x77abfc38dea988c2f9602daa758867918b877f3a', forgottenPassword: undefined, isLoading: false, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.state*************************', Object{screenType: 'notice'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************isLoading*************************', false -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '**************************************************************************' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'HIDE_LOADING_INDICATION'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got SHOW_NOTICE' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'Main ui render function' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'rendering primary' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'SHOW_NOTICE', value: Object{read: false, date: 'Thu Feb 09 2017', title: 'Terms of Use', body: '# Terms of Use # - -**THIS AGREEMENT IS SUBJECT TO BINDING ARBITRATION AND A WAIVER OF CLASS ACTION RIGHTS AS DETAILED IN SECTION 13. PLEASE READ THE AGREEMENT CAREFULLY.** - -_Our Terms of Use have been updated as of September 5, 2016_ - -## 1. Acceptance of Terms ## - -MetaMask 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. - -## 2. Modification of Terms of Use ## - -Except 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. - - - -## 3. Eligibility ## - -You 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. - -MetaMask 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. - -## 4 Account Password and Security ## - -When 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. - -## 5. Representations, Warranties, and Risks ## - -### 5.1. Warranty Disclaimer ### - -You 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. - -### 5.2 Sophistication and Risk of Cryptographic Systems ### - -By 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. - -### 5.3 Risk of Regulatory Actions in One or More Jurisdictions ### - -MetaMask 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. - -### 5.4 Risk of Weaknesses or Exploits in the Field of Cryptography ### - -You 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. - -### 5.5 Volatility of Crypto Currencies ### - -You 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. - -### 5.6 Application Security ### - -You 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. - -## 6. Indemnity ## - -You 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. - -## 7. Limitation on liability ## - -YOU 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. - -SOME 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. - -## 8. Our Proprietary Rights ## - -All 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) - -## 9. Links ## - -The 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. - -## 10. Termination and Suspension ## - -MetaMask 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. - -The 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. - -## 11. No Third Party Beneficiaries ## - -You agree that, except as otherwise expressly provided in these Terms, there shall be no third party beneficiaries to the Terms. - -## 12. Notice and Procedure For Making Claims of Copyright Infringement ## - -If 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: - -· an electronic or physical signature of the person authorized to act on behalf of the owner of the copyright or other intellectual property interest; - -· a description of the copyrighted work or other intellectual property that you claim has been infringed; - -· a description of where the material that you claim is infringing is located on the Service; - -· your address, telephone number, and email address; - -· 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; - -· 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. - -MetaMask’s Copyright Agent can be reached at: - -Email: copyright [at] metamask [dot] io - -Mail: - -Attention: - -MetaMask Copyright ℅ ConsenSys - -49 Bogart Street - -Brooklyn, NY 11206 - -## 13. Binding Arbitration and Class Action Waiver ## - -PLEASE READ THIS SECTION CAREFULLY – IT MAY SIGNIFICANTLY AFFECT YOUR LEGAL RIGHTS, INCLUDING YOUR RIGHT TO FILE A LAWSUIT IN COURT - -### 13.1 Initial Dispute Resolution ### - -The 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. - -### 13.2 Binding Arbitration ### - -If 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. - -The 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. - -The 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. - -### 13.3 Location ### - -Binding 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. - -### 13.4 Class Action Waiver ### - -The 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. - -### 13.5 Exception - Litigation of Intellectual Property and Small Claims Court Claims ### - -Notwithstanding 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. - -### 13.6 30-Day Right to Opt Out ### - -You 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. - -### 13.7 Changes to This Section ### - -MetaMask 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. - -For 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. - -The 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. - -## 14. General Information ## - -### 14.1 Entire Agreement ### - -These 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. - -### 14.2 Waiver and Severability of Terms ### - -The 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. - -### 14.3 Statute of Limitations ### - -You 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. - -### 14.4 Section Titles ### - -The section titles in the Terms are for convenience only and have no legal or contractual effect. - -### 14.5 Communications ### - -Users 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. - -## 15 Related Links ## - -**[Terms of Use](https://metamask.io/terms.html)** - -**[Privacy](https://metamask.io/privacy.html)** - -**[Attributions](https://metamask.io/attributions.html)** - -', id: 0}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -ERROR: 'Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the NoticeScreen component.' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'document.body', - - - - - - - - - - - - -
Created with Raphaël 2.2.0
Terms of Use

Terms of Use

THIS AGREEMENT IS SUBJECT TO BINDING ARBITRATION AND A WAIVER OF CLASS ACTION RIGHTS AS DETAILED IN SECTION 13. PLEASE READ THE AGREEMENT CAREFULLY.

Our Terms of Use have been updated as of September 5, 2016

1. Acceptance of Terms

MetaMask 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 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.

2. Modification of Terms of Use

Except 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.

3. Eligibility

You 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.

MetaMask 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.

4 Account Password and Security

When 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.

5. Representations, Warranties, and Risks

5.1. Warranty Disclaimer

You 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.

5.2 Sophistication and Risk of Cryptographic Systems

By 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.

5.3 Risk of Regulatory Actions in One or More Jurisdictions

MetaMask 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.

5.4 Risk of Weaknesses or Exploits in the Field of Cryptography

You 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.

5.5 Volatility of Crypto Currencies

You 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.

5.6 Application Security

You 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.

6. Indemnity

You 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.

7. Limitation on liability

YOU 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.

SOME 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.

8. Our Proprietary Rights

All 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. For information on other licenses utilized in the development of MetaMask, please see our attribution page at: https://metamask.io/attributions.html

9. Links

The 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.

10. Termination and Suspension

MetaMask 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.

The 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.

11. No Third Party Beneficiaries

You agree that, except as otherwise expressly provided in these Terms, there shall be no third party beneficiaries to the Terms.

12. Notice and Procedure For Making Claims of Copyright Infringement

If 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:

· an electronic or physical signature of the person authorized to act on behalf of the owner of the copyright or other intellectual property interest;

· a description of the copyrighted work or other intellectual property that you claim has been infringed;

· a description of where the material that you claim is infringing is located on the Service;

· your address, telephone number, and email address;

· 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;

· 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.

MetaMask’s Copyright Agent can be reached at:

Email: copyright at metamask dot io

Mail:

Attention:

MetaMask Copyright ℅ ConsenSys

49 Bogart Street

Brooklyn, NY 11206

13. Binding Arbitration and Class Action Waiver

PLEASE READ THIS SECTION CAREFULLY – IT MAY SIGNIFICANTLY AFFECT YOUR LEGAL RIGHTS, INCLUDING YOUR RIGHT TO FILE A LAWSUIT IN COURT

13.1 Initial Dispute Resolution

The 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.

13.2 Binding Arbitration

If 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.

The 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.

The 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.

13.3 Location

Binding 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.

13.4 Class Action Waiver

The 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.

13.5 Exception - Litigation of Intellectual Property and Small Claims Court Claims

Notwithstanding 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.

13.6 30-Day Right to Opt Out

You 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.

13.7 Changes to This Section

MetaMask 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.

For 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.

The 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.

14. General Information

14.1 Entire Agreement

These 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.

14.2 Waiver and Severability of Terms

The 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.

14.3 Statute of Limitations

You 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.

14.4 Section Titles

The section titles in the Terms are for convenience only and have no legal or contractual effect.

14.5 Communications

Users 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.

15 Related Links

Terms of Use

Privacy

Attributions

-Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got UPDATE_METAMASK_STATE' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'Main ui render function' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'rendering primary' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'UPDATE_METAMASK_STATE', value: Object{isInitialized: true, provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', unapprovedTxs: Object{}, selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, isUnlocked: true, keyringTypes: [..., ...], keyrings: [...], identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, computedBalances: Object{}, frequentRpcList: [], currentAccountTab: 'history', tokens: [], useBlockie: false, featureFlags: Object{betaUI: ...}, selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', addressBook: [], currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, noActiveNotices: false, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'document.body', - - - - - - - - - - - - -
Created with Raphaël 2.2.0
Terms of Use

Terms of Use

THIS AGREEMENT IS SUBJECT TO BINDING ARBITRATION AND A WAIVER OF CLASS ACTION RIGHTS AS DETAILED IN SECTION 13. PLEASE READ THE AGREEMENT CAREFULLY.

Our Terms of Use have been updated as of September 5, 2016

1. Acceptance of Terms

MetaMask 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 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.

2. Modification of Terms of Use

Except 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.

3. Eligibility

You 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.

MetaMask 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.

4 Account Password and Security

When 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.

5. Representations, Warranties, and Risks

5.1. Warranty Disclaimer

You 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.

5.2 Sophistication and Risk of Cryptographic Systems

By 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.

5.3 Risk of Regulatory Actions in One or More Jurisdictions

MetaMask 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.

5.4 Risk of Weaknesses or Exploits in the Field of Cryptography

You 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.

5.5 Volatility of Crypto Currencies

You 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.

5.6 Application Security

You 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.

6. Indemnity

You 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.

7. Limitation on liability

YOU 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.

SOME 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.

8. Our Proprietary Rights

All 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. For information on other licenses utilized in the development of MetaMask, please see our attribution page at: https://metamask.io/attributions.html

9. Links

The 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.

10. Termination and Suspension

MetaMask 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.

The 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.

11. No Third Party Beneficiaries

You agree that, except as otherwise expressly provided in these Terms, there shall be no third party beneficiaries to the Terms.

12. Notice and Procedure For Making Claims of Copyright Infringement

If 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:

· an electronic or physical signature of the person authorized to act on behalf of the owner of the copyright or other intellectual property interest;

· a description of the copyrighted work or other intellectual property that you claim has been infringed;

· a description of where the material that you claim is infringing is located on the Service;

· your address, telephone number, and email address;

· 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;

· 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.

MetaMask’s Copyright Agent can be reached at:

Email: copyright at metamask dot io

Mail:

Attention:

MetaMask Copyright ℅ ConsenSys

49 Bogart Street

Brooklyn, NY 11206

13. Binding Arbitration and Class Action Waiver

PLEASE READ THIS SECTION CAREFULLY – IT MAY SIGNIFICANTLY AFFECT YOUR LEGAL RIGHTS, INCLUDING YOUR RIGHT TO FILE A LAWSUIT IN COURT

13.1 Initial Dispute Resolution

The 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.

13.2 Binding Arbitration

If 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.

The 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.

The 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.

13.3 Location

Binding 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.

13.4 Class Action Waiver

The 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.

13.5 Exception - Litigation of Intellectual Property and Small Claims Court Claims

Notwithstanding 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.

13.6 30-Day Right to Opt Out

You 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.

13.7 Changes to This Section

MetaMask 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.

For 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.

The 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.

14. General Information

14.1 Entire Agreement

These 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.

14.2 Waiver and Severability of Terms

The 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.

14.3 Statute of Limitations

You 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.

14.4 Section Titles

The section titles in the Terms are for convenience only and have no legal or contractual effect.

14.5 Communications

Users 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.

15 Related Links

Terms of Use

Privacy

Attributions

-Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got SHOW_LOADING_INDICATION' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'SHOW_LOADING_INDICATION', value: undefined} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'background.markNoticeRead' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got SET_MOUSE_USER_STATE' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'SET_MOUSE_USER_STATE', value: true} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'Main ui render function' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'rendering primary' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: true, seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert', noActiveNotices: false, address: '0x77abfc38dea988c2f9602daa758867918b877f3a', forgottenPassword: undefined, isLoading: true, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.state*************************', Object{screenType: 'notice'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************isLoading*************************', true -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got HIDE_LOADING_INDICATION' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'Main ui render function' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'rendering primary' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: true, seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert', noActiveNotices: false, address: '0x77abfc38dea988c2f9602daa758867918b877f3a', forgottenPassword: undefined, isLoading: false, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.state*************************', Object{screenType: 'notice'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************isLoading*************************', false -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '**************************************************************************' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: true, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'HIDE_LOADING_INDICATION'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got CLEAR_NOTICES' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'Main ui render function' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'rendering primary' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: true, seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert', noActiveNotices: true, address: '0x77abfc38dea988c2f9602daa758867918b877f3a', forgottenPassword: undefined, isLoading: false, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.state*************************', Object{screenType: 'notice'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************isLoading*************************', false -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '**************************************************************************' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: false, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'CLEAR_NOTICES'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: true, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -ERROR: 'Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the NoticeScreen component.' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.props*************************', Object{children: undefined, isInitialized: true, seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert', noActiveNotices: true, address: '0x77abfc38dea988c2f9602daa758867918b877f3a', forgottenPassword: undefined, isLoading: false, leaveImportSeedScreenState: function leaveImportSeedScreenState() { ... }, goToBuyEtherView: function goToBuyEtherView(address) { ... }} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************this.state*************************', Object{screenType: 'back_up_phrase'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '*************************isLoading*************************', false -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '**************************************************************************' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'App Reducer got UPDATE_METAMASK_STATE' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx-helper called with params:' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: Object{unapprovedTxs: Object{}, unapprovedMsgs: Object{}, personalMsgs: Object{}, typedMessages: Object{}, network: '4'} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unapproved txs' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned personal messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'tx helper found 0 unsigned typed messages' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'Main ui render function' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'rendering primary' -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c prev state', 'color: #9E9E9E; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: true, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c action ', 'color: #03A9F4; font-weight: bold', Object{type: 'UPDATE_METAMASK_STATE', value: Object{isInitialized: true, provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', unapprovedTxs: Object{}, selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, isUnlocked: true, keyringTypes: [..., ...], keyrings: [...], identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, computedBalances: Object{}, frequentRpcList: [], currentAccountTab: 'history', tokens: [], useBlockie: false, featureFlags: Object{betaUI: ...}, selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', addressBook: [], currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, noActiveNotices: true, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: '%c next state', 'color: #4CAF50; font-weight: bold', Object{metamask: Object{isInitialized: true, isUnlocked: true, isAccountMenuOpen: false, isMascara: true, isPopup: false, rpcTarget: 'https://rawtestrpc.metamask.io/', identities: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, unapprovedTxs: Object{}, noActiveNotices: true, lastUnreadNotice: Object{read: ..., date: ..., title: ..., body: ..., id: ...}, frequentRpcList: [], addressBook: [], selectedTokenAddress: null, tokenExchangeRates: Object{}, tokens: [], send: Object{gasLimit: ..., gasPrice: ..., gasTotal: ..., tokenBalance: ..., from: ..., to: ..., amount: ..., memo: ..., errors: ..., maxModeOn: ..., editingTransactionId: ...}, coinOptions: Object{}, useBlockie: false, featureFlags: Object{betaUI: ...}, networkEndpointType: 'networkBeta', provider: Object{type: ..., rpcTarget: ...}, network: '4', accounts: Object{0x77abfc38dea988c2f9602daa758867918b877f3a: ...}, currentBlockGasLimit: '0x6c4171', selectedAddressTxList: [], unapprovedMsgs: Object{}, unapprovedMsgCount: 0, unapprovedPersonalMsgs: Object{}, unapprovedPersonalMsgCount: 0, unapprovedTypedMessages: Object{}, unapprovedTypedMessagesCount: 0, keyringTypes: [..., ...], keyrings: [...], computedBalances: Object{}, currentAccountTab: 'history', currentCurrency: 'usd', conversionRate: 923.81, conversionDate: 1519153165, infuraNetworkStatus: Object{}, recentBlocks: [..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ..., ...], shapeShiftTxList: [], lostAccounts: [], selectedAddress: '0x77abfc38dea988c2f9602daa758867918b877f3a', seedWords: 'seven lobster found cream soccer country indicate history track yellow chat desert'}, appState: Object{shouldClose: false, menuOpen: false, modal: Object{open: ..., modalState: ..., previousModalState: ...}, sidebarOpen: false, networkDropdownOpen: false, currentView: Object{name: ..., detailView: ..., context: ...}, accountDetail: Object{subview: ...}, transForward: true, isLoading: false, warning: null, buyView: Object{}, isMouseUser: true, loadingMessage: undefined}, networkVersion: undefined, identities: Object{}} -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -LOG: 'document.body', - - - - - - - - - - - - -
Created with Raphaël 2.2.0
Secret Backup Phrase
Your secret backup phrase makes it easy to back up and restore your account.
WARNING: Never disclose your backup phrase. Anyone with this phrase can take your Ether forever.
seven lobster found cream soccer country indicate history track yellow chat desert
Tips:
Store this phrase in a password manager like 1password.
Write this phrase on a piece of paper and store in a secure location. If you want even more security, write it down on multiple pieces of paper and store each in 2 - 3 different locations.
Memorize this phrase.
-Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 SUCCESS (0 secs / 0 secs) -Chrome 64.0.3282 (Mac OS X 10.12.6) ERROR - Uncaught TypeError: Cannot read property 'scrollTop' of null - at dist/mascara/ui.js:2311 -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 ERROR (0 secs / 0 secs) -Chrome 64.0.3282 (Mac OS X 10.12.6): Executed 0 of 1 ERROR (16.275 secs / 0 secs) From a4ed6af2ad9469a29e100f9246e8960b078cff46 Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 21 Feb 2018 14:54:00 -0330 Subject: [PATCH 066/392] Prevents new transaction from generating popup when metamask is open in an active tab. --- app/scripts/background.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/app/scripts/background.js b/app/scripts/background.js index 0471cee3b..816c655a1 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -30,6 +30,7 @@ const release = platform.getVersion() const raven = setupRaven({ release }) let popupIsOpen = false +let openMetamaskTabsIDs = {} // state persistence const diskStore = new LocalStorageStore({ storageKey: STORAGE_KEY }) @@ -113,9 +114,15 @@ function setupController (initState) { popupIsOpen = popupIsOpen || (remotePort.name === 'popup') controller.setupTrustedCommunication(portStream, 'MetaMask') // record popup as closed + if (remotePort.sender.url.match(/home.html$/)) { + openMetamaskTabsIDs[remotePort.sender.tab.id] = true + } if (remotePort.name === 'popup') { endOfStream(portStream, () => { popupIsOpen = false + if (remotePort.sender.url.match(/home.html$/)) { + openMetamaskTabsIDs[remotePort.sender.tab.id] = false + } }) } } else { @@ -158,7 +165,10 @@ function setupController (initState) { // popup trigger function triggerUi () { - if (!popupIsOpen) notificationManager.showPopup() + extension.tabs.query({ active: true }, (tabs) => { + const currentlyActiveMetamaskTab = tabs.find(tab => openMetamaskTabsIDs[tab.id]) + if (!popupIsOpen && !currentlyActiveMetamaskTab) notificationManager.showPopup() + }) } // On first install, open a window to MetaMask website to how-it-works. From 5ec311ba3e01bd9b0a9ff447fd7639d22a7b3d9c Mon Sep 17 00:00:00 2001 From: Csaba Solya Date: Thu, 22 Feb 2018 14:39:32 +0100 Subject: [PATCH 067/392] add edge support --- app/scripts/background.js | 8 ++++ app/scripts/edge-encryptor.js | 69 +++++++++++++++++++++++++++++++++++ package.json | 1 + 3 files changed, 78 insertions(+) create mode 100644 app/scripts/edge-encryptor.js diff --git a/app/scripts/background.js b/app/scripts/background.js index 6bf7707e8..7bececba1 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -15,6 +15,7 @@ const MetamaskController = require('./metamask-controller') const firstTimeState = require('./first-time-state') const setupRaven = require('./setupRaven') const setupMetamaskMeshMetrics = require('./lib/setupMetamaskMeshMetrics') +const EdgeEncryptor = require('./edge-encryptor') const STORAGE_KEY = 'metamask-config' const METAMASK_DEBUG = 'GULP_METAMASK_DEBUG' @@ -30,6 +31,12 @@ global.METAMASK_NOTIFIER = notificationManager const release = platform.getVersion() const raven = setupRaven({ release }) +// browser check if it is Edge - https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser +// Internet Explorer 6-11 +const isIE = !!document.documentMode +// Edge 20+ +const isEdge = !isIE && !!window.StyleMedia + let popupIsOpen = false // state persistence @@ -78,6 +85,7 @@ function setupController (initState) { initState, // platform specific api platform, + encryptor: isEdge ? new EdgeEncryptor() : undefined, }) global.metamaskController = controller diff --git a/app/scripts/edge-encryptor.js b/app/scripts/edge-encryptor.js new file mode 100644 index 000000000..9d6ac37b3 --- /dev/null +++ b/app/scripts/edge-encryptor.js @@ -0,0 +1,69 @@ +const asmcrypto = require('asmcrypto.js') +const Unibabel = require('browserify-unibabel') + +class EdgeEncryptor { + + encrypt (password, dataObject) { + + var salt = this._generateSalt() + return this.keyFromPassword(password, salt) + .then(function (key) { + + var data = JSON.stringify(dataObject) + var dataBuffer = Unibabel.utf8ToBuffer(data) + var vector = global.crypto.getRandomValues(new Uint8Array(16)) + var resultbuffer = asmcrypto.AES_GCM.encrypt(dataBuffer, key, vector) + + var buffer = new Uint8Array(resultbuffer) + var vectorStr = Unibabel.bufferToBase64(vector) + var vaultStr = Unibabel.bufferToBase64(buffer) + return JSON.stringify({ + data: vaultStr, + iv: vectorStr, + salt: salt, + }) + }) + } + + decrypt (password, text) { + + const payload = JSON.parse(text) + const salt = payload.salt + return this.keyFromPassword(password, salt) + .then(function (key) { + const encryptedData = Unibabel.base64ToBuffer(payload.data) + const vector = Unibabel.base64ToBuffer(payload.iv) + return new Promise((resolve, reject) => { + var result + try { + result = asmcrypto.AES_GCM.decrypt(encryptedData, key, vector) + } catch (err) { + return reject(new Error('Incorrect password')) + } + const decryptedData = new Uint8Array(result) + const decryptedStr = Unibabel.bufferToUtf8(decryptedData) + const decryptedObj = JSON.parse(decryptedStr) + resolve(decryptedObj) + }) + }) + } + + keyFromPassword (password, salt) { + + var passBuffer = Unibabel.utf8ToBuffer(password) + var saltBuffer = Unibabel.base64ToBuffer(salt) + return new Promise((resolve) => { + var key = asmcrypto.PBKDF2_HMAC_SHA256.bytes(passBuffer, saltBuffer, 10000) + resolve(key) + }) + } + + _generateSalt (byteCount = 32) { + var view = new Uint8Array(byteCount) + global.crypto.getRandomValues(view) + var b64encoded = btoa(String.fromCharCode.apply(null, view)) + return b64encoded + } +} + +module.exports = EdgeEncryptor diff --git a/package.json b/package.json index 74a9f15d0..c47c46004 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ ] }, "dependencies": { + "asmcrypto.js": "0.22.0", "async": "^2.5.0", "await-semaphore": "^0.1.1", "babel-runtime": "^6.23.0", From b45295499e0df87c20e1411b43d6e6ba88e9aeed Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 22 Feb 2018 14:57:24 -0800 Subject: [PATCH 068/392] Version 4.0.0 --- CHANGELOG.md | 4 ++++ app/manifest.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fae2e0800..c97e6416f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Current Master +## 4.0.0 2018-2-22 + +- Introduce new MetaMask user interface. + ## 3.14.2 2018-2-15 - Fix bug where log subscriptions would break when switching network. diff --git a/app/manifest.json b/app/manifest.json index c4e134053..2abe673db 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "MetaMask", "short_name": "Metamask", - "version": "4.0.12", + "version": "4.0.0", "manifest_version": 2, "author": "https://metamask.io", "description": "Ethereum Browser Extension", From c1aa59f6eddac0a37f0084e37ab1281e109d1c80 Mon Sep 17 00:00:00 2001 From: Csaba Solya Date: Fri, 23 Feb 2018 10:08:23 +0100 Subject: [PATCH 069/392] adding tests --- test/unit/edge-encryptor-test.js | 66 ++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 test/unit/edge-encryptor-test.js diff --git a/test/unit/edge-encryptor-test.js b/test/unit/edge-encryptor-test.js new file mode 100644 index 000000000..627386051 --- /dev/null +++ b/test/unit/edge-encryptor-test.js @@ -0,0 +1,66 @@ +const assert = require('assert') + +const EdgeEncryptor = require('../../app/scripts/edge-encryptor') + +var password = 'passw0rd1' +var data = 'some random data' + +// polyfill fetch +global.crypto = global.crypto || { + getRandomValues (array) { + for (let i = 0; i < array.length; i++) { + array[i] = Math.random() * 100; + } + } +} + +describe('EdgeEncryptor', function () { + const edgeEncryptor = new EdgeEncryptor() + + describe('encrypt', function () { + + it('should encrypt the data.', function () { + edgeEncryptor.encrypt(password, data) + .then(function (encryptedData) { + assert.notEqual(data, encryptedData) + assert.notEqual(encryptedData.length, 0) + done() + }).catch(function (err) { + done(err) + }) + }) + + it('should not return the same twice.', function () { + + const encryptPromises = [] + encryptPromises.push(edgeEncryptor.encrypt(password, data)) + encryptPromises.push(edgeEncryptor.encrypt(password, data)) + + Promise.all(encryptPromises).then((encryptedData) => { + assert.equal(encryptedData.length, 2) + assert.notEqual(encryptedData[0], encryptedData[1]) + assert.notEqual(encryptedData[0].length, 0) + assert.notEqual(encryptedData[1].length, 0) + }) + }) + }) + + describe('decrypt', function () { + it('should be able to decrypt the encrypted data.', function () { + + edgeEncryptor.encrypt(password, data) + .then(function (encryptedData) { + edgeEncryptor.decrypt(password, encryptedData) + .then(function (decryptedData) { + assert.equal(decryptedData, data) + }) + .catch(function (err) { + done(err) + }) + }) + .catch(function (err) { + done(err) + }) + }) + }) +}) From 73d9bfc52cfb4b63f0960d80a7b68f2bf6f7d88c Mon Sep 17 00:00:00 2001 From: Csaba Solya Date: Fri, 23 Feb 2018 10:09:16 +0100 Subject: [PATCH 070/392] make keyFromPassword private --- app/scripts/edge-encryptor.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/scripts/edge-encryptor.js b/app/scripts/edge-encryptor.js index 9d6ac37b3..24c0c93a8 100644 --- a/app/scripts/edge-encryptor.js +++ b/app/scripts/edge-encryptor.js @@ -6,7 +6,7 @@ class EdgeEncryptor { encrypt (password, dataObject) { var salt = this._generateSalt() - return this.keyFromPassword(password, salt) + return this._keyFromPassword(password, salt) .then(function (key) { var data = JSON.stringify(dataObject) @@ -29,7 +29,7 @@ class EdgeEncryptor { const payload = JSON.parse(text) const salt = payload.salt - return this.keyFromPassword(password, salt) + return this._keyFromPassword(password, salt) .then(function (key) { const encryptedData = Unibabel.base64ToBuffer(payload.data) const vector = Unibabel.base64ToBuffer(payload.iv) @@ -48,7 +48,7 @@ class EdgeEncryptor { }) } - keyFromPassword (password, salt) { + _keyFromPassword (password, salt) { var passBuffer = Unibabel.utf8ToBuffer(password) var saltBuffer = Unibabel.base64ToBuffer(salt) From cd05d77c3fd9fe8e49d38b43728ff90b72b1ca9d Mon Sep 17 00:00:00 2001 From: Csaba Solya Date: Fri, 23 Feb 2018 10:49:56 +0100 Subject: [PATCH 071/392] fix tests --- test/unit/edge-encryptor-test.js | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/test/unit/edge-encryptor-test.js b/test/unit/edge-encryptor-test.js index 627386051..ef733a494 100644 --- a/test/unit/edge-encryptor-test.js +++ b/test/unit/edge-encryptor-test.js @@ -5,21 +5,21 @@ const EdgeEncryptor = require('../../app/scripts/edge-encryptor') var password = 'passw0rd1' var data = 'some random data' -// polyfill fetch global.crypto = global.crypto || { - getRandomValues (array) { + getRandomValues: function (array) { for (let i = 0; i < array.length; i++) { - array[i] = Math.random() * 100; + array[i] = Math.random() * 100 } + return array } } describe('EdgeEncryptor', function () { - const edgeEncryptor = new EdgeEncryptor() + const edgeEncryptor = new EdgeEncryptor() describe('encrypt', function () { - it('should encrypt the data.', function () { + it('should encrypt the data.', function (done) { edgeEncryptor.encrypt(password, data) .then(function (encryptedData) { assert.notEqual(data, encryptedData) @@ -30,6 +30,19 @@ describe('EdgeEncryptor', function () { }) }) + it('should return proper format.', function (done) { + edgeEncryptor.encrypt(password, data) + .then(function (encryptedData) { + let encryptedObject = JSON.parse(encryptedData) + assert.ok(encryptedObject.data, 'there is no data') + assert.ok(encryptedObject.iv && encryptedObject.iv.length != 0, 'there is no iv') + assert.ok(encryptedObject.salt && encryptedObject.salt.length != 0, 'there is no salt') + done() + }).catch(function (err) { + done(err) + }) + }) + it('should not return the same twice.', function () { const encryptPromises = [] @@ -46,13 +59,14 @@ describe('EdgeEncryptor', function () { }) describe('decrypt', function () { - it('should be able to decrypt the encrypted data.', function () { + it('should be able to decrypt the encrypted data.', function (done) { edgeEncryptor.encrypt(password, data) .then(function (encryptedData) { edgeEncryptor.decrypt(password, encryptedData) .then(function (decryptedData) { assert.equal(decryptedData, data) + done() }) .catch(function (err) { done(err) From 8292dabed56b858fa2ccec7497627f5e5aa65181 Mon Sep 17 00:00:00 2001 From: Csaba Solya Date: Fri, 23 Feb 2018 11:03:53 +0100 Subject: [PATCH 072/392] add negative decrypt test --- test/unit/edge-encryptor-test.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/unit/edge-encryptor-test.js b/test/unit/edge-encryptor-test.js index ef733a494..1dad4b91e 100644 --- a/test/unit/edge-encryptor-test.js +++ b/test/unit/edge-encryptor-test.js @@ -76,5 +76,25 @@ describe('EdgeEncryptor', function () { done(err) }) }) + + it('cannot decrypt the encrypted data with wrong password.', function (done) { + + edgeEncryptor.encrypt(password, data) + .then(function (encryptedData) { + edgeEncryptor.decrypt('wrong password', encryptedData) + .then(function (decryptedData) { + assert.fail('could decrypt with wrong password') + done() + }) + .catch(function (err) { + assert.ok(err instanceof Error) + assert.equal(err.message, 'Incorrect password') + done() + }) + }) + .catch(function (err) { + done(err) + }) + }) }) }) From 1b367bc2150434f5d2324d4344dfbbeff0eb4967 Mon Sep 17 00:00:00 2001 From: Csaba Solya Date: Fri, 23 Feb 2018 11:11:14 +0100 Subject: [PATCH 073/392] fix test --- test/unit/edge-encryptor-test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/unit/edge-encryptor-test.js b/test/unit/edge-encryptor-test.js index 1dad4b91e..d3f014d74 100644 --- a/test/unit/edge-encryptor-test.js +++ b/test/unit/edge-encryptor-test.js @@ -43,7 +43,7 @@ describe('EdgeEncryptor', function () { }) }) - it('should not return the same twice.', function () { + it('should not return the same twice.', function (done) { const encryptPromises = [] encryptPromises.push(edgeEncryptor.encrypt(password, data)) @@ -54,6 +54,7 @@ describe('EdgeEncryptor', function () { assert.notEqual(encryptedData[0], encryptedData[1]) assert.notEqual(encryptedData[0].length, 0) assert.notEqual(encryptedData[1].length, 0) + done() }) }) }) From b24d949ca44a2a0a8414625ebd58a6882a3fd81c Mon Sep 17 00:00:00 2001 From: frankiebee Date: Mon, 26 Feb 2018 10:55:30 -0800 Subject: [PATCH 074/392] fix feature flags being undefined --- ui/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/index.js b/ui/index.js index bc3676c1f..fdb2f23e0 100644 --- a/ui/index.js +++ b/ui/index.js @@ -25,6 +25,7 @@ function launchMetamaskUi (opts, cb) { function startApp (metamaskState, accountManager, opts) { // parse opts + if (!metamaskState.featureFlags) metamaskState.featureFlags = {} const store = configureStore({ // metamaskState represents the cross-tab state From 3eba74a0f50d2635c6c80d9e5ce61663b9108eb7 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 26 Feb 2018 16:23:24 -0800 Subject: [PATCH 075/392] Update LICENSE to current year. --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 96e55582b..ddfbecf90 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2016 MetaMask +Copyright (c) 2018 MetaMask Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 746c3e5f1803e9b3712d22a4e4dd7ab43e84e060 Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 27 Feb 2018 13:34:31 -0330 Subject: [PATCH 076/392] Body width container in first time flow is consistent with app bar. --- mascara/src/app/first-time/index.css | 7 +++++- .../css/itcss/components/newui-sections.scss | 24 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/mascara/src/app/first-time/index.css b/mascara/src/app/first-time/index.css index 4314efbe6..4f2400222 100644 --- a/mascara/src/app/first-time/index.css +++ b/mascara/src/app/first-time/index.css @@ -4,6 +4,8 @@ width: 100vw; background-color: #FFF; overflow: auto; + display: flex; + justify-content: center; } .alpha-warning { @@ -23,7 +25,6 @@ display: flex; flex-flow: column; margin-top: 70px; - margin-right: 10vw; width: 35vw; max-width: 550px; } @@ -48,6 +49,10 @@ max-width: 35rem; } +.create-password { + margin: 67px 0 50px 0px; +} + .import-account { max-width: initial; } diff --git a/ui/app/css/itcss/components/newui-sections.scss b/ui/app/css/itcss/components/newui-sections.scss index 73faebe8b..ecf5e1036 100644 --- a/ui/app/css/itcss/components/newui-sections.scss +++ b/ui/app/css/itcss/components/newui-sections.scss @@ -290,3 +290,27 @@ $wallet-view-bg: $alabaster; .token-balance__amount { padding-right: 6px; } + + +// first time +.first-view-main { + display: flex; + flex-direction: row-reverse; + justify-content: space-between; + + @media screen and (max-width: 575px) { + height: 100%; + } + + @media screen and (min-width: 576px) { + width: 85vw; + } + + @media screen and (min-width: 769px) { + width: 80vw; + } + + @media screen and (min-width: 1281px) { + width: 62vw; + } +} \ No newline at end of file From 07edf3f9ffdee9459f4d0b9d30b8b6821d26dbf0 Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 27 Feb 2018 13:35:29 -0330 Subject: [PATCH 077/392] NewUI first time flow warning message change. --- mascara/src/app/first-time/create-password-screen.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mascara/src/app/first-time/create-password-screen.js b/mascara/src/app/first-time/create-password-screen.js index d1a2ec70f..d348eaa1a 100644 --- a/mascara/src/app/first-time/create-password-screen.js +++ b/mascara/src/app/first-time/create-password-screen.js @@ -59,7 +59,7 @@ class CreatePasswordScreen extends Component { ? : (
-

Warning: This is Experimental software and is a Developer BETA

+

Please be aware that this version is still in under development.

Date: Tue, 27 Feb 2018 13:43:22 -0330 Subject: [PATCH 078/392] Move beta warning to app header. --- mascara/src/app/first-time/create-password-screen.js | 1 - ui/app/app.js | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/mascara/src/app/first-time/create-password-screen.js b/mascara/src/app/first-time/create-password-screen.js index d348eaa1a..450d6a479 100644 --- a/mascara/src/app/first-time/create-password-screen.js +++ b/mascara/src/app/first-time/create-password-screen.js @@ -59,7 +59,6 @@ class CreatePasswordScreen extends Component { ? : (
-

Please be aware that this version is still in under development.

Date: Tue, 27 Feb 2018 13:59:33 -0330 Subject: [PATCH 079/392] Adds beta label to Metamask name in full screen app bar. --- ui/app/app.js | 2 ++ ui/app/css/itcss/components/header.scss | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/ui/app/app.js b/ui/app/app.js index 7490c63b1..5d37b9bdf 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -288,6 +288,8 @@ App.prototype.renderAppBar = function () { // metamask name h('h1', 'MetaMask'), + h('div.beta-label', 'BETA'), + ]), h('div.header__right-actions', [ diff --git a/ui/app/css/itcss/components/header.scss b/ui/app/css/itcss/components/header.scss index ac2cecf7e..d91ab3c48 100644 --- a/ui/app/css/itcss/components/header.scss +++ b/ui/app/css/itcss/components/header.scss @@ -76,6 +76,21 @@ } } +.beta-label { + font-family: Roboto; + text-transform: uppercase; + font-weight: 500; + font-size: 0.8rem; + padding-left: 9px; + color: $buttercup; + align-self: flex-start; + margin-top: 10px; + + @media screen and (max-width: 575px) { + display: none; + } +} + h2.page-subtitle { text-transform: uppercase; color: #aeaeae; From baab9917ff741dd8e2f7efea63f85bc3de0f89ca Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 27 Feb 2018 14:14:55 -0330 Subject: [PATCH 080/392] Padding of alpha warning aligns with app-bar --- mascara/src/app/first-time/index.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mascara/src/app/first-time/index.css b/mascara/src/app/first-time/index.css index 4f2400222..109946e1d 100644 --- a/mascara/src/app/first-time/index.css +++ b/mascara/src/app/first-time/index.css @@ -12,7 +12,7 @@ background: #f7861c; color: #fff; line-height: 2em; - padding-left: 2em; + padding-left: 10vw; } .first-view-main { From d9486a3ce535636f890bee76a635571f2be0ec7c Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 27 Feb 2018 10:35:43 -0800 Subject: [PATCH 081/392] Bump Version --- CHANGELOG.md | 6 ++++++ app/manifest.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c97e6416f..fcddc76cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## Current Master +## 4.1.0 2018-2-27 + +- Sentry report failed tx with more specific message +- Fix feature flags being undefined +- Standardized license + ## 4.0.0 2018-2-22 - Introduce new MetaMask user interface. diff --git a/app/manifest.json b/app/manifest.json index 2abe673db..eab6c7063 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "MetaMask", "short_name": "Metamask", - "version": "4.0.0", + "version": "4.1.0", "manifest_version": 2, "author": "https://metamask.io", "description": "Ethereum Browser Extension", From dae5d085d1bb448971e93b4905f8931a10bf5ce6 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 27 Feb 2018 10:37:43 -0800 Subject: [PATCH 082/392] changelog - improve changelog notes --- CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fcddc76cf..abc89f9c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,9 @@ ## 4.1.0 2018-2-27 -- Sentry report failed tx with more specific message -- Fix feature flags being undefined -- Standardized license +- Report failed txs to Sentry with more specific message +- Fix internal feature flags being sometimes undefined +- Standardized license to MIT ## 4.0.0 2018-2-22 From 50f20358c1ffe0e04f65025db9ac9627af313b33 Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 27 Feb 2018 12:01:09 -0800 Subject: [PATCH 083/392] Add import account disclaimer --- old-ui/app/accounts/import/index.js | 26 ++++++++++++++++++++++---- old-ui/app/css/lib.css | 2 +- ui/app/accounts/import/index.js | 22 ++++++++++++++++++++++ 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/old-ui/app/accounts/import/index.js b/old-ui/app/accounts/import/index.js index 3502efe93..a57525ccf 100644 --- a/old-ui/app/accounts/import/index.js +++ b/old-ui/app/accounts/import/index.js @@ -34,10 +34,7 @@ AccountImportSubview.prototype.render = function () { const { type } = state return ( - h('div', { - style: { - }, - }, [ + h('div', [ h('.section-title.flex-row.flex-center', [ h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', { onClick: (event) => { @@ -46,6 +43,27 @@ AccountImportSubview.prototype.render = function () { }), h('h2.page-subtitle', 'Import Accounts'), ]), + h('.error', { + style: { + display: 'inline-block', + alignItems: 'center', + padding: '5px 15px 0px 15px', + }, + }, [ + h('span', 'Imported accounts will not be associated with your originally created MetaMask account seedphrase. Learn more about imported accounts '), + h('span', { + style: { + color: 'rgba(247, 134, 28, 1)', + cursor: 'pointer', + textDecoration: 'underline', + }, + onClick: () => { + global.platform.openWindow({ + url: 'https://metamask.helpscoutdocs.com/article/17-what-are-loose-accounts', + }) + }, + }, 'here.'), + ]), h('div', { style: { padding: '10px', diff --git a/old-ui/app/css/lib.css b/old-ui/app/css/lib.css index f3acbee76..fd63b2b2e 100644 --- a/old-ui/app/css/lib.css +++ b/old-ui/app/css/lib.css @@ -217,7 +217,7 @@ hr.horizontal-line { background: rgba(255,0,0,0.8); color: white; bottom: 0px; - left: -8px; + left: -18px; border-radius: 10px; height: 20px; min-width: 20px; diff --git a/ui/app/accounts/import/index.js b/ui/app/accounts/import/index.js index 71eb9ae23..7e7d3aa91 100644 --- a/ui/app/accounts/import/index.js +++ b/ui/app/accounts/import/index.js @@ -35,6 +35,28 @@ AccountImportSubview.prototype.render = function () { return ( h('div.new-account-import-form', [ + h('.warning', { + style: { + display: 'inline-block', + alignItems: 'center', + padding: '15px 15px 0px 15px', + }, + }, [ + h('span', 'Imported accounts will not be associated with your originally created MetaMask account seedphrase. Learn more about imported accounts '), + h('span', { + style: { + color: 'rgba(247, 134, 28, 1)', + cursor: 'pointer', + textDecoration: 'underline', + }, + onClick: () => { + global.platform.openWindow({ + url: 'https://metamask.helpscoutdocs.com/article/17-what-are-loose-accounts', + }) + }, + }, 'here.'), + ]), + h('div.new-account-import-form__select-section', [ h('div.new-account-import-form__select-label', 'Select Type'), From ac2e92fa5424bbb1517d7443a7c40dcac92af638 Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 27 Feb 2018 12:02:48 -0800 Subject: [PATCH 084/392] Change Loose label to Imported --- old-ui/app/components/account-dropdowns.js | 2 +- ui/app/components/dropdowns/components/account-dropdowns.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/old-ui/app/components/account-dropdowns.js b/old-ui/app/components/account-dropdowns.js index aa7a3ad67..981f4d8a3 100644 --- a/old-ui/app/components/account-dropdowns.js +++ b/old-ui/app/components/account-dropdowns.js @@ -79,7 +79,7 @@ class AccountDropdowns extends Component { try { // Sometimes keyrings aren't loaded yet: const type = keyring.type const isLoose = type !== 'HD Key Tree' - return isLoose ? h('.keyring-label', 'LOOSE') : null + return isLoose ? h('.keyring-label', 'IMPORTED') : null } catch (e) { return } } diff --git a/ui/app/components/dropdowns/components/account-dropdowns.js b/ui/app/components/dropdowns/components/account-dropdowns.js index d3a549884..f637ca19d 100644 --- a/ui/app/components/dropdowns/components/account-dropdowns.js +++ b/ui/app/components/dropdowns/components/account-dropdowns.js @@ -159,7 +159,7 @@ class AccountDropdowns extends Component { try { // Sometimes keyrings aren't loaded yet: const type = keyring.type const isLoose = type !== 'HD Key Tree' - return isLoose ? h('.keyring-label', 'LOOSE') : null + return isLoose ? h('.keyring-label', 'IMPORTED') : null } catch (e) { return } } From 7aa324bdf61e83f9ed64e6b0354d88e0af76f42b Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 27 Feb 2018 12:06:24 -0800 Subject: [PATCH 085/392] Remove committed out merge code --- .../dropdowns/components/account-dropdowns.js | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/ui/app/components/dropdowns/components/account-dropdowns.js b/ui/app/components/dropdowns/components/account-dropdowns.js index f637ca19d..78b059d5b 100644 --- a/ui/app/components/dropdowns/components/account-dropdowns.js +++ b/ui/app/components/dropdowns/components/account-dropdowns.js @@ -134,22 +134,6 @@ class AccountDropdowns extends Component { ]), ]), -// ======= -// }, -// ), -// this.indicateIfLoose(keyring), -// h('span', { -// style: { -// marginLeft: '20px', -// fontSize: '24px', -// maxWidth: '145px', -// whiteSpace: 'nowrap', -// overflow: 'hidden', -// textOverflow: 'ellipsis', -// }, -// }, identity.name || ''), -// h('span', { style: { marginLeft: '20px', fontSize: '24px' } }, isSelected ? h('.check', '✓') : null), -// >>>>>>> master:ui/app/components/account-dropdowns.js ] ) }) From b4aac16c5830e974e5dd1093e80c1221892b9128 Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 27 Feb 2018 12:08:05 -0800 Subject: [PATCH 086/392] Add changes to CHANGELOG --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index abc89f9c7..fce90f89c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## Current Master +- Change Loose label to Imported. +- Add Imported Account disclaimer. + ## 4.1.0 2018-2-27 - Report failed txs to Sentry with more specific message From 5de0471fcb65fb70dbb55e514a2da48b0e187d50 Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 27 Feb 2018 19:14:23 -0330 Subject: [PATCH 087/392] Fix cancel button on buy eth screen. --- old-ui/app/components/coinbase-form.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/old-ui/app/components/coinbase-form.js b/old-ui/app/components/coinbase-form.js index 35b2111ff..1a1b77b50 100644 --- a/old-ui/app/components/coinbase-form.js +++ b/old-ui/app/components/coinbase-form.js @@ -40,7 +40,7 @@ CoinbaseForm.prototype.render = function () { }, 'Continue to Coinbase'), h('button.btn-red', { - onClick: () => props.dispatch(actions.backTobuyView(props.accounts.address)), + onClick: () => props.dispatch(actions.goHome()), }, 'Cancel'), ]), ]) From 2b9af0734b6127349ed4f1ed535dee858633776b Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 27 Feb 2018 20:05:54 -0330 Subject: [PATCH 088/392] Replace 'Contract Published' with 'Contract Deployment' for clearer indication of contract tx state. --- old-ui/app/components/transaction-list-item.js | 2 +- ui/app/components/transaction-list-item.js | 2 +- ui/app/components/tx-list-item.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/old-ui/app/components/transaction-list-item.js b/old-ui/app/components/transaction-list-item.js index 76a456d3f..95670bd54 100644 --- a/old-ui/app/components/transaction-list-item.js +++ b/old-ui/app/components/transaction-list-item.js @@ -123,7 +123,7 @@ function recipientField (txParams, transaction, isTx, isMsg) { } else if (txParams.to) { message = addressSummary(txParams.to) } else { - message = 'Contract Published' + message = 'Contract Deployment' } return h('div', { diff --git a/ui/app/components/transaction-list-item.js b/ui/app/components/transaction-list-item.js index 4e3d2cb93..a45cd441a 100644 --- a/ui/app/components/transaction-list-item.js +++ b/ui/app/components/transaction-list-item.js @@ -180,7 +180,7 @@ function recipientField (txParams, transaction, isTx, isMsg) { } else if (txParams.to) { message = addressSummary(txParams.to) } else { - message = 'Contract Published' + message = 'Contract Deployment' } return h('div', { diff --git a/ui/app/components/tx-list-item.js b/ui/app/components/tx-list-item.js index 7ccc5c315..1a13070c8 100644 --- a/ui/app/components/tx-list-item.js +++ b/ui/app/components/tx-list-item.js @@ -63,7 +63,7 @@ TxListItem.prototype.getAddressText = function () { default: return address ? `${address.slice(0, 10)}...${address.slice(-4)}` - : 'Contract Published' + : 'Contract Deployment' } } From b2f53fa35481006cba37d89ebf4c7a866be4f125 Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 27 Feb 2018 15:50:49 -0800 Subject: [PATCH 089/392] Revert initializing first-time-state --- test/stub/first-time-state.js | 14 -------------- test/unit/metamask-controller-test.js | 6 +++--- 2 files changed, 3 insertions(+), 17 deletions(-) delete mode 100644 test/stub/first-time-state.js diff --git a/test/stub/first-time-state.js b/test/stub/first-time-state.js deleted file mode 100644 index c9d5a4fe9..000000000 --- a/test/stub/first-time-state.js +++ /dev/null @@ -1,14 +0,0 @@ - -// test and development environment variables -const { createTestProviderTools } = require('../stub/provider') -const providerResultStub = {} -const provider = createTestProviderTools({ scaffold: providerResultStub }).provider -// -// The default state of MetaMask -// -module.exports = { - config: {}, - NetworkController: { - provider, - }, -} diff --git a/test/unit/metamask-controller-test.js b/test/unit/metamask-controller-test.js index ac984faf5..adeca9b5f 100644 --- a/test/unit/metamask-controller-test.js +++ b/test/unit/metamask-controller-test.js @@ -4,7 +4,7 @@ const clone = require('clone') const nock = require('nock') const MetaMaskController = require('../../app/scripts/metamask-controller') const blacklistJSON = require('../stub/blacklist') -const firstTimeState = require('../stub/first-time-state') +const firstTimeState = require('../../app/scripts/first-time-state') describe('MetaMaskController', function () { let metamaskController @@ -18,9 +18,9 @@ describe('MetaMaskController', function () { .get('/v2/blacklist') .reply(200, blacklistJSON) - nock('https://rinkeby.infura.io') + nock('https://api.infura.io') .persist() - .post('/metamask') + .get(/.*/) .reply(200) metamaskController = new MetaMaskController({ From f9de87af51ccb1190ca93e524de24f8a32ea3d9e Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 27 Feb 2018 15:51:14 -0800 Subject: [PATCH 090/392] Using noop to not lose it --- test/unit/network-contoller-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/network-contoller-test.js b/test/unit/network-contoller-test.js index cd8c345c5..51ad09f87 100644 --- a/test/unit/network-contoller-test.js +++ b/test/unit/network-contoller-test.js @@ -10,7 +10,7 @@ describe('# Network Controller', function () { let networkController const noop = () => {} const networkControllerProviderInit = { - getAccounts: () => {}, + getAccounts: noop, } beforeEach(function () { From 78f6a4866425ca9fd7795d91ea5dacd47599c1ab Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 28 Feb 2018 13:12:06 -0330 Subject: [PATCH 091/392] Define event locally in onClickOutside method in account-dropdowns.js --- old-ui/app/components/account-dropdowns.js | 2 +- ui/app/components/account-dropdowns.js | 2 +- ui/app/components/dropdowns/components/account-dropdowns.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/old-ui/app/components/account-dropdowns.js b/old-ui/app/components/account-dropdowns.js index aa7a3ad67..7a2357921 100644 --- a/old-ui/app/components/account-dropdowns.js +++ b/old-ui/app/components/account-dropdowns.js @@ -173,7 +173,7 @@ class AccountDropdowns extends Component { minWidth: '180px', }, isOpen: optionsMenuActive, - onClickOutside: () => { + onClickOutside: (event) => { const { classList } = event.target const isNotToggleElement = !classList.contains(this.optionsMenuToggleClassName) if (optionsMenuActive && isNotToggleElement) { diff --git a/ui/app/components/account-dropdowns.js b/ui/app/components/account-dropdowns.js index f69a6ca68..1cd7a0847 100644 --- a/ui/app/components/account-dropdowns.js +++ b/ui/app/components/account-dropdowns.js @@ -173,7 +173,7 @@ class AccountDropdowns extends Component { minWidth: '180px', }, isOpen: optionsMenuActive, - onClickOutside: () => { + onClickOutside: (event) => { const { classList } = event.target const isNotToggleElement = !classList.contains(this.optionsMenuToggleClassName) if (optionsMenuActive && isNotToggleElement) { diff --git a/ui/app/components/dropdowns/components/account-dropdowns.js b/ui/app/components/dropdowns/components/account-dropdowns.js index d3a549884..fa9ffc632 100644 --- a/ui/app/components/dropdowns/components/account-dropdowns.js +++ b/ui/app/components/dropdowns/components/account-dropdowns.js @@ -281,7 +281,7 @@ class AccountDropdowns extends Component { dropdownWrapperStyle, ), isOpen: optionsMenuActive, - onClickOutside: () => { + onClickOutside: (event) => { const { classList } = event.target const isNotToggleElement = !classList.contains(this.optionsMenuToggleClassName) if (optionsMenuActive && isNotToggleElement) { From c4ef9630dae73d68cfc3191a182c03b840a33a0d Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 28 Feb 2018 14:13:44 -0330 Subject: [PATCH 092/392] Prevent user from switching network in old-ui notification --- old-ui/app/components/network.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/old-ui/app/components/network.js b/old-ui/app/components/network.js index 0dbe37cdd..59596dabd 100644 --- a/old-ui/app/components/network.js +++ b/old-ui/app/components/network.js @@ -23,14 +23,15 @@ Network.prototype.render = function () { if (networkNumber === 'loading') { return h('span.pointer', { + className: props.onClick && 'pointer', style: { display: 'flex', alignItems: 'center', flexDirection: 'row', }, - onClick: (event) => this.props.onClick(event), + onClick: (event) => props.onClick && props.onClick(event), }, [ - h('img', { + props.onClick && h('img', { title: 'Attempting to connect to blockchain.', style: { width: '27px', @@ -60,9 +61,10 @@ Network.prototype.render = function () { } return ( - h('#network_component.pointer', { + h('#network_component', { + className: props.onClick && 'pointer', title: hoverText, - onClick: (event) => this.props.onClick(event), + onClick: (event) => props.onClick && props.onClick(event), }, [ (function () { switch (iconName) { @@ -74,7 +76,7 @@ Network.prototype.render = function () { color: '#039396', }}, 'Main Network'), - h('i.fa.fa-caret-down.fa-lg'), + props.onClick && h('i.fa.fa-caret-down.fa-lg'), ]) case 'ropsten-test-network': return h('.network-indicator', [ @@ -84,7 +86,7 @@ Network.prototype.render = function () { color: '#ff6666', }}, 'Ropsten Test Net'), - h('i.fa.fa-caret-down.fa-lg'), + props.onClick && h('i.fa.fa-caret-down.fa-lg'), ]) case 'kovan-test-network': return h('.network-indicator', [ @@ -94,7 +96,7 @@ Network.prototype.render = function () { color: '#690496', }}, 'Kovan Test Net'), - h('i.fa.fa-caret-down.fa-lg'), + props.onClick && h('i.fa.fa-caret-down.fa-lg'), ]) case 'rinkeby-test-network': return h('.network-indicator', [ @@ -104,7 +106,7 @@ Network.prototype.render = function () { color: '#e7a218', }}, 'Rinkeby Test Net'), - h('i.fa.fa-caret-down.fa-lg'), + props.onClick && h('i.fa.fa-caret-down.fa-lg'), ]) default: return h('.network-indicator', [ @@ -120,7 +122,7 @@ Network.prototype.render = function () { color: '#AEAEAE', }}, 'Private Network'), - h('i.fa.fa-caret-down.fa-lg'), + props.onClick && h('i.fa.fa-caret-down.fa-lg'), ]) } })(), From fca2cbc8ef8e0d8434fd8c437497a7a0792e2caf Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Feb 2018 10:37:53 -0800 Subject: [PATCH 093/392] sentry - clean - move setupRaven to lib --- app/scripts/background.js | 2 +- app/scripts/{ => lib}/setupRaven.js | 2 +- app/scripts/popup.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename app/scripts/{ => lib}/setupRaven.js (92%) diff --git a/app/scripts/background.js b/app/scripts/background.js index 476d073d1..0da079eb6 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -13,7 +13,7 @@ const PortStream = require('./lib/port-stream.js') const NotificationManager = require('./lib/notification-manager.js') const MetamaskController = require('./metamask-controller') const firstTimeState = require('./first-time-state') -const setupRaven = require('./setupRaven') +const setupRaven = require('./lib/setupRaven') const setupMetamaskMeshMetrics = require('./lib/setupMetamaskMeshMetrics') const STORAGE_KEY = 'metamask-config' diff --git a/app/scripts/setupRaven.js b/app/scripts/lib/setupRaven.js similarity index 92% rename from app/scripts/setupRaven.js rename to app/scripts/lib/setupRaven.js index 7beffeff9..42e48cb90 100644 --- a/app/scripts/setupRaven.js +++ b/app/scripts/lib/setupRaven.js @@ -1,4 +1,4 @@ -const Raven = require('./vendor/raven.min.js') +const Raven = require('../vendor/raven.min.js') const METAMASK_DEBUG = 'GULP_METAMASK_DEBUG' const PROD = 'https://3567c198f8a8412082d32655da2961d0@sentry.io/273505' const DEV = 'https://f59f3dd640d2429d9d0e2445a87ea8e1@sentry.io/273496' diff --git a/app/scripts/popup.js b/app/scripts/popup.js index 53ab00e00..11d50ee87 100644 --- a/app/scripts/popup.js +++ b/app/scripts/popup.js @@ -8,7 +8,7 @@ const extension = require('extensionizer') const ExtensionPlatform = require('./platforms/extension') const NotificationManager = require('./lib/notification-manager') const notificationManager = new NotificationManager() -const setupRaven = require('./setupRaven') +const setupRaven = require('./lib/setupRaven') // create platform global global.platform = new ExtensionPlatform() From 8e5bcf89359edb70b5d6847a4848c222aa283066 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Feb 2018 10:53:54 -0800 Subject: [PATCH 094/392] sentry - failed tx - improve ethjs-rpc error formating --- app/scripts/background.js | 8 ++--- app/scripts/lib/reportFailedTxToSentry.js | 38 +++++++++++++++++++++++ 2 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 app/scripts/lib/reportFailedTxToSentry.js diff --git a/app/scripts/background.js b/app/scripts/background.js index 0da079eb6..4487ff318 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -14,8 +14,10 @@ const NotificationManager = require('./lib/notification-manager.js') const MetamaskController = require('./metamask-controller') const firstTimeState = require('./first-time-state') const setupRaven = require('./lib/setupRaven') +const reportFailedTxToSentry = require('./lib/reportFailedTxToSentry') const setupMetamaskMeshMetrics = require('./lib/setupMetamaskMeshMetrics') + const STORAGE_KEY = 'metamask-config' const METAMASK_DEBUG = 'GULP_METAMASK_DEBUG' @@ -86,11 +88,7 @@ function setupController (initState) { controller.txController.on(`tx:status-update`, (txId, status) => { if (status !== 'failed') return const txMeta = controller.txController.txStateManager.getTx(txId) - const errorMessage = `Transaction Failed: ${txMeta.err.message}` - raven.captureMessage(errorMessage, { - // "extra" key is required by Sentry - extra: txMeta, - }) + reportFailedTxToSentry({ raven, txMeta }) }) // setup state persistence diff --git a/app/scripts/lib/reportFailedTxToSentry.js b/app/scripts/lib/reportFailedTxToSentry.js new file mode 100644 index 000000000..67b0acf43 --- /dev/null +++ b/app/scripts/lib/reportFailedTxToSentry.js @@ -0,0 +1,38 @@ +const ethJsRpcSlug = 'Error: [ethjs-rpc] rpc error with payload ' +const errorLabelPrefix = 'Error: ' + +module.exports = reportFailedTxToSentry + +// +// utility for formatting failed transaction messages +// for sending to sentry +// + +function reportFailedTxToSentry({ raven, txMeta }) { + const errorMessage = extractErrorMessage(txMeta.err.message) + raven.captureMessage(errorMessage, { + // "extra" key is required by Sentry + extra: txMeta, + }) +} + +// +// ethjs-rpc provides overly verbose error messages +// if we detect this type of message, we extract the important part +// Below is an example input and output +// +// Error: [ethjs-rpc] rpc error with payload {"id":3947817945380,"jsonrpc":"2.0","params":["0xf8eb8208708477359400830398539406012c8cf97bead5deae237070f9587f8e7a266d80b8843d7d3f5a0000000000000000000000000000000000000000000000000000000000081d1a000000000000000000000000000000000000000000000000001ff973cafa800000000000000000000000000000000000000000000000000000038d7ea4c68000000000000000000000000000000000000000000000000000000000000003f48025a04c32a9b630e0d9e7ff361562d850c86b7a884908135956a7e4a336fa0300d19ca06830776423f25218e8d19b267161db526e66895567147015b1f3fc47aef9a3c7"],"method":"eth_sendRawTransaction"} Error: replacement transaction underpriced +// +// "Transaction Failed: replacement transaction underpriced" +// + +function extractErrorMessage(errorMessage) { + const isEthjsRpcError = errorMessage.includes(ethJsRpcSlug) + if (isEthjsRpcError) { + const payloadAndError = errorMessage.slice(ethJsRpcSlug.length) + const originalError = payloadAndError.slice(payloadAndError.indexOf(errorLabelPrefix) + errorLabelPrefix.length) + return `Transaction Failed: ${originalError}` + } else { + return `Transaction Failed: ${errorMessage}` + } +} From c3bd27c9657d5e0236e2960dedd108ca5e2bb0ec Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Feb 2018 10:57:54 -0800 Subject: [PATCH 095/392] sentry - extractErrorMessage - fix comment formatting --- app/scripts/lib/reportFailedTxToSentry.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/lib/reportFailedTxToSentry.js b/app/scripts/lib/reportFailedTxToSentry.js index 67b0acf43..ee73f6845 100644 --- a/app/scripts/lib/reportFailedTxToSentry.js +++ b/app/scripts/lib/reportFailedTxToSentry.js @@ -23,7 +23,7 @@ function reportFailedTxToSentry({ raven, txMeta }) { // // Error: [ethjs-rpc] rpc error with payload {"id":3947817945380,"jsonrpc":"2.0","params":["0xf8eb8208708477359400830398539406012c8cf97bead5deae237070f9587f8e7a266d80b8843d7d3f5a0000000000000000000000000000000000000000000000000000000000081d1a000000000000000000000000000000000000000000000000001ff973cafa800000000000000000000000000000000000000000000000000000038d7ea4c68000000000000000000000000000000000000000000000000000000000000003f48025a04c32a9b630e0d9e7ff361562d850c86b7a884908135956a7e4a336fa0300d19ca06830776423f25218e8d19b267161db526e66895567147015b1f3fc47aef9a3c7"],"method":"eth_sendRawTransaction"} Error: replacement transaction underpriced // -// "Transaction Failed: replacement transaction underpriced" +// Transaction Failed: replacement transaction underpriced // function extractErrorMessage(errorMessage) { From d45116824c289a12ba43fcff257d282ef7f38902 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Wed, 28 Feb 2018 13:03:46 -0800 Subject: [PATCH 096/392] Check in all font files locally. --- app/fonts/Font_Awesome/font-awesome.min.css | 4 + app/fonts/fonts/FontAwesome.otf | Bin 0 -> 106260 bytes app/fonts/fonts/fontawesome-webfont.eot | Bin 0 -> 68875 bytes app/fonts/fonts/fontawesome-webfont.svg | 640 ++++++++++++++++++++ app/fonts/fonts/fontawesome-webfont.ttf | Bin 0 -> 138204 bytes app/fonts/fonts/fontawesome-webfont.woff | Bin 0 -> 81284 bytes app/fonts/fonts/fontawesome-webfont.woff2 | Bin 0 -> 64464 bytes old-ui/app/css/fonts.css | 340 ++++++++++- old-ui/app/css/output/index.css | 341 ++++++++++- ui/app/css/itcss/settings/typography.scss | 338 ++++++++++- 10 files changed, 1657 insertions(+), 6 deletions(-) create mode 100644 app/fonts/Font_Awesome/font-awesome.min.css create mode 100644 app/fonts/fonts/FontAwesome.otf create mode 100644 app/fonts/fonts/fontawesome-webfont.eot create mode 100644 app/fonts/fonts/fontawesome-webfont.svg create mode 100644 app/fonts/fonts/fontawesome-webfont.ttf create mode 100644 app/fonts/fonts/fontawesome-webfont.woff create mode 100644 app/fonts/fonts/fontawesome-webfont.woff2 diff --git a/app/fonts/Font_Awesome/font-awesome.min.css b/app/fonts/Font_Awesome/font-awesome.min.css new file mode 100644 index 000000000..ee4e9782b --- /dev/null +++ b/app/fonts/Font_Awesome/font-awesome.min.css @@ -0,0 +1,4 @@ +/*! + * Font Awesome 4.4.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.4.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.4.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.4.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.4.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.4.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.4.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"} diff --git a/app/fonts/fonts/FontAwesome.otf b/app/fonts/fonts/FontAwesome.otf new file mode 100644 index 0000000000000000000000000000000000000000..681bdd4d4c8dddbaeb4d4f2a1f58c38cad92afe0 GIT binary patch literal 106260 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�*6&+dD#Jbd4u^zH8F41{vx{Ptkc4ZF<7+Bv7~&BL#TD!4j2`mDQ|Hn3y&T;WBUB`)G-Tuf%38Y4tY!f?x_HOBnj^*=pZ)#1ylZEC1i08Pun3NZ33<$* z?2J1iry>3}`_{Q@}^9!Zp zYavi!*_MqEYn`&1%ifZ)Ws8xzcmI{SA!dSG*X4)ty^X zcQ*X*Cfg|9E?2BoOYMS%1=$5m5IW;R{dAibYPI3-V}_X3YgJDn^|bGDud2(CgJT8# z!YY26^!J+SlVuQJjM_9RGEjaSQRyv+fu^~TH2Npk&;8>@?cw!HDnWdS^jeCSpjcmv z&-KW{Rwq=r=Py%w)M`JM*S0wjL*I6OXj&D zT$7J~pEa^-h-vZSgy?1Fx*20DM5!pN|MLF4ckACaMMkEkL_(|xsp5K3hPD+^ z$30u%ceOpF4`dKxE$F5u9jA5_UP-bIeOUbU9z>S;0e!+1U&y<3$w-F@`q1BJedTvV zE?Kf5cY#R{hkmX>lN=B|3DLmhvmdxC(c_PgGzEcL>FwK~T{>KLct@QH)=87$>WP^n zW0E72;>^sSz2xSF&s!a07g&%#xkc~|(j(l3o!c+o0rF}sWd=>M*PmE24bI>hY6XYf zs(h8WU6R!*p*@S{*fd`M^St>HD^{61GAHi3z|w6pmsFfmTw-ke)R(n0H1%u|Tl6Ag z1>iKP*t%!)UU(z<&yP(RJ0@uASTmcCYJ5rO^G9p9Rqr$pE4Vo2hUwgyeWyWC(4Jo6 zdJ4gblQ&M4`?4pT{^yUQr_3764L$F)6+s}F*1EMRv?jTNm}&g2or11Z;ag(3)IDGwKO3zF+3r{ClPqEgc7z& zDfKR}BQMySd}Q=SWE^|Hc@n2Na1!JeQdL~Jq-b+Vy7{Q`9UZTJ$i?IoBovxx8-8;^ zE@FC+n)Ur->H{t^y=Y?zQf~5Ajp;QfH#0BIs^xdk*nXi&)q@in9Ggy!J8icOy`~2D zmSNx8Pu=+IyAoo{&4<^O&z)dA12UDAoRsX8Y~9Z%F8)s4jMR4+AQoJ$Ts(iK6+Q8I zOLz%2_LZRTf+=&d>d3`r7bN0|-r@_uIhAeBv04g~@^va;W(RMVr9@0SStpBRsW>yXuPS2^G5d?bHV6p3g-?e-nITu{UKbiGwV+*d-{p-RF9bg0qAB|K#rjc*hylkxvG!qk`5PWLsYD18$ zR!dhK0*XuQ2a{!{+4i0@b$i|!73tQwvj%YQ{2VZT_viRDgAla5X_aC1>7hru57Jqf zz7v~+MgPJgcfUP!_Ub7iy-v-h{Ggx5P-E!B_#s2QJ9g^Ub;O9db1fg$%q!gJeR$qg zOU+?Sz_xn-+VPjJ*GAOXcNA{+K7816bzTi3u*Alw`>nuME0U)^354SAxwffV`$`okfuvh2 zD<#6i5jXsiUc33EVfpgHt?SKdSH+tP-L?@7X;+n6Df9TQ0 zvoA8!>%7x4)Y(~Fge7dF@le|H@V))iG0hp?>rVlgJR|fox>y=eAPfLqQUz@g(dZZj%v2>7bI^*7C3&ZA*rrvX2jG!HsUA?yBMuzUVpysD@>n$52 zjW^SNN~{h%-JSMP-A{EK4K#cYc4$(&fuIvRZW}z1j#&I9b*a0ar8}kG6Qa`B#2WvV zj_k-iYy9Z@YCAei^~Kt(ORERwT}CK&7$)4C;5`VZCz=AiG0Hr(t)#BDn5RySA0Zn~ z^|Feki`Fh%vUu;>ebp6v_sPW*46z&3K(*`4*)W>i^)B41j8ZxuuhY>}pe8$>bUgl; z{P9LEDJ?E5*O-@{W6hAy70#uD+d}|#dF~UFuqrs(l#rB@n^$!_H{W~{>ed?vnbBks zX3a|46k;y^2-!^Gk3;IxjJ#BH)HODA9(%i8N7mJ+a8v!NXd_aZCTyC%FDFhO%D7K} zX*3#VWY4tDl)oqj>rZ}if)P|gn^NWBQMH&jID%flud`2~b<%L! za}5jV8>W*dv-3}wBfsFX)3Wk&O?f$K@t{l{Ne3gB5_Nb+yZOZA&e*;gL`Hbx+T}_4 z@)y+U0P5@w7+b`A?+-!Df<)e|*AMK?`>f|7);&$v6r*-Eyv^EAV($aQtOn7q zRY4i_5ezBFel>qS&|>^sbes?PO#L`t{vGzdLCsi=*X^IdA`vSx%t!6o47kto!8+_$d%$ zZ-8abpnR+ZBq9@50OE+ZvS%+~G3ojn%MD|ppS&1y>~BXO4Zh0?d$Ym4*%0;u`Nj%B zfb&7r%fEj`J#;_D7oD{j3yv;6(I?wKJET8zU(cL3FozdM5d~o$=^aHUV9r!={EEeR z;8f#>&B7l2PW3fxiP~6z(#XMGuAeT#taY+@2A~- zIpx?Jw%K6mmfmFBW)Azz|Hd}zcb^VJIt`2P5+QQ$BA|QX3|*-07F;;rJfUWgJkU2E z^<^E+${mFmF45q%v{Spoy253Pau%e5BnwTObxdU=2e9Gobn4*G!QPR+LCw;=LNy;p zfPMZw-CA%Dv%XCeoBJy+P*eIccg0L6Uc8};J6)dymSvTGhUlkr|1zte@*UTG7|2?i z*yuSJOS+mHAT?*r>_ZK9vFr3(iYo{wzF0v{!Ye!7djGI+Vwmrg19X>e;cw0OpLC9;d*cu9z)7EzDD%a2(upzsPj|_jEz!I*6*pV86zIZlW>8 zrV>yq#n2=ZTm$Yvm5xMDq`xC9{d@X|UV8|uvD*bhQyBYAokfqaV{~|U;j-wR%fPt) z3sQU>Qu>;dzQBWRIK0=q_i$*%auAHngM~h9N2jdO38Odp&9{c?^bfM)tyxF1>awV7 z$&MvE7LQ{7F{@)%mn3W}(`_w1ShwSnZpY=~M^WYQ?knRA%0uBrSGWy+he2u_;`gS? z^!O_73WV5OS|Q(xV{WTJ7$dOY1T`#3eaonhQci^=fLv%S2dvfH$O}K`j{A z{~fsRx-}P=f5m^Cq&C3H-q05wJ2mugB6c@ErGADMxGx(|$9qF(A8${>QRp-CSWID< zWn+vFf}yd{@jwnwz&HE@(Tf8oP;3D4%QY`$Rrag-a&IWtTXJv|&OC--2JL)xygJ^S zt)i=NehsVH98+%DT<8OwnH90Vi<`#(4M7v|jEABg`XD21Y-Mm*L0Nwc3pwXT<7bOG=Vvoeio%F2S^i(a!PE6@_H2T&qu0!*p7449z;t1JL^kA1m64B>_AGQu{gDogWLRhkx=8)=D5@PS*< z%B_u$T&uaMV}=nz%dI*=kH0(C8FSu`Rz^=0Eh18%>(WmgUIHM9WzRQp%wSAzXV4DpH;Z{-l) z#Dlhnq~@1x0Xg+;3=m>+V+#^x#fryE&B{*8Hhlo_d%aMYP!O9VtEf~iBRL74Jk&6p zjhI-#Uy3vzEq||&qwso&j*0wtfAf zqP1m%1qe4ktZssswBH{*Ldhc9RioCX=r0EKF-&N1Qz(xF)d~i5l;s56ODO3HY}@xM z)<#5lYa8mL{~Y|t8OQwRJlC!Fefb$^TKgL_4f%A@KuE#?*=&6-CZYNPtXNlCd)Ru& zbpOE29`WX+i3{Hw!5nnVVfd8Ei%lW(zoGpXm}5?aQjcYH#&SC51HhkSCMETs(Z2h@ z;RA;Z7<#v>_vwb(%0kn*dVeY{->+y?-)cUON_K4~G$13`J!(bmHZ? z^c`)YL{}nJX!COeyTQ(53VEKcwh_ddoZ@UisjgI@VzL ziLZakRq^$H+)sSrl7N1k{>5H~hTiUcyN}mY?xlRdHyoz7Z4IMS7mqU!5H`gmAf;a< z|A_{3ov6OShb5$xrOLExG}lKBdL%UDa%CCWIa`d1r;vx-RPu-LLfzu&2S40E1ZnG+ zD_M6Cy07Ohr$-jgH7UP0VHW-JA%DY))AF)#8ZQ*ZSvO|M{kB!S;OH*3ln;wf-I5}o zjR)D=|6^IT6Fm{(mR7KaLWce%yd}lQ0}nHVXs52!!d_* z4i_D6I^1!1>hRn_aZnuvN8;$_*u(K1$G(pJ9j7?Xa9rrP!ZF@4${#kp z-)dc}j8?_1%3B?5b)?muR*zf#*y`t2wpPtfoYR|5ot(Nkz3ud&(jIu|(abl&TH(7D$6g!38abIzBYZ*m>Eu3UGn7xw`-m>bR|aOK=iZZB8Mi@XQ# z&9~z_@PYhhej8uKAK;JhC;0RHMg9T*n13ep5&8=s2+2a8P$Fy-b_n~0L&8zvr0|(= zO}H(5C48$Bblr44bQ5$_bZc~xI)psx3UwvAZMyrqhq@niKeslv{#)zLt>0}utaV`P z@vVber?oC>UEaE~^`6#WwSL(8H<1%ti*8~!vA6i4I7M6vLvDnaBW@PAi5JDMi8EZT{8fRhvc^Z9Wt|Q} z@>kAy0JZ$9B+?wjzbTSGhh;M;fka}^)R<=-ViE*6D}0;`|{`iS2d|x8Ux}m zSl~(9_L6|%9fLgWEt9UInIJsHfTg#Yghxk*V-r6?1CYt06)P5jP{~fYMlD$EF^u#* zNqAc%MF^`9CgOs9MVU;NSVIpa7yM8p{1Ax@#8u%yv8q8MFygbIKtPu+8wN{(S{z2; z4CyjY__-n(B$-KwR80`%jVL1*33UA0>SGC62i2NCvknRaC9(?2;K%qMAQ1!%B9zqr zYzSYs`^-TMHxKF{DNDkCbWu2|Ua@--;R8h!PbNZ?L=0NVw8O)rp&i0;URG382EPnn zRumnMZReR1DP{&xg36o9;>u!5bk_3P=Viu>w9J$YIX9-=r6f~g>f*)A=dYaa6PJ!9 zE-o#uO^4#RfM**`N$mm?W6UY3X(_43h}urpFgYeNE__qCE-aN9qN9wgoe)J0(dDUf z-iG{$!bn|w*qlxg#?8Y4exQi}TI-X;|_>u+yePRQ{KpH=D9wUCu2u zXJ({lWE#unJdZDz3rq4#^S0>9GpM1c*hsXI84EOo|B=s{^h7jGZ2uPBkW}y9T}}L2 zK#_hen8>FWL=q7d6+!AHb%DCzrKH#wRYLfPmdMBMdN_3|S|ZC3L*e}TgG|F4GjtHi z>!b2uT$G4bhXi__V3o+9k)^)VsmJ@6+rSdctr68A_;lV94LwB?h87bmWuQfS`%M#{ z`mGk9K1D>FpVowe(1e1}gaF|TkQ%+(E&@trHeFom<1(%9DgD%?cRvjbbqsX zI;`n37rkP}2g~SiV7&OlV)I*ketFT>3S&ilW%4!|4A-vQzO3!Ls*J86)e7=MVR&?j+U@maj39I`6M5&plPXZ(F&J zeYk~f(_Ln(KQt(R0i1ydld&m&#EZur! zwl!$}Z(5&i?*u_xZcdJ$SbTFrCxQeQ5X7mA5prS?Jd&opy9>8gn3XZgKxK?NkXv7|J9e+BxHu!H$Xr*ttLCWDmuoE? zU0D-SD(6H;Wk#7?7fQ_yX?974xe(FH2&4*`Ee$2e81nbCpcw;G;Rga{IzQv5Ig%C8 zXxPMVWJ+RZO=JX8u<3th0hKyBM%2)S(U}{wLBvruALGCR7GzYzU_=as@xw!2o4c+s zOlD(QpN+9;VFl4X-})6qZ%x}=;NvTd_vI&(STPPcR#!>{93Bag5$Gp`?;?^lmGh9R zlAwL`Cdv|vvRGMUByD3bxcoP$nT`44f&S?i`in9EqXZ-} zfh;C)n0NzxH5ajjGuVJ3<3#PUaaPT$ZFIeZ9=RuA1FbrhCeMS_yJ83`B(|8HY4Z|u*wcWmOAqyi5@q(0zKB83v(0}jIxx8-s3D~oG(JLHv=9M|*YYCNaCZ+TfpadF_lo&Cc);uE-G83{Aa}sUS znx=VIt|_-x8_7b9WQc)6Z!1AxGh?vgr?At2$;zyxI=K|D6DltND$NfJinKL${7x{P+@ zRRwr12F#o1&;B73m=LT>P{B|Upd4%>|0CV2b~Epm%(A*a6UJ(m0S*H*!dfk8S{O`W zSJsFkNF%~>4a|{;qw^$iljR&-!2^-%1#p=SYvv>&`$KAiPYMs^48|A8ym69+1rh#7 ziSTJ6vCM}QtOk2A_>0jPyjoDz^)M-`{{AB1a^z1A{r@J=Cz|r$y+$NLt|pXte88Rp zxP}*=SM!#X-sNK|V?5{QbM(L*Q*Va&80JOB)gELl0 zsuc}P1B0s#cq9JgwMDDN9z}YImp>K>g7W(j1gj!OXc3`qonA0EQkqZ_Q%G9yBQPuC ziJ(CgMU_!#>w*H$Bv+JeEi3}cSwOJYrW|=wPHaYeib|Nyn{X+4d8v7(f`ZI!tGP74 zuq1Pf7BK6bRT;N^eX)*!AMa-^?!@d0B0tx+nCCL{o9esVO1>q?1k$9F^c0=wFGU1h z2wRQynp(mIV9NsD#B7A%X47mvsIHueohZ!SBM2amu%>!BY14Vl^h4-a5rQHj667|h zKm*ngCZ*u|e%Z2PyV{Hi#p&u*%ibfuie<$coT>@yC0d~k`Cg!W*PiAY zA~Xoc+NV=3WlDR~IE3j2Ey0Tgh#$&2X|X;vT1gfXtV`k#J&CUpy9@(6kj7AHZ~(d@ z@_QtvB>0fc8(})#>_d=X`S6-bjCYp9m6gPrfOIxQ7!EA}128cR{CXN#K3$E}^(1Ze z)z|V@{ZGP5?+S?*jDlf))2L~r8i|D$Stc3?fBVYHcg-M|ykdw=jYrCq;e32@t~G}k z9#b1vkXc?*XtG)P!t%)2Ot7HYIP#8A9$vV5l~I%C+SswPa7THW{1|P|O5;T`QN&0z zT)YPn6-~EEMZ_>!B5T%I=2fo2Xl0p)F&gicCp1!GkRHNNiKK~T5b7-qeVtku`iMrh z1rAVE-+V|DB8KMg|W)$jJBKAEcxK z=OM%bA~H(~vJGsZ|Wtf`5&PV9sKLWts*FlSNKF&ID0qtoGPrxvi z2!^p7FpLq}4yx+@=zXEvWz+=}6}&iTxWq6qX#S|TW?sB?yYBprd)NHmlhs$`5c^eW zp8Zd`Ja*mYP*do-jbX87(q-u2jvX2Xy^x<=x|VLr&CAcqPtyt=2ZL{A{`NA={yu{V1Df1W?JYpzBZgr- zi?DU$SYNE0x^ctM7&V1NBNWg$2(+A~GC>XtWU^2OpbNCeYixl0BI>{IHbyu#ULdgB zYm86_h!OK~=Kj1hbtgZeSZ%fV&U?CfBi6q^&`6ASh*2tamgD2n<4tqYNZrB%AzDO0 z$bp4*bq5aA$>hkQ{d49lT0DDB^`hF^>grmVbO&wJbTPXyb90fge)f^cgl3DoiJ%1v zc_H`)F*yPFMs5N+5b`DM0Dj7Q^QOEo6XeVIf`zjKtncr@boA{`;>xxpmz&DBWaXEk zGt*GC=6aqC1oe+V(lk?emPp12oHZ9lSi=h4O1)x5 zV$UhDzXCZWPH)??hkzBrgl9596fi5EHdOHkZ-PG!^?IPq!T5i}DsK0A5H55(COQ@9 z&$FAyaP&Jc;5Cln2q2?xplP|i=tSK#V~%FtAT$V_Jys+0A)O@ZPgnzjkx&-s0@?_# zEyP!d#oNo2aO=O+W!w}Sm3Yd9NXUbBQFmZr2?CoW47RDWPYSiyY~Kovwip7AFt5zKY{GhP<%Xw==74J zQWN1zOQOTm%_JF|7G@$)C<6;LW=uSc%}UVkyhwy8B9h3!aJQ6DYfddzY$Dt>Ft9M$*{}*M)a-9GG literal 0 HcmV?d00001 diff --git a/app/fonts/fonts/fontawesome-webfont.eot b/app/fonts/fonts/fontawesome-webfont.eot new file mode 100644 index 0000000000000000000000000000000000000000..a30335d748c65c0bab5880b4e6dba53f5c79206c GIT binary patch literal 68875 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

7r8$?kb-D3z%-c} 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 F002TuuHFCu literal 0 HcmV?d00001 diff --git a/app/fonts/fonts/fontawesome-webfont.svg b/app/fonts/fonts/fontawesome-webfont.svg new file mode 100644 index 000000000..6fd19abcb --- /dev/null +++ b/app/fonts/fonts/fontawesome-webfont.svg @@ -0,0 +1,640 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/fonts/fonts/fontawesome-webfont.ttf b/app/fonts/fonts/fontawesome-webfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d7994e13086b1ac1a216bd754c93e1bccd65f237 GIT binary patch literal 138204 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 literal 0 HcmV?d00001 diff --git a/app/fonts/fonts/fontawesome-webfont.woff b/app/fonts/fonts/fontawesome-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..6fd4ede0f30f170eecb4156beb7235bf01fff00b GIT binary patch literal 81284 zcmZ5nW0dAhw{6=tra5ifoc6SB+fUn^wr$(CZQHhu+wb@DX02T(d*__0q*hjvI;nDz z6B7dh1_A;C<_!cw_^}|k8~@`!yZ?U^6H}7;aTNK{@&1ENMg)_%h^W|)ruV}M{s#&W zZ#hMJrXS7shx7hGFO$}3^;lfddE#vpEoI3*cgGVDi&foU;C{|wOVrtHrDj==p8j30pfFkldupAzhU?5A*DGt@J2G|A}c8SCkr z>o=I_>6wAZO%21w!fMC5@%113m4gEjR1IeZ_w5JA1|b&1KoW-n4j~5AferOvwXSQE zah+1@_DDn5n5dd0liHfPDAc#fzU7kNzDRb6*liqG%p4(BHpD)HH}o+P&d>^62?%?n zvT^cYhB@H6YiGR6$gT}{I=1;PF2U6KvnG>fX|Sjq<;6yR`Oi zzfj`_B+|da`W(r5PMLbX8ClyMhtSxjT;=Fc#>{N{^}>E2KALfSaWJu>$b2v(cP(#e zQh?N#{q#Bz@Xx&p;=0!11?{P{xcJik+-3Zf%5K{vO&*^*kp>pWUBalJ(+NlJQayb9~mb9}|No-GXO8xq>8P94Ck^I$vs&07w4u$Fr{06>`ii zU;f%Ii%-7FRos!|3ghm|RV@YA|Kt~@jOcE(ovW$ih<5q>VjWj50>YUYMD#_?PB2Es z+0ba9CdQDvVk*rTDJorTdgtjJYqCume06DZB~{d;*e9uJ-Qapq&uQ<#o=I`N+wI^@ z*lwCj7;_ou$oQiK=-vwep`Ps^7aj#Ouxh;p=#%)wLKv=>1aFYdgB)*18$baU5I$W_ zSmIJnNCd4dT=1ntUP16acK%#a9IflTXirMSj}oQpOrn9_8v`VvVZfSw7M+*K9#zzG z*5dw_wcMRY5I(cID|UxMVV9A7zK3D2C4xbwQ@3M+1&kIhmdCid>t8!HlGzf}gBL0r zvVQn<&uo{MZp6H5laSarDlzWlu9tJ?7y7o9Ke~Z#4b`X}E5%pVg$Ye*lB=f@LzL!J z>|k;@!>)_YjZ;U95Qs;+8jNteXlpVxU46})c&^>urAqlwg@{CV!Czb4YQ5Ibbi_;X zvHQzZ1&uH2(p}vY3GIG|H!B7t9zSP+2B!Ro&G6-C8kIu_5PqCRoE% zq#LMnW2Hn^H>X$%O!aI@@nkVS6uBr#B+!AI+!n%zRkFk~icobqX8@!DRy$h9`rgq*J+u^|#@mEq}83ofS&jJVXsFUrTiil)0~bwFSt z2^#7(U>T9H>nrB~&gjVIV(yvldtghB=6cb^IwKvLgRJo;_^pzCOJKA4vg3X#^E7gu zzDrM~gL4zk=T;q4tHX=rH6P;}Vi@~0EzYb{rKC0Se0OS>Zl`Jw;P`A8ZT~%FFT{mz zEe3CZ@6cjG1aw~i5}OgmR6b`Yazsf;T1^2V@CpbC5Y^u#eXdt8EhT<$gaabQo#Yutzno)XVD zLr*oeR}wFc<-P=_90Uv{!-4rdZMvHuT?WM1PZJ@qVs3NSV)5L~p<);eGF5fX8Scvc zZ9E0e$H7cmn~R=nRtDMoJ2ym}7sd7&y?A3+bFW>P_u^h2GHlPIH2cFEI{a?ak4>?A zy7&ua8&Zezc`UXY3h+gQxz|$DA2tx2LNHsGUs~a9^-32~Anu=;Sn(zKnW%yi=3lOa z8*Yd>KcN~ z?S(eQ!gl$0?$_5q)i5HPt_oodoApYa)Ay}v^tEoAv2Z-=-|p7ao&7=2?;`J){#Uu# zgmzh??c%Or_i8A$v~)UH8qdo&nHW3=>$b1PAiwdnG+ICE1p8pGe|wR| zpTX%AfHC3!{Hi-DzDys9o;o_dNb(SZ@KT3@ z7xLjAS;Uh~yhMf2VwNygc>$7H|R>k-aM1e(2UcBd; zxCDH**B3m4HiTRs-4y8Cls6Fkatg!(J^@&?oc51D5r5C-ZhQ!0_CSbrku7D^jAuaC zlTPwzosVSsB+cUI(4I(_d87+=1;+j)ql9UuZFS=Zef^|~=ad3!w(*R|wPWg}A?kKz zbDB(Zpt?adI*K7?Yalku;Ai{#bB4$WT<&5u!ma%?`EM;m$UI`NDtGGfPT zX#))!7cBJ+w6ycdY0?mmF9iKbX9L0b5}Be>8%O=J06>DBI=q;PU44rbD^G!YQc(R1 zdX5jiw`4Pb1TAnDJ}j<>sM5bCaLkfx{6rH=7!bTdYbCquM{a){a*shx%xTbw2KhHv zhN)zm?au*KyRn|vHN%b~D4f%rV`ca$bo~k!W+5#Ar38dzob)O$+tay)P){f72DbT} zafu(OxBqjzdb=ybGjs7P^$!*LYlODuH!Fi)GEAW2%A2WnKveQgbpt_b9grC@fN6lT zLjDX#ptOOI+nC*o$~U|06}hJsNOh361@bf7CNnj~dGO1id(>#j`Md`Bo3e)MhCmai zn@tbzFDP1VVJIDr5RXu|LcZ&f5O31W#9sF~(h@z(!r2W~^>fH}k(VO7SL7XVLuaCF zEeIMzh9*$sls!~|W?aB5RtBdAy?@<}Km8T~|KOBTTr}d#Q%)vC{97Hgb^!v=UjMC! zC+O|G8xDQnD*p4N%5@2I?rD)CfM5#1GJ-`|P{)Q}<06MWXw~Rd491pG2@Xy(awP5t zXWCzr-nWFn&Fv>6w2mCiVu!`!D)~8B8UQJm`|{gq68e$Rx$|x1AL@zF16W%OTq$}> zZp~jM;>BJC1W!TdIaG=j9äY>7uxS6S37IVP_>DW-kg%dn+sFHLnFhvXTU%&ox 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 ZUtABnb?tu62nVk>KX+wfW(Hek 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 o-IM%8o*ehr=#Iq=Q0BvwUBdJ3D Date: Wed, 28 Feb 2018 14:04:32 -0800 Subject: [PATCH 097/392] add token - check for logo url before trying to use --- ui/app/add-token.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/app/add-token.js b/ui/app/add-token.js index 3a806d34b..230ab35fe 100644 --- a/ui/app/add-token.js +++ b/ui/app/add-token.js @@ -240,7 +240,7 @@ AddTokenScreen.prototype.renderTokenList = function () { }, [ h('div.add-token__token-icon', { style: { - backgroundImage: `url(images/contract/${logo})`, + backgroundImage: logo && `url(images/contract/${logo})`, }, }), h('div.add-token__token-data', [ From cf6a2f65ab38fe84bcc8218aa9088ff4cb6e5290 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Feb 2018 14:09:35 -0800 Subject: [PATCH 098/392] changelog - add entry about 'Add Token' screen fix --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index abc89f9c7..d33ddb2f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +- Fix "Add Token" screen referencing missing token logo urls + ## 4.1.0 2018-2-27 - Report failed txs to Sentry with more specific message From 190389a068b9005b52e9012bce48b93397007e26 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Feb 2018 14:26:14 -0800 Subject: [PATCH 099/392] v4.1.1 --- CHANGELOG.md | 6 ++++++ app/manifest.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d33ddb2f0..c34ea510a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,13 @@ ## Current Master +## 4.1.1 2018-2-28 + - Fix "Add Token" screen referencing missing token logo urls +- Prevent user from switching network during signature request +- Fix misleading language "Contract Published" -> "Contract Deployment" +- Fix cancel button on "Buy Eth" screen +- Improve new-ui onboarding flow style ## 4.1.0 2018-2-27 diff --git a/app/manifest.json b/app/manifest.json index eab6c7063..80be01759 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "MetaMask", "short_name": "Metamask", - "version": "4.1.0", + "version": "4.1.1", "manifest_version": 2, "author": "https://metamask.io", "description": "Ethereum Browser Extension", From 00cd5a340d81da7f3cd6098ca6b16b4400c71efa Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Feb 2018 16:11:58 -0800 Subject: [PATCH 100/392] 4.1.2 --- CHANGELOG.md | 4 ++++ app/manifest.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c34ea510a..59f116aed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Current Master +## 4.1.2 2018-2-28 + +- Actually includes all the fixes mentioned in 4.1.1 (sorry) + ## 4.1.1 2018-2-28 - Fix "Add Token" screen referencing missing token logo urls diff --git a/app/manifest.json b/app/manifest.json index 80be01759..1c9c420f9 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "MetaMask", "short_name": "Metamask", - "version": "4.1.1", + "version": "4.1.2", "manifest_version": 2, "author": "https://metamask.io", "description": "Ethereum Browser Extension", From 94a60fe4a951b15e46baf928d79d9a8aad20145f Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 1 Mar 2018 16:31:38 -0330 Subject: [PATCH 101/392] Correct ttf format name to 'truetype' --- old-ui/app/css/fonts.css | 84 +++++++++++------------ old-ui/app/css/output/index.css | 84 +++++++++++------------ ui/app/css/itcss/settings/typography.scss | 84 +++++++++++------------ 3 files changed, 126 insertions(+), 126 deletions(-) diff --git a/old-ui/app/css/fonts.css b/old-ui/app/css/fonts.css index 822f8cfc9..b1d701ee5 100644 --- a/old-ui/app/css/fonts.css +++ b/old-ui/app/css/fonts.css @@ -5,7 +5,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 100; - src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('ttf'); + src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('truetype'); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } /* cyrillic */ @@ -13,7 +13,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 100; - src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('ttf'); + src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('truetype'); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } /* greek-ext */ @@ -21,7 +21,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 100; - src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('ttf'); + src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('truetype'); unicode-range: U+1F00-1FFF; } /* greek */ @@ -29,7 +29,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 100; - src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('ttf'); + src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('truetype'); unicode-range: U+0370-03FF; } /* vietnamese */ @@ -37,7 +37,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 100; - src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('ttf'); + src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('truetype'); unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; } /* latin-ext */ @@ -45,7 +45,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 100; - src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('ttf'); + src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('truetype'); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* latin */ @@ -53,7 +53,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 100; - src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('ttf'); + src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('truetype'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } /* cyrillic-ext */ @@ -61,7 +61,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 300; - src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('ttf'); + src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('truetype'); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } /* cyrillic */ @@ -69,7 +69,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 300; - src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('ttf'); + src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('truetype'); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } /* greek-ext */ @@ -77,7 +77,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 300; - src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('ttf'); + src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('truetype'); unicode-range: U+1F00-1FFF; } /* greek */ @@ -85,7 +85,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 300; - src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('ttf'); + src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('truetype'); unicode-range: U+0370-03FF; } /* vietnamese */ @@ -93,7 +93,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 300; - src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('ttf'); + src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('truetype'); unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; } /* latin-ext */ @@ -101,7 +101,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 300; - src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('ttf'); + src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('truetype'); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* latin */ @@ -109,7 +109,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 300; - src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('ttf'); + src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('truetype'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } /* cyrillic-ext */ @@ -117,7 +117,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 400; - src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('ttf'); + src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('truetype'); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } /* cyrillic */ @@ -125,7 +125,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 400; - src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('ttf'); + src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('truetype'); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } /* greek-ext */ @@ -133,7 +133,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 400; - src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('ttf'); + src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('truetype'); unicode-range: U+1F00-1FFF; } /* greek */ @@ -141,7 +141,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 400; - src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('ttf'); + src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('truetype'); unicode-range: U+0370-03FF; } /* vietnamese */ @@ -149,7 +149,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 400; - src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('ttf'); + src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('truetype'); unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; } /* latin-ext */ @@ -157,7 +157,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 400; - src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('ttf'); + src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('truetype'); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* latin */ @@ -165,7 +165,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 400; - src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('ttf'); + src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('truetype'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } /* cyrillic-ext */ @@ -173,7 +173,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 500; - src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('ttf'); + src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('truetype'); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } /* cyrillic */ @@ -181,7 +181,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 500; - src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('ttf'); + src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('truetype'); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } /* greek-ext */ @@ -189,7 +189,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 500; - src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('ttf'); + src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('truetype'); unicode-range: U+1F00-1FFF; } /* greek */ @@ -197,7 +197,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 500; - src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('ttf'); + src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('truetype'); unicode-range: U+0370-03FF; } /* vietnamese */ @@ -205,7 +205,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 500; - src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('ttf'); + src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('truetype'); unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; } /* latin-ext */ @@ -213,7 +213,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 500; - src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('ttf'); + src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('truetype'); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* latin */ @@ -221,7 +221,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 500; - src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('ttf'); + src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('truetype'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } /* cyrillic-ext */ @@ -229,7 +229,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 700; - src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('ttf'); + src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('truetype'); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } /* cyrillic */ @@ -237,7 +237,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 700; - src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('ttf'); + src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('truetype'); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } /* greek-ext */ @@ -245,7 +245,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 700; - src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('ttf'); + src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('truetype'); unicode-range: U+1F00-1FFF; } /* greek */ @@ -253,7 +253,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 700; - src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('ttf'); + src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('truetype'); unicode-range: U+0370-03FF; } /* vietnamese */ @@ -261,7 +261,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 700; - src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('ttf'); + src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('truetype'); unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; } /* latin-ext */ @@ -269,7 +269,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 700; - src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('ttf'); + src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('truetype'); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* latin */ @@ -277,7 +277,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 700; - src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('ttf'); + src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('truetype'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } /* cyrillic-ext */ @@ -285,7 +285,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 900; - src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('ttf'); + src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('truetype'); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } /* cyrillic */ @@ -293,7 +293,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 900; - src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('ttf'); + src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('truetype'); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } /* greek-ext */ @@ -301,7 +301,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 900; - src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('ttf'); + src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('truetype'); unicode-range: U+1F00-1FFF; } /* greek */ @@ -309,7 +309,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 900; - src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('ttf'); + src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('truetype'); unicode-range: U+0370-03FF; } /* vietnamese */ @@ -317,7 +317,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 900; - src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('ttf'); + src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('truetype'); unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; } /* latin-ext */ @@ -325,7 +325,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 900; - src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('ttf'); + src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('truetype'); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* latin */ @@ -333,7 +333,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 900; - src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('ttf'); + src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('truetype'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } diff --git a/old-ui/app/css/output/index.css b/old-ui/app/css/output/index.css index a0e987a7b..bed689ecb 100644 --- a/old-ui/app/css/output/index.css +++ b/old-ui/app/css/output/index.css @@ -33,7 +33,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 100; - src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('ttf'); + src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('truetype'); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } /* cyrillic */ @@ -41,7 +41,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 100; - src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('ttf'); + src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('truetype'); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } /* greek-ext */ @@ -49,7 +49,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 100; - src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('ttf'); + src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('truetype'); unicode-range: U+1F00-1FFF; } /* greek */ @@ -57,7 +57,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 100; - src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('ttf'); + src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('truetype'); unicode-range: U+0370-03FF; } /* vietnamese */ @@ -65,7 +65,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 100; - src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('ttf'); + src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('truetype'); unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; } /* latin-ext */ @@ -73,7 +73,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 100; - src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('ttf'); + src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('truetype'); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* latin */ @@ -81,7 +81,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 100; - src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('ttf'); + src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('truetype'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } /* cyrillic-ext */ @@ -89,7 +89,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 300; - src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('ttf'); + src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('truetype'); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } /* cyrillic */ @@ -97,7 +97,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 300; - src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('ttf'); + src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('truetype'); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } /* greek-ext */ @@ -105,7 +105,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 300; - src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('ttf'); + src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('truetype'); unicode-range: U+1F00-1FFF; } /* greek */ @@ -113,7 +113,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 300; - src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('ttf'); + src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('truetype'); unicode-range: U+0370-03FF; } /* vietnamese */ @@ -121,7 +121,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 300; - src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('ttf'); + src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('truetype'); unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; } /* latin-ext */ @@ -129,7 +129,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 300; - src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('ttf'); + src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('truetype'); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* latin */ @@ -137,7 +137,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 300; - src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('ttf'); + src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('truetype'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } /* cyrillic-ext */ @@ -145,7 +145,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 400; - src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('ttf'); + src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('truetype'); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } /* cyrillic */ @@ -153,7 +153,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 400; - src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('ttf'); + src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('truetype'); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } /* greek-ext */ @@ -161,7 +161,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 400; - src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('ttf'); + src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('truetype'); unicode-range: U+1F00-1FFF; } /* greek */ @@ -169,7 +169,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 400; - src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('ttf'); + src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('truetype'); unicode-range: U+0370-03FF; } /* vietnamese */ @@ -177,7 +177,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 400; - src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('ttf'); + src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('truetype'); unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; } /* latin-ext */ @@ -185,7 +185,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 400; - src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('ttf'); + src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('truetype'); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* latin */ @@ -193,7 +193,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 400; - src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('ttf'); + src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('truetype'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } /* cyrillic-ext */ @@ -201,7 +201,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 500; - src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('ttf'); + src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('truetype'); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } /* cyrillic */ @@ -209,7 +209,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 500; - src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('ttf'); + src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('truetype'); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } /* greek-ext */ @@ -217,7 +217,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 500; - src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('ttf'); + src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('truetype'); unicode-range: U+1F00-1FFF; } /* greek */ @@ -225,7 +225,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 500; - src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('ttf'); + src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('truetype'); unicode-range: U+0370-03FF; } /* vietnamese */ @@ -233,7 +233,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 500; - src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('ttf'); + src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('truetype'); unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; } /* latin-ext */ @@ -241,7 +241,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 500; - src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('ttf'); + src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('truetype'); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* latin */ @@ -249,7 +249,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 500; - src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('ttf'); + src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('truetype'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } /* cyrillic-ext */ @@ -257,7 +257,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 700; - src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('ttf'); + src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('truetype'); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } /* cyrillic */ @@ -265,7 +265,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 700; - src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('ttf'); + src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('truetype'); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } /* greek-ext */ @@ -273,7 +273,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 700; - src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('ttf'); + src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('truetype'); unicode-range: U+1F00-1FFF; } /* greek */ @@ -281,7 +281,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 700; - src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('ttf'); + src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('truetype'); unicode-range: U+0370-03FF; } /* vietnamese */ @@ -289,7 +289,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 700; - src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('ttf'); + src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('truetype'); unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; } /* latin-ext */ @@ -297,7 +297,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 700; - src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('ttf'); + src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('truetype'); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* latin */ @@ -305,7 +305,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 700; - src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('ttf'); + src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('truetype'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } /* cyrillic-ext */ @@ -313,7 +313,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 900; - src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('ttf'); + src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('truetype'); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } /* cyrillic */ @@ -321,7 +321,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 900; - src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('ttf'); + src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('truetype'); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } /* greek-ext */ @@ -329,7 +329,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 900; - src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('ttf'); + src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('truetype'); unicode-range: U+1F00-1FFF; } /* greek */ @@ -337,7 +337,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 900; - src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('ttf'); + src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('truetype'); unicode-range: U+0370-03FF; } /* vietnamese */ @@ -345,7 +345,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 900; - src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('ttf'); + src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('truetype'); unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; } /* latin-ext */ @@ -353,7 +353,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 900; - src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('ttf'); + src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('truetype'); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* latin */ @@ -361,7 +361,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 900; - src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('ttf'); + src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('truetype'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } diff --git a/ui/app/css/itcss/settings/typography.scss b/ui/app/css/itcss/settings/typography.scss index 9d08756d1..8a56d9c6c 100644 --- a/ui/app/css/itcss/settings/typography.scss +++ b/ui/app/css/itcss/settings/typography.scss @@ -4,7 +4,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 100; - src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('ttf'); + src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('truetype'); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } /* cyrillic */ @@ -12,7 +12,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 100; - src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('ttf'); + src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('truetype'); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } /* greek-ext */ @@ -20,7 +20,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 100; - src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('ttf'); + src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('truetype'); unicode-range: U+1F00-1FFF; } /* greek */ @@ -28,7 +28,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 100; - src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('ttf'); + src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('truetype'); unicode-range: U+0370-03FF; } /* vietnamese */ @@ -36,7 +36,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 100; - src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('ttf'); + src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('truetype'); unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; } /* latin-ext */ @@ -44,7 +44,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 100; - src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('ttf'); + src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('truetype'); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* latin */ @@ -52,7 +52,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 100; - src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('ttf'); + src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('truetype'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } /* cyrillic-ext */ @@ -60,7 +60,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 300; - src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('ttf'); + src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('truetype'); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } /* cyrillic */ @@ -68,7 +68,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 300; - src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('ttf'); + src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('truetype'); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } /* greek-ext */ @@ -76,7 +76,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 300; - src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('ttf'); + src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('truetype'); unicode-range: U+1F00-1FFF; } /* greek */ @@ -84,7 +84,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 300; - src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('ttf'); + src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('truetype'); unicode-range: U+0370-03FF; } /* vietnamese */ @@ -92,7 +92,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 300; - src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('ttf'); + src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('truetype'); unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; } /* latin-ext */ @@ -100,7 +100,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 300; - src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('ttf'); + src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('truetype'); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* latin */ @@ -108,7 +108,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 300; - src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('ttf'); + src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('truetype'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } /* cyrillic-ext */ @@ -116,7 +116,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 400; - src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('ttf'); + src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('truetype'); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } /* cyrillic */ @@ -124,7 +124,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 400; - src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('ttf'); + src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('truetype'); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } /* greek-ext */ @@ -132,7 +132,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 400; - src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('ttf'); + src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('truetype'); unicode-range: U+1F00-1FFF; } /* greek */ @@ -140,7 +140,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 400; - src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('ttf'); + src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('truetype'); unicode-range: U+0370-03FF; } /* vietnamese */ @@ -148,7 +148,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 400; - src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('ttf'); + src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('truetype'); unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; } /* latin-ext */ @@ -156,7 +156,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 400; - src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('ttf'); + src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('truetype'); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* latin */ @@ -164,7 +164,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 400; - src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('ttf'); + src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('truetype'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } /* cyrillic-ext */ @@ -172,7 +172,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 500; - src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('ttf'); + src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('truetype'); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } /* cyrillic */ @@ -180,7 +180,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 500; - src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('ttf'); + src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('truetype'); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } /* greek-ext */ @@ -188,7 +188,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 500; - src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('ttf'); + src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('truetype'); unicode-range: U+1F00-1FFF; } /* greek */ @@ -196,7 +196,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 500; - src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('ttf'); + src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('truetype'); unicode-range: U+0370-03FF; } /* vietnamese */ @@ -204,7 +204,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 500; - src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('ttf'); + src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('truetype'); unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; } /* latin-ext */ @@ -212,7 +212,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 500; - src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('ttf'); + src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('truetype'); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* latin */ @@ -220,7 +220,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 500; - src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('ttf'); + src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('truetype'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } /* cyrillic-ext */ @@ -228,7 +228,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 700; - src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('ttf'); + src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('truetype'); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } /* cyrillic */ @@ -236,7 +236,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 700; - src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('ttf'); + src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('truetype'); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } /* greek-ext */ @@ -244,7 +244,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 700; - src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('ttf'); + src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('truetype'); unicode-range: U+1F00-1FFF; } /* greek */ @@ -252,7 +252,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 700; - src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('ttf'); + src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('truetype'); unicode-range: U+0370-03FF; } /* vietnamese */ @@ -260,7 +260,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 700; - src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('ttf'); + src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('truetype'); unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; } /* latin-ext */ @@ -268,7 +268,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 700; - src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('ttf'); + src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('truetype'); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* latin */ @@ -276,7 +276,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 700; - src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('ttf'); + src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('truetype'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } /* cyrillic-ext */ @@ -284,7 +284,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 900; - src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('ttf'); + src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('truetype'); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } /* cyrillic */ @@ -292,7 +292,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 900; - src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('ttf'); + src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('truetype'); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } /* greek-ext */ @@ -300,7 +300,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 900; - src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('ttf'); + src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('truetype'); unicode-range: U+1F00-1FFF; } /* greek */ @@ -308,7 +308,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 900; - src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('ttf'); + src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('truetype'); unicode-range: U+0370-03FF; } /* vietnamese */ @@ -316,7 +316,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 900; - src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('ttf'); + src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('truetype'); unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; } /* latin-ext */ @@ -324,7 +324,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 900; - src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('ttf'); + src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('truetype'); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* latin */ @@ -332,7 +332,7 @@ font-family: 'Roboto'; font-style: normal; font-weight: 900; - src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('ttf'); + src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('truetype'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } From ace4f0d998d75e9df8c31641a292abc4f703582f Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Thu, 1 Mar 2018 13:11:35 -0800 Subject: [PATCH 102/392] Fix exception thrown when styleOverride is not present (#3364) --- ui/app/components/eth-balance.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/app/components/eth-balance.js b/ui/app/components/eth-balance.js index 1be8c9731..c3d084bdc 100644 --- a/ui/app/components/eth-balance.js +++ b/ui/app/components/eth-balance.js @@ -46,7 +46,7 @@ EthBalanceComponent.prototype.renderBalance = function (value) { incoming, currentCurrency, hideTooltip, - styleOveride, + styleOveride = {}, showFiat = true, } = this.props const { fontSize, color, fontFamily, lineHeight } = styleOveride From f22dfd4ae8031e3f7b4972a1cc8f119b99007717 Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Thu, 1 Mar 2018 13:12:10 -0800 Subject: [PATCH 103/392] Fix network menu for custom URLs (#3366) --- .../components/dropdowns/network-dropdown.js | 40 ++-- ui/app/css/itcss/components/network.scss | 5 +- yarn.lock | 191 +++++++++++++++--- 3 files changed, 190 insertions(+), 46 deletions(-) diff --git a/ui/app/components/dropdowns/network-dropdown.js b/ui/app/components/dropdowns/network-dropdown.js index dfaa6b22c..9be5cc5d1 100644 --- a/ui/app/components/dropdowns/network-dropdown.js +++ b/ui/app/components/dropdowns/network-dropdown.js @@ -84,7 +84,7 @@ NetworkDropdown.prototype.render = function () { style: { position: 'absolute', top: '58px', - minWidth: '309px', + width: '309px', zIndex: '55px', }, innerStyle: { @@ -276,11 +276,21 @@ NetworkDropdown.prototype.renderCommonRpc = function (rpcList, provider) { key: `common${rpc}`, closeMenu: () => this.props.hideNetworkDropdown(), onClick: () => props.setRpcTarget(rpc), + style: { + fontFamily: 'DIN OT', + fontSize: '16px', + lineHeight: '20px', + padding: '12px 0', + }, }, [ - h('i.fa.fa-question-circle.fa-lg.menu-icon'), - rpc, - rpcTarget === rpc ? h('.check', '✓') : null, + rpcTarget === rpc ? h('i.fa.fa-check') : h('.network-check__transparent', '✓'), + h('i.fa.fa-question-circle.fa-med.menu-icon-circle'), + h('span.network-name-item', { + style: { + color: rpcTarget === rpc ? '#ffffff' : '#9b9b9b', + }, + }, rpc), ] ) } @@ -293,12 +303,6 @@ NetworkDropdown.prototype.renderCustomOption = function (provider) { if (type !== 'rpc') return null - // Concatenate long URLs - let label = rpcTarget - if (rpcTarget.length > 31) { - label = label.substr(0, 34) + '...' - } - switch (rpcTarget) { case 'http://localhost:8545': @@ -311,11 +315,21 @@ NetworkDropdown.prototype.renderCustomOption = function (provider) { key: rpcTarget, onClick: () => props.setRpcTarget(rpcTarget), closeMenu: () => this.props.hideNetworkDropdown(), + style: { + fontFamily: 'DIN OT', + fontSize: '16px', + lineHeight: '20px', + padding: '12px 0', + }, }, [ - h('i.fa.fa-question-circle.fa-lg.menu-icon'), - label, - h('.check', '✓'), + h('i.fa.fa-check'), + h('i.fa.fa-question-circle.fa-med.menu-icon-circle'), + h('span.network-name-item', { + style: { + color: '#ffffff', + }, + }, rpcTarget), ] ) } diff --git a/ui/app/css/itcss/components/network.scss b/ui/app/css/itcss/components/network.scss index d9a39b8d5..c32d1de5e 100644 --- a/ui/app/css/itcss/components/network.scss +++ b/ui/app/css/itcss/components/network.scss @@ -76,8 +76,11 @@ .network-name-item { font-weight: 100; - flex: 1 0 auto; + flex: 1; color: $dusty-gray; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; } .network-check, diff --git a/yarn.lock b/yarn.lock index a24806923..d9e456aa9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -292,6 +292,13 @@ anymatch@^1.3.0: micromatch "^2.1.5" normalize-path "^2.0.0" +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + append-buffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/append-buffer/-/append-buffer-1.0.2.tgz#d8220cf466081525efea50614f3de6514dfa58f1" @@ -1660,6 +1667,23 @@ braces@^2.3.0: split-string "^3.0.2" to-regex "^3.0.1" +braces@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.1.tgz#7086c913b4e5a08dbe37ac0ee6a2500c4ba691bb" + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + define-property "^1.0.0" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + kind-of "^6.0.2" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + brfs@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/brfs/-/brfs-1.4.3.tgz#db675d6f5e923e6df087fca5859c9090aaed3216" @@ -2144,7 +2168,7 @@ chokidar@1.6.1: optionalDependencies: fsevents "^1.0.0" -chokidar@^1.0.0, chokidar@^1.4.1, chokidar@^1.4.3, chokidar@^1.6.1, chokidar@^1.7.0: +chokidar@^1.0.0, chokidar@^1.4.1, chokidar@^1.4.3, chokidar@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" dependencies: @@ -2159,6 +2183,24 @@ chokidar@^1.0.0, chokidar@^1.4.1, chokidar@^1.4.3, chokidar@^1.6.1, chokidar@^1. optionalDependencies: fsevents "^1.0.0" +chokidar@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.2.tgz#4dc65139eeb2714977735b6a35d06e97b494dfd7" + dependencies: + anymatch "^2.0.0" + async-each "^1.0.0" + braces "^2.3.0" + glob-parent "^3.1.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + normalize-path "^2.1.1" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + upath "^1.0.0" + optionalDependencies: + fsevents "^1.0.0" + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -2929,6 +2971,13 @@ define-property@^1.0.0: dependencies: is-descriptor "^1.0.0" +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + defined@^1.0.0, defined@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" @@ -3432,7 +3481,7 @@ enzyme-adapter-utils@^1.1.0: object.assign "^4.0.4" prop-types "^15.6.0" -enzyme@^3.2.0: +enzyme@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-3.3.0.tgz#0971abd167f2d4bf3f5bd508229e1c4b6dc50479" dependencies: @@ -3801,9 +3850,9 @@ eth-json-rpc-filters@^1.2.5: json-rpc-engine "^3.4.0" lodash.flatmap "^4.5.0" -eth-json-rpc-infura@^2.0.11: - version "2.0.11" - resolved "https://registry.yarnpkg.com/eth-json-rpc-infura/-/eth-json-rpc-infura-2.0.11.tgz#134bf54ff15e96a9116424c0db9b66aa079bfbbe" +eth-json-rpc-infura@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eth-json-rpc-infura/-/eth-json-rpc-infura-3.0.0.tgz#75746cd4027f947b8b3fe0b4dcfd306fc24d7127" dependencies: eth-json-rpc-middleware "^1.5.0" json-rpc-engine "^3.4.0" @@ -4223,6 +4272,18 @@ execa@^0.7.0: signal-exit "^3.0.0" strip-eof "^1.0.0" +execa@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.9.0.tgz#adb7ce62cf985071f60580deb4a88b9e34712d01" + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + execall@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/execall/-/execall-1.0.0.tgz#73d0904e395b3cab0658b08d09ec25307f29bb73" @@ -4331,7 +4392,7 @@ extend-shallow@^2.0.1: dependencies: is-extendable "^0.1.0" -extend-shallow@^3.0.0: +extend-shallow@^3.0.0, extend-shallow@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" dependencies: @@ -4383,6 +4444,19 @@ extglob@^2.0.2: snapdragon "^0.8.1" to-regex "^3.0.1" +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + extsprintf@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" @@ -5278,19 +5352,19 @@ gulp-util@^3.0, gulp-util@^3.0.0, gulp-util@^3.0.2, gulp-util@^3.0.7, gulp-util@ through2 "^2.0.0" vinyl "^0.5.0" -gulp-watch@^4.3.5: - version "4.3.11" - resolved "https://registry.yarnpkg.com/gulp-watch/-/gulp-watch-4.3.11.tgz#162fc563de9fc770e91f9a7ce3955513a9a118c0" +gulp-watch@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/gulp-watch/-/gulp-watch-5.0.0.tgz#6fb03ab1735972e0d2866475b568555836dfd0eb" dependencies: anymatch "^1.3.0" - chokidar "^1.6.1" + chokidar "^2.0.0" glob-parent "^3.0.1" gulp-util "^3.0.7" object-assign "^4.1.0" path-is-absolute "^1.0.1" readable-stream "^2.2.2" slash "^1.0.0" - vinyl "^1.2.0" + vinyl "^2.1.0" vinyl-file "^2.0.0" gulp-zip@^4.0.0: @@ -5888,7 +5962,7 @@ is-descriptor@^0.1.0: is-data-descriptor "^0.1.4" kind-of "^5.0.0" -is-descriptor@^1.0.0: +is-descriptor@^1.0.0, is-descriptor@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" dependencies: @@ -5924,7 +5998,7 @@ is-extglob@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" -is-extglob@^2.1.0: +is-extglob@^2.1.0, is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -5964,6 +6038,12 @@ is-glob@^3.1.0: dependencies: is-extglob "^2.1.0" +is-glob@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" + dependencies: + is-extglob "^2.1.1" + is-hex-prefixed@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" @@ -6019,6 +6099,12 @@ is-odd@^1.0.0: dependencies: is-number "^3.0.0" +is-odd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-2.0.0.tgz#7646624671fd7ea558ccd9a2795182f2958f1b24" + dependencies: + is-number "^4.0.0" + is-path-cwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" @@ -6137,6 +6223,10 @@ is-windows@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.1.tgz#310db70f742d259a16a369202b51af84233310d9" +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + is-word-character@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-word-character/-/is-word-character-1.0.1.tgz#5a03fa1ea91ace8a6eb0c7cd770eb86d65c8befb" @@ -6855,6 +6945,10 @@ lodash.assignin@^4.1.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" +lodash.castarray@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.castarray/-/lodash.castarray-4.4.0.tgz#c02513515e309daddd4c24c60cfddcf5976d9115" + lodash.clonedeep@^4.3.2, lodash.clonedeep@^4.4.1: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" @@ -7313,6 +7407,24 @@ micromatch@^3.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" +micromatch@^3.1.4: + version "3.1.9" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.9.tgz#15dc93175ae39e52e93087847096effc73efcf89" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + miller-rabin@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" @@ -7457,9 +7569,9 @@ mocha-sinon@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/mocha-sinon/-/mocha-sinon-2.0.0.tgz#723a9310e7d737d7b77c7a66821237425b032d48" -mocha@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-4.1.0.tgz#7d86cfbcf35cb829e2754c32e17355ec05338794" +mocha@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.0.1.tgz#759b62c836b0732382a62b6b1fb245ec1bc943ac" dependencies: browser-stdout "1.3.0" commander "2.11.0" @@ -7569,6 +7681,23 @@ nanomatch@^1.2.5: snapdragon "^0.8.1" to-regex "^3.0.1" +nanomatch@^1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.9.tgz#879f7150cb2dab7a471259066c104eee6e0fa7c2" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-odd "^2.0.0" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -7695,7 +7824,7 @@ node-pre-gyp@^0.6.39: tar "^2.2.1" tar-pack "^3.4.0" -node-sass@^4.2.0: +node-sass@^4.2.0, node-sass@^4.7.2: version "4.7.2" resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.7.2.tgz#9366778ba1469eb01438a9e8592f4262bcb6794e" dependencies: @@ -8979,13 +9108,6 @@ react-tooltip-component@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/react-tooltip-component/-/react-tooltip-component-0.3.0.tgz#fb3ec78c3270fe919692bc31f1404108bcf4785e" -react-tooltip@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/react-tooltip/-/react-tooltip-3.4.0.tgz#037f38f797c3e6b1b58d2534ccc8c2c76af4f52d" - dependencies: - classnames "^2.2.5" - prop-types "^15.6.0" - react-transition-group@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-1.2.1.tgz#e11f72b257f921b213229a774df46612346c7ca6" @@ -9176,9 +9298,9 @@ redux-logger@^3.0.6: dependencies: deep-diff "^0.3.5" -redux-test-utils@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/redux-test-utils/-/redux-test-utils-0.1.3.tgz#0d89100f100f86c7c7214976eaece88e7e45bf74" +redux-test-utils@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/redux-test-utils/-/redux-test-utils-0.2.2.tgz#593213f30173c5908f72315f08b705e1606094fe" redux-thunk@^2.2.0: version "2.2.0" @@ -10705,22 +10827,23 @@ test-exclude@^4.1.1: read-pkg-up "^1.0.1" require-main-filename "^1.0.1" -testem@^1.10.3: - version "1.18.4" - resolved "https://registry.yarnpkg.com/testem/-/testem-1.18.4.tgz#e45fed922bec2f54a616c43f11922598ac97eb41" +testem@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/testem/-/testem-2.0.0.tgz#b05c96200c7ac98bae998d71c94c0c5345907d13" dependencies: backbone "^1.1.2" bluebird "^3.4.6" charm "^1.0.0" commander "^2.6.0" consolidate "^0.14.0" - cross-spawn "^5.1.0" + execa "^0.9.0" express "^4.10.7" fireworm "^0.7.0" glob "^7.0.4" http-proxy "^1.13.1" js-yaml "^3.2.5" lodash.assignin "^4.1.0" + lodash.castarray "^4.4.0" lodash.clonedeep "^4.4.1" lodash.find "^4.5.1" lodash.uniqby "^4.7.0" @@ -11187,6 +11310,10 @@ unset-value@^1.0.0: has-value "^0.3.1" isobject "^3.0.0" +upath@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.0.4.tgz#ee2321ba0a786c50973db043a50b7bcba822361d" + urix@^0.1.0, urix@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" @@ -11379,7 +11506,7 @@ vinyl@^0.5.0: clone-stats "^0.0.1" replace-ext "0.0.1" -vinyl@^1.1.0, vinyl@^1.2.0: +vinyl@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-1.2.0.tgz#5c88036cf565e5df05558bfc911f8656df218884" dependencies: From 81fa0742f7e1702eae866c1915319b0de3a2430d Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 2 Mar 2018 10:32:53 -0800 Subject: [PATCH 104/392] Fix inpage provider name regression Fixes #3372 by not minifying the name of our inpage provider, which some people were using to identify MetaMask (not our preferred, supported method of web3.currentProvider.isMetaMask). --- CHANGELOG.md | 2 ++ gulpfile.js | 4 +++- package.json | 2 +- yarn.lock | 6 +++--- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59f116aed..776af1f26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +- Ensure MetaMask's inpage provider is named MetamaskInpageProvider to keep some sites from breaking. + ## 4.1.2 2018-2-28 - Actually includes all the fixes mentioned in 4.1.1 (sorry) diff --git a/gulpfile.js b/gulpfile.js index 3ade82f87..adfb148a9 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -407,7 +407,9 @@ function bundleTask(opts) { // loads map from browserify file .pipe(gulpif(debug, sourcemaps.init({ loadMaps: true }))) // Minification - .pipe(gulpif(opts.isBuild, uglify())) + .pipe(gulpif(opts.isBuild, uglify({ + mangle: { reserved: [ 'MetamaskInpageProvider' ] }, + }))) // writes .map file .pipe(gulpif(debug, sourcemaps.write('./'))) // write completed bundles diff --git a/package.json b/package.json index d712e00ac..354b3abd2 100644 --- a/package.json +++ b/package.json @@ -211,7 +211,7 @@ "gulp-stylefmt": "^1.1.0", "gulp-stylelint": "^4.0.0", "gulp-uglify": "^3.0.0", - "gulp-uglify-es": "^1.0.0", + "gulp-uglify-es": "^1.0.1", "gulp-util": "^3.0.7", "gulp-watch": "^5.0.0", "gulp-zip": "^4.0.0", diff --git a/yarn.lock b/yarn.lock index d9e456aa9..028ffa44e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7348,9 +7348,9 @@ mersenne-twister@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/mersenne-twister/-/mersenne-twister-1.1.0.tgz#f916618ee43d7179efcf641bec4531eb9670978a" -metamascara@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/metamascara/-/metamascara-1.3.1.tgz#a84d6f20ef4ba401ce44eba120857ee1d680747b" +metamascara@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/metamascara/-/metamascara-2.2.1.tgz#f97b87045a245e1bd2e1bcae7a3d4dcd4e17c02a" dependencies: iframe "^1.0.0" iframe-stream "^3.0.0" From cb109a8233819f23fab46c96d1d5f124e0164585 Mon Sep 17 00:00:00 2001 From: Thomas Huang Date: Fri, 2 Mar 2018 12:08:13 -0800 Subject: [PATCH 105/392] Add retry transaction back into old ui transaction list item (#3381) * Add retry transaction back into old ui transaction list item * Update Changelog --- CHANGELOG.md | 1 + .../app/components/transaction-list-item.js | 133 +++++++++++++----- 2 files changed, 96 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 776af1f26..a24ae926d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Current Master - Ensure MetaMask's inpage provider is named MetamaskInpageProvider to keep some sites from breaking. +- Add retry transaction button back into classic ui. ## 4.1.2 2018-2-28 diff --git a/old-ui/app/components/transaction-list-item.js b/old-ui/app/components/transaction-list-item.js index 95670bd54..e7251df8d 100644 --- a/old-ui/app/components/transaction-list-item.js +++ b/old-ui/app/components/transaction-list-item.js @@ -1,6 +1,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits +const connect = require('react-redux').connect const EthBalance = require('./eth-balance') const addressSummary = require('../util').addressSummary @@ -9,18 +10,33 @@ const CopyButton = require('./copyButton') const vreme = new (require('vreme'))() const Tooltip = require('./tooltip') const numberToBN = require('number-to-bn') +const actions = require('../../../ui/app/actions') const TransactionIcon = require('./transaction-list-item-icon') const ShiftListItem = require('./shift-list-item') -module.exports = TransactionListItem + +const mapDispatchToProps = dispatch => { + return { + retryTransaction: transactionId => dispatch(actions.retryTransaction(transactionId)), + } +} + +module.exports = connect(null, mapDispatchToProps)(TransactionListItem) inherits(TransactionListItem, Component) function TransactionListItem () { Component.call(this) } +TransactionListItem.prototype.showRetryButton = function () { + const { transaction = {} } = this.props + const { status, time } = transaction + return status === 'submitted' && Date.now() - time > 30000 +} + TransactionListItem.prototype.render = function () { const { transaction, network, conversionRate, currentCurrency } = this.props + const { status } = transaction if (transaction.key === 'shapeshift') { if (network === '1') return h(ShiftListItem, transaction) } @@ -32,7 +48,7 @@ TransactionListItem.prototype.render = function () { var isMsg = ('msgParams' in transaction) var isTx = ('txParams' in transaction) - var isPending = transaction.status === 'unapproved' + var isPending = status === 'unapproved' let txParams if (isTx) { txParams = transaction.txParams @@ -44,7 +60,7 @@ TransactionListItem.prototype.render = function () { const isClickable = ('hash' in transaction && isLinkable) || isPending return ( - h(`.transaction-list-item.flex-row.flex-space-between${isClickable ? '.pointer' : ''}`, { + h('.transaction-list-item.flex-column', { onClick: (event) => { if (isPending) { this.props.showTx(transaction.id) @@ -56,51 +72,92 @@ TransactionListItem.prototype.render = function () { }, style: { padding: '20px 0', - display: 'flex', - justifyContent: 'space-between', + alignItems: 'center', }, }, [ - - h('.identicon-wrapper.flex-column.flex-center.select-none', [ - h(TransactionIcon, { txParams, transaction, isTx, isMsg }), - ]), - - h(Tooltip, { - title: 'Transaction Number', - position: 'right', + h(`.flex-row.flex-space-between${isClickable ? '.pointer' : ''}`, { + style: { + width: '100%', + }, }, [ - h('span', { + h('.identicon-wrapper.flex-column.flex-center.select-none', [ + h(TransactionIcon, { txParams, transaction, isTx, isMsg }), + ]), + + h(Tooltip, { + title: 'Transaction Number', + position: 'right', + }, [ + h('span', { + style: { + display: 'flex', + cursor: 'normal', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + padding: '10px', + }, + }, nonce), + ]), + + h('.flex-column', {style: {width: '200px', overflow: 'hidden'}}, [ + domainField(txParams), + h('div', date), + recipientField(txParams, transaction, isTx, isMsg), + ]), + + // Places a copy button if tx is successful, else places a placeholder empty div. + transaction.hash ? h(CopyButton, { value: transaction.hash }) : h('div', {style: { display: 'flex', alignItems: 'center', width: '26px' }}), + + isTx ? h(EthBalance, { + value: txParams.value, + conversionRate, + currentCurrency, + width: '55px', + shorten: true, + showFiat: false, + style: {fontSize: '15px'}, + }) : h('.flex-column'), + ]), + + this.showRetryButton() && h('.transition-list-item__retry.grow-on-hover', { + onClick: event => { + event.stopPropagation() + this.resubmit() + }, + style: { + height: '22px', + borderRadius: '22px', + color: '#F9881B', + padding: '0 20px', + backgroundColor: '#FFE3C9', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + fontSize: '8px', + cursor: 'pointer', + }, + }, [ + h('div', { style: { - display: 'flex', - cursor: 'normal', - flexDirection: 'column', - alignItems: 'center', - justifyContent: 'center', + paddingRight: '2px', }, - }, nonce), + }, 'Taking too long?'), + h('div', { + style: { + textDecoration: 'underline', + }, + }, 'Retry with a higher gas price here'), ]), - - h('.flex-column', {style: {width: '150px', overflow: 'hidden'}}, [ - domainField(txParams), - h('div', date), - recipientField(txParams, transaction, isTx, isMsg), - ]), - - // Places a copy button if tx is successful, else places a placeholder empty div. - transaction.hash ? h(CopyButton, { value: transaction.hash }) : h('div', {style: { display: 'flex', alignItems: 'center', width: '26px' }}), - - isTx ? h(EthBalance, { - value: txParams.value, - conversionRate, - currentCurrency, - shorten: true, - showFiat: false, - style: {fontSize: '15px'}, - }) : h('.flex-column'), ]) ) } +TransactionListItem.prototype.resubmit = function () { + const { transaction } = this.props + this.props.retryTransaction(transaction.id) +} + function domainField (txParams) { return h('div', { style: { From 452c5d0513a14419b71ffd92d253fef661b74300 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 2 Mar 2018 12:47:40 -0800 Subject: [PATCH 106/392] Version 4.1.3 --- CHANGELOG.md | 2 ++ app/manifest.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a24ae926d..8fc9d2145 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +## 4.1.3 2018-2-28 + - Ensure MetaMask's inpage provider is named MetamaskInpageProvider to keep some sites from breaking. - Add retry transaction button back into classic ui. diff --git a/app/manifest.json b/app/manifest.json index 1c9c420f9..2b3acf1b5 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "MetaMask", "short_name": "Metamask", - "version": "4.1.2", + "version": "4.1.3", "manifest_version": 2, "author": "https://metamask.io", "description": "Ethereum Browser Extension", From bf17d7e1153180fe68cc568a6f4ffa8db66010dc Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 2 Mar 2018 13:55:56 -0800 Subject: [PATCH 107/392] Add version bumping script One step towards automating our deploy process is automating our version bumping scheme. This PR does that. --- development/run-version-bump.js | 51 ++ development/version-bump.js | 53 ++ docs/bumping_version.md | 33 + docs/publishing.md | 6 +- package.json | 1 + test/unit/development/sample-changelog.md | 914 +++++++++++++++++++++ test/unit/development/sample-manifest.json | 71 ++ test/unit/development/version–bump-test.js | 46 ++ 8 files changed, 1172 insertions(+), 3 deletions(-) create mode 100644 development/run-version-bump.js create mode 100644 development/version-bump.js create mode 100644 docs/bumping_version.md create mode 100644 test/unit/development/sample-changelog.md create mode 100644 test/unit/development/sample-manifest.json create mode 100644 test/unit/development/version–bump-test.js diff --git a/development/run-version-bump.js b/development/run-version-bump.js new file mode 100644 index 000000000..3b26b00db --- /dev/null +++ b/development/run-version-bump.js @@ -0,0 +1,51 @@ +const { promisify } = require('util') +const fs = require('fs') +const readFile = promisify(fs.readFile) +const writeFile = promisify(fs.writeFile) +const path = require('path') +const changelogPath = path.join(__dirname, '..', 'CHANGELOG.md') +const manifestPath = path.join(__dirname, '..', 'app', 'manifest.json') +const manifest = require('../app/manifest.json') +const versionBump = require('./version-bump') + +console.dir(process.argv) +const bumpType = normalizeType(process.argv[2]) + + +readFile(changelogPath) +.then(async (changeBuffer) => { + const changelog = changeBuffer.toString() + + const newData = await versionBump(bumpType, changelog, manifest) + console.dir(newData) + + const manifestString = JSON.stringify(newData.manifest, null, 2) + + console.log('now writing files to ', changelogPath, manifestPath) + console.log(typeof newData.manifest) + await writeFile(changelogPath, newData.changelog) + await writeFile(manifestPath, manifestString) + + return newData.version +}) +.then((version) => console.log(`Bumped ${bumpType} to version ${version}`)) +.catch(console.error) + + +function normalizeType (userInput) { + console.log(`user inputted ${userInput}`) + const err = new Error('First option must be a type (major, minor, or patch)') + if (!userInput || typeof userInput !== 'string') { + console.log('first no') + throw err + } + + const lower = userInput.toLowerCase() + + if (lower !== 'major' && lower !== 'minor' && lower !== 'patch') { + console.log('second no') + throw err + } + + return lower +} diff --git a/development/version-bump.js b/development/version-bump.js new file mode 100644 index 000000000..63dd802d1 --- /dev/null +++ b/development/version-bump.js @@ -0,0 +1,53 @@ +const clone = require('clone') + +async function versionBump(bumpType, changelog, oldManifest) { + const manifest = clone(oldManifest) + const newVersion = newVersionFrom(manifest, bumpType) + + manifest.version = newVersion + const date = (new Date()).toDateString() + + const logHeader = `\n## ${newVersion} ${date}` + const logLines = changelog.split('\n') + for (let i = 0; i < logLines.length; i++) { + if (logLines[i].includes('Current Master')) { + logLines.splice(i + 1, 0, logHeader) + break + } + } + + return { + version: newVersion, + manifest: manifest, + changelog: logLines.join('\n') + } +} + +function newVersionFrom (manifest, bumpType) { + const string = manifest.version + let segments = string.split('.').map((str) => parseInt(str)) + + console.log('bump type is ' + bumpType) + switch (bumpType) { + case 'major': + segments[0] += 1 + segments[1] = 0 + segments[2] = 0 + break + case 'minor': + segments[1] += 1 + segments[2] = 0 + break + case 'patch': + segments[2] += 1 + break + } + + return segments.map(String).join('.') +} + +function bumpManifest (manifest, bumpType) { + +} + +module.exports = versionBump diff --git a/docs/bumping_version.md b/docs/bumping_version.md new file mode 100644 index 000000000..df38369a2 --- /dev/null +++ b/docs/bumping_version.md @@ -0,0 +1,33 @@ +# How to Bump MetaMask's Version Automatically + +``` +npm run version:bump patch +``` + +MetaMask publishes using a loose [semver](https://semver.org/) interpretation. We divide the three segments of our version into three types of version bump: + +## Major + +Means a breaking change, either an API removed, or a major user expectation changed. + +## Minor + +Means a new API or new user feature. + +## Patch + +Means a fix for a bug, or correcting something that should have been assumed to work a different way. + +# Bumping the version + +`npm run version:bump $BUMP_TYPE` where `$BUMP_TYPE` is one of `major`, `minor`, or `patch`. + +This will increment the version in the `app/manifest.json` and `CHANGELOG.md` files according to our current protocol, where the manifest's version is updated, and any line items currently under the changelog's "master" section are now under the new dated version section. + +# Modifying the bump script + +The script that is executed lives [here](../development/run-version-bump.js). +The main functions all live [here](../development/version-bump.js). +The test for this behavior is at `test/unit/development/version-bump-test.js`. + + diff --git a/docs/publishing.md b/docs/publishing.md index 00369acf9..3022b7eda 100644 --- a/docs/publishing.md +++ b/docs/publishing.md @@ -4,15 +4,15 @@ When publishing a new version of MetaMask, we follow this procedure: ## Incrementing Version & Changelog - You must be authorized already on the MetaMask plugin. +Version can be automatically incremented [using our bump script](./bumping-version.md). -1. Update the version in `app/manifest.json` and the Changelog in `CHANGELOG.md`. -2. Visit [the chrome developer dashboard](https://chrome.google.com/webstore/developer/dashboard?authuser=2). +npm run version:bump $BUMP_TYPE` where `$BUMP_TYPE` is one of `major`, `minor`, or `patch`. ## Publishing 1. `npm run dist` to generate the latest build. 2. Publish to chrome store. + - Visit [the chrome developer dashboard](https://chrome.google.com/webstore/developer/dashboard?authuser=2). 3. Publish to firefox addon marketplace. 4. Post on Github releases page. 5. `npm run announce`, post that announcement in our public places. diff --git a/package.json b/package.json index 354b3abd2..d4b498bc8 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "lint:fix": "gulp lint:fix", "disc": "gulp disc --debug", "announce": "node development/announcer.js", + "version:bump": "node development/run-version-bump.js", "generateNotice": "node notices/notice-generator.js", "deleteNotice": "node notices/notice-delete.js" }, diff --git a/test/unit/development/sample-changelog.md b/test/unit/development/sample-changelog.md new file mode 100644 index 000000000..8fc9d2145 --- /dev/null +++ b/test/unit/development/sample-changelog.md @@ -0,0 +1,914 @@ +# Changelog + +## Current Master + +## 4.1.3 2018-2-28 + +- Ensure MetaMask's inpage provider is named MetamaskInpageProvider to keep some sites from breaking. +- Add retry transaction button back into classic ui. + +## 4.1.2 2018-2-28 + +- Actually includes all the fixes mentioned in 4.1.1 (sorry) + +## 4.1.1 2018-2-28 + +- Fix "Add Token" screen referencing missing token logo urls +- Prevent user from switching network during signature request +- Fix misleading language "Contract Published" -> "Contract Deployment" +- Fix cancel button on "Buy Eth" screen +- Improve new-ui onboarding flow style + +## 4.1.0 2018-2-27 + +- Report failed txs to Sentry with more specific message +- Fix internal feature flags being sometimes undefined +- Standardized license to MIT + +## 4.0.0 2018-2-22 + +- Introduce new MetaMask user interface. + +## 3.14.2 2018-2-15 + +- Fix bug where log subscriptions would break when switching network. +- Fix bug where storage values were cached across blocks. +- Add MetaMask light client [testing container](https://github.com/MetaMask/mesh-testing) + +## 3.14.1 2018-2-1 + +- Further fix scrolling for Firefox. + +## 3.14.0 2018-2-1 + +- Removed unneeded data from storage +- Add a "reset account" feature to Settings +- Add warning for importing some kinds of files. +- Scrollable Setting view for Firefox. + +## 3.13.8 2018-1-29 + +- Fix provider for Kovan network. +- Bump limit for EventEmitter listeners before warning. +- Display Error when empty string is entered as a token address. + +## 3.13.7 2018-1-22 + +- Add ability to bypass gas estimation loading indicator. +- Forward failed transactions to Sentry error reporting service +- Re-add changes from 3.13.5 + +## 3.13.6 2017-1-18 + +- Roll back changes to 3.13.4 to fix some issues with the new Infura REST provider. + +## 3.13.5 2018-1-16 + +- Estimating gas limit for simple ether sends now faster & cheaper, by avoiding VM usage on recipients with no code. +- Add an extra px to address for Firefox clipping. +- Fix Firefox scrollbar. +- Open metamask popup for transaction confirmation before gas estimation finishes and add a loading screen over transaction confirmation. +- Fix bug that prevented eth_signTypedData from signing bytes. +- Further improve gas price estimation. + +## 3.13.4 2018-1-9 + +- Remove recipient field if application initializes a tx with an empty string, or 0x, and tx data. Throw an error with the same condition, but without tx data. +- Improve gas price suggestion to be closer to the lowest that will be accepted. +- Throw an error if a application tries to submit a tx whose value is a decimal, and inform that it should be in wei. +- Fix bug that prevented updating custom token details. +- No longer mark long-pending transactions as failed, since we now have button to retry with higher gas. +- Fix rounding error when specifying an ether amount that has too much precision. +- Fix bug where incorrectly inputting seed phrase would prevent any future attempts from succeeding. + +## 3.13.3 2017-12-14 + +- Show tokens that are held that have no balance. +- Reduce load on Infura by using a new block polling endpoint. + +## 3.13.2 2017-12-9 + +- Reduce new block polling interval to 8000 ms, to ease server load. + +## 3.13.1 2017-12-7 + +- Allow Dapps to specify a transaction nonce, allowing dapps to propose resubmit and force-cancel transactions. + +## 3.13.0 2017-12-7 + +- Allow resubmitting transactions that are taking long to complete. + +## 3.12.1 2017-11-29 + +- Fix bug where a user could be shown two different seed phrases. +- Detect when multiple web3 extensions are active, and provide useful error. +- Adds notice about seed phrase backup. + +## 3.12.0 2017-10-25 + +- Add support for alternative ENS TLDs (Ethereum Name Service Top-Level Domains). +- Lower minimum gas price to 0.1 GWEI. +- Remove web3 injection message from production (thanks to @ChainsawBaby) +- Add additional debugging info to our state logs, specifically OS version and browser version. + +## 3.11.2 2017-10-21 + +- Fix bug where reject button would sometimes not work. +- Fixed bug where sometimes MetaMask's connection to a page would be unreliable. + +## 3.11.1 2017-10-20 + +- Fix bug where log filters were not populated correctly +- Fix bug where web3 API was sometimes injected after the page loaded. +- Fix bug where first account was sometimes not selected correctly after creating or restoring a vault. +- Fix bug where imported accounts could not use new eth_signTypedData method. + +## 3.11.0 2017-10-11 + +- Add support for new eth_signTypedData method per EIP 712. +- Fix bug where some transactions would be shown as pending forever, even after successfully mined. +- Fix bug where a transaction might be shown as pending forever if another tx with the same nonce was mined. +- Fix link to support article on token addresses. + +## 3.10.9 2017-10-5 + +- Only rebrodcast transactions for a day not a days worth of blocks +- Remove Slack link from info page, since it is a big phishing target. +- Stop computing balance based on pending transactions, to avoid edge case where users are unable to send transactions. + +## 3.10.8 2017-9-28 + +- Fixed usage of new currency fetching API. + +## 3.10.7 2017-9-28 + +- Fixed bug where sometimes the current account was not correctly set and exposed to web apps. +- Added AUD, HKD, SGD, IDR, PHP to currency conversion list + +## 3.10.6 2017-9-27 + +- Fix bug where newly created accounts were not selected. +- Fix bug where selected account was not persisted between lockings. + +## 3.10.5 2017-9-27 + +- Fix block gas limit estimation. + +## 3.10.4 2017-9-27 + +- Fix bug that could mis-render token balances when very small. (Not actually included in 3.9.9) +- Fix memory leak warning. +- Fix bug where new event filters would not include historical events. + +## 3.10.3 2017-9-21 + +- Fix bug where metamask-dapp connections are lost on rpc error +- Fix bug that would sometimes display transactions as failed that could be successfully mined. + +## 3.10.2 2017-9-18 + +rollback to 3.10.0 due to bug + +## 3.10.1 2017-9-18 + +- Add ability to export private keys as a file. +- Add ability to export seed words as a file. +- Changed state logs to a file download than a clipboard copy. +- Add specific error for failed recipient address checksum. +- Fixed a long standing memory leak associated with filters installed by dapps +- Fix link to support center. +- Fixed tooltip icon locations to avoid overflow. +- Warn users when a dapp proposes a high gas limit (90% of blockGasLimit or higher +- Sort currencies by currency name (thanks to strelok1: https://github.com/strelok1). + +## 3.10.0 2017-9-11 + +- Readded loose keyring label back into the account list. +- Remove cryptonator from chrome permissions. +- Add info on token contract addresses. +- Add validation preventing users from inputting their own addresses as token tracking addresses. +- Added button to reject all transactions (thanks to davidp94! https://github.com/davidp94) + + +## 3.9.13 2017-9-8 + +- Changed the way we initialize the inpage provider to fix a bug affecting some developers. + +## 3.9.12 2017-9-6 + +- Fix bug that prevented Web3 1.0 compatibility +- Make eth_sign deprecation warning less noisy +- Add useful link to eth_sign deprecation warning. +- Fix bug with network version serialization over synchronous RPC +- Add MetaMask version to state logs. +- Add the total amount of tokens when multiple tokens are added under the token list +- Use HTTPS links for Etherscan. +- Update Support center link to new one with HTTPS. +- Make web3 deprecation notice more useful by linking to a descriptive article. + +## 3.9.11 2017-8-24 + +- Fix nonce calculation bug that would sometimes generate very wrong nonces. +- Give up resubmitting a transaction after 3500 blocks. + +## 3.9.10 2017-8-23 + +- Improve nonce calculation, to prevent bug where people are unable to send transactions reliably. +- Remove link to eth-tx-viz from identicons in tx history. + +## 3.9.9 2017-8-18 + +- Fix bug where some transaction submission errors would show an empty screen. +- Fix bug that could mis-render token balances when very small. +- Fix formatting of eth_sign "Sign Message" view. +- Add deprecation warning to eth_sign "Sign Message" view. + +## 3.9.8 2017-8-16 + +- Reenable token list. +- Remove default tokens. + +## 3.9.7 2017-8-15 + +- hotfix - disable token list +- Added a deprecation warning for web3 https://github.com/ethereum/mist/releases/tag/v0.9.0 + +## 3.9.6 2017-8-09 + +- Replace account screen with an account drop-down menu. +- Replace account buttons with a new account-specific drop-down menu. + +## 3.9.5 2017-8-04 + +- Improved phishing detection configuration update rate + +## 3.9.4 2017-8-03 + +- Fixed bug that prevented transactions from being rejected. + +## 3.9.3 2017-8-03 + +- Add support for EGO ujo token +- Continuously update blacklist for known phishing sites in background. +- Automatically detect suspicious URLs too similar to common phishing targets, and blacklist them. + +## 3.9.2 2017-7-26 + +- Fix bugs that could sometimes result in failed transactions after switching networks. +- Include stack traces in txMeta's to better understand the life cycle of transactions +- Enhance blacklister functionality to include levenshtein logic. (credit to @sogoiii and @409H for their help!) + +## 3.9.1 2017-7-19 + +- No longer automatically request 1 ropsten ether for the first account in a new vault. +- Now redirects from known malicious sites faster. +- Added a link to our new support page to the help screen. +- Fixed bug where a new transaction would be shown over the current transaction, creating a possible timing attack against user confirmation. +- Fixed bug in nonce tracker where an incorrect nonce would be calculated. +- Lowered minimum gas price to 1 Gwei. + +## 3.9.0 2017-7-12 + +- Now detects and blocks known phishing sites. + +## 3.8.6 2017-7-11 + +- Make transaction resubmission more resilient. +- No longer validate nonce client-side in retry loop. +- Fix bug where insufficient balance error was sometimes shown on successful transactions. + +## 3.8.5 2017-7-7 + +- Fix transaction resubmit logic to fail slightly less eagerly. + +## 3.8.4 2017-7-7 + +- Improve transaction resubmit logic to fail more eagerly when a user would expect it to. + +## 3.8.3 2017-7-6 + +- Re-enable default token list. +- Add origin header to dapp-bound requests to allow providers to throttle sites. +- Fix bug that could sometimes resubmit a transaction that had been stalled due to low balance after balance was restored. + +## 3.8.2 2017-7-3 + +- No longer show network loading indication on config screen, to allow selecting custom RPCs. +- Visually indicate that network spinner is a menu. +- Indicate what network is being searched for when disconnected. + +## 3.8.1 2017-6-30 + +- Temporarily disabled loading popular tokens by default to improve performance. +- Remove SEND token button until a better token sending form can be built, due to some precision issues. +- Fix precision bug in token balances. +- Cache token symbol and precisions to reduce network load. +- Transpile some newer JavaScript, restores compatibility with some older browsers. + +## 3.8.0 2017-6-28 + +- No longer stop rebroadcasting transactions +- Add list of popular tokens held to the account detail view. +- Add ability to add Tokens to token list. +- Add a warning to JSON file import. +- Add "send" link to token list, which goes to TokenFactory. +- Fix bug where slowly mined txs would sometimes be incorrectly marked as failed. +- Fix bug where badge count did not reflect personal_sign pending messages. +- Seed word confirmation wording is now scarier. +- Fix error for invalid seed words. +- Prevent users from submitting two duplicate transactions by disabling submit. +- Allow Dapps to specify gas price as hex string. +- Add button for copying state logs to clipboard. + +## 3.7.8 2017-6-12 + +- Add an `ethereum:` prefix to the QR code address +- The default network on installation is now MainNet +- Fix currency API URL from cryptonator. +- Update gasLimit params with every new block seen. +- Fix ENS resolver symbol UI. + +## 3.7.7 2017-6-8 + +- Fix bug where metamask would show old data after computer being asleep or disconnected from the internet. + +## 3.7.6 2017-6-5 + +- Fix bug that prevented publishing contracts. + +## 3.7.5 2017-6-5 + +- Prevent users from sending to the `0x0` address. +- Provide useful errors when entering bad characters in ENS name. +- Add ability to copy addresses from transaction confirmation view. + +## 3.7.4 2017-6-2 + +- Fix bug with inflight cache that caused some block lookups to return bad values (affected OasisDex). +- Fixed bug with gas limit calculation that would sometimes create unsubmittable gas limits. + +## 3.7.3 2017-6-1 + +- Rebuilt to fix cache clearing bug. + +## 3.7.2 2017-5-31 + +- Now when switching networks sites that use web3 will reload +- Now when switching networks the extension does not restart +- Cleanup decimal bugs in our gas inputs. +- Fix bug where submit button was enabled for invalid gas inputs. +- Now enforce 95% of block's gasLimit to protect users. +- Removing provider-engine from the inpage provider. This fixes some error handling inconsistencies introduced in 3.7.0. +- Added "inflight cache", which prevents identical requests from clogging up the network, dramatically improving ENS performance. +- Fixed bug where filter subscriptions would sometimes fail to unsubscribe. +- Some contracts will now display logos instead of jazzicons. +- Some contracts will now have names displayed in the confirmation view. + +## 3.7.0 2017-5-23 + +- Add Transaction Number (nonce) to transaction list. +- Label the pending tx icon with a tooltip. +- Fix bug where website filters would pile up and not deallocate when leaving a site. +- Continually resubmit pending txs for a period of time to ensure successful broadcast. +- ENS names will no longer resolve to their owner if no resolver is set. Resolvers must be explicitly set and configured. + +## 3.6.5 2017-5-17 + +- Fix bug where edited gas parameters would not take effect. +- Trim currency list. +- Enable decimals in our gas prices. +- Fix reset button. +- Fix event filter bug introduced by newer versions of Geth. +- Fix bug where decimals in gas inputs could result in strange values. + +## 3.6.4 2017-5-8 + +- Fix main-net ENS resolution. + +## 3.6.3 2017-5-8 + +- Fix bug that could stop newer versions of Geth from working with MetaMask. + +## 3.6.2 2017-5-8 + +- Input gas price in Gwei. +- Enforce Safe Gas Minimum recommended by EthGasStation. +- Fix bug where block-tracker could stop polling for new blocks. +- Reduce UI size by removing internal web3. +- Fix bug where gas parameters would not properly update on adjustment. + +## 3.6.1 2017-4-30 + +- Made fox less nosy. +- Fix bug where error was reported in debugger console when Chrome opened a new window. + +## 3.6.0 2017-4-26 + +- Add Rinkeby Test Network to our network list. + +## 3.5.4 2017-4-25 + +- Fix occasional nonce tracking issue. +- Fix bug where some events would not be emitted by web3. +- Fix bug where an error would be thrown when composing signatures for networks with large ID values. + +## 3.5.3 2017-4-24 + +- Popup new transactions in Firefox. +- Fix transition issue from account detail screen. +- Revise buy screen for more modularity. +- Fixed some other small bugs. + +## 3.5.2 2017-3-28 + +- Fix bug where gas estimate totals were sometimes wrong. +- Add link to Kovan Test Faucet instructions on buy view. +- Inject web3 into loaded iFrames. + +## 3.5.1 2017-3-27 + +- Fix edge case where users were unable to enable the notice button if notices were short enough to not require a scrollbar. + +## 3.5.0 2017-3-27 + +- Add better error messages for when a transaction fails on approval +- Allow sending to ENS names in send form on Ropsten. +- Added an address book functionality that remembers the last 15 unique addresses sent to. +- Can now change network to custom RPC URL from lock screen. +- Removed support for old, lightwallet based vault. Users who have not opened app in over a month will need to recover with their seed phrase. This will allow Firefox support sooner. +- Fixed bug where spinner wouldn't disappear on incorrect password submission on seed word reveal. +- Polish the private key UI. +- Enforce minimum values for gas price and gas limit. +- Fix bug where total gas was sometimes not live-updated. +- Fix bug where editing gas value could have some abrupt behaviors (#1233) +- Add Kovan as an option on our network list. +- Fixed bug where transactions on other networks would disappear when submitting a transaction on another network. + +## 3.4.0 2017-3-8 + +- Add two most recently used custom RPCs to network dropdown menu. +- Add personal_sign method support. +- Add personal_ecRecover method support. +- Add ability to customize gas and gasPrice on the transaction approval screen. +- Increase default gas buffer to 1.5x estimated gas value. + +## 3.3.0 2017-2-20 + +- net_version has been made synchronous. +- Test suite for migrations expanded. +- Network now changeable from lock screen. +- Improve test coverage of eth.sign behavior, including a code example of verifying a signature. + +## 3.2.2 2017-2-8 + +- Revert eth.sign behavior to the previous one with a big warning. We will be gradually implementing the new behavior over the coming time. https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign + +- Improve test coverage of eth.sign behavior, including a code example of verifying a signature. + +## 3.2.2 2017-2-8 + +- Revert eth.sign behavior to the previous one with a big warning. We will be gradually implementing the new behavior over the coming time. https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign + +## 3.2.1 2017-2-8 + +- Revert back to old style message signing. +- Fixed some build errors that were causing a variety of bugs. + +## 3.2.0 2017-2-8 + +- Add ability to import accounts in JSON file format (used by Mist, Geth, MyEtherWallet, and more!) +- Fix unapproved messages not being included in extension badge. +- Fix rendering bug where the Confirm transaction view would let you approve transactions when the account has insufficient balance. + +## 3.1.2 2017-1-24 + +- Fix "New Account" default keychain + +## 3.1.1 2017-1-20 + +- Fix HD wallet seed export + +## 3.1.0 2017-1-18 + +- Add ability to import accounts by private key. +- Fixed bug that returned the wrong transaction hashes on private networks that had not implemented EIP 155 replay protection (like TestRPC). + +## 3.0.1 2017-1-17 + +- Fixed bug that prevented eth.sign from working. +- Fix the displaying of transactions that have been submitted to the network in Transaction History + +## 3.0.0 2017-1-16 + +- Fix seed word account generation (https://medium.com/metamask/metamask-3-migration-guide-914b79533cdd#.t4i1qmmsz). +- Fix Bug where you see an empty transaction flash by on the confirm transaction view. +- Create visible difference in transaction history between an approved but not yet included in a block transaction and a transaction who has been confirmed. +- Fix memory leak in RPC Cache +- Override RPC commands eth_syncing and web3_clientVersion +- Remove certain non-essential permissions from certain builds. +- Add a check for when a tx is included in a block. +- Fix bug where browser-solidity would sometimes warn of a contract creation error when there was none. +- Minor modifications to network display. +- Network now displays properly for pending transactions. +- Implement replay attack protections allowed by EIP 155. +- Fix bug where sometimes loading account data would fail by querying a future block. + +## 2.14.1 2016-12-20 + +- Update Coinbase info. and increase the buy amount to $15 +- Fixed ropsten transaction links +- Temporarily disable extension reload detection causing infinite reload bug. +- Implemented basic checking for valid RPC URIs. + +## 2.14.0 2016-12-16 + +- Removed Morden testnet provider from provider menu. +- Add support for notices. +- Fix broken reload detection. +- Fix transaction forever cached-as-pending bug. + +## 2.13.11 2016-11-23 + +- Add support for synchronous RPC method "eth_uninstallFilter". +- Forgotten password prompts now send users directly to seed word restoration. + +## 2.13.10 2016-11-22 + +- Improve gas calculation logic. +- Default to Dapp-specified gas limits for transactions. +- Ropsten networks now properly point to the faucet when attempting to buy ether. +- Ropsten transactions now link to etherscan correctly. + +## 2.13.9 2016-11-21 + +- Add support for the new, default Ropsten Test Network. +- Fix bug that would cause MetaMask to occasionally lose its StreamProvider connection and drop requests. +- Fix bug that would cause the Custom RPC menu item to not appear when Localhost 8545 was selected. +- Point ropsten faucet button to actual faucet. +- Phase out ethereumjs-util from our encryptor module. + +## 2.13.8 2016-11-16 + +- Show a warning when a transaction fails during simulation. +- Fix bug where 20% of gas estimate was not being added properly. +- Render error messages in confirmation screen more gracefully. + +## 2.13.7 2016-11-8 + +- Fix bug where gas estimate would sometimes be very high. +- Increased our gas estimate from 100k gas to 20% of estimate. +- Fix GitHub link on info page to point at current repository. + +## 2.13.6 2016-10-26 + +- Add a check for improper Transaction data. +- Inject up to date version of web3.js +- Now nicknaming new accounts "Account #" instead of "Wallet #" for clarity. +- Fix bug where custom provider selection could show duplicate items. +- Fix bug where connecting to a local morden node would make two providers appear selected. +- Fix bug that was sometimes preventing transactions from being sent. + +## 2.13.5 2016-10-18 + +- Increase default max gas to `100000` over the RPC's `estimateGas` response. +- Fix bug where slow-loading dapps would sometimes trigger infinite reload loops. + +## 2.13.4 2016-10-17 + +- Add custom transaction fee field to send form. +- Fix bug where web3 was being injected into XML files. +- Fix bug where changing network would not reload current Dapps. + +## 2.13.3 2016-10-4 + +- Fix bug where log queries were filtered out. +- Decreased vault confirmation button font size to help some Linux users who could not see it. +- Made popup a little taller because it would sometimes cut off buttons. +- Fix bug where long account lists would get scrunched instead of scrolling. +- Add legal information to relevant pages. +- Rename UI elements to be more consistent with one another. +- Updated Terms of Service and Usage. +- Prompt users to re-agree to the Terms of Service when they are updated. + +## 2.13.2 2016-10-4 + +- Fix bug where chosen FIAT exchange rate does no persist when switching networks +- Fix additional parameters that made MetaMask sometimes receive errors from Parity. +- Fix bug where invalid transactions would still open the MetaMask popup. +- Removed hex prefix from private key export, to increase compatibility with Geth, MyEtherWallet, and Jaxx. + +## 2.13.1 2016-09-23 + +- Fix a bug with estimating gas on Parity +- Show loading indication when selecting ShapeShift as purchasing method. + +## 2.13.0 2016-09-18 + +- Add Parity compatibility, fixing Geth dependency issues. +- Add a link to the transaction in history that goes to https://metamask.github.io/eth-tx-viz +too help visualize transactions and to where they are going. +- Show "Buy Ether" button and warning on tx confirmation when sender balance is insufficient + +## 2.12.1 2016-09-14 + +- Fixed bug where if you send a transaction from within MetaMask extension the +popup notification opens up. +- Fixed bug where some tx errors would block subsequent txs until the plugin was refreshed. + +## 2.12.0 2016-09-14 + +- Add a QR button to the Account detail screen +- Fixed bug where opening MetaMask could close a non-metamask popup. +- Fixed memory leak that caused occasional crashes. + +## 2.11.1 2016-09-12 + +- Fix bug that prevented caches from being cleared in Opera. + +## 2.11.0 2016-09-12 + +- Fix bug where pending transactions from Test net (or other networks) show up In Main net. +- Add fiat conversion values to more views. +- On fresh install, open a new tab with the MetaMask Introduction video. Does not open on update. +- Block negative values from transactions. +- Fixed a memory leak. +- MetaMask logo now renders as super lightweight SVG, improving compatibility and performance. +- Now showing loading indication during vault unlocking, to clarify behavior for users who are experiencing slow unlocks. +- Now only initially creates one wallet when restoring a vault, to reduce some users' confusion. + +## 2.10.2 2016-09-02 + +- Fix bug where notification popup would not display. + +## 2.10.1 2016-09-02 + +- Fix bug where provider menu did not allow switching to custom network from a custom network. +- Sending a transaction from within MetaMask no longer triggers a popup. +- The ability to build without livereload features (such as for production) can be enabled with the gulp --disableLiveReload flag. +- Fix Ethereum JSON RPC Filters bug. + +## 2.10.0 2016-08-29 + +- Changed transaction approval from notifications system to popup system. +- Add a back button to locked screen to allow restoring vault from seed words when password is forgotten. +- Forms now retain their values even when closing the popup and reopening it. +- Fixed a spelling error in provider menu. + +## 2.9.2 2016-08-24 + +- Fixed shortcut bug from preventing installation. + +## 2.9.1 2016-08-24 + +- Added static image as fallback for when WebGL isn't supported. +- Transaction history now has a hard limit. +- Added info link on account screen that visits Etherscan. +- Fixed bug where a message signing request would be lost if the vault was locked. +- Added shortcut to open MetaMask (Ctrl+Alt+M or Cmd+Opt/Alt+M) +- Prevent API calls in tests. +- Fixed bug where sign message confirmation would sometimes render blank. + +## 2.9.0 2016-08-22 + +- Added ShapeShift to the transaction history +- Added affiliate key to Shapeshift requests +- Added feature to reflect current conversion rates of current vault balance. +- Modify balance display logic. + +## 2.8.0 2016-08-15 + +- Integrate ShapeShift +- Add a form for Coinbase to specify amount to buy +- Fix various typos. +- Make dapp-metamask connection more reliable +- Remove Ethereum Classic from provider menu. + +## 2.7.3 2016-07-29 + +- Fix bug where changing an account would not update in a live Dapp. + +## 2.7.2 2016-07-29 + +- Add Ethereum Classic to provider menu +- Fix bug where host store would fail to receive updates. + +## 2.7.1 2016-07-27 + +- Fix bug where web3 would sometimes not be injected in time for the application. +- Fixed bug where sometimes when opening the plugin, it would not fully open until closing and re-opening. +- Got most functionality working within Firefox (still working on review process before it can be available). +- Fixed menu dropdown bug introduced in Chrome 52. + +## 2.7.0 2016-07-21 + +- Added a Warning screen about storing ETH +- Add buy Button! +- MetaMask now throws descriptive errors when apps try to use synchronous web3 methods. +- Removed firefox-specific line in manifest. + +## 2.6.2 2016-07-20 + +- Fixed bug that would prevent the plugin from reopening on the first try after receiving a new transaction while locked. +- Fixed bug that would render 0 ETH as a non-exact amount. + +## 2.6.1 2016-07-13 + +- Fix tool tips on Eth balance to show the 6 decimals +- Fix rendering of recipient SVG in tx approval notification. +- New vaults now generate only one wallet instead of three. +- Bumped version of web3 provider engine. +- Fixed bug where some lowercase or uppercase addresses were not being recognized as valid. +- Fixed bug where gas cost was misestimated on the tx confirmation view. + +## 2.6.0 2016-07-11 + +- Fix formatting of ETH balance +- Fix formatting of account details. +- Use web3 minified dist for faster inject times +- Fix issue where dropdowns were not in front of icons. +- Update transaction approval styles. +- Align failed and successful transaction history text. +- Fix issue where large domain names and large transaction values would misalign the transaction history. +- Abbreviate ether balances on transaction details to maintain formatting. +- General code cleanup. + +## 2.5.0 2016-06-29 + +- Implement new account design. +- Added a network indicator mark in dropdown menu +- Added network name next to network indicator +- Add copy transaction hash button to completed transaction list items. +- Unify wording for transaction approve/reject options on notifications and the extension. +- Fix bug where confirmation view would be shown twice. + +## 2.4.5 2016-06-29 + +- Fixed bug where MetaMask interfered with PDF loading. +- Moved switch account icon into menu bar. +- Changed status shapes to be a yellow warning sign for failure and ellipsis for pending transactions. +- Now enforce 20 character limit on wallet names. +- Wallet titles are now properly truncated in transaction confirmation. +- Fix formatting on terms & conditions page. +- Now enforce 30 character limit on wallet names. +- Fix out-of-place positioning of pending transaction badges on wallet list. +- Change network status icons to reflect current design. + +## 2.4.4 2016-06-23 + +- Update web3-stream-provider for batch payload bug fix + +## 2.4.3 2016-06-23 + +- Remove redundant network option buttons from settings page +- Switch out font family Transat for Montserrat + +## 2.4.2 2016-06-22 + +- Change out export icon for key. +- Unify copy to clipboard icon +- Fixed eth.sign behavior. +- Fix behavior of batched outbound transactions. + +## 2.4.0 2016-06-20 + +- Clean up UI. +- Remove nonfunctional QR code button. +- Make network loading indicator clickable to select accessible network. +- Show more characters of addresses when space permits. +- Fixed bug when signing messages under 64 hex characters long. +- Add disclaimer view with placeholder text for first time users. + +## 2.3.1 2016-06-09 + +- Style up the info page +- Cache identicon images to optimize for long lists of transactions. +- Fix out of gas errors + +## 2.3.0 2016-06-06 + +- Show network status in title bar +- Added seed word recovery to config screen. +- Clicking network status indicator now reveals a provider menu. + +## 2.2.0 2016-06-02 + +- Redesigned init, vault create, vault restore and seed confirmation screens. +- Added pending transactions to transaction list on account screen. +- Clicking a pending transaction takes you back to the transaction approval screen. +- Update provider-engine to fix intermittent out of gas errors. + +## 2.1.0 2016-05-26 + +- Added copy address button to account list. +- Fixed back button on confirm transaction screen. +- Add indication of pending transactions to account list screen. +- Fixed bug where error warning was sometimes not cleared on view transition. +- Updated eth-lightwallet to fix a critical security issue. + +## 2.0.0 2016-05-23 + +- UI Overhaul per Vlad Todirut's designs. +- Replaced identicons with jazzicons. +- Fixed glitchy transitions. +- Added support for capitalization-based address checksums. +- Send value is no longer limited by javascript number precision, and is always in ETH. +- Added ability to generate new accounts. +- Added ability to locally nickname accounts. + +## 1.8.4 2016-05-13 + +- Point rpc servers to https endpoints. + +## 1.8.3 2016-05-12 + +- Bumped web3 to 0.6.0 +- Really fixed `eth_syncing` method response. + +## 1.8.2 2016-05-11 + +- Fixed bug where send view would not load correctly the first time it was visited per account. +- Migrated all users to new scalable backend. +- Fixed `eth_syncing` method response. + +## 1.8.1 2016-05-10 + +- Initial usage of scalable blockchain backend. +- Made official providers more easily configurable for us internally. + +## 1.8.0 2016-05-10 + +- Add support for calls to `eth.sign`. +- Moved account exporting within subview of the account detail view. +- Added buttons to the account export process. +- Improved visual appearance of account detail transition where button heights would change. +- Restored back button to account detail view. +- Show transaction list always, never collapsed. +- Changing provider now reloads current Dapps +- Improved appearance of transaction list in account detail view. + +## 1.7.0 2016-04-29 + +- Account detail view is now the primary view. +- The account detail view now has a "Change acct" button which shows the account list. +- Clicking accounts in the account list now both selects that account and displays that account's detail view. +- Selected account is now persisted between sessions, so the current account stays selected. +- Account icons are now "identicons" (deterministically generated from the address). +- Fixed link to Slack channel. +- Added a context guard for "define" to avoid UMD's exporting themselves to the wrong module system, fixing interference with some websites. +- Transaction list now only shows transactions for the current account. +- Transaction list now only shows transactions for the current network (mainnet, testnet, testrpc). +- Fixed transaction links to etherscan blockchain explorer. +- Fixed some UI transitions that had weird behavior. + +## 1.6.0 2016-04-22 + +- Pending transactions are now persisted to localStorage and resume even after browser is closed. +- Completed transactions are now persisted and can be displayed via UI. +- Added transaction list to account detail view. +- Fix bug on config screen where current RPC address was always displayed wrong. +- Fixed bug where entering a decimal value when sending a transaction would result in sending the wrong amount. +- Add save button to custom RPC input field. +- Add quick-select button for RPC on `localhost:8545`. +- Improve config view styling. +- Users have been migrated from old test-net RPC to a newer test-net RPC. + +## 1.5.1 2016-04-15 + +- Corrected text above account list. Selected account is visible to all sites, not just the current domain. +- Merged the UI codebase into the main plugin codebase for simpler maintenance. +- Fix Ether display rounding error. Now rendering to four decimal points. +- Fix some inpage synchronous methods +- Change account rendering to show four decimals and a leading zero. + +## 1.5.0 2016-04-13 + +- Added ability to send ether. +- Fixed bugs related to using Javascript numbers, which lacked appropriate precision. +- Replaced Etherscan main-net provider with our own production RPC. + +## 1.4.0 2016-04-08 + +- Removed extra entropy text field for simplified vault creation. +- Now supports exporting an account's private key. +- Unified button and input styles across the app. +- Removed some non-working placeholder UI until it works. +- Fix popup's web3 stream provider +- Temporarily deactivated fauceting indication because it would activate when restoring an empty account. + +## 1.3.2 2016-04-04 + + - When unlocking, first account is auto-selected. + - When creating a first vault on the test-net, the first account is auto-funded. + - Fixed some styling issues. + +## 1.0.1-1.3.1 + +Many changes not logged. Hopefully beginning to log consistently now! + +## 1.0.0 + +Made seed word restoring BIP44 compatible. + +## 0.14.0 + +Added the ability to restore accounts from seed words. diff --git a/test/unit/development/sample-manifest.json b/test/unit/development/sample-manifest.json new file mode 100644 index 000000000..2b3acf1b5 --- /dev/null +++ b/test/unit/development/sample-manifest.json @@ -0,0 +1,71 @@ +{ + "name": "MetaMask", + "short_name": "Metamask", + "version": "4.1.3", + "manifest_version": 2, + "author": "https://metamask.io", + "description": "Ethereum Browser Extension", + "commands": { + "_execute_browser_action": { + "suggested_key": { + "windows": "Alt+Shift+M", + "mac": "Alt+Shift+M", + "chromeos": "Alt+Shift+M", + "linux": "Alt+Shift+M" + } + } + }, + "icons": { + "16": "images/icon-16.png", + "128": "images/icon-128.png" + }, + "applications": { + "gecko": { + "id": "webextension@metamask.io" + } + }, + "default_locale": "en", + "background": { + "scripts": [ + "scripts/chromereload.js", + "scripts/background.js" + ], + "persistent": true + }, + "browser_action": { + "default_icon": { + "19": "images/icon-19.png", + "38": "images/icon-38.png" + }, + "default_title": "MetaMask", + "default_popup": "popup.html" + }, + "content_scripts": [ + { + "matches": [ + "file://*/*", + "http://*/*", + "https://*/*" + ], + "js": [ + "scripts/contentscript.js" + ], + "run_at": "document_start", + "all_frames": true + } + ], + "permissions": [ + "storage", + "clipboardWrite", + "http://localhost:8545/", + "https://*.infura.io/" + ], + "web_accessible_resources": [ + "scripts/inpage.js" + ], + "externally_connectable": { + "matches": [ + "https://metamask.io/*" + ] + } +} diff --git a/test/unit/development/version–bump-test.js b/test/unit/development/version–bump-test.js new file mode 100644 index 000000000..de29851ce --- /dev/null +++ b/test/unit/development/version–bump-test.js @@ -0,0 +1,46 @@ +const assert = require('assert') +const versionBump = require('../../../development/version-bump') +const { promisify } = require('util') +const fs = require('fs') +const readFile = promisify(fs.readFile) +const path = require('path') +const changelogPath = path.join(__dirname, 'sample-changelog.md') +const manifest = require('./sample-manifest.json') +let changelog + + +describe('version bumper', function () { + + beforeEach(async () => { + // load changelog. Mock version is 4.1.3 + const changeBuffer = await readFile(changelogPath) + changelog = changeBuffer.toString() + }) + + it('returns a properly bumped major version', async function () { + const result = await versionBump('major', changelog, manifest) + const expected = '5.0.0' + assert.equal(result.version, expected, 'major bumps correctly') + assert.equal(result.manifest.version, expected, 'major bumps correctly') + console.dir(result.changelog) + assert.ok(result.changelog.includes(expected)) + }) + + it('returns a properly bumped minor version', async function () { + const result = await versionBump('minor', changelog, manifest) + const expected = '4.2.0' + assert.equal(result.version, expected, 'minor bumps correctly') + assert.equal(result.manifest.version, expected, 'minor bumps correctly') + assert.ok(result.changelog.includes(expected)) + }) + + it('returns a properly bumped patch version', async function () { + const result = await versionBump('patch', changelog, manifest) + const expected = '4.1.4' + assert.equal(result.version, expected, 'patch bumps correctly') + assert.equal(result.manifest.version, expected, 'patch bumps correctly') + assert.ok(result.changelog.includes(expected)) + }) +}) + + From 3a9b3794ebccbe3369a67e797186141dc011dd9d Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 2 Mar 2018 13:59:08 -0800 Subject: [PATCH 108/392] Remove logs --- development/run-version-bump.js | 7 ------- development/version-bump.js | 1 - test/unit/development/version–bump-test.js | 1 - 3 files changed, 9 deletions(-) diff --git a/development/run-version-bump.js b/development/run-version-bump.js index 3b26b00db..e06c00db3 100644 --- a/development/run-version-bump.js +++ b/development/run-version-bump.js @@ -8,7 +8,6 @@ const manifestPath = path.join(__dirname, '..', 'app', 'manifest.json') const manifest = require('../app/manifest.json') const versionBump = require('./version-bump') -console.dir(process.argv) const bumpType = normalizeType(process.argv[2]) @@ -17,12 +16,9 @@ readFile(changelogPath) const changelog = changeBuffer.toString() const newData = await versionBump(bumpType, changelog, manifest) - console.dir(newData) const manifestString = JSON.stringify(newData.manifest, null, 2) - console.log('now writing files to ', changelogPath, manifestPath) - console.log(typeof newData.manifest) await writeFile(changelogPath, newData.changelog) await writeFile(manifestPath, manifestString) @@ -33,17 +29,14 @@ readFile(changelogPath) function normalizeType (userInput) { - console.log(`user inputted ${userInput}`) const err = new Error('First option must be a type (major, minor, or patch)') if (!userInput || typeof userInput !== 'string') { - console.log('first no') throw err } const lower = userInput.toLowerCase() if (lower !== 'major' && lower !== 'minor' && lower !== 'patch') { - console.log('second no') throw err } diff --git a/development/version-bump.js b/development/version-bump.js index 63dd802d1..bedf87c01 100644 --- a/development/version-bump.js +++ b/development/version-bump.js @@ -27,7 +27,6 @@ function newVersionFrom (manifest, bumpType) { const string = manifest.version let segments = string.split('.').map((str) => parseInt(str)) - console.log('bump type is ' + bumpType) switch (bumpType) { case 'major': segments[0] += 1 diff --git a/test/unit/development/version–bump-test.js b/test/unit/development/version–bump-test.js index de29851ce..1c445c8b4 100644 --- a/test/unit/development/version–bump-test.js +++ b/test/unit/development/version–bump-test.js @@ -22,7 +22,6 @@ describe('version bumper', function () { const expected = '5.0.0' assert.equal(result.version, expected, 'major bumps correctly') assert.equal(result.manifest.version, expected, 'major bumps correctly') - console.dir(result.changelog) assert.ok(result.changelog.includes(expected)) }) From 0c163dcb32ddafde8a8ed3e9e21be552a5eeeed5 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Fri, 2 Mar 2018 19:07:25 -0330 Subject: [PATCH 109/392] Allow adding 0 balance tokens in old ui and editing custom token info in new (#3395) * Shows tokens with 0 balance in old ui; goHome after adding tokens. * Allow users to edit custom token info when not autofilled. (New UI add token screen). --- old-ui/app/add-token.js | 3 +++ old-ui/app/components/token-list.js | 5 +---- ui/app/add-token.js | 26 +++++++++++++++++++++----- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/old-ui/app/add-token.js b/old-ui/app/add-token.js index 8a3e66978..e869ac39a 100644 --- a/old-ui/app/add-token.js +++ b/old-ui/app/add-token.js @@ -156,6 +156,9 @@ AddTokenScreen.prototype.render = function () { const { address, symbol, decimals } = this.state this.props.dispatch(actions.addToken(address.trim(), symbol.trim(), decimals)) + .then(() => { + this.props.dispatch(actions.goHome()) + }) }, }, 'Add'), ]), diff --git a/old-ui/app/components/token-list.js b/old-ui/app/components/token-list.js index 998ec901d..149733b89 100644 --- a/old-ui/app/components/token-list.js +++ b/old-ui/app/components/token-list.js @@ -194,10 +194,7 @@ TokenList.prototype.componentWillUpdate = function (nextProps) { } TokenList.prototype.updateBalances = function (tokens) { - const heldTokens = tokens.filter(token => { - return token.balance !== '0' && token.string !== '0.000' - }) - this.setState({ tokens: heldTokens, isLoading: false }) + this.setState({ tokens, isLoading: false }) } TokenList.prototype.componentWillUnmount = function () { diff --git a/ui/app/add-token.js b/ui/app/add-token.js index 230ab35fe..a1729ba8e 100644 --- a/ui/app/add-token.js +++ b/ui/app/add-token.js @@ -52,13 +52,16 @@ function AddTokenScreen () { isShowingConfirmation: false, customAddress: '', customSymbol: '', - customDecimals: 0, + customDecimals: null, searchQuery: '', isCollapsed: true, selectedTokens: {}, errors: {}, + autoFilled: false, } this.tokenAddressDidChange = this.tokenAddressDidChange.bind(this) + this.tokenSymbolDidChange = this.tokenSymbolDidChange.bind(this) + this.tokenDecimalsDidChange = this.tokenDecimalsDidChange.bind(this) this.onNext = this.onNext.bind(this) Component.call(this) } @@ -103,6 +106,16 @@ AddTokenScreen.prototype.tokenAddressDidChange = function (e) { } } +AddTokenScreen.prototype.tokenSymbolDidChange = function (e) { + const customSymbol = e.target.value.trim() + this.setState({ customSymbol }) +} + +AddTokenScreen.prototype.tokenDecimalsDidChange = function (e) { + const customDecimals = e.target.value.trim() + this.setState({ customDecimals }) +} + AddTokenScreen.prototype.checkExistingAddresses = function (address) { if (!address) return false const tokensList = this.props.tokens @@ -125,7 +138,7 @@ AddTokenScreen.prototype.validate = function () { errors.customAddress = 'Address is invalid. ' } - const validDecimals = customDecimals >= 0 && customDecimals < 36 + const validDecimals = customDecimals !== null && customDecimals >= 0 && customDecimals < 36 if (!validDecimals) { errors.customDecimals = 'Decimals must be at least 0, and not over 36.' } @@ -166,12 +179,13 @@ AddTokenScreen.prototype.attemptToAutoFillTokenParams = async function (address) this.setState({ customSymbol: symbol, customDecimals: decimals.toString(), + autoFilled: true, }) } } AddTokenScreen.prototype.renderCustomForm = function () { - const { customAddress, customSymbol, customDecimals, errors } = this.state + const { autoFilled, customAddress, customSymbol, customDecimals, errors } = this.state return !this.state.isCollapsed && ( h('div.add-token__add-custom-form', [ @@ -196,8 +210,9 @@ AddTokenScreen.prototype.renderCustomForm = function () { h('div.add-token__add-custom-label', 'Token Symbol'), h('input.add-token__add-custom-input', { type: 'text', + onChange: this.tokenSymbolDidChange, value: customSymbol, - disabled: true, + disabled: autoFilled, }), h('div.add-token__add-custom-error-message', errors.customSymbol), ]), @@ -209,8 +224,9 @@ AddTokenScreen.prototype.renderCustomForm = function () { h('div.add-token__add-custom-label', 'Decimals of Precision'), h('input.add-token__add-custom-input', { type: 'number', + onChange: this.tokenDecimalsDidChange, value: customDecimals, - disabled: true, + disabled: autoFilled, }), h('div.add-token__add-custom-error-message', errors.customDecimals), ]), From 92453f8715b78c0e6e2cdb9b2e1cfe48c0b013ad Mon Sep 17 00:00:00 2001 From: Csaba Solya Date: Sat, 3 Mar 2018 00:32:57 +0100 Subject: [PATCH 110/392] seed phrase verifier --- app/scripts/lib/seed-phrase-verifier.js | 43 ++++++++ app/scripts/metamask-controller.js | 20 +++- test/unit/seed-phrase-verifier-test.js | 136 ++++++++++++++++++++++++ 3 files changed, 197 insertions(+), 2 deletions(-) create mode 100644 app/scripts/lib/seed-phrase-verifier.js create mode 100644 test/unit/seed-phrase-verifier-test.js diff --git a/app/scripts/lib/seed-phrase-verifier.js b/app/scripts/lib/seed-phrase-verifier.js new file mode 100644 index 000000000..9bea2910e --- /dev/null +++ b/app/scripts/lib/seed-phrase-verifier.js @@ -0,0 +1,43 @@ +const KeyringController = require('eth-keyring-controller') + +const seedPhraseVerifier = { + + verifyAccounts(createdAccounts, seedWords) { + + return new Promise((resolve, reject) => { + + if (!createdAccounts || createdAccounts.length < 1) { + return reject(new Error('No created accounts defined.')) + } + + let keyringController = new KeyringController({}) + let Keyring = keyringController.getKeyringClassForType('HD Key Tree') + let opts = { + mnemonic: seedWords, + numberOfAccounts: createdAccounts.length, + } + + let keyring = new Keyring(opts) + keyring.getAccounts() + .then((restoredAccounts) => { + + log.debug('Created accounts: ' + JSON.stringify(createdAccounts)) + log.debug('Restored accounts: ' + JSON.stringify(restoredAccounts)) + + if (restoredAccounts.length != createdAccounts.length) { + // this should not happen... + return reject(new Error("Wrong number of accounts")) + } + + for (let i = 0; i < restoredAccounts.length; i++) { + if (restoredAccounts[i] !== createdAccounts[i]) { + return reject(new Error('Not identical accounts! Original: ' + createdAccounts[i] + ', Restored: ' + restoredAccounts[i])) + } + } + return resolve() + }) + }) + } +} + +module.exports = seedPhraseVerifier \ No newline at end of file diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index ad4e71792..89bcbd51b 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -37,6 +37,7 @@ const version = require('../manifest.json').version const BN = require('ethereumjs-util').BN const GWEI_BN = new BN('1000000000') const percentile = require('percentile') +const seedPhraseVerifier = require('./lib/seed-phrase-verifier') module.exports = class MetamaskController extends EventEmitter { @@ -592,8 +593,23 @@ module.exports = class MetamaskController extends EventEmitter { primaryKeyring.serialize() .then((serialized) => { const seedWords = serialized.mnemonic - this.configManager.setSeedWords(seedWords) - cb(null, seedWords) + + primaryKeyring.getAccounts() + .then((accounts) => { + if (accounts.length < 1) { + return cb(new Error('MetamaskController - No accounts found')) + } + + seedPhraseVerifier.verifyAccounts(accounts, seedWords) + .then(() => { + this.configManager.setSeedWords(seedWords) + cb(null, seedWords) + }) + .catch((err) => { + log.error(err) + cb(err) + }) + }) }) } diff --git a/test/unit/seed-phrase-verifier-test.js b/test/unit/seed-phrase-verifier-test.js new file mode 100644 index 000000000..a7a463dd3 --- /dev/null +++ b/test/unit/seed-phrase-verifier-test.js @@ -0,0 +1,136 @@ +const assert = require('assert') +const clone = require('clone') +const KeyringController = require('eth-keyring-controller') +const firstTimeState = require('../../app/scripts/first-time-state') +const seedPhraseVerifier = require('../../app/scripts/lib/seed-phrase-verifier') +const mockEncryptor = require('../lib/mock-encryptor') + +describe('SeedPhraseVerifier', function () { + + describe('verifyAccounts', function () { + + var password = 'passw0rd1' + let hdKeyTree = 'HD Key Tree' + + it('should be able to verify created account with seed words', async function () { + + let keyringController = new KeyringController({ + initState: clone(firstTimeState), + encryptor: mockEncryptor, + }) + assert(keyringController) + + let vault = await keyringController.createNewVaultAndKeychain(password) + let primaryKeyring = keyringController.getKeyringsByType(hdKeyTree)[0] + + let createdAccounts = await primaryKeyring.getAccounts() + assert.equal(createdAccounts.length, 1) + + let serialized = await primaryKeyring.serialize() + let seedWords = serialized.mnemonic + assert.notEqual(seedWords.length, 0) + + let result = await seedPhraseVerifier.verifyAccounts(createdAccounts, seedWords) + }) + + it('should return error with good but different seed words', async function () { + + let keyringController = new KeyringController({ + initState: clone(firstTimeState), + encryptor: mockEncryptor, + }) + assert(keyringController) + + let vault = await keyringController.createNewVaultAndKeychain(password) + let primaryKeyring = keyringController.getKeyringsByType(hdKeyTree)[0] + + let createdAccounts = await primaryKeyring.getAccounts() + assert.equal(createdAccounts.length, 1) + + let serialized = await primaryKeyring.serialize() + let seedWords = 'debris dizzy just program just float decrease vacant alarm reduce speak stadium' + + try { + let result = await seedPhraseVerifier.verifyAccounts(createdAccounts, seedWords) + assert.fail("Should reject") + } catch (err) { + assert.ok(err.message.indexOf('Not identical accounts!') >= 0, 'Wrong error message') + } + }) + + it('should return error with undefined existing accounts', async function () { + + let keyringController = new KeyringController({ + initState: clone(firstTimeState), + encryptor: mockEncryptor, + }) + assert(keyringController) + + let vault = await keyringController.createNewVaultAndKeychain(password) + let primaryKeyring = keyringController.getKeyringsByType(hdKeyTree)[0] + + let createdAccounts = await primaryKeyring.getAccounts() + assert.equal(createdAccounts.length, 1) + + let serialized = await primaryKeyring.serialize() + let seedWords = 'debris dizzy just program just float decrease vacant alarm reduce speak stadium' + + try { + let result = await seedPhraseVerifier.verifyAccounts(undefined, seedWords) + assert.fail("Should reject") + } catch (err) { + assert.equal(err.message, 'No created accounts defined.') + } + }) + + it('should return error with empty accounts array', async function () { + + let keyringController = new KeyringController({ + initState: clone(firstTimeState), + encryptor: mockEncryptor, + }) + assert(keyringController) + + let vault = await keyringController.createNewVaultAndKeychain(password) + let primaryKeyring = keyringController.getKeyringsByType(hdKeyTree)[0] + + let createdAccounts = await primaryKeyring.getAccounts() + assert.equal(createdAccounts.length, 1) + + let serialized = await primaryKeyring.serialize() + let seedWords = 'debris dizzy just program just float decrease vacant alarm reduce speak stadium' + + try { + let result = await seedPhraseVerifier.verifyAccounts([], seedWords) + assert.fail("Should reject") + } catch (err) { + assert.equal(err.message, 'No created accounts defined.') + } + }) + + it('should be able to verify more than one created account with seed words', async function () { + + let keyringController = new KeyringController({ + initState: clone(firstTimeState), + encryptor: mockEncryptor, + }) + assert(keyringController) + + let vault = await keyringController.createNewVaultAndKeychain(password) + + let primaryKeyring = keyringController.getKeyringsByType(hdKeyTree)[0] + + const keyState = await keyringController.addNewAccount(primaryKeyring) + const keyState2 = await keyringController.addNewAccount(primaryKeyring) + + let createdAccounts = await primaryKeyring.getAccounts() + assert.equal(createdAccounts.length, 3) + + let serialized = await primaryKeyring.serialize() + let seedWords = serialized.mnemonic + assert.notEqual(seedWords.length, 0) + + let result = await seedPhraseVerifier.verifyAccounts(createdAccounts, seedWords) + }) + }) +}) From 4bd7f1a37abcd09dc8816fc5b28ad41bc86b1aea Mon Sep 17 00:00:00 2001 From: Csaba Solya Date: Sat, 3 Mar 2018 00:40:40 +0100 Subject: [PATCH 111/392] fix lint issues --- app/scripts/lib/seed-phrase-verifier.js | 18 +++++++++--------- app/scripts/metamask-controller.js | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/app/scripts/lib/seed-phrase-verifier.js b/app/scripts/lib/seed-phrase-verifier.js index 9bea2910e..97a433fd8 100644 --- a/app/scripts/lib/seed-phrase-verifier.js +++ b/app/scripts/lib/seed-phrase-verifier.js @@ -2,7 +2,7 @@ const KeyringController = require('eth-keyring-controller') const seedPhraseVerifier = { - verifyAccounts(createdAccounts, seedWords) { + verifyAccounts (createdAccounts, seedWords) { return new Promise((resolve, reject) => { @@ -10,23 +10,23 @@ const seedPhraseVerifier = { return reject(new Error('No created accounts defined.')) } - let keyringController = new KeyringController({}) - let Keyring = keyringController.getKeyringClassForType('HD Key Tree') - let opts = { + const keyringController = new KeyringController({}) + const Keyring = keyringController.getKeyringClassForType('HD Key Tree') + const opts = { mnemonic: seedWords, numberOfAccounts: createdAccounts.length, } - let keyring = new Keyring(opts) + const keyring = new Keyring(opts) keyring.getAccounts() .then((restoredAccounts) => { log.debug('Created accounts: ' + JSON.stringify(createdAccounts)) log.debug('Restored accounts: ' + JSON.stringify(restoredAccounts)) - if (restoredAccounts.length != createdAccounts.length) { + if (restoredAccounts.length !== createdAccounts.length) { // this should not happen... - return reject(new Error("Wrong number of accounts")) + return reject(new Error('Wrong number of accounts')) } for (let i = 0; i < restoredAccounts.length; i++) { @@ -37,7 +37,7 @@ const seedPhraseVerifier = { return resolve() }) }) - } + }, } -module.exports = seedPhraseVerifier \ No newline at end of file +module.exports = seedPhraseVerifier diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 89bcbd51b..b9231aa3d 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -599,9 +599,9 @@ module.exports = class MetamaskController extends EventEmitter { if (accounts.length < 1) { return cb(new Error('MetamaskController - No accounts found')) } - + seedPhraseVerifier.verifyAccounts(accounts, seedWords) - .then(() => { + .then(() => { this.configManager.setSeedWords(seedWords) cb(null, seedWords) }) From bdbe29906976915196f347861e913f3f5b523d0e Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 2 Mar 2018 14:33:29 -0800 Subject: [PATCH 112/392] Clean up run version bump script --- development/run-version-bump.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/development/run-version-bump.js b/development/run-version-bump.js index e06c00db3..fde14566e 100644 --- a/development/run-version-bump.js +++ b/development/run-version-bump.js @@ -7,12 +7,13 @@ const changelogPath = path.join(__dirname, '..', 'CHANGELOG.md') const manifestPath = path.join(__dirname, '..', 'app', 'manifest.json') const manifest = require('../app/manifest.json') const versionBump = require('./version-bump') - const bumpType = normalizeType(process.argv[2]) +start().catch(console.error) -readFile(changelogPath) -.then(async (changeBuffer) => { +async function start() { + + const changeBuffer = await readFile(changelogPath) const changelog = changeBuffer.toString() const newData = await versionBump(bumpType, changelog, manifest) @@ -22,10 +23,8 @@ readFile(changelogPath) await writeFile(changelogPath, newData.changelog) await writeFile(manifestPath, manifestString) - return newData.version -}) -.then((version) => console.log(`Bumped ${bumpType} to version ${version}`)) -.catch(console.error) + console.log(`Bumped ${bumpType} to version ${newData.version}`) +} function normalizeType (userInput) { From 0d97ff221017b78ccfa02defdb7a52ad701981a5 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Fri, 2 Mar 2018 22:44:05 -0330 Subject: [PATCH 113/392] Fix NewUI reveal seed flow. (#3410) --- ui/app/actions.js | 5 +++-- ui/app/app.js | 14 +++++++++++--- ui/app/reducers/app.js | 4 ++-- ui/app/reducers/metamask.js | 7 ++++++- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/ui/app/actions.js b/ui/app/actions.js index 64d5b67e0..4f902a6a2 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -853,15 +853,16 @@ function markPasswordForgotten () { function unMarkPasswordForgotten () { return (dispatch) => { return background.unMarkPasswordForgotten(() => { - dispatch(actions.forgotPassword()) + dispatch(actions.forgotPassword(false)) forceUpdateMetamaskState(dispatch) }) } } -function forgotPassword () { +function forgotPassword (forgotPasswordState = true) { return { type: actions.FORGOT_PASSWORD, + value: forgotPasswordState, } } diff --git a/ui/app/app.js b/ui/app/app.js index 5d37b9bdf..bfa8d8aa7 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -89,6 +89,7 @@ function mapStateToProps (state) { currentCurrency: state.metamask.currentCurrency, isMouseUser: state.appState.isMouseUser, betaUI: state.metamask.featureFlags.betaUI, + isRevealingSeedWords: state.metamask.isRevealingSeedWords, // state needed to get account dropdown temporarily rendering from app bar identities, @@ -362,9 +363,16 @@ App.prototype.renderBackButton = function (style, justArrow = false) { App.prototype.renderPrimary = function () { log.debug('rendering primary') var props = this.props - const {isMascara, isOnboarding, betaUI} = props + const { + isMascara, + isOnboarding, + betaUI, + isRevealingSeedWords, + } = props + const isMascaraOnboarding = isMascara && isOnboarding + const isBetaUIOnboarding = betaUI && isOnboarding && !props.isPopup && !isRevealingSeedWords - if ((isMascara || betaUI) && isOnboarding && !props.isPopup) { + if (isMascaraOnboarding || isBetaUIOnboarding) { return h(MascaraFirstTime) } @@ -388,7 +396,7 @@ App.prototype.renderPrimary = function () { if (props.isInitialized && props.forgottenPassword) { log.debug('rendering restore vault screen') return h(HDRestoreVaultScreen, {key: 'HDRestoreVaultScreen'}) - } else if (!props.isInitialized && !props.isUnlocked) { + } else if (!props.isInitialized && !props.isUnlocked && !isRevealingSeedWords) { log.debug('rendering menu screen') return props.isPopup ? h(OldUIInitializeMenuScreen, {key: 'menuScreenInit'}) diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js index 02f024f7c..4dda839a2 100644 --- a/ui/app/reducers/app.js +++ b/ui/app/reducers/app.js @@ -140,10 +140,10 @@ function reduceApp (state, action) { case actions.FORGOT_PASSWORD: return extend(appState, { currentView: { - name: 'restoreVault', + name: action.value ? 'restoreVault' : 'accountDetail', }, transForward: false, - forgottenPassword: true, + forgottenPassword: action.value, }) case actions.SHOW_INIT_MENU: diff --git a/ui/app/reducers/metamask.js b/ui/app/reducers/metamask.js index beeba948d..cddcd0c1f 100644 --- a/ui/app/reducers/metamask.js +++ b/ui/app/reducers/metamask.js @@ -43,12 +43,15 @@ function reduceMetamask (state, action) { useBlockie: false, featureFlags: {}, networkEndpointType: OLD_UI_NETWORK_TYPE, + isRevealingSeedWords: false, }, state.metamask) switch (action.type) { case actions.SHOW_ACCOUNTS_PAGE: - newState = extend(metamaskState) + newState = extend(metamaskState, { + isRevealingSeedWords: false, + }) delete newState.seedWords return newState @@ -124,10 +127,12 @@ function reduceMetamask (state, action) { }, }) + case actions.SHOW_NEW_VAULT_SEED: return extend(metamaskState, { isUnlocked: true, isInitialized: false, + isRevealingSeedWords: true, seedWords: action.value, }) From 6f8077f587fe16ebdb8ce3ffe7a0df9f58c74ffb Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 2 Mar 2018 18:23:27 -0800 Subject: [PATCH 114/392] Swap color scheme for import account label --- ui/app/css/itcss/components/account-menu.scss | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ui/app/css/itcss/components/account-menu.scss b/ui/app/css/itcss/components/account-menu.scss index 8ad7481c7..4752741aa 100644 --- a/ui/app/css/itcss/components/account-menu.scss +++ b/ui/app/css/itcss/components/account-menu.scss @@ -66,8 +66,9 @@ .keyring-label { margin-top: 5px; - background-color: $black; - color: $dusty-gray; + background-color: $dusty-gray; + color: $black; + font-weight: normal; } } From ee254b4f6feeb040607472a0f4d69c7e4173c25e Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 2 Mar 2018 18:24:09 -0800 Subject: [PATCH 115/392] Import Account disclaimer --- ui/app/accounts/import/index.js | 11 ++--------- ui/app/css/itcss/components/new-account.scss | 10 ++++++++++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/ui/app/accounts/import/index.js b/ui/app/accounts/import/index.js index 7e7d3aa91..adb52db74 100644 --- a/ui/app/accounts/import/index.js +++ b/ui/app/accounts/import/index.js @@ -35,17 +35,10 @@ AccountImportSubview.prototype.render = function () { return ( h('div.new-account-import-form', [ - h('.warning', { - style: { - display: 'inline-block', - alignItems: 'center', - padding: '15px 15px 0px 15px', - }, - }, [ + h('.new-account-import-disclaimer', [ h('span', 'Imported accounts will not be associated with your originally created MetaMask account seedphrase. Learn more about imported accounts '), h('span', { style: { - color: 'rgba(247, 134, 28, 1)', cursor: 'pointer', textDecoration: 'underline', }, @@ -54,7 +47,7 @@ AccountImportSubview.prototype.render = function () { url: 'https://metamask.helpscoutdocs.com/article/17-what-are-loose-accounts', }) }, - }, 'here.'), + }, 'here'), ]), h('div.new-account-import-form__select-section', [ diff --git a/ui/app/css/itcss/components/new-account.scss b/ui/app/css/itcss/components/new-account.scss index 81f919df3..c6c254ede 100644 --- a/ui/app/css/itcss/components/new-account.scss +++ b/ui/app/css/itcss/components/new-account.scss @@ -54,6 +54,16 @@ } +.new-account-import-disclaimer { + width: 120%; + background-color: #F4F9FC; + display: inline-block; + align-items: center; + padding: 20px 30px 20px; + font-size: 12px; + line-height: 1.5; +} + .new-account-import-form { display: flex; flex-flow: column; From 3e05b693dbf55ea7ecb791e8f31b7599a6b89ffd Mon Sep 17 00:00:00 2001 From: Csaba Solya Date: Sat, 3 Mar 2018 14:11:02 +0100 Subject: [PATCH 116/392] verify addresses regardless case --- app/scripts/lib/seed-phrase-verifier.js | 2 +- test/unit/seed-phrase-verifier-test.js | 44 +++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/app/scripts/lib/seed-phrase-verifier.js b/app/scripts/lib/seed-phrase-verifier.js index 97a433fd8..1f35c2c67 100644 --- a/app/scripts/lib/seed-phrase-verifier.js +++ b/app/scripts/lib/seed-phrase-verifier.js @@ -30,7 +30,7 @@ const seedPhraseVerifier = { } for (let i = 0; i < restoredAccounts.length; i++) { - if (restoredAccounts[i] !== createdAccounts[i]) { + if (restoredAccounts[i].toLowerCase() !== createdAccounts[i].toLowerCase()) { return reject(new Error('Not identical accounts! Original: ' + createdAccounts[i] + ', Restored: ' + restoredAccounts[i])) } } diff --git a/test/unit/seed-phrase-verifier-test.js b/test/unit/seed-phrase-verifier-test.js index a7a463dd3..3e9acfa82 100644 --- a/test/unit/seed-phrase-verifier-test.js +++ b/test/unit/seed-phrase-verifier-test.js @@ -33,6 +33,50 @@ describe('SeedPhraseVerifier', function () { let result = await seedPhraseVerifier.verifyAccounts(createdAccounts, seedWords) }) + it('should be able to verify created account (upper case) with seed words', async function () { + + let keyringController = new KeyringController({ + initState: clone(firstTimeState), + encryptor: mockEncryptor, + }) + assert(keyringController) + + let vault = await keyringController.createNewVaultAndKeychain(password) + let primaryKeyring = keyringController.getKeyringsByType(hdKeyTree)[0] + + let createdAccounts = await primaryKeyring.getAccounts() + assert.equal(createdAccounts.length, 1) + let upperCaseAccounts = [createdAccounts[0].toUpperCase()] + + let serialized = await primaryKeyring.serialize() + let seedWords = serialized.mnemonic + assert.notEqual(seedWords.length, 0) + + let result = await seedPhraseVerifier.verifyAccounts(upperCaseAccounts, seedWords) + }) + + it('should be able to verify created account (lower case) with seed words', async function () { + + let keyringController = new KeyringController({ + initState: clone(firstTimeState), + encryptor: mockEncryptor, + }) + assert(keyringController) + + let vault = await keyringController.createNewVaultAndKeychain(password) + let primaryKeyring = keyringController.getKeyringsByType(hdKeyTree)[0] + + let createdAccounts = await primaryKeyring.getAccounts() + assert.equal(createdAccounts.length, 1) + let lowerCaseAccounts = [createdAccounts[0].toLowerCase()] + + let serialized = await primaryKeyring.serialize() + let seedWords = serialized.mnemonic + assert.notEqual(seedWords.length, 0) + + let result = await seedPhraseVerifier.verifyAccounts(lowerCaseAccounts, seedWords) + }) + it('should return error with good but different seed words', async function () { let keyringController = new KeyringController({ From 2b86d65d0c3266e8ddfe814abe1d1755fbf23fda Mon Sep 17 00:00:00 2001 From: Csaba Solya Date: Sat, 3 Mar 2018 22:08:10 +0100 Subject: [PATCH 117/392] verify seedwords on log in --- app/scripts/metamask-controller.js | 19 ++++++++-- test/unit/seed-phrase-verifier-test.js | 48 +++++--------------------- ui/app/actions.js | 7 ++++ 3 files changed, 31 insertions(+), 43 deletions(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index b9231aa3d..df9adc248 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -345,6 +345,7 @@ module.exports = class MetamaskController extends EventEmitter { // primary HD keyring management addNewAccount: nodeify(this.addNewAccount, this), placeSeedWords: this.placeSeedWords.bind(this), + verifySeedPhrase: this.verifySeedPhrase.bind(this), clearSeedWordCache: this.clearSeedWordCache.bind(this), resetAccount: this.resetAccount.bind(this), importAccountWithStrategy: this.importAccountWithStrategy.bind(this), @@ -588,6 +589,19 @@ module.exports = class MetamaskController extends EventEmitter { // Used when creating a first vault, to allow confirmation. // Also used when revealing the seed words in the confirmation view. placeSeedWords (cb) { + + this.verifySeedPhrase((err, seedWords) => { + + if (err) { + return cb(err) + } + this.configManager.setSeedWords(seedWords) + return cb(null, seedWords) + }) + } + + verifySeedPhrase (cb) { + const primaryKeyring = this.keyringController.getKeyringsByType('HD Key Tree')[0] if (!primaryKeyring) return cb(new Error('MetamaskController - No HD Key Tree found')) primaryKeyring.serialize() @@ -602,12 +616,11 @@ module.exports = class MetamaskController extends EventEmitter { seedPhraseVerifier.verifyAccounts(accounts, seedWords) .then(() => { - this.configManager.setSeedWords(seedWords) - cb(null, seedWords) + return cb(null, seedWords) }) .catch((err) => { log.error(err) - cb(err) + return cb(err) }) }) }) diff --git a/test/unit/seed-phrase-verifier-test.js b/test/unit/seed-phrase-verifier-test.js index 3e9acfa82..654fb5994 100644 --- a/test/unit/seed-phrase-verifier-test.js +++ b/test/unit/seed-phrase-verifier-test.js @@ -9,16 +9,20 @@ describe('SeedPhraseVerifier', function () { describe('verifyAccounts', function () { - var password = 'passw0rd1' + let password = 'passw0rd1' let hdKeyTree = 'HD Key Tree' - it('should be able to verify created account with seed words', async function () { - - let keyringController = new KeyringController({ + let keyringController + beforeEach(function () { + keyringController = new KeyringController({ initState: clone(firstTimeState), encryptor: mockEncryptor, }) + assert(keyringController) + }) + + it('should be able to verify created account with seed words', async function () { let vault = await keyringController.createNewVaultAndKeychain(password) let primaryKeyring = keyringController.getKeyringsByType(hdKeyTree)[0] @@ -35,12 +39,6 @@ describe('SeedPhraseVerifier', function () { it('should be able to verify created account (upper case) with seed words', async function () { - let keyringController = new KeyringController({ - initState: clone(firstTimeState), - encryptor: mockEncryptor, - }) - assert(keyringController) - let vault = await keyringController.createNewVaultAndKeychain(password) let primaryKeyring = keyringController.getKeyringsByType(hdKeyTree)[0] @@ -57,12 +55,6 @@ describe('SeedPhraseVerifier', function () { it('should be able to verify created account (lower case) with seed words', async function () { - let keyringController = new KeyringController({ - initState: clone(firstTimeState), - encryptor: mockEncryptor, - }) - assert(keyringController) - let vault = await keyringController.createNewVaultAndKeychain(password) let primaryKeyring = keyringController.getKeyringsByType(hdKeyTree)[0] @@ -79,12 +71,6 @@ describe('SeedPhraseVerifier', function () { it('should return error with good but different seed words', async function () { - let keyringController = new KeyringController({ - initState: clone(firstTimeState), - encryptor: mockEncryptor, - }) - assert(keyringController) - let vault = await keyringController.createNewVaultAndKeychain(password) let primaryKeyring = keyringController.getKeyringsByType(hdKeyTree)[0] @@ -104,12 +90,6 @@ describe('SeedPhraseVerifier', function () { it('should return error with undefined existing accounts', async function () { - let keyringController = new KeyringController({ - initState: clone(firstTimeState), - encryptor: mockEncryptor, - }) - assert(keyringController) - let vault = await keyringController.createNewVaultAndKeychain(password) let primaryKeyring = keyringController.getKeyringsByType(hdKeyTree)[0] @@ -129,12 +109,6 @@ describe('SeedPhraseVerifier', function () { it('should return error with empty accounts array', async function () { - let keyringController = new KeyringController({ - initState: clone(firstTimeState), - encryptor: mockEncryptor, - }) - assert(keyringController) - let vault = await keyringController.createNewVaultAndKeychain(password) let primaryKeyring = keyringController.getKeyringsByType(hdKeyTree)[0] @@ -154,12 +128,6 @@ describe('SeedPhraseVerifier', function () { it('should be able to verify more than one created account with seed words', async function () { - let keyringController = new KeyringController({ - initState: clone(firstTimeState), - encryptor: mockEncryptor, - }) - assert(keyringController) - let vault = await keyringController.createNewVaultAndKeychain(password) let primaryKeyring = keyringController.getKeyringsByType(hdKeyTree)[0] diff --git a/ui/app/actions.js b/ui/app/actions.js index 64d5b67e0..9606841ae 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -296,6 +296,13 @@ function tryUnlockMetamask (password) { dispatch(actions.unlockSucceeded()) dispatch(actions.transitionForward()) forceUpdateMetamaskState(dispatch) + + background.verifySeedPhrase((err) => { + if (err) { + dispatch(actions.displayWarning(err.message)) + } + }) + } }) } From f7d4a1080df6d1c8ea5f68f88b01caea065b5e92 Mon Sep 17 00:00:00 2001 From: Csaba Solya Date: Sun, 4 Mar 2018 08:47:46 +0100 Subject: [PATCH 118/392] add documentation --- app/scripts/lib/seed-phrase-verifier.js | 5 +++++ app/scripts/metamask-controller.js | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/app/scripts/lib/seed-phrase-verifier.js b/app/scripts/lib/seed-phrase-verifier.js index 1f35c2c67..9cea22029 100644 --- a/app/scripts/lib/seed-phrase-verifier.js +++ b/app/scripts/lib/seed-phrase-verifier.js @@ -2,6 +2,11 @@ const KeyringController = require('eth-keyring-controller') const seedPhraseVerifier = { + // Verifies if the seed words can restore the accounts. + // + // The seed words can recreate the primary keyring and the accounts belonging to it. + // The created accounts in the primary keyring are always the same. + // The keyring always creates the accounts in the same sequence. verifyAccounts (createdAccounts, seedWords) { return new Promise((resolve, reject) => { diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index df9adc248..f523e3919 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -600,6 +600,10 @@ module.exports = class MetamaskController extends EventEmitter { }) } + // Verifies the current vault's seed words if they can restore the + // accounts belonging to the current vault. + // + // Called when the first account is created and on unlocking the vault. verifySeedPhrase (cb) { const primaryKeyring = this.keyringController.getKeyringsByType('HD Key Tree')[0] From 8fde208f0b1da39ccd63b5f256902786e73e9368 Mon Sep 17 00:00:00 2001 From: Csaba Solya Date: Sun, 4 Mar 2018 08:57:55 +0100 Subject: [PATCH 119/392] move more test code to beforeEach --- test/unit/seed-phrase-verifier-test.js | 31 +++++++------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/test/unit/seed-phrase-verifier-test.js b/test/unit/seed-phrase-verifier-test.js index 654fb5994..4e314806b 100644 --- a/test/unit/seed-phrase-verifier-test.js +++ b/test/unit/seed-phrase-verifier-test.js @@ -13,20 +13,23 @@ describe('SeedPhraseVerifier', function () { let hdKeyTree = 'HD Key Tree' let keyringController - beforeEach(function () { + let vault + let primaryKeyring + + beforeEach(async function () { keyringController = new KeyringController({ initState: clone(firstTimeState), encryptor: mockEncryptor, }) assert(keyringController) + + vault = await keyringController.createNewVaultAndKeychain(password) + primaryKeyring = keyringController.getKeyringsByType(hdKeyTree)[0] }) it('should be able to verify created account with seed words', async function () { - let vault = await keyringController.createNewVaultAndKeychain(password) - let primaryKeyring = keyringController.getKeyringsByType(hdKeyTree)[0] - let createdAccounts = await primaryKeyring.getAccounts() assert.equal(createdAccounts.length, 1) @@ -39,11 +42,9 @@ describe('SeedPhraseVerifier', function () { it('should be able to verify created account (upper case) with seed words', async function () { - let vault = await keyringController.createNewVaultAndKeychain(password) - let primaryKeyring = keyringController.getKeyringsByType(hdKeyTree)[0] - let createdAccounts = await primaryKeyring.getAccounts() assert.equal(createdAccounts.length, 1) + let upperCaseAccounts = [createdAccounts[0].toUpperCase()] let serialized = await primaryKeyring.serialize() @@ -55,9 +56,6 @@ describe('SeedPhraseVerifier', function () { it('should be able to verify created account (lower case) with seed words', async function () { - let vault = await keyringController.createNewVaultAndKeychain(password) - let primaryKeyring = keyringController.getKeyringsByType(hdKeyTree)[0] - let createdAccounts = await primaryKeyring.getAccounts() assert.equal(createdAccounts.length, 1) let lowerCaseAccounts = [createdAccounts[0].toLowerCase()] @@ -71,9 +69,6 @@ describe('SeedPhraseVerifier', function () { it('should return error with good but different seed words', async function () { - let vault = await keyringController.createNewVaultAndKeychain(password) - let primaryKeyring = keyringController.getKeyringsByType(hdKeyTree)[0] - let createdAccounts = await primaryKeyring.getAccounts() assert.equal(createdAccounts.length, 1) @@ -90,9 +85,6 @@ describe('SeedPhraseVerifier', function () { it('should return error with undefined existing accounts', async function () { - let vault = await keyringController.createNewVaultAndKeychain(password) - let primaryKeyring = keyringController.getKeyringsByType(hdKeyTree)[0] - let createdAccounts = await primaryKeyring.getAccounts() assert.equal(createdAccounts.length, 1) @@ -109,9 +101,6 @@ describe('SeedPhraseVerifier', function () { it('should return error with empty accounts array', async function () { - let vault = await keyringController.createNewVaultAndKeychain(password) - let primaryKeyring = keyringController.getKeyringsByType(hdKeyTree)[0] - let createdAccounts = await primaryKeyring.getAccounts() assert.equal(createdAccounts.length, 1) @@ -128,10 +117,6 @@ describe('SeedPhraseVerifier', function () { it('should be able to verify more than one created account with seed words', async function () { - let vault = await keyringController.createNewVaultAndKeychain(password) - - let primaryKeyring = keyringController.getKeyringsByType(hdKeyTree)[0] - const keyState = await keyringController.addNewAccount(primaryKeyring) const keyState2 = await keyringController.addNewAccount(primaryKeyring) From 1bd18cebd7e08edbbcf35407b962e71dcd2c3399 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Mon, 5 Mar 2018 13:33:46 -0330 Subject: [PATCH 120/392] Fixes shapeshift coin selection dropdown. (#3416) --- ui/app/app.js | 4 +++- ui/app/components/shapeshift-form.js | 9 ++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/ui/app/app.js b/ui/app/app.js index bfa8d8aa7..d243e72a4 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -90,6 +90,7 @@ function mapStateToProps (state) { isMouseUser: state.appState.isMouseUser, betaUI: state.metamask.featureFlags.betaUI, isRevealingSeedWords: state.metamask.isRevealingSeedWords, + Qr: state.appState.Qr, // state needed to get account dropdown temporarily rendering from app bar identities, @@ -368,6 +369,7 @@ App.prototype.renderPrimary = function () { isOnboarding, betaUI, isRevealingSeedWords, + Qr, } = props const isMascaraOnboarding = isMascara && isOnboarding const isBetaUIOnboarding = betaUI && isOnboarding && !props.isPopup && !isRevealingSeedWords @@ -508,7 +510,7 @@ App.prototype.renderPrimary = function () { width: '285px', }, }, [ - h(QrView, {key: 'qr'}), + h(QrView, {key: 'qr', Qr}), ]), ]) diff --git a/ui/app/components/shapeshift-form.js b/ui/app/components/shapeshift-form.js index 2270b8236..648b05049 100644 --- a/ui/app/components/shapeshift-form.js +++ b/ui/app/components/shapeshift-form.js @@ -51,8 +51,7 @@ ShapeshiftForm.prototype.componentWillMount = function () { this.props.shapeShiftSubview() } -ShapeshiftForm.prototype.onCoinChange = function (e) { - const coin = e.target.value +ShapeshiftForm.prototype.onCoinChange = function (coin) { this.setState({ depositCoin: coin, errorMessage: '', @@ -133,7 +132,7 @@ ShapeshiftForm.prototype.renderMarketInfo = function () { } ShapeshiftForm.prototype.renderQrCode = function () { - const { depositAddress, isLoading } = this.state + const { depositAddress, isLoading, depositCoin } = this.state const qrImage = qrcode(4, 'M') qrImage.addData(depositAddress) qrImage.make() @@ -141,7 +140,7 @@ ShapeshiftForm.prototype.renderQrCode = function () { return h('div.shapeshift-form', {}, [ h('div.shapeshift-form__deposit-instruction', [ - 'Deposit your BTC to the address below:', + `Deposit your ${depositCoin.toUpperCase()} to the address below:`, ]), h('div', depositAddress), @@ -182,7 +181,7 @@ ShapeshiftForm.prototype.render = function () { h(SimpleDropdown, { selectedOption: this.state.depositCoin, - onSelect: this.onCoinChange, + onSelect: (coin) => this.onCoinChange(coin), options: Object.entries(coinOptions).map(([coin]) => ({ value: coin.toLowerCase(), displayValue: coin, From 68604b53dde23eaeb44657153244928627b723ab Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 5 Mar 2018 23:12:06 -0330 Subject: [PATCH 121/392] Prevent user from selecting max amount until there is an estimated gas total. --- ui/app/send-v2.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ui/app/send-v2.js b/ui/app/send-v2.js index 1d67150e3..3667e9d73 100644 --- a/ui/app/send-v2.js +++ b/ui/app/send-v2.js @@ -396,14 +396,15 @@ SendTransactionScreen.prototype.renderAmountRow = function () { amount, setMaxModeTo, maxModeOn, + gasTotal, } = this.props return h('div.send-v2__form-row', [ - h('div.send-v2__form-label', [ + h('div.send-v2__form-label', [ 'Amount:', this.renderErrorMessage('amount'), - !errors.amount && h('div.send-v2__amount-max', { + !errors.amount && gasTotal && h('div.send-v2__amount-max', { onClick: (event) => { event.preventDefault() setMaxModeTo(true) From b393b54e35091efd3f49e9eccaf472c91f5bd0d1 Mon Sep 17 00:00:00 2001 From: criw Date: Tue, 6 Mar 2018 04:43:12 +0100 Subject: [PATCH 122/392] FIX #3440 improved verification of restore from seed phrase --- old-ui/app/keychains/hd/restore-vault.js | 13 +++++++++++++ ui/app/keychains/hd/restore-vault.js | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/old-ui/app/keychains/hd/restore-vault.js b/old-ui/app/keychains/hd/restore-vault.js index 222172dfd..dcadcccad 100644 --- a/old-ui/app/keychains/hd/restore-vault.js +++ b/old-ui/app/keychains/hd/restore-vault.js @@ -140,6 +140,19 @@ RestoreVaultScreen.prototype.createNewVaultAndRestore = function () { // check seed var seedBox = document.querySelector('textarea.twelve-word-phrase') var seed = seedBox.value.trim() + + // true if the string has more than a space between words. + if (seed.split(' ').length > 1) { + this.warning = 'there can only a space between words' + this.props.dispatch(actions.displayWarning(this.warning)) + return + } + // true if seed contains a character that is not between a-z or a space + if(!seed.match(/^[a-z ]+$/)) { + this.warning = 'seed words only have lowercase characters' + this.props.dispatch(actions.displayWarning(this.warning)) + return + } if (seed.split(' ').length !== 12) { this.warning = 'seed phrases are 12 words long' this.props.dispatch(actions.displayWarning(this.warning)) diff --git a/ui/app/keychains/hd/restore-vault.js b/ui/app/keychains/hd/restore-vault.js index a4ed137f9..c4ba0d8fd 100644 --- a/ui/app/keychains/hd/restore-vault.js +++ b/ui/app/keychains/hd/restore-vault.js @@ -141,6 +141,19 @@ RestoreVaultScreen.prototype.createNewVaultAndRestore = function () { // check seed var seedBox = document.querySelector('textarea.twelve-word-phrase') var seed = seedBox.value.trim() + + // true if the string has more than a space between words. + if (seed.split(' ').length > 1) { + this.warning = 'there can only a space between words' + this.props.dispatch(actions.displayWarning(this.warning)) + return + } + // true if seed contains a character that is not between a-z or a space + if(!seed.match(/^[a-z ]+$/)) { + this.warning = 'seed words only have lowercase characters' + this.props.dispatch(actions.displayWarning(this.warning)) + return + } if (seed.split(' ').length !== 12) { this.warning = 'seed phrases are 12 words long' this.props.dispatch(actions.displayWarning(this.warning)) From 462d57cb6aaeab233bcade5ef1804eeaa290bae2 Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 6 Mar 2018 00:23:29 -0330 Subject: [PATCH 123/392] Gracefully handle null token balance in new ui send. --- ui/app/send-v2.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ui/app/send-v2.js b/ui/app/send-v2.js index 1d67150e3..6ee7c0ca5 100644 --- a/ui/app/send-v2.js +++ b/ui/app/send-v2.js @@ -361,8 +361,9 @@ SendTransactionScreen.prototype.validateAmount = function (value) { }) } + const verifyTokenBalance = selectedToken && tokenBalance !== null let sufficientTokens - if (selectedToken) { + if (verifyTokenBalance) { sufficientTokens = isTokenBalanceSufficient({ tokenBalance, amount, @@ -377,7 +378,7 @@ SendTransactionScreen.prototype.validateAmount = function (value) { if (conversionRate && !sufficientBalance) { amountError = 'Insufficient funds.' - } else if (selectedToken && !sufficientTokens) { + } else if (verifyTokenBalance && !sufficientTokens) { amountError = 'Insufficient tokens.' } else if (amountLessThanZero) { amountError = 'Can not send negative amounts of ETH.' @@ -491,9 +492,12 @@ SendTransactionScreen.prototype.renderFooter = function () { goHome, clearSend, gasTotal, + tokenBalance, + selectedToken, errors: { amount: amountError, to: toError }, } = this.props + const missingTokenBalance = selectedToken && !tokenBalance const noErrors = !amountError && toError === null return h('div.page-container__footer', [ @@ -504,7 +508,7 @@ SendTransactionScreen.prototype.renderFooter = function () { }, }, 'Cancel'), h('button.btn-clear.page-container__footer-button', { - disabled: !noErrors || !gasTotal, + disabled: !noErrors || !gasTotal || missingTokenBalance, onClick: event => this.onSubmit(event), }, 'Next'), ]) From d8038c0de046e7e34f019143eb74238a13a1d69e Mon Sep 17 00:00:00 2001 From: Csaba Solya Date: Tue, 6 Mar 2018 09:23:43 +0100 Subject: [PATCH 124/392] add browserify-unibabel to package.json --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 4d1742d6a..145754d6b 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,7 @@ "boron": "^0.2.3", "browser-passworder": "^2.0.3", "browserify-derequire": "^0.9.4", + "browserify-unibabel": "^3.0.0", "classnames": "^2.2.5", "client-sw-ready-event": "^3.3.0", "clone": "^2.1.1", @@ -78,11 +79,11 @@ "eslint-plugin-react": "^7.4.0", "eth-bin-to-ops": "^1.0.1", "eth-block-tracker": "^2.3.0", + "eth-contract-metadata": "^1.1.5", + "eth-hd-keyring": "^1.2.1", "eth-json-rpc-filters": "^1.2.5", "eth-json-rpc-infura": "^3.0.0", "eth-keyring-controller": "^2.1.4", - "eth-contract-metadata": "^1.1.5", - "eth-hd-keyring": "^1.2.1", "eth-phishing-detect": "^1.1.4", "eth-query": "^2.1.2", "eth-sig-util": "^1.4.2", From 9734969e5d09e73778f18e9842ecb4677589a722 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Tue, 6 Mar 2018 10:51:21 -0330 Subject: [PATCH 125/392] Add missed changelog updates. (#3407) --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fc9d2145..fdc7d7155 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,15 @@ ## Current Master +- Allow adding custom tokens to classic ui when balance is 0 +- Allow editing of symbol and decimal info when adding custom token in new-ui +- NewUI shapeshift form can select all coins (not just BTC) + ## 4.1.3 2018-2-28 - Ensure MetaMask's inpage provider is named MetamaskInpageProvider to keep some sites from breaking. - Add retry transaction button back into classic ui. +- Add network dropdown styles to support long custom RPC urls ## 4.1.2 2018-2-28 From 59007a6c36055f9197ad83ccb1741fa186b85f53 Mon Sep 17 00:00:00 2001 From: Csaba Solya Date: Tue, 6 Mar 2018 15:56:27 +0100 Subject: [PATCH 126/392] modify verifySeedPhrase to async and call it from addNewAccount also --- app/scripts/metamask-controller.js | 62 +++++++++++++++--------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index f523e3919..0a5c1d36f 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -345,7 +345,7 @@ module.exports = class MetamaskController extends EventEmitter { // primary HD keyring management addNewAccount: nodeify(this.addNewAccount, this), placeSeedWords: this.placeSeedWords.bind(this), - verifySeedPhrase: this.verifySeedPhrase.bind(this), + verifySeedPhrase: nodeify(this.verifySeedPhrase, this), clearSeedWordCache: this.clearSeedWordCache.bind(this), resetAccount: this.resetAccount.bind(this), importAccountWithStrategy: this.importAccountWithStrategy.bind(this), @@ -567,14 +567,18 @@ module.exports = class MetamaskController extends EventEmitter { // Opinionated Keyring Management // - async addNewAccount (cb) { + async addNewAccount () { const primaryKeyring = this.keyringController.getKeyringsByType('HD Key Tree')[0] - if (!primaryKeyring) return cb(new Error('MetamaskController - No HD Key Tree found')) + if (!primaryKeyring) { + throw new Error('MetamaskController - No HD Key Tree found') + } const keyringController = this.keyringController const oldAccounts = await keyringController.getAccounts() const keyState = await keyringController.addNewAccount(primaryKeyring) const newAccounts = await keyringController.getAccounts() + await this.verifySeedPhrase() + newAccounts.forEach((address) => { if (!oldAccounts.includes(address)) { this.preferencesController.setSelectedAddress(address) @@ -590,44 +594,42 @@ module.exports = class MetamaskController extends EventEmitter { // Also used when revealing the seed words in the confirmation view. placeSeedWords (cb) { - this.verifySeedPhrase((err, seedWords) => { - - if (err) { + this.verifySeedPhrase() + .then((seedWords) => { + this.configManager.setSeedWords(seedWords) + return cb(null, seedWords) + }) + .catch((err) => { return cb(err) - } - this.configManager.setSeedWords(seedWords) - return cb(null, seedWords) - }) + }) } // Verifies the current vault's seed words if they can restore the // accounts belonging to the current vault. // // Called when the first account is created and on unlocking the vault. - verifySeedPhrase (cb) { + async verifySeedPhrase () { const primaryKeyring = this.keyringController.getKeyringsByType('HD Key Tree')[0] - if (!primaryKeyring) return cb(new Error('MetamaskController - No HD Key Tree found')) - primaryKeyring.serialize() - .then((serialized) => { - const seedWords = serialized.mnemonic + if (!primaryKeyring) { + throw new Error('MetamaskController - No HD Key Tree found') + } - primaryKeyring.getAccounts() - .then((accounts) => { - if (accounts.length < 1) { - return cb(new Error('MetamaskController - No accounts found')) - } + const serialized = await primaryKeyring.serialize() + const seedWords = serialized.mnemonic - seedPhraseVerifier.verifyAccounts(accounts, seedWords) - .then(() => { - return cb(null, seedWords) - }) - .catch((err) => { - log.error(err) - return cb(err) - }) - }) - }) + const accounts = await primaryKeyring.getAccounts() + if (accounts.length < 1) { + throw new Error('MetamaskController - No accounts found') + } + + try { + await seedPhraseVerifier.verifyAccounts(accounts, seedWords) + return seedWords + } catch (err) { + log.error(err.message) + throw err + } } // ClearSeedWordCache From 5f8a632fec0e83b148e4e0b7fc95339fb870d804 Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Tue, 6 Mar 2018 09:14:57 -0800 Subject: [PATCH 127/392] Fix seed phrase validation clearing form (#3417) * Fix seed phrase validation clearing form * Make new ui import seed error feedback live, and allow newlines with and without carriage returns. --- .../first-time/import-seed-phrase-screen.js | 197 ++++++++++-------- mascara/src/app/first-time/index.css | 16 +- ui/app/app.js | 8 +- ui/app/css/itcss/components/header.scss | 7 +- 4 files changed, 133 insertions(+), 95 deletions(-) diff --git a/mascara/src/app/first-time/import-seed-phrase-screen.js b/mascara/src/app/first-time/import-seed-phrase-screen.js index 93c3f9203..de8d675e1 100644 --- a/mascara/src/app/first-time/import-seed-phrase-screen.js +++ b/mascara/src/app/first-time/import-seed-phrase-screen.js @@ -1,13 +1,12 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' import {connect} from 'react-redux' -import LoadingScreen from './loading-screen' +import classnames from 'classnames' import { createNewVaultAndRestore, hideWarning, displayWarning, unMarkPasswordForgotten, - clearNotices, } from '../../../../ui/app/actions' class ImportSeedPhraseScreen extends Component { @@ -17,8 +16,8 @@ class ImportSeedPhraseScreen extends Component { next: PropTypes.func.isRequired, createNewVaultAndRestore: PropTypes.func.isRequired, hideWarning: PropTypes.func.isRequired, - isLoading: PropTypes.bool.isRequired, displayWarning: PropTypes.func, + leaveImportSeedScreenState: PropTypes.func, }; state = { @@ -27,98 +26,130 @@ class ImportSeedPhraseScreen extends Component { confirmPassword: '', } + parseSeedPhrase = (seedPhrase) => { + return seedPhrase + .match(/\w+/g) + .join(' ') + } + + onChange = ({ seedPhrase, password, confirmPassword }) => { + const { + password: prevPassword, + confirmPassword: prevConfirmPassword, + } = this.state + const { displayWarning, hideWarning } = this.props + + let warning = null + + if (seedPhrase && this.parseSeedPhrase(seedPhrase).split(' ').length !== 12) { + warning = 'Seed Phrases are 12 words long' + } else if (password && password.length < 8) { + warning = 'Passwords require a mimimum length of 8' + } else if ((password || prevPassword) !== (confirmPassword || prevConfirmPassword)) { + warning = 'Confirmed password does not match' + } + + if (warning) { + displayWarning(warning) + } else { + hideWarning() + } + + seedPhrase && this.setState({ seedPhrase }) + password && this.setState({ password }) + confirmPassword && this.setState({ confirmPassword }) + } + onClick = () => { - const { password, seedPhrase, confirmPassword } = this.state - const { createNewVaultAndRestore, next, displayWarning, leaveImportSeedScreenState } = this.props + const { password, seedPhrase } = this.state + const { + createNewVaultAndRestore, + next, + displayWarning, + leaveImportSeedScreenState, + } = this.props - if (seedPhrase.split(' ').length !== 12) { - this.warning = 'Seed Phrases are 12 words long' - displayWarning(this.warning) - return - } - - if (password.length < 8) { - this.warning = 'Passwords require a mimimum length of 8' - displayWarning(this.warning) - return - } - - if (password !== confirmPassword) { - this.warning = 'Confirmed password does not match' - displayWarning(this.warning) - return - } - this.warning = null leaveImportSeedScreenState() - createNewVaultAndRestore(password, seedPhrase) + createNewVaultAndRestore(password, this.parseSeedPhrase(seedPhrase)) .then(next) } render () { - return this.props.isLoading - ? - : ( -

- { - e.preventDefault() - this.props.back() - }} - href="#" - > - {`< Back`} - -
- Import an Account with Seed Phrase -
-
- Enter your secret twelve word phrase here to restore your vault. -
-
- -