Merge pull request #1147 from MetaMask/i1144-moarrpc

Save recently used RPCs
feature/default_network_editable
Kevin Serrano 8 years ago committed by GitHub
commit 26cac57838
  1. 2
      CHANGELOG.md
  2. 0
      app/scripts/controllers/currency.js
  3. 63
      app/scripts/controllers/preferences.js
  4. 0
      app/scripts/controllers/shapeshift.js
  5. 33
      app/scripts/lib/controllers/preferences.js
  6. 22
      app/scripts/metamask-controller.js
  7. 1
      development/states/first-time.json
  8. 7
      test/unit/actions/config_test.js
  9. 2
      test/unit/currency-controller-test.js
  10. 2
      test/unit/notice-controller-test.js
  11. 28
      ui/app/actions.js
  12. 35
      ui/app/app.js
  13. 1
      ui/app/config.js
  14. 6
      ui/app/reducers/metamask.js

@ -2,6 +2,8 @@
## Current Master ## Current Master
- Add two most recently used custom RPCs to network dropdown menu.
- Add personal_sign method support. - Add personal_sign method support.
- Add ability to customize gas and gasPrice on the transaction approval screen. - Add ability to customize gas and gasPrice on the transaction approval screen.
- Increase default gas buffer to 1.5x estimated gas value. - Increase default gas buffer to 1.5x estimated gas value.

@ -0,0 +1,63 @@
const ObservableStore = require('obs-store')
const normalizeAddress = require('eth-sig-util').normalize
const extend = require('xtend')
class PreferencesController {
constructor (opts = {}) {
const initState = extend({ frequentRpcList: [] }, opts.initState)
this.store = new ObservableStore(initState)
}
//
// PUBLIC METHODS
//
setSelectedAddress (_address) {
return new Promise((resolve, reject) => {
const address = normalizeAddress(_address)
this.store.updateState({ selectedAddress: address })
resolve()
})
}
getSelectedAddress (_address) {
return this.store.getState().selectedAddress
}
updateFrequentRpcList (_url) {
return this.addToFrequentRpcList(_url)
.then((rpcList) => {
this.store.updateState({ frequentRpcList: rpcList })
return Promise.resolve()
})
}
addToFrequentRpcList (_url) {
let rpcList = this.getFrequentRpcList()
let index = rpcList.findIndex((element) => { return element === _url })
if (index !== -1) {
rpcList.splice(index, 1)
}
if (_url !== 'http://localhost:8545') {
rpcList.push(_url)
}
if (rpcList.length > 2) {
rpcList.shift()
}
return Promise.resolve(rpcList)
}
getFrequentRpcList () {
return this.store.getState().frequentRpcList
}
//
// PRIVATE METHODS
//
}
module.exports = PreferencesController

@ -1,33 +0,0 @@
const ObservableStore = require('obs-store')
const normalizeAddress = require('eth-sig-util').normalize
class PreferencesController {
constructor (opts = {}) {
const initState = opts.initState || {}
this.store = new ObservableStore(initState)
}
//
// PUBLIC METHODS
//
setSelectedAddress(_address) {
return new Promise((resolve, reject) => {
const address = normalizeAddress(_address)
this.store.updateState({ selectedAddress: address })
resolve()
})
}
getSelectedAddress(_address) {
return this.store.getState().selectedAddress
}
//
// PRIVATE METHODS
//
}
module.exports = PreferencesController

@ -11,10 +11,10 @@ const streamIntoProvider = require('web3-stream-provider/handler')
const MetaMaskProvider = require('web3-provider-engine/zero.js') const MetaMaskProvider = require('web3-provider-engine/zero.js')
const setupMultiplex = require('./lib/stream-utils.js').setupMultiplex const setupMultiplex = require('./lib/stream-utils.js').setupMultiplex
const KeyringController = require('./keyring-controller') const KeyringController = require('./keyring-controller')
const PreferencesController = require('./lib/controllers/preferences') const PreferencesController = require('./controllers/preferences')
const CurrencyController = require('./lib/controllers/currency') const CurrencyController = require('./controllers/currency')
const NoticeController = require('./notice-controller') const NoticeController = require('./notice-controller')
const ShapeShiftController = require('./lib/controllers/shapeshift') const ShapeShiftController = require('./controllers/shapeshift')
const MessageManager = require('./lib/message-manager') const MessageManager = require('./lib/message-manager')
const PersonalMessageManager = require('./lib/personal-message-manager') const PersonalMessageManager = require('./lib/personal-message-manager')
const TxManager = require('./transaction-manager') const TxManager = require('./transaction-manager')
@ -244,7 +244,6 @@ module.exports = class MetamaskController extends EventEmitter {
return { return {
// etc // etc
getState: (cb) => cb(null, this.getState()), getState: (cb) => cb(null, this.getState()),
setRpcTarget: this.setRpcTarget.bind(this),
setProviderType: this.setProviderType.bind(this), setProviderType: this.setProviderType.bind(this),
useEtherscanProvider: this.useEtherscanProvider.bind(this), useEtherscanProvider: this.useEtherscanProvider.bind(this),
setCurrentCurrency: this.setCurrentCurrency.bind(this), setCurrentCurrency: this.setCurrentCurrency.bind(this),
@ -265,6 +264,8 @@ module.exports = class MetamaskController extends EventEmitter {
// PreferencesController // PreferencesController
setSelectedAddress: nodeify(preferencesController.setSelectedAddress).bind(preferencesController), setSelectedAddress: nodeify(preferencesController.setSelectedAddress).bind(preferencesController),
setDefaultRpc: nodeify(this.setDefaultRpc).bind(this),
setCustomRpc: nodeify(this.setCustomRpc).bind(this),
// KeyringController // KeyringController
setLocked: nodeify(keyringController.setLocked).bind(keyringController), setLocked: nodeify(keyringController.setLocked).bind(keyringController),
@ -661,10 +662,21 @@ module.exports = class MetamaskController extends EventEmitter {
if (this.isNetworkLoading()) this.lookupNetwork() if (this.isNetworkLoading()) this.lookupNetwork()
} }
setRpcTarget (rpcTarget) { setDefaultRpc () {
this.configManager.setRpcTarget('http://localhost:8545')
extension.runtime.reload()
this.lookupNetwork()
return Promise.resolve('http://localhost:8545')
}
setCustomRpc (rpcTarget, rpcList) {
this.configManager.setRpcTarget(rpcTarget) this.configManager.setRpcTarget(rpcTarget)
return this.preferencesController.updateFrequentRpcList(rpcTarget)
.then(() => {
extension.runtime.reload() extension.runtime.reload()
this.lookupNetwork() this.lookupNetwork()
return Promise.resolve(rpcTarget)
})
} }
setProviderType (type) { setProviderType (type) {

@ -4,6 +4,7 @@
"isUnlocked": false, "isUnlocked": false,
"rpcTarget": "https://rawtestrpc.metamask.io/", "rpcTarget": "https://rawtestrpc.metamask.io/",
"identities": {}, "identities": {},
"frequentRpcList": [],
"unapprovedTxs": {}, "unapprovedTxs": {},
"currentFiat": "USD", "currentFiat": "USD",
"conversionRate": 12.7527416, "conversionRate": 12.7527416,

@ -11,6 +11,7 @@ describe ('config view actions', function() {
var initialState = { var initialState = {
metamask: { metamask: {
rpcTarget: 'foo', rpcTarget: 'foo',
frequentRpcList: []
}, },
appState: { appState: {
currentView: { currentView: {
@ -32,13 +33,13 @@ describe ('config view actions', function() {
it('sets the state.metamask.rpcTarget property of the state to the action.value', function() { it('sets the state.metamask.rpcTarget property of the state to the action.value', function() {
const action = { const action = {
type: actions.SET_RPC_TARGET, type: actions.SET_RPC_TARGET,
value: 'bar', value: 'foo',
} }
var result = reducers(initialState, action) var result = reducers(initialState, action)
assert.equal(result.metamask.provider.type, 'rpc') assert.equal(result.metamask.provider.type, 'rpc')
assert.equal(result.metamask.provider.rpcTarget, action.value) assert.equal(result.metamask.provider.rpcTarget, 'foo')
}) })
}) })
})
})

@ -5,7 +5,7 @@ const assert = require('assert')
const extend = require('xtend') const extend = require('xtend')
const rp = require('request-promise') const rp = require('request-promise')
const nock = require('nock') const nock = require('nock')
const CurrencyController = require('../../app/scripts/lib/controllers/currency') const CurrencyController = require('../../app/scripts/controllers/currency')
describe('config-manager', function() { describe('config-manager', function() {
var currencyController var currencyController

@ -4,7 +4,7 @@ const rp = require('request-promise')
const nock = require('nock') const nock = require('nock')
const configManagerGen = require('../lib/mock-config-manager') const configManagerGen = require('../lib/mock-config-manager')
const NoticeController = require('../../app/scripts/notice-controller') const NoticeController = require('../../app/scripts/notice-controller')
const STORAGE_KEY = 'metamask-persistance-key' const STORAGE_KEY = 'metamask-persistence-key'
describe('notice-controller', function() { describe('notice-controller', function() {
var noticeController var noticeController

@ -112,11 +112,13 @@ var actions = {
// config screen // config screen
SHOW_CONFIG_PAGE: 'SHOW_CONFIG_PAGE', SHOW_CONFIG_PAGE: 'SHOW_CONFIG_PAGE',
SET_RPC_TARGET: 'SET_RPC_TARGET', SET_RPC_TARGET: 'SET_RPC_TARGET',
SET_DEFAULT_RPC_TARGET: 'SET_DEFAULT_RPC_TARGET',
SET_PROVIDER_TYPE: 'SET_PROVIDER_TYPE', SET_PROVIDER_TYPE: 'SET_PROVIDER_TYPE',
USE_ETHERSCAN_PROVIDER: 'USE_ETHERSCAN_PROVIDER', USE_ETHERSCAN_PROVIDER: 'USE_ETHERSCAN_PROVIDER',
useEtherscanProvider: useEtherscanProvider, useEtherscanProvider: useEtherscanProvider,
showConfigPage: showConfigPage, showConfigPage: showConfigPage,
setRpcTarget: setRpcTarget, setRpcTarget: setRpcTarget,
setDefaultRpcTarget: setDefaultRpcTarget,
setProviderType: setProviderType, setProviderType: setProviderType,
// loading overlay // loading overlay
SHOW_LOADING: 'SHOW_LOADING_INDICATION', SHOW_LOADING: 'SHOW_LOADING_INDICATION',
@ -669,12 +671,28 @@ function markAccountsFound() {
// config // config
// //
// default rpc target refers to localhost:8545 in this instance.
function setDefaultRpcTarget (rpcList) {
log.debug(`background.setDefaultRpcTarget`)
return (dispatch) => {
background.setDefaultRpc((err, result) => {
if (err) {
log.error(err)
return dispatch(self.displayWarning('Had a problem changing networks.'))
}
})
}
}
function setRpcTarget (newRpc) { function setRpcTarget (newRpc) {
log.debug(`background.setRpcTarget`) log.debug(`background.setRpcTarget`)
background.setRpcTarget(newRpc) return (dispatch) => {
return { background.setCustomRpc(newRpc, (err, result) => {
type: actions.SET_RPC_TARGET, if (err) {
value: newRpc, log.error(err)
return dispatch(self.displayWarning('Had a problem changing networks!'))
}
})
} }
} }
@ -750,7 +768,7 @@ function exportAccount (address) {
dispatch(self.hideLoadingIndication()) dispatch(self.hideLoadingIndication())
if (err) { if (err) {
console.error(err) log.error(err)
return dispatch(self.displayWarning('Had a problem exporting the account.')) return dispatch(self.displayWarning('Had a problem exporting the account.'))
} }

@ -58,6 +58,7 @@ function mapStateToProps (state) {
forgottenPassword: state.appState.forgottenPassword, forgottenPassword: state.appState.forgottenPassword,
lastUnreadNotice: state.metamask.lastUnreadNotice, lastUnreadNotice: state.metamask.lastUnreadNotice,
lostAccounts: state.metamask.lostAccounts, lostAccounts: state.metamask.lostAccounts,
frequentRpcList: state.metamask.frequentRpcList || [],
} }
} }
@ -211,6 +212,7 @@ App.prototype.renderAppBar = function () {
App.prototype.renderNetworkDropdown = function () { App.prototype.renderNetworkDropdown = function () {
const props = this.props const props = this.props
const rpcList = props.frequentRpcList
const state = this.state || {} const state = this.state || {}
const isOpen = state.isNetworkMenuOpen const isOpen = state.isNetworkMenuOpen
@ -256,12 +258,13 @@ App.prototype.renderNetworkDropdown = function () {
h(DropMenuItem, { h(DropMenuItem, {
label: 'Localhost 8545', label: 'Localhost 8545',
closeMenu: () => this.setState({ isNetworkMenuOpen: false }), closeMenu: () => this.setState({ isNetworkMenuOpen: false }),
action: () => props.dispatch(actions.setRpcTarget('http://localhost:8545')), action: () => props.dispatch(actions.setDefaultRpcTarget(rpcList)),
icon: h('i.fa.fa-question-circle.fa-lg'), icon: h('i.fa.fa-question-circle.fa-lg'),
activeNetworkRender: props.provider.rpcTarget, activeNetworkRender: props.provider.rpcTarget,
}), }),
this.renderCustomOption(props.provider), this.renderCustomOption(props.provider),
this.renderCommonRpc(rpcList, props.provider),
props.isUnlocked && h(DropMenuItem, { props.isUnlocked && h(DropMenuItem, {
label: 'Custom RPC', label: 'Custom RPC',
@ -496,6 +499,12 @@ App.prototype.renderCustomOption = function (provider) {
const { rpcTarget, type } = provider const { rpcTarget, type } = provider
if (type !== 'rpc') return null if (type !== 'rpc') return null
// Concatenate long URLs
let label = rpcTarget
if (rpcTarget.length > 31) {
label = label.substr(0, 34) + '...'
}
switch (rpcTarget) { switch (rpcTarget) {
case 'http://localhost:8545': case 'http://localhost:8545':
@ -503,10 +512,32 @@ App.prototype.renderCustomOption = function (provider) {
default: default:
return h(DropMenuItem, { return h(DropMenuItem, {
label: `${rpcTarget}`, label,
key: rpcTarget,
closeMenu: () => this.setState({ isNetworkMenuOpen: false }), closeMenu: () => this.setState({ isNetworkMenuOpen: false }),
icon: h('i.fa.fa-question-circle.fa-lg'), icon: h('i.fa.fa-question-circle.fa-lg'),
activeNetworkRender: 'custom', activeNetworkRender: 'custom',
}) })
} }
} }
App.prototype.renderCommonRpc = function (rpcList, provider) {
const { rpcTarget } = provider
const props = this.props
return rpcList.map((rpc) => {
if ((rpc === 'http://localhost:8545') || (rpc === rpcTarget)) {
return null
} else {
return h(DropMenuItem, {
label: rpc,
key: rpc,
closeMenu: () => this.setState({ isNetworkMenuOpen: false }),
action: () => props.dispatch(actions.setRpcTarget(rpc)),
icon: h('i.fa.fa-question-circle.fa-lg'),
activeNetworkRender: rpc,
})
}
})
}

@ -5,6 +5,7 @@ const connect = require('react-redux').connect
const actions = require('./actions') const actions = require('./actions')
const currencies = require('./conversion.json').rows const currencies = require('./conversion.json').rows
const validUrl = require('valid-url') const validUrl = require('valid-url')
module.exports = connect(mapStateToProps)(ConfigScreen) module.exports = connect(mapStateToProps)(ConfigScreen)
function mapStateToProps (state) { function mapStateToProps (state) {

@ -18,6 +18,7 @@ function reduceMetamask (state, action) {
conversionDate: 'N/A', conversionDate: 'N/A',
noActiveNotices: true, noActiveNotices: true,
lastUnreadNotice: undefined, lastUnreadNotice: undefined,
frequentRpcList: [],
}, state.metamask) }, state.metamask)
switch (action.type) { switch (action.type) {
@ -53,6 +54,11 @@ function reduceMetamask (state, action) {
isUnlocked: false, isUnlocked: false,
}) })
case actions.SET_RPC_LIST:
return extend(metamaskState, {
frequentRpcList: action.value,
})
case actions.SET_RPC_TARGET: case actions.SET_RPC_TARGET:
return extend(metamaskState, { return extend(metamaskState, {
provider: { provider: {

Loading…
Cancel
Save