Merge pull request #1147 from MetaMask/i1144-moarrpc

Save recently used RPCs
This commit is contained in:
Kevin Serrano 2017-03-08 10:07:15 -08:00 committed by GitHub
commit 26cac57838
14 changed files with 153 additions and 51 deletions

View File

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

View File

@ -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

View File

@ -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

View File

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

View File

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

View File

@ -11,6 +11,7 @@ describe ('config view actions', function() {
var initialState = {
metamask: {
rpcTarget: 'foo',
frequentRpcList: []
},
appState: {
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() {
const action = {
type: actions.SET_RPC_TARGET,
value: 'bar',
value: 'foo',
}
var result = reducers(initialState, action)
assert.equal(result.metamask.provider.type, 'rpc')
assert.equal(result.metamask.provider.rpcTarget, action.value)
assert.equal(result.metamask.provider.rpcTarget, 'foo')
})
})
})
})

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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