diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index f9d23f69e..b0cd1ca8b 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -311,6 +311,9 @@ "connectingToLocalhost": { "message": "Connecting to Localhost 8545" }, + "connectingToGoerli": { + "message": "Connecting to Goerli Test Network" + }, "connectingToUnknown": { "message": "Connecting to Unknown Network" }, @@ -1229,6 +1232,9 @@ "ropsten": { "message": "Ropsten Test Network" }, + "goerli": { + "message": "Goerli Test Network" + }, "rpc": { "message": "Custom RPC" }, diff --git a/app/scripts/controllers/network/createInfuraClient.js b/app/scripts/controllers/network/createInfuraClient.js index 884b94db3..70b332867 100644 --- a/app/scripts/controllers/network/createInfuraClient.js +++ b/app/scripts/controllers/network/createInfuraClient.js @@ -49,6 +49,10 @@ function createNetworkAndChainIdMiddleware ({ network }) { netId = '42' chainId = '0x2a' break + case 'goerli': + netId = '5' + chainId = '0x05' + break default: throw new Error(`createInfuraClient - unknown network "${network}"`) } diff --git a/app/scripts/controllers/network/enums.js b/app/scripts/controllers/network/enums.js index 3190eb37c..2f7025392 100644 --- a/app/scripts/controllers/network/enums.js +++ b/app/scripts/controllers/network/enums.js @@ -3,16 +3,19 @@ const RINKEBY = 'rinkeby' const KOVAN = 'kovan' const MAINNET = 'mainnet' const LOCALHOST = 'localhost' +const GOERLI = 'goerli' const MAINNET_CODE = 1 const ROPSTEN_CODE = 3 const RINKEYBY_CODE = 4 const KOVAN_CODE = 42 +const GOERLI_CODE = 5 const ROPSTEN_DISPLAY_NAME = 'Ropsten' const RINKEBY_DISPLAY_NAME = 'Rinkeby' const KOVAN_DISPLAY_NAME = 'Kovan' const MAINNET_DISPLAY_NAME = 'Main Ethereum Network' +const GOERLI_DISPLAY_NAME = 'Goerli' module.exports = { ROPSTEN, @@ -20,12 +23,15 @@ module.exports = { KOVAN, MAINNET, LOCALHOST, + GOERLI, MAINNET_CODE, ROPSTEN_CODE, RINKEYBY_CODE, KOVAN_CODE, + GOERLI_CODE, ROPSTEN_DISPLAY_NAME, RINKEBY_DISPLAY_NAME, KOVAN_DISPLAY_NAME, MAINNET_DISPLAY_NAME, + GOERLI_DISPLAY_NAME, } diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index ab1198dd3..c00ac7e6a 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -20,8 +20,9 @@ const { KOVAN, MAINNET, LOCALHOST, + GOERLI, } = require('./enums') -const INFURA_PROVIDER_TYPES = [ROPSTEN, RINKEBY, KOVAN, MAINNET] +const INFURA_PROVIDER_TYPES = [ROPSTEN, RINKEBY, KOVAN, MAINNET, GOERLI] const env = process.env.METAMASK_ENV const METAMASK_DEBUG = process.env.METAMASK_DEBUG diff --git a/app/scripts/controllers/network/util.js b/app/scripts/controllers/network/util.js index 261dae721..b0afccd7e 100644 --- a/app/scripts/controllers/network/util.js +++ b/app/scripts/controllers/network/util.js @@ -3,13 +3,16 @@ const { RINKEBY, KOVAN, MAINNET, + GOERLI, ROPSTEN_CODE, RINKEYBY_CODE, KOVAN_CODE, + GOERLI_CODE, ROPSTEN_DISPLAY_NAME, RINKEBY_DISPLAY_NAME, KOVAN_DISPLAY_NAME, MAINNET_DISPLAY_NAME, + GOERLI_DISPLAY_NAME, } = require('./enums') const networkToNameMap = { @@ -17,9 +20,11 @@ const networkToNameMap = { [RINKEBY]: RINKEBY_DISPLAY_NAME, [KOVAN]: KOVAN_DISPLAY_NAME, [MAINNET]: MAINNET_DISPLAY_NAME, + [GOERLI]: GOERLI_DISPLAY_NAME, [ROPSTEN_CODE]: ROPSTEN_DISPLAY_NAME, [RINKEYBY_CODE]: RINKEBY_DISPLAY_NAME, [KOVAN_CODE]: KOVAN_DISPLAY_NAME, + [GOERLI_CODE]: GOERLI_DISPLAY_NAME, } const getNetworkDisplayName = key => networkToNameMap[key] diff --git a/app/scripts/controllers/recent-blocks.js b/app/scripts/controllers/recent-blocks.js index 982ad2aa4..a2b5d1bae 100644 --- a/app/scripts/controllers/recent-blocks.js +++ b/app/scripts/controllers/recent-blocks.js @@ -8,8 +8,9 @@ const { RINKEBY, KOVAN, MAINNET, + GOERLI, } = require('./network/enums') -const INFURA_PROVIDER_TYPES = [ROPSTEN, RINKEBY, KOVAN, MAINNET] +const INFURA_PROVIDER_TYPES = [ROPSTEN, RINKEBY, KOVAN, MAINNET, GOERLI] class RecentBlocksController { diff --git a/app/scripts/lib/buy-eth-url.js b/app/scripts/lib/buy-eth-url.js index fbe6c6c9e..5cae83a9f 100644 --- a/app/scripts/lib/buy-eth-url.js +++ b/app/scripts/lib/buy-eth-url.js @@ -28,6 +28,8 @@ function getBuyEthUrl ({ network, amount, address, service }) { return 'https://www.rinkeby.io/' case 'kovan-faucet': return 'https://github.com/kovan-testnet/faucet' + case 'goerli-faucet': + return 'https://goerli-faucet.slock.it/' } throw new Error(`Unknown cryptocurrency exchange or faucet: "${service}"`) } @@ -42,6 +44,8 @@ function getDefaultServiceForNetwork (network) { return 'rinkeby-faucet' case '42': return 'kovan-faucet' + case '5': + return 'goerli-faucet' } throw new Error(`No default cryptocurrency exchange or faucet for networkId: "${network}"`) } diff --git a/development/states/navigate-txs.json b/development/states/navigate-txs.json index 23255abed..584a754f0 100644 --- a/development/states/navigate-txs.json +++ b/development/states/navigate-txs.json @@ -230,7 +230,8 @@ "kovan": "ok", "mainnet": "ok", "rinkeby": "ok", - "ropsten": "ok" + "ropsten": "ok", + "goerli": "ok" }, "lostAccounts": [] }, @@ -320,4 +321,4 @@ "toSmartContract": false, "fetchingData": false } -} \ No newline at end of file +} diff --git a/development/states/pending-tx.json b/development/states/pending-tx.json index b4a6565fa..28c1751bd 100644 --- a/development/states/pending-tx.json +++ b/development/states/pending-tx.json @@ -704,7 +704,8 @@ "mainnet": "ok", "ropsten": "ok", "kovan": "ok", - "rinkeby": "ok" + "rinkeby": "ok", + "goerli": "ok" }, "shapeShiftTxList": [], "lostAccounts": [] @@ -735,4 +736,4 @@ "os": "mac" }, "browser": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36" -} \ No newline at end of file +} diff --git a/test/data/v17-long-history.json b/test/data/v17-long-history.json index a33d425f8..cccb1ef96 100644 --- a/test/data/v17-long-history.json +++ b/test/data/v17-long-history.json @@ -54,7 +54,8 @@ "mainnet": "degraded", "ropsten": "ok", "kovan": "ok", - "rinkeby": "ok" + "rinkeby": "ok", + "goerli": "ok" } }, "BlacklistController": { @@ -3050,4 +3051,4 @@ ] } } -} \ No newline at end of file +} diff --git a/test/unit/app/controllers/infura-controller-test.js b/test/unit/app/controllers/infura-controller-test.js index 7bd95dd4b..316f80378 100644 --- a/test/unit/app/controllers/infura-controller-test.js +++ b/test/unit/app/controllers/infura-controller-test.js @@ -4,7 +4,7 @@ const InfuraController = require('../../../../app/scripts/controllers/infura') describe('infura-controller', function () { let infuraController, sandbox, networkStatus - const response = {'mainnet': 'degraded', 'ropsten': 'ok', 'kovan': 'ok', 'rinkeby': 'down'} + const response = {'mainnet': 'degraded', 'ropsten': 'ok', 'kovan': 'ok', 'rinkeby': 'down', 'goerli': 'ok'} before(async function () { infuraController = new InfuraController() @@ -58,5 +58,15 @@ describe('infura-controller', function () { assert.equal(networkStatus.rinkeby, 'down') }) }) + + describe('Goerli', function () { + it('should have Goerli', function () { + assert.equal(Object.keys(networkStatus)[4], 'goerli') + }) + + it('should have a value for Goerli status', function () { + assert.equal(networkStatus.goerli, 'ok') + }) + }) }) }) diff --git a/test/unit/app/controllers/network-contoller-test.js b/test/unit/app/controllers/network-contoller-test.js index 7959e6cc1..32f7b337d 100644 --- a/test/unit/app/controllers/network-contoller-test.js +++ b/test/unit/app/controllers/network-contoller-test.js @@ -92,6 +92,9 @@ describe('Network utils', () => { }, { input: 'mainnet', expected: 'Main Ethereum Network', + }, { + input: 'goerli', + expected: 'Goerli', }, ] diff --git a/test/unit/app/controllers/transactions/recipient-blacklist-checker-test.js b/test/unit/app/controllers/transactions/recipient-blacklist-checker-test.js index cb413545f..d3e47c67e 100644 --- a/test/unit/app/controllers/transactions/recipient-blacklist-checker-test.js +++ b/test/unit/app/controllers/transactions/recipient-blacklist-checker-test.js @@ -4,6 +4,7 @@ const { ROPSTEN_CODE, RINKEYBY_CODE, KOVAN_CODE, + GOERLI_CODE, } = require('../../../../../app/scripts/controllers/network/enums') const KeyringController = require('eth-keyring-controller') @@ -27,14 +28,14 @@ describe('Recipient Blacklist Checker', function () { describe('#checkAccount', function () { it('does not fail on test networks', function () { let callCount = 0 - const networks = [ROPSTEN_CODE, RINKEYBY_CODE, KOVAN_CODE] + const networks = [ROPSTEN_CODE, RINKEYBY_CODE, KOVAN_CODE, GOERLI_CODE] for (const networkId in networks) { publicAccounts.forEach((account) => { recipientBlackListChecker.checkAccount(networkId, account) callCount++ }) } - assert.equal(callCount, 30) + assert.equal(callCount, 40) }) it('fails on mainnet', function () { diff --git a/test/unit/ui/etherscan-prefix-for-network.spec.js b/test/unit/ui/etherscan-prefix-for-network.spec.js index f0aeb8306..45e6e563d 100644 --- a/test/unit/ui/etherscan-prefix-for-network.spec.js +++ b/test/unit/ui/etherscan-prefix-for-network.spec.js @@ -23,4 +23,8 @@ describe('Etherscan Network Prefix', () => { assert.equal(etherscanNetworkPrefix(42), 'kovan.') }) + it('returs goerli as prefix for networkId of 5', () => { + assert.equal(etherscanNetworkPrefix(5), 'goerli.') + }) + }) diff --git a/ui/app/components/app/dropdowns/network-dropdown.js b/ui/app/components/app/dropdowns/network-dropdown.js index 7e645725c..dbe3f1bc8 100644 --- a/ui/app/components/app/dropdowns/network-dropdown.js +++ b/ui/app/components/app/dropdowns/network-dropdown.js @@ -204,6 +204,28 @@ NetworkDropdown.prototype.render = function () { ] ), + h( + DropdownMenuItem, + { + key: 'goerli', + closeMenu: () => this.props.hideNetworkDropdown(), + onClick: () => this.handleClick('goerli'), + style: dropdownMenuItemStyle, + }, + [ + providerType === 'goerli' ? h('i.fa.fa-check') : h('.network-check__transparent', '✓'), + h(NetworkDropdownIcon, { + backgroundColor: '#3099f2', // $dodger-blue + isSelected: providerType === 'goerli', + }), + h('span.network-name-item', { + style: { + color: providerType === 'goerli' ? '#ffffff' : '#9b9b9b', + }, + }, this.context.t('goerli')), + ] + ), + h( DropdownMenuItem, { @@ -287,6 +309,8 @@ NetworkDropdown.prototype.getNetworkName = function () { name = this.context.t('rinkeby') } else if (providerName === 'localhost') { name = this.context.t('localhost') + } else if (providerName === 'goerli') { + name = this.context.t('goerli') } else { name = provider.nickname || this.context.t('unknownNetwork') } diff --git a/ui/app/components/app/dropdowns/tests/network-dropdown.test.js b/ui/app/components/app/dropdowns/tests/network-dropdown.test.js index 91e7899a7..4a81b973f 100644 --- a/ui/app/components/app/dropdowns/tests/network-dropdown.test.js +++ b/ui/app/components/app/dropdowns/tests/network-dropdown.test.js @@ -62,7 +62,7 @@ describe('Network Dropdown', () => { }) it('renders 7 DropDownMenuItems ', () => { - assert.equal(wrapper.find(DropdownMenuItem).length, 7) + assert.equal(wrapper.find(DropdownMenuItem).length, 8) }) it('checks background color for first NetworkDropdownIcon', () => { @@ -82,15 +82,19 @@ describe('Network Dropdown', () => { }) it('checks background color for fifth NetworkDropdownIcon', () => { - assert.equal(wrapper.find(NetworkDropdownIcon).at(4).prop('innerBorder'), '1px solid #9b9b9b') + assert.equal(wrapper.find(NetworkDropdownIcon).at(4).prop('backgroundColor'), '#3099f2') // Goerli Blue + }) + + it('checks background color for sixth NetworkDropdownIcon', () => { + assert.equal(wrapper.find(NetworkDropdownIcon).at(5).prop('innerBorder'), '1px solid #9b9b9b') }) it('checks dropdown for frequestRPCList from state ', () => { - assert.equal(wrapper.find(DropdownMenuItem).at(5).text(), '✓http://localhost:7545') + assert.equal(wrapper.find(DropdownMenuItem).at(6).text(), '✓http://localhost:7545') }) - it('checks background color for sixth NetworkDropdownIcon', () => { - assert.equal(wrapper.find(NetworkDropdownIcon).at(5).prop('innerBorder'), '1px solid #9b9b9b') + it('checks background color for seventh NetworkDropdownIcon', () => { + assert.equal(wrapper.find(NetworkDropdownIcon).at(6).prop('innerBorder'), '1px solid #9b9b9b') }) }) diff --git a/ui/app/components/app/loading-network-screen/loading-network-screen.component.js b/ui/app/components/app/loading-network-screen/loading-network-screen.component.js index b79051d0b..97b16d08f 100644 --- a/ui/app/components/app/loading-network-screen/loading-network-screen.component.js +++ b/ui/app/components/app/loading-network-screen/loading-network-screen.component.js @@ -47,6 +47,8 @@ export default class LoadingNetworkScreen extends PureComponent { name = this.context.t('connectingToRinkeby') } else if (providerName === 'localhost') { name = this.context.t('connectingToLocalhost') + } else if (providerName === 'goerli') { + name = this.context.t('connectingToGoerli') } else { name = this.context.t('connectingTo', [providerId]) } diff --git a/ui/app/components/app/modals/deposit-ether-modal.js b/ui/app/components/app/modals/deposit-ether-modal.js index e4ab7eba1..8f7ef792c 100644 --- a/ui/app/components/app/modals/deposit-ether-modal.js +++ b/ui/app/components/app/modals/deposit-ether-modal.js @@ -133,7 +133,7 @@ DepositEtherModal.prototype.render = function () { const { network, toWyre, toCoinSwitch, address, toFaucet } = this.props const { buyingWithShapeshift } = this.state - const isTestNetwork = ['3', '4', '42'].find(n => n === network) + const isTestNetwork = ['3', '4', '5', '42'].find(n => n === network) const networkName = getNetworkDisplayName(network) return h('div.page-container.page-container--full-width.page-container--full-height', {}, [ diff --git a/ui/app/components/app/network-display/index.scss b/ui/app/components/app/network-display/index.scss index e9f2f2057..d70786d20 100644 --- a/ui/app/components/app/network-display/index.scss +++ b/ui/app/components/app/network-display/index.scss @@ -26,6 +26,10 @@ &--rinkeby { background-color: lighten($tulip-tree, 35%); } + + &--goerli { + background-color: lighten($dodger-blue, 35%); + } } &__name { @@ -53,5 +57,9 @@ &--rinkeby { background-color: $tulip-tree; } + + &--goerli { + background-color: $dodger-blue; + } } } diff --git a/ui/app/components/app/network-display/network-display.component.js b/ui/app/components/app/network-display/network-display.component.js index 1142e8606..9ef5341b0 100644 --- a/ui/app/components/app/network-display/network-display.component.js +++ b/ui/app/components/app/network-display/network-display.component.js @@ -6,12 +6,14 @@ import { ROPSTEN_CODE, RINKEYBY_CODE, KOVAN_CODE, + GOERLI_CODE, } from '../../../../../app/scripts/controllers/network/enums' const networkToClassHash = { [MAINNET_CODE]: 'mainnet', [ROPSTEN_CODE]: 'ropsten', [RINKEYBY_CODE]: 'rinkeby', + [GOERLI_CODE]: 'goerli', [KOVAN_CODE]: 'kovan', } diff --git a/ui/app/components/app/network.js b/ui/app/components/app/network.js index 54065dd73..b438287e5 100644 --- a/ui/app/components/app/network.js +++ b/ui/app/components/app/network.js @@ -50,6 +50,9 @@ Network.prototype.render = function () { } else if (providerName === 'rinkeby') { hoverText = context.t('rinkeby') iconName = 'rinkeby-test-network' + } else if (providerName === 'goerli') { + hoverText = context.t('goerli') + iconName = 'goerli-test-network' } else { hoverText = providerId iconName = 'private-network' @@ -63,6 +66,7 @@ Network.prototype.render = function () { 'ropsten-test-network': providerName === 'ropsten' || parseInt(networkNumber) === 3, 'kovan-test-network': providerName === 'kovan', 'rinkeby-test-network': providerName === 'rinkeby', + 'goerli-test-network': providerName === 'goerli', }), title: hoverText, onClick: (event) => { @@ -113,6 +117,16 @@ Network.prototype.render = function () { h('.network-name', context.t('rinkeby')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) + case 'goerli-test-network': + return h('.network-indicator', [ + h(NetworkDropdownIcon, { + backgroundColor: '#3099f2', // $dodger-blue + nonSelectBackgroundColor: '#ecb23e', + loading: networkNumber === 'loading', + }), + h('.network-name', context.t('goerli')), + h('i.fa.fa-chevron-down.fa-lg.network-caret'), + ]) default: return h('.network-indicator', [ networkNumber === 'loading' diff --git a/ui/app/css/itcss/components/network.scss b/ui/app/css/itcss/components/network.scss index c828a2b26..5197f93e1 100644 --- a/ui/app/css/itcss/components/network.scss +++ b/ui/app/css/itcss/components/network.scss @@ -29,6 +29,10 @@ &.rinkeby-test-network .menu-icon-circle div { background-color: rgba(235, 179, 63, .7) !important; } + + &.goerli-test-network .menu-icon-circle div { + background-color: rgba(48, 153, 242, .7) !important; + } } .dropdown-menu-item { diff --git a/ui/app/helpers/constants/common.js b/ui/app/helpers/constants/common.js index 58fae5e5f..a0d6e65b3 100644 --- a/ui/app/helpers/constants/common.js +++ b/ui/app/helpers/constants/common.js @@ -10,4 +10,5 @@ export const NETWORK_TYPES = { MAINNET: 'mainnet', RINKEBY: 'rinkeby', ROPSTEN: 'ropsten', + GOERLI: 'goerli', } diff --git a/ui/app/pages/routes/index.js b/ui/app/pages/routes/index.js index 37ff2df61..1c96eaf8e 100644 --- a/ui/app/pages/routes/index.js +++ b/ui/app/pages/routes/index.js @@ -269,6 +269,8 @@ class Routes extends Component { name = this.context.t('connectingToRinkeby') } else if (providerName === 'localhost') { name = this.context.t('connectingToLocalhost') + } else if (providerName === 'goerli') { + name = this.context.t('connectingToGoerli') } else { name = this.context.t('connectingTo', [providerId]) } @@ -292,6 +294,8 @@ class Routes extends Component { name = this.context.t('rinkeby') } else if (providerName === 'localhost') { name = this.context.t('localhost') + } else if (providerName === 'goerli') { + name = this.context.t('goerli') } else { name = this.context.t('unknownNetwork') } diff --git a/ui/app/selectors/selectors.js b/ui/app/selectors/selectors.js index 554232f7b..da9cf57c7 100644 --- a/ui/app/selectors/selectors.js +++ b/ui/app/selectors/selectors.js @@ -300,9 +300,10 @@ function isEthereumNetwork (state) { MAINNET, RINKEBY, ROPSTEN, + GOERLI, } = NETWORK_TYPES - return [ KOVAN, MAINNET, RINKEBY, ROPSTEN].includes(networkType) + return [ KOVAN, MAINNET, RINKEBY, ROPSTEN, GOERLI].includes(networkType) } function preferencesSelector ({ metamask }) { diff --git a/ui/lib/account-link.js b/ui/lib/account-link.js index 037d990fa..3eaa7cf71 100644 --- a/ui/lib/account-link.js +++ b/ui/lib/account-link.js @@ -17,6 +17,9 @@ module.exports = function (address, network) { case 42: // kovan test net link = `https://kovan.etherscan.io/address/${address}` break + case 5: // goerli test net + link = `https://goerli.etherscan.io/address/${address}` + break default: link = '' break diff --git a/ui/lib/etherscan-prefix-for-network.js b/ui/lib/etherscan-prefix-for-network.js index 2c1904f1c..ce194b0a8 100644 --- a/ui/lib/etherscan-prefix-for-network.js +++ b/ui/lib/etherscan-prefix-for-network.js @@ -14,6 +14,9 @@ module.exports = function (network) { case 42: // kovan test net prefix = 'kovan.' break + case 5: // goerli test net + prefix = 'goerli.' + break default: prefix = '' }