From 8dcf860ad70015a02b0c7be02c319449871d421c Mon Sep 17 00:00:00 2001 From: hackyminer Date: Wed, 6 Jun 2018 02:45:14 +0900 Subject: [PATCH 01/12] support chainid * fixed custom Rpc form to support optional chainid * experimental ETC support added [fixed conflict 8/16] --- app/_locales/en/messages.json | 9 +++ app/scripts/controllers/network/enums.js | 6 ++ app/scripts/controllers/network/network.js | 55 ++++++++++++++++--- app/scripts/controllers/network/networks.js | 21 +++++++ app/scripts/controllers/network/util.js | 5 ++ app/scripts/metamask-controller.js | 4 +- old-ui/app/app.js | 2 + old-ui/app/components/app-bar.js | 14 +++++ old-ui/app/components/network.js | 13 +++++ old-ui/app/config.js | 35 ++++++++++-- .../app/controllers/network-contoller-test.js | 8 ++- ui/app/actions.js | 4 +- ui/app/app.js | 4 ++ .../components/dropdowns/network-dropdown.js | 35 ++++++++++-- ui/app/components/network-display/index.scss | 8 +++ .../network-display.component.js | 2 + ui/app/components/network.js | 13 +++++ ui/app/components/pages/settings/settings.js | 19 +++++-- ui/lib/account-link.js | 1 + 19 files changed, 230 insertions(+), 28 deletions(-) create mode 100644 app/scripts/controllers/network/networks.js diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index a25a2bd59a5b..5a1f7089ca9b 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -635,6 +635,9 @@ "newRPC": { "message": "New RPC URL" }, + "optionalChainId": { + "message": "ChainId (optional)" + }, "next": { "message": "Next" }, @@ -817,6 +820,9 @@ "ropsten": { "message": "Ropsten Test Network" }, + "classic": { + "message": "Ethereum Classic Network" + }, "rpc": { "message": "Custom RPC" }, @@ -835,6 +841,9 @@ "connectingToRinkeby": { "message": "Connecting to Rinkeby Test Network" }, + "connectingToClassic": { + "message": "Connecting to Ethereum Classic Network" + }, "connectingToUnknown": { "message": "Connecting to Unknown Network" }, diff --git a/app/scripts/controllers/network/enums.js b/app/scripts/controllers/network/enums.js index 3190eb37c717..f0ef73f0f469 100644 --- a/app/scripts/controllers/network/enums.js +++ b/app/scripts/controllers/network/enums.js @@ -3,29 +3,35 @@ const RINKEBY = 'rinkeby' const KOVAN = 'kovan' const MAINNET = 'mainnet' const LOCALHOST = 'localhost' +const CLASSIC = 'classic' const MAINNET_CODE = 1 const ROPSTEN_CODE = 3 const RINKEYBY_CODE = 4 const KOVAN_CODE = 42 +const CLASSIC_CODE = 61 const ROPSTEN_DISPLAY_NAME = 'Ropsten' const RINKEBY_DISPLAY_NAME = 'Rinkeby' const KOVAN_DISPLAY_NAME = 'Kovan' const MAINNET_DISPLAY_NAME = 'Main Ethereum Network' +const CLASSIC_DISPLAY_NAME = 'Ethereum Classic' module.exports = { ROPSTEN, RINKEBY, KOVAN, MAINNET, + CLASSIC, LOCALHOST, MAINNET_CODE, ROPSTEN_CODE, RINKEYBY_CODE, KOVAN_CODE, + CLASSIC_CODE, ROPSTEN_DISPLAY_NAME, RINKEBY_DISPLAY_NAME, KOVAN_DISPLAY_NAME, MAINNET_DISPLAY_NAME, + CLASSIC_DISPLAY_NAME, } diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index 76fdc339188f..b9025661db7b 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -11,15 +11,19 @@ const createInfuraClient = require('./createInfuraClient') const createJsonRpcClient = require('./createJsonRpcClient') const createLocalhostClient = require('./createLocalhostClient') const { createSwappableProxy, createEventEmitterProxy } = require('swappable-obj-proxy') +const networks = require('./networks') +const extend = require('xtend') const { ROPSTEN, RINKEBY, KOVAN, MAINNET, + CLASSIC, LOCALHOST, } = require('./enums') const INFURA_PROVIDER_TYPES = [ROPSTEN, RINKEBY, KOVAN, MAINNET] +const ALL_PROVIDER_TYPES = [ROPSTEN, RINKEBY, KOVAN, MAINNET, CLASSIC] const env = process.env.METAMASK_ENV const METAMASK_DEBUG = process.env.METAMASK_DEBUG @@ -51,8 +55,8 @@ module.exports = class NetworkController extends EventEmitter { initializeProvider (providerParams) { this._baseProviderParams = providerParams - const { type, rpcTarget } = this.providerStore.getState() - this._configureProvider({ type, rpcTarget }) + const { type, rpcTarget, chainId } = this.providerStore.getState() + this._configureProvider({ type, rpcTarget, chainId }) this.lookupNetwork() } @@ -72,7 +76,16 @@ module.exports = class NetworkController extends EventEmitter { return this.networkStore.getState() } - setNetworkState (network) { + setNetworkState (network, type) { + if (network === 'loading') { + return this.networkStore.putState(network) + } + + // type must be defined + if (!type) { + return + } + network = networks.networkList[type] && networks.networkList[type].chainId ? networks.networkList[type].chainId : network return this.networkStore.putState(network) } @@ -85,25 +98,27 @@ module.exports = class NetworkController extends EventEmitter { if (!this._provider) { return log.warn('NetworkController - lookupNetwork aborted due to missing provider') } + var { type } = this.providerStore.getState() const ethQuery = new EthQuery(this._provider) ethQuery.sendAsync({ method: 'net_version' }, (err, network) => { if (err) return this.setNetworkState('loading') log.info('web3.getNetwork returned ' + network) - this.setNetworkState(network) + this.setNetworkState(network, type) }) } - setRpcTarget (rpcTarget) { + setRpcTarget (rpcTarget, chainId) { const providerConfig = { type: 'rpc', rpcTarget, + chainId, } this.providerConfig = providerConfig } async setProviderType (type) { assert.notEqual(type, 'rpc', `NetworkController - cannot call "setProviderType" with type 'rpc'. use "setRpcTarget"`) - assert(INFURA_PROVIDER_TYPES.includes(type) || type === LOCALHOST, `NetworkController - Unknown rpc type "${type}"`) + assert(ALL_PROVIDER_TYPES.includes(type) || type === LOCALHOST, `NetworkController - Unknown rpc type "${type}"`) const providerConfig = { type } this.providerConfig = providerConfig } @@ -132,17 +147,20 @@ module.exports = class NetworkController extends EventEmitter { } _configureProvider (opts) { - const { type, rpcTarget } = opts + const { type, rpcTarget, chainId } = opts // infura type-based endpoints const isInfura = INFURA_PROVIDER_TYPES.includes(type) if (isInfura) { this._configureInfuraProvider(opts) + // other predefined endpoints + } else if (ALL_PROVIDER_TYPES.includes(type)){ + this._configurePredefinedProvider(opts) // other type-based rpc endpoints } else if (type === LOCALHOST) { this._configureLocalhostProvider() // url-based rpc endpoints } else if (type === 'rpc') { - this._configureStandardProvider({ rpcUrl: rpcTarget }) + this._configureStandardProvider({ rpcUrl: rpcTarget, chainId }) } else { throw new Error(`NetworkController - _configureProvider - unknown type "${type}"`) } @@ -160,9 +178,28 @@ module.exports = class NetworkController extends EventEmitter { this._setNetworkClient(networkClient) } - _configureStandardProvider ({ rpcUrl }) { + _configurePredefinedProvider ({ type }) { + log.info('NetworkController - configurePredefinedProvider', type) + // setup networkConfig + var settings = { + network: networks.networkList[type].chainId, + } + settings = extend(settings, networks.networkList[type]) + const rpcUrl = networks.networkList[type].rpcUrl + const networkClient = createJsonRpcClient({ rpcUrl }) + this.networkConfig.putState(settings) + this._setNetworkClient(networkClient) + } + + _configureStandardProvider ({ rpcUrl, chainId }) { log.info('NetworkController - configureStandardProvider', rpcUrl) const networkClient = createJsonRpcClient({ rpcUrl }) + // hack to add a 'rpc' network with chainId + networks.networkList['rpc'] = { + chainId: chainId, + rpcUrl, + ticker: 'ETH', + } this._setNetworkClient(networkClient) } diff --git a/app/scripts/controllers/network/networks.js b/app/scripts/controllers/network/networks.js new file mode 100644 index 000000000000..f96556ce1e87 --- /dev/null +++ b/app/scripts/controllers/network/networks.js @@ -0,0 +1,21 @@ +'use strict' +var networks = function() {} + +const { + CLASSIC, + CLASSIC_CODE, +} = require('./enums') + +networks.networkList = { + [CLASSIC]: { + 'chainId': CLASSIC_CODE, + 'ticker': 'ETC', + 'blockExplorerTx': 'https://gastracker.io/tx/[[txHash]]', + 'blockExplorerAddr': 'https://gastracker.io/addr/[[address]]', + 'blockExplorerToken': 'https://gastracker.io/token/[[tokenAddress]]/[[address]]', + 'service': 'Ethereum Commonwealth', + 'rpcUrl': 'https://etc-geth.0xinfra.com', + }, +} + +module.exports = networks diff --git a/app/scripts/controllers/network/util.js b/app/scripts/controllers/network/util.js index 261dae7211cd..3d5059db4812 100644 --- a/app/scripts/controllers/network/util.js +++ b/app/scripts/controllers/network/util.js @@ -3,13 +3,16 @@ const { RINKEBY, KOVAN, MAINNET, + CLASSIC, ROPSTEN_CODE, RINKEYBY_CODE, KOVAN_CODE, + CLASSIC_CODE, ROPSTEN_DISPLAY_NAME, RINKEBY_DISPLAY_NAME, KOVAN_DISPLAY_NAME, MAINNET_DISPLAY_NAME, + CLASSIC_DISPLAY_NAME, } = require('./enums') const networkToNameMap = { @@ -17,9 +20,11 @@ const networkToNameMap = { [RINKEBY]: RINKEBY_DISPLAY_NAME, [KOVAN]: KOVAN_DISPLAY_NAME, [MAINNET]: MAINNET_DISPLAY_NAME, + [CLASSIC]: CLASSIC_DISPLAY_NAME, [ROPSTEN_CODE]: ROPSTEN_DISPLAY_NAME, [RINKEYBY_CODE]: RINKEBY_DISPLAY_NAME, [KOVAN_CODE]: KOVAN_DISPLAY_NAME, + [CLASSIC_CODE]: CLASSIC_DISPLAY_NAME, } const getNetworkDisplayName = key => networkToNameMap[key] diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 2d7d2c671bb5..94c59473fae7 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1373,8 +1373,8 @@ module.exports = class MetamaskController extends EventEmitter { * @param {string} rpcTarget - A URL for a valid Ethereum RPC API. * @returns {Promise} - The RPC Target URL confirmed. */ - async setCustomRpc (rpcTarget) { - this.networkController.setRpcTarget(rpcTarget) + async setCustomRpc (rpcTarget, chainId) { + this.networkController.setRpcTarget(rpcTarget, chainId) await this.preferencesController.updateFrequentRpcList(rpcTarget) return rpcTarget } diff --git a/old-ui/app/app.js b/old-ui/app/app.js index d3e9e823b0d5..8f121e7950e4 100644 --- a/old-ui/app/app.js +++ b/old-ui/app/app.js @@ -298,6 +298,8 @@ App.prototype.getNetworkName = function () { name = 'Kovan Test Network' } else if (providerName === 'rinkeby') { name = 'Rinkeby Test Network' + } else if (providerName === 'classic') { + name = 'Ethereum Classic Network' } else { name = 'Unknown Private Network' } diff --git a/old-ui/app/components/app-bar.js b/old-ui/app/components/app-bar.js index 8ab647efdbf9..55970543c3ec 100644 --- a/old-ui/app/components/app-bar.js +++ b/old-ui/app/components/app-bar.js @@ -287,6 +287,20 @@ module.exports = class AppBar extends Component { ? h('.check', '✓') : null, ]), + h(DropdownMenuItem, { + key: 'classic', + closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }), + onClick: () => dispatch(actions.setProviderType('classic')), + style: { + fontSize: '18px', + }, + }, [ + h('.menu-icon.diamond'), + 'Ethereum Classic Network', + providerType === 'classic' + ? h('.check', '✓') + : null, + ]), h(DropdownMenuItem, { key: 'default', closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }), diff --git a/old-ui/app/components/network.js b/old-ui/app/components/network.js index 59596dabd31e..4e12e2733ca5 100644 --- a/old-ui/app/components/network.js +++ b/old-ui/app/components/network.js @@ -55,6 +55,9 @@ Network.prototype.render = function () { } else if (providerName === 'rinkeby') { hoverText = 'Rinkeby Test Network' iconName = 'rinkeby-test-network' + } else if (providerName === 'classic') { + hoverText = 'Ethereum Classic' + iconName = 'ethereum-classic-network' } else { hoverText = 'Unknown Private Network' iconName = 'unknown-private-network' @@ -108,6 +111,16 @@ Network.prototype.render = function () { 'Rinkeby Test Net'), props.onClick && h('i.fa.fa-caret-down.fa-lg'), ]) + case 'ethereum-classic-network': + return h('.network-indicator', [ + h('.menu-icon.diamond'), + h('.network-name', { + style: { + color: '#267f00', + }}, + 'Ethereum Classic Network'), + props.onClick && h('i.fa.fa-caret-down.fa-lg'), + ]) default: return h('.network-indicator', [ h('i.fa.fa-question-circle.fa-lg', { diff --git a/old-ui/app/config.js b/old-ui/app/config.js index 392a6dba7c1b..1e7fa6a3fe35 100644 --- a/old-ui/app/config.js +++ b/old-ui/app/config.js @@ -68,7 +68,7 @@ ConfigScreen.prototype.render = function () { currentProviderDisplay(metamaskState), - h('div', { style: {display: 'flex'} }, [ + h('div', { style: {display: 'block'} }, [ h('input#new_rpc', { placeholder: 'New RPC URL', style: { @@ -81,7 +81,26 @@ ConfigScreen.prototype.render = function () { if (event.key === 'Enter') { var element = event.target var newRpc = element.value - rpcValidation(newRpc, state) + var chainid = document.querySelector('input#chainid') + rpcValidation(newRpc, chainid.value, state) + } + }, + }), + h('br'), + h('input#chainid', { + placeholder: 'ChainId (optional)', + style: { + width: 'inherit', + flex: '1 0 auto', + height: '30px', + margin: '8px', + }, + onKeyPress (event) { + if (event.key === 'Enter') { + var element = document.querySelector('input#new_rpc') + var newRpc = element.value + var chainid = document.querySelector('input#chainid') + rpcValidation(newRpc, chainid.value, state) } }, }), @@ -93,7 +112,8 @@ ConfigScreen.prototype.render = function () { event.preventDefault() var element = document.querySelector('input#new_rpc') var newRpc = element.value - rpcValidation(newRpc, state) + var chainid = document.querySelector('input#chainid') + rpcValidation(newRpc, chainid.value, state) }, }, 'Save'), ]), @@ -189,9 +209,9 @@ ConfigScreen.prototype.render = function () { ) } -function rpcValidation (newRpc, state) { +function rpcValidation (newRpc, chainid, state) { if (validUrl.isWebUri(newRpc)) { - state.dispatch(actions.setRpcTarget(newRpc)) + state.dispatch(actions.setRpcTarget(newRpc, chainid)) } else { var appendedRpc = `http://${newRpc}` if (validUrl.isWebUri(appendedRpc)) { @@ -249,6 +269,11 @@ function currentProviderDisplay (metamaskState) { value = 'Rinkeby Test Network' break + case 'classic': + title = 'Current Network' + value = 'Ethereum Classic Network' + break + default: title = 'Current RPC' value = metamaskState.provider.rpcTarget diff --git a/test/unit/app/controllers/network-contoller-test.js b/test/unit/app/controllers/network-contoller-test.js index 822311931e67..2721898bdb01 100644 --- a/test/unit/app/controllers/network-contoller-test.js +++ b/test/unit/app/controllers/network-contoller-test.js @@ -47,7 +47,7 @@ describe('# Network Controller', function () { describe('#setNetworkState', function () { it('should update the network', function () { - networkController.setNetworkState(1) + networkController.setNetworkState(1, 'rpc') const networkState = networkController.getNetworkState() assert.equal(networkState, 1, 'network is 1') }) @@ -80,6 +80,9 @@ describe('Network utils', () => { }, { input: 42, expected: 'Kovan', + }, { + input: 61, + expected: 'Ethereum Classic', }, { input: 'ropsten', expected: 'Ropsten', @@ -89,6 +92,9 @@ describe('Network utils', () => { }, { input: 'kovan', expected: 'Kovan', + }, { + input: 'classic', + expected: 'Ethereum Classic', }, { input: 'mainnet', expected: 'Main Ethereum Network', diff --git a/ui/app/actions.js b/ui/app/actions.js index 6bcc64e17aae..9c4e45126bf2 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -1751,10 +1751,10 @@ function updateProviderType (type) { } } -function setRpcTarget (newRpc) { +function setRpcTarget (newRpc, chainId) { return (dispatch) => { log.debug(`background.setRpcTarget: ${newRpc}`) - background.setCustomRpc(newRpc, (err, result) => { + background.setCustomRpc(newRpc, chainId, (err, result) => { if (err) { log.error(err) return dispatch(self.displayWarning('Had a problem changing networks!')) diff --git a/ui/app/app.js b/ui/app/app.js index 4fcf092caf77..d06d3d7542d2 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -228,6 +228,8 @@ class App extends Component { name = this.context.t('connectingToRopsten') } else if (providerName === 'rinkeby') { name = this.context.t('connectingToRinkeby') + } else if (providerName === 'classic') { + name = this.context.t('connectingToClassic') } else { name = this.context.t('connectingToUnknown') } @@ -249,6 +251,8 @@ class App extends Component { name = this.context.t('kovan') } else if (providerName === 'rinkeby') { name = this.context.t('rinkeby') + } else if (providerName === 'classic') { + name = this.context.t('classic') } else { name = this.context.t('unknownNetwork') } diff --git a/ui/app/components/dropdowns/network-dropdown.js b/ui/app/components/dropdowns/network-dropdown.js index e5363ff56a25..df99c8d924c5 100644 --- a/ui/app/components/dropdowns/network-dropdown.js +++ b/ui/app/components/dropdowns/network-dropdown.js @@ -26,6 +26,7 @@ function mapStateToProps (state) { provider: state.metamask.provider, frequentRpcList: state.metamask.frequentRpcList || [], networkDropdownOpen: state.appState.networkDropdownOpen, + network: state.metamask.network, } } @@ -40,8 +41,8 @@ function mapDispatchToProps (dispatch) { setDefaultRpcTarget: type => { dispatch(actions.setDefaultRpcTarget(type)) }, - setRpcTarget: (target) => { - dispatch(actions.setRpcTarget(target)) + setRpcTarget: (target, network) => { + dispatch(actions.setRpcTarget(target, network)) }, showNetworkDropdown: () => dispatch(actions.showNetworkDropdown()), hideNetworkDropdown: () => dispatch(actions.hideNetworkDropdown()), @@ -199,6 +200,28 @@ NetworkDropdown.prototype.render = function () { ] ), + h( + DropdownMenuItem, + { + key: 'classic', + closeMenu: () => this.props.hideNetworkDropdown(), + onClick: () => props.setProviderType('classic'), + style: dropdownMenuItemStyle, + }, + [ + providerType === 'classic' ? h('i.fa.fa-check') : h('.network-check__transparent', '✓'), + h(NetworkDropdownIcon, { + backgroundColor: '#228B22', // forest green + isSelected: providerType === 'classic', + }), + h('span.network-name-item', { + style: { + color: providerType === 'classic' ? '#ffffff' : '#9b9b9b', + }, + }, this.context.t('classic')), + ] + ), + h( DropdownMenuItem, { @@ -263,6 +286,8 @@ NetworkDropdown.prototype.getNetworkName = function () { name = this.context.t('kovan') } else if (providerName === 'rinkeby') { name = this.context.t('rinkeby') + } else if (providerName === 'classic') { + name = this.context.t('classic') } else { name = this.context.t('unknownNetwork') } @@ -273,6 +298,7 @@ NetworkDropdown.prototype.getNetworkName = function () { NetworkDropdown.prototype.renderCommonRpc = function (rpcList, provider) { const props = this.props const rpcTarget = provider.rpcTarget + const network = props.network return rpcList.map((rpc) => { if ((rpc === 'http://localhost:8545') || (rpc === rpcTarget)) { @@ -283,7 +309,7 @@ NetworkDropdown.prototype.renderCommonRpc = function (rpcList, provider) { { key: `common${rpc}`, closeMenu: () => this.props.hideNetworkDropdown(), - onClick: () => props.setRpcTarget(rpc), + onClick: () => props.setRpcTarget(rpc, network), style: { fontSize: '16px', lineHeight: '20px', @@ -307,6 +333,7 @@ NetworkDropdown.prototype.renderCommonRpc = function (rpcList, provider) { NetworkDropdown.prototype.renderCustomOption = function (provider) { const { rpcTarget, type } = provider const props = this.props + const network = props.network if (type !== 'rpc') return null @@ -320,7 +347,7 @@ NetworkDropdown.prototype.renderCustomOption = function (provider) { DropdownMenuItem, { key: rpcTarget, - onClick: () => props.setRpcTarget(rpcTarget), + onClick: () => props.setRpcTarget(rpcTarget, network), closeMenu: () => this.props.hideNetworkDropdown(), style: { fontSize: '16px', diff --git a/ui/app/components/network-display/index.scss b/ui/app/components/network-display/index.scss index 2085cff67cc3..89d46a7b18f5 100644 --- a/ui/app/components/network-display/index.scss +++ b/ui/app/components/network-display/index.scss @@ -23,6 +23,10 @@ &--rinkeby { background-color: lighten($tulip-tree, 35%); } + + &--classic { + background-color: lighten($java, 45%); + } } &__name { @@ -50,5 +54,9 @@ &--rinkeby { background-color: $tulip-tree; } + + &--classic { + background-color: $java; + } } } diff --git a/ui/app/components/network-display/network-display.component.js b/ui/app/components/network-display/network-display.component.js index 38626af20667..64913bdae263 100644 --- a/ui/app/components/network-display/network-display.component.js +++ b/ui/app/components/network-display/network-display.component.js @@ -6,6 +6,7 @@ import { ROPSTEN_CODE, RINKEYBY_CODE, KOVAN_CODE, + CLASSIC_CODE, } from '../../../../app/scripts/controllers/network/enums' const networkToClassHash = { @@ -13,6 +14,7 @@ const networkToClassHash = { [ROPSTEN_CODE]: 'ropsten', [RINKEYBY_CODE]: 'rinkeby', [KOVAN_CODE]: 'kovan', + [CLASSIC_CODE]: 'classic', } export default class NetworkDisplay extends Component { diff --git a/ui/app/components/network.js b/ui/app/components/network.js index 83297c4f2251..832f5f1c8abc 100644 --- a/ui/app/components/network.js +++ b/ui/app/components/network.js @@ -63,6 +63,9 @@ Network.prototype.render = function () { } else if (providerName === 'rinkeby') { hoverText = context.t('rinkeby') iconName = 'rinkeby-test-network' + } else if (providerName === 'classic') { + hoverText = context.t('classic') + iconName = 'ethereum-classic-network' } else { hoverText = context.t('unknownNetwork') iconName = 'unknown-private-network' @@ -76,6 +79,7 @@ Network.prototype.render = function () { 'ropsten-test-network': providerName === 'ropsten' || parseInt(networkNumber) === 3, 'kovan-test-network': providerName === 'kovan', 'rinkeby-test-network': providerName === 'rinkeby', + 'ethereum-classic-network': providerName === 'classic', }), title: hoverText, onClick: (event) => { @@ -122,6 +126,15 @@ Network.prototype.render = function () { h('.network-name', context.t('rinkeby')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) + case 'ethereum-classic-network': + return h('.network-indicator', [ + h(NetworkDropdownIcon, { + backgroundColor: '#228B22', // green + nonSelectBackgroundColor: '#46893D', + }), + h('.network-name', context.t('classic')), + h('i.fa.fa-chevron-down.fa-lg.network-caret'), + ]) default: return h('.network-indicator', [ h('i.fa.fa-question-circle.fa-lg', { diff --git a/ui/app/components/pages/settings/settings.js b/ui/app/components/pages/settings/settings.js index ff42a13dee27..38d8729ac938 100644 --- a/ui/app/components/pages/settings/settings.js +++ b/ui/app/components/pages/settings/settings.js @@ -173,14 +173,23 @@ class Settings extends Component { onChange: event => this.setState({ newRpc: event.target.value }), onKeyPress: event => { if (event.key === 'Enter') { - this.validateRpc(this.state.newRpc) + this.validateRpc(this.state.newRpc, this.state.chainId) + } + }, + }), + h('input.settings__input', { + placeholder: this.context.t('optionalChainId'), + onChange: event => this.setState({ chainId: event.target.value }), + onKeyPress: event => { + if (event.key === 'Enter') { + this.validateRpc(this.state.newRpc, this.state.chainId) } }, }), h('div.settings__rpc-save-button', { onClick: event => { event.preventDefault() - this.validateRpc(this.state.newRpc) + this.validateRpc(this.state.newRpc, this.state.chainId) }, }, this.context.t('save')), ]), @@ -189,11 +198,11 @@ class Settings extends Component { ) } - validateRpc (newRpc) { + validateRpc (newRpc, chainId) { const { setRpcTarget, displayWarning } = this.props if (validUrl.isWebUri(newRpc)) { - setRpcTarget(newRpc) + setRpcTarget(newRpc, chainId) } else { const appendedRpc = `http://${newRpc}` @@ -341,7 +350,7 @@ const mapStateToProps = state => { const mapDispatchToProps = dispatch => { return { setCurrentCurrency: currency => dispatch(actions.setCurrentCurrency(currency)), - setRpcTarget: newRpc => dispatch(actions.setRpcTarget(newRpc)), + setRpcTarget: (newRpc, chainId) => dispatch(actions.setRpcTarget(newRpc, chainId)), displayWarning: warning => dispatch(actions.displayWarning(warning)), revealSeedConfirmation: () => dispatch(actions.revealSeedConfirmation()), setUseBlockie: value => dispatch(actions.setUseBlockie(value)), diff --git a/ui/lib/account-link.js b/ui/lib/account-link.js index 037d990fa223..f95980d01caf 100644 --- a/ui/lib/account-link.js +++ b/ui/lib/account-link.js @@ -18,6 +18,7 @@ module.exports = function (address, network) { link = `https://kovan.etherscan.io/address/${address}` break default: + // FIXME link = '' break } From 110b65b7e6746eb218588d52642bd610be8bc6ab Mon Sep 17 00:00:00 2001 From: hackyminer Date: Tue, 19 Jun 2018 00:05:00 +0900 Subject: [PATCH 02/12] setup settings and use correct ticker / blockexploer URLs * etc logo added * price info from https://min-api.cryptocompare.com/ --- app/images/etc_logo.svg | 20 ++++++++++++ app/scripts/controllers/currency.js | 32 ++++++++++++++++--- app/scripts/controllers/network/network.js | 22 ++++++++++++- app/scripts/metamask-controller.js | 5 +++ old-ui/app/components/account-dropdowns.js | 17 ++++++++-- old-ui/app/components/balance.js | 13 +++++++- old-ui/app/components/eth-balance.js | 14 ++++++-- old-ui/app/components/shift-list-item.js | 2 +- old-ui/app/components/token-cell.js | 32 ++++++++++++++++--- .../app/components/transaction-list-item.js | 16 ++++++++-- .../unit/components/balance-component-test.js | 1 + ui/app/components/account-dropdowns.js | 17 ++++++++-- ui/app/components/account-menu/index.js | 7 +++- ui/app/components/balance-component.js | 9 ++++-- .../dropdowns/components/account-dropdowns.js | 18 +++++++++-- .../dropdowns/token-menu-dropdown.js | 9 ++++-- ui/app/components/eth-balance.js | 15 +++++++-- ui/app/components/identicon.js | 11 +++++-- .../modals/account-details-modal.js | 8 ++++- .../send/currency-display/currency-display.js | 15 ++++++--- ui/app/components/shift-list-item.js | 2 +- ui/app/components/token-cell.js | 13 ++++++-- ui/app/components/tx-list-item.js | 10 +++--- ui/app/components/tx-list.js | 12 +++++-- ui/lib/account-link.js | 7 ++-- ui/lib/explorer-link.js | 10 ++++++ 26 files changed, 284 insertions(+), 53 deletions(-) create mode 100644 app/images/etc_logo.svg create mode 100644 ui/lib/explorer-link.js diff --git a/app/images/etc_logo.svg b/app/images/etc_logo.svg new file mode 100644 index 000000000000..13bc35429fe0 --- /dev/null +++ b/app/images/etc_logo.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/app/scripts/controllers/currency.js b/app/scripts/controllers/currency.js index d5bc5fe2bb9a..b80e1344b190 100644 --- a/app/scripts/controllers/currency.js +++ b/app/scripts/controllers/currency.js @@ -25,6 +25,7 @@ class CurrencyController { */ constructor (opts = {}) { const initState = extend({ + fromCurrency: 'ETH', currentCurrency: 'usd', conversionRate: 0, conversionDate: 'N/A', @@ -36,6 +37,26 @@ class CurrencyController { // PUBLIC METHODS // + /** + * A getter for the fromCurrency property + * + * @returns {string} A 2-4 character shorthand that describes the specific currency + * + */ + getFromCurrency () { + return this.store.getState().fromCurrency + } + + /** + * A setter for the fromCurrency property + * + * @param {string} fromCurrency The new currency to set as the fromCurrency in the store + * + */ + setFromCurrency (fromCurrency) { + this.store.updateState({ ticker: fromCurrency, fromCurrency }) + } + /** * A getter for the currentCurrency property * @@ -104,15 +125,16 @@ class CurrencyController { * */ async updateConversionRate () { - let currentCurrency + let currentCurrency, fromCurrency try { currentCurrency = this.getCurrentCurrency() - const response = await fetch(`https://api.infura.io/v1/ticker/eth${currentCurrency.toLowerCase()}`) + fromCurrency = this.getFromCurrency() + const response = await fetch(`https://min-api.cryptocompare.com/data/pricehistorical?fsym=${fromCurrency.toUpperCase()}&tsyms=${currentCurrency.toUpperCase()}`) const parsedResponse = await response.json() - this.setConversionRate(Number(parsedResponse.bid)) - this.setConversionDate(Number(parsedResponse.timestamp)) + this.setConversionRate(Number(parsedResponse[fromCurrency.toUpperCase()][currentCurrency.toUpperCase()])) + this.setConversionDate(parseInt(new Date().getTime() / 1000)) } catch (err) { - log.warn(`MetaMask - Failed to query currency conversion:`, currentCurrency, err) + log.warn(`MetaMask - Failed to query currency conversion:`, fromCurrency, currentCurrency, err) this.setConversionRate(0) this.setConversionDate('N/A') } diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index b9025661db7b..168483a2f319 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -33,6 +33,10 @@ const defaultProviderConfig = { type: testMode ? RINKEBY : MAINNET, } +const defaultNetworkConfig = { + ticker: 'ETH', +} + module.exports = class NetworkController extends EventEmitter { constructor (opts = {}) { @@ -43,7 +47,8 @@ module.exports = class NetworkController extends EventEmitter { // create stores this.providerStore = new ObservableStore(providerConfig) this.networkStore = new ObservableStore('loading') - this.store = new ComposedStore({ provider: this.providerStore, network: this.networkStore }) + this.networkConfig = new ObservableStore(defaultNetworkConfig) + this.store = new ComposedStore({ provider: this.providerStore, network: this.networkStore, settings: this.networkConfig }) this.on('networkDidChange', this.lookupNetwork) // provider and block tracker this._provider = null @@ -76,6 +81,10 @@ module.exports = class NetworkController extends EventEmitter { return this.networkStore.getState() } + getNetworkConfig () { + return this.networkConfig.getState() + } + setNetworkState (network, type) { if (network === 'loading') { return this.networkStore.putState(network) @@ -170,6 +179,11 @@ module.exports = class NetworkController extends EventEmitter { log.info('NetworkController - configureInfuraProvider', type) const networkClient = createInfuraClient({ network: type }) this._setNetworkClient(networkClient) + // setup networkConfig + var settings = { + ticker: 'ETH', + } + this.networkConfig.putState(settings) } _configureLocalhostProvider () { @@ -200,6 +214,12 @@ module.exports = class NetworkController extends EventEmitter { rpcUrl, ticker: 'ETH', } + // setup networkConfig + var settings = { + network: chainId, + } + settings = extend(settings, networks.networkList['rpc']) + this.networkConfig.putState(settings) this._setNetworkClient(networkClient) } diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 94c59473fae7..28e11e3df1c1 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -193,6 +193,8 @@ module.exports = class MetamaskController extends EventEmitter { }) this.networkController.on('networkDidChange', () => { this.balancesController.updateAllBalances() + var currentCurrency = this.currencyController.getCurrentCurrency() + this.setCurrentCurrency(currentCurrency, function() {}) }) this.balancesController.updateAllBalances() @@ -1329,10 +1331,13 @@ module.exports = class MetamaskController extends EventEmitter { * @param {Function} cb - A callback function returning currency info. */ setCurrentCurrency (currencyCode, cb) { + const { ticker } = this.networkController.getNetworkConfig() try { + this.currencyController.setFromCurrency(ticker) this.currencyController.setCurrentCurrency(currencyCode) this.currencyController.updateConversionRate() const data = { + fromCurrency: ticker || 'ETH', conversionRate: this.currencyController.getConversionRate(), currentCurrency: this.currencyController.getCurrentCurrency(), conversionDate: this.currencyController.getConversionDate(), diff --git a/old-ui/app/components/account-dropdowns.js b/old-ui/app/components/account-dropdowns.js index 262de66019aa..2b9284278b0d 100644 --- a/old-ui/app/components/account-dropdowns.js +++ b/old-ui/app/components/account-dropdowns.js @@ -2,7 +2,7 @@ const Component = require('react').Component const PropTypes = require('prop-types') const h = require('react-hyperscript') const actions = require('../../../ui/app/actions') -const genAccountLink = require('etherscan-link').createAccountLink +const genAccountLink = require('../../../ui/lib/account-link.js') const connect = require('react-redux').connect const Dropdown = require('./dropdown').Dropdown const DropdownMenuItem = require('./dropdown').DropdownMenuItem @@ -189,7 +189,11 @@ class AccountDropdowns extends Component { closeMenu: () => {}, onClick: () => { const { selected, network } = this.props - const url = genAccountLink(selected, network) + let url + if (this.props.settings && this.props.settings.blockExplorerAddr) { + url = this.props.settings.blockExplorerAddr + } + url = genAccountLink(selected, network, url) global.platform.openWindow({ url }) }, }, @@ -298,6 +302,7 @@ AccountDropdowns.propTypes = { keyrings: PropTypes.array, actions: PropTypes.objectOf(PropTypes.func), network: PropTypes.string, + settings: PropTypes.object, style: PropTypes.object, enableAccountOptions: PropTypes.bool, enableAccountsSelector: PropTypes.bool, @@ -316,6 +321,12 @@ const mapDispatchToProps = (dispatch) => { } } +function mapStateToProps (state) { + return { + settings: state.metamask.settings, + } +} + module.exports = { - AccountDropdowns: connect(null, mapDispatchToProps)(AccountDropdowns), + AccountDropdowns: connect(mapStateToProps, mapDispatchToProps)(AccountDropdowns), } diff --git a/old-ui/app/components/balance.js b/old-ui/app/components/balance.js index 57ca845649ee..d1fbc2c78b7a 100644 --- a/old-ui/app/components/balance.js +++ b/old-ui/app/components/balance.js @@ -1,12 +1,18 @@ const Component = require('react').Component const h = require('react-hyperscript') +const connect = require('react-redux').connect const inherits = require('util').inherits const formatBalance = require('../util').formatBalance const generateBalanceObject = require('../util').generateBalanceObject const Tooltip = require('./tooltip.js') const FiatValue = require('./fiat-value.js') -module.exports = EthBalanceComponent +module.exports = connect(mapStateToProps)(EthBalanceComponent) +function mapStateToProps (state) { + return { + ticker: state.metamask.ticker, + } +} inherits(EthBalanceComponent, Component) function EthBalanceComponent () { @@ -16,11 +22,16 @@ function EthBalanceComponent () { EthBalanceComponent.prototype.render = function () { var props = this.props let { value } = props + const { ticker } = props var style = props.style var needsParse = this.props.needsParse !== undefined ? this.props.needsParse : true value = value ? formatBalance(value, 6, needsParse) : '...' var width = props.width + if (ticker !== 'ETH') { + value = value.replace(/ETH/, ticker) + } + return ( h('.ether-balance.ether-balance-amount', { diff --git a/old-ui/app/components/eth-balance.js b/old-ui/app/components/eth-balance.js index 4f538fd31f31..38219d00ebea 100644 --- a/old-ui/app/components/eth-balance.js +++ b/old-ui/app/components/eth-balance.js @@ -1,12 +1,18 @@ const Component = require('react').Component const h = require('react-hyperscript') +const connect = require('react-redux').connect const inherits = require('util').inherits const formatBalance = require('../util').formatBalance const generateBalanceObject = require('../util').generateBalanceObject const Tooltip = require('./tooltip.js') const FiatValue = require('./fiat-value.js') -module.exports = EthBalanceComponent +module.exports = connect(mapStateToProps)(EthBalanceComponent) +function mapStateToProps (state) { + return { + ticker: state.metamask.ticker, + } +} inherits(EthBalanceComponent, Component) function EthBalanceComponent () { @@ -16,10 +22,14 @@ function EthBalanceComponent () { EthBalanceComponent.prototype.render = function () { var props = this.props let { value } = props - const { style, width } = props + const { ticker, style, width } = props var needsParse = this.props.needsParse !== undefined ? this.props.needsParse : true value = value ? formatBalance(value, 6, needsParse) : '...' + if (ticker !== 'ETH') { + value = value.replace(/ETH/, ticker) + } + return ( h('.ether-balance.ether-balance-amount', { diff --git a/old-ui/app/components/shift-list-item.js b/old-ui/app/components/shift-list-item.js index 5454a90bc438..0f30132c7821 100644 --- a/old-ui/app/components/shift-list-item.js +++ b/old-ui/app/components/shift-list-item.js @@ -3,7 +3,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const connect = require('react-redux').connect const vreme = new (require('vreme'))() -const explorerLink = require('etherscan-link').createExplorerLink +const explorerLink = require('../../../ui/lib/explorer-link.js') const actions = require('../../../ui/app/actions') const addressSummary = require('../util').addressSummary diff --git a/old-ui/app/components/token-cell.js b/old-ui/app/components/token-cell.js index 19d7139bb892..5c224c2a00c0 100644 --- a/old-ui/app/components/token-cell.js +++ b/old-ui/app/components/token-cell.js @@ -1,10 +1,16 @@ const Component = require('react').Component const h = require('react-hyperscript') +const connect = require('react-redux').connect const inherits = require('util').inherits const Identicon = require('./identicon') const prefixForNetwork = require('../../lib/etherscan-prefix-for-network') -module.exports = TokenCell +module.exports = connect(mapStateToProps)(TokenCell) +function mapStateToProps (state) { + return { + settings: state.metamask.settings, + } +} inherits(TokenCell, Component) function TokenCell () { @@ -44,14 +50,22 @@ TokenCell.prototype.render = function () { TokenCell.prototype.send = function (address, event) { event.preventDefault() event.stopPropagation() - const url = tokenFactoryFor(address) + let url + if (this.props.settings && this.props.settings.blockExplorerTokenFactory) { + url = this.props.settings.blockExplorerTokenFactory + } + url = tokenFactoryFor(address, url) if (url) { navigateTo(url) } } TokenCell.prototype.view = function (address, userAddress, network, event) { - const url = etherscanLinkFor(address, userAddress, network) + let url + if (this.props.settings && this.props.settings.blockExplorerToken) { + url = this.props.settings.blockExplorerToken + } + url = etherscanLinkFor(address, userAddress, network, url) if (url) { navigateTo(url) } @@ -61,12 +75,20 @@ function navigateTo (url) { global.platform.openWindow({ url }) } -function etherscanLinkFor (tokenAddress, address, network) { +function etherscanLinkFor (tokenAddress, address, network, url) { + if (url) { + return url.replace('[[tokenAddress]]', tokenAddress).replace('[[address]]', address) + } + const prefix = prefixForNetwork(network) return `https://${prefix}etherscan.io/token/${tokenAddress}?a=${address}` } -function tokenFactoryFor (tokenAddress) { +function tokenFactoryFor (tokenAddress, url) { + if (url) { + return url.replace('[[tokenAddress]]', tokenAddress) + } + return `https://tokenfactory.surge.sh/#/token/${tokenAddress}` } diff --git a/old-ui/app/components/transaction-list-item.js b/old-ui/app/components/transaction-list-item.js index 6ecf7d193c08..d9b8257bccb4 100644 --- a/old-ui/app/components/transaction-list-item.js +++ b/old-ui/app/components/transaction-list-item.js @@ -5,7 +5,7 @@ const connect = require('react-redux').connect const EthBalance = require('./eth-balance') const addressSummary = require('../util').addressSummary -const explorerLink = require('etherscan-link').createExplorerLink +const explorerLink = require('../../../ui/lib/explorer-link.js') const CopyButton = require('./copyButton') const vreme = new (require('vreme'))() const Tooltip = require('./tooltip') @@ -15,13 +15,19 @@ const actions = require('../../../ui/app/actions') const TransactionIcon = require('./transaction-list-item-icon') const ShiftListItem = require('./shift-list-item') +function mapStateToProps (state) { + return { + settings: state.metamask.settings, + } +} + const mapDispatchToProps = dispatch => { return { retryTransaction: transactionId => dispatch(actions.retryTransaction(transactionId)), } } -module.exports = connect(null, mapDispatchToProps)(TransactionListItem) +module.exports = connect(mapStateToProps, mapDispatchToProps)(TransactionListItem) inherits(TransactionListItem, Component) function TransactionListItem () { @@ -88,7 +94,11 @@ TransactionListItem.prototype.render = function () { } event.stopPropagation() if (!transaction.hash || !isLinkable) return - var url = explorerLink(transaction.hash, parseInt(network)) + let url + if (this.props.settings && this.props.settings.blockExplorerTx) { + url = this.props.settings.blockExplorerTx + } + url = explorerLink(transaction.hash, parseInt(network), url) global.platform.openWindow({ url }) }, style: { diff --git a/test/unit/components/balance-component-test.js b/test/unit/components/balance-component-test.js index 81e6fdf9eb37..0b3fe7c61dd7 100644 --- a/test/unit/components/balance-component-test.js +++ b/test/unit/components/balance-component-test.js @@ -8,6 +8,7 @@ const mockState = { accounts: { abc: {} }, network: 1, selectedAddress: 'abc', + ticker: 'ETH', }, } diff --git a/ui/app/components/account-dropdowns.js b/ui/app/components/account-dropdowns.js index 043008a36ef1..05300cd91e20 100644 --- a/ui/app/components/account-dropdowns.js +++ b/ui/app/components/account-dropdowns.js @@ -2,7 +2,7 @@ const Component = require('react').Component const PropTypes = require('prop-types') const h = require('react-hyperscript') const actions = require('../actions') -const genAccountLink = require('etherscan-link').createAccountLink +const genAccountLink = require('../../lib/account-link.js') const connect = require('react-redux').connect const Dropdown = require('./dropdown').Dropdown const DropdownMenuItem = require('./dropdown').DropdownMenuItem @@ -188,7 +188,11 @@ class AccountDropdowns extends Component { closeMenu: () => {}, onClick: () => { const { selected, network } = this.props - const url = genAccountLink(selected, network) + let url + if (this.props.settings && this.props.settings.blockExplorerAddr) { + url = this.props.settings.blockExplorerAddr + } + url = genAccountLink(selected, network, url) global.platform.openWindow({ url }) }, }, @@ -297,6 +301,7 @@ AccountDropdowns.propTypes = { actions: PropTypes.objectOf(PropTypes.func), network: PropTypes.string, style: PropTypes.object, + settings: PropTypes.object, enableAccountOptions: PropTypes.bool, enableAccountsSelector: PropTypes.bool, t: PropTypes.func, @@ -315,10 +320,16 @@ const mapDispatchToProps = (dispatch) => { } } +function mapStateToProps (state) { + return { + settings: state.metamask.settings, + } +} + AccountDropdowns.contextTypes = { t: PropTypes.func, } module.exports = { - AccountDropdowns: connect(null, mapDispatchToProps)(AccountDropdowns), + AccountDropdowns: connect(mapStateToProps, mapDispatchToProps)(AccountDropdowns), } diff --git a/ui/app/components/account-menu/index.js b/ui/app/components/account-menu/index.js index bcada41e3887..3f1e9c9871a0 100644 --- a/ui/app/components/account-menu/index.js +++ b/ui/app/components/account-menu/index.js @@ -40,6 +40,7 @@ function mapStateToProps (state) { selectedAddress: state.metamask.selectedAddress, isAccountMenuOpen: state.metamask.isAccountMenuOpen, keyrings: state.metamask.keyrings, + ticker: state.metamask.ticker, identities: state.metamask.identities, accounts: state.metamask.accounts, } @@ -152,6 +153,7 @@ AccountMenu.prototype.renderAccounts = function () { identities, accounts, selectedAddress, + ticker, keyrings, showAccountDetail, } = this.props @@ -163,8 +165,11 @@ AccountMenu.prototype.renderAccounts = function () { const isSelected = identity.address === selectedAddress const balanceValue = accounts[address] ? accounts[address].balance : '' - const formattedBalance = balanceValue ? formatBalance(balanceValue, 6) : '...' const simpleAddress = identity.address.substring(2).toLowerCase() + let formattedBalance = balanceValue ? formatBalance(balanceValue, 6) : '...' + if (ticker !== 'ETH') { + formattedBalance = formattedBalance.replace(/ETH/, ticker) + } const keyring = keyrings.find((kr) => { return kr.accounts.includes(simpleAddress) || diff --git a/ui/app/components/balance-component.js b/ui/app/components/balance-component.js index e31552f2d8f5..6472ea58cac1 100644 --- a/ui/app/components/balance-component.js +++ b/ui/app/components/balance-component.js @@ -20,6 +20,7 @@ function mapStateToProps (state) { return { account, network, + ticker: state.metamask.ticker, conversionRate: state.metamask.conversionRate, currentCurrency: state.metamask.currentCurrency, } @@ -61,11 +62,15 @@ BalanceComponent.prototype.renderTokenBalance = function () { BalanceComponent.prototype.renderBalance = function () { const props = this.props - const { shorten, account } = props + const { shorten, account, ticker } = props const balanceValue = account && account.balance const needsParse = 'needsParse' in props ? props.needsParse : true - const formattedBalance = balanceValue ? formatBalance(balanceValue, 6, needsParse) : '...' const showFiat = 'showFiat' in props ? props.showFiat : true + let formattedBalance = balanceValue ? formatBalance(balanceValue, 6, needsParse) : '...' + + if (ticker !== 'ETH') { + formattedBalance = formattedBalance.replace(/ETH/, ticker) + } if (formattedBalance === 'None' || formattedBalance === '...') { return h('div.flex-column.balance-display', {}, [ diff --git a/ui/app/components/dropdowns/components/account-dropdowns.js b/ui/app/components/dropdowns/components/account-dropdowns.js index 179b6617f96f..8c8a53d67b91 100644 --- a/ui/app/components/dropdowns/components/account-dropdowns.js +++ b/ui/app/components/dropdowns/components/account-dropdowns.js @@ -26,15 +26,18 @@ class AccountDropdowns extends Component { } renderAccounts () { - const { identities, accounts, selected, menuItemStyles, actions, keyrings } = this.props + const { identities, accounts, selected, menuItemStyles, actions, keyrings, ticker } = this.props return Object.keys(identities).map((key, index) => { const identity = identities[key] const isSelected = identity.address === selected const balanceValue = accounts[key].balance - const formattedBalance = balanceValue ? formatBalance(balanceValue, 6) : '...' const simpleAddress = identity.address.substring(2).toLowerCase() + let formattedBalance = balanceValue ? formatBalance(balanceValue, 6) : '...' + if (ticker !== 'ETH') { + formattedBalance = formattedBalance.replace(/ETH/, ticker) + } const keyring = keyrings.find((kr) => { return kr.accounts.includes(simpleAddress) || @@ -253,6 +256,11 @@ class AccountDropdowns extends Component { padding: '8px', } + let link + if (this.props.settings && this.props.settings.blockExplorerAddr) { + link = this.props.settings.blockExplorerAddr + } + return h( Dropdown, { @@ -295,7 +303,7 @@ class AccountDropdowns extends Component { closeMenu: () => {}, onClick: () => { const { selected, network } = this.props - const url = genAccountLink(selected, network) + const url = genAccountLink(selected, network, link) global.platform.openWindow({ url }) }, style: Object.assign( @@ -421,6 +429,8 @@ AccountDropdowns.propTypes = { network: PropTypes.number, // actions.showExportPrivateKeyModal: , style: PropTypes.object, + settings: PropTypes.object, + ticker: PropTypes.string, enableAccountsSelector: PropTypes.bool, enableAccountOption: PropTypes.bool, enableAccountOptions: PropTypes.bool, @@ -458,8 +468,10 @@ const mapDispatchToProps = (dispatch) => { function mapStateToProps (state) { return { + ticker: state.metamask.ticker, keyrings: state.metamask.keyrings, sidebarOpen: state.appState.sidebarOpen, + settings: state.metamask.settings, } } diff --git a/ui/app/components/dropdowns/token-menu-dropdown.js b/ui/app/components/dropdowns/token-menu-dropdown.js index 5a794c7c186e..4ffab823d2ec 100644 --- a/ui/app/components/dropdowns/token-menu-dropdown.js +++ b/ui/app/components/dropdowns/token-menu-dropdown.js @@ -4,7 +4,7 @@ const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../actions') -const genAccountLink = require('etherscan-link').createAccountLink +const genAccountLink = require('../../../lib/account-link.js') const copyToClipboard = require('copy-to-clipboard') const { Menu, Item, CloseArea } = require('./components/menu') @@ -17,6 +17,7 @@ module.exports = connect(mapStateToProps, mapDispatchToProps)(TokenMenuDropdown) function mapStateToProps (state) { return { network: state.metamask.network, + settings: state.metamask.settings, } } @@ -67,7 +68,11 @@ TokenMenuDropdown.prototype.render = function () { h(Item, { onClick: (e) => { e.stopPropagation() - const url = genAccountLink(this.props.token.address, this.props.network) + let url + if (this.props.settings && this.props.settings.blockExplorerAddr) { + url = this.props.settings.blockExplorerAddr + } + url = genAccountLink(this.props.token.address, this.props.network, url) global.platform.openWindow({ url }) this.props.onClose() }, diff --git a/ui/app/components/eth-balance.js b/ui/app/components/eth-balance.js index c3d084bdcb22..dcf865535c1a 100644 --- a/ui/app/components/eth-balance.js +++ b/ui/app/components/eth-balance.js @@ -1,5 +1,6 @@ const { Component } = require('react') const h = require('react-hyperscript') +const connect = require('react-redux').connect const { inherits } = require('util') const { formatBalance, @@ -8,7 +9,12 @@ const { const Tooltip = require('./tooltip.js') const FiatValue = require('./fiat-value.js') -module.exports = EthBalanceComponent +module.exports = connect(mapStateToProps)(EthBalanceComponent) +function mapStateToProps (state) { + return { + ticker: state.metamask.ticker, + } +} inherits(EthBalanceComponent, Component) function EthBalanceComponent () { @@ -17,9 +23,12 @@ function EthBalanceComponent () { EthBalanceComponent.prototype.render = function () { const props = this.props - const { value, style, width, needsParse = true } = props + const { ticker, value, style, width, needsParse = true } = props - const formattedValue = value ? formatBalance(value, 6, needsParse) : '...' + let formattedValue = value ? formatBalance(value, 6, needsParse) : '...' + if (ticker !== 'ETH') { + formattedValue = formattedValue.replace(/ETH/, ticker) + } return ( diff --git a/ui/app/components/identicon.js b/ui/app/components/identicon.js index 4240487451ed..bfbeb110942e 100644 --- a/ui/app/components/identicon.js +++ b/ui/app/components/identicon.js @@ -20,15 +20,22 @@ function IdenticonComponent () { function mapStateToProps (state) { return { + ticker: state.metamask.ticker, useBlockie: state.metamask.useBlockie, } } IdenticonComponent.prototype.render = function () { var props = this.props - const { className = '', address } = props + const { className = '', address, ticker } = props var diameter = props.diameter || this.defaultDiameter + // default logo + var logo = './images/eth_logo.svg' + if (ticker && ticker !== 'ETH') { + logo = `./images/${ticker.toLowerCase()}_logo.svg` + } + return address ? ( h('div', { @@ -48,7 +55,7 @@ IdenticonComponent.prototype.render = function () { ) : ( h('img.balance-icon', { - src: './images/eth_logo.svg', + src: logo, style: { height: diameter, width: diameter, diff --git a/ui/app/components/modals/account-details-modal.js b/ui/app/components/modals/account-details-modal.js index cc90cf578cf2..ad3a47009b35 100644 --- a/ui/app/components/modals/account-details-modal.js +++ b/ui/app/components/modals/account-details-modal.js @@ -15,6 +15,7 @@ function mapStateToProps (state) { network: state.metamask.network, selectedIdentity: getSelectedIdentity(state), keyrings: state.metamask.keyrings, + settings: state.metamask.settings, } } @@ -65,6 +66,11 @@ AccountDetailsModal.prototype.render = function () { exportPrivateKeyFeatureEnabled = false } + let link + if (this.props.settings && this.props.settings.blockExplorerAddr) { + link = this.props.settings.blockExplorerAddr + } + return h(AccountModalContainer, {}, [ h(EditableLabel, { className: 'account-modal__name', @@ -81,7 +87,7 @@ AccountDetailsModal.prototype.render = function () { h('div.account-modal-divider'), h('button.btn-primary.account-modal__button', { - onClick: () => global.platform.openWindow({ url: genAccountLink(address, network) }), + onClick: () => global.platform.openWindow({ url: genAccountLink(address, network, link) }), }, this.context.t('etherscanView')), // Holding on redesign for Export Private Key functionality diff --git a/ui/app/components/send/currency-display/currency-display.js b/ui/app/components/send/currency-display/currency-display.js index 2b8eaa41f70f..b0e75cd754f1 100644 --- a/ui/app/components/send/currency-display/currency-display.js +++ b/ui/app/components/send/currency-display/currency-display.js @@ -1,5 +1,6 @@ const Component = require('react').Component const h = require('react-hyperscript') +const connect = require('react-redux').connect const inherits = require('util').inherits const { conversionUtil, multiplyCurrencies } = require('../../../conversion-util') const { removeLeadingZeroes } = require('../send.utils') @@ -12,7 +13,12 @@ CurrencyDisplay.contextTypes = { t: PropTypes.func, } -module.exports = CurrencyDisplay +module.exports = connect(mapStateToProps)(CurrencyDisplay) +function mapStateToProps (state) { + return { + fromCurrency: state.metamask.fromCurrency, + } +} inherits(CurrencyDisplay, Component) function CurrencyDisplay () { @@ -78,7 +84,7 @@ CurrencyDisplay.prototype.getValueToRender = function ({ selectedToken, conversi } CurrencyDisplay.prototype.getConvertedValueToRender = function (nonFormattedValue) { - const { primaryCurrency, convertedCurrency, conversionRate } = this.props + const { fromCurrency, primaryCurrency, convertedCurrency, conversionRate } = this.props if (conversionRate === 0 || conversionRate === null || conversionRate === undefined) { if (nonFormattedValue !== 0) { @@ -88,7 +94,7 @@ CurrencyDisplay.prototype.getConvertedValueToRender = function (nonFormattedValu let convertedValue = conversionUtil(nonFormattedValue, { fromNumericBase: 'dec', - fromCurrency: primaryCurrency, + fromCurrency: fromCurrency || primaryCurrency, toCurrency: convertedCurrency, numberOfDecimals: 2, conversionRate, @@ -132,6 +138,7 @@ CurrencyDisplay.prototype.render = function () { const { className = 'currency-display', primaryBalanceClassName = 'currency-display__input', + fromCurrency, primaryCurrency, readOnly = false, inError = false, @@ -174,7 +181,7 @@ CurrencyDisplay.prototype.render = function () { step, }), - h('span.currency-display__currency-symbol', primaryCurrency), + h('span.currency-display__currency-symbol', fromCurrency || primaryCurrency), ]), diff --git a/ui/app/components/shift-list-item.js b/ui/app/components/shift-list-item.js index 4334aacba56a..79c9d23dcb05 100644 --- a/ui/app/components/shift-list-item.js +++ b/ui/app/components/shift-list-item.js @@ -4,7 +4,7 @@ const PropTypes = require('prop-types') const h = require('react-hyperscript') const connect = require('react-redux').connect const vreme = new (require('vreme'))() -const explorerLink = require('etherscan-link').createExplorerLink +const explorerLink = require('../../lib/explorer-link.js') const actions = require('../actions') const addressSummary = require('../util').addressSummary diff --git a/ui/app/components/token-cell.js b/ui/app/components/token-cell.js index 4100d76a59eb..af11f35cbbc1 100644 --- a/ui/app/components/token-cell.js +++ b/ui/app/components/token-cell.js @@ -19,6 +19,7 @@ function mapStateToProps (state) { contractExchangeRates: state.metamask.contractExchangeRates, conversionRate: state.metamask.conversionRate, sidebarOpen: state.appState.sidebarOpen, + settings: state.metamask.settings, } } @@ -143,7 +144,11 @@ TokenCell.prototype.send = function (address, event) { } TokenCell.prototype.view = function (address, userAddress, network, event) { - const url = etherscanLinkFor(address, userAddress, network) + let url + if (this.props.settings && this.props.settings.blockExplorerToken) { + url = this.props.settings.blockExplorerToken + } + url = etherscanLinkFor(address, userAddress, network, url) if (url) { navigateTo(url) } @@ -153,7 +158,11 @@ function navigateTo (url) { global.platform.openWindow({ url }) } -function etherscanLinkFor (tokenAddress, address, network) { +function etherscanLinkFor (tokenAddress, address, network, url) { + if (url) { + return url.replace('[[tokenAddress]]', tokenAddress).replace('[[address]]', address) + } + const prefix = prefixForNetwork(network) return `https://${prefix}etherscan.io/token/${tokenAddress}?a=${address}` } diff --git a/ui/app/components/tx-list-item.js b/ui/app/components/tx-list-item.js index 474d62638053..46eb9ef889f3 100644 --- a/ui/app/components/tx-list-item.js +++ b/ui/app/components/tx-list-item.js @@ -32,6 +32,7 @@ module.exports = compose( function mapStateToProps (state) { return { tokens: state.metamask.tokens, + ticker: state.metamask.ticker, currentCurrency: getCurrentCurrency(state), contractExchangeRates: state.metamask.contractExchangeRates, selectedAddressTxList: state.metamask.selectedAddressTxList, @@ -110,6 +111,7 @@ TxListItem.prototype.getSendEtherTotal = function () { const { transactionAmount, conversionRate, + ticker, address, currentCurrency, } = this.props @@ -121,7 +123,7 @@ TxListItem.prototype.getSendEtherTotal = function () { const totalInFiat = conversionUtil(transactionAmount, { fromNumericBase: 'hex', toNumericBase: 'dec', - fromCurrency: 'ETH', + fromCurrency: ticker, toCurrency: currentCurrency, fromDenomination: 'WEI', numberOfDecimals: 2, @@ -130,15 +132,15 @@ TxListItem.prototype.getSendEtherTotal = function () { const totalInETH = conversionUtil(transactionAmount, { fromNumericBase: 'hex', toNumericBase: 'dec', - fromCurrency: 'ETH', - toCurrency: 'ETH', + fromCurrency: ticker, + toCurrency: ticker, fromDenomination: 'WEI', conversionRate, numberOfDecimals: 6, }) return { - total: `${totalInETH} ETH`, + total: `${totalInETH} ${ticker}`, fiatTotal: `${totalInFiat} ${currentCurrency.toUpperCase()}`, } } diff --git a/ui/app/components/tx-list.js b/ui/app/components/tx-list.js index d8c4a9d19793..51c302641a2a 100644 --- a/ui/app/components/tx-list.js +++ b/ui/app/components/tx-list.js @@ -26,6 +26,7 @@ TxList.contextTypes = { function mapStateToProps (state) { return { + settings: state.metamask.settings, txsToRender: selectors.transactionsSelector(state), conversionRate: selectors.conversionRateSelector(state), selectedAddress: selectors.getSelectedAddress(state), @@ -155,7 +156,11 @@ TxList.prototype.renderTransactionListItem = function (transaction, conversionRa } TxList.prototype.view = function (txHash, network) { - const url = etherscanLinkFor(txHash, network) + let url + if (this.props.settings && this.props.settings.blockExplorerTx) { + url = this.props.settings.blockExplorerTx + } + url = etherscanLinkFor(txHash, network, url) if (url) { navigateTo(url) } @@ -165,7 +170,10 @@ function navigateTo (url) { global.platform.openWindow({ url }) } -function etherscanLinkFor (txHash, network) { +function etherscanLinkFor (txHash, network, url) { const prefix = prefixForNetwork(network) + if (url) { + return url.replace('[[txHash]]', txHash) + } return `https://${prefix}etherscan.io/tx/${txHash}` } diff --git a/ui/lib/account-link.js b/ui/lib/account-link.js index f95980d01caf..ad6d38cfbd7d 100644 --- a/ui/lib/account-link.js +++ b/ui/lib/account-link.js @@ -1,4 +1,4 @@ -module.exports = function (address, network) { +module.exports = function (address, network, url) { const net = parseInt(network) let link switch (net) { @@ -18,7 +18,10 @@ module.exports = function (address, network) { link = `https://kovan.etherscan.io/address/${address}` break default: - // FIXME + if (url) { + return url.replace('[[address]]', address) + } + link = '' break } diff --git a/ui/lib/explorer-link.js b/ui/lib/explorer-link.js new file mode 100644 index 000000000000..ce38a02f3bfd --- /dev/null +++ b/ui/lib/explorer-link.js @@ -0,0 +1,10 @@ +const prefixForNetwork = require('./etherscan-prefix-for-network') + +module.exports = function (hash, network, url) { + if (url) { + return url.replace('[[txHash]]', hash) + } + + const prefix = prefixForNetwork(network) + return `https://${prefix}etherscan.io/tx/${hash}` +} From c603f138ce83c758369a116a829e62a275b5ed0c Mon Sep 17 00:00:00 2001 From: hackyminer Date: Fri, 22 Jun 2018 10:10:31 +0900 Subject: [PATCH 03/12] support shapeshift exchange for deposit * fixup for testnet faucet --- app/scripts/controllers/network/networks.js | 2 + app/scripts/lib/buy-eth-url.js | 10 +++- app/scripts/metamask-controller.js | 3 +- old-ui/app/components/buy-button-subview.js | 58 ++++++++++++------- old-ui/app/components/shapeshift-form.js | 5 +- old-ui/app/components/shift-list-item.js | 3 +- ui/app/actions.js | 19 ++++-- ui/app/components/buy-button-subview.js | 6 +- ui/app/components/modals/buy-options-modal.js | 13 ++++- .../components/modals/deposit-ether-modal.js | 29 ++++++++-- ui/app/components/shapeshift-form.js | 25 +++++--- ui/app/components/shift-list-item.js | 3 +- 12 files changed, 126 insertions(+), 50 deletions(-) diff --git a/app/scripts/controllers/network/networks.js b/app/scripts/controllers/network/networks.js index f96556ce1e87..5c53b9fcef8e 100644 --- a/app/scripts/controllers/network/networks.js +++ b/app/scripts/controllers/network/networks.js @@ -15,6 +15,8 @@ networks.networkList = { 'blockExplorerToken': 'https://gastracker.io/token/[[tokenAddress]]/[[address]]', 'service': 'Ethereum Commonwealth', 'rpcUrl': 'https://etc-geth.0xinfra.com', + 'exchanges': ['ShapeShift'], + 'buyUrl': '', }, } diff --git a/app/scripts/lib/buy-eth-url.js b/app/scripts/lib/buy-eth-url.js index 4e2d0bc79429..a1df018e8d89 100644 --- a/app/scripts/lib/buy-eth-url.js +++ b/app/scripts/lib/buy-eth-url.js @@ -11,7 +11,7 @@ module.exports = getBuyEthUrl * network does not match any of the specified cases, or if no network is given, returns undefined. * */ -function getBuyEthUrl ({ network, amount, address }) { +function getBuyEthUrl ({ network, amount, address, link }) { let url switch (network) { case '1': @@ -29,6 +29,14 @@ function getBuyEthUrl ({ network, amount, address }) { case '42': url = 'https://github.com/kovan-testnet/faucet' break + + default: + if (link) { + url = link.replace('[[amount]]', amount).replace('[[address]]', address) + } else { + url = '' + } + break } return url } diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 28e11e3df1c1..b0ed6a2726e1 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1358,7 +1358,8 @@ module.exports = class MetamaskController extends EventEmitter { buyEth (address, amount) { if (!amount) amount = '5' const network = this.networkController.getNetworkState() - const url = getBuyEthUrl({ network, address, amount }) + const link = this.networkController.getNetworkConfig().buyUrl + const url = getBuyEthUrl({ network, address, amount, link }) if (url) this.platform.openWindow({ url }) } diff --git a/old-ui/app/components/buy-button-subview.js b/old-ui/app/components/buy-button-subview.js index 8bb73ae3e9c3..a7e29859c569 100644 --- a/old-ui/app/components/buy-button-subview.js +++ b/old-ui/app/components/buy-button-subview.js @@ -20,6 +20,8 @@ function mapStateToProps (state) { buyView: state.appState.buyView, network: state.metamask.network, provider: state.metamask.provider, + ticker: state.metamask.ticker, + settings: state.metamask.settings, context: state.appState.currentView.context, isSubLoading: state.appState.isSubLoading, } @@ -170,15 +172,39 @@ BuyButtonSubview.prototype.primarySubview = function () { ) default: - return ( - h('h2.error', 'Unknown network ID') - ) - + return this.mainnetSubview() } } BuyButtonSubview.prototype.mainnetSubview = function () { const props = this.props + const network = parseInt(props.network) + + let selected + if (network === 1) { + selected = [ + 'Coinbase', + 'ShapeShift', + ] + } else { + selected = this.props.settings.exchanges || [] + } + + const subtext = { + 'Coinbase': 'Crypto/FIAT (USA only)', + 'ShapeShift': 'Crypto', + } + + let texts = {} + selected.forEach(ex => { + texts[ex] = subtext[ex] + }) + + if (selected.length === 0) { + return ( + h('h2.error', 'No exchange supported') + ) + } return ( @@ -198,14 +224,8 @@ BuyButtonSubview.prototype.mainnetSubview = function () { }, [ h(RadioList, { defaultFocus: props.buyView.subview, - labels: [ - 'Coinbase', - 'ShapeShift', - ], - subtext: { - 'Coinbase': 'Crypto/FIAT (USA only)', - 'ShapeShift': 'Crypto', - }, + labels: selected, + subtext: texts, onClick: this.radioHandler.bind(this), }), ]), @@ -229,13 +249,10 @@ BuyButtonSubview.prototype.mainnetSubview = function () { } BuyButtonSubview.prototype.formVersionSubview = function () { - const network = this.props.network - if (network === '1') { - if (this.props.buyView.formView.coinbase) { - return h(CoinbaseForm, this.props) - } else if (this.props.buyView.formView.shapeshift) { - return h(ShapeshiftForm, this.props) - } + if (this.props.buyView.formView.coinbase) { + return h(CoinbaseForm, this.props) + } else if (this.props.buyView.formView.shapeshift) { + return h(ShapeshiftForm, this.props) } } @@ -252,10 +269,11 @@ BuyButtonSubview.prototype.backButtonContext = function () { } BuyButtonSubview.prototype.radioHandler = function (event) { + const ticker = this.props.ticker switch (event.target.title) { case 'Coinbase': return this.props.dispatch(actions.coinBaseSubview()) case 'ShapeShift': - return this.props.dispatch(actions.shapeShiftSubview(this.props.provider.type)) + return this.props.dispatch(actions.shapeShiftSubview(this.props.provider.type, ticker)) } } diff --git a/old-ui/app/components/shapeshift-form.js b/old-ui/app/components/shapeshift-form.js index 14de309aba74..e17f53ff9c93 100644 --- a/old-ui/app/components/shapeshift-form.js +++ b/old-ui/app/components/shapeshift-form.js @@ -10,6 +10,7 @@ function mapStateToProps (state) { return { warning: state.appState.warning, isSubLoading: state.appState.isSubLoading, + ticker: state.metamask.ticker, } } @@ -237,7 +238,7 @@ ShapeshiftForm.prototype.updateCoin = function (event) { var message = 'Not a valid coin' return props.dispatch(actions.displayWarning(message)) } else { - return props.dispatch(actions.pairUpdate(coin)) + return props.dispatch(actions.pairUpdate(coin, props.ticker)) } } @@ -249,7 +250,7 @@ ShapeshiftForm.prototype.handleLiveInput = function () { if (!coinOptions[coin.toUpperCase()] || coin.toUpperCase() === 'ETH') { return null } else { - return props.dispatch(actions.pairUpdate(coin)) + return props.dispatch(actions.pairUpdate(coin, props.ticker)) } } diff --git a/old-ui/app/components/shift-list-item.js b/old-ui/app/components/shift-list-item.js index 0f30132c7821..517219d23bc7 100644 --- a/old-ui/app/components/shift-list-item.js +++ b/old-ui/app/components/shift-list-item.js @@ -18,6 +18,7 @@ function mapStateToProps (state) { return { conversionRate: state.metamask.conversionRate, currentCurrency: state.metamask.currentCurrency, + ticker: state.metamask.ticker, } } @@ -79,7 +80,7 @@ ShiftListItem.prototype.renderUtilComponents = function () { title: 'QR Code', }, [ h('i.fa.fa-qrcode.pointer.pop-hover', { - onClick: () => props.dispatch(actions.reshowQrCode(props.depositAddress, props.depositType)), + onClick: () => props.dispatch(actions.reshowQrCode(props.depositAddress, props.depositType, props.ticker)), style: { margin: '5px', marginLeft: '23px', diff --git a/ui/app/actions.js b/ui/app/actions.js index 9c4e45126bf2..638395bc8a91 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -2015,11 +2015,17 @@ function coinBaseSubview () { } } -function pairUpdate (coin) { +function pairUpdate (coin, ticker) { + if (!ticker) { + ticker = 'eth' + } else { + ticker = ticker.toLowerCase() + } + return (dispatch) => { dispatch(actions.showSubLoadingIndication()) dispatch(actions.hideWarning()) - shapeShiftRequest('marketinfo', {pair: `${coin.toLowerCase()}_eth`}, (mktResponse) => { + shapeShiftRequest('marketinfo', {pair: `${coin.toLowerCase()}_${ticker}`}, (mktResponse) => { dispatch(actions.hideSubLoadingIndication()) if (mktResponse.error) return dispatch(actions.displayWarning(mktResponse.error)) dispatch({ @@ -2032,8 +2038,11 @@ function pairUpdate (coin) { } } -function shapeShiftSubview (network) { +function shapeShiftSubview (network, ticker) { var pair = 'btc_eth' + if (ticker) { + pair = `btc_${ticker.toLowerCase()}` + } return (dispatch) => { dispatch(actions.showSubLoadingIndication()) shapeShiftRequest('marketinfo', {pair}, (mktResponse) => { @@ -2088,10 +2097,10 @@ function showQrView (data, message) { }, } } -function reshowQrCode (data, coin) { +function reshowQrCode (data, coin, ticker) { return (dispatch) => { dispatch(actions.showLoadingIndication()) - shapeShiftRequest('marketinfo', {pair: `${coin.toLowerCase()}_eth`}, (mktResponse) => { + shapeShiftRequest('marketinfo', {pair: `${coin.toLowerCase()}_${ticker.toLowerCase()}`}, (mktResponse) => { if (mktResponse.error) return dispatch(actions.displayWarning(mktResponse.error)) var message = [ diff --git a/ui/app/components/buy-button-subview.js b/ui/app/components/buy-button-subview.js index c6957d2aaa3e..b1a2ad0b94f1 100644 --- a/ui/app/components/buy-button-subview.js +++ b/ui/app/components/buy-button-subview.js @@ -27,6 +27,7 @@ function mapStateToProps (state) { network: state.metamask.network, provider: state.metamask.provider, context: state.appState.currentView.context, + ticker: state.metamask.ticker, isSubLoading: state.appState.isSubLoading, } } @@ -258,10 +259,11 @@ BuyButtonSubview.prototype.backButtonContext = function () { } BuyButtonSubview.prototype.radioHandler = function (event) { + const ticker = this.props.ticker switch (event.target.title) { case 'Coinbase': - return this.props.dispatch(actions.coinBaseSubview()) + return this.props.dispatch(actions.coinBaseSubview(ticker)) case 'ShapeShift': - return this.props.dispatch(actions.shapeShiftSubview(this.props.provider.type)) + return this.props.dispatch(actions.shapeShiftSubview(this.props.provider.type, ticker)) } } diff --git a/ui/app/components/modals/buy-options-modal.js b/ui/app/components/modals/buy-options-modal.js index c70510b5fcde..a4b8458faadf 100644 --- a/ui/app/components/modals/buy-options-modal.js +++ b/ui/app/components/modals/buy-options-modal.js @@ -10,6 +10,7 @@ function mapStateToProps (state) { return { network: state.metamask.network, address: state.metamask.selectedAddress, + settings: state.metamask.settings, } } @@ -24,7 +25,7 @@ function mapDispatchToProps (dispatch) { showAccountDetailModal: () => { dispatch(actions.showModal({ name: 'ACCOUNT_DETAILS' })) }, - toFaucet: network => dispatch(actions.buyEth({ network })), + toFaucet: (network, address, link) => dispatch(actions.buyEth({ network, address, amount: 0, link })), } } @@ -51,9 +52,15 @@ BuyOptions.prototype.renderModalContentOption = function (title, header, onClick BuyOptions.prototype.render = function () { const { network, toCoinbase, address, toFaucet } = this.props - const isTestNetwork = ['3', '4', '42'].find(n => n === network) + let isTestNetwork = ['3', '4', '42'].find(n => n === network) const networkName = getNetworkDisplayName(network) + let link + if (this.props.settings.isTestNet) { + isTestNetwork = true + link = this.props.settings.buyUrl + } + return h('div', {}, [ h('div.buy-modal-content.transfers-subview', { }, [ @@ -69,7 +76,7 @@ BuyOptions.prototype.render = function () { h('div.buy-modal-content-options.flex-column.flex-center', {}, [ isTestNetwork - ? this.renderModalContentOption(networkName, this.context.t('testFaucet'), () => toFaucet(network)) + ? this.renderModalContentOption(networkName, this.context.t('testFaucet'), () => toFaucet(network, address, link)) : this.renderModalContentOption('Coinbase', this.context.t('depositFiat'), () => toCoinbase(address)), // h('div.buy-modal-content-option', {}, [ diff --git a/ui/app/components/modals/deposit-ether-modal.js b/ui/app/components/modals/deposit-ether-modal.js index 2daa7fa1d75a..d24a326a5a27 100644 --- a/ui/app/components/modals/deposit-ether-modal.js +++ b/ui/app/components/modals/deposit-ether-modal.js @@ -19,6 +19,7 @@ function mapStateToProps (state) { return { network: state.metamask.network, address: state.metamask.selectedAddress, + settings: state.metamask.settings, } } @@ -36,7 +37,7 @@ function mapDispatchToProps (dispatch) { showAccountDetailModal: () => { dispatch(actions.showModal({ name: 'ACCOUNT_DETAILS' })) }, - toFaucet: network => dispatch(actions.buyEth({ network })), + toFaucet: (network, address, link) => dispatch(actions.buyEth({ network, address, amount: 0, link })), } } @@ -119,9 +120,25 @@ DepositEtherModal.prototype.renderRow = function ({ DepositEtherModal.prototype.render = function () { const { network, toCoinbase, address, toFaucet } = this.props - const { buyingWithShapeshift } = this.state + let { buyingWithShapeshift } = this.state + let isTestNetwork = ['3', '4', '42'].find(n => n === network) + let noCoinbase = false + let noShapeShift = false + + if (this.props.settings.exchanges) { + if (this.props.settings.exchanges.indexOf('Coinbase') === -1) { + noCoinbase = true + } + if (this.props.settings.exchanges.indexOf('ShapeShift') === -1) { + noShapeShift = true + } + } + let link + if (this.props.settings.isTestNet) { + isTestNetwork = true + link = this.props.settings.buyUrl + } - const isTestNetwork = ['3', '4', '42'].find(n => n === network) const networkName = getNetworkDisplayName(network) return h('div.page-container.page-container--full-width.page-container--full-height', {}, [ @@ -164,7 +181,7 @@ DepositEtherModal.prototype.render = function () { title: FAUCET_ROW_TITLE, text: this.facuetRowText(networkName), buttonLabel: this.context.t('getEther'), - onButtonClick: () => toFaucet(network), + onButtonClick: () => toFaucet(network, address, link), hide: !isTestNetwork || buyingWithShapeshift, }), @@ -179,7 +196,7 @@ DepositEtherModal.prototype.render = function () { text: COINBASE_ROW_TEXT, buttonLabel: this.context.t('continueToCoinbase'), onButtonClick: () => toCoinbase(address), - hide: isTestNetwork || buyingWithShapeshift, + hide: noCoinbase || isTestNetwork || buyingWithShapeshift, }), this.renderRow({ @@ -192,7 +209,7 @@ DepositEtherModal.prototype.render = function () { text: SHAPESHIFT_ROW_TEXT, buttonLabel: this.context.t('shapeshiftBuy'), onButtonClick: () => this.setState({ buyingWithShapeshift: true }), - hide: isTestNetwork, + hide: noShapeShift || isTestNetwork, hideButton: buyingWithShapeshift, hideTitle: buyingWithShapeshift, onBackClick: () => this.setState({ buyingWithShapeshift: false }), diff --git a/ui/app/components/shapeshift-form.js b/ui/app/components/shapeshift-form.js index 2c4ba40bf576..b9cb92afd8c0 100644 --- a/ui/app/components/shapeshift-form.js +++ b/ui/app/components/shapeshift-form.js @@ -16,19 +16,23 @@ function mapStateToProps (state) { selectedAddress, } = state.metamask const { warning } = state.appState + const ticker = state.metamask.ticker + const provider = state.metamask.provider return { coinOptions, tokenExchangeRates, selectedAddress, + provider, + ticker, warning, } } function mapDispatchToProps (dispatch) { return { - shapeShiftSubview: () => dispatch(shapeShiftSubview()), - pairUpdate: coin => dispatch(pairUpdate(coin)), + shapeShiftSubview: (type, ticker) => dispatch(shapeShiftSubview(type, ticker)), + pairUpdate: (coin, ticker) => dispatch(pairUpdate(coin, ticker)), buyWithShapeShift: data => dispatch(buyWithShapeShift(data)), } } @@ -56,22 +60,27 @@ function ShapeshiftForm () { } ShapeshiftForm.prototype.getCoinPair = function () { - return `${this.state.depositCoin.toUpperCase()}_ETH` + const ticker = this.props.ticker + return `${this.state.depositCoin.toUpperCase()}_${ticker}` } ShapeshiftForm.prototype.componentWillMount = function () { - this.props.shapeShiftSubview() + const ticker = this.props.ticker + const type = this.props.provider.type + this.props.shapeShiftSubview(type, ticker) } ShapeshiftForm.prototype.onCoinChange = function (coin) { + const ticker = this.props.ticker this.setState({ depositCoin: coin, errorMessage: '', }) - this.props.pairUpdate(coin) + this.props.pairUpdate(coin, ticker) } ShapeshiftForm.prototype.onBuyWithShapeShift = function () { + const ticker = this.props.ticker this.setState({ isLoading: true, showQrCode: true, @@ -85,7 +94,7 @@ ShapeshiftForm.prototype.onBuyWithShapeShift = function () { refundAddress: returnAddress, depositCoin, } = this.state - const pair = `${depositCoin}_eth` + const pair = `${depositCoin}_${ticker.toLowerCase()}` const data = { withdrawal, pair, @@ -175,7 +184,7 @@ ShapeshiftForm.prototype.renderQrCode = function () { ShapeshiftForm.prototype.render = function () { const { coinOptions, btnClass, warning } = this.props const { errorMessage, showQrCode, depositAddress } = this.state - const { tokenExchangeRates } = this.props + const { tokenExchangeRates, ticker } = this.props const token = tokenExchangeRates[this.getCoinPair()] return h('div.shapeshift-form-wrapper', [ @@ -209,7 +218,7 @@ ShapeshiftForm.prototype.render = function () { this.context.t('receive'), ]), - h('div.shapeshift-form__selector-input', ['ETH']), + h('div.shapeshift-form__selector-input', [ticker]), ]), diff --git a/ui/app/components/shift-list-item.js b/ui/app/components/shift-list-item.js index 79c9d23dcb05..5071e6395c7b 100644 --- a/ui/app/components/shift-list-item.js +++ b/ui/app/components/shift-list-item.js @@ -25,6 +25,7 @@ function mapStateToProps (state) { selectedAddress: state.metamask.selectedAddress, conversionRate: state.metamask.conversionRate, currentCurrency: state.metamask.currentCurrency, + ticker: state.metamask.ticker, } } @@ -84,7 +85,7 @@ ShiftListItem.prototype.renderUtilComponents = function () { title: this.context.t('qrCode'), }, [ h('i.fa.fa-qrcode.pointer.pop-hover', { - onClick: () => props.dispatch(actions.reshowQrCode(props.depositAddress, props.depositType)), + onClick: () => props.dispatch(actions.reshowQrCode(props.depositAddress, props.depositType, props.ticker)), style: { margin: '5px', marginLeft: '23px', From 11a918e7d6867faa20e27f7498b58cd8f815fc03 Mon Sep 17 00:00:00 2001 From: hackyminer Date: Wed, 1 Aug 2018 17:05:06 +0900 Subject: [PATCH 04/12] update rpcList correctly * rename frequentRpcList to frequentRpcListDetail to prevent compatible issue * increase frequentRpcList length by 1 --- app/scripts/controllers/preferences.js | 26 +++++++++---------- app/scripts/metamask-controller.js | 2 +- old-ui/app/app.js | 2 +- old-ui/app/components/app-bar.js | 21 ++++++++------- ui/app/app.js | 8 +++--- .../components/dropdowns/network-dropdown.js | 23 +++++++++------- ui/app/components/pages/home.js | 4 +-- 7 files changed, 46 insertions(+), 40 deletions(-) diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 707fd7de9eb3..51489d73b1a5 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -23,7 +23,7 @@ class PreferencesController { */ constructor (opts = {}) { const initState = extend({ - frequentRpcList: [], + frequentRpcListDetail: [], currentAccountTab: 'history', accountTokens: {}, tokens: [], @@ -298,10 +298,10 @@ class PreferencesController { * @returns {Promise} Promise resolves with undefined * */ - updateFrequentRpcList (_url) { - return this.addToFrequentRpcList(_url) + updateFrequentRpcList (_url, chainId) { + return this.addToFrequentRpcList(_url, chainId) .then((rpcList) => { - this.store.updateState({ frequentRpcList: rpcList }) + this.store.updateState({ frequentRpcListDetail: rpcList }) return Promise.resolve() }) } @@ -329,29 +329,29 @@ class PreferencesController { * @returns {Promise} The updated frequentRpcList. * */ - addToFrequentRpcList (_url) { - const rpcList = this.getFrequentRpcList() - const index = rpcList.findIndex((element) => { return element === _url }) + addToFrequentRpcList (_url, chainId) { + const rpcList = this.getFrequentRpcListDetail() + const index = rpcList.findIndex((element) => { return element.rpcUrl === _url }) if (index !== -1) { rpcList.splice(index, 1) } if (_url !== 'http://localhost:8545') { - rpcList.push(_url) + rpcList.push({rpcUrl : _url, chainId }) } - if (rpcList.length > 2) { + if (rpcList.length > 3) { rpcList.shift() } return Promise.resolve(rpcList) } /** - * Getter for the `frequentRpcList` property. + * Getter for the `frequentRpcListDetail` property. * - * @returns {array} An array of one or two rpc urls. + * @returns {array} An array of rpc urls. * */ - getFrequentRpcList () { - return this.store.getState().frequentRpcList + getFrequentRpcListDetail () { + return this.store.getState().frequentRpcListDetail } /** diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index b0ed6a2726e1..6525f9d584b2 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1381,7 +1381,7 @@ module.exports = class MetamaskController extends EventEmitter { */ async setCustomRpc (rpcTarget, chainId) { this.networkController.setRpcTarget(rpcTarget, chainId) - await this.preferencesController.updateFrequentRpcList(rpcTarget) + await this.preferencesController.updateFrequentRpcList(rpcTarget, chainId) return rpcTarget } diff --git a/old-ui/app/app.js b/old-ui/app/app.js index 8f121e7950e4..d2689330d20a 100644 --- a/old-ui/app/app.js +++ b/old-ui/app/app.js @@ -72,7 +72,7 @@ function mapStateToProps (state) { forgottenPassword: state.appState.forgottenPassword, nextUnreadNotice: state.metamask.nextUnreadNotice, lostAccounts: state.metamask.lostAccounts, - frequentRpcList: state.metamask.frequentRpcList || [], + frequentRpcListDetail: state.metamask.frequentRpcListDetail || [], featureFlags, // state needed to get account dropdown temporarily rendering from app bar diff --git a/old-ui/app/components/app-bar.js b/old-ui/app/components/app-bar.js index 55970543c3ec..d1dfcf4858dc 100644 --- a/old-ui/app/components/app-bar.js +++ b/old-ui/app/components/app-bar.js @@ -17,7 +17,7 @@ module.exports = class AppBar extends Component { static propTypes = { dispatch: PropTypes.func.isRequired, - frequentRpcList: PropTypes.array.isRequired, + frequentRpcListDetail: PropTypes.array.isRequired, isMascara: PropTypes.bool.isRequired, isOnboarding: PropTypes.bool.isRequired, identities: PropTypes.any.isRequired, @@ -196,7 +196,7 @@ module.exports = class AppBar extends Component { renderNetworkDropdown () { const { dispatch, - frequentRpcList: rpcList, + frequentRpcListDetail: rpcList, provider, } = this.props const { @@ -336,7 +336,7 @@ module.exports = class AppBar extends Component { } renderCustomOption ({ rpcTarget, type }) { - const {dispatch} = this.props + const {dispatch, network} = this.props if (type !== 'rpc') { return null @@ -354,7 +354,7 @@ module.exports = class AppBar extends Component { default: return h(DropdownMenuItem, { key: rpcTarget, - onClick: () => dispatch(actions.setRpcTarget(rpcTarget)), + onClick: () => dispatch(actions.setRpcTarget(rpcTarget, network)), closeMenu: () => this.setState({ isNetworkMenuOpen: false }), }, [ h('i.fa.fa-question-circle.fa-lg.menu-icon'), @@ -364,21 +364,24 @@ module.exports = class AppBar extends Component { } } - renderCommonRpc (rpcList, {rpcTarget}) { + renderCommonRpc (rpcList, provider) { const {dispatch} = this.props + const {rpcTarget, type} = provider - return rpcList.map((rpc) => { - if ((rpc === LOCALHOST_RPC_URL) || (rpc === rpcTarget)) { + return rpcList.map((entry) => { + const rpc = entry.rpcUrl + const selected = type === 'rpc' && rpcTarget === rpc + if ((rpc === LOCALHOST_RPC_URL) || selected) { return null } else { return h(DropdownMenuItem, { key: `common${rpc}`, closeMenu: () => this.setState({ isNetworkMenuOpen: false }), - onClick: () => dispatch(actions.setRpcTarget(rpc)), + onClick: () => dispatch(actions.setRpcTarget(rpc, entry.chainId)), }, [ h('i.fa.fa-question-circle.fa-lg.menu-icon'), rpc, - rpcTarget === rpc + selected ? h('.check', '✓') : null, ]) diff --git a/ui/app/app.js b/ui/app/app.js index d06d3d7542d2..979d8a25c173 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -99,7 +99,7 @@ class App extends Component { network, isMouseUser, provider, - frequentRpcList, + frequentRpcListDetail, currentView, setMouseUserState, } = this.props @@ -139,7 +139,7 @@ class App extends Component { // network dropdown h(NetworkDropdown, { provider, - frequentRpcList, + frequentRpcListDetail, }, []), h(AccountMenu), @@ -269,7 +269,7 @@ App.propTypes = { alertMessage: PropTypes.string, network: PropTypes.string, provider: PropTypes.object, - frequentRpcList: PropTypes.array, + frequentRpcListDetail: PropTypes.array, currentView: PropTypes.object, sidebarOpen: PropTypes.bool, alertOpen: PropTypes.bool, @@ -361,7 +361,7 @@ function mapStateToProps (state) { forgottenPassword: state.appState.forgottenPassword, nextUnreadNotice, lostAccounts, - frequentRpcList: state.metamask.frequentRpcList || [], + frequentRpcListDetail: state.metamask.frequentRpcListDetail || [], currentCurrency: state.metamask.currentCurrency, isMouseUser: state.appState.isMouseUser, betaUI: state.metamask.featureFlags.betaUI, diff --git a/ui/app/components/dropdowns/network-dropdown.js b/ui/app/components/dropdowns/network-dropdown.js index df99c8d924c5..df77d1220c5a 100644 --- a/ui/app/components/dropdowns/network-dropdown.js +++ b/ui/app/components/dropdowns/network-dropdown.js @@ -24,7 +24,7 @@ const notToggleElementClassnames = [ function mapStateToProps (state) { return { provider: state.metamask.provider, - frequentRpcList: state.metamask.frequentRpcList || [], + frequentRpcListDetail: state.metamask.frequentRpcListDetail || [], networkDropdownOpen: state.appState.networkDropdownOpen, network: state.metamask.network, } @@ -69,7 +69,7 @@ module.exports = compose( NetworkDropdown.prototype.render = function () { const props = this.props const { provider: { type: providerType, rpcTarget: activeNetwork } } = props - const rpcList = props.frequentRpcList + const rpcListDetail = props.frequentRpcListDetail const isOpen = this.props.networkDropdownOpen const dropdownMenuItemStyle = { fontSize: '16px', @@ -245,7 +245,7 @@ NetworkDropdown.prototype.render = function () { ), this.renderCustomOption(props.provider), - this.renderCommonRpc(rpcList, props.provider), + this.renderCommonRpc(rpcListDetail, props.provider), h( DropdownMenuItem, @@ -295,21 +295,24 @@ NetworkDropdown.prototype.getNetworkName = function () { return name } -NetworkDropdown.prototype.renderCommonRpc = function (rpcList, provider) { +NetworkDropdown.prototype.renderCommonRpc = function (rpcListDetail, provider) { const props = this.props - const rpcTarget = provider.rpcTarget + const { rpcTarget, type } = provider const network = props.network - return rpcList.map((rpc) => { - if ((rpc === 'http://localhost:8545') || (rpc === rpcTarget)) { + return rpcListDetail.map((entry) => { + const rpc = entry.rpcUrl + const selected = type === 'rpc' && rpcTarget === rpc + if ((rpc === 'http://localhost:8545') || selected) { return null } else { + const chainId = entry.chainId || network return h( DropdownMenuItem, { key: `common${rpc}`, closeMenu: () => this.props.hideNetworkDropdown(), - onClick: () => props.setRpcTarget(rpc, network), + onClick: () => props.setRpcTarget(rpc, chainId), style: { fontSize: '16px', lineHeight: '20px', @@ -317,11 +320,11 @@ NetworkDropdown.prototype.renderCommonRpc = function (rpcList, provider) { }, }, [ - rpcTarget === rpc ? h('i.fa.fa-check') : h('.network-check__transparent', '✓'), + selected ? 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', + color: selected ? '#ffffff' : '#9b9b9b', }, }, rpc), ] diff --git a/ui/app/components/pages/home.js b/ui/app/components/pages/home.js index 5e3fdc9af36f..0263924ef231 100644 --- a/ui/app/components/pages/home.js +++ b/ui/app/components/pages/home.js @@ -141,7 +141,7 @@ Home.propTypes = { loadingMessage: PropTypes.string, network: PropTypes.string, provider: PropTypes.object, - frequentRpcList: PropTypes.array, + frequentRpcListDetail: PropTypes.array, currentView: PropTypes.object, sidebarOpen: PropTypes.bool, isMascara: PropTypes.bool, @@ -220,7 +220,7 @@ function mapStateToProps (state) { forgottenPassword: state.appState.forgottenPassword, nextUnreadNotice, lostAccounts, - frequentRpcList: state.metamask.frequentRpcList || [], + frequentRpcListDetail: state.metamask.frequentRpcListDetail || [], currentCurrency: state.metamask.currentCurrency, isMouseUser: state.appState.isMouseUser, isRevealingSeedWords: state.metamask.isRevealingSeedWords, From 9cbb649a535e0ac481ab2dc36106c371c0c824b1 Mon Sep 17 00:00:00 2001 From: hackyminer Date: Thu, 16 Aug 2018 22:49:36 +0900 Subject: [PATCH 05/12] use ETC Cooperative's api server for ETC --- app/scripts/controllers/network/networks.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/scripts/controllers/network/networks.js b/app/scripts/controllers/network/networks.js index 5c53b9fcef8e..9b188980df95 100644 --- a/app/scripts/controllers/network/networks.js +++ b/app/scripts/controllers/network/networks.js @@ -13,8 +13,8 @@ networks.networkList = { 'blockExplorerTx': 'https://gastracker.io/tx/[[txHash]]', 'blockExplorerAddr': 'https://gastracker.io/addr/[[address]]', 'blockExplorerToken': 'https://gastracker.io/token/[[tokenAddress]]/[[address]]', - 'service': 'Ethereum Commonwealth', - 'rpcUrl': 'https://etc-geth.0xinfra.com', + 'service': 'ETC Cooperative', + 'rpcUrl': 'https://ethereumclassic.network', 'exchanges': ['ShapeShift'], 'buyUrl': '', }, From 58255561547c10e9bb93d36661ad5c669bd917c8 Mon Sep 17 00:00:00 2001 From: hackyminer Date: Tue, 21 Aug 2018 16:38:44 +0900 Subject: [PATCH 06/12] ui: fixed css style --- ui/app/css/itcss/components/settings.scss | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ui/app/css/itcss/components/settings.scss b/ui/app/css/itcss/components/settings.scss index 0dd61ac5eb41..7a94c1cb648a 100644 --- a/ui/app/css/itcss/components/settings.scss +++ b/ui/app/css/itcss/components/settings.scss @@ -48,7 +48,6 @@ display: flex; flex-direction: column; padding: 0 5px; - height: 71px; @media screen and (max-width: 575px) { height: initial; @@ -78,10 +77,12 @@ } .settings__input { - padding-left: 10px; + padding-left: 15px; font-size: 14px; - height: 40px; + height: 56px; border: 1px solid $alto; + margin-bottom: 3px; + border-radius: 2px; } .settings__input::-webkit-input-placeholder { From 089e84e908112d9015c6a797bc7464cc6c4cb9f8 Mon Sep 17 00:00:00 2001 From: chris Date: Thu, 23 Aug 2018 08:20:27 -0400 Subject: [PATCH 07/12] Remove ETC additions --- app/_locales/en/messages.json | 3 --- app/scripts/controllers/network/enums.js | 6 ----- app/scripts/controllers/network/network.js | 20 +--------------- app/scripts/controllers/network/networks.js | 23 ------------------ app/scripts/controllers/network/util.js | 5 ---- old-ui/app/app.js | 2 -- old-ui/app/components/app-bar.js | 14 ----------- old-ui/app/components/network.js | 13 ---------- old-ui/app/config.js | 5 ---- .../app/controllers/network-contoller-test.js | 6 ----- ui/app/app.js | 4 ---- .../components/dropdowns/network-dropdown.js | 24 ------------------- ui/app/components/network-display/index.scss | 7 ------ .../network-display.component.js | 2 -- ui/app/components/network.js | 13 ---------- 15 files changed, 1 insertion(+), 146 deletions(-) delete mode 100644 app/scripts/controllers/network/networks.js diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 7bc940204b42..feba153b3945 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -820,9 +820,6 @@ "ropsten": { "message": "Ropsten Test Network" }, - "classic": { - "message": "Ethereum Classic Network" - }, "rpc": { "message": "Custom RPC" }, diff --git a/app/scripts/controllers/network/enums.js b/app/scripts/controllers/network/enums.js index f0ef73f0f469..3190eb37c717 100644 --- a/app/scripts/controllers/network/enums.js +++ b/app/scripts/controllers/network/enums.js @@ -3,35 +3,29 @@ const RINKEBY = 'rinkeby' const KOVAN = 'kovan' const MAINNET = 'mainnet' const LOCALHOST = 'localhost' -const CLASSIC = 'classic' const MAINNET_CODE = 1 const ROPSTEN_CODE = 3 const RINKEYBY_CODE = 4 const KOVAN_CODE = 42 -const CLASSIC_CODE = 61 const ROPSTEN_DISPLAY_NAME = 'Ropsten' const RINKEBY_DISPLAY_NAME = 'Rinkeby' const KOVAN_DISPLAY_NAME = 'Kovan' const MAINNET_DISPLAY_NAME = 'Main Ethereum Network' -const CLASSIC_DISPLAY_NAME = 'Ethereum Classic' module.exports = { ROPSTEN, RINKEBY, KOVAN, MAINNET, - CLASSIC, LOCALHOST, MAINNET_CODE, ROPSTEN_CODE, RINKEYBY_CODE, KOVAN_CODE, - CLASSIC_CODE, ROPSTEN_DISPLAY_NAME, RINKEBY_DISPLAY_NAME, KOVAN_DISPLAY_NAME, MAINNET_DISPLAY_NAME, - CLASSIC_DISPLAY_NAME, } diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index c3f80e9a3060..4fce0ff09c8b 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -11,7 +11,6 @@ const createInfuraClient = require('./createInfuraClient') const createJsonRpcClient = require('./createJsonRpcClient') const createLocalhostClient = require('./createLocalhostClient') const { createSwappableProxy, createEventEmitterProxy } = require('swappable-obj-proxy') -const networks = require('./networks') const extend = require('xtend') const { @@ -19,11 +18,10 @@ const { RINKEBY, KOVAN, MAINNET, - CLASSIC, LOCALHOST, } = require('./enums') const INFURA_PROVIDER_TYPES = [ROPSTEN, RINKEBY, KOVAN, MAINNET] -const ALL_PROVIDER_TYPES = [ROPSTEN, RINKEBY, KOVAN, MAINNET, CLASSIC] +const ALL_PROVIDER_TYPES = [ROPSTEN, RINKEBY, KOVAN, MAINNET] const env = process.env.METAMASK_ENV const METAMASK_DEBUG = process.env.METAMASK_DEBUG @@ -161,9 +159,6 @@ module.exports = class NetworkController extends EventEmitter { const isInfura = INFURA_PROVIDER_TYPES.includes(type) if (isInfura) { this._configureInfuraProvider(opts) - // other predefined endpoints - } else if (ALL_PROVIDER_TYPES.includes(type)){ - this._configurePredefinedProvider(opts) // other type-based rpc endpoints } else if (type === LOCALHOST) { this._configureLocalhostProvider() @@ -192,19 +187,6 @@ module.exports = class NetworkController extends EventEmitter { this._setNetworkClient(networkClient) } - _configurePredefinedProvider ({ type }) { - log.info('NetworkController - configurePredefinedProvider', type) - // setup networkConfig - var settings = { - network: networks.networkList[type].chainId, - } - settings = extend(settings, networks.networkList[type]) - const rpcUrl = networks.networkList[type].rpcUrl - const networkClient = createJsonRpcClient({ rpcUrl }) - this.networkConfig.putState(settings) - this._setNetworkClient(networkClient) - } - _configureStandardProvider ({ rpcUrl, chainId }) { log.info('NetworkController - configureStandardProvider', rpcUrl) const networkClient = createJsonRpcClient({ rpcUrl }) diff --git a/app/scripts/controllers/network/networks.js b/app/scripts/controllers/network/networks.js deleted file mode 100644 index 9b188980df95..000000000000 --- a/app/scripts/controllers/network/networks.js +++ /dev/null @@ -1,23 +0,0 @@ -'use strict' -var networks = function() {} - -const { - CLASSIC, - CLASSIC_CODE, -} = require('./enums') - -networks.networkList = { - [CLASSIC]: { - 'chainId': CLASSIC_CODE, - 'ticker': 'ETC', - 'blockExplorerTx': 'https://gastracker.io/tx/[[txHash]]', - 'blockExplorerAddr': 'https://gastracker.io/addr/[[address]]', - 'blockExplorerToken': 'https://gastracker.io/token/[[tokenAddress]]/[[address]]', - 'service': 'ETC Cooperative', - 'rpcUrl': 'https://ethereumclassic.network', - 'exchanges': ['ShapeShift'], - 'buyUrl': '', - }, -} - -module.exports = networks diff --git a/app/scripts/controllers/network/util.js b/app/scripts/controllers/network/util.js index 3d5059db4812..261dae7211cd 100644 --- a/app/scripts/controllers/network/util.js +++ b/app/scripts/controllers/network/util.js @@ -3,16 +3,13 @@ const { RINKEBY, KOVAN, MAINNET, - CLASSIC, ROPSTEN_CODE, RINKEYBY_CODE, KOVAN_CODE, - CLASSIC_CODE, ROPSTEN_DISPLAY_NAME, RINKEBY_DISPLAY_NAME, KOVAN_DISPLAY_NAME, MAINNET_DISPLAY_NAME, - CLASSIC_DISPLAY_NAME, } = require('./enums') const networkToNameMap = { @@ -20,11 +17,9 @@ const networkToNameMap = { [RINKEBY]: RINKEBY_DISPLAY_NAME, [KOVAN]: KOVAN_DISPLAY_NAME, [MAINNET]: MAINNET_DISPLAY_NAME, - [CLASSIC]: CLASSIC_DISPLAY_NAME, [ROPSTEN_CODE]: ROPSTEN_DISPLAY_NAME, [RINKEYBY_CODE]: RINKEBY_DISPLAY_NAME, [KOVAN_CODE]: KOVAN_DISPLAY_NAME, - [CLASSIC_CODE]: CLASSIC_DISPLAY_NAME, } const getNetworkDisplayName = key => networkToNameMap[key] diff --git a/old-ui/app/app.js b/old-ui/app/app.js index d2689330d20a..58b065850e6f 100644 --- a/old-ui/app/app.js +++ b/old-ui/app/app.js @@ -298,8 +298,6 @@ App.prototype.getNetworkName = function () { name = 'Kovan Test Network' } else if (providerName === 'rinkeby') { name = 'Rinkeby Test Network' - } else if (providerName === 'classic') { - name = 'Ethereum Classic Network' } else { name = 'Unknown Private Network' } diff --git a/old-ui/app/components/app-bar.js b/old-ui/app/components/app-bar.js index d1dfcf4858dc..5fecb9654240 100644 --- a/old-ui/app/components/app-bar.js +++ b/old-ui/app/components/app-bar.js @@ -287,20 +287,6 @@ module.exports = class AppBar extends Component { ? h('.check', '✓') : null, ]), - h(DropdownMenuItem, { - key: 'classic', - closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }), - onClick: () => dispatch(actions.setProviderType('classic')), - style: { - fontSize: '18px', - }, - }, [ - h('.menu-icon.diamond'), - 'Ethereum Classic Network', - providerType === 'classic' - ? h('.check', '✓') - : null, - ]), h(DropdownMenuItem, { key: 'default', closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }), diff --git a/old-ui/app/components/network.js b/old-ui/app/components/network.js index 4e12e2733ca5..59596dabd31e 100644 --- a/old-ui/app/components/network.js +++ b/old-ui/app/components/network.js @@ -55,9 +55,6 @@ Network.prototype.render = function () { } else if (providerName === 'rinkeby') { hoverText = 'Rinkeby Test Network' iconName = 'rinkeby-test-network' - } else if (providerName === 'classic') { - hoverText = 'Ethereum Classic' - iconName = 'ethereum-classic-network' } else { hoverText = 'Unknown Private Network' iconName = 'unknown-private-network' @@ -111,16 +108,6 @@ Network.prototype.render = function () { 'Rinkeby Test Net'), props.onClick && h('i.fa.fa-caret-down.fa-lg'), ]) - case 'ethereum-classic-network': - return h('.network-indicator', [ - h('.menu-icon.diamond'), - h('.network-name', { - style: { - color: '#267f00', - }}, - 'Ethereum Classic Network'), - props.onClick && h('i.fa.fa-caret-down.fa-lg'), - ]) default: return h('.network-indicator', [ h('i.fa.fa-question-circle.fa-lg', { diff --git a/old-ui/app/config.js b/old-ui/app/config.js index 1e7fa6a3fe35..1203524ea6d6 100644 --- a/old-ui/app/config.js +++ b/old-ui/app/config.js @@ -269,11 +269,6 @@ function currentProviderDisplay (metamaskState) { value = 'Rinkeby Test Network' break - case 'classic': - title = 'Current Network' - value = 'Ethereum Classic Network' - break - default: title = 'Current RPC' value = metamaskState.provider.rpcTarget diff --git a/test/unit/app/controllers/network-contoller-test.js b/test/unit/app/controllers/network-contoller-test.js index 2721898bdb01..7959e6cc1265 100644 --- a/test/unit/app/controllers/network-contoller-test.js +++ b/test/unit/app/controllers/network-contoller-test.js @@ -80,9 +80,6 @@ describe('Network utils', () => { }, { input: 42, expected: 'Kovan', - }, { - input: 61, - expected: 'Ethereum Classic', }, { input: 'ropsten', expected: 'Ropsten', @@ -92,9 +89,6 @@ describe('Network utils', () => { }, { input: 'kovan', expected: 'Kovan', - }, { - input: 'classic', - expected: 'Ethereum Classic', }, { input: 'mainnet', expected: 'Main Ethereum Network', diff --git a/ui/app/app.js b/ui/app/app.js index 979d8a25c173..642ad86e3f25 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -228,8 +228,6 @@ class App extends Component { name = this.context.t('connectingToRopsten') } else if (providerName === 'rinkeby') { name = this.context.t('connectingToRinkeby') - } else if (providerName === 'classic') { - name = this.context.t('connectingToClassic') } else { name = this.context.t('connectingToUnknown') } @@ -251,8 +249,6 @@ class App extends Component { name = this.context.t('kovan') } else if (providerName === 'rinkeby') { name = this.context.t('rinkeby') - } else if (providerName === 'classic') { - name = this.context.t('classic') } else { name = this.context.t('unknownNetwork') } diff --git a/ui/app/components/dropdowns/network-dropdown.js b/ui/app/components/dropdowns/network-dropdown.js index df77d1220c5a..3b5d7f323936 100644 --- a/ui/app/components/dropdowns/network-dropdown.js +++ b/ui/app/components/dropdowns/network-dropdown.js @@ -200,28 +200,6 @@ NetworkDropdown.prototype.render = function () { ] ), - h( - DropdownMenuItem, - { - key: 'classic', - closeMenu: () => this.props.hideNetworkDropdown(), - onClick: () => props.setProviderType('classic'), - style: dropdownMenuItemStyle, - }, - [ - providerType === 'classic' ? h('i.fa.fa-check') : h('.network-check__transparent', '✓'), - h(NetworkDropdownIcon, { - backgroundColor: '#228B22', // forest green - isSelected: providerType === 'classic', - }), - h('span.network-name-item', { - style: { - color: providerType === 'classic' ? '#ffffff' : '#9b9b9b', - }, - }, this.context.t('classic')), - ] - ), - h( DropdownMenuItem, { @@ -286,8 +264,6 @@ NetworkDropdown.prototype.getNetworkName = function () { name = this.context.t('kovan') } else if (providerName === 'rinkeby') { name = this.context.t('rinkeby') - } else if (providerName === 'classic') { - name = this.context.t('classic') } else { name = this.context.t('unknownNetwork') } diff --git a/ui/app/components/network-display/index.scss b/ui/app/components/network-display/index.scss index 89d46a7b18f5..57c5c45d34f5 100644 --- a/ui/app/components/network-display/index.scss +++ b/ui/app/components/network-display/index.scss @@ -24,9 +24,6 @@ background-color: lighten($tulip-tree, 35%); } - &--classic { - background-color: lighten($java, 45%); - } } &__name { @@ -54,9 +51,5 @@ &--rinkeby { background-color: $tulip-tree; } - - &--classic { - background-color: $java; - } } } diff --git a/ui/app/components/network-display/network-display.component.js b/ui/app/components/network-display/network-display.component.js index 64913bdae263..38626af20667 100644 --- a/ui/app/components/network-display/network-display.component.js +++ b/ui/app/components/network-display/network-display.component.js @@ -6,7 +6,6 @@ import { ROPSTEN_CODE, RINKEYBY_CODE, KOVAN_CODE, - CLASSIC_CODE, } from '../../../../app/scripts/controllers/network/enums' const networkToClassHash = { @@ -14,7 +13,6 @@ const networkToClassHash = { [ROPSTEN_CODE]: 'ropsten', [RINKEYBY_CODE]: 'rinkeby', [KOVAN_CODE]: 'kovan', - [CLASSIC_CODE]: 'classic', } export default class NetworkDisplay extends Component { diff --git a/ui/app/components/network.js b/ui/app/components/network.js index 832f5f1c8abc..83297c4f2251 100644 --- a/ui/app/components/network.js +++ b/ui/app/components/network.js @@ -63,9 +63,6 @@ Network.prototype.render = function () { } else if (providerName === 'rinkeby') { hoverText = context.t('rinkeby') iconName = 'rinkeby-test-network' - } else if (providerName === 'classic') { - hoverText = context.t('classic') - iconName = 'ethereum-classic-network' } else { hoverText = context.t('unknownNetwork') iconName = 'unknown-private-network' @@ -79,7 +76,6 @@ Network.prototype.render = function () { 'ropsten-test-network': providerName === 'ropsten' || parseInt(networkNumber) === 3, 'kovan-test-network': providerName === 'kovan', 'rinkeby-test-network': providerName === 'rinkeby', - 'ethereum-classic-network': providerName === 'classic', }), title: hoverText, onClick: (event) => { @@ -126,15 +122,6 @@ Network.prototype.render = function () { h('.network-name', context.t('rinkeby')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) - case 'ethereum-classic-network': - return h('.network-indicator', [ - h(NetworkDropdownIcon, { - backgroundColor: '#228B22', // green - nonSelectBackgroundColor: '#46893D', - }), - h('.network-name', context.t('classic')), - h('i.fa.fa-chevron-down.fa-lg.network-caret'), - ]) default: return h('.network-indicator', [ h('i.fa.fa-question-circle.fa-lg', { From 70bdc5444f8c8479013344e6d79bbd3ffe4abb0c Mon Sep 17 00:00:00 2001 From: chris Date: Thu, 23 Aug 2018 09:46:28 -0400 Subject: [PATCH 08/12] re-add networks object --- app/scripts/controllers/network/network.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index 4fce0ff09c8b..994fb6e5d83f 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -35,6 +35,8 @@ const defaultNetworkConfig = { ticker: 'ETH', } +const networks = {}; + module.exports = class NetworkController extends EventEmitter { constructor (opts = {}) { From 01c0ee882469ff478069f24186e8194062c51d93 Mon Sep 17 00:00:00 2001 From: chris Date: Thu, 23 Aug 2018 09:51:29 -0400 Subject: [PATCH 09/12] Removed 2 more ETC artifacts --- app/_locales/en/messages.json | 3 --- app/images/etc_logo.svg | 20 -------------------- 2 files changed, 23 deletions(-) delete mode 100644 app/images/etc_logo.svg diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index feba153b3945..784e2f6fee66 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -838,9 +838,6 @@ "connectingToRinkeby": { "message": "Connecting to Rinkeby Test Network" }, - "connectingToClassic": { - "message": "Connecting to Ethereum Classic Network" - }, "connectingToUnknown": { "message": "Connecting to Unknown Network" }, diff --git a/app/images/etc_logo.svg b/app/images/etc_logo.svg deleted file mode 100644 index 13bc35429fe0..000000000000 --- a/app/images/etc_logo.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - From 42f52cc16a8f689195294bc3b057eea89c4ea083 Mon Sep 17 00:00:00 2001 From: chris Date: Thu, 23 Aug 2018 10:06:01 -0400 Subject: [PATCH 10/12] Fix Network Dropdown param --- ui/app/components/dropdowns/network-dropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/app/components/dropdowns/network-dropdown.js b/ui/app/components/dropdowns/network-dropdown.js index 7078299a2416..aa31bff1d8d3 100644 --- a/ui/app/components/dropdowns/network-dropdown.js +++ b/ui/app/components/dropdowns/network-dropdown.js @@ -271,7 +271,7 @@ NetworkDropdown.prototype.getNetworkName = function () { return name } -NetworkDropdown.prototype.renderCommonRpc = function (rpcListDetail, provider) { +NetworkDropdown.prototype.renderCommonRpc = function (rpcList, provider) { const props = this.props const reversedRpcList = rpcList.slice().reverse() From b604b40994fa5d791fb79aacfba1df3135dc3148 Mon Sep 17 00:00:00 2001 From: chris Date: Thu, 23 Aug 2018 10:22:42 -0400 Subject: [PATCH 11/12] re-add networks file --- app/scripts/controllers/network/network.js | 3 +-- app/scripts/controllers/network/networks.js | 8 ++++++++ 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 app/scripts/controllers/network/networks.js diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index 994fb6e5d83f..5d6d60f3a89f 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -11,6 +11,7 @@ const createInfuraClient = require('./createInfuraClient') const createJsonRpcClient = require('./createJsonRpcClient') const createLocalhostClient = require('./createLocalhostClient') const { createSwappableProxy, createEventEmitterProxy } = require('swappable-obj-proxy') +const networks = require('./networks') const extend = require('xtend') const { @@ -35,8 +36,6 @@ const defaultNetworkConfig = { ticker: 'ETH', } -const networks = {}; - module.exports = class NetworkController extends EventEmitter { constructor (opts = {}) { diff --git a/app/scripts/controllers/network/networks.js b/app/scripts/controllers/network/networks.js new file mode 100644 index 000000000000..06a161070d0c --- /dev/null +++ b/app/scripts/controllers/network/networks.js @@ -0,0 +1,8 @@ +'use strict' +var networks = function() {} + +networks.networkList = { + +} + +module.exports = networks From dd24b1b86e340cbf2d7a7d57797e909b9b016a37 Mon Sep 17 00:00:00 2001 From: chris Date: Thu, 23 Aug 2018 10:44:28 -0400 Subject: [PATCH 12/12] Fix Entry and Network UI errors --- old-ui/app/components/app-bar.js | 3 ++- ui/app/components/dropdowns/network-dropdown.js | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/old-ui/app/components/app-bar.js b/old-ui/app/components/app-bar.js index e285dd3e3ff9..2642ffca23cb 100644 --- a/old-ui/app/components/app-bar.js +++ b/old-ui/app/components/app-bar.js @@ -354,7 +354,8 @@ module.exports = class AppBar extends Component { const {dispatch} = this.props const reversedRpcList = rpcList.slice().reverse() - return reversedRpcList.map((rpc) => { + return reversedRpcList.map((entry) => { + const rpc = entry.rpcUrl const currentRpcTarget = provider.type === 'rpc' && rpc === provider.rpcTarget if ((rpc === LOCALHOST_RPC_URL) || currentRpcTarget) { diff --git a/ui/app/components/dropdowns/network-dropdown.js b/ui/app/components/dropdowns/network-dropdown.js index aa31bff1d8d3..7bef435874a0 100644 --- a/ui/app/components/dropdowns/network-dropdown.js +++ b/ui/app/components/dropdowns/network-dropdown.js @@ -274,8 +274,10 @@ NetworkDropdown.prototype.getNetworkName = function () { NetworkDropdown.prototype.renderCommonRpc = function (rpcList, provider) { const props = this.props const reversedRpcList = rpcList.slice().reverse() + const network = props.network - return reversedRpcList.map((rpc) => { + return reversedRpcList.map((entry) => { + const rpc = entry.rpcUrl const currentRpcTarget = provider.type === 'rpc' && rpc === provider.rpcTarget if ((rpc === 'http://localhost:8545') || currentRpcTarget) {