migration #9 - break out CurrencyController substate

feature/default_network_editable
kumavis 8 years ago
parent b233e7e37c
commit 9e4ef45b6a
  1. 47
      app/scripts/lib/config-manager.js
  2. 70
      app/scripts/lib/controllers/currency.js
  3. 3
      app/scripts/lib/idStore.js
  4. 47
      app/scripts/metamask-controller.js
  5. 40
      app/scripts/migrations/009.js
  6. 1
      app/scripts/migrations/index.js
  7. 1
      package.json
  8. 75
      test/unit/config-manager-test.js
  9. 87
      test/unit/currency-controller-test.js
  10. 8
      ui/app/actions.js

@ -250,53 +250,6 @@ ConfigManager.prototype.getTOSHash = function () {
return data.TOSHash return data.TOSHash
} }
ConfigManager.prototype.setCurrentFiat = function (currency) {
var data = this.getData()
data.fiatCurrency = currency
this.setData(data)
}
ConfigManager.prototype.getCurrentFiat = function () {
var data = this.getData()
return data.fiatCurrency || 'USD'
}
ConfigManager.prototype.updateConversionRate = function () {
var data = this.getData()
return fetch(`https://www.cryptonator.com/api/ticker/eth-${data.fiatCurrency}`)
.then(response => response.json())
.then((parsedResponse) => {
this.setConversionPrice(parsedResponse.ticker.price)
this.setConversionDate(parsedResponse.timestamp)
}).catch((err) => {
console.warn('MetaMask - Failed to query currency conversion.')
this.setConversionPrice(0)
this.setConversionDate('N/A')
})
}
ConfigManager.prototype.setConversionPrice = function (price) {
var data = this.getData()
data.conversionRate = Number(price)
this.setData(data)
}
ConfigManager.prototype.setConversionDate = function (datestring) {
var data = this.getData()
data.conversionDate = datestring
this.setData(data)
}
ConfigManager.prototype.getConversionRate = function () {
var data = this.getData()
return (data.conversionRate) || 0
}
ConfigManager.prototype.getConversionDate = function () {
var data = this.getData()
return (data.conversionDate) || 'N/A'
}
ConfigManager.prototype.getShapeShiftTxList = function () { ConfigManager.prototype.getShapeShiftTxList = function () {
var data = this.getData() var data = this.getData()
var shapeShiftTxList = data.shapeShiftTxList ? data.shapeShiftTxList : [] var shapeShiftTxList = data.shapeShiftTxList ? data.shapeShiftTxList : []

@ -0,0 +1,70 @@
const ObservableStore = require('obs-store')
const extend = require('xtend')
// every ten minutes
const POLLING_INTERVAL = 600000
class CurrencyController {
constructor (opts = {}) {
const initState = extend({
currentCurrency: 'USD',
conversionRate: 0,
conversionDate: 'N/A',
}, opts.initState)
this.store = new ObservableStore(initState)
}
//
// PUBLIC METHODS
//
getCurrentCurrency () {
return this.store.getState().currentCurrency
}
setCurrentCurrency (currentCurrency) {
this.store.updateState({ currentCurrency })
}
getConversionRate () {
return this.store.getState().conversionRate
}
setConversionRate (conversionRate) {
this.store.updateState({ conversionRate })
}
getConversionDate () {
return this.store.getState().conversionDate
}
setConversionDate (conversionDate) {
this.store.updateState({ conversionDate })
}
updateConversionRate () {
const currentCurrency = this.getCurrentCurrency()
return fetch(`https://www.cryptonator.com/api/ticker/eth-${currentCurrency}`)
.then(response => response.json())
.then((parsedResponse) => {
this.setConversionRate(Number(parsedResponse.ticker.price))
this.setConversionDate(Number(parsedResponse.timestamp))
}).catch((err) => {
console.warn('MetaMask - Failed to query currency conversion.')
this.setConversionRate(0)
this.setConversionDate('N/A')
})
}
scheduleConversionInterval () {
if (this.conversionInterval) {
clearInterval(this.conversionInterval)
}
this.conversionInterval = setInterval(() => {
this.updateConversionRate()
}, POLLING_INTERVAL)
}
}
module.exports = CurrencyController

@ -97,9 +97,6 @@ IdentityStore.prototype.getState = function () {
isDisclaimerConfirmed: configManager.getConfirmedDisclaimer(), isDisclaimerConfirmed: configManager.getConfirmedDisclaimer(),
selectedAddress: configManager.getSelectedAccount(), selectedAddress: configManager.getSelectedAccount(),
shapeShiftTxList: configManager.getShapeShiftTxList(), shapeShiftTxList: configManager.getShapeShiftTxList(),
currentFiat: configManager.getCurrentFiat(),
conversionRate: configManager.getConversionRate(),
conversionDate: configManager.getConversionDate(),
gasMultiplier: configManager.getGasMultiplier(), gasMultiplier: configManager.getGasMultiplier(),
})) }))
} }

@ -12,6 +12,7 @@ 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('./lib/controllers/preferences')
const CurrencyController = require('./lib/controllers/currency')
const NoticeController = require('./notice-controller') const NoticeController = require('./notice-controller')
const MessageManager = require('./lib/message-manager') const MessageManager = require('./lib/message-manager')
const TxManager = require('./transaction-manager') const TxManager = require('./transaction-manager')
@ -41,13 +42,19 @@ module.exports = class MetamaskController extends EventEmitter {
this.configManager = new ConfigManager({ this.configManager = new ConfigManager({
store: this.store, store: this.store,
}) })
this.configManager.updateConversionRate()
// preferences controller // preferences controller
this.preferencesController = new PreferencesController({ this.preferencesController = new PreferencesController({
initState: initState.PreferencesController, initState: initState.PreferencesController,
}) })
// currency controller
this.currencyController = new CurrencyController({
initState: initState.CurrencyController,
})
this.currencyController.updateConversionRate()
this.currencyController.scheduleConversionInterval()
// rpc provider // rpc provider
this.provider = this.initializeProvider(opts) this.provider = this.initializeProvider(opts)
this.provider.on('block', this.logBlock.bind(this)) this.provider.on('block', this.logBlock.bind(this))
@ -97,8 +104,6 @@ module.exports = class MetamaskController extends EventEmitter {
this.checkTOSChange() this.checkTOSChange()
this.scheduleConversionInterval()
// TEMPORARY UNTIL FULL DEPRECATION: // TEMPORARY UNTIL FULL DEPRECATION:
this.idStoreMigrator = new IdStoreMigrator({ this.idStoreMigrator = new IdStoreMigrator({
configManager: this.configManager, configManager: this.configManager,
@ -114,11 +119,15 @@ module.exports = class MetamaskController extends EventEmitter {
this.txManager.store.subscribe((state) => { this.txManager.store.subscribe((state) => {
this.store.updateState({ TransactionManager: state }) this.store.updateState({ TransactionManager: state })
}) })
this.currencyController.store.subscribe((state) => {
this.store.updateState({ CurrencyController: state })
})
// manual mem state subscriptions // manual mem state subscriptions
this.ethStore.subscribe(this.sendUpdate.bind(this)) this.ethStore.subscribe(this.sendUpdate.bind(this))
this.networkStore.subscribe(this.sendUpdate.bind(this)) this.networkStore.subscribe(this.sendUpdate.bind(this))
this.keyringController.memStore.subscribe(this.sendUpdate.bind(this)) this.keyringController.memStore.subscribe(this.sendUpdate.bind(this))
this.currencyController.store.subscribe(this.sendUpdate.bind(this))
this.txManager.memStore.subscribe(this.sendUpdate.bind(this)) this.txManager.memStore.subscribe(this.sendUpdate.bind(this))
this.messageManager.memStore.subscribe(this.sendUpdate.bind(this)) this.messageManager.memStore.subscribe(this.sendUpdate.bind(this))
} }
@ -189,15 +198,13 @@ module.exports = class MetamaskController extends EventEmitter {
this.messageManager.memStore.getState(), this.messageManager.memStore.getState(),
this.keyringController.memStore.getState(), this.keyringController.memStore.getState(),
this.preferencesController.store.getState(), this.preferencesController.store.getState(),
this.currencyController.store.getState(),
this.noticeController.memStore.getState(), this.noticeController.memStore.getState(),
// config manager // config manager
this.configManager.getConfig(), this.configManager.getConfig(),
{ {
shapeShiftTxList: this.configManager.getShapeShiftTxList(), shapeShiftTxList: this.configManager.getShapeShiftTxList(),
lostAccounts: this.configManager.getLostAccounts(), lostAccounts: this.configManager.getLostAccounts(),
currentFiat: this.configManager.getCurrentFiat(),
conversionRate: this.configManager.getConversionRate(),
conversionDate: this.configManager.getConversionDate(),
isDisclaimerConfirmed: this.configManager.getConfirmedDisclaimer(), isDisclaimerConfirmed: this.configManager.getConfirmedDisclaimer(),
seedWords: this.configManager.getSeedWords(), seedWords: this.configManager.getSeedWords(),
} }
@ -223,7 +230,7 @@ module.exports = class MetamaskController extends EventEmitter {
useEtherscanProvider: this.useEtherscanProvider.bind(this), useEtherscanProvider: this.useEtherscanProvider.bind(this),
agreeToDisclaimer: this.agreeToDisclaimer.bind(this), agreeToDisclaimer: this.agreeToDisclaimer.bind(this),
resetDisclaimer: this.resetDisclaimer.bind(this), resetDisclaimer: this.resetDisclaimer.bind(this),
setCurrentFiat: this.setCurrentFiat.bind(this), setCurrentCurrency: this.setCurrentCurrency.bind(this),
setTOSHash: this.setTOSHash.bind(this), setTOSHash: this.setTOSHash.bind(this),
checkTOSChange: this.checkTOSChange.bind(this), checkTOSChange: this.checkTOSChange.bind(this),
setGasMultiplier: this.setGasMultiplier.bind(this), setGasMultiplier: this.setGasMultiplier.bind(this),
@ -550,29 +557,19 @@ module.exports = class MetamaskController extends EventEmitter {
this.verifyNetwork() this.verifyNetwork()
} }
setCurrentFiat (fiat, cb) { setCurrentCurrency (currencyCode, cb) {
try { try {
this.configManager.setCurrentFiat(fiat) this.currencyController.setCurrentCurrency(currencyCode)
this.configManager.updateConversionRate() this.currencyController.updateConversionRate()
this.scheduleConversionInterval()
const data = { const data = {
conversionRate: this.configManager.getConversionRate(), conversionRate: this.currencyController.getConversionRate(),
currentFiat: this.configManager.getCurrentFiat(), currentFiat: this.currencyController.getCurrentCurrency(),
conversionDate: this.configManager.getConversionDate(), conversionDate: this.currencyController.getConversionDate(),
} }
cb(data) cb(null, data)
} catch (err) { } catch (err) {
cb(null, err) cb(err)
}
}
scheduleConversionInterval () {
if (this.conversionInterval) {
clearInterval(this.conversionInterval)
} }
this.conversionInterval = setInterval(() => {
this.configManager.updateConversionRate()
}, 300000)
} }
buyEth (address, amount) { buyEth (address, amount) {

@ -0,0 +1,40 @@
const version = 9
/*
This migration breaks out the CurrencyController substate
*/
const merge = require('deep-merge')
module.exports = {
version,
migrate: function (versionedData) {
versionedData.meta.version = version
try {
const state = versionedData.data
const newState = transformState(state)
versionedData.data = newState
} catch (err) {
console.warn(`MetaMask Migration #${version}` + err.stack)
}
return Promise.resolve(versionedData)
},
}
function transformState (state) {
const newState = merge(state, {
CurrencyController: {
currentCurrency: state.currentFiat || 'USD',
conversionRate: state.conversionRate,
conversionDate: state.conversionDate,
},
})
delete newState.currentFiat
delete newState.conversionRate
delete newState.conversionDate
return newState
}

@ -19,4 +19,5 @@ module.exports = [
require('./006'), require('./006'),
require('./007'), require('./007'),
require('./008'), require('./008'),
require('./009'),
] ]

@ -45,6 +45,7 @@
"clone": "^1.0.2", "clone": "^1.0.2",
"copy-to-clipboard": "^2.0.0", "copy-to-clipboard": "^2.0.0",
"debounce": "^1.0.0", "debounce": "^1.0.0",
"deep-merge": "^1.0.0",
"denodeify": "^1.2.1", "denodeify": "^1.2.1",
"disc": "^1.3.2", "disc": "^1.3.2",
"dnode": "^1.2.2", "dnode": "^1.2.2",

@ -14,81 +14,6 @@ describe('config-manager', function() {
configManager = configManagerGen() configManager = configManagerGen()
}) })
describe('currency conversions', function() {
describe('#setCurrentFiat', function() {
it('should return USD as default', function() {
assert.equal(configManager.getCurrentFiat(), 'USD')
})
it('should be able to set to other currency', function() {
assert.equal(configManager.getCurrentFiat(), 'USD')
configManager.setCurrentFiat('JPY')
var result = configManager.getCurrentFiat()
assert.equal(result, 'JPY')
})
})
describe('#getConversionRate', function() {
it('should return undefined if non-existent', function() {
var result = configManager.getConversionRate()
assert.ok(!result)
})
})
describe('#updateConversionRate', function() {
it('should retrieve an update for ETH to USD and set it in memory', function(done) {
this.timeout(15000)
var usdMock = nock('https://www.cryptonator.com')
.get('/api/ticker/eth-USD')
.reply(200, '{"ticker":{"base":"ETH","target":"USD","price":"11.02456145","volume":"44948.91745289","change":"-0.01472534"},"timestamp":1472072136,"success":true,"error":""}')
assert.equal(configManager.getConversionRate(), 0)
var promise = new Promise(
function (resolve, reject) {
configManager.setCurrentFiat('USD')
configManager.updateConversionRate().then(function() {
resolve()
})
})
promise.then(function() {
var result = configManager.getConversionRate()
assert.equal(typeof result, 'number')
done()
}).catch(function(err) {
console.log(err)
})
})
it('should work for JPY as well.', function() {
this.timeout(15000)
assert.equal(configManager.getConversionRate(), 0)
var jpyMock = nock('https://www.cryptonator.com')
.get('/api/ticker/eth-JPY')
.reply(200, '{"ticker":{"base":"ETH","target":"JPY","price":"11.02456145","volume":"44948.91745289","change":"-0.01472534"},"timestamp":1472072136,"success":true,"error":""}')
var promise = new Promise(
function (resolve, reject) {
configManager.setCurrentFiat('JPY')
configManager.updateConversionRate().then(function() {
resolve()
})
})
promise.then(function() {
var result = configManager.getConversionRate()
assert.equal(typeof result, 'number')
}).catch(function(err) {
console.log(err)
})
})
})
})
describe('confirmation', function() { describe('confirmation', function() {
describe('#getConfirmedDisclaimer', function() { describe('#getConfirmedDisclaimer', function() {

@ -0,0 +1,87 @@
// polyfill fetch
global.fetch = global.fetch || require('isomorphic-fetch')
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')
describe('config-manager', function() {
var currencyController
beforeEach(function() {
currencyController = new CurrencyController()
})
describe('currency conversions', function() {
describe('#setCurrentCurrency', function() {
it('should return USD as default', function() {
assert.equal(currencyController.getCurrentCurrency(), 'USD')
})
it('should be able to set to other currency', function() {
assert.equal(currencyController.getCurrentCurrency(), 'USD')
currencyController.setCurrentCurrency('JPY')
var result = currencyController.getCurrentCurrency()
assert.equal(result, 'JPY')
})
})
describe('#getConversionRate', function() {
it('should return undefined if non-existent', function() {
var result = currencyController.getConversionRate()
assert.ok(!result)
})
})
describe('#updateConversionRate', function() {
it('should retrieve an update for ETH to USD and set it in memory', function(done) {
this.timeout(15000)
var usdMock = nock('https://www.cryptonator.com')
.get('/api/ticker/eth-USD')
.reply(200, '{"ticker":{"base":"ETH","target":"USD","price":"11.02456145","volume":"44948.91745289","change":"-0.01472534"},"timestamp":1472072136,"success":true,"error":""}')
assert.equal(currencyController.getConversionRate(), 0)
currencyController.setCurrentCurrency('USD')
currencyController.updateConversionRate()
.then(function() {
var result = currencyController.getConversionRate()
console.log('currencyController.getConversionRate:', result)
assert.equal(typeof result, 'number')
done()
}).catch(function(err) {
done(err)
})
})
it('should work for JPY as well.', function() {
this.timeout(15000)
assert.equal(currencyController.getConversionRate(), 0)
var jpyMock = nock('https://www.cryptonator.com')
.get('/api/ticker/eth-JPY')
.reply(200, '{"ticker":{"base":"ETH","target":"JPY","price":"11.02456145","volume":"44948.91745289","change":"-0.01472534"},"timestamp":1472072136,"success":true,"error":""}')
var promise = new Promise(
function (resolve, reject) {
currencyController.setCurrentCurrency('JPY')
currencyController.updateConversionRate().then(function() {
resolve()
})
})
promise.then(function() {
var result = currencyController.getConversionRate()
assert.equal(typeof result, 'number')
}).catch(function(err) {
done(err)
})
})
})
})
})

@ -325,12 +325,16 @@ function showInfoPage () {
} }
} }
function setCurrentFiat (fiat) { function setCurrentFiat (currencyCode) {
return (dispatch) => { return (dispatch) => {
dispatch(this.showLoadingIndication()) dispatch(this.showLoadingIndication())
if (global.METAMASK_DEBUG) console.log(`background.setCurrentFiat`) if (global.METAMASK_DEBUG) console.log(`background.setCurrentFiat`)
background.setCurrentFiat(fiat, (data, err) => { background.setCurrentCurrency(currencyCode, (err, data) => {
dispatch(this.hideLoadingIndication()) dispatch(this.hideLoadingIndication())
if (err) {
console.error(err.stack)
return dispatch(actions.displayWarning(err.message))
}
dispatch({ dispatch({
type: this.SET_CURRENT_FIAT, type: this.SET_CURRENT_FIAT,
value: { value: {

Loading…
Cancel
Save