diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ddfb85ce..0b521584b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +7,12 @@ - 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. ## 3.4.0 2017-3-8 diff --git a/app/scripts/config.js b/app/scripts/config.js index b4541a04a..ec421744d 100644 --- a/app/scripts/config.js +++ b/app/scripts/config.js @@ -1,5 +1,6 @@ const MAINET_RPC_URL = 'https://mainnet.infura.io/metamask' const TESTNET_RPC_URL = 'https://ropsten.infura.io/metamask' +const KOVAN_RPC_URL = 'https://kovan.infura.io/metamask' const DEFAULT_RPC_URL = TESTNET_RPC_URL global.METAMASK_DEBUG = 'GULP_METAMASK_DEBUG' @@ -10,5 +11,6 @@ module.exports = { mainnet: MAINET_RPC_URL, testnet: TESTNET_RPC_URL, morden: TESTNET_RPC_URL, + kovan: KOVAN_RPC_URL, }, } diff --git a/app/scripts/contentscript.js b/app/scripts/contentscript.js index ab64dc9fa..020208ceb 100644 --- a/app/scripts/contentscript.js +++ b/app/scripts/contentscript.js @@ -69,14 +69,10 @@ function shouldInjectWeb3 () { } function isAllowedSuffix (testCase) { - var prohibitedTypes = ['xml', 'pdf'] - var currentUrl = window.location.href - var currentRegex - for (let i = 0; i < prohibitedTypes.length; i++) { - currentRegex = new RegExp(`\.${prohibitedTypes[i]}$`) - if (currentRegex.test(currentUrl)) { - return false - } + const doctype = window.document.doctype + if (doctype) { + return doctype.name === 'html' + } else { + return false } - return true } diff --git a/app/scripts/lib/config-manager.js b/app/scripts/lib/config-manager.js index 6868637e5..e31cb45ed 100644 --- a/app/scripts/lib/config-manager.js +++ b/app/scripts/lib/config-manager.js @@ -5,6 +5,7 @@ const normalize = require('eth-sig-util').normalize const TESTNET_RPC = MetamaskConfig.network.testnet const MAINNET_RPC = MetamaskConfig.network.mainnet const MORDEN_RPC = MetamaskConfig.network.morden +const KOVAN_RPC = MetamaskConfig.network.kovan /* The config-manager is a convenience object * wrapping a pojo-migrator. @@ -150,6 +151,9 @@ ConfigManager.prototype.getCurrentRpcAddress = function () { case 'morden': return MORDEN_RPC + case 'kovan': + return KOVAN_RPC + default: return provider && provider.rpcTarget ? provider.rpcTarget : TESTNET_RPC } diff --git a/app/scripts/lib/eth-store.js b/app/scripts/lib/eth-store.js index 8812a507b..243253df2 100644 --- a/app/scripts/lib/eth-store.js +++ b/app/scripts/lib/eth-store.js @@ -19,6 +19,8 @@ class EthereumStore extends ObservableStore { super({ accounts: {}, transactions: {}, + currentBlockNumber: '0', + currentBlockHash: '', }) this._provider = opts.provider this._query = new EthQuery(this._provider) @@ -69,6 +71,8 @@ class EthereumStore extends ObservableStore { _updateForBlock (block) { const blockNumber = '0x' + block.number.toString('hex') this._currentBlockNumber = blockNumber + this.updateState({ currentBlockNumber: parseInt(blockNumber) }) + this.updateState({ currentBlockHash: `0x${block.hash.toString('hex')}`}) async.parallel([ this._updateAccounts.bind(this), this._updateTransactions.bind(this, blockNumber), @@ -129,4 +133,4 @@ class EthereumStore extends ObservableStore { } -module.exports = EthereumStore \ No newline at end of file +module.exports = EthereumStore diff --git a/ui/app/accounts/import/json.js b/ui/app/accounts/import/json.js index 1c2b331d4..5ed31ab0a 100644 --- a/ui/app/accounts/import/json.js +++ b/ui/app/accounts/import/json.js @@ -60,7 +60,7 @@ JsonImportSubview.prototype.render = function () { }, }, 'Import'), - error ? h('span.warning', error) : null, + error ? h('span.error', error) : null, ]) ) } @@ -95,4 +95,3 @@ JsonImportSubview.prototype.createNewKeychain = function () { this.props.dispatch(actions.importNewAccount('JSON File', [ fileContents, password ])) } - diff --git a/ui/app/accounts/import/private-key.js b/ui/app/accounts/import/private-key.js index b139a0374..68ccee58e 100644 --- a/ui/app/accounts/import/private-key.js +++ b/ui/app/accounts/import/private-key.js @@ -48,7 +48,7 @@ PrivateKeyImportView.prototype.render = function () { }, }, 'Import'), - error ? h('span.warning', error) : null, + error ? h('span.error', error) : null, ]) ) } @@ -65,4 +65,3 @@ PrivateKeyImportView.prototype.createNewKeychain = function () { const privateKey = input.value this.props.dispatch(actions.importNewAccount('Private Key', [ privateKey ])) } - diff --git a/ui/app/actions.js b/ui/app/actions.js index 9d6676d01..d02b7dcaa 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -269,11 +269,12 @@ function requestRevealSeed (password) { dispatch(actions.showLoadingIndication()) log.debug(`background.submitPassword`) background.submitPassword(password, (err) => { - if (err) return dispatch(actions.displayWarning(err.message)) + if (err) { + return dispatch(actions.displayWarning(err.message)) + } log.debug(`background.placeSeedWords`) background.placeSeedWords((err) => { if (err) return dispatch(actions.displayWarning(err.message)) - dispatch(actions.hideLoadingIndication()) }) }) } @@ -296,10 +297,10 @@ function importNewAccount (strategy, args) { dispatch(actions.showLoadingIndication('This may take a while, be patient.')) log.debug(`background.importAccountWithStrategy`) background.importAccountWithStrategy(strategy, args, (err) => { - dispatch(actions.hideLoadingIndication()) if (err) return dispatch(actions.displayWarning(err.message)) log.debug(`background.getState`) background.getState((err, newState) => { + dispatch(actions.hideLoadingIndication()) if (err) { return dispatch(actions.displayWarning(err.message)) } diff --git a/ui/app/app.js b/ui/app/app.js index 9c1ba8a3a..5a7596aca 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -255,6 +255,15 @@ App.prototype.renderNetworkDropdown = function () { provider: props.provider, }), + h(DropMenuItem, { + label: 'Kovan Test Network', + closeMenu: () => this.setState({ isNetworkMenuOpen: false}), + action: () => props.dispatch(actions.setProviderType('kovan')), + icon: h('.menu-icon.hollow-diamond'), + activeNetworkRender: props.network, + provider: props.provider, + }), + h(DropMenuItem, { label: 'Localhost 8545', closeMenu: () => this.setState({ isNetworkMenuOpen: false }), diff --git a/ui/app/components/account-export.js b/ui/app/components/account-export.js index 38a1d28ef..888196c5d 100644 --- a/ui/app/components/account-export.js +++ b/ui/app/components/account-export.js @@ -52,6 +52,7 @@ ExportAccountView.prototype.render = function () { }, [ h('p.error', warning), h('input#exportAccount.sizing-input', { + type: 'password', placeholder: 'confirm password', onKeyPress: this.onExportKeyPress.bind(this), style: { diff --git a/ui/app/components/drop-menu-item.js b/ui/app/components/drop-menu-item.js index 9f002234e..3eb6ec876 100644 --- a/ui/app/components/drop-menu-item.js +++ b/ui/app/components/drop-menu-item.js @@ -42,7 +42,10 @@ DropMenuItem.prototype.activeNetworkRender = function () { if (providerType === 'mainnet') return h('.check', '✓') break case 'Ropsten Test Network': - if (provider.type === 'testnet') return h('.check', '✓') + if (providerType === 'testnet') return h('.check', '✓') + break + case 'Kovan Test Network': + if (providerType === 'kovan') return h('.check', '✓') break case 'Localhost 8545': if (activeNetwork === 'http://localhost:8545') return h('.check', '✓') diff --git a/ui/app/components/network.js b/ui/app/components/network.js index 77805fd57..d9045167f 100644 --- a/ui/app/components/network.js +++ b/ui/app/components/network.js @@ -40,6 +40,9 @@ Network.prototype.render = function () { } else if (parseInt(networkNumber) === 3) { hoverText = 'Ropsten Test Network' iconName = 'ropsten-test-network' + } else if (providerName === 'kovan') { + hoverText = 'Kovan Test Network' + iconName = 'kovan-test-network' } else { hoverText = 'Unknown Private Network' iconName = 'unknown-private-network' @@ -70,6 +73,15 @@ Network.prototype.render = function () { }}, 'Ropsten Test Net'), ]) + case 'kovan-test-network': + return h('.network-indicator', [ + h('.menu-icon.hollow-diamond'), + h('.network-name', { + style: { + color: '#690496', + }}, + 'Kovan Test Net'), + ]) default: return h('.network-indicator', [ h('i.fa.fa-question-circle.fa-lg', { diff --git a/ui/app/components/transaction-list-item.js b/ui/app/components/transaction-list-item.js index 44d2dc587..ee32be7d3 100644 --- a/ui/app/components/transaction-list-item.js +++ b/ui/app/components/transaction-list-item.js @@ -28,7 +28,7 @@ TransactionListItem.prototype.render = function () { let isLinkable = false const numericNet = parseInt(network) - isLinkable = numericNet === 1 || numericNet === 3 + isLinkable = numericNet === 1 || numericNet === 3 || numericNet === 42 var isMsg = ('msgParams' in transaction) var isTx = ('txParams' in transaction) diff --git a/ui/app/config.js b/ui/app/config.js index 3f0507f48..444365de2 100644 --- a/ui/app/config.js +++ b/ui/app/config.js @@ -161,6 +161,11 @@ function currentProviderDisplay (metamaskState) { value = 'Ropsten Test Network' break + case 'kovan': + title = 'Current Network' + value = 'Kovan Test Network' + break + default: title = 'Current RPC' value = metamaskState.provider.rpcTarget diff --git a/ui/app/css/lib.css b/ui/app/css/lib.css index 99c6f1b9d..670dc9fd0 100644 --- a/ui/app/css/lib.css +++ b/ui/app/css/lib.css @@ -188,7 +188,7 @@ hr.horizontal-line { .hollow-diamond { transform: rotate(45deg); - border: 1px solid #038789; + border: 3px solid #690496; } .pending-dot { diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js index 7ea1e1d7c..b9e3f7b16 100644 --- a/ui/app/reducers/app.js +++ b/ui/app/reducers/app.js @@ -426,6 +426,7 @@ function reduceApp (state, action) { case actions.DISPLAY_WARNING: return extend(appState, { warning: action.value, + isLoading: false, }) case actions.HIDE_WARNING: diff --git a/ui/lib/account-link.js b/ui/lib/account-link.js index 77db0851d..948f32da1 100644 --- a/ui/lib/account-link.js +++ b/ui/lib/account-link.js @@ -1,7 +1,6 @@ module.exports = function (address, network) { const net = parseInt(network) let link - switch (net) { case 1: // main net link = `http://etherscan.io/address/${address}` @@ -12,6 +11,9 @@ module.exports = function (address, network) { case 3: // ropsten test net link = `http://testnet.etherscan.io/address/${address}` break + case 42: // kovan test net + link = `http://kovan.etherscan.io/address/${address}` + break default: link = '' break diff --git a/ui/lib/explorer-link.js b/ui/lib/explorer-link.js index dc6be2984..7ae19cca0 100644 --- a/ui/lib/explorer-link.js +++ b/ui/lib/explorer-link.js @@ -5,9 +5,12 @@ module.exports = function (hash, network) { case 1: // main net prefix = '' break - case 3: // morden test net + case 3: // ropsten test net prefix = 'testnet.' break + case 42: // kovan test net + prefix = 'kovan.' + break default: prefix = '' }